aboutsummaryrefslogtreecommitdiff
path: root/src/cract.cc
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-06-08 19:54:40 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-06-08 19:54:40 -0300
commiteaa3536c027a4f7c1b879b78ab0ecdefcdb4833d (patch)
tree03f851e558656f8fc36fdb982c28fbc09cef8dac /src/cract.cc
parentab9f606371a1df23e9cacbffa0811db7a9e50100 (diff)
downloadgame-eaa3536c027a4f7c1b879b78ab0ecdefcdb4833d.tar.gz
game-eaa3536c027a4f7c1b879b78ab0ecdefcdb4833d.zip
impl `TCreature::Move` which was absolute hell + some tidying up
Diffstat (limited to 'src/cract.cc')
-rw-r--r--src/cract.cc184
1 files changed, 182 insertions, 2 deletions
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;
}