Getting better at C programming – roguelike game

A long, long, long and even longer time ago, when my computer was not that great, and the internet was expensive like hell dial-up solution I’ve stumbled upon ADOM. It was (and is up till today) probably the greatest achievement of a computer games genre called roguelike. These games – rogue like – derive their type from the first of them – Rogue. It was a simple dungeon crawler game, with schematic graphics and more or less robust controls. I remember spending hours playing them, with mostly ADOM and Angband as my first choices.

I remember also a time, when I was trying to write my own – something circa year 2000. Being in high school, Borland Pascal IDE on my 486 DX4 PC and huge book about Turbo Pascal nearby. Unfortunately I was not able to finish it – obviously I’ve lacked knowledge and skill then – although, when I was thinking about how to make my C learning fun, my thoughts went right back to the roguelike games.

What is more important – somebody already did that! I do not think about hundreds of roguelikes described and presented on RogueBasin wiki. I was surprised to find a whole video tutorial of creating one (simple one, of course) on Youtube. When I’ve discovered that there was no other way – I’m gonna go through the whole thing and code along. I know that this tutorial is a couple of years old. On the other hand – does C programming concepts change that fast? I think not.

I plan to write a follow-up post about every single lesson. Not to walk it through with text! Just to share my thoughts about the process, what I find interesting or not. If there will be nothing to write – so be it. It’s nice to have structured plan to follow. If You plan to use my posts as a learning material please first watch the appropriate video tutorial before, and then read my post and take a look at the code. Any other order will result only in confusion.

Ok, enough of this. Let’s go!

 

Setting up the ground – why I’ve chosen PDCurses

Aforementioned tutorial uses ncurses to support terminal graphics, drawing dungeons, etc. Which is pretty wise as doing that on your own will result only in wasting time on setting up infrastructure and such. However, ncurses supports only POSIX-compliant systems, and I wanted to use this project to also learn something about build process and linking of libraries on different systems. Happily for me – there is an alternative called PDCurses that is:

PDCurses is a public domain curses library for DOS, OS/2, Windows console, X11 and SDL, implementing most of the functions available in X/Open and System V R4 curses. It supports many compilers for these platforms. The X11 port lets you recompile existing text-mode curses programs to produce native X11 applications.

I knew one thing – I need to build this library in order to start working. As my personal computer is running Windows, I’ve started there. First step was to download the latest version of the library. In order to actually build something using C language I needed a compiler and linker. What is more – probably some kind of IDE would be nice too. As usual, I’ve done it oldschool-way and decided to use good old CodeBlocks. What it’s worth, it comes with bundled MinGW, so I was covered with compiler, linker and all other stuff. Won’t go through the installation process as this is pretty trivial. Let’s compile something!

In the downloaded source of PDCurses there is a separate folder called wincon – with the sourcecode and make files for Windows (depending on compiler/IDE You’re using). I’ve settled for MinGW therefore ‘usual’ file should be used. Before trying to run anything it is worth noting that (at least at my machine), GCC compiler installed along with CodeBlocks was not added to the PATH. So in order for build to work I had to edit PATH and add a proper folder to it (it was C:\Program Files\CodeBlocks\MinGW\bin – this folder contains compiler/linker/make and all that stuff). Now it’s time to run (in terminal – I’ve used PowerShell):

mingw32-make -f \.Makefile

After a couple of seconds the compilation process is done. The output of the whole thing is pdcurses.a file that contains all the library’s code. So far so good. Also – that is important – in the main folder with the sourcecode You can find curses.h file. These two files will be needed in the next steps.

 

Application code

Roguelike project has a GitHub repo, unfortunately first 8 lessons are not there. As I wanted to go through them step by step I’ve thought that it’s actually a good thing. You can learn a lot by writing down the code yourself, specific patterns and schemas are going directly to the brain. Running the code that was mindlessly downloaded does not do that. However, as a helpful guy I will be putting the missing code back to the original repository through pull requests.

