draconisPW / PWMAngband

A free, multi-player roguelike dungeon exploration game based on Angband
35 stars 12 forks source link

AI problem #555

Closed igroglaz closed 2 years ago

igroglaz commented 2 years ago

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

igroglaz commented 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.

igroglaz commented 2 years ago

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?

draconisPW commented 2 years ago

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.

draconisPW commented 2 years ago

Went and compared source code in monster_turn_move() between PWM and V and found an error in PWM code. Now fixed.