aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-05-17 15:21:37 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-05-17 15:21:37 -0300
commit8ef2e0070d614624c0a779f7c2a42d6c61c46295 (patch)
treee8e5a90848c331764a3908d6c30404c6dca4d1a8
parent717f5cd9dacf30fe6bf1561db9297e75fd27fdef (diff)
downloadgame-8ef2e0070d614624c0a779f7c2a42d6c61c46295.tar.gz
game-8ef2e0070d614624c0a779f7c2a42d6c61c46295.zip
TSkillProbe + some structs
-rw-r--r--build.bat2
-rw-r--r--src/creature.cc327
-rw-r--r--src/creature.hh181
-rw-r--r--src/enums.hh354
-rw-r--r--src/player.cc44
-rw-r--r--src/player.hh117
6 files changed, 797 insertions, 228 deletions
diff --git a/build.bat b/build.bat
index d969bee..b963864 100644
--- a/build.bat
+++ b/build.bat
@@ -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_