0+S~%SƒvœЋR6‡QџM_WOџwЈџЃТУЧф6џЬЊ)­џџь'џёш pџџџџџџџџ2Tv˜КмўяЭЋ‰gE#2Tv˜Кмў2Tv˜КмўююююююнЬUUUUUUUUЋЊ™xgEАЊ™ˆgE4!3єџџџџџџoUD#@ннннннннннннннннннннннннннннннннРЃѓџџкњџџЃѓџџџџџџџџџџџџџџџџџџџџџџ№џџа№џџ№џџџџџџџџџџџџџџџџџџџџџџ3ѓџџƒѓџџ3ѓџџџџџџџџџџџџџџџџџџџџџџёџџёџџёџџџџџџџџџџџџџџџџџџџџџџн§џџн§џџн§џџџџџџџџџџџџџџџџџџџџџџˆјџџhјџџˆјџџџџџџџџџџџџџџџџџџџџџџН й  rlkjiiiiiiiijjklmnnooooooooooooag knoooooooooooooooooooooooooopp}ppk`PY@07  % № у а а Т А АЁ€‘  Ё АБААСРРСаабааср№ё  02 3FWi y y y i hWED #  № р РРА А    €€€= AAAAAAAAAAA!!!!T T€T`$ $€$`$ $€$`!!A!!!!AAAA AAA!!^€^`^@T T€T`.@.€.`.@$ $€$`$`є#####T T€T`є#####T T€T`###AAAaAAAAAaAaAAAaAAAAAa!!!!!!AA!!!!A! !AAAaAa AAaA!!є#####^€^`^@є#####T T€T`###AAAA$`є####4`50DaШ1‰bШ1‰b гР?нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннЃннннннкннннннЃннннннннннннннннннннннннннннннннннннЃннннннкннннннЃннннннннннннннннннннннннннннннннннннннннннннннннЃннннннкннннннЃннннннннннннннннннннннннннннннннннннЃннннннкннннннЃннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннбннннннннннннннннннннбннннннннннннннбннннннннннннннннннннбннннннннннннннбннннннннннннннннннннбннннннннннннннбнннннннбннбнннннннннннбннннннннннннннннбнннннннбннбнннннннннннбннннннннннннннннбнннннннбннбнннннннннннбнннннннннннннннннннбнннннбннбнннннбнннннннбнннннннннннннннннбнннннбннбнннннбнннннннбнннннннннннннннннбнннннбннбнннннбнннннннбнннннннннннннннннннннннбннбнннннннннннннннннннннннннннннннннннбннбнннннннннннннннннннннннннннннннннннбннбннннннннннннннннннннннннннбнннннннннннннннннннннннбннннннннннннннннннннбнннннннннннннннннннннннбнннннннннннннннннЃнннбнннннннннннннннннннннннбнннннннннннннннннкннннннЃнннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн1:ннннннЁ­нннннн0:нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн1:ннннннЁ­нннннн1:нннннннннннннннннннннннн1:ннннннЁ­нннннн1:0:ннннннЁ­нннннн1:ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн33131ЬСЬСЬСЬ3311133131333131СЬЬСЬСЬС333131313ЬЬ331313331333333331333331ЬЬЬЬ333133Ь133113133333331ЬЬЬЬ333333С1331131333313133131СЬСЬСЬСЬ33133333ЬЬ3133331333'-- title: TiXoNiX -- author: enotofil -- desc: smooth xonix clone -- script: lua -- saveid: tixonix local RND = math.random local SCR = {w=240, h=136} local GAME = {w=80, h=42, scale=3, goal=0.75, lives=3, spawnTime=3600, offX=0, offY=0} local PAUSE = {capture=20, hit=60, level=180} local SPRITES = {out=259, inn=260, enemyOut=256, enemyIn=257, player=258, tail=261} local MUZIX = {title=0, levelUp=1} local SFX = {hit=12, capture=13, spawn=14} local CLS_COLOR = 1 local ALPHA = 15 local KEYFRAME = 3 local INNER_ENEMIES_START_INDEX = 999 function World() local s = {} s.captured = {} s.tail = {} local totalFree = 0 for x = 0, GAME.w-1 do for y = 0, GAME.h-1 do local i = y*GAME.w + x if x<2 or x>GAME.w-3 or y<2 or y>GAME.h-3 then s.captured[i] = true else s.captured[i] = false totalFree = totalFree + 1 end end end s.captureGoal = math.ceil(totalFree * GAME.goal) s.captureCount = 0 function s.CreateTitle() for x = 0, 46 do for y = 0, 10 do if mget(x, y) == 1 then local i = (x+17) + (y+16)*GAME.w s.captured[i] = true end end end s.Draw() end function s.CapturedAt(x, y) if x < 0 or x >= GAME.w then return false end if s.captured[y*GAME.w + x] then return true else return false end end function s.CapturedPrc() return math.floor(100*s.captureCount/s.captureGoal) end function s.TailAt(x, y) if s.tail[y*GAME.w + x] then return true else return false end end function s.AddTail(x, y) s.tail[y*GAME.w + x] = true spr(SPRITES.tail, GAME.offX+x*GAME.scale, GAME.offY+y*GAME.scale, ALPHA) end function s.ClearTail() local lostTail = s.tail s.tail = {} for i,_ in pairs(lostTail) do s.DrawAt(i%GAME.w, i//GAME.w) end end function s.CommitCapture(enemies) -- capture tail for i,_ in pairs(s.tail) do s.captured[i] = true s.captureCount = s.captureCount + 1 s.DrawAt(i%GAME.w, i//GAME.w) end s.tail = {} local enemySpace = {} for _,e in pairs(enemies) do s.floodFill(e.x, e.y, enemySpace) end local score = 0 -- capture outer space without enemies for x = 0, GAME.w-1 do for y = 0, GAME.h-1 do local i = y*GAME.w + x if (not enemySpace[i]) and (not s.captured[i]) then s.captured[i] = true s.captureCount = s.captureCount + 1 score = score + 1 s.DrawAt(x, y) end end end return score end function s.floodFill(x, y, list) local i = GAME.w*y + x if (not list[i]) and (not s.CapturedAt(x,y)) then list[i] = true s.floodFill(x+1,y, list) s.floodFill(x-1,y, list) s.floodFill(x,y+1, list) s.floodFill(x,y-1, list) end end function s.Erase(player, enemies) s.DrawAt(player.x, player.y) s.DrawAt(player.oldX, player.oldY) for _,e in pairs(enemies) do s.DrawAt(e.x, e.y) s.DrawAt(e.oldX, e.oldY) s.DrawAt(e.oldX+e.vx, e.oldY) s.DrawAt(e.oldX, e.oldY+e.vy) end end function s.Draw() for x = 0, GAME.w-1 do for y = 0, GAME.h-1 do s.DrawAt(x, y) end end end function s.DrawAt(x, y) local drawX = GAME.offX+x*GAME.scale local drawY = GAME.offY+y*GAME.scale if s.captured[y*GAME.w + x] then spr(SPRITES.inn, drawX, drawY, ALPHA) elseif s.tail[y*GAME.w + x] then spr(SPRITES.tail, drawX, drawY, ALPHA) else spr(SPRITES.out, drawX, drawY, ALPHA) end end s.Draw() return s end -- Enemy entity, inner or outer function Enemy(x, y) local s = {} if not y then s.x, s.y = RND(4, GAME.w-8), RND(4, GAME.h-8) else s.x, s.y = x, y end s.oldX, s.oldY = s.x, s.y s.vx, s.vy = 1, 1 if RND() > 0.5 then s.vx = s.vx * -1 end if RND() > 0.5 then s.vy = s.vy * -1 end function s.Update(w) local inner = w.CapturedAt(s.x, s.y) repeat local nx = s.x + s.vx local ny = s.y + s.vy local ox = w.CapturedAt(nx, s.y) local oy = w.CapturedAt(s.x, ny) local oxy = w.CapturedAt(nx, ny) if inner then ox, oy, oxy = not ox, not oy, not oxy end -- wall touch check if ox then s.vx = -1*s.vx end if oy then s.vy = -1*s.vy end -- edge touch check if (not ox) and (not oy) and oxy then s.vx = -1*s.vx s.vy = -1*s.vy end until w.CapturedAt(s.x+s.vx, s.y+s.vy)==inner -- move s.oldX, s.oldY = s.x, s.y s.x = s.x + s.vx s.y = s.y + s.vy end function s.Draw(w, tics) local inner = w.CapturedAt(s.x, s.y) local drawX = GAME.offX+s.oldX*GAME.scale + s.vx*(tics%KEYFRAME) local drawY = GAME.offY+s.oldY*GAME.scale + s.vy*(tics%KEYFRAME) if inner then spr(SPRITES.enemyIn, drawX, drawY, ALPHA) else spr(SPRITES.enemyOut, drawX, drawY, ALPHA) end return drawX, drawY end return s end -- Player entity function Player() local s = {} s.x, s.y = GAME.w//2, 0 s.oldX, s.oldY = s.x, s.y s.vx, s.vy = 0, 0 s.hit = false s.captureDone = false function s.IsAt(x, y) return (x==s.x and y==s.y) end function s.Update(w) if s.hit then return end if btn(0) then s.vx, s.vy = 0, -1 end if btn(1) then s.vx, s.vy = 0, 1 end if btn(2) then s.vx, s.vy = -1, 0 end if btn(3) then s.vx, s.vy = 1, 0 end if not w.CapturedAt(s.x, s.y) then sfx(SFX.capture, 24) w.AddTail(s.x, s.y) end -- calc new position s.oldX, s.oldY = s.x, s.y s.x = s.x + s.vx s.y = s.y + s.vy if s.x < 0 or s.x > GAME.w-1 then s.x = s.x - s.vx s.vx = 0 elseif s.y < 0 or s.y > GAME.h-1 then s.y = s.y - s.vy s.vy = 0 end -- finish capture if next(w.tail)~=nil and w.CapturedAt(s.x, s.y) then s.vx, s.vy = 0, 0 s.captureDone = true else s.captureDone = false end end function s.Draw(tics) local drawX = GAME.offX+s.oldX*GAME.scale + s.vx*(tics%KEYFRAME) local drawY = GAME.offY+s.oldY*GAME.scale + s.vy*(tics%KEYFRAME) spr(SPRITES.player, drawX, drawY, ALPHA) return drawX, drawY end return s end -- game manages world, enemies and player function XonixGame() local s = {} s.level = -1 s.lives = GAME.lives s.pauseLeft = 0 s.gameOver = false s.score = 0 s.hiscore = pmem(0) if s.hiscore == 0 then pmem(0, 1000) s.hiscore = pmem(0) end function s.NextLevel() cls(CLS_COLOR) s.tics = 0 s.level = s.level + 1 s.levelDone = false s.spawnTimer = GAME.spawnTime s.world = World() s.enemies = {} s.player = Player() if s.level == 0 then -- Title scene music(MUZIX.title) s.world.CreateTitle() for x=4,70,7 do s.enemies[x] = Enemy(x, 6 + 30*(x%2)) end s.player.x, s.player.oldX = -64, -64 print( "HiScore: Press to start", 0, GAME.h*GAME.scale+2, 3, true ) print( string.format("%13d z", s.hiscore), 0, GAME.h*GAME.scale+2, 12, true ) else music() for i = 1, s.level+1 do s.enemies[i] = Enemy() end end s.AddInnerEnemy() end function s.AddInnerEnemy() local dude = Enemy(GAME.w//2, GAME.h-2) local i = INNER_ENEMIES_START_INDEX while s.enemies[i] ~= nil do i = i + 1 end s.enemies[i] = dude end -- all game logic function s.Update() if s.pauseLeft > 0 then s.pauseLeft = s.pauseLeft - 1 return end if s.gameOver then return "GAME OVER" end if s.levelDone then s.NextLevel() end s.world.Erase(s.player, s.enemies) -- update at KEYFRAME if s.tics % KEYFRAME == 0 then if s.player.hit then s.lives = s.lives - 1 if s.lives == 0 then sfx(SFX.hit, 36) print("GAME OVER", 66, 51, 0, false, 2) print("GAME OVER", 65, 50, 2, false, 2) if s.score > s.hiscore then pmem(0, s.score) print("NEW HISCORE: "..s.score, 31, 71, 0, false, 2) print("NEW HISCORE: "..s.score, 30, 70, 12, false, 2) end s.gameOver = true s.pauseLeft = PAUSE.level else s.player = Player() s.world.ClearTail() end for i in pairs(s.enemies) do --remove all inner enemies if i >= INNER_ENEMIES_START_INDEX then s.enemies[i] = nil end end s.spawnTimer = GAME.spawnTime s.AddInnerEnemy() elseif s.player.captureDone then s.score = s.score + s.world.CommitCapture(s.enemies) s.pauseLeft = PAUSE.capture end -- level finished? local done = s.world.CapturedPrc() if done > 99 then music(MUZIX.levelUp, -1, -1, false) local bonus = (done - 100) * 50 s.score = s.score + bonus print("LEVEL "..s.level.." COMPLETE", 31, 51, 0, false, 2) print("LEVEL "..s.level.." COMPLETE", 30, 50, 12, false, 2) if bonus > 0 then print("BONUS: "..bonus, 66, 71, 0, false, 2) print("BONUS: "..bonus, 65, 70, 9, false, 2) end s.levelDone = true s.pauseLeft = PAUSE.level end -- timeout, spawn new inner enemy if s.spawnTimer < 1 then sfx(SFX.spawn, 36) s.AddInnerEnemy() s.spawnTimer = GAME.spawnTime end -- update player and enemy velocity for _, e in pairs(s.enemies) do e.Update(s.world) end if s.level == 0 then -- press Z at title screen if btn(4) then s.NextLevel() end else s.player.Update(s.world) -- redraw status bar rect(0, GAME.h*GAME.scale, SCR.w, 10, 1) print( "Score: Lives: Done: % Time:", 0, GAME.h*GAME.scale+2, 3, true ) print( string.format("%11d%10d%10d%9d", s.score, s.lives, s.world.CapturedPrc(), s.spawnTimer//60), 0, GAME.h*GAME.scale+2, 12, true ) end end -- draw enemies and player, check collisions if not s.player.hit then local px, py = s.player.Draw(s.tics) if s.world.TailAt(s.player.x, s.player.y) then s.player.hit = true end for _, e in pairs(s.enemies) do local ex, ey = e.Draw(s.world, s.tics) if (math.abs(ex-px)