Tuesday, December 10, 2013

Super Doriath on ColecoVision, Mockup v2. (VI)

I am proud to present an updated graphical version of the game, this time based on: Graphic Mode II. It is still a mock-up and I started to figure out how the tiles will be placed in memory.

Graphic Mode II allows 2 colors per line within a character. While Graphic Mode I (previous version) was based on 2 colors per character.

SuperDoriath, mockup v2.


The inconvenient of using this graphic mode is in term of resources. It take more memory in the cartridge, in the video RAM and also more CPU to create tile-animation (especially because for a given tile to appear anywhere on screen, it need to be copy at 3 different location).

But... it does look way better!

I also expect more sprites-flickering, but I think the additional color for the player worth it.


You may also notice the name become... "Super Doriath". I don't want to just port the game to Coleco Vision, but I want to make it a better game... stay tunes!



And as always, thanks for reading!

Thursday, September 5, 2013

Doriath on ColecoVision, The Tools. (V)



When I first started to see if Doriath could be made on Coleco Vision, I got no idea what are the tools available. After asking on forums, a lot's of people give me some help by telling me where to look for documentation, tools and hardware.

In this article, I want to describe the tools I will be using, my though about it and what I consider to be useful. You does not have to write your software in assembly language, but in my case the choice is clear... assembly language only!

Why? I wanted to get in control of the code and data, explore some limitation of the hardware and I knew that I want to produce the game only on ColecoVision platform. So, no need to port the game and by doing so I can learn more about the machine and its limitation.

Then, the question is... which compiler I will use to produce a binary (.ROM) from the source code I will write (text file)?
I have been suggest to use tniASM for pure assembly language. It's a command line utility, easy to use which can indicate errors by specifying line number where the syntax error occur.



The compiler does not seem to offer much feature. I would have like to see a Map and Listing file, which could help to know the length of functions and data.


I was considering to write my own compiler. In the past, I wrote a compiler for assembly language for some Commodore 64 personal projects. It was a compiler that was producing a disk image, rather than a file!

You may wonder, why someone today will be writing his own compiler if one already exist? In fact, you may be doing so when you see that you can add features or use new concepts. Back to my C64 compiler, I wanted to have an easy way to manage data on a full diskette and not be limited to one file. By writing my own compiler, I could provide keywords that will tell where to place data on disk and eventually automate some disk access without using other utilities.


Basically, by writing your own compiler, you can bring feature that will save you time or give you information to improve what you try to achieve.


Some compilers come with an IDE (Integrated Development Environment) which offer a text editor and debugger. With tniASM, you need to use your favorite text editor and Emulator/Debugger.


Notepad++ is a free and small software which can be run easily and support many features for text editing that we can find in a complex IDE like the Microsoft Visual Studio (text editor).

It support many computer languages and will identify keywords and types by changing colors or style which make them easier to read. It also support the ALT + click and drag mouse feature, which allow to edit columns of text. That feature is very convenient when editing array of data.



Did I think to write my own text editor? In a way yes... when I see that I will be in a text editor, compiling in a command line. Then, getting an error on line # x in file y. Hum... I though there is room for so much improvement that it's seem an interesting project.



I was thinking to have a real-time compiler combine with a text editor. Something which does not need to click... compile, but does self-modify as you type your source. New features like being able to modify code while keeping copy of other versions, allowing the programmer to see if his changes does reduce the number of bytes or clock cycles. Or, to be able to click on the header of a function and tell, add this to a library of functions for reference or re-usability in a newer project. We can even push it further by selecting a bunch of functions set in a library and be able to generate a computer language out of it.



When you are the one writing the software, you can imagine pretty much what you want! You know that the more features you add, the more work hours you will need. As a programmer, I can do barely any kind of software and routines. If it involve so many hours, why not programming something which write software by it's own? I got some serious though about this problem over the years of what limit what a person can write as a program. How we overcome problems which at first we don't know how to solve? Hum, as you can see ideas of big projects are coming out faster than I could make them. I choose to pick up this game & blog writing first. Was it a good idea? ;-P



