Mobs: Add fall damage
This commit is contained in:
parent
19d0875a6f
commit
6e937fee68
@ -36,7 +36,6 @@ You can use the following template:
|
||||
drops = { ADD_YOUR_DROPS_HERE },
|
||||
decider = function(self) --[[ do things ]] end,
|
||||
entity_definition = {
|
||||
-- Add
|
||||
on_activate = function(self)
|
||||
rp_mobs.init_physics(self)
|
||||
rp_mobs.init_tasks(self)
|
||||
@ -110,6 +109,15 @@ functions to learn more about how the node damage mechanic works.
|
||||
Node damage can be temporarily disabled during the mob’s lifetime by setting the
|
||||
entity field `_get_node_damage` to false.
|
||||
|
||||
### Fall damage
|
||||
|
||||
Fall damage hurts the mob when it hits the ground too hard.
|
||||
The fall damage calculation works differently than for players (see
|
||||
`rp_mobs.handle_fall_damage` for details.
|
||||
|
||||
To enable fall damage , add `rp_mobs.init_fall_damage` in `on_activate` and
|
||||
`rp_mobs.handle_fall_damage` in `on_step`.
|
||||
|
||||
### Breath / drowning
|
||||
|
||||
Drowning makes mobs take drowning damage when inside a particular node.
|
||||
@ -124,7 +132,7 @@ by manipulating the drowning fields (see the mob field reference).
|
||||
### Breeding
|
||||
|
||||
Breeding will make mobs mate and create offspring. To enable, add
|
||||
`rp_mobs.handle_breeding` in `on_step`.
|
||||
`rp_mobs.handle_breeding` in `on_step`.
|
||||
|
||||
In particular, to breed, two adult mobs of the same type need to be “horny” and close
|
||||
to each other. Then, a random mob of the pair gets pregnant and will soon
|
||||
@ -137,6 +145,7 @@ There are two ways to make a mob horny:
|
||||
|
||||
Only adults should be horny.
|
||||
|
||||
|
||||
## Mob field reference
|
||||
|
||||
Mob entities use a bunch of custom fields. You may read and edit them at runtime.
|
||||
@ -155,6 +164,7 @@ These fields are available:
|
||||
### Damage
|
||||
|
||||
* `_get_node_damage`: `true` when mob can take damage from nodes (`damage_per_second`) (default: false)
|
||||
* `_get_fall_damage`: `true` when mob can take fall damage (default: false)
|
||||
* `_can_drown`: `true` when mob has breath and can drown in nodes with `drowning` attribute (default: false)
|
||||
* `_drowning_point`: See `rp_mobs.init_breath`.
|
||||
* `_breath_max`: Maximum breath (ignored if `_can_drown` isn’t true)
|
||||
@ -306,6 +316,21 @@ Parameters:
|
||||
* `self`: The mob
|
||||
* `get_node_damage`: If `true`, mob will receive damage from nodes
|
||||
|
||||
### `rp_mobs.init_fall_damage(self, get_fall_damage)`
|
||||
|
||||
Initializes the fall damage for the given mob,
|
||||
If you want the mob to have this, put this into `on_activate`.
|
||||
|
||||
If this is the first time the function is called, the
|
||||
associated entity fields will be initialized. On subsequent
|
||||
calls, this function does nothing because the fields are already
|
||||
initialized.
|
||||
|
||||
Parameters:
|
||||
|
||||
* `self`: The mob
|
||||
* `get_fall_damage`: If `true`, mob will receive fall damage
|
||||
|
||||
### `rp_mobs.attempt_capture = function(mob, capturer, capture_chances, force_take, replace_with)`
|
||||
|
||||
Attempt to capture mob by capturer (a player). This requires a mob to have a mob available as
|
||||
@ -355,6 +380,25 @@ Otherwise, no damage will be taken.
|
||||
Must be called in the `on_step` function in every step.
|
||||
`dtime` is the `dtime` argument of `on_step`.
|
||||
|
||||
### `rp_mobs.handle_fall_damage(mob, dtime, moveresult)`
|
||||
|
||||
Handles fall damage for the mob if the entity field
|
||||
`_get_fall_damage` is `true`.
|
||||
|
||||
Fall damage is calculated differently than for
|
||||
players and there is no guarante the calculation
|
||||
algorithm will be forwards-compatible. It increases
|
||||
linearly with the fall height. Fall damage is further-
|
||||
more modified by the `add_fall_damage_percent` group
|
||||
if falling on a node. Adding the armor group
|
||||
`add_fall_damage_percent` will also modify the
|
||||
fall damage the mob will receive (like for players,
|
||||
see `lua_api.md`).
|
||||
|
||||
This function must be called in the `on_step` function
|
||||
in every step. `dtime` and `moveresult` are the same as
|
||||
in `on_step`.
|
||||
|
||||
### `rp_mobs.handle_drowning(mob, dtime)`
|
||||
|
||||
Handles breath and drowning damage for the mob
|
||||
@ -387,10 +431,18 @@ mob’s yaw.
|
||||
Must be called in the `on_step` function in every step.
|
||||
`dtime` is the `dtime` argument of `on_step`.
|
||||
|
||||
### `rp_mobs.handle_environment_damage(mob, dtime)`
|
||||
### `rp_mobs.handle_environment_damage(mob, dtime, moveresult)`
|
||||
|
||||
Handle all environment damages. This is is the same as
|
||||
calling `rp_mobs.handle_node_damage` and `rp_mobs.handle_drowning`.
|
||||
calling:
|
||||
|
||||
* `rp_mobs.handle_fall_damage`
|
||||
* `rp_mobs.handle_node_damage`
|
||||
* `rp_mobs.handle_drowning`
|
||||
|
||||
Must be called in `on_step` every step.
|
||||
`mob` is the mob. The `dtime` and `moveresult`
|
||||
arguments are the same as for `on_step`.
|
||||
|
||||
### `rp_mobs.on_death_default(mob, killer)`
|
||||
|
||||
|
@ -13,6 +13,8 @@ local NODE_DAMAGE_TIME = 1.0
|
||||
local DROWNING_TIME = 2.0
|
||||
-- Interval (seconds) at which mobs regenerate breath (if they have breath)
|
||||
local REBREATH_TIME = 0.5
|
||||
-- Minimum Y fall height before starting to take fall damage
|
||||
local FALL_DAMAGE_HEIGHT = 5
|
||||
|
||||
-- List of entity variables to store in staticdata
|
||||
-- (so they are persisted when unloading)
|
||||
@ -395,15 +397,24 @@ function rp_mobs.init_breath(self, can_drown, def)
|
||||
return
|
||||
end
|
||||
self._can_drown = can_drown
|
||||
self._breath_max = breath_max
|
||||
self._breath = breath_max
|
||||
self._breath_max = def.breath_max
|
||||
self._breath = def.breath_max
|
||||
self._drowning_point = def.drowning_point
|
||||
end
|
||||
function rp_mobs.init_node_damage(self, get_node_damage)
|
||||
if self._get_node_damage ~= nil then
|
||||
return
|
||||
end
|
||||
self._get_node_damage = get_node_damagee
|
||||
self._get_node_damage = get_node_damage
|
||||
end
|
||||
function rp_mobs.init_fall_damage(self, get_fall_damage)
|
||||
if self._get_fall_damage ~= nil then
|
||||
return
|
||||
end
|
||||
self._get_fall_damage = get_fall_damage
|
||||
if not self._standing_y then
|
||||
self._standing_y = self.object:get_pos().y
|
||||
end
|
||||
end
|
||||
|
||||
function rp_mobs.handle_node_damage(self, dtime)
|
||||
@ -501,14 +512,84 @@ function rp_mobs.handle_drowning(self, dtime)
|
||||
end
|
||||
end
|
||||
|
||||
function rp_mobs.handle_environment_damage(self, dtime)
|
||||
function rp_mobs.handle_fall_damage(self, dtime, moveresult)
|
||||
if not self._get_fall_damage then
|
||||
return
|
||||
end
|
||||
if not rp_mobs.is_alive(self) then
|
||||
return
|
||||
end
|
||||
|
||||
local mob_fall_factor = 1
|
||||
local armor = self.object:get_armor_groups()
|
||||
-- Apply mob’s fall_damage_add_percent modifier
|
||||
if armor.fall_damage_add_percent then
|
||||
mob_fall_factor = 1 + armor.fall_damage_add_percent/100
|
||||
end
|
||||
local is_immortal = armor.immortal ~= nil and armor.immortal ~= 0
|
||||
if moveresult.collides then
|
||||
local collisions = moveresult.collisions
|
||||
for c=1, #collisions do
|
||||
local collision = collisions[c]
|
||||
local old_v = collision.old_velocity
|
||||
local new_v = collision.new_velocity
|
||||
local speed_diff = vector.subtract(new_v, old_v)
|
||||
|
||||
-- We only care about floor collision
|
||||
if (not (speed_diff.y < 0 or old_v.y >= 0)) then
|
||||
|
||||
-- Apply node’s fall_damage_add_percent modifier
|
||||
local node_fall_factor = 1.0
|
||||
if collision.type == "node" then
|
||||
local node = minetest.get_node(collision.node_pos)
|
||||
local g = minetest.get_item_group(node.name, "fall_damage_add_percent")
|
||||
if g ~= 0 then
|
||||
node_fall_factor = 1 + g/100
|
||||
end
|
||||
end
|
||||
|
||||
-- Calculate final fall damage modifier
|
||||
local pre_factor = mob_fall_factor * node_fall_factor
|
||||
|
||||
-- Fall damage is based on fall height. When falling at least the
|
||||
-- FALL_DAMAGE_HEIGHT, mob may take 1 damage per extra node fallen
|
||||
local y_diff = self._standing_y - self.object:get_pos().y
|
||||
|
||||
-- Apply damage modifier
|
||||
y_diff = y_diff * pre_factor
|
||||
|
||||
if (y_diff >= FALL_DAMAGE_HEIGHT and (not is_immortal) and pre_factor > 0) then
|
||||
local damage_f = y_diff - FALL_DAMAGE_HEIGHT
|
||||
local damage = math.floor(math.min(damage_f + 0.5, 65535))
|
||||
if damage > 0 then
|
||||
local hp = self.object:get_hp() - damage
|
||||
self.object:set_hp(hp, { type = "fall" })
|
||||
if hp <= 0 then
|
||||
self._dying = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if moveresult.touching_ground then
|
||||
self._standing_y = self.object:get_pos().y
|
||||
end
|
||||
end
|
||||
|
||||
function rp_mobs.handle_environment_damage(self, dtime, moveresult)
|
||||
rp_mobs.handle_fall_damage(self, dtime, moveresult)
|
||||
rp_mobs.handle_node_damage(self, dtime)
|
||||
rp_mobs.handle_drowning(self, dtime)
|
||||
end
|
||||
|
||||
|
||||
-- Entity variables to persist:
|
||||
rp_mobs.add_persisted_entity_vars({
|
||||
"_get_node_damage", -- true when mob can take damage from nodes (damage_per_second)
|
||||
"_get_fall_damage", -- true when mob can take fall damage
|
||||
"_standing_y", -- Y coordinate when mob was standing on ground. Internally used for fall damage calculations
|
||||
"_can_drown", -- true when mob has breath and can drown in nodes with `drowning` attribute
|
||||
"_drowning_point", -- The position offset that will be checked when doing the drowning check
|
||||
"_breath_max", -- Maximum breath
|
||||
|
@ -38,6 +38,7 @@ rp_mobs.register_mob("rp_mobs_mobs:boar", {
|
||||
textures = { "mobs_boar.png" },
|
||||
makes_footstep_sound = true,
|
||||
on_activate = function(self)
|
||||
rp_mobs.init_fall_damage(self, true)
|
||||
rp_mobs.init_breath(self, true, {
|
||||
breath_max = 10,
|
||||
drowning_point = vector.new(0, -0.1, 0.49)
|
||||
@ -48,8 +49,8 @@ rp_mobs.register_mob("rp_mobs_mobs:boar", {
|
||||
rp_mobs.activate_gravity(self)
|
||||
rp_mobs.init_tasks(self)
|
||||
end,
|
||||
on_step = function(self, dtime)
|
||||
rp_mobs.handle_environment_damage(self, dtime)
|
||||
on_step = function(self, dtime, moveresult)
|
||||
rp_mobs.handle_environment_damage(self, dtime, moveresult)
|
||||
rp_mobs.handle_physics(self)
|
||||
rp_mobs.handle_tasks(self, dtime)
|
||||
rp_mobs.handle_breeding(self, dtime)
|
||||
|
@ -7,17 +7,9 @@ local dummy_texture = "mobs_dummy.png"
|
||||
rp_mobs.register_mob("rp_mobs_mobs:dummy", {
|
||||
description = S("Dummy"),
|
||||
decider = function(self)
|
||||
local task = rp_mobs.create_task({label="Dummy stuff"})
|
||||
rp_mobs.add_microtask_to_task(self, rp_mobs.microtasks.set_yaw("random"), task)
|
||||
local yaw = (math.random(0, 10000) / 10000) * (math.pi*2)
|
||||
rp_mobs.add_microtask_to_task(self, rp_mobs.microtasks.walk_straight_towards(1, "pos", vector.zero(), 0.2), task)
|
||||
local sleep_time = math.random(500, 2000)/1000
|
||||
local mt_sleep = rp_mobs.microtasks.sleep(sleep_time)
|
||||
rp_mobs.add_microtask_to_task(self, mt_sleep, task)
|
||||
rp_mobs.add_task(self, task)
|
||||
end,
|
||||
entity_definition = {
|
||||
hp_max = 1,
|
||||
hp_max = 20,
|
||||
physical = true,
|
||||
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5, rotate=true},
|
||||
@ -25,10 +17,14 @@ rp_mobs.register_mob("rp_mobs_mobs:dummy", {
|
||||
textures = { dummy_texture, dummy_texture, dummy_texture, dummy_texture, dummy_texture, dummy_texture },
|
||||
makes_footstep_sound = false,
|
||||
on_activate = function(self)
|
||||
rp_mobs.init_fall_damage(self, true)
|
||||
rp_mobs.init_physics(self)
|
||||
rp_mobs.init_tasks(self)
|
||||
rp_mobs.activate_gravity(self)
|
||||
self._get_fall_damage = true
|
||||
end,
|
||||
on_step = function(self, dtime)
|
||||
on_step = function(self, dtime, moveresult)
|
||||
rp_mobs.handle_environment_damage(self, dtime, moveresult)
|
||||
rp_mobs.handle_physics(self)
|
||||
rp_mobs.handle_tasks(self, dtime)
|
||||
rp_mobs.decide(self)
|
||||
|
@ -80,6 +80,7 @@ rp_mobs.register_mob("rp_mobs_mobs:sheep", {
|
||||
})
|
||||
end
|
||||
|
||||
rp_mobs.init_fall_damage(self, true)
|
||||
rp_mobs.init_breath(self, true, {
|
||||
breath_max = 10,
|
||||
drowning_point = vector.new(0, -0.5, 0.49)
|
||||
@ -91,8 +92,8 @@ rp_mobs.register_mob("rp_mobs_mobs:sheep", {
|
||||
rp_mobs.init_tasks(self)
|
||||
end,
|
||||
get_staticdata = rp_mobs.get_staticdata_default,
|
||||
on_step = function(self, dtime)
|
||||
rp_mobs.handle_environment_damage(self, dtime)
|
||||
on_step = function(self, dtime, moveresult)
|
||||
rp_mobs.handle_environment_damage(self, dtime, moveresult)
|
||||
rp_mobs.handle_physics(self)
|
||||
rp_mobs.handle_tasks(self, dtime)
|
||||
rp_mobs.handle_breeding(self, dtime)
|
||||
|
Loading…
x
Reference in New Issue
Block a user