-- title: MainFighter -- author: Nalquas -- desc: A rail-shooter set in a fake-3D world made for #FC_JAM. -- script: lua -- input: gamepad -- saveid: MainFighterGame -- Summary of license: You can do whatever you want IF you include the license below, unaltered! -- ============LICENSE============= -- MainFighter - A rail-shooter set in a fake-3D world made for #FC_JAM. -- Copyright (C) 2017-2018 Niklas 'Nalquas' Freund -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- =========END OF LICENSE========= -- Summary of license: You can do whatever you want IF you include the license below, unaltered! --[[ Dev Notes Rough Dev-Log: 23.10.2017 (Day 1): Intro Sequence, Menu Code 24.10.2017 (Day 2): Ground Animation, Player Movement/Animation, Scrolling Background 25.10.2017 (Day 3): Shooting, Ground Enhancement (Stones), Overlay Pause of Development for 4 Days 30.10.2017 (Day 4): Enemy Spawning, Relative Movement of Shots/Enemies to Ground, Enemy Destruction Logic Pause of Development for 2 Days 02.11.2017 (Day 5): Basic Enemy AI, Improved Shooting Routine, Perfected relative Movement, Player Destruction Logic, Explosion Effects, Game Over Effect 03.11.2017 (Day 5.5): Game Over Menu Logic, Foundation for adding story intro 04.11.2017 (Day 6): Story Intro, Foundation for Boss of Level 1 (Mega-TriWing), Improved AI Behaviour 05.11.2017 (Day 7): Boss Behaviour, Title "MainFighter", Victory Menu, Sound Effects, Menu Background Initial Release (Only Level 1 Available) 17.12.2018: Minor improvements on the old menu layout; Smooth ground scrolling, smooth intro; Minor rephrasing 18.12.2018: Reduce intensity of ground/intro bars flying by (made even non-epileptic people sick...); Added a crosshair for easier aiming 22.12.2018: Fixed pmem usage Maximum length: 65.536 Symbols Pmem Definition: 0 - empty 1 - Inverted Y Axis or not? 2-255 - Empty Sounds: 0: BEEP / Boss Spawning (Make it somewhat silent, PLEASE) 1: Engine 2: Shot 3: Explosion 4: Player was hit 5-62: Random Noise / Unassigned 63: Typing Play Area Definition: X: 0-420 (Left-Right) (at offsetFactor=0.75) Y: 0-136 (Up-Down) Z= 0-128 (Distant-Near) (Player at 128) Levels: 0 - Short Story Introduction (No Gameplay - It's a "Cutscene"!) 1 - Earth-like planet, keep it somewhat easy 2 - Space (Asteroid Field?) 3 - Final Level, Alien World with geometric forms (Triangles? O.o), make it hard TO-DO: +Replace printCenter commands with manually positioned print commands (saves space) --]] -- VARIABLES: FPS local FPS={value =0,frames =0,lastTime=-1000} function FPS:getValue() if (time()-self.lastTime <= 1000) then self.frames=self.frames+1 else self.value=self.frames self.frames=0 self.lastTime=time() end return self.value end -- VARIABLES: DEVELOPER ONLY versionNr="1.1" releaseDate="22.12.2018" debug=false -- VARIABLES: GENERAL mode=-1 t=0 invertedY=false if pmem(1)>0 then invertedY=true end -- VARIABLES: INTRO intro={text="Nalquas presents: An update for...",textDis=0,tDelay1=0,name="MainFighter - A game for #FC_JAM",nameDis=0,tDelay2=0,Factor=0,FactorChange=0.15} -- VARIABLES: MENU menu={mode=1,maxMode=3,tClick=0} -- VARIABLES: GAME spawnFactor=82 offsetFactor=0.75 player={alive=true,lastHitTime=0,shotDamage=2.5,speed=1,hp=100,energy=100,x=104,y=52,z=128,spdX=0,spdY=0,spdZ=0.3,groundFactor=0,tShot=0,gameOverCircleSize=0} levelData={} -- Level 1: levelData[1]={ground={c1=11,c2=5},props={c1=7,c2=3},spawnedData={triWing=0,megaTriWing=0},spawnData={triWing=49,megaTriWing=1}} -- Level 2: levelData[2]={ground={c1=11,c2=5},props={c1=7,c2=3},spawnedData={triWing=0,megaTriWing=0},spawnData={triWing=25,megaTriWing=0}} -- Level 3: levelData[3]={ground={c1=1,c2=6},props={c1=9,c2=4},spawnedData={triWing=0,megaTriWing=0},spawnData={triWing=25,megaTriWing=0}} level=1 props={} for i=0,50 do sx=math.random(-50,550) sy=70 props[i]={sx=sx,sy=sy,x=sx,y=sy,spdX=0,spdY=player.spdZ} for j=1,math.random(1,100) do props[i].spdY=props[i].spdY*1.07333333 props[i].y=props[i].y+props[i].spdY if props[i].y>136 then props[i].y=props[i].sy props[i].spdY=player.spdZ end end end shots={speed=4,cost=11} enemyData={} enemyData[1]={correctnessFactor=60,hp=1,speed=0.88,tShotMax=95,sprite=300,spriteSize={x=2,y=2},doSpriteChange=true,size={x=16,y=16,z=16}} -- TriWing enemyData[-1]={correctnessFactor=85,hp=100,speed=0.86,tShotMax=80,sprite=365,spriteSize={x=3,y=4},doSpriteChange=false,size={x=24,y=27,z=16}} -- Mega-TriWing enemies={} explosions={} gameOverMenu={mode=1,maxMode=2,tClick=0} -- VARIABLES: STORY (a.k.a. Level 0) story={tStart=0,tText=60,tBetweenTexts=60,progress=0,maxText=11} story[1]={text="04.11.2743, Somewhere in Deep Space..."} story[2]={text="Droid X2: ...so you're saying they're\nsearching for a \"main character\"?"} story[3]={text="You: Indeed, they're searching one\nfor some \"video game\"."} story[4]={text="Droid X2: I've got no idea what\nthat's supposed to be,"} story[5]={text="Droid X2: ...but you'll never be\nthe main character!"} story[6]={text="You: Hah, you don't know who you're talking with then!"} story[7]={text="Droid X2: Alright... let's make a\ndeal: If you beat all my flying drones,"} story[8]={text="Droid X2: ...then you get to be the\nmain character,"} story[9]={text="Droid X2: ...otherwise,\nI'll be the lucky one."} story[10]={text="You: Deal! Haha! That will be easy,\nyou'll never be the main character!"} story[11]={text="Droid X2: We'll see..."} function Background(bgrValue) poke(0x03FF8, bgrValue) -- Set Background end function printCenter(text,x,y,color,fixed,smallfont) scale=1 width=print(text,0,-12,15,fixed,1,smallfont) print(text,(((x*2)-width)//2)+1,y,color,fixed,scale,smallfont) end function CountInString(text,substring) count=0 for i in string.gmatch(text,substring) do count=count+1 end return count end fancyMemory={text="Placeholder",textDis=12,x=0,y=0,c=15,centered=true,size=1} function printFancyUpdate(text,x,y,c,centered,size) y=y-(CountInString(text,"\n")*4) fancyMemory={text=text,textDis=0,x=x,y=y,c=c,centered=centered,size=size} end function printFancy() if fancyMemory.centered then printCenter(string.sub(fancyMemory.text,0,fancyMemory.textDis),fancyMemory.x,fancyMemory.y,fancyMemory.c,true) else print(string.sub(fancyMemory.text,0,fancyMemory.textDis),fancyMemory.x,fancyMemory.y,fancyMemory.c,true,fancyMemory.size) end if fancyMemory.textDis#introDark then introDark[i].num=0 end end end end end groundDark={} for i=0,15 do groundDark[i]={num=i,y=i^2} end function DrawGround() rect(0,70,240,66,11) for i=0,#groundDark do rect(0,70+(2*groundDark[i].y),240,(math.sqrt(groundDark[i].y)+0.2)*2.5,5) groundDark[i].y=(groundDark[i].num*1.43333)^2 groundDark[i].num=groundDark[i].num+0.05 if groundDark[i].num>#groundDark then groundDark[i].num=0 end end end function MakeShot(x,y,byPlayer) spdY=0.29032132616129 if byPlayer then spdY=-3 end z=0 if byPlayer then z=128 end return {alive=true,byPlayer=byPlayer,x=x,y=y,z=z,spdY=spdY} end shots[0]=MakeShot(-100,-100,true) shots[0].alive=false function MakeEnemy(id) newBtn={} for i=0,7 do newBtn[i]=false end return {alive=false,hp=enemyData[id].hp,spawning=true,spawnVisible=false,tSpawn=0,id=id,speed=enemyData[id].speed,sprite=enemyData[id].sprite,size=enemyData[id].size,x=math.random(32,372),y=math.random(0,64),z=enemyData[id].size.z,spdX=0,spdY=0,spdZ=0,btn=newBtn,tShot=0} end enemies[0]=MakeEnemy(1) enemies[0].spawning=false enemies[0].alive=false function MakeExplosion(x,y,maxSize,sizeFactor) return {alive=true,x=x,y=y,size=1,maxSize=maxSize,sizeIncrease=sizeFactor} end explosions[0]=MakeExplosion(-100,-100) explosions[0].alive=false function CountEnemies() j=0 for i=0,#enemies do if enemies[i].alive or enemies[i].spawning then j=j+1 end end k=(levelData[level].spawnData.triWing-levelData[level].spawnedData.triWing)+(levelData[level].spawnData.megaTriWing-levelData[level].spawnedData.megaTriWing)+j return k end function ResetGameValues() player={alive=true,lastHitTime=0,shotDamage=2.5,speed=1,hp=100,energy=100,x=104,y=52,z=128,spdX=0,spdY=0,spdZ=0.3,groundFactor=0,tShot=0,gameOverCircleSize=0} for i=1,3 do levelData[i].spawnedData={triWing=0,megaTriWing=0} end for i=1,#shots do shots[i]=nil end for i=1,#explosions do explosions[i]=nil end for i=1,#enemies do enemies[i]=nil end fancyMemory={text="Placeholder",textDis=12,x=0,y=0,c=15,centered=true,size=1} story.tText=60 story.tStart=0 story.progress=0 t=0 end -- Message in Console: trace("\n\n-----------------------------\n Nalquas presents:\n MainFighter V"..versionNr.."\n Last updated: "..releaseDate.."\nhttps://nalquas.itch.io/mainfighter\n-----------------------------\n") -- Change palette entry 12 each line to have a good sky gradient function scanline(row) --Possible colors: (B is always X-row*3) -- R G B -- 000-000-255 Pure blue (looks artificial) -- 096-064-255 Sundown, early -- 128-064-255 Sundown, mid -- 128-096-255 Morning -- skygradient (palette position 12) poke(0x3fe4,64) --r poke(0x3fe5,64+row*2.5) --g poke(0x3fe6,200) --b end function TIC() if mode==-1 then -- =================== -- MODE: EPILEPSY WARNING -- =================== if t>120 then if btn(4) then mode=0 t=0 end end Background(0) cls(0) tri(119,15,79,80,159,80,14) rect(114,27,11,36,0) rect(114,68,11,10,0) print("EPILEPSY WARNING!",21,85,15,true,2) print("If you're prone to epileptic attacks,\n do not play this game.",14,99,15,true,1) if t>120 then print("Press Z to continue...",55,120,15,true,1) end elseif mode==0 then -- =================== -- MODE: INTRO -- =================== Background(3) cls(0) IntroFlying() -- Render Flying effect if intro.tDelay1<30 then printCenter(string.sub(intro.text,0,intro.textDis),119,66,15,true) -- Show intro.text else printCenter(string.sub(intro.name,0,intro.nameDis),119,66,15,true) -- Show intro.name end if intro.textDis=30 then if intro.nameDis=90 then mode=1 else intro.tDelay2=intro.tDelay2+1 end else intro.tDelay1=intro.tDelay1+1 end if debug then print("intro.textDis "..intro.textDis.."/"..string.len(intro.text).."\nintro.nameDis "..intro.nameDis.."/"..string.len(intro.name).."\nintro.tDelay1 "..intro.tDelay1.."/30\nintro.tDelay2 "..intro.tDelay2.."/90") end elseif mode==1 then -- =================== -- MODE: MENU -- =================== if menu.tClick>10 then menu.tClick=0 if btn(0) or btn(1) then if btn(0) then menu.mode=menu.mode-1 elseif btn(1) then menu.mode=menu.mode+1 end -- Menu Looping if menu.mode<1 then menu.mode=menu.maxMode elseif menu.mode>menu.maxMode then menu.mode=1 end elseif btn(2) or btn(3) or btn(4) or btn(5) or btn(6) or btn(7) then if menu.mode==1 then ResetGameValues() level=0 mode=2 elseif menu.mode==2 then invertedY=not invertedY if invertedY then pmem(1,1) else pmem(1,0) end elseif menu.mode==3 then exit() else menu.mode=1 end else menu.tClick=11 end end -- Normal Rendering: Background(3) cls(0) IntroFlying() -- Menu Rendering: c={} for i=1,menu.maxMode do if i==menu.mode then if (math.floor(t/8)%2==0) then c[i]=14 else c[i]=9 end else c[i]=15 end end print("MainFighter",53,34,15,true,2) printCenter("Start a new run",119,56,c[1],false) printCenter("Invert Y-Axis ["..tostring(invertedY).."]",119,66,c[2],false) printCenter("Exit to TIC-80",119,76,c[3],false) printCenter("(C) Nalquas, 2017-2018",120,120,15,false) printCenter("GNU General Public License Version 3",120,127,15,false) print("V"..versionNr,4,4,15,false,1) -- Time Incrementation: if menu.tClick<=10 then menu.tClick=menu.tClick+1 end elseif mode==2 then -- =================== -- MODE: GAME -- =================== if level==0 then -- Show Story Intro Background(2) cls(0) if fancyMemory.textDis>=string.len(fancyMemory.text) then if story.tText>=story.tBetweenTexts then if story.progress60 and story.progress=0 then player.spdY=-(player.speed/10) else player.spdY=player.spdY*((player.speed/10)*12) end elseif btn(b) then if player.spdY<=0 then player.spdY=(player.speed/10) else player.spdY=player.spdY*((player.speed/10)*12) end else if player.spdY<(player.speed/10) and player.spdY>-(player.speed/10) then player.spdY=0 else player.spdY=player.spdY/((player.speed/10)*12) end end if btn(2) then if player.spdX>=0 then player.spdX=-(player.speed/10) else player.spdX=player.spdX*((player.speed/10)*12) end elseif btn(3) then if player.spdX<=0 then player.spdX=(player.speed/10) else player.spdX=player.spdX*((player.speed/10)*12) end else if player.spdX<(player.speed/10) and player.spdX>-(player.speed/10) then player.spdX=0 else player.spdX=player.spdX/((player.speed/10)*12) end end if player.tShot>10 then if player.energy>=shots.cost then if btn(4) then shots[#shots+1]=MakeShot((player.x+16)+(offsetFactor*player.x),(player.y+16),true) player.tShot=0 player.energy=player.energy-shots.cost sfx(2,"C-4",32,1,15,0) end end else player.tShot=player.tShot+1 end if player.energy<0 then player.energy=0 elseif player.energy<100 then player.energy=player.energy+0.5 elseif player.energy>100 then player.energy=100 end if player.spdY<-player.speed then player.spdY=-player.speed elseif player.spdY>player.speed then player.spdY=player.speed end if player.spdX<-player.speed then player.spdX=-player.speed elseif player.spdX>player.speed then player.spdX=player.speed end player.x=player.x+player.spdX player.y=player.y+player.spdY if player.x<0 then player.x=0 elseif player.x>208 then player.x=208 end if player.y<0 then player.y=0 elseif player.y>104 then player.y=104 end end -- Spawn Routine if math.random(0,spawnFactor)==1 then if levelData[level].spawnedData.triWing=0 then enemies[i].spdY=-(enemies[i].speed/10) else enemies[i].spdY=enemies[i].spdY*((enemies[i].speed/10)*12) end elseif enemies[i].btn[1] then if enemies[i].spdY<=0 then enemies[i].spdY=(enemies[i].speed/10) else enemies[i].spdY=enemies[i].spdY*((enemies[i].speed/10)*12) end else if enemies[i].spdY<(enemies[i].speed/10) and enemies[i].spdY>-(enemies[i].speed/10) then enemies[i].spdY=0 else enemies[i].spdY=enemies[i].spdY/((enemies[i].speed/10)*12) end end if enemies[i].btn[2] then if enemies[i].spdX>=0 then enemies[i].spdX=-(enemies[i].speed/10) else enemies[i].spdX=enemies[i].spdX*((enemies[i].speed/10)*12) end elseif enemies[i].btn[3] then if enemies[i].spdX<=0 then enemies[i].spdX=(enemies[i].speed/10) else enemies[i].spdX=enemies[i].spdX*((enemies[i].speed/10)*12) end else if enemies[i].spdX<(enemies[i].speed/10) and enemies[i].spdX>-(enemies[i].speed/10) then enemies[i].spdX=0 else enemies[i].spdX=enemies[i].spdX/((enemies[i].speed/10)*12) end end if enemies[i].tShotenemies[i].speed then enemies[i].spdY=enemies[i].speed end if enemies[i].spdX<-enemies[i].speed then enemies[i].spdX=-enemies[i].speed elseif enemies[i].spdX>enemies[i].speed then enemies[i].spdX=enemies[i].speed end enemies[i].x=enemies[i].x+enemies[i].spdX enemies[i].y=enemies[i].y+enemies[i].spdY if enemies[i].x((240+(240*offsetFactor))-enemies[i].size.x*3) then enemies[i].x=((240+(240*offsetFactor))-enemies[i].size.x*3) end if enemies[i].y<0 then enemies[i].y=0 elseif enemies[i].y>(92-enemies[i].size.y) then enemies[i].y=(92-enemies[i].size.y) end end end -- Shot Handling for i=0,#shots do if shots[i].alive then if shots[i].byPlayer then shots[i].spdY=shots[i].spdY/1.07333333 else shots[i].spdY=shots[i].spdY*1.07333333 end shots[i].y=shots[i].y+shots[i].spdY if shots[i].byPlayer then shots[i].z=shots[i].z-shots.speed else shots[i].z=shots[i].z+shots.speed end if shots[i].z<0 or shots[i].y>136 then shots[i].alive=false end if shots[i].byPlayer then for j=0,#enemies do if enemies[j].alive then if shots[i].x>=enemies[j].x and shots[i].y>=enemies[j].y and shots[i].z>=enemies[j].z and shots[i].x<=enemies[j].x+enemies[j].size.x and shots[i].y<=enemies[j].y+enemies[j].size.y and shots[i].z<=enemies[j].z+enemies[j].size.z then enemies[j].hp=enemies[j].hp-player.shotDamage shots[i].alive=false explosions[#explosions+1]=MakeExplosion(shots[i].x,shots[i].y,3,1.003333) break end end end else -- Collision with player if player.hp>0 and player.alive then if shots[i].x-(offsetFactor*player.x)>=player.x and shots[i].y>=player.y and shots[i].z>=player.z-16 and shots[i].x-(offsetFactor*player.x)<=player.x+32 and shots[i].y<=player.y+32 and shots[i].z<=player.z+16 then player.hp=player.hp-5 shots[i].alive=false sfx(4,"F-3",16,3,15,0) player.lastHitTime=t end end end end end -- Enemies: Death for j=0,#enemies do if enemies[j].alive and enemies[j].hp<=0 then enemies[j].alive=false sizeFactor=1 if enemies[j].id==1 then sizeFactor=1.03333 elseif enemies[j].id==-1 then sizeFactor=1.33333 end explosions[#explosions+1]=MakeExplosion(enemies[j].x+(enemies[j].size.x/2),enemies[j].y+(enemies[j].size.y/2),((enemies[j].size.x+enemies[j].size.y)/2.5),sizeFactor) sfx(3,"E-3",32,2,15,0) end end if player.alive and player.hp<=0 then StopSfx() music(1,-1,-1,false) sfx(3,"F-2",64,2,15,-2) player.alive=false end -- RENDERING Background(0) --cls(8) --map(0,0+((level-1)*17),60,11,(-player.x)/5,((player.y)/40)-10,-1,1) -- Sky cls(12) --Clear but do sky at the same time (see scanline) map(0,12+((level-1)*17),60,2,(-player.x)/3,((player.y)/30)+55,13,1) -- Mountains map(0,15+((level-1)*17),60,1,(-player.x)/2.5,((player.y)/30)+63,13,1) -- Trees DrawGround() -- Stones: for i=0,#props do props[i].spdX=0 props[i].x=props[i].x+props[i].spdX props[i].spdY=props[i].spdY*1.027499995 --1.01833333 --1.03666666 --1.07333333 props[i].y=props[i].y+props[i].spdY if props[i].y>136 then props[i].x=math.random(-50,550) props[i].y=props[i].sy props[i].spdY=player.spdZ end r=math.floor(((props[i].y-70)/22)+1) clip(props[i].x-(1.2*player.x)-r,props[i].y-r,(r*2)+1,r) circ(props[i].x-(1.2*player.x),props[i].y,r-1,levelData[level].props.c1) circb(props[i].x-(1.2*player.x),props[i].y,r,levelData[level].props.c2) clip() end -- Explosions (Enemies): for i=0,#explosions do if explosions[i].alive then circ(explosions[i].x-(offsetFactor*player.x),explosions[i].y,explosions[i].size,6) circ(explosions[i].x-(offsetFactor*player.x),explosions[i].y,explosions[i].size-1,14) explosions[i].sizeIncrease=explosions[i].sizeIncrease/1.055555 explosions[i].size=explosions[i].size+explosions[i].sizeIncrease if explosions[i].size>explosions[i].maxSize then explosions[i].alive=false end end end -- Enemies: for i=0,#enemies do if enemies[i].alive then xSpr=0 ySpr=0 if enemyData[enemies[i].id].doSpriteChange then if enemies[i].spdX<=-(enemies[i].speed/2) then xSpr=-2 -- Left elseif enemies[i].spdX>=(enemies[i].speed/2) then xSpr=2 -- Right end if enemies[i].spdY <=-(enemies[i].speed/2) then ySpr=-32 -- Up elseif enemies[i].spdY>=(enemies[i].speed/2) then ySpr=32 -- Down end end spr(enemies[i].sprite+xSpr+ySpr,math.floor(enemies[i].x)-(offsetFactor*player.x),math.floor(enemies[i].y),15,1,0,0,enemyData[enemies[i].id].spriteSize.x,enemyData[enemies[i].id].spriteSize.y) elseif enemies[i].spawning then if enemies[i].tSpawn%5==0 then enemies[i].spawnVisible=not enemies[i].spawnVisible end if enemies[i].spawnVisible then spr(enemies[i].sprite,math.floor(enemies[i].x)-(offsetFactor*player.x),math.floor(enemies[i].y),15,1,0,0,enemyData[enemies[i].id].spriteSize.x,enemyData[enemies[i].id].spriteSize.y) if CountEnemies()==1 then sfx(0,"F-2",2,3,15,0) else if t>player.lastHitTime+16 then sfx(0,"F-2",2,3,9,0) end end end if enemies[i].tSpawn>120 then enemies[i].spawning=false enemies[i].alive=true else enemies[i].tSpawn=enemies[i].tSpawn+1 end end end if player.alive then spr(511,math.floor(player.x)+13,math.floor(player.y)-19,0,1,0,0,1,1) --Crosshair end -- Player's Shots (Behind Player): for i=0,#shots do if shots[i].alive then if shots[i].z<=player.z then circ(shots[i].x-(offsetFactor*player.x),shots[i].y,math.floor((shots[i].z/128)*5)-1,14) end end end -- Player: if player.alive then xSpr=0 if player.spdX<=-0.8 then xSpr=-4 -- Very left elseif player.spdX<=-0.4 then xSpr=-2 -- Left elseif player.spdX>=0.8 then xSpr=4 -- Very Right elseif player.spdX>=0.4 then xSpr=2 -- Right end ySpr=0 if player.spdY <=-0.5 then ySpr=-32 -- Up elseif player.spdY>=0.5 then ySpr=32 -- Down end spr(292+xSpr+ySpr,math.floor(player.x),math.floor(player.y),15,2,0,0,2,2) --Player if (math.abs(xSpr)+math.abs(ySpr))>=0.8 then sfx(1,"C#4",-1,0,8,0) else sfx(1,"C-4",-1,0,8,0) end end -- Player's Shots (In Front of Player): for i=0,#shots do if shots[i].alive then if shots[i].z>player.z then circ(shots[i].x-(offsetFactor*player.x),shots[i].y,math.floor((shots[i].z/128)*5)-1,14) end end end -- OVERLAY -- HP bar: rect(0,129,74,7,1) -- Frame rect(13,130,60,5,6) -- Red 6 rect(13,130,(player.hp/100)*60,5,11) -- Green 11 print("HP",1,130,15,true,1) -- Energy bar: rect(166,129,74,7,1) -- Frame rect(167,130,60,5,4) -- Brown rect(167,130,(player.energy/100)*60,5,14) -- Yellow print("EN",228,130,15,true,1) -- Level Display: --printCenter("Level "..level,119,2,15,true) -- Boss HP Bar: if CountEnemies()<=1 then rect(0,0,86,7,1) -- Frame rect(25,1,60,5,6) -- Red 6 rect(25,1,(enemies[#enemies].hp/100)*60,5,11) -- Green 11 print("BOSS",1,1,15,true,1) else -- Remaining Enemies: print("Remaining: "..CountEnemies(),2,2,15,false,1) end -- FPS Display: print("FPS: " .. FPS:getValue(),202,2,15) if debug then print("player.x "..player.x.."\nplayer.y "..player.y.."\nplayer.spdX "..player.spdX.."\nplayer.spdY "..player.spdY.."\nplayer.tShot "..player.tShot.."\nplayer.hp "..player.hp.."\nplayer.energy "..player.energy.."\nActual X: "..player.x+(offsetFactor*player.x).."\nspawnData "..levelData[level].spawnData.triWing.."\nspawnedData "..levelData[level].spawnedData.triWing,0,50) end -- CHANGE TO GAMEOVER IF ENEMIES ARE DEAD if CountEnemies()<=0 then StopSfx() music(2,-1,-1,false) sfx(3,"F-2",64,2,15,-2) player.alive=false end else -- DO NOT USE cls() UNTIL SCREEN COMPLETELY OCCUPIED! OTHERWISE, EFFECT IS RUINED! if player.gameOverCircleSize<=228 then if CountEnemies()>0 then player.gameOverCircleSize=player.gameOverCircleSize+1.5 circ(player.x+16,player.y+16,player.gameOverCircleSize,6) circ(player.x+16,player.y+16,player.gameOverCircleSize-1,14) else player.gameOverCircleSize=player.gameOverCircleSize+1 circ(enemies[#enemies].x+(enemies[#enemies].size.x/2)-(player.x*offsetFactor),enemies[#enemies].y+16,player.gameOverCircleSize,6) circ(enemies[#enemies].x+(enemies[#enemies].size.x/2)-(player.x*offsetFactor),enemies[#enemies].y+16,player.gameOverCircleSize-1,14) end elseif player.gameOverCircleSize>234 then Background(0) if CountEnemies()>0 then cls(6) else cls(5) end printFancy() if fancyMemory.textDis>=string.len(fancyMemory.text) then -- Show GameOverMenu -- Remaining Enemies: if CountEnemies()>0 then print("Remaining Enemies: "..CountEnemies(),65,55,15,false,1) else print("Now YOU'RE the main character!",37,55,15,false,1) printCenter("More Levels coming soon...",120,127,15,false) end if gameOverMenu.tClick>10 then gameOverMenu.tClick=0 if btn(0) or btn(1) then if btn(0) then gameOverMenu.mode=gameOverMenu.mode-1 elseif btn(1) then gameOverMenu.mode=gameOverMenu.mode+1 end -- Menu Looping if gameOverMenu.mode<1 then gameOverMenu.mode=gameOverMenu.maxMode elseif gameOverMenu.mode>gameOverMenu.maxMode then gameOverMenu.mode=1 end elseif btn(2) or btn(3) or btn(4) or btn(5) or btn(6) or btn(7) then if gameOverMenu.mode==1 then ResetGameValues() level=1 mode=2 elseif gameOverMenu.mode==2 then -- Back to Main Menu ResetGameValues() mode=1 else gameOverMenu.mode=1 end else gameOverMenu.tClick=11 end end -- Menu Rendering: c={} for i=1,gameOverMenu.maxMode do if i==gameOverMenu.mode then if (math.floor(t/8)%2==0) then c[i]=14 else c[i]=9 end else c[i]=15 end end printCenter("Restart",120,70,c[1],false) printCenter("Back to Main Menu",120,78,c[2],false) -- Time Incrementation: if gameOverMenu.tClick<=10 then gameOverMenu.tClick=gameOverMenu.tClick+1 end end else if CountEnemies()>0 then cls(9) else cls(11) end if CountEnemies()>0 then printFancyUpdate("GAME OVER!",62,39,15,false,2) else printFancyUpdate("VICTORY!",71,39,15,false,2) end player.gameOverCircleSize=player.gameOverCircleSize+1.5 end end end else -- =================== -- MODE: UNKNOWN -- =================== mode=1 end t=t+1 end