0ppp,H,,z((@ 8 p2TvͫgE#2Tv2Tv2Tv2Tv """""""" " """""""""" " ""   """"""""("(""""""(""(" ""   """"""""("(""""""""" "" """"""""("("""""""""(" ""03333303300"  " wwwwpppppppwwwwpppppppppppppp00330330300 "   " pppppppwwwwppppppppppppppwwww0003030303      003330333030    03030330030  0303303030330 03030033 33030330 p`P@0  0000??8888???????????????????? &++++((((+++/88???????????????????????????? &++++((((+++/DI@@@@@@@@@@@@@@@@@@@@@@@@@@@@C"""""''''$$$$''''),.//////////HHpOOOOOOOOOOOOOOOOOOOOOOOOOOOO. 9000????9555????=;;;?????????? 5:?0000000000000000000000000000000000000000000000000000000006677::<<??00000000000000000000qppppppt pp p   p p p pP pppppP Pp PP P PPP PPP PPP Pp PPpPP Pp PPpPP PP PP PP P P P P P ttt t tt tt ttttttttt tt tt t@d t u u y u u u y u u u y u u u y y u u y u u u y u u u y u u u y y y yqqQqqqqq PPP@dd!1y9 """""""" """ """"""""""" """"" "" """"" """"""" " "" """""""" " """"""""" """ """"" """" " """""""""" " "" ̻̻̻̻̻̻̻̻̻̻̻̻̰̻̻̻̻̻̻̻̻̻̻̻̻"""̼ ̻̻̻̻̻̻̻̻̻̻ """̻̻̻̻̻̻̻̻̻̻̻̻̻ "̻ ̻̻̻̻̻̻̻̻̻̻̻̻̻̻ " ̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻ """̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻ """̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻ ""̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻"""̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻ ""̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻""""̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻"" ̻̻̻̻̻̻̻̻̻̻̻̻" "̻̻̻̻̻̻̻̻̻̻̻̻""""""""" " """"" """ " "  """ """ "" """  """ """ " "  """ """""" "" """""" " "  """ """ """""""" """ """" "  """ """ " """ "  "" """""" """ """""J0-- title: Killing Time -- author: Hexer -- script: lua local player = {} local enemies = {} local bullets = {} local bones = {} local deaths = {} local vals = { --CUSTOMIZE HERE !!! plr_hp = 0.333 * 60, --Health is measured in TIME (separate from timestop gauge) plr_spd = 2, --Player Speed enm_spd = 0.5, --Enemy Speed plrblt_spd = 3, --Player Bullet Speed plrblt_frq = 8, --Player Bullet Firerate plrblt_cst = 0.125 * 60, --Player Bullet Cost ('1 / Firerate' is ideal!) plrblt_amm = 0.25 * 60, --Gauge recharge on kill enmspw_bfrq = 0.75, --Enemy Base Spawn Frequency enmspw_grw = 1.025, --Enemy Spawn Frequency Growth (percentage) ts_dur = 5 * 60, --Timestop Duration enmspw_dst = 16, --Enemy Spawn Minimum Distance from Player death_spd = 4, --Ticks per animation step bone_time = 20 * 60 --How long enemy stains remain } local enmspw_time = 0 local enmspw_frq = 0 local deadtime = 0 local deadscene = 1 local gamestate = "menu" local timestop = false local bg_phase_x = 0 local bg_phase_y = 0 local bg_spd_x = 0.25 local bg_spd_y = 0.25 local bg_tilesize = 8 local score = 0 local colors = { [true] = { bg = {0, 45, 0}, bgfx = {0, 66, 0}, gauge = {0, 88, 0}, score = {45,122,45}, player = {45,245, 45}, enemy = {245, 245, 45}, bone = {122, 122, 45}, danger = {66,66,0}, }, [false] = { bg = {0, 0, 45}, bgfx = {0, 0, 66}, gauge = {0, 0, 88}, score = {45,45,122}, player = {45,45, 245}, enemy = {245, 45, 45}, bone = {122, 45, 45}, danger = {66, 0, 0} }, } local dir_map = { [0] = {x = 0, y = -1}, [1] = {x = 0, y = 1}, [2] = {x = -1, y = 0}, [3] = {x = 1, y = 0} } local function max(n,m) if n > m then return n else return m end end function clamp(a,b,c) local m, n --figure m, n if c > b then m = c; n = b else n = c; m = b end --clamp if a > m then return m elseif a < n then return n else return a end end function sign(a) if a == 0 then return 0 else return a / math.abs(a) end end function specialrandom(n1, m1, n2, m2) --exclude field within n2 and m2 local r = nil while not r do r = math.random(n1,m1) if r >= n2 and r <= m2 then r = nil end end return r end function spawnenemy() local rx = specialrandom(-8, 240, player.x - vals.enmspw_dst, player.x + vals.enmspw_dst) local ry = specialrandom(-8, 136, player.y - vals.enmspw_dst, player.y + vals.enmspw_dst) local newenemy = { x = rx, y = ry, gc = false } enemies[#enemies+1] = newenemy end function spawnbullet(x, y, d, p) local newbullet = { x = x, y = y, d = d, p = p, gc = false } bullets[#bullets+1] = newbullet end function spawndeath(x, y) local newbone = {x = x + math.random(-3,3), y = y + math.random(-3,3), t = 0, r = math.random(0,7)} local newdeath = {x = x, y = y, t = 0} bones[#bones+1] = newbone deaths[#deaths+1] = newdeath end function colliding(a, b) if a.gc or b.gc then return end if (a.x >= b.x and a.x <= b.x + 8) or (b.x >= a.x and b.x <= a.x + 8) then if (a.y >= b.y and a.y <= b.y + 8) or (b.y >= a.y and b.y <= a.y + 8) then return true end end end local function specialfind(t,x,y) for _, c in ipairs(t) do if c.x == x and c.y == y then return c end end end local function initialize_game() player = { x = 120 - 4, y = 68 - 4, d = 0, w = false, t = 5, c = 0, h = vals.plr_hp } enmspw_time = 0 enmspw_frq = vals.enmspw_bfrq enemies = {} bullets = {} bones = {} deaths = {} timestop = false music(0) end local function terminate_game() player = nil enemies = nil bullets = nil bones = nil deaths = nil timestop = false score = 0 music() end --https://github.com/nesbox/TIC-80/wiki/code-examples-and-snippets#setget-spritesheet-pixel -- set spritesheet pixel function sset(x,y,c) local addr=0x4000+(x//8+y//8*16)*32 -- get sprite address poke4(addr*2+x%8+y%8*8,c) -- set sprite pixel end --https://github.com/nesbox/TIC-80/wiki/code-examples-and-snippets#setget-spritesheet-pixel -- get spritesheet pixel function sget(x,y) local addr=0x4000+(x//8+y//8*16)*32 -- get sprite address return peek4(addr*2+x%8+y%8*8) -- get sprite pixel end local function change_color(i,r,g,b) poke(0x03FC0 + 0 + i * 3, r) poke(0x03FC0 + 1 + i * 3, g) poke(0x03FC0 + 2 + i * 3, b) end local function update_palette() change_color(0, table.unpack(colors[timestop].bg)) change_color(1, table.unpack(colors[timestop].player)) change_color(2, table.unpack(colors[timestop].enemy)) change_color(3, table.unpack(colors[timestop].bone)) change_color(4, table.unpack(colors[timestop].bgfx)) change_color(5, table.unpack(colors[timestop].gauge)) change_color(6, table.unpack(colors[timestop].danger)) change_color(12, table.unpack(colors[timestop].score)) end local function draw(id, x, y) --a bit weird for me --im only gonna be drawing 8x8 sprites for ky = 0, 7 do local kky = ky * 16 for kx = 0, 7 do local color = sget(kx + id * 8, ky) if color ~= 0 then --ignore background pix(x + kx, y + ky, color) end end end end function TIC() if gamestate == "menu" then cls(0) --title for xx = 0, 10 do for yy = 0,1 do draw(432 + xx + yy * 16, 120 + (xx * 8) + 2 - 11 * 4, 56 + (yy * 8) + 2 - 8) draw(400 + xx + yy * 16, 120 + (xx * 8) - 11 * 4, 56 + (yy * 8) - 8) end end --merry-go-round for i = 0, 11 do local id if i == 0 then id = 256 else id = 257 end draw(id, 120 + math.sin(((math.pi / 6) * i) + time() * 0.001) * 13 * 8, 68 + math.cos(((math.pi / 6) * i) + time() * 0.001) * 6 * 8 ) --test end print("Press Z to begin!", 120 - 5.5 * 8, 80, 13) if btn(4) then gamestate = "game" initialize_game() end elseif gamestate == "game" then player.w = true if btn(0) then player.d = 0 elseif btn(1) then player.d = 1 elseif btn(2) then player.d = 2 elseif btn(3) then player.d = 3 else player.w = false end if player.w then player.x = player.x + dir_map[player.d].x * vals.plr_spd player.y = player.y + dir_map[player.d].y * vals.plr_spd player.x = clamp(player.x, 0, 240 - 8) player.y = clamp(player.y, 0, 136 - 8) end if btn(4) and player.c == 0 and player.t > vals.plrblt_cst then player.c = 60 / vals.plrblt_frq player.t = player.t - vals.plrblt_cst local d = player.d local x = player.x + 8 * dir_map[d].x local y = player.y + 8 * dir_map[d].y while specialfind(bullets, x, y) do x = x + dir_map[d].x y = y + dir_map[d].y end sfx(0, "C-4") spawnbullet(x, y, player.d, true) else player.c = clamp(player.c - 1, 0, 9999) end if btnp(5, 60, 4) then if timestop then timestop = false sfx(6,"C-4",-1,1) elseif player.t > 0 then timestop = true sfx(2,"C-4",-1,1) end end if timestop then player.t = clamp(player.t - 1, 0, vals.ts_dur) if player.t == 0 then timestop = false juststopped = true sfx(6,"C-4",-1,1) end else for _, death in ipairs(deaths) do death.t = death.t + 1 end for _, bone in ipairs(bones) do bone.t = bone.t + 1 end bg_phase_x = bg_phase_x + bg_spd_x bg_phase_y = bg_phase_y + bg_spd_y player.t = clamp(player.t + 1, 0, vals.ts_dur) enmspw_time = clamp(enmspw_time - 1, 0, 99999) if enmspw_time == 0 then enmspw_time = 60 / enmspw_frq spawnenemy() end for _, bullet in ipairs(bullets) do local spd = vals.plrblt_spd bullet.x = bullet.x + dir_map[bullet.d].x * spd bullet.y = bullet.y + dir_map[bullet.d].y * spd if bullet.x > -8 and bullet.x < 248 and bullet.y > -8 and bullet.y < 144 then for _, enemy in ipairs(enemies) do if colliding(bullet, enemy) then bullet.gc = true enemy.gc = true enmspw_frq = enmspw_frq * vals.enmspw_grw player.t = player.t + vals.plrblt_amm score = score + 1 pmem(0, max(pmem(0), score)) spawndeath(enemy.x, enemy.y) sfx(1,"C-4", -1, 1) end end else bullet.gc = true end end local hitting_enemy = false for _, enemy in ipairs(enemies) do hitting_enemy = hitting_enemy or colliding(enemy, player) local x0 = player.x - enemy.x local y0 = player.y - enemy.y local x1 = x0 - sign(x0) * vals.enm_spd local y1 = y0 - sign(y0) * vals.enm_spd local xh = math.sqrt((x1^2) + (y0^2)) local yh = math.sqrt((x0^2) + (y1^2)) if xh < yh then enemy.x = enemy.x + sign(x0) * vals.enm_spd else enemy.y = enemy.y + sign(y0) * vals.enm_spd end end if hitting_enemy then player.h = clamp(player.h - 1, 0, vals.plr_hp) sfx(3,"D-7", -1, 1) if player.h == 0 then gamestate = "dead" music() terminate_game() deadtime = 0 deadscene = math.random(1,3) return end else player.h = clamp(player.h + 1, 0, vals.plr_hp) end for i = #enemies, 1, -1 do if enemies[i].gc then table.remove(enemies, i) end end for i = #bullets, 1, -1 do if bullets[i].gc then table.remove(bullets, i) end end for i = #deaths, 1, -1 do if deaths[i].t > 6 * vals.death_spd then table.remove(deaths, i) end end for i = #bones, 1, -1 do if bones[i].t > vals.bone_time then table.remove(bones, i) end end end --## RENDER ##-- update_palette() cls(0) rect(0,0,(1 - (player.h / vals.plr_hp)) * 240, 136, 6) for bx = 0, 240 do for by = 0, 136 do local rx = bx + bg_phase_x local ry = by + bg_phase_y if ((rx // bg_tilesize) + (ry // bg_tilesize)) % 2 == 0 then pix(bx, by, 4) end end end local ss = tostring(score) local hss = tostring(pmem(0)) for i = 1, string.len(ss) do local n = tonumber(string.sub(ss,i,i)) draw(390 + n, 240 - 20 - (string.len(ss) - i - 1) * 6, 136 - 24) end for i = 1, string.len(hss) do local n = tonumber(string.sub(hss,i,i)) draw(390 + n, 240 - 20 - (string.len(hss) - i - 1) * 6, 136 - 12) end local k = player.t / vals.ts_dur rect(0, 136 - 2, 240 * k, 2,5) --bottom >> rect(240 * (1 - k) , 0, 240 * k, 2,5) --top << rect(0, 0, 2, 136 * k,5) --left ^^ rect(240 - 2, 136 * (1 - k), 2, 136 * k,5) --right vv for _, bone in ipairs(bones) do draw(273 + 16 * bone.r, bone.x, bone.y) end for _, death in ipairs(deaths) do draw(258 + 16 * (death.t // 4), death.x, death.y) end for _, enemy in ipairs(enemies) do draw(257, enemy.x, enemy.y) end draw(256, player.x, player.y) for _, bullet in ipairs(bullets) do draw(259, bullet.x, bullet.y) end elseif gamestate == "dead" then deadtime = deadtime + 1 if deadtime == 1.5 * 60 then sfx(19, "C-4", -1, 0) end if deadtime == 3 * 60 then music(1) end if deadtime < 1.5 * 60 then cls(0) sfx(23, "C-5", -1, 0) for sx = 0,240 do for sy = 0,136 do pix(sx,sy,9 + math.random(0,1)) end end else cls(0) --spotlight beam tri(100, 72, 140, 72, 120, -64, 14) --spotlight area for sx = 0, 5 do for sy = 0, 1 do draw(312 + sx + sy*16, 120 - 24 + 8 * sx, 68 - 4 + 8 * sy) end end --death scenes here if deadscene == 1 then --grasping draw(265, 116, 64) --enemy draw(264, 116, (64 - 8 - 6) - math.sin(deadtime*0.2) * 6) --player draw(266, 112, (64 - 8 - 6) - math.sin(deadtime*0.2) * 6) --left hand draw(266, 120, (64 - 8 - 6) - math.sin(deadtime*0.2) * 6) --right hand elseif deadscene == 2 then --smashing local s = math.abs(math.sin(deadtime*0.1)) draw(269, 116, (64 - 2) - s * 16) if s < 0.1 then draw(267, 116, 64) else draw(268, 116, 64) end else --jailing draw(270, (116 - 8), 64) --player draw(271, (116 + 4 + 8), 64) --enemy --jail draw(303, (116 - 4), 64) draw(302, (116 - 4 - 8), 64) draw(287, (116 - 4), (64 - 8)) draw(286, (116 - 4 - 8), (64 - 8)) end end if deadtime >= 3*60 then if btn(4) then gamestate = "game" initialize_game() end print("DEFEAT!", 120 - 8 * 2.25, 68 - 4 + 32,13) print("Press Z to try again!", 120 - 8 * 7, 68 - 4 + 32 + 8,13) end else gamestate = "menu" end end