instance.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "instance.hpp"
  4. #include <stdlib.h>
  5. #include <math.h>
  6. #include <yaml-cpp/yaml.h>
  7. #include "../common/cbasetypes.hpp"
  8. #include "../common/db.hpp"
  9. #include "../common/ers.hpp" // ers_destroy
  10. #include "../common/malloc.hpp"
  11. #include "../common/nullpo.hpp"
  12. #include "../common/showmsg.hpp"
  13. #include "../common/socket.hpp"
  14. #include "../common/strlib.hpp"
  15. #include "../common/timer.hpp"
  16. #include "../common/utilities.hpp"
  17. #include "clan.hpp"
  18. #include "clif.hpp"
  19. #include "guild.hpp"
  20. #include "map.hpp"
  21. #include "npc.hpp"
  22. #include "party.hpp"
  23. #include "pc.hpp"
  24. using namespace rathena;
  25. /// Instance Idle Queue data
  26. struct s_instance_wait {
  27. std::deque<int> id;
  28. int timer;
  29. } instance_wait;
  30. #define INSTANCE_INTERVAL 60000 // Interval used to check when an instance is to be destroyed (ms)
  31. int16 instance_start = 0; // Instance MapID start
  32. int instance_count = 1; // Total created instances
  33. std::unordered_map<int, std::shared_ptr<s_instance_data>> instances;
  34. const std::string InstanceDatabase::getDefaultLocation() {
  35. return std::string(db_path) + "/instance_db.yml";
  36. }
  37. /**
  38. * Reads and parses an entry from the instance_db.
  39. * @param node: YAML node containing the entry.
  40. * @return count of successfully parsed rows
  41. */
  42. uint64 InstanceDatabase::parseBodyNode(const YAML::Node &node) {
  43. int32 instance_id = 0;
  44. if (!this->asInt32(node, "Id", instance_id))
  45. return 0;
  46. if (instance_id <= 0) {
  47. this->invalidWarning(node, "Instance Id is invalid. Valid range 1~%d, skipping.\n", INT_MAX);
  48. return 0;
  49. }
  50. std::shared_ptr<s_instance_db> instance = this->find(instance_id);
  51. bool exists = instance != nullptr;
  52. if (!exists) {
  53. if (!this->nodesExist(node, { "Name", "Enter" }))
  54. return 0;
  55. instance = std::make_shared<s_instance_db>();
  56. instance->id = instance_id;
  57. }
  58. if (this->nodeExists(node, "Name")) {
  59. std::string name;
  60. if (!this->asString(node, "Name", name))
  61. return 0;
  62. for (const auto &instance : instance_db) {
  63. if (instance.second->name.compare(name) == 0) {
  64. this->invalidWarning(node["Name"], "Instance name %s already exists, skipping.\n", name.c_str());
  65. return 0;
  66. }
  67. }
  68. instance->name = name;
  69. }
  70. if (this->nodeExists(node, "TimeLimit")) {
  71. uint32 limit;
  72. if (!this->asUInt32(node, "TimeLimit", limit))
  73. return 0;
  74. instance->limit = limit;
  75. } else {
  76. if (!exists)
  77. instance->limit = 3600;
  78. }
  79. if (this->nodeExists(node, "IdleTimeOut")) {
  80. uint32 idle;
  81. if (!this->asUInt32(node, "IdleTimeOut", idle))
  82. return 0;
  83. instance->timeout = idle;
  84. } else {
  85. if (!exists)
  86. instance->timeout = 300;
  87. }
  88. if (this->nodeExists(node, "NoNpc")) {
  89. bool nonpc;
  90. if (!this->asBool(node, "NoNpc", nonpc))
  91. return 0;
  92. instance->nonpc = nonpc;
  93. }
  94. else {
  95. if (!exists)
  96. instance->nonpc = false;
  97. }
  98. if (this->nodeExists(node, "NoMapFlag")) {
  99. bool nomapflag;
  100. if (!this->asBool(node, "NoMapFlag", nomapflag))
  101. return 0;
  102. instance->nomapflag = nomapflag;
  103. }
  104. else {
  105. if (!exists)
  106. instance->nomapflag = false;
  107. }
  108. if (this->nodeExists(node, "Destroyable")) {
  109. bool destroy;
  110. if (!this->asBool(node, "Destroyable", destroy))
  111. return 0;
  112. instance->destroyable = destroy;
  113. } else {
  114. if (!exists)
  115. instance->destroyable = true;
  116. }
  117. if (this->nodeExists(node, "Enter")) {
  118. const YAML::Node &enterNode = node["Enter"];
  119. if (!this->nodesExist(enterNode, { "Map", "X", "Y" }))
  120. return 0;
  121. if (this->nodeExists(enterNode, "Map")) {
  122. std::string map;
  123. if (!this->asString(enterNode, "Map", map))
  124. return 0;
  125. int16 m = map_mapname2mapid(map.c_str());
  126. if (m == -1) {
  127. this->invalidWarning(enterNode["Map"], "Map %s is not a valid map, skipping.\n", map.c_str());
  128. return 0;
  129. }
  130. instance->enter.map = m;
  131. }
  132. if (this->nodeExists(enterNode, "X")) {
  133. int16 x;
  134. if (!this->asInt16(enterNode, "X", x))
  135. return 0;
  136. instance->enter.x = x;
  137. }
  138. if (this->nodeExists(enterNode, "Y")) {
  139. int16 y;
  140. if (!this->asInt16(enterNode, "Y", y))
  141. return 0;
  142. instance->enter.y = y;
  143. }
  144. }
  145. if (this->nodeExists(node, "AdditionalMaps")) {
  146. const YAML::Node &mapNode = node["AdditionalMaps"];
  147. for (const auto &mapIt : mapNode) {
  148. std::string map = mapIt.first.as<std::string>();
  149. int16 m = map_mapname2mapid(map.c_str());
  150. if (m == instance->enter.map) {
  151. this->invalidWarning(mapNode, "Additional Map %s is already listed as the EnterMap.\n", map.c_str());
  152. continue;
  153. }
  154. if (m == -1) {
  155. this->invalidWarning(mapNode, "Additional Map %s is not a valid map, skipping.\n", map.c_str());
  156. return 0;
  157. }
  158. bool active;
  159. if (!this->asBool(mapNode, map, active))
  160. return 0;
  161. if (active)
  162. instance->maplist.push_back(m);
  163. else
  164. util::vector_erase_if_exists(instance->maplist, m);
  165. }
  166. }
  167. if (!exists)
  168. this->put(instance_id, instance);
  169. return 1;
  170. }
  171. InstanceDatabase instance_db;
  172. /**
  173. * Searches for an instance name in the database
  174. * @param instance_name: Instance to search for
  175. * @return shared_ptr of instance or nullptr on failure
  176. */
  177. std::shared_ptr<s_instance_db> instance_search_db_name(const char *instance_name)
  178. {
  179. for (const auto &it : instance_db) {
  180. if (!strcmp(it.second->name.c_str(), instance_name))
  181. return it.second;
  182. }
  183. return nullptr;
  184. }
  185. /**
  186. * Search for a sd of an Instance
  187. * @param instance_id: Instance ID
  188. * @param sd: Pointer to player data
  189. * @param target: Target display type
  190. */
  191. void instance_getsd(int instance_id, struct map_session_data *&sd, enum send_target *target) {
  192. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
  193. if (!idata) {
  194. sd = nullptr;
  195. return;
  196. }
  197. switch(idata->mode) {
  198. case IM_NONE:
  199. sd = nullptr;
  200. (*target) = SELF;
  201. break;
  202. case IM_GUILD:
  203. sd = guild_getavailablesd(guild_search(idata->owner_id));
  204. (*target) = GUILD;
  205. break;
  206. case IM_PARTY:
  207. sd = party_getavailablesd(party_search(idata->owner_id));
  208. (*target) = PARTY;
  209. break;
  210. case IM_CHAR:
  211. sd = map_charid2sd(idata->owner_id);
  212. (*target) = SELF;
  213. break;
  214. case IM_CLAN:
  215. sd = clan_getavailablesd(clan_search(idata->owner_id));
  216. (*target) = CLAN;
  217. }
  218. return;
  219. }
  220. /**
  221. * Deletes an instance timer (Destroys instance)
  222. */
  223. static TIMER_FUNC(instance_delete_timer){
  224. instance_destroy(id);
  225. return 0;
  226. }
  227. /**
  228. * Create subscription timer
  229. */
  230. static TIMER_FUNC(instance_subscription_timer){
  231. int instance_id = instance_wait.id[0];
  232. if (instance_id <= 0 || instance_wait.id.empty())
  233. return 0;
  234. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
  235. if (!idata)
  236. return 0;
  237. struct map_session_data *sd;
  238. struct party_data *pd;
  239. struct guild *gd;
  240. struct clan *cd;
  241. e_instance_mode mode = idata->mode;
  242. int ret = instance_addmap(instance_id); // Check that maps have been added
  243. switch(mode) {
  244. case IM_NONE:
  245. break;
  246. case IM_CHAR:
  247. if (ret == 0 && (sd = map_charid2sd(idata->owner_id))) // If no maps are created, tell player to wait
  248. clif_instance_changewait(instance_id, 0xffff);
  249. break;
  250. case IM_PARTY:
  251. if (ret == 0 && (pd = party_search(idata->owner_id))) // If no maps are created, tell party to wait
  252. clif_instance_changewait(instance_id, 0xffff);
  253. break;
  254. case IM_GUILD:
  255. if (ret == 0 && (gd = guild_search(idata->owner_id))) // If no maps are created, tell guild to wait
  256. clif_instance_changewait(instance_id, 0xffff);
  257. break;
  258. case IM_CLAN:
  259. if (ret == 0 && (cd = clan_search(idata->owner_id))) // If no maps are created, tell clan to wait
  260. clif_instance_changewait(instance_id, 0xffff);
  261. break;
  262. default:
  263. return 0;
  264. }
  265. instance_wait.id.pop_front();
  266. for (int i = 0; i < instance_wait.id.size(); i++) {
  267. if (idata->state == INSTANCE_IDLE && ((mode == IM_CHAR && sd) || (mode == IM_GUILD && gd) || (mode == IM_PARTY && pd) || (mode == IM_CLAN && cd)))
  268. clif_instance_changewait(instance_id, i + 1);
  269. }
  270. if (!instance_wait.id.empty())
  271. instance_wait.timer = add_timer(gettick() + INSTANCE_INTERVAL, instance_subscription_timer, 0, 0);
  272. else
  273. instance_wait.timer = INVALID_TIMER;
  274. return 0;
  275. }
  276. /**
  277. * Adds timer back to members entering instance
  278. * @param idata: Instance data
  279. * @param instance_id: Instance ID to notify
  280. * @return True on success or false on failure
  281. */
  282. bool instance_startkeeptimer(std::shared_ptr<s_instance_data> idata, int instance_id)
  283. {
  284. // No timer
  285. if (!idata || idata->keep_timer != INVALID_TIMER || idata->keep_limit == 0)
  286. return false;
  287. std::shared_ptr<s_instance_db> db = instance_db.find(idata->id);
  288. if (!db)
  289. return false;
  290. // Add timer
  291. idata->keep_limit = static_cast<unsigned int>(time(nullptr)) + db->limit;
  292. idata->keep_timer = add_timer(gettick() + db->limit * 1000, instance_delete_timer, instance_id, 0);
  293. switch(idata->mode) {
  294. case IM_NONE:
  295. break;
  296. case IM_CHAR:
  297. if (map_charid2sd(idata->owner_id)) // Notify player of the added instance timer
  298. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  299. break;
  300. case IM_PARTY:
  301. if (party_search(idata->owner_id)) // Notify party of the added instance timer
  302. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  303. break;
  304. case IM_GUILD:
  305. if (guild_search(idata->owner_id)) // Notify guild of the added instance timer
  306. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  307. break;
  308. case IM_CLAN:
  309. if (clan_search(idata->owner_id)) // Notify clan of the added instance timer
  310. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  311. break;
  312. default:
  313. return false;
  314. }
  315. return true;
  316. }
  317. /**
  318. * Creates an idle timer for an instance, default is 5 minutes
  319. * @param idata: Instance data
  320. * @param instance_id: Instance ID to notify
  321. * @param True on success or false on failure
  322. */
  323. bool instance_startidletimer(std::shared_ptr<s_instance_data> idata, int instance_id)
  324. {
  325. // No current timer
  326. if (!idata || idata->idle_timer != INVALID_TIMER)
  327. return false;
  328. std::shared_ptr<s_instance_db> db = instance_db.find(idata->id);
  329. if (!db)
  330. return false;
  331. // Add the timer
  332. idata->idle_limit = static_cast<unsigned int>(time(nullptr)) + db->timeout;
  333. idata->idle_timer = add_timer(gettick() + db->timeout * 1000, instance_delete_timer, instance_id, 0);
  334. switch(idata->mode) {
  335. case IM_NONE:
  336. break;
  337. case IM_CHAR:
  338. if (map_charid2sd(idata->owner_id)) // Notify player of added instance timer
  339. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  340. break;
  341. case IM_PARTY:
  342. if (party_search(idata->owner_id)) // Notify party of added instance timer
  343. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  344. break;
  345. case IM_GUILD:
  346. if (guild_search(idata->owner_id)) // Notify guild of added instance timer
  347. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  348. break;
  349. case IM_CLAN:
  350. if (clan_search(idata->owner_id)) // Notify clan of added instance timer
  351. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  352. break;
  353. default:
  354. return false;
  355. }
  356. return true;
  357. }
  358. /**
  359. * Remove the idle timer from an instance
  360. * @param idata: Instace data
  361. * @param instance_id: Instance ID to notify
  362. * @return True on success or false on failure
  363. */
  364. bool instance_stopidletimer(std::shared_ptr<s_instance_data> idata, int instance_id)
  365. {
  366. // No timer
  367. if (!idata || idata->idle_timer == INVALID_TIMER)
  368. return false;
  369. // Delete the timer - Party has returned or instance is destroyed
  370. delete_timer(idata->idle_timer, instance_delete_timer);
  371. idata->idle_timer = INVALID_TIMER;
  372. switch(idata->mode) {
  373. case IM_NONE:
  374. break;
  375. case IM_CHAR:
  376. if (map_charid2sd(idata->owner_id)) // Notify the player
  377. clif_instance_changestatus(instance_id, IN_NOTIFY, 0);
  378. break;
  379. case IM_PARTY:
  380. if (party_search(idata->owner_id)) // Notify the party
  381. clif_instance_changestatus(instance_id, IN_NOTIFY, 0);
  382. break;
  383. case IM_GUILD:
  384. if (guild_search(idata->owner_id)) // Notify the guild
  385. clif_instance_changestatus(instance_id, IN_NOTIFY, 0);
  386. break;
  387. case IM_CLAN:
  388. if (clan_search(idata->owner_id)) // Notify the clan
  389. clif_instance_changestatus(instance_id, IN_NOTIFY, 0);
  390. break;
  391. default:
  392. return false;
  393. }
  394. return true;
  395. }
  396. /**
  397. * Run the OnInstanceInit events for duplicated NPCs
  398. */
  399. static int instance_npcinit(struct block_list *bl, va_list ap)
  400. {
  401. struct npc_data* nd;
  402. nullpo_retr(0, bl);
  403. nullpo_retr(0, nd = (struct npc_data *)bl);
  404. return npc_instanceinit(nd);
  405. }
  406. /**
  407. * Run the OnInstanceDestroy events for duplicated NPCs
  408. */
  409. static int instance_npcdestroy(struct block_list *bl, va_list ap)
  410. {
  411. struct npc_data* nd;
  412. nullpo_retr(0, bl);
  413. nullpo_retr(0, nd = (struct npc_data *)bl);
  414. return npc_instancedestroy(nd);
  415. }
  416. /**
  417. * Update instance with new NPC
  418. */
  419. static int instance_addnpc_sub(struct block_list *bl, va_list ap)
  420. {
  421. struct npc_data* nd;
  422. nullpo_retr(0, bl);
  423. nullpo_retr(0, nd = (struct npc_data *)bl);
  424. return npc_duplicate4instance(nd, va_arg(ap, int));
  425. }
  426. /**
  427. * Add an NPC to an instance
  428. * @param idata: Instance data
  429. */
  430. void instance_addnpc(std::shared_ptr<s_instance_data> idata)
  431. {
  432. // First add the NPCs
  433. for (const auto &it : idata->map) {
  434. struct map_data *mapdata = map_getmapdata(it.m);
  435. map_foreachinallarea(instance_addnpc_sub, it.src_m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, it.m);
  436. }
  437. // Now run their OnInstanceInit
  438. for (const auto &it : idata->map) {
  439. struct map_data *mapdata = map_getmapdata(it.m);
  440. map_foreachinallarea(instance_npcinit, it.m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, it.m);
  441. }
  442. }
  443. /**
  444. * Create an instance
  445. * @param owner_id: Owner block ID
  446. * @param name: Instance name
  447. * @param mode: Instance mode
  448. * @return -4 = no free instances | -3 = already exists | -2 = character/party/guild not found | -1 = invalid type | On success return instance_id
  449. */
  450. int instance_create(int owner_id, const char *name, e_instance_mode mode) {
  451. std::shared_ptr<s_instance_db> db = instance_search_db_name(name);
  452. if (!db) {
  453. ShowError("instance_create: Unknown instance %s creation was attempted.\n", name);
  454. return -1;
  455. }
  456. struct map_session_data *sd = nullptr;
  457. struct party_data *pd;
  458. struct guild *gd;
  459. struct clan* cd;
  460. switch(mode) {
  461. case IM_NONE:
  462. break;
  463. case IM_CHAR:
  464. if (!(sd = map_charid2sd(owner_id))) {
  465. ShowError("instance_create: Character %d not found for instance '%s'.\n", owner_id, name);
  466. return -2;
  467. }
  468. if (sd->instance_id > 0)
  469. return -3; // Player already instancing
  470. break;
  471. case IM_PARTY:
  472. if (!(pd = party_search(owner_id))) {
  473. ShowError("instance_create: Party %d not found for instance '%s'.\n", owner_id, name);
  474. return -2;
  475. }
  476. if (pd->instance_id > 0)
  477. return -3; // Party already instancing
  478. break;
  479. case IM_GUILD:
  480. if (!(gd = guild_search(owner_id))) {
  481. ShowError("instance_create: Guild %d not found for instance '%s'.\n", owner_id, name);
  482. return -2;
  483. }
  484. if (gd->instance_id > 0)
  485. return -3; // Guild already instancing
  486. break;
  487. case IM_CLAN:
  488. if (!(cd = clan_search(owner_id))) {
  489. ShowError("instance_create: Clan %d not found for instance '%s'.\n", owner_id, name);
  490. return -2;
  491. }
  492. if (cd->instance_id > 0)
  493. return -3; // Clan already instancing
  494. break;
  495. default:
  496. ShowError("instance_create: Unknown mode %u for owner_id %d and name %s.\n", mode, owner_id, name);
  497. return -2;
  498. }
  499. if (instance_count <= 0)
  500. return -4;
  501. int instance_id = instance_count++;
  502. std::shared_ptr<s_instance_data> entry = std::make_shared<s_instance_data>();
  503. entry->id = db->id;
  504. entry->owner_id = owner_id;
  505. entry->mode = mode;
  506. entry->regs.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
  507. entry->regs.arrays = nullptr;
  508. instances.insert({ instance_id, entry });
  509. switch(mode) {
  510. case IM_CHAR:
  511. sd->instance_id = instance_id;
  512. break;
  513. case IM_PARTY:
  514. pd->instance_id = instance_id;
  515. int32 i;
  516. ARR_FIND(0, MAX_PARTY, i, pd->party.member[i].leader);
  517. if (i < MAX_PARTY)
  518. sd = map_charid2sd(pd->party.member[i].char_id);
  519. break;
  520. case IM_GUILD:
  521. gd->instance_id = instance_id;
  522. sd = map_charid2sd(gd->member[0].char_id);
  523. break;
  524. case IM_CLAN:
  525. cd->instance_id = instance_id;
  526. break;
  527. }
  528. if (sd != nullptr)
  529. sd->instance_mode = mode;
  530. instance_wait.id.push_back(instance_id);
  531. clif_instance_create(instance_id, instance_wait.id.size());
  532. instance_subscription_timer(0,0,0,0);
  533. ShowInfo("[Instance] Created: %s (%d)\n", name, instance_id);
  534. // Start the instance timer on instance creation
  535. instance_startkeeptimer(entry, instance_id);
  536. return instance_id;
  537. }
  538. /**
  539. * Adds maps to the instance
  540. * @param instance_id: Instance ID to add map to
  541. * @return 0 on failure or map count on success
  542. */
  543. int instance_addmap(int instance_id) {
  544. if (instance_id <= 0)
  545. return 0;
  546. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
  547. // If the instance isn't idle, we can't do anything
  548. if (idata->state != INSTANCE_IDLE)
  549. return 0;
  550. std::shared_ptr<s_instance_db> db = instance_db.find(idata->id);
  551. if (!db)
  552. return 0;
  553. // Set to busy, update timers
  554. idata->state = INSTANCE_BUSY;
  555. if (db->timeout > 0) {
  556. idata->idle_limit = static_cast<unsigned int>(time(nullptr)) + db->timeout;
  557. idata->idle_timer = add_timer(gettick() + db->timeout * 1000, instance_delete_timer, instance_id, 0);
  558. }
  559. if (db->limit > 0) {
  560. //This will allow the instance to get a time in 'instance_startkeeptimer'
  561. idata->keep_limit = 1;
  562. }
  563. idata->nomapflag = db->nomapflag;
  564. idata->nonpc = db->nonpc;
  565. int16 m;
  566. // Add initial map
  567. if ((m = map_addinstancemap(db->enter.map, instance_id, db->nomapflag)) < 0) {
  568. ShowError("instance_addmap: Failed to create initial map for instance '%s' (%d).\n", db->name.c_str(), instance_id);
  569. return 0;
  570. }
  571. struct s_instance_map entry;
  572. entry.m = m;
  573. entry.src_m = db->enter.map;
  574. idata->map.push_back(entry);
  575. // Add extra maps (if any)
  576. for (const auto &it : db->maplist) {
  577. if ((m = map_addinstancemap(it, instance_id, db->nomapflag)) < 0) { // An error occured adding a map
  578. ShowError("instance_addmap: No maps added to instance '%s' (%d).\n", db->name.c_str(), instance_id);
  579. return 0;
  580. } else {
  581. entry.m = m;
  582. entry.src_m = it;
  583. idata->map.push_back(entry);
  584. }
  585. }
  586. // Create NPCs on all maps
  587. if(!db->nonpc)
  588. instance_addnpc(idata);
  589. switch(idata->mode) {
  590. case IM_NONE:
  591. break;
  592. case IM_CHAR:
  593. if (map_charid2sd(idata->owner_id)) // Inform player of the created instance
  594. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  595. break;
  596. case IM_PARTY:
  597. if (party_search(idata->owner_id)) // Inform party members of the created instance
  598. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  599. break;
  600. case IM_GUILD:
  601. if (guild_search(idata->owner_id)) // Inform guild members of the created instance
  602. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  603. break;
  604. case IM_CLAN:
  605. if (clan_search(idata->owner_id)) // Inform clan members of the created instance
  606. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  607. break;
  608. default:
  609. return 0;
  610. }
  611. return idata->map.size();
  612. }
  613. /**
  614. * Fills outname with the name of the instance map name
  615. * @param map_id: Mapid to use
  616. * @param instance_id: Instance id
  617. * @param outname: Pointer to allocated memory that will be filled in
  618. */
  619. void instance_generate_mapname(int map_id, int instance_id, char outname[MAP_NAME_LENGTH]) {
  620. #if MAX_MAP_PER_SERVER > 9999
  621. #error This algorithm is only safe for up to 9999 maps, change at your own risk.
  622. #endif
  623. // Safe up to 9999 maps per map-server
  624. static const int prefix_length = 4;
  625. // Full map name length - prefix length - seperator character - zero termination
  626. static const int suffix_length = MAP_NAME_LENGTH - prefix_length - 1 - 1;
  627. static const int prefix_limit = static_cast<int>(pow(10, prefix_length));
  628. static const int suffix_limit = static_cast<int>(pow(10, suffix_length));
  629. safesnprintf(outname, MAP_NAME_LENGTH, "%0*u#%0*u", prefix_length, map_id % prefix_limit, suffix_length, instance_id % suffix_limit);
  630. }
  631. /**
  632. * Returns an instance map ID
  633. * @param m: Source map ID
  634. * @param instance_id: Instance to search
  635. * @return Map ID in this instance or -1 on failure
  636. */
  637. int16 instance_mapid(int16 m, int instance_id)
  638. {
  639. const char *name = map_mapid2mapname(m);
  640. if (name == nullptr) {
  641. ShowError("instance_mapid: Map ID %d does not exist.\n", m);
  642. return -1;
  643. }
  644. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
  645. if(!idata || idata->state != INSTANCE_BUSY)
  646. return -1;
  647. for (const auto &it : idata->map) {
  648. if (it.src_m == m) {
  649. char alt_name[MAP_NAME_LENGTH];
  650. instance_generate_mapname(m, instance_id, alt_name);
  651. return map_mapname2mapid(alt_name);
  652. }
  653. }
  654. return m;
  655. }
  656. /**
  657. * Removes an instance, all its maps, and NPCs invoked by the client button.
  658. * @param sd: Player data
  659. */
  660. void instance_destroy_command(map_session_data *sd) {
  661. nullpo_retv(sd);
  662. std::shared_ptr<s_instance_data> idata;
  663. int instance_id = 0;
  664. if (sd->instance_mode == IM_CHAR && sd->instance_id > 0) {
  665. idata = util::umap_find(instances, sd->instance_id);
  666. if (idata == nullptr)
  667. return;
  668. instance_id = sd->instance_id;
  669. } else if (sd->instance_mode == IM_PARTY && sd->status.party_id > 0) {
  670. party_data *pd = party_search(sd->status.party_id);
  671. if (pd == nullptr)
  672. return;
  673. idata = util::umap_find(instances, pd->instance_id);
  674. if (idata == nullptr)
  675. return;
  676. int32 i;
  677. ARR_FIND(0, MAX_PARTY, i, pd->data[i].sd == sd && pd->party.member[i].leader);
  678. if (i == MAX_PARTY) // Player is not party leader
  679. return;
  680. instance_id = pd->instance_id;
  681. } else if (sd->instance_mode == IM_GUILD && sd->guild != nullptr && sd->guild->instance_id > 0) {
  682. guild *gd = guild_search(sd->status.guild_id);
  683. if (gd == nullptr)
  684. return;
  685. idata = util::umap_find(instances, gd->instance_id);
  686. if (idata == nullptr)
  687. return;
  688. if (strcmp(sd->status.name, gd->master) != 0) // Player is not guild master
  689. return;
  690. instance_id = gd->instance_id;
  691. }
  692. if (instance_id == 0) // Checks above failed
  693. return;
  694. if (!instance_db.find(idata->id)->destroyable) // Instance is flagged as non-destroyable
  695. return;
  696. instance_destroy(instance_id);
  697. // Check for any other active instances and display their info
  698. if (sd->instance_id > 0)
  699. instance_reqinfo(sd, sd->instance_id);
  700. if (sd->status.party_id > 0) {
  701. party_data *pd = party_search(sd->status.party_id);
  702. if (pd == nullptr)
  703. return;
  704. if (pd->instance_id > 0)
  705. instance_reqinfo(sd, pd->instance_id);
  706. }
  707. if (sd->guild != nullptr && sd->guild->instance_id > 0) {
  708. guild *gd = guild_search(sd->status.guild_id);
  709. if (gd == nullptr)
  710. return;
  711. instance_reqinfo(sd, gd->instance_id);
  712. }
  713. }
  714. /**
  715. * Removes an instance, all its maps, and NPCs.
  716. * @param instance_id: Instance to remove
  717. * @return True on sucess or false on failure
  718. */
  719. bool instance_destroy(int instance_id)
  720. {
  721. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
  722. if (!idata)
  723. return false;
  724. struct map_session_data *sd;
  725. struct party_data *pd;
  726. struct guild *gd;
  727. struct clan *cd;
  728. e_instance_mode mode = idata->mode;
  729. e_instance_notify type = IN_NOTIFY;
  730. switch(mode) {
  731. case IM_NONE:
  732. break;
  733. case IM_CHAR:
  734. sd = map_charid2sd(idata->owner_id);
  735. break;
  736. case IM_PARTY:
  737. pd = party_search(idata->owner_id);
  738. break;
  739. case IM_GUILD:
  740. gd = guild_search(idata->owner_id);
  741. break;
  742. case IM_CLAN:
  743. cd = clan_search(idata->owner_id);
  744. break;
  745. }
  746. if(idata->state == INSTANCE_IDLE) {
  747. for (auto instance_it = instance_wait.id.begin(); instance_it != instance_wait.id.end(); ++instance_it) {
  748. if (*instance_it == instance_id) {
  749. instance_wait.id.erase(instance_it);
  750. for (int i = 0; i < instance_wait.id.size(); i++) {
  751. if (util::umap_find(instances, instance_wait.id[i])->state == INSTANCE_IDLE)
  752. if ((mode == IM_CHAR && sd) || (mode == IM_PARTY && pd) || (mode == IM_GUILD && gd) || (mode == IM_CLAN && cd))
  753. clif_instance_changewait(instance_id, i + 1);
  754. }
  755. if (!instance_wait.id.empty())
  756. instance_wait.timer = add_timer(gettick() + INSTANCE_INTERVAL, instance_subscription_timer, 0, 0);
  757. else
  758. instance_wait.timer = INVALID_TIMER;
  759. break;
  760. }
  761. }
  762. } else {
  763. unsigned int now = static_cast<unsigned int>(time(nullptr));
  764. if(idata->keep_limit && idata->keep_limit <= now)
  765. type = IN_DESTROY_LIVE_TIMEOUT;
  766. else if(idata->idle_limit && idata->idle_limit <= now)
  767. type = IN_DESTROY_ENTER_TIMEOUT;
  768. else
  769. type = IN_DESTROY_USER_REQUEST;
  770. // Run OnInstanceDestroy on all NPCs in the instance
  771. for (const auto &it : idata->map) {
  772. struct map_data *mapdata = map_getmapdata(it.m);
  773. map_foreachinallarea(instance_npcdestroy, it.m, 0, 0, mapdata->xs, mapdata->ys, BL_NPC, it.m);
  774. map_delinstancemap(it.m);
  775. }
  776. }
  777. if(idata->keep_timer != INVALID_TIMER) {
  778. delete_timer(idata->keep_timer, instance_delete_timer);
  779. idata->keep_timer = INVALID_TIMER;
  780. }
  781. if(idata->idle_timer != INVALID_TIMER) {
  782. delete_timer(idata->idle_timer, instance_delete_timer);
  783. idata->idle_timer = INVALID_TIMER;
  784. }
  785. if (mode == IM_CHAR && sd)
  786. sd->instance_id = 0;
  787. else if (mode == IM_PARTY && pd)
  788. pd->instance_id = 0;
  789. else if (mode == IM_GUILD && gd)
  790. gd->instance_id = 0;
  791. else if (mode == IM_CLAN && cd)
  792. cd->instance_id = 0;
  793. if (mode != IM_NONE) {
  794. if(type != IN_NOTIFY)
  795. clif_instance_changestatus(instance_id, type, 0);
  796. else
  797. clif_instance_changewait(instance_id, 0xffff);
  798. }
  799. if( idata->regs.vars ) {
  800. db_destroy(idata->regs.vars);
  801. idata->regs.vars = NULL;
  802. }
  803. if( idata->regs.arrays )
  804. idata->regs.arrays->destroy(idata->regs.arrays, script_free_array_db);
  805. ShowInfo("[Instance] Destroyed: %s (%d)\n", instance_db.find(idata->id)->name.c_str(), instance_id);
  806. instances.erase(instance_id);
  807. return true;
  808. }
  809. /**
  810. * Warp a user into an instance
  811. * @param sd: Player to warp
  812. * @param instance_id: Instance to warp to
  813. * @param name: Map name
  814. * @param x: X coordinate
  815. * @param y: Y coordinate
  816. * @return e_instance_enter value
  817. */
  818. e_instance_enter instance_enter(struct map_session_data *sd, int instance_id, const char *name, short x, short y)
  819. {
  820. nullpo_retr(IE_OTHER, sd);
  821. std::shared_ptr<s_instance_db> db = instance_search_db_name(name);
  822. if (!db) {
  823. ShowError("instance_enter: Unknown instance \"%s\".\n", name);
  824. return IE_OTHER;
  825. }
  826. // If one of the two coordinates was not given or is below zero, we use the entry point from the database
  827. if (x < 0 || y < 0) {
  828. x = db->enter.x;
  829. y = db->enter.y;
  830. }
  831. std::shared_ptr<s_instance_data> idata = nullptr;
  832. struct party_data *pd;
  833. struct guild *gd;
  834. struct clan *cd;
  835. e_instance_mode mode;
  836. if (instance_id <= 0) // Default party checks will be used
  837. mode = IM_PARTY;
  838. else {
  839. if (!(idata = util::umap_find(instances, instance_id)))
  840. return IE_NOINSTANCE;
  841. mode = idata->mode;
  842. }
  843. switch(mode) {
  844. case IM_NONE:
  845. break;
  846. case IM_CHAR:
  847. if (sd->instance_id == 0) // Player must have an instance
  848. return IE_NOINSTANCE;
  849. if (idata->owner_id != sd->status.char_id)
  850. return IE_OTHER;
  851. break;
  852. case IM_PARTY:
  853. if (sd->status.party_id == 0) // Character must be in instance party
  854. return IE_NOMEMBER;
  855. if (!(pd = party_search(sd->status.party_id)))
  856. return IE_NOMEMBER;
  857. if (pd->instance_id == 0 || idata == nullptr) // Party must have an instance
  858. return IE_NOINSTANCE;
  859. if (idata->owner_id != pd->party.party_id)
  860. return IE_OTHER;
  861. break;
  862. case IM_GUILD:
  863. if (sd->status.guild_id == 0) // Character must be in instance guild
  864. return IE_NOMEMBER;
  865. if (!(gd = guild_search(sd->status.guild_id)))
  866. return IE_NOMEMBER;
  867. if (gd->instance_id == 0) // Guild must have an instance
  868. return IE_NOINSTANCE;
  869. if (idata->owner_id != gd->guild_id)
  870. return IE_OTHER;
  871. break;
  872. case IM_CLAN:
  873. if (sd->status.clan_id == 0) // Character must be in instance clan
  874. return IE_NOMEMBER;
  875. if (!(cd = clan_search(sd->status.clan_id)))
  876. return IE_NOMEMBER;
  877. if (cd->instance_id == 0) // Clan must have an instance
  878. return IE_NOINSTANCE;
  879. if (idata->owner_id != cd->id)
  880. return IE_OTHER;
  881. break;
  882. }
  883. if (idata->state != INSTANCE_BUSY)
  884. return IE_OTHER;
  885. if (idata->id != db->id)
  886. return IE_OTHER;
  887. int16 m;
  888. // Does the instance match?
  889. if ((m = instance_mapid(db->enter.map, instance_id)) < 0)
  890. return IE_OTHER;
  891. if (pc_setpos(sd, map_id2index(m), x, y, CLR_OUTSIGHT))
  892. return IE_OTHER;
  893. return IE_OK;
  894. }
  895. /**
  896. * Request some info about the instance
  897. * @param sd: Player to display info to
  898. * @param instance_id: Instance to request
  899. * @return True on success or false on failure
  900. */
  901. bool instance_reqinfo(struct map_session_data *sd, int instance_id)
  902. {
  903. nullpo_retr(false, sd);
  904. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
  905. if (!idata || !instance_db.find(idata->id))
  906. return false;
  907. // Say it's created if instance is not busy
  908. if(idata->state == INSTANCE_IDLE) {
  909. for (int i = 0; i < instance_wait.id.size(); i++) {
  910. if (instance_wait.id[i] == instance_id) {
  911. clif_instance_create(instance_id, i + 1);
  912. sd->instance_mode = idata->mode;
  913. break;
  914. }
  915. }
  916. } else if (idata->state == INSTANCE_BUSY) { // Give info on the instance if busy
  917. int map_instance_id = map_getmapdata(sd->bl.m)->instance_id;
  918. if (map_instance_id == 0 || map_instance_id == instance_id) {
  919. clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
  920. sd->instance_mode = idata->mode;
  921. }
  922. }
  923. return true;
  924. }
  925. /**
  926. * Add players to the instance (for timers) -- Unused?
  927. * @param instance_id: Instance to add
  928. * @return True on success or false on failure
  929. */
  930. bool instance_addusers(int instance_id)
  931. {
  932. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
  933. if(!idata || idata->state != INSTANCE_BUSY || idata->idle_limit == 0)
  934. return false;
  935. // Stop the idle timer if we had one
  936. instance_stopidletimer(idata, instance_id);
  937. // Start the instance keep timer
  938. instance_startkeeptimer(idata, instance_id);
  939. return true;
  940. }
  941. /**
  942. * Delete players from the instance (for timers)
  943. * @param instance_id: Instance to remove
  944. * @return True on success or false on failure
  945. */
  946. bool instance_delusers(int instance_id)
  947. {
  948. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
  949. if(!idata || idata->state != INSTANCE_BUSY || idata->idle_limit == 0)
  950. return false;
  951. int users = 0;
  952. // If no one is in the instance, start the idle timer
  953. for (const auto &it : idata->map)
  954. users += max(map_getmapdata(it.m)->users,0);
  955. // We check the actual map.users before being updated, hence the 1
  956. // The instance should be empty if users are now <= 1
  957. if(users <= 1)
  958. instance_startidletimer(idata, instance_id);
  959. return true;
  960. }
  961. /**
  962. * Reloads the instance in runtime (reloadscript)
  963. */
  964. void do_reload_instance(void)
  965. {
  966. for (const auto &it : instances) {
  967. std::shared_ptr<s_instance_data> idata = it.second;
  968. if (!idata || idata->map.empty())
  969. continue;
  970. else {
  971. // First we load the NPCs again
  972. if(!idata->nonpc)
  973. instance_addnpc(idata);
  974. // Create new keep timer
  975. std::shared_ptr<s_instance_db> db = instance_db.find(idata->id);
  976. if (db && db->limit > 0)
  977. idata->keep_limit = static_cast<unsigned int>(time(nullptr)) + db->limit;
  978. }
  979. }
  980. // Reset player to instance beginning
  981. struct s_mapiterator *iter = mapit_getallusers();
  982. struct map_session_data *sd;
  983. for (sd = (TBL_PC *)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC *)mapit_next(iter)) {
  984. struct map_data *mapdata = map_getmapdata(sd->bl.m);
  985. if (sd && mapdata->instance_id > 0) {
  986. struct party_data *pd;
  987. struct guild *gd;
  988. struct clan *cd;
  989. int instance_id;
  990. std::shared_ptr<s_instance_data> idata = util::umap_find(instances, map[sd->bl.m].instance_id);
  991. std::shared_ptr<s_instance_db> db = instance_db.find(idata->id);
  992. switch (idata->mode) {
  993. case IM_NONE:
  994. continue;
  995. case IM_CHAR:
  996. if (sd->instance_id != mapdata->instance_id) // Someone who is not instance owner is on instance map
  997. continue;
  998. instance_id = sd->instance_id;
  999. break;
  1000. case IM_PARTY:
  1001. if ((!(pd = party_search(sd->status.party_id)) || pd->instance_id != mapdata->instance_id)) // Someone not in party is on instance map
  1002. continue;
  1003. instance_id = pd->instance_id;
  1004. break;
  1005. case IM_GUILD:
  1006. if (!(gd = guild_search(sd->status.guild_id)) || gd->instance_id != mapdata->instance_id) // Someone not in guild is on instance map
  1007. continue;
  1008. instance_id = gd->instance_id;
  1009. break;
  1010. case IM_CLAN:
  1011. if (!(cd = clan_search(sd->status.clan_id)) || cd->instance_id != mapdata->instance_id) // Someone not in clan is on instance map
  1012. continue;
  1013. instance_id = cd->instance_id;
  1014. break;
  1015. default:
  1016. ShowError("do_reload_instance: Unexpected instance mode for instance %s (id=%d, mode=%u).\n", (db) ? db->name.c_str() : "Unknown", mapdata->instance_id, (uint8)idata->mode);
  1017. continue;
  1018. }
  1019. if (db && instance_enter(sd, instance_id, db->name.c_str(), -1, -1) == IE_OK) { // All good
  1020. clif_displaymessage(sd->fd, msg_txt(sd, 515)); // Instance has been reloaded
  1021. instance_reqinfo(sd, instance_id);
  1022. } else // Something went wrong
  1023. ShowError("do_reload_instance: Error setting character at instance start: character_id=%d instance=%s.\n", sd->status.char_id, db->name.c_str());
  1024. }
  1025. }
  1026. mapit_free(iter);
  1027. }
  1028. /**
  1029. * Initializes the instance database
  1030. */
  1031. void do_init_instance(void) {
  1032. instance_start = map_num;
  1033. instance_db.load();
  1034. instance_wait.timer = INVALID_TIMER;
  1035. add_timer_func_list(instance_delete_timer,"instance_delete_timer");
  1036. add_timer_func_list(instance_subscription_timer,"instance_subscription_timer");
  1037. }
  1038. /**
  1039. * Finalizes the instances and instance database
  1040. */
  1041. void do_final_instance(void) {
  1042. for (const auto &it : instances)
  1043. instance_destroy(it.first);
  1044. }