aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-06-12 02:09:27 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-06-12 02:09:27 -0300
commit05ec30b99472e8c17cd33c29d0e7859e02dc9fc8 (patch)
treeddeb2236778e69c4bc35a5c4e85d2e5e88dd737e /src
parent60b89174c6b6300079344267bae60d74347e1fa5 (diff)
downloadgame-05ec30b99472e8c17cd33c29d0e7859e02dc9fc8.tar.gz
game-05ec30b99472e8c17cd33c29d0e7859e02dc9fc8.zip
more work on `operate.cc`
Diffstat (limited to 'src')
-rw-r--r--src/map.cc6
-rw-r--r--src/map.hh2
-rw-r--r--src/operate.cc213
-rw-r--r--src/stubs.hh5
4 files changed, 211 insertions, 15 deletions
diff --git a/src/map.cc b/src/map.cc
index 9ce568d..b9085c9 100644
--- a/src/map.cc
+++ b/src/map.cc
@@ -2017,7 +2017,7 @@ int GetObjectPriority(Object Obj){
}else if(ObjType.isCreatureContainer()){
ObjPriority = PRIORITY_CREATURE;
}else{
- ObjPriority = PRIORITY_OTHER;
+ ObjPriority = PRIORITY_LOW;
}
return ObjPriority;
}
@@ -2043,11 +2043,11 @@ void PlaceObject(Object Obj, Object Con, bool Append){
Object Cur(Con.getAttribute(CONTENT));
if(ConType.isMapContainer()){
// TODO(fusion): Review. The loop below was a bit rough but it seems that
- // append is forced for non PRIORITY_CREATURE and PRIORITY_OTHER.
+ // append is forced for non PRIORITY_CREATURE and PRIORITY_LOW.
int ObjPriority = GetObjectPriority(Obj);
Append = Append
|| (ObjPriority != PRIORITY_CREATURE
- && ObjPriority != PRIORITY_OTHER);
+ && ObjPriority != PRIORITY_LOW);
while(Cur != NONE){
int CurPriority = GetObjectPriority(Cur);
diff --git a/src/map.hh b/src/map.hh
index e1a9e22..8989f05 100644
--- a/src/map.hh
+++ b/src/map.hh
@@ -26,7 +26,7 @@ enum : int {
PRIORITY_BOTTOM = 2,
PRIORITY_TOP = 3,
PRIORITY_CREATURE = 4,
- PRIORITY_OTHER = 5,
+ PRIORITY_LOW = 5,
};
struct Object {
diff --git a/src/operate.cc b/src/operate.cc
index a76e723..603cc7f 100644
--- a/src/operate.cc
+++ b/src/operate.cc
@@ -4,7 +4,6 @@
#include "stubs.hh"
// operate.cc
-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);
@@ -27,6 +26,12 @@ void SeparationEvent(Object Obj, Object Start);
//==================================================================================================
//==================================================================================================
+// TODO(fusion): The radii parameters for `TFindCreatures` are commonly around
+// 16 and 14 for x and y respectively so there is probably some constant involved.
+// Also, since we're talking about radii, these values are quite large when you
+// consider the regular client's viewport dimensions of 15x11 visible fields or
+// 18x14 total fields.
+
void AnnounceMovingCreature(uint32 CreatureID, Object Con){
TCreature *Creature = GetCreature(CreatureID);
if(Creature == NULL){
@@ -37,12 +42,11 @@ void AnnounceMovingCreature(uint32 CreatureID, Object Con){
int ConX, ConY, ConZ;
GetObjectCoordinates(Con, &ConX, &ConY, &ConZ);
- // TODO(fusion): 17 and 15 are probably related to the client's viewport dimensions.
- int SearchWidth = 17 + std::abs(Creature->posx - ConX) / 2;
- int SearchHeight = 15 + std::abs(Creature->posy - ConY) / 2;
+ int SearchRadiusX = 16 + (std::abs(Creature->posx - ConX) / 2) + 1;
+ int SearchRadiusY = 14 + (std::abs(Creature->posy - ConY) / 2) + 1;
int SearchCenterX = (Creature->posx + ConX) / 2;
int SearchCenterY = (Creature->posy + ConY) / 2;
- TFindCreatures Search(SearchWidth, SearchHeight, SearchCenterX, SearchCenterY, FIND_PLAYERS);
+ TFindCreatures Search(SearchRadiusX, SearchRadiusY, SearchCenterX, SearchCenterY, FIND_PLAYERS);
while(true){
uint32 CharacterID = Search.getNext();
if(CharacterID == 0){
@@ -50,9 +54,11 @@ void AnnounceMovingCreature(uint32 CreatureID, Object Con){
}
TPlayer *Player = GetPlayer(CharacterID);
- if(Player != NULL && Player->Connection != NULL){
- SendMoveCreature(Player->Connection, CreatureID, ConX, ConY, ConZ);
+ if(Player == NULL || Player->Connection == NULL){
+ continue;
}
+
+ SendMoveCreature(Player->Connection, CreatureID, ConX, ConY, ConZ);
}
}
@@ -103,8 +109,11 @@ void AnnounceChangedField(Object Obj, int Type){
}
TPlayer *Player = GetPlayer(CharacterID);
- if(Player == NULL || Player->Connection == NULL
- || !Player->Connection->IsVisible(ObjX, ObjY, ObjZ)){
+ if(Player == NULL || Player->Connection == NULL){
+ continue;
+ }
+
+ if(!Player->Connection->IsVisible(ObjX, ObjY, ObjZ)){
continue;
}
@@ -205,6 +214,187 @@ void AnnounceChangedObject(Object Obj, int Type){
}
}
+void AnnounceGraphicalEffect(int x, int y, int z, int Type){
+ if(!IsOnMap(x, y, z)){
+ return;
+ }
+
+ TFindCreatures Search(16, 14, x, y, FIND_PLAYERS);
+ while(true){
+ uint32 CharacterID = Search.getNext();
+ if(CharacterID == 0){
+ break;
+ }
+
+ TPlayer *Player = GetPlayer(CharacterID);
+ if(Player == NULL || Player->Connection == NULL){
+ continue;
+ }
+
+ if(!Player->Connection->IsVisible(x, y, z)){
+ continue;
+ }
+
+ SendGraphicalEffect(Player->Connection, x, y, z, Type);
+ }
+}
+
+void AnnounceTextualEffect(int x, int y, int z, int Color, const char *Text){
+ if(!IsOnMap(x, y, z)){
+ return;
+ }
+
+ TFindCreatures Search(16, 14, x, y, FIND_PLAYERS);
+ while(true){
+ uint32 CharacterID = Search.getNext();
+ if(CharacterID == 0){
+ break;
+ }
+
+ TPlayer *Player = GetPlayer(CharacterID);
+ if(Player == NULL || Player->Connection == NULL){
+ continue;
+ }
+
+ if(!Player->Connection->IsVisible(x, y, z)){
+ continue;
+ }
+
+ SendTextualEffect(Player->Connection, x, y, z, Color, Text);
+ }
+}
+
+void AnnounceMissile(int OrigX, int OrigY, int OrigZ,
+ int DestX, int DestY, int DestZ, int Type){
+ if(!IsOnMap(OrigX, OrigY, OrigZ) || !IsOnMap(DestX, DestY, DestZ)){
+ return;
+ }
+
+ int SearchRadiusX = 16 + (std::abs(OrigX - DestX) / 2) + 1;
+ int SearchRadiusY = 14 + (std::abs(OrigY - DestY) / 2) + 1;
+ int SearchCenterX = (OrigX + DestX) / 2;
+ int SearchCenterY = (OrigY + DestY) / 2;
+ TFindCreatures Search(SearchRadiusX, SearchRadiusY, SearchCenterX, SearchCenterY, FIND_PLAYERS);
+ while(true){
+ uint32 CharacterID = Search.getNext();
+ if(CharacterID == 0){
+ break;
+ }
+
+ TPlayer *Player = GetPlayer(CharacterID);
+ if(Player == NULL || Player->Connection == NULL){
+ continue;
+ }
+
+ if(!Player->Connection->IsVisible(OrigX, OrigY, OrigY)
+ && !Player->Connection->IsVisible(DestX, DestY, DestZ)){
+ continue;
+ }
+
+ SendMissileEffect(Player->Connection,
+ OrigX, OrigY, OrigY,
+ DestX, DestY, DestZ, Type);
+ }
+}
+
+void CheckTopMoveObject(uint32 CreatureID, Object Obj, Object Ignore){
+ if(!Obj.exists()){
+ error("CheckTopMoveObject: Objekt existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(CreatureID == 0 || !IsCreaturePlayer(CreatureID)){
+ return;
+ }
+
+ Object Con = Obj.getContainer();
+ ObjectType ConType = Con.getObjectType();
+ if(!ConType.isMapContainer()){
+ return;
+ }
+
+ ObjectType ObjType = Obj.getObjectType();
+ if(ObjType.isCreatureContainer() && Obj.getCreatureID() == CreatureID){
+ return;
+ }
+
+ Object Best = NONE;
+ bool BestIsCreature = false;
+ Object Help = GetFirstContainerObject(Con);
+ while(Help != NONE){
+ if(Help != Ignore){
+ ObjectType HelpType = Help.getObjectType();
+
+ // NOTE(fusion): We're looking for the top move object. The creature
+ // check here makes sure only the first creature found is kept as the
+ // best candidate, since creatures on a map container are in a sequence.
+ if(Best == NONE || (!HelpType.getFlag(UNMOVE) && (!BestIsCreature || !HelpType.isCreatureContainer()))){
+ Best = Help;
+ BestIsCreature = HelpType.isCreatureContainer();
+ }
+
+ // TODO(fusion): This is probably some inlined function to check whether
+ // an object has a low stack priority.
+ if(!HelpType.getFlag(BANK)
+ && !HelpType.getFlag(CLIP)
+ && !HelpType.getFlag(BOTTOM)
+ && !HelpType.getFlag(TOP)
+ && !HelpType.isCreatureContainer()){
+ break;
+ }
+ }
+ Help = Help.getNextObject();
+ }
+
+ if(Obj != Best){
+ throw NOTACCESSIBLE;
+ }
+}
+
+void CheckTopUseObject(uint32 CreatureID, Object Obj){
+ if(!Obj.exists()){
+ error("CheckTopUseObject: Objekt existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(CreatureID == 0 || !IsCreaturePlayer(CreatureID)){
+ return;
+ }
+
+ Object Con = Obj.getContainer();
+ ObjectType ConType = Con.getObjectType();
+ if(!ConType.isMapContainer()){
+ return;
+ }
+
+ Object Best = NONE;
+ Object Help = GetFirstContainerObject(Con);
+ while(Help != NONE){
+ ObjectType HelpType = Help.getObjectType();
+ if(Best == NONE || (!HelpType.isCreatureContainer() && !HelpType.getFlag(LIQUIDPOOL))){
+ Best = Help;
+ }
+
+ if(HelpType.getFlag(FORCEUSE)){
+ break;
+ }
+
+ if(!HelpType.getFlag(BANK)
+ && !HelpType.getFlag(CLIP)
+ && !HelpType.getFlag(BOTTOM)
+ && !HelpType.getFlag(TOP)
+ && !HelpType.isCreatureContainer()){
+ break;
+ }
+
+ Help = Help.getNextObject();
+ }
+
+ if(Obj != Best){
+ throw NOTACCESSIBLE;
+ }
+}
+
// TODO(fusion): This could have been a simple return value.
void CheckContainerDestination(Object Obj, Object Con){
Object Help = Con;
@@ -343,6 +533,9 @@ void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Ob
error("Move: Übergebenes Objekt existiert nicht mehr.\n");
}
+ // NOTE(fusion): Refresh object type just in case a merge event modified it.
+ ObjType = Obj.getObjectType();
+
int ObjCount = 1;
if(ObjType.getFlag(CUMULATIVE)){
ObjCount = (int)Obj.getAttribute(AMOUNT);
@@ -378,7 +571,7 @@ void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMerge, Ob
}
}
- // NOTE(fusion): `Obj` becomes the split part while `Remainder`, the remainder.
+ // NOTE(fusion): `Obj` becomes the split part while `Remainder`, the remaining part.
Object Remainder = NONE;
if(Split){
Remainder = Obj;
diff --git a/src/stubs.hh b/src/stubs.hh
index a2c5f25..4104dd3 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -86,11 +86,14 @@ extern void SendSetInventory(TConnection *Connection, int Position, Object Obj);
extern void SendEditList(TConnection *Connection, uint8 ListType, uint32 ID, const char *Text);
extern void SendFullScreen(TConnection *Connection);
extern void SendFloors(TConnection *Connection, bool Up);
+extern void SendGraphicalEffect(TConnection *Connection, int x, int y, int z, int Type);
+extern void SendTextualEffect(TConnection *Connection, int x, int y, int z, int Color, const char *Text);
+extern void SendMissileEffect(TConnection *Connection, int OrigX, int OrigY, int OrigZ, int DestX, int DestY, int DestZ, int Type);
extern void SendRow(TConnection *Connection, int Direction);
extern void SendMails(TPlayerData *PlayerData);
extern void SendMarkCreature(TConnection *Connection, uint32 CreatureID, int Color);
extern void SendMessage(TConnection *Connection, int Mode, const char *Text, ...) ATTR_PRINTF(3, 4);
-void SendMoveCreature(TConnection *Connection, uint32 CreatureID, int x, int y, int z);
+extern void SendMoveCreature(TConnection *Connection, uint32 CreatureID, int x, int y, int z);
extern void SendPlayerData(TConnection *Connection);
extern void SendPlayerSkills(TConnection *Connection);
extern void SendPlayerState(TConnection *Connection, uint8 State);