ChibiFighter Beat em up / Tilemap demo!
Introduction to the CF Series...

Suck Hunt is a little demo game which uses the 'MinTile' software tilemap (or hardware on SMS) for graphics, ChibiTracks for music and presents a little fighting game with an AI CPU player.

It runs on CPC / MSX2 / Spectrum NEXT and SAM coupe



Lesson CF1 - Supertiles
The  game area of ChibiFighter uses a 32x20 tilemap.

Each game level has a different tilemap scene. To save memory these are compressed using 'Supertiles' - Blocks of 4x4 tiles.

See ChibiFighter folder


Patterns and Supertiles!
Here is our game screen. The background is 32x20 tiles.

We'll split up the background map into 4x4 tile supertiles. The supertilemap will therefore have 8x5 entries (40 supertiles)

The actual map will use one nibble per supertile definition - meaning 16 supertiles max.

This means each 32x20 level background uses a supertile map of just 20 bytes
Here are the tile patterns we've defined
We combine these into supertile definitions.

The Supertile definitions are also compressed - each 16 tile supertile is stored in 8 bytes. this is achieved by storing each tile as 2 bit definition, with a 4 bit tile lookup.... This means we can only use 4 unique tiles in each supertile.
Here is the supertile map that defines the green play area.
The first byte is the height of the supertile map (it must be the full width of the screen - 8 supertiles)
The next two bytes are a pointer to the supertile definitions.
The remaining bytes are the supertile numbers, one nibble per supertile
The actual supertile definitions each use 8 bytes.

The first 4 bytes are the Index/LookUp Table of the 4 tile pattern numbers that are used in this supertile.

The next 4 bytes are the 16 tiles that make up this 4x4 supertile... Each byte is one line of the supertile, pairs of bits define which Index entry in the LUT define the pattern number for that tile.
LoadSuperTileMapNibble will 'decompress' the supertilemap into the tilemap.

IXL is the First tile pattern num (pattern offset) - this is used to skip the font for the background graphics
HL  is the Source Supertilemap
HL' is the Destination Tilemap in RAM - this is used to actually draw the screen.

With MinTile the RAM tilemap is 36 tiles wide... this is to allow a 4 tile 'scrollable' area

We load in each byte, and split it's two nibbles, processing them with CopyOneSupertile4ByteLut

A   is the Supertile Definition Num
IY  is the address of the Source Supertile definitions
HL' is the Destination Tilemap RAM
IXL is the offset tile num (in pattern data)

Each supertile definition is 8 bytes, so we first multiply A by 8, and add it to the source definitions in IY - storing the result in DE

The first 4 bytes are the Index/LUT of tile numbers
The second 4 bytes are the 2 bit lookup entries - each byte is one line of the 4x4 supertile.

We next shift into the supertile numbers, by setting bit 2 of DE

We load a byte into C - each tile is defined by 2 bits so this is a whole line.

we read 2 bits at a time, and read the actual tilenumber from the index, and put this in VRAM in HL

after each line of the supertile, we move down in the tilemap vram by adding 32 (32+4 = 36... the width of the tilemap in VRAM)
Here we use the supertile code to draw the player life bars at the top of the screen


Lesson CF2 - Titlescreen and GameStart
Lets take a look at the 'compressed' titlescreen code, and the game init routine

See ChibiFighter folder

Titlescreen

Lets draw our title screen!
At the start of the game routine, we INIT the AI vars (in ram), we do this by copying from the template (Maybe ROM)

We set the 'songtimer' - this is for the CPC interrupt handler, it's not actually needed on other systems.

We start the first song for the title screen.
We need to draw the 'ChibiFighter' logo onto the tilemap (TileCache)

The tilemap for the logo is up to 32x13... but we've used some crude compression.

Many of the tiles are 0 (black) - so lets 'compress them'

The tilemap only uses <128 tiles, so the top bit of the tilenumber is free.

If a line has a large string of zero tiles we'll store it a a 1 byte 'skip X tiles' where the top bit is 1... %1nnnnnnn where n is the tiles to skip.

if the line has ended we will end with a %11111111 (255) byte and skip to the next line.

