Saturday, July 4, 2020

Python Setup Cheat Sheet

New post on Python Setup Cheat Sheet coming soon...

Tuesday, June 30, 2020

Candy Kid Code Complete

Candy Kid is a simple maze chase video game originally programmed by Grandstand Leisure from New Zealand in September 1984. The game was written in BASIC programming language on Sega SC-3000.

In 2015, Candy Kid was re-written in C#/.NET and XNA for Windows PC and ported to iOS / Android using MonoGame. After finding the original source code on SMS Power!, Candy Kid was re-written again in 8-bit.

Inspired from previous posts on Sega Console Programming and devkitSMS Programming Setup + Sample, Candy Kid is my fifth 8-bit video game written in C / Z80 assembler to target Sega Master System (SMS).

Let's check it out!

Note: previous titles published for the Master System include 3D City, Simpsons Trivia + Platform Explorer.
Download source code here.

Sega Retro Gaming post documents how to play video games like Candy Kid SMS using the Fusion emulator.
devkitSMS Programming Setup post documents development environment required to build C / Z80 source.
Instructions
Eat all the candy to pass each level. Eat all bonuses to maximize your score! The 3x Candy "Mama" enemies Pro / Adi / Suz have different passive and aggressive personalities and alternate between scatter and attack.

Tools
Here are a list of Tools and frameworks that were used in the development of this project:
 KEY  VALUE
 Programming  devkitSMS
 Compiler  sdcc 3.6
 Assembler  WLA-DX
 IDE  Visual Studio 2015
 Languages  C / Z80
 Graphics  BMP2Tile 0.43 / GIMP 2 / paint.net
 Music  Mod2PSG2 / vgm2psg
 Emulators  Emulicious / Fusion / Meka

ROM Hacking
You can hack this ROM! Download + dump CandyKid into Hex Editor, e.g. HxD, and modify bytes:
 ADDRESS  VARIABLE  DESCRIPTION
 0x004F  Debugger  Used to show debugging info for game.
 0x0050  Invincible  Non-zero value enables invincibility.
 0x0051  FullBoost  Non-zero value enables maximum boost.
 0x0052  Trees Type  Set value to 1=Show otherwise 2=Kill.
 0x0053  Exits Type  Set value to 1=Open otherwise 2=Shut.
 0x0054  Difficulty  Set value to 1=Easy otherwise 2=Hard.
 0x0055  Game Speed  Set value to 1=Slow otherwise 2=Fast.
 0x0056  World No.  Set start World no currently 1 to 10.
 0x0057  Round No.  Set start Round no currently 1 to 10.
 0x0058  Music Off  Set 0=Music to play otherwise silent.
 0x0059  Sound Off  Set 0=Sound to play otherwise silent.

Bonuses
  • There are 4x different bonuses: 100 / 200 / 400 / 800 pts. Double bonus points after level 70.
  • Player will receive extra 2,000 pts after eating all the candy and collecting all bonuses in level.

Cheats
  • Press button 2 five times during Title screen and you'll be invincible each game this is actioned.
  • Press and hold button 2 during game play to action Game Over and force quit out of the game.
  • Press and hold button 2 on Splash screen to reset High score and all options previously saved.

Credits
Extra special thanks goes to sverx for the devkitSMS. Plus StevePro Studios would like to thank eruiz00 and haroldoop for sharing source code from SMS Homebrew projects. Many ideas here were used in this project!

Promotion
Thanks to SMS Power! for making this video. Here is the official Candy Kid Facebook page and Blogger label.

Summary
To summarize, Candy Kid has had a very interesting journey after first appearing on the Sega SC-3000 in 1984 to being ported to Windows PC, iOS + Android in 2015 and finally the Sega Master System in 2020.

In fact, after porting the original game in 2015 the ultimate goal was always to eventually back port Candy Kid to the Master System. Thanks to the awesome Indie game dev scene this goal has now been achieved!

Sunday, May 31, 2020

devkitSMS Programming Sample IV

In 2017, we checked out devkitsms to setup productive development environment to build 8-bit retro video games for the Sega Master System (SMS). In 2019, we improved build process to develop Platform Explorer.

Though after five years of SMS development we would like to connect more the C language with underlying Z80 assembly code. Look for opportunities to consolidate 8-bit retro game development to build Candy Kid!
Let's check it out!

Game
Candy Kid video game was originally programmed by Grandstand Leisure from New Zealand in September 1984. The game written in BASIC on the Sega SC-3000. Thanks to the awesome SMS Power! community Candy Kid is available on Sega Master System in 2020 Coding Competition. Download source code here.

