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.

Wednesday, July 31, 2013

Mostly parsing and magics

Let me start this post with our usual screenshot!
As you may see, there are a lot of changes and improvements since my last post. I'll tell you the story of the last week in the followings, so prepare for a smaller wall of text, a lot had happened! ;)

The first and most obvious thing is that I took many ScummVM members' advices and doubled the screen height again. We all agreed that it will be it's final size. The algorithm was pretty easy, I only had to update Graphics::refreshScreen() a bit. (Oh, and I renamed the class Graph to Graphics. It was sev's idea and I agree with him. Now it reflects much more the purpose of the class, and I added so much things to it during the past days that it lost all of its connections to the Graph unit in Pascal, so there's really no point in keeping the old name.) So, the new refreshScreen():
void Graphics::refreshScreen() {
 // These cycles are for doubling the screen height.
 ::Graphics::Surface picture;
 picture.create(kScreenWidth, kScreenHeight * 2, ::Graphics::PixelFormat::createFormatCLUT8());
 for (uint16 y = 0; y < picture.h / 2; y++)
  for (uint16 x = 0; x < picture.w; x++)
   for (byte j = 0; j < 2; j++) 
    *(byte *)picture.getBasePtr(x, y * 2 + j) = *(byte *)_surface.getBasePtr(x, y); 

 // Now we copy the stretched picture to the screen.
 g_system->copyRectToScreen(picture.pixels, picture.pitch, 0, 0, kScreenWidth, kScreenHeight * 2);
 g_system->updateScreen();

 picture.free();
}
I think the comments make it pretty understandable. I still work with the original 640x200 resolution when loading pictures to the screen (If you check out graphics.h, you can see it for yourself in the form of kScreenWidth and kScreenHeight.), but when I show the actual output, I draw every line twice, so it's like we have a screen height of 400.

I also want to mention that I reworked loading of pictures a little bit in the form of loadPictureGraphic() and loadPictureRow(). The names of these functions came from here, referring to their behavior. Obviously the sooner one loads graphical data that uses "graphic-planar EGA data" as input and the latter one is for loading "row-planar EGA data". In the end, both produce a Surface object with the same format as output. This revision was needed because I had to use these two methods frequently and it made the whole thing much convenient since now Graphics::drawPicture() only accepts a Surface object and two coordinates, and draws the input picture (coming from one of the loading functions or simply by copying parts of the already drawn screen) to the given place. You can check out the current source code of these algorithms in graphics.cpp. I wouldn't describe them further here, because I talked about their operation in my previous posts a lot.

The next thing I spent a large amount of time with during the week was parsing. Since the original code was a bit hard to understand it took me more time to look through all of it than the actual coding, but finally it's done and working! :)
I introduced a new class, Parser (you can check this out here and here), which is practically a rework of Basher. One of my further plans is to completely get rid of Basher and move everything from it to Parser after renaming them. The "funny" thing is that the actual parsing is not done here (yet), but in Acci::parse(), and Acci::do_that() takes actions based on the result of the parsing (run animations, move characters, etc.). Parser now is only for processing the keyboard input and the handling of the visualization of it in a little command line under the main picture and over the toolbar. (You can see it in the screenshot at the top of the post, I wrote "get up" into it.) It's also my plan to move at least these two functions from Acci to Parser, and even more data, if I find out that they are only connected to parsing.
I wouldn't insert any code samples connected to parsing here now, since parse.h and parse.cpp contains quite readable code in my opinion, and Acci::parse() and Acci::do_that() is in such a bad condition that I don't want to advertise them at all. (:D) Let it be enough that they are called by Parser::handleReturn(), and they work properly. But a certain rework will be needed soon if I want to keep my code readable... Anyway, if you want to check out them in their current forms, here you go.