This is very simple 'compression' but greatly reduces the tilemap size.
Here is the tilemap data
After the graphic we show the 'Hyper futile' text, and wait for fire.

New Game

'NewBattle' is executed at the start of each new opponent battle.

The first game we reset the OpponentNum to 0

We reset the sprites from the template.
The ResetRound function clears all the level and player vars back to their defaults.
The next sequence is rather long and annoying!

Really it just loads up the sprite data for the player and cpu characters, positions their sprites and shows the VS message.

GetPlayerSettings loads in the defaults for a character into sprite IX

GetSubSettings loads in the defaults for the 'sub sprite' (Fireball atack)

AnimateSprite updates the sprite animation, and sets the size and pattern settings from the default sprite number

RepaintScreen draws the background tilemap (and text)

DrawPlayers draws the sprite characters



On The SMS it also loads in the 128 tiles for the player / Character into pattern data (overwriting the title screen patterns)



The Getplayer settings functions load in the various parameters of the player / enemy

The enemy sprite also defines the background and level music.
Here are the contents of part of the playerdefs table.

New Round

Battle commences until someone wins two rounds.
This means there can be up to 3 rounds (if there are no draws).

Before each round we show a "Round 1" "Fight" type message.


First we need to initialize the background and reposition the player sprite.

Then we show the text.

We pause before text messages.



After this message, we're ready to start gameplay!

Lesson CF3 - MainLoop and Round End
Lets take a look at the main game loop, and the code that handles the end of a round

See ChibiFighter folder

Main Loop

The first task is to update the 'ticks' - this is used to control timed animation events.

Next we read in keypresses from the joystick.
We want to update our two players. We use two routines.

UpdateFighter handles the input. AnimateSprite updates the graphics bases on scripted sequences - we'll see details of these later.

We use the same routines for the human and CPU, but the ReadAI routine is used to control the CPU - it returns a virtual 'joystick keypress' by the computer, so we can easily switch to Human VS Human, or even CPU vs CPU!
Next we check if the round time limit has been reached.
If it hasn't we update the time.

The counter shows 60 ticks, but there is a second hidden timer RoundTime2, which counts the time until the point to reduce the visible ticks.
Next we repaint the tilemap with RepaintScreen, and draw the sprites with DrawPlayers
Next we handle the collision detection.
As well as the main sprites, we have 2 sub sprites for the fireball attack.

We check if there has been a collision between a player's punches/kicks and fireballs.

Collision detection

First we check the opponents life.

If the opponents life has reached zero, the player has won.
Next we check the life of the object - a fireball which is offscreen will have a life of zero.
We also check if the attack is <0 a negative value is a block... an attack of zero is no attack (just standing around!)

Next we check the distance of the attacker from the opponent - if the attacker is too far away, the attack missed.

We also check if the opponent is blocking (attack <0 - bit 7 nonzero) - if so the attack missed.

In these cases the attack missed, so we clear the attack to 0


The attack has HIT!... so we give the attacker a point. and redraw the scores.
We move the amount of 'attack' of the attacker to the 'hurt' of the opponent - this will drain the injured parties life over the next few ticks.

Round End

If the time runs out we work out which player has the most life left and run PlayerWins with IX pointing to the winner.

If both players have the same lif, it's a draw!
The winner has been decided - we add 1 to their wins, and show their name to the screen.
We now check how many wins each player has

If the CPU has 2 wins the game is over.
If the HUMAN has 2 wins, it's time for the next challenger.

Otherwise it's just another round.
If the human has lost we show a simple gameover screen.

Lesson CF4 - Drawing routines
While the graphics are handled by 'Mintile' (My tilemap code), we have to do some setup to get it working with our code.

See ChibiFighter folder

DrawPlayers

Mintile uses the same code for the tilemap as the sprites.

We need to use selfmodifying code to change the way the tilemap works to switch it to sprite mode!

On some systems we are running from ROM, so instead of selfmodifying, we use 'TileClear'

The ChibiFighter Graphics are 4 color bitmaps, even on 16 color systems, we use a 'Tint', effectively selecting one of 4x four color palettes
We run the DrawSprite routines to show the CPU and Human players
Next we draw the fireballs to the screen, but only if the objects are 'alive'

