Closed igroglaz closed 2 years ago
I suppose this problem appeared several months ago.. I've met it sometimes, but didn't bother about it as it was in the dungeons and not so obvious as we can see at the video above.. Now I've looked into AI to check surrounding and found out that we have problems in it.
Also I suppose there is an elegant way to solve problem with corridors AI: allow 'friends' monsters to push each other in monster_turn_try_push()
My (broken so far) attempt to do it:
// push 'friend' monster
// 1) check grids around player
// 2) if empty spot found - push friendly monster on it
// 3) after that move to this grind by yourself
// pushed mob should be already near player
if (push_ok && mon1->cdis == 1)
{
// 1) check grids around player
int i;
struct loc grid_push;
int tmp = randint0(8);
// just in case
loc_copy(&grid_push, &who->player->grid);
/* Find an empty square near the player to fill */
for (i = 0; i < 8; i++)
{
/* Pick squares near player (pseudo-randomly) */
loc_sum(&grid_push, &who->player->grid, &ddgrid_ddd[(tmp + i) & 7]);
/* Ignore filled grids */
if (!square_isemptyfloor(c, &grid_push))
continue;
// if it's too far away - don't 'jump' there
// difference between grids to check are they close to each other:
// this should be 0 or this 0 ... if > 0: continue
if ((abs((grid_push.x) - grid->x)) - 1 || (abs((grid_push.y) - grid->y)) - 1)
continue;
// this is it, push-destination loc found
break;
}
}
// Push the monster forward, close to player
monster_swap(c, grid, &grid_push);
// Now move us (current monster) on empied floor
monster_swap(c, &mon->grid, grid);
*did_something = true;
return true;
}
or an alternative solution which I also didn't finish in get_move():
/* Monster groups try to surround the player */
if (!done && (group_ai ||
((one_in_(2) && mon->race->friends_base) ||
(one_in_(3) && mon->race->friends)) && square_isview(who->player, &mon->grid))
{
int i;
struct loc grid1;
int monsters_around_p = 0; // how much monsters already surround player
int empty_floors_around_p = 0; // how much empty floors around player
int tmp = randint0(8);
loc_copy(&grid1, &mon->target.grid);
/* Find an empty square near the player to fill */
for (i = 0; i < 8; i++)
{
/* Pick squares near player (pseudo-randomly) */
loc_sum(&grid1, &target, &ddgrid_ddd[(tmp + i) & 7]);
/* Ignore filled grids */
if (!square_isemptyfloor(c, &grid1))
{
// if square got monster - increase monster count
monsters_around_p++;
continue;
}
// square is empty, write it down
empty_floors_around_p++;
/* If we are already adjacent */
// to restore initial behaviour
if (mon->cdis < 2)
continue;
/* Try to fill this hole */
break;
}
// if monster stays already in tact with player &&
// player surrounded by monsters &&
// there is still empty space around &&
// ...monster also got other monsters around him:
// surround
if (mon->cdis == 1 && monsters_around_p > 1 && monsters_around_p < 5 &&
empty_floors_around_p > 0)
{
// calculate how much monsters around our monster
// if there are at least 4 monsters around us - try to move to next open slot to player
}
/* Head in the direction of the chosen grid */
loc_diff(&grid, &grid1, &mon->grid);
}
Not sure which solution is better... 1st is easier to implement, but it's a bit too hardcore as monsters will surround player too ezpz (kinda got additional turn when push their 'friends')... while second solution is pretty hard to implement and it loads CPU more.
I'll be very grateful if you can help with monsters to be able to surround player... though maybe if the bug which is present in video above will be fixed - it will solve corridors problem too?
Made a similar situation in latest V (digging some space around a room,summoning some cave orcs and standing behind a wall one step away from a corner) and the mobs actually surrounded the character, so it's indeed a bug.
Went and compared source code in monster_turn_move() between PWM and V and found an error in PWM code. Now fixed.
tested pure PWMA
https://www.youtube.com/watch?v=5JQkU_rHgYY
I found out that for testing such stuff it's very useful to create admin with 1st lvl. I do it by changing player_outfit_dm(struct player *p)
reminds me old issue https://github.com/draconisPW/PWMAngband/issues/469