Also, not only the text input is working now (By using that you can wake up Avvy typing in "wake" or "wake up" and get him out of bed typing "stand", "stand up", or "get up". Other commands may don't work properly or don't work at all at the moment.), but you can move Avvy around in the first room of the game using the cursor keys or the home/end/page up/page down buttons executing diagonal movements with them. You can also control him with the numeric keyboard and stop him by hitting the numeric key '5' or hitting the direction key he is facing right now again.

We arrived to the second greater part of my last week's work: the MAGICS!
No, not turning people into toads or summoning a demon from Burning Hell using ScummVM, nothing like that. It's the name of the system in Avalanche which forbids the characters to cross the border of the screen and walk right on the toolbar for example. Let me illustrate it with the help of two screenshots!

As you may have noticed checking out Graphics, I added a new Surface object to the engine named _magics. This is the one which stores the image to the left. The white lines on it means the edges of the screen what Avvy (or any NPC) cannot cross.
They are drawn to this Surface in Lucerna::draw_also_lines(), using the data stored in Gyro::lines[] - which's content is loaded in Lucerna::load_also() amongst many other room-related data. If you'd like to read more about this matter, you can always check out the wiki pages of the original author.
So basically the algorithm in triptype::walk() is the following: we check if the next step of the character would cause him to cross a line on _magics and if it would, we simply stop the character.
Vigilant readers may have noticed the blue colored rectangle on the bottom left of the pictures, where the door is. It marks a different kind of "magic", which means that if we cross these lines, we want to leave the room.

My plans for the following weeks are making the speech bubbles (the so-called scrolls), the drop-down menu on the top and the transportation between rooms work. The drawing system will also need a certain rework, since now it can handle only one sprite per screen.

Tuesday, July 23, 2013

Avalot lives!

Yes, he does!
As you may have noticed, the menu bar on the top is also visible. So I can say that everything is shown what is needed for the first scene of the game! (Expect the clock and some status leds to the left of it. That will remain for later as I mentioned before.) Oh, and I got rid of that disgusting pink blanket as well and gave it the pleasant color of flesh! ;)

Let me speak first about Avvy, since it was a bit tricky to make him (and consistently the other characters during the game) appear, and I would have certainly gone mad if fuzzie didn't help me with a lot of explanations and suggestions.
So I added a new function to Graph: drawSprite(), which is - obviously - responsible for drawing the sprites of a character. The data of all characters are stored in an array named 'tr' located in Trip, which have the type of triptype. I made a little revision of this. The original code didn't divide data about a character in any ways, so I did. Everything connected to the display of a sprite (actually, the data what drawSprite() uses) went to a new type named SpriteInfo in grap.h and triptype got a new data member with the name of _info and the type of SpriteInfo. (You can take a look at these types and the array named 'tr' in Trip and Graph.)
The next thing was to implement Graph::drawSprite(). Here came in handy the new type I introduced, because now we only have to pass this data member of a triptype variable to the function and it can work using only these informations. Here it is:
void Graph::drawSprite(const SpriteInfo &sprite, byte picnum, int16 x, int16 y) {

 /* First we make the pixels of the spirte blank. */
 for (byte qay = 0; qay < sprite.yl; qay++) {
  byte *mask = new byte[sprite.xl];

  for (byte qax = 0; qax < sprite.xl; qax++) {
   byte count = qax / 8;
   mask[qax] = ((*sprite.sil[picnum])[qay][count] >> ((7 - qax % 8)) & 1);
   if (mask[qax] == 0)
    *getPixel(x + qax, y + qay) = 0;
  }

  delete[] mask;
 }

 /* Then we draw the picture to the blank places. */
 uint16 i = 0; // Because the original siltype starts at 5!!! See Graph.h for definition.

 for (byte qay = 0; qay < sprite.yl; qay++)
  for (int8 plane = 3; plane >= 0; plane--) // The planes are in the opposite way.
   for (uint16 qax = 0; qax  < sprite.xl; qax += 8) {
    byte pixel = (*sprite.mani[picnum])[i++];
    for (byte bit = 0; bit < 8; bit++) {
     byte pixelBit = (pixel >> bit) & 1;
     *getPixel(x + qax + 7 - bit, y + qay) += (pixelBit << plane);
    } 
   }
}