Font code

Character drawing also goes through 'MinTile'

The 'Mintile routine uses a 32x24 tilecache - which keeps track of updates which are needed to the the onscreen tilemap.

A 'Zero' in the cache means 'skip the tile'... any other value is a tile change.

Once the tile is written to the screen, it's reset to zero in the cache.

Screen Drawing

Repaint screen is a general update of the screen.

This sets up the MinTile code to draw the tilemap (zeroing the cache after drawing)

the 'CLS' routine will transfer the cache to the screen.
Blackout screen wipes the screen to the empty tile (1)

This clears both the cache, and the background tilemap, it's used for Gameover and the title screen.
DrawScreen is a general refresh of the background objects.

First we redraw the Life bar area at the top of the screen.

Then we transfer the entire background tilemap into the cache - this forces MinTile to do a complete redraw.
We've only drawn the empty bar so far, we need to draw the filled life bars and player names.

We do this for the human and CPU player
We draw the other text objects, Time and players score.
The Draw time prints 1 BCD byte to the screen (0-60)

PrintPlayerName will show the character name, and also shows the 'wins'

The round ends with 2 wins, so we only show 0 or 1 icon.
The life bars move towards the center of the screen
They are made up of 3 parts.

A filled part, based on the top 4 bits of the life
A half filled part, based on bit 3 of the life, which may or may not be drawn.
A blank part, which is the remainder of the bar.

Lesson CF5 - Scripted Animators!
The ChibiFighter Animation engine handles sequences of moves and actions by objects in the game.
It's a reworked and optimized version of the one from ChibiAkumas Ep2... Lets check it out!

See ChibiFighter folder

The Animators list

Our animator routine supports up to 15 animation types 1-15.
Each has a pointer to the script in a lookup table.

Animator 0 is 'no animator' - a static sprite!
The first byte of an animator is the 'speed' of the animation (0=fastest 1=every other frame 3=every 1/4th frame etc)

There can be up to 16 lines in the script
each line takes 4 bytes. The first byte is the animation command, the 3 other bytes are parameters relating to that command
We define symbols for the possible animation commands,

There is a lookup table for the code which performs the animation action.

Animation handling

Our ObjectAnimator routine is executed with IX pointing to the sprite to be animated, and A containing the animator byte.

The animator byte is in the format:
TTTTAAAA ... T=Tick / A=Animator
meaning a maximum of 16 animators, and 16 lines per animator script (ticks)
GetAnimatorMempos backs the animator byte up into B, and loads the pointer to the current animation script into HL
The top nibble of the animator byte is the current tick - the line of the script we need to run,

We effectively multiply this nibble by 4, and add this offset to the current animator script pos.

We get the command number - the first of the 4 bytes of the line of the script, and execute it via the 'VectorJump' subroutine.

This uses ex (sp),hl to effectively jump to HL, while preserving the old value of HL which was pushed onto the stack.
VectorLookup will read a 16 bit word from the table of addresses HL

A is used as the entry number, and the result is returned in HL

Animation Commands

At the end of each script we need to update the current tick (line number) of the script.


The Sprite option changes the current graphic.

The first parameter is the sprite number.
The second byte is a flag to force a repaint of the tilemap - Mintile has trouble with half tile moves of complex shaped sprites and this can help reduce glitches
The Third parameter is the direction of the sprite - 0 leaves it unchanged, 1 faces Right (0 in the flags) 2 faces Left (1 in the flags)
Move will make an immediate relative 8 bit move to the sprite's X,Y,Z pos

X is for moving left and right, Y is for jumping, Z is for moving 'In and Out' of the screen (like TMNT or Renegade)

If the player is facing left DoXFlip_IX will reverse the X move.
Attack will set the attack, and optionally a sprite.

This is used for punching or blocking. The sprite for the 'punch' will be set and a >0 attack will be set... or <0 for a block!
Loop is used for the walking animation, which will continue until we stop moving.
Spawn is used to spawn the sub object (fireball)

The pointer to the sub object is loaded in from the SubSprite pointer, and the new object is initialized from the settings array passed in the parameter.


