TASVideos

Tool-assisted game movies
When human skills are just not enough

Game Resources / NES / Ninja Gaiden

Address Description
0060
0061
Score, little endian. Game can only display 4 digits; "00" on the right of score display is static.
0062 Timer fractions. Cycles 60-0, normally decrementing once per frame during game play.
0063 Level Timer. Decrements when $0062 = 60.
0064 Ninpo (Points used for special attacks)
0065 Ryu's Hit Points
0066 Enemy HP Display (seperate from actual enemy HP, stored at $0490-0497)
0067-006C Level Scrolling
006D
006E
Current Stage
006F Related to stage transitions
0075 TODO: explain this
0076 Ryu's Lives
0080-0083 Ryu's Animations
0084 Ryu's facing and state (standing/jumping/clinging to wall/etc.)
0085 Ryu's x position, fractions
0086 Ryu's x position, pixels
0087 Ryu's y speed, fractions
0088 hypothesized unused y position fractions
0089 Ryu's y speed, pixels
008A Ryu's y position
0092 00 until Ryu uses his sword, after which it is 10(hex), meaning the first sword attack after the game starts is always ineffective
0095 Invulnerability timer, runs 60-0 starting when Ryu takes damage.
0096-009F "level objects"
00A2 Screen position, fractions
00A3 Screen position, pixels
00AC Ryu's x speed, fractions
00AD Ryu's x speed, pixels
00B5 RNG
00BF RNG
00C9 Current Special Weapon.
$00=None
$80=Art of the Fire Wheel
$81=Throwing Star
$82=Windmill Star
$84=Invincible Fire Wheel
$85=Jump and Slash
02xx Sprite Data
03xx Background Data
0400-0407 Enemy ID
0408-040F Frames untils enemy action (changing direction, throwing/shooting stuff)
0438-043F Enemy movement
0440-0447 Enemy facing (left/right)
0448-044F Enemy x speed, fractions
0450-0457 Enemy x speed, pixels
0458-045F Enemy x position, fractions
0460-0467 Enemy x position, pixels
0468-046F Enemy y speed, fractions
0470-0477 Enemy y speed, pixels
0478-047F Enemy y position, fractions
0480-0487 Enemy y position, pixels
0490-0497 Enemy hit points (only non-zero for bosses and those grey disc-tossers)
04B8-04BA Boss Explosion Animations
04BB Spec. Weapon C x position
04BC Spec. Weapon B x position
04BD Spec. Weapon A x position
04BE Spec. Weapon C y position
04BF Spec. Weapon B y position
04C0 Spec. Weapon A y position
04C1-04C6 Spec. Weapon Speed (used differently for each weapon)
04C7 Spec. Weapon time-out, fractions (hourglass, invincible fire wheel)
04C8 Spec. Weapon time-out (hourglass, invincible fire wheel)
04D0-04D7 Lantern(or bug or bird)/Power-Up x position, fractions
04D8-04DF Lantern/PU x position, pixels
04E0-04E7 Lantern/PU y position, pixels (no fractions for this)
04E8-04EF Frames until power-up vanishes
05xx Unused
06xx Sound

--Displays most of the RAM addresses relevant to making a TAS over or around the game's info display.
local function NGRAMview()
  yspd = memory.readbytesigned(0x89) + (memory.readbyte(0x87)/256)
  xpos = memory.readbyte(0x86) + (memory.readbyte(0x85)/256)
  ypos = memory.readbyte(0x8A)
  scrnpos = memory.readbyte(0xA3); scrnsub = memory.readbyte(0xA2)
  timerf = memory.readbyte(0x62); timer = memory.readbyte(0x63)
  rnga = memory.readbyte(0xB5); rngb = memory.readbyte(0xBF)
  ninpo = memory.readbyte(0x64)
  bosshp = memory.readbyte(0x497); abosshp = memory.readbyte(0x496)
  inv = memory.readbyte(0x95)
  gui.text(25,9,string.format("Y-Spd:%6.3f",yspd))
  gui.text(25,17,string.format("Position: %5.1f, %3d",scrnpos+xpos+(scrnsub/256),ypos))
  gui.text(129,17,string.format("[%05.1f+%02X,%02X]",xpos,scrnpos,scrnsub))
  gui.text(73,33,string.format("%3d:%02d",timer,timerf))
  if bosshp > 0 then
   if bosshp > 16 then gui.text(177,41,string.format("%02d",abosshp))
    else gui.text(177,41,string.format("%02d",bosshp)); end; end
  if inv > 0 then
   gui.text(229,33,string.format("%02d",inv));end
  gui.text(208,17,string.format("B5:%3d ",rnga))
  gui.text(208,25,string.format("BF:%3d ",rngb))
  gui.text(81,41,string.format("[%02d]",ninpo))
