mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-04 00:20:01 -04:00
187 lines
9.4 KiB
Lua
187 lines
9.4 KiB
Lua
package.path='./?.lua;./?/init.lua;'..package.path
|
|
love=love or require('tests.love_stub')
|
|
local T=require('tests.harness').suite('Gen1 charge announcement #2645')
|
|
local Battle=require('src.battle.BattleState')
|
|
local Pokemon=require('src.pokemon.Pokemon')
|
|
local Save=require('src.core.SaveData')
|
|
local Data=require('src.core.Data')
|
|
local Version=require('src.core.GameVersion')
|
|
local Font=require('src.render.Font')
|
|
local Runtime=require('src.mods.Runtime')
|
|
local Hooks=require('src.mods.Hooks')
|
|
local Events=require('src.mods.Events')
|
|
local TypeChart=require('src.battle.TypeChart')
|
|
local old={version=Version.get(),events=Runtime.events,hooks=Runtime.hooks,errors=Runtime.errors,data={}}
|
|
for k,v in pairs(Data) do old.data[k]=v end
|
|
local fontBindings={}
|
|
local resetFontCaches
|
|
local typeBindings={}
|
|
for i=1,100 do
|
|
local k,v=debug.getupvalue(TypeChart.load,i)
|
|
if not k then break end
|
|
typeBindings[#typeBindings+1]={i,v}
|
|
end
|
|
for i=1,100 do
|
|
local k,v=debug.getupvalue(Font.load,i)
|
|
if not k then break end
|
|
if k=='state' or k=='loadedFrom' then fontBindings[#fontBindings+1]={i,v} end
|
|
if k=='resetTextCaches' then resetFontCaches=v end
|
|
end
|
|
local phrases={SOLARBEAM='took in sunlight',RAZOR_WIND='made a whirlwind',SKULL_BASH='lowered its head',
|
|
SKY_ATTACK='is glowing',FLY='flew up high',DIG='dug a hole'}
|
|
local function countText(b,fragment)
|
|
local n=0
|
|
for _,r in ipairs(b.queue) do if r.text and r.text:find(fragment,1,true) then n=n+1 end end
|
|
return n
|
|
end
|
|
local ok,err=xpcall(function()
|
|
for _,version in ipairs({'red','blue','yellow'}) do
|
|
local root=os.getenv('GEN1_'..version:upper()..'_CACHE')
|
|
if root then
|
|
Version.set(version)
|
|
local data={}
|
|
for _,key in ipairs({'pokemon','moves','items','maps','tilesets','text','sprites','field','constants','font','type_chart'}) do
|
|
data[key]=assert(loadfile(root..'/data/generated/'..key..'.lua'))()
|
|
Data[key]=data[key]
|
|
end
|
|
Font.load(data)
|
|
local function fresh(id,enemy)
|
|
local save=Save.newGame()
|
|
save.options.animations=false;save.options.textSpeed=1
|
|
local mon=Pokemon.new(data,'MEWTWO',50)
|
|
local move={id=id,pp=data.moves[id].pp,maxPp=data.moves[id].pp}
|
|
mon.moves={move};save.party={mon}
|
|
local stack={push=function()end,top=function()end}
|
|
local game={data=data,save=save,stack=stack,input={wasPressed=function()return true end,isDown=function()return true end}}
|
|
local b=Battle.newWild(game,'MEWTWO',80)
|
|
b.rng=function(a)return a or 0 end
|
|
local user,target=b.player,b.enemy
|
|
if enemy then user,target=b.enemy,b.player;user.curMoves={move};user.mon.moves={move} end
|
|
return b,user,target,move
|
|
end
|
|
for _,id in ipairs({'SOLARBEAM','RAZOR_WIND','SKULL_BASH','SKY_ATTACK','FLY','DIG'}) do
|
|
for _,enemy in ipairs({false,true}) do
|
|
local label=version..' '..id..' '..(enemy and 'enemy' or 'player')
|
|
Runtime.install(Events.new(),Hooks.new())
|
|
local b,user,target,move=fresh(id,enemy)
|
|
local hp,pp=target.mon.hp,move.pp
|
|
T.check(b:effectRecord(data.moves[id].effect).charge~=nil,label..' actual ROM effect reaches charge record')
|
|
b:performMove(user,target,move)
|
|
T.eq(countText(b,'used '..data.moves[id].name),0,label..' no used announcement on charging turn')
|
|
T.eq(countText(b,phrases[id]),1,label..' one source charge text')
|
|
T.eq(target.mon.hp,hp,label..' charge does no damage')
|
|
T.eq(user.charging,move,label..' selected instance retained')
|
|
T.eq(user.invulnerable==true,id=='FLY' or id=='DIG',label..' source invulnerability unchanged')
|
|
T.eq(move.pp,enemy and pp or pp-1,label..' prior faithful side PP policy unchanged')
|
|
local observed,drained={},false
|
|
for frame=1,1000 do
|
|
local active=b:updateQueue()
|
|
if b.current and b.current.text then observed[b.current.text]=true end
|
|
if not active then drained=true;break end
|
|
end
|
|
T.check(drained,label..' actual queue drains within bound')
|
|
local announced=false
|
|
for text in pairs(observed) do if text:find('used '..data.moves[id].name,1,true) then announced=true end end
|
|
T.eq(announced,false,label..' actual text consumer never starts used page during charge')
|
|
b.queue={};b.nextInsert=0;b.current=nil;b.waitFrames=nil
|
|
local releasePP=move.pp
|
|
b:performMove(user,target,move)
|
|
T.eq(countText(b,'used '..data.moves[id].name),1,label..' release announces once')
|
|
T.eq(countText(b,phrases[id]),0,label..' release has no second charge page')
|
|
T.eq(user.charging,nil,label..' release clears charge')
|
|
T.eq(user.invulnerable,nil,label..' release clears invulnerability')
|
|
T.eq(move.pp,releasePP,label..' release retains current continuation PP policy')
|
|
end
|
|
end
|
|
for _,required in ipairs({true,false}) do
|
|
local b,user,target,move=fresh('SOLARBEAM',false)
|
|
local events,hooks=Events.new(),Hooks.new()
|
|
Runtime.install(events,hooks)
|
|
local sequence,original={}
|
|
events:on('battle.move_used',function(c)
|
|
sequence[#sequence+1]='event'
|
|
T.eq(c.user,user,version..' event user unchanged')
|
|
original=c.battle.queue[1]
|
|
c.battle:sayNextAuto(original.text)
|
|
end)
|
|
hooks:wrap('battle.charge_required',function(nextFn,c)
|
|
sequence[#sequence+1]='hook'
|
|
T.eq(c.isCalled,false,version..' ordinary hook context')
|
|
c.battle:sayNext('hook-owned text')
|
|
return required
|
|
end)
|
|
local hp=target.mon.hp
|
|
b:performMove(user,target,move)
|
|
T.eq(table.concat(sequence,','),'event,hook',version..' public event/hook order preserved')
|
|
T.eq(countText(b,'used '..data.moves.SOLARBEAM.name),required and 1 or 2,version..' only owned announcement removed after actual decision '..tostring(required))
|
|
T.eq(countText(b,'hook-owned text'),1,version..' nested hook text retained')
|
|
local present=false
|
|
for _,r in ipairs(b.queue) do if r==original then present=true end end
|
|
T.eq(present,not required,version..' exact original row identity '..tostring(required))
|
|
T.eq(user.charging~=nil,required,version..' hook charge decision honored')
|
|
T.eq(target.mon.hp==hp,required,version..' hook bypass damages normally')
|
|
end
|
|
do
|
|
local b,user,target,move=fresh('SOLARBEAM',false)
|
|
local hooks,events=Hooks.new(),Events.new()
|
|
Runtime.install(events,hooks)
|
|
local called
|
|
hooks:wrap('battle.charge_required',function(nextFn,c)called=c.isCalled;return nextFn(c) end)
|
|
local pp=move.pp
|
|
b:performMove(user,target,move,true)
|
|
T.eq(called,true,version..' called hook context retained')
|
|
T.eq(move.pp,pp,version..' called charge keeps PP')
|
|
T.eq(countText(b,'used '..data.moves.SOLARBEAM.name),0,version..' called charge follows source charge branch')
|
|
end
|
|
do
|
|
Runtime.install(Events.new(),Hooks.new())
|
|
local b,user,target,move=fresh('TACKLE',false)
|
|
b:performMove(user,target,move)
|
|
T.eq(countText(b,'used '..data.moves.TACKLE.name),1,version..' ordinary attack announcement retained')
|
|
T.eq(user.charging,nil,version..' ordinary attack has no charge')
|
|
end
|
|
for _,caller in ipairs({'METRONOME','MIRROR_MOVE'}) do
|
|
Runtime.install(Events.new(),Hooks.new())
|
|
local b,user,target,move=fresh(caller,false)
|
|
target.lastMove='SOLARBEAM'
|
|
local pick
|
|
for i,id in ipairs(data.constants.moveOrder) do if id=='SOLARBEAM' then pick=i end end
|
|
b.rng=function(a,limit) return limit==#data.constants.moveOrder and assert(pick) or a or 0 end
|
|
b:performMove(user,target,move)
|
|
T.eq(countText(b,'used '..data.moves[caller].name),1,version..' outer '..caller..' announcement survives nested charge')
|
|
T.eq(countText(b,'used '..data.moves.SOLARBEAM.name),0,version..' nested SolarBeam charge suppresses only its announcement')
|
|
T.eq(countText(b,'took in sunlight'),1,version..' nested charge text survives')
|
|
T.eq(user.charging and user.charging.id,'SOLARBEAM',version..' actual called-move dispatch retains charge instance')
|
|
end
|
|
do
|
|
Runtime.install(Events.new(),Hooks.new())
|
|
local b,user,target,move=fresh('TACKLE',false)
|
|
local copied={}
|
|
for k,v in pairs(data) do copied[k]=v end
|
|
copied.moves={}
|
|
for k,v in pairs(data.moves) do copied.moves[k]=v end
|
|
local custom={}
|
|
for k,v in pairs(data.moves.TACKLE) do custom[k]=v end
|
|
custom.chargeText='%s\ncustom charge page!'
|
|
copied.moves.TACKLE=custom
|
|
copied.move_effects={[custom.effect]={charge={},announceAnim=false}}
|
|
b.data=copied
|
|
b:performMove(user,target,move)
|
|
T.eq(countText(b,'used '..custom.name),0,version..' general merged charge record suppresses announcement')
|
|
T.eq(countText(b,'custom charge page'),1,version..' merged chargeText preserved')
|
|
T.eq(user.charging,move,version..' merged record charge stored without announcement animation')
|
|
T.eq(#b.queue,1,version..' absent announcement animation leaves only charge page')
|
|
end
|
|
else print('SKIP #2645 actual '..version..' cache not explicitly supplied') end
|
|
end
|
|
end,debug.traceback)
|
|
for k in pairs(Data) do if old.data[k]==nil then Data[k]=nil end end
|
|
for k,v in pairs(old.data) do Data[k]=v end
|
|
Version.set(old.version)
|
|
Runtime.install(old.events,old.hooks,old.errors)
|
|
for _,binding in ipairs(fontBindings) do debug.setupvalue(Font.load,binding[1],binding[2]) end
|
|
if resetFontCaches then resetFontCaches() end
|
|
for _,binding in ipairs(typeBindings) do debug.setupvalue(TypeChart.load,binding[1],binding[2]) end
|
|
assert(ok,err)
|
|
T.finish()
|