PageRenderTime 82ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/src/map/map.c

https://gitlab.com/evol/hercules
C | 6503 lines | 4694 code | 822 blank | 987 comment | 1832 complexity | 91234b6f3bf689f90174f9cee4300f7f MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0
  1. /**
  2. * This file is part of Hercules.
  3. * http://herc.ws - http://github.com/HerculesWS/Hercules
  4. *
  5. * Copyright (C) 2012-2015 Hercules Dev Team
  6. * Copyright (C) Athena Dev Teams
  7. *
  8. * Hercules is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #define HERCULES_CORE
  22. #include "config/core.h" // CELL_NOSTACK, CIRCULAR_AREA, CONSOLE_INPUT, DBPATH, RENEWAL
  23. #include "map.h"
  24. #include "map/HPMmap.h"
  25. #include "map/atcommand.h"
  26. #include "map/battle.h"
  27. #include "map/battleground.h"
  28. #include "map/channel.h"
  29. #include "map/chat.h"
  30. #include "map/chrif.h"
  31. #include "map/clif.h"
  32. #include "map/duel.h"
  33. #include "map/elemental.h"
  34. #include "map/guild.h"
  35. #include "map/homunculus.h"
  36. #include "map/instance.h"
  37. #include "map/intif.h"
  38. #include "map/irc-bot.h"
  39. #include "map/itemdb.h"
  40. #include "map/log.h"
  41. #include "map/mail.h"
  42. #include "map/mapreg.h"
  43. #include "map/mercenary.h"
  44. #include "map/mob.h"
  45. #include "map/npc.h"
  46. #include "map/npc.h" // npc_setcells(), npc_unsetcells()
  47. #include "map/party.h"
  48. #include "map/path.h"
  49. #include "map/pc.h"
  50. #include "map/pet.h"
  51. #include "map/quest.h"
  52. #include "map/script.h"
  53. #include "map/skill.h"
  54. #include "map/status.h"
  55. #include "map/storage.h"
  56. #include "map/trade.h"
  57. #include "map/unit.h"
  58. #include "common/HPM.h"
  59. #include "common/cbasetypes.h"
  60. #include "common/conf.h"
  61. #include "common/console.h"
  62. #include "common/core.h"
  63. #include "common/ers.h"
  64. #include "common/grfio.h"
  65. #include "common/memmgr.h"
  66. #include "common/nullpo.h"
  67. #include "common/random.h"
  68. #include "common/showmsg.h"
  69. #include "common/socket.h" // WFIFO*()
  70. #include "common/strlib.h"
  71. #include "common/timer.h"
  72. #include "common/utils.h"
  73. #include <math.h>
  74. #include <stdarg.h>
  75. #include <stdio.h>
  76. #include <stdlib.h>
  77. #include <string.h>
  78. #ifndef _WIN32
  79. #include <unistd.h>
  80. #endif
  81. struct map_interface map_s;
  82. struct mapit_interface mapit_s;
  83. struct map_interface *map;
  84. struct mapit_interface *mapit;
  85. /*==========================================
  86. * server player count (of all mapservers)
  87. *------------------------------------------*/
  88. void map_setusers(int users) {
  89. map->users = users;
  90. }
  91. int map_getusers(void) {
  92. return map->users;
  93. }
  94. /**
  95. * Expands map->bl_list on demand
  96. **/
  97. static inline void map_bl_list_expand(void) {
  98. map->bl_list_size += 250;
  99. RECREATE(map->bl_list, struct block_list *, map->bl_list_size);
  100. }
  101. /**
  102. * Expands map->block_free on demand
  103. **/
  104. static inline void map_block_free_expand(void) {
  105. map->block_free_list_size += 100;
  106. RECREATE(map->block_free, struct block_list *, map->block_free_list_size);
  107. }
  108. /*==========================================
  109. * server player count (this mapserver only)
  110. *------------------------------------------*/
  111. int map_usercount(void) {
  112. return db_size(map->pc_db);
  113. }
  114. /*==========================================
  115. * Attempt to free a map blocklist
  116. *------------------------------------------*/
  117. int map_freeblock (struct block_list *bl) {
  118. nullpo_retr(map->block_free_lock, bl);
  119. if (map->block_free_lock == 0) {
  120. if( bl->type == BL_ITEM )
  121. ers_free(map->flooritem_ers, bl);
  122. else
  123. aFree(bl);
  124. bl = NULL;
  125. } else {
  126. if( map->block_free_count >= map->block_free_list_size )
  127. map_block_free_expand();
  128. map->block_free[map->block_free_count++] = bl;
  129. }
  130. return map->block_free_lock;
  131. }
  132. /*==========================================
  133. * Lock blocklist, (prevent map->freeblock usage)
  134. *------------------------------------------*/
  135. int map_freeblock_lock (void) {
  136. return ++map->block_free_lock;
  137. }
  138. /*==========================================
  139. * Remove the lock on map_bl
  140. *------------------------------------------*/
  141. int map_freeblock_unlock (void) {
  142. if ((--map->block_free_lock) == 0) {
  143. int i;
  144. for (i = 0; i < map->block_free_count; i++) {
  145. if( map->block_free[i]->type == BL_ITEM )
  146. ers_free(map->flooritem_ers, map->block_free[i]);
  147. else
  148. aFree(map->block_free[i]);
  149. map->block_free[i] = NULL;
  150. }
  151. map->block_free_count = 0;
  152. } else if (map->block_free_lock < 0) {
  153. ShowError("map_freeblock_unlock: lock count < 0 !\n");
  154. map->block_free_lock = 0;
  155. }
  156. return map->block_free_lock;
  157. }
  158. // Timer function to check if there some remaining lock and remove them if so.
  159. // Called each 1s
  160. int map_freeblock_timer(int tid, int64 tick, int id, intptr_t data) {
  161. if (map->block_free_lock > 0) {
  162. ShowError("map_freeblock_timer: block_free_lock(%d) is invalid.\n", map->block_free_lock);
  163. map->block_free_lock = 1;
  164. map->freeblock_unlock();
  165. }
  166. return 0;
  167. }
  168. /**
  169. * Updates the counter (cell.cell_bl) of how many objects are on a tile.
  170. * @param add Whether the counter should be increased or decreased
  171. **/
  172. void map_update_cell_bl( struct block_list *bl, bool increase ) {
  173. #ifdef CELL_NOSTACK
  174. int pos;
  175. nullpo_retv(bl);
  176. if( bl->m < 0 || bl->x < 0 || bl->x >= map->list[bl->m].xs
  177. || bl->y < 0 || bl->y >= map->list[bl->m].ys
  178. || !(bl->type&BL_CHAR) )
  179. return;
  180. // When reading from mapcache the cell isn't initialized
  181. // TODO: Maybe start initializing cells when they're loaded instead of
  182. // having to get them here? [Panikon]
  183. if( map->list[bl->m].cell == (struct mapcell *)0xdeadbeaf )
  184. map->cellfromcache(&map->list[bl->m]);
  185. pos = bl->x + bl->y*map->list[bl->m].xs;
  186. if( increase )
  187. map->list[bl->m].cell[pos].cell_bl++;
  188. else
  189. map->list[bl->m].cell[pos].cell_bl--;
  190. #endif
  191. return;
  192. }
  193. /*==========================================
  194. * Adds a block to the map.
  195. * Returns 0 on success, 1 on failure (illegal coordinates).
  196. *------------------------------------------*/
  197. int map_addblock(struct block_list* bl)
  198. {
  199. int16 m, x, y;
  200. int pos;
  201. nullpo_ret(bl);
  202. if (bl->prev != NULL) {
  203. ShowError("map_addblock: bl->prev != NULL\n");
  204. return 1;
  205. }
  206. m = bl->m;
  207. x = bl->x;
  208. y = bl->y;
  209. if( m < 0 || m >= map->count ) {
  210. ShowError("map_addblock: invalid map id (%d), only %d are loaded.\n", m, map->count);
  211. return 1;
  212. }
  213. if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) {
  214. ShowError("map_addblock: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys);
  215. return 1;
  216. }
  217. pos = x/BLOCK_SIZE+(y/BLOCK_SIZE)*map->list[m].bxs;
  218. if (bl->type == BL_MOB) {
  219. bl->next = map->list[m].block_mob[pos];
  220. bl->prev = &map->bl_head;
  221. if (bl->next) bl->next->prev = bl;
  222. map->list[m].block_mob[pos] = bl;
  223. } else {
  224. bl->next = map->list[m].block[pos];
  225. bl->prev = &map->bl_head;
  226. if (bl->next) bl->next->prev = bl;
  227. map->list[m].block[pos] = bl;
  228. }
  229. #ifdef CELL_NOSTACK
  230. map->update_cell_bl(bl, true);
  231. #endif
  232. return 0;
  233. }
  234. /*==========================================
  235. * Removes a block from the map.
  236. *------------------------------------------*/
  237. int map_delblock(struct block_list* bl)
  238. {
  239. int pos;
  240. nullpo_ret(bl);
  241. // blocklist (2ways chainlist)
  242. if (bl->prev == NULL) {
  243. if (bl->next != NULL) {
  244. // can't delete block (already at the beginning of the chain)
  245. ShowError("map_delblock error : bl->next!=NULL\n");
  246. }
  247. return 0;
  248. }
  249. #ifdef CELL_NOSTACK
  250. map->update_cell_bl(bl, false);
  251. #endif
  252. pos = bl->x/BLOCK_SIZE+(bl->y/BLOCK_SIZE)*map->list[bl->m].bxs;
  253. if (bl->next)
  254. bl->next->prev = bl->prev;
  255. if (bl->prev == &map->bl_head) {
  256. //Since the head of the list, update the block_list map of []
  257. if (bl->type == BL_MOB) {
  258. map->list[bl->m].block_mob[pos] = bl->next;
  259. } else {
  260. map->list[bl->m].block[pos] = bl->next;
  261. }
  262. } else {
  263. bl->prev->next = bl->next;
  264. }
  265. bl->next = NULL;
  266. bl->prev = NULL;
  267. return 0;
  268. }
  269. /*==========================================
  270. * Moves a block a x/y target position. [Skotlex]
  271. * Pass flag as 1 to prevent doing skill->unit_move checks
  272. * (which are executed by default on BL_CHAR types)
  273. *------------------------------------------*/
  274. int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) {
  275. struct status_change *sc = NULL;
  276. int x0, y0;
  277. int moveblock;
  278. nullpo_ret(bl);
  279. x0 = bl->x;
  280. y0 = bl->y;
  281. moveblock = ( x0/BLOCK_SIZE != x1/BLOCK_SIZE || y0/BLOCK_SIZE != y1/BLOCK_SIZE);
  282. if (!bl->prev) {
  283. //Block not in map, just update coordinates, but do naught else.
  284. bl->x = x1;
  285. bl->y = y1;
  286. return 0;
  287. }
  288. //TODO: Perhaps some outs of bounds checking should be placed here?
  289. if (bl->type&BL_CHAR) {
  290. sc = status->get_sc(bl);
  291. skill->unit_move(bl,tick,2);
  292. status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER);
  293. status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER);
  294. //status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure...
  295. status_change_end(bl, SC_NJ_TATAMIGAESHI, INVALID_TIMER);
  296. status_change_end(bl, SC_MAGICROD, INVALID_TIMER);
  297. if (sc && sc->data[SC_PROPERTYWALK] &&
  298. sc->data[SC_PROPERTYWALK]->val3 >= skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) )
  299. status_change_end(bl,SC_PROPERTYWALK,INVALID_TIMER);
  300. } else if (bl->type == BL_NPC) {
  301. npc->unsetcells(BL_UCAST(BL_NPC, bl));
  302. }
  303. if (moveblock) map->delblock(bl);
  304. #ifdef CELL_NOSTACK
  305. else map->update_cell_bl(bl, false);
  306. #endif
  307. bl->x = x1;
  308. bl->y = y1;
  309. if (moveblock) map->addblock(bl);
  310. #ifdef CELL_NOSTACK
  311. else map->update_cell_bl(bl, true);
  312. #endif
  313. if (bl->type&BL_CHAR) {
  314. struct map_session_data *sd = BL_CAST(BL_PC, bl);
  315. skill->unit_move(bl,tick,3);
  316. if (sd != NULL && sd->shadowform_id != 0) {
  317. //Shadow Form Target Moving
  318. struct block_list *d_bl;
  319. if ((d_bl = map->id2bl(sd->shadowform_id)) == NULL || !check_distance_bl(bl,d_bl,10)) {
  320. if( d_bl )
  321. status_change_end(d_bl,SC__SHADOWFORM,INVALID_TIMER);
  322. sd->shadowform_id = 0;
  323. }
  324. }
  325. if (sc && sc->count) {
  326. if (sc->data[SC_DANCING])
  327. skill->unit_move_unit_group(skill->id2group(sc->data[SC_DANCING]->val2), bl->m, x1-x0, y1-y0);
  328. else {
  329. if (sc->data[SC_CLOAKING])
  330. skill->check_cloaking(bl, sc->data[SC_CLOAKING]);
  331. if (sc->data[SC_WARM])
  332. skill->unit_move_unit_group(skill->id2group(sc->data[SC_WARM]->val4), bl->m, x1-x0, y1-y0);
  333. if (sc->data[SC_BANDING])
  334. skill->unit_move_unit_group(skill->id2group(sc->data[SC_BANDING]->val4), bl->m, x1-x0, y1-y0);
  335. if (sc->data[SC_NEUTRALBARRIER_MASTER])
  336. skill->unit_move_unit_group(skill->id2group(sc->data[SC_NEUTRALBARRIER_MASTER]->val2), bl->m, x1-x0, y1-y0);
  337. else if (sc->data[SC_STEALTHFIELD_MASTER])
  338. skill->unit_move_unit_group(skill->id2group(sc->data[SC_STEALTHFIELD_MASTER]->val2), bl->m, x1-x0, y1-y0);
  339. if( sc->data[SC__SHADOWFORM] ) {//Shadow Form Caster Moving
  340. struct block_list *d_bl;
  341. if( (d_bl = map->id2bl(sc->data[SC__SHADOWFORM]->val2)) == NULL || !check_distance_bl(bl,d_bl,10) )
  342. status_change_end(bl,SC__SHADOWFORM,INVALID_TIMER);
  343. }
  344. if (sc->data[SC_PROPERTYWALK]
  345. && sc->data[SC_PROPERTYWALK]->val3 < skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2)
  346. && map->find_skill_unit_oncell(bl,bl->x,bl->y,SO_ELECTRICWALK,NULL,0) == NULL
  347. && map->find_skill_unit_oncell(bl,bl->x,bl->y,SO_FIREWALK,NULL,0) == NULL
  348. && skill->unitsetting(bl,sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2,x0, y0,0)
  349. ) {
  350. sc->data[SC_PROPERTYWALK]->val3++;
  351. }
  352. }
  353. /* Guild Aura Moving */
  354. if (sd != NULL && sd->state.gmaster_flag) {
  355. if (sc->data[SC_LEADERSHIP])
  356. skill->unit_move_unit_group(skill->id2group(sc->data[SC_LEADERSHIP]->val4), bl->m, x1-x0, y1-y0);
  357. if (sc->data[SC_GLORYWOUNDS])
  358. skill->unit_move_unit_group(skill->id2group(sc->data[SC_GLORYWOUNDS]->val4), bl->m, x1-x0, y1-y0);
  359. if (sc->data[SC_SOULCOLD])
  360. skill->unit_move_unit_group(skill->id2group(sc->data[SC_SOULCOLD]->val4), bl->m, x1-x0, y1-y0);
  361. if (sc->data[SC_HAWKEYES])
  362. skill->unit_move_unit_group(skill->id2group(sc->data[SC_HAWKEYES]->val4), bl->m, x1-x0, y1-y0);
  363. }
  364. }
  365. } else if (bl->type == BL_NPC) {
  366. npc->setcells(BL_UCAST(BL_NPC, bl));
  367. }
  368. return 0;
  369. }
  370. /*==========================================
  371. * Counts specified number of objects on given cell.
  372. * flag:
  373. * 0x1 - only count standing units
  374. * 0x2 - don't count invinsible units
  375. * TODO: merge with bl_getall_area
  376. *------------------------------------------*/
  377. int map_count_oncell(int16 m, int16 x, int16 y, int type, int flag) {
  378. int bx,by;
  379. struct block_list *bl;
  380. int count = 0;
  381. if (x < 0 || y < 0 || (x >= map->list[m].xs) || (y >= map->list[m].ys))
  382. return 0;
  383. bx = x/BLOCK_SIZE;
  384. by = y/BLOCK_SIZE;
  385. if (type&~BL_MOB) {
  386. for (bl = map->list[m].block[bx+by*map->list[m].bxs]; bl != NULL; bl = bl->next) {
  387. if (bl->x == x && bl->y == y && bl->type&type) {
  388. if (flag&0x2) {
  389. struct status_change *sc = status->get_sc(bl);
  390. if (sc && (sc->option&OPTION_INVISIBLE))
  391. continue;
  392. }
  393. if (flag&0x1) {
  394. struct unit_data *ud = unit->bl2ud(bl);
  395. if (ud && ud->walktimer != INVALID_TIMER)
  396. continue;
  397. }
  398. count++;
  399. }
  400. }
  401. }
  402. if (type&BL_MOB) {
  403. for (bl = map->list[m].block_mob[bx+by*map->list[m].bxs]; bl != NULL; bl = bl->next) {
  404. if (bl->x == x && bl->y == y) {
  405. if (flag&0x2) {
  406. struct status_change *sc = status->get_sc(bl);
  407. if (sc && (sc->option&OPTION_INVISIBLE))
  408. continue;
  409. }
  410. if (flag&0x1) {
  411. struct unit_data *ud = unit->bl2ud(bl);
  412. if (ud && ud->walktimer != INVALID_TIMER)
  413. continue;
  414. }
  415. count++;
  416. }
  417. }
  418. }
  419. return count;
  420. }
  421. /*
  422. * Looks for a skill unit on a given cell
  423. * flag&1: runs battle_check_target check based on unit->group->target_flag
  424. */
  425. struct skill_unit* map_find_skill_unit_oncell(struct block_list* target,int16 x,int16 y,uint16 skill_id,struct skill_unit* out_unit, int flag) {
  426. int16 m,bx,by;
  427. struct block_list *bl;
  428. struct skill_unit *su;
  429. nullpo_retr(NULL, target);
  430. m = target->m;
  431. if (x < 0 || y < 0 || (x >= map->list[m].xs) || (y >= map->list[m].ys))
  432. return NULL;
  433. bx = x/BLOCK_SIZE;
  434. by = y/BLOCK_SIZE;
  435. for( bl = map->list[m].block[bx+by*map->list[m].bxs] ; bl != NULL ; bl = bl->next ) {
  436. if (bl->x != x || bl->y != y || bl->type != BL_SKILL)
  437. continue;
  438. su = BL_UCAST(BL_SKILL, bl);
  439. if( su == out_unit || !su->alive || !su->group || su->group->skill_id != skill_id )
  440. continue;
  441. if( !(flag&1) || battle->check_target(&su->bl,target,su->group->target_flag) > 0 )
  442. return su;
  443. }
  444. return NULL;
  445. }
  446. /** @name Functions for block_list search and manipulation
  447. */
  448. /* @{ */
  449. /**
  450. * Applies func to every block_list in bl_list starting with bl_list[blockcount].
  451. * Sets bl_list_count back to blockcount.
  452. * Returns the sum of values returned by func.
  453. * @param func Function to be applied
  454. * @param blockcount Index of first relevant entry in bl_list
  455. * @param max Maximum sum of values returned by func (usually max number of func calls)
  456. * @param args Extra arguments for func
  457. * @return Sum of the values returned by func
  458. */
  459. static int bl_vforeach(int (*func)(struct block_list*, va_list), int blockcount, int max, va_list args) {
  460. int i;
  461. int returnCount = 0;
  462. map->freeblock_lock();
  463. for (i = blockcount; i < map->bl_list_count && returnCount < max; i++) {
  464. if (map->bl_list[i]->prev) { //func() may delete this bl_list[] slot, checking for prev ensures it wasn't queued for deletion.
  465. va_list argscopy;
  466. va_copy(argscopy, args);
  467. returnCount += func(map->bl_list[i], argscopy);
  468. va_end(argscopy);
  469. }
  470. }
  471. map->freeblock_unlock();
  472. map->bl_list_count = blockcount;
  473. return returnCount;
  474. }
  475. /**
  476. * Applies func to every block_list object of bl_type type on map m.
  477. * Returns the sum of values returned by func.
  478. * @param func Function to be applied
  479. * @param m Map id
  480. * @param type enum bl_type
  481. * @param args Extra arguments for func
  482. * @return Sum of the values returned by func
  483. */
  484. static int map_vforeachinmap(int (*func)(struct block_list*, va_list), int16 m, int type, va_list args) {
  485. int i;
  486. int returnCount = 0;
  487. int bsize;
  488. va_list argscopy;
  489. struct block_list *bl;
  490. int blockcount = map->bl_list_count;
  491. if (m < 0)
  492. return 0;
  493. bsize = map->list[m].bxs * map->list[m].bys;
  494. for (i = 0; i < bsize; i++) {
  495. if (type&~BL_MOB) {
  496. for (bl = map->list[m].block[i]; bl != NULL; bl = bl->next) {
  497. if (bl->type&type) {
  498. if( map->bl_list_count >= map->bl_list_size )
  499. map_bl_list_expand();
  500. map->bl_list[map->bl_list_count++] = bl;
  501. }
  502. }
  503. }
  504. if (type&BL_MOB) {
  505. for (bl = map->list[m].block_mob[i]; bl != NULL; bl = bl->next) {
  506. if( map->bl_list_count >= map->bl_list_size )
  507. map_bl_list_expand();
  508. map->bl_list[map->bl_list_count++] = bl;
  509. }
  510. }
  511. }
  512. va_copy(argscopy, args);
  513. returnCount = bl_vforeach(func, blockcount, INT_MAX, argscopy);
  514. va_end(argscopy);
  515. return returnCount;
  516. }
  517. /**
  518. * Applies func to every block_list object of bl_type type on map m.
  519. * Returns the sum of values returned by func.
  520. * @see map_vforeachinmap
  521. * @param func Function to be applied
  522. * @param m Map id
  523. * @param type enum bl_type
  524. * @param ... Extra arguments for func
  525. * @return Sum of the values returned by func
  526. */
  527. int map_foreachinmap(int (*func)(struct block_list*, va_list), int16 m, int type, ...) {
  528. int returnCount;
  529. va_list ap;
  530. va_start(ap, type);
  531. returnCount = map->vforeachinmap(func, m, type, ap);
  532. va_end(ap);
  533. return returnCount;
  534. }
  535. /**
  536. * Applies func to every block_list object of bl_type type on all maps
  537. * of instance instance_id.
  538. * Returns the sum of values returned by func.
  539. * @see map_vforeachinmap.
  540. * @param func Function to be applied
  541. * @param m Map id
  542. * @param type enum bl_type
  543. * @param ap Extra arguments for func
  544. * @return Sum of the values returned by func
  545. */
  546. int map_vforeachininstance(int (*func)(struct block_list*, va_list), int16 instance_id, int type, va_list ap) {
  547. int i;
  548. int returnCount = 0;
  549. for (i = 0; i < instance->list[instance_id].num_map; i++) {
  550. int m = instance->list[instance_id].map[i];
  551. va_list apcopy;
  552. va_copy(apcopy, ap);
  553. returnCount += map->vforeachinmap(func, m, type, apcopy);
  554. va_end(apcopy);
  555. }
  556. return returnCount;
  557. }
  558. /**
  559. * Applies func to every block_list object of bl_type type on all maps
  560. * of instance instance_id.
  561. * Returns the sum of values returned by func.
  562. * @see map_vforeachininstance.
  563. * @param func Function to be applied
  564. * @param m Map id
  565. * @param type enum bl_type
  566. * @param ... Extra arguments for func
  567. * @return Sum of the values returned by func
  568. */
  569. int map_foreachininstance(int (*func)(struct block_list*, va_list), int16 instance_id, int type, ...) {
  570. int returnCount;
  571. va_list ap;
  572. va_start(ap, type);
  573. returnCount = map->vforeachininstance(func, instance_id, type, ap);
  574. va_end(ap);
  575. return returnCount;
  576. }
  577. /**
  578. * Retrieves all map objects in area that are matched by the type
  579. * and func. Appends them at the end of global bl_list array.
  580. * @param type Matching enum bl_type
  581. * @param m Map
  582. * @param func Matching function
  583. * @param ... Extra arguments for func
  584. * @return Number of found objects
  585. */
  586. static int bl_getall_area(int type, int m, int x0, int y0, int x1, int y1, int (*func)(struct block_list*, va_list), ...) {
  587. va_list args;
  588. int bx, by;
  589. struct block_list *bl;
  590. int found = 0;
  591. if (m < 0)
  592. return 0;
  593. if (x1 < x0) swap(x0, x1);
  594. if (y1 < y0) swap(y0, y1);
  595. // Limit search area to map size
  596. x0 = max(x0, 0);
  597. y0 = max(y0, 0);
  598. x1 = min(x1, map->list[m].xs - 1);
  599. y1 = min(y1, map->list[m].ys - 1);
  600. for (by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++) {
  601. for (bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++) {
  602. if (type&~BL_MOB) {
  603. for (bl = map->list[m].block[bx + by * map->list[m].bxs]; bl != NULL; bl = bl->next) {
  604. if (bl->type&type && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1) {
  605. if( map->bl_list_count >= map->bl_list_size )
  606. map_bl_list_expand();
  607. if (func) {
  608. va_start(args, func);
  609. if (func(bl, args)) {
  610. map->bl_list[map->bl_list_count++] = bl;
  611. found++;
  612. }
  613. va_end(args);
  614. } else {
  615. map->bl_list[map->bl_list_count++] = bl;
  616. found++;
  617. }
  618. }
  619. }
  620. }
  621. if (type&BL_MOB) { // TODO: fix this code duplication
  622. for (bl = map->list[m].block_mob[bx + by * map->list[m].bxs]; bl != NULL; bl = bl->next) {
  623. if (bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1) {
  624. if( map->bl_list_count >= map->bl_list_size )
  625. map_bl_list_expand();
  626. if (func) {
  627. va_start(args, func);
  628. if (func(bl, args)) {
  629. map->bl_list[map->bl_list_count++] = bl;
  630. found++;
  631. }
  632. va_end(args);
  633. } else {
  634. map->bl_list[map->bl_list_count++] = bl;
  635. found++;
  636. }
  637. }
  638. }
  639. }
  640. }
  641. }
  642. return found;
  643. }
  644. /**
  645. * Checks if bl is within range cells from center.
  646. * If CIRCULAR AREA is not used always returns 1, since
  647. * preliminary range selection is already done in bl_getall_area.
  648. * @return 1 if matches, 0 otherwise
  649. */
  650. static int bl_vgetall_inrange(struct block_list *bl, va_list args)
  651. {
  652. #ifdef CIRCULAR_AREA
  653. struct block_list *center = va_arg(args, struct block_list*);
  654. int range = va_arg(args, int);
  655. if (!check_distance_bl(center, bl, range))
  656. return 0;
  657. #endif
  658. return 1;
  659. }
  660. /**
  661. * Applies func to every block_list object of bl_type type within range cells from center.
  662. * Area is rectangular, unless CIRCULAR_AREA is defined.
  663. * Returns the sum of values returned by func.
  664. * @param func Function to be applied
  665. * @param center Center of the selection area
  666. * @param range Range in cells from center
  667. * @param type enum bl_type
  668. * @param ap Extra arguments for func
  669. * @return Sum of the values returned by func
  670. */
  671. int map_vforeachinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, va_list ap) {
  672. int returnCount = 0;
  673. int blockcount = map->bl_list_count;
  674. va_list apcopy;
  675. if (range < 0) range *= -1;
  676. bl_getall_area(type, center->m, center->x - range, center->y - range, center->x + range, center->y + range, bl_vgetall_inrange, center, range);
  677. va_copy(apcopy, ap);
  678. returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy);
  679. va_end(apcopy);
  680. return returnCount;
  681. }
  682. /**
  683. * Applies func to every block_list object of bl_type type within range cells from center.
  684. * Area is rectangular, unless CIRCULAR_AREA is defined.
  685. * Returns the sum of values returned by func.
  686. * @see map_vforeachinrange
  687. * @param func Function to be applied
  688. * @param center Center of the selection area
  689. * @param range Range in cells from center
  690. * @param type enum bl_type
  691. * @param ... Extra arguments for func
  692. * @return Sum of the values returned by func
  693. */
  694. int map_foreachinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, ...) {
  695. int returnCount;
  696. va_list ap;
  697. va_start(ap, type);
  698. returnCount = map->vforeachinrange(func, center, range, type, ap);
  699. va_end(ap);
  700. return returnCount;
  701. }
  702. /**
  703. * Applies func to some block_list objects of bl_type type within range cells from center.
  704. * Limit is set by count parameter.
  705. * Area is rectangular, unless CIRCULAR_AREA is defined.
  706. * Returns the sum of values returned by func.
  707. * @param func Function to be applied
  708. * @param center Center of the selection area
  709. * @param range Range in cells from center
  710. * @param count Maximum sum of values returned by func (usually max number of func calls)
  711. * @param type enum bl_type
  712. * @param ap Extra arguments for func
  713. * @return Sum of the values returned by func
  714. */
  715. int map_vforcountinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int count, int type, va_list ap) {
  716. int returnCount = 0;
  717. int blockcount = map->bl_list_count;
  718. va_list apcopy;
  719. if (range < 0) range *= -1;
  720. bl_getall_area(type, center->m, center->x - range, center->y - range, center->x + range, center->y + range, bl_vgetall_inrange, center, range);
  721. va_copy(apcopy, ap);
  722. returnCount = bl_vforeach(func, blockcount, count, apcopy);
  723. va_end(apcopy);
  724. return returnCount;
  725. }
  726. /**
  727. * Applies func to some block_list objects of bl_type type within range cells from center.
  728. * Limit is set by count parameter.
  729. * Area is rectangular, unless CIRCULAR_AREA is defined.
  730. * Returns the sum of values returned by func.
  731. * @see map_vforcountinrange
  732. * @param func Function to be applied
  733. * @param center Center of the selection area
  734. * @param range Range in cells from center
  735. * @param count Maximum sum of values returned by func (usually max number of func calls)
  736. * @param type enum bl_type
  737. * @param ... Extra arguments for func
  738. * @return Sum of the values returned by func
  739. */
  740. int map_forcountinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int count, int type, ...) {
  741. int returnCount;
  742. va_list ap;
  743. va_start(ap, type);
  744. returnCount = map->vforcountinrange(func, center, range, count, type, ap);
  745. va_end(ap);
  746. return returnCount;
  747. }
  748. /**
  749. * Checks if bl is within shooting range from center.
  750. * There must be a shootable path between bl and center.
  751. * Does not check for range if CIRCULAR AREA is not defined, since
  752. * preliminary range selection is already done in bl_getall_area.
  753. * @return 1 if matches, 0 otherwise
  754. */
  755. static int bl_vgetall_inshootrange(struct block_list *bl, va_list args)
  756. {
  757. struct block_list *center = va_arg(args, struct block_list*);
  758. #ifdef CIRCULAR_AREA
  759. int range = va_arg(args, int);
  760. nullpo_ret(center);
  761. nullpo_ret(bl);
  762. if (!check_distance_bl(center, bl, range))
  763. return 0;
  764. #endif
  765. if (!path->search_long(NULL, center, center->m, center->x, center->y, bl->x, bl->y, CELL_CHKWALL))
  766. return 0;
  767. return 1;
  768. }
  769. /**
  770. * Applies func to every block_list object of bl_type type within shootable range from center.
  771. * There must be a shootable path between bl and center.
  772. * Area is rectangular, unless CIRCULAR_AREA is defined.
  773. * Returns the sum of values returned by func.
  774. * @param func Function to be applied
  775. * @param center Center of the selection area
  776. * @param range Range in cells from center
  777. * @param type enum bl_type
  778. * @param ap Extra arguments for func
  779. * @return Sum of the values returned by func
  780. */
  781. int map_vforeachinshootrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, va_list ap) {
  782. int returnCount = 0;
  783. int blockcount = map->bl_list_count;
  784. va_list apcopy;
  785. if (range < 0) range *= -1;
  786. bl_getall_area(type, center->m, center->x - range, center->y - range, center->x + range, center->y + range, bl_vgetall_inshootrange, center, range);
  787. va_copy(apcopy, ap);
  788. returnCount = bl_vforeach(func, blockcount, INT_MAX, ap);
  789. va_end(apcopy);
  790. return returnCount;
  791. }
  792. /**
  793. * Applies func to every block_list object of bl_type type within shootable range from center.
  794. * There must be a shootable path between bl and center.
  795. * Area is rectangular, unless CIRCULAR_AREA is defined.
  796. * Returns the sum of values returned by func.
  797. * @param func Function to be applied
  798. * @param center Center of the selection area
  799. * @param range Range in cells from center
  800. * @param type enum bl_type
  801. * @param ... Extra arguments for func
  802. * @return Sum of the values returned by func
  803. */
  804. int map_foreachinshootrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, ...) {
  805. int returnCount;
  806. va_list ap;
  807. va_start(ap, type);
  808. returnCount = map->vforeachinshootrange(func, center, range, type, ap);
  809. va_end(ap);
  810. return returnCount;
  811. }
  812. /**
  813. * Applies func to every block_list object of bl_type type in
  814. * rectangular area (x0,y0)~(x1,y1) on map m.
  815. * Returns the sum of values returned by func.
  816. * @param func Function to be applied
  817. * @param m Map id
  818. * @param x0 Starting X-coordinate
  819. * @param y0 Starting Y-coordinate
  820. * @param x1 Ending X-coordinate
  821. * @param y1 Ending Y-coordinate
  822. * @param type enum bl_type
  823. * @param ap Extra arguments for func
  824. * @return Sum of the values returned by func
  825. */
  826. int map_vforeachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, va_list ap) {
  827. int returnCount = 0;
  828. int blockcount = map->bl_list_count;
  829. va_list apcopy;
  830. bl_getall_area(type, m, x0, y0, x1, y1, NULL);
  831. va_copy(apcopy, ap);
  832. returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy);
  833. va_end(apcopy);
  834. return returnCount;
  835. }
  836. /**
  837. * Applies func to every block_list object of bl_type type in
  838. * rectangular area (x0,y0)~(x1,y1) on map m.
  839. * Returns the sum of values returned by func.
  840. * @see map_vforeachinarea
  841. * @param func Function to be applied
  842. * @param m Map id
  843. * @param x0 Starting X-coordinate
  844. * @param y0 Starting Y-coordinate
  845. * @param x1 Ending X-coordinate
  846. * @param y1 Ending Y-coordinate
  847. * @param type enum bl_type
  848. * @param ... Extra arguments for func
  849. * @return Sum of the values returned by func
  850. */
  851. int map_foreachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...) {
  852. int returnCount;
  853. va_list ap;
  854. va_start(ap, type);
  855. returnCount = map->vforeachinarea(func, m, x0, y0, x1, y1, type, ap);
  856. va_end(ap);
  857. return returnCount;
  858. }
  859. /**
  860. * Applies func to some block_list objects of bl_type type in
  861. * rectangular area (x0,y0)~(x1,y1) on map m.
  862. * Limit is set by @count parameter.
  863. * Returns the sum of values returned by func.
  864. * @param func Function to be applied
  865. * @param m Map id
  866. * @param x0 Starting X-coordinate
  867. * @param y0 Starting Y-coordinate
  868. * @param x1 Ending X-coordinate
  869. * @param y1 Ending Y-coordinate
  870. * @param count Maximum sum of values returned by func (usually max number of func calls)
  871. * @param type enum bl_type
  872. * @param ap Extra arguments for func
  873. * @return Sum of the values returned by func
  874. */
  875. int map_vforcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, va_list ap) {
  876. int returnCount = 0;
  877. int blockcount = map->bl_list_count;
  878. va_list apcopy;
  879. bl_getall_area(type, m, x0, y0, x1, y1, NULL);
  880. va_copy(apcopy, ap);
  881. returnCount = bl_vforeach(func, blockcount, count, apcopy);
  882. va_end(apcopy);
  883. return returnCount;
  884. }
  885. /**
  886. * Applies func to some block_list objects of bl_type type in
  887. * rectangular area (x0,y0)~(x1,y1) on map m.
  888. * Limit is set by @count parameter.
  889. * Returns the sum of values returned by func.
  890. * @see map_vforcountinarea
  891. * @param func Function to be applied
  892. * @param m Map id
  893. * @param x0 Starting X-coordinate
  894. * @param y0 Starting Y-coordinate
  895. * @param x1 Ending X-coordinate
  896. * @param y1 Ending Y-coordinate
  897. * @param count Maximum sum of values returned by func (usually max number of func calls)
  898. * @param type enum bl_type
  899. * @param ... Extra arguments for func
  900. * @return Sum of the values returned by func
  901. */
  902. int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...) {
  903. int returnCount;
  904. va_list ap;
  905. va_start(ap, type);
  906. returnCount = map->vforcountinarea(func, m, x0, y0, x1, y1, count, type, ap);
  907. va_end(ap);
  908. return returnCount;
  909. }
  910. /**
  911. * Checks if bl is inside area that was in range cells from the center
  912. * before it was moved by (dx,dy) cells, but it is not in range cells
  913. * from center after movement is completed.
  914. * In other words, checks if bl is inside area that is no longer covered
  915. * by center's range.
  916. * Preliminary range selection is already done in bl_getall_area.
  917. * @return 1 if matches, 0 otherwise
  918. */
  919. static int bl_vgetall_inmovearea(struct block_list *bl, va_list args)
  920. {
  921. int dx = va_arg(args, int);
  922. int dy = va_arg(args, int);
  923. struct block_list *center = va_arg(args, struct block_list*);
  924. int range = va_arg(args, int);
  925. nullpo_ret(bl);
  926. nullpo_ret(center);
  927. if ((dx > 0 && bl->x < center->x - range + dx) ||
  928. (dx < 0 && bl->x > center->x + range + dx) ||
  929. (dy > 0 && bl->y < center->y - range + dy) ||
  930. (dy < 0 && bl->y > center->y + range + dy))
  931. return 1;
  932. return 0;
  933. }
  934. /**
  935. * Applies func to every block_list object of bl_type type in
  936. * area that was covered by range cells from center, but is no
  937. * longer after center is moved by (dx,dy) cells (i.e. area that
  938. * center has lost sight of).
  939. * If used after center has reached its destination and with
  940. * opposed movement vector (-dx,-dy), selection corresponds
  941. * to new area in center's view).
  942. * Uses rectangular area.
  943. * Returns the sum of values returned by func.
  944. * @param func Function to be applied
  945. * @param center Center of the selection area
  946. * @param range Range in cells from center
  947. * @param dx Center's movement on X-axis
  948. * @param dy Center's movement on Y-axis
  949. * @param type enum bl_type
  950. * @param ap Extra arguments for func
  951. * @return Sum of the values returned by func
  952. */
  953. int map_vforeachinmovearea(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, va_list ap) {
  954. int returnCount = 0;
  955. int blockcount = map->bl_list_count;
  956. int m, x0, x1, y0, y1;
  957. va_list apcopy;
  958. if (!range) return 0;
  959. if (!dx && !dy) return 0; // No movement.
  960. if (range < 0) range *= -1;
  961. m = center->m;
  962. x0 = center->x - range;
  963. x1 = center->x + range;
  964. y0 = center->y - range;
  965. y1 = center->y + range;
  966. if (dx == 0 || dy == 0) { // Movement along one axis only.
  967. if (dx == 0) {
  968. if (dy < 0) { y0 = y1 + dy + 1; } // Moving south
  969. else { y1 = y0 + dy - 1; } // North
  970. } else { //dy == 0
  971. if (dx < 0) { x0 = x1 + dx + 1; } // West
  972. else { x1 = x0 + dx - 1; } // East
  973. }
  974. bl_getall_area(type, m, x0, y0, x1, y1, NULL);
  975. }
  976. else { // Diagonal movement
  977. bl_getall_area(type, m, x0, y0, x1, y1, bl_vgetall_inmovearea, dx, dy, center, range);
  978. }
  979. va_copy(apcopy, ap);
  980. returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy);
  981. va_end(apcopy);
  982. return returnCount;
  983. }
  984. /**
  985. * Applies func to every block_list object of bl_type type in
  986. * area that was covered by range cells from center, but is no
  987. * longer after center is moved by (dx,dy) cells (i.e. area that
  988. * center has lost sight of).
  989. * If used after center has reached its destination and with
  990. * opposed movement vector (-dx,-dy), selection corresponds
  991. * to new area in center's view).
  992. * Uses rectangular area.
  993. * Returns the sum of values returned by func.
  994. * @see map_vforeachinmovearea
  995. * @param func Function to be applied
  996. * @param center Center of the selection area
  997. * @param range Range in cells from center
  998. * @param dx Center's movement on X-axis
  999. * @param dy Center's movement on Y-axis
  1000. * @param type enum bl_type
  1001. * @param ... Extra arguments for func
  1002. * @return Sum of the values returned by func
  1003. */
  1004. int map_foreachinmovearea(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...) {
  1005. int returnCount;
  1006. va_list ap;
  1007. va_start(ap, type);
  1008. returnCount = map->vforeachinmovearea(func, center, range, dx, dy, type, ap);
  1009. va_end(ap);
  1010. return returnCount;
  1011. }
  1012. /**
  1013. * Applies func to every block_list object of bl_type type in
  1014. * cell (x,y) on map m.
  1015. * Returns the sum of values returned by func.
  1016. * @param func Function to be applied
  1017. * @param m Map id
  1018. * @param x Target cell X-coordinate
  1019. * @param y Target cell Y-coordinate
  1020. * @param type enum bl_type
  1021. * @param ap Extra arguments for func
  1022. * @return Sum of the values returned by func
  1023. */
  1024. int map_vforeachincell(int (*func)(struct block_list*, va_list), int16 m, int16 x, int16 y, int type, va_list ap) {
  1025. int returnCount = 0;
  1026. int blockcount = map->bl_list_count;
  1027. va_list apcopy;
  1028. bl_getall_area(type, m, x, y, x, y, NULL);
  1029. va_copy(apcopy, ap);
  1030. returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy);
  1031. va_end(apcopy);
  1032. return returnCount;
  1033. }
  1034. /**
  1035. * Applies func to every block_list object of bl_type type in
  1036. * cell (x,y) on map m.
  1037. * Returns the sum of values returned by func.
  1038. * @param func Function to be applied
  1039. * @param m Map id
  1040. * @param x Target cell X-coordinate
  1041. * @param y Target cell Y-coordinate
  1042. * @param type enum bl_type
  1043. * @param ... Extra arguments for func
  1044. * @return Sum of the values returned by func
  1045. */
  1046. int map_foreachincell(int (*func)(struct block_list*, va_list), int16 m, int16 x, int16 y, int type, ...) {
  1047. int returnCount;
  1048. va_list ap;
  1049. va_start(ap, type);
  1050. returnCount = map->vforeachincell(func, m, x, y, type, ap);
  1051. va_end(ap);
  1052. return returnCount;
  1053. }
  1054. /**
  1055. * Helper function for map_foreachinpath()
  1056. * Checks if shortest distance from bl to path
  1057. * between (x0,y0) and (x1,y1) is shorter than range.
  1058. * @see map_foreachinpath
  1059. */
  1060. static int bl_vgetall_inpath(struct block_list *bl, va_list args)
  1061. {
  1062. int m = va_arg(args, int);
  1063. int x0 = va_arg(args, int);
  1064. int y0 = va_arg(args, int);
  1065. int x1 = va_arg(args, int);
  1066. int y1 = va_arg(args, int);
  1067. int range = va_arg(args, int);
  1068. int len_limit = va_arg(args, int);
  1069. int magnitude2 = va_arg(args, int);
  1070. int xi;
  1071. int yi;
  1072. int xu, yu;
  1073. int k;
  1074. nullpo_ret(bl);
  1075. xi = bl->x;
  1076. yi = bl->y;
  1077. k = ( xi - x0 ) * ( x1 - x0 ) + ( yi - y0 ) * ( y1 - y0 );
  1078. if ( k < 0 || k > len_limit ) //Since more skills use this, check for ending point as well.
  1079. return 0;
  1080. if ( k > magnitude2 && !path->search_long(NULL, NULL, m, x0, y0, xi, yi, CELL_CHKWALL) )
  1081. return 0; //Targets beyond the initial ending point need the wall check.
  1082. //All these shifts are to increase the precision of the intersection point and distance considering how it's
  1083. //int math.
  1084. k = ( k << 4 ) / magnitude2; //k will be between 1~16 instead of 0~1
  1085. xi <<= 4;
  1086. yi <<= 4;
  1087. xu = ( x0 << 4 ) + k * ( x1 - x0 );
  1088. yu = ( y0 << 4 ) + k * ( y1 - y0 );
  1089. //Avoid needless calculations by not getting the sqrt right away.
  1090. #define MAGNITUDE2(x0, y0, x1, y1) ( ( ( x1 ) - ( x0 ) ) * ( ( x1 ) - ( x0 ) ) + ( ( y1 ) - ( y0 ) ) * ( ( y1 ) - ( y0 ) ) )
  1091. k = MAGNITUDE2(xi, yi, xu, yu);
  1092. //If all dot coordinates were <<4 the square of the magnitude is <<8
  1093. if ( k > range )
  1094. return 0;
  1095. return 1;
  1096. }
  1097. /**
  1098. * Applies func to every block_list object of bl_type type in
  1099. * path on a line between (x0,y0) and (x1,y1) on map m.
  1100. * Path starts at (x0,y0) and is \a length cells long and \a range cells wide.
  1101. * Objects beyond the initial (x1,y1) ending point are checked
  1102. * for walls in the path.
  1103. * Returns the sum of values returned by func.
  1104. * @param func Function to be applied
  1105. * @param m Map id
  1106. * @param x Target cell X-coordinate
  1107. * @param y Target cell Y-coordinate
  1108. * @param type enum bl_type
  1109. * @param ap Extra arguments for func
  1110. * @return Sum of the values returned by func
  1111. */
  1112. int map_vforeachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, va_list ap) {
  1113. // [Skotlex]
  1114. // check for all targets in the square that
  1115. // contains the initial and final positions (area range increased to match the
  1116. // radius given), then for each object to test, calculate the distance to the
  1117. // path and include it if the range fits and the target is in the line (0<k<1,
  1118. // as they call it).
  1119. // The implementation I took as reference is found at
  1120. // http://web.archive.org/web/20050720125314/http://astronomy.swin.edu.au/~pbourke/geometry/pointline/
  1121. // http://paulbourke.net/geometry/pointlineplane/
  1122. // I won't use doubles/floats, but pure int math for
  1123. // speed purposes. The range considered is always the same no matter how
  1124. // close/far the target is because that's how SharpShooting works currently in
  1125. // kRO
  1126. int returnCount = 0;
  1127. int blockcount = map->bl_list_count;
  1128. va_list apcopy;
  1129. //method specific variables
  1130. int magnitude2, len_limit; //The square of the magnitude
  1131. int mx0 = x0, mx1 = x1, my0 = y0, my1 = y1;
  1132. len_limit = magnitude2 = MAGNITUDE2(x0, y0, x1, y1);
  1133. if (magnitude2 < 1) //Same begin and ending point, can't trace path.
  1134. return 0;
  1135. if (length) { //Adjust final position to fit in the given area.
  1136. //TODO: Find an alternate method which does not requires a square root calculation.
  1137. int k = (int)sqrt((float)magnitude2);
  1138. mx1 = x0 + (x1 - x0) * length / k;
  1139. my1 = y0 + (y1 - y0) * length / k;
  1140. len_limit = MAGNITUDE2(x0, y0, mx1, my1);
  1141. }
  1142. //Expand target area to cover range.
  1143. if (mx0 > mx1) {
  1144. mx0 += range;
  1145. mx1 -= range;
  1146. } else {
  1147. mx0 -= range;
  1148. mx1 += range;
  1149. }
  1150. if (my0 > my1) {
  1151. my0 += range;
  1152. my1 -= range;
  1153. } else {
  1154. my0 -= range;
  1155. my1 += range;
  1156. }
  1157. range *= range << 8; //Values are shifted later on for higher precision using int math.
  1158. bl_getall_area(type, m, mx0, my0, mx1, my1, bl_vgetall_inpath, m, x0, y0, x1, y1, range, len_limit, magnitude2);
  1159. va_copy(apcopy, ap);
  1160. returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy);
  1161. va_end(apcopy);
  1162. return returnCount;
  1163. }
  1164. #undef MAGNITUDE2
  1165. /**
  1166. * Applies func to every block_list object of bl_type type in
  1167. * path on a line between (x0,y0) and (x1,y1) on map m.
  1168. * Path starts at (x0,y0) and is \a length cells long and \a range cells wide.
  1169. * Objects beyond the initial (x1,y1) ending point are checked
  1170. * for walls in the path.
  1171. * Returns the sum of values returned by func.
  1172. * @see map_vforeachinpath
  1173. * @param func Function to be applied
  1174. * @param m Map id
  1175. * @param x Target cell X-coordinate
  1176. * @param y Target cell Y-coordinate
  1177. * @param type enum bl_type
  1178. * @param ... Extra arguments for func
  1179. * @return Sum of the values returned by func
  1180. */
  1181. int map_foreachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, ...) {
  1182. int returnCount;
  1183. va_list ap;
  1184. va_start(ap, type);
  1185. returnCount = map->vforeachinpath(func, m, x0, y0, x1, y1, range, length, type, ap);
  1186. va_end(ap);
  1187. return returnCount;
  1188. }
  1189. /** @} */
  1190. /// Generates a new flooritem object id from the interval [MIN_FLOORITEM, MAX_FLOORITEM).
  1191. /// Used for floor items, skill units and chatroom objects.
  1192. /// @return The new object id
  1193. int map_get_new_object_id(void)
  1194. {
  1195. static int last_object_id = MIN_FLOORITEM - 1;
  1196. int i;
  1197. // find a free id
  1198. i = last_object_id + 1;
  1199. while( i != last_object_id ) {
  1200. if( i == MAX_FLOORITEM )
  1201. i = MIN_FLOORITEM;
  1202. if( !idb_exists(map->id_db, i) )
  1203. break;
  1204. ++i;
  1205. }
  1206. if( i == last_object_id ) {
  1207. ShowError("map_addobject: no free object id!\n");
  1208. return 0;
  1209. }
  1210. // update cursor
  1211. last_object_id = i;
  1212. return i;
  1213. }
  1214. /*==========================================
  1215. * Timered function to clear the floor (remove remaining item)
  1216. * Called each flooritem_lifetime ms
  1217. *------------------------------------------*/
  1218. int map_clearflooritem_timer(int tid, int64 tick, int id, intptr_t data)
  1219. {
  1220. struct block_list *bl = idb_get(map->id_db, id);
  1221. struct flooritem_data *fitem = BL_CAST(BL_ITEM, bl);
  1222. if (fitem == NULL || fitem->cleartimer != tid) {
  1223. ShowError("map_clearflooritem_timer : error\n");
  1224. return 1;
  1225. }
  1226. if (pet->search_petDB_index(fitem->item_data.nameid, PET_EGG) >= 0)
  1227. intif->delete_petdata(MakeDWord(fitem->item_data.card[1], fitem->item_data.card[2]));
  1228. clif->clearflooritem(fitem, 0);
  1229. map->deliddb(&fitem->bl);
  1230. map->delblock(&fitem->bl);
  1231. map->freeblock(&fitem->bl);
  1232. return 0;
  1233. }
  1234. /*
  1235. * clears a single bl item out of the bazooonga.
  1236. */
  1237. void map_clearflooritem(struct block_list *bl)
  1238. {
  1239. struct flooritem_data *fitem = BL_CAST(BL_ITEM, bl);
  1240. nullpo_retv(fitem);
  1241. nullpo_retv(fitem);
  1242. if( fitem->cleartimer != INVALID_TIMER )
  1243. timer->delete(fitem->cleartimer,map->clearflooritem_timer);
  1244. clif->clearflooritem(fitem, 0);
  1245. map->deliddb(&fitem->bl);
  1246. map->delblock(&fitem->bl);
  1247. map->freeblock(&fitem->bl);
  1248. }
  1249. /*==========================================
  1250. * (m,x,y) locates a random available free cell around the given coordinates
  1251. * to place an BL_ITEM object. Scan area is 9x9, returns 1 on success.
  1252. * x and y are modified with the target cell when successful.
  1253. *------------------------------------------*/
  1254. int map_searchrandfreecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int stack) {
  1255. int free_cell,i,j;
  1256. int free_cells[9][2];
  1257. nullpo_ret(x);
  1258. nullpo_ret(y);
  1259. for(free_cell=0,i=-1;i<=1;i++){
  1260. if(i+*y<0 || i+*y>=map->list[m].ys)
  1261. continue;
  1262. for(j=-1;j<=1;j++){
  1263. if(j+*x<0 || j+*x>=map->list[m].xs)
  1264. continue;
  1265. if (map->getcell(m, bl, j + *x, i + *y, CELL_CHKNOPASS) && !map->getcell(m, bl, j + *x, i + *y, CELL_CHKICEWALL))
  1266. continue;
  1267. //Avoid item stacking to prevent against exploits. [Skotlex]
  1268. if(stack && map->count_oncell(m,j+*x,i+*y, BL_ITEM, 0) > stack)
  1269. continue;
  1270. free_cells[free_cell][0] = j+*x;
  1271. free_cells[free_cell++][1] = i+*y;
  1272. }
  1273. }
  1274. if(free_cell==0)
  1275. return 0;
  1276. free_cell = rnd()%free_cell;
  1277. *x = free_cells[free_cell][0];
  1278. *y = free_cells[free_cell][1];
  1279. return 1;
  1280. }
  1281. int map_count_sub(struct block_list *bl,va_list ap) {
  1282. return 1;
  1283. }
  1284. /*==========================================
  1285. * Locates a random spare cell around the object given, using range as max
  1286. * distance from that spot. Used for warping functions. Use range < 0 for
  1287. * whole map range.
  1288. * Returns 1 on success. when it fails and src is available, x/y are set to src's
  1289. * src can be null as long as flag&1
  1290. * when ~flag&1, m is not needed.
  1291. * Flag values:
  1292. * &1 = random cell must be around given m,x,y, not around src
  1293. * &2 = the target should be able to walk to the target tile.
  1294. * &4 = there shouldn't be any players around the target tile (use the no_spawn_on_player setting)
  1295. *------------------------------------------*/
  1296. int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int16 rx, int16 ry, int flag)
  1297. {
  1298. int tries, spawn=0;
  1299. int bx, by;
  1300. int rx2 = 2*rx+1;
  1301. int ry2 = 2*ry+1;
  1302. nullpo_ret(src);
  1303. nullpo_ret(x);
  1304. nullpo_ret(y);
  1305. if( !src && (!(flag&1) || flag&2) )
  1306. {
  1307. ShowDebug("map_search_freecell: Incorrect usage! When src is NULL, flag has to be &1 and can't have &2\n");
  1308. return 0;
  1309. }
  1310. if (flag&1) {
  1311. bx = *x;
  1312. by = *y;
  1313. } else {
  1314. bx = src->x;
  1315. by = src->y;
  1316. m = src->m;
  1317. }
  1318. if (!rx && !ry) {
  1319. //No range? Return the target cell then....
  1320. *x = bx;
  1321. *y = by;
  1322. return map->getcell(m, src, *x, *y, CELL_CHKREACH);
  1323. }
  1324. if (rx >= 0 && ry >= 0) {
  1325. tries = rx2*ry2;
  1326. if (tries > 100) tries = 100;
  1327. } else {
  1328. tries = map->list[m].xs*map->list[m].ys;
  1329. if (tries > 500) tries = 500;
  1330. }
  1331. while(tries--) {
  1332. *x = (rx >= 0)?(rnd()%rx2-rx+bx):(rnd()%(map->list[m].xs-2)+1);
  1333. *y = (ry >= 0)?(rnd()%ry2-ry+by):(rnd()%(map->list[m].ys-2)+1);
  1334. if (*x == bx && *y == by)
  1335. continue; //Avoid picking the same target tile.
  1336. if (map->getcell(m, src, *x, *y, CELL_CHKREACH)) {
  1337. if(flag&2 && !unit->can_reach_pos(src, *x, *y, 1))
  1338. continue;
  1339. if(flag&4) {
  1340. if (spawn >= 100) return 0; //Limit of retries reached.
  1341. if (spawn++ < battle_config.no_spawn_on_player
  1342. && map->foreachinarea(map->count_sub, m, *x-AREA_SIZE, *y-AREA_SIZE,
  1343. *x+AREA_SIZE, *y+AREA_SIZE, BL_PC)
  1344. )
  1345. continue;
  1346. }
  1347. return 1;
  1348. }
  1349. }
  1350. *x = bx;
  1351. *y = by;
  1352. return 0;
  1353. }
  1354. /*==========================================
  1355. * Locates the closest, walkable cell with no blocks of a certain type on it
  1356. * Returns true on success and sets x and y to cell found.
  1357. * Otherwise returns false and x and y are not changed.
  1358. * type: Types of block to count
  1359. * flag:
  1360. * 0x1 - only count standing units
  1361. *------------------------------------------*/
  1362. bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int type, int flag)
  1363. {
  1364. uint8 dir = 6;
  1365. int16 tx;
  1366. int16 ty;
  1367. int costrange = 10;
  1368. nullpo_ret(x);
  1369. nullpo_ret(y);
  1370. tx = *x;
  1371. ty = *y;
  1372. if(!map->count_oncell(m, tx, ty, type, flag))
  1373. return true; //Current cell is free
  1374. //Algorithm only works up to costrange of 34
  1375. while(costrange <= 34) {
  1376. short dx = dirx[dir];
  1377. short dy = diry[dir];
  1378. //Linear search
  1379. if(dir%2 == 0 && costrange%MOVE_COST == 0) {
  1380. tx = *x+dx*(costrange/MOVE_COST);
  1381. ty = *y+dy*(costrange/MOVE_COST);
  1382. if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) {
  1383. *x = tx;
  1384. *y = ty;
  1385. return true;
  1386. }
  1387. }
  1388. //Full diagonal search
  1389. else if(dir%2 == 1 && costrange%MOVE_DIAGONAL_COST == 0) {
  1390. tx = *x+dx*(costrange/MOVE_DIAGONAL_COST);
  1391. ty = *y+dy*(costrange/MOVE_DIAGONAL_COST);
  1392. if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) {
  1393. *x = tx;
  1394. *y = ty;
  1395. return true;
  1396. }
  1397. }
  1398. //One cell diagonal, rest linear (TODO: Find a better algorithm for this)
  1399. else if(dir%2 == 1 && costrange%MOVE_COST == 4) {
  1400. tx = *x+dx*((dir%4==3)?(costrange/MOVE_COST):1);
  1401. ty = *y+dy*((dir%4==1)?(costrange/MOVE_COST):1);
  1402. if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) {
  1403. *x = tx;
  1404. *y = ty;
  1405. return true;
  1406. }
  1407. tx = *x+dx*((dir%4==1)?(costrange/MOVE_COST):1);
  1408. ty = *y+dy*((dir%4==3)?(costrange/MOVE_COST):1);
  1409. if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) {
  1410. *x = tx;
  1411. *y = ty;
  1412. return true;
  1413. }
  1414. }
  1415. //Get next direction
  1416. if (dir == 5) {
  1417. //Diagonal search complete, repeat with higher cost range
  1418. if(costrange == 14) costrange += 6;
  1419. else if(costrange == 28 || costrange >= 38) costrange += 2;
  1420. else costrange += 4;
  1421. dir = 6;
  1422. } else if (dir == 4) {
  1423. //Linear search complete, switch to diagonal directions
  1424. dir = 7;
  1425. } else {
  1426. dir = (dir+2)%8;
  1427. }
  1428. }
  1429. return false;
  1430. }
  1431. /*==========================================
  1432. * Add an item to location (m,x,y)
  1433. * Parameters
  1434. * @item_data item attributes
  1435. * @amount quantity
  1436. * @m, @x, @y mapid,x,y
  1437. * @first_charid, @second_charid, @third_charid, looting priority
  1438. * @flag: &1 MVP item. &2 do stacking check.
  1439. *------------------------------------------*/
  1440. int map_addflooritem(const struct block_list *bl, struct item *item_data, int amount, int16 m, int16 x, int16 y, int first_charid, int second_charid, int third_charid, int flags)
  1441. {
  1442. int r;
  1443. struct flooritem_data *fitem=NULL;
  1444. nullpo_ret(item_data);
  1445. if (!map->searchrandfreecell(m, bl, &x, &y, (flags&2)?1:0))
  1446. return 0;
  1447. r=rnd();
  1448. fitem = ers_alloc(map->flooritem_ers, struct flooritem_data);
  1449. fitem->bl.type = BL_ITEM;
  1450. fitem->bl.prev = fitem->bl.next = NULL;
  1451. fitem->bl.m = m;
  1452. fitem->bl.x = x;
  1453. fitem->bl.y = y;
  1454. fitem->bl.id = map->get_new_object_id();
  1455. if(fitem->bl.id==0){
  1456. ers_free(map->flooritem_ers, fitem);
  1457. return 0;
  1458. }
  1459. fitem->first_get_charid = first_charid;
  1460. fitem->first_get_tick = timer->gettick() + ((flags&1) ? battle_config.mvp_item_first_get_time : battle_config.item_first_get_time);
  1461. fitem->second_get_charid = second_charid;
  1462. fitem->second_get_tick = fitem->first_get_tick + ((flags&1) ? battle_config.mvp_item_second_get_time : battle_config.item_second_get_time);
  1463. fitem->third_get_charid = third_charid;
  1464. fitem->third_get_tick = fitem->second_get_tick + ((flags&1) ? battle_config.mvp_item_third_get_time : battle_config.item_third_get_time);
  1465. memcpy(&fitem->item_data,item_data,sizeof(*item_data));
  1466. fitem->item_data.amount=amount;
  1467. fitem->subx=(r&3)*3+3;
  1468. fitem->suby=((r>>2)&3)*3+3;
  1469. fitem->cleartimer=timer->add(timer->gettick()+battle_config.flooritem_lifetime,map->clearflooritem_timer,fitem->bl.id,0);
  1470. map->addiddb(&fitem->bl);
  1471. map->addblock(&fitem->bl);
  1472. clif->dropflooritem(fitem);
  1473. return fitem->bl.id;
  1474. }
  1475. /**
  1476. * @see DBCreateData
  1477. */
  1478. DBData create_charid2nick(DBKey key, va_list args)
  1479. {
  1480. struct charid2nick *p;
  1481. CREATE(p, struct charid2nick, 1);
  1482. return DB->ptr2data(p);
  1483. }
  1484. /// Adds(or replaces) the nick of charid to nick_db and fullfils pending requests.
  1485. /// Does nothing if the character is online.
  1486. void map_addnickdb(int charid, const char* nick)
  1487. {
  1488. struct charid2nick* p;
  1489. struct charid_request* req;
  1490. if( map->charid2sd(charid) )
  1491. return;// already online
  1492. p = idb_ensure(map->nick_db, charid, map->create_charid2nick);
  1493. safestrncpy(p->nick, nick, sizeof(p->nick));
  1494. while (p->requests) {
  1495. struct map_session_data* sd;
  1496. req = p->requests;
  1497. p->requests = req->next;
  1498. sd = map->charid2sd(req->charid);
  1499. if (sd)
  1500. clif->solved_charname(sd->fd, charid, p->nick);
  1501. aFree(req);
  1502. }
  1503. }
  1504. /// Removes the nick of charid from nick_db.
  1505. /// Sends name to all pending requests on charid.
  1506. void map_delnickdb(int charid, const char* name)
  1507. {
  1508. struct charid2nick* p;
  1509. struct charid_request* req;
  1510. DBData data;
  1511. if (!map->nick_db->remove(map->nick_db, DB->i2key(charid), &data) || (p = DB->data2ptr(&data)) == NULL)
  1512. return;
  1513. while (p->requests) {
  1514. struct map_session_data* sd;
  1515. req = p->requests;
  1516. p->requests = req->next;
  1517. sd = map->charid2sd(req->charid);
  1518. if (sd)
  1519. clif->solved_charname(sd->fd, charid, name);
  1520. aFree(req);
  1521. }
  1522. aFree(p);
  1523. }
  1524. /// Notifies sd of the nick of charid.
  1525. /// Uses the name in the character if online.
  1526. /// Uses the name in nick_db if offline.
  1527. void map_reqnickdb(struct map_session_data * sd, int charid)
  1528. {
  1529. struct charid2nick* p;
  1530. struct charid_request* req;
  1531. struct map_session_data* tsd;
  1532. nullpo_retv(sd);
  1533. tsd = map->charid2sd(charid);
  1534. if( tsd ) {
  1535. clif->solved_charname(sd->fd, charid, tsd->status.name);
  1536. return;
  1537. }
  1538. p = idb_ensure(map->nick_db, charid, map->create_charid2nick);
  1539. if( *p->nick ) {
  1540. clif->solved_charname(sd->fd, charid, p->nick);
  1541. return;
  1542. }
  1543. // not in cache, request it
  1544. CREATE(req, struct charid_request, 1);
  1545. req->next = p->requests;
  1546. p->requests = req;
  1547. chrif->searchcharid(charid);
  1548. }
  1549. /*==========================================
  1550. * add bl to id_db
  1551. *------------------------------------------*/
  1552. void map_addiddb(struct block_list *bl)
  1553. {
  1554. nullpo_retv(bl);
  1555. if (bl->type == BL_PC) {
  1556. struct map_session_data *sd = BL_UCAST(BL_PC, bl);
  1557. idb_put(map->pc_db,sd->bl.id,sd);
  1558. idb_put(map->charid_db,sd->status.char_id,sd);
  1559. } else if (bl->type == BL_MOB) {
  1560. struct mob_data *md = BL_UCAST(BL_MOB, bl);
  1561. idb_put(map->mobid_db,bl->id,bl);
  1562. if( md->state.boss )
  1563. idb_put(map->bossid_db, bl->id, bl);
  1564. }
  1565. if( bl->type & BL_REGEN )
  1566. idb_put(map->regen_db, bl->id, bl);
  1567. idb_put(map->id_db,bl->id,bl);
  1568. }
  1569. /*==========================================
  1570. * remove bl from id_db
  1571. *------------------------------------------*/
  1572. void map_deliddb(struct block_list *bl)
  1573. {
  1574. nullpo_retv(bl);
  1575. if (bl->type == BL_PC) {
  1576. struct map_session_data *sd = BL_UCAST(BL_PC, bl);
  1577. idb_remove(map->pc_db,sd->bl.id);
  1578. idb_remove(map->charid_db,sd->status.char_id);
  1579. } else if (bl->type == BL_MOB) {
  1580. idb_remove(map->mobid_db,bl->id);
  1581. idb_remove(map->bossid_db,bl->id);
  1582. }
  1583. if( bl->type & BL_REGEN )
  1584. idb_remove(map->regen_db,bl->id);
  1585. idb_remove(map->id_db,bl->id);
  1586. }
  1587. /*==========================================
  1588. * Standard call when a player connection is closed.
  1589. *------------------------------------------*/
  1590. int map_quit(struct map_session_data *sd) {
  1591. int i;
  1592. nullpo_ret(sd);
  1593. if(!sd->state.active) { //Removing a player that is not active.
  1594. struct auth_node *node = chrif->search(sd->status.account_id);
  1595. if (node && node->char_id == sd->status.char_id &&
  1596. node->state != ST_LOGOUT)
  1597. //Except when logging out, clear the auth-connect data immediately.
  1598. chrif->auth_delete(node->account_id, node->char_id, node->state);
  1599. //Non-active players should not have loaded any data yet (or it was cleared already) so no additional cleanups are needed.
  1600. return 0;
  1601. }
  1602. if( sd->expiration_tid != INVALID_TIMER )
  1603. timer->delete(sd->expiration_tid,pc->expiration_timer);
  1604. if (sd->npc_timer_id != INVALID_TIMER) //Cancel the event timer.
  1605. npc->timerevent_quit(sd);
  1606. if (sd->npc_id)
  1607. npc->event_dequeue(sd);
  1608. if( sd->bg_id && !sd->bg_queue.arena ) /* TODO: dump this chunk after bg_queue is fully enabled */
  1609. bg->team_leave(sd,BGTL_QUIT);
  1610. if (sd->state.autotrade && core->runflag != MAPSERVER_ST_SHUTDOWN && !channel->config->closing)
  1611. pc->autotrade_update(sd,PAUC_REMOVE);
  1612. skill->cooldown_save(sd);
  1613. pc->itemcd_do(sd,false);
  1614. for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
  1615. struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
  1616. if (queue && queue->event_logout[0] != '\0') {
  1617. npc->event(sd, queue->event_logout, 0);
  1618. }
  1619. }
  1620. /* two times, the npc event above may assign a new one or delete others */
  1621. while (VECTOR_LENGTH(sd->script_queues)) {
  1622. int qid = VECTOR_LAST(sd->script_queues);
  1623. script->queue_remove(qid, sd->status.account_id);
  1624. }
  1625. npc->script_event(sd, NPCE_LOGOUT);
  1626. //Unit_free handles clearing the player related data,
  1627. //map->quit handles extra specific data which is related to quitting normally
  1628. //(changing map-servers invokes unit_free but bypasses map->quit)
  1629. if( sd->sc.count ) {
  1630. //Status that are not saved...
  1631. for(i=0; i < SC_MAX; i++){
  1632. if ( status->get_sc_type(i)&SC_NO_SAVE ) {
  1633. if ( !sd->sc.data[i] )
  1634. continue;
  1635. switch( i ){
  1636. case SC_ENDURE:
  1637. case SC_GDSKILL_REGENERATION:
  1638. if( !sd->sc.data[i]->val4 )
  1639. break;
  1640. default:
  1641. status_change_end(&sd->bl, (sc_type)i, INVALID_TIMER);
  1642. }
  1643. }
  1644. }
  1645. }
  1646. for( i = 0; i < EQI_MAX; i++ ) {
  1647. if( sd->equip_index[ i ] >= 0 )
  1648. if( !pc->isequip( sd , sd->equip_index[ i ] ) )
  1649. pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
  1650. }
  1651. // Return loot to owner
  1652. if( sd->pd ) pet->lootitem_drop(sd->pd, sd);
  1653. if( sd->state.storage_flag == STORAGE_FLAG_NORMAL ) sd->state.storage_flag = STORAGE_FLAG_CLOSED; // No need to Double Save Storage on Quit.
  1654. if( sd->ed ) {
  1655. elemental->clean_effect(sd->ed);
  1656. unit->remove_map(&sd->ed->bl,CLR_TELEPORT,ALC_MARK);
  1657. }
  1658. channel->quit(sd);
  1659. unit->remove_map_pc(sd,CLR_RESPAWN);
  1660. if( map->list[sd->bl.m].instance_id >= 0 ) { // Avoid map conflicts and warnings on next login
  1661. int16 m;
  1662. struct point *pt;
  1663. if( map->list[sd->bl.m].save.map )
  1664. pt = &map->list[sd->bl.m].save;
  1665. else
  1666. pt = &sd->status.save_point;
  1667. if( (m=map->mapindex2mapid(pt->map)) >= 0 ) {
  1668. sd->bl.m = m;
  1669. sd->bl.x = pt->x;
  1670. sd->bl.y = pt->y;
  1671. sd->mapindex = pt->map;
  1672. }
  1673. }
  1674. if( sd->state.vending ) {
  1675. idb_remove(vending->db, sd->status.char_id);
  1676. }
  1677. party->booking_delete(sd); // Party Booking [Spiria]
  1678. pc->makesavestatus(sd);
  1679. pc->clean_skilltree(sd);
  1680. chrif->save(sd,1);
  1681. unit->free_pc(sd);
  1682. return 0;
  1683. }
  1684. /**
  1685. * Looks up a session data by ID.
  1686. *
  1687. * The search is performed using the pc_db.
  1688. *
  1689. * @param id The bl ID to search.
  1690. * @return The searched map_session_data, if it exists.
  1691. * @retval NULL if the ID is invalid or doesn't belong to a player unit.
  1692. */
  1693. struct map_session_data *map_id2sd(int id)
  1694. {
  1695. struct block_list *bl = NULL;
  1696. if (id <= 0)
  1697. return NULL;
  1698. bl = idb_get(map->pc_db,id);
  1699. if (bl)
  1700. Assert_retr(NULL, bl->type == BL_PC);
  1701. return BL_UCAST(BL_PC, bl);
  1702. }
  1703. /**
  1704. * Looks up a NPC data by ID.
  1705. *
  1706. * @param id The bl ID to search.
  1707. * @return The searched npc_data, if it exists.
  1708. * @retval NULL if the ID is invalid or doesn't belong to a NPC.
  1709. */
  1710. struct npc_data *map_id2nd(int id)
  1711. {
  1712. // just a id2bl lookup because there's no npc_db
  1713. struct block_list* bl = map->id2bl(id);
  1714. return BL_CAST(BL_NPC, bl);
  1715. }
  1716. /**
  1717. * Looks up a mob data by ID.
  1718. *
  1719. * The search is performed using the mobid_db.
  1720. *
  1721. * @param id The bl ID to search.
  1722. * @return The searched mob_data, if it exists.
  1723. * @retval NULL if the ID is invalid or doesn't belong to a mob unit.
  1724. */
  1725. struct mob_data *map_id2md(int id)
  1726. {
  1727. struct block_list *bl = NULL;
  1728. if (id <= 0)
  1729. return NULL;
  1730. bl = idb_get(map->mobid_db,id);
  1731. if (bl)
  1732. Assert_retr(NULL, bl->type == BL_MOB);
  1733. return BL_UCAST(BL_MOB, bl);
  1734. }
  1735. /**
  1736. * Looks up a floor item data by ID.
  1737. *
  1738. * @param id The bl ID to search.
  1739. * @return The searched flooritem_data, if it exists.
  1740. * @retval NULL if the ID is invalid or doesn't belong to a floor item.
  1741. */
  1742. struct flooritem_data *map_id2fi(int id)
  1743. {
  1744. struct block_list* bl = map->id2bl(id);
  1745. return BL_CAST(BL_ITEM, bl);
  1746. }
  1747. /**
  1748. * Looks up a chat data by ID.
  1749. *
  1750. * @param id The bl ID to search.
  1751. * @return The searched chat_data, if it exists.
  1752. * @retval NULL if the ID is invalid or doesn't belong to a chat.
  1753. */
  1754. struct chat_data *map_id2cd(int id)
  1755. {
  1756. struct block_list* bl = map->id2bl(id);
  1757. return BL_CAST(BL_CHAT, bl);
  1758. }
  1759. /**
  1760. * Looks up a skill unit data by ID.
  1761. *
  1762. * @param id The bl ID to search.
  1763. * @return The searched skill_unit data, if it exists.
  1764. * @retval NULL if the ID is invalid or doesn't belong to a skill unit.
  1765. */
  1766. struct skill_unit *map_id2su(int id)
  1767. {
  1768. struct block_list* bl = map->id2bl(id);
  1769. return BL_CAST(BL_SKILL, bl);
  1770. }
  1771. /**
  1772. * Looks up a pet data by ID.
  1773. *
  1774. * @param id The bl ID to search.
  1775. * @return The searched pet_data, if it exists.
  1776. * @retval NULL if the ID is invalid or doesn't belong to a pet.
  1777. */
  1778. struct pet_data *map_id2pd(int id)
  1779. {
  1780. struct block_list* bl = map->id2bl(id);
  1781. return BL_CAST(BL_PET, bl);
  1782. }
  1783. /**
  1784. * Looks up a homunculus data by ID.
  1785. *
  1786. * @param id The bl ID to search.
  1787. * @return The searched homun_data, if it exists.
  1788. * @retval NULL if the ID is invalid or doesn't belong to a homunculus.
  1789. */
  1790. struct homun_data *map_id2hd(int id)
  1791. {
  1792. struct block_list* bl = map->id2bl(id);
  1793. return BL_CAST(BL_HOM, bl);
  1794. }
  1795. /**
  1796. * Looks up a mercenary data by ID.
  1797. *
  1798. * @param id The bl ID to search.
  1799. * @return The searched mercenary_data, if it exists.
  1800. * @retval NULL if the ID is invalid or doesn't belong to a mercenary.
  1801. */
  1802. struct mercenary_data *map_id2mc(int id)
  1803. {
  1804. struct block_list* bl = map->id2bl(id);
  1805. return BL_CAST(BL_MER, bl);
  1806. }
  1807. /**
  1808. * Looks up an elemental data by ID.
  1809. *
  1810. * @param id The bl ID to search.
  1811. * @return The searched elemental_data, if it exists.
  1812. * @retval NULL if the ID is invalid or doesn't belong to an elemental.
  1813. */
  1814. struct elemental_data *map_id2ed(int id)
  1815. {
  1816. struct block_list* bl = map->id2bl(id);
  1817. return BL_CAST(BL_ELEM, bl);
  1818. }
  1819. /**
  1820. * Looks up a block_list by ID.
  1821. *
  1822. * The search is performed using the id_db.
  1823. *
  1824. * @param id The bl ID to search.
  1825. * @return The searched block_list, if it exists.
  1826. * @retval NULL if the ID is invalid.
  1827. */
  1828. struct block_list *map_id2bl(int id)
  1829. {
  1830. return idb_get(map->id_db, id);
  1831. }
  1832. /**
  1833. * Verifies whether a block list ID is valid.
  1834. *
  1835. * @param id The bl ID to search.
  1836. * @retval true if the ID exists and is valid.
  1837. * @retval false otherwise.
  1838. */
  1839. bool map_blid_exists(int id)
  1840. {
  1841. return (idb_exists(map->id_db,id));
  1842. }
  1843. /// Returns the nick of the target charid or NULL if unknown (requests the nick to the char server).
  1844. const char *map_charid2nick(int charid) {
  1845. struct charid2nick *p;
  1846. struct map_session_data* sd;
  1847. sd = map->charid2sd(charid);
  1848. if( sd )
  1849. return sd->status.name;// character is online, return it's name
  1850. p = idb_ensure(map->nick_db, charid, map->create_charid2nick);
  1851. if( *p->nick )
  1852. return p->nick;// name in nick_db
  1853. chrif->searchcharid(charid);// request the name
  1854. return NULL;
  1855. }
  1856. /// Returns the struct map_session_data of the charid or NULL if the char is not online.
  1857. struct map_session_data* map_charid2sd(int charid)
  1858. {
  1859. struct block_list *bl = idb_get(map->charid_db, charid);
  1860. if (bl)
  1861. Assert_retr(NULL, bl->type == BL_PC);
  1862. return BL_UCAST(BL_PC, bl);
  1863. }
  1864. /*==========================================
  1865. * Search session data from a nick name
  1866. * (without sensitive case if necessary)
  1867. * return map_session_data pointer or NULL
  1868. *------------------------------------------*/
  1869. struct map_session_data * map_nick2sd(const char *nick)
  1870. {
  1871. struct map_session_data* sd;
  1872. struct map_session_data* found_sd;
  1873. struct s_mapiterator* iter;
  1874. size_t nicklen;
  1875. int qty = 0;
  1876. if( nick == NULL )
  1877. return NULL;
  1878. nicklen = strlen(nick);
  1879. iter = mapit_getallusers();
  1880. found_sd = NULL;
  1881. for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
  1882. if( battle_config.partial_name_scan )
  1883. {// partial name search
  1884. if( strnicmp(sd->status.name, nick, nicklen) == 0 )
  1885. {
  1886. found_sd = sd;
  1887. if( strcmp(sd->status.name, nick) == 0 )
  1888. {// Perfect Match
  1889. qty = 1;
  1890. break;
  1891. }
  1892. qty++;
  1893. }
  1894. }
  1895. else if( strcasecmp(sd->status.name, nick) == 0 )
  1896. {// exact search only
  1897. found_sd = sd;
  1898. break;
  1899. }
  1900. }
  1901. mapit->free(iter);
  1902. if( battle_config.partial_name_scan && qty != 1 )
  1903. found_sd = NULL;
  1904. return found_sd;
  1905. }
  1906. /*==========================================
  1907. * Convext Mirror
  1908. *------------------------------------------*/
  1909. struct mob_data * map_getmob_boss(int16 m)
  1910. {
  1911. DBIterator* iter;
  1912. struct mob_data *md = NULL;
  1913. bool found = false;
  1914. iter = db_iterator(map->bossid_db);
  1915. for (md = dbi_first(iter); dbi_exists(iter); md = dbi_next(iter)) {
  1916. if (md->bl.m == m) {
  1917. found = true;
  1918. break;
  1919. }
  1920. }
  1921. dbi_destroy(iter);
  1922. return (found)? md : NULL;
  1923. }
  1924. struct mob_data *map_id2boss(int id)
  1925. {
  1926. struct block_list *bl = NULL;
  1927. if (id <= 0)
  1928. return NULL;
  1929. bl = idb_get(map->bossid_db,id);
  1930. if (bl)
  1931. Assert_retr(NULL, bl->type == BL_MOB);
  1932. return BL_UCAST(BL_MOB, bl);
  1933. }
  1934. /**
  1935. * Returns the equivalent bitmask to the given race ID.
  1936. *
  1937. * @param race A race identifier (@see enum Race)
  1938. *
  1939. * @return The equivalent race bitmask.
  1940. */
  1941. uint32 map_race_id2mask(int race)
  1942. {
  1943. if (race >= RC_FORMLESS && race < RC_MAX)
  1944. return 1 << race;
  1945. if (race == RC_ALL)
  1946. return RCMASK_ALL;
  1947. if (race == RC_NONPLAYER)
  1948. return RCMASK_NONPLAYER;
  1949. if (race == RC_NONDEMIHUMAN)
  1950. return RCMASK_NONDEMIHUMAN;
  1951. if (race == RC_DEMIPLAYER)
  1952. return RCMASK_DEMIPLAYER;
  1953. if (race == RC_NONDEMIPLAYER)
  1954. return RCMASK_NONDEMIPLAYER;
  1955. ShowWarning("map_race_id2mask: Invalid race: %d\n", race);
  1956. Assert_report((race >= RC_FORMLESS && race < RC_NONDEMIPLAYER) || race == RC_ALL);
  1957. return RCMASK_NONE;
  1958. }
  1959. /// Applies func to all the players in the db.
  1960. /// Stops iterating if func returns -1.
  1961. void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_list args) {
  1962. DBIterator* iter;
  1963. struct map_session_data* sd;
  1964. iter = db_iterator(map->pc_db);
  1965. for( sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter) )
  1966. {
  1967. va_list argscopy;
  1968. int ret;
  1969. va_copy(argscopy, args);
  1970. ret = func(sd, argscopy);
  1971. va_end(argscopy);
  1972. if( ret == -1 )
  1973. break;// stop iterating
  1974. }
  1975. dbi_destroy(iter);
  1976. }
  1977. /// Applies func to all the players in the db.
  1978. /// Stops iterating if func returns -1.
  1979. /// @see map_vforeachpc
  1980. void map_foreachpc(int (*func)(struct map_session_data* sd, va_list args), ...) {
  1981. va_list args;
  1982. va_start(args, func);
  1983. map->vforeachpc(func, args);
  1984. va_end(args);
  1985. }
  1986. /// Applies func to all the mobs in the db.
  1987. /// Stops iterating if func returns -1.
  1988. void map_vforeachmob(int (*func)(struct mob_data* md, va_list args), va_list args) {
  1989. DBIterator* iter;
  1990. struct mob_data* md;
  1991. iter = db_iterator(map->mobid_db);
  1992. for (md = dbi_first(iter); dbi_exists(iter); md = dbi_next(iter)) {
  1993. va_list argscopy;
  1994. int ret;
  1995. va_copy(argscopy, args);
  1996. ret = func(md, argscopy);
  1997. va_end(argscopy);
  1998. if( ret == -1 )
  1999. break;// stop iterating
  2000. }
  2001. dbi_destroy(iter);
  2002. }
  2003. /// Applies func to all the mobs in the db.
  2004. /// Stops iterating if func returns -1.
  2005. /// @see map_vforeachmob
  2006. void map_foreachmob(int (*func)(struct mob_data* md, va_list args), ...) {
  2007. va_list args;
  2008. va_start(args, func);
  2009. map->vforeachmob(func, args);
  2010. va_end(args);
  2011. }
  2012. /// Applies func to all the npcs in the db.
  2013. /// Stops iterating if func returns -1.
  2014. void map_vforeachnpc(int (*func)(struct npc_data* nd, va_list args), va_list args) {
  2015. DBIterator* iter;
  2016. struct block_list* bl;
  2017. iter = db_iterator(map->id_db);
  2018. for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) {
  2019. if (bl->type == BL_NPC) {
  2020. struct npc_data *nd = BL_UCAST(BL_NPC, bl);
  2021. va_list argscopy;
  2022. int ret;
  2023. va_copy(argscopy, args);
  2024. ret = func(nd, argscopy);
  2025. va_end(argscopy);
  2026. if( ret == -1 )
  2027. break;// stop iterating
  2028. }
  2029. }
  2030. dbi_destroy(iter);
  2031. }
  2032. /// Applies func to all the npcs in the db.
  2033. /// Stops iterating if func returns -1.
  2034. /// @see map_vforeachnpc
  2035. void map_foreachnpc(int (*func)(struct npc_data* nd, va_list args), ...) {
  2036. va_list args;
  2037. va_start(args, func);
  2038. map->vforeachnpc(func, args);
  2039. va_end(args);
  2040. }
  2041. /// Applies func to everything in the db.
  2042. /// Stops iterating gif func returns -1.
  2043. void map_vforeachregen(int (*func)(struct block_list* bl, va_list args), va_list args) {
  2044. DBIterator* iter;
  2045. struct block_list* bl;
  2046. iter = db_iterator(map->regen_db);
  2047. for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) {
  2048. va_list argscopy;
  2049. int ret;
  2050. va_copy(argscopy, args);
  2051. ret = func(bl, argscopy);
  2052. va_end(argscopy);
  2053. if( ret == -1 )
  2054. break;// stop iterating
  2055. }
  2056. dbi_destroy(iter);
  2057. }
  2058. /// Applies func to everything in the db.
  2059. /// Stops iterating gif func returns -1.
  2060. /// @see map_vforeachregen
  2061. void map_foreachregen(int (*func)(struct block_list* bl, va_list args), ...) {
  2062. va_list args;
  2063. va_start(args, func);
  2064. map->vforeachregen(func, args);
  2065. va_end(args);
  2066. }
  2067. /// Applies func to everything in the db.
  2068. /// Stops iterating if func returns -1.
  2069. void map_vforeachiddb(int (*func)(struct block_list* bl, va_list args), va_list args) {
  2070. DBIterator* iter;
  2071. struct block_list* bl;
  2072. iter = db_iterator(map->id_db);
  2073. for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) {
  2074. va_list argscopy;
  2075. int ret;
  2076. va_copy(argscopy, args);
  2077. ret = func(bl, argscopy);
  2078. va_end(argscopy);
  2079. if( ret == -1 )
  2080. break;// stop iterating
  2081. }
  2082. dbi_destroy(iter);
  2083. }
  2084. /// Applies func to everything in the db.
  2085. /// Stops iterating if func returns -1.
  2086. /// @see map_vforeachiddb
  2087. void map_foreachiddb(int (*func)(struct block_list* bl, va_list args), ...) {
  2088. va_list args;
  2089. va_start(args, func);
  2090. map->vforeachiddb(func, args);
  2091. va_end(args);
  2092. }
  2093. /// Iterator.
  2094. /// Can filter by bl type.
  2095. struct s_mapiterator
  2096. {
  2097. enum e_mapitflags flags;// flags for special behaviour
  2098. enum bl_type types;// what bl types to return
  2099. DBIterator* dbi;// database iterator
  2100. };
  2101. /// Returns true if the block_list matches the description in the iterator.
  2102. ///
  2103. /// @param _mapit_ Iterator
  2104. /// @param _bl_ block_list
  2105. /// @return true if it matches
  2106. #define MAPIT_MATCHES(_mapit_,_bl_) \
  2107. ( (_bl_)->type & (_mapit_)->types /* type matches */ )
  2108. /// Allocates a new iterator.
  2109. /// Returns the new iterator.
  2110. /// types can represent several BL's as a bit field.
  2111. /// TODO should this be expanded to allow filtering of map/guild/party/chat/cell/area/...?
  2112. ///
  2113. /// @param flags Flags of the iterator
  2114. /// @param type Target types
  2115. /// @return Iterator
  2116. struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types) {
  2117. struct s_mapiterator* iter;
  2118. iter = ers_alloc(map->iterator_ers, struct s_mapiterator);
  2119. iter->flags = flags;
  2120. iter->types = types;
  2121. if( types == BL_PC ) iter->dbi = db_iterator(map->pc_db);
  2122. else if( types == BL_MOB ) iter->dbi = db_iterator(map->mobid_db);
  2123. else iter->dbi = db_iterator(map->id_db);
  2124. return iter;
  2125. }
  2126. /// Frees the iterator.
  2127. ///
  2128. /// @param iter Iterator
  2129. void mapit_free(struct s_mapiterator* iter) {
  2130. nullpo_retv(iter);
  2131. dbi_destroy(iter->dbi);
  2132. ers_free(map->iterator_ers, iter);
  2133. }
  2134. /// Returns the first block_list that matches the description.
  2135. /// Returns NULL if not found.
  2136. ///
  2137. /// @param iter Iterator
  2138. /// @return first block_list or NULL
  2139. struct block_list* mapit_first(struct s_mapiterator* iter) {
  2140. struct block_list* bl;
  2141. nullpo_retr(NULL,iter);
  2142. for (bl = dbi_first(iter->dbi); bl != NULL; bl = dbi_next(iter->dbi) ) {
  2143. if( MAPIT_MATCHES(iter,bl) )
  2144. break;// found match
  2145. }
  2146. return bl;
  2147. }
  2148. /// Returns the last block_list that matches the description.
  2149. /// Returns NULL if not found.
  2150. ///
  2151. /// @param iter Iterator
  2152. /// @return last block_list or NULL
  2153. struct block_list* mapit_last(struct s_mapiterator* iter) {
  2154. struct block_list* bl;
  2155. nullpo_retr(NULL,iter);
  2156. for (bl = dbi_last(iter->dbi); bl != NULL; bl = dbi_prev(iter->dbi)) {
  2157. if( MAPIT_MATCHES(iter,bl) )
  2158. break;// found match
  2159. }
  2160. return bl;
  2161. }
  2162. /// Returns the next block_list that matches the description.
  2163. /// Returns NULL if not found.
  2164. ///
  2165. /// @param iter Iterator
  2166. /// @return next block_list or NULL
  2167. struct block_list* mapit_next(struct s_mapiterator* iter) {
  2168. struct block_list* bl;
  2169. nullpo_retr(NULL,iter);
  2170. for( ; ; ) {
  2171. bl = dbi_next(iter->dbi);
  2172. if( bl == NULL )
  2173. break;// end
  2174. if( MAPIT_MATCHES(iter,bl) )
  2175. break;// found a match
  2176. // try next
  2177. }
  2178. return bl;
  2179. }
  2180. /// Returns the previous block_list that matches the description.
  2181. /// Returns NULL if not found.
  2182. ///
  2183. /// @param iter Iterator
  2184. /// @return previous block_list or NULL
  2185. struct block_list* mapit_prev(struct s_mapiterator* iter) {
  2186. struct block_list* bl;
  2187. nullpo_retr(NULL,iter);
  2188. for( ; ; ) {
  2189. bl = dbi_prev(iter->dbi);
  2190. if( bl == NULL )
  2191. break;// end
  2192. if( MAPIT_MATCHES(iter,bl) )
  2193. break;// found a match
  2194. // try prev
  2195. }
  2196. return bl;
  2197. }
  2198. /// Returns true if the current block_list exists in the database.
  2199. ///
  2200. /// @param iter Iterator
  2201. /// @return true if it exists
  2202. bool mapit_exists(struct s_mapiterator* iter) {
  2203. nullpo_retr(false,iter);
  2204. return dbi_exists(iter->dbi);
  2205. }
  2206. /*==========================================
  2207. * Add npc-bl to id_db, basically register npc to map
  2208. *------------------------------------------*/
  2209. bool map_addnpc(int16 m,struct npc_data *nd) {
  2210. nullpo_ret(nd);
  2211. if( m < 0 || m >= map->count )
  2212. return false;
  2213. if( map->list[m].npc_num == MAX_NPC_PER_MAP ) {
  2214. ShowWarning("too many NPCs in one map %s\n",map->list[m].name);
  2215. return false;
  2216. }
  2217. map->list[m].npc[map->list[m].npc_num]=nd;
  2218. map->list[m].npc_num++;
  2219. idb_put(map->id_db,nd->bl.id,nd);
  2220. return true;
  2221. }
  2222. /*=========================================
  2223. * Dynamic Mobs [Wizputer]
  2224. *-----------------------------------------*/
  2225. // Stores the spawn data entry in the mob list.
  2226. // Returns the index of successful, or -1 if the list was full.
  2227. int map_addmobtolist(unsigned short m, struct spawn_data *spawn) {
  2228. int i;
  2229. nullpo_retr(-1, spawn);
  2230. ARR_FIND( 0, MAX_MOB_LIST_PER_MAP, i, map->list[m].moblist[i] == NULL );
  2231. if( i < MAX_MOB_LIST_PER_MAP ) {
  2232. map->list[m].moblist[i] = spawn;
  2233. return i;
  2234. }
  2235. return -1;
  2236. }
  2237. void map_spawnmobs(int16 m) {
  2238. int i, k=0;
  2239. if (map->list[m].mob_delete_timer != INVALID_TIMER) {
  2240. //Mobs have not been removed yet [Skotlex]
  2241. timer->delete(map->list[m].mob_delete_timer, map->removemobs_timer);
  2242. map->list[m].mob_delete_timer = INVALID_TIMER;
  2243. return;
  2244. }
  2245. for(i=0; i<MAX_MOB_LIST_PER_MAP; i++)
  2246. if(map->list[m].moblist[i]!=NULL) {
  2247. k+=map->list[m].moblist[i]->num;
  2248. npc->parse_mob2(map->list[m].moblist[i]);
  2249. }
  2250. if (battle_config.etc_log && k > 0) {
  2251. ShowStatus("Map %s: Spawned '"CL_WHITE"%d"CL_RESET"' mobs.\n",map->list[m].name, k);
  2252. }
  2253. }
  2254. int map_removemobs_sub(struct block_list *bl, va_list ap)
  2255. {
  2256. struct mob_data *md = NULL;
  2257. nullpo_ret(bl);
  2258. Assert_ret(bl->type == BL_MOB);
  2259. md = BL_UCAST(BL_MOB, bl);
  2260. //When not to remove mob:
  2261. // doesn't respawn and is not a slave
  2262. if( !md->spawn && !md->master_id )
  2263. return 0;
  2264. // respawn data is not in cache
  2265. if( md->spawn && !md->spawn->state.dynamic )
  2266. return 0;
  2267. // hasn't spawned yet
  2268. if( md->spawn_timer != INVALID_TIMER )
  2269. return 0;
  2270. // is damaged and mob_remove_damaged is off
  2271. if( !battle_config.mob_remove_damaged && md->status.hp < md->status.max_hp )
  2272. return 0;
  2273. // is a mvp
  2274. if( md->db->mexp > 0 )
  2275. return 0;
  2276. unit->free(&md->bl,CLR_OUTSIGHT);
  2277. return 1;
  2278. }
  2279. int map_removemobs_timer(int tid, int64 tick, int id, intptr_t data) {
  2280. int count;
  2281. const int16 m = id;
  2282. if (m < 0 || m >= map->count) { //Incorrect map id!
  2283. ShowError("map_removemobs_timer error: timer %d points to invalid map %d\n",tid, m);
  2284. return 0;
  2285. }
  2286. if (map->list[m].mob_delete_timer != tid) { //Incorrect timer call!
  2287. ShowError("map_removemobs_timer mismatch: %d != %d (map %s)\n",map->list[m].mob_delete_timer, tid, map->list[m].name);
  2288. return 0;
  2289. }
  2290. map->list[m].mob_delete_timer = INVALID_TIMER;
  2291. if (map->list[m].users > 0) //Map not empty!
  2292. return 1;
  2293. count = map->foreachinmap(map->removemobs_sub, m, BL_MOB);
  2294. if (battle_config.etc_log && count > 0)
  2295. ShowStatus("Map %s: Removed '"CL_WHITE"%d"CL_RESET"' mobs.\n",map->list[m].name, count);
  2296. return 1;
  2297. }
  2298. void map_removemobs(int16 m) {
  2299. Assert_retv(m >= 0 && m < map->count);
  2300. if (map->list[m].mob_delete_timer != INVALID_TIMER) // should never happen
  2301. return; //Mobs are already scheduled for removal
  2302. map->list[m].mob_delete_timer = timer->add(timer->gettick()+battle_config.mob_remove_delay, map->removemobs_timer, m, 0);
  2303. }
  2304. /*==========================================
  2305. * Hookup, get map_id from map_name
  2306. *------------------------------------------*/
  2307. int16 map_mapname2mapid(const char* name) {
  2308. unsigned short map_index;
  2309. map_index = mapindex->name2id(name);
  2310. if (!map_index)
  2311. return -1;
  2312. return map->mapindex2mapid(map_index);
  2313. }
  2314. /*==========================================
  2315. * Returns the map of the given mapindex. [Skotlex]
  2316. *------------------------------------------*/
  2317. int16 map_mapindex2mapid(unsigned short map_index) {
  2318. if (!map_index || map_index >= MAX_MAPINDEX)
  2319. return -1;
  2320. return map->index2mapid[map_index];
  2321. }
  2322. /*==========================================
  2323. * Switching Ip, port ? (like changing map_server) get ip/port from map_name
  2324. *------------------------------------------*/
  2325. int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port) {
  2326. struct map_data_other_server *mdos;
  2327. nullpo_retr(-1, ip);
  2328. nullpo_retr(-1, port);
  2329. mdos = (struct map_data_other_server*)uidb_get(map->map_db,(unsigned int)name);
  2330. if(mdos==NULL || mdos->cell) //If gat isn't null, this is a local map.
  2331. return -1;
  2332. *ip=mdos->ip;
  2333. *port=mdos->port;
  2334. return 0;
  2335. }
  2336. /*==========================================
  2337. * Checks if both dirs point in the same direction.
  2338. *------------------------------------------*/
  2339. int map_check_dir(int s_dir,int t_dir)
  2340. {
  2341. if(s_dir == t_dir)
  2342. return 0;
  2343. switch(s_dir) {
  2344. case 0: if(t_dir == 7 || t_dir == 1 || t_dir == 0) return 0; break;
  2345. case 1: if(t_dir == 0 || t_dir == 2 || t_dir == 1) return 0; break;
  2346. case 2: if(t_dir == 1 || t_dir == 3 || t_dir == 2) return 0; break;
  2347. case 3: if(t_dir == 2 || t_dir == 4 || t_dir == 3) return 0; break;
  2348. case 4: if(t_dir == 3 || t_dir == 5 || t_dir == 4) return 0; break;
  2349. case 5: if(t_dir == 4 || t_dir == 6 || t_dir == 5) return 0; break;
  2350. case 6: if(t_dir == 5 || t_dir == 7 || t_dir == 6) return 0; break;
  2351. case 7: if(t_dir == 6 || t_dir == 0 || t_dir == 7) return 0; break;
  2352. }
  2353. return 1;
  2354. }
  2355. /*==========================================
  2356. * Returns the direction of the given cell, relative to 'src'
  2357. *------------------------------------------*/
  2358. uint8 map_calc_dir(struct block_list* src, int16 x, int16 y)
  2359. {
  2360. uint8 dir = 0;
  2361. int dx, dy;
  2362. nullpo_ret(src);
  2363. dx = x-src->x;
  2364. dy = y-src->y;
  2365. if (dx == 0 && dy == 0) {
  2366. // both are standing on the same spot.
  2367. // aegis-style, makes knockback default to the left.
  2368. // athena-style, makes knockback default to behind 'src'.
  2369. dir = (battle_config.knockback_left ? 6 : unit->getdir(src));
  2370. } else if (dx >= 0 && dy >=0) {
  2371. // upper-right
  2372. if( dx*2 < dy || dx == 0 ) dir = 0; // up
  2373. else if( dx > dy*2+1 || dy == 0 ) dir = 6; // right
  2374. else dir = 7; // up-right
  2375. } else if (dx >= 0 && dy <= 0) {
  2376. // lower-right
  2377. if( dx*2 < -dy || dx == 0 ) dir = 4; // down
  2378. else if( dx > -dy*2+1 || dy == 0 ) dir = 6; // right
  2379. else dir = 5; // down-right
  2380. } else if (dx <= 0 && dy <= 0) {
  2381. // lower-left
  2382. if( dx*2 > dy || dx == 0 ) dir = 4; // down
  2383. else if( dx < dy*2-1 || dy == 0 ) dir = 2; // left
  2384. else dir = 3; // down-left
  2385. } else {
  2386. // upper-left
  2387. if( -dx*2 < dy || dx == 0 ) dir = 0; // up
  2388. else if( -dx > dy*2+1 || dy == 0) dir = 2; // left
  2389. else dir = 1; // up-left
  2390. }
  2391. return dir;
  2392. }
  2393. /*==========================================
  2394. * Randomizes target cell x,y to a random walkable cell that
  2395. * has the same distance from object as given coordinates do. [Skotlex]
  2396. *------------------------------------------*/
  2397. int map_random_dir(struct block_list *bl, int16 *x, int16 *y)
  2398. {
  2399. short xi;
  2400. short yi;
  2401. short i=0;
  2402. int dist2;
  2403. short dist;
  2404. nullpo_ret(bl);
  2405. nullpo_ret(x);
  2406. nullpo_ret(y);
  2407. xi = *x-bl->x;
  2408. yi = *y-bl->y;
  2409. dist2 = xi*xi + yi*yi;
  2410. dist = (short)sqrt((float)dist2);
  2411. if (dist < 1) dist =1;
  2412. do {
  2413. int j = 1 + 2*(rnd()%4); //Pick a random diagonal direction
  2414. short segment = 1+(rnd()%dist); //Pick a random interval from the whole vector in that direction
  2415. xi = bl->x + segment*dirx[j];
  2416. segment = (short)sqrt((float)(dist2 - segment*segment)); //The complement of the previously picked segment
  2417. yi = bl->y + segment*diry[j];
  2418. } while ((map->getcell(bl->m, bl, xi, yi, CELL_CHKNOPASS) || !path->search(NULL, bl, bl->m, bl->x, bl->y, xi, yi, 1, CELL_CHKNOREACH))
  2419. && (++i)<100);
  2420. if (i < 100) {
  2421. *x = xi;
  2422. *y = yi;
  2423. return 1;
  2424. }
  2425. return 0;
  2426. }
  2427. // gat system
  2428. struct mapcell map_gat2cell(int gat) {
  2429. struct mapcell cell;
  2430. memset(&cell,0,sizeof(struct mapcell));
  2431. switch( gat ) {
  2432. case 0: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // walkable ground
  2433. case 1: cell.walkable = 0; cell.shootable = 0; cell.water = 0; break; // non-walkable ground
  2434. case 2: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ???
  2435. case 3: cell.walkable = 1; cell.shootable = 1; cell.water = 1; break; // walkable water
  2436. case 4: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ???
  2437. case 5: cell.walkable = 0; cell.shootable = 1; cell.water = 0; break; // gap (snipable)
  2438. case 6: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ???
  2439. default:
  2440. ShowWarning("map_gat2cell: unrecognized gat type '%d'\n", gat);
  2441. break;
  2442. }
  2443. return cell;
  2444. }
  2445. int map_cell2gat(struct mapcell cell) {
  2446. if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 0 ) return 0;
  2447. if( cell.walkable == 0 && cell.shootable == 0 && cell.water == 0 ) return 1;
  2448. if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 1 ) return 3;
  2449. if( cell.walkable == 0 && cell.shootable == 1 && cell.water == 0 ) return 5;
  2450. ShowWarning("map_cell2gat: cell has no matching gat type\n");
  2451. return 1; // default to 'wall'
  2452. }
  2453. void map_cellfromcache(struct map_data *m) {
  2454. struct map_cache_map_info *info;
  2455. nullpo_retv(m);
  2456. info = (struct map_cache_map_info *)m->cellPos;
  2457. if (info) {
  2458. char decode_buffer[MAX_MAP_SIZE];
  2459. unsigned long size, xy;
  2460. int i;
  2461. size = (unsigned long)info->xs*(unsigned long)info->ys;
  2462. // TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo]
  2463. decode_zip(decode_buffer, &size, m->cellPos+sizeof(struct map_cache_map_info), info->len);
  2464. CREATE(m->cell, struct mapcell, size);
  2465. // Set cell properties
  2466. for( xy = 0; xy < size; ++xy ) {
  2467. m->cell[xy] = map->gat2cell(decode_buffer[xy]);
  2468. }
  2469. m->getcellp = map->getcellp;
  2470. m->setcell = map->setcell;
  2471. for(i = 0; i < m->npc_num; i++) {
  2472. npc->setcells(m->npc[i]);
  2473. }
  2474. }
  2475. }
  2476. /*==========================================
  2477. * Confirm if celltype in (m,x,y) match the one given in cellchk
  2478. *------------------------------------------*/
  2479. int map_getcell(int16 m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) {
  2480. return (m < 0 || m >= map->count) ? 0 : map->list[m].getcellp(&map->list[m], bl, x, y, cellchk);
  2481. }
  2482. int map_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) {
  2483. struct mapcell cell;
  2484. nullpo_ret(m);
  2485. //NOTE: this intentionally overrides the last row and column
  2486. if(x<0 || x>=m->xs-1 || y<0 || y>=m->ys-1)
  2487. return( cellchk == CELL_CHKNOPASS );
  2488. cell = m->cell[x + y*m->xs];
  2489. switch(cellchk) {
  2490. // gat type retrieval
  2491. case CELL_GETTYPE:
  2492. return map->cell2gat(cell);
  2493. // base gat type checks
  2494. case CELL_CHKWALL:
  2495. return (!cell.walkable && !cell.shootable);
  2496. case CELL_CHKWATER:
  2497. return (cell.water);
  2498. case CELL_CHKCLIFF:
  2499. return (!cell.walkable && cell.shootable);
  2500. // base cell type checks
  2501. case CELL_CHKNPC:
  2502. return (cell.npc);
  2503. case CELL_CHKBASILICA:
  2504. return (cell.basilica);
  2505. case CELL_CHKLANDPROTECTOR:
  2506. return (cell.landprotector);
  2507. case CELL_CHKNOVENDING:
  2508. return (cell.novending);
  2509. case CELL_CHKNOCHAT:
  2510. return (cell.nochat);
  2511. case CELL_CHKICEWALL:
  2512. return (cell.icewall);
  2513. case CELL_CHKNOICEWALL:
  2514. return (cell.noicewall);
  2515. // special checks
  2516. case CELL_CHKPASS:
  2517. #ifdef CELL_NOSTACK
  2518. if (cell.cell_bl >= battle_config.custom_cell_stack_limit) return 0;
  2519. #endif
  2520. case CELL_CHKREACH:
  2521. return (cell.walkable);
  2522. case CELL_CHKNOPASS:
  2523. #ifdef CELL_NOSTACK
  2524. if (cell.cell_bl >= battle_config.custom_cell_stack_limit) return 1;
  2525. #endif
  2526. case CELL_CHKNOREACH:
  2527. return (!cell.walkable);
  2528. case CELL_CHKSTACK:
  2529. #ifdef CELL_NOSTACK
  2530. return (cell.cell_bl >= battle_config.custom_cell_stack_limit);
  2531. #else
  2532. return 0;
  2533. #endif
  2534. default:
  2535. return 0;
  2536. }
  2537. }
  2538. /* [Ind/Hercules] */
  2539. int map_sub_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) {
  2540. nullpo_ret(m);
  2541. map->cellfromcache(m);
  2542. m->getcellp = map->getcellp;
  2543. m->setcell = map->setcell;
  2544. return m->getcellp(m, bl, x, y, cellchk);
  2545. }
  2546. /*==========================================
  2547. * Change the type/flags of a map cell
  2548. * 'cell' - which flag to modify
  2549. * 'flag' - true = on, false = off
  2550. *------------------------------------------*/
  2551. void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) {
  2552. int j;
  2553. if( m < 0 || m >= map->count || x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys )
  2554. return;
  2555. j = x + y*map->list[m].xs;
  2556. switch( cell ) {
  2557. case CELL_WALKABLE: map->list[m].cell[j].walkable = flag; break;
  2558. case CELL_SHOOTABLE: map->list[m].cell[j].shootable = flag; break;
  2559. case CELL_WATER: map->list[m].cell[j].water = flag; break;
  2560. case CELL_NPC: map->list[m].cell[j].npc = flag; break;
  2561. case CELL_BASILICA: map->list[m].cell[j].basilica = flag; break;
  2562. case CELL_LANDPROTECTOR: map->list[m].cell[j].landprotector = flag; break;
  2563. case CELL_NOVENDING: map->list[m].cell[j].novending = flag; break;
  2564. case CELL_NOCHAT: map->list[m].cell[j].nochat = flag; break;
  2565. case CELL_ICEWALL: map->list[m].cell[j].icewall = flag; break;
  2566. case CELL_NOICEWALL: map->list[m].cell[j].noicewall = flag; break;
  2567. default:
  2568. ShowWarning("map_setcell: invalid cell type '%d'\n", (int)cell);
  2569. break;
  2570. }
  2571. }
  2572. void map_sub_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) {
  2573. if( m < 0 || m >= map->count || x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys )
  2574. return;
  2575. map->cellfromcache(&map->list[m]);
  2576. map->list[m].setcell = map->setcell;
  2577. map->list[m].getcellp = map->getcellp;
  2578. map->list[m].setcell(m,x,y,cell,flag);
  2579. }
  2580. void map_setgatcell(int16 m, int16 x, int16 y, int gat) {
  2581. int j;
  2582. struct mapcell cell;
  2583. if( m < 0 || m >= map->count || x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys )
  2584. return;
  2585. j = x + y*map->list[m].xs;
  2586. cell = map->gat2cell(gat);
  2587. map->list[m].cell[j].walkable = cell.walkable;
  2588. map->list[m].cell[j].shootable = cell.shootable;
  2589. map->list[m].cell[j].water = cell.water;
  2590. }
  2591. /*==========================================
  2592. * Invisible Walls
  2593. *------------------------------------------*/
  2594. void map_iwall_nextxy(int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1)
  2595. {
  2596. nullpo_retv(x1);
  2597. nullpo_retv(y1);
  2598. if( dir == 0 || dir == 4 )
  2599. *x1 = x; // Keep X
  2600. else if( dir > 0 && dir < 4 )
  2601. *x1 = x - pos; // Going left
  2602. else
  2603. *x1 = x + pos; // Going right
  2604. if( dir == 2 || dir == 6 )
  2605. *y1 = y;
  2606. else if( dir > 2 && dir < 6 )
  2607. *y1 = y - pos;
  2608. else
  2609. *y1 = y + pos;
  2610. }
  2611. bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable, const char* wall_name)
  2612. {
  2613. struct iwall_data *iwall;
  2614. int i;
  2615. int16 x1 = 0, y1 = 0;
  2616. if( size < 1 || !wall_name )
  2617. return false;
  2618. if( (iwall = (struct iwall_data *)strdb_get(map->iwall_db, wall_name)) != NULL )
  2619. return false; // Already Exists
  2620. if (map->getcell(m, NULL, x, y, CELL_CHKNOREACH))
  2621. return false; // Starting cell problem
  2622. CREATE(iwall, struct iwall_data, 1);
  2623. iwall->m = m;
  2624. iwall->x = x;
  2625. iwall->y = y;
  2626. iwall->size = size;
  2627. iwall->dir = dir;
  2628. iwall->shootable = shootable;
  2629. safestrncpy(iwall->wall_name, wall_name, sizeof(iwall->wall_name));
  2630. for( i = 0; i < size; i++ ) {
  2631. map->iwall_nextxy(x, y, dir, i, &x1, &y1);
  2632. if (map->getcell(m, NULL, x1, y1, CELL_CHKNOREACH))
  2633. break; // Collision
  2634. map->list[m].setcell(m, x1, y1, CELL_WALKABLE, false);
  2635. map->list[m].setcell(m, x1, y1, CELL_SHOOTABLE, shootable);
  2636. clif->changemapcell(0, m, x1, y1, map->getcell(m, NULL, x1, y1, CELL_GETTYPE), ALL_SAMEMAP);
  2637. }
  2638. iwall->size = i;
  2639. strdb_put(map->iwall_db, iwall->wall_name, iwall);
  2640. map->list[m].iwall_num++;
  2641. return true;
  2642. }
  2643. void map_iwall_get(struct map_session_data *sd) {
  2644. struct iwall_data *iwall;
  2645. DBIterator* iter;
  2646. int16 x1, y1;
  2647. int i;
  2648. nullpo_retv(sd);
  2649. if( map->list[sd->bl.m].iwall_num < 1 )
  2650. return;
  2651. iter = db_iterator(map->iwall_db);
  2652. for( iwall = dbi_first(iter); dbi_exists(iter); iwall = dbi_next(iter) ) {
  2653. if( iwall->m != sd->bl.m )
  2654. continue;
  2655. for( i = 0; i < iwall->size; i++ ) {
  2656. map->iwall_nextxy(iwall->x, iwall->y, iwall->dir, i, &x1, &y1);
  2657. clif->changemapcell(sd->fd, iwall->m, x1, y1, map->getcell(iwall->m, &sd->bl, x1, y1, CELL_GETTYPE), SELF);
  2658. }
  2659. }
  2660. dbi_destroy(iter);
  2661. }
  2662. void map_iwall_remove(const char *wall_name)
  2663. {
  2664. struct iwall_data *iwall;
  2665. int16 i, x1, y1;
  2666. if( (iwall = (struct iwall_data *)strdb_get(map->iwall_db, wall_name)) == NULL )
  2667. return; // Nothing to do
  2668. for( i = 0; i < iwall->size; i++ ) {
  2669. map->iwall_nextxy(iwall->x, iwall->y, iwall->dir, i, &x1, &y1);
  2670. map->list[iwall->m].setcell(iwall->m, x1, y1, CELL_SHOOTABLE, true);
  2671. map->list[iwall->m].setcell(iwall->m, x1, y1, CELL_WALKABLE, true);
  2672. clif->changemapcell(0, iwall->m, x1, y1, map->getcell(iwall->m, NULL, x1, y1, CELL_GETTYPE), ALL_SAMEMAP);
  2673. }
  2674. map->list[iwall->m].iwall_num--;
  2675. strdb_remove(map->iwall_db, iwall->wall_name);
  2676. }
  2677. /**
  2678. * @see DBCreateData
  2679. */
  2680. DBData create_map_data_other_server(DBKey key, va_list args)
  2681. {
  2682. struct map_data_other_server *mdos;
  2683. unsigned short map_index = (unsigned short)key.ui;
  2684. mdos=(struct map_data_other_server *)aCalloc(1,sizeof(struct map_data_other_server));
  2685. mdos->index = map_index;
  2686. memcpy(mdos->name, mapindex_id2name(map_index), MAP_NAME_LENGTH);
  2687. return DB->ptr2data(mdos);
  2688. }
  2689. /*==========================================
  2690. * Add mapindex to db of another map server
  2691. *------------------------------------------*/
  2692. int map_setipport(unsigned short map_index, uint32 ip, uint16 port)
  2693. {
  2694. struct map_data_other_server *mdos;
  2695. mdos= uidb_ensure(map->map_db,(unsigned int)map_index, map->create_map_data_other_server);
  2696. if(mdos->cell) //Local map,Do nothing. Give priority to our own local maps over ones from another server. [Skotlex]
  2697. return 0;
  2698. if(ip == clif->map_ip && port == clif->map_port) {
  2699. //That's odd, we received info that we are the ones with this map, but... we don't have it.
  2700. ShowFatalError("map_setipport : received info that this map-server SHOULD have map '%s', but it is not loaded.\n",mapindex_id2name(map_index));
  2701. exit(EXIT_FAILURE);
  2702. }
  2703. mdos->ip = ip;
  2704. mdos->port = port;
  2705. return 1;
  2706. }
  2707. /**
  2708. * Delete all the other maps server management
  2709. * @see DBApply
  2710. */
  2711. int map_eraseallipport_sub(DBKey key, DBData *data, va_list va)
  2712. {
  2713. struct map_data_other_server *mdos = DB->data2ptr(data);
  2714. nullpo_ret(mdos);
  2715. if(mdos->cell == NULL) {
  2716. db_remove(map->map_db,key);
  2717. aFree(mdos);
  2718. }
  2719. return 0;
  2720. }
  2721. int map_eraseallipport(void) {
  2722. map->map_db->foreach(map->map_db,map->eraseallipport_sub);
  2723. return 1;
  2724. }
  2725. /*==========================================
  2726. * Delete mapindex from db of another map server
  2727. *------------------------------------------*/
  2728. int map_eraseipport(unsigned short map_index, uint32 ip, uint16 port) {
  2729. struct map_data_other_server *mdos;
  2730. mdos = (struct map_data_other_server*)uidb_get(map->map_db,(unsigned int)map_index);
  2731. if(!mdos || mdos->cell) //Map either does not exists or is a local map.
  2732. return 0;
  2733. if(mdos->ip==ip && mdos->port == port) {
  2734. uidb_remove(map->map_db,(unsigned int)map_index);
  2735. aFree(mdos);
  2736. return 1;
  2737. }
  2738. return 0;
  2739. }
  2740. /*==========================================
  2741. * [Shinryo]: Init the mapcache
  2742. *------------------------------------------*/
  2743. char *map_init_mapcache(FILE *fp) {
  2744. struct map_cache_main_header header;
  2745. size_t size = 0;
  2746. char *buffer;
  2747. // No file open? Return..
  2748. nullpo_ret(fp);
  2749. // Get file size
  2750. fseek(fp, 0, SEEK_END);
  2751. size = ftell(fp);
  2752. fseek(fp, 0, SEEK_SET);
  2753. // Allocate enough space
  2754. CREATE(buffer, char, size);
  2755. // No memory? Return..
  2756. nullpo_ret(buffer);
  2757. // Read file into buffer..
  2758. if(fread(buffer, sizeof(char), size, fp) != size) {
  2759. ShowError("map_init_mapcache: Could not read entire mapcache file\n");
  2760. aFree(buffer);
  2761. return NULL;
  2762. }
  2763. rewind(fp);
  2764. // Get main header to verify if data is corrupted
  2765. if( fread(&header, sizeof(header), 1, fp) != 1 ) {
  2766. ShowError("map_init_mapcache: Error obtaining main header!\n");
  2767. aFree(buffer);
  2768. return NULL;
  2769. }
  2770. if( GetULong((unsigned char *)&(header.file_size)) != size ) {
  2771. ShowError("map_init_mapcache: Map cache is corrupted!\n");
  2772. aFree(buffer);
  2773. return NULL;
  2774. }
  2775. return buffer;
  2776. }
  2777. /*==========================================
  2778. * Map cache reading
  2779. * [Shinryo]: Optimized some behaviour to speed this up
  2780. *==========================================*/
  2781. int map_readfromcache(struct map_data *m, char *buffer) {
  2782. int i;
  2783. struct map_cache_main_header *header = (struct map_cache_main_header *)buffer;
  2784. struct map_cache_map_info *info = NULL;
  2785. char *p = buffer + sizeof(struct map_cache_main_header);
  2786. nullpo_ret(m);
  2787. nullpo_ret(buffer);
  2788. for(i = 0; i < header->map_count; i++) {
  2789. info = (struct map_cache_map_info *)p;
  2790. if( strcmp(m->name, info->name) == 0 )
  2791. break; // Map found
  2792. // Jump to next entry..
  2793. p += sizeof(struct map_cache_map_info) + info->len;
  2794. }
  2795. if( info && i < header->map_count ) {
  2796. unsigned long size;
  2797. if( info->xs <= 0 || info->ys <= 0 )
  2798. return 0;// Invalid
  2799. m->xs = info->xs;
  2800. m->ys = info->ys;
  2801. size = (unsigned long)info->xs*(unsigned long)info->ys;
  2802. if(size > MAX_MAP_SIZE) {
  2803. ShowWarning("map_readfromcache: %s exceeded MAX_MAP_SIZE of %d\n", info->name, MAX_MAP_SIZE);
  2804. return 0; // Say not found to remove it from list.. [Shinryo]
  2805. }
  2806. m->cellPos = p;
  2807. m->cell = (struct mapcell *)0xdeadbeaf;
  2808. return 1;
  2809. }
  2810. return 0; // Not found
  2811. }
  2812. int map_addmap(const char* mapname) {
  2813. map->list[map->count].instance_id = -1;
  2814. mapindex->getmapname(mapname, map->list[map->count++].name);
  2815. return 0;
  2816. }
  2817. void map_delmapid(int id) {
  2818. Assert_retv(id >= 0 && id < map->count);
  2819. ShowNotice("Removing map [ %s ] from maplist"CL_CLL"\n",map->list[id].name);
  2820. memmove(map->list+id, map->list+id+1, sizeof(map->list[0])*(map->count-id-1));
  2821. map->count--;
  2822. }
  2823. int map_delmap(char* mapname) {
  2824. int i;
  2825. char map_name[MAP_NAME_LENGTH];
  2826. nullpo_ret(mapname);
  2827. if (strcmpi(mapname, "all") == 0) {
  2828. map->count = 0;
  2829. return 0;
  2830. }
  2831. mapindex->getmapname(mapname, map_name);
  2832. for(i = 0; i < map->count; i++) {
  2833. if (strcmp(map->list[i].name, map_name) == 0) {
  2834. map->delmapid(i);
  2835. return 1;
  2836. }
  2837. }
  2838. return 0;
  2839. }
  2840. /**
  2841. *
  2842. **/
  2843. void map_zone_clear_single(struct map_zone_data *zone) {
  2844. int i;
  2845. nullpo_retv(zone);
  2846. for(i = 0; i < zone->disabled_skills_count; i++) {
  2847. aFree(zone->disabled_skills[i]);
  2848. }
  2849. if( zone->disabled_skills )
  2850. aFree(zone->disabled_skills);
  2851. if( zone->disabled_items )
  2852. aFree(zone->disabled_items);
  2853. if( zone->cant_disable_items )
  2854. aFree(zone->cant_disable_items);
  2855. for(i = 0; i < zone->mapflags_count; i++) {
  2856. aFree(zone->mapflags[i]);
  2857. }
  2858. if( zone->mapflags )
  2859. aFree(zone->mapflags);
  2860. for(i = 0; i < zone->disabled_commands_count; i++) {
  2861. aFree(zone->disabled_commands[i]);
  2862. }
  2863. if( zone->disabled_commands )
  2864. aFree(zone->disabled_commands);
  2865. for(i = 0; i < zone->capped_skills_count; i++) {
  2866. aFree(zone->capped_skills[i]);
  2867. }
  2868. if( zone->capped_skills )
  2869. aFree(zone->capped_skills);
  2870. }
  2871. /**
  2872. *
  2873. **/
  2874. void map_zone_db_clear(void) {
  2875. struct map_zone_data *zone;
  2876. DBIterator *iter = db_iterator(map->zone_db);
  2877. for(zone = dbi_first(iter); dbi_exists(iter); zone = dbi_next(iter)) {
  2878. map->zone_clear_single(zone);
  2879. }
  2880. dbi_destroy(iter);
  2881. db_destroy(map->zone_db);/* will aFree(zone) */
  2882. /* clear the pk zone stuff */
  2883. map->zone_clear_single(&map->zone_pk);
  2884. /* clear the main zone stuff */
  2885. map->zone_clear_single(&map->zone_all);
  2886. }
  2887. void map_clean(int i) {
  2888. int v;
  2889. Assert_retv(i >= 0 && i < map->count);
  2890. if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) aFree(map->list[i].cell);
  2891. if(map->list[i].block) aFree(map->list[i].block);
  2892. if(map->list[i].block_mob) aFree(map->list[i].block_mob);
  2893. if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random]
  2894. int j;
  2895. if(map->list[i].mob_delete_timer != INVALID_TIMER)
  2896. timer->delete(map->list[i].mob_delete_timer, map->removemobs_timer);
  2897. for (j=0; j<MAX_MOB_LIST_PER_MAP; j++)
  2898. if (map->list[i].moblist[j]) aFree(map->list[i].moblist[j]);
  2899. }
  2900. if( map->list[i].unit_count ) {
  2901. if( map->list[i].units ) {
  2902. for(v = 0; v < map->list[i].unit_count; v++) {
  2903. aFree(map->list[i].units[v]);
  2904. }
  2905. aFree(map->list[i].units);
  2906. map->list[i].units = NULL;
  2907. }
  2908. map->list[i].unit_count = 0;
  2909. }
  2910. if( map->list[i].skill_count ) {
  2911. if( map->list[i].skills ) {
  2912. for(v = 0; v < map->list[i].skill_count; v++) {
  2913. aFree(map->list[i].skills[v]);
  2914. }
  2915. aFree(map->list[i].skills);
  2916. map->list[i].skills = NULL;
  2917. }
  2918. map->list[i].skill_count = 0;
  2919. }
  2920. if( map->list[i].zone_mf_count ) {
  2921. if( map->list[i].zone_mf ) {
  2922. for(v = 0; v < map->list[i].zone_mf_count; v++) {
  2923. aFree(map->list[i].zone_mf[v]);
  2924. }
  2925. aFree(map->list[i].zone_mf);
  2926. map->list[i].zone_mf = NULL;
  2927. }
  2928. map->list[i].zone_mf_count = 0;
  2929. }
  2930. if( map->list[i].channel )
  2931. channel->delete(map->list[i].channel);
  2932. }
  2933. void do_final_maps(void) {
  2934. int i, v = 0;
  2935. for( i = 0; i < map->count; i++ ) {
  2936. if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf ) aFree(map->list[i].cell);
  2937. if(map->list[i].block) aFree(map->list[i].block);
  2938. if(map->list[i].block_mob) aFree(map->list[i].block_mob);
  2939. if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random]
  2940. int j;
  2941. if(map->list[i].mob_delete_timer != INVALID_TIMER)
  2942. timer->delete(map->list[i].mob_delete_timer, map->removemobs_timer);
  2943. for (j=0; j<MAX_MOB_LIST_PER_MAP; j++)
  2944. if (map->list[i].moblist[j]) aFree(map->list[i].moblist[j]);
  2945. }
  2946. if( map->list[i].unit_count ) {
  2947. if( map->list[i].units ) {
  2948. for(v = 0; v < map->list[i].unit_count; v++) {
  2949. aFree(map->list[i].units[v]);
  2950. }
  2951. aFree(map->list[i].units);
  2952. map->list[i].units = NULL;
  2953. }
  2954. map->list[i].unit_count = 0;
  2955. }
  2956. if( map->list[i].skill_count ) {
  2957. if( map->list[i].skills ) {
  2958. for(v = 0; v < map->list[i].skill_count; v++) {
  2959. aFree(map->list[i].skills[v]);
  2960. }
  2961. aFree(map->list[i].skills);
  2962. map->list[i].skills = NULL;
  2963. }
  2964. map->list[i].skill_count = 0;
  2965. }
  2966. if( map->list[i].zone_mf_count ) {
  2967. if( map->list[i].zone_mf ) {
  2968. for(v = 0; v < map->list[i].zone_mf_count; v++) {
  2969. aFree(map->list[i].zone_mf[v]);
  2970. }
  2971. aFree(map->list[i].zone_mf);
  2972. map->list[i].zone_mf = NULL;
  2973. }
  2974. map->list[i].zone_mf_count = 0;
  2975. }
  2976. if( map->list[i].drop_list_count ) {
  2977. map->list[i].drop_list_count = 0;
  2978. }
  2979. if( map->list[i].drop_list != NULL )
  2980. aFree(map->list[i].drop_list);
  2981. if( map->list[i].channel )
  2982. channel->delete(map->list[i].channel);
  2983. if( map->list[i].qi_data )
  2984. aFree(map->list[i].qi_data);
  2985. HPM->data_store_destroy(&map->list[i].hdata);
  2986. }
  2987. map->zone_db_clear();
  2988. }
  2989. /// Initializes map flags and adjusts them depending on configuration.
  2990. void map_flags_init(void) {
  2991. int i, v = 0;
  2992. for( i = 0; i < map->count; i++ ) {
  2993. // mapflags
  2994. memset(&map->list[i].flag, 0, sizeof(map->list[i].flag));
  2995. // additional mapflag data
  2996. map->list[i].nocommand = 0; // nocommand mapflag level
  2997. map->list[i].bexp = 100; // per map base exp multiplicator
  2998. map->list[i].jexp = 100; // per map job exp multiplicator
  2999. if( map->list[i].drop_list != NULL )
  3000. aFree(map->list[i].drop_list);
  3001. map->list[i].drop_list = NULL;
  3002. map->list[i].drop_list_count = 0;
  3003. if( map->list[i].unit_count ) {
  3004. for(v = 0; v < map->list[i].unit_count; v++) {
  3005. aFree(map->list[i].units[v]);
  3006. }
  3007. aFree(map->list[i].units);
  3008. }
  3009. map->list[i].units = NULL;
  3010. map->list[i].unit_count = 0;
  3011. if( map->list[i].skill_count ) {
  3012. for(v = 0; v < map->list[i].skill_count; v++) {
  3013. aFree(map->list[i].skills[v]);
  3014. }
  3015. aFree(map->list[i].skills);
  3016. }
  3017. map->list[i].skills = NULL;
  3018. map->list[i].skill_count = 0;
  3019. // adjustments
  3020. if( battle_config.pk_mode ) {
  3021. map->list[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
  3022. map->list[i].zone = &map->zone_pk;
  3023. } else /* align with 'All' zone */
  3024. map->list[i].zone = &map->zone_all;
  3025. if( map->list[i].zone_mf_count ) {
  3026. for(v = 0; v < map->list[i].zone_mf_count; v++) {
  3027. aFree(map->list[i].zone_mf[v]);
  3028. }
  3029. aFree(map->list[i].zone_mf);
  3030. }
  3031. map->list[i].zone_mf = NULL;
  3032. map->list[i].zone_mf_count = 0;
  3033. map->list[i].prev_zone = map->list[i].zone;
  3034. map->list[i].invincible_time_inc = 0;
  3035. map->list[i].weapon_damage_rate = 100;
  3036. map->list[i].magic_damage_rate = 100;
  3037. map->list[i].misc_damage_rate = 100;
  3038. map->list[i].short_damage_rate = 100;
  3039. map->list[i].long_damage_rate = 100;
  3040. if( map->list[i].qi_data )
  3041. aFree(map->list[i].qi_data);
  3042. map->list[i].qi_data = NULL;
  3043. map->list[i].qi_count = 0;
  3044. }
  3045. }
  3046. #define NO_WATER 1000000
  3047. /*
  3048. * Reads from the .rsw for each map
  3049. * Returns water height (or NO_WATER if file doesn't exist) or other error is encountered.
  3050. * Assumed path for file is data/mapname.rsw
  3051. * Credits to LittleWolf
  3052. */
  3053. int map_waterheight(char* mapname)
  3054. {
  3055. char fn[256];
  3056. char *rsw, *found;
  3057. nullpo_retr(NO_WATER, mapname);
  3058. //Look up for the rsw
  3059. snprintf(fn, sizeof(fn), "data\\%s.rsw", mapname);
  3060. if ( (found = grfio_find_file(fn)) )
  3061. safestrncpy(fn, found, sizeof(fn)); // replace with real name
  3062. // read & convert fn
  3063. rsw = (char *) grfio_read (fn);
  3064. if (rsw) {
  3065. //Load water height from file
  3066. int wh = (int) *(float*)(rsw+166);
  3067. aFree(rsw);
  3068. return wh;
  3069. }
  3070. ShowWarning("Failed to find water level for %s (%s)\n", mapname, fn);
  3071. return NO_WATER;
  3072. }
  3073. /*==================================
  3074. * .GAT format
  3075. *----------------------------------*/
  3076. int map_readgat (struct map_data* m)
  3077. {
  3078. char filename[256];
  3079. uint8* gat;
  3080. int water_height;
  3081. size_t xy, off, num_cells;
  3082. nullpo_ret(m);
  3083. sprintf(filename, "data\\%s.gat", m->name);
  3084. gat = (uint8 *) grfio_read(filename);
  3085. if (gat == NULL)
  3086. return 0;
  3087. m->xs = *(int32*)(gat+6);
  3088. m->ys = *(int32*)(gat+10);
  3089. num_cells = m->xs * m->ys;
  3090. CREATE(m->cell, struct mapcell, num_cells);
  3091. water_height = map->waterheight(m->name);
  3092. // Set cell properties
  3093. off = 14;
  3094. for( xy = 0; xy < num_cells; ++xy )
  3095. {
  3096. // read cell data
  3097. float height = *(float*)( gat + off );
  3098. uint32 type = *(uint32*)( gat + off + 16 );
  3099. off += 20;
  3100. if( type == 0 && water_height != NO_WATER && height > water_height )
  3101. type = 3; // Cell is 0 (walkable) but under water level, set to 3 (walkable water)
  3102. m->cell[xy] = map->gat2cell(type);
  3103. }
  3104. aFree(gat);
  3105. return 1;
  3106. }
  3107. /*======================================
  3108. * Add/Remove map to the map_db
  3109. *--------------------------------------*/
  3110. void map_addmap2db(struct map_data *m) {
  3111. nullpo_retv(m);
  3112. map->index2mapid[m->index] = m->m;
  3113. }
  3114. void map_removemapdb(struct map_data *m) {
  3115. nullpo_retv(m);
  3116. map->index2mapid[m->index] = -1;
  3117. }
  3118. /*======================================
  3119. * Initiate maps loading stage
  3120. *--------------------------------------*/
  3121. int map_readallmaps (void) {
  3122. int i;
  3123. FILE* fp=NULL;
  3124. int maps_removed = 0;
  3125. if( map->enable_grf )
  3126. ShowStatus("Loading maps (using GRF files)...\n");
  3127. else {
  3128. char mapcachefilepath[254];
  3129. sprintf(mapcachefilepath,"%s/%s%s",map->db_path,DBPATH,"map_cache.dat");
  3130. ShowStatus("Loading maps (using %s as map cache)...\n", mapcachefilepath);
  3131. if( (fp = fopen(mapcachefilepath, "rb")) == NULL ) {
  3132. ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", mapcachefilepath);
  3133. exit(EXIT_FAILURE); //No use launching server if maps can't be read.
  3134. }
  3135. // Init mapcache data.. [Shinryo]
  3136. map->cache_buffer = map->init_mapcache(fp);
  3137. if(!map->cache_buffer) {
  3138. ShowFatalError("Failed to initialize mapcache data (%s)..\n", mapcachefilepath);
  3139. exit(EXIT_FAILURE);
  3140. }
  3141. }
  3142. for(i = 0; i < map->count; i++) {
  3143. size_t size;
  3144. // show progress
  3145. if(map->enable_grf)
  3146. ShowStatus("Loading maps [%i/%i]: %s"CL_CLL"\r", i, map->count, map->list[i].name);
  3147. // try to load the map
  3148. if( !
  3149. (map->enable_grf?
  3150. map->readgat(&map->list[i])
  3151. :map->readfromcache(&map->list[i], map->cache_buffer))
  3152. ) {
  3153. map->delmapid(i);
  3154. maps_removed++;
  3155. i--;
  3156. continue;
  3157. }
  3158. map->list[i].index = mapindex->name2id(map->list[i].name);
  3159. if ( map->index2mapid[map_id2index(i)] != -1 ) {
  3160. ShowWarning("Map %s already loaded!"CL_CLL"\n", map->list[i].name);
  3161. if (map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) {
  3162. aFree(map->list[i].cell);
  3163. map->list[i].cell = NULL;
  3164. }
  3165. map->delmapid(i);
  3166. maps_removed++;
  3167. i--;
  3168. continue;
  3169. }
  3170. map->list[i].m = i;
  3171. map->addmap2db(&map->list[i]);
  3172. memset(map->list[i].moblist, 0, sizeof(map->list[i].moblist)); //Initialize moblist [Skotlex]
  3173. map->list[i].mob_delete_timer = INVALID_TIMER; //Initialize timer [Skotlex]
  3174. map->list[i].bxs = (map->list[i].xs + BLOCK_SIZE - 1) / BLOCK_SIZE;
  3175. map->list[i].bys = (map->list[i].ys + BLOCK_SIZE - 1) / BLOCK_SIZE;
  3176. size = map->list[i].bxs * map->list[i].bys * sizeof(struct block_list*);
  3177. map->list[i].block = (struct block_list**)aCalloc(size, 1);
  3178. map->list[i].block_mob = (struct block_list**)aCalloc(size, 1);
  3179. map->list[i].getcellp = map->sub_getcellp;
  3180. map->list[i].setcell = map->sub_setcell;
  3181. }
  3182. // intialization and configuration-dependent adjustments of mapflags
  3183. map->flags_init();
  3184. if( !map->enable_grf ) {
  3185. fclose(fp);
  3186. }
  3187. // finished map loading
  3188. ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",map->count);
  3189. instance->start_id = map->count; // Next Map Index will be instances
  3190. if (maps_removed)
  3191. ShowNotice("Maps removed: '"CL_WHITE"%d"CL_RESET"'\n",maps_removed);
  3192. return 0;
  3193. }
  3194. /*==========================================
  3195. * Read map server configuration files (conf/map_server.conf...)
  3196. *------------------------------------------*/
  3197. int map_config_read(char *cfgName) {
  3198. char line[1024], w1[1024], w2[1024];
  3199. FILE *fp;
  3200. nullpo_retr(1, cfgName);
  3201. fp = fopen(cfgName,"r");
  3202. if( fp == NULL ) {
  3203. ShowError("Map configuration file not found at: %s\n", cfgName);
  3204. return 1;
  3205. }
  3206. while (fgets(line, sizeof(line), fp)) {
  3207. char* ptr;
  3208. if (line[0] == '/' && line[1] == '/')
  3209. continue;
  3210. if ((ptr = strstr(line, "//")) != NULL)
  3211. *ptr = '\n'; //Strip comments
  3212. if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2)
  3213. continue;
  3214. //Strip trailing spaces
  3215. ptr = w2 + strlen(w2);
  3216. while (--ptr >= w2 && *ptr == ' ');
  3217. ptr++;
  3218. *ptr = '\0';
  3219. if(strcmpi(w1,"timestamp_format")==0)
  3220. safestrncpy(showmsg->timestamp_format, w2, 20);
  3221. else if(strcmpi(w1,"stdout_with_ansisequence")==0)
  3222. showmsg->stdout_with_ansisequence = config_switch(w2) ? true : false;
  3223. else if(strcmpi(w1,"console_silent")==0) {
  3224. showmsg->silent = atoi(w2);
  3225. if (showmsg->silent) // only bother if its actually enabled
  3226. ShowInfo("Console Silent Setting: %d\n", atoi(w2));
  3227. } else if (strcmpi(w1, "userid")==0)
  3228. chrif->setuserid(w2);
  3229. else if (strcmpi(w1, "passwd") == 0)
  3230. chrif->setpasswd(w2);
  3231. else if (strcmpi(w1, "char_ip") == 0)
  3232. map->char_ip_set = chrif->setip(w2);
  3233. else if (strcmpi(w1, "char_port") == 0)
  3234. chrif->setport(atoi(w2));
  3235. else if (strcmpi(w1, "map_ip") == 0)
  3236. map->ip_set = clif->setip(w2);
  3237. else if (strcmpi(w1, "bind_ip") == 0)
  3238. clif->setbindip(w2);
  3239. else if (strcmpi(w1, "map_port") == 0) {
  3240. clif->setport(atoi(w2));
  3241. map->port = (atoi(w2));
  3242. } else if (strcmpi(w1, "map") == 0)
  3243. map->count++;
  3244. else if (strcmpi(w1, "delmap") == 0)
  3245. map->count--;
  3246. else if (strcmpi(w1, "npc") == 0)
  3247. npc->addsrcfile(w2);
  3248. else if (strcmpi(w1, "delnpc") == 0)
  3249. npc->delsrcfile(w2);
  3250. else if (strcmpi(w1, "autosave_time") == 0) {
  3251. map->autosave_interval = atoi(w2);
  3252. if (map->autosave_interval < 1) //Revert to default saving.
  3253. map->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  3254. else
  3255. map->autosave_interval *= 1000; //Pass from sec to ms
  3256. } else if (strcmpi(w1, "minsave_time") == 0) {
  3257. map->minsave_interval= atoi(w2);
  3258. if (map->minsave_interval < 1)
  3259. map->minsave_interval = 1;
  3260. } else if (strcmpi(w1, "save_settings") == 0)
  3261. map->save_settings = atoi(w2);
  3262. else if (strcmpi(w1, "help_txt") == 0)
  3263. strcpy(map->help_txt, w2);
  3264. else if (strcmpi(w1, "help2_txt") == 0)
  3265. strcpy(map->help2_txt, w2);
  3266. else if (strcmpi(w1, "charhelp_txt") == 0)
  3267. strcpy(map->charhelp_txt, w2);
  3268. else if(strcmpi(w1,"db_path") == 0)
  3269. safestrncpy(map->db_path,w2,255);
  3270. else if (strcmpi(w1, "enable_spy") == 0)
  3271. map->enable_spy = config_switch(w2);
  3272. else if (strcmpi(w1, "use_grf") == 0)
  3273. map->enable_grf = config_switch(w2);
  3274. else if (strcmpi(w1, "console_msg_log") == 0)
  3275. showmsg->console_log = atoi(w2);//[Ind]
  3276. else if (strcmpi(w1, "default_language") == 0)
  3277. safestrncpy(map->default_lang_str, w2, sizeof(map->default_lang_str));
  3278. else if (strcmpi(w1, "import") == 0)
  3279. map->config_read(w2);
  3280. else
  3281. ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
  3282. }
  3283. fclose(fp);
  3284. return 0;
  3285. }
  3286. int map_config_read_sub(char *cfgName) {
  3287. char line[1024], w1[1024], w2[1024];
  3288. FILE *fp;
  3289. nullpo_retr(1, cfgName);
  3290. fp = fopen(cfgName,"r");
  3291. if (fp == NULL) {
  3292. ShowError("Map configuration file not found at: %s\n", cfgName);
  3293. return 1;
  3294. }
  3295. while (fgets(line, sizeof(line), fp)) {
  3296. char* ptr;
  3297. if (line[0] == '/' && line[1] == '/')
  3298. continue;
  3299. if ((ptr = strstr(line, "//")) != NULL)
  3300. *ptr = '\n'; //Strip comments
  3301. if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2)
  3302. continue;
  3303. //Strip trailing spaces
  3304. ptr = w2 + strlen(w2);
  3305. while (--ptr >= w2 && *ptr == ' ');
  3306. ptr++;
  3307. *ptr = '\0';
  3308. if (strcmpi(w1, "map") == 0)
  3309. map->addmap(w2);
  3310. else if (strcmpi(w1, "delmap") == 0)
  3311. map->delmap(w2);
  3312. else if (strcmpi(w1, "import") == 0)
  3313. map->config_read_sub(w2);
  3314. }
  3315. fclose(fp);
  3316. return 0;
  3317. }
  3318. void map_reloadnpc_sub(char *cfgName) {
  3319. char line[1024], w1[1024], w2[1024];
  3320. FILE *fp;
  3321. nullpo_retv(cfgName);
  3322. fp = fopen(cfgName,"r");
  3323. if (fp == NULL) {
  3324. ShowError("Map configuration file not found at: %s\n", cfgName);
  3325. return;
  3326. }
  3327. while (fgets(line, sizeof(line), fp)) {
  3328. char* ptr;
  3329. if (line[0] == '/' && line[1] == '/')
  3330. continue;
  3331. if ((ptr = strstr(line, "//")) != NULL)
  3332. *ptr = '\n'; //Strip comments
  3333. if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2)
  3334. continue;
  3335. //Strip trailing spaces
  3336. ptr = w2 + strlen(w2);
  3337. while (--ptr >= w2 && *ptr == ' ');
  3338. ptr++;
  3339. *ptr = '\0';
  3340. if (strcmpi(w1, "npc") == 0)
  3341. npc->addsrcfile(w2);
  3342. else if (strcmpi(w1, "import") == 0)
  3343. map->reloadnpc_sub(w2);
  3344. else if (strcmpi(w1, "delnpc") == 0)
  3345. npc->delsrcfile(w2);
  3346. else
  3347. ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
  3348. }
  3349. fclose(fp);
  3350. }
  3351. /**
  3352. * Reloads all the scripts.
  3353. *
  3354. * @param clear whether to clear the script list before reloading.
  3355. */
  3356. void map_reloadnpc(bool clear) {
  3357. int i;
  3358. if (clear)
  3359. npc->addsrcfile("clear"); // this will clear the current script list
  3360. #ifdef RENEWAL
  3361. map->reloadnpc_sub("npc/re/scripts_main.conf");
  3362. #else
  3363. map->reloadnpc_sub("npc/pre-re/scripts_main.conf");
  3364. #endif
  3365. // Append extra scripts
  3366. for( i = 0; i < map->extra_scripts_count; i++ ) {
  3367. npc->addsrcfile(map->extra_scripts[i]);
  3368. }
  3369. }
  3370. int inter_config_read(char *cfgName) {
  3371. char line[1024],w1[1024],w2[1024];
  3372. FILE *fp;
  3373. nullpo_retr(1, cfgName);
  3374. if (!(fp = fopen(cfgName,"r"))) {
  3375. ShowError("File not found: %s\n",cfgName);
  3376. return 1;
  3377. }
  3378. while (fgets(line, sizeof(line), fp)) {
  3379. if (line[0] == '/' && line[1] == '/')
  3380. continue;
  3381. if (sscanf(line,"%1023[^:]: %1023[^\r\n]", w1, w2) < 2)
  3382. continue;
  3383. /* map sql stuff */
  3384. if(strcmpi(w1,"map_server_ip")==0)
  3385. safestrncpy(map->server_ip, w2, sizeof(map->server_ip));
  3386. else if(strcmpi(w1,"map_server_port")==0)
  3387. map->server_port=atoi(w2);
  3388. else if(strcmpi(w1,"map_server_id")==0)
  3389. safestrncpy(map->server_id, w2, sizeof(map->server_id));
  3390. else if(strcmpi(w1,"map_server_pw")==0)
  3391. safestrncpy(map->server_pw, w2, sizeof(map->server_pw));
  3392. else if(strcmpi(w1,"map_server_db")==0)
  3393. safestrncpy(map->server_db, w2, sizeof(map->server_db));
  3394. else if(strcmpi(w1,"default_codepage")==0)
  3395. safestrncpy(map->default_codepage, w2, sizeof(map->default_codepage));
  3396. else if(strcmpi(w1,"autotrade_merchants_db")==0)
  3397. safestrncpy(map->autotrade_merchants_db, w2, sizeof(map->autotrade_merchants_db));
  3398. else if(strcmpi(w1,"autotrade_data_db")==0)
  3399. safestrncpy(map->autotrade_data_db, w2, sizeof(map->autotrade_data_db));
  3400. else if(strcmpi(w1,"npc_market_data_db")==0)
  3401. safestrncpy(map->npc_market_data_db, w2, sizeof(map->npc_market_data_db));
  3402. /* sql log db */
  3403. else if(strcmpi(w1,"log_db_ip")==0)
  3404. safestrncpy(logs->db_ip, w2, sizeof(logs->db_ip));
  3405. else if(strcmpi(w1,"log_db_id")==0)
  3406. safestrncpy(logs->db_id, w2, sizeof(logs->db_id));
  3407. else if(strcmpi(w1,"log_db_pw")==0)
  3408. safestrncpy(logs->db_pw, w2, sizeof(logs->db_pw));
  3409. else if(strcmpi(w1,"log_db_port")==0)
  3410. logs->db_port = atoi(w2);
  3411. else if(strcmpi(w1,"log_db_db")==0)
  3412. safestrncpy(logs->db_name, w2, sizeof(logs->db_name));
  3413. /* mapreg */
  3414. else if( mapreg->config_read(w1,w2) )
  3415. continue;
  3416. /* import */
  3417. else if(strcmpi(w1,"import")==0)
  3418. map->inter_config_read(w2);
  3419. else
  3420. HPM->parseConf(w1, w2, HPCT_MAP_INTER);
  3421. }
  3422. fclose(fp);
  3423. return 0;
  3424. }
  3425. /*=======================================
  3426. * MySQL Init
  3427. *---------------------------------------*/
  3428. int map_sql_init(void)
  3429. {
  3430. // main db connection
  3431. map->mysql_handle = SQL->Malloc();
  3432. ShowInfo("Connecting to the Map DB Server....\n");
  3433. if( SQL_ERROR == SQL->Connect(map->mysql_handle, map->server_id, map->server_pw, map->server_ip, map->server_port, map->server_db) )
  3434. exit(EXIT_FAILURE);
  3435. ShowStatus("connect success! (Map Server Connection)\n");
  3436. if (map->default_codepage[0] != '\0')
  3437. if ( SQL_ERROR == SQL->SetEncoding(map->mysql_handle, map->default_codepage) )
  3438. Sql_ShowDebug(map->mysql_handle);
  3439. return 0;
  3440. }
  3441. int map_sql_close(void)
  3442. {
  3443. ShowStatus("Close Map DB Connection....\n");
  3444. SQL->Free(map->mysql_handle);
  3445. map->mysql_handle = NULL;
  3446. if (logs->config.sql_logs) {
  3447. logs->sql_final();
  3448. }
  3449. return 0;
  3450. }
  3451. /**
  3452. * Merges two zones into a new one
  3453. * @param main the zone whose data must override the others upon conflict,
  3454. * e.g. enabling pvp on a town means that main is the pvp zone, while "other" is the towns previous zone
  3455. *
  3456. * @return the newly created zone from merging main and other
  3457. **/
  3458. struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone_data *other) {
  3459. char newzone[MAP_ZONE_NAME_LENGTH];
  3460. struct map_zone_data *zone = NULL;
  3461. int cursor, i, j;
  3462. nullpo_retr(NULL, main);
  3463. nullpo_retr(NULL, other);
  3464. sprintf(newzone, "%s+%s",main->name,other->name);
  3465. if( (zone = strdb_get(map->zone_db, newzone)) )
  3466. return zone;/* this zone has already been merged */
  3467. CREATE(zone, struct map_zone_data, 1);
  3468. safestrncpy(zone->name, newzone, MAP_ZONE_NAME_LENGTH);
  3469. zone->merge_type = MZMT_NEVERMERGE;
  3470. zone->disabled_skills_count = main->disabled_skills_count + other->disabled_skills_count;
  3471. zone->disabled_items_count = main->disabled_items_count + other->disabled_items_count;
  3472. zone->mapflags_count = main->mapflags_count + other->mapflags_count;
  3473. zone->disabled_commands_count = main->disabled_commands_count + other->disabled_commands_count;
  3474. zone->capped_skills_count = main->capped_skills_count + other->capped_skills_count;
  3475. CREATE(zone->disabled_skills, struct map_zone_disabled_skill_entry *, zone->disabled_skills_count );
  3476. for(i = 0, cursor = 0; i < main->disabled_skills_count; i++, cursor++ ) {
  3477. CREATE(zone->disabled_skills[cursor], struct map_zone_disabled_skill_entry, 1 );
  3478. memcpy(zone->disabled_skills[cursor], main->disabled_skills[i], sizeof(struct map_zone_disabled_skill_entry));
  3479. }
  3480. for(i = 0; i < other->disabled_skills_count; i++, cursor++ ) {
  3481. CREATE(zone->disabled_skills[cursor], struct map_zone_disabled_skill_entry, 1 );
  3482. memcpy(zone->disabled_skills[cursor], other->disabled_skills[i], sizeof(struct map_zone_disabled_skill_entry));
  3483. }
  3484. for(j = 0; j < main->cant_disable_items_count; j++) {
  3485. for(i = 0; i < other->disabled_items_count; i++) {
  3486. if( other->disabled_items[i] == main->cant_disable_items[j] ) {
  3487. zone->disabled_items_count--;
  3488. break;
  3489. }
  3490. }
  3491. }
  3492. CREATE(zone->disabled_items, int, zone->disabled_items_count );
  3493. for(i = 0, cursor = 0; i < main->disabled_items_count; i++, cursor++ ) {
  3494. zone->disabled_items[cursor] = main->disabled_items[i];
  3495. }
  3496. for(i = 0; i < other->disabled_items_count; i++) {
  3497. for(j = 0; j < main->cant_disable_items_count; j++) {
  3498. if( other->disabled_items[i] == main->cant_disable_items[j] ) {
  3499. break;
  3500. }
  3501. }
  3502. if( j != main->cant_disable_items_count )
  3503. continue;
  3504. zone->disabled_items[cursor] = other->disabled_items[i];
  3505. cursor++;
  3506. }
  3507. CREATE(zone->mapflags, char *, zone->mapflags_count );
  3508. for(i = 0, cursor = 0; i < main->mapflags_count; i++, cursor++ ) {
  3509. CREATE(zone->mapflags[cursor], char, MAP_ZONE_MAPFLAG_LENGTH );
  3510. safestrncpy(zone->mapflags[cursor], main->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH);
  3511. }
  3512. for(i = 0; i < other->mapflags_count; i++, cursor++ ) {
  3513. CREATE(zone->mapflags[cursor], char, MAP_ZONE_MAPFLAG_LENGTH );
  3514. safestrncpy(zone->mapflags[cursor], other->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH);
  3515. }
  3516. CREATE(zone->disabled_commands, struct map_zone_disabled_command_entry *, zone->disabled_commands_count);
  3517. for(i = 0, cursor = 0; i < main->disabled_commands_count; i++, cursor++ ) {
  3518. CREATE(zone->disabled_commands[cursor], struct map_zone_disabled_command_entry, 1);
  3519. memcpy(zone->disabled_commands[cursor], main->disabled_commands[i], sizeof(struct map_zone_disabled_command_entry));
  3520. }
  3521. for(i = 0; i < other->disabled_commands_count; i++, cursor++ ) {
  3522. CREATE(zone->disabled_commands[cursor], struct map_zone_disabled_command_entry, 1);
  3523. memcpy(zone->disabled_commands[cursor], other->disabled_commands[i], sizeof(struct map_zone_disabled_command_entry));
  3524. }
  3525. CREATE(zone->capped_skills, struct map_zone_skill_damage_cap_entry *, zone->capped_skills_count);
  3526. for(i = 0, cursor = 0; i < main->capped_skills_count; i++, cursor++ ) {
  3527. CREATE(zone->capped_skills[cursor], struct map_zone_skill_damage_cap_entry, 1);
  3528. memcpy(zone->capped_skills[cursor], main->capped_skills[i], sizeof(struct map_zone_skill_damage_cap_entry));
  3529. }
  3530. for(i = 0; i < other->capped_skills_count; i++, cursor++ ) {
  3531. CREATE(zone->capped_skills[cursor], struct map_zone_skill_damage_cap_entry, 1);
  3532. memcpy(zone->capped_skills[cursor], other->capped_skills[i], sizeof(struct map_zone_skill_damage_cap_entry));
  3533. }
  3534. zone->info.merged = 1;
  3535. strdb_put(map->zone_db, newzone, zone);
  3536. return zone;
  3537. }
  3538. void map_zone_change2(int m, struct map_zone_data *zone)
  3539. {
  3540. const char *empty = "";
  3541. Assert_retv(m >= 0 && m < map->count);
  3542. if( map->list[m].zone == zone )
  3543. return;
  3544. if( !map->list[m].zone->info.merged ) /* we don't update it for merged zones! */
  3545. map->list[m].prev_zone = map->list[m].zone;
  3546. if( map->list[m].zone_mf_count )
  3547. map->zone_remove(m);
  3548. if( zone->merge_type == MZMT_MERGEABLE && map->list[m].prev_zone->merge_type != MZMT_NEVERMERGE ) {
  3549. zone = map->merge_zone(zone,map->list[m].prev_zone);
  3550. }
  3551. map->zone_apply(m,zone,empty,empty,empty);
  3552. }
  3553. /* when changing from a mapflag to another during runtime */
  3554. void map_zone_change(int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath) {
  3555. Assert_retv(m >= 0 && m < map->count);
  3556. map->list[m].prev_zone = map->list[m].zone;
  3557. if( map->list[m].zone_mf_count )
  3558. map->zone_remove(m);
  3559. map->zone_apply(m,zone,start,buffer,filepath);
  3560. }
  3561. /* removes previous mapflags from this map */
  3562. void map_zone_remove(int m)
  3563. {
  3564. char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH];
  3565. unsigned short k;
  3566. const char *empty = "";
  3567. Assert_retv(m >= 0 && m < map->count);
  3568. for(k = 0; k < map->list[m].zone_mf_count; k++) {
  3569. size_t len = strlen(map->list[m].zone_mf[k]),j;
  3570. params[0] = '\0';
  3571. memcpy(flag, map->list[m].zone_mf[k], MAP_ZONE_MAPFLAG_LENGTH);
  3572. for(j = 0; j < len; j++) {
  3573. if( flag[j] == '\t' ) {
  3574. memcpy(params, &flag[j+1], len - j);
  3575. flag[j] = '\0';
  3576. break;
  3577. }
  3578. }
  3579. npc->parse_mapflag(map->list[m].name,empty,flag,params,empty,empty,empty, NULL);
  3580. aFree(map->list[m].zone_mf[k]);
  3581. map->list[m].zone_mf[k] = NULL;
  3582. }
  3583. aFree(map->list[m].zone_mf);
  3584. map->list[m].zone_mf = NULL;
  3585. map->list[m].zone_mf_count = 0;
  3586. }
  3587. static inline void map_zone_mf_cache_add(int m, char *rflag) {
  3588. Assert_retv(m >= 0 && m < map->count);
  3589. RECREATE(map->list[m].zone_mf, char *, ++map->list[m].zone_mf_count);
  3590. CREATE(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], char, MAP_ZONE_MAPFLAG_LENGTH);
  3591. safestrncpy(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], rflag, MAP_ZONE_MAPFLAG_LENGTH);
  3592. }
  3593. /* TODO: introduce enumerations to each mapflag so instead of reading the string a number of times we read it only once and use its value wherever we need */
  3594. /* cache previous values to revert */
  3595. bool map_zone_mf_cache(int m, char *flag, char *params) {
  3596. char rflag[MAP_ZONE_MAPFLAG_LENGTH];
  3597. int state = 1;
  3598. nullpo_retr(false, flag);
  3599. nullpo_retr(false, params);
  3600. Assert_retr(false, m >= 0 && m < map->count);
  3601. if (params[0] != '\0' && !strcmpi(params, "off"))
  3602. state = 0;
  3603. if (!strcmpi(flag, "nosave")) {
  3604. #if 0 /* not yet supported to be reversed */
  3605. char savemap[32];
  3606. int savex, savey;
  3607. if (state == 0) {
  3608. if( map->list[m].flag.nosave ) {
  3609. sprintf(rflag, "nosave\tSavePoint");
  3610. map_zone_mf_cache_add(m,nosave);
  3611. }
  3612. } else if (!strcmpi(params, "SavePoint")) {
  3613. if( map->list[m].save.map ) {
  3614. sprintf(rflag, "nosave\t%s,%d,%d",mapindex_id2name(map->list[m].save.map),map->list[m].save.x,map->list[m].save.y);
  3615. } else
  3616. sprintf(rflag, "nosave\t%s,%d,%d",mapindex_id2name(map->list[m].save.map),map->list[m].save.x,map->list[m].save.y);
  3617. map_zone_mf_cache_add(m,nosave);
  3618. } else if (sscanf(params, "%31[^,],%d,%d", savemap, &savex, &savey) == 3) {
  3619. if( map->list[m].save.map ) {
  3620. sprintf(rflag, "nosave\t%s,%d,%d",mapindex_id2name(map->list[m].save.map),map->list[m].save.x,map->list[m].save.y);
  3621. map_zone_mf_cache_add(m,nosave);
  3622. }
  3623. }
  3624. #endif // 0
  3625. } else if (!strcmpi(flag,"autotrade")) {
  3626. if( state && map->list[m].flag.autotrade )
  3627. ;/* nothing to do */
  3628. else {
  3629. if( state )
  3630. map_zone_mf_cache_add(m,"autotrade\toff");
  3631. else if( !map->list[m].flag.autotrade )
  3632. map_zone_mf_cache_add(m,"autotrade");
  3633. }
  3634. } else if (!strcmpi(flag,"allowks")) {
  3635. if( state && map->list[m].flag.allowks )
  3636. ;/* nothing to do */
  3637. else {
  3638. if( state )
  3639. map_zone_mf_cache_add(m,"allowks\toff");
  3640. else if( !map->list[m].flag.allowks )
  3641. map_zone_mf_cache_add(m,"allowks");
  3642. }
  3643. } else if (!strcmpi(flag,"town")) {
  3644. if( state && map->list[m].flag.town )
  3645. ;/* nothing to do */
  3646. else {
  3647. if( state )
  3648. map_zone_mf_cache_add(m,"town\toff");
  3649. else if( !map->list[m].flag.town )
  3650. map_zone_mf_cache_add(m,"town");
  3651. }
  3652. } else if (!strcmpi(flag,"nomemo")) {
  3653. if( state && map->list[m].flag.nomemo )
  3654. ;/* nothing to do */
  3655. else {
  3656. if( state )
  3657. map_zone_mf_cache_add(m,"nomemo\toff");
  3658. else if( !map->list[m].flag.nomemo )
  3659. map_zone_mf_cache_add(m,"nomemo");
  3660. }
  3661. } else if (!strcmpi(flag,"noteleport")) {
  3662. if( state && map->list[m].flag.noteleport )
  3663. ;/* nothing to do */
  3664. else {
  3665. if( state )
  3666. map_zone_mf_cache_add(m,"noteleport\toff");
  3667. else if( !map->list[m].flag.noteleport )
  3668. map_zone_mf_cache_add(m,"noteleport");
  3669. }
  3670. } else if (!strcmpi(flag,"nowarp")) {
  3671. if( state && map->list[m].flag.nowarp )
  3672. ;/* nothing to do */
  3673. else {
  3674. if( state )
  3675. map_zone_mf_cache_add(m,"nowarp\toff");
  3676. else if( !map->list[m].flag.nowarp )
  3677. map_zone_mf_cache_add(m,"nowarp");
  3678. }
  3679. } else if (!strcmpi(flag,"nowarpto")) {
  3680. if( state && map->list[m].flag.nowarpto )
  3681. ;/* nothing to do */
  3682. else {
  3683. if( state )
  3684. map_zone_mf_cache_add(m,"nowarpto\toff");
  3685. else if( !map->list[m].flag.nowarpto )
  3686. map_zone_mf_cache_add(m,"nowarpto");
  3687. }
  3688. } else if (!strcmpi(flag,"noreturn")) {
  3689. if( state && map->list[m].flag.noreturn )
  3690. ;/* nothing to do */
  3691. else {
  3692. if( state )
  3693. map_zone_mf_cache_add(m,"noreturn\toff");
  3694. else if( map->list[m].flag.noreturn )
  3695. map_zone_mf_cache_add(m,"noreturn");
  3696. }
  3697. } else if (!strcmpi(flag,"monster_noteleport")) {
  3698. if( state && map->list[m].flag.monster_noteleport )
  3699. ;/* nothing to do */
  3700. else {
  3701. if( state )
  3702. map_zone_mf_cache_add(m,"monster_noteleport\toff");
  3703. else if( map->list[m].flag.monster_noteleport )
  3704. map_zone_mf_cache_add(m,"monster_noteleport");
  3705. }
  3706. } else if (!strcmpi(flag,"nobranch")) {
  3707. if( state && map->list[m].flag.nobranch )
  3708. ;/* nothing to do */
  3709. else {
  3710. if( state )
  3711. map_zone_mf_cache_add(m,"nobranch\toff");
  3712. else if( map->list[m].flag.nobranch )
  3713. map_zone_mf_cache_add(m,"nobranch");
  3714. }
  3715. } else if (!strcmpi(flag,"nopenalty")) {
  3716. if( state && map->list[m].flag.noexppenalty ) /* they are applied together, no need to check both */
  3717. ;/* nothing to do */
  3718. else {
  3719. if( state )
  3720. map_zone_mf_cache_add(m,"nopenalty\toff");
  3721. else if( map->list[m].flag.noexppenalty )
  3722. map_zone_mf_cache_add(m,"nopenalty");
  3723. }
  3724. } else if (!strcmpi(flag,"pvp")) {
  3725. if( state && map->list[m].flag.pvp )
  3726. ;/* nothing to do */
  3727. else {
  3728. if( state )
  3729. map_zone_mf_cache_add(m,"pvp\toff");
  3730. else if( map->list[m].flag.pvp )
  3731. map_zone_mf_cache_add(m,"pvp");
  3732. }
  3733. }
  3734. else if (!strcmpi(flag,"pvp_noparty")) {
  3735. if( state && map->list[m].flag.pvp_noparty )
  3736. ;/* nothing to do */
  3737. else {
  3738. if( state )
  3739. map_zone_mf_cache_add(m,"pvp_noparty\toff");
  3740. else if( map->list[m].flag.pvp_noparty )
  3741. map_zone_mf_cache_add(m,"pvp_noparty");
  3742. }
  3743. } else if (!strcmpi(flag,"pvp_noguild")) {
  3744. if( state && map->list[m].flag.pvp_noguild )
  3745. ;/* nothing to do */
  3746. else {
  3747. if( state )
  3748. map_zone_mf_cache_add(m,"pvp_noguild\toff");
  3749. else if( map->list[m].flag.pvp_noguild )
  3750. map_zone_mf_cache_add(m,"pvp_noguild");
  3751. }
  3752. } else if (!strcmpi(flag, "pvp_nightmaredrop")) {
  3753. if( state && map->list[m].flag.pvp_nightmaredrop )
  3754. ;/* nothing to do */
  3755. else {
  3756. if( state )
  3757. map_zone_mf_cache_add(m,"pvp_nightmaredrop\toff");
  3758. else if( map->list[m].flag.pvp_nightmaredrop )
  3759. map_zone_mf_cache_add(m,"pvp_nightmaredrop");
  3760. }
  3761. #if 0 /* not yet fully supported */
  3762. char drop_arg1[16], drop_arg2[16];
  3763. int drop_per = 0;
  3764. if (sscanf(w4, "%15[^,],%15[^,],%d", drop_arg1, drop_arg2, &drop_per) == 3) {
  3765. int drop_id = 0, drop_type = 0;
  3766. if (!strcmpi(drop_arg1, "random"))
  3767. drop_id = -1;
  3768. else if (itemdb->exists((drop_id = atoi(drop_arg1))) == NULL)
  3769. drop_id = 0;
  3770. if (!strcmpi(drop_arg2, "inventory"))
  3771. drop_type = 1;
  3772. else if (!strcmpi(drop_arg2,"equip"))
  3773. drop_type = 2;
  3774. else if (!strcmpi(drop_arg2,"all"))
  3775. drop_type = 3;
  3776. if (drop_id != 0) {
  3777. int i;
  3778. for (i = 0; i < MAX_DROP_PER_MAP; i++) {
  3779. if (map->list[m].drop_list[i].drop_id == 0){
  3780. map->list[m].drop_list[i].drop_id = drop_id;
  3781. map->list[m].drop_list[i].drop_type = drop_type;
  3782. map->list[m].drop_list[i].drop_per = drop_per;
  3783. break;
  3784. }
  3785. }
  3786. map->list[m].flag.pvp_nightmaredrop = 1;
  3787. }
  3788. } else if (!state) //Disable
  3789. map->list[m].flag.pvp_nightmaredrop = 0;
  3790. #endif // 0
  3791. } else if (!strcmpi(flag,"pvp_nocalcrank")) {
  3792. if( state && map->list[m].flag.pvp_nocalcrank )
  3793. ;/* nothing to do */
  3794. else {
  3795. if( state )
  3796. map_zone_mf_cache_add(m,"pvp_nocalcrank\toff");
  3797. else if( map->list[m].flag.pvp_nocalcrank )
  3798. map_zone_mf_cache_add(m,"pvp_nocalcrank");
  3799. }
  3800. } else if (!strcmpi(flag,"gvg")) {
  3801. if( state && map->list[m].flag.gvg )
  3802. ;/* nothing to do */
  3803. else {
  3804. if( state )
  3805. map_zone_mf_cache_add(m,"gvg\toff");
  3806. else if( map->list[m].flag.gvg )
  3807. map_zone_mf_cache_add(m,"gvg");
  3808. }
  3809. } else if (!strcmpi(flag,"gvg_noparty")) {
  3810. if( state && map->list[m].flag.gvg_noparty )
  3811. ;/* nothing to do */
  3812. else {
  3813. if( state )
  3814. map_zone_mf_cache_add(m,"gvg_noparty\toff");
  3815. else if( map->list[m].flag.gvg_noparty )
  3816. map_zone_mf_cache_add(m,"gvg_noparty");
  3817. }
  3818. } else if (!strcmpi(flag,"gvg_dungeon")) {
  3819. if( state && map->list[m].flag.gvg_dungeon )
  3820. ;/* nothing to do */
  3821. else {
  3822. if( state )
  3823. map_zone_mf_cache_add(m,"gvg_dungeon\toff");
  3824. else if( map->list[m].flag.gvg_dungeon )
  3825. map_zone_mf_cache_add(m,"gvg_dungeon");
  3826. }
  3827. }
  3828. else if (!strcmpi(flag,"gvg_castle")) {
  3829. if( state && map->list[m].flag.gvg_castle )
  3830. ;/* nothing to do */
  3831. else {
  3832. if( state )
  3833. map_zone_mf_cache_add(m,"gvg_castle\toff");
  3834. else if( map->list[m].flag.gvg_castle )
  3835. map_zone_mf_cache_add(m,"gvg_castle");
  3836. }
  3837. }
  3838. else if (!strcmpi(flag,"battleground")) {
  3839. if( state && map->list[m].flag.battleground )
  3840. ;/* nothing to do */
  3841. else {
  3842. if( state )
  3843. map_zone_mf_cache_add(m,"battleground\toff");
  3844. else if( map->list[m].flag.battleground )
  3845. map_zone_mf_cache_add(m,"battleground");
  3846. }
  3847. } else if (!strcmpi(flag,"noexppenalty")) {
  3848. if( state && map->list[m].flag.noexppenalty )
  3849. ;/* nothing to do */
  3850. else {
  3851. if( state )
  3852. map_zone_mf_cache_add(m,"noexppenalty\toff");
  3853. else if( map->list[m].flag.noexppenalty )
  3854. map_zone_mf_cache_add(m,"noexppenalty");
  3855. }
  3856. } else if (!strcmpi(flag,"nozenypenalty")) {
  3857. if( state && map->list[m].flag.nozenypenalty )
  3858. ;/* nothing to do */
  3859. else {
  3860. if( state )
  3861. map_zone_mf_cache_add(m,"nozenypenalty\toff");
  3862. else if( map->list[m].flag.nozenypenalty )
  3863. map_zone_mf_cache_add(m,"nozenypenalty");
  3864. }
  3865. } else if (!strcmpi(flag,"notrade")) {
  3866. if( state && map->list[m].flag.notrade )
  3867. ;/* nothing to do */
  3868. else {
  3869. if( state )
  3870. map_zone_mf_cache_add(m,"notrade\toff");
  3871. else if( map->list[m].flag.notrade )
  3872. map_zone_mf_cache_add(m,"notrade");
  3873. }
  3874. } else if (!strcmpi(flag,"novending")) {
  3875. if( state && map->list[m].flag.novending )
  3876. ;/* nothing to do */
  3877. else {
  3878. if( state )
  3879. map_zone_mf_cache_add(m,"novending\toff");
  3880. else if( map->list[m].flag.novending )
  3881. map_zone_mf_cache_add(m,"novending");
  3882. }
  3883. } else if (!strcmpi(flag,"nodrop")) {
  3884. if( state && map->list[m].flag.nodrop )
  3885. ;/* nothing to do */
  3886. else {
  3887. if( state )
  3888. map_zone_mf_cache_add(m,"nodrop\toff");
  3889. else if( map->list[m].flag.nodrop )
  3890. map_zone_mf_cache_add(m,"nodrop");
  3891. }
  3892. } else if (!strcmpi(flag,"noskill")) {
  3893. if( state && map->list[m].flag.noskill )
  3894. ;/* nothing to do */
  3895. else {
  3896. if( state )
  3897. map_zone_mf_cache_add(m,"noskill\toff");
  3898. else if( map->list[m].flag.noskill )
  3899. map_zone_mf_cache_add(m,"noskill");
  3900. }
  3901. } else if (!strcmpi(flag,"noicewall")) {
  3902. if( state && map->list[m].flag.noicewall )
  3903. ;/* nothing to do */
  3904. else {
  3905. if( state )
  3906. map_zone_mf_cache_add(m,"noicewall\toff");
  3907. else if( map->list[m].flag.noicewall )
  3908. map_zone_mf_cache_add(m,"noicewall");
  3909. }
  3910. } else if (!strcmpi(flag,"snow")) {
  3911. if( state && map->list[m].flag.snow )
  3912. ;/* nothing to do */
  3913. else {
  3914. if( state )
  3915. map_zone_mf_cache_add(m,"snow\toff");
  3916. else if( map->list[m].flag.snow )
  3917. map_zone_mf_cache_add(m,"snow");
  3918. }
  3919. } else if (!strcmpi(flag,"clouds")) {
  3920. if( state && map->list[m].flag.clouds )
  3921. ;/* nothing to do */
  3922. else {
  3923. if( state )
  3924. map_zone_mf_cache_add(m,"clouds\toff");
  3925. else if( map->list[m].flag.clouds )
  3926. map_zone_mf_cache_add(m,"clouds");
  3927. }
  3928. } else if (!strcmpi(flag,"clouds2")) {
  3929. if( state && map->list[m].flag.clouds2 )
  3930. ;/* nothing to do */
  3931. else {
  3932. if( state )
  3933. map_zone_mf_cache_add(m,"clouds2\toff");
  3934. else if( map->list[m].flag.clouds2 )
  3935. map_zone_mf_cache_add(m,"clouds2");
  3936. }
  3937. } else if (!strcmpi(flag,"fog")) {
  3938. if( state && map->list[m].flag.fog )
  3939. ;/* nothing to do */
  3940. else {
  3941. if( state )
  3942. map_zone_mf_cache_add(m,"fog\toff");
  3943. else if( map->list[m].flag.fog )
  3944. map_zone_mf_cache_add(m,"fog");
  3945. }
  3946. } else if (!strcmpi(flag,"fireworks")) {
  3947. if( state && map->list[m].flag.fireworks )
  3948. ;/* nothing to do */
  3949. else {
  3950. if( state )
  3951. map_zone_mf_cache_add(m,"fireworks\toff");
  3952. else if( map->list[m].flag.fireworks )
  3953. map_zone_mf_cache_add(m,"fireworks");
  3954. }
  3955. } else if (!strcmpi(flag,"sakura")) {
  3956. if( state && map->list[m].flag.sakura )
  3957. ;/* nothing to do */
  3958. else {
  3959. if( state )
  3960. map_zone_mf_cache_add(m,"sakura\toff");
  3961. else if( map->list[m].flag.sakura )
  3962. map_zone_mf_cache_add(m,"sakura");
  3963. }
  3964. } else if (!strcmpi(flag,"leaves")) {
  3965. if( state && map->list[m].flag.leaves )
  3966. ;/* nothing to do */
  3967. else {
  3968. if( state )
  3969. map_zone_mf_cache_add(m,"leaves\toff");
  3970. else if( map->list[m].flag.leaves )
  3971. map_zone_mf_cache_add(m,"leaves");
  3972. }
  3973. } else if (!strcmpi(flag,"nightenabled")) {
  3974. if( state && map->list[m].flag.nightenabled )
  3975. ;/* nothing to do */
  3976. else {
  3977. if( state )
  3978. map_zone_mf_cache_add(m,"nightenabled\toff");
  3979. else if( map->list[m].flag.nightenabled )
  3980. map_zone_mf_cache_add(m,"nightenabled");
  3981. }
  3982. } else if (!strcmpi(flag,"noexp")) {
  3983. if( state && map->list[m].flag.nobaseexp )
  3984. ;/* nothing to do */
  3985. else {
  3986. if( state )
  3987. map_zone_mf_cache_add(m,"noexp\toff");
  3988. else if( map->list[m].flag.nobaseexp )
  3989. map_zone_mf_cache_add(m,"noexp");
  3990. }
  3991. }
  3992. else if (!strcmpi(flag,"nobaseexp")) {
  3993. if( state && map->list[m].flag.nobaseexp )
  3994. ;/* nothing to do */
  3995. else {
  3996. if( state )
  3997. map_zone_mf_cache_add(m,"nobaseexp\toff");
  3998. else if( map->list[m].flag.nobaseexp )
  3999. map_zone_mf_cache_add(m,"nobaseexp");
  4000. }
  4001. } else if (!strcmpi(flag,"nojobexp")) {
  4002. if( state && map->list[m].flag.nojobexp )
  4003. ;/* nothing to do */
  4004. else {
  4005. if( state )
  4006. map_zone_mf_cache_add(m,"nojobexp\toff");
  4007. else if( map->list[m].flag.nojobexp )
  4008. map_zone_mf_cache_add(m,"nojobexp");
  4009. }
  4010. } else if (!strcmpi(flag,"noloot")) {
  4011. if( state && map->list[m].flag.nomobloot )
  4012. ;/* nothing to do */
  4013. else {
  4014. if( state )
  4015. map_zone_mf_cache_add(m,"noloot\toff");
  4016. else if( map->list[m].flag.nomobloot )
  4017. map_zone_mf_cache_add(m,"noloot");
  4018. }
  4019. } else if (!strcmpi(flag,"nomobloot")) {
  4020. if( state && map->list[m].flag.nomobloot )
  4021. ;/* nothing to do */
  4022. else {
  4023. if( state )
  4024. map_zone_mf_cache_add(m,"nomobloot\toff");
  4025. else if( map->list[m].flag.nomobloot )
  4026. map_zone_mf_cache_add(m,"nomobloot");
  4027. }
  4028. } else if (!strcmpi(flag,"nomvploot")) {
  4029. if( state && map->list[m].flag.nomvploot )
  4030. ;/* nothing to do */
  4031. else {
  4032. if( state )
  4033. map_zone_mf_cache_add(m,"nomvploot\toff");
  4034. else if( map->list[m].flag.nomvploot )
  4035. map_zone_mf_cache_add(m,"nomvploot");
  4036. }
  4037. } else if (!strcmpi(flag,"nocommand")) {
  4038. /* implementation may be incomplete */
  4039. if( state && sscanf(params, "%d", &state) == 1 ) {
  4040. sprintf(rflag, "nocommand\t%s",params);
  4041. map_zone_mf_cache_add(m,rflag);
  4042. } else if( !state && map->list[m].nocommand ) {
  4043. sprintf(rflag, "nocommand\t%d",map->list[m].nocommand);
  4044. map_zone_mf_cache_add(m,rflag);
  4045. } else if( map->list[m].nocommand ) {
  4046. map_zone_mf_cache_add(m,"nocommand\toff");
  4047. }
  4048. } else if (!strcmpi(flag,"jexp")) {
  4049. if( !state ) {
  4050. if( map->list[m].jexp != 100 ) {
  4051. sprintf(rflag,"jexp\t%d",map->list[m].jexp);
  4052. map_zone_mf_cache_add(m,rflag);
  4053. }
  4054. } if( sscanf(params, "%d", &state) == 1 ) {
  4055. if( state != map->list[m].jexp ) {
  4056. sprintf(rflag,"jexp\t%s",params);
  4057. map_zone_mf_cache_add(m,rflag);
  4058. }
  4059. }
  4060. } else if (!strcmpi(flag,"bexp")) {
  4061. if( !state ) {
  4062. if( map->list[m].bexp != 100 ) {
  4063. sprintf(rflag,"bexp\t%d",map->list[m].jexp);
  4064. map_zone_mf_cache_add(m,rflag);
  4065. }
  4066. } if( sscanf(params, "%d", &state) == 1 ) {
  4067. if( state != map->list[m].bexp ) {
  4068. sprintf(rflag,"bexp\t%s",params);
  4069. map_zone_mf_cache_add(m,rflag);
  4070. }
  4071. }
  4072. } else if (!strcmpi(flag,"loadevent")) {
  4073. if( state && map->list[m].flag.loadevent )
  4074. ;/* nothing to do */
  4075. else {
  4076. if( state )
  4077. map_zone_mf_cache_add(m,"loadevent\toff");
  4078. else if( map->list[m].flag.loadevent )
  4079. map_zone_mf_cache_add(m,"loadevent");
  4080. }
  4081. } else if (!strcmpi(flag,"nochat")) {
  4082. if( state && map->list[m].flag.nochat )
  4083. ;/* nothing to do */
  4084. else {
  4085. if( state )
  4086. map_zone_mf_cache_add(m,"nochat\toff");
  4087. else if( map->list[m].flag.nochat )
  4088. map_zone_mf_cache_add(m,"nochat");
  4089. }
  4090. } else if (!strcmpi(flag,"partylock")) {
  4091. if( state && map->list[m].flag.partylock )
  4092. ;/* nothing to do */
  4093. else {
  4094. if( state )
  4095. map_zone_mf_cache_add(m,"partylock\toff");
  4096. else if( map->list[m].flag.partylock )
  4097. map_zone_mf_cache_add(m,"partylock");
  4098. }
  4099. } else if (!strcmpi(flag,"guildlock")) {
  4100. if( state && map->list[m].flag.guildlock )
  4101. ;/* nothing to do */
  4102. else {
  4103. if( state )
  4104. map_zone_mf_cache_add(m,"guildlock\toff");
  4105. else if( map->list[m].flag.guildlock )
  4106. map_zone_mf_cache_add(m,"guildlock");
  4107. }
  4108. } else if (!strcmpi(flag,"reset")) {
  4109. if( state && map->list[m].flag.reset )
  4110. ;/* nothing to do */
  4111. else {
  4112. if( state )
  4113. map_zone_mf_cache_add(m,"reset\toff");
  4114. else if( map->list[m].flag.reset )
  4115. map_zone_mf_cache_add(m,"reset");
  4116. }
  4117. } else if (!strcmpi(flag,"adjust_unit_duration")) {
  4118. int skill_id, k;
  4119. char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH];
  4120. size_t len = strlen(params);
  4121. modifier[0] = '\0';
  4122. memcpy(skill_name, params, MAP_ZONE_MAPFLAG_LENGTH);
  4123. for(k = 0; k < len; k++) {
  4124. if( skill_name[k] == '\t' ) {
  4125. memcpy(modifier, &skill_name[k+1], len - k);
  4126. skill_name[k] = '\0';
  4127. break;
  4128. }
  4129. }
  4130. if( modifier[0] == '\0' || !( skill_id = skill->name2id(skill_name) ) || !skill->get_unit_id( skill->name2id(skill_name), 0) || atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) {
  4131. ;/* we don't mind it, the server will take care of it next. */
  4132. } else {
  4133. int idx = map->list[m].unit_count;
  4134. ARR_FIND(0, idx, k, map->list[m].units[k]->skill_id == skill_id);
  4135. if( k < idx ) {
  4136. if( atoi(modifier) != map->list[m].units[k]->modifier ) {
  4137. sprintf(rflag,"adjust_unit_duration\t%s\t%d",skill_name,map->list[m].units[k]->modifier);
  4138. map_zone_mf_cache_add(m,rflag);
  4139. }
  4140. } else {
  4141. sprintf(rflag,"adjust_unit_duration\t%s\t100",skill_name);
  4142. map_zone_mf_cache_add(m,rflag);
  4143. }
  4144. }
  4145. } else if (!strcmpi(flag,"adjust_skill_damage")) {
  4146. int skill_id, k;
  4147. char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH];
  4148. size_t len = strlen(params);
  4149. modifier[0] = '\0';
  4150. memcpy(skill_name, params, MAP_ZONE_MAPFLAG_LENGTH);
  4151. for(k = 0; k < len; k++) {
  4152. if( skill_name[k] == '\t' ) {
  4153. memcpy(modifier, &skill_name[k+1], len - k);
  4154. skill_name[k] = '\0';
  4155. break;
  4156. }
  4157. }
  4158. if( modifier[0] == '\0' || !( skill_id = skill->name2id(skill_name) ) || atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) {
  4159. ;/* we don't mind it, the server will take care of it next. */
  4160. } else {
  4161. int idx = map->list[m].skill_count;
  4162. ARR_FIND(0, idx, k, map->list[m].skills[k]->skill_id == skill_id);
  4163. if( k < idx ) {
  4164. if( atoi(modifier) != map->list[m].skills[k]->modifier ) {
  4165. sprintf(rflag,"adjust_skill_damage\t%s\t%d",skill_name,map->list[m].skills[k]->modifier);
  4166. map_zone_mf_cache_add(m,rflag);
  4167. }
  4168. } else {
  4169. sprintf(rflag,"adjust_skill_damage\t%s\t100",skill_name);
  4170. map_zone_mf_cache_add(m,rflag);
  4171. }
  4172. }
  4173. } else if (!strcmpi(flag,"zone")) {
  4174. ShowWarning("You can't add a zone through a zone! ERROR, skipping for '%s'...\n",map->list[m].name);
  4175. return true;
  4176. } else if ( !strcmpi(flag,"nomapchannelautojoin") ) {
  4177. if( state && map->list[m].flag.chsysnolocalaj )
  4178. ;/* nothing to do */
  4179. else {
  4180. if( state )
  4181. map_zone_mf_cache_add(m,"nomapchannelautojoin\toff");
  4182. else if( map->list[m].flag.chsysnolocalaj )
  4183. map_zone_mf_cache_add(m,"nomapchannelautojoin");
  4184. }
  4185. } else if ( !strcmpi(flag,"invincible_time_inc") ) {
  4186. if( !state ) {
  4187. if( map->list[m].invincible_time_inc != 0 ) {
  4188. sprintf(rflag,"invincible_time_inc\t%u",map->list[m].invincible_time_inc);
  4189. map_zone_mf_cache_add(m,rflag);
  4190. }
  4191. } if( sscanf(params, "%d", &state) == 1 ) {
  4192. if( state != map->list[m].invincible_time_inc ) {
  4193. sprintf(rflag,"invincible_time_inc\t%s",params);
  4194. map_zone_mf_cache_add(m,rflag);
  4195. }
  4196. }
  4197. } else if ( !strcmpi(flag,"noknockback") ) {
  4198. if( state && map->list[m].flag.noknockback )
  4199. ;/* nothing to do */
  4200. else {
  4201. if( state )
  4202. map_zone_mf_cache_add(m,"noknockback\toff");
  4203. else if( map->list[m].flag.noknockback )
  4204. map_zone_mf_cache_add(m,"noknockback");
  4205. }
  4206. } else if ( !strcmpi(flag,"weapon_damage_rate") ) {
  4207. if( !state ) {
  4208. if( map->list[m].weapon_damage_rate != 100 ) {
  4209. sprintf(rflag,"weapon_damage_rate\t%d",map->list[m].weapon_damage_rate);
  4210. map_zone_mf_cache_add(m,rflag);
  4211. }
  4212. } if( sscanf(params, "%d", &state) == 1 ) {
  4213. if( state != map->list[m].weapon_damage_rate ) {
  4214. sprintf(rflag,"weapon_damage_rate\t%s",params);
  4215. map_zone_mf_cache_add(m,rflag);
  4216. }
  4217. }
  4218. } else if ( !strcmpi(flag,"magic_damage_rate") ) {
  4219. if( !state ) {
  4220. if( map->list[m].magic_damage_rate != 100 ) {
  4221. sprintf(rflag,"magic_damage_rate\t%d",map->list[m].magic_damage_rate);
  4222. map_zone_mf_cache_add(m,rflag);
  4223. }
  4224. } if( sscanf(params, "%d", &state) == 1 ) {
  4225. if( state != map->list[m].magic_damage_rate ) {
  4226. sprintf(rflag,"magic_damage_rate\t%s",params);
  4227. map_zone_mf_cache_add(m,rflag);
  4228. }
  4229. }
  4230. } else if ( !strcmpi(flag,"misc_damage_rate") ) {
  4231. if( !state ) {
  4232. if( map->list[m].misc_damage_rate != 100 ) {
  4233. sprintf(rflag,"misc_damage_rate\t%d",map->list[m].misc_damage_rate);
  4234. map_zone_mf_cache_add(m,rflag);
  4235. }
  4236. } if( sscanf(params, "%d", &state) == 1 ) {
  4237. if( state != map->list[m].misc_damage_rate ) {
  4238. sprintf(rflag,"misc_damage_rate\t%s",params);
  4239. map_zone_mf_cache_add(m,rflag);
  4240. }
  4241. }
  4242. } else if ( !strcmpi(flag,"short_damage_rate") ) {
  4243. if( !state ) {
  4244. if( map->list[m].short_damage_rate != 100 ) {
  4245. sprintf(rflag,"short_damage_rate\t%d",map->list[m].short_damage_rate);
  4246. map_zone_mf_cache_add(m,rflag);
  4247. }
  4248. } if( sscanf(params, "%d", &state) == 1 ) {
  4249. if( state != map->list[m].short_damage_rate ) {
  4250. sprintf(rflag,"short_damage_rate\t%s",params);
  4251. map_zone_mf_cache_add(m,rflag);
  4252. }
  4253. }
  4254. } else if ( !strcmpi(flag,"long_damage_rate") ) {
  4255. if( !state ) {
  4256. if( map->list[m].long_damage_rate != 100 ) {
  4257. sprintf(rflag,"long_damage_rate\t%d",map->list[m].long_damage_rate);
  4258. map_zone_mf_cache_add(m,rflag);
  4259. }
  4260. } if( sscanf(params, "%d", &state) == 1 ) {
  4261. if( state != map->list[m].long_damage_rate ) {
  4262. sprintf(rflag,"long_damage_rate\t%s",params);
  4263. map_zone_mf_cache_add(m,rflag);
  4264. }
  4265. }
  4266. } else if (!strcmpi(flag,"nocashshop")) {
  4267. if( state && map->list[m].flag.nocashshop )
  4268. ;/* nothing to do */
  4269. else {
  4270. if( state )
  4271. map_zone_mf_cache_add(m,"nocashshop\toff");
  4272. else if( map->list[m].flag.nocashshop )
  4273. map_zone_mf_cache_add(m,"nocashshop");
  4274. }
  4275. }
  4276. return false;
  4277. }
  4278. void map_zone_apply(int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath)
  4279. {
  4280. int i;
  4281. const char *empty = "";
  4282. char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH];
  4283. Assert_retv(m >= 0 && m < map->count);
  4284. nullpo_retv(zone);
  4285. map->list[m].zone = zone;
  4286. for(i = 0; i < zone->mapflags_count; i++) {
  4287. size_t len = strlen(zone->mapflags[i]);
  4288. int k;
  4289. params[0] = '\0';
  4290. memcpy(flag, zone->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH);
  4291. for(k = 0; k < len; k++) {
  4292. if( flag[k] == '\t' ) {
  4293. memcpy(params, &flag[k+1], len - k);
  4294. flag[k] = '\0';
  4295. break;
  4296. }
  4297. }
  4298. if( map->zone_mf_cache(m,flag,params) )
  4299. continue;
  4300. npc->parse_mapflag(map->list[m].name, empty, flag, params, start, buffer, filepath, NULL);
  4301. }
  4302. }
  4303. /* used on npc load and reload to apply all "Normal" and "PK Mode" zones */
  4304. void map_zone_init(void)
  4305. {
  4306. char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH];
  4307. struct map_zone_data *zone;
  4308. const char *empty = "";
  4309. int i,k,j;
  4310. zone = &map->zone_all;
  4311. for(i = 0; i < zone->mapflags_count; i++) {
  4312. size_t len = strlen(zone->mapflags[i]);
  4313. params[0] = '\0';
  4314. memcpy(flag, zone->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH);
  4315. for(k = 0; k < len; k++) {
  4316. if( flag[k] == '\t' ) {
  4317. memcpy(params, &flag[k+1], len - k);
  4318. flag[k] = '\0';
  4319. break;
  4320. }
  4321. }
  4322. for(j = 0; j < map->count; j++) {
  4323. if( map->list[j].zone == zone ) {
  4324. if( map->zone_mf_cache(j,flag,params) )
  4325. break;
  4326. npc->parse_mapflag(map->list[j].name, empty, flag, params, empty, empty, empty, NULL);
  4327. }
  4328. }
  4329. }
  4330. if( battle_config.pk_mode ) {
  4331. zone = &map->zone_pk;
  4332. for(i = 0; i < zone->mapflags_count; i++) {
  4333. size_t len = strlen(zone->mapflags[i]);
  4334. params[0] = '\0';
  4335. memcpy(flag, zone->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH);
  4336. for(k = 0; k < len; k++) {
  4337. if( flag[k] == '\t' ) {
  4338. memcpy(params, &flag[k+1], len - k);
  4339. flag[k] = '\0';
  4340. break;
  4341. }
  4342. }
  4343. for(j = 0; j < map->count; j++) {
  4344. if( map->list[j].zone == zone ) {
  4345. if( map->zone_mf_cache(j,flag,params) )
  4346. break;
  4347. npc->parse_mapflag(map->list[j].name, empty, flag, params, empty, empty, empty, NULL);
  4348. }
  4349. }
  4350. }
  4351. }
  4352. }
  4353. unsigned short map_zone_str2itemid(const char *name) {
  4354. struct item_data *data;
  4355. if( !name )
  4356. return 0;
  4357. if( name[0] == 'I' && name[1] == 'D' && strlen(name) < 8 ) {
  4358. if( !( data = itemdb->exists(atoi(name+2))) ) {
  4359. return 0;
  4360. }
  4361. } else {
  4362. if( !( data = itemdb->search_name(name) ) ) {
  4363. return 0;
  4364. }
  4365. }
  4366. return data->nameid;
  4367. }
  4368. unsigned short map_zone_str2skillid(const char *name) {
  4369. unsigned short nameid = 0;
  4370. if( !name )
  4371. return 0;
  4372. if( name[0] == 'I' && name[1] == 'D' && strlen(name) < 8 ) {
  4373. if( !skill->get_index((nameid = atoi(name+2))) )
  4374. return 0;
  4375. } else {
  4376. if( !( nameid = strdb_iget(skill->name2id_db, name) ) ) {
  4377. return 0;
  4378. }
  4379. }
  4380. return nameid;
  4381. }
  4382. enum bl_type map_zone_bl_type(const char *entry, enum map_zone_skill_subtype *subtype) {
  4383. char temp[200], *parse;
  4384. enum bl_type bl = BL_NUL;
  4385. nullpo_retr(BL_NUL, subtype);
  4386. *subtype = MZS_NONE;
  4387. if( !entry )
  4388. return BL_NUL;
  4389. safestrncpy(temp, entry, 200);
  4390. parse = strtok(temp,"|");
  4391. while (parse != NULL) {
  4392. normalize_name(parse," ");
  4393. if( strcmpi(parse,"player") == 0 )
  4394. bl |= BL_PC;
  4395. else if( strcmpi(parse,"homun") == 0 )
  4396. bl |= BL_HOM;
  4397. else if( strcmpi(parse,"mercenary") == 0 )
  4398. bl |= BL_MER;
  4399. else if( strcmpi(parse,"monster") == 0 )
  4400. bl |= BL_MOB;
  4401. else if( strcmpi(parse,"clone") == 0 ) {
  4402. bl |= BL_MOB;
  4403. *subtype |= MZS_CLONE;
  4404. } else if( strcmpi(parse,"mob_boss") == 0 ) {
  4405. bl |= BL_MOB;
  4406. *subtype |= MZS_BOSS;
  4407. } else if( strcmpi(parse,"elemental") == 0 )
  4408. bl |= BL_ELEM;
  4409. else if( strcmpi(parse,"pet") == 0 )
  4410. bl |= BL_PET;
  4411. else if( strcmpi(parse,"all") == 0 ) {
  4412. bl |= BL_ALL;
  4413. *subtype |= MZS_ALL;
  4414. } else if( strcmpi(parse,"none") == 0 ) {
  4415. bl = BL_NUL;
  4416. } else {
  4417. ShowError("map_zone_db: '%s' unknown type, skipping...\n",parse);
  4418. }
  4419. parse = strtok(NULL,"|");
  4420. }
  4421. return bl;
  4422. }
  4423. /* [Ind/Hercules] */
  4424. void read_map_zone_db(void) {
  4425. config_t map_zone_db;
  4426. config_setting_t *zones = NULL;
  4427. /* TODO: #ifndef required for re/pre-re */
  4428. #ifdef RENEWAL
  4429. const char *config_filename = "db/re/map_zone_db.conf"; // FIXME hardcoded name
  4430. #else
  4431. const char *config_filename = "db/pre-re/map_zone_db.conf"; // FIXME hardcoded name
  4432. #endif
  4433. if (libconfig->read_file(&map_zone_db, config_filename))
  4434. return;
  4435. zones = libconfig->lookup(&map_zone_db, "zones");
  4436. if (zones != NULL) {
  4437. struct map_zone_data *zone;
  4438. config_setting_t *zone_e;
  4439. config_setting_t *skills;
  4440. config_setting_t *items;
  4441. config_setting_t *mapflags;
  4442. config_setting_t *commands;
  4443. config_setting_t *caps;
  4444. const char *name;
  4445. const char *zonename;
  4446. int i,h,v,j;
  4447. int zone_count = 0, disabled_skills_count = 0, disabled_items_count = 0, mapflags_count = 0,
  4448. disabled_commands_count = 0, capped_skills_count = 0;
  4449. enum map_zone_skill_subtype subtype;
  4450. zone_count = libconfig->setting_length(zones);
  4451. for (i = 0; i < zone_count; ++i) {
  4452. bool is_all = false;
  4453. zone_e = libconfig->setting_get_elem(zones, i);
  4454. if (!libconfig->setting_lookup_string(zone_e, "name", &zonename)) {
  4455. ShowError("map_zone_db: missing zone name, skipping... (%s:%d)\n",
  4456. config_setting_source_file(zone_e), config_setting_source_line(zone_e));
  4457. libconfig->setting_remove_elem(zones,i);/* remove from the tree */
  4458. --zone_count;
  4459. --i;
  4460. continue;
  4461. }
  4462. if( strdb_exists(map->zone_db, zonename) ) {
  4463. ShowError("map_zone_db: duplicate zone name '%s', skipping...\n",zonename);
  4464. libconfig->setting_remove_elem(zones,i);/* remove from the tree */
  4465. --zone_count;
  4466. --i;
  4467. continue;
  4468. }
  4469. /* is this the global template? */
  4470. if( strncmpi(zonename,MAP_ZONE_NORMAL_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) {
  4471. zone = &map->zone_all;
  4472. zone->merge_type = MZMT_NEVERMERGE;
  4473. is_all = true;
  4474. } else if( strncmpi(zonename,MAP_ZONE_PK_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) {
  4475. zone = &map->zone_pk;
  4476. zone->merge_type = MZMT_NEVERMERGE;
  4477. is_all = true;
  4478. } else {
  4479. CREATE( zone, struct map_zone_data, 1 );
  4480. zone->merge_type = MZMT_NORMAL;
  4481. zone->disabled_skills_count = 0;
  4482. zone->disabled_items_count = 0;
  4483. }
  4484. safestrncpy(zone->name, zonename, MAP_ZONE_NAME_LENGTH/2);
  4485. if( (skills = libconfig->setting_get_member(zone_e, "disabled_skills")) != NULL ) {
  4486. disabled_skills_count = libconfig->setting_length(skills);
  4487. /* validate */
  4488. for(h = 0; h < libconfig->setting_length(skills); h++) {
  4489. config_setting_t *skillinfo = libconfig->setting_get_elem(skills, h);
  4490. name = config_setting_name(skillinfo);
  4491. if( !map->zone_str2skillid(name) ) {
  4492. ShowError("map_zone_db: unknown skill (%s) in disabled_skills for zone '%s', skipping skill...\n",name,zone->name);
  4493. libconfig->setting_remove_elem(skills,h);
  4494. --disabled_skills_count;
  4495. --h;
  4496. continue;
  4497. }
  4498. if( !map->zone_bl_type(libconfig->setting_get_string_elem(skills,h),&subtype) )/* we don't remove it from the three due to inheritance */
  4499. --disabled_skills_count;
  4500. }
  4501. /* all ok, process */
  4502. CREATE( zone->disabled_skills, struct map_zone_disabled_skill_entry *, disabled_skills_count );
  4503. for(h = 0, v = 0; h < libconfig->setting_length(skills); h++) {
  4504. config_setting_t *skillinfo = libconfig->setting_get_elem(skills, h);
  4505. struct map_zone_disabled_skill_entry * entry;
  4506. enum bl_type type;
  4507. name = config_setting_name(skillinfo);
  4508. if( (type = map->zone_bl_type(libconfig->setting_get_string_elem(skills,h),&subtype)) ) { /* only add if enabled */
  4509. CREATE( entry, struct map_zone_disabled_skill_entry, 1 );
  4510. entry->nameid = map->zone_str2skillid(name);
  4511. entry->type = type;
  4512. entry->subtype = subtype;
  4513. zone->disabled_skills[v++] = entry;
  4514. }
  4515. }
  4516. zone->disabled_skills_count = disabled_skills_count;
  4517. }
  4518. if( (items = libconfig->setting_get_member(zone_e, "disabled_items")) != NULL ) {
  4519. disabled_items_count = libconfig->setting_length(items);
  4520. /* validate */
  4521. for(h = 0; h < libconfig->setting_length(items); h++) {
  4522. config_setting_t *item = libconfig->setting_get_elem(items, h);
  4523. name = config_setting_name(item);
  4524. if( !map->zone_str2itemid(name) ) {
  4525. ShowError("map_zone_db: unknown item (%s) in disabled_items for zone '%s', skipping item...\n",name,zone->name);
  4526. libconfig->setting_remove_elem(items,h);
  4527. --disabled_items_count;
  4528. --h;
  4529. continue;
  4530. }
  4531. if( !libconfig->setting_get_bool(item) )/* we don't remove it from the three due to inheritance */
  4532. --disabled_items_count;
  4533. }
  4534. /* all ok, process */
  4535. CREATE( zone->disabled_items, int, disabled_items_count );
  4536. if( (libconfig->setting_length(items) - disabled_items_count) > 0 ) { //Some are forcefully enabled
  4537. zone->cant_disable_items_count = libconfig->setting_length(items) - disabled_items_count;
  4538. CREATE(zone->cant_disable_items, int, zone->cant_disable_items_count);
  4539. }
  4540. for(h = 0, v = 0, j = 0; h < libconfig->setting_length(items); h++) {
  4541. config_setting_t *item = libconfig->setting_get_elem(items, h);
  4542. name = config_setting_name(item);
  4543. if( libconfig->setting_get_bool(item) ) { /* only add if enabled */
  4544. zone->disabled_items[v++] = map->zone_str2itemid(name);
  4545. } else { /** forcefully enabled **/
  4546. zone->cant_disable_items[j++] = map->zone_str2itemid(name);
  4547. }
  4548. }
  4549. zone->disabled_items_count = disabled_items_count;
  4550. }
  4551. if( (mapflags = libconfig->setting_get_member(zone_e, "mapflags")) != NULL ) {
  4552. mapflags_count = libconfig->setting_length(mapflags);
  4553. /* mapflags are not validated here, so we save all anyway */
  4554. CREATE( zone->mapflags, char *, mapflags_count );
  4555. for(h = 0; h < mapflags_count; h++) {
  4556. CREATE( zone->mapflags[h], char, MAP_ZONE_MAPFLAG_LENGTH );
  4557. name = libconfig->setting_get_string_elem(mapflags, h);
  4558. safestrncpy(zone->mapflags[h], name, MAP_ZONE_MAPFLAG_LENGTH);
  4559. }
  4560. zone->mapflags_count = mapflags_count;
  4561. }
  4562. if( (commands = libconfig->setting_get_member(zone_e, "disabled_commands")) != NULL ) {
  4563. disabled_commands_count = libconfig->setting_length(commands);
  4564. /* validate */
  4565. for(h = 0; h < libconfig->setting_length(commands); h++) {
  4566. config_setting_t *command = libconfig->setting_get_elem(commands, h);
  4567. name = config_setting_name(command);
  4568. if( !atcommand->exists(name) ) {
  4569. ShowError("map_zone_db: unknown command '%s' in disabled_commands for zone '%s', skipping entry...\n",name,zone->name);
  4570. libconfig->setting_remove_elem(commands,h);
  4571. --disabled_commands_count;
  4572. --h;
  4573. continue;
  4574. }
  4575. if( !libconfig->setting_get_int(command) )/* we don't remove it from the three due to inheritance */
  4576. --disabled_commands_count;
  4577. }
  4578. /* all ok, process */
  4579. CREATE( zone->disabled_commands, struct map_zone_disabled_command_entry *, disabled_commands_count );
  4580. for(h = 0, v = 0; h < libconfig->setting_length(commands); h++) {
  4581. config_setting_t *command = libconfig->setting_get_elem(commands, h);
  4582. struct map_zone_disabled_command_entry * entry;
  4583. int group_lv;
  4584. name = config_setting_name(command);
  4585. if( (group_lv = libconfig->setting_get_int(command)) ) { /* only add if enabled */
  4586. CREATE( entry, struct map_zone_disabled_command_entry, 1 );
  4587. entry->cmd = atcommand->exists(name)->func;
  4588. entry->group_lv = group_lv;
  4589. zone->disabled_commands[v++] = entry;
  4590. }
  4591. }
  4592. zone->disabled_commands_count = disabled_commands_count;
  4593. }
  4594. if( (caps = libconfig->setting_get_member(zone_e, "skill_damage_cap")) != NULL ) {
  4595. capped_skills_count = libconfig->setting_length(caps);
  4596. /* validate */
  4597. for(h = 0; h < libconfig->setting_length(caps); h++) {
  4598. config_setting_t *cap = libconfig->setting_get_elem(caps, h);
  4599. name = config_setting_name(cap);
  4600. if( !map->zone_str2skillid(name) ) {
  4601. ShowError("map_zone_db: unknown skill (%s) in skill_damage_cap for zone '%s', skipping skill...\n",name,zone->name);
  4602. libconfig->setting_remove_elem(caps,h);
  4603. --capped_skills_count;
  4604. --h;
  4605. continue;
  4606. }
  4607. if( !map->zone_bl_type(libconfig->setting_get_string_elem(cap,1),&subtype) )/* we don't remove it from the three due to inheritance */
  4608. --capped_skills_count;
  4609. }
  4610. /* all ok, process */
  4611. CREATE( zone->capped_skills, struct map_zone_skill_damage_cap_entry *, capped_skills_count );
  4612. for(h = 0, v = 0; h < libconfig->setting_length(caps); h++) {
  4613. config_setting_t *cap = libconfig->setting_get_elem(caps, h);
  4614. struct map_zone_skill_damage_cap_entry * entry;
  4615. enum bl_type type;
  4616. name = config_setting_name(cap);
  4617. if( (type = map->zone_bl_type(libconfig->setting_get_string_elem(cap,1),&subtype)) ) { /* only add if enabled */
  4618. CREATE( entry, struct map_zone_skill_damage_cap_entry, 1 );
  4619. entry->nameid = map->zone_str2skillid(name);
  4620. entry->cap = libconfig->setting_get_int_elem(cap,0);
  4621. entry->type = type;
  4622. entry->subtype = subtype;
  4623. zone->capped_skills[v++] = entry;
  4624. }
  4625. }
  4626. zone->capped_skills_count = capped_skills_count;
  4627. }
  4628. if( !is_all ) /* global template doesn't go into db -- since it isn't a alloc'd piece of data */
  4629. strdb_put(map->zone_db, zonename, zone);
  4630. }
  4631. /* process inheritance, aka loop through the whole thing again :P */
  4632. for (i = 0; i < zone_count; ++i) {
  4633. config_setting_t *inherit_tree = NULL;
  4634. config_setting_t *new_entry = NULL;
  4635. int inherit_count;
  4636. zone_e = libconfig->setting_get_elem(zones, i);
  4637. libconfig->setting_lookup_string(zone_e, "name", &zonename);
  4638. if( strncmpi(zonename,MAP_ZONE_ALL_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) {
  4639. continue;/* all zone doesn't inherit anything (if it did, everything would link to each other and boom endless loop) */
  4640. }
  4641. if( (inherit_tree = libconfig->setting_get_member(zone_e, "inherit")) != NULL ) {
  4642. /* append global zone to this */
  4643. new_entry = libconfig->setting_add(inherit_tree,MAP_ZONE_ALL_NAME,CONFIG_TYPE_STRING);
  4644. libconfig->setting_set_string(new_entry,MAP_ZONE_ALL_NAME);
  4645. } else {
  4646. /* create inherit member and add global zone to it */
  4647. inherit_tree = libconfig->setting_add(zone_e, "inherit",CONFIG_TYPE_ARRAY);
  4648. new_entry = libconfig->setting_add(inherit_tree,MAP_ZONE_ALL_NAME,CONFIG_TYPE_STRING);
  4649. libconfig->setting_set_string(new_entry,MAP_ZONE_ALL_NAME);
  4650. }
  4651. inherit_count = libconfig->setting_length(inherit_tree);
  4652. for(h = 0; h < inherit_count; h++) {
  4653. struct map_zone_data *izone; /* inherit zone */
  4654. int disabled_skills_count_i = 0; /* disabled skill count from inherit zone */
  4655. int disabled_items_count_i = 0; /* disabled item count from inherit zone */
  4656. int mapflags_count_i = 0; /* mapflag count from inherit zone */
  4657. int disabled_commands_count_i = 0; /* commands count from inherit zone */
  4658. int capped_skills_count_i = 0; /* skill capped count from inherit zone */
  4659. name = libconfig->setting_get_string_elem(inherit_tree, h);
  4660. libconfig->setting_lookup_string(zone_e, "name", &zonename);/* will succeed for we validated it earlier */
  4661. if( !(izone = strdb_get(map->zone_db, name)) ) {
  4662. ShowError("map_zone_db: Unknown zone '%s' being inherit by zone '%s', skipping...\n",name,zonename);
  4663. continue;
  4664. }
  4665. if( strncmpi(zonename,MAP_ZONE_NORMAL_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) {
  4666. zone = &map->zone_all;
  4667. } else if( strncmpi(zonename,MAP_ZONE_PK_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) {
  4668. zone = &map->zone_pk;
  4669. } else
  4670. zone = strdb_get(map->zone_db, zonename);/* will succeed for we just put it in here */
  4671. disabled_skills_count_i = izone->disabled_skills_count;
  4672. disabled_items_count_i = izone->disabled_items_count;
  4673. mapflags_count_i = izone->mapflags_count;
  4674. disabled_commands_count_i = izone->disabled_commands_count;
  4675. capped_skills_count_i = izone->capped_skills_count;
  4676. /* process everything to override, paying attention to config_setting_get_bool */
  4677. if( disabled_skills_count_i ) {
  4678. if( (skills = libconfig->setting_get_member(zone_e, "disabled_skills")) == NULL )
  4679. skills = libconfig->setting_add(zone_e, "disabled_skills",CONFIG_TYPE_GROUP);
  4680. disabled_skills_count = libconfig->setting_length(skills);
  4681. for(j = 0; j < disabled_skills_count_i; j++) {
  4682. int k;
  4683. for(k = 0; k < disabled_skills_count; k++) {
  4684. config_setting_t *skillinfo = libconfig->setting_get_elem(skills, k);
  4685. if( map->zone_str2skillid(config_setting_name(skillinfo)) == izone->disabled_skills[j]->nameid ) {
  4686. break;
  4687. }
  4688. }
  4689. if( k == disabled_skills_count ) {/* we didn't find it */
  4690. struct map_zone_disabled_skill_entry *entry;
  4691. RECREATE( zone->disabled_skills, struct map_zone_disabled_skill_entry *, ++zone->disabled_skills_count );
  4692. CREATE( entry, struct map_zone_disabled_skill_entry, 1 );
  4693. entry->nameid = izone->disabled_skills[j]->nameid;
  4694. entry->type = izone->disabled_skills[j]->type;
  4695. entry->subtype = izone->disabled_skills[j]->subtype;
  4696. zone->disabled_skills[zone->disabled_skills_count-1] = entry;
  4697. }
  4698. }
  4699. }
  4700. if( disabled_items_count_i ) {
  4701. if( (items = libconfig->setting_get_member(zone_e, "disabled_items")) == NULL )
  4702. items = libconfig->setting_add(zone_e, "disabled_items",CONFIG_TYPE_GROUP);
  4703. disabled_items_count = libconfig->setting_length(items);
  4704. for(j = 0; j < disabled_items_count_i; j++) {
  4705. int k;
  4706. for(k = 0; k < disabled_items_count; k++) {
  4707. config_setting_t *item = libconfig->setting_get_elem(items, k);
  4708. name = config_setting_name(item);
  4709. if( map->zone_str2itemid(name) == izone->disabled_items[j] ) {
  4710. if( libconfig->setting_get_bool(item) )
  4711. continue;
  4712. break;
  4713. }
  4714. }
  4715. if( k == disabled_items_count ) {/* we didn't find it */
  4716. RECREATE( zone->disabled_items, int, ++zone->disabled_items_count );
  4717. zone->disabled_items[zone->disabled_items_count-1] = izone->disabled_items[j];
  4718. }
  4719. }
  4720. }
  4721. if( mapflags_count_i ) {
  4722. if( (mapflags = libconfig->setting_get_member(zone_e, "mapflags")) == NULL )
  4723. mapflags = libconfig->setting_add(zone_e, "mapflags",CONFIG_TYPE_ARRAY);
  4724. mapflags_count = libconfig->setting_length(mapflags);
  4725. for(j = 0; j < mapflags_count_i; j++) {
  4726. int k;
  4727. for(k = 0; k < mapflags_count; k++) {
  4728. name = libconfig->setting_get_string_elem(mapflags, k);
  4729. if( strcmpi(name,izone->mapflags[j]) == 0 ) {
  4730. break;
  4731. }
  4732. }
  4733. if( k == mapflags_count ) {/* we didn't find it */
  4734. RECREATE( zone->mapflags, char*, ++zone->mapflags_count );
  4735. CREATE( zone->mapflags[zone->mapflags_count-1], char, MAP_ZONE_MAPFLAG_LENGTH );
  4736. safestrncpy(zone->mapflags[zone->mapflags_count-1], izone->mapflags[j], MAP_ZONE_MAPFLAG_LENGTH);
  4737. }
  4738. }
  4739. }
  4740. if( disabled_commands_count_i ) {
  4741. if( (commands = libconfig->setting_get_member(zone_e, "disabled_commands")) == NULL )
  4742. commands = libconfig->setting_add(zone_e, "disabled_commands",CONFIG_TYPE_GROUP);
  4743. disabled_commands_count = libconfig->setting_length(commands);
  4744. for(j = 0; j < disabled_commands_count_i; j++) {
  4745. int k;
  4746. for(k = 0; k < disabled_commands_count; k++) {
  4747. config_setting_t *command = libconfig->setting_get_elem(commands, k);
  4748. if( atcommand->exists(config_setting_name(command))->func == izone->disabled_commands[j]->cmd ) {
  4749. break;
  4750. }
  4751. }
  4752. if( k == disabled_commands_count ) {/* we didn't find it */
  4753. struct map_zone_disabled_command_entry *entry;
  4754. RECREATE( zone->disabled_commands, struct map_zone_disabled_command_entry *, ++zone->disabled_commands_count );
  4755. CREATE( entry, struct map_zone_disabled_command_entry, 1 );
  4756. entry->cmd = izone->disabled_commands[j]->cmd;
  4757. entry->group_lv = izone->disabled_commands[j]->group_lv;
  4758. zone->disabled_commands[zone->disabled_commands_count-1] = entry;
  4759. }
  4760. }
  4761. }
  4762. if( capped_skills_count_i ) {
  4763. if( (caps = libconfig->setting_get_member(zone_e, "skill_damage_cap")) == NULL )
  4764. caps = libconfig->setting_add(zone_e, "skill_damage_cap",CONFIG_TYPE_GROUP);
  4765. capped_skills_count = libconfig->setting_length(caps);
  4766. for(j = 0; j < capped_skills_count_i; j++) {
  4767. int k;
  4768. for(k = 0; k < capped_skills_count; k++) {
  4769. config_setting_t *cap = libconfig->setting_get_elem(caps, k);
  4770. if( map->zone_str2skillid(config_setting_name(cap)) == izone->capped_skills[j]->nameid ) {
  4771. break;
  4772. }
  4773. }
  4774. if( k == capped_skills_count ) {/* we didn't find it */
  4775. struct map_zone_skill_damage_cap_entry *entry;
  4776. RECREATE( zone->capped_skills, struct map_zone_skill_damage_cap_entry *, ++zone->capped_skills_count );
  4777. CREATE( entry, struct map_zone_skill_damage_cap_entry, 1 );
  4778. entry->nameid = izone->capped_skills[j]->nameid;
  4779. entry->cap = izone->capped_skills[j]->cap;
  4780. entry->type = izone->capped_skills[j]->type;
  4781. entry->subtype = izone->capped_skills[j]->subtype;
  4782. zone->capped_skills[zone->capped_skills_count-1] = entry;
  4783. }
  4784. }
  4785. }
  4786. }
  4787. }
  4788. ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' zones in '"CL_WHITE"%s"CL_RESET"'.\n", zone_count, config_filename);
  4789. /* post-load processing */
  4790. if( (zone = strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)) )
  4791. zone->merge_type = MZMT_MERGEABLE;
  4792. if( (zone = strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)) )
  4793. zone->merge_type = MZMT_MERGEABLE;
  4794. if( (zone = strdb_get(map->zone_db, MAP_ZONE_BG_NAME)) )
  4795. zone->merge_type = MZMT_MERGEABLE;
  4796. }
  4797. /* not supposed to go in here but in skill_final whatever */
  4798. libconfig->destroy(&map_zone_db);
  4799. }
  4800. int map_get_new_bonus_id (void) {
  4801. return map->bonus_id++;
  4802. }
  4803. void map_add_questinfo(int m, struct questinfo *qi) {
  4804. unsigned short i;
  4805. nullpo_retv(qi);
  4806. Assert_retv(m >= 0 && m < map->count);
  4807. /* duplicate, override */
  4808. for(i = 0; i < map->list[m].qi_count; i++) {
  4809. if( map->list[m].qi_data[i].nd == qi->nd )
  4810. break;
  4811. }
  4812. if( i == map->list[m].qi_count )
  4813. RECREATE(map->list[m].qi_data, struct questinfo, ++map->list[m].qi_count);
  4814. memcpy(&map->list[m].qi_data[i], qi, sizeof(struct questinfo));
  4815. }
  4816. bool map_remove_questinfo(int m, struct npc_data *nd) {
  4817. unsigned short i;
  4818. Assert_retr(false, m >= 0 && m < map->count);
  4819. for(i = 0; i < map->list[m].qi_count; i++) {
  4820. struct questinfo *qi = &map->list[m].qi_data[i];
  4821. if( qi->nd == nd ) {
  4822. memset(&map->list[m].qi_data[i], 0, sizeof(struct questinfo));
  4823. if( i != --map->list[m].qi_count ) {
  4824. memmove(&map->list[m].qi_data[i],&map->list[m].qi_data[i+1],sizeof(struct questinfo)*(map->list[m].qi_count-i));
  4825. }
  4826. return true;
  4827. }
  4828. }
  4829. return false;
  4830. }
  4831. /**
  4832. * @see DBApply
  4833. */
  4834. int map_db_final(DBKey key, DBData *data, va_list ap) {
  4835. struct map_data_other_server *mdos = DB->data2ptr(data);
  4836. if(mdos && iMalloc->verify_ptr(mdos) && mdos->cell == NULL)
  4837. aFree(mdos);
  4838. return 0;
  4839. }
  4840. /**
  4841. * @see DBApply
  4842. */
  4843. int nick_db_final(DBKey key, DBData *data, va_list args)
  4844. {
  4845. struct charid2nick* p = DB->data2ptr(data);
  4846. struct charid_request* req;
  4847. if( p == NULL )
  4848. return 0;
  4849. while( p->requests )
  4850. {
  4851. req = p->requests;
  4852. p->requests = req->next;
  4853. aFree(req);
  4854. }
  4855. aFree(p);
  4856. return 0;
  4857. }
  4858. int cleanup_sub(struct block_list *bl, va_list ap) {
  4859. nullpo_ret(bl);
  4860. switch(bl->type) {
  4861. case BL_PC:
  4862. map->quit(BL_UCAST(BL_PC, bl));
  4863. break;
  4864. case BL_NPC:
  4865. npc->unload(BL_UCAST(BL_NPC, bl), false);
  4866. break;
  4867. case BL_MOB:
  4868. unit->free(bl,CLR_OUTSIGHT);
  4869. break;
  4870. case BL_PET:
  4871. //There is no need for this, the pet is removed together with the player. [Skotlex]
  4872. break;
  4873. case BL_ITEM:
  4874. map->clearflooritem(bl);
  4875. break;
  4876. case BL_SKILL:
  4877. skill->delunit(BL_UCAST(BL_SKILL, bl));
  4878. break;
  4879. }
  4880. return 1;
  4881. }
  4882. /**
  4883. * @see DBApply
  4884. */
  4885. int cleanup_db_sub(DBKey key, DBData *data, va_list va) {
  4886. return map->cleanup_sub(DB->data2ptr(data), va);
  4887. }
  4888. /*==========================================
  4889. * map destructor
  4890. *------------------------------------------*/
  4891. int do_final(void) {
  4892. int i;
  4893. struct map_session_data* sd;
  4894. struct s_mapiterator* iter;
  4895. ShowStatus("Terminating...\n");
  4896. channel->config->closing = true;
  4897. HPM->event(HPET_FINAL);
  4898. if (map->cpsd) aFree(map->cpsd);
  4899. //Ladies and babies first.
  4900. iter = mapit_getallusers();
  4901. for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter)))
  4902. map->quit(sd);
  4903. mapit->free(iter);
  4904. /* prepares npcs for a faster shutdown process */
  4905. npc->do_clear_npc();
  4906. // remove all objects on maps
  4907. for (i = 0; i < map->count; i++) {
  4908. ShowStatus("Cleaning up maps [%d/%d]: %s..."CL_CLL"\r", i+1, map->count, map->list[i].name);
  4909. if (map->list[i].m >= 0)
  4910. map->foreachinmap(map->cleanup_sub, i, BL_ALL);
  4911. }
  4912. ShowStatus("Cleaned up %d maps."CL_CLL"\n", map->count);
  4913. if (map->extra_scripts) {
  4914. for (i = 0; i < map->extra_scripts_count; i++)
  4915. aFree(map->extra_scripts[i]);
  4916. aFree(map->extra_scripts);
  4917. map->extra_scripts = NULL;
  4918. map->extra_scripts_count = 0;
  4919. }
  4920. map->id_db->foreach(map->id_db,map->cleanup_db_sub);
  4921. chrif->char_reset_offline();
  4922. chrif->flush();
  4923. atcommand->final();
  4924. battle->final();
  4925. ircbot->final();/* before channel. */
  4926. channel->final();
  4927. chrif->final();
  4928. clif->final();
  4929. npc->final();
  4930. quest->final();
  4931. script->final();
  4932. itemdb->final();
  4933. instance->final();
  4934. gstorage->final();
  4935. guild->final();
  4936. party->final();
  4937. pc->final();
  4938. pet->final();
  4939. mob->final();
  4940. homun->final();
  4941. atcommand->final_msg();
  4942. skill->final();
  4943. status->final();
  4944. unit->final();
  4945. bg->final();
  4946. duel->final();
  4947. elemental->final();
  4948. map->list_final();
  4949. vending->final();
  4950. HPM_map_do_final();
  4951. map->map_db->destroy(map->map_db, map->db_final);
  4952. mapindex->final();
  4953. if(map->enable_grf)
  4954. grfio_final();
  4955. db_destroy(map->id_db);
  4956. db_destroy(map->pc_db);
  4957. db_destroy(map->mobid_db);
  4958. db_destroy(map->bossid_db);
  4959. map->nick_db->destroy(map->nick_db, map->nick_db_final);
  4960. db_destroy(map->charid_db);
  4961. db_destroy(map->iwall_db);
  4962. db_destroy(map->regen_db);
  4963. map->sql_close();
  4964. ers_destroy(map->iterator_ers);
  4965. ers_destroy(map->flooritem_ers);
  4966. aFree(map->list);
  4967. if( map->block_free )
  4968. aFree(map->block_free);
  4969. if( map->bl_list )
  4970. aFree(map->bl_list);
  4971. if( !map->enable_grf )
  4972. aFree(map->cache_buffer);
  4973. aFree(map->MAP_CONF_NAME);
  4974. aFree(map->BATTLE_CONF_FILENAME);
  4975. aFree(map->ATCOMMAND_CONF_FILENAME);
  4976. aFree(map->SCRIPT_CONF_NAME);
  4977. aFree(map->MSG_CONF_NAME);
  4978. aFree(map->GRF_PATH_FILENAME);
  4979. aFree(map->INTER_CONF_NAME);
  4980. aFree(map->LOG_CONF_NAME);
  4981. HPM->event(HPET_POST_FINAL);
  4982. ShowStatus("Finished.\n");
  4983. return map->retval;
  4984. }
  4985. int map_abort_sub(struct map_session_data* sd, va_list ap) {
  4986. chrif->save(sd,1);
  4987. return 1;
  4988. }
  4989. //------------------------------
  4990. // Function called when the server
  4991. // has received a crash signal.
  4992. //------------------------------
  4993. void do_abort(void)
  4994. {
  4995. static int run = 0;
  4996. //Save all characters and then flush the inter-connection.
  4997. if (run) {
  4998. ShowFatalError("Server has crashed while trying to save characters. Character data can't be saved!\n");
  4999. return;
  5000. }
  5001. run = 1;
  5002. if (!chrif->isconnected())
  5003. {
  5004. if (db_size(map->pc_db))
  5005. ShowFatalError("Server has crashed without a connection to the char-server, %u characters can't be saved!\n", db_size(map->pc_db));
  5006. return;
  5007. }
  5008. ShowError("Server received crash signal! Attempting to save all online characters!\n");
  5009. map->foreachpc(map->abort_sub);
  5010. chrif->flush();
  5011. }
  5012. void set_server_type(void) {
  5013. SERVER_TYPE = SERVER_TYPE_MAP;
  5014. }
  5015. /// Called when a terminate signal is received.
  5016. void do_shutdown(void)
  5017. {
  5018. if( core->runflag != MAPSERVER_ST_SHUTDOWN )
  5019. {
  5020. core->runflag = MAPSERVER_ST_SHUTDOWN;
  5021. ShowStatus("Shutting down...\n");
  5022. {
  5023. struct map_session_data* sd;
  5024. struct s_mapiterator* iter = mapit_getallusers();
  5025. for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter)))
  5026. clif->GM_kick(NULL, sd);
  5027. mapit->free(iter);
  5028. sockt->flush_fifos();
  5029. }
  5030. chrif->check_shutdown();
  5031. }
  5032. }
  5033. CPCMD(gm_position) {
  5034. int x = 0, y = 0, m = 0;
  5035. char map_name[25];
  5036. if( line == NULL || sscanf(line, "%d %d %24s",&x,&y,map_name) < 3 ) {
  5037. ShowError("gm:info invalid syntax. use '"CL_WHITE"gm:info xCord yCord map_name"CL_RESET"'\n");
  5038. return;
  5039. }
  5040. if ((m = map->mapname2mapid(map_name)) <= 0) {
  5041. ShowError("gm:info '"CL_WHITE"%s"CL_RESET"' is not a known map\n",map_name);
  5042. return;
  5043. }
  5044. if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) {
  5045. ShowError("gm:info '"CL_WHITE"%d %d"CL_RESET"' is out of '"CL_WHITE"%s"CL_RESET"' map bounds!\n",x,y,map_name);
  5046. return;
  5047. }
  5048. ShowInfo("HCP: updated console's game position to '"CL_WHITE"%d %d %s"CL_RESET"'\n",x,y,map_name);
  5049. map->cpsd->bl.x = x;
  5050. map->cpsd->bl.y = y;
  5051. map->cpsd->bl.m = m;
  5052. }
  5053. CPCMD(gm_use) {
  5054. if( line == NULL ) {
  5055. ShowError("gm:use invalid syntax. use '"CL_WHITE"gm:use @command <optional params>"CL_RESET"'\n");
  5056. return;
  5057. }
  5058. map->cpsd_active = true;
  5059. if( !atcommand->exec(map->cpsd->fd, map->cpsd, line, false) )
  5060. ShowInfo("HCP: '"CL_WHITE"%s"CL_RESET"' failed\n",line);
  5061. else
  5062. ShowInfo("HCP: '"CL_WHITE"%s"CL_RESET"' was used\n",line);
  5063. map->cpsd_active = false;
  5064. }
  5065. /* Hercules Console Parser */
  5066. void map_cp_defaults(void) {
  5067. #ifdef CONSOLE_INPUT
  5068. /* default HCP data */
  5069. map->cpsd = pc->get_dummy_sd();
  5070. strcpy(map->cpsd->status.name, "Hercules Console");
  5071. map->cpsd->bl.x = mapindex->default_x;
  5072. map->cpsd->bl.y = mapindex->default_y;
  5073. map->cpsd->bl.m = map->mapname2mapid(mapindex->default_map);
  5074. console->input->addCommand("gm:info",CPCMD_A(gm_position));
  5075. console->input->addCommand("gm:use",CPCMD_A(gm_use));
  5076. #endif
  5077. }
  5078. void map_load_defaults(void) {
  5079. mapindex_defaults();
  5080. map_defaults();
  5081. /* */
  5082. atcommand_defaults();
  5083. battle_defaults();
  5084. battleground_defaults();
  5085. buyingstore_defaults();
  5086. channel_defaults();
  5087. clif_defaults();
  5088. chrif_defaults();
  5089. guild_defaults();
  5090. gstorage_defaults();
  5091. homunculus_defaults();
  5092. instance_defaults();
  5093. ircbot_defaults();
  5094. itemdb_defaults();
  5095. log_defaults();
  5096. mail_defaults();
  5097. npc_defaults();
  5098. script_defaults();
  5099. searchstore_defaults();
  5100. skill_defaults();
  5101. vending_defaults();
  5102. pc_defaults();
  5103. pc_groups_defaults();
  5104. party_defaults();
  5105. storage_defaults();
  5106. trade_defaults();
  5107. status_defaults();
  5108. chat_defaults();
  5109. duel_defaults();
  5110. elemental_defaults();
  5111. intif_defaults();
  5112. mercenary_defaults();
  5113. mob_defaults();
  5114. unit_defaults();
  5115. mapreg_defaults();
  5116. pet_defaults();
  5117. path_defaults();
  5118. quest_defaults();
  5119. npc_chat_defaults();
  5120. }
  5121. /**
  5122. * --run-once handler
  5123. *
  5124. * Causes the server to run its loop once, and shutdown. Useful for testing.
  5125. * @see cmdline->exec
  5126. */
  5127. static CMDLINEARG(runonce)
  5128. {
  5129. core->runflag = CORE_ST_STOP;
  5130. return true;
  5131. }
  5132. /**
  5133. * --map-config handler
  5134. *
  5135. * Overrides the default map-server configuration filename.
  5136. * @see cmdline->exec
  5137. */
  5138. static CMDLINEARG(mapconfig)
  5139. {
  5140. aFree(map->MAP_CONF_NAME);
  5141. map->MAP_CONF_NAME = aStrdup(params);
  5142. return true;
  5143. }
  5144. /**
  5145. * --battle-config handler
  5146. *
  5147. * Overrides the default battle configuration filename.
  5148. * @see cmdline->exec
  5149. */
  5150. static CMDLINEARG(battleconfig)
  5151. {
  5152. aFree(map->BATTLE_CONF_FILENAME);
  5153. map->BATTLE_CONF_FILENAME = aStrdup(params);
  5154. return true;
  5155. }
  5156. /**
  5157. * --atcommand-config handler
  5158. *
  5159. * Overrides the default atcommands configuration filename.
  5160. * @see cmdline->exec
  5161. */
  5162. static CMDLINEARG(atcommandconfig)
  5163. {
  5164. aFree(map->ATCOMMAND_CONF_FILENAME);
  5165. map->ATCOMMAND_CONF_FILENAME = aStrdup(params);
  5166. return true;
  5167. }
  5168. /**
  5169. * --script-config handler
  5170. *
  5171. * Overrides the default script configuration filename.
  5172. * @see cmdline->exec
  5173. */
  5174. static CMDLINEARG(scriptconfig)
  5175. {
  5176. aFree(map->SCRIPT_CONF_NAME);
  5177. map->SCRIPT_CONF_NAME = aStrdup(params);
  5178. return true;
  5179. }
  5180. /**
  5181. * --msg-config handler
  5182. *
  5183. * Overrides the default messages configuration filename.
  5184. * @see cmdline->exec
  5185. */
  5186. static CMDLINEARG(msgconfig)
  5187. {
  5188. aFree(map->MSG_CONF_NAME);
  5189. map->MSG_CONF_NAME = aStrdup(params);
  5190. return true;
  5191. }
  5192. /**
  5193. * --grf-path handler
  5194. *
  5195. * Overrides the default grf configuration filename.
  5196. * @see cmdline->exec
  5197. */
  5198. static CMDLINEARG(grfpath)
  5199. {
  5200. aFree(map->GRF_PATH_FILENAME);
  5201. map->GRF_PATH_FILENAME = aStrdup(params);
  5202. return true;
  5203. }
  5204. /**
  5205. * --inter-config handler
  5206. *
  5207. * Overrides the default inter-server configuration filename.
  5208. * @see cmdline->exec
  5209. */
  5210. static CMDLINEARG(interconfig)
  5211. {
  5212. aFree(map->INTER_CONF_NAME);
  5213. map->INTER_CONF_NAME = aStrdup(params);
  5214. return true;
  5215. }
  5216. /**
  5217. * --log-config handler
  5218. *
  5219. * Overrides the default log configuration filename.
  5220. * @see cmdline->exec
  5221. */
  5222. static CMDLINEARG(logconfig)
  5223. {
  5224. aFree(map->LOG_CONF_NAME);
  5225. map->LOG_CONF_NAME = aStrdup(params);
  5226. return true;
  5227. }
  5228. /**
  5229. * --script-check handler
  5230. *
  5231. * Enables script-check mode. Checks scripts and quits without running.
  5232. * @see cmdline->exec
  5233. */
  5234. static CMDLINEARG(scriptcheck)
  5235. {
  5236. map->minimal = true;
  5237. core->runflag = CORE_ST_STOP;
  5238. map->scriptcheck = true;
  5239. return true;
  5240. }
  5241. /**
  5242. * --load-script handler
  5243. *
  5244. * Adds a filename to the script auto-load list.
  5245. * @see cmdline->exec
  5246. */
  5247. static CMDLINEARG(loadscript)
  5248. {
  5249. RECREATE(map->extra_scripts, char *, ++map->extra_scripts_count);
  5250. map->extra_scripts[map->extra_scripts_count-1] = aStrdup(params);
  5251. return true;
  5252. }
  5253. /**
  5254. * --generate-translations
  5255. *
  5256. * Creates "./generated_translations.pot"
  5257. * @see cmdline->exec
  5258. **/
  5259. static CMDLINEARG(generatetranslations) {
  5260. script->lang_export_file = aStrdup("./generated_translations.pot");
  5261. if( !(script->lang_export_fp = fopen(script->lang_export_file,"wb")) ) {
  5262. ShowError("export-dialog: failed to open '%s' for writing\n",script->lang_export_file);
  5263. }
  5264. core->runflag = CORE_ST_STOP;
  5265. return true;
  5266. }
  5267. /**
  5268. * Defines the local command line arguments
  5269. */
  5270. void cmdline_args_init_local(void)
  5271. {
  5272. CMDLINEARG_DEF2(run-once, runonce, "Closes server after loading (testing).", CMDLINE_OPT_NORMAL);
  5273. CMDLINEARG_DEF2(map-config, mapconfig, "Alternative map-server configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5274. CMDLINEARG_DEF2(battle-config, battleconfig, "Alternative battle configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5275. CMDLINEARG_DEF2(atcommand-config, atcommandconfig, "Alternative atcommand configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5276. CMDLINEARG_DEF2(script-config, scriptconfig, "Alternative script configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5277. CMDLINEARG_DEF2(msg-config, msgconfig, "Alternative message configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5278. CMDLINEARG_DEF2(grf-path, grfpath, "Alternative GRF path configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5279. CMDLINEARG_DEF2(inter-config, interconfig, "Alternative inter-server configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5280. CMDLINEARG_DEF2(log-config, logconfig, "Alternative logging configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5281. CMDLINEARG_DEF2(script-check, scriptcheck, "Doesn't run the server, only tests the scripts passed through --load-script.", CMDLINE_OPT_SILENT);
  5282. CMDLINEARG_DEF2(load-script, loadscript, "Loads an additional script (can be repeated).", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
  5283. CMDLINEARG_DEF2(generate-translations, generatetranslations, "Creates './generated_translations.pot' file with all translateable strings from scripts, server terminates afterwards.", CMDLINE_OPT_NORMAL);
  5284. }
  5285. int do_init(int argc, char *argv[])
  5286. {
  5287. bool minimal = false;
  5288. int i;
  5289. #ifdef GCOLLECT
  5290. GC_enable_incremental();
  5291. #endif
  5292. map_load_defaults();
  5293. map->INTER_CONF_NAME = aStrdup("conf/inter-server.conf");
  5294. map->LOG_CONF_NAME = aStrdup("conf/logs.conf");
  5295. map->MAP_CONF_NAME = aStrdup("conf/map-server.conf");
  5296. map->BATTLE_CONF_FILENAME = aStrdup("conf/battle.conf");
  5297. map->ATCOMMAND_CONF_FILENAME = aStrdup("conf/atcommand.conf");
  5298. map->SCRIPT_CONF_NAME = aStrdup("conf/script.conf");
  5299. map->MSG_CONF_NAME = aStrdup("conf/messages.conf");
  5300. map->GRF_PATH_FILENAME = aStrdup("conf/grf-files.txt");
  5301. HPM_map_do_init();
  5302. cmdline->exec(argc, argv, CMDLINE_OPT_PREINIT);
  5303. HPM->config_read();
  5304. HPM->event(HPET_PRE_INIT);
  5305. cmdline->exec(argc, argv, CMDLINE_OPT_NORMAL);
  5306. minimal = map->minimal;/* temp (perhaps make minimal a mask with options of what to load? e.g. plugin 1 does minimal |= mob_db; */
  5307. if (!minimal) {
  5308. map->config_read(map->MAP_CONF_NAME);
  5309. CREATE(map->list,struct map_data,map->count);
  5310. map->count = 0;
  5311. map->config_read_sub(map->MAP_CONF_NAME);
  5312. // loads npcs
  5313. map->reloadnpc(false);
  5314. chrif->checkdefaultlogin();
  5315. if (!map->ip_set || !map->char_ip_set) {
  5316. char ip_str[16];
  5317. sockt->ip2str(sockt->addr_[0], ip_str);
  5318. ShowWarning("Not all IP addresses in /conf/map-server.conf configured, auto-detecting...\n");
  5319. if (sockt->naddr_ == 0)
  5320. ShowError("Unable to determine your IP address...\n");
  5321. else if (sockt->naddr_ > 1)
  5322. ShowNotice("Multiple interfaces detected...\n");
  5323. ShowInfo("Defaulting to %s as our IP address\n", ip_str);
  5324. if (!map->ip_set)
  5325. clif->setip(ip_str);
  5326. if (!map->char_ip_set)
  5327. chrif->setip(ip_str);
  5328. }
  5329. battle->config_read(map->BATTLE_CONF_FILENAME);
  5330. atcommand->msg_read(map->MSG_CONF_NAME, false);
  5331. map->inter_config_read(map->INTER_CONF_NAME);
  5332. logs->config_read(map->LOG_CONF_NAME);
  5333. }
  5334. script->config_read(map->SCRIPT_CONF_NAME);
  5335. map->id_db = idb_alloc(DB_OPT_BASE);
  5336. map->pc_db = idb_alloc(DB_OPT_BASE); //Added for reliable map->id2sd() use. [Skotlex]
  5337. map->mobid_db = idb_alloc(DB_OPT_BASE); //Added to lower the load of the lazy mob AI. [Skotlex]
  5338. map->bossid_db = idb_alloc(DB_OPT_BASE); // Used for Convex Mirror quick MVP search
  5339. map->map_db = uidb_alloc(DB_OPT_BASE);
  5340. map->nick_db = idb_alloc(DB_OPT_BASE);
  5341. map->charid_db = idb_alloc(DB_OPT_BASE);
  5342. map->regen_db = idb_alloc(DB_OPT_BASE); // efficient status_natural_heal processing
  5343. map->iwall_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, 2*NAME_LENGTH+2+1); // [Zephyrus] Invisible Walls
  5344. map->zone_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, MAP_ZONE_NAME_LENGTH);
  5345. map->iterator_ers = ers_new(sizeof(struct s_mapiterator),"map.c::map_iterator_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK);
  5346. ers_chunk_size(map->iterator_ers, 25);
  5347. map->flooritem_ers = ers_new(sizeof(struct flooritem_data),"map.c::map_flooritem_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK);
  5348. ers_chunk_size(map->flooritem_ers, 100);
  5349. if (!minimal) {
  5350. map->sql_init();
  5351. if (logs->config.sql_logs)
  5352. logs->sql_init();
  5353. }
  5354. i = mapindex->init();
  5355. if (minimal) {
  5356. // Pretend all maps from the mapindex are on this mapserver
  5357. CREATE(map->list,struct map_data,i);
  5358. for( i = 0; i < MAX_MAPINDEX; i++ ) {
  5359. if (mapindex_exists(i)) {
  5360. map->addmap(mapindex_id2name(i));
  5361. }
  5362. }
  5363. }
  5364. if(map->enable_grf)
  5365. grfio_init(map->GRF_PATH_FILENAME);
  5366. map->readallmaps();
  5367. if (!minimal) {
  5368. timer->add_func_list(map->freeblock_timer, "map_freeblock_timer");
  5369. timer->add_func_list(map->clearflooritem_timer, "map_clearflooritem_timer");
  5370. timer->add_func_list(map->removemobs_timer, "map_removemobs_timer");
  5371. timer->add_interval(timer->gettick()+1000, map->freeblock_timer, 0, 0, 60*1000);
  5372. HPM->event(HPET_INIT);
  5373. }
  5374. atcommand->init(minimal);
  5375. battle->init(minimal);
  5376. instance->init(minimal);
  5377. channel->init(minimal);
  5378. chrif->init(minimal);
  5379. clif->init(minimal);
  5380. ircbot->init(minimal);
  5381. script->init(minimal);
  5382. itemdb->init(minimal);
  5383. skill->init(minimal);
  5384. if (!minimal)
  5385. map->read_zone_db();/* read after item and skill initialization */
  5386. mob->init(minimal);
  5387. pc->init(minimal);
  5388. status->init(minimal);
  5389. party->init(minimal);
  5390. guild->init(minimal);
  5391. gstorage->init(minimal);
  5392. pet->init(minimal);
  5393. homun->init(minimal);
  5394. mercenary->init(minimal);
  5395. elemental->init(minimal);
  5396. quest->init(minimal);
  5397. npc->init(minimal);
  5398. unit->init(minimal);
  5399. bg->init(minimal);
  5400. duel->init(minimal);
  5401. vending->init(minimal);
  5402. if (map->scriptcheck) {
  5403. bool failed = map->extra_scripts_count > 0 ? false : true;
  5404. for (i = 0; i < map->extra_scripts_count; i++) {
  5405. if (npc->parsesrcfile(map->extra_scripts[i], false) != EXIT_SUCCESS)
  5406. failed = true;
  5407. }
  5408. if (failed)
  5409. exit(EXIT_FAILURE);
  5410. exit(EXIT_SUCCESS);
  5411. }
  5412. if( minimal ) {
  5413. HPM->event(HPET_READY);
  5414. exit(EXIT_SUCCESS);
  5415. }
  5416. npc->event_do_oninit( false ); // Init npcs (OnInit)
  5417. npc->market_fromsql(); /* after OnInit */
  5418. if (battle_config.pk_mode)
  5419. ShowNotice("Server is running on '"CL_WHITE"PK Mode"CL_RESET"'.\n");
  5420. Sql_HerculesUpdateCheck(map->mysql_handle);
  5421. #ifdef CONSOLE_INPUT
  5422. console->input->setSQL(map->mysql_handle);
  5423. if (!minimal && core->runflag != CORE_ST_STOP)
  5424. console->display_gplnotice();
  5425. #endif
  5426. ShowStatus("Server is '"CL_GREEN"ready"CL_RESET"' and listening on port '"CL_WHITE"%d"CL_RESET"'.\n\n", map->port);
  5427. if( core->runflag != CORE_ST_STOP ) {
  5428. core->shutdown_callback = map->do_shutdown;
  5429. core->runflag = MAPSERVER_ST_RUNNING;
  5430. }
  5431. map_cp_defaults();
  5432. HPM->event(HPET_READY);
  5433. return 0;
  5434. }
  5435. /*=====================================
  5436. * Default Functions : map.h
  5437. * Generated by HerculesInterfaceMaker
  5438. * created by Susu
  5439. *-------------------------------------*/
  5440. void map_defaults(void) {
  5441. map = &map_s;
  5442. /* */
  5443. map->minimal = false;
  5444. map->scriptcheck = false;
  5445. map->count = 0;
  5446. map->retval = EXIT_SUCCESS;
  5447. map->extra_scripts = NULL;
  5448. map->extra_scripts_count = 0;
  5449. sprintf(map->db_path ,"db");
  5450. sprintf(map->help_txt ,"conf/help.txt");
  5451. sprintf(map->help2_txt ,"conf/help2.txt");
  5452. sprintf(map->charhelp_txt ,"conf/charhelp.txt");
  5453. sprintf(map->wisp_server_name ,"Server"); // can be modified in char-server configuration file
  5454. map->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  5455. map->minsave_interval = 100;
  5456. map->save_settings = 0xFFFF;
  5457. map->agit_flag = 0;
  5458. map->agit2_flag = 0;
  5459. map->night_flag = 0; // 0=day, 1=night [Yor]
  5460. map->enable_spy = 0; //To enable/disable @spy commands, which consume too much cpu time when sending packets. [Skotlex]
  5461. map->INTER_CONF_NAME="conf/inter-server.conf";
  5462. map->LOG_CONF_NAME="conf/logs.conf";
  5463. map->MAP_CONF_NAME = "conf/map-server.conf";
  5464. map->BATTLE_CONF_FILENAME = "conf/battle.conf";
  5465. map->ATCOMMAND_CONF_FILENAME = "conf/atcommand.conf";
  5466. map->SCRIPT_CONF_NAME = "conf/script.conf";
  5467. map->MSG_CONF_NAME = "conf/messages.conf";
  5468. map->GRF_PATH_FILENAME = "conf/grf-files.txt";
  5469. map->default_codepage[0] = '\0';
  5470. map->server_port = 3306;
  5471. sprintf(map->server_ip,"127.0.0.1");
  5472. sprintf(map->server_id,"ragnarok");
  5473. sprintf(map->server_pw,"ragnarok");
  5474. sprintf(map->server_db,"ragnarok");
  5475. map->mysql_handle = NULL;
  5476. map->default_lang_str[0] = '\0';
  5477. map->cpsd_active = false;
  5478. map->port = 0;
  5479. map->users = 0;
  5480. map->ip_set = 0;
  5481. map->char_ip_set = 0;
  5482. map->enable_grf = 0;
  5483. memset(&map->index2mapid, -1, sizeof(map->index2mapid));
  5484. map->id_db = NULL;
  5485. map->pc_db = NULL;
  5486. map->mobid_db = NULL;
  5487. map->bossid_db = NULL;
  5488. map->map_db = NULL;
  5489. map->nick_db = NULL;
  5490. map->charid_db = NULL;
  5491. map->regen_db = NULL;
  5492. map->zone_db = NULL;
  5493. map->iwall_db = NULL;
  5494. map->block_free = NULL;
  5495. map->block_free_count = 0;
  5496. map->block_free_lock = 0;
  5497. map->block_free_list_size = 0;
  5498. map->bl_list = NULL;
  5499. map->bl_list_count = 0;
  5500. map->bl_list_size = 0;
  5501. //all in a big chunk, respects order
  5502. memset(ZEROED_BLOCK_POS(map), 0, ZEROED_BLOCK_SIZE(map));
  5503. map->cpsd = NULL;
  5504. map->list = NULL;
  5505. map->iterator_ers = NULL;
  5506. map->cache_buffer = NULL;
  5507. map->flooritem_ers = NULL;
  5508. /* */
  5509. map->bonus_id = SP_LAST_KNOWN;
  5510. /* funcs */
  5511. map->zone_init = map_zone_init;
  5512. map->zone_remove = map_zone_remove;
  5513. map->zone_apply = map_zone_apply;
  5514. map->zone_change = map_zone_change;
  5515. map->zone_change2 = map_zone_change2;
  5516. map->getcell = map_getcell;
  5517. map->setgatcell = map_setgatcell;
  5518. map->cellfromcache = map_cellfromcache;
  5519. // users
  5520. map->setusers = map_setusers;
  5521. map->getusers = map_getusers;
  5522. map->usercount = map_usercount;
  5523. // blocklist lock
  5524. map->freeblock = map_freeblock;
  5525. map->freeblock_lock = map_freeblock_lock;
  5526. map->freeblock_unlock = map_freeblock_unlock;
  5527. // blocklist manipulation
  5528. map->addblock = map_addblock;
  5529. map->delblock = map_delblock;
  5530. map->moveblock = map_moveblock;
  5531. //blocklist nb in one cell
  5532. map->count_oncell = map_count_oncell;
  5533. map->find_skill_unit_oncell = map_find_skill_unit_oncell;
  5534. // search and creation
  5535. map->get_new_object_id = map_get_new_object_id;
  5536. map->search_freecell = map_search_freecell;
  5537. map->closest_freecell = map_closest_freecell;
  5538. //
  5539. map->quit = map_quit;
  5540. // npc
  5541. map->addnpc = map_addnpc;
  5542. // map item
  5543. map->clearflooritem_timer = map_clearflooritem_timer;
  5544. map->removemobs_timer = map_removemobs_timer;
  5545. map->clearflooritem = map_clearflooritem;
  5546. map->addflooritem = map_addflooritem;
  5547. // player to map session
  5548. map->addnickdb = map_addnickdb;
  5549. map->delnickdb = map_delnickdb;
  5550. map->reqnickdb = map_reqnickdb;
  5551. map->charid2nick = map_charid2nick;
  5552. map->charid2sd = map_charid2sd;
  5553. map->vforeachpc = map_vforeachpc;
  5554. map->foreachpc = map_foreachpc;
  5555. map->vforeachmob = map_vforeachmob;
  5556. map->foreachmob = map_foreachmob;
  5557. map->vforeachnpc = map_vforeachnpc;
  5558. map->foreachnpc = map_foreachnpc;
  5559. map->vforeachregen = map_vforeachregen;
  5560. map->foreachregen = map_foreachregen;
  5561. map->vforeachiddb = map_vforeachiddb;
  5562. map->foreachiddb = map_foreachiddb;
  5563. map->vforeachinrange = map_vforeachinrange;
  5564. map->foreachinrange = map_foreachinrange;
  5565. map->vforeachinshootrange = map_vforeachinshootrange;
  5566. map->foreachinshootrange = map_foreachinshootrange;
  5567. map->vforeachinarea = map_vforeachinarea;
  5568. map->foreachinarea = map_foreachinarea;
  5569. map->vforcountinrange = map_vforcountinrange;
  5570. map->forcountinrange = map_forcountinrange;
  5571. map->vforcountinarea = map_vforcountinarea;
  5572. map->forcountinarea = map_forcountinarea;
  5573. map->vforeachinmovearea = map_vforeachinmovearea;
  5574. map->foreachinmovearea = map_foreachinmovearea;
  5575. map->vforeachincell = map_vforeachincell;
  5576. map->foreachincell = map_foreachincell;
  5577. map->vforeachinpath = map_vforeachinpath;
  5578. map->foreachinpath = map_foreachinpath;
  5579. map->vforeachinmap = map_vforeachinmap;
  5580. map->foreachinmap = map_foreachinmap;
  5581. map->vforeachininstance = map_vforeachininstance;
  5582. map->foreachininstance = map_foreachininstance;
  5583. map->id2sd = map_id2sd;
  5584. map->id2nd = map_id2nd;
  5585. map->id2md = map_id2md;
  5586. map->id2fi = map_id2fi;
  5587. map->id2cd = map_id2cd;
  5588. map->id2su = map_id2su;
  5589. map->id2pd = map_id2pd;
  5590. map->id2hd = map_id2hd;
  5591. map->id2mc = map_id2mc;
  5592. map->id2ed = map_id2ed;
  5593. map->id2bl = map_id2bl;
  5594. map->blid_exists = map_blid_exists;
  5595. map->mapindex2mapid = map_mapindex2mapid;
  5596. map->mapname2mapid = map_mapname2mapid;
  5597. map->mapname2ipport = map_mapname2ipport;
  5598. map->setipport = map_setipport;
  5599. map->eraseipport = map_eraseipport;
  5600. map->eraseallipport = map_eraseallipport;
  5601. map->addiddb = map_addiddb;
  5602. map->deliddb = map_deliddb;
  5603. /* */
  5604. map->nick2sd = map_nick2sd;
  5605. map->getmob_boss = map_getmob_boss;
  5606. map->id2boss = map_id2boss;
  5607. map->race_id2mask = map_race_id2mask;
  5608. // reload config file looking only for npcs
  5609. map->reloadnpc = map_reloadnpc;
  5610. map->check_dir = map_check_dir;
  5611. map->calc_dir = map_calc_dir;
  5612. map->random_dir = map_random_dir; // [Skotlex]
  5613. map->cleanup_sub = cleanup_sub;
  5614. map->delmap = map_delmap;
  5615. map->flags_init = map_flags_init;
  5616. map->iwall_set = map_iwall_set;
  5617. map->iwall_get = map_iwall_get;
  5618. map->iwall_remove = map_iwall_remove;
  5619. map->addmobtolist = map_addmobtolist; // [Wizputer]
  5620. map->spawnmobs = map_spawnmobs; // [Wizputer]
  5621. map->removemobs = map_removemobs; // [Wizputer]
  5622. map->addmap2db = map_addmap2db;
  5623. map->removemapdb = map_removemapdb;
  5624. map->clean = map_clean;
  5625. map->do_shutdown = do_shutdown;
  5626. map->freeblock_timer = map_freeblock_timer;
  5627. map->searchrandfreecell = map_searchrandfreecell;
  5628. map->count_sub = map_count_sub;
  5629. map->create_charid2nick = create_charid2nick;
  5630. map->removemobs_sub = map_removemobs_sub;
  5631. map->gat2cell = map_gat2cell;
  5632. map->cell2gat = map_cell2gat;
  5633. map->getcellp = map_getcellp;
  5634. map->setcell = map_setcell;
  5635. map->sub_getcellp = map_sub_getcellp;
  5636. map->sub_setcell = map_sub_setcell;
  5637. map->iwall_nextxy = map_iwall_nextxy;
  5638. map->create_map_data_other_server = create_map_data_other_server;
  5639. map->eraseallipport_sub = map_eraseallipport_sub;
  5640. map->init_mapcache = map_init_mapcache;
  5641. map->readfromcache = map_readfromcache;
  5642. map->addmap = map_addmap;
  5643. map->delmapid = map_delmapid;
  5644. map->zone_db_clear = map_zone_db_clear;
  5645. map->list_final = do_final_maps;
  5646. map->waterheight = map_waterheight;
  5647. map->readgat = map_readgat;
  5648. map->readallmaps = map_readallmaps;
  5649. map->config_read = map_config_read;
  5650. map->config_read_sub = map_config_read_sub;
  5651. map->reloadnpc_sub = map_reloadnpc_sub;
  5652. map->inter_config_read = inter_config_read;
  5653. map->sql_init = map_sql_init;
  5654. map->sql_close = map_sql_close;
  5655. map->zone_mf_cache = map_zone_mf_cache;
  5656. map->zone_str2itemid = map_zone_str2itemid;
  5657. map->zone_str2skillid = map_zone_str2skillid;
  5658. map->zone_bl_type = map_zone_bl_type;
  5659. map->read_zone_db = read_map_zone_db;
  5660. map->db_final = map_db_final;
  5661. map->nick_db_final = nick_db_final;
  5662. map->cleanup_db_sub = cleanup_db_sub;
  5663. map->abort_sub = map_abort_sub;
  5664. map->update_cell_bl = map_update_cell_bl;
  5665. map->get_new_bonus_id = map_get_new_bonus_id;
  5666. map->add_questinfo = map_add_questinfo;
  5667. map->remove_questinfo = map_remove_questinfo;
  5668. map->merge_zone = map_merge_zone;
  5669. map->zone_clear_single = map_zone_clear_single;
  5670. /**
  5671. * mapit interface
  5672. **/
  5673. mapit = &mapit_s;
  5674. mapit->alloc = mapit_alloc;
  5675. mapit->free = mapit_free;
  5676. mapit->first = mapit_first;
  5677. mapit->last = mapit_last;
  5678. mapit->next = mapit_next;
  5679. mapit->prev = mapit_prev;
  5680. mapit->exists = mapit_exists;
  5681. }