Roguelike AoC – part 13

In the thirteenth lesson of a roguelike game tutorial existing monsters are beginning to move.

Been there, done that

It’s nice to see that my anticipations from a couple of lessons ago came to life. Suddenly the Position in the Player and Monster structs became pointers. I’ve already done that, so a part of the lesson could be skipped.

However, I still don’t know how I was able to live with such a bug in my code. The whole story started when I’ve tried to follow the author’s suggestion, and move Player into the Level struct. It involved actually creating the player in the createLevel function. Suddenly my code started crushing without telling me a thing! After an hour of countless checks, testing and rebuilding the project I found out what was wrong! Let’s take a look at the following code:

Player *playerSetup(void)
{
    Player *newPlayer = malloc(sizeof(Player));

    newPlayer->currentLocation->position.x = 14;
    newPlayer->currentLocation->position.y = 14;
    newPlayer->currentLocation->displaySign = FLOOR_SIGN;

    newPlayer->previousLocation->position.x = 14;
    newPlayer->previousLocation->position.y = 14;
    newPlayer->previousLocation->displaySign = FLOOR_SIGN;

    newPlayer->health = 20;

    playerDraw(newPlayer);

    return newPlayer;
}

Something’s not right, right? The cause of the error lied in a fact, that both currentLocation and previousLocation were not allocated! I honestly don’t know how and why this code was actually working, and how did that happen that stopped working after adding Player pointer to the Level struct. I must be honest – these moments are the best modesty-shaping exercises that a person can think of. When I realise how many things I still don’t know (and even don’t have an idea of what I don’t know) is a katharsis to me. That’s why I write this blog 😉

Along the way I had to rearrange the order of createLevel function – right now it creates everything before the player. In that way I have the whole level setup and stored – the player is just ‘pasted’ into it at the very end. So far it works.

With that change I’ve removed all player-related variables and logic in main.c. The only thing that I had to add was user redrawing at the end of every game loop iteration. That’s just to make sure it looks nice no matter the things I will be doing on the screen.

 

Move Your body!

My functions that are responsible for moving monsters around are also different from the ones proposed by the author. I operate on the locations – so it’s also easier for me to redraw location that the monster is leaving. For the time being I’ve settled on the monsters moving only on the floors – they can’t pass doors (just didn’t want to again make this horrible copy&paste thing).

int moveMonsters(Level *level)
{
    for (int x = 0; x < level->numberOfMonsters; x++) {

        mvprintw(level->monsters[x]->previousLocation->position.y, level->monsters[x]->previousLocation->position.x, level->monsters[x]->previousLocation->displaySign);

        if (level->monsters[x]->pathfinding == TRUE) {
            pathfindingSeek(level->monsters[x], level->user->currentLocation);
        } else {
            // Here will be random pathfinding
        }

        // We redraw the location on which monster just stood
        mvprintw(level->monsters[x]->previousLocation->position.y, level->monsters[x]->previousLocation->position.x, level->monsters[x]->previousLocation->displaySign);
        // We draw monster in the new location
        mvprintw(level->monsters[x]->currentLocation->position.y, level->monsters[x]->currentLocation->position.x, level->monsters[x]->displaySign);
    }

}


int pathfindingSeek(Monster *monster, Location *userLocation)
{
    if ((abs((monster->currentLocation->position.x - 1) - userLocation->position.x) < abs(monster->currentLocation->position.x - userLocation->position.x)) &&
         (mvinch(monster->currentLocation->position.y, monster->currentLocation->position.x - 1)) == *FLOOR_SIGN) {
        monster->previousLocation = monster->currentLocation;
        monster->currentLocation->position.x -= 1;
        return 0;
    } else if ((abs((monster->currentLocation->position.x + 1) - userLocation->position.x) < abs(monster->currentLocation->position.x - userLocation->position.x)) &&
        (mvinch(monster->currentLocation->position.y, monster->currentLocation->position.x + 1)) == *FLOOR_SIGN) {
        monster->previousLocation = monster->currentLocation;
        monster->currentLocation->position.x += 1;
        return 0;
    } else if ((abs((monster->currentLocation->position.y + 1) - userLocation->position.y) < abs(monster->currentLocation->position.y - userLocation->position.y)) &&
        (mvinch(monster->currentLocation->position.y + 1, monster->currentLocation->position.x)) == *FLOOR_SIGN) {
        monster->previousLocation = monster->currentLocation;
        monster->currentLocation->position.y += 1;
        return 0;
    } else if ((abs((monster->currentLocation->position.y - 1) - userLocation->position.y) < abs(monster->currentLocation->position.y - userLocation->position.y)) &&
        (mvinch(monster->currentLocation->position.y - 1, monster->currentLocation->position.x))== *FLOOR_SIGN) {
        monster->previousLocation = monster->currentLocation;
        monster->currentLocation->position.y -= 1;
        return 0;
    }

    return 1;
}

 

Code

Here is the direct link to the GitHub Repo.

You Might Also Like

Leave a Reply

Back to top