The animator code supports complex condition based loops, and executions to subroutines, but they were not needed for this game.

The unused action types can also be re-written to do anything you want!

Lesson CF6 - Fighter Movement Processing
The Animation code performs scripted actions, but actions relating to the player or cpu's decided action are handled by 'UpdateFighter' - let's check that out!

See ChibiFighter folder

UpdateFighter - Actions!

At the start of the routine we check if the player is 'hurt'

If the player is injured, they are on the floor, and they cannot move of their own volition.

We check the Animator is set to 6 (the injury animator)
The D register contains the bits of the joystick in the format %4321RLDU

We can jump with Fire 2, but We may not have a fire 2!
Fire 2 is a 'synonym' for Down+Fire1 which will also jump!
We don't want the player to be able to punch or block forever, so we have a 'timeout' between Fires!

It will only decrease once Fire is released, and stops the player punching again too quickly
We buffer 8 recent keypresses for special moves.

Next we check if fire is pressed,

If it is we check the timeout. The player isn't allowed to hold down fire, the timeout stops this, and clears the keypress if the player hit fire recently
We have a special move... Fireball!

The sequence to perform a fireball is Down, Down-Right, Right+Fire
(or the reverse if facing left)
CmpSeq will compare recent keypressses to DE

We handle the direction the player is facing via DoXJoyFlip_IX which will handle the flipping of Left/Right if pressed


Next we check if the player has tried to jump - this only works if the player is on the ground (Ypos=152)

If the player can jump we set Spr_Ymove - this will decrease the Ypos over time until Spr_Ymove=0
We check the down direction...

If down+Fire are pressed we block
Fire on it's own will punch

Fire+ Left or Right will kick
If an action was decided we set it now!


UpdateFighter - Movements!

If no directions we pressed, we reduce the timeout on the buffer (used for special moves)

We clear the buffer when the timeout hits zero.
If the player is moving left/right AND is on the ground AND it's not already set, we need to set the animator to 1

If the player has stopped moving and was walking we set the animator to 0
Next we check up and down keys.

These move in and out of the screen
We check Left and right, and set bit 0 of the flags accordingly

Flags=1 will flip the sprite - making it face left.
Next we check the players position

The player can be 'pushed' offscreen by an attack, but will slide back in over the next few frames.

We the run the AnimateSprite routine which will handle other movements.


Lesson CF7 - Animate Sprite
The AnimateSprite routine handles automatic movements outside of player control.

See ChibiFighter folder


AnimateSprite

Before we do anything we check the objects life,
An object with a life of zero does not need updating!
W next load in the pointer to the animation script command list.

If the sprites animator isn't zero, we run the Animator script routines, and update the current animator number.
We need to update the position! We need to factor in three things!

Firstly the 16 bit XposW,YposW and ZposW are the center point, so we need to subtract half the width hand height for the final drawing positions Spr_Xpos and Spr_Ypos

Second we need to update the draw Ypos position based on the 'depth' Zpos

Third we need to back up the old width and height - as the new sprite graphic may change them!
Before we draw it The sprite number may have changed, so we load in the info for the current image from the SpriteInfo table.
We now process the sprite moves, If the sprite is attempting to jump we move it up the screen.

If not, and the sprite is above the ground (Ypos<152) we move it closer to the ground.
We now process any moves being applied to the X position
Finally we run the 'remove and zero' routines.

The 'remove sprite routine takes the sprite off the screen - redrawing the tilemap underneath.

the 'Zero' routine attempts to reduce flicker, by stopping the redraw of parts which will be filled by the new sprite - unfortunately it's not 100% accurate when sprites move a 1/2 tile!

Maths!

The Random Number Generator used by ChibiFighter is a fairly crude which uses a 16 bit seed.
Collision detection for Punches and Kicks uses the position of two objects

We're going to check if object IX is in range of IY, Where  IX is the attacker, and IY is the victim!

The range is fixed &0C10 - 12x16 units.
The range checking routine is the one we've used before.


Lesson CF8 - CPU AI
The AI routine makes a decision on the computers actions. These are passed to the main routine as a simulated 'Keypress'

Lets take a peek!

See ChibiFighter folder

AI Routines

