Wednesday, March 12, 2014

Summary

Hey all! :)

Yes, it will be a summary of my past half year of coding on ScummVM, and practically a summary of my latest additions to the Avalanche engine. I'll go through a list of the most significant and spectacular modifications of the engine and describe them one-by-one. Of course, during that period, there were a lot of bugfixes (Even some bugs of the original were fixed!), and other additions and refactorings, but I won't mention all of them.
So... let's get started! (The pictures will become enlarged once you click on them.)

1. Game of Nim:
This was the first thing I implemented since my last post. The graphical part of it wasn't particularly hard, but the game logic got me scratching my head for a while. In the end, the Wikipedia page of the game and a lot of patience helped me trough all the troubles. You can find the - not so nicely refactored - sources in our GitHub repo.

2. Ghost Room:
Basically, it is a little animated scene, which gets triggered when you make Avvy walk to one of the "hidden" corridors of his castle. He (represented by the two grey, little floating eyeballs) walks in innocently, then got scared by the descending ghost and other appearing freaks, so he hastens out of the room. It's was pretty fun to implement, even if I had to fight a bit with the picture of the ghost to decode and display it properly.

3. Shoot em' Up:
This one may need some description: It's a basic shoot em' up mini-game, where your aim is to shoot the bad guys in the pallets. If a criminal doesn't get hit in the face with a rotten vegetable repeatedly in a certain amount of time, it will escape, and your score decreases. The more guys you keep in the pallets when the time counter reaches 0, the more points you'll get. Also, you gain score for each successful shoot, and lose some if you hit a pedestrian by accident. It's wasn't hard to implement, since I've got everything for the graphics, and just a little bit of effort needed to understand the logic behind the mini-game itself.

4. Help:
Of course, there's also the Help menu. The implementation of it was pretty straightforward, the only difficulty was with the display of the big fonts, but I came over it by time and effort too.

5. Main Menu:
 
Last but not least, I finally fought with the menu, and got out as a winner. The biggest problem here were the display of the little buttons on it, because they are all drawn together, not one-by-one, but plane-by-plane. It also uses a different display resolution then the rest of the game, but it was really a minor thing after I solved the mystery of the icons. :)

That's all folks! There are still some missing bits of the game, which you can see on the TO-DO section of the engine on our wiki, but I never said I stopped working on them. :)

By the way, I submitted my proposal just today, and hopefully I'll get accepted to this year's GSoC as well so I'll be able to blog about my progress with CGE2 engine soon. Fingers crossed! ;)

Thursday, October 24, 2013

Membership

Yesterday, I became a full member of the ScummVM team! I just can't describe how grateful and proud I am right now. It's really like a dream came true for me. :)
This isn't strictly connected to my project, but it's so important for me, I knew I must share it in this blog as well. Many thanks again to everyone who supported me during this long journey! And I am still so far away from the end... :)

Friday, October 18, 2013

Merged

Yes, Avalanche engine is finally merged into ScummVM's master! Hurray! :)
It's just a brief check-in, since nothing monumental was added to the engine during the opening of the merge request. Strangerke and me (mostly him) only did refactoring and rearranging of the code and a lot of bug fixing. But there's still a lot to do and a lot to implement, of course. :)
I want to say thank you especially to wjp who helped us a lot of during the debugging and many thanks to every member of the team who helped our work with their constructive criticism!
Hopefully next time I will be able to tell you that another part of the game (the help section, or the main menu) is implemented. See you until then!

Sunday, September 22, 2013

Merging

Hi everybody!

After another bigger break I proudly announce you the pull request of Avalanche engine on GitHub!!!
In the last few days Strangerke and me worked a lot to make the engine more coherent and readable, and we were even able to implement most of the sounds and the harp-playing mini-game alongside it.
There are still lot to do with the game, so my work clearly won't stop by the end of this year's GSoC. If you want to be kept well informed, I suggest you to check the wiki page of the engine regularly, as well as keep on reading this blog, because I won't stop writing posts about my progress neither. (Even if not weekly, thanks to school... but as frequently as it is possible.)
At last I want to say thank you to everyone, especially to my mentors: Strangerke and fuzzie. These two, and practically the whole ScummVM team helped me so much developing my engine that I can't even describe the gratitude I feel toward them! It's a great team to work with and being part of it. I am also very thankful to Google as well since they made my whole project possible with their financial support. Thank you guys, you are all awesome! :)

Friday, September 13, 2013

Renaming and refactoring

