0,]']±>Sï}WÿÍu§ðp8·d%qy)6o;]ÉA¦ösï÷ôôô”°ÂVl†3äÞþîÞÞþîÞÞþîÞÞþîÎÎþîÎÎþîÝýßþÎÎþîÎÎþîÎÎþ>âÝýßÿÎÎþîðÿßÎÎþîÎÎþîÎÎþîÎÎþîðÿßÎÎþîÎÎþîÎÎþîÎÎþîÎÎþîððÿßÃÎþîÎÎþîÎÎþîÎÎþîîîþîîîþîîîîîîîþîîîþîîîþîîîîîîîîïîîþîïîîîîîîîîîþîîîîîîîþîîîþîîîþîîîîîîîþîîîþîîîîîîîþîîîþîîîþîîîîþîîîîîîþîîîþîîîîîîîþîîîþîwV-- title: City Defender -- author: pensoffsky -- desc: My first TIC-80 game. -- license: MIT License -- version: 0.1 -- script: lua function BOOT() --state "game" "over" "menu" "victory" "wavetrans" s_state="menu" init() --rain is in all game states and is not resetted o_ps_rain=create_partsys() end function init() i_wavetrans=0 i_flash=0 math.randomseed(333) o_ps=create_partsys() i_gametic=0 i_wave=1 o_player={ x=110, y=110, s=2, spd=1.5, gun=1, health=3, deathtic=-1 } --bullets shoot_cooldown=0 shoot_delay=12 bullets={} --enemies local c=create_enemy local w1 = {} w1[50]=c(1,120,-8) --bombs row left/right wave_lane(w1,1,180,10,-8,4,1,30,30) wave_lane(w1,1,580,220,-8,4,-1,30,30) --big bombs row wave_lane(w1,3,1000,20,-8,4,1,50,40) --bombers w1[2000]=c(4,10,10) --w1[2500]=c(4,230,10) local w2 = {} --shooty aliens matrix wave_block(w2,6,150,0,20,4,1,40,10) --glide bombs from left and right wave_lane(w2,7,500,10,-8,5,1,90,0) wave_lane(w2,7,700,240,8,5,1,90,0) wave_lane(w2,7,1300,240,8,5,1,90,0) wave_lane(w2,7,2000,240,8,5,1,90,0) --bomb over full width wave_lane(w2,1,2501,10,-8,5,1,200,40) local w3 = {} --bomber w3[119]=c(4,10,10) --shooty aliens matrix wave_block(w3,6,120,10,20,5,1,30,10) --bomb over full width wave_lane(w3,1,2501,10,-8,5,1,200,40) --fast bomb over full width wave_lane(w3,2,2802,10,-8,5,1,200,40) wave_lane(w3,3,3003,20,-8,4,1,200,50) wave_lane(w3,7,3400,10,-8,5,1,90,0) wave_lane(w3,7,3501,240,-8,5,1,90,0) --the currently active enemies on screen enemies={} --definition of the waves for spawning enemies waves={} waves[1]={enemies=w1} waves[1].boss = create_boss(1) waves[2]={enemies=w2} waves[2].boss = create_boss(2) waves[3]={enemies=w3} waves[3].boss = create_boss(3) --city - health 0 -> game over i_cityhealth=3 end function wave_block(wave,etype,tic,x,y,cols,rows,spreadx,spready) local ticplus=0 for ix=0,cols do for iy=0,rows do local tic=tic+ticplus local x=x+(ix*spreadx) local y=y+(iy*spready) wave[tic]=create_enemy(etype,x,y) ticplus=ticplus+1 end end end function wave_lane(wave,etype,tic,x,y,size,dir,delay,spread) --todo start by 0?????? for i=0,size do local tic=tic+(i*delay) local x=x+(i*dir*spread) wave[tic]=create_enemy(etype,x,y) end end function tic_wavetrans() if g_reward == nil then g_reward = 1 end if btnp(5) then if g_reward == 1 then i_cityhealth = i_cityhealth + 1 elseif g_reward == 2 then o_player.gun = o_player.gun + 1 elseif g_reward == 3 then o_player.spd = o_player.spd + 1 end s_state = "game" end if btnp(2) and g_reward>1 then g_reward = g_reward - 1 end if btnp(3) and g_reward<3 then g_reward = g_reward + 1 end --draw game in background updatebullets() draw_game(false) o_ps.tic() --and wave description in foreground print(string.format("Wave %d clear",i_wave-1),10,10,12,false,1.3,false) print("Select powerup (press 'shoot' to select",10,20,12,false,1.3,false) --draw powerup selection menu local posx={ {x=20,str =" City "}, {x=90,str =" Gun "}, {x=160,str=" Speed"} } for i,v in ipairs(posx) do local sprite=12 if i == g_reward then sprite=76 end spr(sprite,v.x,40,-1,2,0,0,4,4) print(v.str,v.x+15,40+30,12) end end function tic_victory() if btnp(5) then init() s_state = "menu" end draw_city(i_cityhealth) o_ps.tic() --todo fireworks effect print("Victory",75,30,12,false,2,false) print("All enemies destroyed",5,50,12,false,2,false) print("press x button for another round", 30, 80,11) end function tic_menu() if btnp(5) then init() s_state = "game" end draw_city(1) print("City Defender",43,40,12,false,2,false) print("press x button to start", 60, 60,11) end function tic_over() if btnp(5) then s_state = "menu" init() end draw_city(0) print("Game Over",43,40,12,false,2,false) print("press x button to restart", 60, 60,11) end function tic_game() local isover=o_player.deathtic>0 if isover and i_gametic > (o_player.deathtic + 100) then s_state="over" return end --spawn enemies based on time i_gametic = i_gametic+1 if isover==false then spawn_enemy(i_gametic) end --collision handling checkcollisions() --enemy spawn and movement if isover==false then updateenemies() end --input handling if isover==false then o_player.s = 2 local player_spd = o_player.spd if btn(5) then shoot() --make player slower when shooting player_spd = player_spd * 0.7 end if btn(2) and o_player.x>0 then o_player.x=o_player.x-player_spd o_player.s = 3 end if btn(3) and o_player.x<232 then o_player.x=o_player.x+player_spd o_player.s = 4 end --debug if btn(4) then o_ps.playerexpl(o_player.x+4,o_player.y+4) end end --updates if isover==false then updatebullets() if shoot_cooldown>0 then shoot_cooldown=shoot_cooldown-1 end end --draw game draw_game(isover) o_ps.tic() --flash handling if i_flash>0 then i_flash=i_flash-1 cls(12) end --maybe switch to next wave or victory state if isover==false then check_nextwave() check_wavegap() end end function draw_city(cityhealth) if cityhealth == 5 then map(120,0) elseif cityhealth == 4 then map(90,0) elseif cityhealth == 3 then map(0,0) elseif cityhealth == 2 then o_ps_rain.fire(48,135) o_ps_rain.fire(120,132) o_ps_rain.fire(200,135) map(30,0) elseif cityhealth == 1 then o_ps_rain.fire(13,135) o_ps_rain.fire(140,132) o_ps_rain.fire(230,135) o_ps_rain.fire(48,135) o_ps_rain.fire(120,135) o_ps_rain.fire(200,135) map(60,0) else for i=1,238,3 do o_ps_rain.fire(i+math.random(2),135) end map(60,0) end o_ps_rain.rain() o_ps_rain.tic() end function draw_game(isover) draw_city(i_cityhealth) print("City Health:", 150, 0, 12) print(i_cityhealth,225,0,12,false,2,false) --print(i_gametic) --print(i_wave, 0, 20, 12) --print(tablelength(waves[i_wave].enemies),0,33) if isover==false then drawobject(o_player) if o_player.health == 3 then line(o_player.x,o_player.y-2,o_player.x+7,o_player.y-2,10) line(o_player.x,o_player.y-4,o_player.x+7,o_player.y-4,10) elseif o_player.health == 2 then line(o_player.x,o_player.y-2,o_player.x+7,o_player.y-2,10) end end drawobjects(bullets) drawobjects(enemies) end function TIC() if s_state == "menu" then tic_menu() elseif s_state == "over" then tic_over() elseif s_state == "game" then tic_game() elseif s_state == "victory" then tic_victory() elseif s_state == "wavetrans" then tic_wavetrans() end end --find gap to next enemy spawn --reindex timeline if needed function check_wavegap() if tablelength(enemies)>0 or waves[i_wave]==nil or waves[i_wave].enemies==nil then do return end end local lowesttic = nil for k,v in pairs(waves[i_wave].enemies) do if lowesttic == nil then lowesttic = k elseif lowesttic > k then lowesttic = k end end local gap=100 local offset=20 if lowesttic and lowesttic > (i_gametic+gap+offset) then local n_enemies={} for k,v in pairs(waves[i_wave].enemies) do n_enemies[k-gap]=v end waves[i_wave].enemies=n_enemies end end --check if enemies are left in current wave --switch to next wave or go to victory state function check_nextwave() if tablelength(enemies) == 0 and tablelength(waves[i_wave].enemies) == 0 then --spawn boss if waves[i_wave].boss then local boss = waves[i_wave].boss waves[i_wave].boss = nil enemies[#enemies+1] = boss return end --next wave / start tic from 0 i_wave = i_wave + 1 i_gametic=0 if i_wave == #waves+1 then o_ps.wavecleared() s_state="victory" else o_ps.wavecleared() s_state="wavetrans" end end end --put enemy into game based on wave and tic function spawn_enemy(tic) --tic is assumed to start at 0 when mode game starts local enemy = waves[i_wave].enemies[tic] waves[i_wave].enemies[tic] = nil if enemy == nil then return else enemies[#enemies+1] = enemy end end function create_boss(i_type) local n_enemy={x=69,y=10,s=8,spd=0,health=1,collgr=true,collpl=true,collbul=true} if i_type==1 then --boss 1, drop bomb n_enemy.s=112 n_enemy.spd=0.8 n_enemy.dir=1 n_enemy.health=20 n_enemy.cooldown=200 n_enemy.draw=function() local ne = n_enemy spr(ne.s,ne.x,ne.y,0,1,0,0,2,2) ne.s = animate(i_gametic,100,ne.s,112,2,118) --draw health bar rect(ne.x+1,ne.y+1,(14/20)*ne.health,2,3) end n_enemy.tic=function() local ne = n_enemy ne.cooldown = ne.cooldown - 1 ne.y = 20 ne.x = ne.x + (ne.spd * ne.dir) if ne.x > 200 then ne.dir=-1 end if ne.x < 20 then ne.dir=1 end if ne.cooldown <= 0 then local spawned = create_enemy(1) spawned.x = ne.x spawned.y = ne.y + 4 --TODO find empty spawn slot waves[i_wave].enemies[i_gametic+1] = spawned --enemies[#enemies+1] = spawned ne.cooldown = 200 + math.random(100) end end end if i_type==2 then --boss 2, drop bomb and shoot n_enemy.s=112 n_enemy.spd=0.8 n_enemy.dir=1 n_enemy.health=20 n_enemy.cooldown=200 n_enemy.shtcd=60 n_enemy.draw=function() local ne = n_enemy spr(ne.s,ne.x,ne.y,0,1,0,0,2,2) ne.s = animate(i_gametic,100,ne.s,112,2,118) --draw health bar rect(ne.x+1,ne.y+1,(14/20)*ne.health,2,3) end n_enemy.tic=function() local ne = n_enemy ne.shtcd=ne.shtcd-1 ne.cooldown = ne.cooldown - 1 ne.y = 20 ne.x = ne.x + (ne.spd * ne.dir) if ne.x > 200 then ne.dir=-1 end if ne.x < 20 then ne.dir=1 end if ne.cooldown <= 0 then local spawned = create_enemy(1) spawned.x = ne.x spawned.y = ne.y + 4 --TODO find empty spawn slot waves[i_wave].enemies[i_gametic+1] = spawned --enemies[#enemies+1] = spawned ne.cooldown = 200 + math.random(100) end if ne.shtcd <= 0 then local blt = create_enemy(5) blt.x = ne.x blt.y = ne.y + 4 --TODO find empty spawn slot waves[i_wave].enemies[i_gametic+1] = blt ne.shtcd = 40 + math.random(30) end end end if i_type==3 then --boss 3, drop bomb/shoot/spawn n_enemy.s=112 n_enemy.spd=0.8 n_enemy.dir=1 n_enemy.health=20 n_enemy.cooldown=200 n_enemy.shtcd=90 n_enemy.draw=function() local ne = n_enemy spr(ne.s,ne.x,ne.y,0,1,0,0,2,2) ne.s = animate(i_gametic,100,ne.s,112,2,118) --draw health bar rect(ne.x+1,ne.y+1,(14/20)*ne.health,2,3) end n_enemy.tic=function() local ne = n_enemy ne.shtcd=ne.shtcd-1 ne.cooldown = ne.cooldown - 1 ne.y = 20 ne.x = ne.x + (ne.spd * ne.dir) if ne.x > 200 then ne.dir=-1 end if ne.x < 20 then ne.dir=1 end if ne.cooldown <= 0 then local spawned = create_enemy(1) spawned.x = ne.x spawned.y = ne.y + 4 --TODO find empty spawn slot waves[i_wave].enemies[i_gametic+1] = spawned --enemies[#enemies+1] = spawned ne.cooldown = 150 + math.random(100) end if ne.shtcd <= 0 then local blt = create_enemy(math.random(3)) blt.x = ne.x blt.y = ne.y + 4 --TODO find empty spawn slot waves[i_wave].enemies[i_gametic+1] = blt ne.shtcd = 90 + math.random(30) end end end return n_enemy end --create instance of an enemy of type (1,2,3,4,5,6,7) function create_enemy(i_type, x, y) local x=x or math.random(232) local y=y or 0 local n_enemy = {x=x,y=y,collgr=true,collpl=true,collbul=true} if i_type==1 then -- bomb n_enemy.s=18 n_enemy.spd=0.3 n_enemy.health=3 n_enemy.draw=function() local ne = n_enemy rect(ne.x,ne.y-1,(8/3)*ne.health,1,3) spr(ne.s,ne.x,ne.y,0) ne.s = animate(i_gametic,2,ne.s,18,1,23) end elseif i_type==2 then --fast bobm n_enemy.s=34 n_enemy.spd=0.6 n_enemy.health=1 n_enemy.draw=function() local ne = n_enemy rect(ne.x,ne.y-1,(8/1)*ne.health,1,3) spr(ne.s,ne.x,ne.y,0) ne.s = animate(i_gametic,19,ne.s,34,1,35) end elseif i_type==3 then --big bomb n_enemy.s=50 n_enemy.spd=0.1 n_enemy.health=10 n_enemy.draw=function() local ne = n_enemy rect(ne.x,ne.y-1,(8/10)*ne.health,1,3) spr(ne.s,ne.x,ne.y,0) ne.s = animate(i_gametic,18,ne.s,50,1,53) end elseif i_type==4 then --bomber, drop bomb n_enemy.s=66 n_enemy.spd=0.5 n_enemy.dir=1 n_enemy.health=5 n_enemy.cooldown=20 n_enemy.draw=function() local ne = n_enemy rect(ne.x,ne.y-1,(8/5)*ne.health,1,3) local flip= 0 if ne.dir==-1 then flip=1 end spr(ne.s,ne.x,ne.y,0,1,flip) ne.s = animate(i_gametic,17,ne.s,66,1,67) end n_enemy.tic=function() local ne = n_enemy ne.cooldown = ne.cooldown - 1 --ne.y = 20 ne.x = ne.x + (ne.spd * ne.dir) if ne.x > 232 then ne.dir=-1 end if ne.x < 8 then ne.dir=1 end if ne.cooldown <= 0 then local spawned = create_enemy(1) spawned.x = ne.x spawned.y = ne.y + 4 --TODO find empty spawn slot waves[i_wave].enemies[i_gametic+1] = spawned --enemies[#enemies+1] = spawned ne.cooldown = 100 + math.random(100) end end elseif i_type==5 then --shot, no collide n_enemy.s=82 n_enemy.spd=0.2 n_enemy.health=1 n_enemy.collgr=false n_enemy.collpl=true n_enemy.collbul=false n_enemy.draw=function() local ne = n_enemy spr(ne.s,ne.x,ne.y,0) ne.s = animate(i_gametic,16,ne.s,82,1,87) end n_enemy.tic=function() local ne = n_enemy ne.y = ne.y + 1 if ne.y > 130 then ne.health=0 end end elseif i_type==6 then --alien, left right, shoot down n_enemy.s=98 n_enemy.spd=0.3 n_enemy.dir=1 n_enemy.dircooldown=150 n_enemy.health=5 n_enemy.cooldown=150 + math.random(50) n_enemy.draw=function() local ne = n_enemy rect(ne.x,ne.y-1,(8/5)*ne.health,1,3) spr(ne.s,ne.x,ne.y,0) ne.s = animate(i_gametic,15,ne.s,98,1,99) end n_enemy.tic=function() local ne = n_enemy ne.cooldown = ne.cooldown - 1 ne.dircooldown = ne.dircooldown - 1 ne.x = ne.x + (ne.spd * ne.dir) if ne.dircooldown <= 0 then ne.dircooldown = 180 if ne.dir > 0 then ne.dir=-1 else ne.dir=1 end end if ne.cooldown <= 0 then local spawned = create_enemy(5, ne.x, ne.y+4) --TODO find empty spawn slot waves[i_wave].enemies[i_gametic+1] = spawned --enemies[#enemies+1] = spawned ne.cooldown = 100 + math.random(100) end end elseif i_type==7 then --glide bomb / direction n_enemy.s=162 n_enemy.spd=0.2 n_enemy.hspd=0.3 n_enemy.health=1 n_enemy.dir=1 n_enemy.tic=function() local ne = n_enemy ne.y = ne.y + ne.spd ne.x = ne.x + (ne.hspd * ne.dir) if ne.x > 232 then ne.dir=-1 end if ne.x < 8 then ne.dir=1 end end n_enemy.draw=function() local ne = n_enemy rect(ne.x,ne.y-1,(8/1)*ne.health,1,3) local flip= 0 if ne.dir==-1 then flip=1 end spr(ne.s,ne.x,ne.y,0,1,flip) ne.s = animate(i_gametic,19,ne.s,162,1,163) end end return n_enemy end --create a bullet above obj function create_bullet(x,y) local n_bullet={x=x,y=y} n_bullet.s = 144 n_bullet.vspd = 1.8 n_bullet.hspd = 0 n_bullet.draw = function() local nb = n_bullet spr(nb.s,nb.x,nb.y,0,1,0,0,1,1) nb.s = animate(i_gametic,3,nb.s,144,1,146) end return n_bullet end --handle enemy/player enemy/ground bullet/enemy function checkcollisions() --collision player enemy for i=1,#enemies do local o_enemy=enemies[i] if o_enemy.collpl == true and collision(o_player,o_enemy) then o_enemy.health = o_enemy.health - 100 o_ps.enemyexpl(o_enemy.x+4,o_enemy.y+4) --todo add sfx o_player.health = o_player.health - 1 flash(1) sfx(2,"F-1",30) if o_player.health <= 0 then i_cityhealth = 0 --remember when player died --to show animation and transition --to game over screen o_ps.playerexpl(o_player.x+4,o_player.y+4) o_player.deathtic=i_gametic end end end --collision enemies ground for i=1,#enemies do local o_enemy=enemies[i] if o_enemy.y >= 120 and o_enemy.collgr == true then o_enemy.health = 0 i_cityhealth = i_cityhealth - 1 flash(1) sfx(1,"F-1",60) if i_cityhealth <= 0 then o_ps.playerexpl(o_player.x+4,o_player.y+4) o_player.deathtic=i_gametic end end end --collision enemies bullets for i=1,#bullets do local o_bullet=bullets[i] for i=1,#enemies do local o_enemy=enemies[i] if o_enemy.collbul == true and collision(o_bullet,o_enemy) then o_ps.bulletexpl(o_enemy.x+4,o_enemy.y+8) --move bullet and enemy off screen o_bullet.y=-20 sfx(0,"F#3",10) o_enemy.health = o_enemy.health - 1 if o_enemy.health <= 0 then o_ps.enemyexpl(o_enemy.x+4,o_enemy.y+4) sfx(2,"F-1",30) end end end end end --draw an object sprite function drawobject(o) if o.draw == nil then spr(o.s,o.x,o.y,0) else o.draw() end end --draw a list of object sprites function drawobjects(a) for i=1,#a do local o=a[i] drawobject(o) end end --move all enemies, remove if below screen function updateenemies() local n_enemies={} for i=1,#enemies do local o_e=enemies[i] if o_e.tic then o_e.tic() else o_e.y=o_e.y + o_e.spd end --keep if enemy is still alive if o_e.health > 0 then n_enemies[#n_enemies+1]=o_e end end enemies=n_enemies end --move bullets and remove if above screen function updatebullets() local n_bullets={} for i=1,#bullets do local bullet=bullets[i] bullet.y=bullet.y - bullet.vspd bullet.x=bullet.x - bullet.hspd --if bullet is still valid if bullet.y > -8 then n_bullets[#n_bullets+1]=bullet end end --only remember alive bullets bullets=n_bullets end --create player bullet regarding gun cooldown function shoot() if shoot_cooldown > 0 then return end shoot_cooldown=shoot_delay local n_bullet=create_bullet(o_player.x, o_player.y) bullets[#bullets+1]=n_bullet if o_player.gun > 1 then n_bullet=create_bullet(o_player.x, o_player.y) n_bullet.hspd = -0.2 bullets[#bullets+1]=n_bullet end if o_player.gun > 2 then n_bullet=create_bullet(o_player.x, o_player.y) n_bullet.hspd = 0.2 bullets[#bullets+1]=n_bullet end sfx(0,"C-3",5) o_ps.shoot(o_player.x+4,o_player.y) end --simple collision handling function collision(a,b) --todo introduce hitbox in object return (math.abs(a.x-b.x)+ math.abs(a.y-b.y)) <= 8 end --helper to get length of table function tablelength(T) local count = 0 for _ in pairs(T) do count = count + 1 end return count end --particle system in one function function create_partsys() local _ps = {} _ps.particles={} _ps.tic=function() local n_particles={} for i=1,#_ps.particles do local o=_ps.particles[i] if o.tic then o.tic() else o.ttl=o.ttl-1 o.x=o.x+o.hspd o.y=o.y+o.vspd circ(o.x,o.y,o.size,o.color) end --only keep alive particles if o.ttl > 0 then n_particles[#n_particles+1]=o end end _ps.particles=n_particles end _ps.rain=function() if math.random(10) > 2 then return end for i=1,1 do local n_part = {} n_part.s=1 n_part.x=math.random(232) n_part.y=-8 n_part.ttl = 500 n_part.hspd = 0 n_part.vspd = 0.1 + (math.random(3)*0.1) n_part.tic = function() local np = n_part np.y= np.y + np.vspd np.ttl=np.ttl-1 spr(np.s,np.x,np.y,0) --if i_gametic % (5+math.random(5)) == 0 then -- if nb.s == 49 then nb.s=65 else nb.s=49 end --end end _ps.particles[#_ps.particles+1]=n_part end end _ps.fire=function(x,y) for i=1,1 do local n_part = {} n_part.x=x n_part.y=y n_part.ttl = 15 + math.random(10) n_part.hspd = 0 + ((math.random(10)-5)*0.02) n_part.vspd = 0 - (math.random(3)*0.1) n_part.tic = function() local np = n_part np.y= np.y + np.vspd np.x=np.x + np.hspd np.ttl=np.ttl-1 local color = 2 if np.ttl < 10 then color = 14 elseif np.ttl < 15 then color = 4 elseif np.ttl < 20 then color = 3 end pix(np.x,np.y,color) --circ(np.x,np.y,1,2) end _ps.particles[#_ps.particles+1]=n_part end end _ps.shoot=function(xpos,ypos) local spd = 2 for i=1,3 do local n_part = {} n_part.x=xpos n_part.y=ypos n_part.ttl = 2 + math.random(2) n_part.hspd = (math.random()-0.5) n_part.vspd = math.random()*spd*(-1) n_part.size = 0.02 n_part.color= 5 _ps.particles[#_ps.particles+1]=n_part end end _ps.bulletexpl=function(xpos,ypos) local spd = 5 for i=1,5 do local n_part = {} n_part.x=xpos n_part.y=ypos n_part.ttl = 10 + math.random(20) n_part.hspd = (math.random()-0.5)*spd n_part.vspd = (math.random()-0.5)*spd n_part.size = 0.05 n_part.color= 5 _ps.particles[#_ps.particles+1]=n_part end end _ps.enemyexpl=function(xpos,ypos) local spd = 3 for i=1,4 do local n_part = {} n_part.x=xpos n_part.y=ypos n_part.ttl = 10 + math.random(20) n_part.hspd = (math.random()-0.5)*spd n_part.vspd = (math.random()-0.5)*spd n_part.size = 2 n_part.color= 13 _ps.particles[#_ps.particles+1]=n_part end end _ps.playerexpl=function(xpos,ypos) local spd = 2 for i=1,200 do local n_part = {} n_part.x=xpos n_part.y=ypos n_part.ttl = 80 + math.random(20) n_part.hspd = (math.random()-0.5)*spd n_part.vspd = (math.random()-0.5)*spd n_part.size = 1 n_part.color= 11 _ps.particles[#_ps.particles+1]=n_part end end _ps.wavecleared=function() for x=1,240,40 do for y=1,136,40 do for i=1,20 do local spd = 1 + math.random(10)*0.1 local n_part = {} n_part.x=x + math.random(10) n_part.y=y + math.random(10) n_part.ttl = 20 + math.random(20) n_part.hspd = (math.random()-0.5)*spd n_part.vspd = (math.random()-0.5)*spd n_part.size = 1+ math.random(1) n_part.color= 1+ math.random(14) _ps.particles[#_ps.particles+1]=n_part end end end end return _ps end function flash(duration) i_flash=duration end --animate(i_gametic,20,ne.s,18,1,23) --animate based on tic modulo function animate(tic, rate, s_cur, s_start, step, s_end) local res = s_cur if tic % rate == 0 then res = s_cur + step if res > s_end then res = s_start end end return res end