From ad1f1814541fc38f7c06e88c7925fbb5bd0dceeb Mon Sep 17 00:00:00 2001 From: fusion32 Date: Mon, 26 May 2025 17:53:28 -0300 Subject: impl Cron and most `map.cc` functions --- TODO.md | 2 +- reference/game.c | 881 ------------------------------------------------------- src/map.cc | 383 +++++++++++++++++++++++- src/map.hh | 35 ++- src/stubs.hh | 5 - 5 files changed, 402 insertions(+), 904 deletions(-) diff --git a/TODO.md b/TODO.md index ec487dc..8c5d1a8 100644 --- a/TODO.md +++ b/TODO.md @@ -10,7 +10,7 @@ The decompiled file has ~115K lines of C. If we take ~15K lines to be rubbish, this can be round to ~100K. Considering a low estimate of 200 lines per day, the whole process could take up to 500 days which is quite a bit but not impossible. Now considering a high estimate of 1K lines per day, it could take 100 days which is also quite a bit. ## TODO AFTER FIRST PASS -- Trim some rough edges. +- Trim rough edges. - Avoid unsafe libc functions like `strcpy`, `strncpy`, `strcat`, `sprintf` etc... - Handle connections inline with `poll`/`epoll` (probably?). - Remove exceptions. diff --git a/reference/game.c b/reference/game.c index 63100e0..5591ba8 100644 --- a/reference/game.c +++ b/reference/game.c @@ -5192,887 +5192,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority return; } -void CronMove(int Destination,int Source) - -{ - int iVar1; - uint uVar2; - TCronEntry *pTVar3; - TCronEntry *pTVar4; - TCronEntry *Entry; - undefined8 local_34; - int iStack_30; - - pTVar3 = vector::operator()(&CronEntry,Destination); - pTVar4 = vector::operator()(&CronEntry,Source); - (pTVar3->Obj).ObjectID = (pTVar4->Obj).ObjectID; - pTVar3->RoundNr = pTVar4->RoundNr; - iVar1 = pTVar4->Next; - pTVar3->Previous = pTVar4->Previous; - pTVar3->Next = iVar1; - pTVar3 = vector::operator()(&CronEntry,Destination); - if (pTVar3->Next != -1) { - pTVar4 = vector::operator()(&CronEntry,pTVar3->Next); - pTVar4->Previous = Destination; - } - if (pTVar3->Previous != -1) { - pTVar4 = vector::operator()(&CronEntry,pTVar3->Previous); - iVar1 = pTVar3->Previous; - pTVar4->Next = Destination; - if (iVar1 != -1) { - return; - } - } - uVar2 = (pTVar3->Obj).ObjectID; - CronHashTable - [uVar2 + ((uVar2 - (int)((ulonglong)uVar2 * 0x200401 >> 0x20) >> 1) + iStack_30 >> 10) * -0x7ff] - = Destination; - return; -} - - - -void CronHeapify(int Position) - -{ - int i; - TCronEntry *pTVar1; - TCronEntry *pTVar2; - int Father; - int iVar3; - - while (Position != 1) { - pTVar1 = vector::operator()(&CronEntry,Position); - iVar3 = Position / 2; - pTVar2 = vector::operator()(&CronEntry,iVar3); - if (pTVar2->RoundNr <= pTVar1->RoundNr) break; - CronMove(0,Position); - CronMove(Position,iVar3); - CronMove(iVar3,0); - Position = iVar3; - } - while( true ) { - iVar3 = Position * 2; - if (CronEntries < iVar3) { - return; - } - i = iVar3 + 1; - if (i <= CronEntries) { - pTVar1 = vector::operator()(&CronEntry,i); - pTVar2 = vector::operator()(&CronEntry,iVar3); - if (pTVar1->RoundNr < pTVar2->RoundNr) { - iVar3 = i; - } - } - pTVar1 = vector::operator()(&CronEntry,Position); - pTVar2 = vector::operator()(&CronEntry,iVar3); - if (pTVar1->RoundNr <= pTVar2->RoundNr) break; - CronMove(0,Position); - CronMove(Position,iVar3); - CronMove(iVar3,0); - Position = iVar3; - } - return; -} - - - -void CronSet(Object *Obj,ulong Delay) - -{ - bool bVar1; - int i; - TCronEntry *pTVar2; - ulong Position; - uint uVar3; - - bVar1 = false; - if (Obj->ObjectID != 0) { - uVar3 = Obj->ObjectID & HashTableMask; - if (HashTableType[uVar3] == '\x02') { - UnswapSector(HashTableData[uVar3]); - } - if ((HashTableType[uVar3] == '\x01') && (*(ulong *)HashTableData[uVar3] == Obj->ObjectID)) { - bVar1 = true; - } - else { - bVar1 = false; - } - } - if (bVar1) { - CronEntries = CronEntries + 1; - pTVar2 = vector::operator()(&CronEntry,CronEntries); - (pTVar2->Obj).ObjectID = Obj->ObjectID; - pTVar2 = vector::operator()(&CronEntry,CronEntries); - pTVar2->RoundNr = Delay + RoundNr; - pTVar2 = vector::operator()(&CronEntry,CronEntries); - pTVar2->Previous = -1; - pTVar2 = vector::operator()(&CronEntry,CronEntries); - pTVar2->Next = CronHashTable[Obj->ObjectID % 0x7ff]; - i = CronEntries; - CronHashTable[Obj->ObjectID % 0x7ff] = CronEntries; - pTVar2 = vector::operator()(&CronEntry,i); - if (pTVar2->Next != -1) { - pTVar2 = vector::operator()(&CronEntry,CronEntries); - pTVar2 = vector::operator()(&CronEntry,pTVar2->Next); - pTVar2->Previous = CronEntries; - } - CronHeapify(CronEntries); - } - else { - error(&DAT_080f1480); - } - return; -} - - - -void CronDelete(int Position) - -{ - uint uVar1; - int iVar2; - bool bVar3; - TCronEntry *pTVar4; - TCronEntry *pTVar5; - TCronEntry *Entry; - undefined8 local_1c; - int iStack_18; - - bVar3 = false; - if ((0 < Position) && (Position <= CronEntries)) { - bVar3 = true; - } - if (!bVar3) { - error(&DAT_080f14c0,Position); - return; - } - pTVar4 = vector::operator()(&CronEntry,Position); - if (pTVar4->Next != -1) { - pTVar5 = vector::operator()(&CronEntry,pTVar4->Next); - pTVar5->Previous = pTVar4->Previous; - } - if (pTVar4->Previous != -1) { - pTVar5 = vector::operator()(&CronEntry,pTVar4->Previous); - iVar2 = pTVar4->Previous; - pTVar5->Next = pTVar4->Next; - if (iVar2 != -1) goto LAB_08057e24; - } - uVar1 = (pTVar4->Obj).ObjectID; - CronHashTable - [uVar1 + ((uVar1 - (int)((ulonglong)uVar1 * 0x200401 >> 0x20) >> 1) + iStack_18 >> 10) * -0x7ff] - = pTVar4->Next; -LAB_08057e24: - iVar2 = CronEntries; - CronEntries = CronEntries + -1; - if (CronEntries < Position) { - return; - } - CronMove(Position,iVar2); - CronHeapify(Position); - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -Object CronCheck(void) - -{ - Object OVar1; - TCronEntry *pTVar2; - ulong *in_stack_00000004; - - OVar1.ObjectID = NONE.ObjectID; - if ((CronEntries != 0) && - (pTVar2 = vector::operator()(&CronEntry,1), OVar1 = NONE, - pTVar2->RoundNr <= RoundNr)) { - pTVar2 = vector::operator()(&CronEntry,1); - OVar1.ObjectID = (pTVar2->Obj).ObjectID; - } - *in_stack_00000004 = OVar1.ObjectID; - return (Object)(ulong)in_stack_00000004; -} - - - -ulong CronInfo(Object *Obj,bool Delete) - -{ - bool bVar1; - TCronEntry *pTVar2; - int Position; - uint uVar3; - int i; - ulong uVar4; - char *Text; - undefined8 local_44; - int iStack_40; - bool Delete_local; - - bVar1 = false; - if (Obj->ObjectID != 0) { - uVar3 = Obj->ObjectID & HashTableMask; - if (HashTableType[uVar3] == '\x02') { - UnswapSector(HashTableData[uVar3]); - } - if ((HashTableType[uVar3] == '\x01') && (*(ulong *)HashTableData[uVar3] == Obj->ObjectID)) { - bVar1 = true; - } - else { - bVar1 = false; - } - } - if (bVar1) { - uVar3 = Obj->ObjectID; - i = CronHashTable - [uVar3 + ((uVar3 - (int)((ulonglong)uVar3 * 0x200401 >> 0x20) >> 1) + iStack_40 >> 10) * - -0x7ff]; - while (i != -1) { - pTVar2 = vector::operator()(&CronEntry,i); - if ((pTVar2->Obj).ObjectID == Obj->ObjectID) { - pTVar2 = vector::operator()(&CronEntry,i); - uVar4 = pTVar2->RoundNr - RoundNr; - if ((int)uVar4 < 1) { - uVar4 = 1; - } - if (!Delete) { - return uVar4; - } - CronDelete(i); - return uVar4; - } - pTVar2 = vector::operator()(&CronEntry,i); - i = pTVar2->Next; - } - Text = "CronInfo: Objekt ist nicht im Cron-System eingetragen.\n"; - } - else { - Text = &DAT_080f1540; - } - error(Text); - return 0; -} - - - -ulong CronStop(Object *Obj) - -{ - bool bVar1; - ulong uVar2; - ulong Position; - uint uVar3; - Object local_1c [4]; - - bVar1 = false; - if (Obj->ObjectID != 0) { - uVar3 = Obj->ObjectID & HashTableMask; - if (HashTableType[uVar3] == '\x02') { - UnswapSector(HashTableData[uVar3]); - } - if ((HashTableType[uVar3] == '\x01') && (*(ulong *)HashTableData[uVar3] == Obj->ObjectID)) { - bVar1 = true; - } - else { - bVar1 = false; - } - } - if (bVar1) { - local_1c[0] = (Object)Obj->ObjectID; - uVar2 = CronInfo(local_1c,true); - } - else { - error(&DAT_080f1580); - uVar2 = 0; - } - return uVar2; -} - - - -void CronExpire(Object *Obj,int Delay) - -{ - bool bVar1; - TObject *pTVar2; - ulong Position; - uint uVar3; - Object local_3c [4]; - Object local_2c [7]; - - bVar1 = false; - if (Obj->ObjectID != 0) { - uVar3 = Obj->ObjectID & HashTableMask; - if (HashTableType[uVar3] == '\x02') { - UnswapSector(HashTableData[uVar3]); - } - if ((HashTableType[uVar3] == '\x01') && (*(ulong *)HashTableData[uVar3] == Obj->ObjectID)) { - bVar1 = true; - } - else { - bVar1 = false; - } - } - if (bVar1) { - local_3c[0] = (Object)Obj->ObjectID; - pTVar2 = AccessObject(local_3c); - ObjectType::setTypeID((ObjectType *)local_2c,(pTVar2->Type).TypeID); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,EXPIRE); - if (bVar1) { - if (Delay == -1) { - local_2c[0] = (Object)Obj->ObjectID; - pTVar2 = AccessObject(local_2c); - ObjectType::setTypeID((ObjectType *)local_3c,(pTVar2->Type).TypeID); - Delay = ObjectType::getAttribute((ObjectType *)local_3c,TOTALEXPIRETIME); - } - local_3c[0] = (Object)Obj->ObjectID; - CronSet(local_3c,Delay); - } - } - else { - error(&DAT_080f15c0); - } - return; -} - - - -void CronChange(Object *Obj,int NewDelay) - -{ - bool bVar1; - TCronEntry *pTVar2; - int Position; - uint uVar3; - int i; - char *Text; - - bVar1 = false; - if (Obj->ObjectID != 0) { - uVar3 = Obj->ObjectID & HashTableMask; - if (HashTableType[uVar3] == '\x02') { - UnswapSector(HashTableData[uVar3]); - } - if ((HashTableType[uVar3] == '\x01') && (*(ulong *)HashTableData[uVar3] == Obj->ObjectID)) { - bVar1 = true; - } - else { - bVar1 = false; - } - } - if (bVar1) { - i = CronHashTable[Obj->ObjectID % 0x7ff]; - while (i != -1) { - pTVar2 = vector::operator()(&CronEntry,i); - if ((pTVar2->Obj).ObjectID == Obj->ObjectID) { - pTVar2 = vector::operator()(&CronEntry,i); - pTVar2->RoundNr = NewDelay + RoundNr; - CronHeapify(i); - return; - } - pTVar2 = vector::operator()(&CronEntry,i); - i = pTVar2->Next; - } - Text = "CronChange: Objekt ist nicht im Cron-System eingetragen.\n"; - } - else { - Text = &DAT_080f1640; - } - error(Text); - return; -} - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -Object GetFirstSpecObject(void) - -{ - TObject *pTVar1; - ulong *in_stack_00000004; - int *in_stack_00000014; - Object local_5c [4]; - ObjectType local_4c [4]; - Object local_3c [4]; - ulong local_2c; - Object Obj; - - GetFirstObject(); - if (local_2c != NONE.ObjectID) { - do { - local_4c[0].TypeID = NONE.ObjectID; - local_3c[0].ObjectID = local_2c; - pTVar1 = AccessObject(local_3c); - ObjectType::setTypeID(local_4c,(pTVar1->Type).TypeID); - ObjectType::setTypeID((ObjectType *)local_3c,*in_stack_00000014); - if (local_4c[0].TypeID == local_3c[0].ObjectID) { - *in_stack_00000004 = local_2c; - return (Object)(ulong)in_stack_00000004; - } - local_5c[0].ObjectID = local_2c; - pTVar1 = AccessObject(local_5c); - local_2c = (pTVar1->NextObject).ObjectID; - } while (local_2c != NONE.ObjectID); - } - *in_stack_00000004 = NONE.ObjectID; - return (Object)(ulong)in_stack_00000004; -} - -bool IsOnMap(int x,int y,int z) - -{ - bool bVar1; - int sx; - int iVar2; - bool bVar3; - - iVar2 = x + 0x1f; - if (-1 < x) { - iVar2 = x; - } - if (0x7fffffff < (uint)y) { - y = y + 0x1f; - } - bVar1 = false; - bVar3 = false; - if ((SectorXMin <= iVar2 >> 5) && (bVar1 = true, SectorXMax < iVar2 >> 5)) { - bVar1 = false; - } - if (bVar1) { - bVar1 = false; - if ((SectorYMin <= y >> 5) && (bVar1 = true, SectorYMax < y >> 5)) { - bVar1 = false; - } - if (bVar1) { - bVar1 = false; - if ((SectorZMin <= z) && (bVar1 = true, SectorZMax < z)) { - bVar1 = bVar3; - } - if (bVar1 != false) { - bVar3 = true; - } - } - } - return bVar3; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -bool CoordinateFlag(void) - -{ - bool bVar1; - TObject *pTVar2; - FLAG in_stack_00000010; - Object local_5c [4]; - ObjectType local_4c [4]; - Object local_3c [4]; - ulong local_2c; - Object Obj; - - GetFirstObject(); - if (local_2c != NONE.ObjectID) { - do { - local_4c[0].TypeID = NONE.ObjectID; - local_3c[0].ObjectID = local_2c; - pTVar2 = AccessObject(local_3c); - ObjectType::setTypeID(local_4c,(pTVar2->Type).TypeID); - bVar1 = ObjectType::getFlag(local_4c,in_stack_00000010); - if (bVar1) { - return true; - } - local_5c[0].ObjectID = local_2c; - pTVar2 = AccessObject(local_5c); - local_2c = (pTVar2->NextObject).ObjectID; - } while (local_2c != NONE.ObjectID); - } - return false; -} - - - -bool IsPremiumArea(int x,int y,int param_3) - -{ - bool bVar1; - int iVar2; - int iVar3; - - iVar2 = x + 0x1f; - if (-1 < x) { - iVar2 = x; - } - iVar2 = iVar2 >> 5; - if (0x7fffffff < (uint)y) { - y = y + 0x1f; - } - bVar1 = true; - iVar3 = y >> 5; - if ((((iVar2 < 0x40c) && ((iVar2 < 0x408 || (bVar1 = true, 0x3e6 < iVar3)))) && - ((iVar2 < 0x406 || (bVar1 = true, iVar3 < 0x3f0)))) && - (((iVar2 < 0x405 || (bVar1 = true, iVar3 < 0x3f1)) && - ((iVar2 < 0x3fe || (bVar1 = true, iVar3 < 0x3f6)))))) { - bVar1 = 0x3f7 < iVar3; - } - return bVar1; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -bool IsProtectionZone(void) - -{ - byte bVar1; - bool bVar2; - int in_stack_00000004; - int in_stack_00000008; - Object local_2c [4]; - ulong local_1c; - Object Con; - - GetMapContainer((int)&local_1c,in_stack_00000004,in_stack_00000008); - bVar2 = false; - if (local_1c != NONE.ObjectID) { - local_2c[0].ObjectID = local_1c; - bVar1 = GetMapContainerFlags(local_2c); - bVar2 = (bool)(bVar1 >> 2 & 1); - } - return bVar2; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -bool IsNoLogoutField(void) - -{ - byte bVar1; - bool bVar2; - int in_stack_00000004; - int in_stack_00000008; - Object local_2c [4]; - ulong local_1c; - Object Con; - - GetMapContainer((int)&local_1c,in_stack_00000004,in_stack_00000008); - bVar2 = false; - if (local_1c != NONE.ObjectID) { - local_2c[0].ObjectID = local_1c; - bVar1 = GetMapContainerFlags(local_2c); - bVar2 = (bool)(bVar1 >> 1 & 1); - } - return bVar2; -} - - - -bool IsHouse(int x,int y,int z) - -{ - bool bVar1; - short sVar2; - TObject *pTVar3; - Object local_3c [4]; - Object local_2c; - Object Con; - - GetMapContainer((int)&local_2c,x,y); - local_3c[0].ObjectID = NONE.ObjectID; - if (local_2c.ObjectID != NONE.ObjectID) { - bVar1 = Object::exists(&local_2c); - if (bVar1) { - local_3c[0].ObjectID = local_2c.ObjectID; - pTVar3 = AccessObject(local_3c); - sVar2 = *(short *)((int)pTVar3->Attributes + 0xe); - goto LAB_0805b121; - } - error(&DAT_080f20a0,x,y,z); - } - sVar2 = 0; -LAB_0805b121: - return sVar2 != 0; -} - - - -ushort GetHouseID(int x,int y,int z) - -{ - bool bVar1; - TObject *pTVar2; - ushort uVar3; - ulong Position; - uint uVar4; - Object local_3c [4]; - uint local_2c; - Object Con; - - GetMapContainer((int)&local_2c,x,y); - uVar3 = 0; - local_3c[0].ObjectID = NONE.ObjectID; - if (local_2c != NONE.ObjectID) { - bVar1 = false; - if (local_2c != 0) { - uVar4 = local_2c & HashTableMask; - if (HashTableType[uVar4] == '\x02') { - UnswapSector(HashTableData[uVar4]); - } - if ((HashTableType[uVar4] == '\x01') && (*(uint *)HashTableData[uVar4] == local_2c)) { - bVar1 = true; - } - else { - bVar1 = false; - } - } - if (bVar1) { - local_3c[0].ObjectID = local_2c; - pTVar2 = AccessObject(local_3c); - uVar3 = *(ushort *)((int)pTVar2->Attributes + 0xe); - } - else { - error(&DAT_080f20a0,x,y,z); - uVar3 = 0; - } - } - return uVar3; -} - - - -void SetHouseID(int x,int y,int z,ushort ID) - -{ - bool bVar1; - bool bVar2; - ushort uVar3; - TObject *pTVar4; - int sy; - int iVar5; - int sx; - int iVar6; - ulong Position; - uint uVar7; - ushort ID_local; - uint local_2c; - Object Con; - - iVar6 = x; - if (0x7fffffff < (uint)x) { - iVar6 = x + 0x1f; - } - iVar5 = y; - if (0x7fffffff < (uint)y) { - iVar5 = y + 0x1f; - } - bVar1 = false; - bVar2 = false; - if ((SectorXMin <= iVar6 >> 5) && (bVar1 = true, SectorXMax < iVar6 >> 5)) { - bVar1 = false; - } - if (bVar1) { - bVar1 = false; - if ((SectorYMin <= iVar5 >> 5) && (bVar1 = true, SectorYMax < iVar5 >> 5)) { - bVar1 = false; - } - if (bVar1) { - bVar1 = false; - if ((SectorZMin <= z) && (bVar1 = true, SectorZMax < z)) { - bVar1 = bVar2; - } - if (bVar1) { - bVar2 = true; - } - } - } - if (!bVar2) { - return; - } - iVar6 = z; - GetMapContainer((int)&local_2c,x,y); - bVar1 = false; - _ID_local = NONE.ObjectID; - if (local_2c != NONE.ObjectID) { - bVar2 = false; - if (local_2c != 0) { - uVar7 = local_2c & HashTableMask; - if (HashTableType[uVar7] == '\x02') { - UnswapSector(HashTableData[uVar7]); - } - if ((HashTableType[uVar7] == '\x01') && (*(uint *)HashTableData[uVar7] == local_2c)) { - bVar2 = true; - } - else { - bVar2 = false; - } - } - if (bVar2) goto LAB_0805b36c; - } - bVar1 = true; -LAB_0805b36c: - if (bVar1) { - print(); - } - else { - uVar3 = GetHouseID(x,y,z); - if (uVar3 == 0) { - _ID_local = local_2c; - pTVar4 = AccessObject((Object *)&ID_local); - pTVar4->Attributes[3] = pTVar4->Attributes[3] + (uint)ID * 0x10000; - } - else { - error(&DAT_080f2160,y,z,iVar6); - } - } - return; -} - - - -int GetDepotNumber(char *Town) - -{ - TDepotInfo *s1; - int iVar1; - int i; - int i_00; - - if (Town == (char *)0x0) { - error("GetDepotNumber: Town ist NULL.\n"); - } - else if ((*Town != '\0') && (i_00 = DepotInfo.min, DepotInfo.min <= DepotInfo.max)) { - do { - s1 = vector::operator()(&DepotInfo,i_00); - iVar1 = stricmp(s1->Town,Town,-1); - if (iVar1 == 0) { - return i_00; - } - i_00 = i_00 + 1; - } while (i_00 <= DepotInfo.max); - } - return -1; -} - - - -char * GetDepotName(int DepotNumber) - -{ - TDepotInfo *pTVar1; - char *Text; - - if ((DepotNumber < DepotInfo.min) || (DepotInfo.max < DepotNumber)) { - Text = &DAT_080f21c0; - } - else { - pTVar1 = vector::operator()(&DepotInfo,DepotNumber); - if (pTVar1 != (TDepotInfo *)0x0) { - pTVar1 = vector::operator()(&DepotInfo,DepotNumber); - return pTVar1->Town; - } - Text = &DAT_080f2200; - } - error(Text,DepotNumber); - return "unknown"; -} - - - -// WARNING: Variable defined which should be unmapped: PremiumAccount_local - -int GetDepotSize(int DepotNumber,bool PremiumAccount) - -{ - int iVar1; - TDepotInfo *pTVar2; - bool PremiumAccount_local; - - if ((DepotNumber < DepotInfo.min) || (DepotInfo.max < DepotNumber)) { - error(&DAT_080f2240,DepotNumber); - iVar1 = 1; - } - else { - pTVar2 = vector::operator()(&DepotInfo,DepotNumber); - if (pTVar2->Size < 1) { - pTVar2 = vector::operator()(&DepotInfo,DepotNumber); - error(&DAT_080f2280,pTVar2->Size,DepotNumber); - pTVar2 = vector::operator()(&DepotInfo,DepotNumber); - pTVar2->Size = 1; - } - if (PremiumAccount) { - pTVar2 = vector::operator()(&DepotInfo,DepotNumber); - iVar1 = pTVar2->Size * 2; - } - else { - pTVar2 = vector::operator()(&DepotInfo,DepotNumber); - iVar1 = pTVar2->Size; - } - } - return iVar1; -} - - - -void GetStartPosition(int *x,int *y,int *z,bool Newbie) - -{ - int iVar1; - - if (Newbie) { - *x = NewbieStartPositionX; - *y = NewbieStartPositionY; - iVar1 = NewbieStartPositionZ; - } - else { - *x = VeteranStartPositionX; - *y = VeteranStartPositionY; - iVar1 = VeteranStartPositionZ; - } - *z = iVar1; - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -bool GetMarkPosition(void) - -{ - TMark *pTVar1; - int iVar2; - int i; - int i_00; - char *in_stack_00000004; - int *in_stack_00000008; - int *in_stack_0000000c; - int *in_stack_00000010; - - i_00 = 0; - if (0 < Marks) { - do { - pTVar1 = vector::operator()(&Mark,i_00); - iVar2 = stricmp(pTVar1->Name,in_stack_00000004,-1); - if (iVar2 == 0) { - pTVar1 = vector::operator()(&Mark,i_00); - *in_stack_00000008 = pTVar1->x; - pTVar1 = vector::operator()(&Mark,i_00); - *in_stack_0000000c = pTVar1->y; - pTVar1 = vector::operator()(&Mark,i_00); - *in_stack_00000010 = pTVar1->z; - return true; - } - i_00 = i_00 + 1; - } while (i_00 < Marks); - } - return false; -} - void RefreshSector(int x,int y,int z,TReadStream *Stream) { diff --git a/src/map.cc b/src/map.cc index 0930083..6526434 100644 --- a/src/map.cc +++ b/src/map.cc @@ -38,8 +38,6 @@ static int CronHashTable[2047]; static int CronEntries; static vector DepotInfo(0, 4, 5); -static int Depots; - static vector Mark(0, 4, 5); static int Marks; @@ -142,6 +140,204 @@ void Object::setAttribute(INSTANCEATTRIBUTE Attribute, uint32 Value){ AccessObject(*this)->Attributes[AttributeOffset] = Value; } +// Cron Management +// ============================================================================= +static void CronMove(int Destination, int Source){ + TCronEntry *DestEntry = CronEntry.at(Destination); + *DestEntry = *CronEntry.at(Source); + + if(DestEntry->Next != -1){ + CronEntry.at(DestEntry->Next)->Previous = Destination; + } + + if(DestEntry->Previous != -1){ + CronEntry.at(DestEntry->Previous)->Next = Destination; + }else{ + CronHashTable[DestEntry->Obj.ObjectID % NARRAY(CronHashTable)] = Destination; + } +} + +static void CronHeapify(int Position){ + while(Position > 1){ + int Parent = Position / 2; + TCronEntry *CurrentEntry = CronEntry.at(Position); + TCronEntry *ParentEntry = CronEntry.at(Parent); + if(ParentEntry->RoundNr <= CurrentEntry->RoundNr){ + break; + } + + // NOTE(fusion): This is emulating a swap, using position 0 as the + // temporary value. It is needed to maintain hash table links valid. + CronMove(0, Position); + CronMove(Position, Parent); + CronMove(Parent, 0); + + Position = Parent; + } + + // IMPORTANT(fusion): This is different from `priority_queue::deleteMin` as + // the last element is still in the heap and needs to be considered. + int Last = CronEntries; + while(true){ + int Smallest = Position * 2; + if(Smallest > Last){ + break; + } + + TCronEntry *SmallestEntry = CronEntry.at(Smallest); + if((Smallest + 1) <= Last){ + TCronEntry *OtherEntry = CronEntry.at(Smallest + 1); + if(OtherEntry->RoundNr < SmallestEntry->RoundNr){ + SmallestEntry = OtherEntry; + Smallest += 1; + } + } + + TCronEntry *CurrentEntry = CronEntry.at(Position); + if(CurrentEntry->RoundNr <= SmallestEntry->RoundNr){ + break; + } + + // NOTE(fusion): Same in the first loop. + CronMove(0, Position); + CronMove(Position, Smallest); + CronMove(Smallest, 0); + + Position = Smallest; + } +} + +static void CronSet(Object Obj, uint32 Delay){ + if(!Obj.exists()){ + error("CronSet: Übergebenes Objekt existiert nicht.\n"); + return; + } + + // TODO(fusion): We don't check if the object is already in the table. + + CronEntries += 1; + + int Position = CronEntries; + TCronEntry *Entry = CronEntry.at(Position); + Entry->Obj = Obj; + Entry->RoundNr = RoundNr + Delay; + Entry->Previous = -1; + Entry->Next = CronHashTable[Obj.ObjectID % NARRAY(CronHashTable)]; + if(Entry->Next != -1){ + CronEntry.at(Entry->Next)->Previous = Position; + } + + CronHeapify(Position); +} + +static void CronDelete(int Position){ + if(Position < 1 || Position > CronEntries){ + error("CronDelete: Ungültige Position %d.\n", Position); + return; + } + + TCronEntry *Entry = CronEntry.at(Position); + + if(Entry->Next != -1){ + CronEntry.at(Entry->Next)->Previous = Entry->Previous; + } + + if(Entry->Previous != -1){ + CronEntry.at(Entry->Previous)->Next = Entry->Next; + }else{ + CronHashTable[Entry->Obj.ObjectID % NARRAY(CronHashTable)] = Entry->Next; + } + + int Last = CronEntries; + CronEntries -= 1; + if(Position != Last){ + CronMove(Position, Last); + CronHeapify(Position); + } +} + +Object CronCheck(void){ + Object Obj = NONE; + if(CronEntries != 0){ + TCronEntry *Entry = CronEntry.at(1); + if(Entry->RoundNr <= RoundNr){ + Obj = Entry->Obj; + } + } + return Obj; +} + +void CronExpire(Object Obj, int Delay){ + if(!Obj.exists()){ + error("CronExpire: Übergebenes Objekt existiert nicht.\n"); + return; + } + + ObjectType ObjType = Obj.getObjectType(); + if(ObjType.getFlag(EXPIRE)){ + if(Delay == -1){ + CronSet(Obj, ObjType.getAttribute(TOTALEXPIRETIME)); + }else{ + CronSet(Obj, (uint32)Delay); + } + } +} + +void CronChange(Object Obj, int NewDelay){ + if(!Obj.exists()){ + error("CronChange: Übergebenes Objekt existiert nicht.\n"); + return; + } + + int Position = CronHashTable[Obj.ObjectID % NARRAY(CronHashTable)]; + while(Position != -1){ + TCronEntry *Entry = CronEntry.at(Position); + if(Entry->Obj == Obj){ + Entry->RoundNr = RoundNr + NewDelay; + CronHeapify(Position); + return; + } + Position = Entry->Next; + } + + error("CronChange: Objekt ist nicht im Cron-System eingetragen.\n"); +} + +uint32 CronInfo(Object Obj, bool Delete){ + if(!Obj.exists()){ + error("CronInfo: Übergebenes Objekt existiert nicht.\n"); + return 0; + } + + int Position = CronHashTable[Obj.ObjectID % NARRAY(CronHashTable)]; + while(Position != -1){ + TCronEntry *Entry = CronEntry.at(Position); + if(Entry->Obj == Obj){ + uint32 Remaining = 1; + if(Entry->RoundNr < RoundNr){ + Remaining = Entry->RoundNr - RoundNr; + } + if(Delete){ + CronDelete(Position); + } + return Remaining; + } + Position = Entry->Next; + } + + error("CronInfo: Objekt ist nicht im Cron-System eingetragen.\n"); + return 0; +} + +uint32 CronStop(Object Obj){ + if(!Obj.exists()){ + error("CronStop: Übergebenes Objekt existiert nicht.\n"); + return 0; + } + + return CronInfo(Obj, true); +} + // Map Management // ============================================================================= static void ReadMapConfig(void){ @@ -161,7 +357,6 @@ static void ReadMapConfig(void){ VeteranStartPositionZ = 0; HashTableSize = 0x100000; Marks = 0; - Depots = 0; char FileName[4096]; snprintf(FileName, sizeof(FileName), "%s/map.dat", DATAPATH); @@ -1772,6 +1967,17 @@ Object GetFirstObject(int x, int y, int z){ } } +Object GetFirstSpecObject(int x, int y, int z, ObjectType Type){ + Object Obj = GetFirstObject(x, y, z); + while(Obj != NONE){ + if(Obj.getObjectType() == Type){ + break; + } + Obj = Obj.getNextObject(); + } + return NONE; +} + uint8 GetMapContainerFlags(Object Obj){ if(!Obj.exists() || !Obj.getObjectType().isMapContainer()){ error("GetMapContainerFlags: Objekt ist kein MapContainer.\n"); @@ -1810,3 +2016,174 @@ void GetObjectCoordinates(Object Obj, int *x, int *y, int *z){ // holds its house id. *z = AccessObject(Obj)->Attributes[3] & 0xFF; } + +bool CoordinateFlag(int x, int y, int z, FLAG Flag){ + bool Result = false; + Object Obj = GetFirstObject(x, y, z); + while(Obj != NONE){ + if(Obj.getObjectType().getFlag(Flag)){ + Result = true; + break; + } + Obj = Obj.getNextObject(); + } + return Result; +} + +bool IsOnMap(int x, int y, int z){ + int SectorX = x / 32; + int SectorY = y / 32; + int SectorZ = z; + + return SectorXMin <= SectorX && SectorX <= SectorXMax + && SectorYMin <= SectorY && SectorY <= SectorYMax + && SectorZMin <= SectorZ && SectorZ <= SectorZMax; +} + +bool IsPremiumArea(int x, int y, int z){ + int SectorX = x / 32; + int SectorY = y / 32; + + // TODO(fusion): This is checking if the position lies within certain bounding + // boxes but it is difficult to unwind the condition due to optimizations. The + // best way to understand the outline of the region is to plot this function. + bool Result = true; + if(SectorX < 0x40C + && (SectorX < 0x408 || SectorY > 0x3E6) + && (SectorX < 0x406 || SectorY < 0x3F0) + && (SectorX < 0x405 || SectorY < 0x3F1) + && (SectorX < 0x3FE || SectorY < 0x3F6)){ + Result = SectorY > 0x3F7; + } + return Result; +} + +bool IsNoLogoutField(int x, int y, int z){ + bool Result = false; + Object Con = GetMapContainer(x, y, z); + if(Con != NONE){ + Result = (GetMapContainerFlags(Con) & 0x02) != 0; + } + return Result; +} + +bool IsProtectionZone(int x, int y, int z){ + bool Result = false; + Object Con = GetMapContainer(x, y, z); + if(Con != NONE){ + Result = (GetMapContainerFlags(Con) & 0x04) != 0; + } + return Result; +} + +bool IsHouse(int x, int y, int z){ + return GetHouseID(x, y, z) != 0; +} + +uint16 GetHouseID(int x, int y, int z){ + Object Con = GetMapContainer(x, y, z); + if(Con == NONE){ + return 0; + } + + if(!Con.exists()){ + error("GetHouseID: Kartencontainer für Punkt [%d,%d,%d] existiert nicht.\n", x, y, z); + return 0; + } + + // NOTE(fusion): See note in `GetObjectCoordinates`. + return (uint16)(AccessObject(Con)->Attributes[3] >> 16); +} + +void SetHouseID(int x, int y, int z, uint16 ID){ + if(!IsOnMap(x, y, z)){ + return; + } + + Object Con = GetMapContainer(x, y, z); + if(Con == NONE || !Con.exists()){ + error("SetHouseID: Kartencontainer für Punkt [%d,%d,%d] existiert nicht.\n", x, y, z); + return; + } + + // NOTE(fusion): See note in `GetObjectCoordinates`. + uint16 PrevID = (uint16)(AccessObject(Con)->Attributes[3] >> 16); + if(PrevID != 0){ + error("SetHouseID: Feld [%d,%d,%d] gehört schon zu einem Haus.\n", x, y, z); + return; + } + + AccessObject(Con)->Attributes[3] |= ((uint32)ID << 16); +} + +int GetDepotNumber(const char *Town){ + if(Town == NULL){ + error("GetDepotNumber: Town ist NULL.\n"); + return -1; + } + + for(int DepotNumber = DepotInfo.min; + DepotNumber <= DepotInfo.max; + DepotNumber += 1){ + if(stricmp(DepotInfo.at(DepotNumber)->Town, Town) == 0){ + return DepotNumber; + } + } + return -1; +} + +const char *GetDepotName(int DepotNumber){ + if(DepotNumber < DepotInfo.min || DepotNumber > DepotInfo.max){ + error("GetDepotName: Ungültiger Name für Depot %d.\n", DepotNumber); + return "unknown"; + } + + return DepotInfo.at(DepotNumber)->Town; +} + +int GetDepotSize(int DepotNumber, bool PremiumAccount){ + if(DepotNumber < DepotInfo.min || DepotNumber > DepotInfo.max){ + error("GetDepotSize: Ungültige Depotnummer %d.\n", DepotNumber); + return 1; + } + + TDepotInfo *Info = DepotInfo.at(DepotNumber); + if(Info->Size < 1){ + error("GetDepotSize: Ungültige Depotgröße %d für Depot %d.\n", Info->Size, DepotNumber); + Info->Size = 1; + } + + int Size = Info->Size; + if(PremiumAccount){ + Size *= 2; + } + + return Size; +} + +bool GetMarkPosition(const char *Name, int *x, int *y, int *z){ + bool Result = false; + for(int i = 0; i < Marks; i += 1){ + TMark *MarkPointer = Mark.at(i); + if(stricmp(MarkPointer->Name, Name) == 0){ + *x = MarkPointer->x; + *y = MarkPointer->y; + *z = MarkPointer->z; + Result = true; + break; + } + } + return Result; +} + +void GetStartPosition(int *x, int *y, int *z, bool Newbie){ + if(Newbie){ + *x = NewbieStartPositionX; + *y = NewbieStartPositionY; + *z = NewbieStartPositionZ; + }else{ + *x = VeteranStartPositionX; + *y = VeteranStartPositionY; + *z = VeteranStartPositionZ; + } +} diff --git a/src/map.hh b/src/map.hh index ac58b98..38aface 100644 --- a/src/map.hh +++ b/src/map.hh @@ -99,6 +99,13 @@ struct TCronEntry { int Next; }; +// NOTE(fusion): Cron management functions. Most for internal use. +Object CronCheck(void); +void CronExpire(Object Obj, int Delay); +void CronChange(Object Obj, int NewDelay); +uint32 CronInfo(Object Obj, bool Delete); +uint32 CronStop(Object Obj); + // NOTE(fusion): Map management functions. Most for internal use. void SwapObject(TWriteBinaryFile *File, Object Obj, uint32 FileNumber); void SwapSector(void); @@ -140,21 +147,21 @@ Object GetContainerObject(Object Con, int Index); Object GetMapContainer(int x, int y, int z); Object GetMapContainer(Object Obj); Object GetFirstObject(int x, int y, int z); -//GetFirstSpecObject +Object GetFirstSpecObject(int x, int y, int z, ObjectType Type); uint8 GetMapContainerFlags(Object Obj); -//CoordinateFlag void GetObjectCoordinates(Object Obj, int *x, int *y, int *z); -//IsOnMap -//IsPremiumArea -//IsProtectionZone -//IsNoLogoutField -//IsHouse -//GetHouseID -//SetHouseID -//GetDepotNumber -//GetDepotName -//GetDepotSize -//GetStartPosition -//GetMarkPosition +bool CoordinateFlag(int x, int y, int z, FLAG Flag); +bool IsOnMap(int x, int y, int z); +bool IsPremiumArea(int x, int y, int z); +bool IsNoLogoutField(int x, int y, int z); +bool IsProtectionZone(int x, int y, int z); +bool IsHouse(int x, int y, int z); +uint16 GetHouseID(int x, int y, int z); +void SetHouseID(int x, int y, int z, uint16 ID); +int GetDepotNumber(const char *Town); +const char *GetDepotName(int DepotNumber); +int GetDepotSize(int DepotNumber, bool PremiumAccount); +bool GetMarkPosition(const char *Name, int *x, int *y, int *z); +void GetStartPosition(int *x, int *y, int *z, bool Newbie); #endif //TIBIA_MAP_HH_ diff --git a/src/stubs.hh b/src/stubs.hh index 0926a52..1c3bde0 100644 --- a/src/stubs.hh +++ b/src/stubs.hh @@ -22,16 +22,11 @@ extern void Change(Object Obj, ObjectType NewType, uint32 Value); extern bool CheckRight(uint32 CreatureID, RIGHT Right); extern void CleanupDynamicStrings(void); extern void CreatePlayerList(bool Online); -extern void CronChange(Object Obj, int NewDelay); -extern void CronExpire(Object Obj, int Delay); -extern uint32 CronInfo(Object Obj, bool Delete); -extern uint32 CronStop(Object Obj); extern void DeleteDynamicString(uint32 Number); extern TCreature *GetCreature(uint32 CreatureID); extern const char *GetDynamicString(uint32 Number); extern TConnection *GetFirstConnection(void); extern TConnection *GetNextConnection(void); -extern bool IsProtectionZone(int x, int y, int z); extern void Log(const char *ProtocolName, const char *Text, ...) ATTR_PRINTF(2, 3); extern void LogoutAllPlayers(void); extern void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Object Ignore); -- cgit v1.2.3