aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-05-26 17:53:28 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-05-26 17:53:28 -0300
commitad1f1814541fc38f7c06e88c7925fbb5bd0dceeb (patch)
treed719a6aaafc0b9758c396758dbfa71ca64244261
parentfbb392953c5af29b6a0924590c24a05befb72e56 (diff)
downloadgame-ad1f1814541fc38f7c06e88c7925fbb5bd0dceeb.tar.gz
game-ad1f1814541fc38f7c06e88c7925fbb5bd0dceeb.zip
impl Cron and most `map.cc` functions
-rw-r--r--TODO.md2
-rw-r--r--reference/game.c881
-rw-r--r--src/map.cc383
-rw-r--r--src/map.hh35
-rw-r--r--src/stubs.hh5
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<TCronEntry>::operator()(&CronEntry,Destination);
- pTVar4 = vector<TCronEntry>::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<TCronEntry>::operator()(&CronEntry,Destination);
- if (pTVar3->Next != -1) {
- pTVar4 = vector<TCronEntry>::operator()(&CronEntry,pTVar3->Next);
- pTVar4->Previous = Destination;
- }
- if (pTVar3->Previous != -1) {
- pTVar4 = vector<TCronEntry>::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<TCronEntry>::operator()(&CronEntry,Position);
- iVar3 = Position / 2;
- pTVar2 = vector<TCronEntry>::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<TCronEntry>::operator()(&CronEntry,i);
- pTVar2 = vector<TCronEntry>::operator()(&CronEntry,iVar3);
- if (pTVar1->RoundNr < pTVar2->RoundNr) {
- iVar3 = i;
- }
- }
- pTVar1 = vector<TCronEntry>::operator()(&CronEntry,Position);
- pTVar2 = vector<TCronEntry>::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<TCronEntry>::operator()(&CronEntry,CronEntries);
- (pTVar2->Obj).ObjectID = Obj->ObjectID;
- pTVar2 = vector<TCronEntry>::operator()(&CronEntry,CronEntries);
- pTVar2->RoundNr = Delay + RoundNr;
- pTVar2 = vector<TCronEntry>::operator()(&CronEntry,CronEntries);
- pTVar2->Previous = -1;
- pTVar2 = vector<TCronEntry>::operator()(&CronEntry,CronEntries);
- pTVar2->Next = CronHashTable[Obj->ObjectID % 0x7ff];
- i = CronEntries;
- CronHashTable[Obj->ObjectID % 0x7ff] = CronEntries;
- pTVar2 = vector<TCronEntry>::operator()(&CronEntry,i);
- if (pTVar2->Next != -1) {
- pTVar2 = vector<TCronEntry>::operator()(&CronEntry,CronEntries);
- pTVar2 = vector<TCronEntry>::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<TCronEntry>::operator()(&CronEntry,Position);
- if (pTVar4->Next != -1) {
- pTVar5 = vector<TCronEntry>::operator()(&CronEntry,pTVar4->Next);
- pTVar5->Previous = pTVar4->Previous;
- }
- if (pTVar4->Previous != -1) {
- pTVar5 = vector<TCronEntry>::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<TCronEntry>::operator()(&CronEntry,1), OVar1 = NONE,
- pTVar2->RoundNr <= RoundNr)) {
- pTVar2 = vector<TCronEntry>::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<TCronEntry>::operator()(&CronEntry,i);
- if ((pTVar2->Obj).ObjectID == Obj->ObjectID) {
- pTVar2 = vector<TCronEntry>::operator()(&CronEntry,i);
- uVar4 = pTVar2->RoundNr - RoundNr;
- if ((int)uVar4 < 1) {
- uVar4 = 1;
- }
- if (!Delete) {
- return uVar4;
- }
- CronDelete(i);
- return uVar4;
- }
- pTVar2 = vector<TCronEntry>::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<TCronEntry>::operator()(&CronEntry,i);
- if ((pTVar2->Obj).ObjectID == Obj->ObjectID) {
- pTVar2 = vector<TCronEntry>::operator()(&CronEntry,i);
- pTVar2->RoundNr = NewDelay + RoundNr;
- CronHeapify(i);
- return;
- }
- pTVar2 = vector<TCronEntry>::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<TDepotInfo>::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<TDepotInfo>::operator()(&DepotInfo,DepotNumber);
- if (pTVar1 != (TDepotInfo *)0x0) {
- pTVar1 = vector<TDepotInfo>::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<TDepotInfo>::operator()(&DepotInfo,DepotNumber);
- if (pTVar2->Size < 1) {
- pTVar2 = vector<TDepotInfo>::operator()(&DepotInfo,DepotNumber);
- error(&DAT_080f2280,pTVar2->Size,DepotNumber);
- pTVar2 = vector<TDepotInfo>::operator()(&DepotInfo,DepotNumber);
- pTVar2->Size = 1;
- }
- if (PremiumAccount) {
- pTVar2 = vector<TDepotInfo>::operator()(&DepotInfo,DepotNumber);
- iVar1 = pTVar2->Size * 2;
- }
- else {
- pTVar2 = vector<TDepotInfo>::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<TMark>::operator()(&Mark,i_00);
- iVar2 = stricmp(pTVar1->Name,in_stack_00000004,-1);
- if (iVar2 == 0) {
- pTVar1 = vector<TMark>::operator()(&Mark,i_00);
- *in_stack_00000008 = pTVar1->x;
- pTVar1 = vector<TMark>::operator()(&Mark,i_00);
- *in_stack_0000000c = pTVar1->y;
- pTVar1 = vector<TMark>::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<TDepotInfo> DepotInfo(0, 4, 5);
-static int Depots;
-
static vector<TMark> 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);