From eaa3536c027a4f7c1b879b78ab0ecdefcdb4833d Mon Sep 17 00:00:00 2001 From: fusion32 Date: Sun, 8 Jun 2025 19:54:40 -0300 Subject: impl `TCreature::Move` which was absolute hell + some tidying up --- Makefile | 8 +- reference/game.c | 483 ------------------------------------------------------- src/cr.hh | 4 + src/cract.cc | 184 ++++++++++++++++++++- src/crcombat.cc | 15 +- src/crmain.cc | 22 +-- src/enums.hh | 39 ++++- src/magic.cc | 16 +- src/objects.hh | 22 ++- src/operate.cc | 82 ++++++++++ src/operate.hh | 10 ++ src/stubs.hh | 4 + 12 files changed, 367 insertions(+), 522 deletions(-) create mode 100644 src/operate.cc create mode 100644 src/operate.hh diff --git a/Makefile b/Makefile index e3acc48..88234fe 100644 --- a/Makefile +++ b/Makefile @@ -13,9 +13,9 @@ else CFLAGS += -O2 endif -HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/config.hh $(SRCDIR)/connection.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/enums.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/objects.hh $(SRCDIR)/script.hh $(SRCDIR)/stubs.hh $(SRCDIR)/thread.hh +HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/config.hh $(SRCDIR)/connection.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/enums.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/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)/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)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/script.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/thread.obj $(BUILDDIR)/time.obj $(BUILDDIR)/util.obj $(CC) -c $(CFLAGS) $(LFLAGS) -o $@ $^ $(BUILDDIR)/config.obj: $(SRCDIR)/config.cc $(HEADERS) @@ -62,6 +62,10 @@ $(BUILDDIR)/objects.obj: $(SRCDIR)/objects.cc $(HEADERS) @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< +$(BUILDDIR)/operate.obj: $(SRCDIR)/operate.cc $(HEADERS) + @mkdir -p $(@D) + $(CC) -c $(CFLAGS) -o $@ $< + $(BUILDDIR)/script.obj: $(SRCDIR)/script.cc $(HEADERS) @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< diff --git a/reference/game.c b/reference/game.c index fec668b..7e6d16d 100644 --- a/reference/game.c +++ b/reference/game.c @@ -22210,58 +22210,6 @@ LAB_0808ffd8: __cxa_throw(puVar3,&RESULT::typeinfo,0); } - - -void CheckContainerDestination(Object *Obj,Object *Con) - -{ - bool bVar1; - undefined4 *puVar2; - int iVar3; - ulong uVar4; - ulong *puVar5; - Object local_4c [4]; - Object local_3c [4]; - ulong local_2c; - Object Help; - - local_2c = Con->ObjectID; - do { - puVar5 = &local_2c; - // try { // try from 08090164 to 08090227 has its CatchHandler @ 08090243 - Object::getObjectType(local_3c); - if (local_3c[0].ObjectID == 0) { - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,CHEST); - if (!bVar1) { - local_4c[0] = (Object)Con->ObjectID; - iVar3 = CountObjectsInContainer(local_4c); - Object::getObjectType(local_3c); - uVar4 = ObjectType::getAttribute((ObjectType *)local_3c,CAPACITY); - if ((int)uVar4 <= iVar3) { - puVar2 = (undefined4 *)__cxa_allocate_exception(4); - *puVar2 = 10; -LAB_080901af: - // WARNING: Subroutine does not return - __cxa_throw(puVar2,&RESULT::typeinfo,0); - } - } - return; - } - local_3c[0] = (Object)Obj->ObjectID; - if (local_2c == local_3c[0].ObjectID) { - puVar2 = (undefined4 *)__cxa_allocate_exception(4,puVar5); - *puVar2 = 9; - goto LAB_080901af; - } - Object::getContainer(local_4c); - local_3c[0].ObjectID = local_4c[0].ObjectID; - local_2c = local_4c[0].ObjectID; - } while( true ); -} - - - void CheckContainerPlace(ObjectType *Type,Object *Con,Object *oldObj) { @@ -22388,175 +22336,6 @@ LAB_080904cb: __cxa_throw(puVar3,&RESULT::typeinfo,0); } - - -void CheckInventoryDestination(Object *Obj,Object *Con,bool Split) - -{ - uint uVar1; - Object OVar2; - bool bVar3; - int ClothesType; - ulong uVar4; - ulong uVar5; - ulong uVar6; - undefined4 *puVar7; - int Position; - bool bVar8; - undefined4 uVar9; - int local_68; - int Hand; - ulong uStack_5c; - bool Split_local; - Object Help; - Object local_4c [4]; - ulong local_3c; - Object local_2c; - Object Help_1; - - local_2c = (Object)Con->ObjectID; - // try { // try from 08090584 to 08090930 has its CatchHandler @ 080909c5 - uVar4 = GetObjectBodyPosition(&local_2c); - uVar1 = uVar4 - 5; - if ((1 < uVar1) && (uVar4 != 10)) { - Object::getObjectType(&local_2c); - bVar3 = ObjectType::getFlag((ObjectType *)&local_2c,CLOTHES); - if (!bVar3) { - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 0xb; - goto LAB_0809079e; - } - Object::getObjectType(&local_2c); - uVar5 = ObjectType::getAttribute((ObjectType *)&local_2c,BODYPOSITION); - if (uVar5 == 0) { - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 0xc; - goto LAB_0809079e; - } - if (uVar4 != uVar5) { - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 0xd; - goto LAB_0809079e; - } - } - local_2c = (Object)Con->ObjectID; - uVar5 = GetObjectCreatureID(&local_2c); - Object::getObjectType(&local_2c); - bVar3 = ObjectType::getFlag((ObjectType *)&local_2c,CLOTHES); - if (bVar3) { - Object::getObjectType(&local_2c); - uVar6 = ObjectType::getAttribute((ObjectType *)&local_2c,BODYPOSITION); - if ((uVar6 == 0) && (uVar1 < 2)) { - uVar9 = 5; - uVar4 = uVar5; - GetBodyObject((ulong)&local_2c,uVar5); - bVar3 = false; - local_3c = NONE.ObjectID; - local_4c[0].ObjectID = NONE.ObjectID; - if ((local_2c.ObjectID != NONE.ObjectID) && - (uStack_5c = Obj->ObjectID, local_4c[0].ObjectID = uStack_5c, - local_2c.ObjectID != uStack_5c)) { - bVar3 = true; - } - if (!bVar3) { - uVar9 = 6; - GetBodyObject((ulong)local_4c,uVar5); - OVar2.ObjectID = local_4c[0].ObjectID; - bVar3 = false; - local_2c.ObjectID = local_4c[0].ObjectID; - bVar8 = local_4c[0].ObjectID != NONE.ObjectID; - uStack_5c = NONE.ObjectID; - local_4c[0].ObjectID = NONE.ObjectID; - if ((bVar8) && - (local_4c[0] = (Object)Obj->ObjectID, local_3c = local_4c[0].ObjectID, - OVar2.ObjectID != local_4c[0].ObjectID)) { - bVar3 = true; - } - uVar4 = uVar5; - if (!bVar3) { - return; - } - } - puVar7 = (undefined4 *)__cxa_allocate_exception(4,uVar4,uVar9); - *puVar7 = 0xe; - goto LAB_0809079e; - } - } - uVar6 = uVar5; - GetBodyObject((ulong)&stack0xffffffa4,uVar5); - local_4c[0].ObjectID = NONE.ObjectID; - local_3c = NONE.ObjectID; - if (uStack_5c == NONE.ObjectID) { - if (uVar1 < 2) { - local_68 = 5; - do { - GetBodyObject((ulong)&stack0xffffffa4,uVar5); - local_4c[0].ObjectID = NONE.ObjectID; - if (uStack_5c != NONE.ObjectID) { - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,CLOTHES); - if (bVar3) { - Object::getObjectType(local_4c); - uVar4 = ObjectType::getAttribute((ObjectType *)local_4c,BODYPOSITION); - if (uVar4 == 0) { - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 0xf; - goto LAB_0809079e; - } - } - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,WEAPON); - if (!bVar3) { - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,THROW); - if (!bVar3) { - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,BOW); - if (!bVar3) { - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,WAND); - if (!bVar3) goto LAB_080906c2; - } - } - } - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,WEAPON); - if (!bVar3) { - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,THROW); - if (!bVar3) { - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,BOW); - if (!bVar3) { - Object::getObjectType(local_4c); - bVar3 = ObjectType::getFlag((ObjectType *)local_4c,WAND); - if (!bVar3) goto LAB_080906c2; - } - } - } - if ((Split) || - (local_4c[0] = (Object)Obj->ObjectID, local_3c = local_4c[0].ObjectID, - uStack_5c != local_4c[0].ObjectID)) { - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 0x10; - goto LAB_0809079e; - } - } -LAB_080906c2: - local_68 = local_68 + 1; - } while (local_68 < 7); - } - return; - } - puVar7 = (undefined4 *)__cxa_allocate_exception(4,uVar6,uVar4); - *puVar7 = 4; -LAB_0809079e: - // WARNING: Subroutine does not return - __cxa_throw(puVar7,&RESULT::typeinfo,0); -} - - - void CheckInventoryPlace(ObjectType *Type,Object *Con,Object *OldObj) { @@ -43304,268 +43083,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority return; } -// DWARF original prototype: void Move(TCreature * this, Object * Obj, int zx, int zy, int zz, uchar -// Count) - -void __thiscall TCreature::Move(TCreature *this,Object *Obj,int zx,int zy,int zz,uchar Count) - -{ - bool bVar1; - bool bVar2; - ulong uVar3; - undefined4 *puVar4; - int *piVar5; - int Delay; - uint Count_00; - Object *Obj_00; - Object *pOVar6; - int iVar7; - int local_a0; - int b_1; - int b; - int iStack_94; - uchar Count_local; - int local_90; - Object local_8c [4]; - Object local_7c [4]; - Object local_6c; - Object DestCon; - Object local_5c; - Object DestObj; - Object local_4c [4]; - Object local_3c [4]; - Object local_2c; - Object Dest; - - b._3_1_ = Count; - // try { // try from 080bf7d5 to 080bfb3a has its CatchHandler @ 080c01e0 - bVar1 = Object::exists(Obj); - if (bVar1) { - local_2c.ObjectID = (this->CrObject).ObjectID; - if (Obj->ObjectID == local_2c.ObjectID) { - Go(this,zx,zy,zz); - return; - } - Object::getObjectType(&local_2c); - if (local_2c.ObjectID == 99) { - TCombat::DelayAttack(&this->Combat,2000); - } - Object::getObjectType(&local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_2c,CUMULATIVE); - // try { // try from 080bfff5 to 080c0037 has its CatchHandler @ 080c01e0 - if ((bVar1) && (uVar3 = Object::getAttribute(Obj,AMOUNT), uVar3 < Count)) { - uVar3 = Object::getAttribute(Obj,AMOUNT); - b._3_1_ = (byte)uVar3; - } - if (zx == 0xffff) { - if (zy == 0) { - b_1 = 1; - iVar7 = b_1; - do { - b_1 = iVar7; - local_6c = (Object)Obj->ObjectID; - // try { // try from 080bfb73 to 080bfb94 has its CatchHandler @ 080c003d - GetBodyContainer((ulong)&local_5c,this->ID); - CheckInventoryDestination(&local_6c,&local_5c,false); - if ((1 < b_1 - 5U) && (b_1 != 10)) break; - iVar7 = b_1 + 1; - } while (b_1 + 1 < 0xb); - zy = b_1; - if (b_1 == 0) { - local_a0 = 1; - do { - pOVar6 = (Object *)this->ID; - iVar7 = local_a0; - // try { // try from 080bfbe3 to 080bfc4b has its CatchHandler @ 080c01e0 - GetBodyObject((ulong)&local_6c,(int)pOVar6); - local_5c.ObjectID = ::NONE.ObjectID; - if (local_6c.ObjectID != ::NONE.ObjectID) { - Object::getObjectType(&local_5c); - pOVar6 = (Object *)0x4; - bVar1 = ObjectType::getFlag((ObjectType *)&local_5c,CONTAINER); - if (bVar1) { - pOVar6 = &local_5c; - local_5c.ObjectID = local_6c.ObjectID; - local_4c[0] = (Object)Obj->ObjectID; - // try { // try from 080bffcb to 080bffcf has its CatchHandler @ 080c0067 - CheckContainerDestination(local_4c,pOVar6); - b_1 = local_a0; - } - } - local_a0 = local_a0 + 1; - } while (local_a0 < 0xb); - zy = b_1; - if (b_1 == 0) { - puVar4 = (undefined4 *)__cxa_allocate_exception(4,pOVar6,iVar7); - *puVar4 = 4; - goto LAB_080bfb23; - } - } - } - if (((0 < zy) && (0x34 < zy - 0xbU)) && (zy < 0x50)) { - pOVar6 = &local_6c; - Obj_00 = (Object *)this->ID; - GetBodyContainer((ulong)pOVar6,(int)Obj_00); - local_5c.ObjectID = ::NONE.ObjectID; - if (zy < 0x40) { - Obj_00 = (Object *)this->ID; - GetBodyObject((ulong)local_3c,(int)Obj_00); - local_5c.ObjectID = local_3c[0].ObjectID; - } - else { - if (zz < 0xfe) { - ObjectType::setTypeID((ObjectType *)&local_2c,0); - Obj_00 = (Object *)this->ID; - GetObject((ulong)local_3c,(int)Obj_00,0xffff,zy,zz,(ObjectType *)zz); - local_5c.ObjectID = local_3c[0].ObjectID; - } - if (zz == 0xfe) { - local_4c[0].ObjectID = ::NONE.ObjectID; - if (local_6c.ObjectID == ::NONE.ObjectID) goto LAB_080bfeb5; - Object::getContainer(local_3c); - local_6c.ObjectID = local_3c[0].ObjectID; - Obj_00 = pOVar6; - } - } - bVar1 = false; - if (local_5c.ObjectID != ::NONE.ObjectID) { - local_4c[0].ObjectID = ::NONE.ObjectID; - local_3c[0].ObjectID = ::NONE.ObjectID; - Object::getObjectType(local_3c); - Obj_00 = (Object *)0x4; - bVar1 = ObjectType::getFlag((ObjectType *)local_3c,CONTAINER); - } - if (bVar1) { - local_6c.ObjectID = local_5c.ObjectID; - local_5c.ObjectID = ::NONE.ObjectID; - local_2c.ObjectID = ::NONE.ObjectID; - } - bVar1 = false; - local_4c[0].ObjectID = ::NONE.ObjectID; - local_3c[0].ObjectID = ::NONE.ObjectID; - if (local_5c.ObjectID != ::NONE.ObjectID) { - Object::getObjectType(local_3c); - Obj_00 = (Object *)0x6; - bVar2 = ObjectType::getFlag((ObjectType *)local_3c,CUMULATIVE); - if (bVar2) { - Object::getObjectType(local_3c); - Obj_00 = &local_5c; - Object::getObjectType(&local_2c); - if (local_3c[0].ObjectID == local_2c.ObjectID) { - bVar1 = true; - } - } - } - if (bVar1) { - Count_00 = (uint)b._3_1_; - Obj_00 = (Object *)0x2; - // try { // try from 080bfd46 to 080bfd4a has its CatchHandler @ 080c01e0 - uVar3 = Object::getAttribute(&local_5c,AMOUNT); - if (100 < uVar3 + Count_00) { - Obj_00 = (Object *)0x2; - // try { // try from 080bfdd1 to 080bffa7 has its CatchHandler @ 080c01e0 - uVar3 = Object::getAttribute(&local_5c,AMOUNT); - Count_00 = 100 - uVar3; - } - if (0 < (int)Count_00) { - Obj_00 = local_8c; - local_2c.ObjectID = ::NONE.ObjectID; - local_7c[0].ObjectID = local_5c.ObjectID; - local_8c[0] = (Object)Obj->ObjectID; - // try { // try from 080bfd98 to 080bfd9c has its CatchHandler @ 080c0082 - Merge(this->ID,Obj_00,local_7c,Count_00,&local_2c); - b._3_1_ = b._3_1_ - (char)Count_00; - if (b._3_1_ == 0) { - return; - } - } - local_7c[0] = (Object)::NONE.ObjectID; - local_5c.ObjectID = local_7c[0].ObjectID; - } - local_8c[0].ObjectID = ::NONE.ObjectID; - if (local_6c.ObjectID != ::NONE.ObjectID) { - local_7c[0].ObjectID = local_6c.ObjectID; - local_8c[0].ObjectID = local_5c.ObjectID; - local_4c[0] = (Object)Obj->ObjectID; - // try { // try from 080bfd13 to 080bfd17 has its CatchHandler @ 080c00b2 - ::Move(this->ID,local_4c,local_7c,(uint)b._3_1_,false,local_8c); - return; - } - puVar4 = (undefined4 *)__cxa_allocate_exception(4,Obj_00); - *puVar4 = 5; - goto LAB_080bfb23; - } - error(&DAT_08106e00,zy); - } - else { - GetMapContainer((int)&local_2c,zx,zy); - bVar1 = Object::exists(&local_2c); - if (bVar1) { - Object::getObjectType(local_3c); - bVar1 = ObjectType::getFlag((ObjectType *)local_3c,HANG); - if (bVar1) { - bVar1 = false; - bVar2 = CoordinateFlag(); - if ((bVar2) || (bVar2 = CoordinateFlag(), bVar2)) { - bVar1 = true; - } - if (bVar1) { - local_3c[0].ObjectID = local_2c.ObjectID; - bVar1 = ObjectInRange(this->ID,local_3c,1); - if (!bVar1) { - bVar1 = ToDoClear(this); - if ((bVar1) && (this->Type == PLAYER)) { - SendSnapback(this->Connection); - } - local_4c[0] = (Object)Obj->ObjectID; - uVar3 = GetObjectCreatureID(local_4c); - if (uVar3 != this->ID) { - local_5c = (Object)Obj->ObjectID; - ToDoMove(this,&local_5c,0xffff,0,0,'\x01'); - } - ToDoGo(this,zx,zy,zz,false,0x7fffffff); - local_5c = (Object)Obj->ObjectID; - ToDoMove(this,&local_5c,zx,zy,zz,'\x01'); - if (this->NrToDo == 0) { - return; - } - this->LockToDo = true; - this->ActToDo = 0; - local_90 = CalculateDelay(this); - iStack_94 = 1; - piVar5 = &stack0xffffff6c; - if (0 < local_90) { - piVar5 = &local_90; - } - iVar7 = *piVar5; - priority_queue<>::insert(&ToDoQueue); - this->NextWakeup = iVar7 + ServerMilliseconds; - return; - } - } - } - local_5c.ObjectID = ::NONE.ObjectID; - local_4c[0].ObjectID = local_2c.ObjectID; - local_6c = (Object)Obj->ObjectID; - ::Move(this->ID,&local_6c,local_4c,(uint)b._3_1_,false,&local_5c); - return; - } - } - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0xffffffff; - } - else { -LAB_080bfeb5: - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 1; - } -LAB_080bfb23: - // WARNING: Subroutine does not return - __cxa_throw(puVar4,&RESULT::typeinfo,0); -} - - - // DWARF original prototype: void Trade(TCreature * this, Object * Obj, ulong PartnerID) void __thiscall TCreature::Trade(TCreature *this,Object *Obj,ulong PartnerID) diff --git a/src/cr.hh b/src/cr.hh index 37a9f3d..2c60163 100644 --- a/src/cr.hh +++ b/src/cr.hh @@ -499,6 +499,10 @@ struct TCreature: TSkillBase { void Go(int DestX, int DestY, int DestZ); void Rotate(int Direction); void Rotate(TCreature *Target); + void Move(Object Obj, int DestX, int DestY, int DestZ, uint8 Count); + void Trade(Object Obj, uint32 TradePartner); + void Use(Object Obj1, Object Obj2, uint8 Dummy); + void Turn(Object Obj); void Attack(void); void Execute(void); uint32 CalculateDelay(void); diff --git a/src/cract.cc b/src/cract.cc index c4e85b6..8306ad5 100644 --- a/src/cract.cc +++ b/src/cract.cc @@ -1,4 +1,5 @@ #include "cr.hh" +#include "operate.hh" #include "stubs.hh" @@ -387,7 +388,7 @@ void TCreature::Go(int DestX, int DestY, int DestZ){ } Object Dest = GetMapContainer(DestX, DestY, DestZ); - Move(this->ID, this->CrObject, Dest, -1, false, NONE); + ::Move(this->ID, this->CrObject, Dest, -1, false, NONE); } void TCreature::Rotate(int Direction){ @@ -415,6 +416,185 @@ void TCreature::Rotate(TCreature *Target){ this->Rotate(Direction); } +void TCreature::Move(Object Obj, int DestX, int DestY, int DestZ, uint8 Count){ + // NOTE(fusion): What a disaster. + + if(!Obj.exists()){ + throw NOTACCESSIBLE; + } + + if(Obj == this->CrObject){ + this->Go(DestX, DestY, DestZ); + return; + } + + ObjectType ObjType = Obj.getObjectType(); + if(ObjType.isCreatureContainer()){ + this->Combat.DelayAttack(2000); + } + + int MoveCount = (int)Count; + if(ObjType.getFlag(CUMULATIVE)){ + int ObjAmount = (int)Obj.getAttribute(AMOUNT); + if(MoveCount > ObjAmount){ + MoveCount = ObjAmount; + } + } + + if(DestX == 0xFFFF){ // SPECIAL_COORDINATE ? + // NOTE(fusion): Any inventory slot. + if(DestY == 0){ + // NOTE(fusion): `CheckInventoryDestination` will throw if it's not + // possible to place the object on the chosen container. We want to + // find a slot that doesn't make it throw while giving priority to + // non hand or ammo slots. + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ + try{ + Object Con = GetBodyContainer(this->ID, Position); + CheckInventoryDestination(Obj, Con, false); + }catch(...){ + continue; + } + + DestY = Position; + if(Position != INVENTORY_RIGHTHAND + && Position != INVENTORY_LEFTHAND + && Position != INVENTORY_AMMO){ + break; + } + } + + // NOTE(fusion): No appropriate inventory slot was found so we now + // fallback to inventory containers. For whatever reason we don't + // give priority to the bag slot. + if(DestY == 0){ + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ + Object Con = GetBodyObject(this->ID, Position); + if(Con != NONE && Con.getObjectType().getFlag(CONTAINER)){ + try{ + CheckContainerDestination(Obj, Con); + }catch(RESULT r){ + continue; + } + + DestY = Position; + } + } + } + + if(DestY == 0){ + throw NOROOM; + } + } + + Object DestCon = NONE; + Object DestObj = NONE; + if(DestY >= INVENTORY_FIRST && DestY <= INVENTORY_LAST){ + DestCon = GetBodyContainer(this->ID, DestY); + DestObj = GetBodyObject(this->ID, DestY); + }else if(DestY >= 64 && DestY < 80){ + DestCon = GetBodyContainer(this->ID, DestY); + if(DestZ < 254){ + // TODO(fusion): The last argument to `GetObject` is the object + // type we expect to find and it seems that the type id of a map + // container (which is 0) can be used as a wildcard for any object + // it finds. + DestObj = GetObject(this->ID, DestX, DestY, DestZ, DestZ, 0); + }else if(DestZ == 254){ + if(DestCon == NONE){ + throw NOTACCESSIBLE; + } + DestCon = DestCon.getContainer(); + } + }else{ + error("TCreature::Move: Ungültiger Containercode %d.\n", DestY); + throw ERROR; + } + + if(DestObj != NONE){ + ObjectType DestObjType = DestObj.getObjectType(); + if(DestObjType.getFlag(CONTAINER)){ + DestCon = DestObj; + DestObj = NONE; + }else if(DestObjType.getFlag(CUMULATIVE) && DestObjType == ObjType){ + int DestAmount = (int)DestObj.getAttribute(AMOUNT); + int MergeCount = MoveCount; + if((DestAmount + MergeCount) > 100){ + MergeCount = 100 - DestAmount; + } + + if(MergeCount > 0){ + try{ + ::Merge(this->ID, Obj, DestObj, MergeCount, NONE); + MoveCount -= MergeCount; + if(MoveCount <= 0){ + return; + } + }catch(RESULT r){ + if(r == TOOHEAVY){ + throw; + } + } + } + + DestObj = NONE; + } + } + + if(DestCon == NONE){ + throw OUTOFRANGE; + } + + try{ + // TODO(fusion): Find out what is this last parameter to `Move`. + ::Move(this->ID, Obj, DestCon, MoveCount, false, DestObj); + }catch(RESULT r){ + // NOTE(fusion): Attempt to exchange inventory items. + if(DestY < 64 && DestObj != NONE + && (r == NOROOM + || r == HANDSNOTFREE + || r == HANDBLOCKED + || r == ONEWEAPONONLY)){ + Object ObjCon = Obj.getContainer(); + ::Move(this->ID, DestObj, ObjCon, -1, false, NONE); + ::Move(this->ID, Obj, DestCon, MoveCount, false, NONE); + }else{ + throw; + } + } + }else{ + Object Dest = GetMapContainer(DestX, DestY, DestZ); + if(!Dest.exists()){ + throw ERROR; + } + + if(ObjType.getFlag(HANG) + && (CoordinateFlag(DestX, DestY, DestZ, HOOKSOUTH) + || CoordinateFlag(DestY, DestY, DestZ, HOOKEAST)) + && !ObjectInRange(this->ID, Dest, 1)){ + if(this->ToDoClear() && this->Type == PLAYER){ + SendSnapback(this->Connection); + } + + // NOTE(fusion): Pick up object if it's not in our inventory. + if(GetObjectCreatureID(Obj) != this->ID){ + this->ToDoMove(Obj, 0xFFFF, 0, 0, 1); + } + + // NOTE(fusion): Walk to destination then try again. + this->ToDoGo(DestX, DestY, DestZ, false, INT_MAX); + this->ToDoMove(Obj, DestX, DestY, DestZ, 1); + this->ToDoStart(); + }else{ + ::Move(this->ID, Obj, Dest, MoveCount, false, NONE); + } + } +} + void TCreature::Attack(void){ this->Combat.Attack(); } @@ -460,7 +640,7 @@ void TCreature::Execute(void){ } case TDMove:{ - this->Move(TD.Move.Obj, TD.Move.x, TD.Move.y, TD.Move.z, TD.Move.Count); + this->Move(TD.Move.Obj, TD.Move.x, TD.Move.y, TD.Move.z, (uint8)TD.Move.Count); break; } diff --git a/src/crcombat.cc b/src/crcombat.cc index dd732e3..25fff0e 100644 --- a/src/crcombat.cc +++ b/src/crcombat.cc @@ -48,10 +48,10 @@ void TCombat::GetWeapon(void){ return; } - // TODO(fusion): We're iterating over left and right hand slots. Make - // it clearer perhaps. - for(int Hand = 5; Hand <= 6; Hand += 1){ - Object Obj = GetBodyObject(Master->ID, Hand); + for(int Position = INVENTORY_HAND_FIRST; + Position <= INVENTORY_HAND_LAST; + Position += 1){ + Object Obj = GetBodyObject(Master->ID, Position); if(Obj == NONE){ continue; } @@ -111,7 +111,7 @@ void TCombat::GetAmmo(void){ } // TODO(fusion): Check if `Master` is NULL? - Object Ammo = GetBodyObject(this->Master->ID, 10); + Object Ammo = GetBodyObject(this->Master->ID, INVENTORY_AMMO); this->Ammo = NONE; if(Ammo != NONE){ ObjectType AmmoType = Ammo.getObjectType(); @@ -283,10 +283,11 @@ int TCombat::GetDefendDamage(void){ } int TCombat::GetArmorStrength(void){ - // TODO(fusion): We're iterating over inventory slots. Make it clearer? int Armor = 0; TCreature *Master = this->Master; - for(int Position = 1; Position <= 10; Position += 1){ + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ Object Obj = GetBodyObject(Master->ID, Position); if(Obj.exists()){ ObjectType ObjType = Obj.getObjectType(); diff --git a/src/crmain.cc b/src/crmain.cc index 5d0f2f3..00cd3e2 100644 --- a/src/crmain.cc +++ b/src/crmain.cc @@ -226,7 +226,9 @@ TCreature::~TCreature(void){ } if(this->LoseInventory != 0){ // LOSE_INVENTORY_NONE ? - for(int Position = 1; Position <= 10; Position += 1){ + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ Object Item = GetBodyObject(this->ID, Position); if(Item == NONE){ continue; @@ -238,7 +240,7 @@ TCreature::~TCreature(void){ continue; } - Move(0, Item, Corpse, -1, false, NONE); + ::Move(0, Item, Corpse, -1, false, NONE); } } @@ -487,10 +489,8 @@ int TCreature::Damage(TCreature *Attacker, int Damage, int DamageType){ Damage = 0; } - // NOTE(fusion): We're iterating over the victim's inventory to apply - // damage reductions, while the damage is greater than zero. - for(int Position = 1; - Position <= 10 && Damage > 0; + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST && Damage > 0; Position += 1){ Object Obj = GetBodyObject(this->ID, Position); if(Obj == NONE){ @@ -739,7 +739,9 @@ int TCreature::Damage(TCreature *Attacker, int Damage, int DamageType){ if(Damage == HitPoints){ if(this->Type == PLAYER){ - for(int Position = 1; Position <= 10; Position += 1){ + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ Object Obj = GetBodyObject(this->ID, Position); if(Obj == NONE){ continue; @@ -2026,11 +2028,11 @@ void ProcessMonsterRaids(void){ } TCreature *Creature = Spawned[random(0, NumSpawned - 1)]; - Object Bag = GetBodyObject(Creature->ID, 3); // BAG ? + Object Bag = GetBodyObject(Creature->ID, INVENTORY_BAG); if(Bag == NONE){ try{ - Bag = Create(GetBodyContainer(Creature->ID, 3), - GetSpecialObject(INVENTORY_CONTAINER), + Bag = Create(GetBodyContainer(Creature->ID, INVENTORY_BAG), + GetSpecialObject(DEFAULT_CONTAINER), 0); }catch(RESULT r){ error("ProcessMonsterRaids: Exception %d bei Rasse %d" diff --git a/src/enums.hh b/src/enums.hh index 2505618..6efcf61 100644 --- a/src/enums.hh +++ b/src/enums.hh @@ -221,6 +221,29 @@ enum INSTANCEATTRIBUTE: int { REMAININGUSES = 17, }; +// NOTE(fusion): Not in debug symbols. +enum InventorySlot: int { + INVENTORY_ANY = 0, + INVENTORY_HEAD = 1, + INVENTORY_NECK = 2, + INVENTORY_BAG = 3, + INVENTORY_TORSO = 4, + INVENTORY_RIGHTHAND = 5, + INVENTORY_LEFTHAND = 6, + INVENTORY_LEGS = 7, + INVENTORY_FEET = 8, + INVENTORY_FINGER = 9, + INVENTORY_AMMO = 10, + + // NOTE(fusion): For iterating over inventory slots. + INVENTORY_FIRST = INVENTORY_HEAD, + INVENTORY_LAST = INVENTORY_AMMO, + + // NOTE(fusion): For iterating over hand slots. + INVENTORY_HAND_FIRST = INVENTORY_RIGHTHAND, + INVENTORY_HAND_LAST = INVENTORY_LEFTHAND, +}; + enum KNOWNCREATURESTATE: int { KNOWNCREATURE_FREE = 0, KNOWNCREATURE_UPTODATE = 1, @@ -435,16 +458,20 @@ enum Skill: int { SKILL_SOUL = 22, }; +// IMPORTANT(fusion): All `DEFAULT_*` values here were renamed from `INVENTORY_*` +// to avoid collisions with `InventorySlot`. I could also have chosen other prefix +// for inventory slots but I feel we'd be wasting them here where their meaning +// were also not clear. enum SPECIALMEANING: int { MONEY_ONE = 1, MONEY_HUNDRED = 2, MONEY_TENTHOUSAND = 3, - INVENTORY_RIGHTHAND = 10, - INVENTORY_LEFTHAND = 11, - INVENTORY_BODY_MALE = 12, - INVENTORY_BODY_FEMALE = 13, - INVENTORY_CONTAINER = 14, - INVENTORY_FOOD = 15, + DEFAULT_RIGHTHAND = 10, + DEFAULT_LEFTHAND = 11, + DEFAULT_BODY_MALE = 12, + DEFAULT_BODY_FEMALE = 13, + DEFAULT_CONTAINER = 14, + DEFAULT_FOOD = 15, DEPOT_LOCKER = 20, DEPOT_CHEST = 21, PARCEL_NEW = 22, diff --git a/src/magic.cc b/src/magic.cc index 1caf83b..a222b3a 100644 --- a/src/magic.cc +++ b/src/magic.cc @@ -2409,7 +2409,9 @@ void CancelInvisibility(TCreature *Actor, Object Target, int ManaPoints, int Sou // it on pvp enforced worlds. // TODO(fusion): This is probably an inlined function. if(WorldType == PVP_ENFORCED){ - for(int Position = 1; Position <= 10; Position += 1){ + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ Object Item = GetBodyObject(Victim->ID, Position); if(Item == NONE){ continue; @@ -2516,8 +2518,8 @@ void ChangeData(TCreature *Actor, const char *Param){ return; } - Object RightHand = GetBodyObject(Actor->ID, 5); // RIGHTHAND ? - Object LeftHand = GetBodyObject(Actor->ID, 6); // LEFTHAND ? + Object RightHand = GetBodyObject(Actor->ID, INVENTORY_RIGHTHAND); + Object LeftHand = GetBodyObject(Actor->ID, INVENTORY_LEFTHAND); if(RightHand != NONE && LeftHand != NONE){ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE, "First drop one object."); return; @@ -2578,9 +2580,9 @@ void EnchantObject(TCreature *Actor, int ManaPoints, int SoulPoints, ObjectType throw ERROR; } - Object Obj = GetBodyObject(Actor->ID, 5); // RIGHTHAND ? + Object Obj = GetBodyObject(Actor->ID, INVENTORY_RIGHTHAND); if(Obj == NONE || Obj.getObjectType() != OldType){ - Obj = GetBodyObject(Actor->ID, 6); // LEFTHAND ? + Obj = GetBodyObject(Actor->ID, INVENTORY_LEFTHAND); if(Obj == NONE || Obj.getObjectType() != OldType){ throw MAGICITEM; } @@ -3670,7 +3672,7 @@ static void RuneSpell(uint32 CreatureID, int SpellNr){ bool RuneCreated = false; ObjectType BlankType = GetSpecialObject(RUNE_BLANK); - Object RightHand = GetBodyObject(Actor->ID, 5); // RIGHTHAND + Object RightHand = GetBodyObject(Actor->ID, INVENTORY_RIGHTHAND); if(RightHand.exists() && RightHand.getObjectType() == BlankType){ CheckMana(Actor, ManaPoints, SoulPoints, 1000); ObjectType RuneType = GetNewObjectType(RuneGr, RuneNr); @@ -3678,7 +3680,7 @@ static void RuneSpell(uint32 CreatureID, int SpellNr){ RuneCreated = true; } - Object LeftHand = GetBodyObject(Actor->ID, 6); // LEFTHAND + Object LeftHand = GetBodyObject(Actor->ID, INVENTORY_LEFTHAND); if(LeftHand.exists() && LeftHand.getObjectType() == BlankType){ // TODO(fusion): Ughh... I'm not sure why we're trying to cast the spell // twice but we need to make so errors from the second cast are only diff --git a/src/objects.hh b/src/objects.hh index 39fa8aa..48dbedf 100644 --- a/src/objects.hh +++ b/src/objects.hh @@ -8,7 +8,7 @@ enum : int{ TYPEID_MAP_CONTAINER = 0, TYPEID_HEAD_CONTAINER = 1, TYPEID_NECK_CONTAINER = 2, - TYPEID_BACKPACK_CONTAINER = 3, + TYPEID_BAG_CONTAINER = 3, TYPEID_TORSO_CONTAINER = 4, TYPEID_RIGHTHAND_CONTAINER = 5, TYPEID_LEFTHAND_CONTAINER = 6, @@ -29,14 +29,14 @@ struct ObjectType { const char *getName(int Count); const char *getDescription(void); - bool isMapContainer(void) const { + bool isMapContainer(void){ return this->TypeID == TYPEID_MAP_CONTAINER; } - bool isBodyContainer(void) const { + bool isBodyContainer(void){ return this->TypeID == TYPEID_HEAD_CONTAINER || this->TypeID == TYPEID_NECK_CONTAINER - || this->TypeID == TYPEID_BACKPACK_CONTAINER + || this->TypeID == TYPEID_BAG_CONTAINER || this->TypeID == TYPEID_TORSO_CONTAINER || this->TypeID == TYPEID_RIGHTHAND_CONTAINER || this->TypeID == TYPEID_LEFTHAND_CONTAINER @@ -46,10 +46,22 @@ struct ObjectType { || this->TypeID == TYPEID_AMMO_CONTAINER; } - bool isCreatureContainer(void) const { + bool isCreatureContainer(void){ return this->TypeID == TYPEID_CREATURE_CONTAINER; } + bool isTwoHanded(void){ + return this->getFlag(CLOTHES) + && this->getAttribute(BODYPOSITION) == 0; + } + + bool isWeapon(void){ + return this->getFlag(WEAPON) + || this->getFlag(BOW) + || this->getFlag(THROW) + || this->getFlag(WAND); + } + bool operator==(const ObjectType &Other) const { return this->TypeID == Other.TypeID; } diff --git a/src/operate.cc b/src/operate.cc new file mode 100644 index 0000000..ef1ba01 --- /dev/null +++ b/src/operate.cc @@ -0,0 +1,82 @@ +#include "operate.hh" + +#include "stubs.hh" + +// 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; + } + Help = Help.getContainer(); + } + + ObjectType ConType = Con.getObjectType(); + if(!ConType.getFlag(CHEST)){ + int ConObjects = CountObjectsInContainer(Con); + int ConCapacity = (int)ConType.getAttribute(CAPACITY); + if(ConObjects >= ConCapacity){ + throw CONTAINERFULL; + } + } +} + +void CheckInventoryDestination(Object Obj, Object Con, bool Split){ + ObjectType ObjType = Obj.getObjectType(); + int ConPosition = GetObjectBodyPosition(Con); + bool HandContainer = ConPosition == INVENTORY_RIGHTHAND + || ConPosition == INVENTORY_LEFTHAND; + + if(!HandContainer && ConPosition != INVENTORY_AMMO){ + if(!ObjType.getFlag(CLOTHES)){ + throw WRONGPOSITION; + } + + int ObjPosition = (int)ObjType.getAttribute(BODYPOSITION); + if(ObjPosition == 0){ + throw WRONGPOSITION2; + }else if(ObjPosition != ConPosition){ + throw WRONGCLOTHES; + } + } + + uint32 CreatureID = GetObjectCreatureID(Con); + if(ObjType.isTwoHanded() && HandContainer){ + Object RightHand = GetBodyObject(CreatureID, INVENTORY_RIGHTHAND); + if(RightHand != NONE && RightHand != Obj){ + throw HANDSNOTFREE; + } + + Object LeftHand = GetBodyObject(CreatureID, INVENTORY_LEFTHAND); + if(LeftHand != NONE && LeftHand != Obj){ + throw HANDSNOTFREE; + } + + return; + } + + if(GetBodyObject(CreatureID, ConPosition) != NONE){ + throw NOROOM; + } + + if(HandContainer){ + for(int Position = INVENTORY_HAND_FIRST; + Position <= INVENTORY_HAND_LAST; + Position += 1){ + Object Other = GetBodyObject(CreatureID, Position); + if(Other != NONE){ + ObjectType OtherType = Other.getObjectType(); + if(OtherType.isTwoHanded()){ + throw HANDBLOCKED; + } + + if(Split || Other != Obj){ + if(OtherType.isWeapon() && ObjType.isWeapon()){ + throw ONEWEAPONONLY; + } + } + } + } + } +} diff --git a/src/operate.hh b/src/operate.hh new file mode 100644 index 0000000..6270ec7 --- /dev/null +++ b/src/operate.hh @@ -0,0 +1,10 @@ +#ifndef TIBIA_OPERATE_HH_ +#define TIBIA_OPERATE_HH_ 1 + +#include "common.hh" +#include "map.hh" + +void CheckContainerDestination(Object Obj, Object Con); +void CheckInventoryDestination(Object Obj, Object Con, bool Split); + +#endif //TIBIA_OPERATE_HH_ diff --git a/src/stubs.hh b/src/stubs.hh index f2f1f0b..867d813 100644 --- a/src/stubs.hh +++ b/src/stubs.hh @@ -27,6 +27,7 @@ extern void CleanHouseField(int x, int y, int z); extern void ConvinceMonster(TCreature *Master, TCreature *Slave); extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster); extern int CountInventoryObjects(uint32 CreatureID, ObjectType Type, uint32 Value); +extern int CountObjectsInContainer(Object Con); 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); @@ -36,12 +37,14 @@ extern void Delete(Object Obj, int Count); extern bool FieldPossible(int x, int y, int z, int FieldType); extern Object GetBodyObject(uint32 CreatureID, int Position); extern Object GetBodyContainer(uint32 CreatureID, int Position); +extern int GetObjectBodyPosition(Object Obj); extern void GetExitPosition(uint16 HouseID, int *x, int *y, int *z); extern TConnection *GetFirstConnection(void); extern int GetHeight(int x, int y, int z); extern TConnection *GetNextConnection(void); extern const char *GetName(Object Obj); extern Object GetObject(uint32 CreatureID, int x, int y, int z, int RNum, ObjectType Type); +extern uint32 GetObjectCreatureID(Object Obj); extern TPlayer *GetPlayer(uint32 CreatureID); extern void GraphicalEffect(int x, int y, int z, int Type); extern void GraphicalEffect(Object Obj, int Type); @@ -55,6 +58,7 @@ extern void LoadMonsterRaid(const char *FileName, int Start, 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); -- cgit v1.2.3