Back to Page
Revision 16 (current)
Edited by WarHippy on 11/28/2023 6:56 PM
%%TOC%%
Crime City is a 1987 action film starring Tony Gibson and Raymond Broady, alongside Jail-Breaker having a Knife and G-Jumper Burglar.
!!! The Player
!! Player Choice
Player 2 starts every stage further to the right than player 1. For this reason, it is better to be player 2, since there are more right-scrolling stages. While there are other left-scrolling stages, only stage 6-2 is forced to be left scrolling.
!! Movement
Movement is simple. Walk speed is 2 pixels per frame with no acceleration. There is no penalty to jumping.
Movement is limited by the bounds of the screen. The camera scrolls at 2 pixels per frame as long as you are at or past the midway point of the screen and not at the end of the stage. However, getting ahead of the scroll speed can still be useful, as you get time to stop and shoot enemies, if needed.
Any action (jumping, high jumping, rolling on the ground, rolling in the air, shooting, collecting a health bottle) changes your hitbox appropriately. This gives the player a lot of control over how they choose to take damage.
! Walking off edges
If you hold forward as you walk of a ledge, you will have 1 frame of zero movement. To avoid this, release forward on that frame, and you will instead move 3 pixels on that frame. Note that when moving to the left, you can hold L+R for the zero movement frame to also move three pixels on that frame.
! Rolling
Pressing down and a direction and jump will start a roll. This also moves 2 pixels per frame, but you get one frame of zero movement when the roll ends.
! Pressing L+R
Pressing left and right simultaneously in the air has two effects:
* You face left while moving right, making it possible to shoot enemies behind you without stopping.
* You pass through scenery. (Note that you can only move to the right using L+R, so a different technique is used when you clip in going to the left)
While pressing L+R, you cannot start a high jump.
! Clipping Left
There are two ways of clipping into scenery while moving leftwards. The first takes advantage of the fact that you can't turn around immediately after shooting. While in the air, if you fire a shot facing right and then immediately hold left you will fall back and to the left for 3 frames. This is just enough to let you clip in and stand on the very edges of the blocks that make up the scenery.
The second way to clip in is to be right next to the wall and get hit by an enemy, twice. Each hit will shunt you 2 pixels to the left, and after 4 pixels you will be in just far enough to stand on the edges of the scenery blocks again.
! Damage boosting
Colliding with an enemy will move you 3 pixels per frame for 7 frames, then if you are on the ground, one frame of no movement. Which direction you are pushed to depends on if you are more to the right or to the left of the enemy.
Colliding with a barrel will move you 12, 12, 12, 12, 12, 10, 10 frames. You are always pushed in the direction the barrel is rolling.
!! Shooting
! Weapons
||Weapon ||Ammo ||Rate of fire||On-Screen ||Notes ||0xA02704 =
|Pistol|50|9 frames|5|Starting weapon|0
|Machine Gun|40|5 frames|9|Fires quickly|1
|Railgun|30|9 frames|4|Pierces through enemies|2
|Shotgun|20|9 frames|3 (9)|Fires three projectiles: one central, one upward, one downward|3
There is a special version of the pistol with unlimited ammo. The icon has a grey ouline instead of yellow. Other than that, has the same ID and weapon data.
! Crouch/Stand Cancel
For weapons other than the machine gun, you can only shoot every 9 frames. You can cancel this pause by ducking for 4 frames (if you were standing) or standing for 4 frames (if you were ducking), to shoot every 5 frames instead of 9.
! Quick Jump After Shooting
Similarly to shooting faster, you can use the same animation cancel to jump sooner after a shot.
After a standing shot, you can crouch for only 3 frames and then jump. After a crouching shot, you must stand for 4 frames before you can jump.
! Bullet Limit
Each weapon has an on-screen bullet limit. For example, for the pistol, it is 5. Trying to shoot while 5 of your bullets are still on screen will produce punches, instead. Bullet limits for the other weapons can be found in the table above.
! Shooting with your old weapon
While you are in the air, and picking up a new weapon, you can continue shooting bullets of the type of your previous weapon, as long as there is not a too long pause between shots. This trick has very limited application.
!! Death
Dying during a boss fight resets the timer to 85. At the end of a level, the timer counts down by 1 second every 2 frames, so every second lost to death saves some number of frames.
Dying while the camera scroll (0xA03EDA) is less than or equal to 1087 will freeze the camera; dying when the camera scroll is greater than 1087 will retain the camera scroll until it reaches its proper value or 1120, whichever comes first.
Therefore, the optimal strategy is to die when the camera scroll is greater than 1087, when the timer is at its highest, and the boss is loaded into enemy slots.
!!! Enemies
!! Bosses
Bosses will be loaded when the following conditions are met:
- the camera scroll (0xA03EDA) reaches 1120.
- there are available enemy slots in the enemy table.
After the boss has been loaded, it will appear on screen when the counter at 0xA02A0C reaches 0.
Bosses have varying health, and some of them have weak points where they take double damage, or body armor, where they take half damage. To hit these, either duck or stand as you fire.
Bosses, like all enemies, remain loaded in memory until all of their projectiles have despawned.
All weapons, including rolling and punching, do a base damage of 1.
||Stage ||Boss ||Health ||Stand ||Duck
|1 |Machine gun |14 |½ |1
|2 |Shotgun |16[#1] |1 |2
|3 |Uzi |8[#1] |2 |1
|3 |RPG |16 |1 |½
|4 |Flame thrower |24 |1 |1
|5 |Helicopter |20 |1 |1
|5 |Bazooka |28 |1 |1
[1]: These bosses die at negative health rather than 0, so in practice they have 1 health more. They also have no invulnerability timer, unlike the other bosses.
!!! Levels
We found two timers and one flag related to levels ending. I have called them "boss is alive" (0xA02A0A), "T1" (0xA02A0C), and "T2" (0xA02A0E).
While "boss is alive" is 1, enemies will continue to fill enemy slots and spawn.
T1 is set once the camera locks onto the final viewpoint of the level and counts down each frame.
On level 1 (check for all levels), new enemies will spawn every 128 frames.
When the boss is defeated, the "boss is alive" flag is set to 0, and enemies stop spawning.
Once the boss is defeated, T2 starts counting up to some predetermined value, then enemies enter their surrender animation and the level ends.
Two frames after the boss despawns, 0xA0225C is given another value, counts down from that, is set to yet another value, counts down for some frames, and the end of level jingle starts.
!! Level 1
!! Level 2
! Level 2_1
! Level 2_2L
! Level 2_2R
! Level 2_3L
! Level 2_3R
! Level 2_4
!! Level 3
!! Level 4
!! Level 5
!! Level 6
! Level 6_1
! Level 6_2
!!! RAM Map
Sprite data is located in the 0x410000-0x41197F block.
Object data is located in the 0xA00000-0xA0FFFF block.
!! Camera
||Address ||Width (bytes) ||Description
|0xA03EDA|2|The number of pixels the camera has scrolled.
|0xA03EE6|2|The leftmost screen pixel.
|0xA03EE8|2|The rightmost screen pixel.
|0xA03EEA|2|The topmost screen pixel.
|0xA03EEC|2|The bottommost screen pixel.
!! Player Data
The player object is 0x300 bytes long. Player 1's information starts at or around 0xA023F8, and player 2's at 0xA026F8. Since player 2 starts all levels more to the right than player 1, and most stages scroll to the right, player 2 is the optimal choice for a playthrough.
||Offset (bytes)||Width (bytes) ||Description
|0x001 |1 |1 if the player is active, 0 otherwise.
|0x002 |2 |Flags indicating the player's behaviour (see below).
|0x004 |2 |Unknown.
|0x006 |2 |Invincibility frames remaining.
|0x00C |2 |Current weapon (see above).
|0x012 |2 |Total X position in the stage (0 - 2560).
|0x014 |2 |Total Y position in the stage.
|0x034 |4 |Unknown
|0x038 |4 |Unknown
|0x03C |4 |Unknown
|0x040 |2 |Y velocity (signed)
|0x05C |2 |Number of bullets fired from current weapon. Yes, this counts UP to the ammo capacity of the weapon and not down.
|0x0A8 |4 |0041 0200 Pointer to the player's first bullet sprite data. Also a Player Bullet structure. (See below.)
|0x0C0 |4 |0041 0180 Pointer to the player's second bullet sprite data. Also a Player Bullet structure.
|0x0D8 |4 |0041 0190 Pointer to the player's third bullet sprite data. Also a Player Bullet structure.
|0x0F0 |4 |0041 01A0 Pointer to the player's fourth bullet sprite data. Also a Player Bullet structure.
|0x108 |4 |0041 01B0 Pointer to the player's fifth bullet sprite data. Also a Player Bullet structure.
|0x120 |4 |0041 01C0 Pointer to the player's sixth bullet sprite data. Also a Player Bullet structure.
|0x138 |4 |0041 01D0 Pointer to the player's seventh bullet sprite data. Also a Player Bullet structure.
|0x150 |4 |0041 00E0 Pointer to the player's eighth bullet sprite data. Also a Player Bullet structure.
|0x168 |4 |0041 00F0 Pointer to the player's ninth bullet sprite data. Also a Player Bullet structure.
! Player Behaviour
Some of the information in the player behaviour address (player address + 0x02) has been decoded.
||Flag ||Description ||If 0 ||If 1
|0x0001 |Player facing |Right |Left
|0x0002 | |Standing |Crouching
|0x0004 | |Not jumping |Jumping
|0x0008 | |Jumping vertically |Jumping left or right
|0x0010 |Unknown | | |
|0x0020 |Unknown | | |
|0x0040 | | |Shooting
|0x0080 | | |Rolling
|0x0100 | |Above the ground |On the ground
|0x0200 | |Moving |Not moving
|0x0400 |Unknown | | |
|0x0800 |Unknown | | |
|0x1000 |Unknown | | |
|0x2000 |Unknown | | |
|0x4000 |Unknown | | |
|0x8000 |Unknown | | |
! Player Bullet Slots
The player bullet slots (offset 0xA8 and onward) are all structured data, some of which is understood. They are each 0x18 long.
||Offset ||Width ||Description
|0x00 |4 |Pointer to the sprite data.
|0x04 |2 |Bullet count, but only in the first bullet slot.
|0x06 |2 |Bullet direction. (signed) 0 = doesn't exist, 1 = left, 128 = collision, -1 = right
|0x08 |2 |Bullet X "position"? Full X position, not on-screen position. It's offset from the actual projectile, and could be where it's hitting instead of where the sprite actually is.
|0x0A |2 |Bullet X sub-pixel?
|0x0C |2 |Bullet Y "position"? Y position from the ground with some offset.
|0x0E |2 |Bullet Y sub-pixel?
|0x10 |2 |Unknown.
|0x12 |2 |Unknown.
|0x14 |2 |Bullet volley number?
|0x16 |2 |Unknown.
!! Enemy Data
The enemy object is 0x200 bytes long. There are eight enemy slots (though the eighth seems reserved for non-enemy objects like chandeliers). Most bosses take up two enemy slots, and as such two slots need to be available for those bosses to spawn into them.
||Offset ||Width ||Description
|0x06 |1 |Unknown.
|0x0C |1 |Enemy state.
|0x0D |1 |Enemy type. See below.
|0x12 |2 |Full X position, not on-screen position.
|0x14 |2 |Y offset from the ground.
|0x16 |2 |Enemy weapon, maybe?
|0x1A |4 |Pointer into the enemy bullet block.
|0x20 |2 |Enemy HP.
|0x34 |4 |Pointer to hitbox data. See below.
|0x4A |2 |Seems to indicate the enemy is attacking.
|0x5D |2 |Enemy HP for "secondBoss" and "laser". These enemies do not seem to have iframes.
|0x73 |1 |Invulnerability frames. For bosses, this seems to cap at 7.
Flamethrower specific information.
||Offset ||Width ||Description
|0x57 |1 |Flamethrower state. 8 = charging, 9 = active
|0x5B |1 |Timer for the flamethrower state.
|0x77 |1 |Flamethrower progress. Cycles through different values to determine state.
Laser specific information.
||# ||Offset ||Width ||Description
|0 |0x042 |2 |If this is 2 and #3 is 0 then the laser is firing in #4 frames.%%%If this is 1 then the laser is charging for #4 frames.
|1 |0x044 |2 |Sometimes 0, sometimes 1.
|2 |0x046 |2 |Changes to 0, then 1E when the laser is fully discharged.
|3 |0x048 |2 |Counts the number of laser particles fired; FFFF = fully discharged.
|4 |0x04A |2 |Timer between changes.
! Enemy Hitboxes
The pointer at 0x34 from the enemy's data block points into the 0x00410000 sprite data region. These offsets are from that pointer's location.
||Offset ||Width ||Description
|0x04 |2 |X position.
|0x06 |2 |Y position.
|0x08 |2 |Width.
|0x10 |2 |Height.
! Enemy "names"
In order to differentiate the different enemy values, Team 3 came up with some nicknames based on the enemy's look. These are not official names.
||0x0D value ||Name
|0 | batonCop
|1 | pistolGuy
|2 | machineGunGuy
|3 | ???
|4 | firstBoss
|5 | layingDownPistol
|6 | oldmanPistol
|7 | crouchingMachineGun
|8 | hostageTaker
|9 | contraGunner
|10 | secondBoss
|11 | boStaffGuy
|12 | bluePistolGuy
|13 | suitGuy
|14 | machineGunGuy [[2]]
|15 | thirdBoss
|16 | fourthBoss
|17 | molotov
|18 | chainGoon
|19 | redShirtPistol
|20 | punkGunner
|21 | ???
|22 | fifthBoss
|23 | ???
|24 | ???
|25 | dog
|26 | motorbiker
|27 | ???
|28 | ???
|29 | ???
|30 | windowSniper
|31 | ???
|32 | ???
|33 | ???
|34 | ???
|35 | windowGunner
|36 | windowMolotov
|37 | laser
|38 | machineGunGuy [[3]]
|39 | crouchingGunner
|40 | finalBoss
|41 | helicopter
|42 | contraMolotov
|43 | ???
|44 | ???
|45 | ???
|46 | ???
|47 | ???
|48 | ???
|49 | ???
|50 | rifleman
|51 | fallingCrate
|52 | barrel
|53 | ???
|54 | ???
|55 | ???
|56 | ???
|57 | platformHorizontal
|58 | platformVertical
|59 | ???
|60 | ???
|61 | overheadLights
|62 | ???
|63 | chandelier
|64 | crusher
|65 | verticalLift
|66 | verticalLift
|67 | verticalLift
|68 | theMayor