diff --git a/api.lua b/api.lua index 510fe00..5c83836 100644 --- a/api.lua +++ b/api.lua @@ -177,20 +177,25 @@ function update_tag(self) end -- check if mob is dead or only hurt -function check_for_death(self) - +function check_for_death(self, pos2) -- return if no change local hp = self.object:get_hp() - - if hp == self.health then - return false + hp.foo.bar(x) + if pos2 == nil then + print("pos2 is nil. api.lua:185") + return end + if hp == self.health then + --print("no damage") + return false + end +print("got damage") local pos = self.object:getpos() -- still got some health? play hurt sound if hp > 0 then - + print("not dead: " .. hp) self.health = hp if self.sounds.damage then @@ -209,22 +214,25 @@ function check_for_death(self) -- drop items when dead local obj - +print("mob died") for _,drop in pairs(self.drops) do - +print("dropping: " .. drop.name) if math.random(1, drop.chance) == 1 then - - obj = minetest.add_item(pos, +print("doing drop at "..pos.x..", "..pos.y..", "..pos.z) +print("doing drop2 at "..pos2.x..", "..pos2.y..", "..pos2.z) + obj = minetest.add_item(pos2, ItemStack(drop.name .. " " .. math.random(drop.min, drop.max))) if obj then - +print("drop successful") obj:setvelocity({ x = math.random(-1, 1), y = 6, z = math.random(-1, 1) }) + else + print("failed to add item") end end end diff --git a/api_fast.lua b/api_fast.lua new file mode 100644 index 0000000..11cd524 --- /dev/null +++ b/api_fast.lua @@ -0,0 +1,340 @@ + + + + + + + + +function mobehavior:register_mob_fast(name, def) + + local mdef = { + hp_max = 1, + health = 1, + rotate = 0, + physical = true, + weight = 5, + collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5}, + visual = "mesh", + visual_size = {x=1, y=1}, + mesh = "model", + fall_speed = -9.81, + textures = {}, -- number of required textures depends on visual + colors = {}, -- number of required colors depends on visual + spritediv = {x=1, y=1}, + initial_sprite_basepos = {x=0, y=0}, + is_visible = true, + makes_footstep_sound = false, + automatic_rotate = false, + + bt_timer = 0, + bt = nil, + btData = nil, + + + on_step = function(self, dtime) + local btdata = self.btData +-- print('newstep') + local pos = self.object:getpos() + local yaw = self.object:getyaw() or 0 + + self.bt_timer = self.bt_timer + dtime + + -- run the behavior tree every two seconds + if self.bt_timer > 2 then + + btdata.pos = pos + btdata.yaw = yaw + btdata.mob = self + + print("\n<<< start >>>") + + -- inventories cannot be serialized and cause the game to crash if + -- placed in the entity's table + local inv = minetest.get_inventory({type="detached", name=self.inv_id}) + btdata.inv = inv + + bt.tick(self.bt, btdata) + print("<<< end >>>\n") + + -- so clear it out after running the behavior trees + btdata.inv = nil + -- the inventory exists on its own + + self.bt_timer = 0 + end + + btdata.lastpos = pos + + + -- handle movement + + local v = self.object:getvelocity() + + -- TODO: floating + + -- going up then apply gravity +-- if v.y > 0.1 then + + self.object:setacceleration({ + x = 0, + y = self.fall_speed, + z = 0 + }) +-- end + + -- TODO: fall damage + + + if self.destination ~= nil then + + --print("destination ") + + local dist = distance(pos, self.destination) + -- print("walk dist ".. dist) + local s = self.destination + local vec = { + x = pos.x - s.x, + y = pos.y - s.y, + z = pos.z - s.z + } + + if vec.x ~= 0 or vec.z ~= 0 then + + yaw = (math.atan(vec.z / vec.x) + math.pi / 2) - self.rotate + + if s.x > pos.x then + yaw = yaw + math.pi + end + + -- print("yaw " .. yaw) + + self.object:setyaw(yaw) + end + + if dist > (self.approachDistance or .1) then +--[[ + if (self.jump + and get_velocity(self) <= 0.5 + and self.object:getvelocity().y == 0) + or (self.object:getvelocity().y == 0 + and self.jump_chance > 0) then + do_jump(self) + end]] + + + + set_velocity(self, self.walk_velocity) + set_animation(self, "walk") + else + -- we have arrived + self.destination = nil + + -- TODO: bump bttimer to get new directions + + set_velocity(self, 0) + set_animation(self, "stand") + end + end + end, + + + on_activate = function(self, staticdata, dtime_s) + self.btData = { + groupID = "default", + + waypoints= {}, + paths= {}, + counters={}, + + history={}, + history_queue={}, + history_depth=20, + + posStack={}, + } + + local btdata = self.btData + + self.inv_id= name..":"..math.random(1, 2000000000) + --print(btdata.id) + + btdata.lastpos = self.object:getpos() + + if type(def.pre_activate) == "function" then + def.pre_activate(self, static_data, dtime_s) + end + + -- load entity variables + if staticdata then + + local tmp = minetest.deserialize(staticdata) + + if tmp then + + for _,stat in pairs(tmp) do + self[_] = stat + end + end + else + self.object:remove() + + return + end + + local inventory = minetest.create_detached_inventory(self.inv_id, {}) + inventory:set_size("main", 9) + + + -- select random texture, set model and size + if not self.base_texture then + + self.base_texture = def.textures[math.random(1, #def.textures)] + self.base_mesh = def.mesh + self.base_size = self.visual_size + self.base_colbox = self.collisionbox + end + + -- set texture, model and size + local textures = self.base_texture + local mesh = self.base_mesh + local vis_size = self.base_size + local colbox = self.base_colbox + + -- specific texture if gotten + if self.gotten == true + and def.gotten_texture then + textures = def.gotten_texture + end + + -- specific mesh if gotten + if self.gotten == true + and def.gotten_mesh then + mesh = def.gotten_mesh + end + + -- set child objects to half size + if self.child == true then + + vis_size = { + x = self.base_size.x / 2, + y = self.base_size.y / 2 + } + + if def.child_texture then + textures = def.child_texture[1] + end + + colbox = { + self.base_colbox[1] / 2, + self.base_colbox[2] / 2, + self.base_colbox[3] / 2, + self.base_colbox[4] / 2, + self.base_colbox[5] / 2, + self.base_colbox[6] / 2 + } + end + + if self.health == 0 then + self.health = math.random (self.hp_min, self.hp_max) + end + + self.object:set_hp(self.health) + self.object:set_armor_groups({fleshy = self.armor}) + self.old_y = self.object:getpos().y + self.object:setyaw(math.random(1, 360) / 180 * math.pi) +-- self.sounds.distance = (self.sounds.distance or 10) + self.textures = textures + self.mesh = mesh + self.collisionbox = colbox + self.visual_size = vis_size + + -- set anything changed above + self.object:set_properties(self) + update_tag(self) + + if type(def.post_activate) == "function" then + def.post_activate(self, static_data, dtime_s) + end + end, + + get_staticdata = function(self) + + -- remove mob when out of range unless tamed + if mobs.remove + and self.remove_ok + and not self.tamed then + + --print ("REMOVED", self.remove_ok, self.name) + + self.object:remove() + + return nil + end + + self.remove_ok = true + self.attack = nil + self.following = nil + self.state = "stand" + + if self.btData ~= nil then + self.btData.inv = nil -- just in case + self.btData.mob = nil -- just in case + end + + -- used to rotate older mobs + if self.drawtype + and self.drawtype == "side" then + self.rotate = math.rad(90) + end + + local tmp = {} + + for _,stat in pairs(self) do + + local t = type(stat) + + if t ~= 'function' + and t ~= 'nil' + and t ~= 'userdata' then + tmp[_] = self[_] + end + end + + -- print('===== '..self.name..'\n'.. dump(tmp)..'\n=====\n') + return minetest.serialize(tmp) + end, + + + + + + + } + + for k,v in pairs(def) do + mdef[k] = v + end + + + + minetest.register_entity(name, mdef) +end + + + + + + + + + + + + + + + + + + diff --git a/entities.lua b/entities.lua index edbb0a5..35a5c93 100644 --- a/entities.lua +++ b/entities.lua @@ -26,8 +26,8 @@ function make_bunny(name, behavior_fn) view_range = 15, floats = 0, drops = { - {name = "mobs:meat_raw", - chance = 1, min = 1, max = 1}, + {name = "mobehavior:meat_raw", chance = 1, min = 1, max = 2}, + {name = "fur:small_pelt", chance = 1, min = 1, max = 1}, }, water_damage = 0, lava_damage = 4, @@ -88,8 +88,8 @@ function make_wolf(name, behavior_fn) view_range = 25, floats = 1, drops = { - {name = "mobs:meat_raw", - chance = 1, min = 1, max = 1}, + {name = "mobehavior:meat_raw", chance = 1, min = 1, max = 1}, + {name = "fur:medium_pelt", chance = 1, min = 1, max = 1}, }, water_damage = 0, lava_damage = 4, @@ -151,7 +151,7 @@ function make_bear(name, behavior_fn) view_range = 25, floats = 1, drops = { - {name = "mobs:meat_raw", + {name = "mobehavior:meat_raw", chance = 1, min = 1, max = 1}, }, water_damage = 0, @@ -213,8 +213,7 @@ function make_rat(name, behavior_fn) view_range = 15, floats = 1, drops = { - {name = "mobs:meat_raw", - chance = 1, min = 1, max = 1}, + {name = "mobehavior:meat_raw", chance = 1, min = 1, max = 1}, }, water_damage = 0, lava_damage = 4, @@ -239,7 +238,8 @@ end function make_NPC(name, behavior_fn) - mobs:register_simple_mob(mn..":"..name, { +-- mobs:register_simple_mob(mn..":"..name, { + mobehavior:register_mob_fast(mn..":"..name, { type = "monster", passive = false, attack_type = "dogfight", diff --git a/giant.lua b/giant.lua index a58d567..729a7ff 100644 --- a/giant.lua +++ b/giant.lua @@ -483,7 +483,7 @@ end - +--[[ make_wolf("wolf", function() return wander_around(6) end) @@ -498,6 +498,7 @@ end) make_bear("bear", function() return wander_around(6) end) +]] make_NPC("npc", function() return wander_around(6) diff --git a/init.lua b/init.lua index f05015e..108db6f 100644 --- a/init.lua +++ b/init.lua @@ -37,9 +37,13 @@ minetest.register_on_shutdown(saveModData) -- Mob Api +-- new api from scratch +dofile(path.."/api_fast.lua") + +dofile(path.."/meat.lua") dofile(path.."/api.lua") dofile(path.."/behavior.lua") -dofile(path.."/simple_api.lua") +-- dofile(path.."/simple_api.lua") dofile(path.."/scripts/init.lua") diff --git a/simple_api.lua b/simple_api.lua index 66d52e9..950ff36 100644 --- a/simple_api.lua +++ b/simple_api.lua @@ -13,6 +13,7 @@ end -- register mob function function mobs:register_simple_mob(name, def) +print("bad bad") --[[ local btdata = { waypoints= {}, @@ -201,8 +202,8 @@ minetest.register_entity(name, { self.object:set_hp(self.object:get_hp() - math.floor(d - 5)) effect(pos, 5, "tnt_smoke.png") - - if check_for_death(self) then + print("death by falling") + if check_for_death(self, pos) then return end end @@ -328,7 +329,7 @@ minetest.register_entity(name, { end, on_punch = function(self, hitter, tflp, tool_capabilities, dir) - + print("got punched !!!!") -- weapon wear local weapon = hitter:get_wielded_item() local punch_interval = 1.4 @@ -359,12 +360,18 @@ minetest.register_entity(name, { max_hear_distance = 5 }) end - +local hp = self.object:get_hp() + + local pos = self.object:getpos() + print("punched (hp: "..hp..")at "..pos.x..", "..pos.y..", "..pos.z) + + -- exit here if dead - if check_for_death(self) then + if check_for_death(self, pos) then + print("died from punch") return end - +print("didn't die from punch") -- blood_particles if self.blood_amount > 0 and not disable_blood then diff --git a/spawning.lua b/spawning.lua index 3bdf54e..83a2025 100644 --- a/spawning.lua +++ b/spawning.lua @@ -18,12 +18,12 @@ minetest.register_abm({ "default:silver_sand", }, neighbors = {"air"}, - interval = 20, - chance = 100, + interval = 30, + chance = 400, catch_up = false, action = function(pos, node, active_object_count, active_object_count_wider) - if active_object_count > 15 then + if active_object_count > 10 then --print("too many local objs " .. active_object_count) return end @@ -52,8 +52,8 @@ minetest.register_abm({ "default:dirt_with_coniferous_litter", }, neighbors = {"air"}, - interval = 2, - chance = 10, + interval = 20, + chance = 200, catch_up = false, action = function(pos, node, active_object_count, active_object_count_wider) @@ -75,3 +75,42 @@ minetest.register_abm({ end end }) + + + + +-- bunnies +minetest.register_abm({ + nodenames = { + "default:dirt_with_grass", + "seasons:spring_default_dirt_with_grass", + "default:dirt_with_coniferous_litter", + "default:desert_sand", + "default:silver_sand", + }, + neighbors = {"air"}, + interval = 30, + chance = 600, + catch_up = false, + + action = function(pos, node, active_object_count, active_object_count_wider) + if active_object_count > 8 then + --print("too many local objs " .. active_object_count) + return + end + + local nearobjs = minetest.get_objects_inside_radius(pos, 40) + if #nearobjs > 4 then + --print("too many near objs") + return + end + + --print("----------spawning rat") + local p = minetest.find_node_near(pos, 3, "air") + if p then + local mob = minetest.add_entity(p, "mobehavior:bunny") + end + end +}) + +