diff options
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | reference/game.c | 483 | ||||
| -rw-r--r-- | src/cr.hh | 4 | ||||
| -rw-r--r-- | src/cract.cc | 184 | ||||
| -rw-r--r-- | src/crcombat.cc | 15 | ||||
| -rw-r--r-- | src/crmain.cc | 22 | ||||
| -rw-r--r-- | src/enums.hh | 39 | ||||
| -rw-r--r-- | src/magic.cc | 16 | ||||
| -rw-r--r-- | src/objects.hh | 22 | ||||
| -rw-r--r-- | src/operate.cc | 82 | ||||
| -rw-r--r-- | src/operate.hh | 10 | ||||
| -rw-r--r-- | src/stubs.hh | 4 |
12 files changed, 367 insertions, 522 deletions
@@ -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)
@@ -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); |