Before I write anything else: sorry for my three days late post! School had started and so much and even more rattles my mind nowadays, I scarcely had time and energy to commit anything and as it appears: I also completely forgot about this obligatory of mine.
In truth I have not much to report just now. Most of our commits with Strangerke (he helps me a GREAT amount these days) consist of renaming and refactoring the existing code. With his experience and great advices I think the engine improved a great deal in readability and even stability. Until the final deadline, we will keep working on the renaming and refactoring. One of our main aims right now (after being almost completely finished with the strings of the game - credits go to my mentor) is moving some remaining (and misplaced) functions to Parser to make it a real, whole parser. We also want to take another look at the graphical methods of the engine and move the appropriate ones to Graphics.
Besides these, there are still a lot to do. I'll soon write a "TODO" section on the wiki page of the engine about these and keep working on implementing the missing features (sounds, some animations, help, etc.) after this year's GSoC.

Monday, September 2, 2013

A completable game

Yes, that's it! Avalot d'Argent is actually in a completable state now! Yaaaay!

A few words about the past week: In truth, I can't say much more than the previous time. I really didn't do anything spectacular, or made actually new code, I mostly spend the week with bugfixing.
Since the game has a very unique storyline, it was hard for me to complete the original one in DOSBox, but with the help of the Pascal code, and some paper and pen (I had to draw a smaller map for one part of the game.), I finally finished it. After that, it was not so difficult to find the bugs in my code. At least it was much easier to find them, then to repair some of them. To be honest, most of the problems were mismatched array indexes and numeric constants, but it didn't make the solving of them any easier.

After the game was completable, I plunged into the implementation of the drop-down menu. As the result of that, now I can proudly present you a screenshot of it and the fact that it's fully functioning and can be controlled with the mouse! (The keyboard support is coming soon as well.)
The implementation of it in fact, wasn't that hard, since I had every tool for it from previous parts of the engine. (For example the plotting of text to the screen, and ScummVM also already implemented the drawing of colored rectangles to the screen. I really didn't need much more than these, but a lot of patience.)

That's all for now. The last weeks of Summer of Code will be spent with heavy renaming and refactoring of my code, so by the end of the program, we'll be able to merge not only a working, but a working and (hopefully) readable and understandable engine into ScummVM! :)

Tuesday, August 27, 2013

Gameplay footage

Hi all! :)

As the title of the post already suggests, it will be a quite unique one. Instead of a picture, I am starting it with a video:


Since during the last week, I solely concentrated on making the game completable, I don't really have any code to show you now. I mostly did fixing of array indexes (since Pascal's indexes usually start at 1, and C's first indexes are always set to 0) and polishing already existing (thanks to the PtoC conversion) functions.

Now there are 23 fully working rooms (what I showed you in the video) out of the existing 34 of them. I think it's a pretty good percentage: 68%. 

If everything will go as planned, I'll soon have a completable (and mostly bug-free :)) game. After that I'll implement the drop-down menus, what are still missing. (I postponed their implementation because they are not essential for playing the game, as you may see in the video, you can also do everything with the command line.) After that, in the remaining time, I'll work on renaming and commenting my code, so I think that the main menu, the help section of it, the sounds, some animations (mostly death animations) and the missing mini-games will remain for after GSoC.

But I'll do my best and we'll see what will come out of it. See you soon! ;)

Tuesday, August 20, 2013

Saving/loading and a little mouse

This screenshot not so flashy as my previous ones, and don't show you much of the actual game, but I think it  still looks pretty decent. :)
After I arrived from my short vacation, my plans were precise: first implement the handling of the mouse, and then the drop-down menu. With a little purposeful nudging from Strangerke, I decided he is right again when he advised me to implement the saving and loading in the engine right after the mouse, so I can make the game completable as soon as possible. I took his advise and you can see the product of my work in the picture. True that the drop-down menu is still not working, but I think it can wait a bit more.

As I mentioned before, I started with the mouse. In truth, there wasn't much to do since the game doesn't have a pathfinding system or anything like that. Avvy just blindly follows the mouse on the screen until he collides with a "magical" line, or if you tell him to stop. In fact there are a lot of ways to do so: you can control Avalot with the keyboard, the mouse, and even with the little compass on the left part of the toolbar on the bottom. Practically, that covers almost everything I had to do with the mouse: moving around the main character with the help of it, accept scrolls by clicking on the screen, replace the cursor of the parser by clicking on the desired position and activate functions by clicking on their icon on the toolbar. These are implemented in Lucerna::checkclick() which you can check out here. Lucerna::verte() is the function responsible for guiding Avvy around on the screen.

