summaryrefslogtreecommitdiff
path: root/README.md
blob: e570f0e63b20225ac63cef3d7c9dc923d54bf361 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# Awards

Adds awards/achievements to Minetest (plus a very good API).

by [rubenwardy](https://rubenwardy.com), licensed under MIT.
With thanks to Wuzzy, kaeza, and MrIbby.

Majority of awards are back ported from Calinou's old fork in Carbone, under same license.


# Introduction

## Awards and Triggers

An award is a single unlockable unit, registered like so:

```lua
awards.register_award("mymod:award", {
	description = "My Example Award",
})
```

Awards are unlocked either using `awards.unlock()` or by a trigger being
fullfilled. A trigger is a condition which unlocks an award. Triggers are
registered at the same time as an award is registered:

```lua
awards.register_award("mymod:award", {
	description = "My Example Award",
	trigger = {
		type   = "dig",
		node   = "default:stone",
		target = 10,
	},
})
```

The above trigger type is an example of a counted_key trigger:
rather than a single counter there's a counter per key - in this
case the key is the value of the `node` field. If you leave out
the key in a `counted_key` trigger, then the total will be used
instead. For example, here is an award which unlocks after you've
placed 10 nodes of any type:

```lua
awards.register_award("mymod:award", {
	description = "Place 10 nodes!",
	trigger = {
		type   = "place",
		target = 10,
	},
})
```

You can also register an *Unlock Function*, which can return the name of an
award to unlock it:

```lua
awards.register_award("mymod:award", {
	title = "Lava Miner",
	description = "Mine any block while being very close to lava.",
})

awards.register_on_dig(function(player, data)
	local pos = player:get_pos()
	if pos and (minetest.find_node_near(pos, 1, "default:lava_source") or
			minetest.find_node_near(pos, 1, "default:lava_flowing")) then
		return "mymod:award"
	end
	return nil
end)
```

The above is a bad example as you don't actually need the stats data given.
It would be better to register a `dignode` callback and call `awards.unlock()`
if the condition is met.

## Trigger Types

The trigger type is used to determine which event will cause the trigger will be
fulfilled. The awards mod comes with a number of predefined types, documented
in [Builtin Trigger Types](#builtin-trigger-types).

Trigger types are registered like so:

```lua
awards.register_trigger("chat", {
	type = "counted",
	progress = "@1/@2 chat messages",
	auto_description = { "Send a chat message", "Chat @1 times" },
})

minetest.register_on_chat_message(function(name, message)
	local player = minetest.get_player_by_name(name)
	if not player or string.find(message, "/")  then
		return
	end
	awards.notify_chat(player)
end)
```

A trigger type has a type as well, which determines how the data is stored and
also how the trigger is fulfilled.

**Trigger Type Types:**

* **custom** requires you handle the calling of awards.unlock() yourself. You also
  need to implement on_register() yourself. You'll also probably want to implement
  `on_register()` to catch awards registered with your trigger type.
* **counted** stores a single counter for each player which is incremented by calling
  `trigger:notify(player)`. Good for homogenous actions like number of chat messages,
  joins, and the like.
* **counted_key** stores a table of counters each indexed by a key. There is also
  a total field (`__total`) which stores the sum of all counters. A counter is
  incremented by calling `trigger:notify(player, key)`. This is good for things like
  placing nodes or crafting items, where the key will be the item or node name.
  If `key` is an item, then you should also add `key_is_item = true` to the
  trigger type definition.

As said, you could use a custom trigger if none of the other ones match your needs.
Here's an example.

```lua
awards.register_trigger("foo", {
	type             = "custom",
	progress         = "@1/@2 foos",
	auto_description = { "Do a foo", "Foo @1 times" },
})

minetest.register_on_foo(function()
	for _, trigger in pairs(awards.on.foo) do
		-- trigger is either a trigger tables or
		--   or an unlock function.

		-- some complex logic
		if condition then
			awards.unlock(trigger)
		end
	end
end)

```

## Award Difficulty

Difficulty is used to determine how awards are sorted in awards lists.

If the award trigger is counted, ie: the trigger requires a `target` property,
then the difficulty multipler is timesd by `target` to get the overall difficulty.
If the award isn't a counted type then the difficulty multiplier is used as the
overal difficulty. Award difficulty affects how awards are sorted in a list -
more difficult awards are further down the list.

In real terms, `difficulty` is a relative difficulty to do one unit of the trigger
if its counted, otherwise it's the relative difficulty of completely doing the
award (if not-counted). For the `dig` trigger type, 1 unit would be 1 node dug.


Actual code used to calculate award difficulty:

```lua
local difficulty = def.difficulty or 1
if def.trigger and def.trigger.target then
	difficulty = difficulty * def.trigger.target
end
```


# API

* awards.register_award(name, def), the def table has the following fields:
	* `title` - title of the award (defaults to name)
	* `description` - longer description of the award, displayed in Awards tab
	* `difficulty` - see [Award Difficulty](#award-difficulty).
	* `requires` - list of awards that need to be unlocked before this one
		is visible.
	* `prizes` - list of items to give when you earn the award
	* `secret` - boolean if this award is secret (i.e. showed on awards list)
	* `sound` - `SimpleSoundSpec` table to play on unlock.
		`false` to disable unlock sound.
	* `icon` - the icon image, use default otherwise.
	* `background` - the background image, use default otherwise.
	* `trigger` - trigger definition, see [Builtin Trigger Types](#builtin-trigger-types).
	* `on_unlock(name, def)` - callback on unlock.
* awards.register_trigger(name, def), the def table has the following fields:
	* `type` - see [Trigger Types](#trigger-types).
	* `progress` - used to format progress, defaults to "%1/%2".
	* `auto_description` - a table of two elements. Each element is a format string. Element 1 is singular, element 2 is plural. Used for the award description (not title) if none is given.
	* `on_register(award_def)` - called when an award registers with this type.
	* "counted_key" only:
		* `auto_description_total` - Used if the trigger is for the total.
		* `get_key(self, def)` - get key for particular award, return nil for a total.
		* `key_is_item` - true if the key is an item name. On notify(),
			any watched groups will also be notified as `group:groupname` keys.
* awards.register_on_unlock(func(name, def))
	* name is the player name
	* def is the award def.
	* return true to cancel HUD
* awards.unlock(name, award)
	* gives an award to a player
	* name is the player name

## Builtin Trigger Types

Callbacks (register a function to be run)

* dig type: Dig a node.
	* node: the dug node type. If nil, all dug nodes are counted
* place type: Place a node.
	* node: the placed node type. If nil, all placed nodes are counted
* craft type: Craft something.
	* item: the crafted item type. If nil, all crafted items are counted
* death type: Die.
	* reason: the death reason, one of the types in PlayerHPChangeReason (see lua_api.txt)
				or nil for total deaths.
* chat type: Write a chat message.
* join type: Join the server.
* eat type: Eat an item.
	* item: the eaten item type. If nil, all eaten items are counted

(for all types) target - how many times to dig/place/craft/etc.

Each type has a register function like so:

* awards.register_on_TRIGGERTYPE(func(player, data))
	* data is the player stats data
	* return award name or null

### dig

```lua
trigger = {
	type   = "dig",
	node   = "default:dirt", -- item, alias, or group
	target = 50,
}
```

### place

```lua
trigger = {
	type   = "place",
	node   = "default:dirt", -- item, alias, or group
	target = 50,
}
```

### craft

```lua
trigger = {
	type   = "craft",
	item   = "default:dirt", -- item, alias, or group
	target = 50,
}
```

### death

```lua
trigger = {
	type   = "death",
	reason = "fall",
	target = 5,
}
```

### chat

```lua
trigger = {
	type   = "chat",
	target = 100,
}
```

### join

```lua
trigger = {
	type   = "join",
	target = 100,
}
```

### eat

```lua
trigger = {
	type   = "eat",
	item   = "default:apple",
	target = 100,
}
```