Use of image masks
I think the comments and mostly the code speak for themselves, but here's a brief summary of it:
The method consists of two parts: before the drawing, we have to blank the pixels of the sprite to black (0). Here, we use the array 'sil' which contains the mask for it. After that we can go through the image itself to draw it plane-by-plane, which is identical to the method I showed you before in my previous posts. You can read about the topic of image masks here in a bit more depth. Note that x and y here are the coordinates of the upper left corner of the rectangle which is an invisible frame around the sprite. (That was what you saw in my previous post in the color of magenta.)

The next thing I implemented was the changing of the disturbing pink color to a smoother 'flesh color'. It wasn't a big deal, I only had to set two palette entries what I did in Graph::flesh_colours(). (Keeping the name of the original function, but moving it from Trip to Graph.)

The third thing was the menu on the top of the screen. I have to tell you, it doesn't operate at all yet, it's only drawn to the screen so we don't have a blank line there. But of course it wasn't as easy as a bunch of writelns or couts. I had to draw the subtitles as pictures to the screen and they had a very nasty way of working. It's all done in Dropdown::chalk():
void Dropdown::chalk(int16 x, int16 y, char t, Common::String z, bool valid) {
 byte ander;
 if (valid)
  ander = 255;
 else
  ander = 170;

 for (byte fv = 0; fv < z.size(); fv++)
  for (byte ff = 0; ff < 8; ff++) {
   byte pixel = ~(_vm->_gyro.little[z[fv]][ff] & ander); // Note that it's the bitwise NOT operator!
   for (byte bit = 0; bit < 8; bit++) {
    byte pixelBit = (pixel >> bit) & 1;
    *_vm->_graph.getPixel(x * 8 + fv * 8 + 7 - bit, y + ff) = pixelBit + (pixelBit << 1) + (pixelBit << 2);
    // We don't have to bother with the planes, since they all have the same value. See the original.
    // Note that it's the bitwise OR operator!
   }
  }

 if (! z.contains(t))
  return;
 else {
  byte fv;
  for (fv = 0; z[fv] != t; fv++); // Search for the character in the string.
 
  // Similar to the cycle before.
  byte pixel = ~ ander;
  for (byte bit = 0; bit < 8; bit++) {
   byte pixelBit = (pixel >> bit) & 1;
   *_vm->_graph.getPixel(x * 8 + fv * 8 + 7 - bit, y + 8) = pixelBit | (pixelBit << 1) | (pixelBit << 2);
  }
 }

 _vm->_lucerna.blitfix();
}
At least here I didn't have to blank out the pixels or bother with planes and these made the whole thing a little bit easier. (In truth understanding the original Pacal code was much harder then implementing it in C++ again.) There is two stances of a menu item: valid (black) and invalid (grayed out). In truth, there's a third one: highlighted, but since the menu doesn't operate yet, I didn't have to bother with the implementation of it. Depending on the current state of the menu item, we get the pixels of the characters with bitwise operations. According to the original code, the planes all have the same value (since in dropdown.pas chalk() does the same for every plane), and since we have 1 byte for every row of a character in 'little', all the characters are 8 pixels wide as well. After that comes the underlining of a character of every text with a very similar algorithm and that's it: we are done. We call chalk() for every menu item after drawing a gray bar on the top of the screen and finally everything looks fine.

Implementing the drop-down menu system will remain for after midterm. My main concerns now are to make Avvy move around in the room with the help of the arrow keys, and if possible, put him into the bed at the beginning of the game, and make the speech bubble system work along with text input, so I'll be able to display the first few animations of the game (when Avalot wakes up to the screaming of her wife). I hope I'll be able to do all of this before midterm. I am giving it all I've got, and we'll soon see the result of it.

