123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617 |
- // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
- // For more information, see LICENCE in the main folder
- #include "battleground.hpp"
- #include <unordered_map>
- #include <common/cbasetypes.hpp>
- #include <common/malloc.hpp>
- #include <common/nullpo.hpp>
- #include <common/random.hpp>
- #include <common/showmsg.hpp>
- #include <common/strlib.hpp>
- #include <common/timer.hpp>
- #include <common/utilities.hpp>
- #include "battle.hpp"
- #include "clif.hpp"
- #include "guild.hpp"
- #include "homunculus.hpp"
- #include "mapreg.hpp"
- #include "mercenary.hpp"
- #include "mob.hpp"
- #include "npc.hpp"
- #include "party.hpp"
- #include "pc.hpp"
- #include "pet.hpp"
- using namespace rathena;
- BattlegroundDatabase battleground_db;
- std::unordered_map<int, std::shared_ptr<s_battleground_data>> bg_team_db;
- std::vector<std::shared_ptr<s_battleground_queue>> bg_queues;
- int bg_queue_count = 1;
- const std::string BattlegroundDatabase::getDefaultLocation() {
- return std::string(db_path) + "/battleground_db.yml";
- }
- /**
- * Reads and parses an entry from the battleground_db
- * @param node: The YAML node containing the entry
- * @return count of successfully parsed rows
- */
- uint64 BattlegroundDatabase::parseBodyNode(const ryml::NodeRef& node) {
- uint32 id;
- if (!this->asUInt32(node, "Id", id))
- return 0;
- std::shared_ptr<s_battleground_type> bg = this->find(id);
- bool exists = bg != nullptr;
- if (!exists) {
- if (!this->nodesExist(node, { "Name", "Locations" }))
- return 0;
- bg = std::make_shared<s_battleground_type>();
- bg->id = id;
- }
- if (this->nodeExists(node, "Name")) {
- std::string name;
- if (!this->asString(node, "Name", name))
- return 0;
- name.resize(NAME_LENGTH);
- bg->name = name;
- }
- if (this->nodeExists(node, "MinPlayers")) {
- int min;
- if (!this->asInt32(node, "MinPlayers", min))
- return 0;
- if (min < 1) {
- this->invalidWarning(node["MinPlayers"], "Minimum players %d cannot be less than 1, capping to 1.\n", min);
- min = 1;
- }
- if (min * 2 > MAX_BG_MEMBERS) {
- this->invalidWarning(node["MinPlayers"], "Minimum players %d exceeds MAX_BG_MEMBERS, capping to %d.\n", min, MAX_BG_MEMBERS / 2);
- min = MAX_BG_MEMBERS / 2;
- }
- bg->required_players = min;
- } else {
- if (!exists)
- bg->required_players = 1;
- }
- if (this->nodeExists(node, "MaxPlayers")) {
- int max;
- if (!this->asInt32(node, "MaxPlayers", max))
- return 0;
- if (max < 1) {
- this->invalidWarning(node["MaxPlayers"], "Maximum players %d cannot be less than 1, capping to 1.\n", max);
- max = 1;
- }
- if (max * 2 > MAX_BG_MEMBERS) {
- this->invalidWarning(node["MaxPlayers"], "Maximum players %d exceeds MAX_BG_MEMBERS, capping to %d.\n", max, MAX_BG_MEMBERS / 2);
- max = MAX_BG_MEMBERS / 2;
- }
- bg->max_players = max;
- } else {
- if (!exists)
- bg->max_players = MAX_BG_MEMBERS / 2;
- }
- if (this->nodeExists(node, "MinLevel")) {
- int min;
- if (!this->asInt32(node, "MinLevel", min))
- return 0;
- if (min > MAX_LEVEL) {
- this->invalidWarning(node["MinLevel"], "Minimum level %d exceeds MAX_LEVEL, capping to %d.\n", min, MAX_LEVEL);
- min = MAX_LEVEL;
- }
- bg->min_lvl = min;
- } else {
- if (!exists)
- bg->min_lvl = 1;
- }
- if (this->nodeExists(node, "MaxLevel")) {
- int max;
- if (!this->asInt32(node, "MaxLevel", max))
- return 0;
- if (max > MAX_LEVEL) {
- this->invalidWarning(node["MaxLevel"], "Maximum level %d exceeds MAX_LEVEL, capping to %d.\n", max, MAX_LEVEL);
- max = MAX_LEVEL;
- }
- bg->max_lvl = max;
- } else {
- if (!exists)
- bg->max_lvl = MAX_LEVEL;
- }
- if (this->nodeExists(node, "Deserter")) {
- uint32 deserter;
- if (!this->asUInt32(node, "Deserter", deserter))
- return 0;
- bg->deserter_time = deserter;
- } else {
- if (!exists)
- bg->deserter_time = 600;
- }
- if (this->nodeExists(node, "StartDelay")) {
- uint32 delay;
- if (!this->asUInt32(node, "StartDelay", delay))
- return 0;
- bg->start_delay = delay;
- } else {
- if (!exists)
- bg->start_delay = 0;
- }
- if (this->nodeExists(node, "Join")) {
- const auto& joinNode = node["Join"];
- if (this->nodeExists(joinNode, "Solo")) {
- bool active;
- if (!this->asBool(joinNode, "Solo", active))
- return 0;
- bg->solo = active;
- } else {
- if (!exists)
- bg->solo = true;
- }
- if (this->nodeExists(joinNode, "Party")) {
- bool active;
- if (!this->asBool(joinNode, "Party", active))
- return 0;
- bg->party = active;
- } else {
- if (!exists)
- bg->party = true;
- }
- if (this->nodeExists(joinNode, "Guild")) {
- bool active;
- if (!this->asBool(joinNode, "Guild", active))
- return 0;
- bg->guild = active;
- } else {
- if (!exists)
- bg->guild = true;
- }
- } else {
- if (!exists) {
- bg->solo = true;
- bg->party = true;
- bg->guild = true;
- }
- }
- if (this->nodeExists(node, "JobRestrictions")) {
- const auto& jobsNode = node["JobRestrictions"];
- for (const auto& jobit : jobsNode) {
- std::string job_name;
- c4::from_chars(jobit.key(), &job_name);
- std::string job_name_constant = "JOB_" + job_name;
- int64 constant;
- if (!script_get_constant(job_name_constant.c_str(), &constant)) {
- this->invalidWarning(node["JobRestrictions"], "Job %s does not exist.\n", job_name.c_str());
- continue;
- }
- bool active;
- if (!this->asBool(jobsNode, job_name, active))
- return 0;
- if (active)
- bg->job_restrictions.push_back(static_cast<int32>(constant));
- else
- util::vector_erase_if_exists(bg->job_restrictions, static_cast<int32>(constant));
- }
- }
- if (this->nodeExists(node, "Locations")) {
- int count = 0;
- for (const auto& location : node["Locations"]) {
- s_battleground_map map_entry;
- if (this->nodeExists(location, "Map")) {
- std::string map_name;
- if (!this->asString(location, "Map", map_name))
- return 0;
- map_entry.mapindex = mapindex_name2id(map_name.c_str());
- if (map_entry.mapindex == 0) {
- this->invalidWarning(location["Map"], "Invalid battleground map name %s, skipping.\n", map_name.c_str());
- return 0;
- }
- if( map_mapindex2mapid( map_entry.mapindex ) < 0 ){
- // Ignore silently, the map is on another mapserver
- return 0;
- }
- }
- if (this->nodeExists(location, "StartEvent")) {
- if (!this->asString(location, "StartEvent", map_entry.bgcallscript))
- return 0;
- if (map_entry.bgcallscript.length() > EVENT_NAME_LENGTH) {
- this->invalidWarning(location["StartEvent"], "StartEvent \"%s\" exceeds maximum of %d characters, capping...\n", map_entry.bgcallscript.c_str(), EVENT_NAME_LENGTH - 1);
- }
- map_entry.bgcallscript.resize(EVENT_NAME_LENGTH);
- if (map_entry.bgcallscript.find("::On") == std::string::npos) {
- this->invalidWarning(location["StartEvent"], "Battleground StartEvent label %s should begin with '::On', skipping.\n", map_entry.bgcallscript.c_str());
- return 0;
- }
- }
- std::vector<std::string> team_list = { "TeamA", "TeamB" };
- for (const auto &it : team_list) {
- c4::csubstr team_name = c4::to_csubstr(it);
- const ryml::NodeRef& team = location;
- if (this->nodeExists(team, it)) {
- s_battleground_team *team_ptr;
- if (it.find("TeamA") != std::string::npos)
- team_ptr = &map_entry.team1;
- else if (it.find("TeamB") != std::string::npos)
- team_ptr = &map_entry.team2;
- else {
- this->invalidWarning(team[team_name], "An invalid Team is defined.\n");
- return 0;
- }
- if (this->nodeExists(team[team_name], "RespawnX")) {
- uint16 warp_x;
- if (!this->asUInt16(team[team_name], "RespawnX", warp_x))
- return 0;
- if (warp_x == 0) {
- this->invalidWarning(node["RespawnX"], "RespawnX has to be greater than zero.\n");
- return 0;
- }
- map_data *md = map_getmapdata(map_mapindex2mapid(map_entry.mapindex));
- if (warp_x >= md->xs) {
- this->invalidWarning(node["RespawnX"], "RespawnX has to be smaller than %hu.\n", md->xs);
- return 0;
- }
- team_ptr->warp_x = warp_x;
- }
- if (this->nodeExists(team[team_name], "RespawnY")) {
- uint16 warp_y;
- if (!this->asUInt16(team[team_name], "RespawnY", warp_y))
- return 0;
- if (warp_y == 0) {
- this->invalidWarning(node["RespawnY"], "RespawnY has to be greater than zero.\n");
- return 0;
- }
- map_data *md = map_getmapdata(map_mapindex2mapid(map_entry.mapindex));
- if (warp_y >= md->ys) {
- this->invalidWarning(node["RespawnY"], "RespawnY has to be smaller than %hu.\n", md->ys);
- return 0;
- }
- team_ptr->warp_y = warp_y;
- }
- if (this->nodeExists(team[team_name], "DeathEvent")) {
- if (!this->asString(team[team_name], "DeathEvent", team_ptr->death_event))
- return 0;
- team_ptr->death_event.resize(EVENT_NAME_LENGTH);
- if (team_ptr->death_event.find("::On") == std::string::npos) {
- this->invalidWarning(team["DeathEvent"], "Battleground DeathEvent label %s should begin with '::On', skipping.\n", team_ptr->death_event.c_str());
- return 0;
- }
- }
- if (this->nodeExists(team[team_name], "QuitEvent")) {
- if (!this->asString(team[team_name], "QuitEvent", team_ptr->quit_event))
- return 0;
- team_ptr->quit_event.resize(EVENT_NAME_LENGTH);
- if (team_ptr->quit_event.find("::On") == std::string::npos) {
- this->invalidWarning(team["QuitEvent"], "Battleground QuitEvent label %s should begin with '::On', skipping.\n", team_ptr->quit_event.c_str());
- return 0;
- }
- }
- if (this->nodeExists(team[team_name], "ActiveEvent")) {
- if (!this->asString(team[team_name], "ActiveEvent", team_ptr->active_event))
- return 0;
- team_ptr->active_event.resize(EVENT_NAME_LENGTH);
- if (team_ptr->active_event.find("::On") == std::string::npos) {
- this->invalidWarning(team["ActiveEvent"], "Battleground ActiveEvent label %s should begin with '::On', skipping.\n", team_ptr->active_event.c_str());
- return 0;
- }
- }
- if (this->nodeExists(team[team_name], "Variable")) {
- if (!this->asString(team[team_name], "Variable", team_ptr->bg_id_var))
- return 0;
- team_ptr->bg_id_var.resize(NAME_LENGTH);
- }
- map_entry.id = count++;
- map_entry.isReserved = false;
- }
- }
- bg->maps.push_back(map_entry);
- }
- }
- if (!exists)
- this->put(id, bg);
- return 1;
- }
- /**
- * Search for a battleground based on the given name
- * @param name: Battleground name
- * @return s_battleground_type on success or nullptr on failure
- */
- std::shared_ptr<s_battleground_type> bg_search_name(const char *name)
- {
- for (const auto &entry : battleground_db) {
- auto bg = entry.second;
- if (!stricmp(bg->name.c_str(), name))
- return bg;
- }
- return nullptr;
- }
- /**
- * Search for a Battleground queue based on the given queue ID
- * @param queue_id: Queue ID
- * @return s_battleground_queue on success or nullptr on failure
- */
- std::shared_ptr<s_battleground_queue> bg_search_queue(int queue_id)
- {
- for (const auto &queue : bg_queues) {
- if (queue_id == queue->queue_id)
- return queue;
- }
- return nullptr;
- }
- /**
- * Search for an available player in Battleground
- * @param bg: Battleground data
- * @return map_session_data
- */
- map_session_data* bg_getavailablesd(s_battleground_data *bg)
- {
- nullpo_retr(nullptr, bg);
- for (const auto &member : bg->members) {
- if (member.sd != nullptr)
- return member.sd;
- }
- return nullptr;
- }
- /**
- * Delete a Battleground team from the db
- * @param bg_id: Battleground ID
- * @return True on success or false otherwise
- */
- bool bg_team_delete(int bg_id)
- {
- std::shared_ptr<s_battleground_data> bgteam = util::umap_find(bg_team_db, bg_id);
- if (bgteam) {
- for (const auto &pl_sd : bgteam->members) {
- bg_send_dot_remove(pl_sd.sd);
- pl_sd.sd->bg_id = 0;
- }
- bg_team_db.erase(bg_id);
- return true;
- }
-
- return false;
- }
- /**
- * Warps a Battleground team
- * @param bg_id: Battleground ID
- * @param mapindex: Map Index
- * @param x: X coordinate
- * @param y: Y coordinate
- * @return True on success or false otherwise
- */
- bool bg_team_warp(int bg_id, unsigned short mapindex, short x, short y)
- {
- std::shared_ptr<s_battleground_data> bgteam = util::umap_find(bg_team_db, bg_id);
- if (bgteam) {
- for (const auto &pl_sd : bgteam->members)
- pc_setpos(pl_sd.sd, mapindex, x, y, CLR_TELEPORT);
- return true;
- }
- return false;
- }
- /**
- * Remove a player's Battleground map marker
- * @param sd: Player data
- */
- void bg_send_dot_remove(map_session_data *sd)
- {
- nullpo_retv(sd);
- if( sd && sd->bg_id )
- clif_bg_xy_remove(sd);
- return;
- }
- /**
- * Join a player to a Battleground team
- * @param bg_id: Battleground ID
- * @param sd: Player data
- * @param is_queue: Joined from queue
- * @return True on success or false otherwise
- */
- bool bg_team_join(int bg_id, map_session_data *sd, bool is_queue)
- {
- if (!sd || sd->bg_id)
- return false;
- std::shared_ptr<s_battleground_data> bgteam = util::umap_find(bg_team_db, bg_id);
- if (bgteam) {
- if (bgteam->members.size() == MAX_BG_MEMBERS)
- return false; // No free slots
- s_battleground_member_data member = {};
- sd->bg_id = bg_id;
- member.sd = sd;
- member.x = sd->bl.x;
- member.y = sd->bl.y;
- if (is_queue) { // Save the location from where the person entered the battleground
- member.entry_point.map = sd->mapindex;
- member.entry_point.x = sd->bl.x;
- member.entry_point.y = sd->bl.y;
- }
- bgteam->members.push_back(member);
- guild_send_dot_remove(sd);
- for (const auto &pl_sd : bgteam->members) {
- if (pl_sd.sd != sd)
- clif_hpmeter_single( *sd, pl_sd.sd->bl.id, pl_sd.sd->battle_status.hp, pl_sd.sd->battle_status.max_hp );
- }
- clif_bg_hp(sd);
- clif_bg_xy(sd);
- return true;
- }
- return false;
- }
- /**
- * Remove a player from Battleground team
- * @param sd: Player data
- * @param quit: True if closed client or false otherwise
- * @param deserter: Whether to apply the deserter status or not
- * @return Remaining count in Battleground team or -1 on failure
- */
- int bg_team_leave(map_session_data *sd, bool quit, bool deserter)
- {
- if (!sd || !sd->bg_id)
- return -1;
- bg_send_dot_remove(sd);
- int bg_id = sd->bg_id;
- std::shared_ptr<s_battleground_data> bgteam = util::umap_find(bg_team_db, bg_id);
- sd->bg_id = 0;
- if (bgteam) {
- // Warping members out only applies to the Battleground Queue System
- if (battle_config.feature_bgqueue) {
- auto member = bgteam->members.begin();
- while (member != bgteam->members.end()) {
- if (member->sd == sd) {
- if (member->entry_point.map != 0 && !map_getmapflag(map_mapindex2mapid(member->entry_point.map), MF_NOSAVE))
- pc_setpos(sd, member->entry_point.map, member->entry_point.x, member->entry_point.y, CLR_TELEPORT);
- else
- pc_setpos( sd, mapindex_name2id( sd->status.save_point.map ), sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT ); // Warp to save point if the entry map has no save flag.
- bgteam->members.erase(member);
- break;
- } else
- member++;
- }
- }
- char output[CHAT_SIZE_MAX];
- if (quit)
- sprintf(output, "Server: %s has quit the game...", sd->status.name);
- else
- sprintf(output, "Server: %s is leaving the battlefield...", sd->status.name);
- clif_bg_message(bgteam.get(), 0, "Server", output, strlen(output) + 1);
- if (!bgteam->logout_event.empty() && quit)
- npc_event(sd, bgteam->logout_event.c_str(), 0);
- if (deserter) {
- std::shared_ptr<s_battleground_type> bg = battleground_db.find(bg_id);
- if (bg)
- sc_start(nullptr, &sd->bl, SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT, 100, 1, static_cast<t_tick>(bg->deserter_time) * 1000); // Deserter timer
- }
- return bgteam->members.size();
- }
- return -1;
- }
- /**
- * Respawn a Battleground player
- * @param sd: Player data
- * @return True on success or false otherwise
- */
- bool bg_member_respawn(map_session_data *sd)
- {
- if (!sd || !sd->bg_id || !pc_isdead(sd))
- return false;
- std::shared_ptr<s_battleground_data> bgteam = util::umap_find(bg_team_db, sd->bg_id);
- if (bgteam) {
- if (bgteam->cemetery.map == 0)
- return false; // Respawn not handled by Core
- pc_setpos(sd, bgteam->cemetery.map, bgteam->cemetery.x, bgteam->cemetery.y, CLR_OUTSIGHT);
- status_revive(&sd->bl, 1, 100);
- return true; // Warped
- }
- return false;
- }
- /**
- * Initialize Battleground data
- * @param mapindex: Map Index
- * @param rx: Return X coordinate (on death)
- * @param ry: Return Y coordinate (on death)
- * @param ev: Logout NPC Event
- * @param dev: Death NPC Event
- * @return Battleground ID
- */
- int bg_create(uint16 mapindex, s_battleground_team* team)
- {
- int bg_team_counter = 1;
- while (bg_team_db.find(bg_team_counter) != bg_team_db.end())
- bg_team_counter++;
- bg_team_db[bg_team_counter] = std::make_shared<s_battleground_data>();
- std::shared_ptr<s_battleground_data> bg = util::umap_find(bg_team_db, bg_team_counter);
- bg->id = bg_team_counter;
- bg->cemetery.map = mapindex;
- bg->cemetery.x = team->warp_x;
- bg->cemetery.y = team->warp_y;
- bg->logout_event = team->quit_event.c_str();
- bg->die_event = team->death_event.c_str();
- bg->active_event = team->active_event.c_str();
- return bg->id;
- }
- /**
- * Get an object's Battleground ID
- * @param bl: Object
- * @return Battleground ID
- */
- int bg_team_get_id(struct block_list *bl)
- {
- nullpo_ret(bl);
- switch( bl->type ) {
- case BL_PC:
- return ((TBL_PC*)bl)->bg_id;
- case BL_PET:
- if( ((TBL_PET*)bl)->master )
- return ((TBL_PET*)bl)->master->bg_id;
- break;
- case BL_MOB: {
- map_session_data *msd;
- struct mob_data *md = (TBL_MOB*)bl;
- if( md->special_state.ai && (msd = map_id2sd(md->master_id)) != nullptr )
- return msd->bg_id;
- return md->bg_id;
- }
- case BL_HOM:
- if( ((TBL_HOM*)bl)->master )
- return ((TBL_HOM*)bl)->master->bg_id;
- break;
- case BL_MER:
- if( ((TBL_MER*)bl)->master )
- return ((TBL_MER*)bl)->master->bg_id;
- break;
- case BL_SKILL:
- return ((TBL_SKILL*)bl)->group->bg_id;
- }
- return 0;
- }
- /**
- * Send a Battleground chat message
- * @param sd: Player data
- * @param mes: Message
- * @param len: Message length
- */
- void bg_send_message(map_session_data *sd, const char *mes, size_t len)
- {
- nullpo_retv(sd);
- if (sd->bg_id == 0)
- return;
-
- std::shared_ptr<s_battleground_data> bgteam = util::umap_find(bg_team_db, sd->bg_id);
- if (bgteam)
- clif_bg_message(bgteam.get(), sd->bl.id, sd->status.name, mes, len);
- return;
- }
- /**
- * Update a player's Battleground minimap icon
- * @see DBApply
- */
- int bg_send_xy_timer_sub(std::shared_ptr<s_battleground_data> bg)
- {
- map_session_data *sd;
- for (auto &pl_sd : bg->members) {
- sd = pl_sd.sd;
- if (sd->bl.x != pl_sd.x || sd->bl.y != pl_sd.y) { // xy update
- pl_sd.x = sd->bl.x;
- pl_sd.y = sd->bl.y;
- clif_bg_xy(sd);
- }
- }
- return 0;
- }
- /**
- * Update a player's Battleground minimap icon
- * @param tid: Timer ID
- * @param tick: Timer
- * @param id: ID
- * @return 0 on success or 1 otherwise
- */
- TIMER_FUNC(bg_send_xy_timer)
- {
- for (const auto &entry : bg_team_db)
- bg_send_xy_timer_sub(entry.second);
- return 0;
- }
- /**
- * Mark a Battleground as ready to begin queuing for a free map
- * @param tid: Timer ID
- * @param tick: Timer
- * @param id: ID
- * @return 0 on success or 1 otherwise
- */
- static TIMER_FUNC(bg_on_ready_loopback)
- {
- int queue_id = (int)data;
- std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
- if (queue == nullptr) {
- ShowError("bg_on_ready_loopback: Invalid battleground queue %d.\n", queue_id);
- return 1;
- }
- std::shared_ptr<s_battleground_type> bg = battleground_db.find(queue->id);
- if (bg) {
- bg_queue_on_ready(bg->name.c_str(), queue);
- return 0;
- } else {
- ShowError("bg_on_ready_loopback: Can't find battleground %d in the battlegrounds database.\n", queue->id);
- return 1;
- }
- }
- /**
- * Reset Battleground queue data if players don't accept in time
- * @param tid: Timer ID
- * @param tick: Timer
- * @param id: ID
- * @return 0 on success or 1 otherwise
- */
- static TIMER_FUNC(bg_on_ready_expire)
- {
- int queue_id = (int)data;
- std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
- if (queue == nullptr) {
- ShowError("bg_on_ready_expire: Invalid battleground queue %d.\n", queue_id);
- return 1;
- }
- std::string bg_name = battleground_db.find(queue->id)->name;
- for (const auto &sd : queue->teama_members) {
- clif_bg_queue_apply_result(BG_APPLY_QUEUE_FINISHED, bg_name.c_str(), sd);
- clif_bg_queue_entry_init(sd);
- }
- for (const auto &sd : queue->teamb_members) {
- clif_bg_queue_apply_result(BG_APPLY_QUEUE_FINISHED, bg_name.c_str(), sd);
- clif_bg_queue_entry_init(sd);
- }
- bg_queue_clear(queue, true);
- return 0;
- }
- /**
- * Start a Battleground when all players have accepted
- * @param tid: Timer ID
- * @param tick: Timer
- * @param id: ID
- * @return 0 on success or 1 otherwise
- */
- static TIMER_FUNC(bg_on_ready_start)
- {
- int queue_id = (int)data;
- std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
- if (queue == nullptr) {
- ShowError("bg_on_ready_start: Invalid battleground queue %d.\n", queue_id);
- return 1;
- }
- queue->tid_start = INVALID_TIMER;
- bg_queue_start_battleground(queue);
- return 0;
- }
- /**
- * Check if the given player is in a battleground
- * @param sd: Player data
- * @return True if in a battleground or false otherwise
- */
- bool bg_player_is_in_bg_map(map_session_data *sd)
- {
- nullpo_retr(false, sd);
- for (const auto &pair : battleground_db) {
- for (const auto &it : pair.second->maps) {
- if (it.mapindex == sd->mapindex)
- return true;
- }
- }
- return false;
- }
- /**
- * Battleground status change check
- * @param sd: Player data
- * @param name: Battleground name
- * @return True if the player is good to join a queue or false otherwise
- */
- static bool bg_queue_check_status(map_session_data* sd, const char *name)
- {
- nullpo_retr(false, sd);
- if (sd->sc.count) {
- if (sd->sc.getSCE(SC_ENTRY_QUEUE_APPLY_DELAY)) { // Exclude any player who's recently left a battleground queue
- char buf[CHAT_SIZE_MAX];
- sprintf(buf, msg_txt(sd, 339), static_cast<int32>((get_timer(sd->sc.getSCE(SC_ENTRY_QUEUE_APPLY_DELAY)->timer)->tick - gettick()) / 1000)); // You can't apply to a battleground queue for %d seconds due to recently leaving one.
- clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], buf, false, SELF);
- return false;
- }
- if (sd->sc.getSCE(SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT)) { // Exclude any player who's recently deserted a battleground
- char buf[CHAT_SIZE_MAX];
- int32 status_tick = static_cast<int32>(DIFF_TICK(get_timer(sd->sc.getSCE(SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT)->timer)->tick, gettick()) / 1000);
- sprintf(buf, msg_txt(sd, 338), status_tick / 60, status_tick % 60); // You can't apply to a battleground queue due to recently deserting a battleground. Time remaining: %d minutes and %d seconds.
- clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], buf, false, SELF);
- return false;
- }
- }
- return true;
- }
- /**
- * Check to see if a Battleground is joinable
- * @param bg: Battleground data
- * @param sd: Player data
- * @param name: Battleground name
- * @return True on success or false otherwise
- */
- bool bg_queue_check_joinable(std::shared_ptr<s_battleground_type> bg, map_session_data *sd, const char *name)
- {
- nullpo_retr(false, sd);
- for (const auto &job : bg->job_restrictions) { // Check class requirement
- if (sd->status.class_ == job) {
- clif_bg_queue_apply_result(BG_APPLY_PLAYER_CLASS, name, sd);
- return false;
- }
- }
- if (bg->min_lvl > 0 && sd->status.base_level < bg->min_lvl) { // Check minimum level requirement
- clif_bg_queue_apply_result(BG_APPLY_PLAYER_LEVEL, name, sd);
- return false;
- }
- if (bg->max_lvl > 0 && sd->status.base_level > bg->max_lvl) { // Check maximum level requirement
- clif_bg_queue_apply_result(BG_APPLY_PLAYER_LEVEL, name, sd);
- return false;
- }
- if (!bg_queue_check_status(sd, name)) // Check status blocks
- return false;
- if (bg_player_is_in_bg_map(sd)) { // Is the player currently in a battleground map? Reject them.
- clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
- return false;
- }
- if (battle_config.bgqueue_nowarp_mapflag > 0 && map_getmapflag(sd->bl.m, MF_NOWARP)) { // Check player's current position for mapflag check
- clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
- return false;
- }
- return true;
- }
- /**
- * Mark a map as reserved for a Battleground
- * @param name: Battleground map name
- * @param state: Whether to mark reserved or not
- * @param ended: Whether the Battleground event is complete; players getting prize
- * @return True on success or false otherwise
- */
- bool bg_queue_reservation(const char *name, bool state, bool ended)
- {
- uint16 mapindex = mapindex_name2id(name);
- for (auto &pair : battleground_db) {
- for (auto &map : pair.second->maps) {
- if (map.mapindex == mapindex) {
- map.isReserved = state;
- for (auto &queue : bg_queues) {
- if (queue->map == &map) {
- if (ended) // The ended flag is applied from bg_reserve (bg_unbook clears it for the next queue)
- queue->state = QUEUE_STATE_ENDED;
- if (!state)
- bg_queue_clear(queue, true);
- }
- }
- return true;
- }
- }
- }
- return false;
- }
- /**
- * Join as an individual into a Battleground
- * @param name: Battleground name
- * @param sd: Player who requested to join the battlegrounds
- */
- void bg_queue_join_solo(const char *name, map_session_data *sd)
- {
- if (!sd) {
- ShowError("bg_queue_join_solo: Tried to join non-existent player\n.");
- return;
- }
- std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
- if (!bg) {
- ShowWarning("bq_queue_join_solo: Could not find battleground \"%s\" requested by %s (AID: %d / CID: %d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
- return;
- }
- if (!bg->solo) {
- clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
- return;
- }
- bg_queue_join_multi(name, sd, { sd }); // Join as solo
- }
- /**
- * Join a party onto the same side of a Battleground
- * @param name: Battleground name
- * @param sd: Player who requested to join the battlegrounds
- */
- void bg_queue_join_party(const char *name, map_session_data *sd)
- {
- if (!sd) {
- ShowError("bg_queue_join_party: Tried to join non-existent player\n.");
- return;
- }
- struct party_data *p = party_search(sd->status.party_id);
- if (!p) {
- clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
- return; // Someone has bypassed the client check for being in a party
- }
- for (const auto &it : p->party.member) {
- if (it.leader && sd->status.char_id != it.char_id) {
- clif_bg_queue_apply_result(BG_APPLY_PARTYGUILD_LEADER, name, sd);
- return; // Not the party leader
- }
- }
- std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
- if (bg) {
- if (!bg->party) {
- clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
- return;
- }
- int p_online = 0;
- for (const auto &it : p->party.member) {
- if (it.online)
- p_online++;
- }
- if (p_online > bg->max_players) {
- clif_bg_queue_apply_result(BG_APPLY_PLAYER_COUNT, name, sd);
- return; // Too many party members online
- }
- std::vector<map_session_data *> list;
- for (const auto &it : p->party.member) {
- if (list.size() == bg->max_players)
- break;
- if (it.online) {
- map_session_data *pl_sd = map_charid2sd(it.char_id);
- if (pl_sd)
- list.push_back(pl_sd);
- }
- }
- bg_queue_join_multi(name, sd, list); // Join as party, all on the same side of the BG
- } else {
- ShowWarning("clif_parse_bg_queue_apply_request: Could not find Battleground: \"%s\" requested by player: %s (AID:%d CID:%d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
- clif_bg_queue_apply_result(BG_APPLY_INVALID_NAME, name, sd);
- return; // Invalid BG name
- }
- }
- /**
- * Join a guild onto the same side of a Battleground
- * @param name: Battleground name
- * @param sd: Player who requested to join the battlegrounds
- */
- void bg_queue_join_guild(const char *name, map_session_data *sd)
- {
- if (!sd) {
- ShowError("bg_queue_join_guild: Tried to join non-existent player\n.");
- return;
- }
- if (!sd->guild) {
- clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
- return; // Someone has bypassed the client check for being in a guild
- }
-
- if (strcmp(sd->status.name, sd->guild->guild.master) != 0) {
- clif_bg_queue_apply_result(BG_APPLY_PARTYGUILD_LEADER, name, sd);
- return; // Not the guild leader
- }
- std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
- if (bg) {
- if (!bg->guild) {
- clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
- return;
- }
- auto &g = sd->guild;
- if (g->guild.connect_member > bg->max_players) {
- clif_bg_queue_apply_result(BG_APPLY_PLAYER_COUNT, name, sd);
- return; // Too many guild members online
- }
- std::vector<map_session_data *> list;
- for (const auto &it : g->guild.member) {
- if (list.size() == bg->max_players)
- break;
- if (it.online) {
- map_session_data *pl_sd = map_charid2sd(it.char_id);
- if (pl_sd)
- list.push_back(pl_sd);
- }
- }
- bg_queue_join_multi(name, sd, list); // Join as guild, all on the same side of the BG
- } else {
- ShowWarning("clif_parse_bg_queue_apply_request: Could not find Battleground: \"%s\" requested by player: %s (AID:%d CID:%d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
- clif_bg_queue_apply_result(BG_APPLY_INVALID_NAME, name, sd);
- return; // Invalid BG name
- }
- }
- /**
- * Join multiple players onto the same side of a Battleground
- * @param name: Battleground name
- * @param sd: Player who requested to join the battlegrounds
- * @param list: Contains all players including the player who requested to join
- */
- void bg_queue_join_multi(const char *name, map_session_data *sd, std::vector <map_session_data *> list)
- {
- if (!sd) {
- ShowError("bg_queue_join_multi: Tried to join non-existent player\n.");
- return;
- }
- std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
- if (!bg) {
- ShowWarning("bq_queue_join_multi: Could not find battleground \"%s\" requested by %s (AID: %d / CID: %d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
- return;
- }
- if (!bg_queue_check_joinable(bg, sd, name)){
- return;
- }
- for (const auto &queue : bg_queues) {
- if (queue->id != bg->id || queue->state == QUEUE_STATE_SETUP_DELAY || queue->state == QUEUE_STATE_ENDED)
- continue;
- // Make sure there's enough space on one side to join as a party/guild in this queue
- if (queue->teama_members.size() + list.size() > bg->max_players && queue->teamb_members.size() + list.size() > bg->max_players) {
- break;
- }
- bool r = rnd_chance(50, 100);
- std::vector<map_session_data *> *team = r ? &queue->teamb_members : &queue->teama_members;
- if (queue->state == QUEUE_STATE_ACTIVE) {
- // If one team has lesser members try to balance (on an active BG)
- if (r && queue->teama_members.size() < queue->teamb_members.size())
- team = &queue->teama_members;
- else if (!r && queue->teamb_members.size() < queue->teama_members.size())
- team = &queue->teamb_members;
- } else {
- // If the designated team is full, put the player into the other team
- if (team->size() + list.size() > bg->required_players)
- team = r ? &queue->teama_members : &queue->teamb_members;
- }
- while (!list.empty() && team->size() < bg->max_players) {
- map_session_data *sd2 = list.back();
- list.pop_back();
- if (!sd2 || sd2->bg_queue_id > 0)
- continue;
- if (!bg_queue_check_joinable(bg, sd2, name))
- continue;
- sd2->bg_queue_id = queue->queue_id;
- team->push_back(sd2);
- clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
- clif_bg_queue_apply_notify(name, sd2);
- }
- if (queue->state == QUEUE_STATE_ACTIVE) { // Battleground is already active
- for (auto &pl_sd : *team) {
- if (queue->map->mapindex == pl_sd->mapindex)
- continue;
- pc_set_bg_queue_timer(pl_sd);
- clif_bg_queue_lobby_notify(name, pl_sd);
- }
- } else if (queue->state == QUEUE_STATE_SETUP && queue->teamb_members.size() >= bg->required_players && queue->teama_members.size() >= bg->required_players) // Enough players have joined
- bg_queue_on_ready(name, queue);
- return;
- }
- // Something went wrong, sends reconnect and then reapply message to client.
- clif_bg_queue_apply_result(BG_APPLY_RECONNECT, name, sd);
- }
- /**
- * Clear Battleground queue for next one
- * @param queue: Queue to clean up
- * @param ended: If a Battleground has ended through normal means (by script command bg_unbook)
- */
- void bg_queue_clear(std::shared_ptr<s_battleground_queue> queue, bool ended)
- {
- if (queue == nullptr)
- return;
- if (queue->tid_requeue != INVALID_TIMER) {
- delete_timer(queue->tid_requeue, bg_on_ready_loopback);
- queue->tid_requeue = INVALID_TIMER;
- }
- if (queue->tid_expire != INVALID_TIMER) {
- delete_timer(queue->tid_expire, bg_on_ready_expire);
- queue->tid_expire = INVALID_TIMER;
- }
- if (queue->tid_start != INVALID_TIMER) {
- delete_timer(queue->tid_start, bg_on_ready_start);
- queue->tid_start = INVALID_TIMER;
- }
- if (ended) {
- if (queue->map != nullptr) {
- queue->map->isReserved = false; // Remove reservation to free up for future queue
- queue->map = nullptr;
- }
- for (const auto &sd : queue->teama_members)
- sd->bg_queue_id = 0;
- for (const auto &sd : queue->teamb_members)
- sd->bg_queue_id = 0;
- queue->teama_members.clear();
- queue->teamb_members.clear();
- queue->teama_members.shrink_to_fit();
- queue->teamb_members.shrink_to_fit();
- queue->accepted_players = 0;
- queue->state = QUEUE_STATE_SETUP;
- }
- }
- /**
- * Sub function for leaving a Battleground queue
- * @param sd: Player leaving
- * @param members: List of players in queue data
- * @param apply_sc: Apply the SC_ENTRY_QUEUE_APPLY_DELAY status on queue leave (default: true)
- * @return True on success or false otherwise
- */
- static bool bg_queue_leave_sub(map_session_data *sd, std::vector<map_session_data *> &members, bool apply_sc)
- {
- if (!sd)
- return false;
- auto list_it = members.begin();
- while (list_it != members.end()) {
- if (*list_it == sd) {
- members.erase(list_it);
- if (apply_sc)
- sc_start(nullptr, &sd->bl, SC_ENTRY_QUEUE_APPLY_DELAY, 100, 1, 60000);
- sd->bg_queue_id = 0;
- pc_delete_bg_queue_timer(sd);
- return true;
- } else {
- list_it++;
- }
- }
- return false;
- }
- /**
- * Leave a Battleground queue
- * @param sd: Player data
- * @param apply_sc: Apply the SC_ENTRY_QUEUE_APPLY_DELAY status on queue leave (default: true)
- * @return True on success or false otherwise
- */
- bool bg_queue_leave(map_session_data *sd, bool apply_sc)
- {
- if (!sd || sd->bg_queue_id == 0)
- return false;
- pc_delete_bg_queue_timer(sd);
- for (auto &queue : bg_queues) {
- if (sd->bg_queue_id == queue->queue_id) {
- if (!bg_queue_leave_sub(sd, queue->teama_members, apply_sc) && !bg_queue_leave_sub(sd, queue->teamb_members, apply_sc)) {
- ShowError("bg_queue_leave: Couldn't find player %s in battlegrounds queue.\n", sd->status.name);
- return false;
- } else {
- if ((queue->state == QUEUE_STATE_SETUP || queue->state == QUEUE_STATE_SETUP_DELAY) && queue->teama_members.empty() && queue->teamb_members.empty()) // If there are no players left in the queue (that hasn't started), discard it
- bg_queue_clear(queue, true);
- return true;
- }
- }
- }
- return false;
- }
- /**
- * Send packets to all clients in queue to notify them that the battleground is ready to be joined
- * @param name: Battleground name
- * @param queue: Battleground queue
- * @return True on success or false otherwise
- */
- bool bg_queue_on_ready(const char *name, std::shared_ptr<s_battleground_queue> queue)
- {
- std::shared_ptr<s_battleground_type> bg = battleground_db.find(queue->id);
- if (!bg) {
- ShowError("bg_queue_on_ready: Couldn't find battleground ID %d in battlegrounds database.\n", queue->id);
- return false;
- }
- if (queue->teama_members.size() < queue->required_players || queue->teamb_members.size() < queue->required_players)
- return false; // Return players to the queue and stop reapplying the timer
- bool map_reserved = false;
- for (auto &map : bg->maps) {
- if (!map.isReserved) {
- map.isReserved = true;
- map_reserved = true;
- queue->map = ↦
- break;
- }
- }
- if (!map_reserved) { // All the battleground maps are reserved. Set a timer to check for an open battleground every 10 seconds.
- queue->tid_requeue = add_timer(gettick() + 10000, bg_on_ready_loopback, 0, (intptr_t)queue->queue_id);
- return false;
- }
- queue->state = QUEUE_STATE_SETUP_DELAY;
- queue->tid_expire = add_timer(gettick() + 20000, bg_on_ready_expire, 0, (intptr_t)queue->queue_id);
- for (const auto &sd : queue->teama_members)
- clif_bg_queue_lobby_notify(name, sd);
- for (const auto &sd : queue->teamb_members)
- clif_bg_queue_lobby_notify(name, sd);
- return true;
- }
- /**
- * Send a player into an active Battleground
- * @param sd: Player to send in
- * @param queue: Queue data
- */
- void bg_join_active(map_session_data *sd, std::shared_ptr<s_battleground_queue> queue)
- {
- if (sd == nullptr || queue == nullptr)
- return;
- // Check player's current position for mapflag check
- if (battle_config.bgqueue_nowarp_mapflag > 0 && map_getmapflag(sd->bl.m, MF_NOWARP)) {
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
- bg_queue_leave(sd);
- clif_bg_queue_entry_init(sd);
- return;
- }
- pc_delete_bg_queue_timer(sd); // Cancel timer so player doesn't leave the queue.
- int bg_id_team_1 = static_cast<int>(mapreg_readreg(add_str(queue->map->team1.bg_id_var.c_str())));
- std::shared_ptr<s_battleground_data> bgteam_1 = util::umap_find(bg_team_db, bg_id_team_1);
- for (auto &pl_sd : queue->teama_members) {
- if (sd != pl_sd)
- continue;
- if (bgteam_1 == nullptr) {
- bg_queue_leave(sd);
- clif_bg_queue_apply_result(BG_APPLY_RECONNECT, battleground_db.find(queue->id)->name.c_str(), sd);
- clif_bg_queue_entry_init(sd);
- return;
- }
- clif_bg_queue_entry_init(pl_sd);
- bg_team_join(bg_id_team_1, pl_sd, true);
- npc_event(pl_sd, bgteam_1->active_event.c_str(), 0);
- return;
- }
- int bg_id_team_2 = static_cast<int>(mapreg_readreg(add_str(queue->map->team2.bg_id_var.c_str())));
- std::shared_ptr<s_battleground_data> bgteam_2 = util::umap_find(bg_team_db, bg_id_team_2);
- for (auto &pl_sd : queue->teamb_members) {
- if (sd != pl_sd)
- continue;
- if (bgteam_2 == nullptr) {
- bg_queue_leave(sd);
- clif_bg_queue_apply_result(BG_APPLY_RECONNECT, battleground_db.find(queue->id)->name.c_str(), sd);
- clif_bg_queue_entry_init(sd);
- return;
- }
- clif_bg_queue_entry_init(pl_sd);
- bg_team_join(bg_id_team_2, pl_sd, true);
- npc_event(pl_sd, bgteam_2->active_event.c_str(), 0);
- return;
- }
- return;
- }
- /**
- * Check to see if any players in the queue are on a map with MF_NOWARP and remove them from the queue
- * @param queue: Queue data
- * @return True if the player is on a map with MF_NOWARP or false otherwise
- */
- bool bg_mapflag_check(std::shared_ptr<s_battleground_queue> queue) {
- if (queue == nullptr || battle_config.bgqueue_nowarp_mapflag == 0)
- return false;
- bool found = false;
- for (const auto &sd : queue->teama_members) {
- if (map_getmapflag(sd->bl.m, MF_NOWARP)) {
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
- bg_queue_leave(sd);
- clif_bg_queue_entry_init(sd);
- found = true;
- }
- }
- for (const auto &sd : queue->teamb_members) {
- if (map_getmapflag(sd->bl.m, MF_NOWARP)) {
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
- bg_queue_leave(sd);
- clif_bg_queue_entry_init(sd);
- found = true;
- }
- }
- if (found) {
- queue->state = QUEUE_STATE_SETUP; // Set back to queueing state
- queue->accepted_players = 0; // Reset acceptance count
- // Free map to avoid creating a reservation delay
- if (queue->map != nullptr) {
- queue->map->isReserved = false;
- queue->map = nullptr;
- }
- // Announce failure to remaining players
- for (const auto &sd : queue->teama_members)
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 340), false, SELF); // Participants were unable to join. Delaying entry for more participants.
- for (const auto &sd : queue->teamb_members)
- clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 340), false, SELF); // Participants were unable to join. Delaying entry for more participants.
- }
- return found;
- }
- /**
- * Update the Battleground queue when the player accepts the invite
- * @param queue: Battleground queue
- * @param sd: Player data
- */
- void bg_queue_on_accept_invite(map_session_data *sd)
- {
- nullpo_retv(sd);
- std::shared_ptr<s_battleground_queue> queue = bg_search_queue(sd->bg_queue_id);
- if (queue == nullptr) {
- ShowError("bg_queue_on_accept_invite: Couldn't find player %s in battlegrounds queue.\n", sd->status.name);
- return;
- }
- queue->accepted_players++;
- clif_bg_queue_ack_lobby(true, mapindex_id2name(queue->map->mapindex), mapindex_id2name(queue->map->mapindex), sd);
- if (queue->state == QUEUE_STATE_ACTIVE) // Battleground is already active
- bg_join_active(sd, queue);
- else if (queue->state == QUEUE_STATE_SETUP_DELAY) {
- if (queue->accepted_players == queue->required_players * 2) {
- if (queue->tid_expire != INVALID_TIMER) {
- delete_timer(queue->tid_expire, bg_on_ready_expire);
- queue->tid_expire = INVALID_TIMER;
- }
- // Check player's current position for mapflag check
- if (battle_config.bgqueue_nowarp_mapflag > 0 && bg_mapflag_check(queue))
- return;
- queue->tid_start = add_timer(gettick() + battleground_db.find(queue->id)->start_delay * 1000, bg_on_ready_start, 0, (intptr_t)queue->queue_id);
- }
- }
- }
- /**
- * Begin the Battleground from the given queue
- * @param queue: Battleground queue
- */
- void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue)
- {
- if (queue == nullptr)
- return;
- std::shared_ptr<s_battleground_type> bg = battleground_db.find(queue->id);
- if (!bg) {
- bg_queue_clear(queue, true);
- ShowError("bg_queue_start_battleground: Could not find battleground ID %d in battlegrounds database.\n", queue->id);
- return;
- }
- // Check player's current position for mapflag check
- if (battle_config.bgqueue_nowarp_mapflag > 0 && bg_mapflag_check(queue))
- return;
- uint16 map_idx = queue->map->mapindex;
- int bg_team_1 = bg_create(map_idx, &queue->map->team1);
- int bg_team_2 = bg_create(map_idx, &queue->map->team2);
- for (const auto &sd : queue->teama_members) {
- clif_bg_queue_entry_init(sd);
- bg_team_join(bg_team_1, sd, true);
- }
- for (const auto &sd : queue->teamb_members) {
- clif_bg_queue_entry_init(sd);
- bg_team_join(bg_team_2, sd, true);
- }
- mapreg_setreg(add_str(queue->map->team1.bg_id_var.c_str()), bg_team_1);
- mapreg_setreg(add_str(queue->map->team2.bg_id_var.c_str()), bg_team_2);
- npc_event_do(queue->map->bgcallscript.c_str());
- queue->state = QUEUE_STATE_ACTIVE;
- bg_queue_clear(queue, false);
- }
- /**
- * Initialize a Battleground queue
- * @param bg_id: Battleground ID
- * @param req_players: Required amount of players
- * @return s_battleground_queue*
- */
- static void bg_queue_create(int bg_id, int req_players)
- {
- auto queue = std::make_shared<s_battleground_queue>();
- queue->queue_id = bg_queue_count++;
- queue->id = bg_id;
- queue->required_players = req_players;
- queue->accepted_players = 0;
- queue->tid_expire = INVALID_TIMER;
- queue->tid_start = INVALID_TIMER;
- queue->tid_requeue = INVALID_TIMER;
- queue->state = QUEUE_STATE_SETUP;
- bg_queues.push_back(queue);
- }
- /**
- * Initialize the Battleground data
- */
- void do_init_battleground(void)
- {
- if (battle_config.feature_bgqueue) {
- battleground_db.load();
- for (const auto &bg : battleground_db)
- bg_queue_create(bg.first, bg.second->required_players);
- }
- add_timer_func_list(bg_send_xy_timer, "bg_send_xy_timer");
- add_timer_func_list(bg_on_ready_loopback, "bg_on_ready_loopback");
- add_timer_func_list(bg_on_ready_expire, "bg_on_ready_expire");
- add_timer_func_list(bg_on_ready_start, "bg_on_ready_start");
- add_timer_interval(gettick() + battle_config.bg_update_interval, bg_send_xy_timer, 0, 0, battle_config.bg_update_interval);
- }
- /**
- * Clear the Battleground data from memory
- */
- void do_final_battleground(void)
- {
- }
|