diff options
| author | fusion32 <marcopuzziello@gmail.com> | 2025-06-11 01:56:41 -0300 |
|---|---|---|
| committer | fusion32 <marcopuzziello@gmail.com> | 2025-06-11 01:58:18 -0300 |
| commit | b167d45f88cfb824a96c3a5a120c34c30768ecda (patch) | |
| tree | 79d52a61067ddaf68e5097ff546f2e55d5c7023e /src/operate.cc | |
| parent | 81a5d53bc566fe2c678577cb3f3e5cadd0711753 (diff) | |
| download | game-b167d45f88cfb824a96c3a5a120c34c30768ecda.tar.gz game-b167d45f88cfb824a96c3a5a120c34c30768ecda.zip | |
first look at `operate.cc`
Diffstat (limited to 'src/operate.cc')
| -rw-r--r-- | src/operate.cc | 272 |
1 files changed, 272 insertions, 0 deletions
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_ ? +} |