Friday, July 19, 2013

Loading pictures


Yes, loads of them! Let me show you the events of the past few days in the form of a screenshot first, and then I'll wrote about them in detail. Here you go:
The first thing you may have noticed looking the picture is that I changed back the resolution to 640x200. I decided to do so because I got the information that DOSBox only emulates the bigger screen height, and as Thomas said in a comment under my previous post, Avalanche really uses 200 pixel height, so I don't see the point in mimicking DOSBox's output instead of recreating the original experience. Also, if we decide that a bigger resolution would be nicer, it wouldn't take much more than adding a few lines of code to Graph::refreshScreen().

The second one is that there are much more things in the picture. Yes, I can say that the toolbar on the bottom is almost fully done and only the clock is missing from it. (Which - I assume - will miss for a couple of days/weeks because it's not so important regrading the actual gameplay, but tricky enough to recreate. And now I have much more urgent tasks to deal with before midterm - the characters, the dropdown menu on the top and the keyboard/mouse input -, and the days are just getting shorter and shorter.)
To be honest, after understanding how EGA graphics work and implementing the loading of the background image, the toolbar itself wasn't such a big problem, since it uses an almost identical method to load the parts of it as pictures. I can divide the bottom of the screen to 5 bigger parts: the background of the toolbar (the big blue thing), the "Thinks:" field of it, the score display, the clock, and that little picture (in the above screenshot a brown STOP sign) at the top left of it which tells the player if Avalot is standing in one place or moving in a given direction.
I implemented these parts in the exact order as I enumerated them in my previous sentence. To do this, I had to find out (obviously, with the help of fuzzie) that these pictures' encoding differ a bit from the background's. They are using row-planar EGA data, instead of graphic-planar EGA data which I used in the algorithm published in my previous post. Luckily, the methods for these two styles don't differ much, so the implementation of a function which will handle all of the pictures what are not the background was quite easy. To do so, I reworked Graph a little bit, and finally Graph::drawPicture() was born (to replace Graph::copySurface()):

void Graph::drawPicture(const byte *source, uint16 destX, uint16 destY) {
 // The height and the width are stored in 2-2 bytes. We have to add 1 to each because Pascal stores the value of them -1.
 uint16 pictureWidth = READ_LE_UINT16(source) + 1;
 uint16 pictureHeight = READ_LE_UINT16(source + 2) + 1;

 uint32 i = 4;

 Graphics::Surface picture; // We make a Surface object for the picture itself.

 picture.create(pictureWidth, pictureHeight, Graphics::PixelFormat::createFormatCLUT8());

 // Produce the picture.
 for (byte y = 0; y < pictureHeight; y++)
  for (int8 plane = 3; plane >= 0; plane--) // The planes are in the opposite way.
   for (uint16 x = 0; x < pictureWidth; x += 8) {
    byte pixel = source[i++];
    for (byte i = 0; i < 8; i++) {
     byte pixelBit = (pixel >> i) & 1;
     *(byte *)picture.getBasePtr(x + 7 - i, y) += (pixelBit << plane);
    } 
   }

 // Copy the picture to a given place on the screen.
 for (uint16 y = 0; y < picture.h; y++)
  for (uint16 x = 0; x < picture.w; x++)
   *(byte *)_surface.getBasePtr(x + destX, y + destY) = *(byte *)picture.getBasePtr(x, y);  
}

During the implementation of it, I found this little help during a simple search with Google. You can see that my code dips a lot from it: I read in the width and the height of the picture first, then create a Graphics::Surface object to store the picture in it, and then a very familiar algorithm comes with a little modification regarding the order of the planes. At last, I copy the image to a given point of the screen. So Tom Swigle, if you are reading this post somewhere, sometime: thank you, you are awesome!
After I finished with drawPicture, my only task was to replace the original PutImage() calls of the Pascal code with it, since I've done the loading of the pictures into byte arrays (what drawPicture gets as a parameter to work with) a few weeks earlier. And that's all, you can see yourself the result of it in the image above.

The last thing you might have noticed in the screenshot is a little pink rectangle in the middle of the screen. Don't worry, it's not a glitch! It's the very place where the hero of the game, Avalot d' Argent himself will manifest - I hope - within a couple of days. (I just put it there to see if I get the coordinates of the character accurately.)
Maybe next time we can see him in the screen as well? ;)