The possible move sequences for the CPU are stored in a table 'Strategy List'.

Each move sequence is 8 bytes. The first byte is a delay between each direction. the rest of the bytes are Keypresses (when bit 7=1) or a 'sequence change' for chaining sequences (when bit 7=0)

Strategy list format:
Speed,Keypress,Keypress,Keypress
    Keypress %1XXXXXXX = Keypress match (%--21RLDU)
    Strategy %0XXXXXXX = Jump to new strategy
ReadAI will return a keypress in the Accumulator.

If the Timeout for the last keypress has not reached zero,we just return the same value.
We load in the current strategy.

Zero means the CPU is still thinking what to do
Each Strategy uses 8 bytes, we calculate the offset to the current strategy and load in the Delay time.

We then shift to the current 'tick' - ant therefore the new keypress.

In theory we can chain strategies by setting the top bit of the strategy byte to 0, but actually this was never used in the final game.
Deciding a new strategy
We combine D and E to decide our final strategy, 

We use random data to make the cpu unpredictable, we store this in B

We compare the player (IY) and CPU (IX) position to decide what to do.
We compare the two characters, and see if they are at the same Z position on the ground.

If they are not, we move the CPU closer to the player
If the Z position is the same We consider if the CPU should jump, there is effectively a 1/4 chance the CPU will decide to jump.
We now decide if the CPU needs to move Left or Right to get closer to the player.
If the Player is far away, we may decide to throw a fireball, otherwise we'll punch or kick!

Which we do is random!... The direction of the punch or kick is based on the D register
There is a very small chance of a fireball attack, just 1 in 16.
At the end we set the new AI Strategy
When the CPU is thinking, the CPU will block for a while and think.

We slow down the CPU to make it dumber to give the human more chance to retaliate.


Lesson CF9 - Amstrad CPC code
The Tile drawing and sound routines are platform specific.

Lets take a look at the CPC version.

See ChibiFighter folder

Sound Routines

Music and SFX are performed by ChibiTracks.

In addition to the song Chibitracks needs various includes to work.
We install a jump to the IM2 interrupt handler at address &0038
Our music is designed to play back at 50hz, but there are 6 interrupts per screen redraw on the CPC,

We use a 'SongTimer', and only update the sound every 1 in 6 interrupts.
Before our music can play, we must set the song base and call StartSong
We can effect SFX by forcibly playing instruments on one of the channels.

This uses the function 'InstPlaySFX' which executes 'CommonSFXModule'

CommonSFXModule, if defined is also used by ChibiTracker for the same purpose.

Tile Drawing Routines

The MinTile shared routine provides calculation and tilemap planning, however we need to do the actual job of 'Drawing' in the platform code.

The code can horizontally flip tiles, on the Amstrad CPC we use a 256 byte lookup table, to 'pre-calculate the flipping of the 4 pixels in a Mode 1 byte
The LUT needs to be byte aligned, so &8100 or &FE00 would be fine, but &FE01 would not!
We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.
DoStrip will draw one horizontal strip of tiles.

The job is defined by the following registers

HL = VRAM Dest
BC' = Tilemap
DE' = Pattern data
IYL = TileMap Width

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)

If using the tile cache we zero the tiles after they are drawn

we use stack misuse to speed up loading the pattern data
DoStripRev has essentially the same function, however it horizontally flips the pattern data via the lookup table.


The rest of the Tilemap code is a multiplatform module called 'MinTile'

We'll look at that soon in a separate series!


Lesson CF10 - Sam Coupe code
The Tile drawing and sound routines are platform specific.

Lets take a look at the SAM version.

See ChibiFighter folder

Sound Routines

Music and SFX are performed by ChibiTracks.

In addition to the song Chibitracks needs various includes to work.
We're going to use IM1 for interrupts, which means we need RAM at memory address &0038.

We load our program in at memory address &8000, but we page the bank into the &0000-7FFF rage, and use the &8000+ range for Vram
We install a jump to the IM2 interrupt handler at address &0038
The ChibiTracks update runs in the interrupt handler, it uses  AF,BC,DE,HL and IX only
Before our music can play, we must set the song base and call StartSong
We can effect SFX by forcibly playing instruments on one of the channels.

