Screen Map:
- Warrior is the first vector game in which Tim Skelly utilized a 16x12 grid of data which described locations on the screen. He would go on to use a similar 32 x 24 grid in Armor Attack.
- Codes used:
$00 Pit
$01 Right Player Safe Zone
$02 Left Player Safe Zone
$05 Corner
$06 Corner
$07 Right Boundary
$09 Corner
$0A Corner
$0B Left Boundary
$0E Top Boundary
$0D Bottom Boundary - All other values in the map are the player's target scale at that position on the screen.
- The knight's scale is eased toward the target scale found in the screen map to make the knights appear to be further or closer to the player as they traverse the different levels of the background scenery.
- Scale range:
$A0 Smallest Scale
$C8 Largest Scale
Graphics:
- The knights image are three separate pieces: Head, Shoulders, Sword & Arms. (There might be another component as there is some vector data that isn't directly referenced by the code that I don't know what it's for... $64C1-$64D5)
- There is different vector data for the head of each knight.
- There are 36 Sword and Arms frames which are mirrored, for a total of 72 frames of animation for the entire sweep of each knight's sword.
- The knights head and body turn to face the opposing knight.
- The sword glow consists of 6 frames of animation. They glow brightly when the player's swords are touching.
Movement:
- When the players swords are touching (and glowing) each knight's x,y movement effects the other knight's x,y position. This allows a skilled player to push the opposing knight into a pit and score.
Polar to Cartesian Conversion:
- To achieve the effect of a knight's head and body turning toward the opposing knight, the game converts the x,y cartesian coordinates of the knights' bodies to polar coordinates (radius, polar angle). This angle is then used as a target angle to gradually rotate toward. The game also calculates a Body-Head Rotation Difference, so that the knight's head rotation stops at an appropriate angle.
- Space Wars was the first vector game to utilize polar coordinates (radius & polar angle, rather than x & y). To convert between the two it used a 32 byte lookup table of Sine & cosine values converted into 8-bit values.
- Warrior expands on this system by utilizing a lookup table of 255 values ($5E9C-$5F9B) for greater accuracy.
- Polar Coordinates would continue to be used in most other Cinematronics games. The code would be further refined and Rip Off, Star Castle, Armor Attack, Solar Quest and Demon all use the same (now 90 byte) sine & cosine lookup table.
Sword System
- My understanding of this is incomplete...
- The sword x,y location is within a "sword box" superimposed over each knight. As the sword x,y location moves from the player's input, the program chooses the appropriate animation frame to display that location. (How?)
- Since the knights rotate as they swing, this "sword box" also rotates, making the simple system
look more realistic. Removing the rotation revealed the "sword box".
Collision Detection:
The game does a number of collision checks:
- Check if Players Swords Are Touching
- Check to see if knights are too close together.
- Collision Check: Left Player: Sword and Right Player: Body
- Collision Check: Right Player: Sword and Left Player: Body
- Collision Check (type 2) Between: (My understanding of this is incomplete...)
Current Player Sword and Opposite Player: Body
AND Current Player Sword and Current Player: Sword Glow
*** This check removed in 4J_v2 to improve gameplay and make scoring easier. This is the "armor check". I'm not sure what Tim Skelly's intention was with this check. When it was removed to see its effect on the game, I found that the gameplay was, to me, improved. There is no velocity variable associated with the swords. - Collision Check (type 2) Between:
Current Player and Other Player's Sword
AND Current Player and Other Player's Sword Glow
Memory Banks:
The game code runs as if it is in banks 5 & 6 ($5000-$6FFF). However the bank switching hardware on 8k boards only looks at bit-0 of the memory bank set using "setp", so its still bank 1 & 2 ($1000-$2FFF).
Tim Skelly did this in his other games as well. It seems to be a "byte saving" technique. The SETP command is used both to bank switch between roms and to switch between the game's 16 banks of 16 bytes of ram. By storing variables in certain banks, when the SETP command is used to jump to a memory location in rom the memory location in ram that will be accessed is already set where the variables exist.
Attract Mode:
Very early Pre-programmed attract mode which runs the same routine of moves each time.
Service Mode:
Turned on by dipswitch. Used by operators to line up monitor image with cabinet artwork.
Easter Eggs or Hidden Code:
None that I've noticed
Free Space:
Bank $5 ($1): $1B (27) Bytes
Bank $6 ($2): $1E (30) Bytes
4 Joystick Version:
The move to a two player version from the the code doesn't appear to be a last minute patch, but rather a decision that was earlier in the game's design. The inputs ARE spaced out as if they were changed from an original 4 joystick spec. The code and attract mode were built with two joysticks in mind and adding the additional controls and required a number of changes and additional variables.
Rom Overview:
5000-5060 Start & Init Variables
5061-507D Game Over
507E-5097 Reset Variables for Attract Mode
5098-50DF Coinage & Timer Dips
50E0-50FF Start Game
Main Loop:
5100-5132 Handle Coins
5133-5159 Read Player Inputs
515A-516C Adjust Directional Input: Right Player
516D-517F Adjust Directional Input: Left Player
5180-51AE Adjust Directional Input
First Done with Right Player (001)
Then Done with Left Player (000)
51AF-51B8 Link Directional Movement if Swords Touching
51B9-51D6 Copy Left Player to Current Player and Goto Update Current Player
51D7-51F2 Copy Current Player to Left Player
51F3-5210 Copy Right Player to Current Player
5211 Update Current Player:
5226-524A Dead
524B-5295 Regenerate Dead Player
5296-52BB Regenerating
52BC Alive:
52BC-533F Pitfall
5340-5352 Directional Input
5353-5477 Swinging Sword
535C-538C Initial Calculations & Conversions
538D-53D5 Change Sword Orientation Based on Directional Input
53D6-53ED Adjust Added Rotation Based on Sword Orientation X
53EE-5405 Adjust Added Rotation Based on Sword Orientation Y
5406-5422 Update Current Player: Body Rotation
5423-5444 Handle Sword Mirroring
5445-546A Lookup Knight Sword Vector Data Offset
546B-5477 Goto Subroutine: Update Current Player, Return to $5586
5478-5585 Moving
5482-54B3 Change Player Location Based on Directional Input
54B4-54F5 Keep Player On Screen
54F6-5512 Skip Collision Checks and Goto Subroutine: Update Current Player, Return to $5586?
5513 Collision Checks:
5513-5528 Players too Close? If So, Set Status to: Invalid Move, Goto $5586
5529-552E Goto Subroutine: Update Current Player, Return to $552F
552F-5551 Collision Check 2: Between ???
5552-5585 Collision Check 2: Between Current Player and Other Player's Sword
5586-558B Switch to Update Right Player ($51D7)
558C-55A8 Copy Current Player to Right Player
55A9-55C5 Check If Players Swords Unable to Touch
55C6-5614 Check if Players Swords Are Touching Set-up
5615-5649 Handle Sword Hum: Check if Players Swords Are Touching
564A-566A Collision Check: Left Player: Sword and Right Player: Body
5669-5688 Left Player Scores
5689-56A4 Collision Check: Right Player: Sword and Left Player: Body
56A5-571F Subroutine: Collision Check
5720-5741 Right Player Scores
5742-5751 Play Game Sounds
5752-5758 Check For Service Mode
5759-57BC Draw Scores & Timer
57BD-581F Draw Left Player
5820-588B Draw Right Player
588C-589E Cold Start Inhibit
589F-58C3 Game Timer
58C4-5915 Service Mode
5916-5966 Service Mode: Vector Data
5967-598A --- Copyright Text ---
598B-59AA Attract Mode: Timer
59AB-59D1 Attract Mode: Demo Input
59D2-5A08 Attract Mode: Read Data
5A09-5A21 Subroutine: Copy $10 Bytes
5A22-5CD2 Subroutine: Update Current Player
5A22-5AA0 Calculate Target Angle between Player Bodies
Calculate Distance Between Current Player and Opposite Player X
Calculate Distance Between Current Player and Opposite Player Y
Adjust for Data Lookup
Lookup Data for Cartesian to Polar Conversion
5AA1-5ADE Rotate Current Player: Head to Target Angle
5ADF-5B0C Calculate Body-Head Rotation Difference
5B0D-5B38 Swinging Sword:
Rotate Head Toward Target Angle Based on Body Rotation
5B39-5B5B Moving:
Rotate Body Toward Target Angle Slowly
5B5C-5B93 Update Sword & Sword Glow
Goto Subroutine: Convert Polar to Cartesian: Current Player: Body Rotation & Scale
Goto Subroutine: Lookup & Adjust Vector Data
Add Current Player Body XY to Result and Store in Sword XY
Goto Subroutine: Lookup & Adjust Vector Data
Add Current Player Body XY to Result and Store in Sword Glow XY
5B94-5B9E Read Screen Data: Setup (Moving does both, swinging sword runs only its code)
5B9F-5BC5 Moving: Read Screen Data for Body XY Location
5BCC-5BDB Scale Data: Ease Current Player: Scale Toward Screen Data Scale
5BDC-5BE8 Not Scale Data:
5BE9-5C2B Screen Data = Pit
5C2C-5C55 Screen Data = Safe Zone
5C56-5C7A Swinging Sword: Read screen Data for Sword XY Location
5C7B-5CD2 Check for Invalid Sword Moves
5CD3-5D3E Subroutine: Collision Check 2
5D3F-5DB8 Subroutine: Draw Vectors
5DB9-5DDB Subroutine: Recalibrate Beam
5DDC-5E9B Data: Screen Data
5E9C-5F9B Data: Convert Cartesian to Polar
5F9C-5FE3 Data: Knight Sword Vector Data Offset Pointers
5FE4-5FFF --- Garbage? --->
6000-609B Subroutine: Convert Polar to Cartesian
609C-60C9 Subroutine: Vector Data Lookup
60CA-6164 Subroutine: Adjust Vector Data
6165-61AD Subroutine: Draw A Number
61AE-6227 Subroutine: Draw Digit
6228-62E3 Vector Data: Digits
62E4-639C Subroutine: Draw Sword Glow
639D-6402 Vector Data: Sword Glow (6 Frames)
6403-6426 --- Copyright Text ---
6427-642E Attract Mode: Read Data
642F-64A7 Data: Attract Mode
64A8-64C0 Vector Data: Shoulders
64C1-64D5 Vector Data:
64D6-650E Vector Data: Left Player: Head
650F-653F Vector Data: Right Player: Head
6540-6FC3 Vector Data: 36 Sword & Arms Frames
6FC4-6FE0 Data: For Convert Polar to Cartesian
6FE1-6FFF --- Garbage? --->
Revision History:
5/17/2015: Initial Draft