diff --git a/api.lua b/api.lua index e6efc46..e5b0a8a 100644 --- a/api.lua +++ b/api.lua @@ -19,7 +19,7 @@ end mobs = { mod = "redo", - version = "20241130", + version = "20241201", spawning_mobs = {}, translate = S, node_snow = has(minetest.registered_aliases["mapgen_snow"]) @@ -263,27 +263,26 @@ end function mob_class:collision() - local pos = self.object:get_pos() ; if not pos then return {0, 0} end + local pos = self.object:get_pos() ; if not pos then return 0, 0 end local x, z = 0, 0 local prop = self.object:get_properties() local width = -prop.collisionbox[1] + prop.collisionbox[4] + 0.5 - local pos2, vec, force for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do if object:is_player() then - pos2 = object:get_pos() - vec = {x = pos.x - pos2.x, z = pos.z - pos2.z} - force = width - vector.distance( - {x = pos.x, y = 0, z = pos.z}, {x = pos2.x, y = 0, z = pos2.z}) + local pos2 = object:get_pos() + local vx, vz = pos.x - pos2.x, pos.z - pos2.z + local force = width - (vx * vx + vz * vz) ^ 0.5 - x = x + (vec.x * force) - z = z + (vec.z * force) + if force > 0 then + force = force * 2 ; x = x + vx * force ; z = z + vz * force + end end end - return({x, z}) + return x, z end -- check if string exists in another string or table @@ -325,7 +324,7 @@ function mob_class:set_velocity(v) local c_x, c_y = 0, 0 -- can mob be pushed, if so calculate direction - if self.pushable then c_x, c_y = unpack(self:collision()) end + if self.pushable then c_x, c_y = self:collision() end local yaw = (self.object:get_yaw() or 0) + (self.rotate or 0) @@ -634,9 +633,9 @@ function mob_class:update_tag(newname) local text = "" - if self.horny == true then + if self.horny then text = "\nLoving: " .. (self.hornytimer - (HORNY_TIME + HORNY_AGAIN_TIME)) - elseif self.child == true then + elseif self.child then text = "\nGrowing: " .. (self.hornytimer - CHILD_GROW_TIME) elseif self._tame_countdown then text = "\nTaming: " .. self._tame_countdown @@ -888,28 +887,23 @@ end -- Returns true if node can deal damage to self -local function is_node_dangerous(mob_object, nodename) - - if mob_object.water_damage > 0 - and minetest.get_item_group(nodename, "water") ~= 0 then return true end - - if mob_object.lava_damage > 0 - and minetest.get_item_group(nodename, "lava") ~= 0 then return true end - - if mob_object.fire_damage > 0 - and minetest.get_item_group(nodename, "fire") ~= 0 then return true end +local function is_node_dangerous(self, nodename) local def = minetest.registered_nodes[nodename] - if mob_object.node_damage and def.damage_per_second > 0 then + if (self.water_damage and def.groups.water) + or (self.lava_damage and def.groups.lava) + or (self.fire_damage and def.groups.fire) then return true end + + if self.node_damage and def.damage_per_second > 0 then -- check for node immunity or special damage local damage = def.damage_per_second for n = 1, #mob_object.immune_to do - if mob_object.immune_to[n][1] == nodename then - damage = mob_object.immune_to[n][2] or 0 ; break + if self.immune_to[n][1] == nodename then + damage = self.immune_to[n][2] or 0 ; break end end @@ -1080,14 +1074,14 @@ function mob_class:do_env_damage() --- suffocation inside solid node if (self.suffocation and self.suffocation ~= 0) - and (nodef.walkable == nil or nodef.walkable == true) + and (nodef.walkable == nil or nodef.walkable) and (nodef.collision_box == nil or nodef.collision_box.type == "regular") and (nodef.node_box == nil or nodef.node_box.type == "regular") and (nodef.groups.disable_suffocation ~= 1) then local damage - if type(self.suffocation) == "boolean" and self.suffocation == true then + if type(self.suffocation) == "boolean" and self.suffocation then damage = 2 else damage = self.suffocation @@ -1123,10 +1117,7 @@ function mob_class:do_jump() local blocked = minetest.registered_nodes[self.looking_above].walkable -- if mob can leap then remove blockages and let them try - if self.can_leap == true then - blocked = false - self.facing_fence = false - end + if self.can_leap then blocked = false ; self.facing_fence = false end -- jump if possible if self.jump and self.jump_height > 0 and not self.fly and not self.child @@ -1231,7 +1222,7 @@ end function mob_class:breed() -- child takes a long time before growing into adult - if self.child == true then + if self.child then self.hornytimer = self.hornytimer + 1 @@ -1274,7 +1265,7 @@ function mob_class:breed() -- horny animal can mate for HORNY_TIME seconds, -- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds - if self.horny == true and self.hornytimer < HORNY_TIME + HORNY_AGAIN_TIME then + if self.horny and self.hornytimer < HORNY_TIME + HORNY_AGAIN_TIME then self.hornytimer = self.hornytimer + 1 @@ -1287,7 +1278,7 @@ function mob_class:breed() end -- find another same animal who is also horny and mate if nearby - if self.horny == true and self.hornytimer <= HORNY_TIME then + if self.horny and self.hornytimer <= HORNY_TIME then local pos = self.object:get_pos() local prop = self.object:get_properties().collisionbox @@ -1323,8 +1314,8 @@ function mob_class:breed() end -- found another similar horny animal that isn't self? - if ent and ent.object ~= self.object and canmate == true - and ent.horny == true and ent.hornytimer <= HORNY_TIME then + if ent and ent.object ~= self.object and canmate + and ent.horny and ent.hornytimer <= HORNY_TIME then local pos2 = ent.object:get_pos() @@ -1394,7 +1385,7 @@ function mob_class:replace(pos) local vel = self.object:get_velocity() ; if not vel then return end if not mobs_griefing or not self.replace_rate or not self.replace_what - or self.child == true or vel.y ~= 0 or random(self.replace_rate) > 1 then + or self.child or vel.y ~= 0 or random(self.replace_rate) > 1 then return end @@ -1450,7 +1441,7 @@ end function mob_class:day_docile() - if self.docile_by_day == true + if self.docile_by_day and self.time_of_day > 0.2 and self.time_of_day < 0.8 then return true end end @@ -1514,22 +1505,21 @@ function mob_class:smart_mobs(s, p, dist, dtime) -- im stuck, search for path if not has_lineofsight then - if los_switcher == true then + if los_switcher then use_pathfind = true los_switcher = false end -- cannot see target! else - if los_switcher == false then + if not los_switcher then los_switcher = true use_pathfind = false minetest.after(1, function(self) - if self.object:get_luaentity() then + if not self.object:get_luaentity() then return end - if has_lineofsight then self.path.following = false end - end + if has_lineofsight then self.path.following = false end end, self) end -- can see target! end @@ -1541,10 +1531,9 @@ function mob_class:smart_mobs(s, p, dist, dtime) minetest.after(1, function(self) - if self.object:get_luaentity() then + if not self.object:get_luaentity() then return end - if has_lineofsight then self.path.following = false end - end + if has_lineofsight then self.path.following = false end end, self) end @@ -1555,16 +1544,15 @@ function mob_class:smart_mobs(s, p, dist, dtime) minetest.after(1, function(self) - if self.object:get_luaentity() then + if not self.object:get_luaentity() then return end - if has_lineofsight then self.path.following = false end - end + if has_lineofsight then self.path.following = false end end, self) end local prop = self.object:get_properties() - if abs(vsubtract(s, target_pos).y) > prop.stepheight then + if abs(s.y - target_pos.y) > prop.stepheight then if height_switcher then use_pathfind = true ; height_switcher = false end else @@ -1583,9 +1571,7 @@ function mob_class:smart_mobs(s, p, dist, dtime) {x = s.x, y = s.y - 4, z = s.z}, 1) -- determine node above ground (adjust height for player models) - if not ssight then - s.y = sground.y + 1 - end + if not ssight then s.y = sground.y + 1 end local p1 = self.attack and self.attack:get_pos() @@ -1837,7 +1823,7 @@ function mob_class:general_attack() -- choose closest player to attack that isnt self if dist ~= 0 and dist < min_dist - and self:line_of_sight(sp, p) == true and not is_peaceful_player(player) then + and self:line_of_sight(sp, p) and not is_peaceful_player(player) then min_dist = dist min_player = player end @@ -1897,7 +1883,7 @@ function mob_class:do_runaway_from() dist = get_distance(p, s) -- choose closest player/mob to runaway from - if dist < min_dist and self:line_of_sight(sp, p) == true then + if dist < min_dist and self:line_of_sight(sp, p) then min_dist = dist min_player = player end @@ -2065,39 +2051,26 @@ function mob_class:do_states(dtime) local yaw = self.object:get_yaw() ; if not yaw then return end -- are we standing in something that hurts ? Try to get out - if is_node_dangerous(self, self.standing_in) then + if is_node_dangerous(self, self.standing_in) then -- and self.pause_timer <= 0 then local s = self.object:get_pos() - local grps = {} - if self.water_damage > 0 then table.insert(grps, "group:water") end - if self.fire_damage > 0 then table.insert(grps, "group:fire") end - if self.lava_damage > 0 then table.insert(grps, "group:lava") end + local lp = minetest.find_nodes_in_area_under_air( + {x = s.x - 7, y = s.y - 1.0, z = s.z - 7}, + {x = s.x + 7, y = s.y + 1.0, z = s.z + 7}, + {"group:cracky", "group:crumbly", "group:choppy", "group:solid"}) - local lp = minetest.find_node_near(s, 1, grps) + -- did we find land ? if so face random block to climb onto + if #lp > 0 then - if lp then + yaw = self:yaw_to_pos( lp[random(#lp)] ) + + self.pause_timer = 3 + self.following = nil + self:set_velocity(self.run_velocity) + self:set_animation("walk") - if self.pause_timer <= 0 then - - lp = minetest.find_nodes_in_area_under_air( - {x = s.x - 5, y = s.y , z = s.z - 5}, - {x = s.x + 5, y = s.y + 2, z = s.z + 5}, - {"group:cracky", "group:crumbly", "group:choppy", "group:solid"}) - - -- did we find land ? if so face random block to climb onto - if lp and #lp > 0 then - yaw = self:yaw_to_pos( lp[random(#lp)] ) - end - - self.pause_timer = 3 - self.following = nil - - self:set_velocity(self.run_velocity) - self:set_animation("walk") - - return - end + return end end @@ -2156,8 +2129,7 @@ function mob_class:do_states(dtime) end -- stand for great fall in front - if self.facing_fence == true or self.at_cliff - or random(100) <= self.stand_chance then + if self.facing_fence or self.at_cliff or random(100) <= self.stand_chance then -- don't stand if mob flies and keep_flying set if (self.fly and not self.keep_flying) or not self.fly then @@ -2443,8 +2415,7 @@ function mob_class:do_states(dtime) self.timer = 0 -- no custom attack or custom attack returns true to continue - if not self.custom_attack - or self:custom_attack(self, p) == true then + if not self.custom_attack or self:custom_attack(self, p) then self:set_animation("punch") @@ -2453,7 +2424,7 @@ function mob_class:do_states(dtime) p2.y = p2.y + .5 s2.y = s2.y + .5 - if self:line_of_sight(p2, s2) == true then + if self:line_of_sight(p2, s2) then -- play attack sound self:mob_sound(self.sounds.attack) @@ -2846,7 +2817,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage) end -- if skittish then run away - if self.runaway == true and self.order ~= "stand" then + if self.runaway and self.order ~= "stand" then local lp = hitter:get_pos() @@ -2861,7 +2832,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage) -- attack puncher and call other mobs for help if self.passive == false and self.state ~= "flop" - and self.child == false and self.attack_players == true + and not self.child and self.attack_players and not (is_player(hitter) and hitter_name == self.owner) and not is_invisible(self, hitter_name) and self.object ~= hitter then @@ -2881,7 +2852,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage) if ent and ent._cmi_is_mob then -- only alert members of same mob and assigned helper - if ent.group_attack == true and ent.state ~= "attack" + if ent.group_attack and ent.state ~= "attack" and not (is_player(hitter) and ent.owner == hitter_name) and (ent.name == self.name or ent.name == self.group_helper) then ent:do_attack(hitter) @@ -3051,13 +3022,13 @@ function mob_class:mob_activate(staticdata, def, dtime) local selbox = self.base_selbox -- is there a specific texture if gotten - if self.gotten == true and def.gotten_texture then textures = def.gotten_texture end + if self.gotten 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 + if self.gotten and def.gotten_mesh then mesh = def.gotten_mesh end -- set child objects to half size - if self.child == true then + if self.child then vis_size = {x = self.base_size.x * .5, y = self.base_size.y * .5} @@ -3573,7 +3544,7 @@ local function can_spawn(pos, name) pos2 = {x = pos.x + x, y = pos.y + y, z = pos.z + z} - if minetest.registered_nodes[node_ok(pos2).name].walkable == true then + if minetest.registered_nodes[node_ok(pos2).name].walkable then return nil end end @@ -3768,7 +3739,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter end -- additional custom checks for spawning mob - if mobs:spawn_abm_check(pos, node, name) == true then + if mobs:spawn_abm_check(pos, node, name) then return end @@ -3803,7 +3774,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter return end else - if day_toggle == true then -- night time but mob wants day + if day_toggle then -- night time but mob wants day --print("--- mob needs day", name) return end @@ -3860,7 +3831,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter local pos2 = {x = pos.x, y = pos.y + n, z = pos.z} - if minetest.registered_nodes[node_ok(pos2).name].walkable == true then + if minetest.registered_nodes[node_ok(pos2).name].walkable then --print ("--- inside block", name, node_ok(pos2).name) return end @@ -3894,7 +3865,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter end -- are we registering an abm or lbm? - if map_load == true then + if map_load then minetest.register_lbm({ name = name .. "_spawning", @@ -4062,7 +4033,7 @@ function mobs:register_arrow(name, def) local entity = thing.ref:get_luaentity() - if entity and self.hit_mob and entity._cmi_is_mob == true then + if entity and self.hit_mob and entity._cmi_is_mob then self:hit_mob(thing.ref) @@ -4096,7 +4067,7 @@ function mobs:register_arrow(name, def) self:hit_node(pos, node) - if (type(self.drop) == "boolean" and self.drop == true) + if (type(self.drop) == "boolean" and self.drop) or (type(self.drop) == "number" and random(self.drop) == 1) then pos.y = pos.y + 1 @@ -4171,7 +4142,7 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) local grp = {spawn_egg = 1} -- do NOT add this egg to creative inventory (e.g. dungeon master) - if no_creative == true then grp.not_in_creative_inventory = 1 end + if no_creative then grp.not_in_creative_inventory = 1 end local invimg = background @@ -4518,7 +4489,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame) self.object:set_hp(self.health) -- make children grow quicker - if self.child == true then + if self.child then -- deduct 10% of the time to adulthood self.hornytimer = floor(self.hornytimer + ( diff --git a/mount.lua b/mount.lua index 4d4003f..ddf6719 100644 --- a/mount.lua +++ b/mount.lua @@ -22,35 +22,17 @@ local abs, cos, floor, sin, sqrt, pi = -- helper functions -local function node_ok(pos, fallback) - - fallback = fallback or mobs.fallback_node - - local node = minetest.get_node_or_nil(pos) - - if node and minetest.registered_nodes[node.name] then return node end - - return {name = fallback} -end - - local function node_is(entity) if not entity.standing_on then return "other" end if entity.standing_on == "air" then return "air" end - if minetest.get_item_group(entity.standing_on, "lava") ~= 0 then - return "lava" - end + local def = minetest.registered_nodes[entity.standing_on] - if minetest.get_item_group(entity.standing_on, "liquid") ~= 0 then - return "liquid" - end - - if minetest.registered_nodes[entity.standing_on].walkable == true then - return "walkable" - end + if def.groups.lava then return "lava" end + if def.groups.liquid then return "liquid" end + if def.groups.walkable then return "walkable" end return "other" end @@ -236,6 +218,11 @@ function mobs.detach(player) end) end +-- vars + +local GRAVITY = -9.8 +local damage_counter = 0 + -- ride mob like car or horse function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) @@ -245,7 +232,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) if entity.player_rotation.y == 90 then rot_view = pi / 2 end - local acce_y = 0 + local acce_y = GRAVITY local velo = entity.object:get_velocity() ; if not velo then return end entity.v = get_v(velo) * get_sign(entity.v) @@ -321,6 +308,35 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) end end + local ni = node_is(entity) + + -- env damage + if ni == "liquid" or ni == "lava" then + + damage_counter = damage_counter + dtime + + if damage_counter > 1 then + + local damage = 0 + + if entity.lava_damage > 0 and ni == "lava" then + damage = entity.lava_damage + elseif entity.water_damage > 0 and ni == "liquid" then + damage = entity.water_damage + end + + if damage >= 1 then + + entity.object:punch(entity.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = damage} + }, nil) + end + + damage_counter = 0 + end + end + -- if not moving then set animation and return if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then @@ -361,12 +377,11 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) p.y = p.y - 0.5 - local ni = node_is(entity) local v = entity.v if ni == "air" then - if can_fly == true then new_acce.y = 0 end + if can_fly then new_acce.y = 0 ; acce_y = 0 end elseif ni == "liquid" or ni == "lava" then