aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/magic.cc303
-rw-r--r--src/magic.hh81
-rw-r--r--src/stubs.hh4
3 files changed, 349 insertions, 39 deletions
diff --git a/src/magic.cc b/src/magic.cc
index 3a7ed45..a09e52d 100644
--- a/src/magic.cc
+++ b/src/magic.cc
@@ -1,6 +1,7 @@
#include "magic.hh"
#include "config.hh"
#include "creature.hh"
+#include "monster.hh"
#include "stubs.hh"
@@ -110,6 +111,304 @@ void TDamageImpact::handleCreature(TCreature *Victim){
}
}
+// TFieldImpact
+// =============================================================================
+TFieldImpact::TFieldImpact(TCreature *Actor, int FieldType){
+ if(Actor == NULL){
+ error("TFieldImpact::TFieldImpact: Actor ist NULL.\n");
+ }
+
+ this->Actor = Actor;
+ this->FieldType = FieldType;
+}
+
+void TFieldImpact::handleField(int x, int y, int z){
+ TCreature *Actor = this->Actor;
+ if(Actor != NULL){
+ bool Peaceful = false;
+ if(WorldType == NON_PVP){
+ Peaceful = Actor->IsPeaceful();
+ }
+
+ CreateField(x, y, z, this->FieldType, Actor->ID, Peaceful);
+ }
+}
+
+// THealingImpact
+// =============================================================================
+THealingImpact::THealingImpact(TCreature *Actor, int Power){
+ if(Actor == NULL){
+ error("THealingImpact::THealingImpact: Actor ist NULL.\n");
+ }
+
+ if(Power < 0){
+ error("THealingImpact::THealingImpact: Power ist negativ (Actor: %s).\n",
+ (Actor != NULL ? Actor->Name : "(unknown)"));
+ }
+
+ this->Actor = Actor;
+ this->Power = Power;
+}
+
+void THealingImpact::handleCreature(TCreature *Victim){
+ if(Victim == NULL){
+ error("THealingImpact::handleCreature: Opfer existiert nicht.\n");
+ return;
+ }
+
+ if(this->Actor != NULL && this->Power >= 0){
+ int HitPoints = Victim->Skills[SKILL_HITPOINTS]->Get();
+ if(HitPoints > 0){
+ Victim->Skills[SKILL_HITPOINTS]->Change(this->Power);
+
+ // NOTE(fusion): Remove paralyze.
+ if(Victim->Skills[SKILL_GO_STRENGTH]->MDAct < 0){
+ Victim->SetTimer(SKILL_GO_STRENGTH, 0, 0, 0, -1);
+ }
+ }
+ }
+}
+
+bool THealingImpact::isAggressive(void){
+ return false;
+}
+
+// TSpeedImpact
+// =============================================================================
+TSpeedImpact::TSpeedImpact(TCreature *Actor, int Percent, int Duration){
+ if(Actor == NULL){
+ error("TSpeedImpact::TSpeedImpact: Actor ist NULL.\n");
+ }
+
+ this->Actor = Actor;
+ this->Percent = Percent;
+ this->Duration = Duration;
+}
+
+void TSpeedImpact::handleCreature(TCreature *Victim){
+ if(Victim == NULL){
+ error("TSpeedImpact::handleCreature: Opfer existiert nicht.\n");
+ return;
+ }
+
+ TCreature *Actor = this->Actor;
+ if(Actor == NULL){
+ return;
+ }
+
+ int Percent = this->Percent;
+ if(Percent < 0){
+ // TODO(fusion): This looks like some inlined function to check if an
+ // aggression is valid.
+ if(Actor == Victim){
+ return;
+ }
+
+ if(WorldType == NON_PVP && Actor->IsPeaceful() && Victim->IsPeaceful()){
+ return;
+ }
+
+ if(GetRaceNoParalyze(Victim->Race)){
+ return;
+ }
+
+ if(Victim->Type == PLAYER && CheckRight(Victim->ID, INVULNERABLE)){
+ return;
+ }
+ }
+
+
+ TSkill *GoStrength = Victim->Skills[SKILL_GO_STRENGTH];
+ if(Percent < -100){
+ // TODO(fusion): Not sure what's this about.
+ GoStrength->SetMDAct(-GoStrength->Act - 20);
+ }else{
+ GoStrength->SetMDAct((GoStrength->Act * Percent) / 100);
+ }
+
+ Victim->SetTimer(SKILL_GO_STRENGTH, this->Duration, 1, 1, -1);
+}
+
+// TDrunkenImpact
+// =============================================================================
+TDrunkenImpact::TDrunkenImpact(TCreature *Actor, int Power, int Duration){
+ if(Actor == NULL){
+ error("TDrunkenImpact::TDrunkenImpact: Actor ist NULL.\n");
+ }
+
+ if(Power > 6){
+ error("TDrunkenImpact::TDrunkenImpact: Power ist zu groß (%d).\n", Power);
+ Power = 6;
+ }
+
+ this->Actor = Actor;
+ this->Power = Power;
+ this->Duration = Duration;
+}
+
+void TDrunkenImpact::handleCreature(TCreature *Victim){
+ if(Victim == NULL){
+ error("TDrunkenImpact::handleCreature: Opfer existiert nicht.\n");
+ return;
+ }
+
+ TCreature *Actor = this->Actor;
+ if(Actor != NULL){
+ // TODO(fusion): This looks like some inlined function to check if an
+ // aggression is valid.
+ if(Actor == Victim){
+ return;
+ }
+
+ if(WorldType == NON_PVP && Actor->IsPeaceful() && Victim->IsPeaceful()){
+ return;
+ }
+
+ if(GetRaceNoParalyze(Victim->Race)){
+ return;
+ }
+
+ if(Victim->Type == PLAYER && CheckRight(Victim->ID, INVULNERABLE)){
+ return;
+ }
+
+ int Power = this->Power;
+ int Duration = this->Duration;
+ TSkill *Drunk = Victim->Skills[SKILL_DRUNK];
+ if(Drunk->TimerValue() <= Power){
+ Victim->SetTimer(SKILL_DRUNK, Power, Duration, Duration, -1);
+ }
+ }
+}
+
+// TStrengthImpact
+// =============================================================================
+TStrengthImpact::TStrengthImpact(TCreature *Actor, int Skills, int Percent, int Duration){
+ if(Actor == NULL){
+ error("TStrengthImpact::TStrengthImpact: Actor ist NULL.\n");
+ }
+
+ this->Actor = Actor;
+ this->Skills = Skills;
+ this->Percent = Percent;
+ this->Duration = Duration;
+}
+
+void TStrengthImpact::handleCreature(TCreature *Victim){
+ if(Victim == NULL){
+ error("TStrengthImpact::handleCreature: Opfer existiert nicht.\n");
+ return;
+ }
+
+ TCreature *Actor = this->Actor;
+ if(Actor == NULL){
+ return;
+ }
+
+ int Percent = this->Percent;
+ if(Percent < 0){
+ // TODO(fusion): This looks like some inlined function to check if an
+ // aggression is valid.
+ if(Actor == Victim){
+ return;
+ }
+
+ if(WorldType == NON_PVP && Actor->IsPeaceful() && Victim->IsPeaceful()){
+ return;
+ }
+
+ if(GetRaceNoParalyze(Victim->Race)){
+ return;
+ }
+
+ if(Victim->Type == PLAYER && CheckRight(Victim->ID, INVULNERABLE)){
+ return;
+ }
+ }
+
+ int Skills = this->Skills;
+ int Duration = this->Duration;
+
+ for(int SkillNr = 6; SkillNr <= 11; SkillNr += 1){
+ if((Skills & 1) == 0
+ && (SkillNr == SKILL_SWORD
+ || SkillNr == SKILL_CLUB
+ || SkillNr == SKILL_AXE
+ || SkillNr == SKILL_SWORD)){
+ continue;
+ }
+
+ if((Skills & 2) == 0 && SkillNr == SKILL_DISTANCE){
+ continue;
+ }
+
+ if((Skills & 4) == 0 && SkillNr == SKILL_SHIELDING){
+ continue;
+ }
+
+ TSkill *Skill = Victim->Skills[SkillNr];
+ if(Percent < -100){
+ Skill->SetMDAct(-Skill->Act - 20);
+ }else{
+ Skill->SetMDAct((Skill->Act * Percent) / 100);
+ }
+ Victim->SetTimer(SkillNr, Duration, 1, 1, -1);
+ }
+}
+
+// TOutfitImpact
+// =============================================================================
+TOutfitImpact::TOutfitImpact(TCreature *Actor, TOutfit Outfit, int Duration){
+ if(Actor == NULL){
+ error("TOutfitImpact::TOutfitImpact: Actor ist NULL.\n");
+ }
+
+ this->Actor = Actor;
+ this->Outfit = Outfit;
+ this->Duration = Duration;
+}
+
+void TOutfitImpact::handleCreature(TCreature *Victim){
+ if(Victim == NULL){
+ error("TOutfitImpact::handleCreature: Opfer existiert nicht.\n");
+ return;
+ }
+
+ Victim->Outfit = this->Outfit;
+ Victim->SetTimer(SKILL_ILLUSION, 1, this->Duration, this->Duration, -1);
+}
+
+// TSummonImpact
+// =============================================================================
+TSummonImpact::TSummonImpact(TCreature *Actor, int Race, int Maximum){
+ if(Actor == NULL){
+ error("TSummonImpact::TSummonImpact: Actor ist NULL.\n");
+ }
+
+ // TODO(fusion): I think there might be a `IsRaceValid` function that was inlined.
+ if(Race < 0 || Race >= NARRAY(RaceData)){
+ error("TSummonImpact::TSummonImpact: Ungültige Rassennummer %d.\n", Race);
+ }
+
+ this->Actor = Actor;
+ this->Race = Race;
+ this->Maximum = Maximum;
+}
+
+void TSummonImpact::handleField(int x, int y, int z){
+ TCreature *Actor = this->Actor;
+ int Race = this->Race;
+ int Maximum = this->Maximum;
+ if(Actor != NULL
+ && Race >= 0 && Race < NARRAY(RaceData)
+ && Actor->SummonedCreatures < Maximum){
+ int x, y, z;
+ if(SearchSummonField(&x, &y, &z, 2)){
+ CreateMonster(Race, x, y, z, 0, Actor->ID, true);
+ }
+ }
+}
+
// Magic Related Functions
// =============================================================================
void CheckMana(TCreature *Creature, int ManaPoints, int SoulPoints, int Delay){
@@ -157,6 +456,8 @@ void CheckMana(TCreature *Creature, int ManaPoints, int SoulPoints, int Delay){
}
}
+// Magic Init Functions
+// =============================================================================
static void InitCircles(void){
char FileName[4096];
snprintf(FileName, sizeof(FileName), "%s/circles.dat", DATAPATH);
@@ -229,7 +530,7 @@ static TSpellList *CreateSpell(int SpellNr, ...){
return Spell;
}
-void InitSpells(void){
+static void InitSpells(void){
TSpellList *Spell;
Spell = CreateSpell(1, "ex", "ura", "");
diff --git a/src/magic.hh b/src/magic.hh
index 91b7c0a..0525ad2 100644
--- a/src/magic.hh
+++ b/src/magic.hh
@@ -7,7 +7,7 @@
struct TImpact{
// VIRTUAL FUNCTIONS
// =========================================================================
- virtual void handleField(int a, int b, int c); // VTABLE[0]
+ virtual void handleField(int x, int y, int z); // VTABLE[0]
virtual void handleCreature(TCreature *Victim); // VTABLE[1]
virtual bool isAggressive(void); // VTABLE[2]
@@ -16,72 +16,77 @@ struct TImpact{
//void *VTABLE; // IMPLICIT
};
-#if 0
-struct TSummonImpact {
- TImpact super_TImpact; // INHERITANCE?
+struct TDamageImpact: TImpact {
+ TDamageImpact(TCreature *Actor, int DamageType, int Power, bool AllowDefense);
+ void handleCreature(TCreature *Victim) override;
+
TCreature *Actor;
- int Race;
- int Maximum;
+ int DamageType;
+ int Power;
+ bool AllowDefense;
};
-struct TSpeedImpact {
- TImpact super_TImpact; // INHERITANCE?
+struct TFieldImpact: TImpact {
+ TFieldImpact(TCreature *Actor, int FieldType);
+ void handleField(int x, int y, int z) override;
+
TCreature *Actor;
- int Percent;
- int Duration;
+ int FieldType;
};
-struct THealingImpact {
- TImpact super_TImpact; // INHERITANCE?
+struct THealingImpact: TImpact {
+ THealingImpact(TCreature *Actor, int Power);
+ void handleCreature(TCreature *Victim) override;
+ bool isAggressive(void) override;
+
TCreature *Actor;
int Power;
};
-struct TOutfitImpact {
- TImpact super_TImpact; // INHERITANCE?
+struct TSpeedImpact: TImpact {
+ TSpeedImpact(TCreature *Actor, int Percent, int Duration);
+ void handleCreature(TCreature *Victim) override;
+
TCreature *Actor;
- TOutfit Outfit;
+ int Percent;
int Duration;
};
-struct TFieldImpact {
- TImpact super_TImpact; // INHERITANCE?
- TCreature *Actor;
- int FieldType;
-};
+struct TDrunkenImpact: TImpact {
+ TDrunkenImpact(TCreature *Actor, int Power, int Duration);
+ void handleCreature(TCreature *Victim) override;
-struct TDrunkenImpact {
- TImpact super_TImpact; // INHERITANCE?
TCreature *Actor;
int Power;
int Duration;
};
-struct TStrengthImpact {
- TImpact super_TImpact; // INHERITANCE?
+struct TStrengthImpact: TImpact {
+ TStrengthImpact(TCreature *Actor, int Skills, int Percent, int Duration);
+ void handleCreature(TCreature *Victim) override;
+
TCreature *Actor;
int Skills;
int Percent;
int Duration;
};
-#endif
-
-struct TDamageImpact: TImpact{
- // REGULAR FUNCTIONS
- // =========================================================================
- TDamageImpact(TCreature *Actor, int DamageType, int Power, bool AllowDefense);
- // VIRTUAL FUNCTIONS
- // =========================================================================
+struct TOutfitImpact: TImpact {
+ TOutfitImpact(TCreature *Actor, TOutfit Outfit, int Duration);
void handleCreature(TCreature *Victim) override;
- // DATA
- // =========================================================================
- // TImpact super_TImpact; // IMPLICIT
TCreature *Actor;
- int DamageType;
- int Power;
- bool AllowDefense;
+ TOutfit Outfit;
+ int Duration;
+};
+
+struct TSummonImpact: TImpact {
+ TSummonImpact(TCreature *Actor, int Race, int Maximum);
+ void handleField(int x, int y, int z) override;
+
+ TCreature *Actor;
+ int Race;
+ int Maximum;
};
struct TCircle {
diff --git a/src/stubs.hh b/src/stubs.hh
index 4bb8ad2..3a58557 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -26,6 +26,8 @@ extern void CircleShapeSpell(TCreature *Actor, int DestX, int DestY, int DestZ,
int Range, int Animation, int Radius, TImpact *Impact, int Effect);
extern void CleanHouseField(int x, int y, int z);
extern int ComputeDamage(TCreature *Creature, int SpellNr, int Damage, int Variation);
+extern void CreateField(int x, int y, int z, int FieldType, uint32 Owner, bool Peaceful);
+extern void CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect);
extern void CreatePlayerList(bool Online);
extern void CreatePool(Object Con, ObjectType Type, uint32 Value);
extern void Delete(Object Obj, int Count);
@@ -34,6 +36,7 @@ extern TCreature *GetCreature(uint32 CreatureID);
extern TConnection *GetFirstConnection(void);
extern TConnection *GetNextConnection(void);
extern TPlayer *GetPlayer(uint32 CreatureID);
+extern bool GetRaceNoParalyze(int Race);
extern int GetRacePoison(int Race);
extern void GraphicalEffect(int x, int y, int z, int Type);
extern void GraphicalEffect(Object Obj, int Type);
@@ -62,6 +65,7 @@ extern void RefreshMap(void);
extern void RefreshSector(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int Size);
extern void SavePlayerDataOrder(void);
extern bool SearchFlightField(uint32 FugitiveID, uint32 PursuerID, int *x, int *y, int *z);
+extern bool SearchSummonField(int *x, int *y, int *z, int Distance);
extern void SendAll(void);
extern void SendAmbiente(TConnection *Connection);
extern void SendClearTarget(TConnection *Connection);