The second and more tricky part of my week was spent with the saving/loading system. After a couple of hours of killing Strangerke's and fuzzie's brains with my stupid questions and fighting myself through these tutorials and reading a lot of code in Hugo and Mortvielle, I finally got a solid footing where I could start from. Practically, I copied or mimicked a lot of code in Hugo regarding the use of the GUI, but the implementation of the actual saving and loading came from Mortvielle by the use of Common::Serializer. This precious little thing gave me a lot of help during the implementation which was mostly done in AvalancheEngine::synchronize() by giving me a very pure and simple interface to work with.
After that I implemented various advanced engine features such as loading from the launcher and the displaying of thumbnails on the save and load screens. My last concern was adding some version control to the system and here we are: all working and done!
By the way, ScummVM has a very convenient and friendly API for developers to include these advanced features, and it was quite a pleasure to work with it as you may see for yourself if you take a look at the tutorials I mentioned before.

Next aim: a completable game. See you soon! ;)

Monday, August 12, 2013

Bubbles

Those connected to speaking!
And I subtly showed you an entirely new (and working) room of the game! Hah!
I am writing this post because I am leaving for three days tomorrow and I'll only come back Thursday night at best (but Friday morning is more possible). So let me sum up for you the progress of the past few days now!
First and foremost let me talk about the thing which needed the most work: the speech bubbles.
In truth, the actual drawing of them wasn't really hard. ::Graphics::Surface::fillRect() and Graphics::drawdrawPieSlice() did the most of the work. The thing I had to implement was the "tails" of the bubbles. For that, I introduced a new function, Graphics::drawTriangle():
void Graphics::drawTriangle(::Graphics::Surface &surface, Common::Point *p, byte color) {
 // Draw the borders with a marking color.
 _scrolls.drawLine(p[0].x, p[0].y, p[1].x, p[1].y, 255);
 _scrolls.drawLine(p[1].x, p[1].y, p[2].x, p[2].y, 255);
 _scrolls.drawLine(p[2].x, p[2].y, p[0].x, p[0].y, 255);

 // Get the top and the bottom of the triangle.
 uint16 maxY = p[0].y, minY = p[0].y;
 for (byte i = 1; i < 3; i++) {
  if (p[i].y < minY)
   minY = p[i].y;
  if (p[i].y > maxY)
   maxY = p[i].y;
 }

 // Fill the triangle.
 for (uint16 y = minY; y <= maxY; y++) {
  uint16 x = 0;
  while (*(byte *)_scrolls.getBasePtr(x, y) != 255)
   x++;
  uint16 minX = x;
  uint16 maxX = x;
  x++;
  while ((*(byte *)_scrolls.getBasePtr(x, y) != 255) && (x != 639))
   x++;
  if (x != 639)
   maxX = x;
  if (minX != maxX)
   _scrolls.drawLine(minX, y, maxX, y, color);
 }

 // Redraw the borders with the actual color.
 _scrolls.drawLine(p[0].x, p[0].y, p[1].x, p[1].y, color);
 _scrolls.drawLine(p[1].x, p[1].y, p[2].x, p[2].y, color);
 _scrolls.drawLine(p[2].x, p[2].y, p[0].x, p[0].y, color);
}
It's clearly not the most optimized, nor the smartest code, but for now, it'll do. The operation of it is quite simple: First, we draw the borders of the triangle with a marking color. (255 is as good as any number bigger than 15, since our EGA palette supports only 16 colors.) After that we search for the highest and the lowest point of the triangle, and moving from the top to the bottom, we go trough every relevant line of the screen and fill the selected parts of it with the color of the shape. In the end, we redraw the borders - now with the desired color.

Finished with the implementation of it, the next thing I had to pay attention was the printing of the characters to the bubbles. Since the original code used Pascal's outtextxy(), I had to come up with something to replace it as accurately as I could. As a solution, I introduced Graphics::drawText():
void Graphics::drawText(::Graphics::Surface &surface, const Common::String &text, fontType font, byte fontHeight, int16 x, int16 y, byte color) {
 for (byte i = 0; i < text.size(); i++)
  for (byte j = 0; j < fontHeight; j++) {
   byte pixel = font[(byte)text[i]][j]; 
   for (byte bit = 0; bit < 8; bit++) {
    byte pixelBit = (pixel >> bit) & 1;
    if (pixelBit)
     *(byte *)surface.getBasePtr(x + i * 8 + 7 - bit, y + j) = color;
   }
  }
}
It's a very simple function, which's only purpose is to draw the given text with the given font to the given place on the given surface with the given color. (GIVENGIVENGIVEN!!!) It works like that: in font (which has the type of fontType), we store a mask for every character. The function simply search for every character's mask in this array, and then using that, the coordinates and the color, draws the picture of the character to the surface. Passing the height of the font is needed, because Avalanche uses 3 types of font and 2 of them has the height of 12 (used on the scrolls), but the third one (used on speech bubbles, the drop-down menu and the text input field) is only 8 pixel high.
Using these two functions it was super easy to implement the speech bubbles, I only had to center the texts a little bit in Scrolls::bubble().

