From 9c74d168961619d754ca9f51aa86686185d3f92e Mon Sep 17 00:00:00 2001 From: fusion32 Date: Sun, 1 Jun 2025 13:05:16 -0300 Subject: impl TImpact structs --- src/magic.cc | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/magic.hh | 81 ++++++++-------- src/stubs.hh | 4 + 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); -- cgit v1.2.3