This uses the function 'InstPlaySFX' which executes 'CommonSFXModule'

CommonSFXModule, if defined is also used by ChibiTracker for the same purpose.

Tile Drawing Routines

The MinTile shared routine provides calculation and tilemap planning, however we need to do the actual job of 'Drawing' in the platform code.

We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.
DoStrip will draw one horizontal strip of tiles.

The job is defined by the following registers

HL = VRAM Dest
BC' = Tilemap
DE' = Pattern data
IYL = TileMap Width

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)

If using the tile cache we zero the tiles after they are drawn




We use 4 color pattern data, and convert it up to 16 color.

Each byte of the pattern data contains color info for 4 pixels (2bpp = 4 color). A 'Tint' is used to select one of 4x four color palettes.

We load the bits into C, and shift them into 2 screen bytes (4 pixels).
If the source byte is zero, we just write directly, to save a little bit shifting time!


We have to do this twice for each 8 pixel (2 byte) wide tile.


DoStripRev has essentially the same function, however the bitshifts are reversed to swap the pairs of pixels



The rest of the Tilemap code is a multiplatform module called 'MinTile'

We'll look at that soon in a separate series!


Lesson CF11 - SMS code
The Tile drawing and sound routines are platform specific.

Lets take a look at the SMS version.

See ChibiFighter folder

Sound Routines

Music and SFX are performed by ChibiTracks.

In addition to the song Chibitracks needs various includes to work.
We're going to use IM1 for interrupts, we need to put a Jump at memory address &0038 in the header
We need to set bit 5 of VDP Register 1 to enable the Vblank interrupt
The ChibiTracks update runs in the interrupt handler, it uses  AF,BC,DE,HL and IX only

On the SMS we need to read in the VDP control port &BF to clear the interrupt - we don't actually need to do anything with the read data!
Before our music can play, we must set the song base and call StartSong
We can effect SFX by forcibly playing instruments on one of the channels.

This uses the function 'InstPlaySFX' which executes 'CommonSFXModule'

CommonSFXModule, if defined is also used by ChibiTracker for the same purpose.

Tile Drawing Routines

The MinTile shared routine provides calculation and tilemap planning, however we need to do the actual job of 'Drawing' in the platform code.

Our Tilemap data is actually 4 color - 2 bitplanes.

We 'Tint' the 4 color data, by using IX as a constant value for the tip 2 bitplanes - effectively giving us 4 palettes of 4 colors.
We define the 4x 4 color palettes, two for our background, and two for our players
The tile loading routines define IX with the top two bitplane values to select the 'palette'
We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.
DoStrip will draw one horizontal strip of tiles.

The job is defined by the following registers

HL = VRAM Dest
BC' = Tilemap
DE' = Pattern data
IYL = TileMap Width

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)

If using the tile cache we zero the tiles after they are drawn



We transfer the tile numbers into the tilemap - each uses the 2 byte tile number (with attributes)
DoStripRev has essentially the same function, however the X-flip bit is set in the attributes

The rest of the Tilemap code is a multiplatform module called 'MinTile'

We'll look at that soon in a separate series!


Lesson CF12 - Spectrum Next code
The Tile drawing and sound routines are platform specific.

Lets take a look at the ZXN version.

See ChibiFighter folder

Sound Routines

Music and SFX are performed by ChibiTracks.

In addition to the song Chibitracks needs various includes to work.
We're going to use IM1 for interrupts,

We need to put a Jump at memory address &0038, but on the spectrum this is ROM.

We can page in RAM at the &0000-1FFF range with NextReg &50
The ChibiTracks update runs in the interrupt handler, it uses  AF,BC,DE,HL and IX only
Before our music can play, we must set the song base and call StartSong
We can effect SFX by forcibly playing instruments on one of the channels.

This uses the function 'InstPlaySFX' which executes 'CommonSFXModule'

CommonSFXModule, if defined is also used by ChibiTracker for the same purpose.

Tile Drawing Routines

The MinTile shared routine provides calculation and tilemap planning, however we need to do the actual job of 'Drawing' in the platform code.

We use a 1 byte per color palette

