From b13a048cdf98273ea3519a9f4859b098f5070576 Mon Sep 17 00:00:00 2001 From: nyje Date: Thu, 18 Jul 2019 20:25:19 +0000 Subject: [PATCH] Basic functionality with punching --- register_bot.lua | 222 +++++++++++++++++++++------- register_commands.lua | 6 +- register_joinleave.lua | 5 +- sounds/error.ogg | Bin 0 -> 12065 bytes textures/vbots_turtle_left_fly.png | Bin 0 -> 1011 bytes textures/vbots_turtle_right_fly.png | Bin 0 -> 1006 bytes 6 files changed, 177 insertions(+), 56 deletions(-) create mode 100644 sounds/error.ogg create mode 100644 textures/vbots_turtle_left_fly.png create mode 100644 textures/vbots_turtle_right_fly.png diff --git a/register_bot.lua b/register_bot.lua index d96869b..c9468d5 100644 --- a/register_bot.lua +++ b/register_bot.lua @@ -34,9 +34,7 @@ local function bot_init(pos, placer) meta:set_string("owner", bot_owner) meta:set_string("infotext", bot_name .. " (" .. bot_owner .. ")") meta:set_string("name", bot_name) - meta:set_int("running",0) - meta:set_int("panel", 0) - meta:set_int("program", 0) + meta:set_int("fly", 0) local inv = meta:get_inventory() inv:set_size("p0", 56) inv:set_size("p1", 56) @@ -46,8 +44,8 @@ local function bot_init(pos, placer) inv:set_size("p5", 56) inv:set_size("p6", 56) inv:set_size("main", 32) - print(bot_owner.." places bot") - print(dump(vbots.bot_info)) + --print(bot_owner.." places bot") + --print(dump(vbots.bot_info)) end @@ -77,13 +75,12 @@ local function bot_restore(pos) if not vbots.bot_info[bot_key] then vbots.bot_info[bot_key] = { owner = bot_owner, pos = pos, name = bot_name} meta:set_string("infotext", bot_name .. " (" .. bot_owner .. ")") - meta:set_int("running",-1) - print(dump(vbots.bot_info)) + --print(dump(vbots.bot_info)) end end ------------------------------------- --- Clean up bot table and bot storage for player +-- Clean up bot table and bot storage ------------------------------------- local function clean_bot_table() for bot_key,bot_data in pairs( vbots.bot_info) do @@ -93,52 +90,177 @@ local function clean_bot_table() vbots.bot_info[bot_key] = nil end end - print("Cleaned") - print(dump(vbots.bot_info)) + --print("Cleaned") + --print(dump(vbots.bot_info)) end +------------------------------------- +-- Bot Action Handlers +------------------------------------- +local function facebot(facing,pos) + local node = minetest.get_node(pos) + minetest.swap_node(pos,{name=node.name, param2=facing}) +end +local function bot_turn_clockwise(pos) + local node = minetest.get_node(pos) + local newface = (node.param2+1)%4 + facebot(newface,pos) +end -minetest.register_node("vbots:bot", { - description = "A vbots bot node", - tiles = { - "vbots_turtle_top1.png", - "vbots_turtle_bottom.png", - "vbots_turtle_right.png", - "vbots_turtle_left.png", - "vbots_turtle_tail.png", - "vbots_turtle_face.png", - }, - stack_max = 1, - is_ground_content = false, - paramtype2 = "facedir", - legacy_facedir_simple = true, - groups = {cracky = 3, snappy = 3, crumbly = 3, oddly_breakable_by_hand = 2}, - on_blast = function() end, - after_place_node = function(pos, placer, itemstack, pointed_thing) - local facing = minetest.dir_to_facedir(placer:get_look_dir()) - print(dump(lookdir)) - minetest.set_node(pos,{name="vbots:bot", param2=(facing+2)%4}) - bot_init(pos, placer) - end, - on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) - local name = clicker:get_player_name() - if name == "" then - return 0 - end - if interact(clicker,pos) then - bot_restore(pos) - minetest.after(0, vbots.show_formspec, clicker, pos) - end - end, - can_dig = function(pos,player) - return interact(player,pos) - end, - on_destruct = function(pos) - local meta = minetest.get_meta(pos) - local bot_key = meta:get_string("key") - vbots.bot_info[bot_key] = nil - clean_bot_table() +local function bot_turn_anticlockwise(pos) + local node = minetest.get_node(pos) + local newface = (node.param2-1)%4 + facebot(newface,pos) +end + +local function bot_turn_random(pos) + if math.random(2)==1 then + bot_turn_clockwise(pos) + else + bot_turn_anticlockwise(pos) end +end + +local function move_bot(pos,direction) + local node = minetest.get_node(pos) + local dir = minetest.facedir_to_dir(node.param2) + local newpos + if direction == "u" then + newpos = {x = pos.x, y = pos.y+1, z = pos.z} + elseif direction == "d" then + newpos = {x = pos.x, y = pos.y-1, z = pos.z} + elseif direction == "f" then + newpos = {x = pos.x-dir.x, y = pos.y, z = pos.z-dir.z} + elseif direction == "b" then + newpos = {x = pos.x+dir.x, y = pos.y, z = pos.z+dir.z} + elseif direction == "l" then + dir = minetest.facedir_to_dir((node.param2+1)%4) + newpos = {x = pos.x+dir.x, y = pos.y, z = pos.z+dir.z} + elseif direction == "r" then + dir = minetest.facedir_to_dir((node.param2-1)%4) + newpos = {x = pos.x+dir.x, y = pos.y, z = pos.z+dir.z} + end + + local moveto_node = minetest.get_node(newpos) + if moveto_node.name == "air" then + local hold = minetest.get_meta(pos):to_table() + minetest.set_node(pos,{name="air"}) + minetest.set_node(newpos,{name=node.name, param2=node.param2}) + if hold then + minetest.get_meta(newpos):from_table(hold) + end + else + minetest.sound_play("error",{pos = newpos, gain = 10}) + end +end + +local function punch_bot(pos,player) + local meta = minetest.get_meta(pos) + local bot_owner = meta:get_string("owner") + if bot_owner == player:get_player_name() then + local item = player:get_wielded_item():get_name() + if item == "vbots:move_forward" then + move_bot(pos,"f") + elseif item == "vbots:move_backward" then + move_bot(pos,"b") + elseif item == "vbots:move_up" then + move_bot(pos,"u") + elseif item == "vbots:move_down" then + move_bot(pos,"d") + elseif item == "vbots:move_left" then + move_bot(pos,"l") + elseif item == "vbots:move_right" then + move_bot(pos,"r") + elseif item == "vbots:turn_clockwise" then + bot_turn_clockwise(pos) + elseif item == "vbots:turn_anticlockwise" then + bot_turn_anticlockwise(pos) + elseif item == "vbots:turn_random" then + bot_turn_random(pos) + end + end +end + +------------------------------------- +-- Bot definitions +------------------------------------- +local function register_bot(node_name,node_desc,node_tiles) + minetest.register_node(node_name, { + description = node_desc, + tiles = node_tiles, + stack_max = 1, + is_ground_content = false, + paramtype2 = "facedir", + legacy_facedir_simple = true, + groups = {cracky = 3, snappy = 3, crumbly = 3, oddly_breakable_by_hand = 2}, + on_blast = function() end, + after_place_node = function(pos, placer, itemstack, pointed_thing) + bot_init(pos, placer) + local facing = minetest.dir_to_facedir(placer:get_look_dir()) + facing = (facing+2)%4 + facebot(facing,pos) + end, + on_punch = function(pos, node, player, pointed_thing) + punch_bot(pos,player) + end, + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local name = clicker:get_player_name() + if name == "" then + return 0 + end + if interact(clicker,pos) then + bot_restore(pos) + minetest.after(0, vbots.show_formspec, clicker, pos) + end + end, + can_dig = function(pos,player) + return interact(player,pos) + end, + on_destruct = function(pos) + local meta = minetest.get_meta(pos) + local bot_key = meta:get_string("key") + vbots.bot_info[bot_key] = nil + clean_bot_table() + end + }) +end + +register_bot("vbots:off", "Inactive Vbot", { + "vbots_turtle_top.png", + "vbots_turtle_bottom.png", + "vbots_turtle_right.png", + "vbots_turtle_left.png", + "vbots_turtle_tail.png", + "vbots_turtle_face.png", +}) +register_bot("vbots:off_fly", "Inactive Flying Vbot", { + "vbots_turtle_top.png", + "vbots_turtle_bottom.png", + "vbots_turtle_right_fly.png", + "vbots_turtle_left_fly.png", + "vbots_turtle_tail.png", + "vbots_turtle_face.png", +}) +register_bot("vbots:on", "Live Vbot", { + "vbots_turtle_top4.png", + "vbots_turtle_bottom.png", + "vbots_turtle_right.png", + "vbots_turtle_left.png", + "vbots_turtle_tail.png", + "vbots_turtle_face.png", +}) +register_bot("vbots:on_fly", "Live Flying Vbot", { + "vbots_turtle_top4.png", + "vbots_turtle_bottom.png", + "vbots_turtle_right_fly.png", + "vbots_turtle_left_fly.png", + "vbots_turtle_tail.png", + "vbots_turtle_face.png", }) + +--register_bot("vbots:active", "Active vbot", "vbots_turtle_top1.png") +--register_bot("vbots:running", "Running vbot", "vbots_turtle_top4.png") + + diff --git a/register_commands.lua b/register_commands.lua index 799f6fd..d32686d 100644 --- a/register_commands.lua +++ b/register_commands.lua @@ -11,9 +11,9 @@ local register_command = function(itemname,description,image) on_drop = function(itemstack, dropper, pos) return nil end, - on_use = function(itemstack, user, pointed_thing) - return nil - end + --on_use = function(itemstack, user, pointed_thing) + -- return nil + --end }) end diff --git a/register_joinleave.lua b/register_joinleave.lua index eee5143..be98d99 100644 --- a/register_joinleave.lua +++ b/register_joinleave.lua @@ -9,15 +9,14 @@ minetest.register_on_leaveplayer(function(player) if bot_name~="" then meta:set_string("infotext", bot_name .. " (" .. bot_data.owner .. ") [Inactive]") - meta:set_int("running",-1) end vbots.bot_info[bot_key] = nil end end - print(dump(vbots.bot_info)) + --print(dump(vbots.bot_info)) end) minetest.register_on_joinplayer(function(player) - print(dump(vbots.bot_info)) + --print(dump(vbots.bot_info)) end) diff --git a/sounds/error.ogg b/sounds/error.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9a401bc7e471d763e5559413bfd5404c66a6c1c0 GIT binary patch literal 12065 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 literal 0 HcmV?d00001 diff --git a/textures/vbots_turtle_left_fly.png b/textures/vbots_turtle_left_fly.png new file mode 100644 index 0000000000000000000000000000000000000000..5d4c5e5b6f3eaa25e90cd1582911d28dd0672285 GIT binary patch literal 1011 zcmV2_F&-9}Nm16AK^_4Im5&A`=WF5(^|14kQjDC>;+l z9S|}d5;GYPG#(E%AP_YmG%X?!IwKc57#BMk7(N&iKPDAGB{(=KIyosCMIIPNCmTl` z8%G};M;{zYA16jECq^w7ODq>mE*(uICQ2sRx>J8G#XkoQ%N=; zSv6EjHXmFxPEI*HRyZMKIVNN*H(xwrT0kIfK`CxBBX&n3cSR$2N+ownCU{6Bc}668 zMym1#t^MntzqMYl*rxJaUzYp9rOshMk|n{20^Zl|7ash@90 zz)DELORJ%AtfF(QqI5{aOS7VKt)z6Vq;;;ObEK$rucmanqk6HYb-bm0sjPOVt#-Vo zezdB0s;zgos(81md9JQ_wyb%#ta!JrdAP26y03b=uzR|&e7&-KzO#M8vw*_1fWWqY zz_x+Fwt~U8f5Eqa!nc6Jw}HaAfWx?e!?=UQxPisEfyTIj#<_vVxq`&Hg2%dp%(;Tk zyoJ%dh0?u-)4hg|0_$G@000SaNLh0L01m?d01m?e$8V@)00007bV*G`2jd444QEa_} zm9a5uVJyT(i~$5f;tIR$GCMPVADzpvUMceLN4!4V%HHw#!l}~f=Lw7vmFgO63!UX@6@RC3bpLD4FGuKW1WfF4At)l0QBqtgMm2_F&-9}Nm16AK^_4Im5&A`=WF5(^|14kQjDC>;+l z9S|}d5;GYPG#(E%AP_YmG%X?!IwKc57#BMk7(N&iKPDAGB{(=KIyosCMIIPNCmTl` z8%G};M;{zYA16jECq^w7ODq>mE*(uICQ2sRx>J8G#XkoQ%N=; zSv6EjHXmFxPEI*HRyZMKIVNN*H(xwrT0kIfK`CxBBX&n3cSR$2N+ownCU{6Bc}668 zMym1#t^MntzqMYl*rxJaUzYp9rOshMk|n{20^Zl|7ash@90 zz)DELORJ%AtfF(QqI5{aOS7VKt)z6Vq;;;ObEK$rucmanqk6HYb-bm0sjPOVt#-Vo zezdB0s;zgos(81md9JQ_wyb%#ta!JrdAP26y03b=uzR|&e7&-KzO#M8vw*_1fWWqY zz_x+Fwt~U8f5Eqa!nc6Jw}HaAfWx?e!?=UQxPisEfyTIj#<_vVxq`&Hg2%dp%(;Tk zyoJ%dh0?u-)4hg|0_$G@000SaNLh0L01m?d01m?e$8V@)00007bV*G`2jd4448SasR1KhiHKWQ{(`^b7r1w)dv{&B zbyYvWLPdlYi-L*Jq?t6G&djx*gZEXw5@iycgu2Yq+)$;M*V+?RCX@xaLrc~sw?Bvqs