diff options
Diffstat (limited to 'src/creature.cc')
| -rw-r--r-- | src/creature.cc | 327 |
1 files changed, 306 insertions, 21 deletions
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 |
