PageRenderTime 145ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 2ms

/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

Large files files are truncated, but you can click here to view the full file

  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_a

Large files files are truncated, but you can click here to view the full file