diff options
| author | fusion32 <marcopuzziello@gmail.com> | 2025-05-17 15:21:37 -0300 |
|---|---|---|
| committer | fusion32 <marcopuzziello@gmail.com> | 2025-05-17 15:21:37 -0300 |
| commit | 8ef2e0070d614624c0a779f7c2a42d6c61c46295 (patch) | |
| tree | e8e5a90848c331764a3908d6c30404c6dca4d1a8 | |
| parent | 717f5cd9dacf30fe6bf1561db9297e75fd27fdef (diff) | |
| download | game-8ef2e0070d614624c0a779f7c2a42d6c61c46295.tar.gz game-8ef2e0070d614624c0a779f7c2a42d6c61c46295.zip | |
TSkillProbe + some structs
| -rw-r--r-- | build.bat | 2 | ||||
| -rw-r--r-- | src/creature.cc | 327 | ||||
| -rw-r--r-- | src/creature.hh | 181 | ||||
| -rw-r--r-- | src/enums.hh | 354 | ||||
| -rw-r--r-- | src/player.cc | 44 | ||||
| -rw-r--r-- | src/player.hh | 117 |
6 files changed, 797 insertions, 228 deletions
@@ -10,7 +10,7 @@ set OUTPUTEXE=out.exe set OUTPUTPDB=out.pdb set INSTALLDIR=..\bin -set SRC="../src/creature.cc" "../src/main.cc" +set SRC="../src/creature.cc" "../src/main.cc" "../src/player.cc" cl -W3 -WX -Zi -we4244 -we4456 -we4457 -wd4996 -std:c++14 -utf-8 -MP8 -DBUILD_DEBUG=1 -DARCH_X64=1 -D_CRT_SECURE_NO_WARNINGS=1 -Fe:"%OUTPUTEXE%" -Fd:"%OUTPUTPDB%" %* %SRC% /link -subsystem:console -incremental:no -opt:ref -dynamicbase "ws2_32.lib" if errorlevel 1 exit /b errorlevel diff --git a/src/creature.cc b/src/creature.cc index b6b046b..7d096d3 100644 --- a/src/creature.cc +++ b/src/creature.cc @@ -1,5 +1,9 @@ #include "creature.hh" + #include "enums.hh" +#include "player.hh" + +#include <math.h> // TSkill REGULAR FUNCTIONS //============================================================================== @@ -20,7 +24,7 @@ int TSkill::Get(void){ int TSkill::GetProgress(void){ int Result = 0; if(this->NextLevel > this->LastLevel){ - Result = (this->NextLevel - this->Exp) * 100 / (this->NextLevel - this->LastLevel); + Result = (this->Exp - this->LastLevel) * 100 / (this->NextLevel - this->LastLevel); // TODO(fusion): This feels too much for reporting a mostly *impossible* error. if(Result < 0 || Result > 100){ @@ -245,18 +249,21 @@ TSkillLevel::~TSkillLevel(void){ } void TSkillLevel::Increase(int Amount){ - if (Amount < 0) { + if(Amount < 0){ error("TSkillLevel::Increase: Amount negativ (%d).\n", Amount); return; } // BUG(fusion): No bounds check as in `TSkillLevel::Decrease`? + // TODO(fusion): This could probably be an oversight but the decompiled + // function was calling `GetExpForLevel` twice instead of using `NextLevel` + // which makes me wonder whether `NextLevel` is properly initialized. int Range = 0; this->Exp += Amount; while(this->Exp >= this->NextLevel){ this->Act += 1; - this->LastLevel = this->GetExpForLevel(this->Act); + this->LastLevel = this->NextLevel; this->NextLevel = this->GetExpForLevel(this->Act + 1); if(this->NextLevel < 0){ // BUG(fusion): We don't check if `Master` is valid here? @@ -294,7 +301,6 @@ void TSkillLevel::Decrease(int Amount){ return; } - int Range = 0; if(Amount < this->Exp){ this->Exp -= Amount; }else{ @@ -302,12 +308,14 @@ void TSkillLevel::Decrease(int Amount){ } // TODO(fusion): This could probably be an oversight but the decompiled - // function was calling `GetExpForLevel` instead of using `LastLevel` + // function was calling `GetExpForLevel` twice instead of using `LastLevel` // which makes me wonder whether `LastLevel` is properly initialized. + int Range = 0; while(this->Exp < this->LastLevel){ this->Act -= 1; this->NextLevel = this->LastLevel; this->LastLevel = this->GetExpForLevel(this->Act); + Range -= 1; } if(Range != 0){ @@ -330,16 +338,16 @@ int TSkillLevel::GetExpForLevel(int Level){ return 0; } - if(Level > 500){ - error("TSkillLevel::GetExpForLevel: Level=%d; Formel gegen Überlauf sichern.\n", Level); - return -1; - } - if(this->Delta <= 0){ error("TSkillLevel::GetExpForLevel: Ungültiger Delta-Wert %d.\n", this->Delta); return 0; } + if(Level > 500){ + error("TSkillLevel::GetExpForLevel: Level=%d; Formel gegen Überlauf sichern.\n", Level); + return -1; // TODO(fusion): Shouldn't this be 0? + } + return ((((Level - 6) * Level + 17) * Level - 12) / 6) * this->Delta; } @@ -358,20 +366,13 @@ bool TSkillLevel::Jump(int Range){ this->Master->Combat.CheckCombatValues(); if(this->Master->Type == PLAYER){ - // TODO(fusion): Probably `TSkill::Get` inlined? - int Level = this->Act; - if(Level < this->Min) - Level = this->Min; - Level += this->MDAct + this->DAct; - // == - - int FromLevel = Level - Range; - int ToLevel = Level; + int ToLevel = this->Get(); + int FromLevel = ToLevel - Range; if(Range > 0){ - SendMessage(this->Master->Connection, TALK_ANONYMOUS_BROADCAST, + SendMessage(this->Master->Connection, TALK_EVENT_MESSAGE, "You advanced from Level %d to Level %d.", FromLevel, ToLevel); }else if(Range < 0){ - SendMessage(this->Master->Connection, TALK_ANONYMOUS_BROADCAST, + SendMessage(this->Master->Connection, TALK_EVENT_MESSAGE, "You were downgraded from Level %d to Level %d.", FromLevel, ToLevel); } } @@ -379,6 +380,290 @@ bool TSkillLevel::Jump(int Range){ return true; } +// TSkillProbe +//============================================================================== +void TSkillProbe::Increase(int Amount){ + if(Amount < 0){ + error("TSkillProbe::Increase: Amount negativ (%d).\n", Amount); + return; + } + + int OldProgress = this->GetProgress(); + + // TODO(fusion): This could probably be an oversight but the decompiled + // function was calling `GetExpForLevel` twice instead of using `NextLevel` + // which makes me wonder whether `NextLevel` is properly initialized. + int Range = 0; + this->Exp += Amount; + while(this->Exp >= this->NextLevel){ + this->Act += 1; + this->LastLevel = this->NextLevel; + this->NextLevel = this->GetExpForLevel(this->Act + 1); + if(this->NextLevel < 0){ + // BUG(fusion): We don't check if `Master` is valid here? + error("TSkillProbe::Increase: Skill vor Überlauf (%s, Skill %d).\n", this->Master->Name, this->SkNr); + this->NextLevel = this->Exp; + this->Exp -= 1000; + break; + } + Range += 1; + } + + if(Range != 0){ + this->Jump(Range); + }else{ + TCreature *Master = this->Master; + if(Master && Master->Type == PLAYER){ + int NewProgress = this->GetProgress(); + if(NewProgress != OldProgress){ + if(this->SkNr == SKILL_MAGIC_LEVEL){ + SendPlayerData(Master->Connection); + }else{ + SendPlayerSkills(Master->Connection); + } + } + } + } +} + +void TSkillProbe::Decrease(int Amount){ + if(Amount < 0){ + error("TSkillProbe::Decrease: Amount negativ (%d).\n", Amount); + return; + } + + int OldProgress = this->GetProgress(); + + if(Amount < this->Exp){ + this->Exp -= Amount; + }else{ + this->Exp = 0; + } + + // TODO(fusion): This could probably be an oversight but the decompiled + // function was calling `GetExpForLevel` twice instead of using `LastLevel` + // which makes me wonder whether `LastLevel` is properly initialized. + int Range = 0; + while(this->Exp < this->LastLevel && this->Act > this->Min){ + this->Act -= 1; + this->NextLevel = this->LastLevel; + this->LastLevel = this->GetExpForLevel(this->Act); + Range -= 1; + } + + if(Range != 0){ + this->Jump(Range); + }else{ + TCreature *Master = this->Master; + if(Master && Master->Type == PLAYER){ + int NewProgress = this->GetProgress(); + if(NewProgress != OldProgress){ + if(this->SkNr == SKILL_MAGIC_LEVEL){ + SendPlayerData(Master->Connection); + }else{ + SendPlayerSkills(Master->Connection); + } + } + } + } +} + +int TSkillProbe::GetExpForLevel(int Level){ + if(Level < 0 || Level < this->Min){ + error("TSkillProbe::GetExpForLevel: Ungültiger Level %d.\n", Level); + return 0; + } + + if(this->Delta <= 0){ + error("TSkillProbe::GetExpForLevel: Ungültiger Delta-Wert %d.\n", this->Delta); + return 0; + } + + // TODO(fusion): This part of the decompiled code was a bit weird. I had to + // look into the disassembly to figure the string parameter of `error` below + // and it is weird that we keep going even with invalid values of `FactorPercent`. + int FactorPercent = this->FactorPercent; + if(FactorPercent < 1000){ + const char *MasterName = "---"; + if(this->Master != NULL){ + MasterName = this->Master->Name; + } + error("TSkillProbe::GetExpForLevel: Ungültiger FactorPercent-Wert %d bei %s.\n", FactorPercent, MasterName); + } + + if(FactorPercent < 1050){ + error("TSkillProbe::GetExpForLevel: Ungültiger FactorPercent-Wert %d. Rechne mit 1000 weiter.\n", FactorPercent); + return (Level - this->Min) * this->Delta; + } + + double Base = (double)FactorPercent / 1000.0; + double Power = pow(Base, (double)(Level - this->Min)); + double Result = (double)this->Delta * ((Power - 1.0) / (Base - 1.0)); + return (int)Result; +} + +void TSkillProbe::ChangeSkill(int FactorPercent, int Delta){ + double Progress = 0.0; + if(this->LastLevel < this->NextLevel){ + Progress = (double)(this->Exp - this->LastLevel) + / (double)(this->NextLevel - this->LastLevel); + } + + double Base = (double)FactorPercent / 1000.0; + + // NOTE(fusion): Similar to `this->GetExpForLevel(this->Act)` but inlined? + double LastLevelPower = pow(Base, (double)(this->Act - this->Min)); + double LastLevel = (double)Delta * ((LastLevelPower - 1.0) / (Base - 1.0)); + + // NOTE(fusion): Similar to `this->GetExpForLevel(this->Act + 1)` but inlined? + double NextLevelPower = pow(Base, (double)(this->Act - this->Min + 1)); + double NextLevel = (double)Delta * ((NextLevelPower - 1.0) / (Base - 1.0)); + + // NOTE(fusion): Renormalize experience. + double Exp = LastLevel + Progress * (NextLevel - LastLevel); + + this->FactorPercent = FactorPercent; + this->LastLevel = (int)LastLevel; + this->NextLevel = (int)NextLevel; + this->Delta = Delta; + this->Exp = (int)Exp; + + TCreature *Master = this->Master; + if(Master != NULL && Master->Type == PLAYER){ + if(this->SkNr == SKILL_MAGIC_LEVEL){ + SendPlayerData(Master->Connection); + }else{ + SendPlayerSkills(Master->Connection); + } + } +} + +int TSkillProbe::ProbeValue(int Max, bool Increase){ + if(Increase){ + this->Increase(1); + } + + // TODO(fusion): Some optimizations made the decompilation output for this + // `RandomFactor` look very weird. It looks correct but we should come back + // to it. + int RandomFactor = ((rand() % 100) + (rand() % 100)) / 2; + int MaxValue = Max * (this->Get() * 5 + 50); + int Result = (RandomFactor * MaxValue) / 10000; + return Result; +} + +bool TSkillProbe::Probe(int Diff, int Prob, bool Increase){ + if(Increase){ + this->Increase(1); + } + + // TODO(fusion): Not sure what's going on here. + bool Result = true; + if(Diff != 0){ + if(this->Act >= (rand() % Diff)){ + Result = (rand() % 100) <= Prob; + }else{ + Result = false; + } + } + return Result; +} + +bool TSkillProbe::SetTimer(int Cycle, int Count, int MaxCount, int AdditionalValue){ + this->Cycle = Cycle; + this->Count = Count; + this->MaxCount = MaxCount; + + if(this->Master == NULL){ + error("TSkillProbe::SetTimer: GetMaster liefert NULL zurueck!\n"); + return false; + } + + if(this->Master->Type == PLAYER){ + ((TPlayer*)this->Master)->CheckState(); + SendPlayerData(this->Master->Connection); + } + + return true; +} + +bool TSkillProbe::Jump(int Range){ + TCreature *Master = this->Master; + if(Master == NULL){ + error("TSkillProbe::Jump: GetMaster liefert NULL zurueck!\n"); + return false; + } + + if(Master->Type == PLAYER){ + if(this->SkNr == SKILL_MAGIC_LEVEL){ + SendPlayerData(Master->Connection); + }else{ + SendPlayerSkills(Master->Connection); + } + + if(Range > 0){ + switch(this->SkNr){ + case SKILL_MAGIC_LEVEL:{ + SendMessage(Master->Connection, TALK_EVENT_MESSAGE, + "You advanced to magic level %d.", this->Get()); + break; + } + case SKILL_SHIELDING:{ + SendMessage(Master->Connection, TALK_EVENT_MESSAGE, "You advanced in shielding."); + break; + } + case SKILL_DISTANCE:{ + SendMessage(Master->Connection, TALK_EVENT_MESSAGE, "You advanced in distance fighting."); + break; + } + case SKILL_SWORD:{ + SendMessage(Master->Connection, TALK_EVENT_MESSAGE, "You advanced in sword fighting."); + break; + } + case SKILL_CLUB:{ + SendMessage(Master->Connection, TALK_EVENT_MESSAGE, "You advanced in club fighting."); + break; + } + case SKILL_AXE:{ + SendMessage(Master->Connection, TALK_EVENT_MESSAGE, "You advanced in axe fighting."); + break; + } + case SKILL_FIST:{ + SendMessage(Master->Connection, TALK_EVENT_MESSAGE, "You advanced in fist fighting."); + break; + } + case SKILL_FISHING:{ + SendMessage(Master->Connection, TALK_EVENT_MESSAGE, "You advanced in fishing."); + break; + } + } + } + } + + return true; +} + +void TSkillProbe::Event(int Range){ + if(this->Cycle == 0){ + TCreature *Master = this->Master; + if(Master == NULL){ + error("TSkillProbe::Event: GetMaster liefert NULL zurueck!\n"); + return; + } + + this->MDAct = 0; + if(Master->Type == PLAYER){ + // TODO(fusion): This is weird because `SKILL_GO_STRENGTH` should + // be TSkillGoStrength, instead of TSkillProbe. + if(this->SkNr == SKILL_GO_STRENGTH){ + ((TPlayer*)Master)->CheckState(); + } + + SendPlayerSkills(Master->Connection); + } + } +} + // Creature Functions //============================================================================== // TODO(fusion): This was the first function I attempted to cleanup but soon diff --git a/src/creature.hh b/src/creature.hh index b471662..1175424 100644 --- a/src/creature.hh +++ b/src/creature.hh @@ -3,9 +3,7 @@ #include "main.hh" -struct TSkillBase; struct TCreature; -struct TPlayer; struct TSkill{ // REGULAR FUNCTIONS @@ -33,44 +31,169 @@ struct TSkill{ virtual int GetExpForLevel(int Level); // VTABLE[ 5] virtual void Advance(int Range); // VTABLE[ 6] virtual void ChangeSkill(int FactorPercent, int Delta); // VTABLE[ 7] - virtual int ProbeValue(int Max, bool Increase); // VTABLE[ 8] - virtual bool Probe(int Diff, int Prob, bool Increase); // VTABLE[ 9] - virtual bool Process(void); // VTABLE[10] - virtual bool SetTimer(int Cycle, int Count, int MaxCount, int AdditionalValue); // VTABLE[11] - virtual bool DelTimer(void); // VTABLE[12] - virtual int TimerValue(void); // VTABLE[13] - virtual bool Jump(int Range); // VTABLE[14] - virtual void Event(int Range); // VTABLE[15] - virtual void Reset(void); // VTABLE[16] + virtual int ProbeValue(int Max, bool Increase); // VTABLE[ 8] + virtual bool Probe(int Diff, int Prob, bool Increase); // VTABLE[ 9] + virtual bool Process(void); // VTABLE[10] + virtual bool SetTimer(int Cycle, int Count, int MaxCount, int AdditionalValue); // VTABLE[11] + virtual bool DelTimer(void); // VTABLE[12] + virtual int TimerValue(void); // VTABLE[13] + virtual bool Jump(int Range); // VTABLE[14] + virtual void Event(int Range); // VTABLE[15] + virtual void Reset(void); // VTABLE[16] // DATA // ========================================================================= //void *VTABLE; // IMPLICIT - int DAct; // Delta Value - Probably from equipment. - int MDAct; // Delta Magic Value - Probably from spells. - uint16 SkNr; - TCreature *Master; - int Act; // Actual Value (?) - int Max; - int Min; - int FactorPercent; - int LastLevel; - int NextLevel; - int Delta; - int Exp; - int Cycle; - int MaxCycle; - int Count; - int MaxCount; - int AddLevel; + int DAct; // Delta Value - Probably from equipment. + int MDAct; // Delta Magic Value - Probably from spells. + uint16 SkNr; + TCreature *Master; + int Act; // Actual Value (?) + int Max; + int Min; + int FactorPercent; + int LastLevel; + int NextLevel; + int Delta; + int Exp; + int Cycle; + int MaxCycle; + int Count; + int MaxCount; + int AddLevel; }; struct TSkillLevel: TSkill { ~TSkillLevel(void) override; void Increase(int Amount) override; void Decrease(int Amount) override; - int GetExpForLevel(int Level) override; + int GetExpForLevel(int Level) override; bool Jump(int Range) override; }; +struct TSkillProbe: TSkill { + ~TSkillProbe(void) override; + void Increase(int Amount) override; + void Decrease(int Amount) override; + int GetExpForLevel(int Level) override; + void ChangeSkill(int FactorPercent, int Delta) override; + int ProbeValue(int Max, bool Increase) override; + bool Probe(int Diff, int Prob, bool Increase) override; + bool SetTimer(int Cycle, int Count, int MaxCount, int AdditionalValue) override; + bool Jump(int Range) override; + void Event(int Range) override; +}; + +struct TSkillBase{ + // REGULAR FUNCTIONS + // ========================================================================= + // TODO + + // DATA + // ========================================================================= + TSkill *Skills[25]; + TSkill *TimerList[25]; + uint16 FirstFreeTimer; +}; + +// TODO(fusion): Maybe split this file? +//============================================================================== +struct TCombatEntry{ + uint32 ID; + uint32 Damage; + int TimeStamp; +}; + +struct TCombat{ + TCreature *Master; + uint32 EarliestAttackTime; + uint32 EarliestDefendTime; + uint32 LastDefendTime; + uint32 LatestAttackTime; + uint32 AttackMode; + uint32 ChaseMode; + uint32 SecureMode; + uint32 AttackDest; + bool Following; + Object Shield; + Object Close; + Object Missile; + Object Throw; + Object Wand; + Object Ammo; + bool Fist; + uint32 CombatDamage; + int ActCombatEntry; + TCombatEntry CombatList[20]; + int LearningPoints; +}; + +struct TOutfit{ + int OutfitID; + union{ + uint16 ObjectType; + uint8 Colors[4]; + }; +}; + +struct TCreature: TSkillBase { + // REGULAR FUNCTIONS + // ========================================================================= + // TODO + + // VIRTUAL FUNCTIONS + // ========================================================================= + // TODO + + // DATA + // ========================================================================= + //void *VTABLE; // IMPLICIT + //TSkillBase super_TSkillBase; // IMPLICIT + TCombat Combat; + uint32 ID; + TCreature *NextHashEntry; + uint32 NextChainCreature; + char Name[31]; + char Murderer[31]; + TOutfit OrgOutfit; + TOutfit Outfit; + int startx; + int starty; + int startz; + int posx; + int posy; + int posz; + int Sex; + int Race; + int Direction; + int Radius; + CreatureType Type; + bool IsDead; + int LoseInventory; + bool LoggingOut; + bool LogoutAllowed; + uint32 EarliestLogoutRound; + uint32 EarliestProtectionZoneRound; + uint32 EarliestYellRound; + uint32 EarliestTradeChannelRound; + uint32 EarliestSpellTime; + uint32 EarliestMultiuseTime; + uint32 EarliestWalkTime; + uint32 LifeEndRound; + TKnownCreature *FirstKnowingConnection; + int SummonedCreatures; + uint32 FireDamageOrigin; + uint32 PoisonDamageOrigin; + uint32 EnergyDamageOrigin; + Object CrObject; + vector<TToDoEntry> ToDoList; + int ActToDo; + int NrToDo; + uint32 NextWakeup; + bool Stop; + bool LockToDo; + uint8 Profession; + TConnection *Connection; +}; + #endif //TIBIA_CREATURE_HH_ diff --git a/src/enums.hh b/src/enums.hh index 8212db1..7791b5e 100644 --- a/src/enums.hh +++ b/src/enums.hh @@ -7,159 +7,159 @@ // there are no collision problems (possibly yet). enum CreatureType: int { - PLAYER = 0, - MONSTER = 1, - NPC = 2, + PLAYER = 0, + MONSTER = 1, + NPC = 2, }; enum RESULT: int { - ERROR = -1, - NOERROR = 0, - NOTACCESSIBLE = 1, - NOTMOVABLE = 2, - NOTTAKABLE = 3, - NOROOM = 4, - OUTOFRANGE = 5, - OUTOFHOME = 6, - CANNOTTHROW = 7, - TOOHEAVY = 8, - CROSSREFERENCE = 9, - CONTAINERFULL = 10, - WRONGPOSITION = 11, - WRONGPOSITION2 = 12, - WRONGCLOTHES = 13, - HANDSNOTFREE = 14, - HANDBLOCKED = 15, - ONEWEAPONONLY = 16, - NOMATCH = 17, - NOTCUMULABLE = 18, - TOOMANYPARTS = 19, - EMPTYCONTAINER = 20, - SPLITOBJECT = 21, - NOKEYMATCH = 22, - UPSTAIRS = 23, - DOWNSTAIRS = 24, - CREATURENOTEXISTING = 25, - PLAYERNOTEXISTING = 26, - PLAYERNOTONLINE = 27, - NAMEAMBIGUOUS = 28, - NOTUSABLE = 29, - FEDUP = 30, - DESTROYED = 31, - SPELLUNKNOWN = 32, - LOWMAGICLEVEL = 33, - MAGICITEM = 34, - NOTENOUGHMANA = 35, - NOSKILL = 36, - TARGETLOST = 37, - OUTOFAMMO = 38, - NOCREATURE = 39, - TOOLONG = 40, - TARGETOUTOFRANGE = 41, - TARGETHIDDEN = 42, - ATTACKNOTALLOWED = 43, - NOWAY = 44, - LOGINERROR = 45, - LOGINABORT = 46, - PROTECTIONZONE = 47, - ENTERPROTECTIONZONE = 48, - EXHAUSTED = 49, - NOTINVITED = 50, - NOPREMIUMACCOUNT = 51, - MOVENOTPOSSIBLE = 52, - ALREADYTRADING = 53, - PARTNERTRADING = 54, - TOOMANYOBJECTS = 55, - TOOMANYSLAVES = 56, - NOTTURNABLE = 57, - SECUREMODE = 58, - NOTENOUGHSOULPOINTS = 59, - LOWLEVEL = 60, + ERROR = -1, + NOERROR = 0, + NOTACCESSIBLE = 1, + NOTMOVABLE = 2, + NOTTAKABLE = 3, + NOROOM = 4, + OUTOFRANGE = 5, + OUTOFHOME = 6, + CANNOTTHROW = 7, + TOOHEAVY = 8, + CROSSREFERENCE = 9, + CONTAINERFULL = 10, + WRONGPOSITION = 11, + WRONGPOSITION2 = 12, + WRONGCLOTHES = 13, + HANDSNOTFREE = 14, + HANDBLOCKED = 15, + ONEWEAPONONLY = 16, + NOMATCH = 17, + NOTCUMULABLE = 18, + TOOMANYPARTS = 19, + EMPTYCONTAINER = 20, + SPLITOBJECT = 21, + NOKEYMATCH = 22, + UPSTAIRS = 23, + DOWNSTAIRS = 24, + CREATURENOTEXISTING = 25, + PLAYERNOTEXISTING = 26, + PLAYERNOTONLINE = 27, + NAMEAMBIGUOUS = 28, + NOTUSABLE = 29, + FEDUP = 30, + DESTROYED = 31, + SPELLUNKNOWN = 32, + LOWMAGICLEVEL = 33, + MAGICITEM = 34, + NOTENOUGHMANA = 35, + NOSKILL = 36, + TARGETLOST = 37, + OUTOFAMMO = 38, + NOCREATURE = 39, + TOOLONG = 40, + TARGETOUTOFRANGE = 41, + TARGETHIDDEN = 42, + ATTACKNOTALLOWED = 43, + NOWAY = 44, + LOGINERROR = 45, + LOGINABORT = 46, + PROTECTIONZONE = 47, + ENTERPROTECTIONZONE = 48, + EXHAUSTED = 49, + NOTINVITED = 50, + NOPREMIUMACCOUNT = 51, + MOVENOTPOSSIBLE = 52, + ALREADYTRADING = 53, + PARTNERTRADING = 54, + TOOMANYOBJECTS = 55, + TOOMANYSLAVES = 56, + NOTTURNABLE = 57, + SECUREMODE = 58, + NOTENOUGHSOULPOINTS = 59, + LOWLEVEL = 60, }; enum RIGHT: int { - PREMIUM_ACCOUNT = 0, - NOTATION = 1, - NAMELOCK = 2, - STATEMENT_REPORT = 3, - BANISHMENT = 4, - FINAL_WARNING = 5, - IP_BANISHMENT = 6, - KICK = 7, - HOME_TELEPORT = 8, - GAMEMASTER_BROADCAST = 9, - ANONYMOUS_BROADCAST = 10, - NO_BANISHMENT = 11, - ALLOW_MULTICLIENT = 12, - LOG_COMMUNICATION = 13, - READ_GAMEMASTER_CHANNEL = 14, - READ_TUTOR_CHANNEL = 15, - HIGHLIGHT_HELP_CHANNEL = 16, - SEND_BUGREPORTS = 17, - NAME_INSULTING = 18, - NAME_SENTENCE = 19, - NAME_NONSENSICAL_LETTERS = 20, - NAME_BADLY_FORMATTED = 21, - NAME_NO_PERSON = 22, - NAME_CELEBRITY = 23, - NAME_COUNTRY = 24, - NAME_FAKE_IDENTITY = 25, - NAME_FAKE_POSITION = 26, - STATEMENT_INSULTING = 27, - STATEMENT_SPAMMING = 28, - STATEMENT_ADVERT_OFFTOPIC = 29, - STATEMENT_ADVERT_MONEY = 30, - STATEMENT_NON_ENGLISH = 31, - STATEMENT_CHANNEL_OFFTOPIC = 32, - STATEMENT_VIOLATION_INCITING = 33, - CHEATING_BUG_ABUSE = 34, - CHEATING_GAME_WEAKNESS = 35, - CHEATING_MACRO_USE = 36, - CHEATING_MODIFIED_CLIENT = 37, - CHEATING_HACKING = 38, - CHEATING_MULTI_CLIENT = 39, - CHEATING_ACCOUNT_TRADING = 40, - CHEATING_ACCOUNT_SHARING = 41, - GAMEMASTER_THREATENING = 42, - GAMEMASTER_PRETENDING = 43, - GAMEMASTER_INFLUENCE = 44, - GAMEMASTER_FALSE_REPORTS = 45, - KILLING_EXCESSIVE_UNJUSTIFIED = 46, - DESTRUCTIVE_BEHAVIOUR = 47, - SPOILING_AUCTION = 48, - INVALID_PAYMENT = 49, - TELEPORT_TO_CHARACTER = 50, - TELEPORT_TO_MARK = 51, - TELEPORT_VERTICAL = 52, - TELEPORT_TO_COORDINATE = 53, - LEVITATE = 54, - SPECIAL_MOVEUSE = 55, - MODIFY_GOSTRENGTH = 56, - SHOW_COORDINATE = 57, - RETRIEVE = 58, - ENTER_HOUSES = 59, - OPEN_NAMEDOORS = 60, - INVULNERABLE = 61, - UNLIMITED_MANA = 62, - KEEP_INVENTORY = 63, - ALL_SPELLS = 64, - UNLIMITED_CAPACITY = 65, - ZERO_CAPACITY = 66, - ATTACK_EVERYWHERE = 67, - NO_ATTACK = 68, - NO_RUNES = 69, - NO_LOGOUT_BLOCK = 70, - GAMEMASTER_OUTFIT = 71, - ILLUMINATE = 72, - CHANGE_PROFESSION = 73, - IGNORED_BY_MONSTERS = 74, - SHOW_KEYHOLE_NUMBERS = 75, - CREATE_OBJECTS = 76, - CREATE_MONEY = 77, - CREATE_MONSTERS = 78, - CHANGE_SKILLS = 79, - CLEANUP_FIELDS = 80, - NO_STATISTICS = 81, + PREMIUM_ACCOUNT = 0, + NOTATION = 1, + NAMELOCK = 2, + STATEMENT_REPORT = 3, + BANISHMENT = 4, + FINAL_WARNING = 5, + IP_BANISHMENT = 6, + KICK = 7, + HOME_TELEPORT = 8, + GAMEMASTER_BROADCAST = 9, + ANONYMOUS_BROADCAST = 10, + NO_BANISHMENT = 11, + ALLOW_MULTICLIENT = 12, + LOG_COMMUNICATION = 13, + READ_GAMEMASTER_CHANNEL = 14, + READ_TUTOR_CHANNEL = 15, + HIGHLIGHT_HELP_CHANNEL = 16, + SEND_BUGREPORTS = 17, + NAME_INSULTING = 18, + NAME_SENTENCE = 19, + NAME_NONSENSICAL_LETTERS = 20, + NAME_BADLY_FORMATTED = 21, + NAME_NO_PERSON = 22, + NAME_CELEBRITY = 23, + NAME_COUNTRY = 24, + NAME_FAKE_IDENTITY = 25, + NAME_FAKE_POSITION = 26, + STATEMENT_INSULTING = 27, + STATEMENT_SPAMMING = 28, + STATEMENT_ADVERT_OFFTOPIC = 29, + STATEMENT_ADVERT_MONEY = 30, + STATEMENT_NON_ENGLISH = 31, + STATEMENT_CHANNEL_OFFTOPIC = 32, + STATEMENT_VIOLATION_INCITING = 33, + CHEATING_BUG_ABUSE = 34, + CHEATING_GAME_WEAKNESS = 35, + CHEATING_MACRO_USE = 36, + CHEATING_MODIFIED_CLIENT = 37, + CHEATING_HACKING = 38, + CHEATING_MULTI_CLIENT = 39, + CHEATING_ACCOUNT_TRADING = 40, + CHEATING_ACCOUNT_SHARING = 41, + GAMEMASTER_THREATENING = 42, + GAMEMASTER_PRETENDING = 43, + GAMEMASTER_INFLUENCE = 44, + GAMEMASTER_FALSE_REPORTS = 45, + KILLING_EXCESSIVE_UNJUSTIFIED = 46, + DESTRUCTIVE_BEHAVIOUR = 47, + SPOILING_AUCTION = 48, + INVALID_PAYMENT = 49, + TELEPORT_TO_CHARACTER = 50, + TELEPORT_TO_MARK = 51, + TELEPORT_VERTICAL = 52, + TELEPORT_TO_COORDINATE = 53, + LEVITATE = 54, + SPECIAL_MOVEUSE = 55, + MODIFY_GOSTRENGTH = 56, + SHOW_COORDINATE = 57, + RETRIEVE = 58, + ENTER_HOUSES = 59, + OPEN_NAMEDOORS = 60, + INVULNERABLE = 61, + UNLIMITED_MANA = 62, + KEEP_INVENTORY = 63, + ALL_SPELLS = 64, + UNLIMITED_CAPACITY = 65, + ZERO_CAPACITY = 66, + ATTACK_EVERYWHERE = 67, + NO_ATTACK = 68, + NO_RUNES = 69, + NO_LOGOUT_BLOCK = 70, + GAMEMASTER_OUTFIT = 71, + ILLUMINATE = 72, + CHANGE_PROFESSION = 73, + IGNORED_BY_MONSTERS = 74, + SHOW_KEYHOLE_NUMBERS = 75, + CREATE_OBJECTS = 76, + CREATE_MONEY = 77, + CREATE_MONSTERS = 78, + CHANGE_SKILLS = 79, + CLEANUP_FIELDS = 80, + NO_STATISTICS = 81, }; // NOTE(fusion): This didn't exist int the decompiled version but is handy when @@ -171,12 +171,12 @@ enum Skill: int { SKILL_MANA = 3, SKILL_GO_STRENGTH = 4, // speed? SKILL_CARRY_WEIGHT = 5, // capacity? - SKILL_FIST = 6, - SKILL_CLUB = 7, + SKILL_SHIELDING = 6, + SKILL_DISTANCE = 7, SKILL_SWORD = 8, - SKILL_AXE = 9, - SKILL_DISTANCE = 10, - SKILL_SHIELDING = 11, + SKILL_CLUB = 9, + SKILL_AXE = 10, + SKILL_FIST = 11, // 12? SKILL_FISHING = 13, SKILL_FED = 14, @@ -185,35 +185,35 @@ enum Skill: int { SKILL_POISON = 17, SKILL_BURNING = 18, SKILL_ENERGY = 19, - // 20? - // 21? + SKILL_DRUNK = 20, + SKILL_MANASHIELD = 21, SKILL_SOUL = 22, }; enum TalkMode: int { - TALK_SAY = 1, - TALK_WHISPER = 2, - TALK_YELL = 3, - TALK_PRIVATE_MESSAGE = 4, - TALK_CHANNEL_CALL = 5, - TALK_GAMEMASTER_REQUEST = 6, - TALK_GAMEMASTER_ANSWER = 7, - TALK_PLAYER_ANSWER = 8, - TALK_GAMEMASTER_BROADCAST = 9, - TALK_GAMEMASTER_CHANNELCALL = 10, - TALK_GAMEMASTER_MESSAGE = 11, - TALK_HIGHLIGHT_CHANNELCALL = 12, - TALK_ANONYMOUS_BROADCAST = 13, - TALK_ANONYMOUS_CHANNELCALL = 14, - TALK_ANONYMOUS_MESSAGE = 15, - TALK_ANIMAL_LOW = 16, - TALK_ANIMAL_LOUD = 17, - TALK_ADMIN_MESSAGE = 18, - TALK_EVENT_MESSAGE = 19, - TALK_LOGIN_MESSAGE = 20, - TALK_STATUS_MESSAGE = 21, - TALK_INFO_MESSAGE = 22, - TALK_FAILURE_MESSAGE = 23, + TALK_SAY = 1, + TALK_WHISPER = 2, + TALK_YELL = 3, + TALK_PRIVATE_MESSAGE = 4, + TALK_CHANNEL_CALL = 5, + TALK_GAMEMASTER_REQUEST = 6, + TALK_GAMEMASTER_ANSWER = 7, + TALK_PLAYER_ANSWER = 8, + TALK_GAMEMASTER_BROADCAST = 9, + TALK_GAMEMASTER_CHANNELCALL = 10, + TALK_GAMEMASTER_MESSAGE = 11, + TALK_HIGHLIGHT_CHANNELCALL = 12, + TALK_ANONYMOUS_BROADCAST = 13, + TALK_ANONYMOUS_CHANNELCALL = 14, + TALK_ANONYMOUS_MESSAGE = 15, + TALK_ANIMAL_LOW = 16, + TALK_ANIMAL_LOUD = 17, + TALK_ADMIN_MESSAGE = 18, + TALK_EVENT_MESSAGE = 19, + TALK_LOGIN_MESSAGE = 20, + TALK_STATUS_MESSAGE = 21, + TALK_INFO_MESSAGE = 22, + TALK_FAILURE_MESSAGE = 23, }; #endif //TIBIA_ENUMS_HH_ diff --git a/src/player.cc b/src/player.cc new file mode 100644 index 0000000..a6cd4a5 --- /dev/null +++ b/src/player.cc @@ -0,0 +1,44 @@ +#include "player.hh" +#include "enums.hh" + +void TPlayer::CheckState(void){ + if(this->Connection != NULL){ + uint8 State = 0; + + if(this->Skills[SKILL_POISON]->TimerValue() > 0){ + State |= 0x01; + } + + if(this->Skills[SKILL_BURNING]->TimerValue() > 0){ + State |= 0x02; + } + + if(this->Skills[SKILL_ENERGY]->TimerValue() > 0){ + State |= 0x04; + } + + // TODO(fusion): Not sure about this one. + if(this->Skills[SKILL_DRUNK]->TimerValue() > 0 && this->Skills[SKILL_DRUNK]->Get() == 0){ + State |= 0x08; + } + + if(this->Skills[SKILL_MANASHIELD]->TimerValue() > 0 || this->Skills[SKILL_MANASHIELD]->Get() > 0){ + State |= 0x10; + } + + if(this->Skills[SKILL_GO_STRENGTH]->MDAct < 0){ + State |= 0x20; + }else if(this->Skills[SKILL_GO_STRENGTH]->MDAct > 0){ + State |= 0x40; + } + + if(RoundNr < this->EarliestLogoutRound){ + State |= 0x80; + } + + if(State != this->OldState){ + SendPlayerState(this->Connection, State); + this->OldState = State; + } + } +} diff --git a/src/player.hh b/src/player.hh new file mode 100644 index 0000000..b6009a1 --- /dev/null +++ b/src/player.hh @@ -0,0 +1,117 @@ +#ifndef TIBIA_PLAYER_HH_ +#define TIBIA_PLAYER_HH_ 1 + +#include "main.hh" +#include "creature.hh" + +struct TPlayerData { + uint32 CharacterID; + pid_t Locked; + int Sticky; + bool Dirty; + int Race; + TOutfit OriginalOutfit; + TOutfit CurrentOutfit; + time_t LastLoginTime; + time_t LastLogoutTime; + int startx; + int starty; + int startz; + int posx; + int posy; + int posz; + int Profession; + int PlayerkillerEnd; + int Actual[25]; + int Maximum[25]; + int Minimum[25]; + int DeltaAct[25]; + int MagicDeltaAct[25]; + int Cycle[25]; + int MaxCycle[25]; + int Count[25]; + int MaxCount[25]; + int AddLevel[25]; + int Experience[25]; + int FactorPercent[25]; + int NextLevel[25]; + int Delta[25]; + uint8 SpellList[256]; + int QuestValues[500]; + int MurderTimestamps[20]; + uint8 *Inventory; + int InventorySize; + uint8 *Depot[9]; + int DepotSize[9]; + ulong AccountID; + int Sex; + char Name[30]; + uint8 Rights[12]; + char Guild[31]; + char Rank[31]; + char Title[31]; + int Buddies; + uint32 Buddy[100]; + char BuddyName[100][30]; + uint32 EarliestYellRound; + uint32 EarliestTradeChannelRound; + uint32 EarliestSpellTime; + uint32 EarliestMultiuseTime; + uint32 TalkBufferFullTime; + uint32 MutingEndRound; + uint32 Addressees[20]; + uint32 AddresseesTimes[20]; + int NumberOfMutings; +}; + +struct TPlayer: TCreature { + // REGULAR FUNCTIONS + // ========================================================================= + void CheckState(void); + + // VIRTUAL FUNCTIONS + // ========================================================================= + // TODO + + // DATA + // ========================================================================= + //TCreature super_TCreature; // IMPLICIT + ulong AccountID; + char Guild[31]; + char Rank[31]; + char Title[31]; + char IPAddress[16]; + uint8 Rights[12]; + Object Depot; + int DepotNr; + int DepotSpace; + RESULT ConstructError; + TPlayerData *PlayerData; + Object TradeObject; + uint32 TradePartner; + bool TradeAccepted; + int OldState; + uint32 Request; + int RequestTimestamp; + uint32 RequestProcessingGamemaster; + int TutorActivities; + uint8 SpellList[256]; + int QuestValues[500]; + Object OpenContainer[16]; + vector<long_unsigned_int> AttackedPlayers; + int NumberOfAttackedPlayers; + bool Aggressor; + vector<long_unsigned_int> FormerAttackedPlayers; + int NumberOfFormerAttackedPlayers; + bool FormerAggressor; + uint32 FormerLogoutRound; + uint32 PartyLeader; + uint32 PartyLeavingRound; + uint32 TalkBufferFullTime; + uint32 MutingEndRound; + int NumberOfMutings; + uint32 Addressees[20]; + uint32 AddresseesTimes[20]; +}; + +#endif //TIBIA_PLAYER_HH_ |
