From b167d45f88cfb824a96c3a5a120c34c30768ecda Mon Sep 17 00:00:00 2001 From: fusion32 Date: Wed, 11 Jun 2025 01:56:41 -0300 Subject: first look at `operate.cc` --- TODO.md | 4 +- reference/game.c | 455 ------------------------------------------------------- src/cract.cc | 3 +- src/operate.cc | 272 +++++++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 458 deletions(-) diff --git a/TODO.md b/TODO.md index 32dcda7..2d28ca4 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,8 @@ ## TODO NEXT -- INFO.CC - OPERATE.CC - HOUSES.CC -- CRPLAYER.CC, CRNONPL.CC +- CRPLAYER.CC +- CRNONPL.CC - MOVEUSE.CC - SENDING.CC - RECEIVING.CC diff --git a/reference/game.c b/reference/game.c index c00ab3e..213e714 100644 --- a/reference/game.c +++ b/reference/game.c @@ -20717,461 +20717,6 @@ LAB_080926bf: __cxa_throw(puVar3,&RESULT::typeinfo,0); } - - -void Move(ulong CreatureID,Object *Obj,Object *Con,int Count,bool NoMerge,Object *Ignore) - -{ - Object OVar1; - bool bVar2; - TCreature *cr; - ulong uVar3; - TCreature *pTVar4; - int iVar5; - undefined4 *puVar6; - TCreature *cr_1; - char *Text; - Object *pOVar7; - Object *Destination; - ulong oldCreature; - Object *local_94; - int x; - int y; - int z; - int x_1; - int y_1; - int z_1; - Object Rest; - Object local_6c; - Object oldCon; - Object local_5c [4]; - Object local_4c [4]; - Object local_3c; - Object Top; - Object local_2c [7]; - - // try { // try from 0809276c to 08092fab has its CatchHandler @ 08093120 - bVar2 = Object::exists(Obj); - if (bVar2) { - bVar2 = Object::exists(Con); - if (!bVar2) { - error("Move: Zielobjekt existiert nicht.\n"); - local_2c[0] = (Object)Obj->ObjectID; - GetObjectCoordinates(local_2c,&z,&x_1,&y_1); - Object::getObjectType(local_2c); - error("# Objekt %d an [%d,%d,%d]\n",local_2c[0].ObjectID,z,x_1,y_1); - goto LAB_08093028; - } - Object::getObjectType(local_2c); - bVar2 = ObjectType::getFlag((ObjectType *)local_2c,CONTAINER); - if (bVar2) { - Object::getObjectType(local_2c); - pOVar7 = (Object *)0x6; - bVar2 = ObjectType::getFlag((ObjectType *)local_2c,CUMULATIVE); - if (!bVar2) { -LAB_08092800: - OVar1.ObjectID = local_3c.ObjectID; - if ((!NoMerge) && - (pOVar7 = Con, Object::getObjectType(local_2c), - OVar1.ObjectID = local_3c.ObjectID, local_2c[0].ObjectID == 0)) { - Object::getObjectType(local_2c); - pOVar7 = (Object *)0x6; - bVar2 = ObjectType::getFlag((ObjectType *)local_2c,CUMULATIVE); - OVar1.ObjectID = local_3c.ObjectID; - if (bVar2) { - pOVar7 = Obj; - Object::getContainer(local_2c); - local_3c = (Object)Con->ObjectID; - OVar1.ObjectID = local_2c[0].ObjectID; - if (local_3c.ObjectID != local_2c[0].ObjectID) { - GetObjectCoordinates(&local_3c,(int *)&local_94,&x,&y); - GetTopObject((int)&local_3c,(int)local_94,x,(bool)(undefined1)y); - local_5c[0] = (Object)NONE.ObjectID; - local_4c[0].ObjectID = NONE.ObjectID; - pOVar7 = local_94; - OVar1.ObjectID = local_3c.ObjectID; - if (local_3c.ObjectID != NONE.ObjectID) { - local_5c[0] = (Object)Ignore->ObjectID; - local_6c.ObjectID = local_3c.ObjectID; - z_1 = Obj->ObjectID; - // try { // try from 08092ff7 to 08092ffb has its CatchHandler @ 080930df - Merge(CreatureID,(Object *)&z_1,&local_6c,Count,local_5c); - return; - } - } - } - } - local_3c.ObjectID = OVar1.ObjectID; - bVar2 = Object::exists(Obj); - if (!bVar2) { - error(&DAT_080ff6c0,pOVar7); - } - Object::getObjectType((Object *)&z_1); - bVar2 = ObjectType::getFlag((ObjectType *)&z_1,CUMULATIVE); - if ((bVar2) && (Count == -1)) { - Count = Object::getAttribute(Obj,AMOUNT); - } - z_1 = Ignore->ObjectID; - local_6c = (Object)Obj->ObjectID; - CheckTopMoveObject(CreatureID,&local_6c,(Object *)&z_1); - Object::getObjectType((Object *)&z_1); - bVar2 = z_1 != 0; - z_1 = Obj->ObjectID; - CheckMoveObject(CreatureID,(Object *)&z_1,bVar2); - Object::getObjectType((Object *)&z_1); - if (z_1 == 0) { - z_1 = Con->ObjectID; - local_6c = (Object)Obj->ObjectID; - CheckMapDestination(CreatureID,&local_6c,(Object *)&z_1); - } - else { - oldCreature._3_1_ = false; - Object::getObjectType((Object *)&z_1); - bVar2 = ObjectType::getFlag((ObjectType *)&z_1,CUMULATIVE); - if ((bVar2) && (uVar3 = Object::getAttribute(Obj,AMOUNT), Count < (int)uVar3)) { - oldCreature._3_1_ = true; - } - Object::getObjectType((Object *)&z_1); - bVar2 = false; - if ((0 < z_1) && (z_1 < 0xb)) { - bVar2 = true; - } - if (bVar2) { - z_1 = Con->ObjectID; - local_6c = (Object)Obj->ObjectID; - CheckInventoryDestination(&local_6c,(Object *)&z_1,oldCreature._3_1_); - } - else { - z_1 = Con->ObjectID; - local_6c = (Object)Obj->ObjectID; - CheckContainerDestination(&local_6c,(Object *)&z_1); - } - if (oldCreature._3_1_ == false) { - z_1 = Obj->ObjectID; - iVar5 = CountObjects((Object *)&z_1); - local_6c = (Object)Con->ObjectID; - pOVar7 = local_5c; - local_5c[0] = (Object)Obj->ObjectID; - Destination = &local_6c; - } - else { - z_1 = Con->ObjectID; - iVar5 = 1; - local_6c.ObjectID = NONE.ObjectID; - pOVar7 = &local_6c; - Destination = (Object *)&z_1; - } - CheckDepotSpace(CreatureID,pOVar7,Destination,iVar5); - z_1 = Con->ObjectID; - uVar3 = GetObjectCreatureID((Object *)&z_1); - if (uVar3 != 0) { - z_1 = Obj->ObjectID; - CheckWeight(uVar3,(Object *)&z_1,Count); - } - } - z_1 = NONE.ObjectID; - Object::getObjectType(&local_6c); - bVar2 = ObjectType::getFlag((ObjectType *)&local_6c,CUMULATIVE); - if ((bVar2) && (uVar3 = Object::getAttribute(Obj,AMOUNT), Count < (int)uVar3)) { - z_1 = Obj->ObjectID; - local_6c.ObjectID = z_1; - local_5c[0].ObjectID = z_1; - local_4c[0].ObjectID = z_1; - SplitObject(local_5c,(int)local_4c); - local_6c.ObjectID = local_5c[0].ObjectID; - Obj->ObjectID = (ulong)local_5c[0]; - } - Object::getContainer(&local_6c); - local_5c[0] = (Object)Obj->ObjectID; - pOVar7 = (Object *)GetObjectCreatureID(local_5c); - local_5c[0].ObjectID = local_6c.ObjectID; - local_4c[0].ObjectID = local_6c.ObjectID; - if (Con->ObjectID != local_6c.ObjectID) { - local_3c = (Object)Obj->ObjectID; - SeparationEvent(&local_3c,local_4c); - } - Object::getObjectType(local_5c); - if ((local_5c[0].ObjectID != 99) && - (local_5c[0].ObjectID = NONE.ObjectID, z_1 == NONE.ObjectID)) { - local_4c[0] = (Object)Obj->ObjectID; - AnnounceChangedObject(local_4c,0); - local_4c[0] = (Object)Obj->ObjectID; - NotifyTrades(local_4c); - local_4c[0] = (Object)Obj->ObjectID; - iVar5 = CountObjects(local_4c); - local_3c = (Object)Obj->ObjectID; - NotifyDepot(CreatureID,&local_3c,iVar5); - } - Object::getObjectType(local_5c); - bVar2 = ObjectType::getFlag((ObjectType *)local_5c,CONTAINER); - if ((bVar2) && (CreatureID == 0)) { - local_5c[0] = (Object)Obj->ObjectID; - CloseContainer(local_5c,true); - } - Object::getObjectType(local_5c); - if (local_5c[0].ObjectID == 99) { - local_5c[0] = (Object)Obj->ObjectID; - pTVar4 = GetCreature(local_5c); - if (pTVar4 == (TCreature *)0x0) { - uVar3 = Object::getCreatureID(Obj); - error(&DAT_080ff680,uVar3); - } - else { - local_5c[0] = (Object)Con->ObjectID; - TCreature::NotifyTurn(pTVar4,local_5c); - } - local_5c[0] = (Object)Con->ObjectID; - uVar3 = Object::getCreatureID(Obj); - AnnounceMovingCreature(uVar3,local_5c); - } - local_5c[0] = (Object)Con->ObjectID; - local_4c[0] = (Object)Obj->ObjectID; - MoveObject(local_4c,local_5c); - Object::getObjectType(local_5c); - if (local_5c[0].ObjectID != 99) { - local_5c[0] = (Object)Obj->ObjectID; - AnnounceChangedObject(local_5c,1); - local_5c[0] = (Object)Obj->ObjectID; - NotifyTrades(local_5c); - local_5c[0] = (Object)Obj->ObjectID; - iVar5 = CountObjects(local_5c); - local_4c[0] = (Object)Obj->ObjectID; - NotifyDepot(CreatureID,local_4c,-iVar5); - } - local_5c[0].ObjectID = NONE.ObjectID; - local_4c[0].ObjectID = NONE.ObjectID; - if (z_1 != NONE.ObjectID) { - local_4c[0].ObjectID = z_1; - AnnounceChangedObject(local_4c,2); - local_4c[0].ObjectID = z_1; - NotifyTrades(local_4c); - } - Object::getObjectType(local_5c); - if (local_5c[0].ObjectID == 99) { - local_5c[0] = (Object)Obj->ObjectID; - pTVar4 = GetCreature(local_5c); - if (pTVar4 == (TCreature *)0x0) { - uVar3 = Object::getCreatureID(Obj); - error(&DAT_080ff680,uVar3); - } - else { - TCreature::NotifyGo(pTVar4); - } - } - Object::getObjectType(local_5c); - local_5c[0] = (Object)Obj->ObjectID; - NotifyCreature(local_5c[0].ObjectID,pOVar7,SUB41(local_5c,0)); - Object::getContainer(local_5c); - Object::getObjectType(local_4c); - local_4c[0] = (Object)Obj->ObjectID; - local_3c.ObjectID = local_4c[0].ObjectID; - uVar3 = GetObjectCreatureID(&local_3c); - NotifyCreature(uVar3,(Object *)uVar3,SUB41(local_4c,0)); - Object::getObjectType(local_5c); - bVar2 = ObjectType::getFlag((ObjectType *)local_5c,CONTAINER); - if (bVar2) { - local_5c[0] = (Object)Obj->ObjectID; - CloseContainer(local_5c,false); - } - local_5c[0] = (Object)Con->ObjectID; - local_4c[0].ObjectID = local_6c.ObjectID; - local_3c = (Object)Obj->ObjectID; - MovementEvent(&local_3c,local_4c,local_5c); - local_5c[0] = (Object)Obj->ObjectID; - Object::getContainer(local_4c); - CollisionEvent(local_5c,local_4c); - local_5c[0].ObjectID = local_6c.ObjectID; - local_4c[0] = (Object)Obj->ObjectID; - NotifyAllCreatures(local_4c,3,local_5c); - return; - } - if (Count != 0) { - pOVar7 = (Object *)0x2; - uVar3 = Object::getAttribute(Obj,AMOUNT); - if (Count <= (int)uVar3) goto LAB_08092800; - } - // try { // try from 0809300c to 080930cd has its CatchHandler @ 08093120 - uVar3 = Object::getAttribute(Obj,AMOUNT); - error(&DAT_080ff700,Count,uVar3); - goto LAB_08093028; - } - Text = "Move: Zielobjekt ist kein Container.\n"; - } - else { - Text = &DAT_080ff7e0; - } - error(Text); -LAB_08093028: - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar6,&RESULT::typeinfo,0); -} - - - -void Merge(ulong CreatureID,Object *Obj,Object *Dest,int Count,Object *Ignore) - -{ - bool bVar1; - ulong uVar2; - ulong uVar3; - undefined4 *puVar4; - ulong newCreature; - char *Text; - ulong oldCreature; - Object local_6c [4]; - Object local_5c [4]; - Object local_4c; - Object Con; - Object local_3c; - Object oldCon; - Object local_2c [7]; - - // try { // try from 0809314b to 080936c5 has its CatchHandler @ 080936d1 - bVar1 = Object::exists(Obj); - if (bVar1) { - bVar1 = Object::exists(Dest); - if (!bVar1) { - Text = "Merge: Zielobjekt existiert nicht.\n"; - goto LAB_080936c1; - } - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CUMULATIVE); - if ((!bVar1) || - ((Count != 0 && (uVar2 = Object::getAttribute(Obj,AMOUNT), Count <= (int)uVar2)))) { - local_2c[0] = (Object)Dest->ObjectID; - if (Obj->ObjectID == local_2c[0].ObjectID) { - return; - } - Object::getObjectType(local_2c); - Object::getObjectType(&local_3c); - ObjectType::setTypeID((ObjectType *)&local_4c,local_3c.ObjectID); - if (local_2c[0].ObjectID == local_4c.ObjectID) { - Object::getObjectType(&local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_4c,CUMULATIVE); - if (bVar1) { - if (Count == -1) { - Count = Object::getAttribute(Obj,AMOUNT); - } - uVar2 = Object::getAttribute(Dest,AMOUNT); - if (uVar2 + Count < 0x65) { - Object::getContainer(&local_4c); - local_3c = (Object)Ignore->ObjectID; - local_2c[0] = (Object)Obj->ObjectID; - CheckTopMoveObject(CreatureID,local_2c,&local_3c); - Object::getObjectType(&local_3c); - bVar1 = local_3c.ObjectID != 0; - local_3c = (Object)Obj->ObjectID; - CheckMoveObject(CreatureID,&local_3c,bVar1); - Object::getObjectType(&local_3c); - if (local_3c.ObjectID == 0) { - local_3c.ObjectID = local_4c.ObjectID; - local_2c[0] = (Object)Obj->ObjectID; - CheckMapDestination(CreatureID,local_2c,&local_3c); - } - else { - local_3c.ObjectID = local_4c.ObjectID; - local_2c[0] = (Object)Obj->ObjectID; - CheckDepotSpace(CreatureID,local_2c,&local_3c,0); - local_3c.ObjectID = local_4c.ObjectID; - uVar2 = GetObjectCreatureID(&local_3c); - if (uVar2 != 0) { - local_3c = (Object)Obj->ObjectID; - CheckWeight(uVar2,&local_3c,Count); - } - } - Object::getContainer(&local_3c); - local_2c[0] = (Object)Obj->ObjectID; - uVar2 = GetObjectCreatureID(local_2c); - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,MOVEMENTEVENT); - if (bVar1) { - Object::getObjectType(local_2c); - error(&DAT_080ff820,local_2c[0].ObjectID); - } - Object::getContainer(local_2c); - local_5c[0].ObjectID = local_3c.ObjectID; - local_6c[0].ObjectID = local_3c.ObjectID; - if (local_2c[0].ObjectID != local_3c.ObjectID) { - oldCreature = Obj->ObjectID; - SeparationEvent((Object *)&oldCreature,local_6c); - } - uVar3 = Object::getAttribute(Obj,AMOUNT); - if (Count < (int)uVar3) { - oldCreature = Obj->ObjectID; - uVar3 = Object::getAttribute(Obj,AMOUNT); - ChangeObject((Object *)&oldCreature,AMOUNT,uVar3 - Count); - oldCreature = Obj->ObjectID; - AnnounceChangedObject((Object *)&oldCreature,2); - oldCreature = Obj->ObjectID; - NotifyTrades((Object *)&oldCreature); - oldCreature = Dest->ObjectID; - uVar3 = Object::getAttribute(Dest,AMOUNT); - ChangeObject((Object *)&oldCreature,AMOUNT,uVar3 + Count); - } - else { - oldCreature = Obj->ObjectID; - AnnounceChangedObject((Object *)&oldCreature,0); - oldCreature = Obj->ObjectID; - NotifyTrades((Object *)&oldCreature); - oldCreature = Obj->ObjectID; - NotifyDepot(CreatureID,(Object *)&oldCreature,1); - oldCreature = Dest->ObjectID; - local_6c[0] = (Object)Obj->ObjectID; - MergeObjects(local_6c,(Object *)&oldCreature); - } - oldCreature = Dest->ObjectID; - AnnounceChangedObject((Object *)&oldCreature,2); - oldCreature = Dest->ObjectID; - NotifyTrades((Object *)&oldCreature); - Object::getObjectType((Object *)&oldCreature); - oldCreature = Dest->ObjectID; - NotifyCreature(uVar2,(Object *)uVar2,SUB41((Object *)&oldCreature,0)); - Object::getContainer((Object *)&oldCreature); - Object::getObjectType(local_6c); - local_6c[0] = (Object)Dest->ObjectID; - local_5c[0].ObjectID = local_6c[0].ObjectID; - uVar2 = GetObjectCreatureID(local_5c); - NotifyCreature(uVar2,(Object *)uVar2,SUB41(local_6c,0)); - oldCreature = Dest->ObjectID; - Object::getContainer(local_6c); - CollisionEvent((Object *)&oldCreature,local_6c); - oldCreature = NONE.ObjectID; - local_6c[0] = (Object)Dest->ObjectID; - NotifyAllCreatures(local_6c,2,(Object *)&oldCreature); - return; - } - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0x13; - } - else { - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0x12; - } - } - else { - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0x11; - } - goto LAB_08093635; - } - error(&DAT_080ff880,Count); - } - else { - Text = &DAT_080ff900; -LAB_080936c1: - error(Text); - } - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0xffffffff; -LAB_08093635: - // WARNING: Subroutine does not return - __cxa_throw(puVar4,&RESULT::typeinfo,0); -} - - - void Change(Object *Obj,ObjectType *NewType,ulong Value) { diff --git a/src/cract.cc b/src/cract.cc index 22e5b93..d6fd2ee 100644 --- a/src/cract.cc +++ b/src/cract.cc @@ -556,7 +556,8 @@ void TCreature::Move(Object Obj, int DestX, int DestY, int DestZ, uint8 Count){ ::Move(this->ID, Obj, DestCon, MoveCount, false, DestObj); }catch(RESULT r){ // NOTE(fusion): Attempt to exchange inventory items. - if(DestY < 64 && DestObj != NONE + if(DestY >= INVENTORY_FIRST && DestY <= INVENTORY_LAST + && DestObj != NONE && (r == NOROOM || r == HANDSNOTFREE || r == HANDBLOCKED diff --git a/src/operate.cc b/src/operate.cc index cb4819d..041d663 100644 --- a/src/operate.cc +++ b/src/operate.cc @@ -3,6 +3,26 @@ #include "stubs.hh" +// operate.cc +void AnnounceMovingCreature(uint32 CreatureID, Object Con); +void CheckTopMoveObject(uint32 CreatureID, Object Obj, Object Ignore); +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): This could have been a simple return value. void CheckContainerDestination(Object Obj, Object Con){ Object Help = Con; @@ -81,3 +101,255 @@ void CheckInventoryDestination(Object Obj, Object Con, bool Split){ } } } + +void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Object Ignore){ + if(!Obj.exists()){ + error("Move: Übergebenes Objekt existiert nicht.\n"); + throw ERROR; + } + + if(!Con.exists()){ + int ObjX, ObjY, ObjZ; + ObjectType ObjType = Obj.getObjectType(); + GetObjectCoordinates(Obj, &ObjX, &ObjY, &ObjZ); + error("Move: Zielobjekt existiert nicht.\n"); + error("# Objekt %d an [%d,%d,%d]\n", ObjType.TypeID, ObjX, ObjY, ObjZ); + throw ERROR; + } + + ObjectType ConType = Con.getObjectType(); + if(!ConType.getFlag(CONTAINER)){ + error("Move: Zielobjekt ist kein Container.\n"); + throw ERROR; + } + + ObjectType ObjType = Obj.getObjectType(); + if(ObjType.getFlag(CUMULATIVE) && (Count == 0 || Count > (int)Obj.getAttribute(AMOUNT))){ + error("Move: Ungültige Anzahl %d von %d an Teilen bei kumulierbarem Objekt.\n", + Count, (int)Obj.getAttribute(AMOUNT)); + throw ERROR; + } + + Object OldCon = Obj.getContainer(); + if(!NoMerge && ConType.isMapContainer() + && ObjType.getFlag(CUMULATIVE) + && OldCon != Con){ + int ConX, ConY, ConZ; + GetObjectCoordinates(Con, &ConX, &ConY, &ConZ); + Object Top = GetTopObject(ConX, ConY, ConZ, true); + if(Top != NONE){ + try{ + Merge(CreatureID, Obj, Top, Count, Ignore); + return; // <-- EARLY RETURN IF `Merge` SUCCEEDS. + }catch(RESULT r){ + if(r == DESTROYED){ + throw; + } + } + } + } + + // TODO(fusion): The only event inside `Merge` that could modify the object + // and still throw some non `DESTROYED` error is the separation event. + // From what I've seen, it is used exclusively with non CUMULATIVE objects + // like depot switches to perform "step out" events but using them with + // CUMULATIVE objects could be problematic as the event is triggered on the + // whole object which includes both the remainder and moved parts, meaning + // that transforming the object then would already make the merge "invalid". + + if(!Obj.exists()){ + error("Move: Übergebenes Objekt existiert nicht mehr.\n"); + } + + int ObjCount = 1; + if(ObjType.getFlag(CUMULATIVE)){ + ObjCount = (int)Obj.getAttribute(AMOUNT); + } + + if(Count == -1){ + Count = ObjCount; + } + + bool Split = Count < ObjCount; + uint32 ObjOwnerID = GetObjectCreatureID(Obj); + uint32 ConOwnerID = GetObjectCreatureID(Con); + CheckTopMoveObject(CreatureID, Obj, Ignore); + if(ConType.isMapContainer()){ + CheckMoveObject(CreatureID, Obj, false); + CheckMapDestination(CreatureID, Obj, Con); + }else{ + CheckMoveObject(CreatureID, Obj, true); + if(ConType.isBodyContainer()){ + CheckInventoryDestination(Obj, Con, Split); + }else{ + CheckContainerDestination(Obj, Con); + } + + if(Split){ + CheckDepotSpace(CreatureID, NONE, Con, 1); + }else{ + CheckDepotSpace(CreatureID, Obj, Con, CountObjects(Obj)); + } + + if(ConOwnerID != 0){ + CheckWeight(ConOwnerID, Obj, Count); + } + } + + // NOTE(fusion): `Obj` becomes the split part while `Remainder`, the remainder. + Object Remainder = NONE; + if(Split){ + Remainder = Obj; + Obj = SplitObject(Obj, Count); + } + + if(OldCon != Con){ + SeparationEvent(Obj, OldCon); + } + + // TODO(fusion): There is surely a way to reduce these creature checks? + // perhaps split them into two linear paths, with a few duplications but + // easier to read. + + if(!ObjType.isCreatureContainer() && Remainder == NONE){ + AnnounceChangedObject(Obj, 0); // OBJECT_DISAPPEAR ? + NotifyTrades(Obj); + NotifyDepot(CreatureID, Obj, CountObjects(Obj)); + } + + // TODO(fusion): This could probably be moved to the end of the function + // along with the other `CloseContainer`. + if(ObjType.getFlag(CONTAINER) && CreatureID == 0){ + CloseContainer(Obj, true); + } + + if(ObjType.isCreatureContainer()){ + uint32 MovingCreatureID = Obj.getCreatureID(); + TCreature *Creature = GetCreature(MovingCreatureID); + if(Creature != NULL){ + Creature->NotifyTurn(Con); + }else{ + error("Move: Kreatur mit ungültiger ID %d.\n", MovingCreatureID); + } + AnnounceMovingCreature(MovingCreatureID, Con); + } + + MoveObject(Obj, Con); + + if(!ObjType.isCreatureContainer()){ + AnnounceChangedObject(Obj, 1); // OBJECT_APPEAR + NotifyTrades(Obj); + NotifyDepot(CreatureID, Obj, -CountObjects(Obj)); + } + + if(Remainder != NONE){ + AnnounceChangedObject(Remainder, 2); // OBJECT_CHANGED + NotifyTrades(Remainder); + } + + if(ObjType.isCreatureContainer()){ + uint32 MovingCreatureID = Obj.getCreatureID(); + TCreature *Creature = GetCreature(MovingCreatureID); + if(Creature != NULL){ + Creature->NotifyGo(); + }else{ + error("Move: Kreatur mit ungültiger ID %d.\n", MovingCreatureID); + } + } + + NotifyCreature(ObjOwnerID, Obj, OldCon.getObjectType().isBodyContainer()); + NotifyCreature(ConOwnerID, Obj, Con.getObjectType().isBodyContainer()); + + if(ObjType.getFlag(CONTAINER)){ + CloseContainer(Obj, false); + } + + MovementEvent(Obj, OldCon, Con); + CollisionEvent(Obj, Con); + NotifyAllCreatures(Obj, 3, OldCon); // CREATURE_MOVE_STIMULUS_ ? +} + +void Merge(uint32 CreatureID, Object Obj, Object Dest, int Count, Object Ignore){ + if(!Obj.exists()){ + error("Merge: Übergebenes Objekt existiert nicht.\n"); + throw ERROR; + } + + if(!Dest.exists()){ + error("Merge: Zielobjekt existiert nicht.\n"); + throw ERROR; + } + + ObjectType ObjType = Obj.getObjectType(); + if(ObjType.getFlag(CUMULATIVE) && (Count == 0 || Count > (int)Obj.getAttribute(AMOUNT))){ + error("Merge: Ungültige Anzahl %d an Teilen bei kumulierbarem Objekt.\n", Count); + throw ERROR; + } + + if(Obj == Dest){ + return; + } + + if(ObjType != Dest.getObjectType()){ + throw NOMATCH; + } + + if(!ObjType.getFlag(CUMULATIVE)){ + throw NOTCUMULABLE; + } + + int ObjCount = Obj.getAttribute(AMOUNT); + int DestCount = Dest.getAttribute(AMOUNT); + if(Count == -1){ + Count = ObjCount; + } + + if((Count + DestCount) > 100){ + throw TOOMANYPARTS; + } + + Object DestCon = Dest.getContainer(); + uint32 DestOwnerID = GetObjectCreatureID(Dest); + CheckTopMoveObject(CreatureID, Obj, Ignore); + if(DestCon.getObjectType().isMapContainer()){ + CheckMoveObject(CreatureID, Obj, false); + CheckMapDestination(CreatureID, Obj, DestCon); + }else{ + CheckMoveObject(CreatureID, Obj, true); + CheckDepotSpace(CreatureID, Obj, DestCon, 0); + if(DestOwnerID != 0){ + CheckWeight(DestOwnerID, Obj, Count); + } + } + + Object ObjCon = Obj.getContainer(); + uint32 ObjOwnerID = GetObjectCreatureID(Obj); + + // TODO(fusion): What is even going on here? + if(ObjType.getFlag(MOVEMENTEVENT)){ + error("Merge: Movement-Event für kumulierbares Objekt %d wird nicht ausgelöst.\n", ObjType.TypeID); + } + + if(ObjCon != DestCon){ + SeparationEvent(Obj, ObjCon); + } + + if(Count < ObjCount){ + ChangeObject(Obj, AMOUNT, ObjCount - Count); + AnnounceChangedObject(Obj, 2); // OBJECT_CHANGED ? + NotifyTrades(Obj); + ChangeObject(Dest, AMOUNT, DestCount + Count); + }else{ + AnnounceChangedObject(Obj, 0); // OBJECT_DISAPPEAR ? + NotifyTrades(Obj); + NotifyDepot(CreatureID, Obj, 1); + MergeObjects(Obj, Dest); + } + + AnnounceChangedObject(Dest, 2); // OBJECT_CHANGED ? + NotifyTrades(Dest); + NotifyCreature(ObjOwnerID, Dest, ObjCon.getObjectType().isBodyContainer()); + NotifyCreature(DestOwnerID, Dest, DestCon.getObjectType().isBodyContainer()); + CollisionEvent(Dest, DestCon); + NotifyAllCreatures(Dest, 2, NONE); // CREATURE_MOVE_STIMULUS_ ? +} -- cgit v1.2.3