From e5b8aadd493b8b5df4ed661f2491de33d634b001 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Wed, 18 Jun 2025 18:57:37 -0300 Subject: finish `crplayer.cc` --- Makefile | 10 +- TODO.md | 1 - reference/game.c | 2460 ----------------------------------------------------- src/common.hh | 2 + src/connection.hh | 2 + src/cr.hh | 72 +- src/crmain.cc | 4 +- src/crplayer.cc | 1813 +++++++++++++++++++++++++++++++++------ src/crskill.cc | 16 +- src/enums.hh | 17 + src/stubs.hh | 8 + 11 files changed, 1664 insertions(+), 2741 deletions(-) diff --git a/Makefile b/Makefile index c937038..a10d2e8 100644 --- a/Makefile +++ b/Makefile @@ -13,10 +13,10 @@ else CFLAGS += -O2 endif -HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/config.hh $(SRCDIR)/connection.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/enums.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/objects.hh $(SRCDIR)/operate.hh $(SRCDIR)/script.hh $(SRCDIR)/stubs.hh $(SRCDIR)/thread.hh +HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/config.hh $(SRCDIR)/connection.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/enums.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/moveuse.hh $(SRCDIR)/objects.hh $(SRCDIR)/operate.hh $(SRCDIR)/query.hh $(SRCDIR)/script.hh $(SRCDIR)/stubs.hh $(SRCDIR)/thread.hh -$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/config.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/script.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/thread.obj $(BUILDDIR)/time.obj $(BUILDDIR)/util.obj - echo $(CC) $(CFLAGS) $(LFLAGS) -o $@ $^ +$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/config.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/query.obj $(BUILDDIR)/script.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/thread.obj $(BUILDDIR)/time.obj $(BUILDDIR)/util.obj + @echo $(CC) $(CFLAGS) $(LFLAGS) -o $@ $^ $(BUILDDIR)/config.obj: $(SRCDIR)/config.cc $(HEADERS) @mkdir -p $(@D) @@ -70,6 +70,10 @@ $(BUILDDIR)/operate.obj: $(SRCDIR)/operate.cc $(HEADERS) @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< +$(BUILDDIR)/query.obj: $(SRCDIR)/query.cc $(HEADERS) + @mkdir -p $(@D) + $(CC) -c $(CFLAGS) -o $@ $< + $(BUILDDIR)/script.obj: $(SRCDIR)/script.cc $(HEADERS) @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< diff --git a/TODO.md b/TODO.md index ecfef37..eed0a40 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,4 @@ ## TODO NEXT -- CRPLAYER.CC - QUERY.CC - COMMUNICATION.CC - HOUSES.CC diff --git a/reference/game.c b/reference/game.c index a3130b1..3711e19 100644 --- a/reference/game.c +++ b/reference/game.c @@ -18382,2466 +18382,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority return; } -// DWARF original prototype: void ClearConnection(TPlayer * this) - -void __thiscall TPlayer::ClearConnection(TPlayer *this) - -{ - int GamemasterID; - TCreature *pTVar1; - TCreature *pTVar2; - - (this->super_TCreature).Connection = (TConnection *)0x0; - if (this->Request != 0) { - if (this->RequestProcessingGamemaster == 0) { - DeleteGamemasterRequest((this->super_TCreature).Name); - } - else { - pTVar1 = GetCreature(this->RequestProcessingGamemaster); - pTVar2 = (TCreature *)0x0; - if ((pTVar1 != (TCreature *)0x0) && (pTVar2 = pTVar1, pTVar1->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - pTVar2 = (TCreature *)0x0; - } - if (pTVar2 != (TCreature *)0x0) { - SendFinishRequest(pTVar2->Connection,(this->super_TCreature).Name); - } - } - this->Request = 0; - } - return; -} - - - -// DWARF original prototype: void LoadData(TPlayer * this) - -void __thiscall TPlayer::LoadData(TPlayer *this) - -{ - anon_union_4_2_730cd3ca_for_TOutfit_2 aVar1; - uint uVar2; - int iVar3; - TPlayerData *pTVar4; - uchar *puVar5; - int *piVar6; - int SkillNr; - uchar *puVar7; - int *piVar8; - - pTVar4 = this->PlayerData; - if (pTVar4 != (TPlayerData *)0x0) { - (this->super_TCreature).Race = pTVar4->Race; - aVar1 = (pTVar4->OriginalOutfit).field_1; - (this->super_TCreature).OrgOutfit.OutfitID = (pTVar4->OriginalOutfit).OutfitID; - (this->super_TCreature).OrgOutfit.field_1 = aVar1; - GetStartPosition(&(this->super_TCreature).startx,&(this->super_TCreature).starty, - &(this->super_TCreature).startz,true); - (this->super_TCreature).posx = (this->super_TCreature).startx; - (this->super_TCreature).posy = (this->super_TCreature).starty; - (this->super_TCreature).posz = (this->super_TCreature).startz; - (this->super_TCreature).Direction = 2; - TSkillBase::SetSkills - (&(this->super_TCreature).super_TSkillBase,(this->super_TCreature).Race); - pTVar4 = this->PlayerData; - aVar1 = (pTVar4->CurrentOutfit).field_1; - (this->super_TCreature).Outfit.OutfitID = (pTVar4->CurrentOutfit).OutfitID; - (this->super_TCreature).Outfit.field_1 = aVar1; - if (pTVar4->startx != 0) { - (this->super_TCreature).startx = pTVar4->startx; - (this->super_TCreature).starty = pTVar4->starty; - (this->super_TCreature).startz = pTVar4->startz; - } - if (pTVar4->posx != 0) { - (this->super_TCreature).posx = pTVar4->posx; - (this->super_TCreature).posy = pTVar4->posy; - (this->super_TCreature).posz = pTVar4->posz; - } - uVar2 = 2000; - (this->super_TCreature).Profession = (uchar)pTVar4->Profession; - puVar5 = pTVar4->SpellList; - puVar7 = this->SpellList; - for (iVar3 = 0x40; iVar3 != 0; iVar3 = iVar3 + -1) { - *(undefined4 *)puVar7 = *(undefined4 *)puVar5; - puVar5 = puVar5 + 4; - puVar7 = puVar7 + 4; - } - piVar8 = this->QuestValues; - pTVar4 = this->PlayerData; - piVar6 = pTVar4->QuestValues; - if (((uint)piVar8 & 4) != 0) { - piVar8 = this->QuestValues + 1; - piVar6 = pTVar4->QuestValues + 1; - this->QuestValues[0] = pTVar4->QuestValues[0]; - uVar2 = 0x7cc; - } - for (uVar2 = uVar2 >> 2; uVar2 != 0; uVar2 = uVar2 - 1) { - *piVar8 = *piVar6; - piVar6 = piVar6 + 1; - piVar8 = piVar8 + 1; - } - pTVar4 = this->PlayerData; - iVar3 = 0; - do { - if (pTVar4->Minimum[iVar3] != -0x80000000) { - TSkill::Load((this->super_TCreature).super_TSkillBase.Skills[iVar3]); - pTVar4 = this->PlayerData; - } - iVar3 = iVar3 + 1; - } while (iVar3 < 0x19); - (this->super_TCreature).EarliestYellRound = pTVar4->EarliestYellRound; - (this->super_TCreature).EarliestTradeChannelRound = pTVar4->EarliestTradeChannelRound; - (this->super_TCreature).EarliestSpellTime = pTVar4->EarliestSpellTime; - (this->super_TCreature).EarliestMultiuseTime = pTVar4->EarliestMultiuseTime; - this->TalkBufferFullTime = pTVar4->TalkBufferFullTime; - this->MutingEndRound = pTVar4->MutingEndRound; - this->NumberOfMutings = pTVar4->NumberOfMutings; - return; - } - error("TPlayer::LoadData: PlayerData ist NULL.\n"); - return; -} - - - -// DWARF original prototype: void SaveData(TPlayer * this) - -void __thiscall TPlayer::SaveData(TPlayer *this) - -{ - TPlayerData *pTVar1; - anon_union_4_2_730cd3ca_for_TOutfit_2 aVar2; - uint uVar3; - int iVar4; - int SkillNr; - uchar *puVar5; - int *piVar6; - uchar *puVar7; - int *piVar8; - - pTVar1 = this->PlayerData; - if (pTVar1 != (TPlayerData *)0x0) { - aVar2 = (this->super_TCreature).OrgOutfit.field_1; - (pTVar1->OriginalOutfit).OutfitID = (this->super_TCreature).OrgOutfit.OutfitID; - (pTVar1->OriginalOutfit).field_1 = aVar2; - pTVar1 = this->PlayerData; - aVar2 = (this->super_TCreature).Outfit.field_1; - (pTVar1->CurrentOutfit).OutfitID = (this->super_TCreature).Outfit.OutfitID; - (pTVar1->CurrentOutfit).field_1 = aVar2; - this->PlayerData->startx = (this->super_TCreature).startx; - this->PlayerData->starty = (this->super_TCreature).starty; - this->PlayerData->startz = (this->super_TCreature).startz; - this->PlayerData->posx = (this->super_TCreature).posx; - this->PlayerData->posy = (this->super_TCreature).posy; - this->PlayerData->posz = (this->super_TCreature).posz; - uVar3 = 2000; - this->PlayerData->Profession = (uint)(this->super_TCreature).Profession; - puVar5 = this->SpellList; - puVar7 = this->PlayerData->SpellList; - for (iVar4 = 0x40; iVar4 != 0; iVar4 = iVar4 + -1) { - *(undefined4 *)puVar7 = *(undefined4 *)puVar5; - puVar5 = puVar5 + 4; - puVar7 = puVar7 + 4; - } - piVar6 = this->QuestValues; - pTVar1 = this->PlayerData; - piVar8 = pTVar1->QuestValues; - if (((uint)piVar8 & 4) != 0) { - piVar8 = pTVar1->QuestValues + 1; - piVar6 = this->QuestValues + 1; - pTVar1->QuestValues[0] = this->QuestValues[0]; - uVar3 = 0x7cc; - } - for (uVar3 = uVar3 >> 2; uVar3 != 0; uVar3 = uVar3 - 1) { - *piVar8 = *piVar6; - piVar6 = piVar6 + 1; - piVar8 = piVar8 + 1; - } - iVar4 = 0; - do { - if ((this->super_TCreature).super_TSkillBase.Skills[iVar4] == (TSkill *)0x0) { - this->PlayerData->Minimum[iVar4] = -0x80000000; - } - else { - TSkill::Save((this->super_TCreature).super_TSkillBase.Skills[iVar4]); - } - iVar4 = iVar4 + 1; - } while (iVar4 < 0x19); - this->PlayerData->EarliestYellRound = (this->super_TCreature).EarliestYellRound; - this->PlayerData->EarliestTradeChannelRound = - (this->super_TCreature).EarliestTradeChannelRound; - this->PlayerData->EarliestSpellTime = (this->super_TCreature).EarliestSpellTime; - this->PlayerData->EarliestMultiuseTime = (this->super_TCreature).EarliestMultiuseTime; - this->PlayerData->TalkBufferFullTime = this->TalkBufferFullTime; - this->PlayerData->MutingEndRound = this->MutingEndRound; - this->PlayerData->NumberOfMutings = this->NumberOfMutings; - return; - } - error("TPlayer::SaveData: PlayerData ist NULL.\n"); - return; -} - - - -// DWARF original prototype: void LoadInventory(TPlayer * this, bool SetStandardInventory) - -void __thiscall TPlayer::LoadInventory(TPlayer *this,bool SetStandardInventory) - -{ - TPlayerData *pTVar1; - bool bVar2; - byte bVar3; - RESULT r; - int Position; - undefined1 local_5c [4]; - TReadBuffer Buffer; - Object Con; - Object local_3c [4]; - Object local_2c [7]; - - pTVar1 = this->PlayerData; - if (pTVar1 == (TPlayerData *)0x0) { - error("TPlayer::LoadInventory: PlayerData ist NULL.\n"); - } - else if (pTVar1->Inventory == (uchar *)0x0) { - if ((this->super_TCreature).Profession == '\0') { - bVar2 = CheckRight((this->super_TCreature).ID,ZERO_CAPACITY); - if ((!bVar2) && (SetStandardInventory)) { - // try { // try from 080abb37 to 080abca5 has its CatchHandler @ 080abd71 - GetSpecialObject((SPECIALMEANING)local_3c); - GetBodyContainer((ulong)&Buffer.Position,(this->super_TCreature).ID); - Create(local_2c,(ObjectType *)&Buffer.Position,(ulong)local_3c); - GetSpecialObject((SPECIALMEANING)local_3c); - GetBodyContainer((ulong)local_2c,(this->super_TCreature).ID); - Create((Object *)&Buffer.Position,(ObjectType *)local_2c,(ulong)local_3c); - GetSpecialObject((SPECIALMEANING)local_3c); - GetBodyContainer((ulong)local_2c,(this->super_TCreature).ID); - Create((Object *)&Buffer.Position,(ObjectType *)local_2c,(ulong)local_3c); - GetSpecialObject((SPECIALMEANING)local_3c); - GetBodyContainer((ulong)local_2c,(this->super_TCreature).ID); - Create((Object *)&Buffer.Position,(ObjectType *)local_2c,(ulong)local_3c); - GetSpecialObject((SPECIALMEANING)local_2c); - local_5c = (undefined1 [4])Buffer.Position; - Create(local_3c,(ObjectType *)local_5c,(ulong)local_2c); - } - } - } - else { - // try { // try from 080abcca to 080abd5a has its CatchHandler @ 080abdb0 - TReadBuffer::TReadBuffer((TReadBuffer *)local_5c,pTVar1->Inventory,pTVar1->InventorySize); - while( true ) { - bVar3 = TReadBuffer::readByte((TReadBuffer *)local_5c); - if (bVar3 == 0xff) break; - GetBodyContainer((ulong)&Buffer.Position,(this->super_TCreature).ID); - LoadObjects((TReadStream *)local_5c,(Object *)&Buffer.Position); - GetBodyObject((ulong)&Buffer.Position,(this->super_TCreature).ID); - local_3c[0] = (Object)::NONE.ObjectID; - local_2c[0].ObjectID = local_3c[0].ObjectID; - if (Buffer.Position != ::NONE.ObjectID) { - local_2c[0].ObjectID = Buffer.Position; - SendSetInventory((this->super_TCreature).Connection,(uint)bVar3,local_2c); - } - } - } - return; -} - - - -// DWARF original prototype: void SaveInventory(TPlayer * this) - -void __thiscall TPlayer::SaveInventory(TPlayer *this) - -{ - bool bVar1; - TPlayerData *pTVar2; - uchar *puVar3; - int con; - int iVar4; - TDynamicWriteBuffer *Position; - Object local_4c [4]; - undefined1 local_3c [4]; - TDynamicWriteBuffer HelpBuffer; - Object Obj; - - pTVar2 = this->PlayerData; - if (pTVar2 == (TPlayerData *)0x0) { - error("TPlayer::SaveInventory: PlayerData ist NULL.\n"); - } - else { - if (pTVar2->Inventory != (uchar *)0x0) { - operator_delete__(pTVar2->Inventory); - this->PlayerData->Inventory = (uchar *)0x0; - pTVar2 = this->PlayerData; - } - pTVar2->InventorySize = 0; - HelpBuffer.super_TWriteBuffer.Position = (this->super_TCreature).CrObject.ObjectID; - local_3c = (undefined1 [4])::NONE.ObjectID; - if (HelpBuffer.super_TWriteBuffer.Position != ::NONE.ObjectID) { - // try { // try from 080abe5b to 080abe5f has its CatchHandler @ 080abfb1 - TDynamicWriteBuffer::TDynamicWriteBuffer((TDynamicWriteBuffer *)local_3c,0x4000); - iVar4 = 1; - do { - Position = (TDynamicWriteBuffer *)(this->super_TCreature).ID; - // try { // try from 080abe79 to 080abecf has its CatchHandler @ 080abf72 - GetBodyObject((ulong)&HelpBuffer.super_TWriteBuffer.Position,(int)Position); - bVar1 = Object::exists((Object *)&HelpBuffer.super_TWriteBuffer.Position); - if (bVar1) { - // try { // try from 080abf14 to 080abf35 has its CatchHandler @ 080abf72 - TDynamicWriteBuffer::writeByte((TDynamicWriteBuffer *)local_3c,(uchar)iVar4); - local_4c[0].ObjectID = HelpBuffer.super_TWriteBuffer.Position; - Position = (TDynamicWriteBuffer *)local_3c; - SaveObjects(local_4c,(TWriteStream *)local_3c,false); - } - iVar4 = iVar4 + 1; - } while (iVar4 < 0xb); - if (HelpBuffer.super_TWriteBuffer.Size != 0) { - TDynamicWriteBuffer::writeByte((TDynamicWriteBuffer *)local_3c,0xff); - this->PlayerData->InventorySize = HelpBuffer.super_TWriteBuffer.Size; - pTVar2 = this->PlayerData; - puVar3 = (uchar *)operator_new__(pTVar2->InventorySize); - pTVar2->Inventory = puVar3; - memcpy(this->PlayerData->Inventory, - HelpBuffer.super_TWriteBuffer.super_TWriteStream._vptr_TWriteStream, - this->PlayerData->InventorySize); - Position = (TDynamicWriteBuffer *) - HelpBuffer.super_TWriteBuffer.super_TWriteStream._vptr_TWriteStream; - } - // try { // try from 080abefe to 080abf02 has its CatchHandler @ 080abfb1 - TDynamicWriteBuffer::~TDynamicWriteBuffer((TDynamicWriteBuffer *)local_3c,(int)Position) - ; - } - } - return; -} - - - -// DWARF original prototype: void StartCoordinates(TPlayer * this) - -void __thiscall TPlayer::StartCoordinates(TPlayer *this) - -{ - GetStartPosition(&(this->super_TCreature).startx,&(this->super_TCreature).starty, - &(this->super_TCreature).startz,true); - return; -} - - - -// DWARF original prototype: void TakeOver(TPlayer * this, TConnection * Connection) - -void __thiscall TPlayer::TakeOver(TPlayer *this,TConnection *Connection) - -{ - char *__dest; - Object OVar1; - bool bVar2; - TCreature *cr; - TPlayerData *pTVar3; - __pid_t _Var4; - char *__src; - TCreature *pTVar5; - TPlayer *pTVar6; - TCreature *pTVar7; - ulong extraout_EDX; - ulong id; - ulong extraout_EDX_00; - TPlayerData *PlayerData; - Object *pOVar8; - uint Window; - Object local_4c [4]; - ulong local_3c; - ulong local_2c; - - __dest = (this->super_TCreature).Name; - Log("game",&DAT_08103d40,__dest); - (this->super_TCreature).LoggingOut = false; - (this->super_TCreature).LogoutAllowed = false; - (this->super_TCreature).Connection = Connection; - TConnection::EnterGame(Connection); - pTVar3 = GetPlayerPoolSlot((this->super_TCreature).ID); - if (pTVar3 == (TPlayerData *)0x0) { - error("TPlayer::TakeOver: PlayerData-Slot nicht gefunden.\n"); - } - else { - _Var4 = getpid(); - if (pTVar3->Locked != _Var4) { - error("TPlayer::TakeOver: PlayerData-Slot ist nicht korrekt gesperrt (%d).\n", - pTVar3->Locked); - } - if (pTVar3->Sticky < 2) { - error("TPlayer::TakeOver: Falscher Sticky-Wert %d.\n",pTVar3->Sticky); - } - else { - Semaphore::down(&PlayerDataPoolMutex); - pTVar3->Sticky = pTVar3->Sticky + -1; - Semaphore::up(&PlayerDataPoolMutex); - } - strcpy(__dest,pTVar3->Name); - InsertPlayerIndex(&PlayerIndexHead,0,__dest,(this->super_TCreature).ID); - __src = TConnection::GetIPAddress(Connection); - strcpy(this->IPAddress,__src); - *(undefined4 *)this->Rights = *(undefined4 *)pTVar3->Rights; - *(undefined4 *)(this->Rights + 4) = *(undefined4 *)(pTVar3->Rights + 4); - *(undefined4 *)(this->Rights + 8) = *(undefined4 *)(pTVar3->Rights + 8); - (this->super_TCreature).Sex = pTVar3->Sex; - strcpy(this->Guild,pTVar3->Guild); - strcpy(this->Rank,pTVar3->Rank); - pOVar8 = this->OpenContainer; - strcpy(this->Title,pTVar3->Title); - CheckOutfit(this); - Window = 0; - do { - if (Window < 0x10) { - local_2c = pOVar8->ObjectID; - } - else { - error(&DAT_08103de0); - local_2c = ::NONE.ObjectID; - } - local_3c = ::NONE.ObjectID; - local_4c[0].ObjectID = ::NONE.ObjectID; - if (local_2c != ::NONE.ObjectID) { - SetOpenContainer(this,Window,local_4c); - SendCloseContainer((this->super_TCreature).Connection,Window); - } - Window = Window + 1; - pOVar8 = pOVar8 + 1; - } while ((int)Window < 0x10); - TCombat::StopAttack(&(this->super_TCreature).Combat,0); - LeaveAllChannels((this->super_TCreature).ID); - if (this->Request != 0) { - if (this->RequestProcessingGamemaster == 0) { - DeleteGamemasterRequest(__dest); - } - else { - pTVar5 = GetCreature(this->RequestProcessingGamemaster); - pTVar7 = (TCreature *)0x0; - if ((pTVar5 != (TCreature *)0x0) && (pTVar7 = pTVar5, pTVar5->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - pTVar7 = (TCreature *)0x0; - } - if (pTVar7 != (TCreature *)0x0) { - SendFinishRequest(pTVar7->Connection,__dest); - } - } - this->Request = 0; - } - this->RequestTimestamp = 0; - this->RequestProcessingGamemaster = 0; - local_4c[0] = ::NONE; - if ((this->TradeObject).ObjectID != ::NONE.ObjectID) { - local_3c = ::NONE.ObjectID; - (this->TradeObject).ObjectID = ::NONE.ObjectID; - pTVar6 = GetPlayer(this->TradePartner); - OVar1 = ::NONE; - if (pTVar6 != (TPlayer *)0x0) { - local_4c[0] = (Object)::NONE.ObjectID; - bVar2 = false; - if (((pTVar6->TradeObject).ObjectID != ::NONE.ObjectID) && - (pTVar6->TradePartner == (this->super_TCreature).ID)) { - bVar2 = true; - } - local_3c = local_4c[0].ObjectID; - if (bVar2) { - local_2c = ::NONE.ObjectID; - (pTVar6->TradeObject).ObjectID = ::NONE.ObjectID; - local_3c = OVar1.ObjectID; - SendCloseTrade((pTVar6->super_TCreature).Connection); - SendMessage((pTVar6->super_TCreature).Connection,0x17,"Trade cancelled."); - } - } - } - bVar2 = CheckRight((this->super_TCreature).ID,READ_GAMEMASTER_CHANNEL); - id = extraout_EDX; - if (bVar2) { - CloseProcessedRequests((this->super_TCreature).ID); - id = extraout_EDX_00; - } - SendInitGame((TConnection *)(this->super_TCreature).ID,id); - SendRights((this->super_TCreature).Connection); - SendFullScreen((this->super_TCreature).Connection); - SendBodyInventory((this->super_TCreature).Connection,(this->super_TCreature).ID); - SendAmbiente((this->super_TCreature).Connection); - SendPlayerData((this->super_TCreature).Connection); - SendPlayerSkills((this->super_TCreature).Connection); - this->OldState = 0; - CheckState(this); - SendBuddies(this); - } - return; -} - - - -// DWARF original prototype: void Death(TPlayer * this) - -void __thiscall TPlayer::Death(TPlayer *this) - -{ - TConnection *Connection; - TSkill *pTVar1; - bool bVar2; - int iVar3; - undefined4 uVar4; - TSkill *sk; - uint uVar5; - int Percent; - int iVar6; - - bVar2 = CheckRight((this->super_TCreature).ID,INVULNERABLE); - if (bVar2) { - error("TPlayer::Death: Aha, so geht das aber nicht!! Goetter kann man nicht toeten!!\n"); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[2]; - (*pTVar1->_vptr_TSkill[2])((this->super_TCreature).super_TSkillBase.Skills[2],pTVar1->Max); - } - else { - Connection = (this->super_TCreature).Connection; - if (Connection != (TConnection *)0x0) { - SendPlayerData(Connection); - SendMessage((this->super_TCreature).Connection,0x13,"You are dead.\n"); - TConnection::Die((this->super_TCreature).Connection); - } - TCreature::Death(&this->super_TCreature); - if (WorldType == PVP_ENFORCED) { - TCombat::DistributeExperiencePoints - (&(this->super_TCreature).Combat, - (this->super_TCreature).super_TSkillBase.Skills[0]->Exp / 0x14); - } - bVar2 = CheckRight((this->super_TCreature).ID,PREMIUM_ACCOUNT); - if (bVar2) { - bVar2 = 9 < (this->super_TCreature).Profession; - } - else { - bVar2 = false; - } - uVar5 = 0x65; - iVar6 = (uint)!bVar2 * 3 + 7; - do { - if (uVar5 < 500) { - print(); - iVar3 = this->QuestValues[uVar5]; - } - else { - error(&DAT_08103ea0); - iVar3 = 0; - } - if (iVar3 != 0) { - iVar6 = iVar6 + -1; - if (uVar5 < 500) { - print(); - this->QuestValues[uVar5] = 0; - } - else { - error(&DAT_08103ee0); - } - } - uVar5 = uVar5 + 1; - } while ((int)uVar5 < 0x6a); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[8]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[10]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[9]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[7]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[0xb]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[6]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[1]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[0xd]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[0]; - uVar4 = __divdi3((longlong)pTVar1->Exp * (longlong)iVar6,100,0); - (*pTVar1->_vptr_TSkill[4])(pTVar1,uVar4); - } - return; -} - - - -// DWARF original prototype: void AttackStimulus(TPlayer * this, ulong param_1) - -void __thiscall TPlayer::AttackStimulus(TPlayer *this,ulong param_1) - -{ - if ((this->super_TCreature).IsDead == false) { - TCreature::BlockLogout(&this->super_TCreature,0x3c,false); - } - return; -} - - - -// DWARF original prototype: void DamageStimulus(TPlayer * this, ulong param_1, int param_2, int -// param_3) - -void __thiscall TPlayer::DamageStimulus(TPlayer *this,ulong param_1,int param_2,int param_3) - -{ - if ((this->super_TCreature).IsDead != false) { - return; - } - TCreature::BlockLogout(&this->super_TCreature,0x3c,false); - return; -} - - - -// DWARF original prototype: void IdleStimulus(TPlayer * this) - -void __thiscall TPlayer::IdleStimulus(TPlayer *this) - -{ - RESULT r; - - if ((this->super_TCreature).Combat.AttackDest != 0) { - // try { // try from 080ac866 to 080ac872 has its CatchHandler @ 080ac875 - TCreature::ToDoAttack(&this->super_TCreature); - TCreature::ToDoStart(&this->super_TCreature); - } - return; -} - - - -// DWARF original prototype: void SetOpenContainer(TPlayer * this, int Window, Object * Con) - -void __thiscall TPlayer::SetOpenContainer(TPlayer *this,int Window,Object *Con) - -{ - bool bVar1; - bool bVar2; - char *Text; - Object local_3c [4]; - ulong local_2c; - - if (0xf < (uint)Window) { - Text = &DAT_08104040; - goto LAB_080ac947; - } - bVar1 = false; - local_2c = ::NONE.ObjectID; - local_3c[0].ObjectID = ::NONE.ObjectID; - if (Con->ObjectID != ::NONE.ObjectID) { - bVar2 = Object::exists(Con); - if (bVar2) { - Object::getObjectType(local_3c); - bVar2 = ObjectType::getFlag((ObjectType *)local_3c,CONTAINER); - if (bVar2) goto LAB_080ac914; - } - bVar1 = true; - } -LAB_080ac914: - if (!bVar1) { - this->OpenContainer[Window].ObjectID = Con->ObjectID; - return; - } - Text = "TPlayer::SetOpenContainer: Container existiert nicht.\n"; -LAB_080ac947: - error(Text); - return; -} - - - -// DWARF original prototype: Object GetOpenContainer(TPlayer * this, int Window) - -Object __thiscall TPlayer::GetOpenContainer(TPlayer *this,int Window) - -{ - Object OVar1; - uint in_stack_0000000c; - - if (in_stack_0000000c < 0x10) { - OVar1.ObjectID = (ulong)*(_func_int_varargs ***)(Window + 0xca0 + in_stack_0000000c * 4); - } - else { - error(&DAT_08103de0); - OVar1 = ::NONE; - } - (this->super_TCreature)._vptr_TCreature = (_func_int_varargs **)OVar1.ObjectID; - return (Object)(ulong)this; -} - - - -// DWARF original prototype: void CloseAllContainers(TPlayer * this) - -void __thiscall TPlayer::CloseAllContainers(TPlayer *this) - -{ - Object *pOVar1; - int i; - uint Window; - Object local_4c [4]; - ulong local_3c; - ulong local_2c; - - pOVar1 = this->OpenContainer; - Window = 0; - do { - if (Window < 0x10) { - local_2c = pOVar1->ObjectID; - } - else { - error(&DAT_08103de0); - local_2c = ::NONE.ObjectID; - } - local_3c = ::NONE.ObjectID; - local_4c[0].ObjectID = ::NONE.ObjectID; - if (local_2c != ::NONE.ObjectID) { - SetOpenContainer(this,Window,local_4c); - SendCloseContainer((this->super_TCreature).Connection,Window); - } - Window = Window + 1; - pOVar1 = pOVar1 + 1; - } while ((int)Window < 0x10); - return; -} - - - -// DWARF original prototype: Object InspectTrade(TPlayer * this, bool OwnOffer, int Position) - -Object __thiscall TPlayer::InspectTrade(TPlayer *this,bool OwnOffer,int Position) - -{ - TSkill *pTVar1; - bool bVar2; - TCreature *cr; - TCreature *pTVar3; - int iVar4; - TCreature *pTVar5; - undefined3 in_stack_00000009; - int in_stack_00000010; - Object local_4c [4]; - Object local_3c [4]; - TSkill *local_2c; - Object Obj; - - if (*(TSkill **)(_OwnOffer + 0x3b0) == (TSkill *)::NONE.ObjectID) { -LAB_080acaaf: - (this->super_TCreature)._vptr_TCreature = (_func_int_varargs **)::NONE.ObjectID; - return (Object)(ulong)this; - } - local_2c = (TSkill *)0x0; - pTVar1 = *(TSkill **)(_OwnOffer + 0x3b0); - if ((char)Position == '\0') { - if (*(ulong *)(_OwnOffer + 0x3b4) == 0) goto LAB_080acaaf; - pTVar3 = GetCreature(*(ulong *)(_OwnOffer + 0x3b4)); - pTVar5 = (TCreature *)0x0; - if ((pTVar3 != (TCreature *)0x0) && (pTVar5 = pTVar3, pTVar3->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - pTVar5 = (TCreature *)0x0; - } - local_2c = (TSkill *)::NONE.ObjectID; - if (pTVar5 == (TCreature *)0x0) goto LAB_080acb9b; - bVar2 = false; - pTVar1 = pTVar5[1].super_TSkillBase.TimerList[0xb]; - if ((pTVar1 == (TSkill *)::NONE.ObjectID) || - (pTVar5[1].super_TSkillBase.TimerList[0xc] != *(TSkill **)(_OwnOffer + 0x208))) { - bVar2 = true; - } - if (bVar2) goto LAB_080acaaf; - } - while( true ) { - local_2c = pTVar1; - bVar2 = false; - if ((local_2c != (TSkill *)::NONE.ObjectID) && (0 < in_stack_00000010)) { - bVar2 = true; - } - if (!bVar2) break; - local_4c[0].ObjectID = (ulong)local_2c; - local_3c[0].ObjectID = ::NONE.ObjectID; - iVar4 = CountObjects(local_4c); - if (in_stack_00000010 < iVar4) { - in_stack_00000010 = in_stack_00000010 + -1; - GetFirstContainerObject(local_3c); - } - else { - in_stack_00000010 = in_stack_00000010 - iVar4; - Object::getNextObject(local_3c); - } - pTVar1 = (TSkill *)local_3c[0].ObjectID; - } -LAB_080acb9b: - (this->super_TCreature)._vptr_TCreature = (_func_int_varargs **)local_2c; - return (Object)(ulong)this; -} - - - -// WARNING: Type propagation algorithm not settling -// DWARF original prototype: void AcceptTrade(TPlayer * this) - -void __thiscall TPlayer::AcceptTrade(TPlayer *this) - -{ - Object *Obj_00; - TPlayer *pTVar1; - TSkill *this_00; - bool bVar2; - bool bVar3; - TCreature *cr; - TCreature *pTVar4; - int iVar5; - int iVar6; - ulong uVar7; - int iVar8; - undefined4 *puVar9; - ulong uVar10; - RESULT r; - int NewWeight; - bool bVar11; - int Step; - bool local_bd; - bool invert; - int iStack_bc; - bool first; - int pos; - TSkill *sk; - int p; - TPlayer *Player [2]; - Object local_8c; - ObjectType Type0; - Object local_7c; - ObjectType Type1; - Object local_6c [4]; - Object local_5c; - Object Help; - Object local_4c [4]; - ulong local_3c; - Object Con [2]; - Object Obj [2]; - - if ((this->TradeObject).ObjectID != ::NONE.ObjectID) { - pTVar4 = GetCreature(this->TradePartner); - p = 0; - if ((pTVar4 != (TCreature *)0x0) && (p = (int)pTVar4, pTVar4->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - p = 0; - } - if (p != 0) { - bVar2 = false; - if ((*(ulong *)(p + 0x3b0) == ::NONE.ObjectID) || - (*(ulong *)(p + 0x3b4) != (this->super_TCreature).ID)) { - bVar2 = true; - } - if ((!bVar2) && (this->TradeAccepted = true, *(char *)(p + 0x3b8) != '\0')) { - pTVar1 = (TPlayer *)(this->TradeObject).ObjectID; - sk = (TSkill *)0x0; - Player[0] = (TPlayer *)p; - Obj[0].ObjectID = *(ulong *)(p + 0x3b0); - local_3c = ::NONE.ObjectID; - local_4c[0].ObjectID = ::NONE.ObjectID; - Con[0] = ::NONE; - local_5c.ObjectID = ::NONE.ObjectID; - do { - local_5c.ObjectID = Obj[(int)((int)&sk[-1].AddLevel + 3)].ObjectID; - // try { // try from 080acd0a to 080ace9d has its CatchHandler @ 080ad450 - bVar2 = ObjectAccessible((Player[(int)((int)&sk[-1].AddLevel + 3)]-> - super_TCreature).ID,&local_5c,1); - if (!bVar2) { - puVar9 = (undefined4 *)__cxa_allocate_exception(4); - *puVar9 = 1; - goto LAB_080acf89; - } - Object::getObjectType(&local_5c); - bVar2 = ObjectType::getFlag((ObjectType *)&local_5c,UNMOVE); - if (bVar2) { - puVar9 = (undefined4 *)__cxa_allocate_exception(4); - *puVar9 = 2; - goto LAB_080acf89; - } - Object::getObjectType(&local_5c); - bVar2 = ObjectType::getFlag((ObjectType *)&local_5c,TAKE); - if (!bVar2) { - puVar9 = (undefined4 *)__cxa_allocate_exception(4); - *puVar9 = 3; - goto LAB_080acf89; - } - iVar8 = -(int)sk; - bVar2 = CheckRight((Player[iVar8]->super_TCreature).ID,ZERO_CAPACITY); - if (bVar2) { -LAB_080ad379: - puVar9 = (undefined4 *)__cxa_allocate_exception(4); - *puVar9 = 8; -LAB_080acf89: - // WARNING: Subroutine does not return - // try { // try from 080acf9c to 080acfa0 has its CatchHandler @ 080ad450 - __cxa_throw(puVar9,&RESULT::typeinfo,0); - } - bVar2 = CheckRight((Player[iVar8]->super_TCreature).ID,UNLIMITED_CAPACITY); - if (!bVar2) { - this_00 = (Player[iVar8]->super_TCreature).super_TSkillBase.Skills[5]; - if (this_00 == (TSkill *)0x0) { - error("TPlayer::AcceptTrade: Skill CARRYSTRENGTH existiert nicht.\n"); - puVar9 = (undefined4 *)__cxa_allocate_exception(4); - *puVar9 = 0xffffffff; - goto LAB_080acf89; - } - iVar5 = GetInventoryWeight((Player[iVar8]->super_TCreature).ID); - local_5c.ObjectID = Obj[(int)((int)&sk[-1].AddLevel + 3)].ObjectID; - iVar6 = GetCompleteWeight(&local_5c); - iVar5 = iVar5 + iVar6; - local_5c.ObjectID = Obj[iVar8].ObjectID; - uVar7 = GetObjectCreatureID(&local_5c); - if (uVar7 == (Player[iVar8]->super_TCreature).ID) { - local_4c[0].ObjectID = Obj[iVar8].ObjectID; - // try { // try from 080ad3a1 to 080ad3b8 has its CatchHandler @ 080ad450 - iVar8 = GetCompleteWeight(local_4c); - iVar5 = iVar5 - iVar8; - } - iVar8 = TSkill::Get(this_00); - if (iVar8 * 100 < iVar5) goto LAB_080ad379; - } - local_bd = true; - iStack_bc = 0; - Object::getObjectType(&local_5c); - bVar2 = ObjectType::getFlag((ObjectType *)&local_5c,MOVEMENTEVENT); - while( true ) { - iStack_bc = iStack_bc + 1; - iVar8 = -(int)sk; - uVar7 = (Player[iVar8]->super_TCreature).ID; - iVar5 = iStack_bc; - // try { // try from 080acedf to 080acee3 has its CatchHandler @ 080ad430 - GetBodyObject((ulong)&local_5c,uVar7); - if ((local_bd != bVar2) && - (local_4c[0].ObjectID = ::NONE.ObjectID, - local_5c.ObjectID == ::NONE.ObjectID)) { - local_6c[0].ObjectID = Obj[iVar8].ObjectID; - GetBodyContainer((ulong)&local_7c,(Player[iVar8]->super_TCreature).ID); - Object::getObjectType(&local_8c); - CheckInventoryPlace((ObjectType *)&local_8c,&local_7c,local_6c); - uVar7 = (Player[iVar8]->super_TCreature).ID; - iVar5 = iStack_bc; - GetBodyContainer((ulong)&local_7c,uVar7); - local_8c.ObjectID = local_7c.ObjectID; - Con[iVar8].ObjectID = local_7c.ObjectID; - } - bVar11 = false; - if (local_bd == bVar2) { - local_8c = (Object)::NONE.ObjectID; - local_7c.ObjectID = ::NONE.ObjectID; - if (local_5c.ObjectID != ::NONE.ObjectID) { - Object::getObjectType(&local_7c); - uVar7 = 4; - bVar3 = ObjectType::getFlag((ObjectType *)&local_7c,CONTAINER); - if (bVar3) { - local_7c.ObjectID = Obj[-(int)sk].ObjectID; - local_6c[0].ObjectID = local_7c.ObjectID; - if (local_5c.ObjectID != local_7c.ObjectID) { - bVar11 = true; - } - } - } - } - if (bVar11) { - // try { // try from 080ad1d2 to 080ad365 has its CatchHandler @ 080ad430 - Object::getContainer(local_6c); - bVar11 = local_6c[0].ObjectID == local_5c.ObjectID; - local_4c[0].ObjectID = local_5c.ObjectID; - local_6c[0].ObjectID = local_5c.ObjectID; - iVar8 = CountObjectsInContainer(local_6c); - Object::getObjectType(local_4c); - uVar7 = 1; - uVar10 = ObjectType::getAttribute((ObjectType *)local_4c,CAPACITY); - if ((int)uVar10 <= (int)(iVar8 - (uint)bVar11)) { - puVar9 = (undefined4 *)__cxa_allocate_exception(4); - *puVar9 = 10; - // WARNING: Subroutine does not return - __cxa_throw(puVar9,&RESULT::typeinfo,0); - } - local_4c[0].ObjectID = local_5c.ObjectID; - Con[-(int)sk].ObjectID = local_5c.ObjectID; - local_6c[0].ObjectID = local_5c.ObjectID; - } - local_8c.ObjectID = ::NONE.ObjectID; - if (Con[-(int)sk].ObjectID != ::NONE.ObjectID) break; - if (9 < iStack_bc) { - if (local_bd == false) { - puVar9 = (undefined4 *)__cxa_allocate_exception(4,uVar7,iVar5); - *puVar9 = 4; - goto LAB_080acf89; - } - local_bd = false; - iStack_bc = 0; - } - } - sk = (TSkill *)((int)&sk->_vptr_TSkill + 1); - } while ((int)sk < 2); - (this->TradeObject).ObjectID = ::NONE.ObjectID; - local_8c = ::NONE; - local_7c.ObjectID = ::NONE.ObjectID; - *(ulong *)(p + 0x3b0) = ::NONE.ObjectID; - SendCloseTrade((this->super_TCreature).Connection); - SendCloseTrade(*(TConnection **)(p + 0x318)); - Object::getObjectType(&local_8c); - Object::getObjectType(&local_7c); - local_6c[0].ObjectID = ::NONE.ObjectID; - local_4c[0].ObjectID = (Player[0]->super_TCreature).CrObject.ObjectID; - // try { // try from 080ad052 to 080ad1a1 has its CatchHandler @ 080ad501 - GetMapContainer(&local_5c); - Obj_00 = (Object *)(Player + 1); - Player[1] = pTVar1; - Move(0,Obj_00,&local_5c,-1,true,local_6c); - Player[1] = (TPlayer *)::NONE.ObjectID; - local_5c.ObjectID = (this->super_TCreature).CrObject.ObjectID; - GetMapContainer(local_6c); - local_4c[0].ObjectID = Obj[0].ObjectID; - Move(0,local_4c,local_6c,-1,true,Obj_00); - Player[1] = (TPlayer *)::NONE.ObjectID; - local_6c[0].ObjectID = Con[0].ObjectID; - local_5c.ObjectID = (ulong)pTVar1; - Move(0,&local_5c,local_6c,-1,true,Obj_00); - Player[1] = (TPlayer *)::NONE.ObjectID; - local_6c[0].ObjectID = local_3c; - local_5c.ObjectID = Obj[0].ObjectID; - Move(0,&local_5c,local_6c,-1,true,Obj_00); - } - } - } - return; -} - - - -// DWARF original prototype: void RejectTrade(TPlayer * this) - -void __thiscall TPlayer::RejectTrade(TPlayer *this) - -{ - bool bVar1; - TCreature *cr; - TCreature *pTVar2; - TCreature *pTVar3; - - if ((this->TradeObject).ObjectID != ::NONE.ObjectID) { - (this->TradeObject).ObjectID = ::NONE.ObjectID; - pTVar2 = GetCreature(this->TradePartner); - pTVar3 = (TCreature *)0x0; - if ((pTVar2 != (TCreature *)0x0) && (pTVar3 = pTVar2, pTVar2->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - pTVar3 = (TCreature *)0x0; - } - if (pTVar3 != (TCreature *)0x0) { - bVar1 = false; - if ((pTVar3[1].super_TSkillBase.TimerList[0xb] != (TSkill *)::NONE.ObjectID) && - (pTVar3[1].super_TSkillBase.TimerList[0xc] == (TSkill *)(this->super_TCreature).ID)) - { - bVar1 = true; - } - if (bVar1) { - pTVar3[1].super_TSkillBase.TimerList[0xb] = (TSkill *)::NONE.ObjectID; - SendCloseTrade(pTVar3->Connection); - SendMessage(pTVar3->Connection,0x17,"Trade cancelled."); - } - } - } - return; -} - - - -// DWARF original prototype: void ClearProfession(TPlayer * this) - -void __thiscall TPlayer::ClearProfession(TPlayer *this) - -{ - if ((this->super_TCreature).Profession == '\0') { - return; - } - (this->super_TCreature).Profession = '\0'; - TCombat::CheckCombatValues(&(this->super_TCreature).Combat); - IncrementNewbiesOnline(); - return; -} - - - -// WARNING: Variable defined which should be unmapped: prof_local -// DWARF original prototype: void SetProfession(TPlayer * this, uchar prof) - -void __thiscall TPlayer::SetProfession(TPlayer *this,uchar prof) - -{ - byte bVar1; - int Rest; - TSkill *pTVar2; - int iVar3; - _func_int_varargs **pp_Var4; - undefined4 uVar5; - uchar prof_local; - - if (prof == '\n') { - bVar1 = (this->super_TCreature).Profession; - if (bVar1 == 0) { - this = (TPlayer *)&DAT_08104220; - } - else { - if (bVar1 < 10) { - (this->super_TCreature).Profession = bVar1 + 10; - TCombat::CheckCombatValues(&(this->super_TCreature).Combat); - (this->super_TCreature).super_TSkillBase.Skills[0x16]->Max = 200; - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[0x16]; - iVar3 = (*pTVar2->_vptr_TSkill[0xd])(pTVar2); - if (0xe < iVar3) { - TSkillBase::SetTimer(&(this->super_TCreature).super_TSkillBase); - } - return; - } - this = (TPlayer *)s_TPlayer__SetProfession__Spieler_h_081041c0; - } - error((char *)this); - return; - } - if ((this->super_TCreature).Profession != '\0') { - this = (TPlayer *)s_TPlayer__SetProfession__Player___08104180; - goto LAB_080ad750; - } - if (prof == '\x02') { - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[8]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x4b0,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[10]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x4b0,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[9]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x4b0,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[0xb]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x4b0,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[7]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x44c,0x1e); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[6]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x44c,100); - (this->super_TCreature).super_TSkillBase.Skills[2]->AddLevel = 10; - (this->super_TCreature).super_TSkillBase.Skills[5]->AddLevel = 0x14; - (this->super_TCreature).super_TSkillBase.Skills[3]->AddLevel = 0xf; - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[1]; - pp_Var4 = pTVar2->_vptr_TSkill; - uVar5 = 0x578; - goto LAB_080ad830; - } - if (prof < 3) { - if (prof == '\x01') { - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[8]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x44c,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[10]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x44c,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[9]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x44c,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[0xb]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x44c,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[7]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x578,0x1e); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[6]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x44c,100); - (this->super_TCreature).super_TSkillBase.Skills[2]->AddLevel = 0xf; - (this->super_TCreature).super_TSkillBase.Skills[5]->AddLevel = 0x19; - (this->super_TCreature).super_TSkillBase.Skills[3]->AddLevel = 5; - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[1]; - pp_Var4 = pTVar2->_vptr_TSkill; - uVar5 = 3000; - goto LAB_080ad830; - } -LAB_080ad742: - this = (TPlayer *)s_TPlayer__SetProfession__Beruf__d_08104140; -LAB_080ad750: - error((char *)this); - return; - } - if (prof == '\x03') { - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[8]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,2000,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[10]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,2000,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[9]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,2000,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[0xb]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x5dc,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[7]; - pp_Var4 = pTVar2->_vptr_TSkill; - uVar5 = 2000; - } - else { - if (prof != '\x04') goto LAB_080ad742; - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[8]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x708,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[10]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x708,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[9]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x708,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[0xb]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x5dc,0x32); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[7]; - pp_Var4 = pTVar2->_vptr_TSkill; - uVar5 = 0x708; - } - (*pp_Var4[7])(pTVar2,uVar5,0x1e); - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[6]; - (*pTVar2->_vptr_TSkill[7])(pTVar2,0x5dc,100); - (this->super_TCreature).super_TSkillBase.Skills[2]->AddLevel = 5; - (this->super_TCreature).super_TSkillBase.Skills[5]->AddLevel = 10; - (this->super_TCreature).super_TSkillBase.Skills[3]->AddLevel = 0x1e; - pTVar2 = (this->super_TCreature).super_TSkillBase.Skills[1]; - pp_Var4 = pTVar2->_vptr_TSkill; - uVar5 = 0x44c; -LAB_080ad830: - (*pp_Var4[7])(pTVar2,uVar5,0x640); - (this->super_TCreature).Profession = prof; - TCombat::CheckCombatValues(&(this->super_TCreature).Combat); - DecrementNewbiesOnline(); - return; -} - - -// DWARF original prototype: bool SpellKnown(TPlayer * this, int SpellNumber) - -bool __thiscall TPlayer::SpellKnown(TPlayer *this,int SpellNumber) - -{ - bool bVar1; - - if ((uint)SpellNumber < 0x100) { - bVar1 = this->SpellList[SpellNumber] != '\0'; - } - else { - error(&DAT_08104280,SpellNumber); - bVar1 = false; - } - return bVar1; -} - - - -// DWARF original prototype: void LearnSpell(TPlayer * this, int SpellNumber) - -void __thiscall TPlayer::LearnSpell(TPlayer *this,int SpellNumber) - -{ - if (0xff < (uint)SpellNumber) { - error(&DAT_08104300); - return; - } - if (this->SpellList[SpellNumber] == '\0') { - this->SpellList[SpellNumber] = '\x01'; - return; - } - error("TPlayer::LearnSpell: Der Spieler kennt den Spruch schon.\n"); - return; -} - - - -// DWARF original prototype: int GetQuestValue(TPlayer * this, int Number) - -int __thiscall TPlayer::GetQuestValue(TPlayer *this,int Number) - -{ - int iVar1; - - if ((uint)Number < 500) { - print(); - iVar1 = this->QuestValues[Number]; - } - else { - error(&DAT_08103ea0,Number); - iVar1 = 0; - } - return iVar1; -} - - - -// DWARF original prototype: void SetQuestValue(TPlayer * this, int Number, int Value) - -void __thiscall TPlayer::SetQuestValue(TPlayer *this,int Number,int Value) - -{ - if (499 < (uint)Number) { - error(&DAT_08103ee0); - return; - } - print(); - this->QuestValues[Number] = Value; - return; -} - - - -// DWARF original prototype: void CheckOutfit(TPlayer * this) - -void __thiscall TPlayer::CheckOutfit(TPlayer *this) - -{ - anon_union_4_2_730cd3ca_for_TOutfit_2 aVar1; - int iVar2; - bool bVar3; - - bVar3 = CheckRight((this->super_TCreature).ID,GAMEMASTER_OUTFIT); - if (bVar3) { - if ((this->super_TCreature).OrgOutfit.OutfitID == 0x4b) { - return; - } - (this->super_TCreature).OrgOutfit.field_1.Colors[0] = '\0'; - (this->super_TCreature).OrgOutfit.OutfitID = 0x4b; - (this->super_TCreature).OrgOutfit.field_1.Colors[1] = '\0'; - (this->super_TCreature).OrgOutfit.field_1.Colors[2] = '\0'; - (this->super_TCreature).OrgOutfit.field_1.Colors[3] = '\0'; - } - else { - if ((this->super_TCreature).Sex == 1) { - iVar2 = (this->super_TCreature).OrgOutfit.OutfitID; - bVar3 = false; - if ((0x7f < iVar2) && (iVar2 < 0x87)) { - bVar3 = true; - } - if (bVar3) { - return; - } - (this->super_TCreature).OrgOutfit.OutfitID = 0x80; - } - else { - iVar2 = (this->super_TCreature).OrgOutfit.OutfitID; - bVar3 = false; - if ((0x87 < iVar2) && (iVar2 < 0x8f)) { - bVar3 = true; - } - if (bVar3) { - return; - } - (this->super_TCreature).OrgOutfit.OutfitID = 0x88; - } - builtin_memcpy(&(this->super_TCreature).OrgOutfit.field_1,"NE:L",4); - } - aVar1 = (this->super_TCreature).OrgOutfit.field_1; - (this->super_TCreature).Outfit.OutfitID = (this->super_TCreature).OrgOutfit.OutfitID; - (this->super_TCreature).Outfit.field_1 = aVar1; - return; -} - -// WARNING: Variable defined which should be unmapped: Execute_local -// DWARF original prototype: bool MovePossible(TPlayer * this, int x, int y, int z, bool Execute, -// bool Jump) - -bool __thiscall TPlayer::MovePossible(TPlayer *this,int x,int y,int z,bool Execute,bool Jump) - -{ - bool bVar1; - bool bVar2; - ushort HouseID; - ushort HouseID_00; - undefined4 *puVar3; - int iVar4; - int iVar5; - bool Execute_local; - - if (Jump) { - bVar2 = JumpPossible(x,y,z,false); - } - else { - bVar2 = false; - // try { // try from 080adffe to 080ae18e has its CatchHandler @ 080ae196 - bVar1 = CoordinateFlag(); - if (bVar1) { - bVar2 = CoordinateFlag(); - bVar2 = !bVar2; - } - } - bVar1 = false; - if (bVar2 != false) { - if (Execute) { - if ((RoundNr < (this->super_TCreature).EarliestProtectionZoneRound) && - (bVar2 = IsProtectionZone(), bVar2)) { - iVar5 = (this->super_TCreature).posz; - iVar4 = (this->super_TCreature).posy; - bVar2 = IsProtectionZone(); - if (!bVar2) { - puVar3 = (undefined4 *)__cxa_allocate_exception(4,iVar4,iVar5); - *puVar3 = 0x30; - goto LAB_080ae0ab; - } - } - HouseID_00 = GetHouseID(x,y,z); - if (((HouseID_00 != 0) && (bVar2 = IsInvited(HouseID_00,this,0x7fffffff), !bVar2)) && - (bVar2 = CheckRight((this->super_TCreature).ID,ENTER_HOUSES), !bVar2)) { - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = 0x32; -LAB_080ae0ab: - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); - } - } - else { - bVar2 = CoordinateFlag(); - if (bVar2) { - return false; - } - } - bVar1 = true; - } - return bVar1; -} - - - -// DWARF original prototype: void AddBuddy(TPlayer * this, char * Name) - -void __thiscall TPlayer::AddBuddy(TPlayer *this,char *Name) - -{ - int *piVar1; - bool bVar2; - TPlayerIndexEntry *Entry; - TConnection *pTVar3; - int iVar4; - TPlayerIndexEntry *pTVar5; - ulong CharacterID_00; - ulong CharacterID_01; - ulong extraout_EDX; - ulong extraout_EDX_00; - ulong CharacterID; - char *pcVar6; - TPlayer *pTStack_40; - bool Online; - TPlayer *pl; - char RealName [30]; - - if (Name == (char *)0x0) { - pcVar6 = "TPlayer::AddBuddy: Name ist NULL.\n"; - } - else { - if (this->PlayerData != (TPlayerData *)0x0) { - if (((this->PlayerData->Buddies < 100) && - ((bVar2 = CheckRight((this->super_TCreature).ID,READ_GAMEMASTER_CHANNEL), bVar2 || - (this->PlayerData->Buddies < 100)))) && - ((bVar2 = CheckRight((this->super_TCreature).ID,PREMIUM_ACCOUNT), bVar2 || - (this->PlayerData->Buddies < 0x14)))) { - iVar4 = IdentifyPlayer(Name,true,true,&stack0xffffffc0); - if (iVar4 == 0) { - CharacterID_00 = (pTStack_40->super_TCreature).ID; - strcpy((char *)&pl,(pTStack_40->super_TCreature).Name); - bVar2 = true; - } - else { - if (Name == (char *)0x0) { - error("GetCharacterID: Name ist NULL.\n"); - CharacterID_00 = 0; - } - else { - pTVar5 = SearchPlayerIndex(Name); - CharacterID_00 = 0; - if (pTVar5 != (TPlayerIndexEntry *)0x0) { - CharacterID_00 = pTVar5->CharacterID; - } - } - if (CharacterID_00 == 0) { - SendResult((this->super_TCreature).Connection,PLAYERNOTEXISTING); - return; - } - if (Name == (char *)0x0) { - error("GetCharacterName: Name ist NULL.\n"); - pTVar5 = (TPlayerIndexEntry *)0x0; - } - else { - pTVar5 = SearchPlayerIndex(Name); - if (pTVar5 == (TPlayerIndexEntry *)0x0) { - error("GetCharacterName: Spieler existiert nicht.\n"); - pTVar5 = (TPlayerIndexEntry *)0x8107675; - } - } - strcpy((char *)&pl,pTVar5->Name); - bVar2 = false; - } - iVar4 = 0; - CharacterID_01 = this->PlayerData->Buddies; - if (0 < (int)CharacterID_01) { - do { - if (this->PlayerData->Buddy[iVar4] == CharacterID_00) { - pTVar3 = (this->super_TCreature).Connection; - pcVar6 = "This player is already in your list."; - goto LAB_080ae24e; - } - iVar4 = iVar4 + 1; - } while (iVar4 < (int)CharacterID_01); - } - if ((bVar2) && - (bVar2 = CheckRight(CharacterID_00,NO_STATISTICS), CharacterID_01 = extraout_EDX, - bVar2)) { - CheckRight((this->super_TCreature).ID,READ_GAMEMASTER_CHANNEL); - CharacterID_01 = extraout_EDX_00; - } - pTVar3 = (this->super_TCreature).Connection; - SendBuddyData(pTVar3,CharacterID_01,(char *)pTVar3,SUB41(CharacterID_00,0)); - AddBuddyOrder(&this->super_TCreature,CharacterID_00); - this->PlayerData->Buddy[this->PlayerData->Buddies] = CharacterID_00; - strcpy(this->PlayerData->BuddyName[this->PlayerData->Buddies],(char *)&pl); - piVar1 = &this->PlayerData->Buddies; - *piVar1 = *piVar1 + 1; - return; - } - pTVar3 = (this->super_TCreature).Connection; - pcVar6 = "You cannot add more buddies."; -LAB_080ae24e: - SendMessage(pTVar3,0x17,pcVar6); - return; - } - pcVar6 = "TPlayer::AddBuddy: PlayerData ist NULL.\n"; - } - error(pcVar6); - return; -} - - - -// DWARF original prototype: void RemoveBuddy(TPlayer * this, ulong CharacterID) - -void __thiscall TPlayer::RemoveBuddy(TPlayer *this,ulong CharacterID) - -{ - int *piVar1; - TPlayerData *pTVar2; - int i; - int iVar3; - int Position; - int iVar4; - - pTVar2 = this->PlayerData; - if (pTVar2 == (TPlayerData *)0x0) { - error("TPlayer::RemoveBuddy: PlayerData ist NULL.\n"); - return; - } - iVar3 = 0; - iVar4 = -1; - if (0 < pTVar2->Buddies) { - do { - iVar4 = iVar3; - if (pTVar2->Buddy[iVar3] == CharacterID) break; - iVar3 = iVar3 + 1; - iVar4 = -1; - } while (iVar3 < pTVar2->Buddies); - } - if (iVar4 == -1) { - return; - } - pTVar2->Buddy[iVar4] = pTVar2->Buddy[pTVar2->Buddies + -1]; - pTVar2 = this->PlayerData; - strcpy(pTVar2->BuddyName[iVar4],pTVar2->BuddyName[pTVar2->Buddies + -1]); - piVar1 = &this->PlayerData->Buddies; - *piVar1 = *piVar1 + -1; - RemoveBuddyOrder(&this->super_TCreature,CharacterID); - return; -} - - - -// WARNING: Variable defined which should be unmapped: ViewAll -// DWARF original prototype: void SendBuddies(TPlayer * this) - -void __thiscall TPlayer::SendBuddies(TPlayer *this) - -{ - bool bVar1; - TCreature *cr; - TPlayerData *pTVar2; - TCreature *pTVar3; - TConnection *Connection; - TPlayerData *extraout_EDX; - TPlayerData *extraout_EDX_00; - TPlayerData *extraout_EDX_01; - int i; - int iVar4; - TConnection *Name; - TCreature *local_18; - bool ViewAll; - - if (this->PlayerData != (TPlayerData *)0x0) { - bVar1 = CheckRight((this->super_TCreature).ID,READ_GAMEMASTER_CHANNEL); - pTVar2 = this->PlayerData; - if (0 < pTVar2->Buddies) { - iVar4 = 0; - do { - pTVar3 = GetCreature(pTVar2->Buddy[iVar4]); - local_18 = (TCreature *)0x0; - pTVar2 = extraout_EDX; - if ((pTVar3 != (TCreature *)0x0) && (local_18 = pTVar3, pTVar3->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - local_18 = (TCreature *)0x0; - pTVar2 = extraout_EDX_01; - } - if (local_18 == (TCreature *)0x0) { - Name = (this->super_TCreature).Connection; - pTVar2 = this->PlayerData; - Connection = (TConnection *)pTVar2->Buddy[iVar4]; - } - else { - if (!bVar1) { - CheckRight(local_18->ID,NO_STATISTICS); - pTVar2 = extraout_EDX_00; - } - Name = (this->super_TCreature).Connection; - Connection = (TConnection *)this->PlayerData->Buddy[iVar4]; - } - SendBuddyData(Connection,(ulong)pTVar2,(char *)Name,SUB41(Connection,0)); - iVar4 = iVar4 + 1; - pTVar2 = this->PlayerData; - } while (iVar4 < pTVar2->Buddies); - } - return; - } - error("TPlayer::SendBuddies: PlayerData ist NULL.\n"); - return; -} - - - -// DWARF original prototype: void Regenerate(TPlayer * this) - -void __thiscall TPlayer::Regenerate(TPlayer *this) - -{ - TSkill *pTVar1; - bool bVar2; - RESULT r; - ulong uVar3; - int iVar4; - int iVar5; - time_t tVar6; - int Fed; - int Regeneration; - int iVar7; - time_t OfflineTime; - char *pcVar8; - Object *pOVar9; - Object local_4c [4]; - Object local_3c [4]; - Object local_2c; - Object Bed; - - iVar4 = (this->super_TCreature).posz; - iVar7 = (this->super_TCreature).posy; - pOVar9 = (Object *)(this->super_TCreature).posx; - GetFirstObject(); - local_3c[0].ObjectID = ::NONE.ObjectID; - if (local_2c.ObjectID != ::NONE.ObjectID) { - do { - local_4c[0].ObjectID = ::NONE.ObjectID; - local_3c[0].ObjectID = ::NONE.ObjectID; - Object::getObjectType(local_4c); - pOVar9 = (Object *)0x14; - bVar2 = ObjectType::getFlag((ObjectType *)local_4c,BED); - if (bVar2) break; - pOVar9 = &local_2c; - Object::getNextObject(local_3c); - local_2c.ObjectID = local_3c[0].ObjectID; - local_3c[0].ObjectID = ::NONE.ObjectID; - } while (local_2c.ObjectID != ::NONE.ObjectID); - } - local_4c[0].ObjectID = ::NONE.ObjectID; - if (local_2c.ObjectID == ::NONE.ObjectID) { - pcVar8 = "TPlayer::Regenerate: Bett nicht gefunden.\n"; - } - else { - Object::getObjectType(local_4c); - pOVar9 = (Object *)0x18; - bVar2 = ObjectType::getFlag((ObjectType *)local_4c,TEXT); - if (bVar2) { - uVar3 = Object::getAttribute(&local_2c,TEXTSTRING); - if (uVar3 == 0) { - return; - } - uVar3 = Object::getAttribute(&local_2c,TEXTSTRING); - pcVar8 = GetDynamicString(uVar3); - iVar4 = stricmp(pcVar8,(this->super_TCreature).Name,-1); - if (iVar4 != 0) { - return; - } - if ((this->PlayerData == (TPlayerData *)0x0) || (this->PlayerData->LastLogoutTime == 0)) - { - iVar4 = 0; - } - else { - tVar6 = time((time_t *)0x0); - iVar4 = tVar6 - this->PlayerData->LastLogoutTime; - } - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[0xe]; - iVar5 = (*pTVar1->_vptr_TSkill[0xd])(pTVar1); - iVar7 = iVar4 / 0xf; - if (iVar5 / 3 < iVar4 / 0xf) { - iVar7 = iVar5 / 3; - } - if (0 < iVar7) { - iVar5 = iVar7 + 3; - if (-1 < iVar7) { - iVar5 = iVar7; - } - TSkill::Change((this->super_TCreature).super_TSkillBase.Skills[2],iVar5 >> 2); - TSkill::Change((this->super_TCreature).super_TSkillBase.Skills[3],iVar7); - pTVar1 = (this->super_TCreature).super_TSkillBase.Skills[0xe]; - (*pTVar1->_vptr_TSkill[0xd])(pTVar1); - TSkillBase::SetTimer(&(this->super_TCreature).super_TSkillBase); - } - if (899 < iVar4) { - TSkill::Change((this->super_TCreature).super_TSkillBase.Skills[0x16],iVar4 / 900); - } - local_4c[0].ObjectID = local_2c.ObjectID; - local_3c[0].ObjectID = local_2c.ObjectID; - // try { // try from 080ae8eb to 080ae8ef has its CatchHandler @ 080ae94d - UseObjects(0,local_3c,local_4c); - return; - } - pcVar8 = &DAT_081044c0; - } - error(pcVar8,pOVar9,iVar7,iVar4); - return; -} - - - -// WARNING: Variable defined which should be unmapped: CheckFormer_local -// DWARF original prototype: bool IsAttacker(TPlayer * this, ulong Victim, bool CheckFormer) - -bool __thiscall TPlayer::IsAttacker(TPlayer *this,ulong Victim,bool CheckFormer) - -{ - ulong *puVar1; - int i; - int iVar2; - bool CheckFormer_local; - - iVar2 = 0; - if (0 < this->NumberOfAttackedPlayers) { - do { - puVar1 = vector<>::operator()(&this->AttackedPlayers,iVar2); - if (*puVar1 == Victim) { - return true; - } - iVar2 = iVar2 + 1; - } while (iVar2 < this->NumberOfAttackedPlayers); - } - if (((CheckFormer) && (RoundNr <= this->FormerLogoutRound + 5)) && - (iVar2 = 0, 0 < this->NumberOfFormerAttackedPlayers)) { - do { - puVar1 = vector<>::operator()(&this->FormerAttackedPlayers,iVar2); - if (*puVar1 == Victim) { - return true; - } - iVar2 = iVar2 + 1; - } while (iVar2 < this->NumberOfFormerAttackedPlayers); - } - return false; -} - - - -// DWARF original prototype: bool IsAggressor(TPlayer * this, bool CheckFormer) - -bool __thiscall TPlayer::IsAggressor(TPlayer *this,bool CheckFormer) - -{ - bool bVar1; - - if ((this->Aggressor != false) || - (((CheckFormer && (RoundNr <= this->FormerLogoutRound + 5)) && - (this->FormerAggressor != false)))) { - bVar1 = true; - } - else { - bVar1 = false; - } - return bVar1; -} - - - -// DWARF original prototype: bool IsAttackJustified(TPlayer * this, ulong Victim) - -bool __thiscall TPlayer::IsAttackJustified(TPlayer *this,ulong Victim) - -{ - bool bVar1; - TPlayer *pTVar2; - TPlayer *this_00; - ulong uVar3; - ulong uVar4; - - pTVar2 = (TPlayer *)GetCreature(Victim); - this_00 = (TPlayer *)0x0; - if ((pTVar2 != (TPlayer *)0x0) && (this_00 = pTVar2, (pTVar2->super_TCreature).Type != PLAYER)) - { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - this_00 = (TPlayer *)0x0; - } - if (this_00 == (TPlayer *)0x0) { - error("TPlayer::IsAttackJustified: Opfer existiert nicht.\n"); - } - else if ((WorldType != PVP_ENFORCED) && (this_00->PlayerData->PlayerkillerEnd == 0)) { - if ((this_00->Aggressor == false) && - ((this_00->FormerLogoutRound + 5 < RoundNr || (this_00->FormerAggressor == false)))) { - bVar1 = false; - } - else { - bVar1 = true; - } - if (!bVar1) { - uVar4 = this->PartyLeavingRound; - if ((uVar4 == 0) || (RoundNr <= uVar4 + 5)) { - uVar3 = this->PartyLeader; - } - else { - uVar3 = 0; - } - if (uVar3 != 0) { - if ((uVar4 == 0) || (RoundNr <= uVar4 + 5)) { - uVar4 = this->PartyLeader; - } - else { - uVar4 = 0; - } - if ((this_00->PartyLeavingRound == 0) || (RoundNr <= this_00->PartyLeavingRound + 5) - ) { - uVar3 = this_00->PartyLeader; - } - else { - uVar3 = 0; - } - if (uVar4 == uVar3) { - return true; - } - } - bVar1 = IsAttacker(this_00,(this->super_TCreature).ID,true); - return bVar1; - } - } - return true; -} - - - -// DWARF original prototype: void RecordAttack(TPlayer * this, ulong Victim) - -void __thiscall TPlayer::RecordAttack(TPlayer *this,ulong Victim) - -{ - TConnection *this_00; - bool bVar1; - TCreature *cr; - TPlayer *pTVar2; - ulong *puVar3; - KNOWNCREATURESTATE KVar4; - ulong uVar5; - ulong uVar6; - TPlayer *this_01; - - if (WorldType != NORMAL) { - return; - } - if (Victim == (this->super_TCreature).ID) { - return; - } - pTVar2 = (TPlayer *)GetCreature(Victim); - this_01 = (TPlayer *)0x0; - if ((pTVar2 != (TPlayer *)0x0) && (this_01 = pTVar2, (pTVar2->super_TCreature).Type != PLAYER)) - { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - this_01 = (TPlayer *)0x0; - } - if (this_01 == (TPlayer *)0x0) { - error("TPlayer::RecordAttack: Opfer existiert nicht.\n"); - return; - } - bVar1 = IsAttacker(this_01,(this->super_TCreature).ID,true); - if ((!bVar1) && (bVar1 = IsAttacker(this,Victim,false), !bVar1)) { - uVar6 = this->PartyLeavingRound; - if ((uVar6 == 0) || (RoundNr <= uVar6 + 5)) { - uVar5 = this->PartyLeader; - } - else { - uVar5 = 0; - } - if (uVar5 != 0) { - if ((uVar6 == 0) || (RoundNr <= uVar6 + 5)) { - uVar6 = this->PartyLeader; - } - else { - uVar6 = 0; - } - if ((this_01->PartyLeavingRound == 0) || (RoundNr <= this_01->PartyLeavingRound + 5)) { - uVar5 = this_01->PartyLeader; - } - else { - uVar5 = 0; - } - if (uVar6 == uVar5) goto LAB_080aec5e; - } - puVar3 = vector<>::operator()(&this->AttackedPlayers,this->NumberOfAttackedPlayers); - *puVar3 = Victim; - this->NumberOfAttackedPlayers = this->NumberOfAttackedPlayers + 1; - print(); - this_00 = (this_01->super_TCreature).Connection; - if ((this_00 != (TConnection *)0x0) && - (KVar4 = TConnection::KnownCreature(this_00,(this->super_TCreature).ID,false), - KVar4 == KNOWNCREATURE_UPTODATE)) { - SendCreatureSkull((this_01->super_TCreature).Connection,(this->super_TCreature).ID); - } - } -LAB_080aec5e: - bVar1 = IsAttackJustified(this,Victim); - if ((!bVar1) && (this->Aggressor == false)) { - this->Aggressor = true; - print(); - AnnounceChangedCreature((this->super_TCreature).ID,5); - return; - } - return; -} - - - -// DWARF original prototype: void RecordMurder(TPlayer * this, ulong Victim) - -void __thiscall TPlayer::RecordMurder(TPlayer *this,ulong Victim) - -{ - TPlayerData *pTVar1; - int iVar2; - bool bVar3; - TCreature *cr; - TCreature *pTVar4; - time_t tVar5; - int i; - int iVar6; - TCreature *pTVar7; - int Playerkilling; - - if (((WorldType == NORMAL) && (Victim != (this->super_TCreature).ID)) && - (bVar3 = IsAttackJustified(this,Victim), !bVar3)) { - pTVar4 = GetCreature(Victim); - pTVar7 = (TCreature *)0x0; - if ((pTVar4 != (TCreature *)0x0) && (pTVar7 = pTVar4, pTVar4->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - pTVar7 = (TCreature *)0x0; - } - if (pTVar7 == (TCreature *)0x0) { - error("TPlayer::RecordMurder: Opfer existiert nicht.\n"); - return; - } - print(); - iVar6 = 1; - do { - this->PlayerData->MurderTimestamps[iVar6 + -1] = - this->PlayerData->MurderTimestamps[iVar6]; - iVar6 = iVar6 + 1; - } while (iVar6 < 0x14); - pTVar1 = this->PlayerData; - tVar5 = time((time_t *)0x0); - pTVar1->MurderTimestamps[0x13] = tVar5; - SendMessage((this->super_TCreature).Connection,0x12, - "Warning! The murder of %s was not justified.",pTVar7->Name); - iVar6 = CheckPlayerkilling(this); - if (iVar6 != 0) { - pTVar1 = this->PlayerData; - iVar2 = pTVar1->PlayerkillerEnd; - tVar5 = time((time_t *)0x0); - pTVar1->PlayerkillerEnd = tVar5 + 0x278d00; - if (iVar2 == 0) { - print(); - AnnounceChangedCreature((this->super_TCreature).ID,5); - } - if (iVar6 == 2) { - PunishmentOrder((TCreature *)0x0,(this->super_TCreature).Name,this->IPAddress,0x1c,2 - ,"Exceeding the limit of unjustified kills by 100%.",0, - (vector<> *)0x0,0,false); - } - } - } - return; -} - - - -// WARNING: Variable defined which should be unmapped: LastMonth -// DWARF original prototype: int CheckPlayerkilling(TPlayer * this) - -int __thiscall TPlayer::CheckPlayerkilling(TPlayer *this) - -{ - int iVar1; - int iVar2; - int Now; - time_t tVar3; - int i; - int iVar4; - int LastDay; - int iVar5; - int LastWeek; - int iVar6; - int local_14; - int LastMonth; - - local_14 = 0; - tVar3 = time((time_t *)0x0); - iVar4 = 0; - iVar5 = 0; - iVar6 = 0; - do { - iVar1 = this->PlayerData->MurderTimestamps[iVar4]; - iVar2 = local_14; - if (iVar1 != 0) { - if (tVar3 + -0x15180 < iVar1) { - iVar5 = iVar5 + 1; - } - if (tVar3 + -0x93a80 < iVar1) { - iVar6 = iVar6 + 1; - } - iVar2 = local_14 + 1; - if (iVar1 <= tVar3 + -0x278d00) { - iVar2 = local_14; - } - } - local_14 = iVar2; - iVar4 = iVar4 + 1; - } while (iVar4 < 0x14); - if (((iVar5 < 6) && (iVar6 < 10)) && (local_14 < 0x14)) { - if (((2 < iVar5) || (4 < iVar6)) || (iVar5 = 0, 9 < local_14)) { - iVar5 = 1; - } - } - else { - iVar5 = 2; - } - return iVar5; -} - - - -// WARNING: Variable defined which should be unmapped: Victim_local -// DWARF original prototype: void ClearAttacker(TPlayer * this, ulong Victim) - -void __thiscall TPlayer::ClearAttacker(TPlayer *this,ulong Victim) - -{ - vector<> *this_00; - TCreature *cr; - ulong *puVar1; - ulong *puVar2; - TCreature *pTVar3; - KNOWNCREATURESTATE KVar4; - int i; - int i_00; - TCreature *pTVar5; - ulong Victim_local; - - i_00 = 0; - if (0 < this->NumberOfAttackedPlayers) { - this_00 = &this->AttackedPlayers; - do { - puVar1 = vector<>::operator()(this_00,i_00); - if (*puVar1 == Victim) { - puVar1 = vector<>::operator()(this_00,i_00); - puVar2 = vector<>::operator()(this_00,this->NumberOfAttackedPlayers + -1); - *puVar1 = *puVar2; - this->NumberOfAttackedPlayers = this->NumberOfAttackedPlayers + -1; - pTVar3 = GetCreature(Victim); - pTVar5 = (TCreature *)0x0; - if ((pTVar3 != (TCreature *)0x0) && (pTVar5 = pTVar3, pTVar3->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - pTVar5 = (TCreature *)0x0; - } - if (pTVar5 == (TCreature *)0x0) { - return; - } - print(); - if (pTVar5->Connection == (TConnection *)0x0) { - return; - } - KVar4 = TConnection::KnownCreature - (pTVar5->Connection,(this->super_TCreature).ID,false); - if (KVar4 != KNOWNCREATURE_UPTODATE) { - return; - } - SendCreatureSkull(pTVar5->Connection,(this->super_TCreature).ID); - return; - } - i_00 = i_00 + 1; - } while (i_00 < this->NumberOfAttackedPlayers); - } - return; -} - - - -// DWARF original prototype: void ClearPlayerkillingMarks(TPlayer * this) - -void __thiscall TPlayer::ClearPlayerkillingMarks(TPlayer *this) - -{ - char cVar1; - TCreature *cr; - ulong *puVar2; - ulong *puVar3; - TCreature *pTVar4; - KNOWNCREATURESTATE KVar5; - TPlayer **ppTVar6; - TPlayer *pl; - int i_2; - int iVar7; - int i; - int iVar8; - int iVar9; - TCreature *pTVar10; - - print(); - iVar7 = this->NumberOfAttackedPlayers; - this->FormerLogoutRound = RoundNr; - cVar1 = this->Aggressor; - this->NumberOfFormerAttackedPlayers = iVar7; - this->FormerAggressor = (bool)cVar1; - if (0 < iVar7) { - iVar9 = 0; - do { - puVar2 = vector<>::operator()(&this->FormerAttackedPlayers,iVar9); - iVar8 = iVar9 + 1; - puVar3 = vector<>::operator()(&this->AttackedPlayers,iVar9); - *puVar2 = *puVar3; - iVar7 = this->NumberOfAttackedPlayers; - iVar9 = iVar8; - } while (iVar8 < iVar7); - cVar1 = this->Aggressor; - } - if (cVar1 != '\0') { - this->Aggressor = false; - this->NumberOfAttackedPlayers = 0; - print(); - AnnounceChangedCreature((this->super_TCreature).ID,5); - iVar7 = this->NumberOfAttackedPlayers; - } - if ((0 < iVar7) && (this->NumberOfAttackedPlayers = 0, 0 < iVar7)) { - iVar9 = 0; - do { - puVar2 = vector<>::operator()(&this->AttackedPlayers,iVar9); - pTVar4 = GetCreature(*puVar2); - pTVar10 = (TCreature *)0x0; - if ((pTVar4 != (TCreature *)0x0) && (pTVar10 = pTVar4, pTVar4->Type != PLAYER)) { - error("GetPlayer: Kreatur ist kein Spieler.\n"); - pTVar10 = (TCreature *)0x0; - } - if (pTVar10 != (TCreature *)0x0) { - print(); - if ((pTVar10->Connection != (TConnection *)0x0) && - (KVar5 = TConnection::KnownCreature - (pTVar10->Connection,(this->super_TCreature).ID,false), - KVar5 == KNOWNCREATURE_UPTODATE)) { - SendCreatureSkull(pTVar10->Connection,(this->super_TCreature).ID); - } - } - iVar9 = iVar9 + 1; - } while (iVar9 < iVar7); - } - iVar7 = 0; - if (0 < FirstFreePlayer) { - do { - ppTVar6 = vector::operator()(&PlayerList,iVar7); - if (*ppTVar6 == (TPlayer *)0x0) { - error("TPlayer::ClearPlayerkillingMarks: Spieler %d existiert nicht.\n",iVar7); - } - else { - ClearAttacker(*ppTVar6,(this->super_TCreature).ID); - } - iVar7 = iVar7 + 1; - } while (iVar7 < FirstFreePlayer); - } - return; -} - - - -// DWARF original prototype: int GetPlayerkillingMark(TPlayer * this, TPlayer * Observer) - -int __thiscall TPlayer::GetPlayerkillingMark(TPlayer *this,TPlayer *Observer) - -{ - bool bVar1; - ulong uVar2; - ulong uVar3; - - if (WorldType == NORMAL) { - if (Observer != (TPlayer *)0x0) { - if (this->PlayerData->PlayerkillerEnd != 0) { - return 4; - } - if (this->Aggressor != false) { - return 3; - } - uVar2 = 0; - if (this->PartyLeavingRound == 0) { - uVar2 = this->PartyLeader; - } - if (uVar2 != 0) { - uVar2 = 0; - if (this->PartyLeavingRound == 0) { - uVar2 = this->PartyLeader; - } - if (Observer->PartyLeavingRound == 0) { - uVar3 = Observer->PartyLeader; - } - else { - uVar3 = 0; - } - if (uVar2 == uVar3) { - return 2; - } - } - bVar1 = IsAttacker(this,(Observer->super_TCreature).ID,false); - return (uint)bVar1; - } - error("TPlayer::GetPlayerkillingMark: Beobachter existiert nicht.\n"); - } - return 0; -} - - - -// DWARF original prototype: ulong GetPartyLeader(TPlayer * this, bool CheckFormer) - -ulong __thiscall TPlayer::GetPartyLeader(TPlayer *this,bool CheckFormer) - -{ - if (this->PartyLeavingRound != 0) { - if (!CheckFormer) { - return 0; - } - if (this->PartyLeavingRound + 5 < RoundNr) { - return 0; - } - } - return this->PartyLeader; -} - - - -// DWARF original prototype: void JoinParty(TPlayer * this, ulong Leader) - -void __thiscall TPlayer::JoinParty(TPlayer *this,ulong Leader) - -{ - this->PartyLeavingRound = 0; - this->PartyLeader = Leader; - return; -} - - - -// DWARF original prototype: void LeaveParty(TPlayer * this) - -void __thiscall TPlayer::LeaveParty(TPlayer *this) - -{ - this->PartyLeavingRound = RoundNr; - return; -} - - - -// DWARF original prototype: int GetPartyMark(TPlayer * this, TPlayer * Observer) - -int __thiscall TPlayer::GetPartyMark(TPlayer *this,TPlayer *Observer) - -{ - bool bVar1; - ulong uVar2; - ulong uVar3; - ulong uVar4; - ulong Guest; - ulong local_18; - - if (Observer == (TPlayer *)0x0) { - error("TPlayer::GetPartyMark: Beobachter existiert nicht.\n"); - } - else { - uVar2 = Observer->PartyLeavingRound; - uVar3 = 0; - if (uVar2 == 0) { - uVar3 = Observer->PartyLeader; - } - Guest = (this->super_TCreature).ID; - if (Guest == uVar3) { - return 4; - } - uVar4 = 0; - uVar3 = this->PartyLeavingRound; - if (uVar3 == 0) { - uVar4 = this->PartyLeader; - } - if (uVar4 != 0) { - local_18 = 0; - if (uVar3 == 0) { - local_18 = this->PartyLeader; - } - uVar4 = 0; - if (uVar2 == 0) { - uVar4 = Observer->PartyLeader; - } - if (local_18 == uVar4) { - return 3; - } - } - uVar4 = 0; - if (uVar2 == 0) { - uVar4 = Observer->PartyLeader; - } - uVar2 = (Observer->super_TCreature).ID; - if (uVar2 == uVar4) { - bVar1 = IsInvitedToParty(Guest,uVar2); - if (bVar1) { - return 2; - } - Guest = (this->super_TCreature).ID; - uVar3 = this->PartyLeavingRound; - } - uVar2 = 0; - if (uVar3 == 0) { - uVar2 = this->PartyLeader; - } - if ((Guest == uVar2) && - (bVar1 = IsInvitedToParty((Observer->super_TCreature).ID,Guest), bVar1)) { - return 1; - } - } - return 0; -} - - - -// DWARF original prototype: int RecordTalk(TPlayer * this) - -int __thiscall TPlayer::RecordTalk(TPlayer *this) - -{ - uint uVar1; - uint uVar2; - ulong uVar3; - int iVar4; - - uVar3 = RoundNr; - uVar1 = this->TalkBufferFullTime; - uVar2 = ServerMilliseconds; - if ((ServerMilliseconds < uVar1) && (uVar2 = uVar1, ServerMilliseconds < uVar1 - 0x1d4c)) { - iVar4 = this->NumberOfMutings + 1; - this->NumberOfMutings = iVar4; - iVar4 = iVar4 * iVar4 * 5; - this->MutingEndRound = uVar3 + iVar4; - } - else { - this->TalkBufferFullTime = uVar2 + 0x9c4; - iVar4 = 0; - } - return iVar4; -} - - - -// DWARF original prototype: int RecordMessage(TPlayer * this, ulong Addressee) - -int __thiscall TPlayer::RecordMessage(TPlayer *this,ulong Addressee) - -{ - ulong uVar1; - int i; - int iVar2; - int FreeSlot; - int iVar3; - - uVar1 = RoundNr; - iVar2 = 0; - iVar3 = -1; - do { - if (this->Addressees[iVar2] == Addressee) { - this->AddresseesTimes[iVar2] = RoundNr; - goto LAB_080af797; - } - if ((this->Addressees[iVar2] == 0) || (this->AddresseesTimes[iVar2] < RoundNr - 600)) { - iVar3 = iVar2; - } - iVar2 = iVar2 + 1; - } while (iVar2 < 0x14); - if (iVar3 < 0) { - iVar3 = this->NumberOfMutings + 1; - this->NumberOfMutings = iVar3; - iVar3 = iVar3 * iVar3 * 5; - this->MutingEndRound = uVar1 + iVar3; - } - else { - this->Addressees[iVar3] = Addressee; - this->AddresseesTimes[iVar3] = RoundNr; -LAB_080af797: - iVar3 = 0; - } - return iVar3; -} - - - -// DWARF original prototype: int CheckForMuting(TPlayer * this) - -int __thiscall TPlayer::CheckForMuting(TPlayer *this) - -{ - int iVar1; - - iVar1 = 0; - if (RoundNr < this->MutingEndRound) { - iVar1 = this->MutingEndRound - RoundNr; - } - return iVar1; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void InitPlayer(void) - -{ - TPlayerData *pTVar1; - - FirstFreePlayer = 0; - pTVar1 = PlayerDataPool; - do { - pTVar1->CharacterID = 0; - pTVar1 = pTVar1 + 1; - } while ((int)pTVar1 < 0x907a435); - // try { // try from 080af836 to 080af83f has its CatchHandler @ 080af842 - CreatePlayerList(true); - InitPlayerIndex(); - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void ExitPlayer(void) - -{ - ExitPlayerPool(); - CreatePlayerList(false); - return; -} - - - void __tcf_0(void *param_1) { diff --git a/src/common.hh b/src/common.hh index 4737c54..384d76e 100644 --- a/src/common.hh +++ b/src/common.hh @@ -16,6 +16,8 @@ typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; typedef uintptr_t uintptr; typedef size_t usize; diff --git a/src/connection.hh b/src/connection.hh index 4a5e544..5e2b1ba 100644 --- a/src/connection.hh +++ b/src/connection.hh @@ -20,6 +20,8 @@ struct TConnection { bool IsVisible(int x, int y, int z); void EnterGame(void); const char *GetIPAddress(void); + void Die(void); + KNOWNCREATURESTATE KnownCreature(uint32 CreatureID, bool UpdateFollows); // DATA // ================= diff --git a/src/cr.hh b/src/cr.hh index 83ab647..37671b8 100644 --- a/src/cr.hh +++ b/src/cr.hh @@ -184,6 +184,8 @@ struct TSkill{ int GetProgress(void); void Check(void); void Change(int Amount); + void SetMax(void); + void DecreasePercent(int Percent); void SetMDAct(int MDAct); void Load(int Act, int Max, int Min, int DAct, int MDAct, int Cycle, int MaxCycle, int Count, int MaxCount, int AddLevel, @@ -716,45 +718,61 @@ struct TPlayer: TCreature { TPlayer(TConnection *Connection, uint32 CharacterID); void SetInList(void); void DelInList(void); - -//== - - // TODO(fusion): Eventually sort these out when we implement player functions. + void ClearRequest(void); + void ClearConnection(void); + void LoadData(void); + void SaveData(void); + void LoadInventory(bool SetStandardInventory); + void SaveInventory(void); + void StartCoordinates(void); + void TakeOver(TConnection *Connection); + void SetOpenContainer(int ContainerNr, Object Con); + Object GetOpenContainer(int ContainerNr); + void CloseAllContainers(void); + Object InspectTrade(bool OwnOffer, int Position); + void AcceptTrade(void); + void RejectTrade(void); + void ClearProfession(void); + void SetProfession(uint8 Profession); uint8 GetRealProfession(void); uint8 GetEffectiveProfession(void); uint8 GetActiveProfession(void); bool GetActivePromotion(void); - void ClearProfession(void); - void SetProfession(uint8 Profession); - int GetQuestValue(int Number); - void SetQuestValue(int Number, int Value); - void JoinParty(uint32 Leader); - void LeaveParty(void); - uint32 GetPartyLeader(bool CheckFormer); bool SpellKnown(int SpellNr); - bool IsAttackJustified(uint32 Victim); - void RecordAttack(uint32 Victim); - void RecordMurder(uint32 Victim); + void LearnSpell(int SpellNr); + int GetQuestValue(int QuestNr); + void SetQuestValue(int QuestNr, int Value); + void CheckOutfit(void); void CheckState(void); + void AddBuddy(const char *Name); + void RemoveBuddy(uint32 CharacterID); + void SendBuddies(void); + void Regenerate(void); + bool IsAttacker(uint32 VictimID, bool CheckFormer); + bool IsAggressor(bool CheckFormer); + bool IsAttackJustified(uint32 VictimID); + void RecordAttack(uint32 VictimID); + void RecordMurder(uint32 VictimID); + int CheckPlayerkilling(int Now); + void ClearAttacker(uint32 VictimID); void ClearPlayerkillingMarks(void); - void SaveInventory(void); - Object GetOpenContainer(int ContainerNr); - void SetOpenContainer(int ContainerNr, Object Con); - void RejectTrade(void); - Object InspectTrade(bool OwnOffer, int Position); - int CheckForMuting(void); + int GetPlayerkillingMark(TPlayer *Observer); + uint32 GetPartyLeader(bool CheckFormer); + void JoinParty(uint32 LeaderID); + void LeaveParty(void); + int GetPartyMark(TPlayer *Observer); int RecordTalk(void); - int RecordMessage(uint32 Addressee); - void LoadData(void); - void SaveData(void); - void CheckOutfit(void); - void Regenerate(void); - void LoadInventory(bool SetDefaultInventory); - void SendBuddies(void); + int RecordMessage(uint32 AddresseeID); + int CheckForMuting(void); // VIRTUAL FUNCTIONS // ================= ~TPlayer(void) override; + void Death(void) override; + bool MovePossible(int x, int y, int z, bool Execute, bool Jump) override; + void DamageStimulus(uint32 AttackerID, int Damage, int DamageType) override; + void IdleStimulus(void) override; + void AttackStimulus(uint32 AttackerID) override; // DATA // ================= diff --git a/src/crmain.cc b/src/crmain.cc index ddf5393..a98f33e 100644 --- a/src/crmain.cc +++ b/src/crmain.cc @@ -1050,8 +1050,8 @@ void ProcessCreatures(void){ // and most of the time it is redundant because functions will check if // it's NULL before attempting anything. - int FoodRegen = Creature->Skills[SKILL_FED]->Get(); - if(FoodRegen > 0 && (RoundNr % FoodRegen) == 0 && !Creature->IsDead + int FoodInterval = Creature->Skills[SKILL_FED]->Get(); + if(FoodInterval > 0 && (RoundNr % FoodInterval) == 0 && !Creature->IsDead && !IsProtectionZone(Creature->posx, Creature->posy, Creature->posz)){ Creature->Skills[SKILL_HITPOINTS]->Change(1); Creature->Skills[SKILL_MANA]->Change(4); diff --git a/src/crplayer.cc b/src/crplayer.cc index 67ff996..24fcd56 100644 --- a/src/crplayer.cc +++ b/src/crplayer.cc @@ -1,4 +1,5 @@ #include "cr.hh" +#include "config.hh" #include "info.hh" #include "operate.hh" #include "query.hh" @@ -84,35 +85,39 @@ TPlayer::TPlayer(TConnection *Connection, uint32 CharacterID): this->AddresseesTimes[AddresseeNr] = 0; } - TPlayerData *Slot = AttachPlayerPoolSlot(CharacterID, false); - if(Slot == NULL){ + TPlayerData *PlayerData = AttachPlayerPoolSlot(CharacterID, false); + if(PlayerData == NULL){ error("TPlayer::TPlayer: PlayerData-Slot nicht gefunden.\n"); this->ConstructError = ERROR; return; } - SendMails(Slot); - - this->PlayerData = Slot; + SendMails(PlayerData); + this->PlayerData = PlayerData; this->Connection = Connection; - strcpy(this->Name, Slot->Name); - this->SetID(CharacterID); + strcpy(this->Name, PlayerData->Name); + // TODO(fusion): There is a try..catch block somewhere in here that also sets + // `this->ConstructorError` but I couldn't figure its scope. It could be the + // whole function from this point. + // I couldn't find any functions here with unhandled exceptions so we might + // want to keep an eye out. + this->SetID(CharacterID); InsertPlayerIndex(&PlayerIndexHead, 0, this->Name, CharacterID); this->LoadData(); - this->AccountID = Slot->AccountID; + this->AccountID = PlayerData->AccountID; strcpy(this->IPAddress, Connection->GetIPAddress()); - STATIC_ASSERT(sizeof(this->Rights) == sizeof(Slot->Rights)); - memcpy(this->Rights, Slot->Rights, sizeof(this->Rights)); + STATIC_ASSERT(sizeof(this->Rights) == sizeof(PlayerData->Rights)); + memcpy(this->Rights, PlayerData->Rights, sizeof(this->Rights)); - this->Sex = Slot->Sex; - strcpy(this->Guild, Slot->Guild); - strcpy(this->Rank, Slot->Rank); - strcpy(this->Title, Slot->Title); + this->Sex = PlayerData->Sex; + strcpy(this->Guild, PlayerData->Guild); + strcpy(this->Rank, PlayerData->Rank); + strcpy(this->Title, PlayerData->Title); - if(Slot->PlayerkillerEnd < (int)time(NULL)){ - Slot->PlayerkillerEnd = 0; + if(PlayerData->PlayerkillerEnd < (int)time(NULL)){ + PlayerData->PlayerkillerEnd = 0; } this->CheckOutfit(); @@ -135,309 +140,1621 @@ TPlayer::TPlayer(TConnection *Connection, uint32 CharacterID): } } - // TODO(fusion): Handle login after death? - if(this->Skills[SKILL_HITPOINTS]->Get() <= 0){ - for(int SkillNr = 0; - SkillNr < NARRAY(this->Skills); - SkillNr += 1){ - this->DelTimer(SkillNr); - this->Skills[SkillNr]->SetMDAct(0); - this->Skills[SkillNr]->DAct = 0; - } + // TODO(fusion): Handle login after death? + if(this->Skills[SKILL_HITPOINTS]->Get() <= 0){ + for(int SkillNr = 0; + SkillNr < NARRAY(this->Skills); + SkillNr += 1){ + this->DelTimer(SkillNr); + this->Skills[SkillNr]->SetMDAct(0); + this->Skills[SkillNr]->DAct = 0; + } + + this->Skills[SKILL_HITPOINTS]->SetMax(); + this->Skills[SKILL_MANA ]->SetMax(); + this->Outfit = this->OrgOutfit; + this->posx = this->startx; + this->posy = this->starty; + this->posz = this->startz; + } + + if(PlayerData->LastLoginTime == 0 && CheckRight(CharacterID, GAMEMASTER_OUTFIT)){ + Log("game", "Gamemaster-Charakter %s loggt zum ersten Mal ein -> Level 2 setzen.\n", this->Name); + this->Skills[SKILL_LEVEL]->Act = 2; + this->Skills[SKILL_LEVEL]->Exp = 100; + this->Skills[SKILL_LEVEL]->LastLevel = 100; + this->Skills[SKILL_LEVEL]->NextLevel = 200; + } + + if(CoordinateFlag(this->posx, this->posy, this->posz, BED)){ + this->Regenerate(); + } + + uint16 HouseID = GetHouseID(this->posx, this->posy, this->posz); + if(HouseID != 0 + && !IsInvited(HouseID, this, PlayerData->LastLogoutTime) + && !CheckRight(CharacterID, ENTER_HOUSES)){ + GetExitPosition(HouseID, &this->posx, &this->posy, &this->posz); + } + + if(!CheckRight(CharacterID, PREMIUM_ACCOUNT)){ + if(IsPremiumArea(this->startx, this->starty, this->startz)){ + Log("game", "Spieler %s wird aus PayArea-Stadt ausgebürgert und erhält neue Heimatstadt.\n", this->Name); + GetStartPosition(&this->startx, &this->starty, &this->startz, (this->Profession == PROFESSION_NONE)); + } + + if(IsPremiumArea(this->posx, this->posy, this->posz)){ + Log("game", "Spieler %s wird aus PayArea geworfen und in seine Heimatstadt gesetzt.\n", this->Name); + this->posx = this->startx; + this->posy = this->starty; + this->posz = this->startz; + } + }else{ + Log("game", "Spieler besitzt Premium Account.\n"); + } + + this->SetOnMap(); + Connection->EnterGame(); + SendInitGame(Connection, CharacterID); + SendRights(Connection); + SendFullScreen(Connection); + GraphicalEffect(this->CrObject, EFFECT_ENERGY); + this->LoadInventory(PlayerData->LastLoginTime == 0); + this->NotifyChangeInventory(); + SendAmbiente(Connection); + AnnounceChangedCreature(CharacterID, CREATURE_LIGHT_CHANGED); + SendPlayerSkills(Connection); + this->CheckState(); + this->SendBuddies(); + + if(PlayerData->LastLoginTime != 0){ + char TimeString[100]; + struct tm LastLogin = GetLocalTimeTM(PlayerData->LastLoginTime); + strftime(TimeString, sizeof(TimeString), "%d. %b %Y %X %Z", &LastLogin); + SendMessage(Connection, TALK_LOGIN_MESSAGE, + "Your last visit in Tibia: %s.", TimeString); + }else if(!CheckRight(this->ID, GAMEMASTER_OUTFIT)){ + Log("game", "Spieler %s loggt zum ersten Mal ein -> Outfitwahl.\n", this->Name); + SendMessage(Connection, TALK_LOGIN_MESSAGE, + "Welcome to Tibia! Please choose your outfit."); + SendOutfit(Connection); + } + + PlayerData->LastLoginTime = time(NULL); +} + +TPlayer::~TPlayer(void){ + LogoutOrder(this); + if(this->ConstructError != NOERROR){ + this->DelInList(); + return; + } + + ASSERT(this->PlayerData); + TPlayerData *PlayerData = this->PlayerData; + PlayerData->LastLogoutTime = time(NULL); + this->SaveData(); + + if(!this->IsDead){ + Log("game", "Spieler %s loggt aus.\n", this->Name); + GraphicalEffect(this->posx, this->posy, this->posz, EFFECT_POFF); + this->SaveInventory(); + }else{ + Log("game", "Spieler %s ist gestorben.\n", this->Name); + + // NOTE(fusion): This is a disaster. We're deleting inventory data here + // so `~TCreature` can handle dropping loot and then re-generate it with + // `SaveInventory` if `LoseInventory` is not `LOSE_INVENTORY_ALL`, which + // makes sense but is poorly executed. + delete[] PlayerData->Inventory; + PlayerData->Inventory = NULL; + + bool ResetCharacter = false; + if(this->Profession != PROFESSION_NONE && this->Skills[SKILL_LEVEL]->Get() <= 5){ + Log("game", "Setze Spieler %s komplett zurück wegen Level.\n", this->Name); + ResetCharacter = true; + }else if(this->Skills[SKILL_HITPOINTS]->Max <= 0){ + Log("game", "Setze Spieler %s komplett zurück wegen MaxHitpoints.\n", this->Name); + ResetCharacter = true; + } + + if(ResetCharacter){ + PlayerData->CurrentOutfit = PlayerData->OriginalOutfit; + PlayerData->startx = 0; + PlayerData->starty = 0; + PlayerData->startz = 0; + PlayerData->posx = 0; + PlayerData->posy = 0; + PlayerData->posz = 0; + PlayerData->Profession = PROFESSION_NONE; + + for(int SpellNr = 0; + SpellNr < NARRAY(PlayerData->SpellList); + SpellNr += 1){ + PlayerData->SpellList[SpellNr] = 0; + } + + for(int QuestNr = 0; + QuestNr < NARRAY(PlayerData->QuestValues); + QuestNr += 1){ + PlayerData->QuestValues[QuestNr] = 0; + } + + // NOTE(fusion): This is used to reset skills back to default. See + // `LoadData`. + for(int SkillNr = 0; + SkillNr < NARRAY(PlayerData->Minimum); + SkillNr += 1){ + PlayerData->Minimum[SkillNr] = INT_MIN; + } + + this->LoseInventory = LOSE_INVENTORY_ALL; + } + + if(PlayerData->PlayerkillerEnd != 0){ + this->LoseInventory = LOSE_INVENTORY_ALL; + } + + if(CheckRight(this->ID, KEEP_INVENTORY)){ + this->LoseInventory = LOSE_INVENTORY_NONE; + } + } + + if(CheckRight(this->ID, READ_GAMEMASTER_CHANNEL)){ + CloseProcessedRequests(this->ID); + } + + this->ClearRequest(); + LeaveAllChannels(this->ID); + + if(this->GetPartyLeader(false) != 0){ + ::LeaveParty(this->ID, true); + } + + this->ClearPlayerkillingMarks(); + this->DelInList(); + + PlayerData->Dirty = true; + // TODO(fusion): Something is telling me that `PlayerData->Sticky` is also poorly managed. + DecreasePlayerPoolSlotSticky(PlayerData); + ReleasePlayerPoolSlot(PlayerData); +} + +void TPlayer::Death(void){ + if(CheckRight(this->ID, INVULNERABLE)){ + error("TPlayer::Death: Aha, so geht das aber nicht!! Goetter kann man nicht toeten!!\n"); + this->Skills[SKILL_HITPOINTS]->SetMax(); + return; + } + + if(this->Connection != NULL){ + SendPlayerData(this->Connection); + SendMessage(this->Connection, TALK_EVENT_MESSAGE, "You are dead.\n"); + this->Connection->Die(); + } + + TCreature::Death(); + + if(WorldType == PVP_ENFORCED){ + this->Combat.DistributeExperiencePoints(this->Skills[SKILL_LEVEL]->Exp / 20); + } + + // TODO(fusion): Probably related to blessings? + int LossPercent = (this->GetActivePromotion() ? 7 : 10); + for(int QuestNr = 101; QuestNr <= 105; QuestNr += 1){ + if(this->GetQuestValue(QuestNr) != 0){ + this->SetQuestValue(QuestNr, 0); + LossPercent -= 1; + } + } + + this->Skills[SKILL_LEVEL ]->DecreasePercent(LossPercent); + this->Skills[SKILL_MAGIC_LEVEL]->DecreasePercent(LossPercent); + this->Skills[SKILL_SHIELDING ]->DecreasePercent(LossPercent); + this->Skills[SKILL_DISTANCE ]->DecreasePercent(LossPercent); + this->Skills[SKILL_SWORD ]->DecreasePercent(LossPercent); + this->Skills[SKILL_CLUB ]->DecreasePercent(LossPercent); + this->Skills[SKILL_AXE ]->DecreasePercent(LossPercent); + this->Skills[SKILL_FIST ]->DecreasePercent(LossPercent); + this->Skills[SKILL_FISHING ]->DecreasePercent(LossPercent); +} + +bool TPlayer::MovePossible(int x, int y, int z, bool Execute, bool Jump){ + bool Result = TCreature::MovePossible(x, y, z, Execute, Jump); + if(Result && Execute){ + if(this->EarliestProtectionZoneRound > RoundNr + && IsProtectionZone(x, y, z) + && !IsProtectionZone(this->posx, this->posy, this->posz)){ + throw ENTERPROTECTIONZONE; + } + + uint16 HouseID = GetHouseID(x, y, z); + if(HouseID != 0 + && !IsInvited(HouseID, this, INT_MAX) + && !CheckRight(this->ID, ENTER_HOUSES)){ + throw NOTINVITED; + } + } + return Result; +} + +void TPlayer::DamageStimulus(uint32 AttackerID, int Damage, int DamageType){ + if(!this->IsDead){ + this->BlockLogout(60, false); + } +} + +void TPlayer::IdleStimulus(void){ + if(this->Combat.AttackDest != 0){ + try{ + this->ToDoAttack(); + this->ToDoStart(); + }catch(RESULT r){ + this->ToDoClear(); + if(r != NOERROR){ + if(r != NOWAY){ + SendResult(this->Connection, r); + } + + this->ToDoWait(1000); + this->ToDoStart(); + } + } + } +} + +void TPlayer::AttackStimulus(uint32 AttackerID){ + if(!this->IsDead){ + this->BlockLogout(60, false); + } +} + +void TPlayer::SetInList(void){ + this->SetInCrList(); + + PlayerMutex.down(); + *PlayerList.at(FirstFreePlayer) = this; + FirstFreePlayer += 1; + PlayerMutex.up(); + + NotifyBuddies(this->ID, this->Name, true); + IncrementPlayersOnline(); + if(this->Profession == PROFESSION_NONE){ + IncrementNewbiesOnline(); + } +} + +void TPlayer::DelInList(void){ + NotifyBuddies(this->ID, this->Name, false); + + for(int Index = 0; Index < FirstFreePlayer; Index += 1){ + if(*PlayerList.at(Index) == this){ + // TODO(fusion): This can't be right? If the player at `Index` changes + // before entering the critical section, we could end up removing the + // wrong player from the list.. + PlayerMutex.down(); + FirstFreePlayer -= 1; + *PlayerList.at(Index) = *PlayerList.at(FirstFreePlayer); + *PlayerList.at(FirstFreePlayer) = NULL; + PlayerMutex.up(); + + DecrementPlayersOnline(); + if(this->Profession == PROFESSION_NONE){ + DecrementNewbiesOnline(); + } + + break; + } + } +} + +void TPlayer::ClearRequest(void){ + if(this->Request != 0){ + if(this->RequestProcessingGamemaster != 0){ + TCreature *Gamemaster = GetPlayer(this->RequestProcessingGamemaster); + if(Gamemaster != NULL){ + SendFinishRequest(Gamemaster->Connection, this->Name); + } + }else{ + DeleteGamemasterRequest(this->Name); + } + + this->Request = 0; + this->RequestTimestamp = 0; + this->RequestProcessingGamemaster = 0; + } +} + +void TPlayer::ClearConnection(void){ + this->Connection = NULL; + this->ClearRequest(); +} + +void TPlayer::LoadData(void){ + TPlayerData *PlayerData = this->PlayerData; + if(PlayerData == NULL){ + error("TPlayer::LoadData: PlayerData ist NULL.\n"); + return; + } + + this->Race = PlayerData->Race; + this->OrgOutfit = PlayerData->OriginalOutfit; + this->Outfit = PlayerData->CurrentOutfit; + + GetStartPosition(&this->startx, &this->starty, &this->startz, true); + this->posx = this->startx; + this->posy = this->starty; + this->posz = this->startz; + this->Direction = DIRECTION_SOUTH; + + if(PlayerData->startx != 0){ + this->startx = PlayerData->startx; + this->starty = PlayerData->starty; + this->startz = PlayerData->startz; + } + + if(PlayerData->posx != 0){ + this->posx = PlayerData->posx; + this->posy = PlayerData->posy; + this->posz = PlayerData->posz; + } + + this->Profession = PlayerData->Profession; + this->EarliestYellRound = PlayerData->EarliestYellRound; + this->EarliestTradeChannelRound = PlayerData->EarliestTradeChannelRound; + this->EarliestSpellTime = PlayerData->EarliestSpellTime; + this->EarliestMultiuseTime = PlayerData->EarliestMultiuseTime; + this->TalkBufferFullTime = PlayerData->TalkBufferFullTime; + this->MutingEndRound = PlayerData->MutingEndRound; + this->NumberOfMutings = PlayerData->NumberOfMutings; + + + STATIC_ASSERT(NARRAY(this->SpellList) == NARRAY(PlayerData->SpellList)); + for(int SpellNr = 0; + SpellNr < NARRAY(this->SpellList); + SpellNr += 1){ + this->SpellList[SpellNr] = PlayerData->SpellList[SpellNr]; + } + + STATIC_ASSERT(NARRAY(this->QuestValues) == NARRAY(PlayerData->QuestValues)); + for(int QuestNr = 0; + QuestNr < NARRAY(this->QuestValues); + QuestNr += 1){ + this->QuestValues[QuestNr] = PlayerData->QuestValues[QuestNr]; + } + + // NOTE(fusion): `Minimum` is set to `INT_MIN` to skip loading a skill, and + // stick with the race's default. + this->SetSkills(PlayerData->Race); + STATIC_ASSERT(NARRAY(this->Skills) == NARRAY(PlayerData->Actual)); + for(int SkillNr = 0; + SkillNr < NARRAY(this->Skills); + SkillNr += 1){ + if(PlayerData->Minimum[SkillNr] == INT_MIN){ + continue; + } + + this->Skills[SkillNr]->Load( + PlayerData->Actual[SkillNr], + PlayerData->Maximum[SkillNr], + PlayerData->Minimum[SkillNr], + PlayerData->DeltaAct[SkillNr], + PlayerData->MagicDeltaAct[SkillNr], + PlayerData->Cycle[SkillNr], + PlayerData->MaxCycle[SkillNr], + PlayerData->Count[SkillNr], + PlayerData->MaxCount[SkillNr], + PlayerData->AddLevel[SkillNr], + PlayerData->Experience[SkillNr], + PlayerData->FactorPercent[SkillNr], + PlayerData->NextLevel[SkillNr], + PlayerData->Delta[SkillNr]); + } +} + +void TPlayer::SaveData(void){ + TPlayerData *PlayerData = this->PlayerData; + if(PlayerData == NULL){ + error("TPlayer::SaveData: PlayerData ist NULL.\n"); + return; + } + + PlayerData->OriginalOutfit = this->OrgOutfit; + PlayerData->CurrentOutfit = this->Outfit; + + PlayerData->startx = this->startx; + PlayerData->starty = this->starty; + PlayerData->startz = this->startz; + PlayerData->posx = this->posx; + PlayerData->posy = this->posy; + PlayerData->posz = this->posz; + + PlayerData->Profession = this->Profession; + PlayerData->EarliestYellRound = this->EarliestYellRound; + PlayerData->EarliestTradeChannelRound = this->EarliestTradeChannelRound; + PlayerData->EarliestSpellTime = this->EarliestSpellTime; + PlayerData->EarliestMultiuseTime = this->EarliestMultiuseTime; + PlayerData->TalkBufferFullTime = this->TalkBufferFullTime; + PlayerData->MutingEndRound = this->MutingEndRound; + PlayerData->NumberOfMutings = this->NumberOfMutings; + + STATIC_ASSERT(NARRAY(this->SpellList) == NARRAY(PlayerData->SpellList)); + for(int SpellNr = 0; + SpellNr < NARRAY(this->SpellList); + SpellNr += 1){ + PlayerData->SpellList[SpellNr] = this->SpellList[SpellNr]; + } + + STATIC_ASSERT(NARRAY(this->QuestValues) == NARRAY(PlayerData->QuestValues)); + for(int QuestNr = 0; + QuestNr < NARRAY(this->QuestValues); + QuestNr += 1){ + PlayerData->QuestValues[QuestNr] = this->QuestValues[QuestNr]; + } + + STATIC_ASSERT(NARRAY(this->Skills) == NARRAY(PlayerData->Actual)); + for(int SkillNr = 0; + SkillNr < NARRAY(this->Skills); + SkillNr += 1){ + // TODO(fusion): Is this even possible? I've seen a few checks here and + // here but it seems all skills are created in TCreature's constructor. + if(this->Skills[SkillNr] == NULL){ + PlayerData->Minimum[SkillNr] = INT_MIN; + continue; + } + + this->Skills[SkillNr]->Save( + &PlayerData->Actual[SkillNr], + &PlayerData->Maximum[SkillNr], + &PlayerData->Minimum[SkillNr], + &PlayerData->DeltaAct[SkillNr], + &PlayerData->MagicDeltaAct[SkillNr], + &PlayerData->Cycle[SkillNr], + &PlayerData->MaxCycle[SkillNr], + &PlayerData->Count[SkillNr], + &PlayerData->MaxCount[SkillNr], + &PlayerData->AddLevel[SkillNr], + &PlayerData->Experience[SkillNr], + &PlayerData->FactorPercent[SkillNr], + &PlayerData->NextLevel[SkillNr], + &PlayerData->Delta[SkillNr]); + } +} + +void TPlayer::LoadInventory(bool SetStandardInventory){ + TPlayerData *PlayerData = this->PlayerData; + if(PlayerData == NULL){ + error("TPlayer::LoadInventory: PlayerData ist NULL.\n"); + return; + } + + if(PlayerData->Inventory != NULL){ + try{ + TReadBuffer ReadBuffer(PlayerData->Inventory, PlayerData->InventorySize); + while(true){ + int Position = (int)ReadBuffer.readByte(); + if(Position == 0xFF){ + break; + } + + LoadObjects(&ReadBuffer, GetBodyContainer(this->ID, Position)); + Object BodyObj = GetBodyObject(this->ID, Position); + if(BodyObj != NONE){ + SendSetInventory(this->Connection, Position, BodyObj); + } + } + }catch(const char *str){ + error("TPlayer::LoadInventory: Kann Inventory von Spieler %s nicht lesen.\n", this->Name); + error("# Fehler: %s\n", str); + } + }else if(SetStandardInventory + && this->Profession == PROFESSION_NONE + && !CheckRight(this->ID, ZERO_CAPACITY)){ + try{ + Create(GetBodyContainer(this->ID, INVENTORY_RIGHTHAND), + GetSpecialObject(DEFAULT_RIGHTHAND), 0); + Create(GetBodyContainer(this->ID, INVENTORY_LEFTHAND), + GetSpecialObject(DEFAULT_LEFTHAND), 0); + if(this->Sex == 1){ + Create(GetBodyContainer(this->ID, INVENTORY_LEFTHAND), + GetSpecialObject(DEFAULT_BODY_MALE), 0); + }else{ + Create(GetBodyContainer(this->ID, INVENTORY_LEFTHAND), + GetSpecialObject(DEFAULT_BODY_FEMALE), 0); + } + + Object Bag = Create(GetBodyContainer(this->ID, INVENTORY_BAG), + GetSpecialObject(DEFAULT_CONTAINER), 0); + Create(Bag, GetSpecialObject(DEFAULT_FOOD), 1); + }catch(RESULT r){ + error("TPlayer::LoadInventory: Exception %d beim Erstellen des Standard-Inventorys.\n", r); + } + } +} + +void TPlayer::SaveInventory(void){ + TPlayerData *PlayerData = this->PlayerData; + if(PlayerData == NULL){ + error("TPlayer::SaveInventory: PlayerData ist NULL.\n"); + return; + } + + // TODO(fusion): Set `PlayerData->Dirty`? + delete[] PlayerData->Inventory; + PlayerData->Inventory = NULL; + PlayerData->InventorySize = 0; + if(this->CrObject == NONE){ + return; + } + + try{ + TDynamicWriteBuffer HelpBuffer(KB(16)); + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ + Object Obj = GetBodyObject(this->ID, Position); + if(Obj.exists()){ + HelpBuffer.writeByte((uint8)Position); + SaveObjects(Obj, &HelpBuffer, false); + } + } + + if(HelpBuffer.Position > 0){ + HelpBuffer.writeByte(0xFF); + + int InventorySize = HelpBuffer.Position; + PlayerData->Inventory = new uint8[InventorySize]; + PlayerData->InventorySize = InventorySize; + memcpy(PlayerData->Inventory, HelpBuffer.Data, InventorySize); + } + }catch(const char *str){ + error("TPlayer::SaveInventory: Kann Inventory von Spieler %s nicht schreiben.\n", this->Name); + error("# Fehler: %s\n", str); + } +} + +void TPlayer::StartCoordinates(void){ + GetStartPosition(&this->startx, &this->starty, &this->startz, true); +} + +void TPlayer::TakeOver(TConnection *Connection){ + Log("game", "Spieler %s übernimmt Verbindung.\n", this->Name); + + this->LoggingOut = false; + this->LogoutAllowed = false; + this->Connection = Connection; + Connection->EnterGame(); + + TPlayerData *PlayerData = GetPlayerPoolSlot(this->ID); + if(PlayerData == NULL){ + error("TPlayer::TakeOver: PlayerData-Slot nicht gefunden.\n"); + return; + } + + if(PlayerData->Locked != getpid()){ + error("TPlayer::TakeOver: PlayerData-Slot ist nicht korrekt gesperrt (%d).\n", PlayerData->Locked); + } + + if(PlayerData->Sticky > 1){ + DecreasePlayerPoolSlotSticky(PlayerData); + }else{ + error("TPlayer::TakeOver: Falscher Sticky-Wert %d.\n", PlayerData->Sticky); + } + + strcpy(this->Name, PlayerData->Name); + InsertPlayerIndex(&PlayerIndexHead, 0, this->Name, this->ID); + strcpy(this->IPAddress, Connection->GetIPAddress()); + memcpy(this->Rights, PlayerData->Rights, sizeof(this->Rights)); + this->Sex = PlayerData->Sex; + strcpy(this->Guild, PlayerData->Guild); + strcpy(this->Rank, PlayerData->Rank); + strcpy(this->Title, PlayerData->Title); + this->OldState = 0; + + this->CheckOutfit(); + this->ClearRequest(); + this->Combat.StopAttack(0); + LeaveAllChannels(this->ID); + this->CloseAllContainers(); + this->RejectTrade(); + + if(CheckRight(this->ID, READ_GAMEMASTER_CHANNEL)){ + CloseProcessedRequests(this->ID); + } + + SendInitGame(Connection, this->ID); + SendRights(Connection); + SendFullScreen(Connection); + SendBodyInventory(Connection, this->ID); + SendAmbiente(Connection); + SendPlayerData(Connection); + SendPlayerSkills(Connection); + this->CheckState(); + this->SendBuddies(); +} + +void TPlayer::SetOpenContainer(int ContainerNr, Object Con){ + if(ContainerNr < 0 || ContainerNr >= NARRAY(this->OpenContainer)){ + error("TPlayer::SetOpenContainer: Ungültige Fensternummer %d.\n", ContainerNr); + return; + } + + if(Con != NONE && (!Con.exists() || !Con.getObjectType().getFlag(CONTAINER))){ + error("TPlayer::SetOpenContainer: Container existiert nicht.\n"); + return; + } + + this->OpenContainer[ContainerNr] = Con; +} + +Object TPlayer::GetOpenContainer(int ContainerNr){ + if(ContainerNr < 0 || ContainerNr >= NARRAY(this->OpenContainer)){ + error("TPlayer::GetOpenContainer: Ungültige Fensternummer %d.\n", ContainerNr); + return NONE; + } + + return this->OpenContainer[ContainerNr]; +} + +void TPlayer::CloseAllContainers(void){ + for(int ContainerNr = 0; + ContainerNr < NARRAY(this->OpenContainer); + ContainerNr += 1){ + Object Con = this->GetOpenContainer(ContainerNr); + if(Con != NONE){ + this->SetOpenContainer(ContainerNr, NONE); + SendCloseContainer(this->Connection, ContainerNr); + } + } +} + +Object TPlayer::InspectTrade(bool OwnOffer, int Position){ + Object Obj = this->TradeObject; + if(Obj == NONE){ + return NONE; + } + + if(!OwnOffer){ + if(this->TradePartner == 0){ + return NONE; + } + + TPlayer *Partner = GetPlayer(this->TradePartner); + if(Partner == NULL + || Partner->TradeObject == NONE + || Partner->TradePartner != this->ID){ + return NONE; + } + + Obj = Partner->TradeObject; + } + + while(Obj != NONE && Position > 0){ + int ObjCount = CountObjects(Obj); + if(Position < ObjCount){ + Obj = GetFirstContainerObject(Obj); + Position -= 1; + }else{ + Obj = Obj.getNextObject(); + Position -= ObjCount; + } + } + + return Obj; +} + +void TPlayer::AcceptTrade(void){ + if(this->TradeObject == NONE){ + return; + } + + TPlayer *Partner = GetPlayer(this->TradePartner); + if(Partner == NULL + || Partner->TradeObject == NONE + || Partner->TradePartner != this->ID){ + return; + } + + this->TradeAccepted = true; + if(!Partner->TradeAccepted){ + return; + } + + TPlayer *Player[2] = { this, Partner }; + Object Dest[2] = { NONE, NONE }; + Object Obj[2] = { this->TradeObject, Partner->TradeObject }; + ObjectType ObjType[2] = { Obj[0].getObjectType(), Obj[1].getObjectType() }; + for(int i = 0; i < 2; i += 1){ + int Cur = i; + int Other = 1 - i; + + try{ + if(!ObjectAccessible(Player[Cur]->ID, Obj[Cur], 1)){ + throw NOTACCESSIBLE; + } + + if(ObjType[Cur].getFlag(UNMOVE)){ + throw NOTMOVABLE; + } + + if(!ObjType[Cur].getFlag(TAKE)){ + throw NOTTAKABLE; + } + + if(CheckRight(Player[Other]->ID, ZERO_CAPACITY)){ + throw TOOHEAVY; + } + + if(!CheckRight(Player[Other]->ID, UNLIMITED_CAPACITY)){ + TSkill *CarryStrength = Player[Other]->Skills[SKILL_CARRY_STRENGTH]; + if(CarryStrength == NULL){ + error("TPlayer::AcceptTrade: Skill CARRYSTRENGTH existiert nicht.\n"); + throw ERROR; + } + + // NOTE(fusion): Check if the other player has enough carry strength, + // considering the object that will be added and the object that may + // be removed. + int MaxWeight = CarryStrength->Get() * 100; + int FinalWeight = GetInventoryWeight(Player[Other]->ID) + + GetCompleteWeight(Obj[Cur]); + if(GetObjectCreatureID(Obj[Other]) == Player[Other]->ID){ + FinalWeight -= GetCompleteWeight(Obj[Other]); + } + + if(FinalWeight > MaxWeight){ + throw TOOHEAVY; + } + } + + // NOTE(fusion): We're looking for the object's destination on the + // other player's inventory. It is similar to `CreateAtCreature` but + // not quite. This should probably be its own function. + bool CheckContainers = ObjType[Cur].getFlag(MOVEMENTEVENT); + for(int j = 0; j < 2; j += 1){ + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ + // TODO(fusion): It was only a matter of time until one of these showed up. + try{ + Object BodyObj = GetBodyObject(Player[Other]->ID, Position); + if(CheckContainers){ + if(BodyObj != NONE && BodyObj != Obj[Other] + && BodyObj.getObjectType().getFlag(CONTAINER)){ + // NOTE(fusion): Check if the container has enough capacity, + // considering the object that will be added and the object + // that may be removed. + int MaxCount = BodyObj.getObjectType().getAttribute(CAPACITY); + int FinalCount = CountObjectsInContainer(BodyObj) + 1; + if(Obj[Other].getContainer() == BodyObj){ + FinalCount -= 1; + } + + if(FinalCount > MaxCount){ + throw CONTAINERFULL; + } + + Dest[Other] = BodyObj; + break; + } + }else{ + if(BodyObj == NONE){ + Object BodyCon = GetBodyContainer(Player[Other]->ID, Position); + CheckInventoryPlace(ObjType[Cur], BodyCon, Obj[Other]); + Dest[Other] = BodyCon; + break; + } + } + }catch(RESULT r){ + // no-op + } + } + + if(Dest[Other] != NONE){ + break; + } + + CheckContainers = !CheckContainers; + } + + if(Dest[Other] == NONE){ + throw NOROOM; + } + }catch(RESULT r){ + if(r == TOOHEAVY || r == NOROOM){ + SendResult(Player[Other]->Connection, r); + }else{ + SendResult(Player[Cur]->Connection, r); + } + + Player[Cur]->TradeObject = NONE; + Player[Other]->TradeObject = NONE; + SendCloseTrade(Player[Cur]->Connection); + SendCloseTrade(Player[Other]->Connection); + return; + } + } + + this->TradeObject = NONE; + Partner->TradeObject = NONE; + SendCloseTrade(this->Connection); + SendCloseTrade(Partner->Connection); + + // TODO(fusion): I feel this could be problematic. + ::Move(0, Obj[0], GetMapContainer(Player[1]->CrObject), -1, true, NONE); + ::Move(0, Obj[1], GetMapContainer(Player[0]->CrObject), -1, true, NONE); + ::Move(0, Obj[0], Dest[1], -1, true, NONE); + ::Move(0, Obj[1], Dest[0], -1, true, NONE); +} + +void TPlayer::RejectTrade(void){ + if(this->TradeObject != NONE){ + this->TradeObject = NONE; + TPlayer *Partner = GetPlayer(this->TradePartner); + if(Partner != NULL + && Partner->TradeObject != NONE + && Partner->TradePartner == this->ID){ + Partner->TradeObject = NONE; + SendCloseTrade(Partner->Connection); + SendMessage(Partner->Connection, TALK_FAILURE_MESSAGE, "Trade cancelled."); + } + } +} + +void TPlayer::ClearProfession(void){ + if(this->Profession != PROFESSION_NONE){ + this->Profession = PROFESSION_NONE; + this->Combat.CheckCombatValues(); + IncrementNewbiesOnline(); + } +} + +void TPlayer::SetProfession(uint8 Profession){ + if(Profession == PROFESSION_PROMOTED){ + if(this->Profession == PROFESSION_NONE){ + error("TPlayer::SetProfession: Spieler hat noch keinen Beruf für Veredelung.\n"); + return; + } + + if(this->Profession >= PROFESSION_PROMOTED){ + error("TPlayer::SetProfession: Spieler hat seinen Beruf schon veredelt.\n"); + return; + } + + this->Profession += PROFESSION_PROMOTED; + this->Combat.CheckCombatValues(); + + // TODO(fusion): This is similar to the TPlayer's constructor. It is + // problably some `CheckSoul` inlined function? + { + TSkill *Soul = this->Skills[SKILL_SOUL]; + Soul->Max = 200; + + int Timer = Soul->TimerValue(); + if(Timer >= 15){ + int Cycle = (Timer + 14) / 15; + int Count = (Timer + 14) % 15; + this->SetTimer(SKILL_SOUL, Cycle, Count, 15, -1); + } + } + + return; + } + + if(this->Profession != PROFESSION_NONE){ + error("TPlayer::SetProfession: Player '%s' hat bereits einen Beruf!\n", this->Name); + return; + } + + if(Profession == PROFESSION_KNIGHT){ + this->Skills[SKILL_HITPOINTS ]->AddLevel = 15; + this->Skills[SKILL_MANA ]->AddLevel = 5; + this->Skills[SKILL_CARRY_STRENGTH]->AddLevel = 25; + this->Skills[SKILL_MAGIC_LEVEL ]->ChangeSkill(3000, 1600); + this->Skills[SKILL_SHIELDING ]->ChangeSkill(1100, 100); + this->Skills[SKILL_DISTANCE ]->ChangeSkill(1400, 30); + this->Skills[SKILL_SWORD ]->ChangeSkill(1100, 50); + this->Skills[SKILL_CLUB ]->ChangeSkill(1100, 50); + this->Skills[SKILL_AXE ]->ChangeSkill(1100, 50); + this->Skills[SKILL_FIST ]->ChangeSkill(1100, 50); + }else if(Profession == PROFESSION_PALADIN){ + this->Skills[SKILL_HITPOINTS ]->AddLevel = 10; + this->Skills[SKILL_MANA ]->AddLevel = 15; + this->Skills[SKILL_CARRY_STRENGTH]->AddLevel = 20; + this->Skills[SKILL_MAGIC_LEVEL ]->ChangeSkill(1400, 1600); + this->Skills[SKILL_SHIELDING ]->ChangeSkill(1100, 100); + this->Skills[SKILL_DISTANCE ]->ChangeSkill(1100, 30); + this->Skills[SKILL_SWORD ]->ChangeSkill(1200, 50); + this->Skills[SKILL_CLUB ]->ChangeSkill(1200, 50); + this->Skills[SKILL_AXE ]->ChangeSkill(1200, 50); + this->Skills[SKILL_FIST ]->ChangeSkill(1200, 50); + }else if(Profession == PROFESSION_SORCERER){ + this->Skills[SKILL_HITPOINTS ]->AddLevel = 5; + this->Skills[SKILL_MANA ]->AddLevel = 30; + this->Skills[SKILL_CARRY_STRENGTH]->AddLevel = 10; + this->Skills[SKILL_MAGIC_LEVEL ]->ChangeSkill(1100, 1600); + this->Skills[SKILL_SHIELDING ]->ChangeSkill(1500, 100); + this->Skills[SKILL_DISTANCE ]->ChangeSkill(2000, 30); + this->Skills[SKILL_SWORD ]->ChangeSkill(2000, 50); + this->Skills[SKILL_CLUB ]->ChangeSkill(2000, 50); + this->Skills[SKILL_AXE ]->ChangeSkill(2000, 50); + this->Skills[SKILL_FIST ]->ChangeSkill(1500, 50); + }else if(Profession == PROFESSION_DRUID){ + this->Skills[SKILL_HITPOINTS ]->AddLevel = 5; + this->Skills[SKILL_MANA ]->AddLevel = 30; + this->Skills[SKILL_CARRY_STRENGTH]->AddLevel = 10; + this->Skills[SKILL_MAGIC_LEVEL ]->ChangeSkill(1100, 1600); + this->Skills[SKILL_SHIELDING ]->ChangeSkill(1500, 100); + this->Skills[SKILL_DISTANCE ]->ChangeSkill(1800, 30); + this->Skills[SKILL_SWORD ]->ChangeSkill(1800, 50); + this->Skills[SKILL_CLUB ]->ChangeSkill(1800, 50); + this->Skills[SKILL_AXE ]->ChangeSkill(1800, 50); + this->Skills[SKILL_FIST ]->ChangeSkill(1500, 50); + }else{ + error("TPlayer::SetProfession: Beruf %d existiert nicht!\n", Profession); + return; + } + + this->Profession = Profession; + this->Combat.CheckCombatValues(); + DecrementNewbiesOnline(); +} + +uint8 TPlayer::GetRealProfession(void){ + return this->Profession; +} + +uint8 TPlayer::GetEffectiveProfession(void){ + uint8 Profession = this->Profession; + if(Profession >= PROFESSION_PROMOTED){ + Profession -= PROFESSION_PROMOTED; + } + return Profession; +} + +uint8 TPlayer::GetActiveProfession(void){ + uint8 Profession; + if(CheckRight(this->ID, PREMIUM_ACCOUNT)){ + Profession = this->GetRealProfession(); + }else{ + Profession = this->GetEffectiveProfession(); + } + return Profession; +} + +bool TPlayer::GetActivePromotion(void){ + return CheckRight(this->ID, PREMIUM_ACCOUNT) + && this->Profession >= PROFESSION_PROMOTED; +} + +bool TPlayer::SpellKnown(int SpellNr){ + if(SpellNr < 0 || SpellNr >= NARRAY(this->SpellList)){ + error("TPlayer::SpellKnown: Ungültige Spruchnummer %d.\n", SpellNr); + return false; + } + + return this->SpellList[SpellNr] != 0; +} + +void TPlayer::LearnSpell(int SpellNr){ + if(SpellNr < 0 || SpellNr >= NARRAY(this->SpellList)){ + error("TPlayer::LearnSpell: Ungültige Spruchnummer %d.\n", SpellNr); + return; + } + + if(this->SpellList[SpellNr] != 0){ + error("TPlayer::LearnSpell: Der Spieler kennt den Spruch schon.\n"); + return; + } + + this->SpellList[SpellNr] = 1; +} + +int TPlayer::GetQuestValue(int QuestNr){ + if(QuestNr < 0 || QuestNr >= NARRAY(this->QuestValues)){ + error("TPlayer::GetQuestValue: Ungültige Nummer %d.\n", QuestNr); + return 0; + } + + print(3, "Wert der Questvariablen %d von %s: %d.\n", + QuestNr, this->Name, this->QuestValues[QuestNr]); + return this->QuestValues[QuestNr]; +} + +void TPlayer::SetQuestValue(int QuestNr, int Value){ + if(QuestNr < 0 || QuestNr >= NARRAY(this->QuestValues)){ + error("TPlayer::SetQuestValue: Ungültige Nummer %d.\n", QuestNr); + return; + } + + print(3, "Neuer Wert für Questvariable %d von %s: %d.\n", + QuestNr, this->Name, Value); + this->QuestValues[QuestNr] = Value; +} + +void TPlayer::CheckOutfit(void){ + if(CheckRight(this->ID, GAMEMASTER_OUTFIT)){ + if(this->OrgOutfit.OutfitID == 75){ + return; + } + + this->OrgOutfit.OutfitID = 75; + this->OrgOutfit.Colors[0] = 0; + this->OrgOutfit.Colors[1] = 0; + this->OrgOutfit.Colors[2] = 0; + this->OrgOutfit.Colors[3] = 0; + }else if(this->Sex == 1){ + if(this->OrgOutfit.OutfitID >= 128 && this->OrgOutfit.OutfitID <= 134){ + return; + } + + this->OrgOutfit.OutfitID = 128; + this->OrgOutfit.Colors[0] = 78; + this->OrgOutfit.Colors[1] = 69; + this->OrgOutfit.Colors[2] = 58; + this->OrgOutfit.Colors[3] = 76; + }else{ + if(this->OrgOutfit.OutfitID >= 136 && this->OrgOutfit.OutfitID <= 142){ + return; + } + + this->OrgOutfit.OutfitID = 136; + this->OrgOutfit.Colors[0] = 78; + this->OrgOutfit.Colors[1] = 69; + this->OrgOutfit.Colors[2] = 58; + this->OrgOutfit.Colors[3] = 76; + } + + this->Outfit = this->OrgOutfit; +} + +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): I think the result from `Get()` here tells whether the + // player has some drunk suppression item equipped? + if(this->Skills[SKILL_DRUNKEN]->TimerValue() > 0 + && this->Skills[SKILL_DRUNKEN]->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; + } + } +} + +void TPlayer::AddBuddy(const char *Name){ + if(Name == NULL){ + error("TPlayer::AddBuddy: Name ist NULL.\n"); + return; + } + + TPlayerData *PlayerData = this->PlayerData; + if(PlayerData == NULL){ + error("TPlayer::AddBuddy: PlayerData ist NULL.\n"); + return; + } + + if(PlayerData->Buddies >= 100){ + SendMessage(this->Connection, TALK_FAILURE_MESSAGE, + "You cannot add more buddies."); + return; + } + + if(PlayerData->Buddies >= 20 + && !CheckRight(this->ID, PREMIUM_ACCOUNT) + && !CheckRight(this->ID, READ_GAMEMASTER_CHANNEL)){ + SendMessage(this->Connection, TALK_FAILURE_MESSAGE, + "You cannot add more buddies."); + return; + } + + TPlayer *Buddy = NULL; + uint32 BuddyID = 0; + char BuddyName[30] = {}; + bool Online = false; + if(IdentifyPlayer(Name, true, true, &Buddy) == 0){ + BuddyID = Buddy->ID; + strcpy(BuddyName, Buddy->Name); + Online = true; + }else{ + BuddyID = GetCharacterID(Name); + if(BuddyID == 0){ + SendResult(this->Connection, PLAYERNOTEXISTING); + return; + } + strcpy(BuddyName, GetCharacterName(Name)); + Online = false; + } + + for(int i = 0; i < PlayerData->Buddies; i += 1){ + if(PlayerData->Buddy[i] == BuddyID){ + SendMessage(this->Connection, TALK_FAILURE_MESSAGE, + "This player is already in your list."); + return; + } + } + + PlayerData->Buddy[PlayerData->Buddies] = BuddyID; + strcpy(PlayerData->BuddyName[PlayerData->Buddies], BuddyName); + PlayerData->Buddies += 1; + + Online = Online && (!CheckRight(BuddyID, NO_STATISTICS) + || CheckRight(this->ID, READ_GAMEMASTER_CHANNEL)); + SendBuddyData(this->Connection, BuddyID, BuddyName, Online); + AddBuddyOrder(this, BuddyID); +} + +void TPlayer::RemoveBuddy(uint32 CharacterID){ + TPlayerData *PlayerData = this->PlayerData; + if(PlayerData == NULL){ + error("TPlayer::RemoveBuddy: PlayerData ist NULL.\n"); + return; + } + + int BuddyIndex = 0; + while(BuddyIndex < PlayerData->Buddies){ + if(PlayerData->Buddy[BuddyIndex] == CharacterID){ + break; + } + BuddyIndex += 1; + } + + if(BuddyIndex < PlayerData->Buddies){ + // NOTE(fusion): A little swap and pop action. + PlayerData->Buddies -= 1; + PlayerData->Buddy[BuddyIndex] = PlayerData->Buddy[PlayerData->Buddies]; + strcpy(PlayerData->BuddyName[BuddyIndex], PlayerData->BuddyName[PlayerData->Buddies]); + RemoveBuddyOrder(this, CharacterID); + } +} + +void TPlayer::SendBuddies(void){ + TPlayerData *PlayerData = this->PlayerData; + if(PlayerData == NULL){ + error("TPlayer::SendBuddies: PlayerData ist NULL.\n"); + return; + } + + bool ReadGamemasterChannel = CheckRight(this->ID, READ_GAMEMASTER_CHANNEL); + for(int i = 0; i < PlayerData->Buddies; i += 1){ + bool Online = false; + uint32 BuddyID = PlayerData->Buddy[i]; + const char *BuddyName = PlayerData->BuddyName[i]; + TPlayer *Buddy = GetPlayer(BuddyID); + if(Buddy != NULL){ + Online = ReadGamemasterChannel || !CheckRight(BuddyID, NO_STATISTICS); + BuddyName = Buddy->Name; + } + SendBuddyData(this->Connection, BuddyID, BuddyName, Online); + } +} + +void TPlayer::Regenerate(void){ + // TODO(fusion): This is probably some inlined function that searches for an + // object with an specific flag on a field. + Object Bed = GetFirstObject(this->posx, this->posy, this->posz); + while(Bed != NONE){ + if(Bed.getObjectType().getFlag(BED)){ + break; + } + Bed = Bed.getNextObject(); + } + + if(Bed == NONE){ + error("TPlayer::Regenerate: Bett nicht gefunden.\n"); + return; + } + + if(!Bed.getObjectType().getFlag(TEXT)){ + error("TPlayer::Regenerate: Bett trägt keinen Text.\n"); + return; + } + + uint32 Text = Bed.getAttribute(TEXTSTRING); + if(Text == 0 || stricmp(GetDynamicString(Text), this->Name) != 0){ + return; + } + + int OfflineTime = 0; + if(this->PlayerData != NULL && this->PlayerData->LastLogoutTime != 0){ + OfflineTime = (int)(time(NULL) - this->PlayerData->LastLogoutTime); + } + + int FoodTime = this->Skills[SKILL_FED]->TimerValue(); + int Regen = std::min(FoodTime / 3, OfflineTime / 15); + if(Regen > 0){ + this->Skills[SKILL_HITPOINTS]->Change(Regen / 4); + this->Skills[SKILL_MANA ]->Change(Regen); + this->SetTimer(SKILL_FED, (FoodTime - Regen * 3), 0, 0, -1); + } - this->Skills[SKILL_HITPOINTS]->Set(this->Skills[SKILL_HITPOINTS]->Max); - this->Skills[SKILL_MANA ]->Set(this->Skills[SKILL_MANA ]->Max); - this->Outfit = this->OrgOutfit; - this->posx = this->startx; - this->posy = this->starty; - this->posz = this->startz; + if(OfflineTime > 900){ + this->Skills[SKILL_SOUL]->Change(OfflineTime / 900); } - if(Slot->LastLoginTime == 0 && CheckRight(CharacterID, GAMEMASTER_OUTFIT)){ - Log("game", "Gamemaster-Charakter %s loggt zum ersten Mal ein -> Level 2 setzen.\n", this->Name); - this->Skills[SKILL_LEVEL]->Act = 2; - this->Skills[SKILL_LEVEL]->Exp = 100; - this->Skills[SKILL_LEVEL]->LastLevel = 100; - this->Skills[SKILL_LEVEL]->NextLevel = 200; + try{ + UseObjects(0, Bed, Bed); + }catch(RESULT r){ + error("TPlayer::Regenerate: Exception %d beim Aufräumen des Bettes.\n", r); } +} - if(CoordinateFlag(this->posx, this->posy, this->posz, BED)){ - this->Regenerate(); +bool TPlayer::IsAttacker(uint32 VictimID, bool CheckFormer){ + for(int i = 0; i < this->NumberOfAttackedPlayers; i += 1){ + if(*this->AttackedPlayers.at(i) == VictimID){ + return true; + } } - uint16 HouseID = GetHouseID(this->posx, this->posy, this->posz); - if(HouseID != 0 - && !IsInvited(HouseID, this, Slot->LastLogoutTime) - && !CheckRight(CharacterID, ENTER_HOUSES)){ - GetExitPosition(HouseID, &this->posx, &this->posy, &this->posz); + if(CheckFormer && (this->FormerLogoutRound + 5) >= RoundNr){ + for(int i = 0; i < this->NumberOfFormerAttackedPlayers; i += 1){ + if(*this->FormerAttackedPlayers.at(i) == VictimID){ + return true; + } + } } - if(!CheckRight(CharacterID, PREMIUM_ACCOUNT)){ - if(IsPremiumArea(this->startx, this->starty, this->startz)){ - Log("game", "Spieler %s wird aus PayArea-Stadt ausgebürgert und erhält neue Heimatstadt.\n", this->Name); - GetStartPosition(&this->startx, &this->starty, &this->startz, (this->Profession == PROFESSION_NONE)); + return false; +} + +bool TPlayer::IsAggressor(bool CheckFormer){ + return this->Aggressor + || (CheckFormer && this->FormerAggressor + && (this->FormerLogoutRound + 5) >= RoundNr); +} + +bool TPlayer::IsAttackJustified(uint32 VictimID){ + TPlayer *Victim = GetPlayer(VictimID); + if(Victim == NULL){ + error("TPlayer::IsAttackJustified: Opfer existiert nicht.\n"); + return true; + } + + if(WorldType != PVP_ENFORCED // TODO(fusion): Probably `WorldType == NORMAL` ? + && Victim->PlayerData != NULL + && Victim->PlayerData->PlayerkillerEnd == 0){ + if(Victim->IsAggressor(true)){ + return true; } - if(IsPremiumArea(this->posx, this->posy, this->posz)){ - Log("game", "Spieler %s wird aus PayArea geworfen und in seine Heimatstadt gesetzt.\n", this->Name); - this->posx = this->startx; - this->posy = this->starty; - this->posz = this->startz; + if(Victim->GetPartyLeader(true) != 0 + && Victim->GetPartyLeader(true) == this->GetPartyLeader(true)){ + return true; } - }else{ - Log("game", "Spieler besitzt Premium Account.\n"); + + return Victim->IsAttacker(this->ID, true); } - this->SetOnMap(); - Connection->EnterGame(); - SendInitGame(Connection, CharacterID); - SendRights(Connection); - SendFullScreen(Connection); - GraphicalEffect(this->CrObject, EFFECT_ENERGY); - this->LoadInventory(Slot->LastLoginTime == 0); - this->NotifyChangeInventory(); - SendAmbiente(Connection); - AnnounceChangedCreature(CharacterID, CREATURE_LIGHT_CHANGED); - SendPlayerSkills(Connection); - this->CheckState(); - this->SendBuddies(); + return true; +} - if(Slot->LastLoginTime != 0){ - char TimeString[100]; - struct tm LastLogin = GetLocalTimeTM(Slot->LastLoginTime); - strftime(TimeString, sizeof(TimeString), "%d. %b %Y %X %Z", &LastLogin); - SendMessage(Connection, TALK_LOGIN_MESSAGE, - "Your last visit in Tibia: %s.", TimeString); - }else if(!CheckRight(this->ID, GAMEMASTER_OUTFIT)){ - Log("game", "Spieler %s loggt zum ersten Mal ein -> Outfitwahl.\n", this->Name); - SendMessage(Connection, TALK_LOGIN_MESSAGE, - "Welcome to Tibia! Please choose your outfit."); - SendOutfit(Connection); +void TPlayer::RecordAttack(uint32 VictimID){ + if(WorldType != NORMAL || VictimID == this->ID){ + return; + } + + TPlayer *Victim = GetPlayer(VictimID); + if(Victim == NULL){ + error("TPlayer::RecordAttack: Opfer existiert nicht.\n"); + return; + } + + if(!Victim->IsAttacker(this->ID, true) && !this->IsAttacker(VictimID, false) + && (Victim->GetPartyLeader(true) == 0 + || Victim->GetPartyLeader(true) != this->GetPartyLeader(true))){ + *this->AttackedPlayers.at(this->NumberOfAttackedPlayers) = VictimID; + this->NumberOfAttackedPlayers += 1; + print(3, "Spieler %s ist Angreifer für Spieler %s.\n", this->Name, Victim->Name); + if(Victim->Connection != NULL + && Victim->Connection->KnownCreature(this->ID, false) == KNOWNCREATURE_UPTODATE){ + SendCreatureSkull(Victim->Connection, this->ID); + } } - Slot->LastLoginTime = time(NULL); + if(!this->IsAttackJustified(VictimID) && !this->Aggressor){ + this->Aggressor = true; + print(3, "Spieler %s ist Aggressor.\n", this->Name); + AnnounceChangedCreature(this->ID, CREATURE_SKULL_CHANGED); + } } -TPlayer::~TPlayer(void){ - LogoutOrder(this); - if(this->ConstructError != NOERROR){ - this->DelInList(); +void TPlayer::RecordMurder(uint32 VictimID){ + if(WorldType != NORMAL || VictimID == this->ID + || this->IsAttackJustified(VictimID)){ return; } - ASSERT(this->PlayerData); - TPlayerData *Slot = this->PlayerData; - Slot->LastLogoutTime = time(NULL); - this->SaveData(); + TPlayer *Victim = GetPlayer(VictimID); + if(Victim == NULL){ + error("TPlayer::RecordMurder: Opfer existiert nicht.\n"); + return; + } - if(!this->IsDead){ - Log("game", "Spieler %s loggt aus.\n", this->Name); - GraphicalEffect(this->posx, this->posy, this->posz, EFFECT_POFF); - this->SaveInventory(); - }else{ - Log("game", "Spieler %s ist gestorben.\n", this->Name); + print(3, "Ungerechtfertigter Mord von %s an %s.\n", this->Name, Victim->Name); - // NOTE(fusion): This is a disaster. We're deleting the slot's inventory - // here so `~TCreature` can handle dropping loot and then re-generate it - // with `SaveInventory` if `LoseInventory` is not `LOSE_INVENTORY_ALL`, - // which makes sense but is poorly executed. - delete[] Slot->Inventory; - Slot->Inventory = NULL; + int Now = (int)time(NULL); - bool ResetCharacter = false; - if(this->Profession != PROFESSION_NONE && this->Skills[SKILL_LEVEL]->Get() <= 5){ - Log("game", "Setze Spieler %s komplett zurück wegen Level.\n", this->Name); - ResetCharacter = true; - }else if(this->Skills[SKILL_HITPOINTS]->Max <= 0){ - Log("game", "Setze Spieler %s komplett zurück wegen MaxHitpoints.\n", this->Name); - ResetCharacter = true; - } + // TODO(fusion): It's just annoying that we check `PlayerData` in some places + // but not others. + ASSERT(this->PlayerData != NULL); + TPlayerData *PlayerData = this->PlayerData; + for(int i = 1; i < NARRAY(PlayerData->MurderTimestamps); i += 1){ + PlayerData->MurderTimestamps[i - 1] = PlayerData->MurderTimestamps[i]; + } + PlayerData->MurderTimestamps[NARRAY(PlayerData->MurderTimestamps) - 1] = Now; + SendMessage(this->Connection, TALK_ADMIN_MESSAGE, + "Warning! The murder of %s was not justified.", Victim->Name); - if(ResetCharacter){ - Slot->CurrentOutfit = Slot->OriginalOutfit; - Slot->startx = 0; - Slot->starty = 0; - Slot->startz = 0; - Slot->posx = 0; - Slot->posy = 0; - Slot->posz = 0; - Slot->Profession = PROFESSION_NONE; + int Playerkilling = this->CheckPlayerkilling(Now); + if(Playerkilling != 0){ + int OldPlayerkillerEnd = PlayerData->PlayerkillerEnd; + PlayerData->PlayerkillerEnd = Now + 2592000; // 30 days + if(OldPlayerkillerEnd == 0){ + print(3, "Spieler %s ist Playerkiller.\n", this->Name); + AnnounceChangedCreature(this->ID, CREATURE_SKULL_CHANGED); + } - for(int SpellNr = 0; - SpellNr < NARRAY(Slot->SpellList); - SpellNr += 1){ - Slot->SpellList[SpellNr] = 0; - } + if(Playerkilling == 2){ + // TODO(fusion): This might be an inlined function that calls `PunishmentOrder`? + PunishmentOrder(NULL, this->Name, this->IPAddress, 28, 2, + "Exceeding the limit of unjustified kills by 100%.", + 0, NULL, 0, false); + } + } +} - for(int QuestNr = 0; - QuestNr < NARRAY(Slot->QuestValues); - QuestNr += 1){ - Slot->QuestValues[QuestNr] = 0; - } +int TPlayer::CheckPlayerkilling(int Now){ + int LastDay = 0; + int LastWeek = 0; + int LastMonth = 0; - // TODO(fusion): This one looks sketchy. - for(int SkillNr = 0; - SkillNr < NARRAY(Slot->Minimum); - SkillNr += 1){ - Slot->Minimum[SkillNr] = INT_MIN; - } + ASSERT(this->PlayerData != NULL); + TPlayerData *PlayerData = this->PlayerData; + for(int i = 0; i < NARRAY(PlayerData->MurderTimestamps); i += 1){ + int Timestamp = PlayerData->MurderTimestamps[i]; + if(Timestamp == 0){ + continue; + } - this->LoseInventory = LOSE_INVENTORY_ALL; + if((Now - Timestamp) < 86000){ + LastDay += 1; } - if(Slot->PlayerkillerEnd != 0){ - this->LoseInventory = LOSE_INVENTORY_ALL; + if((Now - Timestamp) < 604800){ + LastWeek += 1; } - if(CheckRight(this->ID, KEEP_INVENTORY)){ - this->LoseInventory = LOSE_INVENTORY_NONE; + if((Now - Timestamp) < 2592000){ + LastMonth += 1; } } - if(CheckRight(this->ID, READ_GAMEMASTER_CHANNEL)){ - CloseProcessedRequests(this->ID); + if(LastDay >= 6 || LastWeek >= 10 || LastMonth >= 20){ + return 2; // EXCESSIVE_KILLING ? + }else if(LastDay >= 3 || LastWeek >= 5 || LastMonth >= 10){ + return 1; // PLAYERKILLER ? + }else{ + return 0; } +} - if(this->Request != 0){ - if(this->RequestProcessingGamemaster == 0){ - DeleteGamemasterRequest(this->Name); - }else{ - TCreature *Gamemaster = GetCreature(this->RequestProcessingGamemaster); - if(Gamemaster != NULL){ - if(Gamemaster->Type == PLAYER){ - SendFinishRequest(Gamemaster->Connection, this->Name); - }else{ - error("GetPlayer: Kreatur ist kein Spieler.\n"); - } - } +void TPlayer::ClearAttacker(uint32 VictimID){ + int AttackedIndex = 0; + while(AttackedIndex < this->NumberOfAttackedPlayers){ + if(*this->AttackedPlayers.at(AttackedIndex) == VictimID){ + break; } - this->Request = 0; + AttackedIndex += 1; } - LeaveAllChannels(this->ID); - - if(this->GetPartyLeader(false) != 0){ - ::LeaveParty(this->ID, true); + if(AttackedIndex >= this->NumberOfAttackedPlayers){ + return; } - this->ClearPlayerkillingMarks(); - this->DelInList(); + // NOTE(fusion): A little swap and pop action. + this->NumberOfAttackedPlayers -= 1; + *this->AttackedPlayers.at(AttackedIndex) = *this->AttackedPlayers.at(this->NumberOfAttackedPlayers); - Slot->Dirty = true; - // TODO(fusion): Something is telling me that `Slot->Sticky` is also poorly managed. - DecreasePlayerPoolSlotSticky(Slot); - ReleasePlayerPoolSlot(Slot); + TPlayer *Victim = GetPlayer(VictimID); + if(Victim != NULL + && Victim->Connection != NULL + && Victim->Connection->KnownCreature(this->ID, false) == KNOWNCREATURE_UPTODATE){ + SendCreatureSkull(Victim->Connection, this->ID); + } } -void TPlayer::SetInList(void){ - this->SetInCrList(); - - PlayerMutex.down(); - *PlayerList.at(FirstFreePlayer) = this; - FirstFreePlayer += 1; - PlayerMutex.up(); +void TPlayer::ClearPlayerkillingMarks(void){ + print(3, "Lösche Markierungen von Spieler %s.\n", this->Name); - NotifyBuddies(this->ID, this->Name, true); - IncrementPlayersOnline(); - if(this->Profession == PROFESSION_NONE){ - IncrementNewbiesOnline(); + for(int i = 0; i < this->NumberOfAttackedPlayers; i += 1){ + *this->FormerAttackedPlayers.at(i) = *this->AttackedPlayers.at(i); } -} - -void TPlayer::DelInList(void){ - NotifyBuddies(this->ID, this->Name, false); - for(int Index = 0; Index < FirstFreePlayer; Index += 1){ - if(*PlayerList.at(Index) == this){ - // TODO(fusion): This can't be right? If the player at `Index` changes - // before entering the critical section, we could end up removing the - // wrong player from the list.. - PlayerMutex.down(); - FirstFreePlayer -= 1; - *PlayerList.at(Index) = *PlayerList.at(FirstFreePlayer); - *PlayerList.at(FirstFreePlayer) = NULL; - PlayerMutex.up(); + this->NumberOfFormerAttackedPlayers = this->NumberOfAttackedPlayers; + this->NumberOfAttackedPlayers = 0; + this->FormerAggressor = this->Aggressor; + this->FormerLogoutRound = RoundNr; - DecrementPlayersOnline(); - if(this->Profession == PROFESSION_NONE){ - DecrementNewbiesOnline(); + if(this->Aggressor){ + this->Aggressor = false; + print(3, "Spieler %s ist kein Aggressor mehr.\n", this->Name); + AnnounceChangedCreature(this->ID, CREATURE_SKULL_CHANGED); + }else{ + for(int i = 0; i < this->NumberOfFormerAttackedPlayers; i += 1){ + TPlayer *Victim = GetPlayer(*this->FormerAttackedPlayers.at(i)); + if(Victim != NULL){ + print(3, "Spieler %s ist kein Angreifer mehr für Spieler %s.\n", this->Name, Victim->Name); + if(Victim->Connection != NULL + && Victim->Connection->KnownCreature(this->ID, false) == KNOWNCREATURE_UPTODATE){ + SendCreatureSkull(Victim->Connection, this->ID); + } } + } + } - break; + for(int i = 0; i < FirstFreePlayer; i += 1){ + TPlayer *Player = *PlayerList.at(i); + if(Player != NULL){ + Player->ClearAttacker(this->ID); + }else{ + error("TPlayer::ClearPlayerkillingMarks: Spieler %d existiert nicht.\n", i); } } } -uint8 TPlayer::GetRealProfession(void){ - return this->Profession; -} +int TPlayer::GetPlayerkillingMark(TPlayer *Observer){ + if(WorldType == NORMAL){ + if(Observer == NULL){ + error("TPlayer::GetPlayerkillingMark: Beobachter existiert nicht.\n"); + return SKULL_NONE; + } -uint8 TPlayer::GetEffectiveProfession(void){ - uint8 Profession = this->Profession; - if(Profession >= 10){ - Profession -= 10; + ASSERT(this->PlayerData); + if(this->PlayerData->PlayerkillerEnd != 0){ + return SKULL_RED; + } + + if(this->Aggressor){ + return SKULL_WHITE; + } + + if(this->GetPartyLeader(false) != 0 + && this->GetPartyLeader(false) == Observer->GetPartyLeader(false)){ + return SKULL_GREEN; + } + + if(this->IsAttacker(Observer->ID, false)){ + return SKULL_YELLOW; + } } - return Profession; + + return SKULL_NONE; } -uint8 TPlayer::GetActiveProfession(void){ - uint8 Profession; - if(CheckRight(this->ID, PREMIUM_ACCOUNT)){ - Profession = this->Profession; +uint32 TPlayer::GetPartyLeader(bool CheckFormer){ + if(this->PartyLeavingRound == 0 || (CheckFormer && (this->PartyLeavingRound + 5) >= RoundNr)){ + return this->PartyLeader; }else{ - Profession = this->GetEffectiveProfession(); + return 0; } - return Profession; } -bool TPlayer::GetActivePromotion(void){ - return CheckRight(this->ID, PREMIUM_ACCOUNT) - && this->Profession >= 10; +void TPlayer::JoinParty(uint32 LeaderID){ + this->PartyLeavingRound = 0; + this->PartyLeader = LeaderID; } -void TPlayer::CheckState(void){ - if(this->Connection != NULL){ - uint8 State = 0; +void TPlayer::LeaveParty(void){ + this->PartyLeavingRound = RoundNr; +} - if(this->Skills[SKILL_POISON]->TimerValue() > 0){ - State |= 0x01; - } +int TPlayer::GetPartyMark(TPlayer *Observer){ + if(Observer == NULL){ + error("TPlayer::GetPartyMark: Beobachter existiert nicht.\n"); + return PARTY_SHIELD_NONE; + } - if(this->Skills[SKILL_BURNING]->TimerValue() > 0){ - State |= 0x02; - } + if(Observer->GetPartyLeader(false) == this->ID){ + return PARTY_SHIELD_LEADER; + } - if(this->Skills[SKILL_ENERGY]->TimerValue() > 0){ - State |= 0x04; - } + if(this->GetPartyLeader(false) != 0 + && this->GetPartyLeader(false) == Observer->GetPartyLeader(false)){ + return PARTY_SHIELD_MEMBER; + } - // TODO(fusion): I think the result from `Get()` here tells whether the - // player has some drunk suppression item equipped? - if(this->Skills[SKILL_DRUNKEN]->TimerValue() > 0 - && this->Skills[SKILL_DRUNKEN]->Get() == 0){ - State |= 0x08; - } + if(Observer->GetPartyLeader(false) == Observer->ID + && IsInvitedToParty(this->ID, Observer->ID)){ + return PARTY_SHIELD_GUEST; + } - if(this->Skills[SKILL_MANASHIELD]->TimerValue() > 0 - || this->Skills[SKILL_MANASHIELD]->Get() > 0){ - State |= 0x10; - } + if(this->GetPartyLeader(false) == this->ID + && IsInvitedToParty(Observer->ID, this->ID)){ + return PARTY_SHIELD_HOST; + } - if(this->Skills[SKILL_GO_STRENGTH]->MDAct < 0){ - State |= 0x20; - }else if(this->Skills[SKILL_GO_STRENGTH]->MDAct > 0){ - State |= 0x40; + return PARTY_SHIELD_NONE; // PARTY_NONE +} + +int TPlayer::RecordTalk(void){ + int Muting = 0; + if(this->TalkBufferFullTime > ServerMilliseconds){ + if(this->TalkBufferFullTime > (ServerMilliseconds + 7500)){ + this->NumberOfMutings += 1; + Muting = (this->NumberOfMutings * this->NumberOfMutings) * 5; + this->MutingEndRound = RoundNr + (uint32)Muting; + }else{ + this->TalkBufferFullTime += 2500; } + }else{ + this->TalkBufferFullTime = ServerMilliseconds + 2500; + } + return Muting; +} - if(RoundNr < this->EarliestLogoutRound){ - State |= 0x80; +int TPlayer::RecordMessage(uint32 AddresseeID){ + STATIC_ASSERT(NARRAY(this->Addressees) == NARRAY(this->AddresseesTimes)); + int AddresseeNr = -1; + for(int i = 0; i < NARRAY(this->Addressees); i += 1){ + if(this->Addressees[i] == AddresseeID){ + AddresseeNr = i; + break; } - if(State != this->OldState){ - SendPlayerState(this->Connection, State); - this->OldState = State; + if(this->Addressees[i] == 0 || RoundNr > (this->AddresseesTimes[i] + 600)){ + AddresseeNr = i; } } + + int Muting = 0; + if(AddresseeNr == -1){ + this->NumberOfMutings += 1; + Muting = (this->NumberOfMutings * this->NumberOfMutings) * 5; + this->MutingEndRound = RoundNr + (uint32)Muting; + }else{ + this->Addressees[AddresseeNr] = AddresseeID; + this->AddresseesTimes[AddresseeNr] = RoundNr; + } + return Muting; +} + +int TPlayer::CheckForMuting(void){ + int Muting = 0; + if(this->MutingEndRound > RoundNr){ + Muting = (int)(this->MutingEndRound - RoundNr); + } + return Muting; } // Player Utility @@ -689,18 +2006,20 @@ void SaveDepot(TPlayerData *PlayerData, int DepotNr, Object Con){ } PlayerData->Dirty = true; - if(PlayerData->Depot[DepotNr] != NULL){ - delete PlayerData->Depot[DepotNr]; - PlayerData->Depot[DepotNr] = NULL; - } + delete[] PlayerData->Depot[DepotNr]; + PlayerData->Depot[DepotNr] = NULL; + PlayerData->DepotSize[DepotNr] = 0; try{ TDynamicWriteBuffer HelpBuffer(KB(16)); SaveObjects(GetFirstContainerObject(Con), &HelpBuffer, false); - PlayerData->Depot[DepotNr] = new uint8[HelpBuffer.Size]; - PlayerData->DepotSize[DepotNr] = HelpBuffer.Size; - memcpy(PlayerData->Depot[DepotNr], HelpBuffer.Data, HelpBuffer.Size); + if(HelpBuffer.Position > 0){ + int DepotSize = HelpBuffer.Position; + PlayerData->Depot[DepotNr] = new uint8[DepotSize]; + PlayerData->DepotSize[DepotNr] = DepotSize; + memcpy(PlayerData->Depot[DepotNr], HelpBuffer.Data, DepotSize); + } }catch(const char *str){ error("SaveDepot: Kann Depot nicht schreiben (%s).\n", str); PlayerData->Depot[DepotNr] = NULL; diff --git a/src/crskill.cc b/src/crskill.cc index 235f277..923c0ab 100644 --- a/src/crskill.cc +++ b/src/crskill.cc @@ -29,7 +29,11 @@ int TSkill::Get(void){ int TSkill::GetProgress(void){ int Result = 0; if(this->NextLevel > this->LastLevel){ - Result = (this->Exp - this->LastLevel) * 100 / (this->NextLevel - this->LastLevel); + // NOTE(fusion): Use 64-bit integers to avoid overflows. + int64 Result64 = (int64)(this->Exp - this->LastLevel) * 100 + / (int64)(this->NextLevel - this->LastLevel); + + Result = (int)Result64; // TODO(fusion): This feels too much for reporting a mostly *impossible* error. if(Result < 0 || Result > 100){ @@ -64,6 +68,16 @@ void TSkill::Change(int Amount){ } } +void TSkill::SetMax(void){ + this->Set(this->Max); +} + +void TSkill::DecreasePercent(int Percent){ + // NOTE(fusion): Use 64-bit integers to avoid overflows. + int64 Amount64 = ((int64)this->Exp * (int64)Percent) / 100; + this->Decrease((int)Amount64); +} + void TSkill::SetMDAct(int MDAct){ this->MDAct = MDAct; if(this->SkNr == SKILL_GO_STRENGTH && this->Master && this->Master->Type == PLAYER){ diff --git a/src/enums.hh b/src/enums.hh index 940d19e..7eb2671 100644 --- a/src/enums.hh +++ b/src/enums.hh @@ -283,6 +283,14 @@ enum LiquidType: int { LIQUID_LEMONADE = 12, }; +enum PartyShield: int { + PARTY_SHIELD_NONE = 0, + PARTY_SHIELD_HOST = 1, + PARTY_SHIELD_GUEST = 2, + PARTY_SHIELD_MEMBER = 3, + PARTY_SHIELD_LEADER = 4, +}; + // NOTE(fusion): Not in debug symbols. enum PROFESSION: uint8 { PROFESSION_NONE = 0, @@ -290,6 +298,7 @@ enum PROFESSION: uint8 { PROFESSION_PALADIN = 2, PROFESSION_SORCERER = 3, PROFESSION_DRUID = 4, + PROFESSION_PROMOTED = 10, PROFESSION_ELITE_KNIGHT = 11, PROFESSION_ROYAL_PALADIN = 12, PROFESSION_MASTER_SORCERER = 13, @@ -478,6 +487,14 @@ enum Skill: int { SKILL_SOUL = 22, }; +enum Skull: int { + SKULL_NONE = 0, + SKULL_YELLOW = 1, + SKULL_GREEN = 2, + SKULL_WHITE = 3, + SKULL_RED = 4, +}; + // IMPORTANT(fusion): All `DEFAULT_*` values here were renamed from `INVENTORY_*` // to avoid collisions with `InventorySlot`. I could also have chosen other prefix // for inventory slots but I feel we'd be wasting them here where their meaning diff --git a/src/stubs.hh b/src/stubs.hh index 9c251ef..561fc95 100644 --- a/src/stubs.hh +++ b/src/stubs.hh @@ -7,6 +7,7 @@ #include "cr.hh" #include "magic.hh" #include "map.hh" +#include "operate.hh" // IMPORTANT(fusion): These function definitions exist to test compilation. They're // not yet implemented and will cause the linker to fail with unresolved symbols. @@ -15,6 +16,8 @@ typedef void TRefreshSectorFunction(int SectorX, int SectorY, int SectorZ, const typedef void TSendMailsFunction(TPlayerData *PlayerData); extern void AbortWriter(void); +extern void AddBuddyOrder(TCreature *Creature, uint32 CharacterID); +extern void RemoveBuddyOrder(TCreature *Creature, uint32 BuddyID); extern void BroadcastMessage(int Mode, const char *Text, ...) ATTR_PRINTF(2, 3); extern void ChangeNPCState(TCreature *Npc, int NewState, bool Stimulus); extern void CharacterDeathOrder(TCreature *Creature, int OldLevel, @@ -46,6 +49,10 @@ extern void ProcessConnections(void); extern void ProcessMonsterhomes(void); extern void ProcessReaderThreadReplies(TRefreshSectorFunction *RefreshSector, TSendMailsFunction *SendMails); extern void ProcessWriterThreadReplies(void); +extern void PunishmentOrder(TCreature *Creature, const char *Name, const char *IPAddress, + int Reason, int Action, const char *Comment, int NumberOfStatements, + vector *ReportedStatements, uint32 StatementID, + bool IPBanishment); extern void ReceiveData(void); extern void SavePlayerData(TPlayerData *Slot); extern bool LoadPlayerData(TPlayerData *Slot); @@ -53,6 +60,7 @@ extern bool PlayerDataExists(uint32 CharacterID); extern void SavePlayerDataOrder(void); extern void SendAll(void); extern void SendAmbiente(TConnection *Connection); +extern void SendBodyInventory(TConnection *Connection, uint32 CreatureID); extern void SendBuddyData(TConnection *Connection, uint32 CharacterID, const char *Name, bool Online); extern void SendBuddyStatus(TConnection *Connection, uint32 CharacterID, bool Online); extern void SendClearTarget(TConnection *Connection); -- cgit v1.2.3