version control never
-- GBA Shaman King - Master of Spirits 2, TASing script
-- Ram watch, Yoh and enemy information
-- Written by xy2_, 2017
-- Static data: tables
-- Color table
local color= {
opaque= {
[0]=0xFF00FF00, -- Green
0xFFFFFF00, -- Yellow
0xFFFF0000, -- Red
0xFFBA8E7D, -- Brown
0xFF0000FF, -- Blue
0xFF665046, -- Dark brown
0xFFFF007F, -- Purple
0xFF00FFFF, -- Cyan
};
trans= {
[0]=0x7700FF00, -- Green
0x77FFFF00, -- Yellow
0x77FF0000, -- Red
0x77BA8E7D, -- Brown
0x770000FF, -- Blue
0x44665046, -- Dark brown
0x77FF007F, -- Purple
0x7700FFFF, -- Cyan
}
}
-- Text of possible Yoh states; self-explainatory
local stateText= {
[0]= { "Standing","","" } ,
{ "Walking","","" } ,
{ "Ground","sliding","" } ,
{ "Crouching","","" } ,
{ "Crouched","","" } ,
{ "Standing","up","" } ,
{ "Pre-","jumping","" } ,
{ "Jumping","","" } ,
{ "Falling,","initial","" } ,
{ "Falling","","" } ,
{ "Landing","","" } ,
{ "Back","dashing","" } ,
{ "Entering","door","" } ,
{ "Exiting","door","" } ,
{ "Taking","damage","" } ,
{ "Taking","damage,","crouched" } ,
{ "Taking","damage,","air" } ,
{ "Knockback","damage","" } ,
{ "Knockback","upwards","" } ,
{ "Knockback","hitting","ground" } ,
{ "Knockback","fall","" } ,
{ "Knockback","ground","" } ,
{ "Knockback","getting up","" } ,
{ "Electro-","cuted","" } ,
{ "Electro-","cuted","2" } ,
{ "Taking","damage?","" } ,
{ "Taking","damage?","" } ,
{ "1st slash,","wooden,","ground" } ,
{ "1st slash,","light,","ground" } ,
{ "1st slash,","antiquity,","ground" } ,
{ "2nd slash,","wooden,","ground" } ,
{ "2nd slash,","light,","ground" } ,
{ "2nd slash,","antiquity,","ground" } ,
{ "3rd slash,","wooden,","ground" } ,
{ "3rd slash,","light,","ground" } ,
{ "3rd slash,","antiquity,","ground" } ,
{ "1st slash,","wooden,","air" } ,
{ "1st slash,","light,","air" } ,
{ "1st slash,","antiquity,","air" } ,
{ "2nd slash,","wooden,","air" } ,
{ "2nd slash,","light,","air" } ,
{ "2nd slash,","antiquity,","air" } ,
{ "3rd slash,","wooden,","air" } ,
{ "3rd slash,","light,","air" } ,
{ "3rd slash,","antiquity,","air" } ,
{ "Crouch","slash,","wooden" } ,
{ "Crouch","slash,","light" } ,
{ "Crouch","slash,","antiquity" } ,
{ "Halo","Bump,","ground" } ,
{ "Halo","Bump,","air" } ,
{ "Nipopo","Punch", "ground" } ,
{ "Nipopo","Punch", "air" } ,
{ "Daodondo","","" } ,
{ "Gussy", "Kenji", "ground" } ,
{ "Gussy", "Kenji", "air" } ,
{ "Jaguar","Swipe","" } ,
{ "Footballer","","" } ,
{ "Footballer,","sparks","" } ,
{ "Big", "Thumb","" } ,
{ "Big", "Thumb,","smoke" } ,
{ "Big", "Thumb,","Tokageroh" } ,
{ "Celestial","Slash,","ground" } ,
{ "Celestial","Slash,","air" } ,
{ "Celestial","Slash,","blade" } ,
[73]= { "Totem","Attack","" } ,
[292]={ "Leap,","wooden,","start" } ,
[295]={ "Leap,","wooden,","brandish" } ,
[298]={ "Leap,","wooden","" } ,
}
-- Soul info
local soulInfo= {
-- Format: string, active/passive (active=1), soul level (1= lv2, 2=lv3, 3=soul combo), splash number if splash
-- Example: { "Tokageroh",1,0,4 } means the soul name is Tokageroh, it's a normal soul, and it has a splash & it's splash number is 4
-- The splash number can be determined by looking in RAM: there are timers for each soul that has a splash
[0]= { "Empty" , 0 } ,
{ "Halo Bump" , 1 , 0 , 0 } ,
{ "Cel.Slash" , 1 , 1 } ,
{ "Mosuke" , 0 } ,
{ "I.T.Antiq." , 1 , 2 } ,
{ "Tokageroh" , 1 , 0 , 4 } ,
{ "Corey" , 1 } ,
{ "Eliza" , 0 } ,
{ "S.Shield" , 0 } ,
{ "S.Tail" , 0 } ,
{ "S.Wing" , 0 } ,
{ "S.Horn" , 0 } ,
{ "S.Rod" , 0 } ,
{ "T.Attack" , 1 } ,
{ "Mic" , 1 , 0 , 7 } ,
{ "LeeP-Long" , 1 } ,
{ "Bason" , 1 } ,
{ "GT.Impale" , 1 , 1 } ,
{ "GrandTaoD." , 1 } ,
{ "Chloe" , 1 } ,
{ "Michael" , 1 } ,
{ "R.ofLight" , 1 , 3 } ,
{ "Kanta" , 1 } ,
{ "GussyKenji" , 1 } ,
{ "Tamegoroh" , 0 } ,
{ "Shikigami" , 1 } ,
{ "Fk.steiny" , 0 } ,
{ "Ponchi" , 1 } ,
{ "Konchi" , 1 } ,
{ "Ch.-Moryo" , 1 } ,
{ "Shaolin" , 1 } ,
{ "Blk.Raven" , 0 } ,
{ "TaotheGrt" , 1 } ,
{ "Ian" , 0 } ,
{ "Nizba" , 0 } ,
{ "Dreisa" , 0 } ,
{ "Yophia" , 0 } ,
{ "M.Memorial" , 0 , 3 } ,
{ "Badbh" , 0 } ,
{ "Vodianoi" , 0 } ,
{ "Deht" , 0 } ,
{ "Gororo" , 1 } ,
{ "Zenki" , 1 } ,
{ "Kohki" , 1 } ,
{ "Golem" , 1 } ,
{ "Orona" , 0 } ,
{ "PascalAvaf" , 1 } ,
{ "Jaguarman" , 1 , 3 } ,
{ "Yamagami" , 1 } ,
{ "Gundari" , 0 } ,
{ "Raphael" , 0 } ,
{ "Gabriel" , 0 } ,
{ "Uriel" , 0 } ,
{ "Metatoron" , 0 } ,
{ "Sariel" , 0 } ,
{ "Remiel" , 0 } ,
{ "Mash" , 1 } ,
{ "Blaumro" , 1 } ,
{ "F.baller" , 1 } ,
{ "Sh.-Shion" , 1 } ,
{ "Blocks" , 1 } ,
{ "Jen" , 1 } ,
{ "Ashcroft" , 1 } ,
{ "Jack" , 1 } ,
{ "Chuck" , 1 } ,
{ "C. & Joao" , 1 } ,
{ "Antonio" , 1 } ,
{ "Jose" , 1 } ,
{ "Pancho" , 1 } ,
{ "Zapata" , 1 } ,
{ "Miguel" , 1 } ,
{ "Grd.Phant." , 1 } ,
{ "M.scope" , 1 } ,
{ "Mama" , 1 } ,
{ "Cifer" , 1 } ,
{ "S.of Fire" , 0 } ,
{ "Matamune" , 1 } ,
{ "GdHaloBlade" , 1 , 1 } ,
{ "U.C.Charge" , 1 , 3 } ,
{ "Tokageroh" , 1 , 1 } ,
{ "Corey" , 1 , 1 } ,
{ "Eliza" , 1 , 1 } ,
{ "T.Attack" , 1 , 1 } ,
{ "Mic" , 1 , 1 } ,
{ "LeeP-Long" , 1 , 1 } ,
{ "Chloe" , 1 , 1 } ,
{ "S. of All" , 1 } ,
{ "Skunk" , 1 } ,
{ "K.itachi" , 1 } ,
{ "Korogashi" , 1 } ,
{ "Enra-Enra" , 1 } ,
{ "O.F.Tama" , 1 } ,
{ "Jangalian" , 1 } ,
{ "GreatOgre" , 1 } ,
{ "Skelesaur" , 1 } ,
{ "Triglav" , 1 } ,
{ "F. Field" , 1 , 3 } ,
{ "Expl.Kick" , 1 , 3 } ,
{ "FinalBeam" , 1 , 3 } ,
{ "Blizzard" , 1 , 3 } ,
{ "Vik. Ship" , 1 , 3 } ,
{ "Jav. Tear" , 1 , 3 } ,
{ "Hom. Laser" , 1 , 3 } ,
{ "Gledhill" , 1 } ,
}
local rngResults = {}
local pastRNG = {0, 0}
-- SK2 rng re-implementation in Lua
--#############################################################################
local function RngLua(value)
--#############################################################################
local high = (value * 0x41C6) % 0x10000 -- Shoutouts to Scepheo
local low = (value * 0x4E6D) % 0x100000000
return ((low + high * 0x10000) % 0x100000000) + 0x3039
end
-- Displays a table of the next X rng values, based on current RNG
--#############################################################################
local function RngPredict(x,y,number)
--#############################################################################
local RNG = memory.read_u32_le(0x16C0, "IWRAM")
-- Display the number of steps the RNG has advanced, if it advanced
pastRNG[2]= pastRNG[1]
pastRNG[1]= RNG
if pastRNG[2] ~= pastRNG[1] then
for i=1,number do
if RNG == rngResults[i] then
gui.pixelText(x+33,y, i, 0xFFFFFFFF, color.trans[6])
gui.pixelText(x+33,y+i*7, "!", 0xFFFFFFFF, color.trans[2])
end
end
end
gui.pixelText(x,y, string.format("%08X", RNG))
rngResults[1] = RngLua(RNG)
for i=1,number do
rngResults[i+1] = RngLua(rngResults[i])
gui.pixelText(x,y+i*7, string.format("%08X", rngResults[i]))
end
end
-- General RAM watch, and value display on screen
--#############################################################################
local function DisplayHud(x,y)
--#############################################################################
-- Furyoku
local furyoku = memory.read_u16_le(0x64AA, "IWRAM")
gui.pixelText (x+0,y+0, string.format("%4d", furyoku), 0xFFFFFFFF, color.trans[4])
-- Furyoku refill
local frefill = memory.read_u16_le(0x22CA, "IWRAM")
if refill == 0 then
gui.pixelText(x+0,y+7, string.format("%4d", frefill), 0xFFFFFFFF, color.trans[0])
else
gui.pixelText(x+0,y+7, string.format("%4d", frefill), 0xFFFFFFFF, color.trans[2])
end
-- In-game time (current segment)
local igtframeseg = memory.read_u32_le(0x36DD, "IWRAM")
gui.pixelText(x+180,y+0, string.format("%8d", igtframeseg), color.opaque[6])
-- In-game time (current area)
local igtframearea= memory.read_u32_le(0x0498, "IWRAM")
gui.pixelText(x+180,y+7, string.format("%8d", igtframearea), color.opaque[7])
-- In-game time (global)
local igtframe = memory.read_u32_le(0x62AC, "IWRAM")
gui.pixelText(x+180,y+14, string.format("%8d", igtframe), color.opaque[1])
-- Global timer
local globalframe = memory.read_u32_le(0x62A8, "IWRAM")
gui.pixelText(x+180,y+21, string.format("%8d", globalframe))
-- Speed
local xspeed = memory.read_s32_le(0x1A78, "IWRAM")
local yspeed = memory.read_s32_le(0x1A7C, "IWRAM")
gui.pixelText(x+215,y, string.format("%6d", xspeed))
gui.pixelText(x+215,y+7, string.format("%6d", yspeed))
-- Ground/air? Displays G on ground, A on air
local groair = memory.read_u8(0x1A40, "IWRAM")
if groair == 1 then
gui.pixelText(x+215,y+14, "G", 0xFFFFFFFF, color.trans[4])
else
gui.pixelText(x+215,y+14, "A", 0xFFFFFFFF, color.trans[1])
end
-- Buffered down input timer to backdash
local downbuffer = memory.read_u8(0x16E3, "IWRAM")
if downbuffer >= 1 then
gui.pixelText(x+219,y+14, "V" .. string.format("%4d", downbuffer))
else
gui.pixelText(x+219,y+14, string.format("%5d", downbuffer))
end
-- X and Y position
local xposition = memory.read_s32_le(0x1A70, "IWRAM")
local yposition = memory.read_s32_le(0x1A74, "IWRAM")
gui.pixelText(x+203,y+35, string.format("%9d", xposition))
gui.pixelText(x+203,y+42, string.format("%9d", yposition))
-- Relative position to camera (>= 120 » Yoh invincible)
local xrelative = math.abs(memory.read_s16_le(0x1A80, "IWRAM")-120)
if xrelative >= 120 then
gui.pixelText(x+223,y+49, "!" ..string.format("%3d", xrelative), 0xFFFFFFFF, color.trans[6])
elseif xrelative >= 18 then
gui.pixelText(x+223,y+49, "*" .. string.format("%3d", xrelative), color.opaque[6])
elseif xrelative >= 1 then
gui.pixelText(x+223,y+49, "+" .. string.format("%3d", xrelative), color.opaque[7])
else
gui.pixelText(x+223,y+49, string.format("%4d", xrelative))
end
end
-- A visual separator for the sidebar
--#############################################################################
local function Separator(x,y, length)
--#############################################################################
gui.drawLine(x+14,y, x+length,y)
for i=0,6 do
gui.drawPixel(x+i*2,y)
end
end
-- General movie information
--#############################################################################
local function MovieInfo(x,y)
--#############################################################################
local frame= emu.framecount()
if emu.islagged() == true then
gui.pixelText(x,y, frame, 0xFFFFFFFF, color.opaque[2])
else
gui.pixelText(x,y, frame)
end
local lagcount= emu.lagcount()
gui.pixelText(x,y+7, lagcount, color.opaque[2])
end
-- Displays information about Yoh's animations on the sidebar
--#############################################################################
local function GetYohState(x,y)
--#############################################################################
local state = memory.read_u16_le(0x1A08, "IWRAM")
local duration = memory.read_u8( 0x1A05, "IWRAM")
local statetimer = memory.read_u8( 0x1A10, "IWRAM")
local delay = memory.read_u16_le(0x1A59, "IWRAM")
local t = stateText[state]
if t then
gui.pixelText(x,y, state .. ":" .. statetimer)
gui.pixelText(x,y+ 7,t[1],color.opaque[1])
gui.pixelText(x,y+14,t[2],color.opaque[1])
gui.pixelText(x,y+21,t[3],color.opaque[1])
gui.pixelText(x,y+28, duration .. ":" .. delay, 0xFFFFFFFF, color.trans[2])
else
gui.pixelText(x,y, state .. ":" .. statetimer)
gui.pixelText(x,y+ 7,"NULL!!!",0xFFC0C0C0)
gui.pixelText(x,y+28, duration .. ":" .. delay, 0xFFFFFFFF, color.trans[2])
end
end
-- Information about our inventory - mediums
--#############################################################################
local function MediumInfo(x,y)
--#############################################################################
-- local leafcount = memory.read_u8(0x2358, "IWRAM")
-- local rockcount = memory.read_u8(0x2359, "IWRAM")
-- local dollcount = memory.read_u8(0x235A, "IWRAM")
-- TODO: find proper values
-- gui.pixelText(x,y, leafcount, color.opaque[0])
-- gui.pixelText(x+11,y, rockcount, color.opaque[3])
-- gui.pixelText(x+22,y, dollcount, color.opaque[5])
end
-- Information about our inventory - souls
--#############################################################################
local function SoulInfo(x,y)
--#############################################################################
-- Current deck
local deck= memory.read_u8(0x658B, "IWRAM")
for i=0,4 do -- For each of the slots in the deck
local soul= memory.read_u8(0x6557 + 0x1*i + 0x5*deck, "IWRAM")
local t= soulInfo[soul]
if t then -- Just in case
if soul == 0 then -- Is there a soul equipped?
gui.pixelText(x,y+i*7, t[1], color.opaque[5])
elseif t[3] == 3 then -- Is it a soul combo?
gui.pixelText(x,y+i*7, t[1], color.opaque[1])
elseif t[3] == 1 then -- Is it a lv2 soul?
gui.pixelText(x,y+i*7, t[1], color.opaque[7])
elseif t[3] == 2 then -- Is it a lv3 soul?
gui.pixelText(x,y+i*7, t[1], color.opaque[2])
elseif t[2] == 1 then -- Is it an active soul?
gui.pixelText(x,y+i*7, t[1], color.opaque[0])
else -- It's a passive soul
gui.pixelText(x,y+i*7, t[1])
end
if t[4] then -- Does this soul have a splash?
-- Base splash adress
local splasht = memory.read_u16_le(0x64E0 + 0x2*t[4], "IWRAM")
if splasht >= 1 then
gui.pixelText(x-18,y, string.format("%4d", splasht), color.opaque[6])
else
gui.pixelText(x-6,y, splasht, 0xFFFFFFFF, color.trans[6])
end
end
end
end
end
-- Draws hitboxes
-- Object size: C8 (200)
--#############################################################################
local function DrawHitbox(x,y, offset, id)
--#############################################################################
local cameraX = memory.read_s24_le(0x6359, "IWRAM")
local cameraY = memory.read_s24_le(0x635D, "IWRAM")
-- Figure out appropriate pixel values
local X1 = memory.read_s24_le(0x1A89 + offset, "IWRAM")
local X2 = memory.read_s24_le(0x1A8D + offset, "IWRAM")
local Y1 = memory.read_s24_le(0x1A91 + offset, "IWRAM")
local Y2 = memory.read_s24_le(0x1A95 + offset, "IWRAM")
-- Hitbox
local pixelX1, pixelX2 = X1-cameraX+120, X2-cameraX+120
local pixelY1, pixelY2 = cameraY-Y1+70, cameraY-Y2+70
-- Invicibility
local invicibility = memory.read_u8(0x1A5D + offset, "IWRAM")
-- Add invicibility counter if invicible
if invicibility >= 1 then
gui.drawBox (x+pixelX1, y+pixelY1, x+pixelX2, y+pixelY2, color.opaque[1], color.trans[5])
gui.pixelText (x+pixelX1, y+pixelY1, invicibility, 0xFFFFFFFF, color.trans[1])
else
gui.drawBox (x+pixelX1, y+pixelY1, x+pixelX2, y+pixelY2, color.opaque[5], color.trans[5])
end
-- Poison
if id == 1 then
local poison = memory.read_u16_le(0x1A5E + offset, "IWRAM")
if poison >= 1 then
-- local poisontimer = memory.read_u16_le(0x1A59, "IWRAM")
gui.pixelText (x+pixelX1, y+pixelY1+7, poison, 0xFFFFFFFF, color.trans[0])
-- gui.pixelText (x+pixelX1, y+pixelY1+14, poisontimer, color.opaque[0])
end
end
local relposX, relposY = memory.read_s16_le(0x1A80, "IWRAM"), memory.read_s16_le(0x1A82, "IWRAM")
-- Slot number
gui.pixelText(x+pixelX1 - 9, y+pixelY2 - 7, string.format("%02d", id), 0xFFFFFFFF, color.trans[7])
-- Facing direction
local fdirection = memory.read_u8(0x1A65 + offset, "IWRAM")
if fdirection == 1 then
gui.pixelText (x+pixelX1, y+pixelY2 - 7, "<")
elseif fdirection == 0 then
gui.pixelText (x+pixelX1, y+pixelY2 - 7, ">")
else
gui.pixelText (x+pixelX1, y+pixelY2 - 7, "?")
end
-- Raw damage output
local rawdmg = memory.read_u8(0x1A62 + offset, "IWRAM")
gui.pixelText (x+pixelX1 + 8, y+pixelY2 - 7, rawdmg, 0xFFFFFFFF, color.trans[2])
-- Health
local health= memory.read_u16_le(0x1A60 + offset, "IWRAM")
gui.pixelText(x+pixelX1 + 10, y+pixelY1, health, color.opaque[1])
-- State, animation and timer information
if id ~= 1 then
local state = memory.read_u16_le(0x1A08 + offset, "IWRAM")
local duration = memory.read_u8( 0x1A05 + offset, "IWRAM")
local statetimer = memory.read_u8( 0x1A10 + offset, "IWRAM")
local delay = memory.read_u16_le(0x1A59 + offset, "IWRAM")
gui.pixelText (x+pixelX1 + 24, y+pixelY2, state .. ":" .. statetimer)
gui.pixelText (x+pixelX1 + 24, y+pixelY2 - 7, duration .. ":" .. delay, 0xFFFFFFFF, color.trans[2])
end
end
client.SetGameExtraPadding(0,0,40,0)
--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
while true do
--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
MovieInfo(241,0)
RngPredict(0,20,15)
Separator(241,15,38)
GetYohState(241,17)
Separator(241,54,38)
-- InventoryInfo(241,56)
SoulInfo(241,56)
DisplayHud(0,0)
for i=1,2 do
-- if memory.read_u16_le(0x1A60 + i*200, "IWRAM") ~= 0 then
DrawHitbox(0,8, (i-1)*200, i)
-- end
end
emu.frameadvance()
end