instance.cpp 32 KB

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