new game: minesweeper
sokoban: player is teleported to start position when game starts, level clear addedmaster
parent
98c2697736
commit
9a0eebbf63
1
init.lua
1
init.lua
|
@ -3,5 +3,6 @@ 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").."/minesweeper.lua")
|
||||
dofile(minetest.get_modpath("games").."/life.lua")
|
||||
print("[games] loaded")
|
|
@ -0,0 +1,240 @@
|
|||
--Minesweeper
|
||||
local minesweeper = {};
|
||||
minesweeper.games = {};-- games in progress
|
||||
|
||||
minetest.register_node("games:minesweeper", {
|
||||
description = "minesweeper",
|
||||
tiles = {"default_copper_block.png"},
|
||||
groups = {oddly_breakable_by_hand=2},
|
||||
is_ground_content = false,
|
||||
paramtype = "light",
|
||||
light_source = 10,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local width = 10;meta:set_int("width",width);
|
||||
local height = 10;meta:set_int("height",height);
|
||||
local count = 20;meta:set_int("count",count);
|
||||
meta:set_string("player",""); -- whos playing
|
||||
meta:set_int("t",0); -- start of game
|
||||
|
||||
local form = "size[3,3] field[0.25,0.5;1,1;width;width ;"..width.."]"..
|
||||
"field[2.25,0.5;1,1;height;height ;"..height.."]" ..
|
||||
"field[0.25,1.5;1,1;count;count ;"..count.."]" ..
|
||||
"button_exit[0.,2.5;1,1;OK;OK]";
|
||||
meta:set_string("formspec", form);
|
||||
meta:set_string("owner", placer:get_player_name());
|
||||
meta:set_string("infotext","Minesweeper, punch or activate to start the game");
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then return end
|
||||
if fields.OK then
|
||||
local meta = minetest.get_meta(pos);
|
||||
local width = tonumber(fields.width) or 5;
|
||||
local height = tonumber(fields.height) or 5;
|
||||
local count = tonumber(fields.count) or 5;
|
||||
local form = "size[3,3] field[0.25,0.5;1,1;width;width ;"..width.."]"..
|
||||
"field[2.25,0.5;1,1;height;height ;"..height.."]" ..
|
||||
"field[0.25,1.5;1,1;count;count ;"..count.."]" ..
|
||||
"button_exit[0.,2.5;1,1;OK;OK]";
|
||||
meta:set_string("formspec", form);
|
||||
-- clear gamearea
|
||||
|
||||
local i,j;
|
||||
for i=1,width do
|
||||
for j=1,height do
|
||||
minetest.set_node({x=pos.x+i+1,y=pos.y,z=pos.z+j+1},{name = "air"});
|
||||
end
|
||||
end
|
||||
meta:set_int("mines",0);
|
||||
meta:set_int("width",width);
|
||||
meta:set_int("height",height);
|
||||
meta:set_int("count", count);
|
||||
meta:set_string("infotext", "minesweeper game set. punch block to start game.")
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = function(pos, node, puncher, pointed_thing)
|
||||
|
||||
if puncher:get_player_control().sneak then return end
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
-- can we start new game? not too soon and player not still playing
|
||||
local t0 = meta:get_int("t");
|
||||
local t1 = minetest.get_gametime();
|
||||
if t1-t0<5 then return end
|
||||
meta:set_int("t",t1);
|
||||
local pname = meta:get_string("player");
|
||||
local name = puncher:get_player_name();
|
||||
local mines = meta:get_int("mines");
|
||||
|
||||
|
||||
if pname~=name then
|
||||
local player = minetest.get_player_by_name(pname);
|
||||
if player then
|
||||
local p = player:getpos();
|
||||
local dist = math.sqrt((p.x-pos.x)^2+(p.y-pos.y)^2+(p.z-pos.z)^2);
|
||||
if dist< 30 then minetest.chat_send_player(name, "games: minesweeper game still in progress") return end
|
||||
end
|
||||
elseif minesweeper.games[name] then -- if game in progress end it
|
||||
|
||||
local finished = true;
|
||||
|
||||
-- check if mines are marked correctly!
|
||||
local width = meta:get_int("width");
|
||||
local height = meta:get_int("height");
|
||||
local count = meta:get_int("count");
|
||||
local i,j,mpos;
|
||||
for i=1,width do
|
||||
for j=1,height do
|
||||
mpos = {x=pos.x+i+1,y=pos.y,z=pos.z+j+1};
|
||||
if minetest.get_node(mpos).name ~= "games:markmine" and minetest.get_meta(mpos):get_int("mine")==1 then -- FAIL
|
||||
finished = false;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if not finished then
|
||||
|
||||
minetest.chat_send_all("games: BOOM! ".. name .. " has failed to detect all the mines! ")
|
||||
if mpos then minetest.swap_node(mpos,{name = "default:cobble"}) end
|
||||
minesweeper.games[pname]=nil; -- end game
|
||||
return;
|
||||
|
||||
else -- done
|
||||
|
||||
|
||||
-- activates block below minesweeper game block upon game completion
|
||||
local pos = {x=pos.x,y=pos.y-1,z=pos.z};
|
||||
local node = minetest.get_node(pos); if not node.name then return end -- error
|
||||
local table = minetest.registered_nodes[node.name];
|
||||
if table and table.mesecons and table.mesecons.effector then
|
||||
local effector=table.mesecons.effector;
|
||||
effector.action_on(pos,node,16)
|
||||
end;
|
||||
meta:set_string("infotext", name .. " just solved minesweeper level");
|
||||
minesweeper.games[name]=nil;
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if not minesweeper.games[name] then -- no game yet, place mines
|
||||
meta:set_string("player",name);
|
||||
minesweeper.create_game(pos);
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
minesweeper.create_game = function(pos)
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
local width = meta:get_int("width");
|
||||
local height = meta:get_int("height");
|
||||
local count = meta:get_int("count");
|
||||
local i,j;
|
||||
for i=1,width do
|
||||
for j=1,height do
|
||||
minetest.set_node({x=pos.x+i+1,y=pos.y,z=pos.z+j+1},{name = "games:dirt"}); --??
|
||||
end
|
||||
end
|
||||
|
||||
local mines = 0;
|
||||
local mtable = {};
|
||||
math.randomseed(minetest.get_gametime());
|
||||
|
||||
for i=1,count do -- place max up to count mines
|
||||
local x = math.random(width);
|
||||
local z = math.random(height);
|
||||
if not mtable[{x,z}] then
|
||||
mtable[{x,z}]=true
|
||||
local mmeta = minetest.get_meta({x=pos.x+x+1,y=pos.y,z=pos.z+z+1});
|
||||
mmeta:set_int("mine",1);
|
||||
mines=mines+1;
|
||||
end
|
||||
end
|
||||
|
||||
local pname = meta:get_string("player");
|
||||
minesweeper.games[pname] = {pos=pos}; -- position of gameblock
|
||||
meta:set_int("mines", mines); -- remaining mines
|
||||
meta:set_string("infotext", "Minesweeper game started, there are ".. mines .. " mines. Mark all mines by double punch from distance. Mark area as safe by standing over it and punching. When you are done punch gameblock.");
|
||||
minetest.chat_send_player(pname, "game: Minesweeper game started");
|
||||
|
||||
end
|
||||
|
||||
local punch_minesweep = function(pos, node, puncher, pointed_thing)
|
||||
|
||||
-- find closeby game and play
|
||||
local gpos, dist;
|
||||
for _,v in pairs(minesweeper.games) do
|
||||
dist = math.sqrt((v.pos.x-pos.x)^2+(v.pos.y-pos.y)^2+(v.pos.z-pos.z)^2);
|
||||
if dist<32 then gpos = v.pos end
|
||||
end
|
||||
|
||||
local name = puncher:get_player_name();
|
||||
if not gpos then
|
||||
minetest.chat_send_player(name,"games: punch nearby game block for minesweeper to start playing.")
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
local t0 = meta:get_int("t");
|
||||
local t1 = minetest.get_gametime();
|
||||
if t1-t0<1 then -- un/mark mine
|
||||
if node.name == "games:dirt" then
|
||||
minetest.swap_node(pos,{name = "games:markmine"})
|
||||
else
|
||||
minetest.swap_node(pos,{name = "games:dirt"})
|
||||
end
|
||||
return
|
||||
end
|
||||
meta:set_int("t",t1);
|
||||
|
||||
local ppos = puncher:getpos(); -- player position
|
||||
dist = math.sqrt((ppos.x-pos.x)^2+(ppos.y-pos.y)^2+(ppos.z-pos.z)^2);
|
||||
if dist> 1 then -- just probe, count mines
|
||||
local mines = 0;
|
||||
for i = -1,1 do
|
||||
for j = -1,1 do
|
||||
local mmeta = minetest.get_meta({x=pos.x+i,y=pos.y,z=pos.z+j});
|
||||
if mmeta:get_int("mine") == 1 then mines = mines +1 end
|
||||
end
|
||||
end
|
||||
--minetest.chat_send_player(name, "Found " .. mines .. " nearby mines. Punch 2x to mark mine")
|
||||
meta:set_string("infotext", "found ".. mines .. " nearby mines")
|
||||
else -- marking blocks as safe?
|
||||
if meta:get_int("mine")==1 then
|
||||
minetest.chat_send_all("games: BOOM! ".. name .. " has stepped on mine ")
|
||||
minetest.swap_node(pos,{name = "games:markmine"})
|
||||
local gmeta = minetest.get_meta(gpos);
|
||||
local pname = gmeta:get_string("player");
|
||||
minesweeper.games[pname]=nil; -- end game
|
||||
return
|
||||
end
|
||||
minetest.set_node(pos,{name = "default:dirt_with_grass"})
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
minetest.register_node("games:dirt", {
|
||||
description = "Dirt with mines, punch from far to check for mines, stand near and punch to clear mine",
|
||||
tiles = {"default_dirt.png"},
|
||||
groups = {immortal = 1},
|
||||
sounds = default.node_sound_dirt_defaults(),
|
||||
on_punch = punch_minesweep;
|
||||
|
||||
})
|
||||
|
||||
minetest.register_node("games:markmine", {
|
||||
description = "Dirt with mines, punch from far to check for mines, stand near and punch to clear mine",
|
||||
tiles = {"default_lava.png"},
|
||||
groups = {immortal = 1},
|
||||
sounds = default.node_sound_dirt_defaults(),
|
||||
on_punch = punch_minesweep;
|
||||
});
|
42
sokoban.lua
42
sokoban.lua
|
@ -1,5 +1,4 @@
|
|||
-- SOKOBAN GAME
|
||||
-- basic board game mechanics ( checkers )
|
||||
-- by rnd
|
||||
|
||||
|
||||
|
@ -72,14 +71,28 @@ minetest.register_node("games:crate", { -- block that player pushes around, basi
|
|||
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.");
|
||||
minetest.chat_send_all("games: ".. 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
|
||||
|
||||
local imax = meta:get_int("imax"); local jmax = meta:get_int("jmax");
|
||||
|
||||
local i,j;
|
||||
for i = 1,imax do
|
||||
for j=1,jmax do
|
||||
minetest.set_node({x= sokoban.pos.x+i,y=sokoban.pos.y,z=sokoban.pos.z+j}, {name = "air"}); -- clear level
|
||||
end
|
||||
end
|
||||
|
||||
-- activates block below sokoban game block upon game completion
|
||||
local pos = {x=sokoban.pos.x,y=sokoban.pos.y-1,z=sokoban.pos.z};
|
||||
local node = minetest.get_node(pos); if not node.name then return end -- error
|
||||
local table = minetest.registered_nodes[node.name];
|
||||
if table and table.mesecons and table.mesecons.effector then
|
||||
local effector=table.mesecons.effector;
|
||||
effector.action_on(pos,node,16)
|
||||
end;
|
||||
sokoban.playername = ""; sokoban.level = 1
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
@ -99,7 +112,7 @@ description = "sokoban crate",
|
|||
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]"
|
||||
"button_exit[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);
|
||||
|
@ -150,13 +163,17 @@ description = "sokoban crate",
|
|||
if not lvl_found then file:close();return end
|
||||
|
||||
sokoban.blocks = 0;sokoban.level = lvl+1; sokoban.moves=0;
|
||||
local imax=0; local jmax = 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
|
||||
imax=i;
|
||||
meta:set_int("imax",imax); meta:set_int("jmax", jmax); -- remember game dimensions
|
||||
file:close(); minetest.chat_send_all("games: sokoban level "..sokoban.level .." loaded by ".. name .. ". It has " .. sokoban.blocks .. " boxes to push. "); return
|
||||
end
|
||||
i=i+1;
|
||||
if string.len(str)>jmax then jmax = string.len(str) end -- determine max dimensions
|
||||
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;
|
||||
|
@ -167,7 +184,12 @@ description = "sokoban crate",
|
|||
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
|
||||
sender:setpos({x=p.x,y=p.y+3,z=p.z}); -- move player to start position
|
||||
p.y=p.y-1;minetest.set_node(p,{name="default:glass"});
|
||||
p.y=p.y+1;minetest.set_node(p,{name="air"})
|
||||
p.y=p.y+2;minetest.set_node(p,{name="default:ladder"})
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue