Thursday, July 17, 2008

Gnibbles

I started playing Gnibbles back in 2002, and stopped in the same year. Then, I again started playing few months back.

I installed one year old version. In that, there is support for multiple players, and AI players (computer plays). At max 6 players (including computer and AI) can play at a time. There was one major drawback in that game. If any player loses all the lives, then whenever that player loses a life, then the game will be restarted in that level. It was a major drawback, and it is almost impossible to cross any difficult level with that.

Around few weeks back, I installed Hard Heron Ubuntu Linux. It had gnibbles version 2.22.2.1. In that , if any worm loses all the lives, then after some random time, it will come again, and it can go through any walls. But, AI player does not know that it can go through walls. So, it plays normally. I liked this feature a lot, but, I wanted the AI player to know that it can go through walls, and play accordingly. But, I came to know later that, it is a bug, and they fixed it in the next release. There is another problem in this version. If the worm is killed, then it immediately starts going down. But, in few levels, where there is a wall immediately below the worm, the worm would be killed immediately. So, if the worm loses a life in those levels, then it will lose all the lives immediately. This is a major drawback, but comes only in level 25.

I installed the latest version of Gnibbles. They fixed both the above bugs. I liked the first bug, and I wanted that feature, and at the same time, I want to fix the second bug. Because, this is open source code, I could change the code and run with my feature. This is the second time for me to change a open source code, and first non-java code.

This is the procedure to fix the above bugs in Ubuntu Linux.

Download the gnibbles source code v 2.22.2.1 from http://archive.ubuntu.com/ubuntu/pool/main/g/gnome-games/gnome-games_2.22.2.1.orig.tar.gz

Type ./configure from gnome-games_2.22.2.1 directory

If you have default installation, you will have to install too many softwares to compile the code. Whenever it gives any error, search for the error in google with ubuntu in the search string. Most of the time, you will get the answer in the first three results. You will have to install the package by sudo apt-get packagename.

Once you install all the softwares, type make. This will build all the games. Now, goto gnibbles folder, and type ./gnibbles. You may get one error that couldn't find pixmaps/gnibbles/gnibbles-logo.svg. Fixing this error took lot of time. From the code, it looks like it tried to find this file from GNOME_FILE_DOMAIN_APP_DATADIR. This is an enum, and I could not find good documentation to understand more about this. After a lot of time, I found that, I had to change make file to specify this directory.

In gnibbles/Makefile, we have to change gnibbles_CPPFLAGS.
Original version

gnibbles_CPPFLAGS = -I$(top_srcdir)/libgames-support \
-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
-DREAL_DATADIR=\""$(datadir)"\" $(AM_CPPFLAGS) $(am__append_2)


Changed Version

gnibbles_CPPFLAGS = -I$(top_srcdir)/libgames-support \
-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
-DREAL_DATADIR=\""$(datadir)"\" -DDATADIR=\""$(datadir)"\" $(AM_CPPFLAGS) $(am__append_2)


If we define DATADIR while compiling, it uses that directory as GNOME_FILE_DOMAIN_APP_DATADIR. So, it searches for the file ${datadir}/pixmaps/gnibbles/gnibbles-logo.svg. In your make file, set prefix to a folder in which you have write permissions.

Then, copy all the *.svg files in gnibbles and gnibbles/pix to the directory ${prefix}/share/pixmaps/gnibbles. Copy all the *.gnl files in gnibbles to ${prefix}/share/gnibbles.

Now, type make from gnibbles directory. After that if you type ./gnibbles, it should run the game without any problem.

The code diff for the fixes that I did.


C:\temp>diff old\worm.c new\worm.c
125a126
> worm->direction_start = t_direction;
638,643c639,646
< for (dir = 1; dir <= 4; dir++) {
< if (dir == opposite) continue;
< if (!gnibbles_worm_test_move_head (worm)) {
< worm->direction = dir;
< } else {
< continue;
---
> if (worm->lives > 0) {
> for (dir = 1; dir <= 4; dir++) {
> if (dir == opposite) continue;
> if (!gnibbles_worm_test_move_head (worm)) {
> worm->direction = dir;
> } else {
> continue;
> }

C:\temp>
C:\temp>diff old\gnibbles.c new\gnibbles.c
517c517,519
< worms[i]->ystart, WORMDOWN);
---
> worms[i]->ystart,
> worms[i]->direction_start);
525c527
< if (worms[i]->lives)
---
>
529c531
< if (worms[i]->lives)
---
>

C:\temp>
C:\temp>diff old\worm.h new\worm.h
42a43
> gint direction_start;

C:\temp>


The first change in worm.c is in gnibbles_worm_set_start(). It sets the correct direction of the worm, if it loses a life. So, it will not always go down, and get killed immediately.

The second change in worm.c is in gnibbles_worm_ai_move(). Here, I added one condition if (worm->lives > 0) for the last for loop. The last for loop checks, in which direction it can go safely. Dead worms can go in any direction without any problem. So, we don't need to check for the safe direction. This allows the worm to concentrate on bonuses and allows to go through walls.

The change in worm.h is in typedef struct GnibblesWorm. gint direction_start is added to that struct.

The first change in gnibbles.c is in gnibbles_move_worms(). While calling gnibbles_worm_set_start(), for the direction WORMDOWN is passed. So, if the worm loses life, it always start in the down direction. It is changed to worms[i]->direction_start.

Next change in gnibbles.c is in the same function. While calling, gnibbles_worm_move_tail, and gnibbles_worm_draw_head() there was a check whether worms are live or not. I removed that check to allow the dead worm to start immediately.

With these changes, I got the game which I was expecting. If you face any problems in this, please let me know.

My friend told me that, if we change the games like this to suit our needs, then the spirit of the game may be lost. I think it is not a problem because we are changing rules of all the games including cricket to make it more interesting. So, the same goes here.

No comments:

Post a Comment