[highlight]THIS IS STILL A WORK IN PROGRESS[/highlight]
[release]
[tab]What?[/tab]Snakoban is a little java applet made by a guy called Kevan. He describes it as an "idle experiment"
[tab]Why?[/tab] I lost an hour playing it, and I thought "Oh people might like this in gmod to waste time.", so I made it.
[tab]How?[/tab]Well the first thing I did (just now) was a faithful nearly 1:1 conversion from Java to Lua, just as a starting base. However, I can see a lot of potential for new ways of playing this, with distinct levels and such, so I'll do that later.
[tab]Won't he mind?[/tab] Nah, he says the code is free game on his website. (See below)
[tab]Pics[/tab][IMG]http://i37.tinypic.com/4uunh1.jpg[/IMG]
[tab]Original?[/tab][url=http://kevan.org/proce55ing/snakoban/]Original Game[/url] - [url=http://kevan.org/proce55ing/snakoban/snakoban.java]Original Source[/url]
[tab]How do I use this?[/tab] Put the code below in a clientside autorun file, then put [i]play_snakoban[/i] in console and hit enter.
[tab]Instructions?[/tab][quote] * Push the blocks into the holes, and mind your tail.
* Use w, a, s and d to move the snake.
* Press q to start again. [/quote]
[tab]Improvements?[/tab] This code could do with tons, as it's a fairly direct java2lua conversion. Please don't comment on the code, I'm going to make a cleaned up version later. // comments are his direct from the source, all others are mine.
[tab]Code[/tab][lua]--[[
~ Snakoban (Original) ~
~ Original code/concept by Kevan Davis, 26/8/03 ~
~ [url]http://kevan.org/proce55ing/snakoban/[/url] ~
~ Lua-ified by Lexi, 19/10/09 ~
~ This version is a faithful convertion
using the original variable names,
comments, general structure and gameplay. ~
--]]
-- Lua quirk. Define the functions here first
-- to make sure they can all see each other.
-- Also,make them local to prevent leakage.
local setup,loop,addBlock,keyPressed,moveSnake
local square = {}
local tailage = {}
local gamemode = 1
local speed = 200
local level, step
local head = 1
local tail = 2
local block = 3
local hole = 4
local fill = 5
local boardsize = 10
local squaresize = 20
local snakelength
local offx, offy = 0,0
// Setup function, automatically called once at the start.
function setup()
// Fill the board with blank squares, except for the edges, which
// start as filled holes.
for i = 1,boardsize do
square[i] = {}
for j = 1,boardsize do
if i == 1 or j == 1 or i == boardsize or j == boardsize then
square[i][j] = fill
else
square[i][j] = 0
end
end
tailage[i] = {}
end
-- The colours that were defined here are now in the draw function.
// Call the "add a block-and-hole at random" function, five times.
addBlock()
addBlock()
addBlock()
addBlock()
addBlock()
// Set the starting snake length.
snakelength = 5
// Place the snake.
for i = 1, snakelength do
square[i+1][2] = tail
tailage[i+1][2] = snakelength - (i-1)
end
square[snakelength+1][2] = head
// Set the level and step. (Level is how many blocks you need to
// clear to finish that level; step is how many have been cleared.)
level,step = 1,0
end
// The "loop" function is automatically called again and again,
// forever, by Proce55ing. It's the main game loop.
--[[
In this case, it's a think used to detect the keypresses
and move the snake.
--]]
local nextthink = 0
function loop()
--[[
This stuff has been moved to the derma draw.
~ Lexi
--]]
if nextthink > CurTime() then return end
nextthink = CurTime() + (speed / 1000)
-- Check for keys.
keyPressed()
-- Move the snake.
moveSnake()
end
// Function to add a block at random.
function addBlock()
for i = 0,200 do
// Pick a random x and y, and see if that square is empty.
// If it is, change it to a block and set "i" to one, to break
// this loop.
local rx = math.random(boardsize-2)+1
local ry = math.random(boardsize-2)+1
if square[rx][ry] == 0 then
-- I don't know why he does this, it still puts blocks where it shouldn't.
-- Copied directly from the java.
if ((square[rx-1][ry-1] != fill && square[rx][ry-1] != fill &&
square[rx+1][ry-1] != fill && square[rx-1][ry] != fill &&
square[rx+1][ry] != fill && square[rx-1][ry+1] != fill &&
square[rx][ry+1] != fill && square[rx+1][ry+1] != fill &&
square[rx-1][ry-1] != block && square[rx][ry-1] != block &&
square[rx+1][ry-1] != block && square[rx-1][ry] != block &&
square[rx+1][ry] != block && square[rx-1][ry+1] != block &&
square[rx][ry+1] != block && square[rx+1][ry+1] != block)
|| i>198) then
square[rx][ry] = block
break
end
end
end
for i = 0, 500 do
// Same again, to place a hole.
local rx = math.random(boardsize-2)+1
local ry = math.random(boardsize-2)+1
if square[rx][ry] == 0 then
if ((square[rx-1][ry-1] != fill && square[rx][ry-1] != fill &&
square[rx+1][ry-1] != fill && square[rx-1][ry] != fill &&
square[rx+1][ry] != fill && square[rx-1][ry+1] != fill &&
square[rx][ry+1] != fill && square[rx+1][ry+1] != fill &&
square[rx-1][ry-1] != block && square[rx][ry-1] != block &&
square[rx+1][ry-1] != block && square[rx-1][ry] != block &&
square[rx+1][ry] != block && square[rx-1][ry+1] != block &&
square[rx][ry+1] != block && square[rx+1][ry+1] != block)
|| i>200) then
square[rx][ry] = hole
break
end
end
end
end
// This functiong gets called by Proce55ing whenever a key is
// pressed...
--[[
In fact, it's called every 'speed' miliseconds, so we need
to make sure a key has actually been pressed.
--]]
function keyPressed()
// If playing as Sokoban, reset the offsets each keypress.
if gamemode == 1 then
offy,offx = 0,0
end
// See what grid offset the key provokes.
if input.IsKeyDown(KEY_W) then
offy,offx = -1,0
end
if input.IsKeyDown(KEY_S) then
offy,offx = 1,0
end
if input.IsKeyDown(KEY_A) then
offx,offy = -1,0
end
if input.IsKeyDown(KEY_D) then
offx,offy = 1,0
end
// Toggle mode (1=Sokoban, 2=Snake)
if input.IsKeyDown(KEY_M) then
gamemode = 3 - gamemode
end
// Restart
if input.IsKeyDown(KEY_Q) then
setup()
end
// Restart
if input.IsKeyDown(KEY_MINUS) and speed < 200 then
speed = speed + 10
end
if input.IsKeyDown(KEY_EQUAL) and speed > 0 then
speed = speed - 10
end
// If in Sokoban mode, move the snake after each keypress.
-- Actually this will happen anyway.
end
function moveSnake()
local headx,heady = 1,1
local oldest,oldestx,oldesty = snakelength,1,1
local finished = 1
// Run through the board to see where the snake's head is, and
// store its coordinates in headx and heady.
for x = 1, boardsize do
for y = 1, boardsize do
if square[x][y] == head then
headx,heady = x,y
end
end
end
// See whether "current head position plus offset" is a block.
if square[headx+offx] and square[headx+offx][heady+offy] == block then
// See whether "current head position plus offset *twice*" is
// empty; if it is, the block can be pushed. Clever!
if square[headx+(offx*2)][heady+(offy*2)] == 0 then
// Move the block.
square[headx+(offx*2)][heady+(offy*2)] = block
square[headx+offx][heady+offy] = 0
end
if square[headx+(offx*2)] and square[headx+(offx*2)][heady+(offy*2)] == hole then
// Or fill a hole, for that matter.
// Add a new block first, so that it doesn't land where
// the old one was.
addBlock()
// If they've finished a level, add another block.
if step == level then
step,level = 0,level + 1
if level == 21 then level = 20 end
snakelength = snakelength + 1
addBlock()
end
// Fill the hole, kill the block.
square[headx+(offx*2)][heady+(offy*2)] = 0
square[headx+offx][heady+offy] = 0
step = step + 1
end
end
// See whether "current position plus offset" is empty (or if
// the player has pressed X).
if square[headx+offx] and square[headx+offx][heady+offy]==0 or input.IsKeyDown(KEY_X) then
// S
I'v played this before, it's a good idea to release it here in my opinion. Helps pass the time on those slower RP servers, etc. Great job on the conversion.
Seems like "language X" to Lua conversions are catching on. ;) Fantastic port Lexic.
Ok here we go, as promised an improved version. I haven't had the chance to test all the way up to level 25, so if someone can do that for me, I'd appreciate it. I think I've fixed the slugish controls but I'm not sure.
Please, have a go and this time you can comment on the code/visuals. :v:
[lua]--[[
~ Snakoban (Lexi Varient) ~
~ Original code/concept by Kevan Davis, 26/8/03 ~
~ [url]http://kevan.org/proce55ing/snakoban/[/url] ~
~ Made by Lexi, 19/10/09 ~
~ This version is an overhaul, with different code,
game style and play, keeping the concept. ~
--]]
--[[ Functions ]]--
local restart,setup,think,addBox
--[[ Global Storage ]]--
local board = {}
local tail = {}
local ox,oy = 0,0
local hx,hy = 2,2
local frame
--[[ Predefined Config ]]-- -=[ Important note: Editing these will probably break things ]=-
local squaresize = 20 -- How many px each board is on the screen
local initialBoard = 10 -- How large the board is to start with
local initialSnake = 5 -- How long the snake is to start with
local enlargeevery = 5 -- Enlarge the board size every x levels
--[[ Constants ]]--
local NONE = 0
local HEAD = 1
local TAIL = 2
local BOX = 3
local HOLE = 4
local FILL = 5
--[[ Runtime Variables ]]--
local step = 0
local score = 0 -- Not used until level 25
local speed = 160
local level = 1
local gamemode = 1
local boardsize = initialBoard
local snakelength = initialSnake
-- Restarts the game, setting vars to inital and reloading the board.
function restart()
boardsize = initialBoard
snakelength = initialSnake
level = 1
score = 0
step = 1
ox,oy = 0,0
setup()
end
--[[
Sets up a new board with the right board size,
spawns the right number of blocks for the level
and adds a snake.
--]]
function setup()
--[[
Fill the board with blank boards, except for the edges, which
start as filled holes.
--]]
board,tail = {},{}
for x = 1,boardsize do
board[x] = {}
tail[x] = {}
for y = 1,boardsize do
if x == 1 or y == 1 or x == boardsize or y == boardsize then
board[x][y] = FILL
else
board[x][y] = NONE
end
end
end
-- Add the required number of boxes to pass the level
for i = 1,level do
addBox()
end
-- Add some extras to make it easier
addBox()
addBox()
-- Place the snake.
for i = 1, snakelength do
board[i+1][2] = TAIL
tail [i+1][2] = snakelength - i
end
board[snakelength+1][2] = HEAD
hx,hy = snakelength+1,2
frame:InvalidateLayout()
end
-- A think used to detect the keypresses and move the snake.
local nextthink = 0
function think()
if nextthink > CurTime() then return end
nextthink = CurTime() + (speed / 1000)
// If playing as Sokoban, reset the offsets each think.
if gamemode == 1 then
oy,ox = 0,0
end
// See what grid offset the key provokes.
if input.IsKeyDown(KEY_W) then
oy,ox = -1,0
elseif input.IsKeyDown(KEY_S) then
oy,ox = 1,0
elseif input.IsKeyDown(KEY_A) then
ox,oy = -1,0
elseif input.IsKeyDown(KEY_D) then
ox,oy = 1,0
end
// Toggle mode (1=Sokoban style, 2=Snake style)
if input.IsKeyDown(KEY_M) then
gamemode = 3 - gamemode
end
// Restart
if input.IsKeyDown(KEY_Q) then
restart()
end
// Adjust Speed
if input.IsKeyDown(KEY_MINUS) and speed < 200 then
speed = speed + 10
elseif input.IsKeyDown(KEY_EQUAL) and speed > 0 then
speed = speed - 10
end
-- Move the snake.
// See whether "current head position plus offset" is a box
if board[hx+ox] and board[hx+ox][hy+oy] == BOX then
// See whether "current head position plus offset *twice*" is
// empty; if it is, the box can be pushed. Clever!
if board[hx+ox*2][hy+oy*2] == NONE then
// Move the block.
board[hx+ox*2][hy+oy*2] = BOX
board[hx+ox][hy+oy] = NONE
elseif board[hx+ox*2] and board[hx+ox*2][hy+oy*2] == HOLE then
// Or fill a hole, for that matter.
if level == 25 then -- If we're on level 25, we do stuff differently
score = score + 1 -- Add one to the score
if score % enlargeevery == 0 then -- Every enlargeevery (5) scores we
snakelength = snakelength + 1 -- Make the snake larger
if score % (enlargeevery*2) == 0 then -- Every enlargevery*2 (10) scores we
addBox() -- Throw in another block/hole pair for fun.
end
end
else
if step == level then -- If we've pushed enough blocks in holes to advance a level
step,level = 0, level + 1
snakelength = snakelength + 1
frame:SetTitle("Snakoban - Level "..level.." - 0 / "..level)
if level % enlargeevery == 0 then -- Every enlargevery(5) levels we enlarge the board
boardsize = boardsize + enlargeevery -- Make the board big enough to fit the new snake
setup() -- Make a new board
return -- Stop the snake moving excessively.
end
for i = 1,level do
addBox() -- Replace the missing boxes
end
end
board[hx+ox*2][hy+oy*2] = NONE -- Remove the hole.
-- This would be "fill in the hole" if this had individual levels, but it doesn't. D:
board[hx+ox][hy+oy] = NONE -- Remove the box
frame:SetTitle("Snakoban - Level "..level.." - "..step.." / "..level)
step = step + 1
end
end
end
// See whether "current position plus offset" is empty. There was a cheat here, but I removed it.
if board[hx+ox] and board[hx+ox][hy+oy] == NONE then
// Set the current head to a tail (with "tail age" zero).
board[hx][hy] = TAIL
tail [hx][hy] = 0
// Move the head.
hx = hx + ox
hy = hy + oy
board[hx][hy] = HEAD
// Run through the board aging all the tail bits...
for x = 1, boardsize do
for y = 1, boardsize do
if board[x][y] == TAIL then
// Age the tail, see if it's too old.
tail[x][y] = tail[x][y] + 1
if tail[x][y] > snakelength then
board[x][y] = NONE
end
end
end
end
end
end
// Function to add a box and a hole at random.
function addBox()
for i = 0,500 do
local rx = math.random(boardsize-4)+2 -- This ensures boxes are not put in the gutters.
local ry = math.random(boardsize-4)+2
if board[rx][ry] == NONE then
board[rx][ry] = BOX
break
end
end
for i = 0,500 do
local rx = math.random(boardsize-4)+2
local ry = math.random(boardsize-4)+2
if board[rx][ry] == NONE then
board[rx][ry] = HOLE
break
end
end
end
concommand.Add("play_snakoban2",function()
if IsValid(frame) then frame:Remove() end
frame = vgui.Create("DFrame")
frame.pl = frame.PerformLayout
function frame:PerformLayout()
self:SetSize(boardsize * squaresize, boardsize * squaresize + 21)
self.panel:InvalidateLayout()
return self:pl()
end
frame:SetDeleteOnClose(true)
frame:SetDraggable(true)
frame:SetSizable(false)
frame:SetTitle("Snakoban - Level 1 - 0 / 1")
local panel = vgui.Create("Panel",frame)
function panel:PerformLayout()
self:SetPos(0,21)
self:SetSize(boardsize * squaresize, boardsize * squaresize)
end
function panel:Paint() -- This is mostly Kevan's work again.
local blockr,blockg,blockb = level * 10, 0, 200 - (level * 10)
surface.SetDrawColor(51,51,51,255)
surface.DrawRect(0,0,self:GetSize())
// Loop through and draw each board.
for x = 1, boardsize do
for y = 1, boardsize do
local sq = board[x][y]
local draw
if sq == HEAD then
surface.SetDrawColor(0,200,0,255)
draw = true
elseif sq == TAIL then
surface.SetDrawColor(0,100,0,255)
draw = true
elseif sq == BOX then
surface.SetDrawColor(blockr,blockg,blockb,255)
draw = true
elseif sq == HOLE then
surface.SetDrawColor(0,0,0,255)
draw = true
elseif sq == FILL then
surface.SetDrawColor(100,0,0,255)
draw = true
end
if draw then
surface.DrawRect((x-1)*squaresize,(y-1)*squaresize,squaresize,squaresize)
surface.SetDrawColor(0,0,0,255)
surface.DrawOutlinedRect((x-1)*squaresize,(y-1)*squaresize,squaresize,squaresize)
end
end
end
end
panel.Think = think
frame.panel = panel
restart()
frame:MakePopup()
frame:Center()
end)
[/lua]
Oh my God, what are you DOING? Shouldn't those be [i]local[/i] functions?
[editline]01:32PM[/editline]
Ballsack. I keep sniffing my own ass in this game.
[QUOTE=CptFuzzies;17919131]Oh my God, what are you DOING? Shouldn't those be [i]local[/i] functions?
[editline]01:32PM[/editline]
Ballsack. I keep sniffing my own ass in this game.[/QUOTE]
They are. :v:
Functions are first class values, so line #10, [i]local restart,setup,think,addBox [/i] means that all those functions are local.
To test, run this snipit.
[lua]do
local a
function a()
print"Foo!"
end
end
a()[/lua]
One line mode for lua_run: [i]lua_run_cl do local a function a() print[[foo]] end end a()[/i]
[editline]10:00PM[/editline]
well I've been playing mine but when you get to the higher levels, it just gets a bit dull.
[IMG]http://i38.tinypic.com/2hf6f5v.jpg[/IMG]
I've done a bunch of bugfixing, I'm just going to make the tail fade then I'll update my post. Someone needs to come in and make my version challenging. :saddowns:
Hahaha, ya got me. I saw those, and apparently missed the connection.
Also, I give you MAAAD props for doing a proper language conversion. :v: Included commented code and everything.
[IMG]http://i37.tinypic.com/2qcmheh.jpg[/IMG]
Fading snake.
[lua]--[[
~ Snakoban (Lexi Varient) ~
~ Original code/concept by Kevan Davis, 26/8/03 ~
~ [url]http://kevan.org/proce55ing/snakoban/[/url] ~
~ Made by Lexi, 19/10/09 ~
~ This version is an overhaul, with different code,
game style and play, keeping the concept. ~
--]]
--[[ Functions ]]--
local restart,setup,think,addBox
--[[ Global Storage ]]--
local board = {}
local tail = {}
local ox,oy = 0,0
local hx,hy = 2,2
local frame
--[[ Predefined Config ]]-- -=[ Important note: Editing these will probably break things ]=-
local squaresize = 20 -- How many px each board is on the screen
local initialBoard = 10 -- How large the board is to start with
local initialSnake = 5 -- How long the snake is to start with
local enlargeevery = 5 -- Enlarge the board size every x levels
--[[ Constants ]]--
local NONE = 0
local HEAD = 1
local TAIL = 2
local BOX = 3
local HOLE = 4
local FILL = 5
--[[ Runtime Variables ]]--
local step = 0
local score = 0 -- Not used until level 25
local speed = 160
local level = 1
local gamemode = 1
local boardsize = initialBoard
local snakelength = initialSnake
--[[ debug ]]--
local boxes = 0
-- Restarts the game, setting vars to inital and reloading the board.
function restart()
boardsize = initialBoard
snakelength = initialSnake
level = 1
score = 0
step = 1
ox,oy = 0,0
frame:SetTitle("Snakoban - Level 1 - 0 / 1")
setup()
end
--[[
Sets up a new board with the right board size,
spawns the right number of blocks for the level
and adds a snake.
--]]
function setup()
--[[
Fill the board with blank boards, except for the edges, which
start as filled holes.
--]]
boxes = 0
board,tail = {},{}
for x = 1,boardsize do
board[x] = {}
tail[x] = {}
for y = 1,boardsize do
if x == 1 or y == 1 or x == boardsize or y == boardsize then
board[x][y] = FILL
else
board[x][y] = NONE
end
end
end
-- Add the required number of boxes to pass the level
for i = 1,level do
addBox()
end
-- Add some extras to make it easier
addBox()
addBox()
-- Place the snake.
for i = 1, snakelength do
board[i+1][2] = TAIL
tail [i+1][2] = snakelength - i
end
board[snakelength+1][2] = HEAD
hx,hy = snakelength+1,2
frame:InvalidateLayout()
end
-- A think used to detect the keypresses and move the snake.
local nextthink = 0
function think()
if nextthink > CurTime() then return end
nextthink = CurTime() + (speed / 1000)
// If playing as Sokoban, reset the offsets each think.
if gamemode == 1 then
oy,ox = 0,0
end
// See what grid offset the key provokes.
if input.IsKeyDown(KEY_W) then
oy,ox = -1,0
elseif input.IsKeyDown(KEY_S) then
oy,ox = 1,0
elseif input.IsKeyDown(KEY_A) then
ox,oy = -1,0
elseif input.IsKeyDown(KEY_D) then
ox,oy = 1,0
end
// Toggle mode (1=Sokoban style, 2=Snake style)
if input.IsKeyDown(KEY_M) then
gamemode = 3 - gamemode
end
// Restart
if input.IsKeyDown(KEY_Q) then
restart()
end
// Adjust Speed
if input.IsKeyDown(KEY_MINUS) and speed < 200 then
speed = speed + 10
elseif input.IsKeyDown(KEY_EQUAL) and speed > 0 then
speed = speed - 10
end
-- Move the snake.
// See whether "current head position plus offset" is a box
if board[hx+ox] and board[hx+ox][hy+oy] == BOX then
// See whether "current head position plus offset *twice*" is
// empty; if it is, the box can be pushed. Clever!
if board[hx+ox*2][hy+oy*2] == NONE then
// Move the block.
board[hx+ox*2][hy+oy*2] = BOX
board[hx+ox][hy+oy] = NONE
elseif board[hx+ox*2] and board[hx+ox*2][hy+oy*2] == HOLE then
// Or fill a hole, for that matter.
if level == 25 then -- If we're on level 25, we do stuff differently
score = score + 1 -- Add one to the score
frame:SetTitle("Snakoban - Level "..level.." - "..score.." boxes cleared.")
if score % enlargeevery == 0 then -- Every enlargeevery (5) scores we
snakelength = snakelength + 1 -- Make the snake larger
if score % (enlargeevery*2) == 0 then -- Every enlargevery*2 (10) scores we
addBox() -- Throw in another block/hole pair for fun.
end
end
else
if step == level then -- If we've pushed enough blocks in holes to advance a level
step,level = 0, level + 1
snakelength = snakelength + 1
frame:SetTitle("Snakoban - Level "..level.." - 0 / "..level)
if level % enlargeevery == 0 then -- Every enlargevery(5) levels we enlarge the board
boardsize = boardsize + enlargeevery -- Make the board big enough to fit the new snake
step = step + 1 -- Add a step because it won't get added otherwise
setup() -- Make a new board
return -- Stop the snake moving excessively.
end
for i = 1,level do
addBox() -- Replace the missing boxes
end
end
frame:SetTitle("Snakoban - Level "..level.." - "..step.." / "..level)
end
board[hx+ox*2][hy+oy*2] = NONE -- Remove the hole.
board[hx+ox][hy+oy] = NONE -- Remove the box
step = step + 1
boxes = boxes - 1
end
end
// See whether "current position plus offset" is empty. There was a cheat here, but I removed it.
if board[hx+ox] and board[hx+ox][hy+oy] == NONE then
// Set the current head to a tail (with "tail age" zero).
board[hx][hy] = TAIL
tail [hx][hy] = 0
// Move the head.
hx = hx + ox
hy = hy + oy
board[hx][hy] = HEAD
// Run through the board aging all the tail bits...
for x = 1, boardsize do
for y = 1, boardsize do
if board[x][y] == TAIL then
// Age the tail, see if it's too old.
tail[x][y] = tail[x][y] + 1
if tail[x][y] >= snakelength then
board[x][y] = NONE
end
end
end
end
end
end
// Function to add a box and a hole at random.
function addBox()
for i = 0,500 do
local rx = math.random(boardsize-4)+2 -- This ensures boxes are not put in the gutters.
local ry = math.random(boardsize-4)+2
if board[rx][ry] == NONE then
board[rx][ry] = BOX
boxes = boxes + 1
break
end
end
for i = 0,500 do
local rx = math.random(boardsize-4)+2
local ry = math.random(boardsize-4)+2
if board[rx][ry] == NONE then
board[rx][ry] = HOLE
break
end
end
end
concommand.Add("play_snakoban2",function()
if IsValid(frame) then frame:Remove() end
frame = vgui.Create("DFrame")
frame.pl = frame.PerformLayout
function frame:PerformLayout()
self:SetSize(boardsize * squaresize, boardsize * squaresize + 21)
self.panel:InvalidateLayout()
return self:pl()
end
frame:SetDeleteOnClose(true)
frame:SetDraggable(true)
frame:SetSizable(false)
frame:SetTitle("Snakoban")
local panel = vgui.Create("Panel",frame)
function panel:PerformLayout()
self:SetPos(0,21)
self:SetSize(boardsize * squaresize, boardsize * squaresize)
end
function panel:Paint() -- This is mostly Kevan's work again.
local blockr,blockg,blockb = level * 10, 0, 250 - level * 10
surface.SetDrawColor(51,51,51,255)
surface.DrawRect(0,0,self:GetSize())
--[[
surface.SetTextColor(255,255,255,255)
surface.SetFont"DefaultLarge"
surface.SetTextPos(25,20)
surface.DrawText(boxes)
--]]
// Loop through and draw each board.
for x = 1, boardsize do
for y = 1, boardsize do
local sq = board[x][y]
local draw
if sq == HEAD then
surface.SetDrawColor(0,200,0,255)
draw = true
elseif sq == TAIL then
surface.SetDrawColor(0,50+100*(1-tail[x][y]/snakelength),0,255)
draw = true
elseif sq == BOX then
surface.SetDrawColor(blockr,blockg,blockb,255)
draw = true
elseif sq == HOLE then
surface.SetDrawColor(0,0,0,255)
draw = true
elseif sq == FILL then
surface.SetDrawColor(100,0,0,255)
draw = true
end
if draw then
surface.DrawRect((x-1)*squaresize,(y-1)*squaresize,squaresize,squaresize)
surface.SetDrawColor(0,0,0,255)
surface.DrawOutlinedRect((x-1)*squaresize,(y-1)*squaresize,squaresize,squaresize)
end
end
end
end
panel.Think = think
frame.panel = panel
restart()
frame:MakePopup()
frame:Center()
end)
[/lua]
I can't think of anything to do now. You're better at invention, you have a go. :v:
[QUOTE=Salads;17920137][img]http://img188.imageshack.us/img188/2884/snakoban.png[/img]
Challenging.[/QUOTE] But doable. :v:
[IMG]http://i36.tinypic.com/2n7lux.jpg[/IMG]
:science:
[editline]10:38PM[/editline]
Updated OP. This syntax highlighter is balls.
[editline]11:02PM[/editline]
Hmm.
I think I may have overdone the difficulty modifier a little.
[IMG]http://i34.tinypic.com/eguyc7.jpg[/IMG]
:laffo:
Final testing version for tonight. This [i]does[/i] get progressively harder.
Every box you push into a hole has a 50% chance to respawn and every box that's on the screen has a 50% chance to still be there every size upgrade.
I can't seem to get past level 9 though, so it might be a bit too hard. :v:
[lua]--[[
~ Snakoban (Lexi Varient) ~
~ Original code/concept by Kevan Davis, 26/8/03 ~
~ [url]http://kevan.org/proce55ing/snakoban/[/url] ~
~ Made by Lexi, 19/10/09 ~
~ This version is an overhaul, with different code,
game style and play, keeping the concept. ~
--]]
--[[ Functions ]]--
local restart,setup,think,addBox
--[[ Global Storage ]]--
local board = {}
local tail = {}
local ox,oy = 0,0
local hx,hy = 2,2
local frame
--[[ Predefined Config ]]-- -=[ Important note: Editing these will probably break things ]=-
local squaresize = 20 -- How many px each board is on the screen
local initialBoard = 10 -- How large the board is to start with
local initialSnake = 5 -- How long the snake is to start with
local enlargeevery = 5 -- Enlarge the board size every x levels
--[[ Constants ]]--
local NONE = 0
local HEAD = 1
local TAIL = 2
local BOX = 3
local HOLE = 4
local FILL = 5
--[[ Runtime Variables ]]--
local step = 0
local boxes = 0
local score = 0 -- Not used until level 25
local speed = 160
local level = 1
local gamemode = 1
local boardsize = initialBoard
local snakelength = initialSnake
-- Restarts the game, setting vars to inital and reloading the board.
function restart()
boardsize = initialBoard
snakelength = initialSnake
level = 1
score = 0
boxes = 0
step = 1
ox,oy = 0,0
frame:SetTitle("Snakoban - Level 1 - 0 / 1")
setup()
end
--[[
Sets up a new board with the right board size,
spawns the right number of blocks for the level
and adds a snake.
--]]
function setup()
--[[
Fill the board with blank boards, except for the edges, which
start as filled holes.
--]]
board,tail = {},{}
for x = 1,boardsize do
board[x] = {}
tail[x] = {}
for y = 1,boardsize do
if x == 1 or y == 1 or x == boardsize or y == boardsize then
board[x][y] = FILL
else
board[x][y] = NONE
end
end
end
local a = boxes
boxes = 0
--[
if a > 0 then
for i = 1,a do
if math.random() > 0.5 then
addBox()
end
end
end
--]]
-- Add the required number of boxes to pass the level
for i = 1,level do
addBox()
end
-- Add some extras for the hell of it
addBox()
-- Place the snake.
for i = 1, snakelength do
board[i+1][2] = TAIL
tail [i+1][2] = snakelength - i
end
board[snakelength+1][2] = HEAD
hx,hy = snakelength+1,2
frame:InvalidateLayout()
end
-- A think used to detect the keypresses and move the snake.
local nextthink = 0
function think()
if nextthink > CurTime() then return end
nextthink = CurTime() + (speed / 1000)
// If playing as Sokoban, reset the offsets each think.
if gamemode == 1 then
oy,ox = 0,0
end
// See what grid offset the key provokes.
if input.IsKeyDown(KEY_W) then
oy,ox = -1,0
elseif input.IsKeyDown(KEY_S) then
oy,ox = 1,0
elseif input.IsKeyDown(KEY_A) then
ox,oy = -1,0
elseif input.IsKeyDown(KEY_D) then
ox,oy = 1,0
end
// Toggle mode (1=Sokoban style, 2=Snake style)
if input.IsKeyDown(KEY_M) then
gamemode = 3 - gamemode
end
// Restart
if input.IsKeyDown(KEY_Q) then
restart()
end
// Adjust Speed
if input.IsKeyDown(KEY_MINUS) and speed < 200 then
speed = speed + 10
elseif input.IsKeyDown(KEY_EQUAL) and speed > 0 then
speed = speed - 10
end
-- Move the snake.
// See whether "current head position plus offset" is a box
if board[hx+ox] and board[hx+ox][hy+oy] == BOX then
// See whether "current head position plus offset *twice*" is
// empty; if it is, the box can be pushed. Clever!
if board[hx+ox*2][hy+oy*2] == NONE then
// Move the block.
board[hx+ox*2][hy+oy*2] = BOX
board[hx+ox][hy+oy] = NONE
elseif board[hx+ox*2] and board[hx+ox*2][hy+oy*2] == HOLE then
// Or fill a hole, for that matter.
if level == 25 then -- If we're on level 25, we do stuff differently
score = score + 1 -- Add one to the score
frame:SetTitle("Snakoban - Level "..level.." - "..score.." boxes cleared.")
if score % enlargeevery == 0 then -- Every enlargeevery (5) scores we
snakelength = snakelength + 1 -- Make the snake larger
if score % (enlargeevery*2) == 0 then -- Every enlargevery*2 (10) scores we
addBox() -- Throw in another block/hole pair for fun.
end
end
else
if step == level then -- If we've pushed enough blocks in holes to advance a level
step,level = 0, level + 1
snakelength = snakelength + 1
frame:SetTitle("Snakoban - Level "..level.." - 0 / "..level)
if level % enlargeevery == 0 then -- Every enlargevery(5) levels we enlarge the board
boardsize = boardsize + enlargeevery -- Make the board big enough to fit the new snake
step = step + 1 -- Add a step because it won't get added otherwise
setup() -- Make a new board
return -- Stop the snake moving excessively.
end
addBox()
end
frame:SetTitle("Snakoban - Level "..level.." - "..step.." / "..level)
end
if math.random() > 0.5 then
addBox()
end
board[hx+ox*2][hy+oy*2] = NONE -- Remove the hole.
board[hx+ox][hy+oy] = NONE -- Remove the box
step = step + 1
end
end
// See whether "current position plus offset" is empty. There was a cheat here, but I removed it.
if board[hx+ox] and board[hx+ox][hy+oy] == NONE then
// Set the current head to a tail (with "tail age" zero).
board[hx][hy] = TAIL
tail [hx][hy] = 0
// Move the head.
hx = hx + ox
hy = hy + oy
board[hx][hy] = HEAD
// Run through the board aging all the tail bits...
for x = 1, boardsize do
for y = 1, boardsize do
if board[x][y] == TAIL then
// Age the tail, see if it's too old.
tail[x][y] = tail[x][y] + 1
if tail[x][y] >= snakelength then
board[x][y] = NONE
end
end
end
end
end
end
// Function to add a box and a hole at random.
function addBox()
for i = 0,500 do
local rx = math.random(boardsize-4)+2 -- This ensures boxes are not put in the gutters.
local ry = math.random(boardsize-4)+2
if board[rx][ry] == NONE then
board[rx][ry] = BOX
boxes = boxes + 1
break
end
end
for i = 0,500 do
local rx = math.random(boardsize-4)+2
local ry = math.random(boardsize-4)+2
if board[rx][ry] == NONE then
board[rx][ry] = HOLE
break
end
end
end
concommand.Add("play_snakoban2",function()
if IsValid(frame) then frame:Remove() end
frame = vgui.Create("DFrame")
frame.pl = frame.PerformLayout
function frame:PerformLayout()
self:SetSize(boardsize * squaresize, boardsize * squaresize + 21)
self.panel:InvalidateLayout()
return self:pl()
end
frame:SetDeleteOnClose(true)
frame:SetDraggable(true)
frame:SetSizable(false)
frame:SetTitle("Snakoban")
local panel = vgui.Create("Panel",frame)
function panel:PerformLayout()
self:SetPos(0,21)
self:SetSize(boardsize * squaresize, boardsize * squaresize)
end
function panel:Paint() -- This is mostly Kevan's work again.
local blockr,blockg,blockb = level * 10, 0, 250 - level * 10
surface.SetDrawColor(51,51,51,255)
surface.DrawRect(0,0,self:GetSize())
--[[
surface.SetTextColor(255,255,255,255)
surface.SetFont"DefaultLarge"
surface.SetTextPos(25,20)
surface.DrawText(boxes)
--]]
// Loop through and draw each board.
for x = 1, boardsize do
for y = 1, boardsize do
local sq = board[x][y]
local draw
if sq == HEAD then
surface.SetDrawColor(0,200,0,255)
draw = true
elseif sq == TAIL then
surface.SetDrawColor(0,50+100*(1-tail[x][y]/snakelength),0,255)
draw = true
elseif sq == BOX then
surface.SetDrawColor(blockr,blockg,blockb,255)
draw = true
elseif sq == HOLE then
surface.SetDrawColor(0,0,0,255)
draw = true
elseif sq == FILL then
surface.SetDrawColor(100,0,0,255)
draw = true
end
if draw then
surface.DrawRect((x-1)*squaresize,(y-1)*squaresize,squaresize,squaresize)
surface.SetDrawColor(0,0,0,255)
surface.DrawOutlinedRect(
Can someone move this back to the main Lua Scripting subforum please. It's release ready yet, it's a WIP.
Sorry, you need to Log In to post a reply to this thread.