Back to Page
Revision 15 (current)
Edited by feos on 12/15/2015 6:36 PM
%%TAB Memory map
RAM
$ffa172 - camera x
$ffa174 - camera y
$ffa1d4 - RNG
$fffc2a - config pointer. loads events for puppy love
$fffc9a - reserved config pointer
$fffc7b - puppy toss position. 0 causes 3 bounces, 2 causes 1 bounce.
$fffc87 - puppy counter
$fffc88+offset - speeds for puppies, offset = puppy counter
ROM
$25d482 - puppy speed table
$275fea-$277b79 - approximate limits of puppy config table
%%TAB Lua
%%SRC_EMBED lua
gui.register(function()
camx = memory.readword(0xffa172)
camy = memory.readword(0xffa174)
Objects()
Bounce()
end)
function Objects()
local base0 = 0xffa2ea
for i=0,0x23 do
local base = base0+i*0x6e
local id = memory.readbyte(base)
if id>0 and id~=0x82 then
local hp = memory.readbytesigned(base+1)
local x = memory.readword(base+2)-4096-camx
local y = memory.readword(base+4)-4096-camy
--local x = Clamp(x,0,310)
--local y = Clamp(y,0,214)
local dx = memory.readwordsigned(base+0x18)
local dy = memory.readwordsigned(base+0x1a)
local hitboxbase = memory.readlong(base+0x14)
local x1 = memory.readbyte(hitboxbase+2)
local x2 = memory.readbyte(hitboxbase+4)
local y1 = memory.readbyte(hitboxbase+3)
local y2 = memory.readbyte(hitboxbase+5)
--PostRngRoll(base,x,y)
if x1>0 and x2>0 and y1>0 and y2>0 then
local of = 124
x1 = x1+x-of
x2 = x2+x-of
y1 = y1+y-of
y2 = y2+y-of
gui.box(x1,y1,x2,y2,0,"green")
end
if hp>0 then
gui.text(x,y-2,hp,"green")
end
end
end
end
function Bounce()
if memory.readbyte(0xffa515)==0x60
then offset = 8
else offset = 0 end
local counter = memory.readbyte(0xfffc87)
local a0 = 0xfffc88
local d0 = SHIFT(memory.readbyte(a0+counter),-5)+offset
local a3 = 0x25d482
local vel = memory.readword(a3+d0)
local bounce = 0
if vel == 0x200 then bounce = 3
elseif vel == 0x3e0 then bounce = 1
else bounce = 2
end
gui.text(0,0,string.format("next bounce: %d",bounce))
end
function Dump()
for p=0x275fea,0x277b79 do
local a = memory.readbyte(p)
if a==0x62 then
table.insert(bombs,string.format("%X",p))
elseif a==8 then
table.insert(goback,string.format("%X",p))
elseif a==3 then
table.insert(goforth,string.format("%X",p))
end
end
print("bombs:")
print(bombs)
print("")
print("goback:")
print(goback)
print("")
print("goforth:")
print(goforth)
print("")
end
%%END_EMBED
%%TAB Dumps
Config table addresses that contain given objects.%%%
Generated by function Dump().
__Bombs__
276037, 276065, 2760B9, 276109, 276142, 276164, 276168, 27616C, 276170, 276174, 276178, 27617C, 276182, 2765DE, 276637, 276679, 2766F9, 276783, 276F85, 276FDD, 277040, 277086, 2770CA, 27715F
__GoBack__
27605E, 276060, 2760A8, 2760AA, 2760AC, 2760EB, 2760ED, 2760EF, 27612F, 276131, 276133, 276135, 2765A1, 2765A3, 2765B4, 2765F9, 2765FB, 2765FD, 276616, 276618, 276652, 276654, 276656, 276658, 27669A, 27669C, 27669E, 2766D3, 276720, 276722, 276724, 276726, 276799, 2767BB, 2767DD, 2767ED, 2767FF, 276821, 276F1B, 276F59, 276F5B, 276F9E, 276FA0, 276FA2, 276FA4, 277005, 277032, 277034, 277061, 277063, 277065, 27707A, 2770A9, 2770AB, 2770AD, 2770BE, 2770D9, 2770FB, 27711D, 27713F, 277161
__GoForth__
2760BE, 2761B3, 2761D9, 2761E3, 276203, 276211, 276266, 276275, 27629D, 2762AB, 2762BB, 2762DF, 276313, 27633D, 276363, 276394, 2763A6, 276402, 276416, 27644A, 27646C, 276494, 2764A3, 2764DB, 2764E9, 276545, 276559, 27658D, 27667E, 27684F, 27685E, 27686C, 2768A1, 2768B9, 276903, 276940, 276956, 276980, 2769B6, 2769C8, 2769E2, 276A0C, 276A4A, 276A83, 276A98, 276AA6, 276AD7, 276B07, 276B39, 276B6D, 276B9F, 276BD8, 276BED, 276C01, 276C39, 276C51, 276C83, 276CB7, 276CFC, 276D39, 276D4E, 276D68, 276D98, 276DB4, 276DE6, 276E17, 276E59, 276E94, 276ECB, 277045, 2771C0, 27720C, 277238, 277281, 2772C0, 277314, 27735D, 27736B, 2773B8, 277410, 27743C, 277485, 2774BE, 27750E, 277556, 277566, 2775B3, 277613, 27763F, 277688, 2776C1, 277711, 27775A, 27776E, 2777BB, 27781B, 277847, 277890, 2778C9, 277919, 277961, 277973, 2779C0, 277A20, 277A4C, 277A95, 277ACE, 277B1E, 277B69
%%TAB_END
! Puppy Love spawns
Actions are read consecutively from config tables, 30-32 spawn objects whose toss position is decided by the second digit, and type is read from the next byte.
Sometimes config pointer will jump back or forth, using reserved config pointer, and offset figured out from RNG. By manipulating the RNG you must be able to affect end pointer values.
64 - force Psyclow up
63 - force him down
30-32 - do the spawn
62 - bomb
68 - globe
70 - puppy
03 - jump forth through config table
08 - jump back through config table
7a - end of batch, wait how player handles the objects
2b,2d,0 - just skip
! Randomness
New RNG value only depends on the old one, so the only way to manipulate it is to force more or less of its calls.
It is called twice per object bounce (to figure out the sound and the flips), once or twice in a while by Peter (to do animation), a ton of times per Psycrow explosion feathers (13 times per frame), a bunch of times by letters of the new round.
So by dropping different puppies at different times you can skip some of these, resulting in RNG difference. Note that Psycrow freezes if scrolled a bit left, while Peter never stops poking the RNG, so it's also possible to delay puppy tosses and affect RNG differently.
26:C2CE 48 E7 MOVEM.L {d0-a7}[[70 00]],-(SP)
26:C2D2 52 47 ADDQ.W #1,D7
26:C2D4 22 39 MOVE.L ($00FFA1D4),D1
26:C2DA 24 01 MOVE.L D1,D2
26:C2DC 5E 82 ADDQ.L #7,D2
26:C2DE D2 81 ADD.L D1,D1
26:C2E0 D2 81 ADD.L D1,D1
26:C2E2 26 01 MOVE.L D1,D3
26:C2E4 D2 81 ADD.L D1,D1
26:C2E6 D2 82 ADD.L D2,D1
26:C2E8 D2 83 ADD.L D3,D1
26:C2EA 23 C1 MOVE.L D1,($00FFA1D4)
26:C2F0 24 01 MOVE.L D1,D2
26:C2F2 48 42 SWAP.W D2
26:C2F4 B5 41 EOR.W D2,D1
26:C2F6 CE C1 MULU.W D1,D7
26:C2F8 48 47 SWAP.W D7
26:C2FA 4C DF MOVEM.L (SP)+,{a7-d0}[[00 0e]]
26:C2FE 4E 75 RTS