summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFedja Beader <fedja@protonmail.ch>2024-02-27 21:16:21 +0100
committerFedja Beader <fedja@protonmail.ch>2024-02-27 21:27:59 +0100
commitffe1f2785a134bab3cb46b7dac99792583d15519 (patch)
treefa1cdd86ec752c58ef7aa7b0416575daf9dd7fa0
parenteaf17b389e9f66aaca443da61c0b3d93e04c9926 (diff)
downloadtmwa-mobspawn.tar.gz
tmwa-mobspawn.tar.bz2
tmwa-mobspawn.tar.xz
tmwa-mobspawn.zip
Try not to respawn monsters in player visual rangemobspawn
-rw-r--r--src/map/mob.cpp69
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);