Back to the tools... In order to execute and debug my game, I will be using an emulator: BlueMSX. It does contain a debugger which allow to enable breakpoints, step through the execution and so on. I don't think it offer a feature to measure clock ticks between 2 points. The only way I can think about profiling stuff is to loop a routine N times and calculate the number of NMI interrupts. Having a precision of 1/60 seconds is not too bad but it could be definitively better, I would say... 16.7 times better!

When I was thinking about having my own compiler combine with a text editor, I was also thinking about emulating the chips. But then, that mean having to support all hardware components, doing reverse engineering on the hardware and so on. In short... a project for the next 3-5 years considering a 4-6 hours of free time per week and not doing any other projects. So, for now, I will focus on the game itself and learn the tools that other did.


Even if testing in an emulator could be good enough, as I am interested to know the details how it work. I got to test some stuff on the real hardware. People are selling their Coleco Vision mostly on eBay.

I am not interested to have one forever but will prefer to have one for testing until the end of the project. I don't like to pile up stuff and prefer to keep things which I use. I could resume my way of consuming goods on saying that I tend to be fast on giving my things and slow on acquiring new stuff. I like organize place and easy to clean. I regret so much when I purchase something which I don't use. So, when it's time to buy I would ask myself many times, do I really need this?

Lucky I am, my best friend is quite the opposite and agree to provide me a Coleco Vision. I promise him the game in return of the rent! Is it a good deal? Well, I guess we will find out only at the end of the project.

On the other hand, I purchase an Atarimax Ultimate SD cartridge. Having the hardware is one thing, being able to put my software in is another thing! There was two options, this cartridge or an EEPROM and an EEPROM programmer. It is more easy and fast to write a file on SD card than it is to write on an EEPROM.


So far, I have receive it and started to experiment how the video chip is working. On my first day, I achieve a stable CPU-VDP (Z80 and TMS99x8) communication for every frame and display 48 sprites on screen (where the limit is known to be 32). On my second day, I tested the text mode by switching the color and char patterns at specific place on screen. I also create a new video mode based on the multicolor mode. But instead of a resolution of 64x48, the new one is 64x192.

You can get my source code, binary and screenshot here:
http://atariage.com/forums/topic/216268-my-first-test-on-the-tms9918/#entry2823655


EPROM



If you would like to burn an EPROM, there is one available with a PCB for 12$. From the pictures I saw, I think you need to buy a socket if you want to easily remove, reburn and place back the chip. When I will complete the project, I think to go with someone that could distribute the game rather than doing it myself. Being a producer and distributor could be a cool thing to do but that will involve more spending in money and time. With one game only, and the small market potential, I think it make more sense to go with a distributor.

Website for the EPROM cartridge: http://www.colecovision.eu




An EPROM programmer is necessary in order to program your chips. Eprom programmers like the one from Batronix can program a variety of chips. I don't know the voltage required to write, but I guess the speed being not too fast, maybe a MSP430 combined with enough memory to hold 32 Kb could do the job. A MSP430 (16-bits microcontroller) devkit from TI cost 4.30$ US! That's just a guess, but if someone could come with a programmer around 25$, that will make this solution more affordable.

You can find the this EPROM programmer at batronix.com.

I was talking above about chips emulations. In fact, when analyzing the limit of the hardware, being able to measure things make a big difference between hypothesis and facts. Being able for example to probe the video signal to see the timing of HSYNC and VSYNC via analogue probes and be able to measure data transfers on bus via digital probes could be useful. I saw that Rigol seem to have an interesting product for that type of measurements. However, I did not investigate more about it and there might be other brands which are better.

If I would be thinking to build a new hardware design, then for sure this tool will be required. But, for software development so much can be done without it.

The model DS1102D is a 100 Mhz mixed signal, available for 840$ + Taxes + Shipping at batronix.com.



And as always, thanks for reading!

Thursday, August 22, 2013

Doriath on ColecoVision, Mockup. (IV)



In my previous article, I manage to re-size screens according to the Coleco Vision specification. However, each tile or character shown was the original tile from the Commodore 64. On the Commodore 64, tiles can be either 8 x 8 pixels using 2 colors or 4 x 8 pixels (larger pixel size) using 4 colors among the 16 colors available.


