instance.cpp 34 KB

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