From 15b40c7915fca14e537534ae9ba03f3add965943 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Fri, 13 Jun 2025 03:35:56 -0300 Subject: more work on `operate.cc` --- Makefile | 6 +- TODO.md | 4 + reference/game.c | 1806 ------------------------------------------------------ src/cr.hh | 1 + src/crcombat.cc | 1 + src/crmain.cc | 5 +- src/crskill.cc | 2 +- src/info.cc | 11 + src/info.hh | 1 + src/magic.cc | 2 +- src/map.cc | 27 - src/map.hh | 1 - src/moveuse.cc | 56 ++ src/moveuse.hh | 9 + src/operate.cc | 974 +++++++++++++++++++++++++++-- src/operate.hh | 40 ++ src/stubs.hh | 16 +- 17 files changed, 1069 insertions(+), 1893 deletions(-) create mode 100644 src/moveuse.cc create mode 100644 src/moveuse.hh diff --git a/Makefile b/Makefile index 3569eba..c937038 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ endif HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/config.hh $(SRCDIR)/connection.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/enums.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/objects.hh $(SRCDIR)/operate.hh $(SRCDIR)/script.hh $(SRCDIR)/stubs.hh $(SRCDIR)/thread.hh -$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/config.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/script.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/thread.obj $(BUILDDIR)/time.obj $(BUILDDIR)/util.obj +$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/config.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/script.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/thread.obj $(BUILDDIR)/time.obj $(BUILDDIR)/util.obj echo $(CC) $(CFLAGS) $(LFLAGS) -o $@ $^ $(BUILDDIR)/config.obj: $(SRCDIR)/config.cc $(HEADERS) @@ -58,6 +58,10 @@ $(BUILDDIR)/map.obj: $(SRCDIR)/map.cc $(HEADERS) @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< +$(BUILDDIR)/moveuse.obj: $(SRCDIR)/moveuse.cc $(HEADERS) + @mkdir -p $(@D) + $(CC) -c $(CFLAGS) -o $@ $< + $(BUILDDIR)/objects.obj: $(SRCDIR)/objects.cc $(HEADERS) @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< diff --git a/TODO.md b/TODO.md index 2d28ca4..51efb7f 100644 --- a/TODO.md +++ b/TODO.md @@ -28,5 +28,9 @@ The decompiled file has ~115K lines of C. If we take ~15K lines to be rubbish, t - Replace unsafe libc functions like `strcpy`, `strncpy`, `strcat`, `sprintf` etc... - Handle connections inline with `poll`/`epoll` (probably?). - Remove exceptions. + - Would be desirable but I feel it could change too much of the original code flow while also + littering functions with early return checks like `if(err != NOERROR) { return err }` although + we could also have some macros to simplify this since we know we only use `RESULT` for errors. + But then would we be in a better place? - Review signal usage for timing (SIGALRM, etc...). - Support Windows. diff --git a/reference/game.c b/reference/game.c index b68c771..9a9762d 100644 --- a/reference/game.c +++ b/reference/game.c @@ -18375,1812 +18375,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority return; } -void CheckMapPlace(ulong CreatureID,ObjectType *Type,Object *MapCon) - -{ - bool bVar1; - bool bVar2; - undefined4 *puVar3; - int iVar4; - int iVar5; - int iVar6; - int iVar7; - undefined4 uVar8; - int local_38; - int x; - int y; - int z; - - z = MapCon->ObjectID; - // try { // try from 0808fec5 to 08090120 has its CatchHandler @ 08090127 - GetObjectCoordinates((Object *)&z,&local_38,&x,&y); - bVar1 = ObjectType::getFlag(Type,UNMOVE); - if (!bVar1) { - uVar8 = 0; - iVar6 = y; - bVar1 = CoordinateFlag(); - if (!bVar1) { - iVar4 = 0x29; - bVar1 = ObjectType::getFlag(Type,HANG); - iVar7 = y; - iVar5 = x; - if (!bVar1) goto LAB_0808ffd8; - bVar1 = false; - uVar8 = 0x2a; - iVar4 = x; - iVar6 = y; - bVar2 = CoordinateFlag(); - if (bVar2) { -LAB_080900f0: - bVar1 = true; - } - else { - uVar8 = 0x2b; - bVar2 = CoordinateFlag(); - iVar4 = iVar5; - iVar6 = iVar7; - if (bVar2) goto LAB_080900f0; - } - if (!bVar1) goto LAB_0808ffd8; - } - } - iVar5 = y; - if (CreatureID == 0) { - return; - } - bVar1 = false; - uVar8 = 0; - iVar6 = y; - bVar2 = CoordinateFlag(); - if (bVar2) { - uVar8 = 0x20; - bVar1 = CoordinateFlag(); - bVar1 = !bVar1; - iVar6 = iVar5; - } - if (bVar1) { - return; - } - iVar4 = 0x20; - bVar1 = ObjectType::getFlag(Type,UNPASS); - if (bVar1) goto LAB_0808ffd8; - bVar1 = false; - bVar2 = CoordinateFlag(); - if (bVar2) { - bVar1 = CoordinateFlag(); - bVar1 = !bVar1; - } - if (bVar1) { - return; - } - bVar1 = false; - uVar8 = 0x2a; - iVar4 = x; - iVar6 = y; - bVar2 = CoordinateFlag(); - if (bVar2) { -LAB_0808ffb3: - bVar1 = true; - } - else { - uVar8 = 0x2b; - bVar2 = CoordinateFlag(); - iVar4 = x; - iVar6 = y; - if (bVar2) goto LAB_0808ffb3; - } - if (bVar1) { - iVar4 = 0x29; - bVar1 = ObjectType::getFlag(Type,HANG); - if (bVar1) { - return; - } - } -LAB_0808ffd8: - puVar3 = (undefined4 *)__cxa_allocate_exception(4,iVar4,iVar6,uVar8); - *puVar3 = 4; - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); -} - -void CheckContainerPlace(ObjectType *Type,Object *Con,Object *oldObj) - -{ - bool bVar1; - int iVar2; - ulong uVar3; - undefined4 *puVar4; - Object local_3c [4]; - Object local_2c [7]; - - // try { // try from 08090283 to 08090364 has its CatchHandler @ 08090394 - GetSpecialObject((SPECIALMEANING)local_2c); - if (Type->TypeID != local_2c[0].ObjectID) { - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CHEST); - if (!bVar1) { - bVar1 = ObjectType::getFlag(Type,UNMOVE); - if (bVar1) { - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 2; - } - else { - bVar1 = ObjectType::getFlag(Type,TAKE); - if (bVar1) { - local_2c[0].ObjectID = NONE.ObjectID; - if (oldObj->ObjectID != NONE.ObjectID) { - return; - } - local_3c[0] = (Object)Con->ObjectID; - iVar2 = CountObjectsInContainer(local_3c); - Object::getObjectType(local_2c); - uVar3 = ObjectType::getAttribute((ObjectType *)local_2c,CAPACITY); - if (iVar2 < (int)uVar3) { - return; - } - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 10; - } - else { - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 3; - } - } - // WARNING: Subroutine does not return - __cxa_throw(puVar4,&RESULT::typeinfo,0); - } - } - return; -} - - - -void CheckDepotSpace(ulong CreatureID,Object *Source,Object *Destination,int Count) - -{ - bool bVar1; - TCreature *pTVar2; - undefined4 *puVar3; - TCreature *cr; - Object *pOVar4; - Object local_3c [4]; - Object local_2c [7]; - - if (CreatureID == 0) { - return; - } - // try { // try from 080903d9 to 08090536 has its CatchHandler @ 08090540 - pTVar2 = GetCreature(CreatureID); - if (pTVar2 == (TCreature *)0x0) { - error("CheckDepotSpace: Kreatur %lu existiert nicht.\n",CreatureID); - } - else { - local_2c[0].ObjectID = NONE.ObjectID; - if (Destination->ObjectID != NONE.ObjectID) { - if (pTVar2->Type != PLAYER) { - return; - } - bVar1 = false; - if ((pTVar2[1].super_TSkillBase.TimerList[6] == (TSkill *)NONE.ObjectID) || - (Count <= (int)pTVar2[1].super_TSkillBase.TimerList[8])) { - bVar1 = true; - } - if (bVar1) { - return; - } - while( true ) { - local_2c[0].ObjectID = NONE.ObjectID; - bVar1 = false; - local_3c[0].ObjectID = NONE.ObjectID; - if ((Source->ObjectID != NONE.ObjectID) && - (Object::getObjectType(local_3c), local_3c[0].ObjectID != 0)) { - bVar1 = true; - } - if (!bVar1) break; - local_3c[0].ObjectID = (ulong)pTVar2[1].super_TSkillBase.TimerList[6]; - if ((TSkill *)Source->ObjectID == (TSkill *)local_3c[0].ObjectID) { - return; - } - Object::getContainer(local_2c); - Source->ObjectID = (ulong)local_2c[0]; - } - while( true ) { - pOVar4 = Destination; - Object::getObjectType(local_3c); - if (local_3c[0].ObjectID == 0) { - return; - } - local_3c[0].ObjectID = (ulong)pTVar2[1].super_TSkillBase.TimerList[6]; - if ((TSkill *)Destination->ObjectID == (TSkill *)local_3c[0].ObjectID) break; - Object::getContainer(local_2c); - local_3c[0].ObjectID = local_2c[0].ObjectID; - Destination->ObjectID = (ulong)local_2c[0]; - } - puVar3 = (undefined4 *)__cxa_allocate_exception(4,pOVar4); - *puVar3 = 10; - goto LAB_080904cb; - } - error("CheckDepotSpace: Ziel existiert nicht.\n"); - } - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = 0xffffffff; -LAB_080904cb: - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); -} - -void CheckInventoryPlace(ObjectType *Type,Object *Con,Object *OldObj) - -{ - uint uVar1; - bool bVar2; - int ClothesType; - ulong uVar3; - ulong uVar4; - ulong uVar5; - undefined4 *puVar6; - int Position; - int iVar7; - ulong uVar8; - undefined4 uVar9; - ulong local_ac; - Object Help; - Object local_9c [4]; - ulong local_8c [4]; - ulong local_7c; - ulong local_6c [4]; - ulong local_5c; - ulong local_4c [4]; - ulong local_3c; - Object local_2c [7]; - - local_2c[0] = (Object)Con->ObjectID; - // try { // try from 08090a00 to 08090e39 has its CatchHandler @ 08090ea0 - uVar3 = GetObjectBodyPosition(local_2c); - uVar1 = uVar3 - 5; - if ((1 < uVar1) && (uVar3 != 10)) { - bVar2 = ObjectType::getFlag(Type,CLOTHES); - if (!bVar2) { - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0xb; - goto LAB_08090c8d; - } - uVar4 = ObjectType::getAttribute(Type,BODYPOSITION); - if (uVar4 == 0) { - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0xc; - goto LAB_08090c8d; - } - if (uVar3 != uVar4) { - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0xd; - goto LAB_08090c8d; - } - } - local_2c[0] = (Object)Con->ObjectID; - uVar4 = GetObjectCreatureID(local_2c); - bVar2 = ObjectType::getFlag(Type,CLOTHES); - if (((!bVar2) || (uVar5 = ObjectType::getAttribute(Type,BODYPOSITION), uVar5 != 0)) || - (1 < uVar1)) { - bVar2 = false; - uVar5 = uVar4; - uVar8 = uVar3; - GetBodyObject((ulong)&local_ac,uVar4); - local_9c[0].ObjectID = NONE.ObjectID; - local_8c[0] = NONE.ObjectID; - if (local_ac != NONE.ObjectID) { - uVar5 = uVar4; - GetBodyObject((ulong)local_8c,uVar4); - local_7c = OldObj->ObjectID; - uVar8 = uVar3; - local_6c[0] = local_7c; - if (local_8c[0] != local_7c) { - bVar2 = true; - } - } - if (!bVar2) { - if (1 < uVar1) { - return; - } - iVar7 = 5; - do { - GetBodyObject((ulong)&local_ac,uVar4); - local_9c[0].ObjectID = NONE.ObjectID; - if ((local_ac != NONE.ObjectID) && - (local_9c[0] = (Object)OldObj->ObjectID, local_ac != local_9c[0].ObjectID)) { - Object::getObjectType(local_9c); - bVar2 = ObjectType::getFlag((ObjectType *)local_9c,CLOTHES); - if (bVar2) { - Object::getObjectType(local_9c); - uVar3 = ObjectType::getAttribute((ObjectType *)local_9c,BODYPOSITION); - if (uVar3 == 0) { - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0xf; - goto LAB_08090c8d; - } - } - bVar2 = ObjectType::getFlag(Type,WEAPON); - if (((bVar2) || (bVar2 = ObjectType::getFlag(Type,THROW), bVar2)) || - ((bVar2 = ObjectType::getFlag(Type,BOW), bVar2 || - (bVar2 = ObjectType::getFlag(Type,WAND), bVar2)))) { - Object::getObjectType(local_9c); - bVar2 = ObjectType::getFlag((ObjectType *)local_9c,WEAPON); - if (!bVar2) { - Object::getObjectType(local_9c); - bVar2 = ObjectType::getFlag((ObjectType *)local_9c,THROW); - if (!bVar2) { - Object::getObjectType(local_9c); - bVar2 = ObjectType::getFlag((ObjectType *)local_9c,BOW); - if (!bVar2) { - Object::getObjectType(local_9c); - bVar2 = ObjectType::getFlag((ObjectType *)local_9c,WAND); - if (!bVar2) goto LAB_08090b3f; - } - } - } - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0x10; - goto LAB_08090c8d; - } - } -LAB_08090b3f: - iVar7 = iVar7 + 1; - if (6 < iVar7) { - return; - } - } while( true ); - } - puVar6 = (undefined4 *)__cxa_allocate_exception(4,uVar5,uVar8); - *puVar6 = 4; - goto LAB_08090c8d; - } - bVar2 = false; - GetBodyObject((ulong)local_2c,uVar4); - local_3c = NONE.ObjectID; - local_4c[0] = NONE.ObjectID; - if (local_2c[0].ObjectID == NONE.ObjectID) { -LAB_08090dd4: - uVar9 = 6; - uVar3 = uVar4; - GetBodyObject((ulong)local_6c,uVar4); - local_7c = NONE.ObjectID; - local_8c[0] = NONE.ObjectID; - if (local_6c[0] != NONE.ObjectID) { - uVar9 = 6; - GetBodyObject((ulong)local_8c,uVar4); - local_ac = OldObj->ObjectID; - uVar3 = uVar4; - local_9c[0].ObjectID = local_ac; - if (local_8c[0] != local_ac) goto LAB_08090e56; - } - } - else { - uVar9 = 5; - uVar3 = uVar4; - GetBodyObject((ulong)local_4c,uVar4); - local_6c[0] = OldObj->ObjectID; - local_5c = local_6c[0]; - if (local_4c[0] == local_6c[0]) goto LAB_08090dd4; -LAB_08090e56: - bVar2 = true; - } - if (!bVar2) { - return; - } - puVar6 = (undefined4 *)__cxa_allocate_exception(4,uVar3,uVar9); - *puVar6 = 0xe; -LAB_08090c8d: - // WARNING: Subroutine does not return - __cxa_throw(puVar6,&RESULT::typeinfo,0); -} - - - -void CheckWeight(ulong CreatureID,Object *Obj,int Count) - -{ - TSkill *this; - bool bVar1; - ulong uVar2; - TCreature *pTVar3; - int iVar4; - int iVar5; - int iVar6; - undefined4 *puVar7; - TSkill *sk; - TCreature *cr; - Object local_2c [7]; - - local_2c[0] = (Object)Obj->ObjectID; - // try { // try from 08090ee0 to 08091075 has its CatchHandler @ 08091078 - uVar2 = GetObjectCreatureID(local_2c); - if (uVar2 == CreatureID) { - return; - } - pTVar3 = GetCreature(CreatureID); - if (pTVar3 == (TCreature *)0x0) { - error("CheckWeight: Kreatur %d existiert nicht.\n",CreatureID); -LAB_08091005: - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 0xffffffff; - } - else { - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,TAKE); - if (bVar1) { - if (pTVar3->Type == PLAYER) { - bVar1 = CheckRight(CreatureID,UNLIMITED_CAPACITY); - if (bVar1) { - return; - } - if ((pTVar3->Type == PLAYER) && - (bVar1 = CheckRight(CreatureID,ZERO_CAPACITY), bVar1)) goto LAB_08090fbd; - } - this = (pTVar3->super_TSkillBase).Skills[5]; - if (this == (TSkill *)0x0) { - error("CheckWeight: Skill CARRYSTRENGTH existiert nicht.\n"); - goto LAB_08091005; - } - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CUMULATIVE); - if (bVar1) { - local_2c[0] = (Object)Obj->ObjectID; - iVar4 = GetWeight(local_2c,Count); - } - else { - cr = (TCreature *)Obj->ObjectID; - iVar4 = GetCompleteWeight((Object *)&cr); - } - iVar5 = GetInventoryWeight(CreatureID); - iVar6 = TSkill::Get(this); - if (iVar4 + iVar5 <= iVar6 * 100) { - return; - } - } -LAB_08090fbd: - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 8; - } - // WARNING: Subroutine does not return - __cxa_throw(puVar7,&RESULT::typeinfo,0); -} - - - -// WARNING: Variable defined which should be unmapped: sk - -void CheckWeight(ulong CreatureID,ObjectType *Type,ulong Data,int oldWeight) - -{ - TSkill *this; - bool bVar1; - TCreature *pTVar2; - ulong uVar3; - int iVar4; - int iVar5; - undefined4 *puVar6; - TCreature *cr; - TSkill *sk; - - // try { // try from 080910a8 to 080911f2 has its CatchHandler @ 080911f5 - pTVar2 = GetCreature(CreatureID); - if (pTVar2 == (TCreature *)0x0) { - error("CheckWeight: Kreatur %d existiert nicht.\n",CreatureID); -LAB_0809118c: - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0xffffffff; - } - else { - bVar1 = ObjectType::getFlag(Type,TAKE); - if (bVar1) { - if (pTVar2->Type == PLAYER) { - bVar1 = CheckRight(CreatureID,UNLIMITED_CAPACITY); - if (bVar1) { - return; - } - if ((pTVar2->Type == PLAYER) && - (bVar1 = CheckRight(CreatureID,ZERO_CAPACITY), bVar1)) goto LAB_08091156; - } - this = (pTVar2->super_TSkillBase).Skills[5]; - if (this == (TSkill *)0x0) { - error("CheckWeight: Skill CARRYSTRENGTH existiert nicht.\n"); - goto LAB_0809118c; - } - uVar3 = ObjectType::getAttribute(Type,WEIGHT); - bVar1 = ObjectType::getFlag(Type,CUMULATIVE); - if ((bVar1) && (1 < Data)) { - uVar3 = Data * uVar3; - } - if ((int)uVar3 <= oldWeight) { - return; - } - iVar4 = GetInventoryWeight(CreatureID); - iVar5 = TSkill::Get(this); - if ((int)(uVar3 + iVar4) <= oldWeight + iVar5 * 100) { - return; - } - } -LAB_08091156: - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 8; - } - // WARNING: Subroutine does not return - __cxa_throw(puVar6,&RESULT::typeinfo,0); -} - - - -void __regparm1 NotifyCreature(ulong CreatureID,Object *Obj,bool Inventory) - -{ - bool bVar1; - TCreature *this; - undefined3 in_stack_00000009; - char in_stack_0000000c; - TCreature *cr; - Object OStack_2c; - bool Inventory_local; - - if (Obj != (Object *)0x0) { - Object::getObjectType(&stack0xffffffd4); - if (OStack_2c.ObjectID != 99) { - this = GetCreature((ulong)Obj); - if (this == (TCreature *)0x0) { - error("NotifyCreature: Kreatur existiert nicht.\n",_Inventory); - } - else { - Object::getObjectType(&stack0xffffffd4); - bVar1 = ObjectType::getFlag((ObjectType *)&stack0xffffffd4,LIGHT); - if ((bVar1) && (in_stack_0000000c != '\0')) { - AnnounceChangedCreature((ulong)Obj,2); - } - TCreature::NotifyChangeInventory(this); - } - } - } - return; -} - - - -// WARNING: Variable defined which should be unmapped: Inventory_local - -void __regparm3 NotifyCreature(ulong CreatureID,ObjectType *Type,bool Inventory) - -{ - bool bVar1; - TCreature *this; - TCreature *cr; - ulong in_stack_00000004; - ObjectType *in_stack_00000008; - char in_stack_0000000c; - bool Inventory_local; - - if (in_stack_00000004 == 0) { - return; - } - this = GetCreature(in_stack_00000004); - if (this != (TCreature *)0x0) { - bVar1 = ObjectType::getFlag(in_stack_00000008,LIGHT); - if ((bVar1) && (in_stack_0000000c != '\0')) { - AnnounceChangedCreature(in_stack_00000004,2); - } - TCreature::NotifyChangeInventory(this); - return; - } - error("NotifyCreature: Kreatur existiert nicht.\n"); - return; -} - - - -void NotifyAllCreatures(Object *Obj,int Type,Object *OldCon) - -{ - bool bVar1; - ulong uVar2; - ulong uVar3; - TCreature *pTVar4; - uint uVar5; - uint uVar6; - char *Text; - int local_a4; - int oldx; - int oldy; - int oldz; - int x; - int y; - int z; - TFindCreatures Search; - undefined1 local_5c [4]; - TFindCreatures Search1; - Object local_2c [7]; - - bVar1 = Object::exists(Obj); - if (bVar1) { - Object::getObjectType(local_2c); - if (local_2c[0].ObjectID != 99) { - return; - } - if (Type != 3) { - local_2c[0] = (Object)Obj->ObjectID; - TFindCreatures::TFindCreatures((TFindCreatures *)&z,10,10,local_2c,7); - while (uVar2 = TFindCreatures::getNext((TFindCreatures *)&z), uVar2 != 0) { - uVar3 = Object::getCreatureID(Obj); - pTVar4 = GetCreature(uVar2); - (*pTVar4->_vptr_TCreature[9])(pTVar4,uVar3,Type); - } - return; - } - bVar1 = Object::exists(OldCon); - if (bVar1) { - local_2c[0] = (Object)Obj->ObjectID; - GetObjectCoordinates(local_2c,&oldz,&x,&y); - local_2c[0] = (Object)OldCon->ObjectID; - GetObjectCoordinates(local_2c,&local_a4,&oldx,&oldy); - uVar5 = oldz - local_a4; - if (0x7fffffff < uVar5) { - uVar5 = -uVar5; - } - if ((int)uVar5 < 0x15) { - uVar5 = x - oldx; - if (0x7fffffff < uVar5) { - uVar5 = -uVar5; - } - if ((int)uVar5 < 0x15) { - uVar5 = x - oldx; - if (0x7fffffff < uVar5) { - uVar5 = -uVar5; - } - uVar6 = oldz - local_a4; - if (0x7fffffff < uVar6) { - uVar6 = -uVar6; - } - TFindCreatures::TFindCreatures - ((TFindCreatures *)&z,(int)(uVar6 + 1) / 2 + 10, - (int)(uVar5 + 1) / 2 + 10,(oldz + local_a4) / 2,(oldx + x) / 2,7); - while (uVar2 = TFindCreatures::getNext((TFindCreatures *)&z), uVar2 != 0) { - uVar3 = Object::getCreatureID(Obj); - pTVar4 = GetCreature(uVar2); - (*pTVar4->_vptr_TCreature[9])(pTVar4,uVar3,2); - } - return; - } - } - TFindCreatures::TFindCreatures((TFindCreatures *)local_5c,10,10,local_a4,oldx,7); - while (uVar2 = TFindCreatures::getNext((TFindCreatures *)local_5c), uVar2 != 0) { - uVar3 = Object::getCreatureID(Obj); - pTVar4 = GetCreature(uVar2); - (*pTVar4->_vptr_TCreature[9])(pTVar4,uVar3,2); - } - TFindCreatures::TFindCreatures((TFindCreatures *)&z,10,10,oldz,x,7); - while (uVar2 = TFindCreatures::getNext((TFindCreatures *)&z), uVar2 != 0) { - uVar3 = Object::getCreatureID(Obj); - pTVar4 = GetCreature(uVar2); - (*pTVar4->_vptr_TCreature[9])(pTVar4,uVar3,2); - } - return; - } - Text = &DAT_080ff300; - } - else { - Text = &DAT_080ff2c0; - } - error(Text); - return; -} - - - -void NotifyTrades(Object *Obj) - -{ - bool bVar1; - ulong ID; - ulong CharacterID; - TPlayer *this; - TPlayer *pl; - TPlayer *pTVar2; - char *pcVar3; - Object *Obj_00; - Object OStack_8c; - bool Affected; - Object Help_1; - Object local_7c [4]; - Object local_6c; - Object Help; - undefined1 local_5c [4]; - TFindCreatures Search; - Object local_2c; - Object TradeObject; - - bVar1 = Object::exists(Obj); - if (bVar1) { - Object::getObjectType(&local_2c); - if (local_2c.ObjectID != 99) { - Obj_00 = &local_2c; - local_2c = (Object)Obj->ObjectID; - pcVar3 = (char *)0xa; - pTVar2 = (TPlayer *)0xc; - TFindCreatures::TFindCreatures((TFindCreatures *)local_5c,0xc,10,Obj_00,1); -LAB_08091720: - CharacterID = TFindCreatures::getNext((TFindCreatures *)local_5c); - if (CharacterID != 0) { - this = GetPlayer(CharacterID); - if (this == (TPlayer *)0x0) { - error("NotifyTrade: Spieler existiert nicht.\n",pTVar2,pcVar3,Obj_00); - } - else { - Obj_00 = (Object *)0x0; - pcVar3 = (char *)0x1; - pTVar2 = this; - TPlayer::InspectTrade((TPlayer *)&local_2c,SUB41(this,0),1); - local_6c = (Object)NONE.ObjectID; - if (local_2c.ObjectID != NONE.ObjectID) { - local_6c = (Object)Obj->ObjectID; - bVar1 = local_2c.ObjectID == local_6c.ObjectID; - if (!bVar1) { - while( true ) { - Object::getObjectType(local_7c); - if (local_7c[0].ObjectID == 0) break; - local_7c[0].ObjectID = local_6c.ObjectID; - if (local_2c.ObjectID == local_6c.ObjectID) { - bVar1 = true; - } - Object::getContainer(&stack0xffffff74); - local_7c[0].ObjectID = OStack_8c.ObjectID; - local_6c.ObjectID = OStack_8c.ObjectID; - } - if (!bVar1) { - OStack_8c.ObjectID = local_2c.ObjectID; - while( true ) { - pTVar2 = (TPlayer *)&stack0xffffff74; - Object::getObjectType(local_7c); - if (local_7c[0].ObjectID == 0) break; - local_7c[0] = (Object)Obj->ObjectID; - if (OStack_8c.ObjectID == local_7c[0].ObjectID) { - bVar1 = true; - } - Object::getContainer(&local_6c); - OStack_8c.ObjectID = local_6c.ObjectID; - local_7c[0].ObjectID = OStack_8c.ObjectID; - } - if (!bVar1) goto LAB_08091720; - } - } - SendCloseTrade((this->super_TCreature).Connection); - pcVar3 = "Trade cancelled."; - pTVar2 = (TPlayer *)0x17; - SendMessage((this->super_TCreature).Connection,0x17,"Trade cancelled."); - TPlayer::RejectTrade(this); - } - } - goto LAB_08091720; - } - } - } - else { - error(&DAT_080ff360); - } - return; -} - - - -void NotifyDepot(ulong CreatureID,Object *Obj,int Count) - -{ - bool bVar1; - TCreature *pTVar2; - undefined4 *puVar3; - TCreature *cr; - Object local_3c [4]; - Object local_2c [7]; - - if (CreatureID != 0) { - pTVar2 = GetCreature(CreatureID); - if (pTVar2 == (TCreature *)0x0) { - error("NotifyDepot: Kreatur %lu existiert nicht.\n",CreatureID); - } - else { - bVar1 = Object::exists(Obj); - if (!bVar1) { - error("NotifyDepot: Objekt existiert nicht.\n"); - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); - } - if ((pTVar2->Type == PLAYER) && - (local_2c[0].ObjectID = NONE.ObjectID, - pTVar2[1].super_TSkillBase.TimerList[6] != (TSkill *)NONE.ObjectID)) { - while (Object::getObjectType(local_2c), local_2c[0].ObjectID != 0) { - local_2c[0].ObjectID = (ulong)pTVar2[1].super_TSkillBase.TimerList[6]; - if ((TSkill *)Obj->ObjectID == (TSkill *)local_2c[0].ObjectID) { - pTVar2[1].super_TSkillBase.TimerList[8] = - (TSkill *) - ((int)&pTVar2[1].super_TSkillBase.TimerList[8]->_vptr_TSkill + Count); - print(); - return; - } - Object::getContainer(local_3c); - local_2c[0].ObjectID = local_3c[0].ObjectID; - Obj->ObjectID = (ulong)local_3c[0]; - } - } - } - } - return; -} - - - -void CloseContainer(Object *Con,bool Force) - -{ - bool bVar1; - bool bVar2; - ulong ID; - ulong CharacterID; - TPlayer *this; - int con; - int ContNr; - bool Affected; - TPlayer *pl; - Object OStack_7c; - bool Force_local; - Object local_6c [4]; - undefined1 local_5c [4]; - TFindCreatures Search; - _func_int_varargs **local_2c; - Object Obj; - - bVar2 = Object::exists(Con); - if (bVar2) { - Object::getObjectType((Object *)&local_2c); - if (local_2c != (_func_int_varargs **)0x63) { - local_2c = (_func_int_varargs **)Con->ObjectID; - TFindCreatures::TFindCreatures((TFindCreatures *)local_5c,0xc,10,(Object *)&local_2c,1); - while (CharacterID = TFindCreatures::getNext((TFindCreatures *)local_5c), - CharacterID != 0) { - this = GetPlayer(CharacterID); - if (this == (TPlayer *)0x0) { - error("CloseContainer: Spieler existiert nicht.\n"); - } - else { - ContNr = 0; - do { - bVar2 = false; - TPlayer::GetOpenContainer((TPlayer *)&local_2c,(int)this); - while( true ) { - bVar1 = false; - local_6c[0].ObjectID = NONE.ObjectID; - OStack_7c.ObjectID = NONE.ObjectID; - if ((local_2c != (_func_int_varargs **)NONE.ObjectID) && - (Object::getObjectType(&stack0xffffff84), OStack_7c.ObjectID != 0)) { - bVar1 = true; - } - if (!bVar1) break; - OStack_7c = (Object)Con->ObjectID; - if (local_2c == (_func_int_varargs **)OStack_7c.ObjectID) { - bVar2 = true; - } - Object::getContainer(local_6c); - local_2c = (_func_int_varargs **)local_6c[0].ObjectID; - } - if (bVar2) { - if (!Force) { - OStack_7c = (Object)Con->ObjectID; - bVar2 = ObjectAccessible((this->super_TCreature).ID,&stack0xffffff84 - ,1); - if (bVar2) { - SendContainer((this->super_TCreature).Connection,ContNr); - goto LAB_08091b89; - } - } - local_6c[0].ObjectID = NONE.ObjectID; - TPlayer::SetOpenContainer(this,ContNr,local_6c); - SendCloseContainer((this->super_TCreature).Connection,ContNr); - } -LAB_08091b89: - ContNr = ContNr + 1; - } while (ContNr < 0x10); - } - } - } - } - else { - error(&DAT_080ff4a0); - } - return; -} - - - -Object Create(Object *Con,ObjectType *Type,ulong Value) - -{ - bool bVar1; - ulong uVar2; - TCreature *this; - undefined4 *puVar3; - int _TypeID; - ulong in_stack_00000010; - char *Text; - ulong newCreature; - int x; - int y; - int z; - Object Obj; - Object local_5c [4]; - Object local_4c; - Object Top; - Object local_3c [4]; - Object local_2c [7]; - - // try { // try from 08091c0b to 0809230e has its CatchHandler @ 08092330 - bVar1 = Object::exists((Object *)Type); - if (bVar1) { - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CONTAINER); - if (!bVar1) { - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CHEST); - if (!bVar1) { - Text = "Create: Zielobjekt ist kein Container.\n"; - goto LAB_080922e0; - } - } - ObjectType::setTypeID((ObjectType *)local_2c,0); - if (*(ulong *)Value != local_2c[0].ObjectID) { - Object::getObjectType(local_2c); - if (local_2c[0].ObjectID == 0) { - local_2c[0].ObjectID = Type->TypeID; - ObjectType::setTypeID((ObjectType *)local_3c,*(int *)Value); - CheckMapPlace(0,(ObjectType *)local_3c,local_2c); - } - else { - Object::getObjectType(local_3c); - bVar1 = false; - if ((0 < (int)local_3c[0].ObjectID) && ((int)local_3c[0].ObjectID < 0xb)) { - bVar1 = true; - } - if (bVar1) { - local_4c.ObjectID = NONE.ObjectID; - local_3c[0].ObjectID = Type->TypeID; - ObjectType::setTypeID((ObjectType *)local_2c,*(int *)Value); - CheckInventoryPlace((ObjectType *)local_2c,local_3c,&local_4c); - } - else { - local_3c[0].ObjectID = NONE.ObjectID; - local_2c[0].ObjectID = Type->TypeID; - ObjectType::setTypeID((ObjectType *)&local_4c,*(int *)Value); - CheckContainerPlace((ObjectType *)&local_4c,local_2c,local_3c); - } - local_4c.ObjectID = Type->TypeID; - uVar2 = GetObjectCreatureID(&local_4c); - if (uVar2 != 0) { - ObjectType::setTypeID((ObjectType *)&local_4c,*(int *)Value); - CheckWeight(uVar2,(ObjectType *)&local_4c,in_stack_00000010,0); - } - } - Object::getObjectType(&local_4c); - if ((local_4c.ObjectID == 0) && - (bVar1 = ObjectType::getFlag((ObjectType *)Value,CUMULATIVE), bVar1)) { - if (in_stack_00000010 == 0) { - in_stack_00000010 = 1; - } - local_4c.ObjectID = Type->TypeID; - GetObjectCoordinates(&local_4c,(int *)&newCreature,&x,&y); - GetTopObject((int)&local_4c,newCreature,x,(bool)(undefined1)y); - bVar1 = false; - local_3c[0].ObjectID = NONE.ObjectID; - local_2c[0].ObjectID = NONE.ObjectID; - if (local_4c.ObjectID != NONE.ObjectID) { - Object::getObjectType(local_2c); - ObjectType::setTypeID((ObjectType *)local_5c,*(int *)Value); - if ((local_2c[0].ObjectID == local_5c[0].ObjectID) && - (uVar2 = Object::getAttribute(&local_4c,AMOUNT), - uVar2 + in_stack_00000010 < 0x65)) { - bVar1 = true; - } - } - if (bVar1) { - uVar2 = Object::getAttribute(&local_4c,AMOUNT); - z = local_4c.ObjectID; - Change((Object *)&z,AMOUNT,uVar2 + in_stack_00000010); - Con->ObjectID = (ulong)local_4c; - return (Object)(ulong)Con; - } - } - ObjectType::setTypeID((ObjectType *)local_5c,*(int *)Value); - local_4c.ObjectID = Type->TypeID; - SetObject((Object *)&z,(ObjectType *)&local_4c,(ulong)local_5c); - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,CUMULATIVE); - if (bVar1) { - local_5c[0].ObjectID = z; - ChangeObject(local_5c,AMOUNT,in_stack_00000010); - } - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,MAGICFIELD); - if (bVar1) { - local_5c[0].ObjectID = z; - ChangeObject(local_5c,RESPONSIBLE,in_stack_00000010); - } - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,LIQUIDPOOL); - if (bVar1) { - local_5c[0].ObjectID = z; - ChangeObject(local_5c,POOLLIQUIDTYPE,in_stack_00000010); - } - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,LIQUIDCONTAINER); - if (bVar1) { - local_5c[0].ObjectID = z; - ChangeObject(local_5c,CONTAINERLIQUIDTYPE,in_stack_00000010); - } - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,KEY); - if (bVar1) { - local_5c[0].ObjectID = z; - ChangeObject(local_5c,KEYNUMBER,in_stack_00000010); - } - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,RUNE); - if (bVar1) { - local_5c[0].ObjectID = z; - ChangeObject(local_5c,CHARGES,in_stack_00000010); - } - if (*(int *)Value != 99) { -LAB_08091e32: - local_5c[0].ObjectID = z; - AnnounceChangedObject(local_5c,1); - local_5c[0].ObjectID = z; - NotifyTrades(local_5c); - Object::getContainer(local_5c); - Object::getObjectType(&local_4c); - local_4c.ObjectID = z; - local_3c[0].ObjectID = z; - uVar2 = GetObjectCreatureID(local_3c); - NotifyCreature(uVar2,(Object *)uVar2,SUB41(&local_4c,0)); - Object::getContainer(local_5c); - Object::getContainer(&local_4c); - local_3c[0].ObjectID = z; - MovementEvent(local_3c,&local_4c,local_5c); - Object::getContainer(local_5c); - local_4c.ObjectID = z; - CollisionEvent(&local_4c,local_5c); - local_5c[0].ObjectID = NONE.ObjectID; - local_4c.ObjectID = z; - NotifyAllCreatures(&local_4c,1,local_5c); - Con->ObjectID = z; - return (Object)(ulong)Con; - } - this = GetCreature(in_stack_00000010); - if (this != (TCreature *)0x0) { - _TypeID = 10; - do { - ObjectType::setTypeID((ObjectType *)&local_4c,_TypeID); - local_3c[0].ObjectID = z; - SetObject(local_5c,(ObjectType *)local_3c,(ulong)&local_4c); - _TypeID = _TypeID + -1; - } while (0 < _TypeID); - local_5c[0].ObjectID = z; - local_3c[0].ObjectID = z; - (this->CrObject).ObjectID = z; - local_4c.ObjectID = z; - TCreature::NotifyCreate(this); - goto LAB_08091e32; - } - error(&DAT_080ff520,in_stack_00000010); - local_5c[0].ObjectID = z; - Delete(local_5c,-1); - goto LAB_08091ff4; - } - Text = "Create: Objekttyp existiert nicht.\n"; - } - else { - Text = "Create: Zielobjekt existiert nicht.\n"; - } -LAB_080922e0: - error(Text); -LAB_08091ff4: - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); -} - - - -Object Copy(Object *Con,Object *Source) - -{ - bool bVar1; - ulong uVar2; - undefined4 *puVar3; - ulong newCreature; - Object *Obj; - Object *in_stack_0000000c; - char *Text; - Object local_5c [4]; - Object local_4c [4]; - Object local_3c; - Object Help; - Object local_2c [7]; - - // try { // try from 08092368 to 08092715 has its CatchHandler @ 08092730 - bVar1 = Object::exists(Obj); - if (bVar1) { - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CONTAINER); - if (!bVar1) { - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CHEST); - if (!bVar1) { - Text = "Copy: Ziel ist kein Container.\n"; - goto LAB_080926bf; - } - } - bVar1 = Object::exists(in_stack_0000000c); - if (bVar1) { - Object::getObjectType(local_2c); - if (local_2c[0].ObjectID != 99) { - Object::getObjectType(local_2c); - if (local_2c[0].ObjectID == 0) { - local_2c[0] = (Object)Obj->ObjectID; - local_3c.ObjectID = in_stack_0000000c->ObjectID; - CheckMapDestination(0,&local_3c,local_2c); - } - else { - local_3c = (Object)Obj->ObjectID; - uVar2 = GetObjectCreatureID(&local_3c); - if (uVar2 != 0) { - local_3c.ObjectID = in_stack_0000000c->ObjectID; - CheckWeight(uVar2,&local_3c,-1); - } - Object::getObjectType(&local_3c); - bVar1 = false; - if ((0 < (int)local_3c.ObjectID) && ((int)local_3c.ObjectID < 0xb)) { - bVar1 = true; - } - if (bVar1) { - local_3c = (Object)Obj->ObjectID; - local_2c[0].ObjectID = in_stack_0000000c->ObjectID; - CheckInventoryDestination(local_2c,&local_3c,true); - } - else { - local_3c = (Object)Obj->ObjectID; - local_2c[0].ObjectID = in_stack_0000000c->ObjectID; - CheckContainerDestination(local_2c,&local_3c); - } - } - local_3c.ObjectID = in_stack_0000000c->ObjectID; - local_2c[0] = (Object)Obj->ObjectID; - CopyObject(Con,local_2c); - Object::getObjectType(&local_3c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_3c,CONTAINER); - if (bVar1) { - local_2c[0].ObjectID = in_stack_0000000c->ObjectID; - GetFirstContainerObject(&local_3c); - local_4c[0] = (Object)NONE.ObjectID; - local_2c[0].ObjectID = local_4c[0].ObjectID; - if (local_3c.ObjectID != NONE.ObjectID) { - do { - local_5c[0] = (Object)Con->ObjectID; - local_4c[0].ObjectID = NONE.ObjectID; - local_2c[0].ObjectID = local_3c.ObjectID; - Copy(local_4c,local_5c); - Object::getNextObject(local_4c); - local_3c.ObjectID = local_4c[0].ObjectID; - bVar1 = local_4c[0].ObjectID != NONE.ObjectID; - local_2c[0].ObjectID = NONE.ObjectID; - local_4c[0].ObjectID = NONE.ObjectID; - } while (bVar1); - } - } - local_5c[0] = (Object)Con->ObjectID; - AnnounceChangedObject(local_5c,1); - local_5c[0] = (Object)Con->ObjectID; - NotifyTrades(local_5c); - Object::getContainer(local_5c); - Object::getObjectType(local_4c); - local_4c[0] = (Object)Con->ObjectID; - local_3c.ObjectID = local_4c[0].ObjectID; - uVar2 = GetObjectCreatureID(&local_3c); - NotifyCreature(uVar2,(Object *)uVar2,SUB41(local_4c,0)); - Object::getContainer(local_5c); - Object::getContainer(local_4c); - local_3c = (Object)Con->ObjectID; - MovementEvent(&local_3c,local_4c,local_5c); - Object::getContainer(local_5c); - local_4c[0] = (Object)Con->ObjectID; - CollisionEvent(local_4c,local_5c); - local_5c[0].ObjectID = NONE.ObjectID; - local_4c[0] = (Object)Con->ObjectID; - NotifyAllCreatures(local_4c,1,local_5c); - return (Object)(ulong)Con; - } - Text = "Copy: Quelle ist eine Kreatur.\n"; - } - else { - Text = "Copy: Quelle existiert nicht.\n"; - } - } - else { - Text = "Copy: Ziel existiert nicht.\n"; - } -LAB_080926bf: - error(Text); - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); -} - -void Change(Object *Obj,ObjectType *NewType,ulong Value) - -{ - bool bVar1; - bool bVar2; - ulong uVar3; - int iVar4; - undefined4 *puVar5; - ulong Data; - char *pcVar6; - Object OVar7; - ulong Creature; - Object local_7c; - ObjectType OldType; - Object local_6c [4]; - Object local_5c [4]; - Object local_4c [4]; - Object local_3c [4]; - Object local_2c [7]; - - // try { // try from 0809370b to 08093ef9 has its CatchHandler @ 08093f30 - bVar1 = Object::exists(Obj); - if (bVar1) { - Object::getObjectType(local_2c); - if ((local_2c[0].ObjectID == 99) || (NewType->TypeID == 99)) { - pcVar6 = &DAT_080ffa00; - } - else { - ObjectType::setTypeID((ObjectType *)local_2c,0); - if (NewType->TypeID == local_2c[0].ObjectID) { - local_3c[0] = (Object)Obj->ObjectID; - Delete(local_3c,-1); - return; - } - Object::getObjectType(local_3c); - bVar1 = ObjectType::getFlag((ObjectType *)local_3c,CONTAINER); - if (bVar1) { - bVar1 = ObjectType::getFlag(NewType,CONTAINER); - if (!bVar1) { - local_2c[0] = (Object)Obj->ObjectID; - GetFirstContainerObject(local_3c); - local_5c[0] = (Object)NONE.ObjectID; - local_4c[0].ObjectID = NONE.ObjectID; - if (local_3c[0].ObjectID == NONE.ObjectID) goto LAB_08093e33; - Object::getObjectType(local_5c); - iVar4 = NewType->TypeID; - pcVar6 = &DAT_080ff9c0; - OVar7.ObjectID = local_5c[0].ObjectID; -LAB_08093e9d: - error(pcVar6,iVar4,OVar7.ObjectID); - puVar5 = (undefined4 *)__cxa_allocate_exception(4); - *puVar5 = 0x14; - goto LAB_08093d62; - } -LAB_08093e33: - bVar1 = ObjectType::getFlag(NewType,CONTAINER); - if (bVar1) { - uVar3 = ObjectType::getAttribute(NewType,CAPACITY); - local_5c[0] = (Object)Obj->ObjectID; - iVar4 = CountObjectsInContainer(local_5c); - if ((int)uVar3 < iVar4) { - Object::getObjectType(local_4c); - iVar4 = NewType->TypeID; - pcVar6 = &DAT_080ff980; - OVar7.ObjectID = local_4c[0].ObjectID; - goto LAB_08093e9d; - } - } - } - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,CHEST); - if ((!bVar1) || (bVar1 = ObjectType::getFlag(NewType,CHEST), bVar1)) { - bVar1 = false; - Object::getObjectType(local_5c); - bVar2 = ObjectType::getFlag((ObjectType *)local_5c,CUMULATIVE); - if (bVar2) { - Object::getObjectType(local_5c); - ObjectType::setTypeID((ObjectType *)local_4c,NewType->TypeID); - ObjectType::setTypeID((ObjectType *)local_3c,local_4c[0].ObjectID); - if ((local_5c[0].ObjectID != local_3c[0].ObjectID) && - (uVar3 = Object::getAttribute(Obj,AMOUNT), 1 < uVar3)) { - bVar1 = true; - } - } - if (!bVar1) { - local_5c[0] = (Object)Obj->ObjectID; - uVar3 = GetObjectCreatureID(local_5c); - if (uVar3 != 0) { - Object::getObjectType(local_5c); - ObjectType::setTypeID((ObjectType *)local_4c,NewType->TypeID); - ObjectType::setTypeID((ObjectType *)local_3c,local_4c[0].ObjectID); - if (local_5c[0].ObjectID != local_3c[0].ObjectID) { - Object::getContainer(local_3c); - Object::getObjectType(local_2c); - bVar1 = false; - if ((0 < (int)local_2c[0].ObjectID) && ((int)local_2c[0].ObjectID < 0xb) - ) { - bVar1 = true; - } - if (bVar1) { - local_7c = (Object)Obj->ObjectID; - ObjectType::setTypeID((ObjectType *)local_6c,NewType->TypeID); - Object::getContainer(local_2c); - CheckInventoryPlace((ObjectType *)local_6c,local_2c,&local_7c); - } - else { - local_2c[0] = (Object)Obj->ObjectID; - ObjectType::setTypeID((ObjectType *)local_6c,NewType->TypeID); - Object::getContainer(&local_7c); - CheckContainerPlace((ObjectType *)local_6c,&local_7c,local_2c); - } - local_7c = (Object)Obj->ObjectID; - iVar4 = GetWeight(&local_7c,-1); - Object::getObjectType(local_6c); - bVar1 = ObjectType::getFlag((ObjectType *)local_6c,CUMULATIVE); - if (bVar1) { - Data = Object::getAttribute(Obj,AMOUNT); - } - else { - Data = 1; - } - ObjectType::setTypeID((ObjectType *)local_6c,NewType->TypeID); - CheckWeight(uVar3,(ObjectType *)local_6c,Data,iVar4); - } - } - Object::getObjectType(&local_7c); - Object::getObjectType(local_6c); - bVar1 = ObjectType::getFlag((ObjectType *)local_6c,CONTAINER); - if ((bVar1) && (bVar1 = ObjectType::getFlag(NewType,CONTAINER), !bVar1)) { - local_6c[0] = (Object)Obj->ObjectID; - CloseContainer(local_6c,true); - } - ObjectType::setTypeID((ObjectType *)local_6c,NewType->TypeID); - local_5c[0] = (Object)Obj->ObjectID; - ChangeObject(local_5c,(ObjectType *)local_6c); - Object::getObjectType(local_6c); - bVar1 = ObjectType::getFlag((ObjectType *)local_6c,CUMULATIVE); - if ((bVar1) && - (bVar1 = ObjectType::getFlag((ObjectType *)&local_7c,CUMULATIVE), !bVar1)) { - local_6c[0] = (Object)Obj->ObjectID; - ChangeObject(local_6c,AMOUNT,Value); - } - Object::getObjectType(local_6c); - bVar1 = ObjectType::getFlag((ObjectType *)local_6c,MAGICFIELD); - if ((bVar1) && - (bVar1 = ObjectType::getFlag((ObjectType *)&local_7c,MAGICFIELD), !bVar1)) { - local_6c[0] = (Object)Obj->ObjectID; - ChangeObject(local_6c,RESPONSIBLE,Value); - } - Object::getObjectType(local_6c); - bVar1 = ObjectType::getFlag((ObjectType *)local_6c,LIQUIDPOOL); - if ((bVar1) && - (bVar1 = ObjectType::getFlag((ObjectType *)&local_7c,LIQUIDPOOL), !bVar1)) { - local_6c[0] = (Object)Obj->ObjectID; - ChangeObject(local_6c,POOLLIQUIDTYPE,Value); - } - Object::getObjectType(local_6c); - bVar1 = ObjectType::getFlag((ObjectType *)local_6c,LIQUIDCONTAINER); - if ((bVar1) && - (bVar1 = ObjectType::getFlag((ObjectType *)&local_7c,LIQUIDCONTAINER), !bVar1 - )) { - local_6c[0] = (Object)Obj->ObjectID; - ChangeObject(local_6c,CONTAINERLIQUIDTYPE,Value); - } - Object::getObjectType(local_6c); - bVar1 = ObjectType::getFlag((ObjectType *)local_6c,KEY); - if ((bVar1) && - (bVar1 = ObjectType::getFlag((ObjectType *)&local_7c,KEY), !bVar1)) { - local_6c[0] = (Object)Obj->ObjectID; - ChangeObject(local_6c,KEYNUMBER,Value); - } - Object::getObjectType(local_6c); - bVar1 = ObjectType::getFlag((ObjectType *)local_6c,RUNE); - if ((bVar1) && - (bVar1 = ObjectType::getFlag((ObjectType *)&local_7c,RUNE), !bVar1)) { - local_6c[0] = (Object)Obj->ObjectID; - ChangeObject(local_6c,CHARGES,Value); - } - local_6c[0] = (Object)Obj->ObjectID; - AnnounceChangedObject(local_6c,2); - local_6c[0] = (Object)Obj->ObjectID; - NotifyTrades(local_6c); - Object::getContainer(local_6c); - Object::getObjectType(local_5c); - local_5c[0] = (Object)Obj->ObjectID; - local_4c[0].ObjectID = local_5c[0].ObjectID; - uVar3 = GetObjectCreatureID(local_4c); - NotifyCreature(uVar3,(Object *)uVar3,SUB41(local_5c,0)); - local_6c[0].ObjectID = NONE.ObjectID; - local_5c[0] = (Object)Obj->ObjectID; - NotifyAllCreatures(local_5c,2,local_6c); - return; - } - puVar5 = (undefined4 *)__cxa_allocate_exception(4); - *puVar5 = 0x15; - goto LAB_08093d62; - } - pcVar6 = &DAT_080ff940; - } - } - else { - pcVar6 = &DAT_080ffa40; - } - error(pcVar6); - puVar5 = (undefined4 *)__cxa_allocate_exception(4); - *puVar5 = 0xffffffff; -LAB_08093d62: - // WARNING: Subroutine does not return - __cxa_throw(puVar5,&RESULT::typeinfo,0); -} - - - -void Change(Object *Obj,INSTANCEATTRIBUTE Attribute,ulong Value) - -{ - bool bVar1; - ulong uVar2; - ulong uVar3; - int oldWeight; - undefined4 *puVar4; - ulong Creature; - Object local_3c [4]; - Object local_2c [7]; - - // try { // try from 08093f6b to 0809414b has its CatchHandler @ 08094150 - bVar1 = Object::exists(Obj); - if (bVar1) { - if ((((CHESTQUESTNUMBER < Attribute) && (Attribute != DOORLEVEL)) && - (Attribute != DOORQUESTNUMBER)) && - (((Attribute != DOORQUESTVALUE && (Attribute != ABSTELEPORTDESTINATION)) && - (Attribute != REMAININGEXPIRETIME)))) { - local_2c[0] = (Object)Obj->ObjectID; - uVar2 = GetObjectCreatureID(local_2c); - if (((uVar2 != 0) && (Attribute == AMOUNT)) && - (uVar3 = Object::getAttribute(Obj,AMOUNT), uVar3 < Value)) { - local_2c[0] = (Object)Obj->ObjectID; - oldWeight = GetWeight(local_2c,-1); - Object::getObjectType(local_3c); - CheckWeight(uVar2,(ObjectType *)local_3c,Value,oldWeight); - } - local_3c[0] = (Object)Obj->ObjectID; - ChangeObject(local_3c,Attribute,Value); - if (((Attribute == AMOUNT) || (Attribute == CONTAINERLIQUIDTYPE)) || - (Attribute == POOLLIQUIDTYPE)) { - local_3c[0] = (Object)Obj->ObjectID; - AnnounceChangedObject(local_3c,2); - } - local_3c[0] = (Object)Obj->ObjectID; - NotifyTrades(local_3c); - Object::getContainer(local_3c); - Object::getObjectType(local_2c); - Creature = Obj->ObjectID; - local_2c[0].ObjectID = Creature; - uVar2 = GetObjectCreatureID((Object *)&Creature); - NotifyCreature(uVar2,(Object *)uVar2,SUB41(local_2c,0)); - return; - } - error(&DAT_080ffa80,Attribute); - } - else { - error(&DAT_080ffa40); - } - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar4,&RESULT::typeinfo,0); -} - - - -void Delete(Object *Obj,int Count) - -{ - bool bVar1; - TCreature *cr; - ulong uVar2; - TCreature *this; - undefined4 *puVar3; - bool Inventory; - ObjectType *Type; - ulong oldCreature; - Object local_5c; - Object oldCon; - Object local_4c; - ObjectType oldType; - Object local_3c [4]; - Object local_2c; - Object Rest; - - // try { // try from 0809418b to 08094506 has its CatchHandler @ 08094510 - bVar1 = Object::exists(Obj); - if (!bVar1) { - error(&DAT_080ffb60); -LAB_080944d1: - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); - } - Object::getObjectType(&local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_2c,CUMULATIVE); - if ((bVar1) && ((Count == 0 || (uVar2 = Object::getAttribute(Obj,AMOUNT), (int)uVar2 < Count)))) - { - error(&DAT_080ffb00,Count); - goto LAB_080944d1; - } - local_2c.ObjectID = NONE.ObjectID; - Object::getObjectType(local_3c); - bVar1 = ObjectType::getFlag((ObjectType *)local_3c,CUMULATIVE); - if (((bVar1) && (Count != -1)) && (uVar2 = Object::getAttribute(Obj,AMOUNT), Count < (int)uVar2) - ) { - local_5c = (Object)Obj->ObjectID; - local_4c.ObjectID = local_5c.ObjectID; - local_3c[0].ObjectID = local_5c.ObjectID; - local_2c.ObjectID = local_5c.ObjectID; - SplitObject(local_3c,(int)&local_5c); - local_4c.ObjectID = local_3c[0].ObjectID; - Obj->ObjectID = (ulong)local_3c[0]; - } - else { - local_5c = (Object)Obj->ObjectID; - NotifyTrades(&local_5c); - } - Object::getObjectType(&local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_5c,CONTAINER); - if (!bVar1) { - Object::getObjectType(&local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_5c,CHEST); - if (!bVar1) goto LAB_080942ee; - } - Object::getObjectType(&local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_5c,CONTAINER); - if (bVar1) { - local_5c = (Object)Obj->ObjectID; - CloseContainer(&local_5c,true); - } - while( true ) { - local_4c = (Object)Obj->ObjectID; - GetFirstContainerObject(&local_5c); - local_4c.ObjectID = NONE.ObjectID; - if (local_5c.ObjectID == NONE.ObjectID) break; - local_4c.ObjectID = local_5c.ObjectID; - DeleteObject(&local_4c); - } -LAB_080942ee: - Object::getContainer(&local_5c); - local_4c = (Object)Obj->ObjectID; - uVar2 = GetObjectCreatureID(&local_4c); - Object::getObjectType(&local_4c); - local_3c[0].ObjectID = local_5c.ObjectID; - oldCreature = Obj->ObjectID; - SeparationEvent((Object *)&oldCreature,local_3c); - bVar1 = Object::exists(Obj); - if (bVar1) { - oldCreature = NONE.ObjectID; - if (local_2c.ObjectID == NONE.ObjectID) { - local_3c[0] = (Object)Obj->ObjectID; - AnnounceChangedObject(local_3c,0); - } - oldCreature = NONE.ObjectID; - local_3c[0] = (Object)Obj->ObjectID; - NotifyAllCreatures(local_3c,0,(Object *)&oldCreature); - if (local_4c.ObjectID == 99) { - this = GetCreature(uVar2); - if (this == (TCreature *)0x0) { - error(&DAT_080ffac0,uVar2); - } - else { - TCreature::NotifyDelete(this); - } - } - oldCreature = Obj->ObjectID; - DeleteObject((Object *)&oldCreature); - oldCreature = NONE.ObjectID; - local_3c[0].ObjectID = NONE.ObjectID; - if (local_2c.ObjectID != NONE.ObjectID) { - local_3c[0].ObjectID = local_2c.ObjectID; - AnnounceChangedObject(local_3c,2); - local_3c[0].ObjectID = local_2c.ObjectID; - NotifyTrades(local_3c); - } - Object::getObjectType((Object *)&oldCreature); - ObjectType::setTypeID((ObjectType *)&oldCreature,local_4c.ObjectID); - NotifyCreature(uVar2,Type,Inventory); - } - return; -} - - - -void Empty(Object *Con,int Rest) - -{ - bool bVar1; - int iVar2; - undefined4 *puVar3; - char *Text; - bool IsCorpse; - int Count; - Object local_4c [4]; - Object local_3c [4]; - Object local_2c; - Object Obj; - - // try { // try from 0809454b to 080946b9 has its CatchHandler @ 080946c5 - bVar1 = Object::exists(Con); - if (bVar1) { - if (Rest < 0) { - error(&DAT_081013ed,Rest); - goto LAB_08094680; - } - Object::getObjectType(&local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_2c,CONTAINER); - if (bVar1) { - local_2c = (Object)Con->ObjectID; - iVar2 = CountObjectsInContainer(&local_2c); - local_2c = (Object)Con->ObjectID; - CloseContainer(&local_2c,true); - Object::getObjectType(&local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_2c,CORPSE); - for (; Rest < iVar2; iVar2 = iVar2 + -1) { - local_3c[0] = (Object)Con->ObjectID; - GetFirstContainerObject(&local_2c); - if (bVar1) { - local_3c[0].ObjectID = local_2c.ObjectID; - Delete(local_3c,-1); - } - else { - local_3c[0].ObjectID = NONE.ObjectID; - Object::getContainer(local_4c); - Count = local_2c.ObjectID; - Move(0,(Object *)&Count,local_4c,-1,false,local_3c); - } - } - return; - } - Text = &DAT_080ffba0; - } - else { - Text = &DAT_080ffbe0; - } - error(Text); -LAB_08094680: - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void GraphicalEffect(void) - -{ - int in_stack_00000004; - int in_stack_00000008; - int in_stack_0000000c; - int in_stack_00000010; - - AnnounceGraphicalEffect(in_stack_00000004,in_stack_00000008,in_stack_0000000c,in_stack_00000010) - ; - return; -} - - - -void GraphicalEffect(Object *Obj,int Type) - -{ - bool bVar1; - int local_28; - int x; - int y; - int z; - - bVar1 = Object::exists(Obj); - if (bVar1) { - z = Obj->ObjectID; - GetObjectCoordinates((Object *)&z,&local_28,&x,&y); - AnnounceGraphicalEffect(local_28,x,y,Type); - } - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void TextualEffect(void) - -{ - bool bVar1; - Object *in_stack_00000004; - int in_stack_00000008; - char *in_stack_0000000c; - int local_58; - int x; - int y; - int z; - char Buffer [10]; - Object local_3c [4]; - Object local_2c [7]; - - bVar1 = Object::exists(in_stack_00000004); - if (bVar1) { - Object::getObjectType(local_2c); - if (local_2c[0].ObjectID != 0) { - z = in_stack_00000004->ObjectID; - GetMapContainer(local_3c); - in_stack_00000004->ObjectID = local_3c[0].ObjectID; - } - vsnprintf((char *)&z,10,in_stack_0000000c,&stack0x00000010); - local_3c[0].ObjectID = in_stack_00000004->ObjectID; - GetObjectCoordinates(local_3c,&local_58,&x,&y); - AnnounceTextualEffect(local_58,x,y,in_stack_00000008,(char *)&z); - } - else { - error(&DAT_080ffc20); - } - return; -} - - - -void Missile(Object *Start,Object *Dest,int Type) - -{ - bool bVar1; - char *Text; - int local_44; - int zx; - int zy; - int zz; - int sx; - int sy; - int sz; - - bVar1 = Object::exists(Start); - if (bVar1) { - bVar1 = Object::exists(Dest); - if (bVar1) { - sz = Start->ObjectID; - GetObjectCoordinates((Object *)&sz,&zz,&sx,&sy); - sz = Dest->ObjectID; - GetObjectCoordinates((Object *)&sz,&local_44,&zx,&zy); - AnnounceMissile(zz,sx,sy,local_44,zx,zy,Type); - return; - } - Text = &DAT_080ffca0; - } - else { - Text = &DAT_080ffc60; - } - error(Text); - return; -} - - - void Look(ulong CreatureID,Object *Obj) { diff --git a/src/cr.hh b/src/cr.hh index 162cb68..a2206f4 100644 --- a/src/cr.hh +++ b/src/cr.hh @@ -717,6 +717,7 @@ struct TPlayer: TCreature { Object GetOpenContainer(int ContainerNr); void SetOpenContainer(int ContainerNr, Object Con); void RejectTrade(void); + Object InspectTrade(bool OwnOffer, int Position); // VIRTUAL FUNCTIONS // ================= diff --git a/src/crcombat.cc b/src/crcombat.cc index c1f27a4..0b45ea4 100644 --- a/src/crcombat.cc +++ b/src/crcombat.cc @@ -2,6 +2,7 @@ #include "config.hh" #include "info.hh" #include "magic.hh" +#include "operate.hh" #include "stubs.hh" diff --git a/src/crmain.cc b/src/crmain.cc index 52a7c13..7e0ab42 100644 --- a/src/crmain.cc +++ b/src/crmain.cc @@ -592,7 +592,7 @@ int TCreature::Damage(TCreature *Attacker, int Damage, int DamageType){ this->SetTimer(SKILL_ILLUSION, 0, 0, 0, -1); this->Outfit = this->OrgOutfit; AnnounceChangedCreature(this->ID, CREATURE_OUTFIT_CHANGED); - NotifyAllCreatures(this->CrObject, 2, NONE); // CREATURE_APPEAR ? + NotifyAllCreatures(this->CrObject, OBJECT_CHANGED, NONE); } if(DamageType == DAMAGE_MANADRAIN){ @@ -890,8 +890,7 @@ void TCreature::CreatureMoveStimulus(uint32 CreatureID, int Type){ return; } - // TODO(fusion): Find out what `Type` is here. - if(Type != 2 // STIMULUS_TYPE_?? + if(Type != OBJECT_CHANGED || !this->LockToDo || this->ActToDo >= this->NrToDo || this->ToDoList.at(this->ActToDo)->Code != TDAttack){ diff --git a/src/crskill.cc b/src/crskill.cc index f400dc9..235f277 100644 --- a/src/crskill.cc +++ b/src/crskill.cc @@ -956,7 +956,7 @@ void TSkillIllusion::Event(int Range){ if(this->Get() <= 0){ Master->Outfit = Master->OrgOutfit; AnnounceChangedCreature(Master->ID, CREATURE_OUTFIT_CHANGED); - NotifyAllCreatures(Master->CrObject, 2, NONE); + NotifyAllCreatures(Master->CrObject, OBJECT_CHANGED, NONE); } } } diff --git a/src/info.cc b/src/info.cc index 3cdfe02..0461356 100644 --- a/src/info.cc +++ b/src/info.cc @@ -486,6 +486,17 @@ Object GetInventoryObject(uint32 CreatureID, ObjectType Type, uint32 Value){ return Result; } +bool IsHeldByContainer(Object Obj, Object Con){ + // TODO(fusion): Why do we check for map container in some loops? + while(Obj != NONE && !Obj.getObjectType().isMapContainer()){ + if(Obj == Con){ + return true; + } + Obj = Obj.getContainer(); + } + return false; +} + int CountObjectsInContainer(Object Con){ if(!Con.exists()){ error("CountObjectsInContainer: Container existiert nicht.\n"); diff --git a/src/info.hh b/src/info.hh index adf3ce4..0a7f919 100644 --- a/src/info.hh +++ b/src/info.hh @@ -31,6 +31,7 @@ Object GetContainer(uint32 CreatureID, int x, int y, int z); Object GetObject(uint32 CreatureID, int x, int y, int z, int RNum, ObjectType Type); Object GetRowObject(Object Obj, ObjectType Type, uint32 Value, bool Recurse); Object GetInventoryObject(uint32 CreatureID, ObjectType Type, uint32 Value); +bool IsHeldByContainer(Object Obj, Object Con); int CountObjectsInContainer(Object Con); int CountObjects(Object Obj); int CountObjects(Object Obj, ObjectType Type, uint32 Value); diff --git a/src/magic.cc b/src/magic.cc index 6cff8bc..0b161ec 100644 --- a/src/magic.cc +++ b/src/magic.cc @@ -2401,7 +2401,7 @@ void CancelInvisibility(TCreature *Actor, Object Target, int ManaPoints, int Sou if(Victim->Skills[SKILL_ILLUSION]->Get() == 0){ Victim->Outfit = Victim->OrgOutfit; AnnounceChangedCreature(Victim->ID, CREATURE_OUTFIT_CHANGED); - NotifyAllCreatures(Victim->CrObject, 2, NONE); // CREATURE_APPEAR ? + NotifyAllCreatures(Victim->CrObject, OBJECT_CHANGED, NONE); }else{ Effect = EFFECT_BLOCK_HIT; diff --git a/src/map.cc b/src/map.cc index b9085c9..0329e20 100644 --- a/src/map.cc +++ b/src/map.cc @@ -1971,33 +1971,6 @@ void ChangeObject(Object Obj, INSTANCEATTRIBUTE Attribute, uint32 Value){ Obj.setAttribute(Attribute, Value); } -// TODO(fusion): This probably belongs to `operate.cc`. -void ChangeObject(Object Obj, ObjectType NewType, uint32 Value){ - if(!Obj.exists()){ - error("ChangeObject: Übergebenes Objekt existiert nicht (1, NewType=%d).\n", NewType.TypeID); - return; - } - - // TODO(fusion): Why are we checking if `Obj` exists a second time? There is - // no reason to assume `Obj.getContainer()` would change anything since the - // first call. - Object Con = Obj.getContainer(); - if(!Obj.exists()){ - error("ChangeObject: Übergebenes Objekt existiert nicht (2, NewType=%d).\n", NewType.TypeID); - return; - } - - ObjectType ObjType = Obj.getObjectType(); - if(ObjType.getFlag(CUMULATIVE)){ - uint32 Amount = Obj.getAttribute(AMOUNT); - if(Amount > 1){ - Move(0, Obj, Con, Amount - 1, true, NONE); - } - } - - Change(Obj, NewType, Value); -} - int GetObjectPriority(Object Obj){ if(!Obj.exists()){ error("GetObjectPriority: Übergebenes Objekt existiert nicht.\n"); diff --git a/src/map.hh b/src/map.hh index 8989f05..81edef0 100644 --- a/src/map.hh +++ b/src/map.hh @@ -145,7 +145,6 @@ Object CreateObject(void); void DeleteObject(Object Obj); void ChangeObject(Object Obj, ObjectType NewType); void ChangeObject(Object Obj, INSTANCEATTRIBUTE Attribute, uint32 Value); -void ChangeObject(Object Obj, ObjectType NewType, uint32 Value); int GetObjectPriority(Object Obj); void PlaceObject(Object Obj, Object Con, bool Append); void CutObject(Object Obj); diff --git a/src/moveuse.cc b/src/moveuse.cc new file mode 100644 index 0000000..f11fffa --- /dev/null +++ b/src/moveuse.cc @@ -0,0 +1,56 @@ +#include "operate.hh" + +// NOTE(fusion): Oh no. +void ChangeObject(Object Obj, ObjectType NewType, uint32 Value){ + if(!Obj.exists()){ + error("ChangeObject: Übergebenes Objekt existiert nicht (1, NewType=%d).\n", NewType.TypeID); + return; + } + + Object Con = Obj.getContainer(); + while(true){ + if(!Obj.exists()){ + error("ChangeObject: Übergebenes Objekt existiert nicht (2, NewType=%d).\n", NewType.TypeID); + return; + } + + try{ + // NOTE(fusion): `Change` requires CUMULATIVE objects to have AMOUNT + // equal to one or it fails with `SPLITOBJECT`. + ObjectType ObjType = Obj.getObjectType(); + if(ObjType.getFlag(CUMULATIVE)){ + uint32 Amount = Obj.getAttribute(AMOUNT); + if(Amount > 1){ + Move(0, Obj, Con, Amount - 1, true, NONE); + } + } + + Change(Obj, NewType, Value); + return; + }catch(RESULT r){ + if(!Obj.exists()){ + error("ChangeObject: Übergebenes Objekt existiert nicht (3, NewType=%d).\n", NewType.TypeID); + return; + } + + if(r == CONTAINERFULL){ + Con = GetMapContainer(Obj); + }else if(r == TOOHEAVY){ + Object MapCon = GetMapContainer(Obj); + Move(0, Obj, MapCon, -1, true, NONE); + }else if(r == NOROOM){ + if(!Obj.getObjectType().getFlag(CUMULATIVE) + || Obj.getAttribute(AMOUNT) <= 1){ + throw; + } + + // TODO(fusion): Why do we use `Con` with `GetMapContainer` here? + uint32 Amount = Obj.getAttribute(AMOUNT); + Object MapCon = GetMapContainer(Con); + Move(0, Obj, MapCon, Amount - 1, true, NONE); + }else{ + throw; + } + } + } +} diff --git a/src/moveuse.hh b/src/moveuse.hh new file mode 100644 index 0000000..1036142 --- /dev/null +++ b/src/moveuse.hh @@ -0,0 +1,9 @@ +#ifndef TIBIA_MOVEUSE_HH_ +#define TIBIA_MOVEUSE_HH_ 1 + +#include "common.hh" +#include "map.hh" + +void ChangeObject(Object Obj, ObjectType NewType, uint32 Value); + +#endif //TIBIA_MOVEUSE_HH_ diff --git a/src/operate.cc b/src/operate.cc index 34df0a7..5f7d4d3 100644 --- a/src/operate.cc +++ b/src/operate.cc @@ -4,29 +4,6 @@ #include "stubs.hh" -// operate.cc -void CheckMoveObject(uint32 CreatureID, Object Obj, bool Take); -void CheckMapDestination(uint32 CreatureID, Object Obj, Object MapCon); -void CheckDepotSpace(uint32 CreatureID, Object Source, Object Destination, int Count); -void CheckWeight(uint32 CreatureID, Object Obj, int Count); -void NotifyCreature(uint32 CreatureID, Object Obj, bool Inventory); -void NotifyCreature(uint32 CreatureID, ObjectType Type, bool Inventory); -//void NotifyAllCreatures(Object Obj, int Type, Object OldCon); -void NotifyTrades(Object Obj); -void NotifyDepot(uint32 CreatureID, Object Obj, int Count); -void CloseContainer(Object Con, bool Force); - -// moveuse.cc -void MovementEvent(Object Obj, Object Start, Object Dest); -void CollisionEvent(Object Obj, Object Dest); -void SeparationEvent(Object Obj, Object Start); - - -//================================================================================================== -//================================================================================================== -//================================================================================================== -//================================================================================================== - // TODO(fusion): The radii parameters for `TFindCreatures` are commonly around // 16 and 14 for x and y respectively so there is probably some constant involved. // Also, since we're talking about radii, these values are quite large when you @@ -449,9 +426,9 @@ void CheckMoveObject(uint32 CreatureID, Object Obj, bool Take){ } } -// NOTE(fusion): This is a helper function for `CheckMapDestination` and improves -// the readability of an otherwise convoluted function. -static bool IsMapDestinationBlocked(int DestX, int DestY, int DestZ, ObjectType Type){ +// NOTE(fusion): This is a helper function for `CheckMapDestination` and `CheckMapPlace` +// and improves the readability of otherwise two convoluted functions. +static bool IsMapBlocked(int DestX, int DestY, int DestZ, ObjectType Type){ if(Type.isCreatureContainer()){ return false; } @@ -466,9 +443,11 @@ static bool IsMapDestinationBlocked(int DestX, int DestY, int DestZ, ObjectType return false; } - if(CoordinateFlag(DestX, DestY, DestZ, HOOKSOUTH) || CoordinateFlag(DestX, DestY, DestZ, HOOKEAST)){ - if(Type.getFlag(HANG) && !CoordinateFlag(DestX, DestY, DestZ, HANG)){ - return true; + if(Type.getFlag(HANG)){ + bool HasHook = CoordinateFlag(DestX, DestY, DestZ, HOOKSOUTH) + || CoordinateFlag(DestX, DestY, DestZ, HOOKEAST); + if(HasHook && !CoordinateFlag(DestX, DestY, DestZ, HANG)){ + return false; } } } @@ -484,7 +463,7 @@ void CheckMapDestination(uint32 CreatureID, Object Obj, Object MapCon){ int DestX, DestY, DestZ; ObjectType ObjType = Obj.getObjectType(); GetObjectCoordinates(MapCon, &DestX, &DestY, &DestZ); - if(IsMapDestinationBlocked(DestX, DestY, DestZ, ObjType)){ + if(IsMapBlocked(DestX, DestY, DestZ, ObjType)){ throw NOROOM; } @@ -507,8 +486,12 @@ void CheckMapDestination(uint32 CreatureID, Object Obj, Object MapCon){ } } - // TODO(fusion): Should probably check if moving creature is NULL? TCreature *MovingCreature = GetCreature(Obj); + if(MovingCreature == NULL){ + error("CheckMapDestination: Moving creature is NULL."); + throw ERROR; + } + if(OrigZ == DestZ || MovingCreature->Type != MONSTER){ if(!MovingCreature->MovePossible(DestX, DestY, DestZ, true, OrigZ != DestZ)){ if(CreatureID == MovingCreature->ID){ @@ -579,14 +562,34 @@ void CheckMapDestination(uint32 CreatureID, Object Obj, Object MapCon){ } } -// TODO(fusion): This could have been a simple return value. -void CheckContainerDestination(Object Obj, Object Con){ - Object Help = Con; - while(Help != NONE && !Help.getObjectType().isMapContainer()){ - if(Help == Obj){ - throw CROSSREFERENCE; +void CheckMapPlace(uint32 CreatureID, ObjectType Type, Object MapCon){ + int DestX, DestY, DestZ; + GetObjectCoordinates(MapCon, &DestX, &DestY, &DestZ); + + if(!Type.getFlag(UNMOVE) && !CoordinateFlag(DestX, DestY, DestZ, BANK)){ + if(!Type.getFlag(HANG)){ + throw NOROOM; + } + + if(!CoordinateFlag(DestX, DestY, DestZ, HOOKSOUTH) + && !CoordinateFlag(DestX, DestY, DestZ, HOOKEAST)){ + throw NOROOM; } - Help = Help.getContainer(); + } + + // TODO(fusion): The original function used a slightly modified version of + // `IsMapBlocked` which wouldn't check if there was already a HANG item at + // the destination but since this function seems to only be called from + // `Create` which sets `CreatureID` to zero, I assume this was probably an + // oversight? + if(CreatureID != 0 && IsMapBlocked(DestX, DestY, DestZ, Type)){ + throw NOROOM; + } +} + +void CheckContainerDestination(Object Obj, Object Con){ + if(IsHeldByContainer(Con, Obj)){ + throw CROSSREFERENCE; } ObjectType ConType = Con.getObjectType(); @@ -599,6 +602,60 @@ void CheckContainerDestination(Object Obj, Object Con){ } } +void CheckContainerPlace(ObjectType Type, Object Con, Object OldObj){ + if(Type == GetSpecialObject(DEPOT_CHEST)){ + return; + } + + ObjectType ConType = Con.getObjectType(); + if(!ConType.getFlag(CHEST)){ + if(Type.getFlag(UNMOVE)){ + throw NOTMOVABLE; + } + + if(!Type.getFlag(TAKE)){ + throw NOTTAKABLE; + } + + if(OldObj == NONE){ + int ConObjects = CountObjectsInContainer(Con); + int ConCapacity = (int)ConType.getAttribute(CAPACITY); + if(ConObjects >= ConCapacity){ + throw CONTAINERFULL; + } + } + } +} + +void CheckDepotSpace(uint32 CreatureID, Object Source, Object Destination, int Count){ + if(CreatureID == 0){ + return; + } + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("CheckDepotSpace: Kreatur %u existiert nicht.\n", CreatureID); + throw ERROR; + } + + if(Destination == NONE){ + error("CheckDepotSpace: Ziel existiert nicht.\n"); + throw ERROR; + } + + if(Creature->Type == PLAYER){ + TPlayer *Player = (TPlayer*)Creature; + if(Player->Depot == NONE || Count <= Player->DepotSpace){ + return; + } + + if(!IsHeldByContainer(Source, Player->Depot) + && IsHeldByContainer(Destination, Player->Depot)){ + throw CONTAINERFULL; + } + } +} + void CheckInventoryDestination(Object Obj, Object Con, bool Split){ ObjectType ObjType = Obj.getObjectType(); int ConPosition = GetObjectBodyPosition(Con); @@ -619,7 +676,7 @@ void CheckInventoryDestination(Object Obj, Object Con, bool Split){ } uint32 CreatureID = GetObjectCreatureID(Con); - if(ObjType.isTwoHanded() && HandContainer){ + if(HandContainer && ObjType.isTwoHanded()){ Object RightHand = GetBodyObject(CreatureID, INVENTORY_RIGHTHAND); if(RightHand != NONE && RightHand != Obj){ throw HANDSNOTFREE; @@ -658,6 +715,546 @@ void CheckInventoryDestination(Object Obj, Object Con, bool Split){ } } +void CheckInventoryPlace(ObjectType Type, Object Con, Object OldObj){ + // TODO(fusion): This is awfully similar to `CheckInventoryDestination` with + // a few subtle differences. Perhaps they use the same underlying function? + + int ConPosition = GetObjectBodyPosition(Con); + bool HandContainer = ConPosition == INVENTORY_RIGHTHAND + || ConPosition == INVENTORY_LEFTHAND; + + if(!HandContainer && ConPosition != INVENTORY_AMMO){ + if(!Type.getFlag(CLOTHES)){ + throw WRONGPOSITION; + } + + int TypePosition = (int)Type.getAttribute(BODYPOSITION); + if(TypePosition == 0){ + throw WRONGPOSITION2; + }else if(TypePosition != ConPosition){ + throw WRONGCLOTHES; + } + } + + uint32 CreatureID = GetObjectCreatureID(Con); + if(HandContainer && Type.isTwoHanded()){ + Object RightHand = GetBodyObject(CreatureID, INVENTORY_RIGHTHAND); + if(RightHand != NONE && RightHand != OldObj){ + throw HANDSNOTFREE; + } + + Object LeftHand = GetBodyObject(CreatureID, INVENTORY_LEFTHAND); + if(LeftHand != NONE && LeftHand != OldObj){ + throw HANDSNOTFREE; + } + + return; + } + + if(GetBodyObject(CreatureID, ConPosition) != NONE + && GetBodyObject(CreatureID, ConPosition) != OldObj){ + throw NOROOM; + } + + if(HandContainer){ + for(int Position = INVENTORY_HAND_FIRST; + Position <= INVENTORY_HAND_LAST; + Position += 1){ + Object Other = GetBodyObject(CreatureID, Position); + if(Other != NONE && Other != OldObj){ + ObjectType OtherType = Other.getObjectType(); + if(OtherType.isTwoHanded()){ + throw HANDBLOCKED; + } + + if(OtherType.isWeapon() && Type.isWeapon()){ + throw ONEWEAPONONLY; + } + } + } + } +} + +void CheckWeight(uint32 CreatureID, Object Obj, int Count){ + if(GetObjectCreatureID(Obj) == CreatureID){ + return; + } + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("CheckWeight: Kreatur %d existiert nicht.\n", CreatureID); + throw ERROR; + } + + ObjectType ObjType = Obj.getObjectType(); + if(!ObjType.getFlag(TAKE)){ + throw TOOHEAVY; + } + + if(Creature->Type == PLAYER){ + if(CheckRight(CreatureID, UNLIMITED_CAPACITY)){ + return; + } + + if(CheckRight(CreatureID, ZERO_CAPACITY)){ + throw TOOHEAVY; + } + } + + TSkill *CarryStrength = Creature->Skills[SKILL_CARRY_STRENGTH]; + if(CarryStrength == NULL){ + error("CheckWeight: Skill CARRYSTRENGTH existiert nicht.\n"); + throw ERROR; + } + + int ObjWeight; + if(ObjType.getFlag(CUMULATIVE)){ + ObjWeight = GetWeight(Obj, Count); + }else{ + ObjWeight = GetCompleteWeight(Obj); + } + + int InventoryWeight = GetInventoryWeight(CreatureID); + int MaxWeight = CarryStrength->Get() * 100; + if((InventoryWeight + ObjWeight) > MaxWeight){ + throw TOOHEAVY; + } +} + +void CheckWeight(uint32 CreatureID, ObjectType Type, uint32 Value, int OldWeight){ + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("CheckWeight: Kreatur %d existiert nicht.\n", CreatureID); + throw ERROR; + } + + if(!Type.getFlag(TAKE)){ + throw TOOHEAVY; + } + + if(Creature->Type == PLAYER){ + if(CheckRight(CreatureID, UNLIMITED_CAPACITY)){ + return; + } + + if(CheckRight(CreatureID, ZERO_CAPACITY)){ + throw TOOHEAVY; + } + } + + TSkill *CarryStrength = Creature->Skills[SKILL_CARRY_STRENGTH]; + if(CarryStrength == NULL){ + error("CheckWeight: Skill CARRYSTRENGTH existiert nicht.\n"); + throw ERROR; + } + + int TypeWeight = (int)Type.getAttribute(WEIGHT); + if(Type.getFlag(CUMULATIVE) && (int)Value > 1){ + TypeWeight *= (int)Value; + } + + if(TypeWeight > OldWeight){ + int InventoryWeight = GetInventoryWeight(CreatureID); + int MaxWeight = CarryStrength->Get() * 100; + if((InventoryWeight + TypeWeight) > MaxWeight){ + throw TOOHEAVY; + } + } +} + +void NotifyCreature(uint32 CreatureID, Object Obj, bool Inventory){ + if(CreatureID == 0){ + return; + } + + ObjectType ObjType = Obj.getObjectType(); + if(!ObjType.isCreatureContainer()){ + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("NotifyCreature: Kreatur existiert nicht.\n"); + return; + } + + if(Inventory && ObjType.getFlag(LIGHT)){ + AnnounceChangedCreature(CreatureID, CREATURE_LIGHT_CHANGED); + } + + Creature->NotifyChangeInventory(); + } +} + +void NotifyCreature(uint32 CreatureID, ObjectType Type, bool Inventory){ + if(CreatureID == 0){ + return; + } + + // TODO(fusion): Shouldn't we check if `Type` is creature container too? + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("NotifyCreature: Kreatur existiert nicht.\n"); + return; + } + + if(Inventory && Type.getFlag(LIGHT)){ + AnnounceChangedCreature(CreatureID, CREATURE_LIGHT_CHANGED); + } + + Creature->NotifyChangeInventory(); +} + +void NotifyAllCreatures(Object Obj, int Type, Object OldCon){ + if(!Obj.exists()){ + error("NotifyAllCreatures: Übergebenes Objekt existiert nicht.\n"); + return; + } + + ObjectType ObjType = Obj.getObjectType(); + if(!ObjType.isCreatureContainer()){ + return; + } + + int ObjX, ObjY, ObjZ; + uint32 CreatureID = Obj.getCreatureID(); + GetObjectCoordinates(Obj, &ObjX, &ObjY, &ObjZ); + + constexpr int StimulusRadius = 10; + int SearchRadiusX = StimulusRadius; + int SearchRadiusY = StimulusRadius; + int SearchCenterX = ObjX; + int SearchCenterY = ObjY; + if(Type == OBJECT_MOVED){ + if(!OldCon.exists()){ + error("NotifyAllCreatures: Übergebener alter Container existiert nicht.\n"); + return; + } + + // NOTE(fusion): Report stimulus as `OBJECT_CHANGED`. + Type = OBJECT_CHANGED; + + // NOTE(fusion): Perform a secondary search if the distances are beyond + // the stimulus diameter or, extend the primary search otherwise. + int OldX, OldY, OldZ; + GetObjectCoordinates(OldCon, &OldX, &OldY, &OldZ); + int DistanceX = std::abs(ObjX - OldX); + int DistanceY = std::abs(ObjY - OldY); + if(DistanceX > (StimulusRadius * 2) || DistanceY > (StimulusRadius * 2)){ + TFindCreatures Search(StimulusRadius, StimulusRadius, OldX, OldY, FIND_ALL); + while(true){ + uint32 SpectatorID = Search.getNext(); + if(SpectatorID == 0){ + break; + } + + // TODO(fusion): Check if the spectator is NULL? + TCreature *Spectator = GetCreature(SpectatorID); + Spectator->CreatureMoveStimulus(CreatureID, Type); + } + }else{ + SearchRadiusX = StimulusRadius + (DistanceX + 1) / 2; + SearchRadiusY = StimulusRadius + (DistanceY + 1) / 2; + SearchCenterX = (ObjX + OldX) / 2; + SearchCenterY = (ObjY + OldY) / 2; + } + } + + TFindCreatures Search(SearchRadiusX, SearchRadiusY, SearchCenterX, SearchCenterY, FIND_ALL); + while(true){ + uint32 SpectatorID = Search.getNext(); + if(SpectatorID == 0){ + break; + } + + // TODO(fusion): Check if the spectator is NULL? + TCreature *Spectator = GetCreature(SpectatorID); + Spectator->CreatureMoveStimulus(CreatureID, Type); + } +} + +void NotifyTrades(Object Obj){ + if(!Obj.exists()){ + error("NotifyTrades: Übergebenes Objekt existiert nicht.\n"); + return; + } + + ObjectType ObjType = Obj.getObjectType(); + if(ObjType.isCreatureContainer()){ + return; + } + + // TODO(fusion): These radii seem to be correct but I'm skeptical because + // you're required to be close to the trade object to even start the trade. + // Maybe you can walk around after a trade is started? + TFindCreatures Search(12, 10, Obj, FIND_PLAYERS); + while(true){ + uint32 CharacterID = Search.getNext(); + if(CharacterID == 0){ + break; + } + + TPlayer *Player = GetPlayer(CharacterID); + if(Player == NULL){ + error("NotifyTrade: Spieler existiert nicht.\n"); + continue; + } + + Object TradeObject = Player->InspectTrade(true, 0); + if(TradeObject != NONE){ + if(IsHeldByContainer(Obj, TradeObject) || IsHeldByContainer(TradeObject, Obj)){ + SendCloseTrade(Player->Connection); + SendMessage(Player->Connection, TALK_FAILURE_MESSAGE, "Trade cancelled."); + Player->RejectTrade(); + } + } + } +} + +void NotifyDepot(uint32 CreatureID, Object Obj, int Count){ + if(CreatureID == 0){ + return; + } + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("NotifyDepot: Kreatur %u existiert nicht.\n", CreatureID); + // TODO(fusion): We should probably also throw here. + //throw ERROR; + return; + } + + if(!Obj.exists()){ + error("NotifyDepot: Objekt existiert nicht.\n"); + throw ERROR; + } + + if(Creature->Type == PLAYER){ + TPlayer *Player = (TPlayer*)Creature; + if(Player->Depot == NONE){ + return; + } + + if(IsHeldByContainer(Obj, Player->Depot)){ + Player->DepotSpace += Count; + print(3, "Neuer Depot-Freiraum für %s: %d\n", + Player->Name, Player->DepotSpace); + } + } +} + +void CloseContainer(Object Con, bool Force){ + if(!Con.exists()){ + error("CloseContainer: Übergebener Container existiert nicht.\n"); + return; + } + + ObjectType ConType = Con.getObjectType(); + if(ConType.isCreatureContainer()){ + return; + } + + // TODO(fusion): Similar to `NotifyTrades`. + TFindCreatures Search(12, 10, Con, FIND_PLAYERS); + while(true){ + uint32 CharacterID = Search.getNext(); + if(CharacterID == 0){ + break; + } + + TPlayer *Player = GetPlayer(CharacterID); + if(Player == NULL){ + error("CloseContainer: Spieler existiert nicht.\n"); + continue; + } + + for(int ContainerNr = 0; + ContainerNr < NARRAY(Player->OpenContainer); + ContainerNr += 1){ + Object OpenCon = Player->GetOpenContainer(ContainerNr); + if(IsHeldByContainer(OpenCon, Con)){ + if(Force || !ObjectAccessible(Player->ID, Con, 1)){ + Player->SetOpenContainer(ContainerNr, NONE); + SendCloseContainer(Player->Connection, ContainerNr); + }else{ + // TODO(fusion): Why are we doing this? Is the container being refreshed? + SendContainer(Player->Connection, ContainerNr); + } + } + } + } +} + +Object Create(Object Con, ObjectType Type, uint32 Value){ + if(!Con.exists()){ + error("Create: Zielobjekt existiert nicht.\n"); + throw ERROR; + } + + ObjectType ConType = Con.getObjectType(); + if(!ConType.getFlag(CONTAINER) && !ConType.getFlag(CHEST)){ + error("Create: Zielobjekt ist kein Container.\n"); + throw ERROR; + } + + // TODO(fusion): The map container does indeed use type id zero but it seems + // it is also considered a "no type" id so we might also want to add an alias + // to it as `isValid()`, `isVoid()`, `isNone()`, or `isNull()` perhaps. + if(Type.isMapContainer()){ + error("Create: Objekttyp existiert nicht.\n"); + throw ERROR; + } + + if(ConType.isMapContainer()){ + CheckMapPlace(0, Type, Con); + }else if(ConType.isBodyContainer()){ + CheckInventoryPlace(Type, Con, NONE); + }else{ + CheckContainerPlace(Type, Con, NONE); + } + + uint32 ConOwnerID = GetObjectCreatureID(Con); + if(ConOwnerID != 0){ + CheckWeight(ConOwnerID, Type, Value, 0); + } + + // NOTE(fusion): Attempt to merge with top object. + if(ConType.isMapContainer() && Type.getFlag(CUMULATIVE)){ + int ConX, ConY, ConZ; + GetObjectCoordinates(Con, &ConX, &ConY, &ConZ); + Object Top = GetTopObject(ConX, ConY, ConZ, true); + if(Top != NONE && Top.getObjectType() == Type){ + uint32 Count = Top.getAttribute(AMOUNT); + if(Value != 0){ + Count += Value; + }else{ + Count += 1; + } + + if(Count <= 100){ + Change(Top, AMOUNT, Count); + return Top; + } + } + } + + // TODO(fusion): I feel these usages of `Value` should be exclusive? + + Object Obj = SetObject(Con, Type, (Type.isCreatureContainer() ? Value : 0)); + + if(Type.getFlag(CUMULATIVE)){ + ChangeObject(Obj, AMOUNT, Value); + } + + if(Type.getFlag(MAGICFIELD)){ + ChangeObject(Obj, RESPONSIBLE, Value); + } + + if(Type.getFlag(LIQUIDPOOL)){ + ChangeObject(POOLLIQUIDTYPE, Value); + } + + if(Type.getFlag(LIQUIDCONTAINER)){ + ChangeObject(CONTAINERLIQUIDTYPE, Value); + } + + if(Type.getFlag(KEY)){ + ChangeObject(KEYNUMBER, Value); + } + + if(Type.getFlag(RUNE)){ + ChangeObject(CHARGES, Value); + } + + if(Type.isCreatureContainer()){ + // BUG(fusion): We should just check this before creating the object. + // Also, using `Delete` instead of `DeleteObject` here is problematic + // because the object's placement wasn't yet broadcasted. + TCreature *Creature = GetCreature(Value); + if(Creature == NULL){ + error("Create: Ungültige Kreatur-ID %u\n", Value); + Delete(Obj, -1); + throw ERROR; + } + + // IMPORTANT(fusion): Creature body containers are created here and their + // type ids match inventory slots exactly. We're looping in reverse because + // `SetObject` will insert objects at the front of the object chain. + for(int Position = INVENTORY_LAST; + Position >= INVENTORY_FIRST; + Position -= 1){ + SetObject(Obj, ObjectType(Position), 0); + } + + Creature->NotifyCreate(); + } + + AnnounceChangedObject(Obj, OBJECT_CREATED); + NotifyTrades(Obj); + NotifyCreature(ConOwnerID, Obj, ConType.isBodyContainer()); + MovementEvent(Obj, Con, Con); // TODO(fusion): This one doesn't make a lot of sense. + CollisionEvent(Obj, Con); + NotifyAllCreatures(Obj, OBJECT_CREATED, NONE); + return Obj; +} + +Object Copy(Object Con, Object Source){ + if(!Con.exists()){ + error("Copy: Ziel existiert nicht.\n"); + throw ERROR; + } + + ObjectType ConType = Con.getObjectType(); + if(!ConType.getFlag(CONTAINER) && !ConType.getFlag(CHEST)){ + error("Copy: Ziel ist kein Container.\n"); + throw ERROR; + } + + if(!Source.exists()){ + error("Copy: Quelle existiert nicht.\n"); + throw ERROR; + } + + ObjectType SourceType = Source.getObjectType(); + if(SourceType.isCreatureContainer()){ + error("Copy: Quelle ist eine Kreatur.\n"); + throw ERROR; + } + + if(ConType.isMapContainer()){ + CheckMapDestination(0, Source, Con); + }else if(ConType.isBodyContainer()){ + // TODO(fusion): Not sure about this third param. + CheckInventoryDestination(Source, Con, true); + }else{ + CheckContainerDestination(Source, Con); + } + + uint32 ConOwnerID = GetObjectCreatureID(Con); + if(ConOwnerID != 0){ + CheckWeight(ConOwnerID, Source, -1); + } + + // TODO(fusion): Using `Copy` recursively here should work because the object + // is placed when `CopyObject` is called. The thing is, announce and notify + // functions will do meaningless work there (I think, check what happens when + // we're actually running). + Object Obj = CopyObject(Con, Source); + if(SourceType.getFlag(CONTAINER)){ + Object Help = GetFirstContainerObject(Source); + while(Help != NONE){ + Copy(Obj, Help); + Help = Help.getNextObject(); + } + } + + AnnounceChangedObject(Obj, OBJECT_CREATED); + NotifyTrades(Obj); + NotifyCreature(ConOwnerID, Obj, ConType.isBodyContainer()); + MovementEvent(Obj, Con, Con); // TODO(fusion): Same as `Create`. + CollisionEvent(Obj, Con); + NotifyAllCreatures(Obj, OBJECT_CREATED, NONE); + return Obj; +} + void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Object Ignore){ if(!Obj.exists()){ error("Move: Übergebenes Objekt existiert nicht.\n"); @@ -778,6 +1375,10 @@ void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Ob // TODO(fusion): This could probably be moved to the end of the function // along with the other `CloseContainer`. + // Probably the other way around, since events could modify the object + // and I don't think it makes a difference if we close it before or after + // performing the move. + // Except it does because the object's position will be different lol. if(ObjType.getFlag(CONTAINER) && CreatureID == 0){ CloseContainer(Obj, true); } @@ -825,7 +1426,7 @@ void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Ob MovementEvent(Obj, OldCon, Con); CollisionEvent(Obj, Con); - NotifyAllCreatures(Obj, 3, OldCon); // CREATURE_MOVE_STIMULUS_ ? + NotifyAllCreatures(Obj, OBJECT_MOVED, OldCon); } void Merge(uint32 CreatureID, Object Obj, Object Dest, int Count, Object Ignore){ @@ -910,5 +1511,296 @@ void Merge(uint32 CreatureID, Object Obj, Object Dest, int Count, Object Ignore) NotifyCreature(ObjOwnerID, Dest, ObjCon.getObjectType().isBodyContainer()); NotifyCreature(DestOwnerID, Dest, DestCon.getObjectType().isBodyContainer()); CollisionEvent(Dest, DestCon); - NotifyAllCreatures(Dest, 2, NONE); // CREATURE_MOVE_STIMULUS_ ? + NotifyAllCreatures(Dest, OBJECT_CHANGED, NONE); +} + +void Change(Object Obj, ObjectType NewType, uint32 Value){ + if(Obj.exists()){ + error("Change: Übergebenes Objekt existiert nicht.\n"); + throw ERROR; + } + + ObjectType OldType = Obj.getObjectType(); + if(OldType.isCreatureContainer() || NewType.isCreatureContainer()){ + error("Change: Kann keine Kreaturen verändern.\n"); + throw ERROR; + } + + // TODO(fusion): Same thing as `Create`. The zero type id is also used as + // a "no type" id. + if(NewType.isMapContainer()){ + Delete(Obj, -1); + return; + } + + if(OldType.getFlag(CONTAINER)){ + if(!NewType.getFlag(CONTAINER) && GetFirstContainerObject(Obj) != NONE){ + error("Change: Zielobjekt %d für %d ist kein Container mehr.\n", + NewType.TypeID, OldType.TypeID); + throw EMPTYCONTAINER; + } + + if(NewType.getFlag(CONTAINER)){ + int ObjectCount = CountObjectsInContainer(Obj); + int NewCapacity = (int)NewType.getAttribute(CAPACITY); + if(ObjectCount < NewCapacity){ + error("Change: Zielobjekt %d für %d ist kleinerer Container.\n", + NewType.TypeID, OldType.TypeID); + throw EMPTYCONTAINER; + } + } + } + + if(OldType.getFlag(CHEST) && !NewType.getFlag(CHEST)){ + error("Change: Schatztruhe muß Schatztruhe bleiben.\n"); + throw ERROR; + } + + if(OldType.getFlag(CUMULATIVE) + && OldType != NewType + && Obj.getAttribute(AMOUNT) > 1){ + throw SPLITOBJECT; + } + + Object Con = Obj.getContainer(); + ObjectType ConType = Con.getObjectType(); + uint32 ObjOwnerID = GetObjectCreatureID(Obj); + if(ObjOwnerID != 0 && OldType != NewType){ + if(ConType.isBodyContainer()){ + CheckInventoryPlace(NewType, Con, Obj); + }else{ + CheckContainerPlace(NewType, Con, Obj); + } + + uint32 Count = 1; + if(OldType.getFlag(CUMULATIVE)){ + Count = Obj.getAttribute(AMOUNT); + } + + int OldWeight = GetWeight(Obj, -1); + CheckWeight(ObjOwnerID, NewType, Count, OldWeight); + } + + if(OldType.getFlag(CONTAINER) && !NewType.getFlag(CONTAINER)){ + CloseContainer(Obj, true); + } + + ChangeObject(Obj, NewType); + + // TODO(fusion): Same thing as `Create`. I feel these usages of `Value` + // should be exclusive. + + if(NewType.getFlag(CUMULATIVE) && !OldType.getFlag(CUMULATIVE)){ + ChangeObject(Obj, AMOUNT, Value); + } + + if(NewType.getFlag(MAGICFIELD) && !OldType.getFlag(MAGICFIELD)){ + ChangeObject(Obj, RESPONSIBLE, Value); + } + + if(NewType.getFlag(LIQUIDPOOL) && !OldType.getFlag(LIQUIDPOOL)){ + ChangeObject(Obj, POOLLIQUIDTYPE, Value); + } + + if(NewType.getFlag(LIQUIDCONTAINER) && !OldType.getFlag(LIQUIDCONTAINER)){ + ChangeObject(Obj, CONTAINERLIQUIDTYPE, Value); + } + + if(NewType.getFlag(KEY) && !OldType.getFlag(KEY)){ + ChangeObject(Obj, KEYNUMBER, Value); + } + + if(NewType.getFlag(RUNE) && !OldType.getFlag(RUNE)){ + ChangeObject(Obj, CHARGES, Value); + } + + AnnounceChangedObject(Obj, OBJECT_CHANGED); + NotifyTrades(Obj); + NotifyCreature(ObjOwnerID, Obj, ConType.isBodyContainer()); + NotifyAllCreatures(Obj, OBJECT_CHANGED, NONE); +} + +void Change(Object Obj, INSTANCEATTRIBUTE Attribute, uint32 Value){ + if(!Obj.exists()){ + error("Change: Übergebenes Objekt existiert nicht.\n"); + throw ERROR; + } + + if(Attribute == CONTENT + || Attribute == CHESTQUESTNUMBER + || Attribute == DOORLEVEL + || Attribute == DOORQUESTNUMBER + || Attribute == DOORQUESTVALUE + || Attribute == ABSTELEPORTDESTINATION + || Attribute == REMAININGEXPIRETIME){ + error("Change: Kann Attribut %d nicht ändern.\n", Attribute); + throw ERROR; + } + + uint32 ObjOwnerID = GetObjectCreatureID(Obj); + if(ObjOwnerID != 0 && Attribute == AMOUNT && Value > Obj.getAttribute(AMOUNT)){ + int OldWeight = GetWeight(Obj, -1); + CheckWeight(ObjOwnerID, Obj.getObjectType(), Value, OldWeight); + } + + ChangeObject(Obj, Attribute, Value); + if(Attribute == AMOUNT + || Attribute == CONTAINERLIQUIDTYPE + || Attribute == POOLLIQUIDTYPE){ + AnnounceChangedObject(Obj, OBJECT_CHANGED); + } + + NotifyTrades(Obj); + NotifyCreature(ObjOwnerID, Obj, Obj.getContainer().getObjectType().isBodyContainer()); +} + +void Delete(Object Obj, int Count){ + if(!Obj.exists()){ + error("Delete: Übergebenes Objekt existiert nicht.\n"); + throw ERROR; + } + + ObjectType ObjType = Obj.getObjectType(); + if(ObjType.getFlag(CUMULATIVE) && Count > (int)Obj.getAttribute(AMOUNT)){ + error("Delete: Ungültige Anzahl %d an Teilen bei kumulierbarem Objekt.\n", Count); + throw ERROR; + } + + Object Remainder = NONE; + if(ObjType.getFlag(CUMULATIVE) && Count != -1 + && Count < (int)Obj.getAttribute(AMOUNT)){ + Remainder = Obj; + Obj = SplitObject(Obj, Count); + }else{ + NotifyTrades(Obj); + } + + if(ObjType.getFlag(CONTAINER) || ObjType.getFlag(CHEST)){ + if(ObjType.getFlag(CONTAINER)){ + CloseContainer(Obj, true); + } + + Object Help = GetFirstContainerObject(Obj); + while(Help != NONE){ + Object Next = Help.getNextObject(); + DeleteObject(Help); + Help = Next; + } + } + + Object Con = Obj.getContainer(); + uint32 ObjOwnerID = GetObjectCreatureID(Obj); + SeparationEvent(Obj, Con); + + // BUG(fusion): Object may have been destroyed by the separation event? This + // looks suspicious because even if the object is properly destroyed, its + // remainder could be left unannounced. + // If it's a container, its objects don't get a separation event trigger, + // and the separation event trigger on the container itself is only triggered + // after it is empty. + if(Obj.exists()){ + if(Remainder == NONE){ + AnnounceChangedObject(Obj, OBJECT_DELETED); + } + + NotifyAllCreatures(Obj, OBJECT_DELETED, NONE); + if(ObjType.isCreatureContainer()){ + TCreature *Creature = GetCreature(ObjOwnerID); + if(Creature != NULL){ + Creature->NotifyDelete(); + }else{ + error("Delete: Kreatur mit ungültiger ID %d.\n", ObjOwnerID); + } + } + + DeleteObject(Obj); + + if(Remainder != NONE){ + AnnounceChangedObject(Remainder, OBJECT_CHANGED); + NotifyTrades(Remainder); + } + + NotifyCreature(ObjOwnerID, ObjType, Con.getObjectType().isBodyContainer()); + } +} + +void Empty(Object Con, int Remainder){ + if(!Con.exists()){ + error("Empty: Übergebener Container existiert nicht.\n"); + throw ERROR; + } + + if(Remainder < 0){ + error("Empty: Ungültiger Rest %d.\n", Remainder); + throw ERROR; + } + + ObjectType ConType = Con.getObjectType(); + if(!ConType.getFlag(CONTAINER)){ + error("Empty: Übergebenes Objekt ist kein Container.\n"); + throw ERROR; + } + + CloseContainer(Con, true); + + bool IsCorpse = ConType.getFlag(CORPSE); + int ObjectCount = CountObjectsInContainer(Con); + Object Help = GetFirstContainerObject(Con); + while(Help != NONE && ObjectCount > Remainder){ + Object Next = Help.getNextObject(); + if(IsCorpse){ + Delete(Help, -1); + }else{ + Move(0, Help, Con.getContainer(), -1, false, NONE); + } + Help = Next; + ObjectCount -= 1; + } +} + +void GraphicalEffect(int x, int y, int z, int Type){ + AnnounceGraphicalEffect(x, y, z, Type); +} + +void GraphicalEffect(Object Obj, int Type){ + if(Obj.exists()){ + int ObjX, ObjY, ObjZ; + GetObjectCoordinates(Obj, &ObjX, &ObjY, &ObjZ); + AnnounceGraphicalEffect(ObjX, ObjY, ObjZ, Type); + } +} + +void TextualEffect(Object Obj, int Color, const char *Format, ...){ + if(!Obj.exists()){ + error("TextualEffect: Übergebener Mapcontainer existiert nicht.\n"); + return; + } + + char Buffer[10]; + va_list ap; + va_start(ap, Format); + vsnprintf(Buffer, sizeof(Buffer), Format, ap); + va_end(ap); + + int ObjX, ObjY, ObjZ; + GetObjectCoordinates(Obj, &ObjX, &ObjY, &ObjZ); + AnnounceTextualEffect(ObjX, ObjY, ObjZ, Color, Buffer); +} + +void Missile(Object Start, Object Dest, int Type){ + if(!Start.exists()){ + error("Missile: Übergebener Startpunkt existiert nicht.\n"); + return; + } + + if(!Dest.exists()){ + error("Missile: Übergebener Zielpunkt existiert nicht.\n"); + return; + } + + int StartX, StartY, StartZ; + int DestX, DestY, DestZ; + GetObjectCoordinates(Start, &StartX, &StartY, &StartZ); + GetObjectCoordinates(Dest, &DestX, &DestY, &DestZ); + AnnounceMissile(StartX, StartY, StartZ, DestX, DestY, DestZ, Type); } diff --git a/src/operate.hh b/src/operate.hh index de7b54d..7d137fd 100644 --- a/src/operate.hh +++ b/src/operate.hh @@ -17,9 +17,49 @@ enum : int { OBJECT_DELETED = 0, OBJECT_CREATED = 1, OBJECT_CHANGED = 2, + OBJECT_MOVED = 3, }; +void AnnounceMovingCreature(uint32 CreatureID, Object Con); +void AnnounceChangedCreature(uint32 CreatureID, int Type); +void AnnounceChangedField(Object Obj, int Type); +void AnnounceChangedContainer(Object Obj, int Type); +void AnnounceChangedInventory(Object Obj, int Type); +void AnnounceChangedObject(Object Obj, int Type); +void AnnounceGraphicalEffect(int x, int y, int z, int Type); +void AnnounceTextualEffect(int x, int y, int z, int Color, const char *Text); +void AnnounceMissile(int OrigX, int OrigY, int OrigZ, + int DestX, int DestY, int DestZ, int Type); +void CheckTopMoveObject(uint32 CreatureID, Object Obj, Object Ignore); +void CheckTopUseObject(uint32 CreatureID, Object Obj); +void CheckTopMultiuseObject(uint32 CreatureID, Object Obj); +void CheckMoveObject(uint32 CreatureID, Object Obj, bool Take); +void CheckMapDestination(uint32 CreatureID, Object Obj, Object MapCon); +void CheckMapPlace(uint32 CreatureID, ObjectType Type, Object MapCon); void CheckContainerDestination(Object Obj, Object Con); +void CheckContainerPlace(ObjectType Type, Object Con, Object OldObj); +void CheckDepotSpace(uint32 CreatureID, Object Source, Object Destination, int Count); void CheckInventoryDestination(Object Obj, Object Con, bool Split); +void CheckInventoryPlace(ObjectType Type, Object Con, Object OldObj); +void CheckWeight(uint32 CreatureID, Object Obj, int Count); +void CheckWeight(uint32 CreatureID, ObjectType Type, uint32 Value, int OldWeight); +void NotifyCreature(uint32 CreatureID, Object Obj, bool Inventory); +void NotifyCreature(uint32 CreatureID, ObjectType Type, bool Inventory); +void NotifyAllCreatures(Object Obj, int Type, Object OldCon); +void NotifyTrades(Object Obj); +void NotifyDepot(uint32 CreatureID, Object Obj, int Count); +void CloseContainer(Object Con, bool Force); +Object Create(Object Con, ObjectType Type, uint32 Value); +Object Copy(Object Con, Object Source); +void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Object Ignore); +void Merge(uint32 CreatureID, Object Obj, Object Dest, int Count, Object Ignore); +void Change(Object Obj, ObjectType NewType, uint32 Value); +void Change(Object Obj, INSTANCEATTRIBUTE Attribute, uint32 Value); +void Delete(Object Obj, int Count); +void Empty(Object Con, int Remainder); +void GraphicalEffect(int x, int y, int z, int Type); +void GraphicalEffect(Object Obj, int Type); +void TextualEffect(Object Obj, int Color, const char *Format, ...) ATTR_PRINTF(3, 4); +void Missile(Object Start, Object Dest, int Type); #endif //TIBIA_OPERATE_HH_ diff --git a/src/stubs.hh b/src/stubs.hh index 4104dd3..c8b2e63 100644 --- a/src/stubs.hh +++ b/src/stubs.hh @@ -15,10 +15,7 @@ typedef void TRefreshSectorFunction(int SectorX, int SectorY, int SectorZ, const typedef void TSendMailsFunction(TPlayerData *PlayerData); extern void AbortWriter(void); -extern void AnnounceChangedCreature(uint32 CreatureID, int Type); -extern void AnnounceChangedObject(Object Obj, int Type); extern void BroadcastMessage(int Mode, const char *Text, ...) ATTR_PRINTF(2, 3); -extern void Change(Object Obj, ObjectType NewType, uint32 Value); extern void ChangeNPCState(TCreature *Npc, int NewState, bool Stimulus); extern void CharacterDeathOrder(TCreature *Creature, int OldLevel, uint32 Offender, const char *Remark, bool Unjustified); @@ -26,18 +23,14 @@ extern bool CheckRight(uint32 CreatureID, RIGHT Right); extern void CleanHouseField(int x, int y, int z); extern void ConvinceMonster(TCreature *Master, TCreature *Slave); extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster); -extern Object Create(Object Con, ObjectType Type, uint32 Value); extern Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value); extern TCreature *CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect); extern void CreatePlayerList(bool Online); extern void CreatePool(Object Con, ObjectType Type, uint32 Value); -extern void Delete(Object Obj, int Count); extern void GetExitPosition(uint16 HouseID, int *x, int *y, int *z); extern TConnection *GetFirstConnection(void); extern TConnection *GetNextConnection(void); extern TPlayer *GetPlayer(uint32 CreatureID); -extern void GraphicalEffect(int x, int y, int z, int Type); -extern void GraphicalEffect(Object Obj, int Type); extern int IdentifyPlayer(const char *Name, bool ExactMatch, bool IgnoreGamemasters, TPlayer **Player); extern void InitLog(const char *ProtocolName); extern void KickGuest(uint16 HouseID, TPlayer *Host, TPlayer *Guest); @@ -47,12 +40,8 @@ extern void LoadMonsterRaid(const char *FileName, int Start, bool *Type, int *Date, int *Interval, int *Duration); extern void Log(const char *ProtocolName, const char *Text, ...) ATTR_PRINTF(2, 3); extern void LogoutAllPlayers(void); -extern void Missile(Object Start, Object Dest, int Type); -extern void Merge(uint32 CreatureID, Object Obj, Object Dest, int Count, Object Ignore); -extern void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Object Ignore); extern void NetLoadCheck(void); extern void NetLoadSummary(void); -extern void NotifyAllCreatures(Object Obj, int Type, Object OldCon); extern void ProcessCommunicationControl(void); extern void ProcessConnections(void); extern void ProcessCronSystem(void); @@ -67,6 +56,7 @@ extern void SavePlayerDataOrder(void); extern void SendAll(void); extern void SendAmbiente(TConnection *Connection); extern void SendClearTarget(TConnection *Connection); +extern void SendContainer(TConnection *Connection, int ContainerNr); extern void SendCloseContainer(TConnection *Connection, int ContainerNr); extern void SendCloseTrade(TConnection *Connection); extern void SendCreatureHealth(TConnection *Connection, uint32 CreatureID); @@ -104,8 +94,10 @@ extern void ShowGuestList(uint16 HouseID, TPlayer *Player, char *Buffer); extern void ShowSubownerList(uint16 HouseID, TPlayer *Player, char *Buffer); extern void ShowNameDoor(Object Door, TPlayer *Player, char *Buffer); extern void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, bool CheckSpamming); -extern void TextualEffect(Object Obj, int Color, const char *Text, ...) ATTR_PRINTF(3, 4); extern void Turn(uint32 CreatureID, Object Obj); extern void Use(uint32 CreatureID, Object Obj1, Object Object2, uint8 Info); +extern void MovementEvent(Object Obj, Object Start, Object Dest); +extern void CollisionEvent(Object Obj, Object Dest); +extern void SeparationEvent(Object Obj, Object Start); #endif //TIBIA_STUBS_HH_ -- cgit v1.2.3