// Compile and execute the shipped server command against a small server API fixture. #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include using DWORD = uint32_t; constexpr int ENTITY_CHARACTER=1, ATTR_BANPK=4, MOB_RANK_BOSS=4, CHAT_TYPE_COMMAND=5, SECTREE_SIZE=6400; struct Character; using LPCHARACTER=Character*; struct Entity { virtual ~Entity() {} bool IsType(int) { return true; } }; using LPENTITY=Entity*; struct Party {}; struct Sectree { bool safe=false; std::vector entities; DWORD GetAttribute(long,long) { return safe ? ATTR_BANPK : 0; } template void for_each_entity(F& f) { for(auto* e:entities) f(e); } template void ForEachAround(F& f) { for(auto* e:entities) f(e); } }; struct Character: Entity { DWORD vid=0; int x=0,y=0,rank=0,hp=100,maxhp=100; bool pc=false,dead=false,stun=false,canHandle=true; Sectree* sec=nullptr; Party* party=nullptr; Character* victim=nullptr; int next=0, beginCount=0; std::vector replies; bool IsMonster() { return !pc; } bool IsPC() { return pc; } bool IsDead() { return dead; } bool IsStun() { return stun; } bool CanHandleItem() { return canHandle; } bool CanBeginFight() { return !victim && !dead && !stun; } int GetHP() { return hp; } int GetMaxHP() { return maxhp; } int GetX() { return x; } int GetY() { return y; } int GetMapIndex() { return 1; } DWORD GetPlayerID() { return vid; } int GetMobRank() { return rank; } Sectree* GetSectree() { return sec; } Party* GetParty() { return party; } DWORD GetVID() { return vid; } Character* GetVictim() { return victim; } int GetQuestFlag(const char*) { return next; } void SetQuestFlag(const char*,int value) { next=value; } void BeginFight(Character* owner) { victim=owner; ++beginCount; } void ChatPacket(int,const char* format,...) { char buf[256]; va_list ap; va_start(ap,format); vsnprintf(buf,sizeof(buf),format,ap); va_end(ap); replies.emplace_back(buf); } }; struct CHARACTER_MANAGER { std::map mobs; static CHARACTER_MANAGER& instance() { static CHARACTER_MANAGER value; return value; } Character* Find(DWORD vid) { return mobs[vid]; } int GetMobExpRate(LPCHARACTER) { return 200; } int GetMobGoldAmountRate(LPCHARACTER) { return 300; } int GetMobGoldDropRate(LPCHARACTER) { return 400; } int GetMobItemRate(LPCHARACTER ch) { assert(ch); return 999; } // locale rules require a real character int GetGlobalMobItemRate() { return 500; } }; using LPSECTREE=Sectree*; struct SectreeMap { std::map, Sectree*> cells; template void for_each_in_rect(int x0,int y0,int x1,int y1,F& f) { for (const auto& cell:cells) if (cell.first.first>=x0/SECTREE_SIZE && cell.first.first<=x1/SECTREE_SIZE && cell.first.second>=y0/SECTREE_SIZE && cell.first.second<=y1/SECTREE_SIZE) cell.second->for_each_entity(f); } Sectree* Find(int x,int y) { auto it=cells.find({x/SECTREE_SIZE,y/SECTREE_SIZE}); return it==cells.end() ? nullptr : it->second; } }; using LPSECTREE_MAP=SectreeMap*; struct SECTREE_MANAGER { SectreeMap map; static SECTREE_MANAGER& instance() { static SECTREE_MANAGER m; return m; } SectreeMap* GetMap(int) { return ↦ } }; int now=100; int get_global_time() { return now; } #define DISTANCE_APPROX(x,y) int(std::hypot(x,y)) #define ACMD(name) void name(LPCHARACTER ch,const char* argument) #define MT_AUTOHUNT_SERVER_TEST #include "../../tools/server/autohunt-pull/autohunt_pull.h" constexpr int PRIV_EXP_PCT=4, PRIV_ITEM_DROP=1, PRIV_GOLD_DROP=2, PRIV_GOLD10_DROP=3; struct CPrivManager { static CPrivManager& instance() { static CPrivManager pm; return pm; } int GetPriv(LPCHARACTER ch, int type) { assert(ch); return type*10; } }; #include "../../tools/server/autohunt-pull-range/server_bonuses.h" int main() { Sectree sec; Character owner; owner.pc=true; owner.sec=&sec; owner.vid=1; SECTREE_MANAGER::instance().map.cells[{0,0}]=&sec; Character other; other.pc=true; std::vector parties(25); std::vector mobs(50); for(size_t i=0;i candidates; for(int g=24;g>=0;--g) for(int m=0;m