Software
Follow all instructions from the previous post: this documents how to setup the pre-requisite software.
Note: ensure you have downloaded and installed the devkitSMS and Small Device C Compiler [SDCC].

Checklist
Here is a checklist of tasks to complete in order to try and improve the existing development environment:
  • Connect more the C language and Z80 assembly code via emulation
  • Implement various code architectural updates from the devkitSMS
  • Apply techniques to resolve vulnerabilities debugging source code
  • Explore strategies to confront the 32KB ROM game code capacity

Emulation
In 2013, we checked out Sega Console Programming with goal to build retro game in Z80 assembler for the Sega Master System. However, the process to write Z80 assembly language from scratch seemed daunting.

In 2019, since collaborating with Calindro, we now have the opportunity to understand relationship between C source code and the generated Z80 assembly: Emulicious will decorate Z80 code in the debugger with its corresponding C function!

Launch Emulicious. Tools menu | ensure "Reopen Tools" option is checked. Launch the debugger. File menu | ensure "Load Sources automatically" is checked + Run menu | ensure "Suspend On Open" is checked. Close
Ensure the output.map file is not deleted in build script. E.g. both output.sms and output.map are built and loaded into Emulicious. The output.map maps C source code functions to the underlying Z80 assembly code.

Example
Search for main function. Ctrl + F | Find "_main" Ctrl+click "main" to navigate there. Ctrl+click any function name to navigate + inspect Z80 assembly code built for that function. Click Alt+Left to navigate back. Nice!

Coding
The following coding changes and enhancements have been made throughout Candy Kid development cycle:

Collision
Leverage the built-in SMS_VDPFlags for fast sprite collision detection. If value equals 0x20 then at least two sprites have collided then implement slow(er) collision detection by checking if sprite rectangle(s) intersect:

play_screen.c
gamer_collision = devkit_isCollisionDetected();
if ( 0 != gamer_collision )             // Fast.
{                                       // Slow.
    for( enemy = 0; enemy < MAX_ENEMIES; enemy++ )
    {
        eo = &global_enemy_objects[ enemy ];
        if( go->posnX > eo->posnX )     { dx = go->posnX - eo->posnX; }
        else                            { dx = eo->posnX - go->posnX; }

        if( go->posnY > eo->posnY )     { dy = go->posnY - eo->posnY; }
        else                            { dy = eo->posnY - go->posnY; }

        if( dx <= distance && dy <= distance ) { gamer_collision = enemy; break; }
    }
}

Levels
In 2018, Duckslayer Adventures by haroldoop gave a great example of how levels could be stored externally in text files then converted into byte arrays using folder2c. The byte arrays are then interpreted for drawing:
 KEY  VALUE
 0  Blank
 1  Trees
 2  Candy
 3  BonusA
 4  BonusB
 5  BonusC
 6  BonusD
  // Level0101
  3000000004
  0002222000
  0000000000
  0211111120
  0210110120
  0210110120
  0211111120
  0000000000
  0002222000
  5000000006

SRAM
Persisting important data like Hi Scores and player settings across game sessions makes for better gaming experience. Here is the Candy Kid implementation with SRAM support currently included in the devkitSMS:

storage_manager.c
#define MAGIC   0xACE0B004
#define FINAL   0xFF

// Global variable.
struct_storage_object global_savegame_object;

unsigned char engine_storage_manager_available()
{
    struct_storage_object *savegame = ( struct_storage_object* ) ( devkit_SMS_SRAM() );
    unsigned char foundMagic;

    devkit_SMS_enableSRAM();
    foundMagic = MAGIC == savegame->Magic;
    devkit_SMS_disableSRAM();
    return foundMagic;
}
void engine_storage_manager_read()
{
    struct_storage_object *savegame = ( struct_storage_object* ) ( devkit_SMS_SRAM() );
    struct_state_object *st = &global_state_object;

    devkit_SMS_enableSRAM();
    st->state_object_high_score = savegame->save_high_score;
//  ...
    devkit_SMS_disableSRAM();
}
void engine_storage_manager_write()
{
    struct_storage_object *savegame = ( struct_storage_object* ) ( devkit_SMS_SRAM() );
    struct_state_object *st = &global_state_object;

    devkit_SMS_enableSRAM();
    savegame->Magic = MAGIC;
    savegame->save_high_score = st->state_object_high_score;
//  ...
    savegame->terminal = FINAL;
    devkit_SMS_disableSRAM();
}
void engine_storage_manager_erase()
{
    struct_storage_object *savegame = ( struct_storage_object* ) ( devkit_SMS_SRAM() );

    devkit_SMS_enableSRAM();
    savegame->Magic = 0x00000000;
    savegame->save_high_score = DEF_HI_SCORE;
//  ...
    savegame->terminal = FINAL;
    devkit_SMS_disableSRAM();
}