We select the palette with reg &40, and send the values with &41
Although the screen is 256 color, We use a total of 16 colors

We define the 4x 4 color palettes, two for our background, and two for our players
We use a 'TileTint' to select one of the 4 palettes
We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.

We page in the screen VRAM into the &2000-3FFF range.


DoStrip will draw one horizontal strip of tiles.

The job is defined by the following registers

HL = VRAM Dest
BC' = Tilemap
DE' = Pattern data
IYL = TileMap Width

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)

If using the tile cache we zero the tiles after they are drawn

The source bitmap data is 4 color, so we multiply the tile number by 16 to get the pattern data address

We read in a byte from the DE source.

We take 2 bits from this, shift them in position and OR in the tint from B

We do this 4 times (4 pixels) before reading in a second byte.

After 2 bytes we've done a full line.
We repeat for 8 lines, then move across one tile and repeat for the rest of the strup
DoStripRev has essentially the same function, however we draw the pixels from right to left, reversing the pattern bitmap


The rest of the Tilemap code is a multiplatform module called 'MinTile'

We'll look at that soon in a separate series!

Lesson CF13 - MSX2 code
The Tile drawing and sound routines are platform specific.

Lets take a look at the MSX2 version.

See ChibiFighter folder

Sound Routines

Music and SFX are performed by ChibiTracks.

In addition to the song Chibitracks needs various includes to work.
We're going to use IM1 for interrupts,

By default on the MSX2, the low area is ROM, so &0038 is redirected to the firmware interrupt handler, however we can redirect this by patching a jump to our own interrupt hander at address &FD9A
We also need to set bit 5 of Mode Register 1 to enable the VBlank interrupt
The ChibiTracks update runs in the interrupt handler, it uses  AF,BC,DE,HL and IX only

When we return we pass control back to the firmware interrupt handler, so we do not enable interrupts before returning
Before our music can play, we must set the song base and call StartSong
We can effect SFX by forcibly playing instruments on one of the channels.

This uses the function 'InstPlaySFX' which executes 'CommonSFXModule'

CommonSFXModule, if defined is also used by ChibiTracker for the same purpose.

Tile Drawing Routines

The MinTile shared routine provides calculation and tilemap planning, however we need to do the actual job of 'Drawing' in the platform code.

We need to transfer our tile patterns to the hidden area of VRAM (Lines 256+)

For sprites we need to store a normal copy, and an Xflipped copy.
We're running in 16 color mode, but our source patterns are only 4 color

We define the 4x 4 color palettes, two for our background, and two for our players
We send our tile patterns to Vram, applying a 'Tint' to select one of the 4 colors

There are two versions 'SendTiles' for background graphics, and 'SendTilesDuo' which sends a regular tile and Xflips the tile.
We transfer the 16 bytes of the source pattern. we use a HMMC command to send the data.

Each pattern byte contains 4 pixels. We have formatted the source data to allow it to easily be converted.

We mask the first two pixels and OR in our tint, sending them to the VDP.

We then load the data again, bit shift it 2 pixels, and mask the second two pixels.
SendTilesDUO will define the pattern, once normally, and once x-flipped 128 Y-lines down

Each line of our tile pattern is 2 bytes, we move to the right of the tile, and rotate the bytes of the source data to Xflip them
DoStrip will draw one horizontal strip of tiles.

The job is defined by the following registers

HL = X,Y pos in VRAM
BC' = Tilemap
DE' = Pattern data
IYL = TileMap Width

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)

If using the tile cache we zero the tiles after they are drawn

We calculate the source pos in VRAM for the tile we want to transfer and use HMMM to write the tile to the screen.
We repeat for 8 lines, then move across one tile and repeat for the rest of the strup
DoStripRev has essentially the same function, however we use the flipped version of the tiles


The rest of the Tilemap code is a multiplatform module called 'MinTile'

We'll look at that soon in a separate series!




 

View Options
Default Dark
Simple (Hide this menu)
Print Mode (white background)

Top Menu
***Main Menu***
Youtube channel
Patreon
Introduction to Assembly (Basics for absolute beginners)
Email Newsletter
Amazon Affiliate Link
Forum
AkuSprite Editor
Dec/Bin/Hex/Oct/Ascii Table

