aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-06-10 19:19:09 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-06-10 19:19:09 -0300
commit81a5d53bc566fe2c678577cb3f3e5cadd0711753 (patch)
tree6423174670804c4ff6660753c9eb826527df2b97 /src
parent699341773dda3ae14a5025b9285bdd05c99bc234 (diff)
downloadgame-81a5d53bc566fe2c678577cb3f3e5cadd0711753.tar.gz
game-81a5d53bc566fe2c678577cb3f3e5cadd0711753.zip
finish `info.cc`
Diffstat (limited to 'src')
-rw-r--r--src/common.hh5
-rw-r--r--src/enums.hh2
-rw-r--r--src/info.cc406
-rw-r--r--src/info.hh8
-rw-r--r--src/magic.cc4
-rw-r--r--src/objects.cc22
-rw-r--r--src/stubs.hh4
-rw-r--r--src/util.cc25
8 files changed, 446 insertions, 30 deletions
diff --git a/src/common.hh b/src/common.hh
index ded9079..9800e6a 100644
--- a/src/common.hh
+++ b/src/common.hh
@@ -169,6 +169,11 @@ int stricmp(const char *s1, const char *s2, int Max = INT_MAX);
char *findFirst(char *s, char c);
char *findLast(char *s, char c);
+bool CheckBitIndex(int BitSetBytes, int Index);
+bool CheckBit(uint8 *BitSet, int Index);
+void SetBit(uint8 *BitSet, int Index);
+void ClearBit(uint8 *BitSet, int Index);
+
template<typename T>
void RandomShuffle(T *Buffer, int Size){
if(Buffer == NULL){
diff --git a/src/enums.hh b/src/enums.hh
index 5f7810c..940d19e 100644
--- a/src/enums.hh
+++ b/src/enums.hh
@@ -91,7 +91,7 @@ enum DamageType: int {
// NOTE(fusion): Not in debug symbols.
enum Direction: int {
- DIRECTION_INVALID = -1,
+ DIRECTION_NONE = -1,
DIRECTION_NORTH = 0,
DIRECTION_EAST = 1,
DIRECTION_SOUTH = 2,
diff --git a/src/info.cc b/src/info.cc
index fc1df61..d15f470 100644
--- a/src/info.cc
+++ b/src/info.cc
@@ -908,7 +908,6 @@ bool SearchSpawnField(int *x, int *y, int *z, int Distance, bool Player){
matrix<int> Map(-Distance, Distance, -Distance, Distance, INT_MAX);
*Map.at(0, 0) = 0;
-
int BestX = 0;
int BestY = 0;
int BestTieBreaker = -1;
@@ -1014,6 +1013,411 @@ bool SearchSpawnField(int *x, int *y, int *z, int Distance, bool Player){
return Result;
}
+bool SearchFlightField(uint32 FugitiveID, uint32 PursuerID, int *x, int *y, int *z){
+ TCreature *Fugitive = GetCreature(FugitiveID);
+ if(Fugitive == NULL){
+ error("SearchFlightField: Flüchtling existiert nicht.\n");
+ return false;
+ }
+
+ TCreature *Pursuer = GetCreature(PursuerID);
+ if(Pursuer == NULL){
+ error("SearchFlightField: Verfolger existiert nicht.\n");
+ return false;
+ }
+
+ if(Fugitive->posz != Pursuer->posz){
+ error("SearchFlightField: Flüchtling und Verfolger sind auf verschiedenen Ebenen.\n");
+ return false;
+ }
+
+ // NOTE(fusion): Fugitive's coordinates relative to the pursuer.
+ int FugitiveX = Fugitive->posx - Pursuer->posx;
+ int FugitiveY = Fugitive->posy - Pursuer->posy;
+
+ int Try[8] = {};
+ for(int i = 0; i < NARRAY(Try); i += 1){
+ Try[i] = DIRECTION_NONE;
+ }
+
+ if(FugitiveY <= 0){
+ Try[0] = DIRECTION_NORTH;
+ }
+
+ if(FugitiveX >= 0){
+ Try[1] = DIRECTION_EAST;
+ }
+
+ if(FugitiveY >= 0){
+ Try[2] = DIRECTION_SOUTH;
+ }
+
+ if(FugitiveX <= 0){
+ Try[3] = DIRECTION_WEST;
+ }
+
+ if(FugitiveX <= 0 && FugitiveY >= 0){
+ Try[4] = DIRECTION_SOUTHWEST;
+ }
+
+ if(FugitiveX >= 0 && FugitiveY >= 0){
+ Try[5] = DIRECTION_SOUTHEAST;
+ }
+
+ if(FugitiveX >= 0 && FugitiveY <= 0){
+ Try[6] = DIRECTION_NORTHEAST;
+ }
+
+ if(FugitiveX <= 0 && FugitiveY <= 0){
+ Try[7] = DIRECTION_NORTHWEST;
+ }
+
+ RandomShuffle(&Try[0], 4);
+ RandomShuffle(&Try[4], 4);
+ for(int i = 0; i < NARRAY(Try); i += 1){
+ if(Try[i] == DIRECTION_NONE){
+ continue;
+ }
+
+ int FieldX = Fugitive->posx;
+ int FieldY = Fugitive->posy;
+ int FieldZ = Fugitive->posz;
+ switch(Try[i]){
+ case DIRECTION_NORTH: FieldY -= 1; break;
+ case DIRECTION_EAST: FieldX += 1; break;
+ case DIRECTION_SOUTH: FieldY += 1; break;
+ case DIRECTION_WEST: FieldX -= 1; break;
+ case DIRECTION_SOUTHWEST: FieldX -= 1; FieldY += 1; break;
+ case DIRECTION_SOUTHEAST: FieldX += 1; FieldY += 1; break;
+ case DIRECTION_NORTHWEST: FieldX -= 1; FieldY -= 1; break;
+ case DIRECTION_NORTHEAST: FieldX += 1; FieldY -= 1; break;
+ default:{
+ error("SearchFlightField: Ungültige Richtung %d.\n", Try[i]);
+ return false;
+ }
+ }
+
+ if(Fugitive->MovePossible(FieldX, FieldY, FieldZ, false, false)){
+ *x = FieldX;
+ *y = FieldY;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SearchSummonField(int *x, int *y, int *z, int Distance){
+ int BestX = 0;
+ int BestY = 0;
+ int BestTieBreaker = -1;
+ for(int OffsetY = -Distance; OffsetY <= Distance; OffsetY += 1)
+ for(int OffsetX = -Distance; OffsetX <= Distance; OffsetX += 1){
+ int TieBreaker = random(0, 99);
+ if(TieBreaker <= BestTieBreaker){
+ continue;
+ }
+
+ int FieldX = *x + OffsetX;
+ int FieldY = *y + OffsetY;
+ int FieldZ = *z;
+ if(CoordinateFlag(FieldX, FieldY, FieldZ, BANK)
+ && !CoordinateFlag(FieldX, FieldY, FieldZ, UNPASS)
+ && !CoordinateFlag(FieldX, FieldY, FieldZ, AVOID)
+ && !IsProtectionZone(FieldX, FieldY, FieldZ)
+ && !IsHouse(FieldX, FieldY, FieldZ)
+ && ThrowPossible(*x, *y, *z, FieldX, FieldY, FieldZ, 0)){
+ BestX = FieldX;
+ BestY = FieldY;
+ BestTieBreaker = TieBreaker;
+ }
+ }
+
+ bool Result = false;
+ if(BestTieBreaker >= 0){
+ *x = BestX;
+ *y = BestY;
+ Result = true;
+ }
+
+ return Result;
+}
+
+bool ThrowPossible(int OrigX, int OrigY, int OrigZ,
+ int DestX, int DestY, int DestZ, int Power){
+ // NOTE(fusion): `MinZ` contains the highest floor we're able to throw. We'll
+ // iterate from it towards the destination floor, checking the line between the
+ // origin and destination until we find a valid throwing path (or not).
+ int MinZ = std::max<int>(OrigZ - Power, 0);
+ for(int CurZ = OrigZ - 1; CurZ >= MinZ; CurZ -= 1){
+ Object Obj = GetFirstObject(OrigX, OrigY, CurZ);
+ if(Obj != NONE && Obj.getObjectType().getFlag(BANK)){
+ MinZ = CurZ + 1;
+ break;
+ }
+ }
+
+ // NOTE(fusion): I'm using `T` as the parameter for the line between the
+ // origin and destination.
+ int MaxT = std::max<int>(
+ std::abs(DestX - OrigX),
+ std::abs(DestY - OrigX));
+
+ int StartT = 1;
+ if((DestX < OrigX && CoordinateFlag(OrigX, OrigY, OrigZ, HOOKEAST))
+ || (DestY < OrigY && CoordinateFlag(OrigX, OrigY, OrigZ, HOOKSOUTH))){
+ StartT = 0;
+ }
+
+ while(MinZ <= DestZ){
+ int LastX = OrigX;
+ int LastY = OrigY;
+ if(DestX != OrigX || DestY != OrigY){
+ // NOTE(fusion): Get the current coordinates with linear interpolation.
+ for(int T = StartT; T <= MaxT; T += 1){
+ int CurX = (OrigX * (MaxT - T) + DestX * T) / MaxT;
+ int CurY = (OrigY * (MaxT - T) + DestY * T) / MaxT;
+ int CurZ = MinZ;
+ if(CoordinateFlag(CurX, CurY, CurZ, UNTHROW)){
+ break;
+ }
+
+ LastX = CurX;
+ LastY = CurY;
+ }
+ }
+
+ if(LastX == DestX && LastY == DestY){
+ int LastZ = MinZ;
+ for(; LastZ < DestZ; LastZ += 1){
+ Object Obj = GetFirstObject(DestX, DestY, LastZ);
+ if(Obj != NONE && Obj.getObjectType().getFlag(BANK)){
+ break;
+ }
+ }
+
+ if(LastZ == DestZ){
+ return true;
+ }
+ }
+
+ MinZ += 1;
+ }
+
+ return false;
+}
+
+void GetCreatureLight(uint32 CreatureID, int *Brightness, int *Color){
+ TCreature *Creature = GetCreature(CreatureID);
+ if(Creature == NULL){
+ error("GetCreatureLight: Kreatur existiert nicht.\n");
+ *Brightness = 0;
+ *Color = 0;
+ return;
+ }
+
+ int OutBrightness = 0;
+ if(Creature->Skills[SKILL_LIGHT] != NULL){
+ OutBrightness = Creature->Skills[SKILL_LIGHT]->TimerValue();
+ }
+
+ if(Creature->Type == PLAYER && CheckRight(CreatureID, ILLUMINATE)){
+ if(OutBrightness < 7){
+ OutBrightness = 7;
+ }
+ }
+
+ int OutRed = 5 * OutBrightness;
+ int OutGreen = 5 * OutBrightness;
+ int OutBlue = 5 * OutBrightness;
+ for(int Position = INVENTORY_FIRST;
+ Position <= INVENTORY_LAST;
+ Position += 1){
+ Object Obj = GetBodyObject(CreatureID, Position);
+ if(Obj == NONE){
+ continue;
+ }
+
+ ObjectType ObjType = Obj.getObjectType();
+ if(!ObjType.getFlag(LIGHT)){
+ continue;
+ }
+
+ int ObjBrightness = (int)ObjType.getAttribute(BRIGHTNESS);
+ int ObjColor = (int)ObjType.getAttribute(LIGHTCOLOR);
+ int ObjRed = (ObjColor / 36) * ObjBrightness;
+ int ObjGreen = (ObjColor % 36 / 6) * ObjBrightness;
+ int ObjBlue = (ObjColor % 36 % 6) * ObjBrightness;
+
+ if(OutBrightness < ObjBrightness){
+ OutBrightness = ObjBrightness;
+ }
+
+ if(OutRed < ObjRed){
+ OutRed = ObjRed;
+ }
+
+ if(OutGreen < ObjGreen){
+ OutGreen = ObjGreen;
+ }
+
+ if(OutBlue < ObjBlue){
+ OutBlue = ObjBlue;
+ }
+ }
+
+ int OutColor = 0;
+ if(OutBrightness > 0){
+ OutColor = (OutRed / OutBrightness) * 36
+ + (OutGreen / OutBrightness) * 6
+ + (OutBlue / OutBrightness);
+ }
+
+ *Brightness = OutBrightness;
+ *Color = OutColor;
+}
+
+int GetInventoryWeight(uint32 CreatureID){
+ TCreature *Creature = GetCreature(CreatureID);
+ if(Creature == NULL){
+ error("GetInventoryWeight: Kreatur %d existiert nicht.\n", CreatureID);
+ return 0;
+ }
+
+ Object Help = GetFirstContainerObject(Creature->CrObject);
+ return GetRowWeight(Help);
+}
+
+bool CheckRight(uint32 CharacterID, RIGHT Right){
+ TPlayer *Player = GetPlayer(CharacterID);
+ if(Player == NULL){
+ error("CheckRight: Spieler existiert nicht; Right=%d.\n", Right);
+ return false;
+ }
+
+ if(!CheckBitIndex(NARRAY(Player->Rights), Right)){
+ error("CheckRight: Ungültige Rechtnummer %d.\n", Right);
+ return false;
+ }
+
+ return CheckBit(Player->Rights, Right);
+}
+
+bool CheckBanishmentRight(uint32 CharacterID, int Reason, int Action){
+ TPlayer *Player = GetPlayer(CharacterID);
+ if(Player == NULL){
+ error("CheckBanishmentRight: Spieler existiert nicht.\n");
+ return false;
+ }
+
+ // NOTE(fusion): Banishment rights range from 18 to 49 and match banishment
+ // reasons exactly when subtracting 18.
+
+ if(Reason < 0 || Reason > 31){
+ error("CheckBanishmentRight: Ungültiger Banngrund %d von Spieler %d.\n",
+ Reason, CharacterID);
+ return false;
+ }
+
+ if(Action < 0 || Action > 6){
+ error("CheckBanishmentRight: Ungültige Aktion %d von Spieler %d.\n",
+ Action, CharacterID);
+ return false;
+ }
+
+ bool Result = false;
+ if(CheckRight(CharacterID, (RIGHT)(Reason + 18))){
+ bool Name = (Reason >= 0 && Reason <= 8);
+ bool Statement = (Reason >= 9 && Reason <= 27) || Reason == 29;
+ switch(Action){
+ case 0:{
+ Result = CheckRight(CharacterID, NOTATION);
+ break;
+ }
+
+ case 1:{
+ Result = Name && CheckRight(CharacterID, NAMELOCK);
+ break;
+ }
+
+ case 2:{
+ Result = !Name && CheckRight(CharacterID, BANISHMENT);
+ break;
+ }
+
+ case 3:{
+ Result = Name && CheckRight(CharacterID, NAMELOCK)
+ && CheckRight(CharacterID, BANISHMENT);
+ break;
+ }
+
+ case 4:{
+ Result = !Name && CheckRight(CharacterID, BANISHMENT)
+ && CheckRight(CharacterID, FINAL_WARNING);
+ break;
+ }
+
+ case 5:{
+ Result = Name && CheckRight(CharacterID, NAMELOCK)
+ && CheckRight(CharacterID, BANISHMENT)
+ && CheckRight(CharacterID, FINAL_WARNING);
+ break;
+ }
+
+ case 6:{
+ Result = Statement && CheckRight(CharacterID, STATEMENT_REPORT);
+ break;
+ }
+ }
+ }
+
+ return Result;
+}
+
+const char *GetBanishmentReason(int Reason){
+ const char *Result;
+ switch(Reason){
+ case 0: Result = "NAME_INSULTING"; break;
+ case 1: Result = "NAME_SENTENCE"; break;
+ case 2: Result = "NAME_NONSENSICAL_LETTERS"; break;
+ case 3: Result = "NAME_BADLY_FORMATTED"; break;
+ case 4: Result = "NAME_NO_PERSON"; break;
+ case 5: Result = "NAME_CELEBRITY"; break;
+ case 6: Result = "NAME_COUNTRY"; break;
+ case 7: Result = "NAME_FAKE_IDENTITY"; break;
+ case 8: Result = "NAME_FAKE_POSITION"; break;
+ case 9: Result = "STATEMENT_INSULTING"; break;
+ case 10: Result = "STATEMENT_SPAMMING"; break;
+ case 11: Result = "STATEMENT_ADVERT_OFFTOPIC"; break;
+ case 12: Result = "STATEMENT_ADVERT_MONEY"; break;
+ case 13: Result = "STATEMENT_NON_ENGLISH"; break;
+ case 14: Result = "STATEMENT_CHANNEL_OFFTOPIC"; break;
+ case 15: Result = "STATEMENT_VIOLATION_INCITING"; break;
+ case 16: Result = "CHEATING_BUG_ABUSE"; break;
+ case 17: Result = "CHEATING_GAME_WEAKNESS"; break;
+ case 18: Result = "CHEATING_MACRO_USE"; break;
+ case 19: Result = "CHEATING_MODIFIED_CLIENT"; break;
+ case 20: Result = "CHEATING_HACKING"; break;
+ case 21: Result = "CHEATING_MULTI_CLIENT"; break;
+ case 22: Result = "CHEATING_ACCOUNT_TRADING"; break;
+ case 23: Result = "CHEATING_ACCOUNT_SHARING"; break;
+ case 24: Result = "GAMEMASTER_THREATENING"; break;
+ case 25: Result = "GAMEMASTER_PRETENDING"; break;
+ case 26: Result = "GAMEMASTER_INFLUENCE"; break;
+ case 27: Result = "GAMEMASTER_FALSE_REPORTS"; break;
+ case 28: Result = "KILLING_EXCESSIVE_UNJUSTIFIED"; break;
+ case 29: Result = "DESTRUCTIVE_BEHAVIOUR"; break;
+ case 30: Result = "SPOILING_AUCTION"; break;
+ case 31: Result = "INVALID_PAYMENT"; break;
+ default:{
+ error("GetBanishmentReason: Ungültiger Verbannungsgrund %d.\n", Reason);
+ Result = "";
+ break;
+ }
+ }
+ return Result;
+}
+
void InitInfo(void){
// no-op
}
diff --git a/src/info.hh b/src/info.hh
index 3cb6399..adf3ce4 100644
--- a/src/info.hh
+++ b/src/info.hh
@@ -44,6 +44,14 @@ bool FieldPossible(int x, int y, int z, int FieldType);
bool SearchFreeField(int *x, int *y, int *z, int Distance, uint16 HouseID, bool Jump);
bool SearchLoginField(int *x, int *y, int *z, int Distance, bool Player);
bool SearchSpawnField(int *x, int *y, int *z, int Distance, bool Player);
+bool SearchFlightField(uint32 FugitiveID, uint32 PursuerID, int *x, int *y, int *z);
+bool SearchSummonField(int *x, int *y, int *z, int Distance);
+bool ThrowPossible(int OrigX, int OrigY, int OrigZ,
+ int DestX, int DestY, int DestZ, int Power);
+void GetCreatureLight(uint32 CreatureID, int *Brightness, int *Color);
+int GetInventoryWeight(uint32 CreatureID);
+bool CheckBanishmentRight(uint32 CharacterID, int Reason, int Action);
+const char *GetBanishmentReason(int Reason);
void InitInfo(void);
void ExitInfo(void);
diff --git a/src/magic.cc b/src/magic.cc
index 28c1aa5..728b681 100644
--- a/src/magic.cc
+++ b/src/magic.cc
@@ -898,7 +898,7 @@ int GetDirection(int dx, int dy){
}else if(dy > 0){
Result = DIRECTION_SOUTH;
}else{
- Result = DIRECTION_INVALID;
+ Result = DIRECTION_NONE;
}
}else{
// NOTE(fusion): This function uses the approximate tangent value, avoiding
@@ -1242,7 +1242,7 @@ void CreateFieldWall(TCreature *Actor, Object Target,
break;
}
- case DIRECTION_INVALID:{
+ case DIRECTION_NONE:{
throw NOROOM;
}
diff --git a/src/objects.cc b/src/objects.cc
index 198a11d..5231fc8 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -254,28 +254,6 @@ static const char InstanceAttributeNames[18][30] = {
"RemainingUses", // REMAININGUSES
};
-//
-
-// BITSET Helpers
-// =============================================================================
-static inline bool CheckBit(uint8 *Set, int Index){
- int ByteIndex = (int)(Index / 8);
- uint8 BitMask = (uint8)(1 << (Index % 8));
- return (Set[ByteIndex] & BitMask) != 0;
-}
-
-static inline void SetBit(uint8 *Set, int Index){
- int ByteIndex = (int)(Index / 8);
- uint8 BitMask = (uint8)(1 << (Index % 8));
- Set[ByteIndex] |= BitMask;
-}
-
-static inline void ClearBit(uint8 *Set, int Index){
- int ByteIndex = (int)(Index / 8);
- uint8 BitMask = (uint8)(1 << (Index % 8));
- Set[ByteIndex] &= ~BitMask;
-}
-
// ObjectType
// =============================================================================
void ObjectType::setTypeID(int TypeID){
diff --git a/src/stubs.hh b/src/stubs.hh
index 63615d7..4c1b0cb 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -64,8 +64,6 @@ extern void RefreshCylinders(void);
extern void RefreshMap(void);
extern void RefreshSector(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int Size);
extern void SavePlayerDataOrder(void);
-extern bool SearchFlightField(uint32 FugitiveID, uint32 PursuerID, int *x, int *y, int *z);
-extern bool SearchSummonField(int *x, int *y, int *z, int Distance);
extern void SendAll(void);
extern void SendAmbiente(TConnection *Connection);
extern void SendClearTarget(TConnection *Connection);
@@ -89,8 +87,6 @@ extern void ShowSubownerList(uint16 HouseID, TPlayer *Player, char *Buffer);
extern void ShowNameDoor(Object Door, TPlayer *Player, char *Buffer);
extern void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, bool CheckSpamming);
extern void TextualEffect(Object Obj, int Color, const char *Text, ...) ATTR_PRINTF(3, 4);
-extern bool ThrowPossible(int FromX, int FromY, int FromZ,
- int ToX, int ToY, int ToZ, int Power);
extern void Turn(uint32 CreatureID, Object Obj);
extern void Use(uint32 CreatureID, Object Obj1, Object Object2, uint8 Info);
diff --git a/src/util.cc b/src/util.cc
index 0982cd7..4a3523b 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -167,6 +167,31 @@ char *findLast(char *s, char c){
return Last;
}
+// BitSet Utility
+// =============================================================================
+bool CheckBitIndex(int BitSetBytes, int Index){
+ return Index >= 0 && Index < (BitSetBytes * 8);
+}
+
+bool CheckBit(uint8 *BitSet, int Index){
+ int ByteIndex = (int)(Index / 8);
+ uint8 BitMask = (uint8)(1 << (Index % 8));
+ return (BitSet[ByteIndex] & BitMask) != 0;
+}
+
+void SetBit(uint8 *BitSet, int Index){
+ int ByteIndex = (int)(Index / 8);
+ uint8 BitMask = (uint8)(1 << (Index % 8));
+ BitSet[ByteIndex] |= BitMask;
+}
+
+void ClearBit(uint8 *BitSet, int Index){
+ int ByteIndex = (int)(Index / 8);
+ uint8 BitMask = (uint8)(1 << (Index % 8));
+ BitSet[ByteIndex] &= ~BitMask;
+}
+
+
// TReadStream
// =============================================================================
bool TReadStream::readFlag(void){