diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map/mob.cpp | 69 |
1 files changed, 59 insertions, 10 deletions
diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 4fd9d6d..4097230 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -2,7 +2,7 @@ // mob.cpp - Really scary code. // // Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2004-2024 The Mana World Development Team // Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> // Copyright © 2013 Freeyorp // @@ -1132,7 +1132,6 @@ int mob_setdelayspawn(BlockId id) */ int mob_spawn(BlockId id) { - int x = 0, y = 0; tick_t tick = gettick(); dumb_ptr<mob_data> md; dumb_ptr<block_list> bl; @@ -1155,11 +1154,19 @@ int mob_spawn(BlockId id) map_delblock(md); } + // good coordinates, passability test only. + int good_x = 0, good_y = 0; + // best coordinates + int best_x = 0, best_y = 0, best_distance = -1; + md->bl_m = md->spawn.m; { - int i = 0; - do + int coord_test_count = 0; + int proximity_test_count = 0; + + for (; coord_test_count < 50; ++coord_test_count) { + int x = 0, y = 0; if (md->spawn.x0 == 0 && md->spawn.y0 == 0) { x = random_::in(1, md->bl_m->xs - 2); @@ -1172,12 +1179,54 @@ int mob_spawn(BlockId id) x = md->spawn.x0 - md->spawn.xs / 2 + random_::in(0, md->spawn.xs); y = md->spawn.y0 - md->spawn.ys / 2 + random_::in(0, md->spawn.ys); } - i++; + + if (bool(map_getcell(md->bl_m, x, y) & MapCell::UNWALKABLE)) + continue; + + // Record good coordinates + good_x = x; + good_y = y; + + // Set to 5 attempts, because + // (1) That's what ML is set to; + // (2) TODO foreachinarea fills up a std::vector... expensive. + if (proximity_test_count < 5) + { + proximity_test_count++; + + int min_distance = std::numeric_limits<int>::max(); + auto proximity_check = [&x, &y, &min_distance](dumb_ptr<block_list> bl) + { + // Set min_distance to closest player's distance + int dx = abs(bl->bl_x - x); + int dy = abs(bl->bl_y - y); + int dist = std::max(dx, dy); + if (dist < min_distance) + min_distance = dist; + }; + //map_foreachinarea(std::bind(clif_movemob_sub, ph::_1, md), + map_foreachinarea(proximity_check, + md->bl_m, + x - AREA_SIZE, y - AREA_SIZE, + x + AREA_SIZE, y + AREA_SIZE, + BL::PC); + + // update best coordinates, if needed + if (min_distance > best_distance) + { + best_x = x; + best_y = y; + best_distance = min_distance; + } + + if (min_distance < AREA_SIZE) + continue; // try harder + } + + break; // above two tests passed. } - while (bool(map_getcell(md->bl_m, x, y) & MapCell::UNWALKABLE) - && i < 50); - if (i >= 50) + if (coord_test_count >= 50) { Timer(tick + 5_s, std::bind(mob_delayspawn, ph::_1, ph::_2, @@ -1187,8 +1236,8 @@ int mob_spawn(BlockId id) } } - md->to_x = md->bl_x = x; - md->to_y = md->bl_y = y; + md->to_x = md->bl_x = good_x; + md->to_y = md->bl_y = good_y; md->dir = DIR::S; map_addblock(md); |