There is a hard and fast game creation rule:
"When you create something that can shoot, you must immediately make it shoot."
Well maybe not :-), but for sure it's what I do next.
In the original RIP OFF game there are two ways to defend the precious fuel capsules. You can:
- Crash into the enemy tanks that are trying to steal your fuel, explosively destroying both them and yourself. Any nearby fuel capsules will be unharmed. The penalty for this action is the few seconds that you are offline and defenseless until you respawn.
- Shoot the enemy with the tank's main gun. There can only be a maximum of four shells active at any given time.
Since the game is limited to four shells, I didn't have to get too fancy with the implementation. I started by setting aside some memory to hold the shell's data.
/ Tank shells. Only 4 concurrent tank shells allowed. s1, 0 / Shell 1. Life,x,y,dx,dy. x1, 0 y1, 0 dx1, 0 dy1, 0 s2, 0 / Shell 2. Life,x,y,dx,dy. x2, 0 y2, 0 dx2, 0 dy2, 0 s3, 0 / Shell 2. Life,x,y,dx,dy. x3, 0 y3, 0 dx3, 0 dy3, 0 s4, 0 / Shell 4. Life,x,y,dx,dy. x4, 0 y4, 0 dx4, 0 dy4, 0 slf, -77 / Initial shell time to live.
Each shell has:
- A time to live (TTL) value which is 0 when a shell is inactive and set to a fixed negative value (slf) when the shell is "fired". TTL is incremented for each step the shell takes across the screen until it hits 0 again.
- The x, y screen coordinates used to display the shell.
- dx, dy deltas to apply to the x, y screen coordinates for each step the shell traverses.
Some code was added to detect when the fire button on the controller was pressed. A fire flag is set only when the button state goes from off to on. That is to say the button must be released before the next shell can be launched.
lac pin / Check fire button off in previous read.
and (040000
sza / Is button off?
jmp nfr / No - Skip checking for fire bit.
ril 1s / Parse fire input.
spi / Is the fire bit set?
stf 4 / Yes - Set flag 4 for fire.
nfr,
A section of code was added to "launch" a shell if the fire flag is set. This is called from the main loop.
/ Check to see if a shell has been fired.
pop, dap pox / Set return address.
szf i 4 / Is flag 4 set?
jmp pox / No - Return.
clf 4 / Clear the fire flag.
lac \sn / Calculate shell vector x.
sar 6s
cma
dac \fdx
lac \cs / Calculate shell vector y.
sar 6s
dac \fdy
cs1, lac s1 / Yes - Check shell 1.
sza / Is shell 1 available?
jmp cs2 / No - Check shell 2.
fire s1,x1,y1,dx1,dy1 / Start shell in slot 1.
jmp pox / Exit.
cs2, lac s2 / Yes - Check shell 2.
sza / Is shell 2 available?
jmp cs3 / No - Check shell 2.
fire s2,x2,y2,dx2,dy2 / Start shell in slot 2.
jmp pox / Exit.
cs3, lac s3 / Yes - Check shell 3.
sza / Is shell 3 available?
jmp cs4 / No - Check shell 4.
fire s3,x3,y3,dx3,dy3 / Start shell in slot 3.
jmp pox / Exit.
cs4, lac s4 / Yes - Check shell 4.
sza / Is shell 4 available?
jmp pox / No - Return.
fire s4,x4,y4,dx4,dy4 / Start shell in slot 4.
pox, jmp . / Return.
If the fire flag is set it is cleared and a vector (dx, dy) is calculated that controls the shell's speed and direction based on the current orientation of the tank. Then a search begins for a shell "slot" that is not being used based on the time to live being 0. If an unused slot is found it is activated via the "fire" macro.
/ Fire a shell!
define fire LIFE,X,Y,DX,DY
lac slf / Get the shell time to live.
dac LIFE / Set the shell life.
lac \fx / Set the starting x,y coordinates.
dac X
lac \fy
dac Y
lac \fdx / Set the direction vector.
dac DX
lac \fdy
dac DY
term
Here the time to live, x,y coordinates, and dx,dy deltas are set.
To move the shells another subroutine was written that gets called each time through the main loop of the game.
/ Move all active shells.
mov, dap mvx / Set return address.
lac s1 / Check shell 1.
sma / Is shell 1 active?
jmp mv2 / No - Check shell 2.
move s1,x1,y1,dx1,dy1 / Yes - Move shell 1 one position.
mv2, lac s2 / Check shell 2.
sma / Is shell 2 active?
jmp mv3 / No - Check shell 3.
move s2,x2,y2,dx2,dy2 / Yes - Move shell 2 one position.
mv3, lac s3 / Check shell 3.
sma / Is shell 3 active?
jmp mv4 / No - Check shell 4.
move s3,x3,y3,dx3,dy3 / Yes - Move shell 3 one position.
mv4, lac s4 / Check shell 4.
sma / Is shell 4 active?
jmp mvx / No - Return.
move s4,x4,y4,dx4,dy4 / Yes - Move shell 4 one position.
mvx, jmp .
Each shell with a non-zero time to live is advanced one position based on the dx,dy values via the "move" macro.
/ Move the shell one step on the screen!
define move LIFE,X,Y,DX,DY
lac LIFE / Reduce time to live by 1.
add (1
dac LIFE
lac X / Show the shell on screen.
lio Y
dpy-i 300
add DX / Increment the X coordinate.
dac X
swap / Increment the Y coordinate.
add DY
dac Y
term
The TTL is decremented by one, the shell is displayed, and dx and dy are added to the x and y coordinates for the next loop. It's not fancy but it gets the job done.
My main loop so far.
/ Main loop.
fr0, load \ict, -4500 / Initial instruction budget (delay).
idx \frc / Increment frame counter.
jsp tnk / Draw and control the player's tank.
jsp pop / Check to see if a shell has been fired.
jsp mov / Move any active shells.
count \ict, . / Use up rest of time of main loop.
jmp fr0 / Next frame.
Here is what it looks like.
Michael Gardi
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.