first look at operate.cc

This commit is contained in:
fusion32 2025-06-11 01:56:41 -03:00
parent 81a5d53bc5
commit b167d45f88
4 changed files with 276 additions and 458 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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_ ?
}