add RND games
This commit is contained in:
parent
13500bb5aa
commit
9147c4f8d1
213
mods/games/checkers.lua
Normal file
213
mods/games/checkers.lua
Normal file
@ -0,0 +1,213 @@
|
||||
-- CHECKERS GAME
|
||||
|
||||
local checkers ={};
|
||||
checkers.piece = "";checkers.time = 0;
|
||||
checkers.pos = {} -- bottom left position of 8x8 checkerboard piece
|
||||
checkers.piece_pos = {} -- position of pick up piece
|
||||
|
||||
--game pieces
|
||||
|
||||
local function draw_board() -- pos is bottom left position of checkerboard
|
||||
|
||||
local pos = checkers.pos;
|
||||
if pos == nil then return end
|
||||
local node;
|
||||
for i = 1,8 do
|
||||
for j =1,8 do
|
||||
node = minetest.get_node({x=pos.x+i-1,y=pos.y,z=pos.z-1}).name;
|
||||
if (i+j) % 2 == 1 then
|
||||
if node~="games:board_black" then minetest.set_node({x=pos.x+i-1,y=pos.y,z=pos.z+j-1},{name = "games:board_black"}) end
|
||||
else
|
||||
if node~="games:board_white" then minetest.set_node({x=pos.x+i-1,y=pos.y,z=pos.z+j-1},{name = "games:board_white"}) end
|
||||
end
|
||||
node = minetest.get_node({x=pos.x+i-1,y=pos.y+1,z=pos.z+j-1}).name;
|
||||
if node~="air" then minetest.set_node({x=pos.x+i-1,y=pos.y+1,z=pos.z+j-1},{name = "air"}) end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1,4 do -- place pieces
|
||||
minetest.set_node({x=pos.x+2*i-1,y=pos.y+1,z=pos.z},{name = "games:checkers_red"})
|
||||
minetest.set_node({x=pos.x+2*i-2,y=pos.y+1,z=pos.z+1},{name = "games:checkers_red"})
|
||||
|
||||
minetest.set_node({x=pos.x+2*i-1,y=pos.y+1,z=pos.z+6},{name = "games:checkers_blue"})
|
||||
minetest.set_node({x=pos.x+2*i-2,y=pos.y+1,z=pos.z+7},{name = "games:checkers_blue"})
|
||||
end
|
||||
|
||||
for i = 1,8 do -- place kings
|
||||
node = minetest.get_node({x=pos.x+i-1,y=pos.y+1,z=pos.z-2}).name;
|
||||
if node~="games:checkers_red_queen" then minetest.set_node({x=pos.x+i-1,y=pos.y+1,z=pos.z-2},{name = "games:checkers_red_queen"}) end
|
||||
node = minetest.get_node({x=pos.x+i-1,y=pos.y,z=pos.z-2}).name;
|
||||
if node~="games:board_white" then minetest.set_node({x=pos.x+i-1,y=pos.y,z=pos.z-2},{name = "games:board_white"}) end
|
||||
|
||||
node = minetest.get_node({x=pos.x+i-1,y=pos.y+1,z=pos.z+9}).name;
|
||||
if node~="games:checkers_blue_queen" then minetest.set_node({x=pos.x+i-1,y=pos.y+1,z=pos.z+9},{name = "games:checkers_blue_queen"}) end
|
||||
node = minetest.get_node({x=pos.x+i-1,y=pos.y,z=pos.z+9}).name;
|
||||
if node~="games:board_white" then minetest.set_node({x=pos.x+i-1,y=pos.y,z=pos.z+9},{name = "games:board_white"}) end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
minetest.register_node("games:checkers", {
|
||||
description = "checkers crate",
|
||||
tiles = {"moreblocks_iron_checker.png","crate.png","crate.png","crate.png","crate.png","crate.png"},
|
||||
groups = {oddly_breakable_by_hand=1},
|
||||
is_ground_content = false,
|
||||
paramtype = "light",
|
||||
light_source = 14,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext","checkers game block, punch to start game")
|
||||
meta:set_int("time", minetest.get_gametime());
|
||||
meta:set_string("player1","");meta:set_string("player2","");
|
||||
meta:set_int("state",0); -- state 0 : waiting for players 1: active game
|
||||
checkers.pos = {x = pos.x+1, y=pos.y-1, z=pos.z+1}
|
||||
end,
|
||||
on_punch = function(pos, node, player)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
local meta = minetest.get_meta(pos);
|
||||
local state = meta:get_int("state");
|
||||
local name1 = meta:get_string("player1")
|
||||
local name2 = meta:get_string("player2")
|
||||
|
||||
if state == 1 then
|
||||
local player1 = minetest.get_player_by_name(name1)
|
||||
local player2 = minetest.get_player_by_name(name2)
|
||||
local endgame = 0;
|
||||
if not player1 or not player2 then endgame = 1 end
|
||||
|
||||
if endgame == 0 then
|
||||
local p = player1:getpos();
|
||||
local dist = math.abs(p.x-pos.x)+math.abs(p.y-pos.y)+math.abs(p.z-pos.z);
|
||||
if dist>32 then endgame = 1 end
|
||||
p = player2:getpos();
|
||||
dist = math.abs(p.x-pos.x)+math.abs(p.y-pos.y)+math.abs(p.z-pos.z);
|
||||
if dist>16 then endgame = 1 end
|
||||
end
|
||||
|
||||
if endgame == 1 then
|
||||
meta:set_int("state",0); meta:set_string("infotext", "checkers waiting for players, punch block to sign up.");
|
||||
meta:set_string("player1","");meta:set_string("player2","");
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local startgame = 0;
|
||||
if name1=="" then
|
||||
meta:set_string("player1",name); name1 = name; if name2~="" then startgame = 1;end
|
||||
elseif name2=="" then
|
||||
meta:set_string("player2",name); name2 = name; if name1~="" then startgame = 1;end
|
||||
end
|
||||
|
||||
if startgame == 0 and name~=name1 and name~=name2 then
|
||||
return
|
||||
end
|
||||
|
||||
if startgame == 1 or state == 1 then
|
||||
meta:set_int("state",1);
|
||||
meta:set_string("infotext", "game of checkers started. players " .. name1 .. " and " .. name2);
|
||||
checkers.pos = {x = pos.x+1, y=pos.y, z=pos.z+1}
|
||||
draw_board()
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
minetest.register_chatcommand("checkers", {
|
||||
description = "Start a game of checkers and refresh board display",
|
||||
privs = {kick=true},
|
||||
func = function(name,param)
|
||||
draw_board();checkers.piece = ""
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
function register_piece(name, desc, tiles, punch)
|
||||
minetest.register_node(name, {
|
||||
description = desc,
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
tiles = tiles,
|
||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=3},
|
||||
sounds = default.node_sound_defaults(),
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.5, -0.5, -0.5, 0.5, -0.3, 0.5},
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.5, -0.5, -0.5, 0.5, -0.3, 0.5},
|
||||
|
||||
},
|
||||
on_punch= punch,
|
||||
})
|
||||
end
|
||||
function register_board(name,desc,tiles)
|
||||
minetest.register_node(name, {
|
||||
description = desc,
|
||||
tiles = tiles,
|
||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=3},
|
||||
sounds = default.node_sound_defaults(),
|
||||
on_punch = function(pos, node, player) -- place piece on board
|
||||
local name = player:get_player_name(); if name == nil then return end
|
||||
if checkers.pos.x == nil then minetest.chat_send_player(name,"punch checkers game block before playing.") return end
|
||||
|
||||
local meta = minetest.get_meta({x=checkers.pos.x-1,y=checkers.pos.y,z=checkers.pos.z-1}); local state = meta:get_int("state");
|
||||
if state ~= 1 then minetest.chat_send_player(name,"punch checkers game block before playing.") return end
|
||||
local name1 = meta:get_string("player1");local name2 = meta:get_string("player2");
|
||||
if name~=name1 and name~=name2 then return end
|
||||
|
||||
if checkers.piece == "" then return end
|
||||
local t = minetest.get_gametime(); if t-checkers.time <1 then return end; checkers.time = t;
|
||||
local above = {x=pos.x,y=pos.y+1;z=pos.z};
|
||||
local x,y; x= above.z-checkers.pos.z+1; y=above.x-checkers.pos.x+1;
|
||||
minetest.set_node(above, {name = checkers.piece});
|
||||
|
||||
local text = "#CHECKERS : " .. name .." moved: ".. checkers.piece_pos.z-checkers.pos.z+1 .. "," .. checkers.piece_pos.x-checkers.pos.x+1 .. " to " ..
|
||||
x .. "," .. y;
|
||||
|
||||
minetest.chat_send_player(name1,text);minetest.chat_send_player(name2,text);
|
||||
checkers.piece = ""
|
||||
end,
|
||||
on_rightclick = function(pos, node, player, itemstack, pointed_thing) -- capture piece
|
||||
local name = player:get_player_name(); if name == nil then return end
|
||||
if checkers.pos.x == nil then minetest.chat_send_player(name,"punch checkers game block before playing.") return end
|
||||
local meta = minetest.get_meta({x=checkers.pos.x-1,y=checkers.pos.y, z=checkers.pos.z-1}); local state = meta:get_int("state");
|
||||
if state ~= 1 then minetest.chat_send_player(name,"punch checkers game block before playing.") return end
|
||||
local name1 = meta:get_string("player1");local name2 = meta:get_string("player2");
|
||||
if name~=name1 and name~=name2 then return end
|
||||
if checkers.piece == "" then return end
|
||||
minetest.chat_send_all(name .." captured piece at ".. checkers.piece_pos.z-checkers.pos.z+1 .. ","..checkers.piece_pos.x-checkers.pos.x+1)
|
||||
checkers.piece = "" return
|
||||
end
|
||||
|
||||
})
|
||||
end
|
||||
|
||||
local piece_punch = function(pos, node, player) -- pick up piece
|
||||
local name = player:get_player_name(); if name == nil then return end
|
||||
if checkers.pos.x == nil then minetest.chat_send_player(name,"punch checkers game block before playing.") return end
|
||||
|
||||
local meta = minetest.get_meta({x=checkers.pos.x-1,y=checkers.pos.y,z=checkers.pos.z-1}); local state = meta:get_int("state");
|
||||
if state ~= 1 then minetest.chat_send_player(name,"punch checkers game block before playing.") return end
|
||||
local name1 = meta:get_string("player1");local name2 = meta:get_string("player2");
|
||||
if name~=name1 and name~=name2 then return end
|
||||
|
||||
if checkers.piece~="" then return end -- dont pick up another piece before last one was put down
|
||||
|
||||
local t = minetest.get_gametime(); if t-checkers.time <1 then return end; checkers.time = t;
|
||||
checkers.piece = node.name; minetest.set_node(pos, {name="air"});
|
||||
checkers.piece_pos = {x=pos.x,y=pos.y,z=pos.z};
|
||||
end
|
||||
|
||||
register_board("games:board_white","white board",{"wool_white.png"})
|
||||
register_board("games:board_black","black board",{"wool_black.png"})
|
||||
|
||||
register_piece("games:checkers_blue","blue piece",{"wool_blue.png"},piece_punch)
|
||||
register_piece("games:checkers_blue_queen","blue queen piece",{"queen_blue.png"},piece_punch)
|
||||
|
||||
register_piece("games:checkers_red","red piece",{"wool_red.png"},piece_punch)
|
||||
register_piece("games:checkers_red_queen","red piece",{"queen_red.png"},piece_punch)
|
1
mods/games/depends.txt
Normal file
1
mods/games/depends.txt
Normal file
@ -0,0 +1 @@
|
||||
default
|
7
mods/games/init.lua
Normal file
7
mods/games/init.lua
Normal file
@ -0,0 +1,7 @@
|
||||
-- rnd: collection of puzzle games for minetest
|
||||
dofile(minetest.get_modpath("games").."/maze.lua")
|
||||
dofile(minetest.get_modpath("games").."/sokoban.lua")
|
||||
dofile(minetest.get_modpath("games").."/spleef.lua")
|
||||
dofile(minetest.get_modpath("games").."/checkers.lua")
|
||||
--dofile(minetest.get_modpath("games").."/life.lua")
|
||||
print("[games] loaded")
|
104
mods/games/life.lua
Normal file
104
mods/games/life.lua
Normal file
@ -0,0 +1,104 @@
|
||||
-- game of life
|
||||
|
||||
local life_table = {};
|
||||
local dim = 5;
|
||||
|
||||
minetest.register_abm(
|
||||
{nodenames = {"games:life"},
|
||||
interval = 5.0,
|
||||
chance = 1,
|
||||
action = function(pos)
|
||||
|
||||
local meta = minetest.get_meta(pos); local infotext = meta:get_string("infotext");
|
||||
if infotext~="RUN" then return end
|
||||
|
||||
if life_table[0]==nil then return end-- punch node again to initialize
|
||||
|
||||
local table_new = {};
|
||||
local i,j,k,c,n,p;
|
||||
local dp = {{-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{-1,1},{0,1},{1,1}};
|
||||
for i = -dim,dim do
|
||||
table_new[i]={};
|
||||
for j = -dim,dim do
|
||||
c = life_table[i][j];
|
||||
n=0;
|
||||
for k = 1,8 do
|
||||
p={i+dp[k][1],j+dp[k][2]};
|
||||
if p[1]<-dim then p[1]=dim elseif p[1]>dim then p[1]=-dim end;
|
||||
if p[2]<-dim then p[2]=dim elseif p[2]>dim then p[2]=-dim end;
|
||||
if life_table[ p[1] ][ p[2] ]==1 then n=n+1 end
|
||||
end
|
||||
if c == 1 then --alive
|
||||
if n>=2 and n<=3 then table_new[i][j]=1
|
||||
else
|
||||
table_new[i][j]=0
|
||||
end
|
||||
else -- dead
|
||||
if n==3 then table_new[i][j]=1 else table_new[i][j]=0 end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
p={x=pos.x,y=pos.y+1,z=pos.z}
|
||||
for i = -dim,dim do
|
||||
for j = -dim,dim do
|
||||
life_table[i][j]=table_new[i][j]
|
||||
p.x = pos.x+i;p.z=pos.z+j;
|
||||
if minetest.get_node(p).name=="air" then
|
||||
if life_table[i][j]==1 then minetest.set_node(p,{name="stairs:slab_stone"}) end
|
||||
else
|
||||
if life_table[i][j]==0 then minetest.set_node(p,{name="air"}) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end,
|
||||
})
|
||||
|
||||
local function init_game(pos)
|
||||
local name; local i,j;local p = {x=pos.x;y=pos.y+1,z=pos.z};
|
||||
for i = -dim,dim do
|
||||
life_table[i]={};
|
||||
for j = -dim,dim do
|
||||
p.x = pos.x+i;p.z=pos.z+j
|
||||
name = minetest.get_node(p).name;
|
||||
if name == "air" then life_table[i][j]=0 else life_table[i][j]=1 end
|
||||
if life_table[i][j]==1 then minetest.set_node(p,{name="stairs:slab_stone"}) end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("games:life", {
|
||||
description = "game of life, game field is 1 above ",
|
||||
inventory_image = "default_tree.png",
|
||||
wield_image = "default_tree.png",
|
||||
wield_scale = {x=0.8,y=2.5,z=1.3},
|
||||
tiles = {"default_tree.png"},
|
||||
stack_max = 1,
|
||||
groups = {oddly_breakable_by_hand=3},
|
||||
|
||||
on_punch = function(pos, node, puncher, pointed_thing)
|
||||
|
||||
local name = puncher:get_player_name();if name == nil then return end
|
||||
local privs = minetest.get_player_privs(name);
|
||||
if not privs.ban then return end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local infotext = meta:get_string("infotext");
|
||||
if infotext=="RUN" then infotext ="STOP" else infotext="RUN" end
|
||||
meta:set_string("infotext", infotext)
|
||||
init_game(pos)
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
-- minetest.register_craft({
|
||||
-- output = "games:life",
|
||||
-- recipe = {
|
||||
-- {"default:stone","","default:stone"},
|
||||
-- {"","default:stone",""},
|
||||
-- {"default:stone","","default:stone"},
|
||||
-- }
|
||||
-- })
|
189
mods/games/maze.lua
Normal file
189
mods/games/maze.lua
Normal file
@ -0,0 +1,189 @@
|
||||
-- maze generation
|
||||
-- http://en.wikipedia.org/wiki/Maze_generation_algorithm#Depth-first_search, recursive backtracker
|
||||
-- representation of node coordinate (row,coloumn)=(i,j) -> (i-1)*n+j, i=1..n, j=1...m
|
||||
-- representation of walls: below node k --> k, left of node k --> k+m.n
|
||||
|
||||
-- good overview of maze generation algorithms using javascript/html5
|
||||
-- http://www.jamisbuck.org/presentations/rubyconf2011/index.html#recursive-backtracker
|
||||
|
||||
-- helper functions
|
||||
--stack in lua
|
||||
local stack={};
|
||||
function stack.push(s,e) s[#s+1]=e end
|
||||
function stack.pop(s) local r = s[#s];s[#s]=nil;return r end
|
||||
--function table2string(s) local r = ""; for i,v in pairs(s) do r = r.. " ["..i.."]=".. v ; end return r end
|
||||
|
||||
function maze_deep_first_search(m,n,start,seed) -- returns a table of strings representing line renders
|
||||
|
||||
local steps,maxsteps; steps= 0; maxsteps = 999999;
|
||||
local maze = {}
|
||||
maze.m = m; maze.n = n;
|
||||
maze.unvisited = {};maze.stack = {}; maze.walls = {};
|
||||
maze.free = maze.m*maze.n;
|
||||
local i,j,k
|
||||
local nb,wall -- unvisited neighbbors, walls
|
||||
|
||||
--init structures
|
||||
for i=1,maze.m do
|
||||
for j =1,maze.n do
|
||||
k=(i-1)*maze.n+j;maze.unvisited[k]=true -- initially all cells unvisited
|
||||
maze.walls[k]=true;maze.walls[k+maze.n*maze.m]=true; -- walls are there
|
||||
end
|
||||
end
|
||||
|
||||
math.randomseed(seed)
|
||||
maze.current = start
|
||||
maze.unvisited [ maze.current ] = false;
|
||||
maze.free = maze.free-1; maze.stack[1+#maze.stack] = maze.current
|
||||
|
||||
while maze.free>0 and steps<maxsteps do -- main loop
|
||||
steps=steps+1
|
||||
-- check current node neighbors
|
||||
k=maze.current
|
||||
j = k % maze.n;i=math.ceil(k/maze.n); -- get coords back from index
|
||||
if j==0 then j = maze.n end
|
||||
--print("coords current node "..k .. " = " .. i .. " " ..j)
|
||||
|
||||
nb={};wall={}-- check unvisited neighbors & wall removals
|
||||
|
||||
if i>1 then -- down
|
||||
k=(i-2)*maze.n+j; if maze.unvisited[k] then wall[#wall+1]=k+maze.n;nb[#nb+1]=k end
|
||||
end
|
||||
if i<maze.m then -- up
|
||||
k=(i)*maze.n+j; if maze.unvisited[k] then wall[#wall+1]=k;nb[#nb+1]=k end
|
||||
end
|
||||
if j<maze.n then --right
|
||||
k=(i-1)*maze.n+j+1; if maze.unvisited[k] then wall[#wall+1]=k+maze.n*maze.m; nb[#nb+1]=k end
|
||||
end
|
||||
if j>1 then --left
|
||||
k=(i-1)*maze.n+j-1; if maze.unvisited[k] then wall[#wall+1]=k+1+maze.n*maze.m;nb[#nb+1]=k end
|
||||
end
|
||||
|
||||
--print(" unvisited neighbors " .. table2string(nb))
|
||||
if (#nb)>0 then -- if unvisited neighbors, choose random one as next current node
|
||||
stack.push(maze.stack,maze.current) -- remember previous current node
|
||||
k=math.random(#nb); -- pick random unvisited neighbor
|
||||
maze.walls[wall[k]]=false; -- remove wall
|
||||
--print(" removed wall ".. wall[k])
|
||||
k=nb[k];
|
||||
maze.current = k; -- new current cell
|
||||
maze.unvisited[k]=false; maze.free = maze.free-1 -- one less unvisited
|
||||
--print("new explore " .. k);
|
||||
|
||||
elseif (#maze.stack)~=0 then -- no unvisited neighbors, backtrack using stack
|
||||
|
||||
maze.current = stack.pop(maze.stack)
|
||||
--print("backtrack to "..maze.current)
|
||||
|
||||
else -- even stack is empty, just pick random unvisited cell
|
||||
k = math.random(maze.free); j=1;
|
||||
for i =1,maze.m*maze.n do
|
||||
if maze.unvisited[i] then
|
||||
if j==k then k=i; break end -- pick node
|
||||
j=j+1
|
||||
end
|
||||
end
|
||||
--print(" stack empty, random pick " ..k)
|
||||
maze.current=k;maze.unvisited[k]=false; maze.free = maze.free -1;
|
||||
end
|
||||
end -- of do
|
||||
|
||||
-- render maze with chars, row by row
|
||||
maze.ret = {};
|
||||
local hor;local vert;
|
||||
local wall = "1"
|
||||
|
||||
for i=1,maze.m do
|
||||
hor="";vert="";
|
||||
k= (i-1)*maze.n;
|
||||
-- horizontal
|
||||
for j = 1, maze.n do
|
||||
k=k+1;
|
||||
-- if maze.walls[k+maze.n*maze.m] then vert=vert.."X." else vert=vert.. "0." end
|
||||
-- if maze.walls[k] then hor=hor.."XX" else hor=hor.."X0" end
|
||||
if maze.walls[k+maze.n*maze.m] then vert=vert..wall.."0" else vert=vert.. "00" end
|
||||
if maze.walls[k] then hor=hor..wall..wall else hor=hor..wall.."0" end
|
||||
end
|
||||
maze.ret[1+#maze.ret]=hor..wall;maze.ret[1+#maze.ret]=vert..wall;
|
||||
end
|
||||
maze.ret[1+#maze.ret] = string.rep(wall,2*maze.n+1)
|
||||
return maze.ret
|
||||
end
|
||||
|
||||
-- RUN PROGRAM
|
||||
local maze=maze_deep_first_search(10,30,1,2015)
|
||||
--for _,v in pairs(maze) do print(v) end
|
||||
|
||||
|
||||
|
||||
core.register_privilege("maze", "Can create mazes")
|
||||
minetest.register_chatcommand("maze", {
|
||||
description = "/maze (optional m,n,start,seed) generates maze at players position, directed towards positive x,z axix",
|
||||
privs = {maze = true},
|
||||
func = function(name, param)
|
||||
local m,n,start, seed
|
||||
if param == "" then m=10;n=10;start=1;seed=1 else
|
||||
local words = {}; local word
|
||||
for word in param:gmatch("%w+") do words[1+#words]= word end
|
||||
if words[1]~=nil then m = tonumber(words[1]) else m = 10 end
|
||||
if words[2]~=nil then n = tonumber(words[2]) else n = 10 end
|
||||
if words[3]~=nil then start = tonumber(words[3]) else start = 1 end
|
||||
if words[4]~=nil then seed = tonumber(words[4]) else seed = 1 end
|
||||
end
|
||||
if m*n>1000000 then minetest.chat_send_player(name, "limit maze size to 1000000 cells") return end
|
||||
local player = minetest.env:get_player_by_name(name); if player==nil then return end
|
||||
local pos = player:getpos();local p
|
||||
local maze=maze_deep_first_search(m,n,start,seed) -- m,n,start,seed
|
||||
local i,j,k;local p = {x=pos.x,y=pos.y,z=pos.z};
|
||||
for i,v in pairs(maze) do
|
||||
p.x = pos.x+i
|
||||
for k = 1,string.len(v) do
|
||||
p.z=pos.z+k
|
||||
if string.sub(v,k,k)=="1" then
|
||||
minetest.set_node(p,{name="games:stone_maze"})
|
||||
else minetest.set_node(p,{name="air"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("games:glass_maze", {
|
||||
description = "maze_glass",
|
||||
drawtype = "glasslike_framed_optional",
|
||||
tiles = {"maze_glass.png"},
|
||||
inventory_image = minetest.inventorycube("maze_glass.png"),
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
groups = {immortal = 1,disable_jump=1},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("games:stone_maze", {
|
||||
description = "maze_wall",
|
||||
tiles = {"default_brick.png"},
|
||||
is_ground_content = true,
|
||||
groups = {immortal = 1,disable_jump=1},
|
||||
legacy_mineral = true,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
|
||||
local name = player:get_player_name(); if name == nil then return end
|
||||
if minetest.is_protected(pos, name) then
|
||||
return
|
||||
end
|
||||
local player_inv = player:get_inventory()
|
||||
if player_inv:room_for_item("main", {"games:stone_maze"}) then
|
||||
player_inv:add_item("main", "games:stone_maze")
|
||||
minetest.remove_node(pos) -- remove bones
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
})
|
||||
|
||||
|
181
mods/games/sokoban.lua
Normal file
181
mods/games/sokoban.lua
Normal file
@ -0,0 +1,181 @@
|
||||
-- SOKOBAN GAME
|
||||
-- basic board game mechanics ( checkers )
|
||||
-- by rnd
|
||||
|
||||
|
||||
local sokoban = {};
|
||||
sokoban.push_time = 0
|
||||
sokoban.blocks = 0;sokoban.level = 0; sokoban.moves=0;
|
||||
sokoban.load=0;sokoban.playername =""; sokoban.pos = {};
|
||||
local SOKOBAN_WALL = "games:stone_maze"
|
||||
local SOKOBAN_FLOOR = "default:stone"
|
||||
local SOKOBAN_GOAL = "default:tree"
|
||||
|
||||
|
||||
minetest.register_node("games:crate", { -- block that player pushes around, basically main sokoban routine
|
||||
description = "sokoban crate",
|
||||
tiles = {"crate.png"},
|
||||
paramtype = "light",
|
||||
light_source = 10,
|
||||
is_ground_content = false,
|
||||
groups = {immortal = 1},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_punch = function(pos, node, player)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
if sokoban.playername~=name then
|
||||
if sokoban.playername == "" then
|
||||
minetest.chat_send_player(name,"Please right click level loader block to load and play Sokoban")
|
||||
return
|
||||
end
|
||||
minetest.chat_send_player(name,"Only ".. sokoban.playername .. " can play. To play new level please right click loader block and select level.")
|
||||
return
|
||||
end
|
||||
local time = sokoban.push_time; local t = minetest.get_gametime();
|
||||
if t-time<1 then return end;sokoban.push_time = t
|
||||
local p=player:getpos();local q={x=pos.x,y=pos.y,z=pos.z}
|
||||
p.x=p.x-q.x;p.y=p.y-q.y;p.z=p.z-q.z
|
||||
if math.abs(p.y+0.5)>0 then return end
|
||||
if math.abs(p.x)>math.abs(p.z) then
|
||||
if p.z<-0.5 or p.z>0.5 or math.abs(p.x)>1.5 then return end
|
||||
if p.x+q.x>q.x then q.x= q.x-1
|
||||
else q.x = q.x+1
|
||||
end
|
||||
else
|
||||
if p.x<-0.5 or p.x>0.5 or math.abs(p.z)>1.5 then return end
|
||||
if p.z+q.z>q.z then q.z= q.z-1
|
||||
else q.z = q.z+1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if minetest.get_node(q).name=="air" then -- push crate
|
||||
sokoban.moves = sokoban.moves+1
|
||||
local old_infotext = minetest.get_meta(pos):get_string("infotext");
|
||||
minetest.set_node(pos,{name="air"})
|
||||
minetest.set_node(q,{name="games:crate"})
|
||||
minetest.sound_play("default_dig_dig_immediate", {pos=q,gain=1.0,max_hear_distance = 24,})
|
||||
local meta = minetest.get_meta(q);
|
||||
q.y=q.y-1;
|
||||
if minetest.get_node(q).name==SOKOBAN_GOAL then
|
||||
if old_infotext~="GOAL REACHED" then
|
||||
sokoban.blocks = sokoban.blocks -1;
|
||||
end
|
||||
meta:set_string("infotext", "GOAL REACHED")
|
||||
else
|
||||
if old_infotext=="GOAL REACHED" then
|
||||
sokoban.blocks = sokoban.blocks +1
|
||||
end
|
||||
meta:set_string("infotext", "push crate on top of goal block")
|
||||
end
|
||||
end
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
if sokoban.blocks~=0 then
|
||||
minetest.chat_send_player(name,"move " .. sokoban.moves .. " : " ..sokoban.blocks .. " crates left ");
|
||||
else
|
||||
minetest.chat_send_all("#SOKOBAN : ".. name .. " just solved sokoban level ".. sokoban.level .. " in " .. sokoban.moves .. " moves.");
|
||||
local meta = minetest.get_meta(sokoban.pos);
|
||||
meta:set_string("infotext", name .. " just solved sokoban level ".. sokoban.level .. " in " .. sokoban.moves .. " moves.");
|
||||
|
||||
-- if playerdata~=nil then -- award xp if playerdata exist
|
||||
-- playerdata[name].xp = playerdata[name].xp + (sokoban.level-0.5)*100
|
||||
-- end
|
||||
sokoban.playername = ""; sokoban.level = 1
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
minetest.register_node("games:sokoban", { -- level loader block
|
||||
description = "sokoban crate",
|
||||
tiles = {"default_brick.png","crate.png","crate.png","crate.png","crate.png","crate.png"},
|
||||
groups = {oddly_breakable_by_hand=1},
|
||||
is_ground_content = false,
|
||||
paramtype = "light",
|
||||
light_source = 14,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
local form =
|
||||
"size[3,1]" .. -- width, height
|
||||
"field[0,0.5;3,1;level;enter level 1 to 90;1]"..
|
||||
"button[2.5,0.25;1,1;OK;OK]"
|
||||
meta:set_string("formspec", form)
|
||||
meta:set_string("infotext","sokoban level loader, right click to select level")
|
||||
meta:set_int("time", minetest.get_gametime()-300);
|
||||
end,
|
||||
on_punch = function(pos, node, player) -- make timer ready to enter
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
local privs = minetest.get_player_privs(name);
|
||||
if not privs.ban then return end
|
||||
local meta = minetest.get_meta(pos)
|
||||
minetest.chat_send_player(name,"Sokoban loader reset. Load level now.")
|
||||
end,
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
local name = sender:get_player_name(); if name==nil then return end
|
||||
local privs = minetest.get_player_privs(name);
|
||||
|
||||
if fields.OK ~= "OK" then return end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
if not privs.kick and sokoban.playername~="" then
|
||||
local player = minetest.get_player_by_name(sokoban.playername)
|
||||
if player and name~= sokoban.playername then
|
||||
local ppos = player:getpos();
|
||||
local dist = math.max(math.abs(pos.x-ppos.x),math.abs(pos.y-ppos.y),math.abs(pos.z-ppos.z));
|
||||
if dist<32 then
|
||||
minetest.chat_send_player(name,sokoban.playername .. " is still playing. Wait until he is finished and then try again");
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sokoban.pos = pos;
|
||||
sokoban.playername = name
|
||||
local lvl;
|
||||
if tonumber(fields.level) ~=nil then
|
||||
lvl = tonumber(fields.level)-1
|
||||
end
|
||||
if lvl == nil then return end
|
||||
if lvl <0 or lvl >89 then return end
|
||||
|
||||
local file = io.open(minetest.get_modpath("games").."/sokoban.txt","r")
|
||||
if not file then minetest.chat_send_player(name,"failed to open sokoban.txt") return end
|
||||
local str = ""; local s; local p = {x=pos.x,y=pos.y,z=pos.z}; local i,j;i=0;
|
||||
local lvl_found = false
|
||||
while str~= nil do
|
||||
str = file:read("*line");
|
||||
if str~=nil and str =="; "..lvl then lvl_found=true break end
|
||||
end
|
||||
if not lvl_found then file:close();return end
|
||||
|
||||
sokoban.blocks = 0;sokoban.level = lvl+1; sokoban.moves=0;
|
||||
while str~= nil do
|
||||
str = file:read("*line");
|
||||
if str~=nil then
|
||||
if string.sub(str,1,1)==";" then
|
||||
file:close(); minetest.chat_send_all("Sokoban level "..sokoban.level .." loaded by ".. name .. ". It has " .. sokoban.blocks .. " boxes to push. "); return
|
||||
end
|
||||
i=i+1;
|
||||
for j = 1,string.len(str) do
|
||||
p.x=pos.x+i;p.y=pos.y; p.z=pos.z+j; s=string.sub(str,j,j);
|
||||
p.y=p.y-1;
|
||||
if minetest.get_node(p).name~=SOKOBAN_FLOOR then minetest.set_node(p,{name=SOKOBAN_FLOOR}); end -- clear floor
|
||||
p.y=p.y+1;
|
||||
if s==" " and minetest.get_node(p).name~="air" then minetest.set_node(p,{name="air"}) end
|
||||
if s=="#" and minetest.get_node(p).name~=SOKOBAN_WALL then minetest.set_node(p,{name=SOKOBAN_WALL}) end
|
||||
if s=="$" then minetest.set_node(p,{name="games:crate"});sokoban.blocks=sokoban.blocks+1 end
|
||||
if s=="." then p.y=p.y-1;minetest.set_node(p,{name=SOKOBAN_GOAL}); p.y=p.y+1;minetest.set_node(p,{name="air"}) end
|
||||
--starting position
|
||||
if s=="@" then p.y=p.y-1;minetest.set_node(p,{name="default:glass"}); p.y=p.y+1;minetest.set_node(p,{name="air"}) end
|
||||
if s~="@" then p.y = pos.y+2;minetest.set_node(p,{name="games:glass_maze"});
|
||||
else p.y=pos.y+2;minetest.set_node(p,{name="default:ladder"})
|
||||
end -- roof above to block jumps
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
file:close();
|
||||
end,
|
||||
})
|
1398
mods/games/sokoban.txt
Normal file
1398
mods/games/sokoban.txt
Normal file
File diff suppressed because it is too large
Load Diff
38
mods/games/spleef.lua
Normal file
38
mods/games/spleef.lua
Normal file
@ -0,0 +1,38 @@
|
||||
-- SPLEEF GAME
|
||||
|
||||
local spleef_size = 15;
|
||||
minetest.register_node("games:spleef", {
|
||||
description = "spleef game",
|
||||
tiles = {"default_copper_block.png"},
|
||||
groups = {oddly_breakable_by_hand=1},
|
||||
is_ground_content = false,
|
||||
paramtype = "light",
|
||||
light_source = 10,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_punch = function(pos, node, player)
|
||||
local name = player:get_player_name(); if name==nil then return end
|
||||
for i = 1, spleef_size do -- init game area
|
||||
for j = 1, spleef_size do
|
||||
minetest.set_node({x=pos.x+i+1,y=pos.y,z=pos.z+j+1},{name = "games:spleefblock"})
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
minetest.register_node("games:spleefblock", {
|
||||
description = "spleef game block",
|
||||
tiles = {"default_copper_block.png"},
|
||||
groups = {dig_immediate=3},
|
||||
is_ground_content = false,
|
||||
paramtype = "light",
|
||||
light_source = 10,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
local inv = placer:get_inventory();
|
||||
inv:remove_item("main", ItemStack("games:spleefblock 90"))
|
||||
minetest.set_node(pos,{name = "air"})
|
||||
itemstack:clear();
|
||||
end
|
||||
}
|
||||
)
|
BIN
mods/games/textures/crate.png
Normal file
BIN
mods/games/textures/crate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
mods/games/textures/maze_glass.png
Normal file
BIN
mods/games/textures/maze_glass.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 169 B |
BIN
mods/games/textures/moreblocks_iron_checker.png
Normal file
BIN
mods/games/textures/moreblocks_iron_checker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 850 B |
BIN
mods/games/textures/queen_blue.png
Normal file
BIN
mods/games/textures/queen_blue.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 473 B |
BIN
mods/games/textures/queen_red.png
Normal file
BIN
mods/games/textures/queen_red.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 480 B |
Loading…
x
Reference in New Issue
Block a user