Copyright © 2020 by Víctor Parada
This is a little game for the 2020 NOMAM's BASIC 10-liners Contest. This program fits in the EXTREM-256 category, and it was written using FastBasic 4.3 for the 8-bits ATARI XL/XE. Development started on 2019-07-19, and it took 6+5 days. The final version's date is 2020-03-06.
UPDATE: It obtained the 11 place of 25 entries in the category.
Your personal trainer Simona does some exercises with you, and you must follow her as fast as you can.
Simona is your personal trainer in pink, and she'll invite you to do some exersizes. | |
There are 3 different levels: EASY: There are only 4 different basic movements to remember, one for each joystick direction (up, down, left and right). REGULAR: There are 4 extra movements in addition to the 4 basic ones, but you only have to move the joystick in the same 4 directions, and the extra ones will be automatically selected for the series. HARD: You have to press the trigger to select the extra movements along with the joystick, giving real 8 different movements to remember. |
|
If you perform the same movement than her before she returns to the neutral position, you will score a hit. | |
If you don't do the same movement at time, yow will score a fail. | |
Simona will increase difficulty during the exercises by speeding up a bit every time. | |
The game is over when you fail 100 movements! |
Thinking about a game with a simple animation, it came to me an idea of an animated Simon-like game: instead of colors and sounds, the player might remember positions, and the most practical way to do that should be gymastics or aerobics. It took me many days to design the game in my mind, performing some calculations about the RAM requirements and which should be a good graphic resolution. I also thought about the name of the game: "Simona's Fitness Club", and obviously Simona would be the character for the game. But I had to start with something and that could by some drawings, so I used Paint program in zoom mode and started to put pixels to draw a girl in sport clothes from the 80's. After some minutes, I had a nice toon of her that it was detailed enough, but not so big for a tenliner. Then, I drawed some other positions and also the transitions from the resting one. The next day I completed full sequences for 8 movements and the corresponding transitions. I decided to have 2 different movements for each side in order to introduce difficulty to the game.
Initial design of the character
The whole series
I had to transfer this design to the Atari, but instead of convert the whole bitmap to be used in some graphics mode of the Atari, I decided to send it already sliced and ready to use from the BASIC program, and I selected FastBasic for this project. I picked every different image and put them in a row. Each image has a height of 18 pixels and a width of 11 pixels. As any 4 colour graphics mode uses a byte every 4 pixels, I'd need 3 bytes per line, and a total of 54 bytes per image. The grand total would be 918 bytes for the whole 17 images, and that is 40% of the available coding space in the EXTREM-256 category, or 75% in PUR-120. I was sure I'd need to compress the images, so I deliberately designed the images with portions of it in a static position, in order to reuse the bytes, and those were the legs. It won't make any difference in the amount of storage if a graphics mode or a text mode (in ANTIC 5) would be used. A redefined charset would require 9 chars per image: 3 bytes height (3x8=24 lines) and 3 chars width (3x4=12 pixels), and I didn't try to find how to split the images to get the common characters from different images. To simplfy, I just bet for a graphics mode and defined only 6 tiles per image, and the height of each of them was 9 pixels. I wrote a script that read the picture, splitted every image into tiles, found the duplicated ones, and wrote the bitmap of the selected tiles and an index to the required tiles for every image. The result was only 62 tiles instead of 159, with a total of 558 bytes, less than 22% of the coding space in EXTREM-256 category. The index used 17x6=102 aditional bytes, and the unpack routine used about 120 bytes more, but it did it directly into the precached buffers. A simple loop modifying the memory pointer of a GRAPHICS 5 screen pointing to the buffers showed me the animation for whole exercises sequence, and I liked it.
All 17 images of Simona
Animation in the Atari
In the bottom of the screen was displayed the next cache buffer, and that gave me the idea of two ladies in the playfield at the same time: one for Simona and one for the player, but they shouldn't be the same image, at least the color of the clothes should be different, and I already was using all 3 colors and the background. I could had a 4th color if I had used ANTIC text mode 4, and used inverse video in the chars of one of the ladies, but the images would be much smaller. By those days, I was talking with DMSC about adding display list interrupts (DLI) to his FastBasic language. With a single DLI it would be possible to have 2 completely different color sets, one for each character. But the development of DLI in FastBasic took too much time trying to find the best way to add such powerful feature to the language that it could manage many interruptions in the same screen and be simple to use at the same time, and the developement of this game got frozen for many months... During this stand-by period, I thought about a variation of the game: instead of a Simon-like game, make a reflex game, trying to react as fast as possible. When the call for the 2020 contest arrived, I had to decide which of the variations to try first, and the reflex version won over the memory one.
The first thing I did when I resumed the programming, was to split the screen with a custom display list (over text mode 0) with the DLI using a FastBasic prototype. I liked very much the colors I selected for the second lady, and she immediately became Simona.
Prototype of the game using a prototype of DLI in FastBasic's beta version.
The next step was to be able to control the other lady with the joystick, because Simona would be controlled by the computer. There were 8 different movements, but the controls were only 4 (up, down, left and right), each with two movements, so I added the trigger as a selector of the variation for the same joystick direction for the tests. During the game, the trigger should not be required, because the variation would be selected automatically to be the same than Simona's, but during this tests, I thought that it could be nice to have different difficulties, the original and the triggered version with all 8 commands. I found that there were no simple way to recognize which was the base and which was the extended movement for each direction, so I changed the order of the series and grouped the movements that used extended arms as the alternate ones.
The player can move to any direction while Simona is performing a series.
For the game dynamics, I used loop with a circular timer. At given values of the counter, Simona whould change the position: at zero, she would select a direction and display the transition to that movement, at the quarter she whould show the selected direction, at the half she would display the transition again, and at the last quarter she would be again in the rest mode. For the player, the sequence should be the same, but it will use its own timer that it would start when the user moves the joystic. To score a hit, the timer for the player should start before the first half of Simona's timer. To have a continuous movement of the player, it won't be able to move the joystick for a new selection during the first half of the own cycle (timer). It won't be an endless game, so a fail counter was included: you can hit or miss a movement, and the game would finish at some misses count. To add difficulty, I introduced continuos increase of speed during the game loop.
Scoring hits and misses.
The game was almost ready, and as it was using about 70% of the available coding space, I decided to add some messages using another new feature of FastBasic that it was available in its beta prototype. To select each of the two difficulty levels, just 2 flag variables should be selected, and this messages allowed a simple way to select one of the difficulty levels. Then, a third game difficulty was included: the use of only the first set of movements. It was just a different combination of the same 2 flag variables.
Introducing a messages system (without DLI).
With the official release of FastBasic 4.3, I could include the DLI feature using its final syntax, and the game was ready to be sent to the contest with only 9 lines of code, but I had no documentation of it, because I used the available time to try the original concept of the game: a memory game like in Simon.
Final version using the brand new release of FastBasic with DLI.
Get the SIMONAF.ATR file and set it as drive 1 in a real Atari (or emulator). Turn the computer on and the game should start after the loading completes. A joystick in port 1 is required.
The abbreviated BASIC code is the following:
The full and expanded BASIC listing is:
graphics 0 poke 710,0 poke 752,1 poke 82,0 |
Set up screen |
|
GR 5: SCR=$BBA0 GR 0: SCR=$BC40 |
? ? "Follow Simona" ? ? "Setting up..." |
|
j=adr("{binary data}")+1 |
Joystick movements |
|
Prepare Simona's movements |
mset $8000,$3800,0 |
Clean frames buffer |
a=adr("{binary data}")+1 |
Tiles needed for each frame (17 frames of 3x2 tiles) |
move adr("{binary data}")+1,$8000,225 |
Bitmap data for every tile (4x9) |
move adr("{binary data}")+1,$80E1,225 |
|
move adr("{binary data}")+1,$81C2,108 |
|
for k=0 to 16 s=$840A+k*512 for b=0 to 5 x=$8000+9*peek(a+b+k*6) for c=0 to 8 poke s+(b/2)+180*(b&1)+c*20,peek(x+c) next c next b next k |
Unpack frames |
? "{binary data}" |
Clean the text screen |
move adr("{binary data}")+1,708,4 |
Set up colors (hair,skin,clothing,text) |
dli set u = $CA into $D019, $96 into $D016, $16 into $D017, $4A into $D018 dli u |
|
move adr("{binary data} |
Set up the display list |
")+1,$BB6A,54 dpoke 560,$BB6A |
|
pause 50 |
Wait for a second |
q=$BB6E |
Frame vector for Player |
p=$BB86 |
Frame vector for Simona |
a=adr("{binary data}")+1 |
Frames for sequences, 4 frames each |
r=adr("{binary data}")+1 |
Tones for the rhythm, 1 per frame |
d=adr("{binary data}") |
List of messages |
n=1 exec m |
Display welcome message |
do |
Main loop |
n=47 exec m |
Display difficulty selection message |
repeat |
|
n=68 exec m until x<7 |
Display get ready message |
? "{binary data}" position 20,0 ? "{binary data}" |
Reset on-screen scoreboard |
z=4+4*(x<>5) |
Number of movements, 8 for normal and hard, 4 for easy |
y=x=3 |
Trigger is needed in hard |
f=0 |
Fails count |
h=0 |
Hits count |
w=16 |
Delay for speed control |
g=0 |
Current delay counter, forces a movement at start |
i=3 |
Current movement step |
e=63 |
Current step counter for player movement |
s=0 |
Current player movement |
v=0 |
Timming to decrease delay |
n=107 exec m |
Display count down... |
repeat |
Game loop |
if g=0 |
Time to move? |
c=10 |
Set volume for tone |
i=(i+1)&3 |
Next step for the movement |
g=w |
Set the next delay |
if i=0 |
Time to a new move? |
t=rand(z)*4+4 |
Select next movement |
inc v if v>15 v=0 w=w-(w>7+y*5) endif |
Time to speed up? |
o=w*3-2 endif |
Set response timer |
k=$8400+peek(a+t+i)*512+4 endif |
Simona's next step |
sound 0,peek(r+i),8,c |
Play the tone |
c=c-2*(c>0) |
Decrease the volume for the next loop |
if e>3*w+2 |
Player can move if is not moving or if it is finishing the previous one |
s=peek(j+stick(0))*4 |
Select players movement |
if s |
Player moves? |
e=0 |
Start player's sequence |
if y |
Hard routine? |
s=s+16*(strig(0)=0) else |
2nd type of movement is get when the trigger was pressed |
s=s+16*(t>16) endif endif endif l=$8400+peek(a+s+e/w)*512 |
Automatic selection of 2nd type of movement |
pause 0 dpoke q,l dpoke p,k |
Refresh movements |
if o=0 |
Check for a hit or miss |
if t=s if h<9999 inc h position 35,0 ? h endif |
Hit! |
else inc f position 26,0 ? f endif endif |
Miss... |
dec g |
Decrease delay time for the next series |
dec o |
Decrease response timer |
e=e+(e<4*w-1) |
Increase players counter |
poke 77,0 |
Disables attract mode |
until f>=100 |
Game ends at 100 misses!!! |
sound |
Stop sounds |
dpoke p,$8404 dpoke q,$8400 |
Restore initial position
|
n=131 exec m |
Display game over message |
loop |
Back to game loop |
proc m |
Procedure to display a group of messages |
c=d+n x=7 |
Find text of the message |
while peek(c) and x=7 |
Repeat for every word(s) of the list, or until a key is pressed |
v=peek(c) position 7-v/2,0 pause 0 ? $(c) |
Print next word(s) centered in text area |
b=0 repeat x=peek(53279) inc b pause 1 until b>25 or x<7 |
Wait for a moment or a key press |
mset $BC40,20,0 pause 8 |
Clean message area |
c=c+v+1 wend endproc |
Move to next line |
Return to my 10-liners page.
© 2020 by Víctor Parada - 2020-03-20 (updated: 2020-08-15)