Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function everything()
- gui.text(0,0,"JT="..JumpTimer)
- gui.text(32,0,"Jump="..FrameJump)
- gui.text(96,0,"State="..CurrentState.."-"..AttamptCount[CurrentState])
- gui.text(160,0,"SD="..SameDeathCount)
- gui.text(192,0,"FH="..FailHoleCount)
- gui.text(224,0,"FE="..FailEnemyCount)
- gui.text(0,8,"Retry:"..RetryCount)
- gui.text(64,8,"Enemy:"..EnemyCount)
- gui.text(128,8,"Hole:"..HoleCount)
- gui.text(192,8,"Wall:"..WallCount)
- gui.text(0,16,"G="..Gaming)
- gui.text(32,16,"FD="..FailDeathCount) --若卡在一片区域过不去,这个值就会累计,累计8次奖励1次新存档尝试机会
- gui.text(64,16,"LW="..SameLastWallCount) --越不过同一个墙时会累计,累计到99次时该墙免疫
- gui.text(96,16,"WR="..WallAllowRetry) --允许墙计数器
- gui.text(128,16,"WT="..WallFreeTriggerCount) --无进展撞墙计数器,达到800次开启自由撞墙模式
- gui.text(160,16,"WF="..WallFreeMode) --自由撞墙模式,一般是关的
- gui.text(192,16,"MF="..MazeFailCount) --迷宫走失败次数
- gui.text(224,16,"JC="..FirstFrameJumpChance)
- end
- AutoTurbo=false --自动加速重复部分
- PersistSavestate=false --是否存档到文件
- AttamptAllowed=10 --设定每个新存档允许尝试次数
- JumpRandomness=32 --设定跳跃概率为1/32
- SwimRandomnessSlow=50 --设定游泳概率为1/50
- SwimRandomnessFast=15 --设定游泳频繁游泳概率为1/15
- SwimMax=120 --设定水下最大存档间隔为120帧(2秒)
- HoleMax=25 --设定连续落同样沟最多次数
- HoleDiff=50 --设定落沟时间最大误差
- WallMax=25 --设定连续撞同样墙最多次数
- SameWallMax=99 --设定撞同样墙最多次数(不一定连续),超过该次数则该墙免疫,相同墙撞99次应该够多了吧
- WallAllowedTime=30 --设定撞墙后允许的时间间隔
- WallFreeTrigger=800 --设定无进展撞墙多少次后开启自由撞墙模式,默认800
- WallFreeTimer1=54 --设定自由撞墙模式下第一次撞墙后过多少帧后判断Mario是否向右,默认64(经4-4手动测算)
- WallFreeTimer2=110 --设定自由撞墙模式下第一次撞墙后过多少帧后判断Mario是否已超越撞墙位置,默认112(经4-4手动测算)
- WallFreeTimer3=32 --设定自由撞墙模式下第一次撞墙过后向右走多少帧后判断Mario是否已超越撞墙位置,默认32(经手动测算,针对8-4)
- lastst=st
- lastframe=0
- Gaming=0 --游戏状态,0表示不在游戏,1表示在游戏,>1表示在执行开局倒跳
- JumpTimer=0
- RetryCount=0
- EnemyCount=0
- HoleCount=0
- WallCount=0
- FrameFall=9999999
- FrameLast=0
- CurrentState=9
- FrameJump=0
- FrameRetry=0
- Castle=0
- WallAllowedFrame=0 --允许撞墙的最大时间帧数
- WallAllowX0=0 --允许撞的墙X坐标大
- WallAllowX1=0 --允许撞的墙X坐标
- WallFreeMode=0 --自由撞墙模式,一般是关的
- WallFreeTriggerCount=0 --判断有多少次无进展撞墙,达到WallFreeTrigger设定值后开启自由撞墙模式
- WallFreeFrame0=0 --第一次撞墙时间
- WallFreeFrame1=0 --第一次撞墙时间+WallFreeTimer1
- WallFreeFrame2=0 --第一次撞墙时间+WallFreeTimer2
- WallFreeX0=0 --第一次撞墙X坐标
- WallFreeX1=0
- Turbo=false --初始为false,判断是否在Turbo状态用
- FrameMax=0 --到达最大帧数
- SwimRandomness=SwimRandomnessSlow
- SuggestJumpAtStart=false --开启时会提示一读档就跳
- AttamptCount={0,0,0,0,0,0,0,0,0} --在当前存档的尝试次数
- FrameStart={0,0,0,0,0,0,0,0,0} --起始帧
- FrameRunningLast={0,0,0,0,0,0,0,0,0} --未防止跑动中撞到敌人或墙,在观看World3录像后决定加
- DeathBy=0
- DeathFrame=0 --死亡时间帧数记录
- DeathX0=0 --对撞墙有用的X位置记录
- DeathX1=0 --对撞墙有用的X位置记录
- SameDeathCount=0 --相同连续死亡积累次数
- SameLastWallCount=0 --达到最终的墙次数,次数累积太多(和SameWallMax(默认50次)相比)会对该墙产生免疫,免疫就可越过该墙
- FailDeathCount=0 --探索未成功的死亡次数积累
- FailHoleCount=0 --每增加10,增加1首帧跳跃几率
- FailEnemyCount=0 --每增加600,返回安全大存档减速重来
- BestDeath=0 --最佳死亡时间帧数
- BestHoleDeath=0 --最佳落沟死亡时间帧数
- BestWallHit=0 --最佳撞墙时间帧数
- BestDeathX0=0 --最佳死亡X位置大
- BestDeathX1=0 --最佳死亡X位置小
- DeathState={0,0} --死亡存档时间帧数,目前只设两个死亡存档记录
- DeathStateCount={0,0} --死亡存档死亡率
- PressLeft=0 --特殊情况按左
- PressDown=0 --特殊情况按下
- MazeTimer=0 --迷宫中加载判定点后的计时器
- MazeTimer0=0 --为记录MazeTimer+8特殊情况的一个计数器
- MazeFailCount=0 --走迷宫失败次数
- MazeMode=false --迷宫模式
- PipeMazeMode=false --水管迷宫模式
- PipeExitBan=0 --会始终为刚开局时的750水管出口信息,随后只有水管出口信息不等于这个值时才有机会按下,防止进入错误管道
- PipeExitBan2=0 --对应751的值
- PipeExitBan3=0 --对应751的值
- FirstFrameJumpChance=0 --落地第一帧即跳的几率,默认是0,每未成功落沟死10次加一,达到5即最大(表示5/6的几率落地即跳),达到10即大力度跳概率最大(为1/2),达到50即清零防死循环
- StateCloseAllow=0 --允许最接近存档,只对两种撞墙模式有效,水面和普通不一样,为防止7-2陷入墙缝
- WarpZoneCount=0
- FrameEnd=9999999
- SS={}
- SS[2]=savestate.object(2)
- SS[3]=savestate.object(3)
- SS[4]=savestate.object(4)
- SS[5]=savestate.object(5)
- SS[6]=savestate.object(6)
- SS[7]=savestate.object(7)
- SS[8]=savestate.object(8)
- SS[9]=savestate.object(9)
- InputLeft={}
- InputRight={}
- InputDown={}
- InputA={}
- InputB={}
- controller={down=false,left=false,right=false,A=false,B=false,start=false}
- Acceleration={false,true,true, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, true,true,false, false,false,false, false,true,false, true,false,false, false,true,true}
- function add1(a) --循环加法,例如输入8输出为2
- if a+1>8 then
- return a+1-7
- else
- return a+1
- end
- end
- function sub1(a) --循环减法,例如输入2输出为8
- if a-1<2 then
- return a-1+7
- else
- return a-1
- end
- end
- function diadd()
- di=di+1
- if di>80 then
- di=1
- end
- end
- function djsub()
- dj=dj-1
- if dj<1 then
- dj=80
- end
- end
- function SwitchLeftRight() --调换左右方向,在自由撞墙模式用
- if PressLeft>0 then
- PressLeft=0 --如果当前按左,则开始按右
- else
- PressLeft=120 --设定向左至少2秒时间
- end
- emu.print("SwitchLeftRight")
- end
- function AddChance(a) --奖励允许尝试次数
- AttamptCount[CurrentState]=AttamptCount[CurrentState]+a
- AttamptCount[CurrentState-1]=AttamptCount[CurrentState-1]+a
- if a>0 then emu.print("AddChance="..a) end
- end
- function WallFreeEmpty() --清空自由撞墙模式下相关数值,但不关闭自由撞墙模式本身
- WallFreeFrame0=0
- WallFreeFrame1=0
- WallFreeFrame2=0
- WallFreeX0=0
- WallFreeX1=0
- end
- function DeathStatAdd(a) --添加死亡记录,1=碰敌人,2=落沟,3=撞墙,4=其他,同时计算一些数据
- local b
- if a==DeathBy and ((a==1 and emu.framecount()==DeathFrame) or (a==2 and math.abs(emu.framecount()-DeathFrame)<HoleDiff) or (a==3 and (emu.framecount()==DeathFrame or (X0==DeathX0 and X1==DeathX1)))) then
- SameDeathCount=SameDeathCount+1 --添加重复死亡次数
- b=5 --设定存档死亡指数添加值,因为是重复死亡所以加的多
- else
- SameDeathCount=0 --设定新死亡记录
- DeathBy=a --新死亡方式
- DeathFrame=emu.framecount() --新死亡时间
- DeathX0=X0 --新死亡X坐标
- DeathX1=X1
- b=1
- end
- if FrameStart[CurrentState]==DeathState[2] then --假如恰巧和2号死亡存档撞上,则将2的数据复制到1,再进行添加值等操作
- DeathState[1]=DeathState[2]
- DeathStateCount[1]=DeathStateCount[2]
- end
- if FrameStart[CurrentState]==DeathState[1] then --假如新死亡存档和前一死亡一样
- DeathStateCount[1]=DeathStateCount[1]+b --死亡指数根据死亡方式不同,添加值不一样
- else
- DeathState[2]=DeathState[1] --将1的数据转移到2,然后给1写入新数据
- DeathStateCount[2]=DeathStateCount[1]
- DeathState[1]=FrameStart[CurrentState] --不一样则清空之前的死亡存档记录,新建死亡存档
- DeathStateCount[1]=b --新建存档初始值和添加值一样
- end
- if emu.framecount()<=BestDeath or (a==2 and emu.framecount()<BestHoleDeath+20) or ((WallFreeMode>0 or Swimming) and (X0<BestDeathX0 or (X0==BestDeathX0 and X1<=BestDeathX1))) then --若死亡时间没超过之前的最好成绩,假如自由撞墙模式开启或游泳模式则需判断X位置才知道是否为最好成绩
- if a==3 then --如果无进展撞墙
- if X0==BestDeathX0 and X1==BestDeathX1 then --若在最佳位置死亡(肯定是撞到了同样的墙)
- SameLastWallCount=SameLastWallCount+1 --撞同样最终墙次数积累
- if SameLastWallCount==SameWallMax then--若计数器已达到设定次数(默认50次够多了)
- WallAllowedFrame=BestWallHit+WallAllowedTime --设定允许撞墙时间范围,WallAllowedTime默认60
- WallAllowX0=BestDeathX0 --这三个值对MarioWall判定很重要,一旦设定则不更改,直到在下个墙也撞50次,或关卡结尾
- WallAllowX1=BestDeathX1
- emu.print(WallAllowedFrame..",X0="..WallAllowX0..",X1="..WallAllowX1)
- end
- end
- WallFreeTriggerCount=WallFreeTriggerCount+1 --无进展撞墙计数+1
- if WallFreeTriggerCount>=WallFreeTrigger then --若超过无进展撞墙数设定(默认500),则开启自由撞墙模式
- WallFreeMode=1
- FirstFrameJumpChance=0 --刚开启自由撞墙模式后,首帧起跳概率经常清零
- end
- if X0>BestDeathX0 or (X0==BestDeathX0 and X1>BestDeathX1) then --若已超过最佳死亡位置记录(因为落沟死不加位置记录)
- SameLastWallCount=0
- BestDeathX0=X0
- BestDeathX1=X1
- BestWallHit=emu.framecount()
- end
- elseif a==2 then --落沟死,则添加无进展落沟死计数
- if emu.framecount()>BestHoleDeath then --落沟死给了20帧的容错空间,若没超过20帧就算作同一个沟
- BestHoleDeath=emu.framecount()
- BestDeath=math.max(BestDeath,BestHoleDeath)
- end
- FailHoleCount=FailHoleCount+1
- if FailHoleCount%10==0 then --无进展落沟每10次,首帧跳跃几率增加1
- FirstFrameJumpChance=FirstFrameJumpChance+1
- if FirstFrameJumpChance>50 then FirstFrameJumpChance=0 end --首帧跳概率过大的话(超过50)清零,防止死循环
- emu.print("FirstFrameJumpChance="..FirstFrameJumpChance)
- end
- elseif a==1 then --碰敌人死,添加无进展碰敌人死亡计数
- FailEnemyCount=FailEnemyCount+1
- if X0>BestDeathX0 or (X0==BestDeathX0 and X1>BestDeathX1) then --若已超过最佳死亡位置记录(因为落沟死不加位置记录)
- SameLastWallCount=0
- BestDeathX0=X0
- BestDeathX1=X1
- end
- end
- FailDeathCount=FailDeathCount+1 --未成功死亡次数积累,和奖励次数有关
- if FailDeathCount%300==0 and FailEnemyCount%500~=0 then --累计300次返回3存档
- CurrentState=sub1(sub1(sub1(CurrentState)))
- emu.print("Reverse 3 states")
- end
- if FailDeathCount%1000==0 and FailEnemyCount%500~=0 then --若未成功死亡次数积累过1000,则返回之前稳定大存档重试
- LoadStateBig9()
- end
- else --若已超过之前的最好成绩(若自由撞墙模式则表示已超过之前最好位置)
- AddChance(math.floor(FailDeathCount/10)) --奖励当前存档的尝试次数,累积死10次前后存档各奖励1次
- BestDeath=emu.framecount() --若成功达到新最好成绩
- if a~=2 then
- SameLastWallCount=0 --撞同样墙死亡次数清零,因为已越过该墙,证明该墙是可以通过的,更新落沟死不算,落沟死前撞的墙依然有效(针对4-3的情况)
- BestDeathX0=X0 --记录最好X坐标,落沟死不记录X坐标
- BestDeathX1=X1
- end
- FailDeathCount=0 --未成功死亡次数清零
- FailHoleCount=0
- FailEnemyCount=0
- FirstFrameJumpChance=0 --首帧即跳概率清零
- WallFreeMode=0 --关闭自由撞墙模式
- WallFreeTriggerCount=0 --清空
- WallFreeEmpty() --清空
- if a==3 then BestWallHit=emu.framecount() end --添加最好撞墙时间记录
- if a==2 then BestHoleDeath=emu.framecount() end --添加最好落沟死记录
- end
- end
- function SaveNewState() --存档,可用存档范围:2-8,9为大档,轻易不存9
- CurrentState=add1(CurrentState) --存档位置+1
- AttamptCount[CurrentState]=AttamptAllowed --设定每个新存档允许尝试次数
- FrameStart[CurrentState]=emu.framecount() --保存存档位置帧数
- FrameRunningLast[CurrentState]=0 --清空允许最后跑动帧记录
- savestate.save(SS[CurrentState]) --存档
- if PersistSavestate then savestate.persist(SS[CurrentState]) end --存档到文件(这两行加一起才算正式存档)
- emu.print("Saved state:"..CurrentState)
- end
- function SaveNewStateBig9() --存大档,即第9存档,每次保证100%准确时才存(在每关开头或迷宫关解开迷宫后)
- savestate.save(SS[9]) --存大档
- if PersistSavestate then savestate.persist(SS[9]) end --存档到文件(这两行加一起才算正式存档)
- SaveNewState() --存完大档再存个小档(因为大档不常读取)
- AttamptCount[CurrentState]=888 --设定该小档能无限读取
- emu.print("SaveNewStateBig9")
- end
- function LoadStateBig9() --读大档,即第9存档
- savestate.load(SS[9])
- SaveNewState() --存完大档再存个小档(因为大档不常读取)
- SaveNewState() --存两个档,防止连续死亡后又返回了读大档前的存档
- AttamptCount[CurrentState]=999 --设定该小档能无限读取
- FrameRetry=0
- Retry()
- emu.print("LoadStateBig9")
- end
- function RestartLevel() --从关卡开头重试
- LoadStateBig9()
- WallAllowX0=0 --开局将墙允许信息清零
- WallAllowX1=0
- WallAllowedFrame=0
- FailDeathCount=0
- FailEnemyCount=0
- FailHoleCount=0
- FirstFrameJumpChance=0 --清空第一帧跳跃几率
- MazeFailCount=0
- MazeTimer=0
- WarpZoneCount=0
- MazeMode=false
- PipeMazeMode=false
- PipeExitBan=memory.readbyte(0x750)
- end
- function MazeJudge() --判断迷宫,之所以放在这里是因为如果放在主循环则只能检测一次,这个必须每次读档后都重新检测
- if LoopCommand>0 then --检测到迷宫循环判定
- MazeX0=X0
- MazeX1=math.floor(X1/16)*16 --将X1值统一为16整数倍,避免出现位置不同加载迷宫判定导致判定错误等尴尬局面
- MazeTimer=emu.framecount()+1 --指定迷宫判定点为下一帧
- MazeTimer0=MazeTimer
- if PipeMazeMode then MazeTimer=MazeTimer+9 end --水管迷宫模式可将判定时间随机延后8帧,这样8-4第一场景才能进入水管
- MazeMode=true
- elseif emu.framecount()-MazeTimer>=0 and emu.framecount()-MazeTimer<2 then --若当前帧为迷宫判定点
- if X0<MazeX0 or memory.readbyte(0x6D9)~=memory.readbyte(0x6DA) then --若检测到循环,或在7-4走分支失败,走迷宫失败
- MazeFailCount=MazeFailCount+1
- if MazeFailCount>=20 then --连续走迷宫失败20次
- WallFreeTriggerCount=math.max(WallFreeTrigger-100,WallFreeTriggerCount) --例如WallFreeTrigger默认是800,一走迷宫失败就设置成至少700,相当于省了很多撞墙时间
- if MazeX0>BestDeathX0 or (MazeX0==BestDeathX0 and MazeX1>BestDeathX1) then --若走迷宫失败,添加最佳死亡位置记录
- BestDeathX0=MazeX0
- BestDeathX1=MazeX1
- end
- SuggestJumpAtStart=true --暗示开头起跳
- LoadStateBig9() --返回大存档,一般是关卡开头或上一次走迷宫成功处
- MazeFailCount=0 --迷宫失败次数清零
- MazeTimer=0
- else --还没失败20次
- X0=MazeX0 --即将记录的X位置用前一帧的数据,X坐标+15表示防止在迷宫左侧碰敌人死亡也被算X位置超越
- X1=MazeX1+15
- DeathStatAdd(4) --添加失败数据记录,以保存X位置等信息
- if MazeFailCount==15 then CurrentState=sub1(CurrentState) end --失败第15次时,再返回一层存档
- if FrameStart[CurrentState]>MazeTimer0-3 then CurrentState=sub1(CurrentState) end --避免让存档点离迷宫判定点太近,如果不做这判断很可能会在迷宫判定点落地而出现问题
- if WallFreeFrame2>=MazeTimer then --假如迷宫重试时,还在第一次撞墙之后,则FrameRetry要设置对,防止继续撞墙
- FrameRetry=WallFreeFrame0
- else
- FrameRetry=emu.framecount()+40 --防止总在迷宫点附近起跳
- end
- Retry() --再试看看能否走出迷宫,同时迷宫时间点清零
- MazeTimer=0
- emu.print("Maze fail, MFC="..MazeFailCount)
- end
- elseif (X0==MazeX0 and X1>MazeX1) or X0>MazeX0 then --若没循环,表示走迷宫成功!
- WallFreeMode=0 --关闭自由撞墙模式
- WallFreeTriggerCount=0
- WallFreeEmpty() --清空自由撞墙模式下相关数值
- MazeTimer=0
- MazeFailCount=0 --迷宫失败次数清零
- MazeMode=false
- PipeMazeMode=false
- SaveNewStateBig9() --保存大存档
- emu.print("Maze win!")
- end
- elseif MazeMode==false then --若LoopCommand==0
- MazeTimer=0 --迷宫时间点清空
- end
- end
- function MarioJump() --跳跃
- if PressDown==0 or Swimming then JumpTimer=math.random(1,35) end --跳跃力度在1-32之间
- end
- function MarioBigJump() --大力度跳跃
- JumpTimer=math.random(24,35) --跳跃力度在1-32之间
- emu.print("MarioBigJump")
- end
- function Retry() --重试
- RetryCount=RetryCount+1
- if AttamptCount[CurrentState]>0 then
- AttamptCount[CurrentState]=AttamptCount[CurrentState]-1 --减少一次该存档对应的剩余尝试次数
- else --要是剩余尝试次数为0了
- CurrentState=sub1(CurrentState)
- end
- savestate.load(SS[CurrentState]) --读档
- X0=memory.readbyte(0x6D)
- if X0>128 then X0=0 end --防止迷宫中此值能达到255影响判断
- X1=memory.readbyte(0x86) --读档后更新内存地址,防止后面判断出错
- X2=memory.readbyte(0x400)
- Y0=memory.readbyte(0xB5)
- Y1=memory.readbyte(0xCE)
- SX1=memory.readbyte(0x57)
- SY1=memory.readbyte(0x9F)
- S1=memory.readbyte(0x3AD)
- S2=memory.readbyte(0x71C)
- st=memory.readbyte(0x1D)
- E0=memory.readbyte(0x0E)
- ScrollLock=memory.readbyte(0x723)
- LoopCommand=memory.readbyte(0x745) --读档后必须刷新迷宫循环判定,否则之前信息延留会出现问题
- if FrameFall>FrameStart[CurrentState] then --假如掉落时间在存档后,则在开始和掉落这段时间内起跳
- FrameLast=math.min(FrameFall-1,FrameRetry-2) --计算有效范围最后一帧
- else --掉落时间无效,于是在开始和重试-2这段时间内起跳
- FrameLast=FrameRetry-2 --计算不算掉落帧的话有效范围最后一帧
- end
- if FrameRunningLast[CurrentState]>=FrameStart[CurrentState] then --FrameRunningLast表示允许跑动的最后一帧,也就是说在开始跑动帧到这帧中间必须起跳
- FrameLast=math.min(FrameLast,FrameRunningLast[CurrentState])
- end
- if FrameLast>FrameStart[CurrentState] then
- FrameJump=math.random(FrameStart[CurrentState],FrameLast) --将跳跃位置定在有效范围中间
- else
- FrameJump=FrameStart[CurrentState] --如果FrameLast比存档起始帧小的话,就在起始帧起跳
- end
- if math.random(10)==1 or (FrameRunningLast[CurrentState]==0 and math.random(5)==1) then --有1/10的概率将起跳时间前移,有可能导致不起跳,为了避免离敌人比较近的时候每次试都是跳着试,给一点点跑过去的机会
- if FrameRunningLast[CurrentState]>=FrameStart[CurrentState] then --若最后允许跑动帧有效,则跳跃随机在存档和最后允许跑动帧中间
- FrameJump=math.random(FrameStart[CurrentState],FrameRunningLast[CurrentState])
- else --最后允许跑动帧无效,则跳跃时间提前40帧,有可能导致不起跳
- FrameJump=FrameJump-40
- end
- end
- if FrameRetry==0 then --FrameRetry=0暗示读档后计算起跳时间无效,会沿用随机起跳状态
- FrameJump=FrameStart[CurrentState]-9
- end
- if SuggestJumpAtStart then
- if math.random(3)<3 then
- FrameJump=FrameStart[CurrentState] --赋予2/3的几率刚读档就起跳
- end
- SuggestJumpAtStart=false
- end
- if FirstFrameJumpChance>0 and not Swimming and SX1>24 then --检测到有首帧即跳的概率,会随机一部分(1/6到5/6的概率)让其首帧跳
- if math.random(6)<=math.min(FirstFrameJumpChance,5) then --最小概率1/6,最大概率5/6
- FrameJump=FrameStart[CurrentState] --刚读档就起跳
- end
- end
- if Swimming then --游泳时加入慢游快游两种状态,读档后随机其中一种
- if math.random(2)==1 then --一半概率为慢游 一半概率为快游
- SwimRandomness=SwimRandomnessSlow
- else
- SwimRandomness=SwimRandomnessFast
- end
- end
- st=memory.readbyte(0x1D) --重新判断状态,很可能为0
- lastst=0 --读档后将上一个st清零,不然会判断错误陷入死循环
- lastframe=0
- JumpTimer=0
- WallFreeEmpty() --自由撞墙模式的数值清空
- MazeJudge() --读档后再次判断迷宫
- PressLeft=0 --向右走
- JustLoaded=1
- end
- function MarioEnemy() --马里奥碰敌人
- EnemyCount=EnemyCount+1
- DeathStatAdd(1) --添加碰敌人死亡记录
- if lastst==0 and lastframe+1==emu.framecount() then --如果重试的前一帧马里奥还在地面跑,将最后一帧跑动帧设置成当前帧
- FrameRunningLast[CurrentState]=math.max(FrameStart[CurrentState],emu.framecount()-3)
- end
- if FailEnemyCount>=500 then --无进展碰敌人每500次,返回之前安全大存档减速重试
- RestartLevel()
- PressLeft=math.random(120) --随机按左0-2秒
- emu.print("PressLeft="..PressLeft)
- else
- FrameRetry=emu.framecount()-1 --假如碰敌人死,死亡时间前移1帧(需要提前3帧起跳才有可能避开敌人,后面会减2帧)
- Retry()
- end
- end
- function MarioHole() --马里奥落沟中死亡
- HoleCount=HoleCount+1
- DeathStatAdd(2) --添加落沟死亡记录
- if FrameFall>FrameStart[CurrentState] and FrameFall<emu.framecount() then --判断如果跑入沟中,则将坠落前一帧设为允许跑动最后一帧
- FrameRunningLast[CurrentState]=FrameFall-1
- end
- if SameDeathCount>=HoleMax then --假如同一沟中死亡次数过多
- CurrentState=sub1(CurrentState) --返回前一存档
- SuggestJumpAtStart=true --建议开头跳跃
- emu.print("HoleMax!")
- end
- FrameRetry=emu.framecount()-8 --假如掉沟死,死亡时间前移8帧
- Retry()
- end
- function MarioWall() --马里奥撞墙,假如在允许的时间内撞到允许的墙则没事,关键参数WallAllowedFrame、WallAllowX0和WallAllowX1都是在DeathStatAdd()中计算
- local SameWallAsAllowed
- X1=math.floor(X1/16)*16+2 --如果撞墙,将X1值统一为16整数倍+2,避免出现穿墙或斜角入墙导致判定错误等尴尬局面
- if WallFreeMode==0 then --正常模式(非自由撞墙模式)
- if X0==WallAllowX0 and X1==WallAllowX1 then --判断是否撞到了允许的墙上
- SameWallAsAllowed=true --撞到了允许的墙上
- else
- SameWallAsAllowed=false --撞到的是别的墙
- end --以上代码没啥用,以下代码是关键
- if SameWallAsAllowed==false then --假如撞的墙不是允许的墙
- WallCount=WallCount+1
- DeathStatAdd(3) --添加撞墙记录
- if SameDeathCount>=WallMax then --假如连续太多次(25)撞到相同墙
- CurrentState=sub1(CurrentState) --返回前一存档
- SuggestJumpAtStart=true --建议开头跳跃
- emu.print("WallMax!")
- end
- if ScrollLock==1 then --如果到水关结尾位置(或城堡关最后),撞100次墙后就赋予Mario自由撞墙能力
- WallFreeTriggerCount=math.max(WallFreeTrigger-50,WallFreeTriggerCount) --例如WallFreeTrigger默认是500,一到水关结尾就设置成至少400,相当于省了很多撞墙时间
- end
- if lastst==0 and lastframe+1==emu.framecount() then --如果重试的前一帧马里奥还在地面跑,将最后一帧跑动帧设置成当前帧
- FrameRunningLast[CurrentState]=math.max(FrameStart[CurrentState],emu.framecount()-2)
- end
- FrameRetry=emu.framecount()
- Retry() --普通撞墙重试
- else --撞到允许墙
- if emu.framecount()>WallAllowedFrame then --假如已经越过允许的最大撞墙时间,又撞到了被允许的墙上
- while FrameStart[sub1(CurrentState)]>BestDeath-20 do --前一存档的起始时间必须小于撞墙时间10帧,不然就前一一存档,这是为防止2-2结尾进入1格狭缝做大量存档导致死循环
- CurrentState=sub1(CurrentState)
- end
- WallFreeTriggerCount=WallFreeTriggerCount+1 --无进展撞墙计数+1
- FrameRetry=BestWallHit --重试时间设为初次撞墙时间
- Retry() --则不计入撞墙和死亡记录,但依然会重来
- end
- emu.print("Same wall again!")
- end
- elseif WallFreeMode==1 then --假如到自由撞墙模式(累计无进展撞墙次数过多导致,一般是在2-2结尾或迷宫关)
- if emu.framecount()>WallFreeFrame2 then --第一次撞墙,或若在第一次撞墙2秒后又撞到墙,则设定为新第一次撞墙
- WallFreeFrame0=emu.framecount()
- WallFreeX0=X0
- WallFreeX1=X1
- if math.random(3)<=2 and SY1>1 and SY1<9 and MazeMode and not PipeMazeMode then --2/3的概率且有向下速度的时候向左走,例如4-4的情况
- PressLeft=120
- WallFreeFrame1=WallFreeFrame0+WallFreeTimer1 --第一个判定节点,马里奥按右才能通过
- WallFreeFrame2=WallFreeFrame0+WallFreeTimer2 --第二个判定节点,马里奥比撞墙时X位置大才能通过
- else --1/3的概率或二段跳的时候向右走,例如2-2和8-4的情况
- WallFreeFrame2=WallFreeFrame0+WallFreeTimer3 --第二个判定节点,马里奥比撞墙时X位置大才能通过
- end
- if st>0 and SY1<9 and memory.readbyte(0x86)>=X1+2 and memory.readbyte(0x86)<=X1+3 then --检测穿墙
- PressLeft=3
- SuggestJumpAtStart=true --落地即跳
- end
- if S1>236 then --防止4-2进入Warp Zone死循环
- WarpZoneCount=WarpZoneCount+1
- if WarpZoneCount>9 then
- RestartLevel()
- WallFreeMode=0 --关闭自由撞墙模式
- WallFreeTriggerCount=0 --清空
- WallFreeEmpty() --自由撞墙模式的数值清空
- end
- end
- emu.print("First wall bump at "..WallFreeFrame0)
- else --若本次撞墙还在撞墙时间范围内
- if X0==WallFreeX0 and X1==WallFreeX1 then --若撞的墙是第一次撞墙,保持撞墙后随机的方向
- else --若撞的墙和第一次撞墙不是一个墙,则有很大概率会向右走
- PressLeft=0
- end
- end
- end
- end
- function MarioFall() --马里奥开始下落
- FrameFall=emu.framecount()
- if math.random(3)==1 and WallFreeMode==0 and SY1<8 then --下落有三分之一概率会重试,为提高4-3和4-4等关卡的概率,判断纵向速度是Mars的主意,为防止踩弹簧弹跳也重来
- FrameRetry=emu.framecount()+1
- Retry()
- end
- end
- function MarioLand() --马里奥刚落地
- if WallFreeMode==0 or emu.framecount()>WallFreeFrame2 or emu.framecount()==WallFreeFrame0 then --正常模式,或自由撞墙模式已过时间范围,或落地这帧刚好是第一次撞墙帧,允许二段跳的可能
- if (emu.framecount()==DeathState[1] and math.random(DeathStateCount[1])>10) or (emu.framecount()==DeathState[2] and math.random(DeathStateCount[2])>10 and SX1~=0 and memory.readbyte(0x70E)==0) then --若触发死亡存档以及死亡概率,DeathStateCount越大重试概率越大
- FrameRetry=emu.framecount()
- Retry() --重新再来
- emu.print("DeathStateCount[1]="..DeathStateCount[1]..", DeathStateCount[2]="..DeathStateCount[2])
- else --假如没触发死亡存档,则可新建存档
- SaveNewState()
- if FirstFrameJumpChance>0 and not Swimming and SX1>24 then --检测到有首帧即跳的概率,会随机一部分(1/6到5/6的概率)让其一落地就跳
- if math.random(6)<=math.min(FirstFrameJumpChance,5) then --最小概率1/6,最大概率5/6
- MarioJump() --瞬间起跳
- if math.random(30)<=math.min(FirstFrameJumpChance,10) then --最小概率1/30,最大概率10/30即三分之一的概率大力度起跳
- MarioBigJump() --用24-35之间的大力度跳
- end
- end
- end
- if SX1==0 and (WallFreeMode==0 or emu.framecount()==WallFreeFrame0) then --如果落地瞬间速度为0,暗示很可能是二段跳瞬间,不能放过
- MarioBigJump() --瞬间大力度起跳
- PressLeft=0 --确保是向右跳,向左跳无意义
- AttamptCount[CurrentState]=AttamptCount[CurrentState]+2 --因为可能是二段跳,奖励两次尝试机会
- elseif PipeMazeMode and memory.readbyte(0x750)~=PipeExitBan and memory.readbyte(0x751)~=PipeExitBan2 and memory.readbyte(0x751)~=PipeExitBan3 then --如果是水管迷宫模式,水管出口信息和关卡开头不一样,则按下1帧
- PressDown=1
- elseif memory.readbyte(0x750)==PipeExitBan then --设置并判断第二个不允许的管道信息,751
- if PipeExitBan2==memory.readbyte(0x751) then
- else
- PipeExitBan3=PipeExitBan2
- PipeExitBan2=memory.readbyte(0x751)
- end
- end
- end
- elseif SuggestJumpAtStart then --假如自由撞墙模式开启且在时间范围内,落地就不存档
- MarioJump() --落地即起跳,可能是前面有穿墙动作,建议起跳
- SuggestJumpAtStart=false
- end
- end
- function MarioFlagpole() --马里奥碰旗杆
- Gaming=0
- WallFreeMode=0
- emu.print("MarioFlagpole")
- end
- function MarioPipe() --马里奥进水管
- Gaming=0
- WallFreeMode=0
- emu.print("MarioPipe")
- end
- function MarioCastle() --马里奥城堡关碰斧头
- Gaming=0
- WallFreeMode=0
- Castle=1
- emu.print("MarioCastle="..Castle)
- end
- function MarioSwim() --水下游泳状态
- if math.random(SwimRandomness)==1 then
- JumpTimer=2 --这里不用MarioJump,因为游泳每下如果游多可能会冲突
- end
- if emu.framecount()-FrameStart[CurrentState]>SwimMax and WallFreeMode==0 then --到达最大存档间隔,水中默认最多每隔2秒保存一个存档
- SaveNewState()
- end
- if SX1>16 then --在水中地面上速度大于16就按下
- controller.down=true
- end
- end
- gui.register(everything) --显示值用
- while true do --主循环
- controller.down=false
- controller.left=false
- controller.right=false
- controller.A=false
- controller.B=false
- controller.start=false
- X0=memory.readbyte(0x6D)
- if X0>128 then X0=0 end --防止迷宫中此值能达到255影响判断
- X1=memory.readbyte(0x86)
- X2=memory.readbyte(0x400)
- Y0=memory.readbyte(0xB5)
- Y1=memory.readbyte(0xCE)
- SX1=memory.readbyte(0x57)
- SY1=memory.readbyte(0x9F)
- S1=memory.readbyte(0x3AD)
- S2=memory.readbyte(0x71C)
- st=memory.readbyte(0x1D)
- E0=memory.readbyte(0x0E)
- ScrollLock=memory.readbyte(0x723)
- LoopCommand=memory.readbyte(0x745) --迷宫循环判定
- JustLoaded=0 --为防止读档后st值错乱加的判定
- if Gaming>1 then --执行开局倒跳
- controller.B=true
- controller.left=Acceleration[(25-Gaming)*3+1]
- controller.right=Acceleration[(25-Gaming)*3+2]
- controller.A=Acceleration[(25-Gaming)*3+3] --用存储在Acceleration中的按键
- Gaming=Gaming-1
- if Gaming==4 and st==0 then --这帧默认是左右都不按,但要是这帧在地上则要按左右
- controller.left=true
- controller.right=true
- controller.B=true
- end
- if Gaming==2 then --存个大档
- SaveNewStateBig9()
- end
- elseif Gaming==1 then --主要游戏部分
- if Y1>196 and Y0==1 then --掉坑的新判定,不用以前的音效,而是用坐标
- MarioHole()
- elseif memory.readbyte(0x00FC)==1 then
- MarioEnemy()
- elseif memory.readbyte(0x0713)==64 then
- MarioFlagpole()
- elseif E0==3 or E0==2 then
- MarioPipe()
- elseif SX1==0 then --撞墙
- MarioWall()
- elseif memory.readbyte(0x770)==2 then --判断碰斧头通关
- MarioCastle()
- end
- if Gaming==1 then --如果游戏还在继续
- if memory.readbyte(0x0704)==1 then --判断游泳状态
- Swimming=true
- MarioSwim()
- StateCloseAllow=30 --游泳时设置值大一些
- else
- Swimming=false
- StateCloseAllow=20
- end
- if WallFreeMode>0 then --若是自由撞墙模式,有两个时间节点要判断
- if emu.framecount()<=WallFreeFrame2 and X0==WallFreeX0 and X1>WallFreeX1+4 then --若过了第一次撞墙的位置
- if st==0 then SaveNewState() end --还在地面就存个档,如果在空中就不必存档了,因为落地时会存档
- WallFreeEmpty() --自由撞墙模式的数值清空
- elseif emu.framecount()==WallFreeFrame1 and PressLeft>0 then --在第一时间节点Mario必须是向右走的,向左走不允许
- while WallFreeFrame0>0 and FrameStart[sub1(CurrentState)]>WallFreeFrame0-StateCloseAllow do --前一存档的起始时间必须小于撞墙时间20帧,不然就前移一存档,这是为防止2-2结尾进入1格狭缝做大量存档导致死循环
- CurrentState=sub1(CurrentState)
- end
- FrameRetry=WallFreeFrame0 --重试时间设为第一次撞墙时间
- Retry() --返回撞墙前重试,同时将自由撞墙模式数值清空
- elseif emu.framecount()==WallFreeFrame2 then --到第二个节点,但没过第一次撞墙位置
- while WallFreeFrame0>0 and FrameStart[sub1(CurrentState)]>WallFreeFrame0-StateCloseAllow do --前一存档的起始时间必须小于撞墙时间20帧,不然就前移一存档,这是为防止2-2结尾进入1格狭缝做大量存档导致死循环
- CurrentState=sub1(CurrentState)
- end
- FrameRetry=WallFreeFrame0 --重试时间设为第一次撞墙时间
- Retry() --返回撞墙前重试,同时将自由撞墙模式数值清空
- end
- end
- if MazeMode and memory.readbyte(0x750)~=PipeExitBan then PipeMazeMode=true end --迷宫模式下,检测到水管信息变化,则开启水管迷宫模式
- MazeJudge()
- controller.B=true --B键一直打开
- if st==2 and lastst==0 and lastframe+1==emu.framecount() and JustLoaded==0 and Swimming==false then --判断两个st状态差,若开始下落
- MarioFall()
- elseif st==0 and lastst>0 and lastframe+1==emu.framecount() and JustLoaded==0 then --判断刚刚落地状态
- MarioLand()
- elseif PipeMazeMode and st==0 and memory.readbyte(0x86)%16==3 and memory.readbyte(0x750)~=PipeExitBan and memory.readbyte(0x751)~=PipeExitBan2 and memory.readbyte(0x751)~=PipeExitBan3 then --水管迷宫模式在地面跑动到像19这样的位置时会按下1帧
- PressDown=1
- end
- if PressLeft>0 then --如遇特殊情况需要按左
- controller.left=true
- PressLeft=PressLeft-1
- elseif PressDown>0 then
- controller.down=true
- PressDown=0
- else --PressLeft==0并且PressDown==0,表示向右走
- controller.right=true --一直按住右键
- end
- if st==0 then --在地面跑动中
- if FrameJump==emu.framecount() then --若指定当前帧跳
- MarioJump()
- if FirstFrameJumpChance>0 and not Swimming then --检测到有首帧即跳的概率,会随机一部分(1/20到10/30的概率)让其最大力度跳跃
- if math.random(30)<=math.min(FirstFrameJumpChance,10) then --最小概率1/30,最大概率10/30即三分之一的概率最大力度起跳
- MarioBigJump() --用24-35之间的大力度跳
- end
- end
- elseif FrameJump>emu.framecount() then --若指定帧在后面,则继续跑
- elseif math.random(JumpRandomness)==1 then --若没指定跳跃帧的话,参考设定的跳跃概率做随机跳跃
- MarioJump()
- end
- end
- if JumpTimer>0 then --跳跃?
- controller.A=true
- JumpTimer=JumpTimer-1
- end
- lastst=st
- lastframe=emu.framecount()
- end
- else --Gaming==0 游戏还未开始
- if emu.framecount()==41 then --判断按Start的帧
- controller.start=true
- end
- if Castle==1 and E0==0 then
- Castle=0
- end
- if emu.framecount()>99 and E0==8 and Castle==0 then --0x0E=8说明准备开始游戏
- if SY1==0 and memory.readbyte(0x0704)~=1 then --如果在地面且不在游泳
- Gaming=25 --开始开局倒跳
- else
- Gaming=1 --不开局倒跳
- SaveNewStateBig9() --存个大档
- end
- WallAllowX0=0 --开局将墙允许信息清零
- WallAllowX1=0
- WallAllowedFrame=0
- WallFreeMode=0 --关闭自由撞墙模式
- WallFreeTriggerCount=0 --清空
- WallFreeEmpty() --自由撞墙模式的数值清空
- FailDeathCount=0
- FailEnemyCount=0
- FailHoleCount=0
- FirstFrameJumpChance=0 --清空第一帧跳跃几率
- MazeFailCount=0
- MazeTimer=0
- WarpZoneCount=0
- MazeMode=false
- PipeMazeMode=false
- PipeExitBan=memory.readbyte(0x750)
- controller.left=true
- controller.right=true --开局左右1帧
- end
- if memory.readbyte(0x00FC)==4 and emu.framecount()<FrameEnd then --见到公主音乐响起,保存按键到文件
- file=io.open("SMBbotInput_"..emu.framecount().."_Retry"..RetryCount..".txt","w")
- for FrameEnd=0,emu.framecount() do
- if FrameEnd==41 then file:write("|0|....T...|||\n")
- else
- if (InputRight[FrameEnd]==true) then file:write("|0|R")
- else file:write("|0|.") end
- if (InputLeft[FrameEnd]==true) then file:write("L")
- else file:write(".") end
- if (InputDown[FrameEnd]==true) then file:write("D...")
- else file:write("....") end
- if (InputB[FrameEnd]==true) then file:write("B")
- else file:write(".") end
- if (InputA[FrameEnd]==true) then file:write("A|||\n")
- else file:write(".|||\n") end
- end
- end
- emu.pause()
- end
- end
- if FrameMax<emu.framecount() then --当前帧大于此前最好成绩
- FrameMax=emu.framecount()
- if Turbo and AutoTurbo then
- emu.speedmode("normal") --恢复正常速度
- Turbo=false
- end
- else
- if AutoTurbo and Turbo==false then
- emu.speedmode("maximum") --加速重复部分
- Turbo=true
- end
- end
- joypad.set(1,controller)
- if controller.left then InputLeft[emu.framecount()]=true
- else InputLeft[emu.framecount()]=false end
- if controller.right then InputRight[emu.framecount()]=true
- else InputRight[emu.framecount()]=false end
- if controller.down then InputDown[emu.framecount()]=true
- else InputDown[emu.framecount()]=false end
- if controller.A then InputA[emu.framecount()]=true
- else InputA[emu.framecount()]=false end
- if controller.B then InputB[emu.framecount()]=true
- else InputB[emu.framecount()]=false end
- emu.frameadvance()
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement