diff --git a/commands.lua b/commands.lua index 36c777a..be43b0d 100644 --- a/commands.lua +++ b/commands.lua @@ -457,10 +457,11 @@ basic_robot.commands.write_book = function(name,title,text) -- returns itemstack local data = {} if title == "" or not title then title = "program book "..minetest.get_gametime() end - data.title = title + data.title = title or "" data.text = text or "" data.text_len = #data.text data.page = 1 + data.description = title or "" data.page_max = math.ceil((#data.text:gsub("[^\n]", "") + 1) / lpp) data.owner = name --local data_str = minetest.serialize(data) -- pre 0.4.16 @@ -484,15 +485,16 @@ basic_robot.give_drops = function(nodename, inv) -- gives apropriate drops when if max_items==0 then -- just drop all the items (taking the rarity into consideration) max_items = #table.drop.items or 0; end + max_items = math.random(max_items) -- return random number of items local drop = table.drop; local i = 0; for k,v in pairs(drop.items) do - if i > max_items then break end; i=i+1; + if i > max_items then break end; + i=i+1; local rare = v.rarity or 1; if rare>0 and math.random(1, rare)==1 then dropname = v.items[math.random(1,#v.items)]; -- pick item randomly from list inv:add_item("main",dropname); - break end end else diff --git a/init.lua b/init.lua index f5c5e73..67ccb69 100644 --- a/init.lua +++ b/init.lua @@ -209,7 +209,7 @@ function getSandboxEnv (name) label = function(text) local obj = basic_robot.data[name].obj; - obj:set_properties({nametag = text}); -- "[" .. name .. "] " .. + obj:set_properties({nametag = text or ""}); -- "[" .. name .. "] " .. end, display_text = function(text,linesize,size) @@ -1578,6 +1578,7 @@ minetest.register_on_player_receive_fields( if not data then data = {} end local text = fields.book or ""; if string.len(text) > 64000 then + local sender = player:get_player_name(); minetest.chat_send_all("#ROBOT: " .. sender .. " is spamming with long text.") return end data.text = text or "" diff --git a/scripts/copy_paste.lua b/scripts/copy_paste.lua index 9dae0a6..471a509 100644 --- a/scripts/copy_paste.lua +++ b/scripts/copy_paste.lua @@ -11,6 +11,22 @@ if not paste then end end data = {}; + + display_marker = function(pos,label) + minetest.add_particle( + { + pos = pos, + expirationtime = 10, + velocity = {x=0, y=0,z=0}, + size = 18, + texture = label..".png", + acceleration = {x=0,y=0,z=0}, + collisiondetection = true, + collision_removal = true, + }) + + end + self.listen(1) self.label("COPY-PASTE MASTER v1.2 gold edition. commands: c1 c2 r c p") end @@ -21,12 +37,16 @@ speaker, msg = self.listen_msg() if speaker == "rnd" then local player = _G.minetest.get_player_by_name(speaker); local p = player:getpos(); p.x = round(p.x); p.y=round(p.y); p.z = round(p.z); + if p.y<0 then p.y = p.y +1 end -- needed cause of minetest bug if msg == "c1" then paste.src1 = {x=p.x,y=p.y,z=p.z};say("marker 1 set at " .. p.x .. " " .. p.y .. " " .. p.z) + display_marker(p,"099") -- c elseif msg == "c2" then paste.src2 = {x=p.x,y=p.y,z=p.z};say("marker 2 set at " .. p.x .. " " .. p.y .. " " .. p.z) + display_marker(p,"099") -- c elseif msg == "r" then paste.ref = {x=p.x,y=p.y,z=p.z};say("reference set at " .. p.x .. " " .. p.y .. " " .. p.z) + display_marker(p,"114") -- r elseif msg == "c" then -- copy local x1 = math.min(paste.src1.x,paste.src2.x);local y1 = math.min(paste.src1.y,paste.src2.y);local z1 = math.min(paste.src1.z,paste.src2.z); local x2 = math.max(paste.src1.x,paste.src2.x);local y2 = math.max(paste.src1.y,paste.src2.y);local z2 = math.max(paste.src1.z,paste.src2.z); diff --git a/scripts/games/CTF_bot.lua b/scripts/games/CTF_bot.lua index 5cff02d..742b1d5 100644 --- a/scripts/games/CTF_bot.lua +++ b/scripts/games/CTF_bot.lua @@ -1,137 +1,146 @@ --- simple ctf robot, rnd ---instructions: build game arena and place blue/red buttons as flags. edit flag positions below ---you must register 'keyboard' events by placing robot with same 'id' as robot running this code at 'event register' positions - default (32*i,64*j+1, 32*k) + -- simple ctf robot, rnd + --instructions: build game arena and place blue/red buttons as flags. edit flag positions below + --you must register 'keyboard' events by placing robot with same 'id' as robot running this code at 'event register' positions - default (32*i,64*j+1, 32*k) -if not ctf then - _G.minetest.forceload_block(self.pos(),true) - ctf = { - [1] = {state = 1, flagnode = "basic_robot:button8080FF", pos = {x=-18,y=501,z=17}, name = "blue", owner = "", score = 0}, -- team[1] - [2] = {state = 1, flagnode = "basic_robot:buttonFF8080", pos = {x=-79,y=501,z=46}, name = "red", owner = "", score = 0}, -- team[2] - } - - teams = {} -- example : {["rnd"] = {1,0, player, health points at start}}; -- team, ownership of flag - maxscore = 3; - t = 0 - teamid = 1; -- team selector when joining - - gamestate = 0; - self.listen(1) - self.spam(1) - - get_id = function(pos) - local range = 1000; - return pos.x + range*pos.y+range^2*pos.z - end - - flag_id = {}; for i = 1,#ctf do flag_id[get_id(ctf[i].pos)] = i end - - render_flags = function() - for i = 1,#ctf do minetest.set_node(ctf[i].pos, {name = ctf[i].flagnode}) end - end - -end - -if gamestate == 0 then -- welcome - say(colorize("red","#CAPTURE THE FLAG GAME. say '\\join' to join game. to start game one of joined players says '\\start'")) - gamestate = 1 -elseif gamestate == 1 then - speaker,msg = self.listen_msg() - if msg == "join" then - local pl = minetest.get_player_by_name(speaker); - teams[speaker] = {teamid, 0, pl,20};pl:set_hp(20) - local msg1 = ""; local msg2 = "" - for k,v in pairs(teams) do - if v[1] == 1 then msg1 = msg1 .. k .. " " elseif v[1] == 2 then msg2 = msg2 .. k .. " " end + if not ctf then + _G.minetest.forceload_block(self.pos(),true) + ctf = { + [1] = {state = 1, flagnode = "basic_robot:button8080FF", pos = {x=-18,y=502,z=110}, name = "blue", owner = "", score = 0}, -- team[1] + [2] = {state = 1, flagnode = "basic_robot:buttonFF8080", pos = {x=-18,y=502,z=80}, name = "red", owner = "", score = 0}, -- team[2] + } + + teams = {} -- example : {["rnd"] = {1,0, player, health points at start}}; -- team, ownership of flag + maxscore = 3; + t = 0 + teamid = 1; -- team selector when joining + + gamestate = 0; + self.listen(1) + self.spam(1) + + get_id = function(pos) + local range = 1000; + return pos.x + range*pos.y+range^2*pos.z end - say(colorize("yellow","#CTF : " .. speaker .. " joined team " .. ctf[teamid].name .. ". TEAM " .. ctf[1].name .. ": " .. msg1 .. ", TEAM " .. ctf[2].name .. ": " .. msg2)) - teamid = 3-teamid; -- 1,2 - elseif msg == "start" then -- game start - if teams[speaker] then - gamestate = 2 - keyboard.get() -- clear keyboard buffer - say(colorize("red","#CTF GAME STARTED. GET ENEMY FLAG AND BRING IT BACK TO YOUR FLAG. DONT LET YOUR HEALTH GO BELOW 5 HEARTS OR YOU ARE OUT.")) - for k,_ in pairs(teams) do -- teleport players - local data = teams[k];data[3]:setpos( ctf[data[1]].pos ) - end - render_flags() + flag_id = {}; for i = 1,#ctf do flag_id[get_id(ctf[i].pos)] = i end + + render_flags = function() + for i = 1,#ctf do minetest.set_node(ctf[i].pos, {name = ctf[i].flagnode}) end end + end -elseif gamestate == 2 then - -- check player health - for k,v in pairs(teams) do - local hp = teams[k][3]:get_hp(); - if not hp or hp<10 then -- teams[k][4] - - local cflag = teams[k][2]; - if cflag>0 then -- drop flag - ctf[cflag].state = 1 - ctf[cflag].owner = "" - minetest.set_node(ctf[cflag].pos, {name = ctf[cflag].flagnode}) - say(colorize("red", "#CTF " .. k .. " dropped " .. ctf[cflag].name .. " flag!")) + if gamestate == 0 then -- welcome + say(colorize("red","#CAPTURE THE FLAG GAME. say '\\join' to join game. to start game one of joined players says '\\start'")) + gamestate = 1 + elseif gamestate == 1 then + speaker,msg = self.listen_msg() + if msg == "join" then + local pl = minetest.get_player_by_name(speaker); + teams[speaker] = {teamid, 0, pl,20};pl:set_hp(20) + local msg1 = ""; local msg2 = "" + for k,v in pairs(teams) do + if v[1] == 1 then msg1 = msg1 .. k .. " " elseif v[1] == 2 then msg2 = msg2 .. k .. " " end end - if not hp then -- player left - say(colorize("yellow", "#CTF " .. k .. " left the game!")) - teams[k] = nil - else -- reset player - say(colorize("yellow", "#CTF " .. k .. " resetted!")) - v[2] = 0 -- player has no flag - v[3]:set_hp(20) - v[3]:setpos( ctf[v[1]].pos ) - end - - + say(colorize("yellow","#CTF : " .. speaker .. " joined team " .. ctf[teamid].name .. ". TEAM " .. ctf[1].name .. ": " .. msg1 .. ", TEAM " .. ctf[2].name .. ": " .. msg2)) + teamid = 3-teamid; -- 1,2 + elseif msg == "start" then -- game start + if teams[speaker] then + gamestate = 2 + keyboard.get() -- clear keyboard buffer + say(colorize("red","#CTF GAME STARTED. GET ENEMY FLAG AND BRING IT BACK TO YOUR FLAG. DONT LET YOUR HEALTH GO BELOW 3 HEARTS OR YOU ARE OUT.")) + for k,_ in pairs(teams) do -- teleport players + local data = teams[k];data[3]:setpos( ctf[data[1]].pos ) + end + render_flags() + end end - end - - - event = keyboard.get() - if event and teams[event.puncher] then - --say(serialize(event)) - local punch_id = get_id({x=event.x,y=event.y,z=event.z}); - local flag = flag_id[punch_id]; - if flag then - local state = ctf[flag].state - local puncher = event.puncher; - if state == 1 then -- flag is here, ready to be taken or capture of enemy flag - if teams[puncher][1] ~= flag then -- take - say(colorize("red","#CTF " .. puncher .. " has taken " .. ctf[flag].name .. " flag !")) - ctf[flag].state = 2; - ctf[flag].owner = puncher; - teams[puncher][2] = flag; - minetest.set_node(ctf[flag].pos, {name = "basic_robot:buttonFFFF80"}) - else -- capture? - if teams[puncher][2] > 0 then - local cflag = teams[puncher][2] -- puncher has this flag - local data = ctf[cflag]; - - local team = teams[puncher][1]; - ctf[team].score = ctf[team].score + 1 - ctf[team].owner = "" - ctf[cflag].state = 1; -- reset captured flag state - minetest.set_node(ctf[cflag].pos, {name = ctf[cflag].flagnode}) - teams[puncher][2] = 0 - say(colorize("orange","#CTF " .. puncher .. " has captured " .. data.name .. " flag! Team " .. ctf[team].name .. " has score " .. ctf[team].score )) - if ctf[team].score == maxscore then - say(colorize("yellow","#CTF: TEAM " .. ctf[team].name .. " WINS! ")) - gamestate = 3;t=5; -- intermission, duration 5 - - --reset - teams = {} - for i=1,#ctf do ctf[i].state = 1 ctf[i].score = 0 ctf[i].owner = "" end - end - - end - + + elseif gamestate == 2 then + speaker,msg = self.listen_msg() + if msg == "score" then + local msg1 = ""; local msg2 = "" + for k,v in pairs(teams) do + if v[1] == 1 then msg1 = msg1 .. k .. " " elseif v[1] == 2 then msg2 = msg2 .. k .. " " end + end + say(colorize("yellow","SCORE " .. ctf[1].score .. "/" .. ctf[2].score) .."\n" .. colorize("yellow","TEAM " .. ctf[1].name .. ": " .. msg1 .. ", TEAM " .. ctf[2].name .. ": " .. msg2)) + end + + -- check player health + for k,v in pairs(teams) do + local hp = teams[k][3]:get_hp(); + if not hp or hp<6 then -- teams[k][4] + + local cflag = teams[k][2]; + if cflag>0 then -- drop flag + ctf[cflag].state = 1 + ctf[cflag].owner = "" + minetest.set_node(ctf[cflag].pos, {name = ctf[cflag].flagnode}) + say(colorize("red", "#CTF " .. k .. " dropped " .. ctf[cflag].name .. " flag!")) + end + if not hp then -- player left + say(colorize("yellow", "#CTF " .. k .. " left the game!")) + teams[k] = nil + else -- reset player + say(colorize("yellow", "#CTF " .. k .. " resetted!")) + v[2] = 0 -- player has no flag + v[3]:set_hp(20) + v[3]:setpos( ctf[v[1]].pos ) end - + + end end - --say(serialize(event)) - end -elseif gamestate == 3 then -- intermission - if t>0 then t=t-1 else gamestate = 0 end -end \ No newline at end of file + + + event = keyboard.get() + if event and teams[event.puncher] then + --say(serialize(event)) + local punch_id = get_id({x=event.x,y=event.y,z=event.z}); + local flag = flag_id[punch_id]; + if flag then + local state = ctf[flag].state + local puncher = event.puncher; + if state == 1 then -- flag is here, ready to be taken or capture of enemy flag + if teams[puncher][1] ~= flag then -- take + say(colorize("red","#CTF " .. puncher .. " has taken " .. ctf[flag].name .. " flag !")) + ctf[flag].state = 2; + ctf[flag].owner = puncher; + teams[puncher][2] = flag; + minetest.set_node(ctf[flag].pos, {name = "basic_robot:buttonFFFF80"}) + else -- capture? + if teams[puncher][2] > 0 then + local cflag = teams[puncher][2] -- puncher has this flag + local data = ctf[cflag]; + + local team = teams[puncher][1]; + ctf[team].score = ctf[team].score + 1 + ctf[team].owner = "" + ctf[cflag].state = 1; -- reset captured flag state + minetest.set_node(ctf[cflag].pos, {name = ctf[cflag].flagnode}) + teams[puncher][2] = 0 + say(colorize("orange","#CTF " .. puncher .. " has captured " .. data.name .. " flag! Team " .. ctf[team].name .. " has score " .. ctf[team].score )) + if ctf[team].score == maxscore then + say(colorize("yellow","#CTF: TEAM " .. ctf[team].name .. " WINS! ")) + gamestate = 3;t=5; -- intermission, duration 5 + + --reset + teams = {} + for i=1,#ctf do ctf[i].state = 1 ctf[i].score = 0 ctf[i].owner = "" end + end + + end + + end + + + end + end + --say(serialize(event)) + end + elseif gamestate == 3 then -- intermission + if t>0 then t=t-1 else gamestate = 0 end + end \ No newline at end of file diff --git a/scripts/games/battle_minesweeper_game.lua b/scripts/games/battle_minesweeper_game.lua index b1ebc06..5eae232 100644 --- a/scripts/games/battle_minesweeper_game.lua +++ b/scripts/games/battle_minesweeper_game.lua @@ -4,6 +4,10 @@ if not data then paused = true turn = 2; + turntimeout = 5 + shorttimeout = 1 + shortround = false + turnmessage = "" t = 0; SIGNUP = 0; GAME = 1; INTERMISSION = 2 state = SIGNUP @@ -12,6 +16,8 @@ if not data then data = {}; init_game = function() + abilitypoints = {0,0}; -- points to use ability, step outside ring to use them in following round + shortround = false data = {}; minescount = 32 for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area @@ -44,8 +50,17 @@ if not data then return count end + near_chat = function(msg) + + end + greeting = function() - _G.minetest.chat_send_all(colorize("red","#BATTLE MINESWEEPER : two player battle in minesweeper. say join to play.\nRules: 1. each player has 5 second turn to make a move 2. if you dont make move you lose\n3. if you make move in other player turn you lose. 4. if you hit bomb or mark bomb falsely you lose")) + _G.minetest.chat_send_all(colorize("red", + "#BATTLE MINESWEEPER : two player battle in minesweeper. say join to play.\nRules: ".. + "1. each player has 5 second turn to make a move 2. if you dont make move you lose\n".. + "3. if you make move in other player turn you lose. 4. if you hit bomb or mark bomb falsely you lose\n".. + "5. by playing fast you get ability charge. when you collect 10 you can step out of ring when your round ends and opponent will only have 2s to play his turn." + )) end player_lost = function () @@ -53,22 +68,38 @@ if not data then local player = _G.minetest.get_player_by_name(players[i]); if player then player:setpos({x=spawnpos.x,y=spawnpos.y+10,z=spawnpos.z}) end end + _G.minetest.sound_play("electric_zap",{pos=spawnpos, max_hear_distance = 100}) state = INTERMISSION; t = 0 end function change_turn() + shortround = false -- reset ability if activated if turn == 1 then _G.minetest.sound_play("default_break_glass",{pos=spawnpos, max_hear_distance = 100}) else - _G.minetest.sound_play("note_a",{pos=spawnpos, max_hear_distance = 100}) + _G.minetest.sound_play("default_cool_lava",{pos=spawnpos, max_hear_distance = 100}) end if paused == false then - say(players[turn] .. " lost : didn't make a move"); + say(players[turn] .. " lost : didn't make a move fast enough "); player_lost() else + local player = minetest.get_player_by_name(players[turn]) + local ppos = player:getpos() + local x = ppos.x - spawnpos.x;local y = ppos.y - spawnpos.y;local z = ppos.z - spawnpos.z; + local points = abilitypoints[turn] + if x<1 or x>m or z<1 or z>n then -- outside area + local points = abilitypoints[turn] + if points>=10 then -- do we have enough points? + shortround = true -- next round will be shorter, 2s + _G.minetest.sound_play("grinder",{pos=spawnpos, max_hear_distance = 100}) + abilitypoints[turn] = abilitypoints[turn]-10 + end + end + if turn == 1 then turn = 2 else turn = 1 end - self.label("turn " .. turn .. " " .. players[turn]) + turnmessage = "turn " .. turn .. " " .. players[turn] .. ",charge " .. abilitypoints[turn] .. "\n" + self.label(turnmessage) t=0 paused = false end @@ -96,6 +127,7 @@ if state == SIGNUP then if player then player:setpos({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z}) end end _G.minetest.chat_send_all(colorize("red","BATTLE MINESWEEPER " .. m .. "x" ..n .. " with " .. minescount .. " mines.\n" .. players[turn] .. " its your move!")) + init_game() end end @@ -104,17 +136,24 @@ if state == SIGNUP then elseif state == GAME then t = t + 1; - if t>5 then -- change of turn + if (t>turntimeout) or (shortround and t>shorttimeout) then -- change of turn change_turn() + else + self.label(turnmessage .. " " .. (turntimeout-t+1)) end event = keyboard.get(); if event and event.type == 2 and not paused then if event.puncher == players[turn] then local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; - if x<1 or x>m or z<1 or z>n then + local points = abilitypoints[turn] + if x<1 or x>m or z<1 or z>n then -- outside area else local ppos = player.getpos(event.puncher) + + points = points + math.max(turntimeout-t-2,0); if points>40 then points = 40 end + abilitypoints[turn] = points + if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine if data[x] and data[x][z] == 1 then if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then @@ -146,5 +185,5 @@ elseif state == GAME then end elseif state == INTERMISSION then - t=t+1; if t> 15 then state = SIGNUP;players = {}; paused = true; init_game(); greeting() end + t=t+1; if t> 15 then state = SIGNUP;players = {}; paused = true; greeting() end end \ No newline at end of file