Debugging
Buffer overflow [or overrun] is an anomaly where writing data to buffer overruns the buffer's boundary and overwrites adjacent memory. In Candy Kid, the player can be killed by any one of the three Mama enemies; Actors 0-2. But Kid can also be killed by death tree ie "actor" 4. When Kid is killed we initially reset the "kill" enemy unconditionally. Thus if killed by death tree enemy "4" would be reset hence a buffer overrun occurs! Big thanks to Calindro + sverx for helping debug this issue. The solution is to check enemy kill before reset.


Capacity
The following challenges were encountered with 32KB ROM game code capacity during development cycle:

Input
The previous input manager had clean interface that's "Easy to use correctly" and "Hard to use incorrectly" But this suffered from code bloat + additional costly bytes. Therefore, inject key test for simpler interface:

input_manager.c
#include "input_manager.h"
#include "..\devkit\_sms_manager.h"

static unsigned int curr_joypad1 = 0;
static unsigned int prev_joypad1 = 0;

// Public methods.
void engine_input_manager_update()
{
    prev_joypad1 = curr_joypad1;
    curr_joypad1 = devkit_SMS_getKeysStatus();
}
unsigned char engine_input_manager_hold( unsigned char data )
{
    return curr_joypad1 & data && !( prev_joypad1 & data );
}
unsigned char engine_input_manager_move( unsigned char data )
{
    return curr_joypad1 & data;
}

Banks
In 2017, Astro Force by eruiz00 gave great example on how to store static data in fixedbank.c to scale out more game content and bank switch on-the-fly without consuming the precious 32KB ROM for game code.

Candy Kid attempts to replicate this strategy, unfortunately still hitting 32KB capacity for game code. Next step could be store function pointer arrays in fixedbank.c like Astro Force to conserve more precious bytes!

fixedbank.c
const unsigned char bossX_object_speed[] = { 1, 1, 2, 1, 1, 1, 3, 3, 1, 1, 1, 1 };
const unsigned char bossX_object_delay[] = { 2, 2, 3, 1, 1, 1, 2, 2, 3, 3, 2, 2 };
const unsigned char enemy_object_image[] = { 0, 2, 4, 12, 14, 16, 24, 26, 28, 36, 38, 40 };
const unsigned char enemy_object_speed[] = { 2, 3, 1, 3, 2, 1, 3, 2, 1, 1, 2, 3 };
const unsigned char enemy_object_delay[] = { 3, 3, 1, 2, 3, 1, 2, 1, 2, 2, 3, 3 };
const unsigned char enemy_object_hands[] = { 90, 80, 70, 60, 95, 85, 75, 65, 99, 90, 80, 70 };
const unsigned char enemy_object_waits[] = { 80, 60, 40, 20, 85, 65, 45, 25, 90, 70, 50, 30 };
const unsigned char enemy_object_tours[] = { 64, 72, 80, 88, 68, 76, 84, 92, 72, 80, 88, 96 };
const unsigned char enemy_object_kills[] = { 65, 73, 81, 89, 69, 77, 85, 93, 73, 81, 89, 97 };
const unsigned char gamer_object_image[] = { 0, 2, 4, 12, 14, 16 };
const unsigned char gamer_object_speed[] = { 1, 2, 3, 3 };
const unsigned char gamer_object_delay[] = { 1, 1, 2, 1 };
// TODO potentially include function pointer arrays here also!

Build
In previous projects our build.bat file had always used SDCC compiler switch to favor code speed. However, as Candy Kid was struggling to stay within 32KB ROM limit, unfortunately was necessary to favor code size:

build.bat
sdcc -c -mz80 --opt-code-size --peep-file peep-rules.txt --std-c99 main.c

Command
In 2009, we implemented the Command Design pattern to record sprite movement in Henway to playback for debugging and demo modes. Therefore, we would also like to implement the Command Design pattern for Candy Kid. The motivation here is record enemy movement for Reinforcement Learning in video games.