Funny fact – I remember the times (early 90s’) when programming books were accompanied by floppy discs. However, that was not that often – usually You had to rewrite the code by hand. My most prized achievement back then was actually rewriting circa 50 pages of Turbo Pascal code, that was simulating behaviour of a disc manager. Graphics was very similar to the capabilities that PDCurses provides, so You might say – I’ve came back home 😉

 

 

Code

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>

typedef struct Player {
    int xPosition;
    int yPosition;
    int health;
} Player;


int screenSetup(void);
int mapSetup(void);
Player *playerSetup(void);

int main() {
    Player *user;
    // There is a warning here (-Wunused-but-set-variable) - that will be fixed ;)
    char keyPressed;

    screenSetup();
    mapSetup();
    user = playerSetup();

    while((keyPressed = getch()) != 'q') {

    }

    endwin();
    return 0;
}


Player* playerSetup(void)
{
    Player *newPlayer = malloc(sizeof(Player));
    newPlayer->xPosition = 14;
    newPlayer->yPosition = 14;
    newPlayer->health = 20;

    mvprintw(newPlayer->yPosition, newPlayer->xPosition, "@");
    move(newPlayer->yPosition, newPlayer->xPosition);

    return newPlayer;
}

int screenSetup(void)
{
    initscr();
    printw("Hello world");
    noecho();
    refresh();

    return 0;
}

int mapSetup(void)
{
    int x = 13;
    int y = 13;
    mvprintw(y++, x, "---------");
    mvprintw(y++, x, "|-------|");
    mvprintw(y++, x, "|-------|");
    mvprintw(y++, x, "|-------|");
    mvprintw(y++, x, "|-------|");
    mvprintw(y, x,   "---------");

    x = 30;
    mvprintw(y++, x, "---------");
    mvprintw(y++, x, "|-------|");
    mvprintw(y++, x, "|-------|");
    mvprintw(y++, x, "|-------|");
    mvprintw(y++, x, "|-------|");
    mvprintw(y, x,   "---------");

    x = 13;
    y = 25;
    mvprintw(y++, x, "------------");
    mvprintw(y++, x, "|----------|");
    mvprintw(y++, x, "|----------|");
    mvprintw(y++, x, "|----------|");
    mvprintw(y++, x, "|----------|");
    mvprintw(y, x,   "------------");

    return 0;
}

I wanna build it!

We got the code. We got necessary libraries. Now it’s time to put everything together. First step is compilation of code units. In order to succeed here, we have to provide header files during builds, for PDCurses code to be compiled properly. Therefore, it’s crucial to provide a compiler with proper location of the header file (E is disc identifier I am working on). From the main folder of the project:

gcc.exe -Wall -O2 -IE:\Projekty\Roguelike\PDCurses-3.9 -c E:\Projekty\Roguelike\main.c -o main.o

During compilation, we will get a warning that one of the variables is not used. The specific place in the code is
marked with comment. For the time being that does not matter. What matters is new and shiny strong>main.o file in the main project folder. So far so good.

Now it is time to create final executable file with a little help from the linker. This time what is needed is the
actual PDCurses library. The library will become a part of resulting executable, which is call static linking and will be discussed in separate blog post I plan to write (along with dynamic linking).

gcc.exe -o Roguelike.exe main.o -s PDCurses-3.9\wincon\pdcurses.a

Hooray! Our output file – Roguelike.exe can be run as every simple program. And it works! At least on my machine 😉 The code can be found in my GitHub repo.

Last word about formatting

AFAIK there was some kind of perpetual flame war about code formatting standard in the C world. As You probably know I’ve not read K&R book so far. However, I’ve actually read ‘Linux Kernel coding style guide’, and formatting I’m using in my code samples are compliant with it. If You don’t like it – sorry – I’m not gonna change that.

You Might Also Like

Leave a Reply

Back to top