Besides these improvements, I managed to implement a lot of the game logics, so now the first 4 rooms of the game are complete and playable, all the NPC-s on these screens are fully functioning, and everything is basically very fancy. I could even make Spludwick (the mage on the screenshot above) follow Avvy around the room as in the original game.

That's all for now! I hope next time I will be able to tell you about how I managed to implement the handling of the mouse in the game and I am planning to get done with the drop-down menu right after that. See you soon!

Thursday, August 8, 2013

Arces

They are everywhere! Just like in this picture:
As you can see, there are two significant alterations since my last post: an error message on the screen in the embrace of a scroll, and the hands of the clock. Let me start with the former!

The complete "scrolldrivers" are not implemented yet, and at the moment my engine only can display these gray scrolls with black (mostly error) messages in them. Later, with the handling of multiple sprites on the screen, there'll come the speech bubbles, since they have a very similar algorithm.
My idea to implement the scrolls was quite simple. I introduced a new surface object (Graphics::_scrolls) which I use like this: When a scroll is needed to be drawn, we copy the whole screen to _scrolls (which obviously has the very same size as the screen, 640x200), then draw the scroll to this copy (it's method depends on the type of the scroll - currently the engine only supports this one) and do the followings:
::Graphics::Surface temp;
 temp.copyFrom(_vm->_graphics->_surface);
 _vm->_graphics->_surface.copyFrom(_vm->_graphics->_scrolls); // TODO: Rework it using getSubArea !!!!!!!
 _vm->_graphics->refreshScreen();

 Common::Event event;
 while (!_vm->shouldQuit()) {
  _vm->getEvent(event);
  if ((event.type == Common::EVENT_KEYDOWN) && ((event.kbd.keycode == Common::KEYCODE_ESCAPE) || (event.kbd.keycode == Common::KEYCODE_RETURN) || (event.kbd.keycode == Common::KEYCODE_HASH) || (event.kbd.keycode == Common::KEYCODE_PLUS)))
   break;
 }

 _vm->_graphics->_surface.copyFrom(temp);
I hope the code speaks for itself clearly enough, but if it does not, here's a brief explanation: We make a backup for the actual screen, then draw the content of _scolls to _surface, and put _surface's new content to the screen using Grahpics::refreshScreen(). After that we enter an (almost) endless loop, which checks for keyboard input, and if the user hits the proper key, we stop presenting the scroll: we copy the original content of _surface back. I don't call refreshScreen() again here, since the main loop of the game will does it anyway.
After I talked about the methodology of the scroll system, let me say a word or two about the drawing of this particular type of scrolls. It all happen in Scrolls::drawscroll(). The gray body and the red borders of the scroll were easy enough, they are just simple ::Graphics::Surface::fillRect() calls with the proper parameters. Putting the text on the scrolls was a very easy task as well, since it's almost completely the same as I used previously in Dropdown::chalk(). The real pain came when it was time to draw the corners of the scrolls. For that, I had to reimplement Pascal's procedure arc(), since ScummVM doesn't have anything like that. For that, I used Free Pascal's InternalEllipse() with some minor modifications. Basically, it does the very same under the name of Graphics::drawArc(). After implementing that, I could also recreate the behavior of Pascal's pieslice() in Graphics::drawPieSlice() calling drawArc() multiple times with smaller radius every time than before. (As always, you can check out both of them here.) With the use of these two I was able to implement the drawing of this type of scroll fully.

Right after that came the idea: Why not hit two birds with one stone and implement the clock as well? I tried to work around the use of Pascal's arc() in this case before, but the result was catastrophic. Now I have Pascal's arc() in C++! Why not try again? So, the trying went very well as you may see. But because the drawing of the clock used the full functionality of arc() (which in Pascal stored the coordinates of the end point of the arc in a variable, which was accessible with GetArcCoords()), I had to add a return value to Graphics::drawArc() which presented the very same value as GetArcCoords() did in Pascal. After that it was very easy to implement the hands of the clock. You can see the final functions for yourself  in Graphics.