Compare commits

...

5 Commits

Author SHA1 Message Date
rubenwardy 12e6cb7291 Update copyright year 2021-01-25 12:26:08 +00:00
rubenwardy 8892bcd8e9 Items: Split Item Aliases from Item Names 2021-01-25 12:18:39 +00:00
rubenwardy 3e265da9b5 Objects: Add damage documentation 2021-01-25 11:05:28 +00:00
rubenwardy c258e67f35 Update writing guide 2021-01-25 08:57:13 +00:00
rubenwardy 6622a49cd1 Basic Map Operations: Improve chapter
Fixes #100
2021-01-25 08:51:11 +00:00
6 changed files with 127 additions and 26 deletions

View File

@ -4,6 +4,7 @@
],
"spellright.documentTypes": [
"latex",
"plaintext"
"plaintext",
"markdown"
]
}

View File

@ -3,7 +3,7 @@
[![Build status](https://gitlab.com/rubenwardy/minetest_modding_book/badges/master/pipeline.svg)](https://gitlab.com/rubenwardy/minetest_modding_book/pipelines)<br>
[Read Online](https://rubenwardy.com/minetest_modding_book/)
Book written by rubenwardy.
Book written by rubenwardy.
License: CC-BY-SA 3.0
## Finding your way around
@ -23,15 +23,25 @@ License: CC-BY-SA 3.0
I'm happy to fix the formatting of any chapters. It is
the writing which is the hard bit, not the formatting.
### Chapter Guidelines
### Chapter and Writing Guide
Grammar and such:
* British English, except when referring common code words like `color` and
`initialize`.
* Prefer pronounless text, but `you` if you must. Never `we` nor `I`.
* Titles and subheadings should be in Title Case.
* References to code (such as function names) should be formatted as \`inline-code`.
* Italics used for emphasis, not necessarily for technical words.
* Full stops and correct punctionation, except for lists without full sentences.
Formatting:
* Do not rely on anything that isn't printable to a physical book.
* Any links must be invisible - ie: if they're removed, then the chapter must
still make sense.
* Table of contents for each chapter with anchor links.
* Add `your turn`s to the end of a chapter when relevant.
* Titles and subheadings should be in Title Case.
### Making a Chapter

View File

@ -14,7 +14,8 @@ basic requirements for many mods.
- [What are Nodes and Items?](#what-are-nodes-and-items)
- [Registering Items](#registering-items)
- [Item Names and Aliases](#item-names-and-aliases)
- [Item Names](#item-names)
- [Item Aliases](#item-aliases)
- [Textures](#textures)
- [Registering a basic node](#registering-a-basic-node)
- [Actions and Callbacks](#actions-and-callbacks)
@ -55,7 +56,7 @@ minetest.register_craftitem("modname:itemname", {
})
```
### Item Names and Aliases
### Item Names
Every item has an item name used to refer to it, which should be in the
following format:
@ -66,6 +67,8 @@ The modname is the name of the mod in which the item is registered, and the
item name is the name of the item itself.
The item name should be relevant to what the item is and can't already be registered.
### Item Aliases
Items can also have *aliases* pointing to their name.
An *alias* is a pseudo-item name which results in the engine treating any
occurrences of the alias as if it were the item name.
@ -74,8 +77,6 @@ There are two main common uses of this:
* Renaming removed items to something else.
There may be unknown nodes in the world and in inventories if an item is
removed from a mod without any corrective code.
It's important to avoid aliasing to an unobtainable node if the remove node
could be obtained.
* Adding a shortcut. `/giveme dirt` is easier than `/giveme default:dirt`.
Registering an alias is pretty simple.

View File

@ -13,11 +13,11 @@ In this chapter, you will learn how to perform basic actions on the map.
- [Map Structure](#map-structure)
- [Reading](#reading)
- [Reading Nodes](#reading-nodes)
- [Finding Nodes](#finding-nodes)
- [Reading Nodes](#reading-nodes)
- [Finding Nodes](#finding-nodes)
- [Writing](#writing)
- [Writing Nodes](#writing-nodes)
- [Removing Nodes](#removing-nodes)
- [Writing Nodes](#writing-nodes)
- [Removing Nodes](#removing-nodes)
- [Loading Blocks](#loading-blocks)
- [Deleting Blocks](#deleting-blocks)
@ -74,6 +74,10 @@ For example, say we wanted to make a certain type of plant that grows
better near mese; you would need to search for any nearby mese nodes,
and adapt the growth rate accordingly.
`minetest.find_node_near` will return the first found node in a certain radius
which matches the node names or groups given. In the following example,
we look for a mese node within 5 nodes of the position:
```lua
local grow_speed = 1
local node_pos = minetest.find_node_near(pos, 5, { "default:mese" })
@ -84,7 +88,7 @@ end
```
Let's say, for example, that the growth rate increases the more mese there is
nearby. You should then use a function which can find multiple nodes in area:
nearby. You should then use a function that can find multiple nodes in the area:
```lua
local pos1 = vector.subtract(pos, { x = 5, y = 5, z = 5 })
@ -94,9 +98,9 @@ local pos_list =
local grow_speed = 1 + #pos_list
```
The above code doesn't quite do what we want, as it checks based on area, whereas
`find_node_near` checks based on range. In order to fix this, we will,
unfortunately, need to manually check the range ourselves.
The above code finds the number of nodes in a *cuboid volume*. This is different
to `find_node_near`, which uses the distance to the position (ie: a *sphere*). In
order to fix this, we will need to manually check the range ourselves:
```lua
local pos1 = vector.subtract(pos, { x = 5, y = 5, z = 5 })
@ -112,11 +116,11 @@ for i=1, #pos_list do
end
```
Now your code will correctly increase `grow_speed` based on mese nodes in range.
Now the code will correctly increase `grow_speed` based on mese nodes in range.
Note how we compared the squared distance from the position, rather than square
rooting it to obtain the actual distance. This is because computers find square
roots computationally expensive, so you should avoid them as much as possible.
roots computationally expensive, so they should avoided as much as possible.
There are more variations of the above two functions, such as
`find_nodes_with_meta` and `find_nodes_in_area_under_air`, which work similarly
@ -127,8 +131,8 @@ and are useful in other circumstances.
### Writing Nodes
You can use `set_node` to write to the map. Each call to set_node will cause
lighting to be recalculated, which means that set_node is fairly slow for large
numbers of nodes.
lighting to be recalculated and node callbacks to run, which means that set_node
is fairly slow for large numbers of nodes.
```lua
minetest.set_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
@ -140,7 +144,7 @@ print(node.name) --> default:mese
set_node will remove any associated metadata or inventory from that position.
This isn't desirable in all circumstances, especially if you're using multiple
node definitions to represent one conceptual node. An example of this is the
furnace node - whilst you think conceptually of it as one node, it's actually
furnace node - whilst you conceptually think of it as one node, it's actually
two.
You can set a node without deleting metadata or the inventory like so:
@ -160,7 +164,7 @@ minetest.remove_node(pos)
minetest.set_node(pos, { name = "air" })
```
In fact, remove_node will call set_node with the name being air.
In fact, remove_node is just a helper function that calls set_node with `"air"`.
## Loading Blocks
@ -205,7 +209,8 @@ local function emerge_callback(pos, action,
end
```
This is not the only way of loading blocks; using an LVM will also cause the
This is not the only way of loading blocks; using an
[Lua Voxel Manipulator (LVM)](../advmap/lvm.html) will also cause the
encompassed blocks to be loaded synchronously.
## Deleting Blocks

View File

@ -20,12 +20,13 @@ own.
- [Position and Velocity](#position-and-velocity)
- [Object Properties](#object-properties)
- [Entities](#entities)
- [Health and Damage](#health-and-damage)
- [Attachments](#attachments)
- [Your Turn](#your-turn)
## What are Objects, Players, and Entities?
Players and Entities are both types of Objects. An Object is something that can move
Players and Entities are both types of Objects. An object is something that can move
independently of the node grid and has properties such as velocity and scale.
Objects aren't items, and they have their own separate registration system.
@ -235,6 +236,89 @@ use a [chat command](../players/chat.html) to spawn entities:
/spawnentity mymod:entity
## Health and Damage
### HitPoints (HP)
Each object has a HitPoints (HP) number, which represents the current health.
Players have a maximum hp set using the `hp_max` object property.
An object will die if its hp reaches 0.
```lua
local hp = object:get_hp()
object:set_hp(hp + 3)
```
### Punch, Damage Groups, and Armor Groups
Damage is the reduction of an object's HP. An object can *punch* another object to
inflict damage. A punch isn't necessarily an actual punch - it can be an
explosion, a sword slash, or something else.
The total damage is calculated by multiplying the punch's damage groups with the
target's vulnerabilities. This is then limited depending on how recent the last
punch was. We will go over an example of this calculation in a bit.
Just like [node dig groups](../items/nodes_items_crafting.html#tools-capabilities-and-dig-types),
these groups can take any name and do not need to be registered. However, it's
common to use the same group names as with node digging.
How vulnerable an object is to particular types of damage depends on its
`armor_groups` [object property](#object-properties). Despite its misleading
name, `armor_groups` specify the percentage damage taken from particular damage
groups, not the resistance. If a damage group is not listed in an object's armor
groups, that object is completely invulnerable to it.
```lua
target:set_properties({
armor_groups = { fleshy = 90, crumbly = 50 },
})
```
In the above example, the object will take 90% of `fleshy` damage and 50% of
`crumbly` damage.
When a player punches an object, the damage groups come from the item they are
currently wielding. In other cases, mods decide which damage groups are used.
### Example Damage Calculation
Let's punch the `target` object:
```lua
local tool_capabilities = {
full_punch_interval = 0.8,
damage_groups = { fleshy = 5, choppy = 10 },
-- This is only used for digging nodes, but is still required
max_drop_level=1,
groupcaps={
fleshy={times={[1]=2.5, [2]=1.20, [3]=0.35}, uses=30, maxlevel=2},
},
}
local time_since_last_punch = tool_capabilities.full_punch_interval
target:punch(object, time_since_last_punch, tool_capabilities)
```
Now, let's work out what the damage will be. The punch's damage groups are
`fleshy=5` and `choppy=10`, and `target` will take 90% damage from fleshy and 0%
from choppy.
First, we multiply the damage groups by the vulnerability and sum the result.
We then multiply by a number between 0 or 1 depending on the `time_since_last_punch`.
```lua
= (5*90/100 + 10*0/100) * limit(time_since_last_punch / full_punch_interval, 0, 1)
= (5*90/100 + 10*0/100) * 1
= 4.5
```
As HP is an integer, the damage is rounded to 5 points.
## Attachments
Attached objects will move when the parent - the object they are attached to -
@ -245,7 +329,7 @@ An object can have an unlimited number of children, but at most one parent.
child:set_attach(parent, bone, position, rotation)
```
An Object's `get_pos()` will always return the global position of the object, no
An object's `get_pos()` will always return the global position of the object, no
matter whether it is attached or not.
`set_attach` takes a relative position, but not as you'd expect.
The attachment position is relative to the parent's origin as scaled up by 10 times.

View File

@ -63,7 +63,7 @@ layout: base
</ul>
<footer>
&copy; 2014-20
&copy; 2014-21
{% if language == "en" %}
| Helpful? Consider
<a href="https://rubenwardy.com/donate/">donating</a>