Alt Tech
Archive.org
Bitchute
Odysee
Rumble
DailyMotion
Please note: I wlll upload more content to these alt platforms based on the views they bring in

Z80 Content
***Z80 Tutorial List***
Learn Z80 Assembly (2021)
Learn Z80 Assembly (old)
Hello World
Advanced Series
Multiplatform Series
Platform Specific Series
ChibiAkumas Series
Grime Z80
Z80 Downloads
Z80 Cheatsheet
Sources.7z
DevTools kit
Z80 Platforms
Amstrad CPC
Elan Enterprise
Gameboy & Gameboy Color
Master System & GameGear
MSX & MSX2
Sam Coupe
TI-83
ZX Spectrum
Spectrum NEXT
Camputers Lynx

6502 Content
***6502 Tutorial List***
Learn 6502 Assembly
Advanced Series
Platform Specific Series
Hello World Series
Grime 6502
6502 Downloads
6502 Cheatsheet
Sources.7z
DevTools kit
6502 Platforms
Apple IIe
Atari 800 and 5200
Atari Lynx
BBC Micro
Commodore 64
Commodore PET
Commander x16
Super Nintendo (SNES)
Nintendo NES / Famicom
PC Engine (Turbografx-16)
Vic 20

68000 Content
***68000 Tutorial List***
Learn 68000 Assembly
Hello World Series
Platform Specific Series
Grime 68000
68000 Downloads
68000 Cheatsheet
Sources.7z
DevTools kit
68000 Platforms
Amiga 500
Atari ST
Neo Geo
Sega Genesis / Mega Drive
Sinclair QL
X68000 (Sharp x68k)

8086 Content
Learn 8086 Assembly
Platform Specific Series
Hello World Series
8086 Downloads
8086 Cheatsheet
Sources.7z
DevTools kit
8086 Platforms
Wonderswan
MsDos

ARM Content
Learn ARM Assembly
Learn ARM Thumb Assembly
Platform Specific Series
ARM Downloads
ARM Cheatsheet
Sources.7z
DevTools kit
ARM Platforms
Gameboy Advance
Nintendo DS
Risc Os

Risc-V Content
Learn Risc-V Assembly
Risc-V Downloads
Risc-V Cheatsheet
Sources.7z
DevTools kit

MIPS Content
Learn Risc-V Assembly
MIPS Downloads
MIPS Cheatsheet
Sources.7z
DevTools kit
N64 Platforms
Playstation
N64

PDP-11 Content
Learn PDP-11 Assembly
PDP-11 Downloads
PDP-11 Cheatsheet
Sources.7z
DevTools kit

TMS9900 Content
Learn TMS9900 Assembly
TMS9900 Downloads
TMS9900 Cheatsheet
Sources.7z
DevTools kit
TMS9900 Platforms
Ti 99

6809 Content
Learn 6809 Assembly
Learn 6309 Assembly
6809 Downloads
6809/6309 Cheatsheet
Sources.7z
DevTools kit
6809 Platforms
Dragon 32/Tandy Coco
Fujitsu FM7
TRS-80 Coco 3
Vectrex

65816 Content
Learn 65816 Assembly
65816 Downloads
65816 Cheatsheet
Sources.7z
DevTools kit
65816 Platforms
SNES

eZ80 Content
Learn eZ80 Assembly
eZ80 Downloads
eZ80 Cheatsheet
Sources.7z
DevTools kit
eZ80 Platforms
Ti84 PCE

IBM370 Content
Learn IBM370 Assembly
IBM370 Downloads
IBM370 Cheatsheet
Sources.7z
DevTools kit

Super-H Content
Learn SH2 Assembly
SH2 Downloads
SH2 Cheatsheet
Sources.7z
DevTools kit
SH2 Platforms
32x
Saturn

PowerPC Content
Learn PowerPC Assembly
PowerPC Downloads
PowerPC Cheatsheet
Sources.7z
DevTools kit
PowerPC Platforms
Gamecube

Work in Progress
ChibiAndroids

Misc bits
Ruby programming









Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!



































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!


























































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!