2024-03-19 15:27:28 +01:00

887 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Repixture Mobs API
NOTE: This API is EXPERIMENTAL and subject to change! Use at your own risk.
## Core concepts
### Mobs
In this mod, a "mob" refers a non-player entity with added capabilities like a task queue. Mobs can be used to implement things like animals or monsters.
### Tasks, microtasks and task queues
The heart of this mod are tasks. A task is a single defined goal that a mob has to achieve in some manner. Every task can either succeed or fail. Tasks include high-level goals such as "find and eat food", "flee from the player", "kill the player", "roam randomly", etc.
Additionally, every task consists of a number of microtasks. These are intended for more low-level and simple activities such as "go to point XYZ", "jump", "attack in direction A".
To use tasks, they must be initialized by calling `rp_mobs.init_tasks` in `on_activate` and be handled (i.e. executed) every step by calling `rp_mobs.handle_tasks` in `on_step`.
Finally, task queues organize the execution of tasks. A task queue is a sequence of tasks that get executed in order. Tasks get automatically removed from the queue once finished. Task queues also optionally have a `decider` function which is called every time the task queue is empty.
A mob can have any number of task queues active at a time. While tasks and microtasks are executed sequentially, task queues run in parallel.
Task queues, tasks and microtask form a tree-like structure, like so:
Task queue 1
|
`- Task 1
|
`- Microtask 1
`- Microtask 2
|
`- Task 2
`- Microtask 1
`- Microtask 2
So on the top level, you have task queues, which consist of tasks, which in turn consist of microtasks.
### Physics and movement
This mod doesn't handle physics. Just use Minetests built-in functions like `set_velocity` and `set_acceleration`.
Theres one exception: Gravity. This mod provides a default gravity vector at `rp_mobs.GRAVITY_VECTOR`.
To activate gravity for a mob, you can call `mob.object:set_acceleration(rp_mobs.GRAVITY_VECTOR)`.
### Registering a mob
You add (register) a mob via `rp_mobs.register_mob`. Mob definitions in this API are very low-level and similar to typical entity definitions in Minetest. You still have to provide a full entity definition via `entity_definition` including the callback functions like `on_activate` and `on_rightclick`.
You're supposed to use the Repixture Mob API functionality by inserting the various helper functions into the callbacks like `on_step` and `on_activate` where appropriate.
You can use the following template:
rp_mobs.register_mob("MOBNAME", {
description = "MOB DESCRIPTION",
drops = { ADD_YOUR_DROPS_HERE },
entity_definition = {
on_activate = function(self, staticdata)
rp_mobs.init_mob(self)
rp_mobs.restore_state(self, staticdata)
rp_mobs.init_tasks(self)
end,
on_step = function(self, dtime, moveresult)
rp_mobs.handle_dying(self, dtime)
rp_mobs.handle_tasks(self, dtime, moveresult)
end,
get_staticdata = rp_mobs.get_staticdata_default,
on_death = rp_mobs.on_death_default,
on_punch = rp_mobs.on_punch_default,
},
})
## Data structures
This section defines the data structures used in the functions below.
### Task
A task is just a table. You can optionally define this field:
* `label`: Brief string explaining what the task does. Only for debug
Tasks can be created with `rp_mobs.create_task`.
The task's microtasks are stored internally. Use `rp_mobs.add_microtask_to_task`
to add a microtask to a task.
### Microtask
A microtask is a table with the following fields:
* `label`: Same as for tasks
* `on_step`: Called every step of the mob. Handle the microtask behavior here
* `on_finished`: Return true if the microtask is complete, false otherwise
* `on_end`: Called when the microtask has ended. Useful for cleaning up state
* `on_start`: Called when the microtask has begun. Called just before `on_step`
* `singlestep`: If true, this microtask will run for only 1 step and automatically succeeds (default: false)
* `statedata`: Table containing data that can be modified and read at runtime
Every microtask needs to have `on_step` and either `on_finished` or `singlestep = true`.
All other fields are optional. It is not allowed to add any fields not listed above.
`on_finished`, `on_end` and `on_start` have parameters `self, mob` with `self` being
a reference to the microtask table itself and `mob` being the mob object that is affected.
`on_step` has the parameters `self, mob, dtime, moveresult`, where `dtime` is the time in
seconds that have passed since it was last called, or 0 on the first call (like for the entity
`on_step` function), and `moveresult` is the `moveresult` of the entity `on_step`
function (only available if `physical=true` in the entity definition, otherwise it'll be `nil`).
The `statedata` field can be used to associate arbitrary data with the microtask in
order to preserve some state. You may read and write to it in functions
like `on_step`.
Microtasks can be created with `rp_mobs.create_microtask`.
## Subsystems
Subsystems implement core mob features. The task handling is also a subsystem.
Each subsystem can be enabled by adding a `handle_*` function in `on_step` and
most of the time, also an `init_*` function in `on_activate`.
The `handle_*` function in `on_step` **must** be called on *every* step.
Failing to do so leads to undefined behavior.
For example, to enable the Tasks subsystem, call `rp_mobs.init_tasks` in `on_activate`
of the mob entity definition, and `rp_mobs.handle_tasks` in `on_step`. See the
function reference for details.
The Tasks subsystem is mandatory and must be enabled for all mobs.
### Subsystem overview
This overview is a list of all subsystems and the required functions you need to call:
Subsystem | on_activate function | on_step function
------------+--------------------------+----------------------------
Core* | rp_mobs.init_mob | **
Tasks* | rp_mobs.init_tasks | rp_mobs.handle_tasks
Dying | ** | rp_mobs.handle_dying
Node damage | rp_mobs.init_node_damage | rp_mobs.handle_node_damage***
Fall damage | rp_mobs.init_fall_damage | rp_mobs.handle_fall_damage***
Breath | rp_mobs.init_breath | rp_mobs.handle_breath***
Breeding | ** | rp_mobs.handle_breeding
* = mandatory
** = no init function required
*** = can be replaced with rp_mobs.handle_environment_damage
### Core subsystem
The core subsystem must always be added to the mob. It does initialization
work that is mandatory for all mobs. Add `rp_mobs.init_mob` to the beginning
of the `on_activate` function.
### Dying
An entity “dies” in Minetest when its HP reaches 0, which instantly removes it and
triggers the `on_death` function.
We do not like instant removal so this mod provides a simple graphical death effect
delay. This flips over the mob and makes it come to a screeching halt.
The mob is still visible but all player interactions are disabled. After a short
delay, the mob disappears, causing `on_death` to be called.
To use this subsystem, add `rp_mobs.handle_dying` into `on_step`.
**IMPORTANT**: You also must follow a restriction: Never call `set_hp` to
damage the mob. Instead, punch the mob with the built-in `punch` function
or call `rp_mobs.damage`.
Internally, this subsystem works by storing a variable for the mob to hold
the dead/alive state. It can be queried with `rp_mobs.is_alive`.
When the mob has received fatal damage, the HP remains at 1 but the mob
counts as dead.
If this subsystem is not used, the mob will instantly disappear when the HP reaches 0.
But `on_death` is still called (allowing for mob drops).
### Node damage
Node damage enables the mob being vulnerable to nodes with the `damage_per_second` field.
If you want your mob to use this, add `rp_mobs.init_node_damage` to `on_activate`
and `rp_mobs.handle_node_damage` to `on_step`. Read the documentation of these
functions to learn more about how the node damage mechanic works.
Node damage can be temporarily disabled during the mobs 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
The breath subsystem enables breath and a drowning mechanic. This makes mobs take
drowning damage when inside a particular node.
If you want your mob to use this, add `rp_mobs.init_breath` to `on_activate`
and `rp_mobs.handle_drowning` in `on_step`. Read the documentation of these
functions to learn more about the drowning mechanic in general.
The drowning status can also be changed during the mobs lifetime in `on_step`
by manipulating the drowning fields (see the mob field reference).
### Breeding
Breeding will make mobs mate and create offspring. To enable, call
`rp_mobs.handle_breeding` in `on_step`. You also need to add the tag
`"child_exists"` to the mob definition.
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
spawn a child mob. The child mob will grow to an adult after some time.
There are two ways to make a mob horny:
1. Call `rp_mobs.feed_tame_breed` in `on_rightclick` (i.e. player gives mob enough food)
2. Call `rp_mobs.make_horny` to instantly make the 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.
These fields are available:
### Status
* `_tamed`: `true` if mob is tame
* `_tame_level`: tame level. Starts at 0 and increases for any food given, used to trigger taming
* `_horny_level`: 'horny' level. Starts at 0 and increases for any food given to an adult, used to trigger horny mode
* `_child`: `true` if mob is a child
* `_horny`: `true` if mob is “horny”. If another horny mob is nearby, they will mate and spawn a child soon
* `_pregnant`: `true` if mob is pregnant and about to spawn a child
### Textures
NOTE: You must update these whenever you want to change a mob's texture. If the mob does not use a custom
child texture, `_textures_child` can be skipped.
* `_textures_adult`: Stores a copy of the current mob textures table for the mob in adult form
* `_textures_child`: Stores a copy of the current mob textures table for the mob in child form
### 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` isnt true)
* `_breath`: Current breath (ignored if `_can_drown` isnt true)
Please note:
You *must* call `rp_mobs.init_node_damage` before you touch the `_get_node_damage` field.
You *must* call `rp_mobs.init_breath` before you touch the breath/drowning fields.
### Internal use
A bunch of fields are meant for internal use by `rp_mobs`. Do not change them. Reading them is fine.
* `_cmi_is_mob`: Always `true`. Indicates the entity is a mob
* `_child_grow_timer`: time the mob has been a child (seconds)
* `_horny_timer`: time the mob has been horny (seconds)
* `_breed_check_timer`: timer for the breed check (seconds)
* `_pregnant_timer`: time the mob has been pregnant (seconds)
* `_last_feeder`: Name of the last player who fed the mob
* `_dying`: Is `true` when mob is currently dying and about to be removed
* `_dying_timer`: time the mob has been in the dying state (seconds)
## Function reference
### Registrations
#### `rp_mobs.register_mob(mobname, def)`
Register a mob with the entity identifier `mobname` and definition `def`.
The mob definition will be stored under `rp_mobs.registered_mobs[mobname]`.
The field `_cmi_is_mob=true` will be set automatically for all mobs and can be used to check whether any given entity is a mob.
`def` is a definition table with the following optional fields:
* `description`: Short mob name used for display purposes
* `drops`: Items to drop (see 'Drop table' below) on death when mob dies as adult (default: empty table)
* `child_drops`: Items to drop when mob dies as child (default: empty table)
* `drop_func(self)`: (optional) Called when mob is dropping its death drop items. Must return table of items to drop.
These items are dropped on top of the items in `drops` and `child_drops`.
This function **must not** manipulate the mob in any way.
* `default_sounds`: Table of default sound names to play automatically on built-in events. Sounds will be played by `rp_mobs.default_mob_sound`
* `death`: When mob dies
* `damage`: When mob takes non-fatal damage
* `punch_no_damage`: When mob was punched but took no damage
* `eat`: When mob eats something (this has a default sound)
* `call`: Occasional mob call (only played manually)
* `horny`: When mob becomes horny
* `give_birth`: When mob gives birth to a child
* `front_body_point`: A point of the front side of the mob. Used by the mob to "see"
forwards to detect dangerous land (cliffs, damaging blocks, etc.)
Should be on the mob model and roughly in the center of that side.
* `dead_y_offset`: Y offset of collisionbox when mob is in 'dying' state. Set this to
a number so that the mob lies on top of the ground (it should neither
float nor be inside the ground)
* `entity_definition`: Entity definition table. It may contain this custom function:
* `_on_capture(self, capturer)`: Called when a mob capture is attempted by capturer (a player).
Triggered by `rp_mobs.call_on_capture`
* `textures_child`: If set, this will be the mob texture for the mob as a child. Same syntax as `textures`
of the entity definition. Adult mobs will use `textures`
* `animations`: Table of available mob animations
* The keys are string identifies for each animation, like `"walk"`
* The values are tables with the following fields:
* `frame_range`: Same as `frame_range` in `object:set_animation`
* `default_frame_speed`: Default `frame_speed` (from `object:set_animation`) when this animation is played
* Built-in animations are:
* `"idle"`: Played when mob has nothing to do (empty task queue)
* `"dead_static"`: Played when mob is dead (no animation, just a static frame)
* `tags`: Table of tags.
* Tags are arbitrary strings used to logically categorize the mob.
* The table keys are tag names and value for each key must always be 1.
* You can check if a mob has a tag with `rp_mobs.has_tag` or `rp_mobs.mobdef_has_tag`.
* Built-in tag names:
* `"animal"`: This mob is an animal. Some items and achievements check for this tag
* `"peaceful"`: Mob is considered 'peaceful' towards players if unprovoked. It normally leaves
the player alone. Peaceful mobs may still turn hostile when provoked.
Mobs that start hostile towards the player do not count as peaceful.
If the setting `spawn_peaceful_only` is enabled, only mobs with this tag can spawn.
* `"child_exists"`: Mob has a functional child version. This tag is only
for informing other mobs; it does not have an effect in the `rp_mobs` code
* Example: `tags = { animal = 1, peaceful = 1, exploder = 1 }`
* A peaceful animal, plus a custom `"exploder"` tag.
##### Drop table
For the arguments `drops` and `child_drops`, two types of values are supported:
1. List of itemstrings: Will drop every item in this list
2. List of drop probabilities: Will drop items by a given chance
* `name`: Technical itemname
* `chance`: Chance given in 1/`chance` for this item to drop
* `min`: Minimum item count when it drops
* `max`: Maximum item count when it drops
#### `rp_mobs.register_mob_item(mobname, invimg, desc, on_create_capture_item)`
Registers an item representing a mob. It can be used by players to spawn
the mob by placing it. This item is also used when a mob is captured.
The mob item may contain metadata to store the mob's HP and internal state
of the mob.
* `mobname`: Mob identifier
* `invimg`: Inventory image texture
* `desc`: Description for inventory
* `on_create_capture_item`: (optional) Function is called with arguments
`mob, itemstack` when mob has been captured and is becoming an itemstack.
You can use this function to modify the itemstack's metadata, e.g. to
use a item image override if the mob can have different appearances.
**Must** return an itemstack for the itemstack that is *actually* created.
#### `rp_mobs.register_capture_tool(itemname, definition)`
Registers an *existing* tool as a capture tool.
* `itemname`: Item name of the item that captures
* `definition`: A table with these fields:
* `uses`: Number of uses before the tool breaks. 0 = unlimited
* `sound`: (optional) Name of sound that plays when “swinging” the tool
* `sound_gain`: (optional) Gain of that sound (as in `SimpleSoundSpec`)
* `sound_max_hear_distance`: (optional) `max_hear_distance` of that sound (as in `SimpleSoundSpec`)
### Default entity handlers
These functions should be set as the callback functions of the mob entity.
The code will usually look like this:
```
get_staticdata = rp_mobs.get_staticdata_default, -- required
on_death = rp_mobs.on_death_default, -- optional, custom handler recommended
on_punch = rp_mobs.on_punch_default, -- optional
```
#### `rp_mobs.get_staticdata_default(mob)`
The default handler for `get_staticdata` of the mob's entity definition.
This will handle the staticdata of the mob for you. All the mob's internal
information will be stored including the `_custom_state`.
`_temp_custom_state` will be discarded.
This function *must* be set explicitly for every mob.
Set `get_staticdata = rp_mobs.get_staticdata_default` to use this.
#### `rp_mobs.on_death_default(mob, killer)`
The default handler for `on_death` of the mob's entity definition.
It must be set explicitly for every mob, unless you want to have a custom death handling.
Currently, the default death handler just drops the mob death items.
Set `on_death = rp_mobs.on_death_default` to use the default death behavior.
#### `rp_mobs.on_punch_default(mob, puncher, time_from_last_punch, tool_capabilities, dir, damage)`
Default `on_punch` handler of mob. Set this function to `on_punch`. The arguments are the same as for `on_punch`.
This will play a the `damage` sound if the mob took damage, otherwise, `hit_no_damage` is played (if the sound exists).
### `on_activate` functions
These are functions to be used in the `on_activate` handler to initialize certain subsystems, like tasks.
Calling `rp_mobs.restore_state` in `on_activate` is a requirement, but everything else is optional depending on your needs.
#### `rp_mobs.init_mob(mob)`
This initializes the mob and does initialization work in order to do things that
are required for all mobs.
This function **must** be called in `on_activate` before any other mob-related function.
#### `rp_mobs.restore_state(mob, staticdata)`
This will restore the mob's state data from the given `staticdata` in `on_activate`.
This *must* be called in `on_activate`.
#### `rp_mobs.init_tasks(mob)`
Initialize the task and microtask queues for the mob.
This is supposed to go into `on_activate` of the entity definition.
This function **must** be called before any other task-related function is called.
#### `rp_mobs.init_breath(mob, can_drown, def)`
Initializes the breath and drowning mechanic 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, drowning and
associated entity fields will be initialized. On subsequent calls,
this function does nothing because the fields are already
initialized.
* `self`: The mob
* `can_drown`: If `true`, drowning is possible, otherwise, it is not.
* `def`: A table with the following fields:
* `breath_max`: Maximum (and initial) breath points. Positive number
* `drowning_point`: Optional position offset vector that will be checked when doing
the drowning check. Its an offset from the mob position (`get_pos()`). If the
node at the drowning point is a drowning node, the mob can drown.
Default: no offset
#### `rp_mobs.init_node_damage(mob, get_node_damage)`
Initializes the node damage mechanic for the given mob,
activating damage from nodes with `damage_per_second`.
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:
* `mob`: The mob
* `get_node_damage`: If `true`, mob will receive damage from nodes
#### `rp_mobs.init_fall_damage(mob, 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
### Subsystems: `on_step` handlers
These are functions you need to call in the `on_step` callback function of the mob entity in order for a subsystem to work properly.
Each of these functions assumes the corresponding `rp_mobs.init_*` function has been called before.
#### `rp_mobs.handle_tasks(mob, dtime, moveresult)`
Handle the task queues, tasks, microtasks of the mob for a single step. Required for the task system to work.
This is supposed to go into `on_step` of the entity definition. It must be called every step.
`dtime` and `moveresult` must be passed from the arguments of the same name of the entitys `on_step`.
#### `rp_mobs.handle_dying(self, dtime)`
Handles the dying state of the mob if the mob has been killed. If the internal mob state
`_dying` is true, the dying effect is applied and the mob gets removed after a short delay,
triggering the `on_death` callback. It is recommended to put this function before
any other `rp_mobs` subsystem calls.
See the section about the “Dying” subsystem for details.
`dtime` must be passed from the argument of the same name of the entitys `on_step`.
#### `rp_mobs.handle_node_damage(mob, dtime)`
Handles node damage for the mob if the entity
field `_get_node_damage` is `true`. Node damage is taken
in nodes with a non-zero `damage_per_second`.
In the current implementation, only the mob position is checked,
other nodes are ignored. This behavior may change in the future.
Checks if the mob is standing in a damaging node and if yes, damage it.
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 guarantee 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
if the entity field `_can_drown` is `true`.
Mob drowning is meant to closely reflect player drowning.
This function requires that `rp_mobs.init_breath` has
been called in `on_activate` before.
Technically, this function checks if the mobs drowning
point is inside a node with a non-zero non-nil `drowning`
field. If this is the case, the internal `_breath` will
be reduced in a regular interval. If `_breath` reaches zero,
the mob will take damage equal to the nodes `drowning` value.
If the mob is in a non-drowning node, it will regain
breath up to `_breath_max`.
In `"ignore"` nodes, breath will not be changed.
By default, the mob position will be checked to determine
which node is checked for the `drowning` field. If
`_drowning_point` is set, is must be a vector added to
the mob position to check a different position. This
is usually where the mobs “head” is. The drowning point
should be inside the collisionbox, otherwise the mob
might regain breath when touching a wall.
The drowning point will automatically be rotated with the
mobs 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, moveresult)`
Handle all environment damages. This is is the same as 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`.
### Task functions
This section contains the functions to create tasks, microtasks and task queues and to add them to the mob.
See also `rp_mobs.init_tasks` and `rp_mobs.handle_tasks`.
#### `rp_mobs.create_task_queue(empty_decider, step_decider)`
Create a task queue object and returns it. The two arguments are
optional decider functions.
In this function you can update the task queue by adding new
tasks to it. Avoid complex and slow algorithms here!
* `empty_decider(task_queue, mob)`: called when the task queue is empty
* `step_decider(task_queue, mob, dtime)`: called at every server step
The function arguments are:
* `task_queue`: Reference to task queue on which the decider is run on.
You can modify it at will.
* `mob`: Reference to mob object
* `dtime`: Time in seconds the last time the step decider was called (from `on_step`)
If decider argument is nil, nothing will be done for that event.
#### `rp_mobs.create_task(def)`
Create a task according to the specified `def` table. See the data structure above for the possible table fields.
Returns the task.
#### `rp_mobs.create_microtask(def)`
Create a microtask according to the specified `def` table. See the data structure above for the possible table fields.
The `statedata` field will always be initialized as an empty table.
Returns the microtask.
Note this only creates it in memory. To actually execute it, you have to add
it to a task with `rp_mobs.add_microtask_to_task` and then execute
the task.
#### `rp_mobs.add_task_queue(mob, task_queue)`
Add a task queue to the given mob.
#### `rp_mobs.add_task_to_task_queue(task, task_queue)`
Add a task `task` to the given task queue object.
#### `rp_mobs.add_microtask_to_task(mob, microtask, task)`
Add the microtask `microtask` to the specified `task`.
#### `rp_mobs.end_current_task_in_task_queue(mob, task_queue)`
Ends the currently active task in the given `task_queue` of `mob`.
If the task queue is empty, nothing happens.
### Task template functions
This mod comes with a number of template functions for common microtasks like walking. See `API_template.md` for a reference.
### Breeding functions
#### `rp_mobs.feed_tame_breed(mob, feeder, allowed_foods, food_till_tamed, food_till_horny, add_child_grow_timer, effect, eat_sound)`
Requires the Breeding subsystem.
Let the player `feeder` feed the `mob` with their wielded item and optionally cause the mob to become tame and become horny.
Should be called in `on_rightclick`.
* `mob`: The mob that is fed
* `feeder`: Player who feeds the mob
* `allowed_foods`: List of allowed food items, where each entry must be a table with these fields:
* `name`: item name of food item
* `points` optional food points to add to mob when eaten, defaults to `_rp_hunger_food`
of item definition, and if that one is nil, too, defaults to 1
* `food_till_tamed`: How many food points the mob needs until it is tamed (if nil, can't be tamed by food)
* `food_till_horny`: How many food points the adult mob needs until it becomes horny (if nil, can't be made horny by food)
* `add_child_growth_timer`: (optional) If mob is a child, by how many seconds the child growth timer is increased (default: `20`)
* `effect`: (optional) `true` to show particle effects, `false` otherwise (default: `true`)
* `eat_sound`: (optional) Name of sound to play (default: `"mobs_eat"`)
#### `rp_mobs.make_horny(mob, force)`
Make mob horny, if possible.
#### `rp_mobs.make_unhorny(mob)`
Disable mob being horny.
### Children functions
These function handle the child/adult status of the mob.
#### `rp_mobs.turn_into_adult(mob)`
Turns the mob into an adult.
#### `rp_mobs.turn_into_child(mob)`
Turns the mob into a child.
IMPORTANT: You *must* check whether the mob has the `"child_exists"` tag before calling this.
Don't call this function if the mob does not have this tag.
#### `rp_mobs.advance_child_growth(mob, dtime)`
Advance the child growth timer of the given mob by dtime (in seconds) and turn it into an adult once the time has passed.
Should be added into the `on_step` function of the mob if you want children to grow up. If children must not grow up automatically, don't add this function.
### Capturing functions
#### `rp_mobs.attempt_capture = function(mob, capturer, capture_chances, force_take, replace_with)`
Requires the Capturing subsystem.
Attempt to capture mob by capturer (a player). This requires a mob to have a mob available as
an item (see `rp_mobs.register_mob_items`), unless `replace_with` is set.
It is recommended to put this function in the `_on_capture` field of the mobs entity definition.
A mob capture may or may not succeed. A mob capture succeeds if all of these are true:
1. The wielded item is in `capture_chances`
2. The random capture chance succeeds
3. The mob is tamed _or_ `force_take` is `true`
4. The mob is not a child
If successful, `capturer` will get the mob in item form and it will wear out the wielded tool
(exception: no wear in Creative Mode). `capturer` might receive a message. If the mob
was horny, the mob will stop being horny.
The created mob item stores the internal mob state and HP so it will be restored
when the mob is being placed again.
Parameters:
* `mob`: The mob to capture
* `capturer`: Player trying to capture
* `capture_changes`: Table defining which items can capture and their chance to capture:
* key: itemname, e.g. `"rp_mobs:net"`
* value: capture chance, specified as `1/value`. e.g. value 5 is a 1/5 chance.
* `force_take`: (optional) If `true`, can capture non-tamed mob
* `replace_with`: (optional) Give this item instead of the registered mob item.
If `nil` (default), gives the registered mob item.
#### `rp_mobs.call_on_capture(mob, capture)`
Requires the Capturing subsystem.
Handle the mobs capturing logic by calling the `_on_capture` function of the mobs entity definition. This function *must* exist.
It is recommended to put this into `on_rightclick`, if you want this mob to be capturable.
### Animation functions
#### `rp_mobs.set_animation(mob, animation_name, animation_speed)`
Set the animation for the given mob. The animation name is set in the mob definition in `_animations`. The name *must* exist in this table
* `mob`: Mob object
* `animation_name`: Name of the animation to play, as specified in mob definition
* `animation_speed`: (optional): Override the default frame speed of the animation
This function handles the animation internals for you. If you call this function with the same animation name and speed twice in a row, nothing happens; no unnecessary network traffic is generated. If you call the function twice in row with the same animation name but a different frame speed, only the animation speed is updated the animation does not restart. In all other cases, the animation is set and started from the beginning.
### Sound functions
#### `rp_mobs.mob_sound(mob, sound, keep_pitch)`
Plays a sound for the given mob. The pitch will be slightly randomized. Child mobs have a 50% higher pitch.
* `mob`: Mob to play sound for
* `sound`: A `SimpleSoundSpec`
* `keep_pitch`: If `true`, pitch will not be randomized and not be affected by child status
#### `rp_mobs.default_mob_sound(mob, default_sound, keep_pitch)`
Plays a default mob sound for the given mob. Default sounds are specified in `rp_mobs.register_mob`. The pitch will be slightly randomized. Child mobs have a 50% higher pitch.
* `mob`: Mob to play sound for
* `default_sound`: Name of a default mob sound, like `"damage"`
* `keep_pitch`: If `true`, pitch will not be randomized and not be affected by child status
#### `rp_mobs.default_hurt_sound(mob, keep_pitch)`
Make a mob play its “hurt” sound. The pitch will be slightly randomized. Child mobs have a 50% higher pitch.
* `mob`: Mob to play sound for
* `keep_pitch`: If `true`, pitch will not be randomized and not be affected by child status
### Event functions
#### `rp_mobs.register_on_die(callback)`
Registers a function `callback(mob, killer)` where `mob` is a mob reference and `killer`
is an object reference to the mob killer (or nil if there's no killer).
The function `callback` will be called when a mob has entered the 'dying' state, i.e.
lying on the side but not disappeared yet.
This is useful to trigger kill-related achievements but it could be used
for other reasons.
NOTE: This function differs from `on_death` in the entity definition. This callback
triggers when the mob enters the 'dying' state, while `on_death` triggers when
the entity is being *actually* removed.
IMPORTANT: Due to the implementation details, `on_death` will *not* provide
the correct `killer` argument.
### Utility functions
#### `rp_mobs.is_alive(mob)`
Returns `true` if the given mob is alive, false otherwise. `mob` *must* be a mob.
#### `rp_mobs.heal(mob, heal)`
Adds `heal` HP to mob. `heal` must not be negative.
#### `rp_mobs.damage(mob, damage, no_sound, damager)`
Removes `damage` HP from mob, optionally playing the mob's `"damage"` sound. `damage` must not be negative. If the mob HP reaches 0, the mob dies.
`damager` is an optional object that damaged the mob (used for Hunter achievement).
If `no_sound` is true, then no damage sound will be played.
It is recommended to damage a mob only with this function instead of calling `mob:set_hp` directly in order to ensure consistency across mobs.
#### `rp_mobs.die(mob, killer)`
Kill the mob by putting it into the 'dying' state.
`killer` is an optional object that killed the mob (used for Hunter achievement).
See the section about the “Dying” subsystem for details.
#### `rp_mobs.drop_death_items(mob, pos)`
Make mob `mob` drop its death items at `pos`, as if it had died.
This does not kill the mob.
#### `rp_mobs.spawn_mob_drop(pos, item)`
Spawns an mob drop at `pos`. A mob drop is an item stack “dropped”
by a mob, usually on death, but it may also be used on other events.
`item` is an itemstring or `ItemStack`
The difference from `minetest.add_item` is that it adds some random velocity
so this is the recommended function to make a mob drop something.
#### `rp_mobs.has_tag(mob, tag_name)`
Returns true if mob has the given `tag_name` or false if not.
See `rp_mobs.register_mob` for for info about tags.
#### `rp_mobs.mobdef_has_tag(mob_name, tag_name)
Return true if the mob definition for the mob with the given `mob_name` exists
and has a tag with the given `tag_name`. Returns false otherwise.
See `rp_mobs.register_mob` for for info about tags.
## Appendix
### Glossary
* Mob: Non-player entity with added capabilities and a task queue
* Task queue: Sequence of tasks a mob will execute in order; can run in parallel
* Task: A sequence of microtasks a mob will execute in order; cant run in parallel
* Microtask: A simple function a mob will execute every step until a goal condition is met
* Decider: A function that is called when the task queue is empty in order to generate new tasks