diff options
| author | fusion32 <marcopuzziello@gmail.com> | 2025-05-26 17:53:28 -0300 |
|---|---|---|
| committer | fusion32 <marcopuzziello@gmail.com> | 2025-05-26 17:53:28 -0300 |
| commit | ad1f1814541fc38f7c06e88c7925fbb5bd0dceeb (patch) | |
| tree | d719a6aaafc0b9758c396758dbfa71ca64244261 | |
| parent | fbb392953c5af29b6a0924590c24a05befb72e56 (diff) | |
| download | game-ad1f1814541fc38f7c06e88c7925fbb5bd0dceeb.tar.gz game-ad1f1814541fc38f7c06e88c7925fbb5bd0dceeb.zip | |
impl Cron and most `map.cc` functions
| -rw-r--r-- | TODO.md | 2 | ||||
| -rw-r--r-- | reference/game.c | 881 | ||||
| -rw-r--r-- | src/map.cc | 383 | ||||
| -rw-r--r-- | src/map.hh | 35 | ||||
| -rw-r--r-- | src/stubs.hh | 5 |
5 files changed, 402 insertions, 904 deletions
@@ -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)
{
@@ -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; + } +} @@ -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); |