The game on Coleco Vision will be using Graphic Mode I. This graphic mode allows up to 256 tiles. Each tile is 8 x 8 pixels and is limited to a 2 colors pattern among the 15 colors available. The 2 colors of the tiles are specified for each 8 consecutive tiles among the 256, which give a total of 32 entries ( 256 tiles in total / 8 tiles ).

The screen during the game is divided into 2 parts: information (upper part) and action (lower part). In order to keep the same number of lines for the action part, the information is limited to 4 lines (instead of 5). The 5th line in the original game is use to display the content of the chest box for few seconds when the player open one. This information can be display on line 4 for few seconds and switch back to display the position of the player. The information section (shown above) will need 4 sprites to enhance the icons.

I decided to add the scroll fragment and I am not sure if the wisdom display in the original game is relevant. From my understanding the wisdom give an idea about the completion of the game. But, amulets and scroll fragments seem a better indicator. In case I need to add wisdom, I plan to add the percentage above the scroll fragment number (similar to what I did for the Stamina Potion & Stamina).


The keypad on the Coleco Vision controller will be use to activate items:

  1. Stamina Potion
  2. Portcullis Key
  3. Trapdoor Key
  4. Fungata Potion
  5. Cloronar Potion
  6. Scroll Fragment
  #. Option Screen (To Be Define...)

A plastic with the proper graphic would be design once these options are confirm.


In order to validate the look of the game, I decided to work on the tiles and use the original sprites (but with the Coleco Vision colors).


I have redraw the larges tiles using the restriction mentioned above. I try to maintain the original look and feel while doing some small improvement.

I took 7 screenshots of the original games which has different characteristics.



This screen offer a mix of different color elements. A mix of cave & brick tiles and include various elements like: fire, ladder, rope, portcullis and a drop of water. I decided to keep the ladder near the brown color, but use 2 greens for the rope.

This screen is to verify how it look when most of the elements are red. The brown on Coleco Vision being mostly red. 

This screen is to verify the yellow use for the cave patterns versus the King's enemy.


This screen is to verify how the mushroom will look like (enhanced with 1 sprite).


This screen is to verify how the purple used for Mingos's enemies look like next to the red used for the bricks.


This screen is to verify how the cave pattern look like. I work mostly on these tiles trying different patterns of pixels and colors. I was thinking to enhance it with some tiles of dark yellow and white colors, but the look on one screen make me think that the spread of white mark may look like a bug.


This screen is to see how the water look like.


It may not be final, but so far I am quite please with this look. In order to keep record of each tile (character), I created a template where I add the tiles the game need.

The first two columns are reserved for my own usage (the Coleco Vision palette and the colors I pick for the 8 tiles on this line).

I add a red layer over the tiles which are needed to display the information above the action screen. A green layer is over the tiles which will cause collision detection between sprites and background.

The charset will be at least use in 2 copies in the Video RAM. One where all tiles will be copied, and the 2nd one where the last 8 lines will be missing. These 8 lines give a total of 64 tiles reserved to display a Draconis or Krakoli.

Some characters will be updated to produce an animation: 1 tile for fire torch,  9 tiles for water and 16 tiles for water spray. Since these animation are running below refresh rate, these animated background objects will be schedule to happen at different frame. This will reduce the amount of work that need to be done to render a single frame.


Please leave your comments below. ^_^

And as always, Thanks for reading...


Tuesday, July 30, 2013

Could the world of Doriath from C64 fit into the Coleco Vision? (Part 3)


The biggest challenge so far in this project seem to be how to store the entire maze? After all, looking back to games on Coleco Vision, many got less than 10 different screens (some games like Donkey Kong only display 3 screens)!

In my first post, I end up with a map of 256 rooms to adjust. Re-sizing them from 40 columns wide to 32. But, after spending a few hours on that task, I realize that it would take days and days!



I then start to look to other approach, I find out that each room are divided into 8 large tiles (as shown above). Before describing how these large tiles work, I need to explain the states of the dynamic elements found in this game.


MAZE STATES

Some elements in the maze has two different states. For example, a chest box can be either close or open. The state of these elements will determine how they will be draw on screen.