Sunday, July 14, 2013

First screenshot

Yes, you are not dreaming! It's true, it's fresh, it's happening RIGHT NOW! Ladies and gentlemen, I proudly present you the very first screenshot of Avalot d' Argent in the holy embrace of SvummVM!
Okay, the colors really need some adjustments, but apart from that you can see that the background image is successfully loaded and shown accurately. (Of course here will come the GUI in the top and the bottom, but that's not my first priority at the moment.)

Lucerna
Let me tell you a little story about my fight with the bits! Everything started after my latest post: I began to mess around with graphics, and I had some mailing with dreammaster, who helped me a lot and gave me an awesome "Graphics in ScummVM for dummies" guide. By following that, I successfully set up the basics of the screen handling in my engine, what you can find here and here. Graph's initial purpose was to replace the Graph unit from Pascal with a C++ class, so it can work in synergy with Lucerna (the class/unit which is responsible for the screen, keyboard and mouse handling) but as time passes I am slowly getting convinced that it will eventually become a replacement for Lucerna. I don't see it clear yet, time will tell...
At the moment Graph is not much more than a wrapper around a Graphics::Surface object.
I got the resolution of the game (what you can find in the header file of Graph) from this function call in the original code: 
 gd:=3; gm:=0; initgraph(gd,gm,'');
Where 3 stands for EGA graphic driver and 0 means EGALo mode, which is equal to 640x200 screen resolution, 16 colors and 4 screen pages. (I'll bother with these "pages" later.)
I also had some difficulties setting up the color palette to mimic the EGA display, but dreammaster told me a lot about it, and by "borrowing" a little bit of code from Strangerke's Mortvielle engine, I get over with it quite fast too. As you may see it in the screenshot at the beginning of the post, there is still a couple of things to do with it, since the colors in the original game are much more livid, but I'll leave it's fix for later.

The next big deal came right after that. I had a long conversation with fuzzie (who is "substituting" Strangerke, my mentor, while he is on holiday) about the topic and she told me a great deal about EGA displays and how did they handle data.
The function which is responsible for loading the data of each screen is Lucerna::load(). The tricky part was here to notice the loop in the original code (which is fuzzie's merit), and recognize that we have to face the "four plane style". After that, recreating it in C++ was quite easy, and fuzzie helped me a lot with that as well.
Here's the result of it:

f.seek(177);

/*for (bit = 0; bit <= 3; bit++) {
 port[0x3c4] = 2;
 port[0x3ce] = 4;
 port[0x3c5] = 1 << bit;
 port[0x3cf] = bit;
 blockread(f, a0, 12080);
 move(a0, a1, 12080);
}*/

Graphics::Surface background;
background.create(_vm->_graph._screenWidth, _vm->_graph._screenHeight, Graphics::PixelFormat::createFormatCLUT8());

byte backgroundHeight = 8 * 12080 / _vm->_graph._screenWidth; // With 640 width it's 151
// The 8 = number of bits in a byte, and 12080 comes from the original code (see above)

for (byte plane = 0; plane < 4; plane++)
 for (uint16 y = 0; y < backgroundHeight; y++)
  for (uint16 x = 0; x < _vm->_graph._screenWidth; x += 8) {
   byte pixel = f.readByte();
   for (byte i = 0; i < 8; i++) {
    byte pixelBit = (pixel >> i) & 1;
    *(byte *)background.getBasePtr(x + 7 - i, y) += (pixelBit << plane);
   } 
  }

_vm->_graph.copySurface(background);

background.free();

As you can see I left the automatically converted loop in a comment. Under that, there's my C++ interpretation of it. You can find the idea behind that loop's core on this page. We guessed it's using four planes because the original loop goes from 0 to 3. So my code does the very same. It first reads the blue component of every pixel: since every bit represent a pixel, we jump in the x loop 8 times every time, and read a byte only after every 8th processed pixel. After that, we loop through the given byte, get the blue component of every pixel, and put them in their place. We do that four times, so every plane (blue, green, red, intensity) is read by the end of the big, plane loop, and finally we got the background image!
The interesting part with this is the following: we read an image with the size of 640x151. That's ok, but after playing the game a couple of times using DOSBox, I clearly saw that it shows the background image (and obviously the whole game too) in a much bigger resolution. I found that the window's size the emulator uses is 640x400. It's very strange since the original Pascal code (as I mentioned above) uses half of that height. To mimic DOSBox's output, I put a little supplement into Graph::copySurface() which copies every line of the background 2 times. After that, my graphical output became almost the same with the one DOSBox produced, but I am still not sure if it's the right way of operation and I am still searching for traces of this "stretching" in the original code.

(P.s.: Thomas: if you read this post and have any clue or suggestion about this resolution-problem, I'd be very glad if you could share it with me in a comment or by mail! :) Is the original output of the game really in 640x400, and if it is, where the "trick" is located in the original code which makes it possible?)

Tuesday, July 9, 2013

End of file handling

Hey everybody!

Sorry for my long absence! The case is that we just renovated our house with my family during the weekend (starting with Thursday), so I didn't have much time to spend with coding. But as we finished with all the work around our house yesterday, here I am again, more tenacious than ever!
I also finished today with the file handling (at least with those parts what don't involve saving/loading current game stance, only loading screens, sprites, texts, etc.). Sometimes figuring out what the Pascal sources are intended to do and converting it to C++ code was a rather tricky thing. (For example the problem with Pascal-style arrays and strings. Especially strings.) But finally I came over it, and now it's done and working. At least I think it does. I made several tests to them, almost trying with all the functions and all their source files (mostly *.AVDs), but the real test will be using them in the final code. (You can check this link, if you'd like to know more about Avalanche engine's file types and other related topics. Written by the original author of the game himself!)
My plans for the following days are these: I'll follow the program flow with the help of the warnings I placed previously in the code during stubbing, and going one by one, I'll implement each and every function in the code. I think the real pain will come with the screen processing units, but I don't think I have anything to fear as long as I have as awesome helpers as fuzzie or dreammaster.
(Sadly, my mentor, Strangerke is on holiday and we can connect only rarely, but luckily SvummVM has a great community, so I don't think that I'll be suffering from the absence of help even for a minute.)

Tuesday, July 2, 2013

Lets begin with file handling!

Yes, lets go!
As I am finished with the stubbing at last (*Phew!*), I can finally start reworking the code and implementing the functions of the classes made during the past two weeks. My plans for today is filling the gaps in the main class Avalot and then following the execution path of the program to get an even better sight of the behavior of it. (Because during the stubbing of the engine I think I understand the connections between the original units pretty well, but there are still blind spots here and there.) After that, I'll jump right into file handling and keep working on it until everything is going fine and smooth.
See you later! I'll report you guys as soon as I progress significantly!

Monday, July 1, 2013

End of stubbing

I just wanted to tell you guys that I am finished with the stubbing. And I am totally exhausted. And I am finished with the stubbing.
I can't describe how relieved I feel now. :D

Saturday, June 29, 2013

Sign of life

Hey everybody!

Don't worry, I am still alive! ;) The cause of the absence of posts is that I still keep on stubbing the engine to make it work, to make it more object oriented and in general: more C++-like. (Which I am sure you can see if you check my GitHub repository regularly.)
I followed a dead track for some days: I made all of the Pascal units into C namespaces, but after my mentor highlighted a much better way (using C++ classes instead of namespaces), I changed my methods and I am proceeding quite well now. Sometimes I just really don't know what I would do without him.
Thomas (one of the original creators of the game) was also very kind and provided me with a recreation of the missing ROOMNUMS.INC file (It can be found in my repo under the name of "roomnums.h" now.), which I am using since then. He saved me a bunch of time with his action and I am very thankful for that.
So please stay tuned! Only a few more days and I'll be finished with the stubbing and I can finally start working on the implementation of the functions and the real fun will begin.
See you soon!

Friday, June 21, 2013

Stubbing

Just beautiful... But it's a bit repetitive, isn't it? :)
That's the actual output of my project, as well as a blank main ScummVM window.
Although it doesn't seem so (judging by the picture), I've made incredible progression (compared to myself) during the past three days. My engine is now up and hooked into the VM. (After many hours of struggling with the detection - Right, Arnaud? ;D)
Besides that, I also included the main loop of the game in avalanche.cpp and started working on the include files of the original sources what I'll need in order to make the function run_avalot() (in the main loop) operate. (Which calls the method of the class Avalot you see in the picture, which will be responsible for the actual gameplay.) My first target was Gyro, what I stubbed heavily to make it behave, and during the following days I'll keep on adding and working on these (now header, not include) files as fast as possible.
Listening to the advice of my mentor, I also reorganised the sources: I made a new folder for the already used and the not-yet used converted files and left the files I made myself in the root. I think now my work will be more followable for those who doesn't have the MSVS2010 project file I use.

Tuesday, June 18, 2013

Beginning

As Google Summer of Code officially started on yesterday, I started the actual coding as well. The amount of code is still frightening a bit, but with the help of my mentor and enough tenacity, I am sure I will succeed.
Looking through the automatically converted sources (made with PtoC) and adding the standard header to the files (with the awesome help of License Header Manager for Visual Studio) and a namespace for my engine took up most of my Monday. Luckily, I am a bit more familiar with Git by now, so using it didn't cause me any troubles.
My plan is now to make the converted sources more readable using Artistic Style, then add an empty engine to my work and hook it into ScummVM. You can read more about the procedure here. (And I hope soon here, in my blog as well when I am finished with it.)
There is still the problem of the missing ROOMNUMS.INC, but I think we'll be able to get through it, thanks to this great wiki the original author made himself to help the porters. (Especially with the help of this page.)
By the way, if you are interested in my work and would like to follow it a little closer, you can find my repository on GitHub, where I "commit early, commit often."

Tuesday, May 28, 2013

Acceptance

Yesterday I got my e-mail from Google: my project is among the accepted ones, I can participate in Google Summer of Code this year! I just can't describe the happiness I felt then. It's something like a dream came true for me.

So this is my very first post in my very first blog, where I will describe my progression during GSoC in 2013. I hope it will be as much fun to read as I think it will be to write.

My project (in a nutshell) is the following: https://google-melange.appspot.com/gsoc/project/google/gsoc2013/uruk/53001
I have a detailed plan for the next few months and I hope I will be able to accomplish everything I described earlier. On the other hand, I don't take ScummVM as a one-time thing, so it won't be a tragedy if I don't finish my project by the end of September. (But of course I will try my best to do so.) I'd really love to stay in the community and become a developer myself with this engine, and later with other projects. I think the organization's goals are great and I am proud that I can contribute to the success of it.

The actual coding will begin by the 17th of June, so I'll start posting regularly by then. See you later, my dear reader! I hope we'll have a great summer together! ;)


P.S.: Sorry for my English well in advance - I am not a native speaker and never been the best with the language itself.