commit e7e158052f11cc0d42e50a75b24f10736c79e127 Author: d Date: Tue May 31 13:26:54 2016 +0900 First commit diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..14a15a2 Binary files /dev/null and b/.DS_Store differ diff --git a/_aux.lua b/_aux.lua new file mode 100644 index 0000000..7232d2d --- /dev/null +++ b/_aux.lua @@ -0,0 +1,17 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +maidroid._aux = {} + +-- maidroidのインベントリを得る +function maidroid._aux.get_maidroid_inventory(self) + return minetest.get_inventory{ + type = "detached", + name = self.invname, + } +end + + + diff --git a/api.lua b/api.lua new file mode 100644 index 0000000..dea0918 --- /dev/null +++ b/api.lua @@ -0,0 +1,159 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +local _aux = maidroid._aux + +-- インベントリにユニークな値を与えるための補助関数 +local gen_inv_serialnumber = (function () + local serialnumber = 0 + return function () + serialnumber = serialnumber + 1 + return serialnumber - 1 + end +end) () + +local main_invsize = 16 +local main_invname = "main" +local module_invsize = 1 +local module_invname = "module" + +-- モジュール名と定義を対応づけるテーブル +maidroid.registered_modules = {} + +-- 新しいmoduleを登録する関数 +function maidroid.register_module(module_name, def) + maidroid.registered_modules[module_name] = def + minetest.register_craftitem(module_name, { + description = def.description, + stack_max = 1, + }) +end + +-- アニメーションの区切りフレーム +maidroid.animations = { + stand = {x = 0, y = 79}, + lay = {x = 162, y = 166}, + walk = {x = 168, y = 187}, + mine = {x = 189, y = 198}, + walk_mine = {x = 200, y = 219}, + sit = {x = 81, y = 160}, +} + +-- 新しいmaidroidを登録する関数 +function maidroid.register_maidroid(product_name, def) + minetest.register_entity(product_name, { + hp_max = def.hp_max or 1, + physical = true, + weight = def.weight or 5, + collistionbox = def.collistionbox or { -0.35, -0.5, -0.35, 0.35, 1.1, 0.35 }, + visual = "mesh", + visual_size = {x = 10, y = 10}, + mesh = def.mesh or "maidroid.b3d", + textures = def.textures or {"maidroid.png"}, + is_visible = true, + makes_footstep_sound = true, + module = nil, + invname = "", + on_activate = function(self, staticdata) + self.invname = "maidroid"..tostring(gen_inv_serialnumber()) + local inv = minetest.create_detached_inventory(self.invname, { + on_put = function(inv, listname, index, stack, player) + if listname == module_invname then + local module_name = stack:get_name() + local module_def = maidroid.registered_modules[module_name] + self.module = module_def + module_def.initialize(self) + end + end, + arrow_put = function(inv, listname, index, stack, player) + local item_name = stack:get_name() + local is_module = maidroid.registered_modules[item_name] + if listname == main_invname + or (listname == module_invname and is_module) then + return stack:get_count() + end + return 0 + end, + on_take = function(inv, listname, index, stack, player) + if listname == module_invname then + local module_name = stack:get_name() + local module_def = maidroid.registered_modules[module_name] + self.module = nil + module_def.finalize(self) + end + end, + }) + inv:set_size(main_invname, main_invsize) + inv:set_size(module_invname, module_invsize) + if self.module then self.module.initialize(self) end + -- process staticdata + if staticdata ~= "" then + local data = minetest.deserialize(staticdata) + local stack = ItemStack(data.inv.module) + stack:set_count(1) + inv:add_item(module_invname, stack) + for _, item in ipairs(data.inv.main) do + local itemstack = ItemStack(item.name) + itemstack:set_count(item.count) + inv:add_item(main_invname, itemstack) + end + end + end, + on_step = function(self, dtime) + if self.module then self.module.on_step(self, dtime) end + end, + on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir) + end, + on_rightclick = function(self, clicker) + local formspec = "size[8,9]" + .."list[detached:"..self.invname..";"..main_invname..";0,0;4,4;]" + .."label[5,0;MODULE]" + .."list[detached:"..self.invname..";"..module_invname..";6,0;1,1;]" + .."list[current_player;"..main_invname..";0,5;8,1;]" + .."list[current_player;"..main_invname..";0,6.2;8,3;8]" + minetest.show_formspec(clicker:get_player_name(), self.invname, formspec) + end, + get_staticdata = function(self) + local inv = _aux.get_maidroid_inventory(self) + local staticdata = {} + staticdata.inv = {} + staticdata.inv.module = inv:get_list(module_invname)[1]:get_name() + staticdata.inv.main = {} + for _, item in ipairs(inv:get_list(main_invname)) do + local count = item:get_count() + local itemname = item:get_name() + if count ~= 0 then + local itemdata = { count = count, name = itemname } + table.insert(staticdata.inv.main, itemdata) + end + end + return minetest.serialize(staticdata) + end, + }) + -- スポーンエッグを登録 + minetest.register_craftitem(product_name.."_swawn_egg", { + description = def.description.." Swapn Egg", + on_use = function(itemstack, user, pointed_thing) + minetest.add_entity(pointed_thing.above, "maidroid:maidroid") + return itemstack + end + }) + -- 野生のmaidroidのentityの登録 + minetest.register_entity(product_name.."_wild", { + hp_max = def.hp_max or 1, + physical = true, + weight = def.weight or 5, + on_activate = function(self, staticdata) + end, + on_step = function(self, dtime) + end, + on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir) + end, + on_rightclick = function(self, clicker) + end, + get_staticdata = function(self) + end, + }) +end diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..0bd96ea --- /dev/null +++ b/init.lua @@ -0,0 +1,15 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +maidroid = {} +maidroid.modname = "maidroid" +maidroid.modpath = minetest.get_modpath("maidroid") + +dofile(maidroid.modpath.."/_aux.lua") +dofile(maidroid.modpath.."/util.lua") +dofile(maidroid.modpath.."/api.lua") +dofile(maidroid.modpath.."/modules.lua") +dofile(maidroid.modpath.."/maidroids.lua") + diff --git a/maidroids.lua b/maidroids.lua new file mode 100644 index 0000000..59a29b6 --- /dev/null +++ b/maidroids.lua @@ -0,0 +1,19 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +maidroid.register_maidroid("maidroid:maidroid", { + hp_max = 10, + description = "Maidroid : Maidroid", +}) + +maidroid.register_maidroid("maidroid:maidroid_mk2", { + hp_max = 10, + description = "Maidroid : Maidroid MkII", +}) + +maidroid.register_maidroid("maidroid:maidroid_mk3", { + hp_max = 10, + description = "Maidroid : Maidroid MkIII", +}) diff --git a/maidroids/maidroid.lua b/maidroids/maidroid.lua new file mode 100644 index 0000000..b28b04f --- /dev/null +++ b/maidroids/maidroid.lua @@ -0,0 +1,3 @@ + + + diff --git a/models/maidroid.b3d b/models/maidroid.b3d new file mode 100755 index 0000000..76243ba Binary files /dev/null and b/models/maidroid.b3d differ diff --git a/models/maidroid.png b/models/maidroid.png new file mode 100755 index 0000000..d9c5f77 Binary files /dev/null and b/models/maidroid.png differ diff --git a/module_generator.lua b/module_generator.lua new file mode 100644 index 0000000..88fb4a6 --- /dev/null +++ b/module_generator.lua @@ -0,0 +1,10 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +minetest.register_node("maidroid:module_generator", { + drawtype = "nodebox", + visual_scale = 1.0, + tiles = {}, +}) diff --git a/modules.lua b/modules.lua new file mode 100644 index 0000000..1e85998 --- /dev/null +++ b/modules.lua @@ -0,0 +1,12 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +maidroid.modules = {} +local modules_dir = maidroid.modpath.."/modules" + +dofile(modules_dir.."/_aux.lua") +dofile(modules_dir.."/chasing_player_module.lua") +dofile(modules_dir.."/farming_module.lua") +dofile(modules_dir.."/lumberjack_module.lua") diff --git a/modules/_aux.lua b/modules/_aux.lua new file mode 100644 index 0000000..7577f43 --- /dev/null +++ b/modules/_aux.lua @@ -0,0 +1,64 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +-- いい感じにモジュール化出来ないので名前空間に隠す +maidroid.modules._aux = {} + +-- 向いている方向と速度ベクトルを変える +function maidroid.modules._aux.change_dir(self) + local rnd = function() return math.random(0, 5) * 2 - 5 end + local dir = {x = rnd(), y = 0, z = rnd()} + local vel = vector.multiply(vector.normalize(dir), 3) + self.object:setvelocity(vel) + self.object:setyaw(math.atan2(vel.z, vel.x) + math.pi / 2) +end + +-- yawから向いている方向ベクトルを得る +function maidroid.modules._aux.get_forward(yaw) + return { x = math.sin(yaw), y = 0.0, z = -math.cos(yaw) } +end + +-- 方向ベクトルを丸める +function maidroid.modules._aux.get_round_forward(forward) + local rforward = { x = 0, y = 0, z = 0} + if math.abs((forward.x / (math.abs(forward.x) + math.abs(forward.z)))) > 0.5 then + if forward.x > 0 then rforward.x = 1 + else rforward.x = -1 end + end + if math.abs((forward.z / (math.abs(forward.x) + math.abs(forward.z)))) > 0.5 then + if forward.z > 0 then rforward.z = 1 + else rforward.z = -1 end + end + return rforward +end + +-- 真下の位置を返すだけ +function maidroid.modules._aux.get_under_pos(vec) + return { x = vec.x, y = vec.y - 1, z = vec.z } +end + +-- 真上の位置を返すだけ +function maidroid.modules._aux.get_upper_pos(vec) + return { x = vec.x, y = vec.y + 1, z = vec.z } +end + +-- 落ちているアイテムを拾う +function maidroid.modules._aux.get_item(self, radius, target_pred) + local pos = self.object:getpos() + local pred = target_list or (function() return true end) + local all_objects = minetest.get_objects_inside_radius(pos, radius) + for _, obj in ipairs(all_objects) do + if not obj:is_player() and obj:get_luaentity() then + local itemstring = obj:get_luaentity().itemstring + if itemstring then + if pred(itemstring) then + local inv = maidroid._aux.get_maidroid_inventory(self) + local stack = ItemStack(itemstring) + local leftover = inv:add_item("main", stack) + end + end + end + end +end diff --git a/modules/chasing_player_module.lua b/modules/chasing_player_module.lua new file mode 100644 index 0000000..b8f54d1 --- /dev/null +++ b/modules/chasing_player_module.lua @@ -0,0 +1,72 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +local util = maidroid.util +local _aux = maidroid.modules._aux + +local state = { idle = 0, chase = 1} +local view_of_range = 7 -- 発見可能距離 +local stop_of_range = 2 -- 止まる距離 + +-- プレーヤを追跡するだけのモジュール +maidroid.register_module("maidroid:chasing_player_module", { + description = "Maidroid Module : Chasing Player", + inventory_image = "maidroid_chasing_player_module.png", + initialize = function(self) + self.state = state.idle + self.object:setacceleration{x = 0, y = -10, z = 0} + self.object:setvelocity{x = 0, y = 0, z = 0} + end, + finalize = function(self) + self.state = nil + self.object:setvelocity{x = 0, y = 0, z = 0} + end, + on_step = function(self, dtime) + local pos = self.object:getpos() + local all_objects = minetest.get_objects_inside_radius(pos, view_of_range) + local player = nil + for _, obj in pairs(all_objects) do + if obj:is_player() then player = obj; break end + end + if not player then + self.object:set_animation(maidroid.animations.stand, 15, 0) + self.state = state.idle + return + end + local ppos = player:getpos() + local dir = vector.subtract(ppos, pos) + local vel = self.object:getvelocity() + if (vector.length(dir) < stop_of_range) then + if self.state == state.chase then + self.object:set_animation(maidroid.animations.stand, 15, 0) + self.state = state.idle + self.object:setvelocity({x = 0, y = vel.y, z = 0}) + end + else + if self.state == state.idle then + self.object:set_animation(maidroid.animations.walk, 15, 0) + self.state = state.chase + end + self.object:setvelocity({x = dir.x, y = vel.y, z = dir.z}) + end + local yaw = math.atan2(dir.z, dir.x) + math.pi/2 + self.object:setyaw(yaw) + -- jump process + if vel.y == 0 and self.state == state.chase then + local rdir = vector.round(dir) + local front_vec = { x = 0, y = 0, z = 0 } + if math.abs((rdir.x / (math.abs(rdir.x) + math.abs(rdir.z)))) > 0.5 then + if rdir.x > 0 then front_vec.x = 1 else front_vec.x = -1 end + end + if math.abs((rdir.z / (math.abs(rdir.x) + math.abs(rdir.z)))) > 0.5 then + if rdir.z > 0 then front_vec.z = 1 else front_vec.z = -1 end + end + local front_pos = vector.add(vector.round(pos), front_vec) + if minetest.get_node(front_pos).name ~= "air" then + self.object:setvelocity({x = dir.x, y = 5, z = dir.z}) + end + end + end, +}) diff --git a/modules/farming_module.lua b/modules/farming_module.lua new file mode 100644 index 0000000..0625768 --- /dev/null +++ b/modules/farming_module.lua @@ -0,0 +1,125 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +local _aux = maidroid.modules._aux +local state = {walk = 0, punch = 1, plant = 2} + +-- 各植物ノードの種類の最大番号を探し出す +local target_plants_list = {} +minetest.after(0, function() + local max = {} + for name, node in pairs(minetest.registered_nodes) do + if minetest.get_item_group(name, "plant") > 0 then + local s, i = string.match(name, "(.+)_(%d+)") + if max[s] == nil or max[s] < i then max[s] = i end + end + end + for s, i in pairs(max) do + table.insert(target_plants_list, s.."_"..i) + end +end) + +local max_punch_time = 20 +local max_plant_time = 15 + +-- 種を持っているか否かを確認する +local function has_seed_item(self) + local inv = maidroid._aux.get_maidroid_inventory(self) + local stacks = inv:get_list("main") + for _, stack in ipairs(stacks) do + local item_name = stack:get_name() + if minetest.get_item_group(item_name, "seed") > 0 then + return true + end + end + return false +end + +-- 農業を行うモジュール +maidroid.register_module("maidroid:farming_module", { + description = "Maidroid Module : Farming", + inventory_image = "maidroid_farming_module.png", + initialize = function(self) + self.object:set_animation(maidroid.animations.walk, 15, 0) + self.object:setacceleration{x = 0, y = -10, z = 0} + self.state = state.walk + self.preposition = self.object:getpos() + self.time_count = 0 + _aux.change_dir(self) + end, + finalize = function(self) + self.state = nil + self.preposition = nil + self.time_count = nil + self.object:setvelocity{x = 0, y = 0, z = 0} + end, + on_step = function(self, dtime) + local pos = self.object:getpos() + local rpos = vector.round(pos) + local yaw = self.object:getyaw() + local forward_vec = _aux.get_forward(yaw) + local forward_vec2 = _aux.get_round_forward(forward_vec) + local forward_pos = vector.add(rpos, forward_vec2) + local forward_node = minetest.get_node(forward_pos) + local forward_under_pos = vector.subtract(forward_pos, {x = 0, y = 1, z = 0}) + if self.state == state.walk then -- searching plants or spaces + if maidroid.util.table_find_value(target_plants_list, forward_node.name) then + self.state = state.punch + self.object:set_animation(maidroid.animations.mine, 15, 0) + self.object:setvelocity{x = 0, y = 0, z = 0} + elseif pos.x == self.preposition.x or pos.z == self.preposition.z then + _aux.change_dir(self) + elseif forward_node.name == "air" + and minetest.get_item_group(inetest.get_node(forward_under_pos).name, "wet") > 0 + and has_seed_item(self) then + self.state = state.plant + self.object:set_animation(maidroid.animations.mine, 15, 0) + self.object:setvelocity{x = 0, y = 0, z = 0} + end + elseif self.state == state.punch then + if self.time_count >= max_punch_time then + if maidroid.util.table_find_value(target_plants_list, forward_node.name) then + local inv = minetest.get_inventory{type = "detached", name = self.invname} + local stacks = minetest.get_node_drops(forward_node.name) + for _, stack in ipairs(stacks) do + local leftover = inv:add_item("main", stack) + minetest.add_item(forward_pos, leftover) + end + end + self.state = state.walk + self.object:set_animation(maidroid.animations.walk, 15, 0) + self.time_count = 0 + _aux.change_dir(self) + else + self.time_count = self.time_count + 1 + end + elseif self.state == state.plant then + if self.time_count >= max_plant_time then + if forward_node.name == "air" and minetest.get_item_group( + minetest.get_node(forward_under_pos).name, "soil") > 0 then + local inv = minetest.get_inventory{type = "detached", name = self.invname} + local stacks = inv:get_list("main") + for idx, stack in ipairs(stacks) do + local item_name = stack:get_name() + if minetest.get_item_group(item_name, "seed") > 0 then + minetest.add_node(forward_pos, {name = item_name, param2 = 1}) + stack:take_item(1) + inv:set_stack("main", idx, stack) + break + end + end + end + self.state = state.walk + self.object:set_animation(maidroid.animations.walk, 15, 0) + self.time_count = 0 + _aux.change_dir(self) + else + self.time_count = self.time_count + 1 + end + end + self.preposition = pos + return + end +}) diff --git a/modules/lumberjack_module.lua b/modules/lumberjack_module.lua new file mode 100644 index 0000000..5ddf0cc --- /dev/null +++ b/modules/lumberjack_module.lua @@ -0,0 +1,132 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +local util = maidroid.util +local _aux = maidroid.modules._aux + +local state = {walk = 0, plant = 1, punch = 2} +local max_punch_time = 20 +local max_plant_time = 20 +local target_tree_list = { "default:tree" } +local target_sapling_list = { "default:sapling" } + +-- punchを始める必要があるか否かを調べる +local function check_punch_flag(forward_pos) + local forward_upper_pos = util.table_shallow_copy(forward_pos) + while true do + local forward_upper_node = minetest.get_node(forward_upper_pos) + if util.table_find_value(target_tree_list, forward_upper_node.name) then + return true, forward_upper_pos, forward_upper_node + elseif forward_upper_node.name ~= "air" then break end + forward_upper_pos.y = forward_upper_pos.y + 1 + end + return false, nil, nil +end + +-- 苗木を持っているかを調べる +local function has_sapling_item(self) + local inv = maidroid._aux.get_maidroid_inventory(self) + local stacks = inv:get_list("main") + for _, stack in ipairs(stacks) do + local item_name = stack:get_name() + if util.table_find_value(target_sapling_list, item_name) then + return true + end + end + return false +end + +-- 木こりモジュールを登録する +maidroid.register_module("maidroid:lumberjack", { + description = "Maidroid Module : Lumberjack", + inventory_image = "maidroid_lumberjack_module.png", + initialize = function(self) + self.state = state.walk + self.time_count = 0 + self.object:setacceleration{x = 0, y = -10, z = 0} + self.object:set_animation(maidroid.animations.walk, 15, 0) + self.preposition = self.object:getpos() + _aux.change_dir(self) + end, + finalize = function(self) + self.state = nil + self.time_count = nil + self.preposition = nil + self.object:setvelocity{x = 0, y = 0, z = 0} + end, + on_step = function(self, dtime) + local pos = self.object:getpos() + local rpos = vector.round(pos) + local yaw = self.object:getyaw() + local forward = _aux.get_forward(yaw) + local rforward = _aux.get_round_forward(forward) + local forward_pos = vector.add(rpos, rforward) + local forward_node = minetest.get_node(forward_pos) + local forward_under_pos = _aux.get_under_pos(forward_pos) + local forward_under_node = minetest.get_node(forward_under_pos) + if self.state == state.walk then + if check_punch_flag(forward_pos) then -- punch tree node + self.state = state.punch + self.object:set_animation(maidroid.animations.mine, 15, 0) + self.object:setvelocity{x = 0, y = 0, z = 0} + elseif pos.x == self.preposition.x or pos.z == self.preposition.z then + _aux.change_dir(self) + elseif forward_node.name == "air" + and minetest.get_item_group(forward_under_node.name, "soil") > 0 + and has_sapling_item(self) then + self.state = state.plant + self.object:set_animation(maidroid.animations.mine, 15, 0) + self.object:setvelocity{x = 0, y = 0, z = 0} + end + elseif self.state == state.punch then + if self.time_count >= max_punch_time then + local punch_flag, forward_upper_pos, forward_upper_node + = check_punch_flag(forward_pos) + if punch_flag then + minetest.remove_node(forward_upper_pos) + local inv = minetest.get_inventory{type = "detached", name = self.invname} + local stacks = minetest.get_node_drops(forward_upper_node.name) + for _, stack in ipairs(stacks) do + local leftover = inv:add_item("main", stack) + minetest.add_item(forward_pos, leftover) + end + end + if (not forward_upper_pos) or (forward_upper_pos and + not check_punch_flag(_aux.get_upper_pos(forward_upper_pos))) then + self.state = state.walk + self.object:set_animation(maidroid.animations.walk, 15, 0) + _aux.change_dir(self) + end + self.time_count = 0 + else + self.time_count = self.time_count + 1 + end + elseif self.state == state.plant then + if self.time_count > max_plant_time then + if forward_node.name == "air" + and minetest.get_item_group(forward_under_node.name, "soil") > 0 then + local inv = minetest.get_inventory{type = "detached", name = self.invname} + local stacks = inv:get_list("main") + for i, stack in ipairs(stacks) do + local itemname = stack:get_name() + if util.table_find_value(target_sapling_list, itemname) then + minetest.add_node(forward_pos, {name = itemname, param2 = 1}) + stack:take_item(1) + inv:set_stack("main", i, stack) + break + end + end + end + self.state = state.walk + self.object:set_animation(maidroid.animations.walk, 15, 0) + self.time_count = 0 + _aux.change_dir(self) + else + self.time_count = self.time_count + 1 + end + end + self.preposition = pos + end +}) diff --git a/textures/normal_maidroid.png b/textures/normal_maidroid.png new file mode 100755 index 0000000..c9a3203 Binary files /dev/null and b/textures/normal_maidroid.png differ diff --git a/textures/normal_module.png b/textures/normal_module.png new file mode 100755 index 0000000..9c21c64 Binary files /dev/null and b/textures/normal_module.png differ diff --git a/util.lua b/util.lua new file mode 100644 index 0000000..b51403e --- /dev/null +++ b/util.lua @@ -0,0 +1,23 @@ +------------------------------------------------------------ +-- Copyright (c) 2016 tacigar +-- https://github.com/tacigar/maidroid +------------------------------------------------------------ + +maidroid.util = {} + +-- ある値を持つキーが存在するかを調べる +function maidroid.util.table_find_value(tbl, value) + for k, v in ipairs(tbl) do + if v == value then return true, k end + end + return false, nil +end + +-- テーブルの浅いコピー +function maidroid.util.table_shallow_copy(source) + local copy = {} + for key, value in pairs(source) do + copy[key] = value + end + return copy +end