There are 7 different elements (illustrated above) which the player can encounter when entering a room: 
   - Chest Box;
   - Up to 2 Enemies (Enemy #1, Enemy #2);
   - Mushroom;
   - Flower;
   - Trap Door;
   - Door (Portcullis).


Looking at the entire maze, we will never have a mushroom and a flower in the same room. In fact, we will never have more than one enemy when there is a mushroom or a flower. We can now group the information as follows:
   - Chest Box;
   - Enemy #1;
   - Enemy #2 / Mushroom / Flower;
   - Trap Door;
   - Door (Portcullis).


There are 14 trap doors in the game. We can found a trap door with : a Chest Box + 1 Enemy, a Portcullis + 1 Enemy or 2 Enemies.


Knowing that, we can reduce it to 4 bits of information:
   - Chest Box;
   - Enemy #1;
   - Enemy #2 / Mushroom / Flower / Trap Door;
   - Door (Portcullis) / Trap Door.


Where, when there are 2 enemies, the state of the trap door will be located at the door state, otherwise at enemy #2. A value of 0 will represents the default state: chest box close, enemy alive, door close and so on.


ROOM States (Bits Description)

7 6 5 4  3 2 1 0
x x x x  x x x x
| | | |  | | | |
| | | |  | | | +--- -Chest Box  A, 1=Open 
| | | |  | | +----- -Enemy #1   A, 1=Killed
| | | |  | +------- -Enemy #2   A, 1=Killed / Mushroom  A, 1=Active /
| | | |  |           Flower     A, 1=Grown  / Trap Door A, 1=Open
| | | |  +--------- -Portcullis A, 1=Open   / Trap Door A, 1=Open
| | | |  
| | | |  
| | | +------------ -Chest Box  B, 1=Open 
| | +-------------- -Enemy #1   B, 1=Killed
| +---------------- -Enemy #2   B, 1=Killed / Mushroom  B, 1=Active /
|                    Flower     B, 1=Grown  / Trap Door B, 1=Open
+------------------ -Portcullis B, 1=Open   / Trap Door B, 1=Open

Where A is for the rooms numbers which are even (0, 2, 4, ...), while B is for the odd numbers (1, 3, 5, ...). The initialization of the maze (at least for the rooms) will consist of writing zeros at these 128 bytes RAM.

Note: When the player exit a room and all possible elements for that given room are set, all 4 bits should be set to 1. So, even if a room contain none of these element, when the player leave that room all bits should be set to 1.

The nibble corresponding to the current room will be store into a specific byte, which will simplify the reference to this information in our code (+ 1 byte RAM). The higher nibble of that byte RAM will specify if the element is present (set to one) or not.

A total of 129 bytes (RAM) will be use for the entire maze states.


Enemies

In order to determine if a trap door will be draw open or close, we need to know if there will be one or two enemies.



Among the 256 rooms, 39 has two enemies while 73 has only one enemy. Enemies are described by their type, their initial coordinates on screen and their type of movement (stand still, short distance walk, long distance walk or move straight forward).

I compare these attributes (by taking out bytes from the original game) and found that the unique description needed for two enemies went down to 37. Doing the same for single enemy, the number went down to 60.


Enemies (Bits Description)

Byte 0:

7 6 5 4  3 2 1 0
x x x x  x x x x
| | | |  | | | |
| | | |  +-+-+-+--- - Enemy Type: 1=Plebata, 2=Plebata-Archer, 
| | | |               3=Roimort, 4=Wispith, 5=Cobron, 6=Magusaan,
| | | |               7=Quasilin, 8=Mingos, 9=Krakoli, 10=Draconis.
| | | +------------ - Position X (5th bit)
| +-+-------------- - Movement: 0=None, 1=Short, 2=Long,
|                     3=Straight Ahead.
+------------------ - Initial Direction: 0=Left, 1=Right.


Byte 1:

7 6 5 4  3 2 1 0
x x x x  x x x x
| | | |  | | | |
| | | |  +-+-+-+--- - Position: X (lowest 4 bits), from 0-31
+-+-+-+------------ - Position: Y, from 0-15

The enemy initial coordinates on screen is ( x*8, y*8+16 ) pixels.

The reference table to access these 2 bytes (or 4 bytes, if two enemies) will use 256 bytes, one byte per room. In fact, 7 bits out of 8 will be use because they will refer to less than 128 enemies descriptions.

The enemies descriptions will take 120 bytes for 1 enemy (60 x 2 bytes) and 148 bytes for 2 enemies (37 x 4 bytes).

A reference number equal to 0 will be reserved for 0 enemy. Then reference numbers from 1 to 60 will be use for single enemy and from 61 to 98 for two enemies.

Six bytes in RAM will be use per enemy :
   - Type (bit 0-3: type, bit 4-7: reserved)
   - Attributes (bit 0-3: color, bit 4: fire a spell?, bit 5-6: movement, bit 7: direction left/right)
   - Enemy X position (in pixel)
   - Enemy Y position (in pixel)
   - Spell X position (in pixel)
   - Spell Y position (in pixel)

I may use 2 additional bits (currently reserved) to allow X coordinates to be greater than 255.

Total size to store enemies information:
256 + 120 + 148 = 524 bytes (ROM) and 2 x 6 = 12 bytes (RAM).


Large Tiles

The main component of the maze are the 8 large tiles which I mention at the beginning of this article. When doing some analysis, I notice that each corner (2 x 2 characters) can have 3 patterns.




A corner can be either transparent (display whatever is on the tile), use a brick or a cave pattern. There are 4 cave patterns, each one match a specific corner.


Large Tile Corners (Bits Description)

7 6 5 4  3 2 1 0
x x x x  x x x x
| | | |  | | | |
| | | |  | | | +--- - Top-Left     Pattern : 0=Brick, 1=Cave
| | | |  | | +----- - Top-Right    Pattern : 0=Brick, 1=Cave
| | | |  | +------- - Bottom-Left  Pattern : 0=Brick, 1=Cave
| | | |  +--------- - Bottom-Right Pattern : 0=Brick, 1=Cave
| | | | 
| | | +------------ - Top-Left     Opaque : If set, Yes.
| | +-------------- - Top-Right    Opaque : If set, Yes.
| +---------------- - Bottom-Left  Opaque : If set, Yes.
+------------------ - Bottom-Right Opaque : If set, Yes.



When we ignore these corners, there are only 70 large tiles. 

On the other hand, we can count 142 different large tiles which required corners. These large tiles take 2 bytes for their description. The first byte being the pattern of the large tile (among the 70 we found). The 2nd byte is the byte described above (Large Tile Corners). 

Each room will use 8 bytes, one for each large tile. Also, since there are 5 different patterns of 2 x 2 characters for corners, we need to add 20 extra bytes.

Total size to store large tile references and corners: 
256 x 8 + 142 x 2 + 20 = 2,352 bytes (ROM)



Large Tiles - Type A      (0x00-0x1F)

The 70 large tiles can be grouped based on their design properties. In the first group, they are organized in a specific order which tell which wall to be draw based on the 4 lowest bits.

If you look closely, you will notice that bit 0 (set to 1) will draw the wall on the left, bit 1 the one on the right and so on. Bit 4 (#16 to 31) will draw a ladder in middle prior to the walls. Tile #31 is a special case where the two upper lines will be erase, then 2 brick corners will be draw. These tiles will be generated by code only, no data is required.


Large Tiles - Type B      (0x20-0x2D)

Large tiles of Type B are the one which required to be store as is (8 x 10 = 80 characters), except for the one which has a chest box. The Chest Box appear only when the large tile number is odd (35, 37, 39 and 41). The position of the Chest Box is equal to the 4 lower bits divided by 2. For example, large tile 35 which is 0x23 in hexadecimal: (0x23 & 0x0F)/2 =  0x03>>1 = 1. Using the same logic: 37 give x = 2, number 39 give x = 3 and number 41 give x = 4. Which is the position of the first character used to display the chest box. The vertical position being constant. These positions are relative to the tile, not to the screen.

To store the 7 large tiles design of Type B, I will need 7 x 80 = 560 bytes. To store the Chest Box open and close, I will need an additional 2 x 6 = 12 bytes.


The total size required to store large tiles of Type B is: 
560 + 12 = 572 bytes (ROM).


Large Tiles - Type C      (0x30-0x38)

Large tiles of Type C are the one using water patterns. You will notice in the original game that the water is animated. At this point in time, I have an idea how the water is animated but not entirely sure about its details. I would store the entire water pattern on the first water tile (#48). I think there is different characters used and the bitmap inside these character get updated at each frame.

Since the water fall on tile #48 is 4 characters wide and 10 characters tall, it will required 40 bytes. Water fall on pattern #49 and 50 is almost identical to #48. On pattern #49, I could store the last 2 lines (16 bytes). Pattern #50 may look like 2 cave corners, but they are not. They use a slightly different variation which make their slope look sharper. To store these 2 corners, I will need 8 bytes.

The water fall at #51 and 52 contain a water fall but also a lake which we see on tile #53 and 54. Specific code should be written to handle these two cases. We will need 16 bytes of data for the last two lines at #51 and 8 bytes for #52. Tiles #53 and 54 will required 16 bytes each, while tiles #55 and 56 which are 5 lines height, will required 40 bytes each.


The total size required to store large tiles of Type C is: 
40 + 16 + 8 + 16 + 8 + 2*16 + 2*40 = 200 bytes (ROM)


Large Tiles - Type D      (0x39-0x3E)

Large tiles of Type D are in fact the leftover ones! They have been moved here in order to reduce the numbers of indexes reserved. Leaving more indexes available for tiles which need corners patterns for their description.

Tile #57 and 58 had 2 columns wide and will required 20 bytes each. Tile #59 will required 40 bytes. The 3 others large tiles (#60 to 62) are 4 lines height and will required 32 bytes each.

The total size required to store large tiles of Type D is:
2 * 20 + 40 + 3 * 32 = 176 bytes (ROM)


Large Tiles - Type E      (0x40-0x46)

Large tiles of Type E contain a rope in its center. The rope will be draw first and then some part could be erased for #66 and 67. The corners on #67 and 68 are usual corners which can be add after the large tile has been draw.

The data required on tile #65 to 67 is : 3 x 16 = 48 bytes. And, the data required for tile #68 to 70: 4 x 20 = 80 bytes.

The total size required to store large tiles of Type E is: 48 + 80 = 128 bytes (ROM)



Large Tiles - Type F      (0x48-0x4E)

Large tiles of Type F could feature some interactive elements. The flower needs 2 and 14 bytes, for a total of 16 bytes. The mushroom needs 2 x 6 bytes (as there are 2 characters on the ground which differ from the pattern of tile #72). The torch needs 6 bytes (a character which display the fire on top of it will also be stored). Trap door needs 2 x 3 characters for open and close drawing. And portcullis will be generated because it's only one character.

The background of these tiles will need 16 bytes for the 2 lines on tile #72 to 74. Tile #75 will take 32 bytes.Tile number 77 will required 4 bytes (one corner which is repeat on both side), the extra character needed below the trap door close will be added in code. Large tile #78 will needs 4 bytes for the top and bottom parts of the portcullis.

The total size required to store large tiles of Type F is:
(16 + 12 + 6 + 6) + (16 + 32 + 4 + 4) = 96 bytes (ROM)


Large Tiles - Type G      (0x50-0x58)
Finally, large tiles of Type G feature some low-danger elements : lava (#80 to 82), water split (#83 to 85) and water drop (#86 to 88). Some information will be added to our game engine to manage these animation which could reduce player's stamina in some circumstance.

The lava tiles need 16 bytes each, the water split tiles need 24 bytes each, tile #86 needs 32 bytes, #87 needs 5 x 8 = 40 bytes and #88 need 6 x 8 = 48 bytes. 

The total size required to store the large tiles of type G is:
3 x 16 + 3 x 24 + 32 + 40 + 48 = 240 bytes (ROM).




Chest Boxes




A fixed length vector with room numbers will be use to determine the content of each chest box. Room numbers will be store grouped together. The order would be: Amulets (in amulet order), blue keys, white keys, scroll fragments, red potions and the green potion. Since stamina potions are the most common item, if the room number is not found in the list, it will be a stamina potion. The amulet ID would be directly taken from it's position in the list.


There are: 59 stamina potions (default value, not stored), 14 blue keys (portcullis), 11 white keys (trap door), 9 amulets (including Plebata and Quasilin), 8 scroll fragments, 4 red potions and 1 green potion. 

To store these information: 47 bytes will be required.

Note: There is 14 traps and 17 doors to open. So, there are a total of 6 keys missing?


Maze Conversion & Total Size
After re-sizing 70 large tiles, I was able to generate the maze adapted for Coleco Vision display (32 columns by 20 lines per room). You can see above the result for part of the maze: on left: original game on Commodore 64 and on right: Coleco Vision, but using the original charset and colors.  


The total size required to store the maze information (excluding charsets and sprites) is:

                                    ROM     RAM
Maze States...........................0     129
Enemies.............................524      12
Large Tiles References............2,352       0
Large Tiles A.........................0       0
Large Tiles B.......................572       0
Large Tiles C.......................200       0
Large Tiles D.......................176       0
Large Tiles E.......................128       0
Large Tiles F........................96       0
Large Tiles G.......................240       0
Chest Box (contents).................47       0
----------------------------------------   ----------
Total............................ 4,335     141 bytes

With less data, more code will need to be written. How much bytes will the code will be taken? These numbers are not final but it give you a good idea about how small things can get. How big 4,335 bytes is? If we take that number divided by the number of rooms we get 16.9 bytes. So, in average a room take less than 17 characters long to describe how it should be draw (excluding charsets and sprites).

If I would want to save even more bytes, I would study the references tables which describe the 8 tiles and also the 256 bytes that tell where to look at for the enemies description. Together, they represent 2,304 bytes (more than 53% of the total data described here). By using more code, CPU cycles and 9 extra bytes in RAM, I think the total size could be reduce below 4 Kb!

I will conclude this article (pretty long one)... with an example to illustrate the process.
And as always, Thanks for reading...


- - -

Example:
Room name 'Hall 01 of Cerim's Deep' or room #0x20.


1. Entering for the first time room #0x20, retrieving the states...
  • Look at offset 0x20>>1 = 0x10 in RAM, for the lowest nibble (even room number).
  • The binary value found will be 0000 which we will store to the current room state byte.

2. Getting Enemies Information
  • Read the enemies index from the enemy look-up table using the room number 0x20.
  • The index return will be between 1 and 60 because there is one enemy in this room.
  • Two bytes will be read from the enemy information: 83 F7.
  • In RAM, 12 bytes will be written for the enemies: 03 8A 38 88 00 00  00 00 00 00 00 00
  • If enemy bit is set, to indicated that the enemy is kill, the enemy type is set to 0. (e.g.: if Roimort is dead, the 12 bytes would then be: 00 8A 38 88 00 00  00 00 00 00 00 00).
  • Bit 5 on the current room state byte will be set (since there is one enemy).

3. Drawing the room

The large tiles reference values in decimal, for room 0x20 are: 
42, 88, *1, 44
39, 83, 77, *2

where *1 and *2 are numbers higher than 88 (the last tile), which mean they consist of large tiles + corner patterns byte.


*1 will point to the 2 following bytes: 64 (tile) and 0x33 (corners).
*2 will point to the 2 following bytes: 81 (tile) and 0x22 (corner).

Each large tiles will be draw. When drawing large tile #39, the Chest will be draw closed as the bit state in RAM is 0. When drawing large tile #77, the second byte for the enemy being 0x00 (color = transparent) indicate that there is only 1 enemy in that room. The bit for the 2nd enemy will be use to determine if the trap door is close or open.

When drawing large tile #39, the bit 4 for the current room state byte will be set. When drawing large tile #77, after looking for the 2nd enemy attribute byte, bit 6 of the current room state byte will be set.


4. When the player passes next to the chest box. 

A function will be call to know what is inside. The value 0x20 will be find in the chest box vector (unless the chest box contain a stamina potion) and it's position will determine the corresponding object type found.


5. When the player exit the room: Saving Room State.

The current room state byte will be read and a comparison will be made between the two nibbles (lower and higher 4-bits). If they are identical, the lower nibble will be set to 0xF. Then the lower nibble of current room state will be stored at the lower nibble of offset 0x10 in RAM. 


Note: I did not provide details about water and lava elements for now, they will be describe later.