most info.cc functions
This commit is contained in:
parent
cd8f3f412c
commit
699341773d
1829
reference/game.c
1829
reference/game.c
File diff suppressed because it is too large
Load Diff
@ -798,6 +798,9 @@ void LoadMonsterRaid(const char *FileName, int Start,
|
|||||||
void LoadMonsterRaids(void);
|
void LoadMonsterRaids(void);
|
||||||
void ProcessMonsterRaids(void);
|
void ProcessMonsterRaids(void);
|
||||||
|
|
||||||
|
void InitCr(void);
|
||||||
|
void ExitCr(void);
|
||||||
|
|
||||||
// crskill.cc
|
// crskill.cc
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
int GetSkillByName(const char *Name);
|
int GetSkillByName(const char *Name);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "cr.hh"
|
#include "cr.hh"
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
|
#include "info.hh"
|
||||||
#include "operate.hh"
|
#include "operate.hh"
|
||||||
|
|
||||||
#include "stubs.hh"
|
#include "stubs.hh"
|
||||||
@ -497,7 +498,7 @@ void TCreature::Move(Object Obj, int DestX, int DestY, int DestZ, uint8 Count){
|
|||||||
if(DestY >= INVENTORY_FIRST && DestY <= INVENTORY_LAST){
|
if(DestY >= INVENTORY_FIRST && DestY <= INVENTORY_LAST){
|
||||||
DestCon = GetBodyContainer(this->ID, DestY);
|
DestCon = GetBodyContainer(this->ID, DestY);
|
||||||
DestObj = GetBodyObject(this->ID, DestY);
|
DestObj = GetBodyObject(this->ID, DestY);
|
||||||
}else if(DestY >= 64 && DestY < 80){
|
}else if(DestY >= CONTAINER_FIRST && DestY <= CONTAINER_LAST){
|
||||||
DestCon = GetBodyContainer(this->ID, DestY);
|
DestCon = GetBodyContainer(this->ID, DestY);
|
||||||
if(DestZ < 254){
|
if(DestZ < 254){
|
||||||
// TODO(fusion): The last argument to `GetObject` is the object
|
// TODO(fusion): The last argument to `GetObject` is the object
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "cr.hh"
|
#include "cr.hh"
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
|
#include "info.hh"
|
||||||
#include "magic.hh"
|
#include "magic.hh"
|
||||||
|
|
||||||
#include "stubs.hh"
|
#include "stubs.hh"
|
||||||
|
|||||||
40
src/enums.hh
40
src/enums.hh
@ -242,6 +242,10 @@ enum InventorySlot: int {
|
|||||||
// NOTE(fusion): For iterating over hand slots.
|
// NOTE(fusion): For iterating over hand slots.
|
||||||
INVENTORY_HAND_FIRST = INVENTORY_RIGHTHAND,
|
INVENTORY_HAND_FIRST = INVENTORY_RIGHTHAND,
|
||||||
INVENTORY_HAND_LAST = INVENTORY_LEFTHAND,
|
INVENTORY_HAND_LAST = INVENTORY_LEFTHAND,
|
||||||
|
|
||||||
|
// NOTE(fusion): For iterating over container slots.
|
||||||
|
CONTAINER_FIRST = 64,
|
||||||
|
CONTAINER_LAST = 79,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum KNOWNCREATURESTATE: int {
|
enum KNOWNCREATURESTATE: int {
|
||||||
@ -250,17 +254,33 @@ enum KNOWNCREATURESTATE: int {
|
|||||||
KNOWNCREATURE_OUTDATED = 2
|
KNOWNCREATURE_OUTDATED = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NOTE(fusion): Not in debug symbols.
|
||||||
|
enum LiquidColor: uint8 {
|
||||||
|
LIQUID_COLORLESS = 0,
|
||||||
|
LIQUID_BLUE = 1,
|
||||||
|
LIQUID_RED = 2,
|
||||||
|
LIQUID_BROWN = 3,
|
||||||
|
LIQUID_GREEN = 4,
|
||||||
|
LIQUID_YELLOW = 5,
|
||||||
|
LIQUID_WHITE = 6,
|
||||||
|
LIQUID_PURPLE = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE(fusion): Not in debug symbols.
|
||||||
enum LiquidType: int {
|
enum LiquidType: int {
|
||||||
LIQUID_NONE = 0,
|
LIQUID_NONE = 0,
|
||||||
LIQUID_WATER = 1,
|
LIQUID_WATER = 1,
|
||||||
LIQUID_WINE = 2,
|
LIQUID_WINE = 2,
|
||||||
LIQUID_BEER = 3,
|
LIQUID_BEER = 3,
|
||||||
LIQUID_MUD = 4,
|
LIQUID_MUD = 4,
|
||||||
LIQUID_BLOOD = 5,
|
LIQUID_BLOOD = 5,
|
||||||
LIQUID_SLIME = 6,
|
LIQUID_SLIME = 6,
|
||||||
LIQUID_MANA = 10,
|
LIQUID_OIL = 7,
|
||||||
LIQUID_LIFE = 11,
|
LIQUID_URINE = 8,
|
||||||
LIQUID_LEMONADE = 12,
|
LIQUID_MILK = 9,
|
||||||
|
LIQUID_MANA = 10,
|
||||||
|
LIQUID_LIFE = 11,
|
||||||
|
LIQUID_LEMONADE = 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(fusion): Not in debug symbols.
|
// NOTE(fusion): Not in debug symbols.
|
||||||
|
|||||||
930
src/info.cc
930
src/info.cc
@ -3,6 +3,681 @@
|
|||||||
|
|
||||||
#include "stubs.hh"
|
#include "stubs.hh"
|
||||||
|
|
||||||
|
const char *GetLiquidName(int LiquidType){
|
||||||
|
const char *LiquidName;
|
||||||
|
switch(LiquidType) {
|
||||||
|
case LIQUID_NONE: LiquidName = "nothing"; break;
|
||||||
|
case LIQUID_WATER: LiquidName = "water"; break;
|
||||||
|
case LIQUID_WINE: LiquidName = "wine"; break;
|
||||||
|
case LIQUID_BEER: LiquidName = "beer"; break;
|
||||||
|
case LIQUID_MUD: LiquidName = "mud"; break;
|
||||||
|
case LIQUID_BLOOD: LiquidName = "blood"; break;
|
||||||
|
case LIQUID_SLIME: LiquidName = "slime"; break;
|
||||||
|
case LIQUID_OIL: LiquidName = "oil"; break;
|
||||||
|
case LIQUID_URINE: LiquidName = "urine"; break;
|
||||||
|
case LIQUID_MILK: LiquidName = "milk"; break;
|
||||||
|
case LIQUID_MANA: LiquidName = "manafluid"; break;
|
||||||
|
case LIQUID_LIFE: LiquidName = "lifefluid"; break;
|
||||||
|
case LIQUID_LEMONADE: LiquidName = "lemonade"; break;
|
||||||
|
default:{
|
||||||
|
error("GetLiquidName: Ungültiger Flüssigkeitstyp %d\n", LiquidType);
|
||||||
|
LiquidName = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LiquidName;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 GetLiquidColor(int LiquidType){
|
||||||
|
uint8 LiquidColor;
|
||||||
|
switch(LiquidType){
|
||||||
|
case LIQUID_NONE: LiquidColor = LIQUID_COLORLESS; break;
|
||||||
|
case LIQUID_WATER: LiquidColor = LIQUID_BLUE; break;
|
||||||
|
case LIQUID_WINE: LiquidColor = LIQUID_PURPLE; break;
|
||||||
|
case LIQUID_BEER: LiquidColor = LIQUID_BROWN; break;
|
||||||
|
case LIQUID_MUD: LiquidColor = LIQUID_BROWN; break;
|
||||||
|
case LIQUID_BLOOD: LiquidColor = LIQUID_RED; break;
|
||||||
|
case LIQUID_SLIME: LiquidColor = LIQUID_GREEN; break;
|
||||||
|
case LIQUID_OIL: LiquidColor = LIQUID_BROWN; break;
|
||||||
|
case LIQUID_URINE: LiquidColor = LIQUID_YELLOW; break;
|
||||||
|
case LIQUID_MILK: LiquidColor = LIQUID_WHITE; break;
|
||||||
|
case LIQUID_MANA: LiquidColor = LIQUID_PURPLE; break;
|
||||||
|
case LIQUID_LIFE: LiquidColor = LIQUID_RED; break;
|
||||||
|
case LIQUID_LEMONADE: LiquidColor = LIQUID_YELLOW; break;
|
||||||
|
default:{
|
||||||
|
error("GetLiquidColor: Ungültiger Flüssigkeitstyp %d\n", LiquidType);
|
||||||
|
LiquidColor = LIQUID_COLORLESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LiquidColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *GetName(Object Obj){
|
||||||
|
char ObjectName[50] = {};
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.isCreatureContainer()){
|
||||||
|
TCreature *Creature = GetCreature(Obj);
|
||||||
|
if(Creature != NULL){
|
||||||
|
snprintf(ObjectName, sizeof(ObjectName), "%s", Creature->Name);
|
||||||
|
}else{
|
||||||
|
error("GetName: Kreatur %d existiert nicht.\n", Obj.getCreatureID());
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// IMPORTANT(fusion): `ObjectType::getName` returns the same static buffer
|
||||||
|
// from `Plural`.
|
||||||
|
const char *TypeName = ObjType.getName(1);
|
||||||
|
if(TypeName != NULL){
|
||||||
|
strcpy(ObjectName, TypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LiquidType = LIQUID_NONE;
|
||||||
|
if(ObjType.getFlag(LIQUIDCONTAINER)){
|
||||||
|
LiquidType = (int)Obj.getAttribute(CONTAINERLIQUIDTYPE);
|
||||||
|
}else if(ObjType.getFlag(LIQUIDPOOL)){
|
||||||
|
LiquidType = (int)Obj.getAttribute(POOLLIQUIDTYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LiquidType != LIQUID_NONE){
|
||||||
|
strcat(ObjectName, " of ");
|
||||||
|
strcat(ObjectName, GetLiquidName(LiquidType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Count = 1;
|
||||||
|
if(ObjType.getFlag(CUMULATIVE)){
|
||||||
|
Count = (int)Obj.getAttribute(AMOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IMPORTANT(fusion): `Plural` will return a static buffer.
|
||||||
|
return Plural(ObjectName, Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *GetInfo(Object Obj){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
error("GetInfo: Übergebenes Objekt existiert nicht.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Obj.getObjectType().getDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetWeight(Object Obj, int Count){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
error("GetWeight: Übergebenes Objekt existiert nicht.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(fusion): Why do some UNTAKE items have weight, and even worse, hardcoded?
|
||||||
|
|
||||||
|
int Result = 0;
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.getFlag(TAKE)){
|
||||||
|
int Weight = (int)ObjType.getAttribute(WEIGHT);
|
||||||
|
if(!ObjType.getFlag(CUMULATIVE)){
|
||||||
|
Count = 1;
|
||||||
|
}else if(Count == -1){
|
||||||
|
Count = (int)Obj.getAttribute(AMOUNT);
|
||||||
|
}
|
||||||
|
Result = Weight * Count;
|
||||||
|
}else if(ObjType.TypeID == 2904){ // LARGE AMPHORA
|
||||||
|
Result = 19500;
|
||||||
|
}else if(ObjType.TypeID == 3458){ // ANVIL
|
||||||
|
Result = 50000;
|
||||||
|
}else if(ObjType.TypeID == 3510){ // COAL BASIN
|
||||||
|
Result = 22800;
|
||||||
|
}else if(ObjType.TypeID == 4311){ // DEAD HUMAN
|
||||||
|
Result = 80000;
|
||||||
|
}else{
|
||||||
|
error("GetWeight: Objekttyp %d ist nicht nehmbar.\n", ObjType.TypeID);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetCompleteWeight(Object Obj){
|
||||||
|
int Result = GetWeight(Obj, -1);
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.getFlag(CONTAINER) || ObjType.getFlag(CHEST)){
|
||||||
|
Object Help = GetFirstContainerObject(Obj);
|
||||||
|
Result += GetRowWeight(Help);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetRowWeight(Object Obj){
|
||||||
|
int Result = 0;
|
||||||
|
while(Obj != NONE){
|
||||||
|
// TODO(fusion): This is probably `GetCompleteWeight` inlined.
|
||||||
|
Result += GetWeight(Obj, -1);
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.getFlag(CONTAINER) || ObjType.getFlag(CHEST)){
|
||||||
|
Object Help = GetFirstContainerObject(Obj);
|
||||||
|
Result += GetRowWeight(Help);
|
||||||
|
}
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 GetObjectCreatureID(Object Obj){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
error("GetObjectCreatureID: Übergebenes Objekt existiert nicht.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 CreatureID = 0;
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.isCreatureContainer()){
|
||||||
|
CreatureID = Obj.getCreatureID();
|
||||||
|
break;
|
||||||
|
}else if(ObjType.isMapContainer()){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Obj = Obj.getContainer();
|
||||||
|
}
|
||||||
|
return CreatureID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetObjectBodyPosition(Object Obj){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
error("GetObjectBodyPosition: Übergebenes Objekt existiert nicht.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Position = 0;
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.isBodyContainer()){
|
||||||
|
// NOTE(fusion): Body container type ids match inventory slots exactly.
|
||||||
|
Position = ObjType.TypeID;
|
||||||
|
break;
|
||||||
|
}else if(ObjType.isMapContainer()){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Obj = Obj.getContainer();
|
||||||
|
}
|
||||||
|
return Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetObjectRNum(Object Obj){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
error("GetObjectRNum: Übergebenes Objekt existiert nicht.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.isMapContainer()){
|
||||||
|
error("GetObjectRNum: Objekt ist MapContainer.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Result = 0;
|
||||||
|
Object Con = Obj.getContainer();
|
||||||
|
Object Help = GetFirstContainerObject(Con);
|
||||||
|
while(Help != NONE && Help != Obj){
|
||||||
|
Result += 1;
|
||||||
|
Help = Help.getNextObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Help != Obj){
|
||||||
|
error("GetObjectRNum: Objekt liegt nicht in Container\n");
|
||||||
|
Result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjectInRange(uint32 CreatureID, Object Obj, int Range){
|
||||||
|
TCreature *Creature = GetCreature(CreatureID);
|
||||||
|
if(Creature == NULL){
|
||||||
|
error("ObjectInRange: Ungültige Kreatur CreatureID=%d übergeben.\n", CreatureID);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Obj.exists()){
|
||||||
|
error("ObjectInRange: Übergebenes Objekt existiert nicht.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ObjX, ObjY, ObjZ;
|
||||||
|
GetObjectCoordinates(Obj, &ObjX, &ObjY, &ObjZ);
|
||||||
|
return Creature->posz == ObjZ
|
||||||
|
&& std::abs(Creature->posx - ObjX) <= Range
|
||||||
|
&& std::abs(Creature->posy - ObjY) <= Range;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjectAccessible(uint32 CreatureID, Object Obj, int Range){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
error("ObjectAccessible: Übergebenes Objekt existiert nicht.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(!ObjType.isCreatureContainer()){
|
||||||
|
uint32 OwnerID = GetObjectCreatureID(Obj);
|
||||||
|
if(OwnerID != 0){
|
||||||
|
return OwnerID == CreatureID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ObjType.getFlag(HANG)){
|
||||||
|
int ObjX, ObjY, ObjZ;
|
||||||
|
GetObjectCoordinates(Obj, &ObjX, &ObjY, &ObjZ);
|
||||||
|
|
||||||
|
bool HookSouth = CoordinateFlag(ObjX, ObjY, ObjZ, HOOKSOUTH);
|
||||||
|
bool HookEast = CoordinateFlag(ObjX, ObjY, ObjZ, HOOKEAST);
|
||||||
|
if(HookSouth || HookEast){
|
||||||
|
TCreature *Creature = GetCreature(CreatureID);
|
||||||
|
if(Creature == NULL){
|
||||||
|
error("ObjectAccessible: Kreatur existiert nicht.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(HookSouth){
|
||||||
|
if(Creature->posy < ObjY
|
||||||
|
|| Creature->posy > (ObjY + Range)
|
||||||
|
|| Creature->posx < (ObjX - Range)
|
||||||
|
|| Creature->posx > (ObjX + Range)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(HookEast){
|
||||||
|
if(Creature->posx < ObjX
|
||||||
|
|| Creature->posx > (ObjX + Range)
|
||||||
|
|| Creature->posy < (ObjY - Range)
|
||||||
|
|| Creature->posy > (ObjY + Range)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjectInRange(CreatureID, Obj, Range);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ObjectDistance(Object Obj1, Object Obj2){
|
||||||
|
if(!Obj1.exists() || !Obj2.exists()){
|
||||||
|
error("ObjectDistance: Übergebene Objekte existieren nicht.\n");
|
||||||
|
return INT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Distance = INT_MAX;
|
||||||
|
int ObjX1, ObjY1, ObjZ1;
|
||||||
|
int ObjX2, ObjY2, ObjZ2;
|
||||||
|
GetObjectCoordinates(Obj1, &ObjX1, &ObjY1, &ObjZ1);
|
||||||
|
GetObjectCoordinates(Obj2, &ObjX2, &ObjY2, &ObjZ2);
|
||||||
|
if(ObjZ1 == ObjZ2){
|
||||||
|
Distance = std::max<int>(
|
||||||
|
std::abs(ObjX1 - ObjX2),
|
||||||
|
std::abs(ObjY1 - ObjY2));
|
||||||
|
}
|
||||||
|
return Distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object GetBodyContainer(uint32 CreatureID, int Position){
|
||||||
|
if((Position < INVENTORY_FIRST || Position > INVENTORY_LAST)
|
||||||
|
&& (Position < CONTAINER_FIRST || Position > CONTAINER_LAST)){
|
||||||
|
error("GetBodyContainer: ungültige Position: %d\n", Position);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCreature *Creature = GetCreature(CreatureID);
|
||||||
|
if(Creature == NULL){
|
||||||
|
error("GetBodyContainer: Kreatur %d existiert nicht.\n", CreatureID);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Position >= INVENTORY_FIRST && Position <= INVENTORY_LAST){
|
||||||
|
if(!Creature->CrObject.exists()){
|
||||||
|
error("GetBodyContainer: Kreatur-Objekt von %s existiert nicht (Pos %d).\n",
|
||||||
|
Creature->Name, Position);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetContainerObject(Creature->CrObject, Position - INVENTORY_FIRST);
|
||||||
|
}else{
|
||||||
|
if(Creature->Type != PLAYER){
|
||||||
|
error("GetBodyContainer: Nur Spieler haben offene Container.\n");
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((TPlayer*)Creature)->GetOpenContainer(Position - CONTAINER_FIRST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object GetBodyObject(uint32 CreatureID, int Position){
|
||||||
|
if(Position < INVENTORY_FIRST || Position > INVENTORY_LAST){
|
||||||
|
error("GetBodyObject: ungültige Position %d\n", Position);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object Obj = NONE;
|
||||||
|
Object Con = GetBodyContainer(CreatureID, Position);
|
||||||
|
if(Con != NONE){
|
||||||
|
Obj = GetFirstContainerObject(Con);
|
||||||
|
}
|
||||||
|
return Obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object GetTopObject(int x, int y, int z, bool Move){
|
||||||
|
Object Obj = GetFirstObject(x, y, z);
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(!ObjType.getFlag(BANK)
|
||||||
|
&& !ObjType.getFlag(CLIP)
|
||||||
|
&& !ObjType.getFlag(BOTTOM)
|
||||||
|
&& !ObjType.getFlag(TOP)
|
||||||
|
&& (!Move || !ObjType.isCreatureContainer())){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return Obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object GetContainer(uint32 CreatureID, int x, int y, int z){
|
||||||
|
if(x == 0xFFFF){ // SPECIAL_COORDINATE ?
|
||||||
|
return GetBodyContainer(CreatureID, y);
|
||||||
|
}else{
|
||||||
|
return GetMapContainer(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object GetObject(uint32 CreatureID, int x, int y, int z, int RNum, ObjectType Type){
|
||||||
|
Object Obj = NONE;
|
||||||
|
if(x == 0xFFFF){ // SPECIAL_COORDINATE ?
|
||||||
|
if(y >= INVENTORY_FIRST && y <= INVENTORY_LAST){
|
||||||
|
Obj = GetBodyObject(CreatureID, y);
|
||||||
|
}else if(y >= CONTAINER_FIRST && y <= CONTAINER_LAST){
|
||||||
|
Object Con = GetBodyContainer(CreatureID, y);
|
||||||
|
if(Con != NONE){
|
||||||
|
Obj = GetContainerObject(Con, RNum);
|
||||||
|
}
|
||||||
|
}else if(y != 0){
|
||||||
|
error("GetObject: Ungültiger ContainerCode x=%d,y=%d,z=%d,RNum=%d,Type=%d.\n",
|
||||||
|
x, y, z, RNum, Type.TypeID);
|
||||||
|
}
|
||||||
|
}else if(RNum == -1){
|
||||||
|
Obj = GetTopObject(x, y, z, false);
|
||||||
|
}else{
|
||||||
|
Obj = GetFirstObject(x, y, z);
|
||||||
|
while(Obj != NONE){
|
||||||
|
if(Obj.getObjectType().getDisguise() == Type){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(fusion): `Type` can be a map container (TypeID = 0) as a wildcard for
|
||||||
|
// any object found.
|
||||||
|
if(Obj != NONE && !Type.isMapContainer()
|
||||||
|
&& Obj.getObjectType().getDisguise() != Type){
|
||||||
|
Obj = NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object GetRowObject(Object Obj, ObjectType Type, uint32 Value, bool Recurse){
|
||||||
|
Object Result = NONE;
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(Recurse && ObjType.getFlag(CONTAINER)){
|
||||||
|
Object Help = GetFirstContainerObject(Obj);
|
||||||
|
Result = GetRowObject(Help, Type, Value, Recurse);
|
||||||
|
if(Result != NONE){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ObjType == Type
|
||||||
|
&& (!ObjType.getFlag(LIQUIDCONTAINER) || Obj.getAttribute(CONTAINERLIQUIDTYPE) == Value)
|
||||||
|
&& (!ObjType.getFlag(KEY) || Obj.getAttribute(KEYNUMBER) == Value)){
|
||||||
|
Result = Obj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object GetInventoryObject(uint32 CreatureID, ObjectType Type, uint32 Value){
|
||||||
|
TCreature *Creature = GetCreature(CreatureID);
|
||||||
|
if(Creature == NULL){
|
||||||
|
error("GetInventoryObject: Kreatur %d existiert nicht.\n",CreatureID);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object Result = NONE;
|
||||||
|
|
||||||
|
// NOTE(fusion): Search inventory containers.
|
||||||
|
{
|
||||||
|
Object BodyCon = GetFirstContainerObject(Creature->CrObject);
|
||||||
|
while(BodyCon != NONE){
|
||||||
|
Object BodyObj = GetFirstContainerObject(BodyCon);
|
||||||
|
if(BodyObj != NONE && BodyObj.getObjectType().getFlag(CONTAINER)){
|
||||||
|
Object Help = GetFirstContainerObject(BodyObj);
|
||||||
|
Result = GetRowObject(Help, Type, Value, true);
|
||||||
|
if(Result != NONE){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BodyCon = BodyCon.getNextObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(fusion): Search inventory slots.
|
||||||
|
if(Result == NONE){
|
||||||
|
Object BodyCon = GetFirstContainerObject(Creature->CrObject);
|
||||||
|
while(BodyCon != NONE){
|
||||||
|
Object BodyObj = GetFirstContainerObject(BodyCon);
|
||||||
|
Result = GetRowObject(BodyObj, Type, Value, false);
|
||||||
|
if(Result != NONE){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BodyCon = BodyCon.getNextObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CountObjectsInContainer(Object Con){
|
||||||
|
if(!Con.exists()){
|
||||||
|
error("CountObjectsInContainer: Container existiert nicht.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Count = 0;
|
||||||
|
Object Obj = GetFirstContainerObject(Con);
|
||||||
|
while(Obj != NONE){
|
||||||
|
Count += 1;
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CountObjects(Object Obj){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Count = 1;
|
||||||
|
if(Obj.getObjectType().getFlag(CONTAINER)){
|
||||||
|
Object Help = GetFirstContainerObject(Obj);
|
||||||
|
while(Help != NONE){
|
||||||
|
Count += CountObjects(Help);
|
||||||
|
Help = Help.getNextObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CountObjects(Object Obj, ObjectType Type, uint32 Value){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(fusion): This is different from the other `CountObjects` as it does
|
||||||
|
// check other objects in the chain.
|
||||||
|
int Count = 0;
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.getFlag(CONTAINER)){
|
||||||
|
Object Help = GetFirstContainerObject(Obj);
|
||||||
|
// BUG(fusion): We probably meant to pass `Value` down the the call stack?
|
||||||
|
Count += CountObjects(Help, Type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ObjType == Type
|
||||||
|
&& (!ObjType.getFlag(LIQUIDCONTAINER) || Obj.getAttribute(CONTAINERLIQUIDTYPE) == Value)
|
||||||
|
&& (!ObjType.getFlag(KEY) || Obj.getAttribute(KEYNUMBER) == Value)){
|
||||||
|
if(ObjType.getFlag(CUMULATIVE)){
|
||||||
|
Count += (int)Obj.getAttribute(AMOUNT);
|
||||||
|
}else{
|
||||||
|
Count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CountInventoryObjects(uint32 CreatureID, ObjectType Type, uint32 Value){
|
||||||
|
TCreature *Creature = GetCreature(CreatureID);
|
||||||
|
if(Creature == NULL){
|
||||||
|
error("CountInventoryObjects: Kreatur %d existiert nicht; Objekttyp %d.\n",
|
||||||
|
CreatureID, Type.TypeID);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Creature->CrObject == NONE){
|
||||||
|
error("CountInventoryObjects: Kreatur %s hat kein Kreatur-Objekt.\n",
|
||||||
|
Creature->Name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object Help = GetFirstContainerObject(Help);
|
||||||
|
return CountObjects(Help, Type, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CountMoney(Object Obj){
|
||||||
|
if(!Obj.exists()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Result = 0;
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.getFlag(CONTAINER)){
|
||||||
|
Object Help = GetFirstContainerObject(Obj);
|
||||||
|
Result += CountMoney(Help);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(fusion): This was three different if statements but I don't think
|
||||||
|
// we'd want the same object type to be all special money objects.
|
||||||
|
if(ObjType == GetSpecialObject(MONEY_ONE)){
|
||||||
|
Result += (int)Obj.getAttribute(AMOUNT);
|
||||||
|
}else if(ObjType == GetSpecialObject(MONEY_HUNDRED)){
|
||||||
|
Result += (int)Obj.getAttribute(AMOUNT) * 100;
|
||||||
|
}else if(ObjType == GetSpecialObject(MONEY_TENTHOUSAND)){
|
||||||
|
Result += (int)Obj.getAttribute(AMOUNT) * 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CountInventoryMoney(uint32 CreatureID){
|
||||||
|
TCreature *Creature = GetCreature(CreatureID);
|
||||||
|
if(Creature == NULL){
|
||||||
|
error("CountInventoryMoney: Kreatur %d existiert nicht.\n", CreatureID);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Creature->CrObject == NONE){
|
||||||
|
error("CountInventoryMoney: Kreatur %s hat kein Kreatur-Objekt.\n", Creature->Name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object Help = GetFirstContainerObject(Creature->CrObject);
|
||||||
|
return CountMoney(Help);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalculateChange(int Amount, int *Gold, int *Platinum, int *Crystal){
|
||||||
|
// TODO(fusion): This function is kind of a mess. We should simplify or
|
||||||
|
// get rid of it entirely. It is used when removing gold from a creature
|
||||||
|
// but doesnt doesn't report errors outside from the `error` logging. It
|
||||||
|
// expects the caller to also check whether the amount of gold, platinum,
|
||||||
|
// and crystal is sufficient? We'll see when it gets applied.
|
||||||
|
|
||||||
|
int Go = *Gold;
|
||||||
|
int Pl = *Platinum;
|
||||||
|
int Cr = *Crystal;
|
||||||
|
|
||||||
|
print(3, "Zahle %d mit %d/%d/%d Münzen...\n", Amount, Go, Pl, Cr);
|
||||||
|
if((Cr * 10000 + Pl * 100 + Go) < Amount){
|
||||||
|
error("CalculateChange: %d/%d/%d Münzen reichen nicht zur Bezahlung von %d.\n",
|
||||||
|
Go, Pl, Cr, Amount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AmountCr = Amount / 10000;
|
||||||
|
int AmountRem = Amount % 10000;
|
||||||
|
if((Pl * 100 + Go) < AmountRem){
|
||||||
|
Cr = AmountCr + 1;
|
||||||
|
Pl = (AmountRem - 10000) / 100;
|
||||||
|
Go = (AmountRem - 10000) % 100;
|
||||||
|
}else{
|
||||||
|
if(Cr < AmountCr){
|
||||||
|
AmountRem = Amount - Cr * 10000;
|
||||||
|
}else{
|
||||||
|
Cr = AmountCr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AmountPl = AmountRem / 100;
|
||||||
|
int AmountGo = AmountRem % 100;
|
||||||
|
if(Go < AmountGo){
|
||||||
|
Pl = AmountPl + 1;
|
||||||
|
Go = AmountGo - 100;
|
||||||
|
}else if(Pl < AmountPl){
|
||||||
|
Go = AmountRem - Pl * 100;
|
||||||
|
}else{
|
||||||
|
Pl = AmountPl;
|
||||||
|
Go = AmountGo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print(3, "Verwende %d/%d/%d Münzen.\n", Go, Pl, Cr);
|
||||||
|
*Gold = Go;
|
||||||
|
*Platinum = Pl;
|
||||||
|
*Crystal = Cr;
|
||||||
|
|
||||||
|
if((Cr * 10000 + Pl * 100 + Go) != Amount){
|
||||||
|
error("CalculateChange: Fehlerhafte Berechnung: %d/%d/%d Münzen für %d.\n",
|
||||||
|
Go, Pl, Cr, Amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetHeight(int x, int y, int z){
|
||||||
|
int Result = 0;
|
||||||
|
Object Obj = GetFirstObject(x, y, z);
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.getFlag(HEIGHT)){
|
||||||
|
Result += (int)ObjType.getAttribute(ELEVATION);
|
||||||
|
}
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
bool JumpPossible(int x, int y, int z, bool AvoidPlayers){
|
bool JumpPossible(int x, int y, int z, bool AvoidPlayers){
|
||||||
bool HasBank = false;
|
bool HasBank = false;
|
||||||
Object Obj = GetFirstObject(x, y, z);
|
Object Obj = GetFirstObject(x, y, z);
|
||||||
@ -29,6 +704,39 @@ bool JumpPossible(int x, int y, int z, bool AvoidPlayers){
|
|||||||
return HasBank;
|
return HasBank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FieldPossible(int x, int y, int z, int FieldType){
|
||||||
|
Object Obj = GetFirstObject(x, y, z);
|
||||||
|
|
||||||
|
// NOTE(fusion): Only the first object on a given coordinate can be a bank
|
||||||
|
// on regular circumstances, so it makes sense to check it right away to
|
||||||
|
// determine whether a bank is present.
|
||||||
|
if(Obj == NONE || !Obj.getObjectType().getFlag(BANK)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(!ObjType.isCreatureContainer()){
|
||||||
|
if(ObjType.getFlag(UNPASS)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ObjType.getFlag(UNLAY)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(FieldType == FIELD_TYPE_MAGICWALL || FieldType == FIELD_TYPE_WILDGROWTH){
|
||||||
|
if(ObjType.getFlag(UNPASS)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool SearchFreeField(int *x, int *y, int *z, int Distance, uint16 HouseID, bool Jump){
|
bool SearchFreeField(int *x, int *y, int *z, int Distance, uint16 HouseID, bool Jump){
|
||||||
int OffsetX = 0;
|
int OffsetX = 0;
|
||||||
int OffsetY = 0;
|
int OffsetY = 0;
|
||||||
@ -55,8 +763,9 @@ bool SearchFreeField(int *x, int *y, int *z, int Distance, uint16 HouseID, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(MovePossible){
|
if(MovePossible){
|
||||||
if(HouseID == HOUSEID_ANY || !IsHouse(FieldX, FieldY, FieldZ)
|
if(HouseID == HOUSEID_ANY
|
||||||
|| (HouseID != 0 && HouseID == GetHouseID(FieldX, FieldY, FieldZ))){
|
|| !IsHouse(FieldX, FieldY, FieldZ)
|
||||||
|
|| GetHouseID(FieldX, FieldY, FieldZ) == HouseID){
|
||||||
*x = FieldX;
|
*x = FieldX;
|
||||||
*y = FieldY;
|
*y = FieldY;
|
||||||
return true;
|
return true;
|
||||||
@ -95,3 +804,220 @@ bool SearchFreeField(int *x, int *y, int *z, int Distance, uint16 HouseID, bool
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(fusion): This is a helper function for `SearchLoginField`. Perhaps we
|
||||||
|
// should try to merge it there?
|
||||||
|
static bool LoginPossible(int x, int y, int z, uint16 HouseID, bool Player){
|
||||||
|
Object Obj = GetFirstObject(x, y, z);
|
||||||
|
if(Obj == NONE){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Player && IsNoLogoutField(x, y, z)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IsHouse(x, y, z) && GetHouseID(x, y, z) != HouseID){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBank = false;
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.getFlag(BANK)){
|
||||||
|
HasBank = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ObjType.isCreatureContainer()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ObjType.getFlag(UNPASS) && ObjType.getFlag(UNMOVE)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Player && ObjType.getFlag(AVOID) && ObjType.getFlag(UNMOVE)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
return HasBank;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchLoginField(int *x, int *y, int *z, int Distance, bool Player){
|
||||||
|
uint16 HouseID = GetHouseID(*x, *y, *z);
|
||||||
|
if(SearchFreeField(x, y, z, Distance, HouseID, false)
|
||||||
|
&& (!Player || !IsNoLogoutField(*x, *y, *z))){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OffsetX = 0;
|
||||||
|
int OffsetY = 0;
|
||||||
|
int CurrentDistance = 0;
|
||||||
|
int CurrentDirection = DIRECTION_EAST;
|
||||||
|
while(CurrentDistance <= Distance){
|
||||||
|
int FieldX = *x + OffsetX;
|
||||||
|
int FieldY = *y + OffsetY;
|
||||||
|
int FieldZ = *z;
|
||||||
|
|
||||||
|
if(LoginPossible(FieldX, FieldY, FieldZ, HouseID, Player)){
|
||||||
|
*x = FieldX;
|
||||||
|
*y = FieldY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(fusion): Same as `SearchFreeField`.
|
||||||
|
if(CurrentDirection == DIRECTION_NORTH){
|
||||||
|
OffsetY -= 1;
|
||||||
|
if(OffsetY <= -CurrentDistance){
|
||||||
|
CurrentDirection = DIRECTION_WEST;
|
||||||
|
}
|
||||||
|
}else if(CurrentDirection == DIRECTION_WEST){
|
||||||
|
OffsetX -= 1;
|
||||||
|
if(OffsetX <= -CurrentDistance){
|
||||||
|
CurrentDirection = DIRECTION_SOUTH;
|
||||||
|
}
|
||||||
|
}else if(CurrentDirection == DIRECTION_SOUTH){
|
||||||
|
OffsetY += 1;
|
||||||
|
if(OffsetY >= CurrentDistance){
|
||||||
|
CurrentDirection = DIRECTION_EAST;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
ASSERT(CurrentDirection == DIRECTION_EAST);
|
||||||
|
OffsetX += 1;
|
||||||
|
if(OffsetX > CurrentDistance){
|
||||||
|
CurrentDistance = OffsetX;
|
||||||
|
CurrentDirection = DIRECTION_NORTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchSpawnField(int *x, int *y, int *z, int Distance, bool Player){
|
||||||
|
// TODO(fusion): It seems `Distance` can be a negative number to do some
|
||||||
|
// extended search?
|
||||||
|
bool Minimize = true;
|
||||||
|
if(Distance < 0){
|
||||||
|
Minimize = false;
|
||||||
|
Distance = -Distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 HouseID = GetHouseID(*x, *y, *z);
|
||||||
|
matrix<int> Map(-Distance, Distance, -Distance, Distance, INT_MAX);
|
||||||
|
*Map.at(0, 0) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
int BestX = 0;
|
||||||
|
int BestY = 0;
|
||||||
|
int BestTieBreaker = -1;
|
||||||
|
int ExpansionPhase = 0;
|
||||||
|
while(true){
|
||||||
|
bool Found = false;
|
||||||
|
bool Expanded = false;
|
||||||
|
for(int OffsetY = -Distance; OffsetY <= Distance; OffsetY += 1)
|
||||||
|
for(int OffsetX = -Distance; OffsetX <= Distance; OffsetX += 1){
|
||||||
|
if(*Map.at(OffsetX, OffsetY) != ExpansionPhase){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FieldX = *x + OffsetX;
|
||||||
|
int FieldY = *y + OffsetY;
|
||||||
|
int FieldZ = *z;
|
||||||
|
if(IsHouse(FieldX, FieldY, FieldZ) && GetHouseID(FieldX, FieldY, FieldZ) != HouseID){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Player && IsProtectionZone(FieldX, FieldY, FieldZ)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object Obj = GetFirstObject(FieldX, FieldY, FieldZ);
|
||||||
|
if(Obj == NONE){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExpansionPossible = true;
|
||||||
|
bool LoginPossible = true;
|
||||||
|
bool LoginBad = false;
|
||||||
|
while(Obj != NONE){
|
||||||
|
ObjectType ObjType = Obj.getObjectType();
|
||||||
|
if(ObjType.isCreatureContainer()){
|
||||||
|
LoginPossible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ObjType.getFlag(UNPASS)){
|
||||||
|
if(ObjType.getFlag(UNMOVE)){
|
||||||
|
ExpansionPossible = false;
|
||||||
|
LoginPossible = false;
|
||||||
|
}else{
|
||||||
|
LoginBad = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ObjType.getFlag(AVOID)){
|
||||||
|
if(ObjType.getFlag(UNMOVE)){
|
||||||
|
ExpansionPossible = false;
|
||||||
|
LoginPossible = LoginPossible && !Player;
|
||||||
|
}else{
|
||||||
|
LoginBad = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj = Obj.getNextObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ExpansionPossible || ExpansionPhase == 0){
|
||||||
|
for(int NeighborOffsetY = OffsetY - 1; NeighborOffsetY <= OffsetY + 1; NeighborOffsetY += 1)
|
||||||
|
for(int NeighborOffsetX = OffsetX - 1; NeighborOffsetX <= OffsetX + 1; NeighborOffsetX += 1){
|
||||||
|
if(-Distance <= NeighborOffsetX && NeighborOffsetX <= Distance
|
||||||
|
&& -Distance <= NeighborOffsetY && NeighborOffsetY <= Distance){
|
||||||
|
int *NeighborPhase = Map.at(NeighborOffsetX, NeighborOffsetY);
|
||||||
|
if(*NeighborPhase > ExpansionPhase){
|
||||||
|
*NeighborPhase = ExpansionPhase
|
||||||
|
+ std::abs(NeighborOffsetX - OffsetX)
|
||||||
|
+ std::abs(NeighborOffsetY - OffsetY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LoginPossible && (!Player || !IsNoLogoutField(FieldX, FieldY, FieldZ))){
|
||||||
|
int TieBreaker = random(0, 99);
|
||||||
|
if(!LoginBad){
|
||||||
|
TieBreaker += 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(TieBreaker > BestTieBreaker){
|
||||||
|
BestX = FieldX;
|
||||||
|
BestY = FieldY;
|
||||||
|
BestTieBreaker = TieBreaker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((Found && Minimize) || !Expanded){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpansionPhase += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result = false;
|
||||||
|
if(BestTieBreaker >= 0){
|
||||||
|
*x = BestX;
|
||||||
|
*y = BestY;
|
||||||
|
Result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitInfo(void){
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExitInfo(void){
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|||||||
32
src/info.hh
32
src/info.hh
@ -12,7 +12,39 @@ enum HouseList: uint8 {
|
|||||||
DOORLIST = 3,
|
DOORLIST = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *GetLiquidName(int LiquidType);
|
||||||
|
uint8 GetLiquidColor(int LiquidType);
|
||||||
|
const char *GetName(Object Obj);
|
||||||
|
int GetWeight(Object Obj, int Count);
|
||||||
|
int GetCompleteWeight(Object Obj);
|
||||||
|
int GetRowWeight(Object Obj);
|
||||||
|
uint32 GetObjectCreatureID(Object Obj);
|
||||||
|
int GetObjectBodyPosition(Object Obj);
|
||||||
|
int GetObjectRNum(Object Obj);
|
||||||
|
bool ObjectInRange(uint32 CreatureID, Object Obj, int Range);
|
||||||
|
bool ObjectAccessible(uint32 CreatureID, Object Obj, int Range);
|
||||||
|
int ObjectDistance(Object Obj1, Object Obj2);
|
||||||
|
Object GetBodyContainer(uint32 CreatureID, int Position);
|
||||||
|
Object GetBodyObject(uint32 CreatureID, int Position);
|
||||||
|
Object GetTopObject(int x, int y, int z, bool Move);
|
||||||
|
Object GetContainer(uint32 CreatureID, int x, int y, int z);
|
||||||
|
Object GetObject(uint32 CreatureID, int x, int y, int z, int RNum, ObjectType Type);
|
||||||
|
Object GetRowObject(Object Obj, ObjectType Type, uint32 Value, bool Recurse);
|
||||||
|
Object GetInventoryObject(uint32 CreatureID, ObjectType Type, uint32 Value);
|
||||||
|
int CountObjectsInContainer(Object Con);
|
||||||
|
int CountObjects(Object Obj);
|
||||||
|
int CountObjects(Object Obj, ObjectType Type, uint32 Value);
|
||||||
|
int CountInventoryObjects(uint32 CreatureID, ObjectType Type, uint32 Value);
|
||||||
|
int CountMoney(Object Obj);
|
||||||
|
int CountInventoryMoney(uint32 CreatureID);
|
||||||
|
void CalculateChange(int Amount, int *Gold, int *Platinum, int *Crystal);
|
||||||
|
int GetHeight(int x, int y, int z);
|
||||||
bool JumpPossible(int x, int y, int z, bool AvoidPlayers);
|
bool JumpPossible(int x, int y, int z, bool AvoidPlayers);
|
||||||
|
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 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);
|
||||||
|
void InitInfo(void);
|
||||||
|
void ExitInfo(void);
|
||||||
|
|
||||||
#endif //TIBIA_INFO_HH_
|
#endif //TIBIA_INFO_HH_
|
||||||
|
|||||||
@ -2487,11 +2487,7 @@ void ObjectIllusion(TCreature *Actor, int ManaPoints, int SoulPoints, Object Tar
|
|||||||
CheckMana(Actor, ManaPoints, SoulPoints, 1000);
|
CheckMana(Actor, ManaPoints, SoulPoints, 1000);
|
||||||
if(Actor->Skills[SKILL_ILLUSION]->Get() == 0){
|
if(Actor->Skills[SKILL_ILLUSION]->Get() == 0){
|
||||||
Actor->Outfit.OutfitID = 0;
|
Actor->Outfit.OutfitID = 0;
|
||||||
if(TargetType.getFlag(DISGUISE)){
|
Actor->Outfit.ObjectType = (uint16)TargetType.getDisguise().TypeID;
|
||||||
Actor->Outfit.ObjectType = (uint16)TargetType.getAttribute(DISGUISETARGET);
|
|
||||||
}else{
|
|
||||||
Actor->Outfit.ObjectType = (uint16)TargetType.TypeID;
|
|
||||||
}
|
|
||||||
Actor->SetTimer(SKILL_ILLUSION, 1, Duration, Duration, -1);
|
Actor->SetTimer(SKILL_ILLUSION, 1, Duration, Duration, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -197,5 +197,7 @@ int CheckForSpell(uint32 CreatureID, const char *Text);
|
|||||||
void UseMagicItem(uint32 CreatureID, Object Obj, Object Dest);
|
void UseMagicItem(uint32 CreatureID, Object Obj, Object Dest);
|
||||||
void DrinkPotion(uint32 CreatureID, Object Obj);
|
void DrinkPotion(uint32 CreatureID, Object Obj);
|
||||||
|
|
||||||
|
void InitMagic(void);
|
||||||
|
void ExitMagic(void);
|
||||||
|
|
||||||
#endif //TIBIA_MAGIC_HH_
|
#endif //TIBIA_MAGIC_HH_
|
||||||
|
|||||||
14
src/main.cc
14
src/main.cc
@ -1,6 +1,8 @@
|
|||||||
#include "common.hh"
|
#include "common.hh"
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
|
#include "info.hh"
|
||||||
#include "map.hh"
|
#include "map.hh"
|
||||||
|
#include "magic.hh"
|
||||||
#include "objects.hh"
|
#include "objects.hh"
|
||||||
|
|
||||||
#include "stubs.hh"
|
#include "stubs.hh"
|
||||||
@ -230,10 +232,10 @@ static void InitAll(void){
|
|||||||
//InitReader();
|
//InitReader();
|
||||||
InitObjects();
|
InitObjects();
|
||||||
InitMap();
|
InitMap();
|
||||||
//InitInfo();
|
InitInfo();
|
||||||
//InitMoveUse();
|
//InitMoveUse();
|
||||||
//InitMagic();
|
InitMagic();
|
||||||
//InitCr();
|
InitCr();
|
||||||
//InitHouses();
|
//InitHouses();
|
||||||
InitTime();
|
InitTime();
|
||||||
//ApplyPatches();
|
//ApplyPatches();
|
||||||
@ -248,10 +250,10 @@ static void ExitAll(void){
|
|||||||
|
|
||||||
EndGame();
|
EndGame();
|
||||||
ExitTime();
|
ExitTime();
|
||||||
//ExitCr();
|
ExitCr();
|
||||||
//ExitMagic();
|
ExitMagic();
|
||||||
//ExitMoveUse();
|
//ExitMoveUse();
|
||||||
//ExitInfo();
|
ExitInfo();
|
||||||
//ExitHouses();
|
//ExitHouses();
|
||||||
ExitMap(SaveMapOn);
|
ExitMap(SaveMapOn);
|
||||||
ExitObjects();
|
ExitObjects();
|
||||||
|
|||||||
@ -62,6 +62,14 @@ struct ObjectType {
|
|||||||
|| this->getFlag(WAND);
|
|| this->getFlag(WAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectType getDisguise(void){
|
||||||
|
if(this->getFlag(DISGUISE)){
|
||||||
|
return (int)this->getAttribute(DISGUISETARGET);
|
||||||
|
}else{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const ObjectType &Other) const {
|
bool operator==(const ObjectType &Other) const {
|
||||||
return this->TypeID == Other.TypeID;
|
return this->TypeID == Other.TypeID;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "operate.hh"
|
#include "operate.hh"
|
||||||
|
#include "info.hh"
|
||||||
|
|
||||||
#include "stubs.hh"
|
#include "stubs.hh"
|
||||||
|
|
||||||
|
|||||||
15
src/stubs.hh
15
src/stubs.hh
@ -26,26 +26,15 @@ extern bool CheckRight(uint32 CreatureID, RIGHT Right);
|
|||||||
extern void CleanHouseField(int x, int y, int z);
|
extern void CleanHouseField(int x, int y, int z);
|
||||||
extern void ConvinceMonster(TCreature *Master, TCreature *Slave);
|
extern void ConvinceMonster(TCreature *Master, TCreature *Slave);
|
||||||
extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster);
|
extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster);
|
||||||
extern int CountInventoryObjects(uint32 CreatureID, ObjectType Type, uint32 Value);
|
|
||||||
extern int CountObjects(Object Obj);
|
|
||||||
extern int CountObjectsInContainer(Object Con);
|
|
||||||
extern Object Create(Object Con, ObjectType Type, uint32 Value);
|
extern Object Create(Object Con, ObjectType Type, uint32 Value);
|
||||||
extern Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value);
|
extern Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value);
|
||||||
extern TCreature *CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect);
|
extern TCreature *CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect);
|
||||||
extern void CreatePlayerList(bool Online);
|
extern void CreatePlayerList(bool Online);
|
||||||
extern void CreatePool(Object Con, ObjectType Type, uint32 Value);
|
extern void CreatePool(Object Con, ObjectType Type, uint32 Value);
|
||||||
extern void Delete(Object Obj, int Count);
|
extern void Delete(Object Obj, int Count);
|
||||||
extern bool FieldPossible(int x, int y, int z, int FieldType);
|
|
||||||
extern Object GetBodyObject(uint32 CreatureID, int Position);
|
|
||||||
extern Object GetBodyContainer(uint32 CreatureID, int Position);
|
|
||||||
extern int GetObjectBodyPosition(Object Obj);
|
|
||||||
extern void GetExitPosition(uint16 HouseID, int *x, int *y, int *z);
|
extern void GetExitPosition(uint16 HouseID, int *x, int *y, int *z);
|
||||||
extern TConnection *GetFirstConnection(void);
|
extern TConnection *GetFirstConnection(void);
|
||||||
extern int GetHeight(int x, int y, int z);
|
|
||||||
extern TConnection *GetNextConnection(void);
|
extern TConnection *GetNextConnection(void);
|
||||||
extern const char *GetName(Object Obj);
|
|
||||||
extern Object GetObject(uint32 CreatureID, int x, int y, int z, int RNum, ObjectType Type);
|
|
||||||
extern uint32 GetObjectCreatureID(Object Obj);
|
|
||||||
extern TPlayer *GetPlayer(uint32 CreatureID);
|
extern TPlayer *GetPlayer(uint32 CreatureID);
|
||||||
extern void GraphicalEffect(int x, int y, int z, int Type);
|
extern void GraphicalEffect(int x, int y, int z, int Type);
|
||||||
extern void GraphicalEffect(Object Obj, int Type);
|
extern void GraphicalEffect(Object Obj, int Type);
|
||||||
@ -64,9 +53,6 @@ extern void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMe
|
|||||||
extern void NetLoadCheck(void);
|
extern void NetLoadCheck(void);
|
||||||
extern void NetLoadSummary(void);
|
extern void NetLoadSummary(void);
|
||||||
extern void NotifyAllCreatures(Object Obj, int Type, Object OldCon);
|
extern void NotifyAllCreatures(Object Obj, int Type, Object OldCon);
|
||||||
extern bool ObjectAccessible(uint32 CreatureID, Object Obj, int Range);
|
|
||||||
extern int ObjectDistance(Object Obj1, Object Obj2);
|
|
||||||
extern bool ObjectInRange(uint32 CreatureID, Object Obj, int Range);
|
|
||||||
extern void ProcessCommunicationControl(void);
|
extern void ProcessCommunicationControl(void);
|
||||||
extern void ProcessConnections(void);
|
extern void ProcessConnections(void);
|
||||||
extern void ProcessCronSystem(void);
|
extern void ProcessCronSystem(void);
|
||||||
@ -79,7 +65,6 @@ extern void RefreshMap(void);
|
|||||||
extern void RefreshSector(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int Size);
|
extern void RefreshSector(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int Size);
|
||||||
extern void SavePlayerDataOrder(void);
|
extern void SavePlayerDataOrder(void);
|
||||||
extern bool SearchFlightField(uint32 FugitiveID, uint32 PursuerID, int *x, int *y, int *z);
|
extern bool SearchFlightField(uint32 FugitiveID, uint32 PursuerID, int *x, int *y, int *z);
|
||||||
extern bool SearchLoginField(int *x, int *y, int *z, int Distance, bool Player);
|
|
||||||
extern bool SearchSummonField(int *x, int *y, int *z, int Distance);
|
extern bool SearchSummonField(int *x, int *y, int *z, int Distance);
|
||||||
extern void SendAll(void);
|
extern void SendAll(void);
|
||||||
extern void SendAmbiente(TConnection *Connection);
|
extern void SendAmbiente(TConnection *Connection);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user