command_manager.h
void engine_command_manager_add( unsigned int frame, unsigned char command_type, unsigned char args );
void engine_command_manager_execute( unsigned int frame );
play_screen.c
void screen_play_screen_update( unsigned char *screen_type )
{
    // Implement logic to boost and move Candy Kid gamer.
    engine_command_manager_add( frame, command_type_gamer_speed, gamer_boost );
    engine_command_manager_add( frame, command_type_gamer_mover, gamer_direction );

    // Implement logic to boost and move Candy Mama enemies.
    engine_command_manager_add( frame, command_type_enemy_speed, ( enemy | ( enemy_boost << 4 ) ) );
    engine_command_manager_add( frame, command_type_enemy_mover, ( enemy | ( enemy_direction << 4 ) ) );

    // Execute all commands for this frame.
    engine_command_manager_execute( frame );
}
Rather than boost and move actors directly from game events we add these as commands to an array and execute them accordingly. However, even when storing 255 commands this quickly added to 1KB memory!

command_manager.c
#define MAX_FRAMES 255
static unsigned int command_object_frames[ MAX_FRAMES ];
static unsigned char command_object_cmds[ MAX_FRAMES ];
static unsigned char command_object_args[ MAX_FRAMES ];
Unfortunately, due to competition time constraints and hitting 32KB capacity for game code the Command Design pattern was not fully implemented. Next steps: code refactor and perhaps storing less commands.


z88dk
In 2016, 3D City was built using an old version of the z88dk which worked on emulators but real Master System hardware experienced graphics glitches. Subsequently, the updated version of z88dk integrates devkitSMS which also works on real hardware. In fact, this is how Galactic Revenge was built by eruiz00. This was preferred because the libraries are optimized in assembly language and produce smaller object code.

Therefore, this seemed a promising option for Candy Kid especially late in the development cycle when the game hit 32KB capacity for game code. Unfortunately, z88dk does not support the following two APIs used:
 SMSlib.h  extern volatile unsigned char SMS_VDPFlags;
 PSGlib.h  void PSGResume (void);


Summary
To summarize, the development process to build Candy Kid, like all previous SMS projects, has been very educational + has provided numerous opportunities to collaborate more with the SMS Power! community.

However, the biggest challenge in completing Candy Kid was to stay within the 32KB ROM game code limit. Here is a short list of current + future options:
  • Build game code in Z80 assembly directly for complete control of the machine code byte output
  • Refactor duplicate code to store generic code in function pointer arrays accessible by fixed bank
  • Integrate z88dk and devkitSMS that produces smaller object code by using only supported APIs
  • Upgrade from 8-bit Master System to 16-bit Mega Drive and bypass 32KB hard limit altogether

In fact, the final option is the most unique: much like how the Sega Master System has the devkitSMS to support homebrew game development using C language, the Sega Mega Drive has the SGDK. Therefore, would be interesting to transition many Sega Retro Gaming ideas developed from 8-bit onward to 16-bit!

Wednesday, January 1, 2020

Retrospective XI

Last year, I conducted a simple retrospective for 2018. Therefore, here is a retrospective for 2019.

2019 Achievements
  • Streamline Sega Master System retro game development using the devkitSMS
  • Win the Sega Master System annual coding competition with Platform Explorer
  • Apply devkitSMS programming skills to Mega Drive prototypes using the SGDK
  • Upgrade MonoGame version cross platform for future 3D graphics and shaders
  • Complete Linux installation process using virtual machine on Windows and Mac
  • Integrate new scripting languages including Python, Powershell and Terrarform
  • Expand cloud computing experience: Amazon Web services and Azure DevOps
  • Learn from Data Scientists and Machine Learning Engineers strategies at work
Note: winning the Sega Master System annual coding competition is a unique achievement!

2020 Objectives
  • Setup Sega dev + debugging environment for MegaDrive similar to Master System
  • Build MonoGame project cross platform containing 3D models and custom shaders
  • Integrate new software deployment techniques for containerization + orchestration
  • Continue AI and Machine Learning application to personal and professional projects

Personal
Earlier in 2019, I gave presentation on Game Development. I believe this provides excellent experience for Software Engineering in general because algorithms must be written efficiently to achieve consistent frame rates. Therefore, after working with Sega Master System would now like to experiment with the Mega Drive!


Professional
20 Predictions about Software Development trends in 2020 include: Infrastructure as all roads lead to Cloud, Containerization [Docker] + Orchestration [Kubernetes] and Microservices as REST APIs will be mainstream.

However, the big buzz continues to be centered around: Artificial Intelligence, Machine Learning and how can Big Data be leveraged by companies to improve their customer experiences and gain competitive advantage.


Future
After giving the presentation earlier in 2019, I was advised afterwards about a new interesting development connecting Artificial Intelligence and Video Games now described as Reinforcement Learning in Video Games.

Therefore, this seems excellent motivation to investigate Machine Learning Software such as TensorFlow for various applications of ML such as Reinforcement Learning and see if this can be applied to Video Games J