/* EQ2Emulator: Everquest II Server Emulator Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) This file is part of EQ2Emulator. EQ2Emulator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. EQ2Emulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with EQ2Emulator. If not, see . */ #ifndef EQ2_WORLD_H #define EQ2_WORLD_H #include #include #include #include #include #include #include "SpawnLists.h" #include "zoneserver.h" #include "NPC.h" #include "Widget.h" #include "Object.h" #include "GroundSpawn.h" #include "Sign.h" #include "Variables.h" #include "MutexList.h" #include "PlayerGroups.h" #include "./Zone/region_map.h" #include "./Zone/map.h" using namespace std; struct MerchantInfo{ vector inventory_ids; /*int32 faction_id; sint32 faction_min; sint32 faction_max; float low_buy_multiplier; float high_buy_multiplier; float low_sell_multiplier; float high_sell_multiplier;*/ }; struct MerchantItemInfo{ int32 item_id; int16 quantity; int32 price_item_id; int32 price_item2_id; int16 price_item_qty; int16 price_item2_qty; int32 price_status; int64 price_coins; int32 price_stationcash; }; struct LootTable{ string name; int32 mincoin; int32 maxcoin; int16 maxlootitems; float lootdrop_probability; float coin_probability; }; struct LootDrop{ int32 item_id; int16 item_charges; bool equip_item; float probability; int32 no_drop_quest_completed_id; }; struct GroundSpawnEntry { int16 min_skill_level; int16 min_adventure_level; int8 bonus_table; float harvest1; float harvest3; float harvest5; float harvest_imbue; float harvest_rare; float harvest10; int32 harvest_coin; }; struct GroundSpawnEntryItem { int32 item_id; int8 is_rare; int32 grid_id; }; struct TransportDestination{ int32 unique_id; int8 type; string display_name; string message; int32 destination_zone_id; float destination_x; float destination_y; float destination_z; float destination_heading; int32 cost; int8 min_level; int8 max_level; int32 req_quest; int16 req_quest_step; int32 req_quest_complete; int32 map_x; int32 map_y; int32 faction_id; int32 faction_value; int32 expansion_flag; int32 holiday_flag; int32 min_client_version; int32 max_client_version; int32 flight_path_id; int16 mount_id; int8 mount_red_color; int8 mount_green_color; int8 mount_blue_color; }; struct LocationTransportDestination{ int32 unique_id; string message; int32 destination_zone_id; float destination_x; float destination_y; float destination_z; float destination_heading; float trigger_x; float trigger_y; float trigger_z; float trigger_radius; int32 cost; int32 faction_id; int32 faction_value; }; //ideally we wouldn't need to store this information as we could get it from the Client object, //however since the client object disconnects from the server when zoning we can't count on it being available /*struct PlayerGroup; struct GroupOptions{ int8 loot_method; int8 loot_items_rarity; int8 auto_split; int8 default_yell; int8 group_autolock; int8 solo_autolock; }; struct GroupMemberInfo{ string name; string zone; sint32 hp_current; sint32 hp_max; sint32 power_current; sint32 power_max; int16 level_current; int16 level_max; int8 race_id; int8 class_id; Client* client; PlayerGroup* group; }; struct PlayerGroup{ deque members; GroupOptions options; };*/ struct LottoPlayer { int32 end_time; int8 num_matches; bool set; }; struct HouseZone { int32 id; string name; int64 cost_coin; int32 cost_status; int64 upkeep_coin; int32 upkeep_status; int8 vault_slots; int8 alignment; int8 guild_level; int32 zone_id; int32 exit_zone_id; float exit_x; float exit_y; float exit_z; float exit_heading; }; struct Deposit { int32 timestamp; int64 amount; int64 last_amount; int32 status; int32 last_status; string name; }; struct HouseHistory { HouseHistory() { timestamp = 0; amount = 0; name = string(""); reason = string(""); status = 0; pos_flag = 0; } HouseHistory(int32 in_timestamp, int64 in_amount, string in_name, string in_reason, int32 in_status, int8 in_pos_flag) { timestamp = in_timestamp; amount = in_amount; name = in_name; reason = in_reason; status = in_status; pos_flag = in_pos_flag; } int32 timestamp; int64 amount; string name; string reason; int32 status; int8 pos_flag; }; struct PlayerHouse { int32 house_id; int64 unique_id; int32 instance_id; int32 upkeep_due; int64 escrow_coins; int32 escrow_status; string player_name; list deposits; map depositsMap; list history; }; // Constants for STATs counters // Server Utilization #define STAT_SERVER_OS_TYPE 1 // what OS this server is running on #define STAT_SERVER_CPU_TYPE 2 // cpu type/speed (ie., Intel P4 3.0GHz) #define STAT_SERVER_CPU_CURRENT 3 // current CPU usage by EQ2World.exe process #define STAT_SERVER_CPU_PEAK 4 // highest CPU usage by EQ2World.exe this session #define STAT_SERVER_PHYSICAL_RAM_TOTAL 5 // total RAM in server #define STAT_SERVER_PHYSICAL_RAM_CURRENT 6 // current RAM usage by EQ2World.exe #define STAT_SERVER_PHYSICAL_RAM_PEAK 7 // highest RAM usage by EQ2World.exe this session #define STAT_SERVER_VIRTUAL_RAM_TOTAL 8 // total vRAM in server #define STAT_SERVER_VIRTUAL_RAM_CURRENT 9 // current vRAM usage by EQ2World.exe #define STAT_SERVER_VIRTUAL_RAM_PEAK 10 // highest vRAM usage by EQ2World.exe this session #define STAT_SERVER_DISK_USAGE 11 // size of /eq2emulator folder and contents #define STAT_SERVER_THREAD_COUNT 12 // thread count of EQ2World.exe process #define STAT_SERVER_AVG_LATENCY 13 // network latency between world and loginserver // Server Stats #define STAT_SERVER_CREATED 100 // unix_timestamp of date server first came online #define STAT_SERVER_START_TIME 101 // unix_timestamp of date/time server booted up #define STAT_SERVER_ACCEPTED_CONNECTION 102 // successful connections since server startup #define STAT_SERVER_MOST_CONNECTIONS 103 // most players online in history of server #define STAT_SERVER_NUM_ACCOUNTS 104 // total number of unique accounts #define STAT_SERVER_NUM_CHARACTERS 105 // total number of player characters #define STAT_SERVER_AVG_CHAR_LEVEL 106 // average level of player characters #define STAT_SERVER_NUM_ACTIVE_ZONES 107 // number of currently running/loaded zones #define STAT_SERVER_NUM_ACTIVE_INSTANCES 108 // number of active zones that are "instances" // Player PvE counters #define STAT_PLAYER_TOTAL_NPC_KILLS 1000 // total NPC kills by player #define STAT_PLAYER_TOTAL_DEATHS 1001 // total non-PvP deaths of player #define STAT_PLAYER_KVD_RATIO 1002 // kill-versus-death ratio of player #define STAT_PLAYER_HIGHEST_MELEE_HIT 1003 // players highest melee hit to date #define STAT_PLAYER_HIGHEST_MAGIC_HIT 1004 // players highest magic hit to date #define STAT_PLAYER_HIGHEST_HO_HIT 1005 // players highest heroic opportunity hit #define STAT_PLAYER_TOTAL_STATUS 1006 // player total status #define STAT_PLAYER_TOTAL_WEALTH 1007 // player total wealth #define STAT_PLAYER_QUESTS_COMPLETED 1008 // total quests completed #define STAT_PLAYER_RECIPES_KNOWN 1009 // total recipes player knows #define STAT_PLAYER_TOTAL_CRAFTED_ITEMS 1010 // total items crafted by player #define STAT_PLAYER_ITEMS_DISCOVERED 1011 // total items discovered by player #define STAT_PLAYER_RARES_HARVESTED 1012 // total rare harvests by player #define STAT_PLAYER_ITEMS_HARVESTED 1013 // total rare harvests by player #define STAT_PLAYER_MASTER_ABILITIES 1014 // total master abilities player has #define STAT_PLAYER_HIGHEST_FALLING_HIT 1015 // player's highest damage amount taken from falling // Player PvP counters #define STAT_PLAYER_TOTAL_PVP_KILLS 1100 // total PVP kills by player #define STAT_PLAYER_PVP_KILL_STREAK 1101 // longest PVP kill streak of player #define STAT_PLAYER_TOTAL_PVP_DEATHS 1102 // total PVP deaths of player #define STAT_PLAYER_PVP_DEATH_STREAK 1103 // longest PVP death streak of player #define STAT_PLAYER_PVP_KVD_RATIO 1104 // PVP kill-versus-death ratio of player #define STAT_PLAYER_TOTAL_ARENA_KILLS 1105 // total Arena kills of player // MOST stats for players #define STAT_PLAYER_MOST_NPC_KILLS 1200 // IPvP: Player with most NPC kills #define STAT_PLAYER_MOST_NPC_DEATHS 1201 // IPvP: Player with most non-PVP deaths #define STAT_PLAYER_MOST_PVP_KILLS 1202 // IPvP: Player with most PvP kills #define STAT_PLAYER_MOST_PVP_DEATHS 1203 // IPvP: Player with most PvP deaths #define STAT_PLAYER_MOST_ARENA_KILLS 1204 // IPvP: Player with most Arena kills #define STAT_PLAYER_MOST_STATUS 1205 // IPvP: Player with most Status #define STAT_PLAYER_MOST_WEALTH 1206 // IPvP: Player with most Wealth // HIGHEST stats for players #define STAT_PLAYER_HIGHEST_NPC_KVD_RATIO 1300 // IPvP: Player with highest NPC kill-versus-death ratio #define STAT_PLAYER_HIGHEST_PVP_KILL_STREAK 1301 // IPvP: Player with longest PvP kill streak #define STAT_PLAYER_HIGHEST_PVP_DEATH_STREAK 1302 // IPvP: Player with longest PvP death streak #define STAT_PLAYER_HIGHEST_PVP_KVD_RATIO 1303 // IPvP: Player with highest PvP kill-versus-death ratio #define STAT_PLAYER_HIGHEST_HP 1304 // IPvP: Player with highest HP on server #define STAT_PLAYER_HIGHEST_POWER 1305 // IPvP: Player with highest Power on server #define STAT_PLAYER_HIGHEST_RESISTS 1306 // IPvP: Player with highest Resists on server struct Statistic { int32 stat_id; sint32 stat_value; int32 stat_date; bool save_needed; }; // Player EVENT defines // Some EVENTs are single occurrance (S), while others are cummulative throughout the life of the player (C) #define PLAYER_EVENT_NEW_ADV_LEVEL 2000 // (C) player achieves a new adventure level #define PLAYER_EVENT_NEW_TS_LEVEL 2001 // (C) player achieves a new tradeskill level #define PLAYER_EVENT_NEW_AA 2002 // (C) player earns AA pt #define PLAYER_EVENT_NEW_ACHIEVEMENT 2003 // (C) player new achievement #define PLAYER_EVENT_LAST_DEATH 2004 // (S) player was last killed #define PLAYER_EVENT_LAST_KILL 2005 // (S) player last killed spawn_id #define PLAYER_EVENT_DISCOVER_POI 2006 // (C) player discovers location_id // These maybe should be World stat events, since it is about 1 player discovering a new item? #define PLAYER_EVENT_DISCOVER_ITEM 2007 // (C) player discovers item_id #define PLAYER_EVENT_DISCOVER_RECIPE 2008 // (C) player discovers recipe_id struct PlayerHistory { int32 history_zone; int32 history_id; sint32 history_value; int32 history_date; bool save_needed; }; struct GlobalLoot { int8 minLevel; int8 maxLevel; int32 table_id; int32 loot_tier; }; #define TRANSPORT_TYPE_LOCATION 0 #define TRANSPORT_TYPE_ZONE 1 #define TRANSPORT_TYPE_GENERIC 2 #define TRANSPORT_TYPE_FLIGHT 3 // structs MUST start with class_id and race_id, in that order as int8's struct StartingStructHeader { int8 class_id; int8 race_id; }; struct StartingSkill { StartingStructHeader header; int32 skill_id; int16 current_val; int16 max_val; int32 progress; // what is this for..? }; struct StartingSpell { StartingStructHeader header; int32 spell_id; int8 tier; int32 knowledge_slot; }; #define MAX_VOICEOVER_TYPE 2 struct VoiceOverStruct{ string mp3_string; string text_string; string emote_string; int32 key1; int32 key2; bool is_garbled; int8 garble_link_id; }; class ZoneList { public: ZoneList(); ~ZoneList(); void Add(ZoneServer* zone); void Remove(ZoneServer* zone); ZoneServer* Get(int32 id, bool loadZone = true, bool skip_existing_zones = false); ZoneServer* Get(const char* zone_name, bool loadZone=true, bool skip_existing_zones = false); ZoneServer* GetByInstanceID(int32 id, int32 zone_id=0, bool skip_existing_zones = false); /// Get the instance for the given zone id with the lowest population /// The id of the zone to look up /// ZoneServer* of an active zone with the given id ZoneServer* GetByLowestPopulation(int32 zone_id); void AddClientToMap(string name, Client* client){ name = ToLower(name); MClientList.lock(); client_map[name] = client; MClientList.unlock(); } void CheckFriendList(Client* client); void CheckFriendZoned(Client* client); // move to Chat/Chat.h? bool HandleGlobalChatMessage(Client* from, char* to, int16 channel, const char* message, const char* channel_name = 0, int32 current_language_id = 0); void HandleGlobalBroadcast(const char* message); void HandleGlobalAnnouncement(const char* message); // int32 Count(); Client* GetClientByCharName(string name){ name = ToLower(name); Client* ret = 0; MClientList.lock(); if(client_map.count(name) > 0) ret = client_map[name]; MClientList.unlock(); return ret; } Client* GetClientByCharID(int32 id) { Client* ret = 0; MClientList.lock(); map::iterator itr; for (itr = client_map.begin(); itr != client_map.end(); itr++) { if (itr->second->GetCharacterID() == id) { ret = itr->second; break; } } MClientList.unlock(); return ret; } Client* GetClientByEQStream(EQStream* eqs) { Client* ret = 0; if (eqs) { MClientList.lock(); map::iterator itr; for (itr = client_map.begin(); itr != client_map.end(); itr++) { if (itr->second->getConnection() == eqs) { ret = itr->second; break; } } MClientList.unlock(); } return ret; } void UpdateVitality(float amount); void RemoveClientFromMap(string name, Client* client){ name = ToLower(name); MClientList.lock(); if(client_map.count(name) > 0 && client_map[name] == client) client_map.erase(name); MClientList.unlock(); } bool ClientConnected(int32 account_id); void RemoveClientZoneReference(ZoneServer* zone); void ReloadClientQuests(); bool DepopFinished(); void Depop(); void Repop(); void DeleteSpellProcess(); void LoadSpellProcess(); void ProcessWhoQuery(const char* query, Client* client); void ProcessWhoQuery(vector* queries, ZoneServer* zone, vector* players, bool isGM); void SendZoneList(Client* client); void WritePlayerStatistics(); void ShutDownZones(); void ReloadMail(); void ReloadSpawns(); void WatchdogHeartbeat(); void SendTimeUpdate(); private: Mutex MClientList; Mutex MZoneList; map removed_zoneservers; map client_map; list zlist; }; class World { public: World(); ~World(); int8 GetClassID(const char* name); void Process(); void init(); PacketStruct* GetWorldTime(int16 version); void WorldTimeTick(); float GetXPRate(); float GetTSXPRate(); void LoadVitalityInformation(); void UpdateVitality(); WorldTime* GetWorldTimeStruct(){ return &world_time; } ulong GetCurrentThreadID(); int64 GetThreadUsageCPUTime(); // These 2 functions are never used. What was their purpose? Should they be removed? void AddNPCAppearance(int32 id, AppearanceData* appearance){ npc_appearance_list[id] = appearance; } AppearanceData* GetNPCAppearance(int32 id) { return npc_appearance_list[id]; } void ReloadGuilds(); bool ReportBug(string data, char* player_name, int32 account_id, const char* spawn_name, int32 spawn_id, int32 zone_id); void AddSpawnScript(int32 id, const char* name); void AddSpawnEntryScript(int32 id, const char* name); void AddSpawnLocationScript(int32 id, const char* name); void AddZoneScript(int32 id, const char* name); const char* GetSpawnScript(int32 id); const char* GetSpawnEntryScript(int32 id); const char* GetSpawnLocationScript(int32 id); const char* GetZoneScript(int32 id); void ResetSpawnScripts(); void ResetZoneScripts(); int16 GetMerchantItemQuantity(int32 merchant_id, int32 item_id); void DecreaseMerchantQuantity(int32 merchant_id, int32 item_id, int16 amount); int32 GetInventoryID(int32 merchant_id, int32 item_id); void AddMerchantItem(int32 inventory_id, MerchantItemInfo ItemInfo); void RemoveMerchantItem(int32 inventory_id, int32 item_id); vector* GetMerchantList(int32 merchant_id); vector* GetMerchantItemList(int32 merchant_id, int8 merchant_type, Player* player); MerchantInfo* GetMerchantInfo(int32 merchant_id); map* GetMerchantInfo(); void AddMerchantInfo(int32 merchant_id, MerchantInfo* multiplier); void DeleteMerchantsInfo(); void DeleteMerchantItems(); void DeleteSpawns(); vector* GetClientVariables(); void WritePlayerStatistics(); void WriteServerStatistics(); void AddServerStatistic(int32 stat_id, sint32 stat_value, int32 stat_date); void UpdateServerStatistic(int32 stat_id, sint32 stat_value, bool overwrite = false); sint32 GetServerStatisticValue(int32 stat_id); void RemoveServerStatistics(); //PlayerGroup* AddGroup(Client* leader); //void AddGroupMember(PlayerGroup* group, Client* member); //void RemoveGroupMember(Client* member, bool immediate = false); //void DisbandGroup(PlayerGroup* group, bool lock = true); void SendGroupQuests(PlayerGroup* group, Client* client); //void UpdateGroupBuffs(); //void RemoveGroupBuffs(PlayerGroup *group, Client *client); //void SetPendingGroup(char* name, char* leader); //void GroupMessage(PlayerGroup* group, const char* message, ...); //void SimpleGroupMessage(PlayerGroup* group, const char* message); //void GroupChatMessage(PlayerGroup* group, Spawn* from, const char* message); //const char* GetPendingGroup(string name); //void GroupReadLock(); //void GroupReadUnLock(); //void CheckRemoveGroupedPlayer(); //void SendGroupUpdate(PlayerGroup* group, Client* exclude = 0); bool RejoinGroup(Client* client, int32 group_id); //bool MakeLeader(Client* leader, string new_leader); void AddBonuses(Item* item, ItemStatsValues* values, int16 type, sint32 value, Entity* entity); void CreateGuild(const char* guild_name, Client* leader = 0, int32 group_id = 0); void SaveGuilds(); void PickRandomLottoDigits(int32* digits); void AddLottoPlayer(int32 character_id, int32 end_time); void RemoveLottoPlayer(int32 character_id); void SetLottoPlayerNumMatches(int32 character_id, int8 num_matches); void CheckLottoPlayers(); void PopulateTOVStatMap(); int32 LoadItemBlueStats(); sint16 GetItemStatAOMValue(sint16 subtype); sint16 GetItemStatTOVValue(sint16 subtype); sint16 GetItemStatDOVValue(sint16 subtype); sint16 GetItemStatCOEValue(sint16 subtype); sint16 GetItemStatKAValue(sint16 subtype); sint16 GetItemStatTESTValue(sint16 subtype); vector biography; volatile bool items_loaded; volatile bool spells_loaded; volatile bool achievments_loaded; void AddHouseZone(int32 id, string name, int64 cost_coins, int32 cost_status, int64 upkeep_coins, int32 upkeep_status, int8 vault_slots, int8 alignment, int8 guild_level, int32 zone_id, int32 exit_zone_id, float exit_x, float exit_y, float exit_z, float exit_heading); HouseZone* GetHouseZone(int32 id); void AddPlayerHouse(int32 char_id, int32 house_id, int64 unique_id, int32 instance_id, int32 upkeep_due, int64 escrow_coins, int32 escrow_status, string player_name); PlayerHouse* GetPlayerHouseByHouseID(int32 char_id, int32 house_id); PlayerHouse* GetPlayerHouseByUniqueID(int64 unique_id); PlayerHouse* GetPlayerHouseByInstanceID(int32 instance_id); vector GetAllPlayerHouses(int32 char_id); vector GetAllPlayerHousesByHouseID(int32 house_id); void ReloadHouseData(PlayerHouse* ph); PlayerGroupManager* GetGroupManager() { return &m_playerGroupManager; } bool CheckTempBugCRC(char* msg); void SyncCharacterAbilities(Client* client); void LoadStartingLists(); void PurgeStartingLists(); multimap*> starting_skills; multimap*> starting_spells; Mutex MStartingLists; void SetReloadingSubsystem(string subsystem); void RemoveReloadingSubSystem(string subsystem); bool IsReloadingSubsystems(); int32 GetSuppressedWarningTime() { return suppressed_warning; } void SetSuppressedWarning() { suppressed_warning = Timer::GetCurrentTime2(); } map GetOldestReloadingSubsystem(); void LoadRegionMaps(std::string zoneFile); RegionMap* GetRegionMap(std::string zoneFile, int32 client_version); void LoadMaps(std::string zoneFile); Map* GetMap(std::string zoneFile, int32 client_version); void SendTimeUpdate(); // just in case we roll over a time as to not send bad times to clients (days before hours, hours before minutes as examples) Mutex MWorldTime; void LoadVoiceOvers(); void PurgeVoiceOvers(); typedef std::multimap::iterator VOMapIterator; bool FindVoiceOver(int8 type, int32 id, int16 index, VoiceOverStruct* struct_ = nullptr, bool* find_garbled = nullptr, VoiceOverStruct* garble_struct_ = nullptr); void AddVoiceOver(int8 type, int32 id, int16 index, VoiceOverStruct* struct_); void CopyVoiceOver(VoiceOverStruct* struct1, VoiceOverStruct* struct2); /* NPC Spells */ void AddNPCSpell(int32 list_id, int32 spell_id, int8 tier, bool spawn_cast, bool aggro_cast); vector* GetNPCSpells(int32 primary_list, int32 secondary_list); void PurgeNPCSpells(); Mutex MVoiceOvers; static sint64 newValue; private: multimap*> voiceover_map[3]; int32 suppressed_warning = 0; map reloading_subsystems; //void RemovePlayerFromGroup(PlayerGroup* group, GroupMemberInfo* info, bool erase = true); //void DeleteGroupMember(GroupMemberInfo* info); Mutex MReloadingSubsystems; Mutex MMerchantList; Mutex MSpawnScripts; Mutex MZoneScripts; //Mutex MGroups; mutable std::shared_mutex MNPCSpells; map merchant_info; map > merchant_inventory_items; int32 vitality_frequency; float vitality_amount; float xp_rate; float ts_xp_rate; // JA WorldTime world_time; map npc_appearance_list; map spawn_scripts; map spawnentry_scripts; map spawnlocation_scripts; map zone_scripts; //vector player_groups; //map group_removal_pending; //map pending_groups; map server_statistics; MutexMap lotto_players; int32 last_checked_time; Timer save_time_timer; Timer time_tick_timer; Timer vitality_timer; Timer player_stats_timer; Timer server_stats_timer; //Timer remove_grouped_player; Timer guilds_timer; Timer lotto_players_timer; Timer group_buff_updates; Timer watchdog_timer; map m_houseZones; // Map > map > m_playerHouses; Mutex MHouseZones; Mutex MPlayerHouses; map tov_itemstat_conversion; map dov_itemstat_conversion; map coe_itemstat_conversion; map ka_itemstat_conversion; PlayerGroupManager m_playerGroupManager; Mutex MBugReport; map bug_report_crc; std::map region_maps; std::map maps; Mutex MWorldMaps; Mutex MWorldRegionMaps; map > npc_spell_list; }; #endif