From 95d2e2b4e793899100951303a6fd9c1c9640c5b5 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 29 Mar 2009 13:22:34 +0000 Subject: [PATCH] Added some of Miau's Lua scripts --- output/luaScripts/Gradius-BulletHell.lua | 439 +++++++++++++ output/luaScripts/MegamanII-LaserEyes.lua | 730 ++++++++++++++++++++++ output/luaScripts/ZapperFun.lua | 72 +++ output/luaScripts/m_utils.lua | 233 +++++++ 4 files changed, 1474 insertions(+) create mode 100644 output/luaScripts/Gradius-BulletHell.lua create mode 100644 output/luaScripts/MegamanII-LaserEyes.lua create mode 100644 output/luaScripts/ZapperFun.lua create mode 100644 output/luaScripts/m_utils.lua diff --git a/output/luaScripts/Gradius-BulletHell.lua b/output/luaScripts/Gradius-BulletHell.lua new file mode 100644 index 00000000..29fe3a85 --- /dev/null +++ b/output/luaScripts/Gradius-BulletHell.lua @@ -0,0 +1,439 @@ +SCRIPT_TITLE = "Gradius - Bullet Hell" +SCRIPT_VERSION = "1.0" + +require "m_utils" +m_require("m_utils",0) + +--[[ +Gradius - Bullet Hell +version 1.0 by miau + +Visit http://morphcat.de/lua/ for the most recent version and other scripts. + + +Controls + Press select to fire a bomb that will destroy all enemy bullets and grant you + invincibility for a short period of time. + +Supported roms + Gradius (J), Gradius (U), Gradius (E) + +Known bugs + - dying from blue bullets doesn't trigger the death sound effect +-]] + +--configurable vars +local BOMBS_PER_LIFE = 5 +local HITBOX = {-2, 4, 9, 9} --vic viper's hit box for collision detection with blue bullets +-------------------------------------------------------------------------------------------- + + + +local MAX_EXSPR = 64 +local timer = 0 +local spr = {} +local exspr = {} +local exsprdata = {} +local deathtimer = 0 +local bombtimer = 0 +local paused = 0 +local bombs = BOMBS_PER_LIFE +local bulletimg = "" + + +function makebinstr(t) + local str = "" + for i,v in ipairs(t) do + str = str..string.char(v) + end + return str +end + +function initialize() + --Transparency doesn't seem to work for gd images, bummer! + bulletimg = makebinstr( { + 0xff, 0xfe, 0, 0x6, 0, 0x6, 0x1, 0xff, + 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x2, 0x33, 0x6e, 0, + 0x2, 0x33, 0x6e, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x2, 0x33, 0x6e, 0, 0x4d, 0xb6, 0xff, 0, + 0xdb, 0xff, 0xfc, 0, 0x2, 0x33, 0x6e, 0, + 0, 0, 0, 0, 0x2, 0x33, 0x6e, 0, + 0x4d, 0xb6, 0xff, 0, 0x4d, 0xb6, 0xff, 0, + 0xdb, 0xff, 0xfc, 0, 0xdb, 0xff, 0xfc, 0, + 0x2, 0x33, 0x6e, 0, 0x2, 0x33, 0x6e, 0, + 0xdb, 0xff, 0xfc, 0, 0xdb, 0xff, 0xfc, 0, + 0x4d, 0xb6, 0xff, 0, 0x4d, 0xb6, 0xff, 0, + 0x2, 0x33, 0x6e, 0, 0, 0, 0, 0, + 0x2, 0x33, 0x6e, 0, 0xdb, 0xff, 0xfc, 0, + 0x4d, 0xb6, 0xff, 0, 0x2, 0x33, 0x6e, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x2, 0x33, 0x6e, 0, + 0x2, 0x33, 0x6e, 0, 0, 0, 0, 0, + 0, 0, 0 } ) + + for i=0,31 do + spr[i] = { + status=0, + id=0, + x=0, + y=0, + timer=-1, + } + end +end + + +function createexsprite(s) + for i=0,MAX_EXSPR-1 do + if(exspr[i]==nil) then + exspr[i]=s + if(exspr[i].id==nil) then + exspr[i].id=0 + end + if(exspr[i].x==nil) then + exspr[i].x=0 + end + if(exspr[i].y==nil) then + exspr[i].y=0 + end + if(exspr[i].vx==nil) then + exspr[i].vx=0 + end + if(exspr[i].vy==nil) then + exspr[i].vy=0 + end + if(exspr[i].timer==nil) then + exspr[i].timer=0 + end + if(exspr[i].ai==nil) then + exspr[i].ai="" + end + return exspr[i] + end + end + return nil +end + +function destroyallexsprites() + exspr = {} +end + +function destroyexsprite(i) + exspr[i] = nil +end + +function destroysprite(i) + memory.writebyte(0x100+i,0x00) + memory.writebyte(0x120+i,0x00) + memory.writebyte(0x300+i,0x00) +end + + +function drawexsprite(id,x,y) + gui.gdoverlay(x, y, bulletimg) +end + + +function getvicdistance(x,y) + return getdistance(vic.x+4,vic.y+8,x,y) +end + +function doexspriteai(s) + if(s.ai=="Stray") then + if(s.timer==0) then + s.vx = -3 + s.vy = AND(timer,0x0F) / 8 - 1 + end + elseif(s.ai=="AimOnce") then + if(s.timer==0) then + s.vx,s.vy = get_vdir(s,vic) + s.vx = s.vx * 2 + s.vy = s.vy * 2 + --s.vy = AND(timer,0x0F) / 8 - 1 + end + elseif(s.ai=="AimDelayed") then + if(s.timer>=30 and s.timer<=33) then + local x,y = get_vdir(s,vic) + s.vx = (x+s.vx) + s.vy = (y+s.vy) + end + elseif(s.ai=="AimRight") then + if(s.timer==0) then + s.vx,s.vy = get_vdir(s,vic) + s.vx = s.vx * 2.5 + s.vy = s.vy * 1.5 + end + elseif(s.ai=="AimLeft") then + if(s.timer==0) then + s.vx,s.vy = get_vdir(s,vic) + s.vx = s.vx * 1.5 + s.vy = s.vy * 2.5 + end + elseif(s.ai=="BossPattern1") then + if(s.timer==0) then + s.vx = math.random(-100,0)/50 + s.vy = math.random(-100,0)/70 + elseif(s.timer>=30 and s.timer <=35) then + s.vx=s.vx/1.1 + s.vy=s.vy/1.1 + elseif(s.timer==70) then + local x,y = get_vdir(s,vic) + s.vx = x*3 + s.vy = y*3 + end + elseif(s.ai=="LimitedLifeSpan") then + if(s.timer>120) then + s.x=999 --results in death + end + end + + if(s.timer>600) then --delete extended sprites after 10 seconds in case one gets stuck on screen + s.x=999 + end +end + +function doboss1ai(s) + if(s.timer>80 and s.timer<320 and AND(s.timer,63)==0) then + createexsprite({x=s.x,y=s.y,ai="BossPattern1"}) + createexsprite({x=s.x,y=s.y,ai="BossPattern1"}) + createexsprite({x=s.x,y=s.y,ai="BossPattern1"}) + createexsprite({x=s.x,y=s.y,ai="BossPattern1"}) + createexsprite({x=s.x,y=s.y,ai="BossPattern1"}) + createexsprite({x=s.x,y=s.y,ai="BossPattern1"}) + createexsprite({x=s.x,y=s.y,ai="BossPattern1"}) + end + if(s.timer>320 and s.timer<520) then --pattern2 a + if(math.mod(s.timer,27)<=9 and AND(s.timer,3)==3) then + createexsprite({x=s.x,y=s.y,vx=-0.2,ai="AimDelayed"}) + end + end + if(s.timer>320 and s.timer<520) then --pattern2 b + if(AND(s.timer,63)==0) then + createexsprite({x=s.x,y=s.y,vx=-0.7,vy=-1.6}) + createexsprite({x=s.x,y=s.y,vx=-1.1,vy=-0.8}) + createexsprite({x=s.x,y=s.y,vx=-1.2,vy=-0}) + createexsprite({x=s.x,y=s.y,vx=-1.1,vy=0.8}) + createexsprite({x=s.x,y=s.y,vx=-0.7,vy=1.6}) + end + elseif(s.timer>520) then + s.timer = 60 + end +end + + +function dospriteai(s) + if(s.id==0x85) then --Fan + if(s.timer==30) then + createexsprite({x=s.x,y=s.y,ai="Stray"}) + end + elseif(s.id==0x86) then --Jumper + if(AND(s.timer,127)==40) then + createexsprite({x=s.x,y=s.y,vx=-1.5,vy=-0.5}) + createexsprite({x=s.x,y=s.y,vx=-1,vy=-1.1}) + createexsprite({x=s.x,y=s.y,vx=0,vy=-1.4}) + createexsprite({x=s.x,y=s.y,vx=1,vy=-1.1}) + createexsprite({x=s.x,y=s.y,vx=1.5,vy=-0.5}) + end + elseif(s.id==0x88) then --Rugul + if(AND(s.timer,63)==30) then + createexsprite({x=s.x,y=s.y,ai="Stray"}) + end + elseif(s.id==0x84 or s.id==0x9C) then --Fose, Uska(?) + if(AND(s.timer,63)==30) then + createexsprite({x=s.x,y=s.y,vx=0,vy=-2}) + elseif(AND(s.timer,63)==60) then + createexsprite({x=s.x,y=s.y,vx=0,vy=2}) + end + elseif(s.id==0x89 or s.id==0x8C) then --Rush + if(AND(timer,63)==5) then + createexsprite({x=s.x,y=s.y,vx=-1,vy=-1}) + end + elseif(s.id==0x96) then --Moai + elseif(s.id==0x97) then --Mother and Child + if(AND(timer,7)==0) then + local t = s.timer/15 + createexsprite({x=s.x+16,y=s.y+16,vx=math.sin(t)-1,vy=math.cos(t),ai="LimitedLifeSpan"}) + end + elseif(s.id==0x8B) then --Zabu + if(s.timer==5) then + createexsprite({x=s.x,y=s.y,vx=0.5,ai="AimDelayed"}) + end + elseif(s.id==0x92 or s.id==0x93 or s.id==0x87 or s.id==0x91) then --Dee-01, Ducker + --if(s.timer==5) then + local t = AND(s.timer,127) + if(t>60 and t<79 and AND(s.timer,3)==3) then + --createexsprite({x=s.x,y=s.y,ai="AimOnce"}) + createexsprite({x=s.x,y=s.y,ai="AimOnce"}) + end + elseif(s.id==0x98) then --boss... + doboss1ai(s) + end +end + + +function updatevars() + paused = memory.readbyte(0x0015) + if(paused==1) then + return + end + --load original sprites from ram + for i=0,31 do + --if(i==0 or memory.readbyte(0x0300+i)~=0) then + if(memory.readbyte(0x0300+i)~=spr[i].id) then + spr[i].timer = 0 + end + spr[i].status=memory.readbyte(0x0100+i) --1=alive, 2=dead + spr[i].id=memory.readbyte(0x0300+i) + spr[i].x=memory.readbyte(0x0360+i) + spr[i].y=memory.readbyte(0x0320+i) + spr[i].timer=spr[i].timer+1 + if(spr[i].id==0) then + spr[i].timer = 0 + else + dospriteai(spr[i]) + end + + if(i>3 and bombtimer>0 and getvicdistance(spr[i].x+4,spr[i].y+4)<30) then + if(spr[i].id~=0x29 and spr[i].id~=0x01 and spr[i].id~=0x99 and spr[i].id~=0x98 and spr[i].id~=0x94 and spr[i].id~=0x97 and spr[i].id~=0x96 and spr[i].id~=0x1E) then + --excluded: hidden bonus (0x29), power ups and moai bullets (0x01), boss (0x99+0x98), tentacle (0x94), mother (0x97), moai (0x96), gate (0x1E) + destroysprite(i) + end + end + --end + end + vic = spr[0] + + + + + if(deathtimer>0) then + if(deathtimer==120) then + destroyallexsprites() + deathtimer = 0 + bombs = BOMBS_PER_LIFE + else + if(deathtimer==1) then + --this is part of what gradius does to kill vic viper... + --faster and without the annoying sound effect. who cares! + memory.writebyte(0x4C,0x78) + memory.writebyte(0x0100,0x02) --status = dead + memory.writebyte(0x0160,0x00) + memory.writebyte(0x0140,0x00) + memory.writebyte(0x1B,0xA0) + memory.writebyte(0x0120,0x2D) --chr?-- + end + deathtimer = deathtimer + 1 + end + end + + + local jp = joypad.get(1) + if(jp.select and jp.select~=last_select and bombs>0) then + bombtimer = 1 + bombs = bombs - 1 + destroyallexsprites() + --destroy bullets + for i=1,31 do + if(spr[i].id<4 and spr[i].id~=1) then + destroysprite(i) + end + end + end + last_select = jp.select + + + if(last_vic_status~=vic.status) then + if(vic.status==2) then --vic died in the original game, start death timer to destroy all extended sprites + deathtimer = 1 + end + end + last_vic_status = vic.status + + --calculations on extended sprites + for i=0,MAX_EXSPR-1 do + if(exspr[i]~=nil) then + if(bombtimer>0 and getvicdistance(exspr[i].x+4,exspr[i].y+4)<25) then + destroyexsprite(i) + else + doexspriteai(exspr[i]) + exspr[i].timer = exspr[i].timer + 1 + exspr[i].x=exspr[i].x+exspr[i].vx + exspr[i].y=exspr[i].y+exspr[i].vy + if(exspr[i].x>255 or exspr[i].x<0 or exspr[i].y>255 or exspr[i].y<0) then + --destroy exsprite + exspr[i]=nil + break + end + --collision check with vic viper + if(deathtimer==0 and vic.status==1 and exspr[i].x>=vic.x+HITBOX[1] and exspr[i].x<=vic.x+HITBOX[3] + and exspr[i].y>=vic.y+HITBOX[2] and exspr[i].y<=vic.y+HITBOX[4]) then + deathtimer = 1 + end + end + end + end + + +end + +function render() + --bcbox(vic.x-2, vic.y+4, vic.x+9, vic.y+9, "#ffffff") + + gui.text(0, 8, string.format("bombs %d",bombs)); + --gui.text(0, 8, string.format("Lives %d",memory.readbyte(0x0020))); + --gui.text(0, 28, string.format("bombtimer %d",bombtimer)); + + --[[for i=1,31 do + if(spr[i].id~=0) then + gui.text(spr[i].x, spr[i].y, string.format("%X",spr[i].id)); + end + end--]] + + for i=0,MAX_EXSPR-1 do + if(exspr[i]~=nil) then + drawexsprite(exspr[i].id,exspr[i].x,exspr[i].y) + end + end + + + if(bombtimer>0) then + if(bombtimer<12) then + memory.writebyte(0x11,0xFF) --monochrome screen + else + memory.writebyte(0x11,0x1E) + end + bombtimer = bombtimer + 1 + for i=0,64 do + local x = vic.x+4+math.sin(i)*bombtimer*4 + math.random(0,12) + local y = vic.y+8+math.cos(i)*bombtimer*4 + math.random(0,12) + local c = 255-bombtimer + local cs = string.format("#%02x%02x00",c,c) + bcpixel(x,y,cs) + bcpixel(x-1,y,cs) + bcpixel(x+1,y,cs) + bcpixel(x,y+1,cs) + bcpixel(x,y-1,cs) + + x = vic.x+4+math.sin(i)*(20+math.sin(bombtimer/5)) + y = vic.y+8+math.cos(i)*(20+math.sin(bombtimer/5)) + bcpixel(x,y,cs) + bcpixel(x-1,y,cs) + bcpixel(x,y-1,cs) + end + if(bombtimer==180) then + bombtimer=0 + end + end +end + + +initialize() +vic = spr[0] +while(true) do + updatevars() + render() + EMU.frameadvance() + timer = timer + 1 +end diff --git a/output/luaScripts/MegamanII-LaserEyes.lua b/output/luaScripts/MegamanII-LaserEyes.lua new file mode 100644 index 00000000..33c202f9 --- /dev/null +++ b/output/luaScripts/MegamanII-LaserEyes.lua @@ -0,0 +1,730 @@ +SCRIPT_TITLE = "Mega Man 2 LASER EYES" +SCRIPT_VERSION = "1.0" + +require "m_utils" +m_require("m_utils",0) + +--[[ +Mega Man 2 LASER EYES +version 1.0 by miau + +Visit http://morphcat.de/lua/ for the most recent version and other scripts. + + +Controls + Press select to fire a laser from Mega Man's eyes aimed at the closest object. + Left-click to drag and drop objects. + Middle-clicking instantly moves Mega Man to the cursor position. + +Supported roms + Rockman 2 - Dr Wily no Nazo (J), Mega Man 2 (U), Mega Man 2 (E) + +Known bugs +- shooting lasers at bosses is glitchy, do it at your own risk +- eyes might turn black for a short period of time after screen transition +- some objects have duplicate IDs which will result in wrong names being shown for them + +-]] + +--configurable vars +local show_info = false --show sprite info on startup +local show_cursor = false --set this to true when recording a video + +--sound effects to use for various script events, nil to disable +local SFX_LASER = 0x25 +local SFX_EXPLOSION = 0x2B +local SFX_TARGET = nil --0x39 --0x21 +-------------------------------------------------------------------------------------------- +--List of sound effects +--0x21 press +--0x22 peeewwwwwww +--0x23 metal blade +--0x24 mega buster +--0x25 sniper armor shot? +--0x26 hit1 +--0x27 air shooter +--0x28 energy +--0x29 touch ground +--0x2A wily thing +--0x2B destroy1 +--0x2C ?? +--0x2D reflected shot +--0x2E ?? (metal blade-like noise channel usage, short) +--0x2F menu selector +--0x30 mega man appear +--0x31 leaf shield +--0x32 menu open +--0x33 ?? (short, low noise) +--0x34 gate open +--0x35 atomic fire charge 1 +--0x36 atomic fire charge 2 +--0x37 atomic fire charge 2 +--0x38 atomic fire shot ? +--0x39 prop-top leap +--0x3A mega man disappearing +--0x3B diving into water +--0x3C appearing platform +--0x3D wily stage lava drops +--0x3E wily stage lava drops +--0x3F ?? (similar to 0x27) +--0x40 ?? (short noise) +--0x41 death +--0x42 e-tank/1up +--0x43 ?? (short noise in fixed intervals) + + + + + + +local sprdb = {} --enemy names source: http://megaman.wikia.com +sprdb[0x00] = {name="Squirt"} +sprdb[0x01] = {name="Squirt"} --spawned by Lantern Fish +sprdb[0x04] = {name="M-445"} +sprdb[0x07] = {name="Snapper Controller",invincible=true} +sprdb[0x08] = {name="Snapper"} +sprdb[0x0A] = {name="Crabbot"} +sprdb[0x0C] = {name="Croaker"} +sprdb[0x0D] = {name="Croaker (tiny)"} +sprdb[0x0E] = {name="",invincible=true} --bubble...underwater mega man +sprdb[0x0F] = {name="Lantern Fish"} +sprdb[0x13] = {name="Platform"} +sprdb[0x15] = {name="Beam"} +sprdb[0x16] = {name="Bubble Bat"} +sprdb[0x17] = {name="Robo-Rabbit"} +sprdb[0x18] = {name="Carrot"} --or mega man being hit +sprdb[0x1D] = {name="Mecha Monkey"} +sprdb[0x1E] = {name="Atomic Chicken Controller",invincible=true} +sprdb[0x1F] = {name="Atomic Chicken"} +--sprdb[0x1B] = {name="Climbing Mega Man"} --or hot dog fire +--sprdb[0x1C] = {name=""} --or hot dog fire controller? +sprdb[0x21] = {name="Telly Spawn Point",invincible=true} +sprdb[0x22] = {name="Telly"} +sprdb[0x23] = {name="Hothead"} --or Mega Buster +sprdb[0x24] = {name="Tackle Fire"} +--sprdb[0x27] = {name="Light Control"} +--sprdb[0x28] = {name="Light Control"} +sprdb[0x29] = {name="Cogwheel"} +sprdb[0x2A] = {name="Pierobot"} +sprdb[0x2B] = {name="Prop-Top Controller",invincible=true} +sprdb[0x2C] = {name="Prop-Top"} +sprdb[0x2E] = {name="Hot Dog"} +sprdb[0x2F] = {name="Gate"} +sprdb[0x30] = {name="Press"} +sprdb[0x31] = {name="Blocky"} +sprdb[0x32] = {name="Big Fish Controller",invincible=true} +--sprdb[0x33] = {name=""} --Bubble Lead +sprdb[0x34] = {name="Neo Met"} +sprdb[0x35] = {name="Bullet"} --Sniper Armor/Sniper Joe +sprdb[0x36] = {name="Fan Fiend"} --or Metal Blade +sprdb[0x37] = {name="Pipi Controller",invincible=true} --or Flash weapon (Time Stopper) controller(?) +sprdb[0x38] = {name="Pipi"} +sprdb[0x3A] = {name="Pipi Egg"} --or Item-3(?) +sprdb[0x3B] = {name="Pipi Egg Shell"} +sprdb[0x3C] = {name="Child Pipi"} +sprdb[0x3D] = {name="Lightning Lord"} +sprdb[0x3E] = {name="Thunder Chariot"} +--sprdb[0x3F] = {name="Lightning Bolt"} --or "splash"... (mega man diving into water) +sprdb[0x3F] = {invincible=true} +sprdb[0x40] = {name="Air Tikki"} +sprdb[0x41] = sprdb[0x40] +sprdb[0x44] = {name="Air Tikki Horn"} +sprdb[0x45] = {name="Gremlin"} +sprdb[0x46] = {name="Spring Head"} +sprdb[0x47] = {name="Mole Controller",invincible=true} +sprdb[0x48] = {name="Mole (rising)"} +sprdb[0x49] = {name="Mole (falling)"} +sprdb[0x4B] = {name="Crazy Cannon"} +sprdb[0x4D] = {name="Bullet (Crazy Cannon)"} +sprdb[0x4E] = {name="Sniper Armor"} +sprdb[0x4F] = {name="Sniper Joe"} +sprdb[0x50] = {name="Squirm"} +sprdb[0x51] = {name="Squirm Pipe"} + +sprdb[0x5C] = {name="Metal Blade"} +sprdb[0x5D] = {name="Air Shooter"} +sprdb[0x5E] = {name="Crash Bomb"} + +--[[sprdb[0x60] = {name="Bubble Man"} +sprdb[0x61] = sprdb[0x60] +sprdb[0x62] = sprdb[0x60] +sprdb[0x63] = {name="Metal Man"} --or Falling Blocks (Dragon) (id2:80) +sprdb[0x64] = sprdb[0x63] --or Falling Blocks (Dragon).. Dragon Controller? (id2:80) +sprdb[0x65] = sprdb[0x63] --or Dragon Body (id2:8B) +sprdb[0x66] = {name="Air Man"} --or Dragon Bottom (id2:8B) +sprdb[0x67] = sprdb[0x66] +sprdb[0x68] = sprdb[0x66] +sprdb[0x69] = {name="Crash Man"} +sprdb[0x6A] = sprdb[0x69] --running or wily boss no.2 (id2:8B/CB/83/C3/80) +sprdb[0x6B] = sprdb[0x69] --jumping +sprdb[0x70] = {name="Dragon"} --(id2:8B) +sprdb[0x71] = {name="Big Fish"} --Wily Boss 3 (id2:83) +--]] + +sprdb[0x76] = {name="Large Life Energy",invincible=true} +sprdb[0x77] = {name="Small Life Energy",invincible=true} +sprdb[0x78] = {name="Large Weapon Energy",invincible=true} +sprdb[0x79] = {name="Small Weapon Energy",invincible=true} +sprdb[0x7A] = {name="E-Tank",invincible=true} +sprdb[0x7B] = {name="1UP",invincible=true} + + +local eyes = {} +eyes.open = { + {0,0,0,0,0,1,1,0,1,0,0,0,0}, + {0,0,0,0,0,1,1,0,1,0,0,0,0}, +} +eyes.running = { + {0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,1,0,1,0,0,0,0}, + {0,0,0,0,0,1,1,0,1,0,0,0,0}, +} +eyes.shooting = { + {0,0,0,0,0,0,0,0,0,1,1,0,1}, + {0,0,0,0,0,0,0,0,0,1,1,0,1}, +} +eyes.ladder = { + {0,0,0,0,0,0,0,1,1,0,0,0,0}, + {0,0,0,0,0,0,0,1,1,0,0,0,0}, +} +eyes.closed = { + {0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,1,1,1,1,0,1,1,0,0,0}, +} +eyes.none = {} + +local mmeyes = eyes.open +local timer = 0 +local spr = {} +local last_inp = {} +local inp = {} +local laser = {timer=0} +local last_laser = 0 + + + +--very limited and hacky particle engine following +local P_MAX = 150 +local particle = {p={}} + +function particle.laserai(pi) + local function checkcollision(px,py,rx,ry) + if(px>=rx-8 and px<=rx+8 and py>=ry-8 and py<=ry+8) then + return true + else + return false + end + end + + for i=1,31 do + if(spr[i].a and is_enemy(i)) then + local px = particle.p[pi].x + local py = particle.p[pi].y + local px2 = particle.p[pi].x+particle.p[pi].vx*6 + local py2 = particle.p[pi].y+particle.p[pi].vy*6 + local rx = spr[i].x+spr[i].hx*256 + local ry = spr[i].y + if(checkcollision(px,py,rx,ry) or checkcollision(px2,py2,rx,ry)) then + --if(spr[i].hp>5) then + -- memory.writebyte(0x06C0+i,spr[i].hp-5) + --else + memory.writebyte(0x06C0+i,1) + play_sfx(SFX_EXPLOSION) + particle.explosion(spr[i].x+spr[i].hx*256,spr[i].y) + destroy_sprite(i) + --end + end + end + end +end + + +function particle.create(new) + for i=0,P_MAX-1 do + if(particle.p[i]==nil) then + particle.p[i]=new + if(particle.p[i].x==nil) then + particle.p[i].x=0 + end + if(particle.p[i].y==nil) then + particle.p[i].y=0 + end + if(particle.p[i].vx==nil) then + particle.p[i].vx=0 + end + if(particle.p[i].vy==nil) then + particle.p[i].vy=0 + end + if(particle.p[i].timer==nil) then + particle.p[i].timer=0 + end + if(particle.p[i].lspan==nil) then + particle.p[i].lspan=60 + end + if(particle.p[i].color==nil) then + particle.p[i].color="#FFFFFF" + end + return i + end + end + return nil +end + +function particle.explosion(x,y) --faster than using particle.create + local j = 0 + for i=0,P_MAX-1 do + if(particle.p[i]==nil) then + local vx = math.random(-50,50)/30 + local vy = math.random(-50,50)/30 + local color = "#FF0000" + particle.p[i] = {} + particle.p[i].x = x + particle.p[i].y = y + particle.p[i].vx = vx + particle.p[i].vy = vy + particle.p[i].color = color + particle.p[i].lspan = math.random(20,40) + particle.p[i].timer=0 + if(j==40) then + return + end + j = j + 1 + end + end +end + +function particle.destroy(i) + particle.p[i] = nil +end + + +function particle.update() + for i=0,P_MAX-1 do + if(particle.p[i]) then + if(particle.p[i].timer >= particle.p[i].lspan) then + particle.destroy(i) + else + if(particle.p[i].aifunc) then + particle.p[i].aifunc(i) + end + if(particle.p[i]) then + particle.p[i].x = particle.p[i].x + particle.p[i].vx + particle.p[i].y = particle.p[i].y + particle.p[i].vy + particle.p[i].timer = particle.p[i].timer + 1 + end + end + end + end +end + +function particle.render(xdisp,ydisp) + local j=0 + for i=0,P_MAX-1 do + if(particle.p[i]) then + bcline2(particle.p[i].x-xdisp,particle.p[i].y-ydisp, particle.p[i].x-xdisp+particle.p[i].vx*6,particle.p[i].y+particle.p[i].vy*6-ydisp, particle.p[i].color) + if(particle.p[i].aifunc) then + bcline2(particle.p[i].x-xdisp,particle.p[i].y+1-ydisp, particle.p[i].x-xdisp+particle.p[i].vx*6,particle.p[i].y+particle.p[i].vy*6+1-ydisp, particle.p[i].color) + end + j = j + 1 + end + end +end + + + + +function initialize() + for i=0,31 do + spr[i] = { + a=0, + id=0, + id2=0, + x=0, + y=0, + hp=0, + --timer=-1, + } + end +end + + +function unselect_all() + for i=0,31 do + spr[i].selected=false + spr[i].moving = false + end +end + +function getx16(s) + return s.hx*256+s.x +end + +function get_target() + --closest target + local closest = nil + local dmin = 9999 + for i=1,31 do + if(spr[i].a and is_enemy(i) and spr[i].seltimer>=10 and + ( (spr[i].sx>=megaman.sx and megaman.dir==1) + or (spr[i].sx<=megaman.sx and megaman.dir==-1) + or megaman.dir==0)) then + local d = getdistance(megaman.sx,megaman.sy,spr[i].sx,spr[i].sy) + if(d=0x80) + if(spr[i].a==false) then + spr[i].seltimer=nil + end + + if(spr[i].a) then + if(inp.xmouse>=spr[i].sx-8 and inp.xmouse<=spr[i].sx+8 and inp.ymouse>=spr[i].sy-8 and inp.ymouse<=spr[i].sy+8) then + spr[i].hover = true + spr[i].clicked = inp.leftclick + if(inp.leftclick and last_inp.leftclick==nil) then + unselect_all() + spr[i].selected=true + end + else + spr[i].hover = false + if(inp.leftclick==nil) then + spr[i].clicked = false + end + end + + --auto-target + if(is_enemy(i)) then + if(spr[i].seltimer==nil) then + spr[i].seltimer=1 + else + spr[i].seltimer = spr[i].seltimer + 1 + end + end + + if(spr[i].selected) then + --[[if(inp.delete) then + destroy_sprite(i) + elseif(inp.pagedown) then + memory.writebyte(0x0400+i,spr[i].id-1) + elseif(inp.pageup) then + memory.writebyte(0x0400+i,spr[i].id+1) + end-]] + + if(spr[i].clicked) then + if(inp.xmouse~=last_inp.xmouse or inp.ymouse~=last_inp.ymouse) then + spr[i].moving = true + end + else + spr[i].moving = false + end + end + + if(spr[i].moving) then + local x = inp.xmouse+scroll_x + memory.writebyte(0x0460+i,inp.xmouse+scroll_x) + memory.writebyte(0x04A0+i,inp.ymouse) + memory.writebyte(0x0440+i,scroll_hx+math.floor(x/256)) + end + + end + --end + end + + megaman = spr[0] + if(megaman.id2==0x80) then + megaman.dir=-1 + else + megaman.dir=1 + end + if(megaman.id==0x1B) then + megaman.dir = 0 + end + + + if(inp.middleclick) then --change mega man's coordinates + local x = inp.xmouse+scroll_x + memory.writebyte(0x0460,x) + memory.writebyte(0x04A0,inp.ymouse) + memory.writebyte(0x0440,scroll_hx+math.floor(x/256)) + end + + --LASER!!! + jp = joypad.read(1) + if(jp.select and (last_jp.select==nil or timer-last_laser>22)) then + local t = get_target() + local vx,vy + play_sfx(SFX_LASER) + if(t) then + vx,vy = getvdir(megaman.sx,megaman.sy-3,spr[t].sx,spr[t].sy) + vx = vx * 10 + vy = vy * 10 + else + if(megaman.dir==0) then + vx = 0 + vy = -10 + else + vx = megaman.dir*10 + vy = 0 + end + end + last_laser = timer + + particle.create({x=getx16(megaman),y=megaman.y-3,vx=vx,vy=vy,color="#FF0000",aifunc=particle.laserai}) + end + + if(inp.xmouse<83 and inp.ymouse<18) then + if(inp.leftclick and last_inp.leftclick==nil) then + if(show_info) then + show_info = false + else + show_info = true + end + end + end + + last_jp = jp + last_inp = inp +end + +function render() + + if(show_info) then + gui.text(0,8,"Sprite Info: ON") + else + gui.text(0,8,"Sprite Info: OFF") + end + if(inp.xmouse<83 and inp.ymouse<18) then + if(show_info) then + gui.drawbox(0,9,77,17,"red") + else + gui.drawbox(0,9,83,17,"red") + end + end + + particle.render(scroll_x+scroll_hx*256,0) + + --LASER EYES!!! + --TODO: prevent play_sfx from playing sounds during title screen/stage select + if(memory.readbyte(0x580) == 0x0D) then --title screen tune is being played + megaman.sx=211 + megaman.sy=131 + megaman.dir = -1 + mmeyes = eyes.open + + --lasers during title screen + if(AND(timer,7)==0 and math.random(0,1)==0) then + --play_sfx(SFX_LASER) + local vx,vy=getvdir(megaman.sx,megaman.sy-3,0,math.random(30,220)) + vx=vx*10 + vy=vy*10 + particle.create({x=megaman.sx+6,y=megaman.sy-3,vx=vx,vy=vy,color="#FF0000",aifunc=LaserAI}) + mmeyes = eyes.none + end + elseif(megaman.a) then --sprite active + local f = memory.readbyte(0x06A0)*256 + memory.readbyte(0x0680) + local frame = memory.readbyte(0x06A0) + local ftimer = memory.readbyte(0x0680) + if(memory.readbyte(0x69)~=0x0E) then --menu opened or "stage intro" tune + mmeyes = eyes.none + elseif(megaman.id==0x00) then --BLINK! change occurs on next frame + if(f >= 0xA01) then + mmeyes = eyes.closed + elseif(f>=0x001) then + mmeyes = eyes.open + end + elseif(megaman.id==0x01 or megaman.id==0x03 or megaman.id==0x05 or megaman.id==0x07 or megaman.id==0x0B or megaman.id==0x11 or megaman.id==0x13) then + mmeyes = eyes.shooting + elseif(megaman.id==0x04 or megaman.id==0x0C or megaman.id==0x0D or megaman.id==0x10) then + mmeyes = eyes.open + elseif(megaman.id==0x08 or megaman.id==0x09 or megaman.id==0x14) then + if((f>=0x201 and f<=0x300) or (f>=0x001 and f<=0x100)) then + mmeyes = eyes.running + else + mmeyes = eyes.open + end + elseif(megaman.id==0x18) then --getting hurt + mmeyes = eyes.closed + elseif(megaman.id==0x1C or megaman.id==0x1E) then --mega buster, other weapons + mmeyes = eyes.ladder + else--if(megaman.id==0x1A or megaman.id==0x1B) then --respawning after death, climbing a ladder + mmeyes = eyes.none + end + + --if(megaman.hp==0) then + -- mmeyes = eyes.none + --end + else + mmeyes = eyes.none + end + + if(mmeyes ~= eyes.none) then + local eyecolor = "#FF0000" + if(timer-last_laser<5) then + eyecolor = "#FFFFFF" + end + if(megaman.dir==-1) then + for y=1,4 do + if(mmeyes[y]) then + for x=1,14 do + if(mmeyes[y][15-x]==1) then + bcpixel(megaman.sx-9+x,megaman.sy-5+y,eyecolor) + end + end + end + end + else + for y=1,4 do + if(mmeyes[y]) then + for x=1,14 do + if(mmeyes[y][x]==1) then + bcpixel(megaman.sx-5+x,megaman.sy-5+y,eyecolor) + end + end + end + end + end + end + + + for i=0,31 do + if(spr[i].a) then + local x,y + local boxcolor + if(spr[i].clicked) then + boxcolor="#AA5500" + elseif(spr[i].hover) then + boxcolor="#FFCCAA" + else + boxcolor=nil + end + x = spr[i].sx + y = spr[i].sy + if(boxcolor) then + bcbox(x-9,y-9,x+9,y+9,boxcolor) + end + + if(spr[i].seltimer) then + if(spr[i].seltimer<30) then + local b=30-spr[i].seltimer + local c = (30-spr[i].seltimer)*8 + bcbox(x-9-b,y-9-b,x+9+b,y+9+b,string.format("#CC%02X%02X",c,c)) + if(spr[i].seltimer==23) then + play_sfx(SFX_TARGET) + end + elseif(spr[i].seltimer>90 or AND(timer,7)>2) then + bcbox(x-9,y-9,x+9,y+9,"red") + end + end + + + if(show_info and (spr[i].hover or spr[i].clicked or spr[i].seltimer)) then + --bctext(AND(spr[i].x+255-scroll_x,255), spr[i].y, i); + if(i==0) then + bctext(x, y, "Blue Bomber") + bctext(x, y+8, "("..spr[i].sx..","..spr[i].sy..")") + bctext(x, y+16, "HP "..spr[i].hp) + elseif(i>4) then + if(sprdb[spr[i].id] and sprdb[spr[i].id].name --[[and i>4--]]) then + bctext(x, y, sprdb[spr[i].id].name) + else + bctext(x, y, "("..spr[i].id..")") + end + bctext(x, y+8, "("..spr[i].sx..","..spr[i].sy..")") + if(spr[i].hp~=0) then + bctext(x, y+16, "HP "..spr[i].hp) + end + end + end + end + end + + if(show_cursor) then + local col2 + if(inp.leftclick) then + col2 = "#FFAA00" + elseif(inp.rightclick) then + col2 = "#0099EE" + elseif(inp.middleclick) then + col2 = "#AACC00" + else + col2 = "white" + end + drawcursor(inp.xmouse,inp.ymouse,"black",col2) + end +end + + + +initialize() + +while(true) do + update_vars() + render() + EMU.frameadvance() + timer = timer + 1 +end + + diff --git a/output/luaScripts/ZapperFun.lua b/output/luaScripts/ZapperFun.lua new file mode 100644 index 00000000..dd09256d --- /dev/null +++ b/output/luaScripts/ZapperFun.lua @@ -0,0 +1,72 @@ +-- Zapper Fun +-- quick and dirty script that shows zapper position and fire button presses in FCEUX +-- Written by miau +-- http://morphcat.de/lua/ + +local Z_LSPAN = 20 --life span (in frames) of white box +local Z_LSPAN_CLICK = 30 --life span of red box +local Z_MAX = 60 --maximum amount of boxes on screen + +local zbuf = {} +local zindex = 1 +local timer = 0 +local lastclick = zapper.read().click +local lastx = zapper.read().x +local lasty = zapper.read().y + +function zapper_addcoord(x,y,click) + zbuf[zindex] = {t=timer,x=x,y=y,click=click} + zindex = zindex + 1 + if(zindex>Z_MAX) then + zindex = 1 + end +end + +function box(x1,y1,x2,y2,color1,color2) + if(x1>=0 and y1>=0 and x2<=255 and y2<=255) then + gui.drawbox(x1, y1, x2, y2, color1, color2) + end +end + + + + while(true) do + local x = zapper.read().xmouse + local y = zapper.read().ymouse + local click = zapper.read().click + --gui.text(0, 8, string.format("x=%d",x)); + --gui.text(0, 18, string.format("y=%d",y)); + --gui.text(0, 28, string.format("click=%d",click)); + if(click==1 and click~=lastclick) then + zapper_addcoord(x,y,1) + elseif(x~=lastx or y~=lasty) then + zapper_addcoord(x,y,0) + end + lastclick=click + lastx=x + lasty=y + box(x-3, y-3, x+3, y+3, "white", 0) + + for i=1,Z_MAX do + if(zbuf[i]) then + ltime = timer-zbuf[i].t + if(zbuf[i].click==0) then + if(ltime MODULE_VERSION would raise an error + modulename.test() +-]] +function m_require(module,requiredver) + if(module==nil or module=="m_utils") then + if(M_UTILS_VERSION>=requiredver) then + return true + else + error("\n\nThis script requires m_utils version "..requiredver..".\n".. + "Your m_utils.lua is version "..M_UTILS_VERSION.."\n".. + "Check http://morphcat.de/lua/ for a newer version.") + end + else + --give the module the possibility to be backwards compatible + --not very elegant, but there seems to be no other way using require + REQUIRED_MODULE_VERSION = requiredver + local ret = require(module) + if(requiredver==nil) then --got no version checking to do + return ret + elseif(ret==nil or ret==false) then + error("Could not load module "..module.." or module invalid.") + elseif(type(ret)~="table") then + error("Invalid module "..module..", doesn't return itself.") + elseif(ret.MODULE_VERSION==nil) then + error("Invalid module "..module..", missing version information.") + elseif(ret.MODULE_VERSION < requiredver) then + error("\n\nThis script requires "..module.." version "..requiredver..".\n".. + "Your "..module.." module is version "..ret.MODULE_VERSION..".\n".. + "If it's one of miau's Lua modules check\n".. + "http://morphcat.de/lua/ for a newer version.\n") + else + return ret + end + end +end + + +--drawing functions with bounds checking +function bcbox(x1,y1,x2,y2,color1) + if(x1>=0 and y1>=0 and x2<=255 and y2<=255) then + gui.drawbox(x1, y1, x2, y2, color1, 0) + end +end + +function bcpixel(x,y,color) + if(x>=0 and y>=0 and x<=255 and y<=255) then + gui.drawpixel(x,y,color) + end +end + +function bcline(x1,y1,x2,y2,color) + if(x1>=0 and y1>=0 and x2<=255 and y2<=255 + and x2>=0 and y2>=0 and x1<=255 and y1<=255) then + gui.drawline(x1, y1, x2, y2, color) + end +end + + +--bc + clipping, just make sure x2,y2 is the point that will most likely leave the screen first +function bcline2(x1,y1,x2,y2,color) + if(x1>=0 and y1>=0 and x1<=255 and y1<=255) then + if(x2>255 or y2>255 or x2<0 or y2<0) then + local vx,vy=getvdir(x1,y1,x2,y2) + --TODO: replace brute force-y method with line intersection formula + if(math.abs(vx)==1 or math.abs(vy)==1) then + local x=x1 + local y=y1 + while(x<254 and x>1 and y<254 and y>1) do + x = x + vx + y = y + vy + end + x = math.floor(x) + y = math.floor(y) + --logf(" ("..x1..","..y1..")-("..x..","..y..")\r\n") + gui.drawline(x1,y1,x,y,color) + end + else + gui.drawline(x1,y1,x2,y2,color) + end + end +end + +function bctext(x,y,text) + if(x>=0 and y>=0 and x<=255 and y<=255) then + --make sure the text is always visible or else... possible memory leaks(?) and crashes on FCEUX <= 2.0.3 + local len=string.len(text)*8+1 + if(x+len > 255) then + x = 255-len + end + if(x < 0) then + x = 0 + end + + if(y > 222) then --NTSC + y=222 + end + gui.text(x, y, text) + end +end + + +function getdistance(x1,y1,x2,y2) + return math.floor(math.sqrt((x1-x2)^2+(y1-y2)^2)) +end + +--returns direction vector of a line +function getvdir(srcx,srcy,destx,desty) + local x1 = srcx + local x2 = destx + local y1 = srcy + local y2 = desty + local xc = x2-x1 + local yc = y2-y1 + if(math.abs(xc)>math.abs(yc)) then + yc = yc/math.abs(xc) + xc = xc/math.abs(xc) + elseif(math.abs(yc)>math.abs(xc)) then + xc = xc/math.abs(yc) + yc = yc/math.abs(yc) + else + if(xc<0) then + xc=-1 + elseif(xc>0) then + xc=1 + else + xc=0 + end + if(yc<0) then + yc=-1 + elseif(yc>0) then + yc=1 + else + yc=0 + end + end + + return xc,yc +end + + +local m_cursor = { + {1,0,0,0,0,0,0,0}, + {1,1,0,0,0,0,0,0}, + {1,2,1,0,0,0,0,0}, + {1,2,2,1,0,0,0,0}, + {1,2,2,2,1,0,0,0}, + {1,2,2,2,2,1,0,0}, + {1,2,2,2,2,2,1,0}, + {1,2,1,1,1,1,1,1}, + {1,1,0,0,0,0,0,0}, + {1,0,0,0,0,0,0,0}, +} +function drawcursor(px,py,col1,col2) + if(px>0 and py>0 and px<256-8 and py<256-10) then + for y=1,10 do + if(m_cursor[y]) then + for x=1,8 do + if(m_cursor[y][x]==1) then + gui.drawpixel(px+x,py+y,col1) + elseif(m_cursor[y][x]==2) then + gui.drawpixel(px+x,py+y,col2) + end + end + end + end + end +end + +--debug functions +function logf(s) + local fo = io.open("E:/emu/nes/fceux-2.0.4.win32-unofficial/lua/log.txt", "ab") + if(fo~=nil) then + fo:write(s) + fo:close() + return true + end +end + +function logtable(a) + for i,v in pairs(a) do + if(type(v)=="table") then + printarrrec(v) + else + if(v==false) then + v="false" + elseif(v==true) then + v="true" + end + logf(i.." = "..v.."\r\n") + end + end +end +