• Snakoban
    14 replies, posted
[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:
[img]http://img188.imageshack.us/img188/2884/snakoban.png[/img] Challenging.
What the [i]balls[/i]?
[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.