end
gui.register(NGRAMview)
emu.frameadvance()
--Accurately tracks the game's inaccurate conception of time, displaying how many "seconds" elapse over the course of a game session.
--Obviously, it is not smart enough to account for save states, but here it is in case somebody finds this interesting.
local minutes=0;seconds=0;frames=0
while true do
 prevt = memory.readbyte(0x62)
 emu.frameadvance()
 currt = memory.readbyte(0x62)
 if prevt ~= currt then
  frames=frames+1;end
 if frames == 61 then
  seconds=seconds+1;frames=0;end
 if seconds == 60 then
  minutes=minutes+1;seconds=0;end
 gui.text(199,9,string.format("%02d:%02d:%02d",minutes,seconds,frames))
end

Movement and Attacking

Horizontal Movement

Ryu has only three possible horizontal speeds: 1.5, 1, and 0.5 pixels per frame.
  • 1.5 p/f: when running either direction or pressing forward while airborne.
  • 0.5 p/f: when pressing back while airborne.
  • 1 p/f: when bouncing after taking damage from an enemy, until contact with a wall or platform. (the player has no control over Ryu's movement during this)

Use of ↔, ←+↕ or ← or →+B or A (←/→+B/A only applicable when airborne, and if used for more than one from B and A must alternate every frame) serves to prevent a new speed value from being written, thereby preserving speed when transitioning from one type of movement to another. This is primarily useful for full-speed backwards air movement, but can also be used for more precise adjustments to Ryu's position. Example: ↔ on the frame control is regained after taking damage, then releasing ← and continuing on holding → puts Ryu a half-pixel behind where he'd be if only → had been held, which can actually be favorable in some instances. Care must also be taken to avoid this happening where it would be undesirable, such as pressing ← for one frame mid-jump to trigger an enemy spawn, then pressing →+B on the following frame. This would leave Ryu one pixel behind where he would have been if the attack had come one frame later, after resuming normal forward movement.

Sticky Floors

Landing on certain tiles (mostly found at platform edges, but not always or exclusively) will stop Ryu's forward movement for one frame. Usually this is avoidable, but in cases where it is not, and it is possible to jump on the following frame, it provides an opportunity to execute a special attack without losing time.

Vertical Movement

Ryu move upwards in four ways: jumping from a floor or platform, jumping from a wall, being hit by an enemy, or climbing ladders. Each of these has its own rules, detailed below.
  • standing jump: rises 48 pixels, peaks 19-24 frames after jumping.
  pattern: -4,-4,-4,-4,-4,-3,-3,-3,-3,-3,-2,-2,-2,-2,-1,-1,-1,-1,0,0,0,0,0,0,1...
  • wall jump: rises 15 pixels, peaks 10-14 frames after jumping.
  pattern: -2,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,0,1...
  • damage boost: rises 29 pixels, peaks 14-19 frames after hit.
  pattern: -3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-1,-1,-1,-1,0,0,0,0,0,0,1...
  • climbing a ladder moves Ryu 1 pixel per frame.

You might be wondering where the fractions are. Is it really that simple? Well, sort of. Ninja Gaiden does track vertical speed in units ($89) and fractions ($87) but, apparently, always rounds that up when adding to the position ($8A). $88 is never read from, but 0 is written to it during screen transitions at the same time the adjacent values are set, so it seems possible that it was originally intended to be y-position fractions, but for whatever reason it was left unused.

Wall-Climbing

Attacking

Randomness

RNG

From power on, $BF increments once every frame, from 0 to 255. It is used to determine the delay (in frames) between tosses and the speed of the tossed objects for the four different object-tossing enemies (actually all the same enemy, just with variant sprites). A logical shift right is performed on the value of $BF for the toss-delay (so, 128 possible values). $BF is directly copied to the x and y sub-pixel speeds and an AND #$01 sets the x speed. The y speed is simply set to -3. $BF is also used similarly for the final boss and the 'shrimp' it spews, but with two shift-rights for the spew-timer and a few more steps for the x speed to get possible values between -3 and 3.

Inherited Sub-Pixels

New enemy sub-pixel position gets added to the subpixel of the previous enemy in this slot that he had while disappearing. If the previous enemy disappeared at 0x07.00, the new one will have position 0xEF.80 (previous 0x08.80 => new 0xF0.00).

Level Timer

Glitches with no known application

Taking damage at the same time a boss is killed

Vertical screen-wrapping

That happens when taking a hit from a vertical position of 4, 5, 14, 15, 16, 25, 26, 35, 36, 45, 46, 55, 56, 65, 66, 75, 84, 93, 102, or 111 or jumping from a wall with a vertical position of 73, 82, or 91, because there is no cap on falling speed and because the game only checks if Ryu is in the eight pixel death zone at the bottom of the screen, but doesn't care if he passes it, so falling from the right position will just make him wrap around to the top of the screen.

Making Enemies Fall from Platforms

that one thing where you pass through an enemy or grab a power-up and graphics glitch out for a frame

TODO: fill in all the gaps


See also



Combined RSS Feed
GameResources/NES/NinjaGaiden last edited by feos on 2013-01-20 09:23:51
Page info and history | Latest diff | List referrers | View Source