diff --git a/BGM/blank.ogg b/BGM/blank.ogg index 4679cc90..477e9f81 100644 Binary files a/BGM/blank.ogg and b/BGM/blank.ogg differ diff --git a/BGM/cruelty.ogg b/BGM/cruelty.ogg index 04191c89..a9478e80 100644 Binary files a/BGM/cruelty.ogg and b/BGM/cruelty.ogg differ diff --git a/BGM/final.ogg b/BGM/final.ogg index 24f69657..7ef90097 100644 Binary files a/BGM/final.ogg and b/BGM/final.ogg differ diff --git a/BGM/infinite.ogg b/BGM/infinite.ogg index ee25b1aa..8f32f656 100644 Binary files a/BGM/infinite.ogg and b/BGM/infinite.ogg differ diff --git a/BGM/newera.ogg b/BGM/newera.ogg new file mode 100644 index 00000000..4e4cab0c Binary files /dev/null and b/BGM/newera.ogg differ diff --git a/BGM/push.ogg b/BGM/push.ogg index 498429ce..06807a2b 100644 Binary files a/BGM/push.ogg and b/BGM/push.ogg differ diff --git a/BGM/race.ogg b/BGM/race.ogg index 46e7ecee..a6feecae 100644 Binary files a/BGM/race.ogg and b/BGM/race.ogg differ diff --git a/BGM/reason.ogg b/BGM/reason.ogg index 3abac919..c91c6f05 100644 Binary files a/BGM/reason.ogg and b/BGM/reason.ogg differ diff --git a/BGM/way.ogg b/BGM/way.ogg index 439928d0..430a4ef1 100644 Binary files a/BGM/way.ogg and b/BGM/way.ogg differ diff --git a/ai.lua b/ai.lua index 31291b5f..05431033 100644 --- a/ai.lua +++ b/ai.lua @@ -49,14 +49,15 @@ FCL[5]=FCL[3] clearScore={[0]=0,0,2,4,12} function ifoverlapAI(f,bk,x,y) if y<1 then return true end - if y>#f then return nil end + if y>#f then return end for i=1,#bk do for j=1,#bk[1]do if f[y+i-1]and bk[i][j]>0 and f[y+i-1][x+j-1]>0 then return true end end end end function resetField(f0,f,start) - while f[start]do + ::L::if f[start]then removeRow(f,start) + goto L end for i=start,#f0 do f[i]=getNewRow() @@ -85,8 +86,9 @@ function getScore(field,bn,cb,cx,cy) if #field==0 then return 9e99 end--PC best for x=1,10 do local h=#field - while field[h][x]==0 and h>1 do + ::L::if field[h][x]==0 and h>1 then h=h-1 + goto L end height[x]=h if x>3 and x<8 and h>highest then highest=h end @@ -136,8 +138,9 @@ function AI_getControls(ctrl) local cb=blocks[bn][dir] for cx=1,11-#cb[1]do--each pos local cy=#Tfield+1 - while not ifoverlapAI(Tfield,cb,cx,cy-1)do + ::L::if not ifoverlapAI(Tfield,cb,cx,cy-1)then cy=cy-1 + goto L end--move to bottom for i=1,#cb do local y=cy+i-1 @@ -156,8 +159,11 @@ function AI_getControls(ctrl) end end end - while #Tfield>0 do + + ::L:: + if #Tfield>0 then removeRow(Tfield,1) + goto L end--Release cache if best.hold then ins(ctrl,8) diff --git a/call&sys.lua b/call&sys.lua index 1fec9af4..b1e1b6d9 100644 --- a/call&sys.lua +++ b/call&sys.lua @@ -12,7 +12,6 @@ function onVirtualkey(x,y) end return nearest end - function buttonControl_key(i) if i=="up"or i=="down"or i=="left"or i=="right"then if not Buttons.sel then @@ -142,7 +141,7 @@ function keyDown.setting2(key) end end function keyDown.play(key) - if key=="escape"then back()return nil end + if key=="escape"then back()return end local m=setting.keyMap for p=1,4 do local lib=setting.keyLib[p] @@ -150,7 +149,7 @@ function keyDown.play(key) for k=1,12 do if key==m[lib[s]][k]then pressKey(k,players[p]) - return nil + return end end end @@ -165,7 +164,7 @@ function keyUp.play(key) for k=1,12 do if key==m[lib[s]][k]then releaseKey(k,players[p]) - return nil + return end end end @@ -220,7 +219,7 @@ function gamepadDown.setting2(key) end end function gamepadDown.play(key) - if key=="back"then back()return nil end + if key=="back"then back()return end local m=setting.keyMap for p=1,4 do local lib=setting.keyLib[p] @@ -228,7 +227,7 @@ function gamepadDown.play(key) for k=1,12 do if key==m[8+lib[s]][k]then pressKey(k,players[p]) - return nil + return end end end @@ -243,7 +242,7 @@ function gamepadUp.play(key) for k=1,12 do if key==m[8+lib[s]][k]then releaseKey(k,players[p]) - return nil + return end end end @@ -254,7 +253,7 @@ function wheelmoved.mode(x,y) modeSel=min(max(modeSel-sgn(y),1),#modeID) levelSel=ceil(#modeLevel[modeID[modeSel]]*.5) end ---Warning,these are not system callbacks! + function love.mousemoved(x,y,dx,dy,t) @@ -267,7 +266,7 @@ function love.mousemoved(x,y,dx,dy,t) if not(B.hide and B.hide())then if abs(mx-B.x)1 then local r - repeat + ::L:: r=players.alive[rnd(#players.alive)] - until r~=p + if r==p then goto L end return r end end @@ -214,7 +246,7 @@ function freshTarget(P) for i=1,#P.atker do if not P.atker[i].alive then rem(P.atker,i) - break + return end end end @@ -292,50 +324,55 @@ function royaleLevelup() end function freshgho() if P.gameEnv._20G or P.keyPressing[7]and P.gameEnv.sdarr==0 then - while not ifoverlap(P.cb,P.cx,P.cy-1)do + ::L::if not ifoverlap(P.cb,P.cx,P.cy-1)then P.cy=P.cy-1 P.spinLast=false + goto L end P.y_img=P.cy else P.y_img=P.cy>#P.field+1 and #P.field+1 or P.cy - while not ifoverlap(P.cb,P.cx,P.y_img-1)do + ::L::if not ifoverlap(P.cb,P.cx,P.y_img-1)then P.y_img=P.y_img-1 + goto L end end end function freshLockDelay() - if P.lockDelay11 or y<1 then return true end - if y>#P.field then return nil end + if y>#P.field then return end for i=1,#bk do for j=1,#bk[1]do if P.field[y+i-1]and bk[i][j]>0 and P.field[y+i-1][x+j-1]>0 then return true end end end end function ckfull(i) - for j=1,10 do if P.field[i][j]==0 then return nil end end + for j=1,10 do if P.field[i][j]==0 then return end end return true end -function checkrow(s,num)--(cy,r) - local c=0--rows cleared - for i=s,s+num-1 do +function checkrow(start,height)--(cy,r) + local c=0 + for i=start,start+height-1 do if ckfull(i)then ins(P.clearing,1,i) - P.falling=P.gameEnv.fall - c=c+1--row cleared+1 + c=c+1 if not P.small then - for k=1,250 do - PTC.dust[P.id]:setPosition(rnd(300),600-30*i+rnd(30)) - PTC.dust[P.id]:emit(1) + local S=PTC.dust[P.id] + for k=1,100 do + S:setPosition(rnd(300),600-30*i+rnd(30)) + S:emit(3) end end end end + if c>0 then P.falling=P.gameEnv.fall end return c end function solid(x,y) @@ -346,6 +383,7 @@ end function resetblock() P.holded=false P.spinLast=false + P.bn,P.cb=rem(P.nxt,1),rem(P.nb,1) P.freshNext() P.sc,P.dir=scs[P.bn][0],0 P.r,P.c=#P.cb,#P.cb[1] @@ -369,7 +407,10 @@ end function pressKey(i,p) P=p P.keyPressing[i]=true - P.isKeyDown[i]=true + if P.id==1 then + virtualkeyDown[i]=true + virtualkeyPressTime[i]=10 + end if i==10 then act.restart() elseif P.alive then @@ -402,8 +443,8 @@ function pressKey(i,p) end function releaseKey(i,p) p.keyPressing[i]=false - p.isKeyDown[i]=false - -- if playmode=="recording"then ins(rec,{-i,frame})end + if p.id==1 then virtualkeyDown[i]=false end + -- if recording then ins(rec,{-i,frame})end end function spin(d,ifpre) local idir=(P.dir+d)%4 @@ -413,7 +454,7 @@ function spin(d,ifpre) if P.id==1 then stat.rotate=stat.rotate+1 end - return nil + return end local icb=blocks[P.bn][idir] local isc=scs[P.bn][idir] @@ -446,7 +487,7 @@ function hold(ifpre) P.hn,P.bn=P.bn,P.hn P.hb,P.cb=blocks[P.hn][0],P.hb - if P.bn==0 then P.freshNext()end + if P.bn==0 then P.bn,P.cb=rem(P.nxt,1),rem(P.nb,1)P.freshNext()end P.sc,P.dir=scs[P.bn][0],0 P.r,P.c=#P.cb,#P.cb[1] P.cx,P.cy=blockPos[P.bn],21+ceil(P.fieldBeneath/30)-P.r+min(int(#P.field*.2),2) @@ -513,11 +554,11 @@ function drop() if P.b2b>480 then showText(P,"Techrash B2B2B","fly",70) csend=6 - sendTime=80 + sendTime=100 exblock=exblock+1 elseif P.b2b>=30 then showText(P,"Techrash B2B","drive",70) - sendTime=70 + sendTime=80 csend=5 else showText(P,"Techrash","stretch",80) @@ -619,7 +660,8 @@ function drop() showText(P,exblock,"zoomout",10,70) end end - while csend>0 and P.atkBuffer[1]do + ::L:: + if csend>0 and P.atkBuffer[1]then if exblock>0 then exblock=exblock-1 else @@ -630,6 +672,7 @@ function drop() if P.atkBuffer[1].amount==0 then rem(P.atkBuffer,1) end + goto L end if csend>0 then if modeEnv.royaleMode then @@ -681,36 +724,6 @@ function lock() end end end -function garbageSend(S,R,send,time) - local pos=rnd(10) - createBeam(S,R,send<4 and 1 or send<7 and 2 or 3) - R.lastRecv=S - if R.atkBuffer.sum<20 then - send=min(send,20-R.atkBuffer.sum) - R.atkBuffer.sum=R.atkBuffer.sum+send - ins(R.atkBuffer,{pos,amount=send,countdown=time,cd0=time,time=0,sent=false,lv=send<4 and 1 or send<7 and 2 or 3}) - if R.id==1 then sysSFX(send<4 and "blip_1"or"blip_2",min(send+1,5)*.1)end - end -end -function garbageRelease() - local t=P.showTime*2 - for i=1,#P.atkBuffer do - local atk=P.atkBuffer[i] - if not atk.sent and atk.countdown<=0 then - for j=1,atk.amount do - ins(P.field,1,getNewRow(13)) - ins(P.visTime,1,getNewRow(t)) - for k=1,#atk do - P.field[1][atk[k]]=0 - end - end - P.atkBuffer.sum=P.atkBuffer.sum-atk.amount - atk.sent=true - atk.time=0 - P.fieldBeneath=P.fieldBeneath+atk.amount*30 - end - end -end act={ moveLeft=function(auto) if P.keyPressing[9]then @@ -735,7 +748,7 @@ act={ if P.keyPressing[9]then if P.atkMode~=2 then P.atkMode=2 - changeAtk(P,P~=mostBadge and mostBadge or secBadge or randomTarget(P)) + freshTarget(P) end else if not auto then @@ -757,7 +770,7 @@ act={ if P.keyPressing[9]then if P.atkMode~=3 then P.atkMode=3 - changeAtk(P,P~=mostDangerous and mostDangerous or secDangerous or randomTarget(P)) + freshTarget(P) end else if P.waiting<=0 then @@ -805,15 +818,17 @@ act={ end, insDown=function()if P.cy~=P.y_img then P.cy,P.lockDelay,P.spinLast=P.y_img,P.gameEnv.lock,false end end, insLeft=function() - while not ifoverlap(P.cb,P.cx-1,P.cy)do + ::L::if not ifoverlap(P.cb,P.cx-1,P.cy)then P.cx,P.lockDelay=P.cx-1,P.gameEnv.lock freshgho() + goto L end end, insRight=function() - while not ifoverlap(P.cb,P.cx+1,P.cy)do + ::L::if not ifoverlap(P.cb,P.cx+1,P.cy)then P.cx,P.lockDelay=P.cx+1,P.gameEnv.lock freshgho() + goto L end end, down1=function() diff --git a/list.lua b/list.lua index d928d91e..368fbb96 100644 --- a/list.lua +++ b/list.lua @@ -29,7 +29,7 @@ PClist={--ZSLJTOI {7,3,2,5},{7,4,6,5},{7,5,2,3},{7,3,5,7},{7,3,2,5},{7,3,5,1},{7,5,2,3},{3,6,2,5}, {3,1,2,5},{3,1,1,5},{3,1,5,2},{3,1,5,1},{3,5,1,2},{4,5,3,2},{4,2,6,5},{6,5,3,2}, {1,4,2,5},{1,5,3,6},{5,2,6,3},{5,2,1,3},{5,2,7,4},{2,4,1,5},{2,4,5,1},{2,1,4,5}, - {2,5,4,3},{2,5,6,7},{7,5,4,2}, + {2,5,4,3},{2,5,6,7},{7,5,4,2},{4,5,3,5}, } color={ red={1,0,0}, @@ -68,7 +68,7 @@ attackColor={ gc.setColor(1,t,0) end, function(t) - gc.setColor(1,.4,.3+t*.7) + gc.setColor(1,.5+t*.5,.5+t*.5) end, function(t) gc.setColor(.2+t*.8,.2+t*.8,1) @@ -94,15 +94,15 @@ blockColor={ } clearName={"Single","Double","Triple"} spinName={[0]={}} +for j=1,7 do + spinName[0][j]=blockName[j].." spin" +end for i=1,3 do spinName[i]={} for j=1,7 do spinName[i][j]=blockName[j].." spin "..clearName[i] end end -for j=1,7 do - spinName[0][j]=blockName[j].." spin" -end miniTitle_rect={ {2,0,5,1},{4,1,1,6}, @@ -132,6 +132,7 @@ bgm={ "blank", "way", "race", + "newera", "push", "reason", "infinite", @@ -205,7 +206,7 @@ customRange={ fall={1,3,5,7,10,15,20,30,60}, next={0,1,2,3,4,5,6}, hold={true,false}, - sequence={1,2,3}, + sequence={"bag7","his4","rnd"}, visible={1,2,3}, target={10,20,40,100,200,500,1000,1e99}, freshLimit={0,8,15,1e99}, @@ -234,6 +235,9 @@ reAtk={0,0,1,1,1,2,2,3,3} reDef={0,1,1,2,3,3,4,4,5} marathon_drop={[0]=60,48,40,30,24,18,15,12,10,8,7,6,5,4,3,2,1,1,0,0} +rush_lock={20,18,16,14,12} +rush_wait={12,10,9,8,7} +rush_fall={12,11,10,9,8} death_lock={12,11,10,9,8} death_wait={9,8,7,6,5} death_fall={10,9,8,7,6} @@ -247,31 +251,37 @@ defaultModeEnv={ drop=60, target=10, reach=Event.gameover.win, + bgm="race", }, { drop=60, target=20, reach=Event.gameover.win, + bgm="race", }, { drop=60, target=40, reach=Event.gameover.win, + bgm="race", }, { drop=60, target=100, reach=Event.gameover.win, + bgm="race", }, { drop=60, target=400, reach=Event.gameover.win, + bgm="push", }, { drop=60, target=1000, reach=Event.gameover.win, + bgm="push", }, }, marathon={ @@ -280,18 +290,32 @@ defaultModeEnv={ lock=1e99, target=200, reach=Event.marathon_reach, + bgm="way", }, { drop=60, fall=20, target=10, reach=Event.marathon_reach, + bgm="way", }, { _20G=true, fall=20, target=200, reach=Event.marathon_reach, + bgm="newera", + }, + { + _20G=true, + drop=0, + lock=rush_lock[1], + wait=rush_wait[1], + fall=rush_fall[1], + target=50, + reach=Event.marathon_reach_lunatic, + arr=2, + bgm="race", }, { _20G=true, @@ -300,8 +324,9 @@ defaultModeEnv={ wait=death_wait[1], fall=death_fall[1], target=50, - reach=Event.marathon_reach_lunatic, + reach=Event.marathon_reach_ultimete, arr=1, + bgm="push", }, }, zen={ @@ -310,6 +335,7 @@ defaultModeEnv={ lock=1e99, target=200, reach=Event.gameover.win, + bgm="infinite", }, }, infinite={ @@ -317,10 +343,13 @@ defaultModeEnv={ drop=1e99, lock=1e99, oncehold=false, + bgm="infinite", }, }, solo={ - {}, + { + bgm="race", + }, }, tsd={ { @@ -329,12 +358,14 @@ defaultModeEnv={ lock=1e99, target=1, reach=Event.tsd_reach, + bgm="reason", }, { drop=60, lock=60, target=1, reach=Event.tsd_reach, + bgm="reason", }, }, blind={ @@ -342,18 +373,21 @@ defaultModeEnv={ drop=30, lock=60, visible=2, + bgm="newera", }, { drop=15, - lock=30, + lock=60, visible=0, freshLimit=10, + bgm="reason", }, { _20G=true, lock=60, visible=0, freshLimit=15, + bgm="reason", }, { _20G=true, @@ -363,6 +397,7 @@ defaultModeEnv={ fall=15, visible=0, arr=1, + bgm="push", }, }, dig={ @@ -370,10 +405,12 @@ defaultModeEnv={ drop=60, lock=120, fall=20, + bgm="push", }, { drop=10, lock=30, + bgm="push", }, }, survivor={ @@ -381,21 +418,25 @@ defaultModeEnv={ drop=60, lock=120, fall=30, + bgm="push", }, { drop=30, lock=60, fall=20, + bgm="newera", }, { drop=10, - lock=20, + lock=60, fall=15, + bgm="race", }, { drop=5, - lock=15, + lock=60, fall=10, + bgm="push", }, }, sudden={ @@ -405,24 +446,28 @@ defaultModeEnv={ lock=1e99, target=0, reach=Event.sudden_reach, + bgm="way", }, { drop=30, lock=60, target=0, reach=Event.sudden_reach, + bgm="way", }, { drop=15, lock=60, target=0, reach=Event.sudden_reach_hard, + bgm="way", }, { drop=5, - lock=20, + lock=40, target=0, reach=Event.sudden_reach_hard, + bgm="way", }, }, pctrain={ @@ -432,20 +477,22 @@ defaultModeEnv={ drop=120, lock=120, fall=20, - sequence=4, + sequence="pc", target=0, freshLimit=1e99, reach=Event.newPC, + bgm="newera", }, { next=4, hold=false, drop=60, lock=60, - fall=15, - sequence=4, + fall=20, + sequence="pc", target=0, reach=Event.newPC, + bgm="newera", }, }, pcchallenge={ @@ -453,26 +500,26 @@ defaultModeEnv={ oncehold=false, drop=300, lock=1e99, - sequence=1, target=100, reach=Event.gameover.win, freshLimit=1e99, + bgm="newera", }, { drop=60, lock=120, fall=10, - sequence=1, target=100, reach=Event.gameover.win, + bgm="infinite", }, { drop=20, lock=60, fall=20, - sequence=1, target=100, reach=Event.gameover.win, + bgm="infinite", }, }, techmino41={ @@ -482,6 +529,7 @@ defaultModeEnv={ royalePowerup={2,5,10,20}, royaleRemain={30,20,15,10,5}, pushSpeed=2, + bgm="race", }, }, techmino99={ @@ -491,36 +539,42 @@ defaultModeEnv={ royalePowerup={2,6,14,30}, royaleRemain={75,50,35,20,10}, pushSpeed=2, + bgm="race", }, }, drought={ { drop=20, - lock=30, - sequence=5, + lock=60, + sequence=drought1, target=100, reach=Event.gameover.win, + bgm="reason", }, { drop=20, - lock=30, - sequence=6, + lock=60, + sequence=drought2, target=100, reach=Event.gameover.win, + bgm="reason", }, }, hotseat={ - {}, + { + bgm="way", + }, }, custom={ { - reach=Event.gameover.win + bgm="reason", + reach=Event.gameover.win, }, }, } modeLevel={ sprint={"10L","20L","40L","100L","400L","1000L"}, - marathon={"EASY","NORMAL","EXTRA","DEATH"}, + marathon={"EASY","NORMAL","HARD","LUNATIC","ULTIMATE"}, zen={"NORMAL"}, infinite={"NORMAL"}, solo={"EASY","NORMAL","HARD","LUNATIC"}, @@ -529,7 +583,7 @@ modeLevel={ dig={"NORMAL","LUNATIC"}, survivor={"EASY","NORMAL","HARD","LUNATIC"}, sudden={"EASY","NORMAL","HARD","LUNATIC"}, - pctrain={"HARD","LUNATIC"}, + pctrain={"NORMAL","LUNATIC"}, pcchallenge={"NORMAL","HARD","LUNATIC"}, techmino41={"EASY","NORMAL","HARD","LUNATIC","ULTIMATE"}, techmino99={"EASY","NORMAL","HARD","LUNATIC","ULTIMATE"}, @@ -585,8 +639,7 @@ modeInfo={ } freshMethod={ - function() - P.bn,P.cb=rem(P.nxt,1),rem(P.nb,1) + bag7=function() if #P.nxt<6 then local bag={1,2,3,4,5,6,7} for i=1,7 do @@ -595,26 +648,41 @@ freshMethod={ end end end, - function() - P.bn,P.cb=rem(P.nxt,1),rem(P.nb,1) - local i,j=nil,0 - repeat - i,j=rnd(7),j+1 - until not(i==P.his[1]or i==P.his[2]or i==P.his[3]or i==P.his[4]) + his4=function() + if #P.nxt<6 then + local j,i=0 + ::L:: + i,j=rnd(7),j+1 + if(i==P.his[1]or i==P.his[2]or i==P.his[3]or i==P.his[4])then goto L end + P.nxt[6],P.nb[6]=i,blocks[i][0] + rem(P.his,1)ins(P.his,i) + end + end, + rnd=function() + local i + ::L:: + i=rnd(7) + if i==P.nxt[5]then goto L end P.nxt[6],P.nb[6]=i,blocks[i][0] - rem(P.his,1)ins(P.his,i) + end,--random + pc=function() + if P.cstat.piece%4==0 then + local r=rnd(#PClist) + local f=P.cstat.event==1 + for i=1,4 do + local b=PClist[r][i] + if f then + if b<3 then b=3-b + elseif b<5 then b=7-b + end + end + ins(P.nxt,b) + ins(P.nb,blocks[b][0]) + end + P.cstat.event=(P.cstat.event+1)%2 + end end, - function() - P.bn,P.cb=rem(P.nxt,1),rem(P.nb,1) - repeat i=rnd(7)until i~=P.nxt[5] - P.nxt[6],P.nb[6]=i,blocks[i][0] - end, - function() - P.bn,P.cb=rem(P.nxt,1),rem(P.nb,1) - --generate in newPC - end, - function() - P.bn,P.cb=rem(P.nxt,1),rem(P.nb,1) + drought1=function() if #P.nxt<6 then local bag={1,2,3,4,5,6} for i=1,6 do @@ -623,14 +691,13 @@ freshMethod={ end end end, - function() - P.bn,P.cb=rem(P.nxt,1),rem(P.nb,1) + drought2=function() if #P.nxt<6 then local bag={1,1,1,2,2,2,3,3,3,4,4,4,6,6,6,5,7} - repeat + ::L:: ins(P.nxt,rem(bag,rnd(#bag))) ins(P.nb,blocks[P.nxt[#P.nxt]][0]) - until not bag[1] + if bag[1]then goto L end end end, } @@ -697,17 +764,17 @@ TRS={ }, [7]={ [01]={{0,0},{1,0},{-2,0},{-2,-1},{1,2}}, - [10]={{0,0},{2,0},{-1,0},{2,1},{-1,-2}}, + [03]={{0,0},{-1,0},{2,0},{2,-1},{-1,2}}, + [10]={{0,0},{2,0},{-1,0},{-1,-2},{2,1},{0,2}}, + [30]={{0,0},{-2,0},{1,0},{1,-2},{-2,1},{0,2}}, [12]={{0,0},{-1,0},{2,0},{-1,2},{2,-1}}, + [32]={{0,0},{1,0},{-2,0},{1,-2},{-2,-1}}, [21]={{0,0},{-2,0},{1,0},{1,-2},{-2,1}}, [23]={{0,0},{2,0},{-1,0},{-1,-2},{2,1}}, - [32]={{0,0},{-2,0},{1,0},{-2,-1},{1,2}}, - [30]={{0,0},{1,0},{-2,0},{1,-2},{-2,1}}, - [03]={{0,0},{-1,0},{2,0},{2,-1},{-1,2}}, [02]={{0,0},{-1,0},{1,0},{0,-1},{0,1}}, [20]={{0,0},{1,0},{-1,0},{0,1},{0,-1}}, [13]={{0,0},{0,-1},{-1,0},{1,0},{0,1}}, - [31]={{0,0},{0,-1},{1,0},{-1,0},{0,1}}, + [31]={{0,0},{0,1},{1,0},{-1,0},{0,1}}, } }TRS[3],TRS[4]=TRS[2],TRS[1] @@ -861,7 +928,10 @@ virtualkey={ {x=0,y=0,r=0},--toRight {x=0,y=0,r=0},--toDown ]] + } +virtualkeyDown={false,false,false,false,false,false,false,false,false,false,false,false,false} +virtualkeyPressTime={0,0,0,0,0,0,0,0,0,0,0,0,0} virtualkeySet={ { {80,720-200,6400,80},--moveLeft @@ -912,16 +982,16 @@ virtualkeySet={ {80,320,6400,80},--restart },--Keyboard set { - {1280-360,40,1600,40},--moveLeft - {1280-280,40,1600,40},--moveRight - {1280-520,40,1600,40},--rotRight - {1280-600,40,1600,40},--rotLeft - {1280-440,40,1600,40},--rotFlip - {1280-40,40,1600,40},--hardDrop - {1280-120,40,1600,40},--softDrop - {1280-200,40,1600,40},--hold - {1280-680,40,1600,40},--swap - {-10,-10,0,0},--restart + {1280-360,40,0,40},--moveLeft + {1280-280,40,0,40},--moveRight + {1280-520,40,0,40},--rotRight + {1280-600,40,0,40},--rotLeft + {1280-440,40,0,40},--rotFlip + {1280-40,40,0,40},--hardDrop + {1280-120,40,0,40},--softDrop + {1280-200,40,0,40},--hold + {1280-680,40,0,40},--swap + {1280-760,40,0,40},--restart },--PC key feedback } diff --git a/main.lua b/main.lua index 742f3077..07ada2a1 100644 --- a/main.lua +++ b/main.lua @@ -54,11 +54,12 @@ gameEnv0={ drop=30,lock=45, wait=1,fall=1, next=6,hold=true,oncehold=true, - sequence=1,visible=1, + sequence="bag7",visible=1, _20G=false,target=1e99, freshLimit=15, virtualkey={}, reach=null, + bgm="race" --not all is actually used,some only provide a key } customSel={ @@ -78,28 +79,23 @@ loadmode={ sprint=function() createPlayer(1,340,15) curBG="game1" - BGM("race") end, marathon=function() createPlayer(1,340,15) curBG="strap" - BGM("way") end, zen=function() createPlayer(1,340,15) curBG="strap" - BGM("infinite") end, infinite=function() createPlayer(1,340,15) curBG="glow" - BGM("infinite") end, solo=function() createPlayer(1,20,15)--Player createPlayer(2,660,85,.9,customRange.opponent[3*curMode.lv])--AI curBG="game2" - BGM("race") end, death=function() createPlayer(1,340,15) @@ -109,12 +105,10 @@ loadmode={ tsd=function() createPlayer(1,340,15) curBG="matrix" - BGM("reason") end, blind=function() createPlayer(1,340,15) curBG="glow" - BGM("push") end, dig=function() createPlayer(1,340,15) @@ -127,121 +121,76 @@ loadmode={ pushSpeed=1 end curBG="game2" - BGM("push") end, survivor=function() createPlayer(1,340,15) local P=players[1] - if curMode.lv==1 then - ins(players[1].task,Event.task.survivor_easy) - pushSpeed=1 - elseif curMode.lv==2 then - ins(players[1].task,Event.task.survivor_normal) - pushSpeed=1 - elseif curMode.lv==3 then - ins(players[1].task,Event.task.survivor_hard) - pushSpeed=2 - elseif curMode.lv==4 then - ins(players[1].task,Event.task.survivor_lunatic) - pushSpeed=2 - end + ins(players[1].task,Event.task[curMode.lv==1 and"survivor_easy"or curMode.lv==2 and"survivor_normal"or curMode.lv==3 and"survivor_hard"or curMode.lv==4 and"survivor_lunatic"]) + pushSpeed=curMode.lv>2 and 2 or 1 curBG="game2" - BGM("push") end, sudden=function() createPlayer(1,340,15) curBG="matrix" - BGM("way") end, pctrain=function() createPlayer(1,340,15) - local r=rnd(#PClist) - local P=players[1] - for i=1,4 do - local b=PClist[r][i] - ins(P.nxt,b) - ins(P.nb,blocks[b][0]) - end + P=players[1] Event.newPC() + P.freshNext() curBG="matrix" - BGM("infinite") end, pcchallenge=function() createPlayer(1,340,15) curBG="matrix" - BGM("infinite") end, techmino41=function() createPlayer(1,340,15)--Player if curMode.lv==5 then players[1].gameEnv.drop=15 end local n,min,max=2 - if curMode.lv==1 then - min,max=5,30 - elseif curMode.lv==2 then - min,max=3,25 - elseif curMode.lv==3 then - min,max=2,20 - elseif curMode.lv==4 then - min,max=2,10 - elseif curMode.lv==5 then - min,max=1,6 + if curMode.lv==1 then min,max=5,30 + elseif curMode.lv==2 then min,max=3,25 + elseif curMode.lv==3 then min,max=2,20 + elseif curMode.lv==4 then min,max=2,10 + elseif curMode.lv==5 then min,max=1,6 end - for i=1,4 do - for j=1,5 do - createPlayer(n,77*i-55,140*j-125,.2,rnd(min,max)) - n=n+1 - end - end - for i=9,12 do - for j=1,5 do - createPlayer(n,77*i+275,140*j-125,.2,rnd(min,max)) - n=n+1 - end - end--AIs + for i=1,4 do for j=1,5 do + createPlayer(n,77*i-55,140*j-125,.2,rnd(min,max)) + n=n+1 + end end + for i=9,12 do for j=1,5 do + createPlayer(n,77*i+275,140*j-125,.2,rnd(min,max)) + n=n+1 + end end + --AIs curBG="game3" - BGM("race") end, techmino99=function() createPlayer(1,340,15)--Player if curMode.lv==5 then players[1].gameEnv.drop=15 end local n,min,max=2 - if curMode.lv==1 then - min,max=5,32 - elseif curMode.lv==2 then - min,max=3,25 - elseif curMode.lv==3 then - min,max=2,18 - elseif curMode.lv==4 then - min,max=2,12 - elseif curMode.lv==5 then - min,max=1,12 + if curMode.lv==1 then min,max=5,32 + elseif curMode.lv==2 then min,max=3,25 + elseif curMode.lv==3 then min,max=2,18 + elseif curMode.lv==4 then min,max=2,12 + elseif curMode.lv==5 then min,max=1,12 end - for i=1,7 do - for j=1,7 do - createPlayer(n,46*i-36,97*j-72,.135,rnd(min,max)) - n=n+1 - end - end - for i=15,21 do - for j=1,7 do - createPlayer(n,46*i+264,97*j-72,.135,rnd(min,max)) - n=n+1 - end - end--AIs + for i=1,7 do for j=1,7 do + createPlayer(n,46*i-36,97*j-72,.135,rnd(min,max)) + n=n+1 + end end + for i=15,21 do for j=1,7 do + createPlayer(n,46*i+264,97*j-72,.135,rnd(min,max)) + n=n+1 + end end + --AIs curBG="game3" - BGM("race") end, drought=function() createPlayer(1,340,15) curBG="strap" - BGM("reason") - end, - gmroll=function() - createPlayer(1,340,15) - curBG="glow" - BGM("push") end, hotseat=function() if curMode.lv==1 then @@ -258,10 +207,8 @@ loadmode={ createPlayer(4,955,160,.5) end curBG="game2" - BGM("way") end, custom=function() - modeEnv={} for i=1,#customID do local k=customID[i] modeEnv[k]=customRange[k][customSel[k]] @@ -275,7 +222,6 @@ loadmode={ createPlayer(2,660,85,.9,modeEnv.opponent) end curBG="matrix" - BGM("reason") end, } mesDisp={ @@ -386,18 +332,20 @@ mesDisp={ Event={ gameover={ win=function() + local P=players.alive[1] P.alive=false P.control=false P.timing=false P.waiting=1e99 P.b2b=0 if modeEnv.royaleMode then - P.rank=#players.alive + P.rank=1 P.result="WIN" changeAtk(P) end - while P.task[1]do + ::L::if P.task[1]then rem(P.task) + goto L end for i=1,#P.atkBuffer do P.atkBuffer[i].sent=true @@ -418,8 +366,9 @@ Event={ P.timing=false P.waiting=1e99 P.b2b=0 - while P.task[1]do + ::L::if P.task[1]then rem(P.task) + goto L end for i=1,#players.alive do if players.alive[i]==P then @@ -430,10 +379,13 @@ Event={ if modeEnv.royaleMode then changeAtk(P) P.result="K.O." - P.rank=#players.alive + P.rank=#players.alive+1 P.strength=0 - if P.lastRecv and P.lastRecv.alive then - local A=P.lastRecv + local A=P + ::L:: + A=A.lastRecv + if A and not A.alive then goto L end + if A and A~=P then if P.id==1 or A.id==1 then throwBadge(P,A,P.badge) P.killMark=A.id==1 @@ -468,13 +420,17 @@ Event={ if P.id==1 and players[2]and players[2].ai then SFX("fail")end ins(P.task,Event.task.lose) if #players.alive==1 then - ins(players.alive[1].task,Event.task.winTrigger) + local t=P + P=players.alive[1] + Event.gameover.win() + P=t end end, }, marathon_reach=function() local s=int(P.cstat.row*.1) if s>=20 then + P.cstat.row=200 Event.gameover.win() else P.gameEnv.drop=marathon_drop[s] @@ -485,6 +441,21 @@ Event={ end, marathon_reach_lunatic=function() if P.gameEnv.target==250 then + P.cstat.row=250 + Event.gameover.win() + else + P.gameEnv.target=P.gameEnv.target+50 + local t=P.gameEnv.target/50 + P.gameEnv.lock=rush_lock[t] + P.gameEnv.wait=rush_wait[t] + P.gameEnv.fall=rush_fall[t] + showText(P,"STAGE "..t,"fly",80,-120) + SFX("reach") + end + end, + marathon_reach_ultimate=function() + if P.gameEnv.target==250 then + P.cstat.row=250 Event.gameover.win() else P.gameEnv.target=P.gameEnv.target+50 @@ -492,7 +463,7 @@ Event={ P.gameEnv.lock=death_lock[t] P.gameEnv.wait=death_wait[t] P.gameEnv.fall=death_fall[t] - showText(P,"STAGE "..t,"fly",80,-120) + showText(P,"STAGE "..t,"beat",80,-120) SFX("reach") end end, @@ -520,7 +491,7 @@ Event={ local P=players[1] if P.cstat.piece%4==0 then if #P.field==#P.clearing then - P.counter=P.cstat.piece==0 and 19 or 0 + P.counter=P.cstat.piece==0 and 20 or 0 ins(P.task,Event.task.PC) if curMode.lv==2 then local s=P.cstat.pc*.5 @@ -535,28 +506,12 @@ Event={ end end end - local r=rnd(#PClist) - local f=P.cstat.pc%2==0 - for i=1,4 do - local b=PClist[r][i] - if f then - if b<3 then b=3-b - elseif b<5 then b=7-b - end - end - ins(P.nxt,b) - ins(P.nb,blocks[b][0]) - end else Event.gameover.lose() end end end, task={ - winTrigger=function() - Event.gameover.win() - return true - end, win=function() P.endCounter=P.endCounter+1 if P.endCounter>80 then @@ -633,7 +588,7 @@ Event={ local P=players[1] P.counter=P.counter+1 if P.counter==max(60,180-2*P.cstat.event)then - ins(P.atkBuffer,{rnd(10),amount=1,countdown=0,cd0=0,time=0,sent=false,lv=1}) + ins(P.atkBuffer,{rnd(10),amount=1,countdown=30,cd0=30,time=0,sent=false,lv=1}) P.counter=0 P.cstat.event=P.cstat.event+1 end @@ -642,15 +597,11 @@ Event={ local P=players[1] P.counter=P.counter+1 if P.counter==max(60,180-2*P.cstat.event)then - local d=P.cstat.event - if rnd()<.33 then - ins(P.atkBuffer,{rnd(10),amount=1,countdown=20,cd0=20,time=0,sent=false,lv=1}) - elseif rnd()<.33 then - ins(P.atkBuffer,{rnd(10),amount=2,countdown=40,cd0=40,time=0,sent=false,lv=1}) - elseif rnd()<.5 then - ins(P.atkBuffer,{rnd(10),amount=3,countdown=60,cd0=60,time=0,sent=false,lv=2}) - else - ins(P.atkBuffer,{rnd(10),amount=4,countdown=90,cd0=90,time=0,sent=false,lv=3}) + local d=P.cstat.event+1 + if d%4==0 then ins (P.atkBuffer,{rnd(10),amount=1,countdown=60,cd0=60,time=0,sent=false,lv=1}) + elseif d%4==1 then ins(P.atkBuffer,{rnd(10),amount=2,countdown=70,cd0=70,time=0,sent=false,lv=1}) + elseif d%4==2 then ins(P.atkBuffer,{rnd(10),amount=3,countdown=80,cd0=80,time=0,sent=false,lv=2}) + elseif d%4==3 then ins(P.atkBuffer,{rnd(10),amount=4,countdown=90,cd0=90,time=0,sent=false,lv=3}) end P.counter=0 P.cstat.event=P.cstat.event+1 @@ -661,9 +612,9 @@ Event={ P.counter=P.counter+1 if P.counter==max(80,150-2*P.cstat.event)then if rnd()<.33 then - ins(P.atkBuffer,{rnd(10),amount=1,countdown=0,cd0=0,time=0,sent=false,lv=1}) + ins(P.atkBuffer,{rnd(10),amount=1,countdown=20,cd0=20,time=0,sent=false,lv=1}) else - ins(P.atkBuffer,{rnd(10),amount=3,countdown=0,cd0=0,time=0,sent=false,lv=1}) + ins(P.atkBuffer,{rnd(10),amount=3,countdown=40,cd0=40,time=0,sent=false,lv=2}) end P.counter=0 P.cstat.event=P.cstat.event+1 diff --git a/paint.lua b/paint.lua index 01e0f7b6..159abd91 100644 --- a/paint.lua +++ b/paint.lua @@ -99,7 +99,7 @@ FX={ setFont(t.font) gc.translate(150,290+t.dy) if t.t<20 then - local k=.2*(5+(25-t.t)^.5)-.5 + local k=.2*(5+(25-t.t)^.5)-.45 gc.scale(k,k) end gc.setColor(1,1,1,a) @@ -156,31 +156,32 @@ function drawPixel(y,x,id,alpha) gc.draw(blockSkin[id],30*x-30,600-30*y) end function drawPixelmini(y,x,id) - gc.draw(blockSkinmini[id],30*x-30,600-30*y,nil,5) + end function VirtualkeyPreview() for i=1,#virtualkey do gc.setColor(1,sel==i and .5 or 1,sel==i and .5 or 1,setting.virtualkeyAlpha*.2) local b=virtualkey[i] - gc.setLineWidth(b[4]*.08) + gc.setLineWidth(b[4]*.07) gc.circle("line",b[1],b[2],b[4]-5) - if setting.virtualkeyIcon then gc.draw(virtualkeyIcon[i],b[1],b[2],nil,2*b[4]*.0125,nil,18,18)end + if setting.virtualkeyIcon then gc.draw(virtualkeyIcon[i],b[1],b[2],nil,b[4]*.025,nil,18,18)end end end function drawVirtualkey() local a=setting.virtualkeyAlpha*.2 local P=players[1] for i=1,#virtualkey do - local p=P.isKeyDown[i] - local b=virtualkey[i] - if p then - gc.setColor(.75,.75,1,a) - else - gc.setColor(1,1,1,a) + local p,b=virtualkeyDown[i],virtualkey[i] + if p then gc.setColor(.75,.75,.75,a) + else gc.setColor(1,1,1,a) + end + gc.setLineWidth(b[4]*.07) + gc.circle("line",b[1],b[2]+virtualkeyPressTime[i],b[4]-5) + if setting.virtualkeyIcon then gc.draw(virtualkeyIcon[i],b[1],b[2]+virtualkeyPressTime[i],nil,b[4]*.025,nil,18,18)end + if virtualkeyPressTime[i]>0 then + gc.setColor(1,1,1,a*virtualkeyPressTime[i]*.1) + gc.circle("line",b[1],b[2],b[4]*(1.4-virtualkeyPressTime[i]*.04)) end - gc.setLineWidth(b[4]*.08) - gc.circle("line",b[1],p and b[2]+15 or b[2],b[4]-5) - if setting.virtualkeyIcon then gc.draw(virtualkeyIcon[i],b[1],p and b[2]+15 or b[2],nil,b[4]*.025,nil,18,18)end end end @@ -261,7 +262,7 @@ end function Pnt.main() gc.setColor(1,1,1) setFont(30) - gc.print("Alpha V0.7.7",370,140) + gc.print("Alpha V0.7.8",370,140) gc.print(system,530,110) gc.draw(titleImage,30,30) end @@ -309,38 +310,38 @@ function Pnt.play() if P.small then gc.push("transform") gc.translate(P.x,P.y)gc.scale(P.size)--Scale - gc.setColor(0,0,0,.4)gc.rectangle("fill",0,0,300,600)--Black Background - gc.setLineWidth(13) + gc.setColor(0,0,0,.4)gc.rectangle("fill",0,0,60,120)--Black Background gc.stencil(stencil_field_small,"replace",1) - gc.translate(0,P.fieldBeneath) + gc.translate(0,P.fieldBeneath*.2) gc.setStencilTest("equal",1) gc.setColor(1,1,1,P.result and max(20-P.endCounter,0)*.05 or 1) for j=int(P.fieldBeneath/30+1),#P.field do if P.falling<=0 or without(P.clearing,j)then for i=1,10 do if P.field[j][i]>0 then - drawPixelmini(j,i,P.field[j][i]) + gc.draw(blockSkinmini[P.field[j][i]],6*i-6,120-6*j) end end end end gc.setStencilTest()--In-playField mask - gc.translate(0,-P.fieldBeneath) - gc.setColor(frameColor[P.strength])gc.rectangle("line",-7,-7,314,614)--Draw boarder + gc.translate(0,-P.fieldBeneath*.2) + gc.setLineWidth(2) + gc.setColor(frameColor[P.strength])gc.rectangle("line",-1,-1,62,122)--Draw boarder if modeEnv.royaleMode then gc.setColor(1,1,1) for i=1,P.strength do - gc.draw(badgeIcon,61*i-47,15,nil,3) + gc.draw(badgeIcon,12*i-7,4,nil,.5) end end if P.result then gc.setColor(1,1,1,min(P.endCounter,60)*.01) - setFont(100) - mStr(P.result,150,235) + setFont(22)mStr(P.result,32,47) + setFont(20)mStr(P.rank,30,82) if P.killMark then - gc.setLineWidth(20) + gc.setLineWidth(4) gc.setColor(1,0,0,min(P.endCounter,25)*.04) - gc.circle("line",150,300,420-10*min(P.endCounter,30)) + gc.circle("line",31,60,84-2*min(P.endCounter,30)) end end gc.pop() @@ -395,8 +396,8 @@ function Pnt.play() gc.draw(PTC.dust[p])--Draw game field gc.setStencilTest()--In-playField mask gc.translate(0,-P.fieldBeneath) - gc.setLineWidth(5) - gc.setColor(1,1,1)gc.rectangle("line",-2,-12,304,614)--Draw boarder + gc.setLineWidth(3) + gc.setColor(1,1,1)gc.rectangle("line",-1,-11,302,612)--Draw boarder local h=0 for i=1,#P.atkBuffer do @@ -410,30 +411,30 @@ function Pnt.play() end if a.countdown>0 then gc.setColor(attackColor[a.lv][1]) - gc.rectangle("fill",307,600-h,12,-bar+5) + gc.rectangle("fill",304,600-h,12,-bar+3) gc.setColor(attackColor[a.lv][2]) - gc.rectangle("fill",307,600-h+(-bar+5),12,-(-bar+5)*(1-a.countdown/a.cd0)) + gc.rectangle("fill",304,600-h+(-bar+3),12,-(-bar+3)*(1-a.countdown/a.cd0)) --Timing else attackColor.animate[a.lv]((sin((Timer()-i)*20)+1)*.5) - gc.rectangle("fill",307,600-h,12,-bar+5) + gc.rectangle("fill",304,600-h,12,-bar+3) --Warning end else gc.setColor(attackColor[a.lv][1]) bar=bar*(20-a.time)*.05 - gc.rectangle("fill",307,600-h,12,-bar+3) + gc.rectangle("fill",304,600-h,12,-bar+2) --Disappear end h=h+bar end--Buffer line gc.setColor(P.b2b<40 and color.white or P.b2b<=480 and color.lightRed or color.lightBlue) - gc.rectangle("fill",-17,600,10,-P.b2b1) + gc.rectangle("fill",-13,600,10,-P.b2b1) gc.setColor(color.red) - gc.rectangle("fill",-23,600-40,16,5) + gc.rectangle("fill",-19,600-40,16,5) gc.setColor(color.blue) - gc.rectangle("fill",-23,600-480,16,5) + gc.rectangle("fill",-19,600-480,16,5) --B2B bar setFont(40) diff --git a/timer.lua b/timer.lua index e1239e37..b3a9557b 100644 --- a/timer.lua +++ b/timer.lua @@ -64,6 +64,11 @@ function Tmr.play(dt) rem(FX.badge,i) end end + for i=1,#virtualkey do + if virtualkeyPressTime[i]>0 then + virtualkeyPressTime[i]=virtualkeyPressTime[i]-1 + end + end for i=1,3 do PTC.attack[i]:update(dt) end @@ -83,7 +88,7 @@ function Tmr.play(dt) P.moving=0 end end - return nil + return end--Counting,include pre-das for p=1,#players do P=players[p] @@ -159,8 +164,9 @@ function Tmr.play(dt) removeRow(P.field,P.clearing[i]) removeRow(P.visTime,P.clearing[i]) end - while P.clearing[1]do + ::L::if P.clearing[1]then rem(P.clearing) + goto L end end elseif P.waiting>0 then @@ -245,7 +251,5 @@ function Tmr.play(dt) PTC.dust[p]:update(dt) end end - if modeEnv.royaleMode and frame%60==0 then - freshMostDangerous() - end + if modeEnv.royaleMode and frame%60==0 then freshMostDangerous()end end \ No newline at end of file diff --git a/toolfunc.lua b/toolfunc.lua index c5c6bee8..41caa20b 100644 --- a/toolfunc.lua +++ b/toolfunc.lua @@ -1,22 +1,22 @@ function string.splitS(s,sep) local t={} - repeat + ::L:: local i=find(s,sep)or #s+1 ins(t,sub(s,1,i-1)) s=sub(s,i+#sep) - until #s==0 + if #s~=0 then goto L end return t end function sgn(i)return i>0 and 1 or i<0 and -1 or 0 end--Row numbe is A-uth-or's id! function stringPack(s,v)return s..toS(v)end function without(t,v) for i=1,#t do - if t[i]==v then return nil end + if t[i]==v then return end end return true end function mStr(s,x,y) - gc.printf(s,x-250,y,500,"center") + gc.printf(s,x-300,y,600,"center") end function getNewRow(val) @@ -66,7 +66,7 @@ function stencil_field() gc.rectangle("fill",150,60,300,610) end function stencil_field_small() - gc.rectangle("fill",0,0,300,600) + gc.rectangle("fill",0,0,60,120) end --Single-usage funcs @@ -78,14 +78,15 @@ end function sysSFX(s,v) if setting.sfx then local n=1 - while sfx[s][n]:isPlaying()do + ::L::if sfx[s][n]:isPlaying()then n=n+1 if not sfx[s][n]then sfx[s][n]=sfx[s][n-1]:clone() sfx[s][n]:seek(0) - break + goto quit end - end + goto L + end::quit:: sfx[s][n]:setVolume(v or 1) sfx[s][n]:play() end @@ -93,14 +94,15 @@ end function SFX(s,v) if setting.sfx and not P.ai then local n=1 - while sfx[s][n]:isPlaying()do + ::L::if sfx[s][n]:isPlaying()then n=n+1 if not sfx[s][n]then sfx[s][n]=sfx[s][n-1]:clone() sfx[s][n]:seek(0) - break + goto quit end - end + goto L + end::quit:: sfx[s][n]:setVolume(v or 1) sfx[s][n]:play() end