1
0
mirror of https://gitlab.com/rubenwardy/awards.git synced 2025-06-28 22:26:17 +02:00

9 Commits

Author SHA1 Message Date
8c0bb00b1a Improve documentation 2018-06-14 00:20:30 +01:00
237525b518 Add support for groups in triggers 2018-06-13 22:52:55 +01:00
21e1ce6675 Fix convert_data crash when craft data is missing
Crash occurs when no data for "craft" is available in the old data, fixed with a additional check.
2018-05-31 15:06:56 +01:00
0ae58ad0c3 Fix locked awards not taking difficulty into account 2018-04-17 22:37:09 +01:00
7d462c6aa5 Add difficulty multiplers to default mod awards 2018-04-17 22:29:13 +01:00
f0052386c8 Add award difficulty multipler 2018-04-17 22:25:53 +01:00
08f654cf94 Remove debug prints
Fixes #57
2018-04-17 22:10:40 +01:00
3fc12eb689 Update README.md 2018-04-06 22:12:56 +01:00
98fca7914b Add on_unlock() documentation 2018-04-06 22:11:08 +01:00
5 changed files with 342 additions and 124 deletions

346
README.md
View File

@ -7,96 +7,223 @@ With thanks to Wuzzy, kaeza, and MrIbby.
Majority of awards are back ported from Calinou's old fork in Carbone, under same license. Majority of awards are back ported from Calinou's old fork in Carbone, under same license.
# API
## Registering Awards
# Introduction
## Awards and Triggers
An award is a single unlockable unit, registered like so:
```lua ```lua
awards.register_award("mymod:myaward", { awards.register_award("mymod:award", {
description = "The title of the award", description = "My Example Award",
})
```
-- Optional: 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:
requires = { "amod:an_award" }, -- don't show this award or allow it to be unlocked ```lua
-- until required awards are unlocked awards.register_award("mymod:award", {
description = "My Example Award",
sound = {}, -- SimpleSoundSpec or false to play no sound trigger = {
-- if not provided, uses default sound type = "dig",
image = "icon_image.png", -- uses default icon otherwise node = "default:stone",
background = "background_image.png", -- uses default background otherwise target = 10,
trigger = { -- is only unlocked by direct calls to awards.unlock() otherwise
type = "trigger_type",
-- see specific docs on the trigger to see what else goes here
}, },
}) })
``` ```
## Registering Trigger Types 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 ```lua
local trigger = awards.register_trigger(name, { awards.register_award("mymod:award", {
type = "", -- type of trigger, defaults to custom description = "Place 10 nodes!",
trigger = {
progress = "%2/%2" type = "place",
auto_description = { "Mine: @2", "Mine: @1×@2" }, target = 10,
},
on_register = function(self, def) end,
-- "counted_key" only, when no key is given (ie: a total)
auto_description_total = { "Mine @1 block.", "Mine @1 blocks." },
-- "counted_key" only, get key for particular award - return nil for a total
get_key = function(self, def)
return minetest.registered_aliases[def.trigger.node] or def.trigger.node
end,
}) })
``` ```
Types: You can also register an *Unlock Function*, which can return the name of an
award to unlock it:
* "custom" requires you handle the calling of awards.unlock() yourself. You also ```lua
need to implement on_register() yourself. awards.register_award("mymod:award", {
* "counted" stores a single counter for each player which is incremented by calling title = "Lava Miner",
trigger:notify(player). Good for homogenous actions like number of chat messages, 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. joins, and the like.
* "counted_key" stores a table of counters each indexed by a key. There is also * **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 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 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. 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 = "counted",
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.
## Helper Functions 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:
* `description` - the title of the award. Required.
* `difficulty` - see [Award Difficulty](#award-difficulty).
* `requires` - list of awards that need to be unlocked before this one
is visible.
* `sound` - `SimpleSoundSpec` table to play on unlock.
`false` to disable unlock sound.
* `image` - 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)) * awards.register_on_unlock(func(name, def))
* name is the player name * name is the player name
* def is the award def. * def is the award def.
* return true to cancel HUD * return true to cancel HUD
* awards.unlock(name, award) * awards.unlock(name, award)
* gives an award to a player * gives an award to a player
* name is the player name * name is the player name
# Included in the Mod ## Builtin Trigger Types
The API, above, allows you to register awards
and triggers (things that look for events and unlock awards, they need
to be registered in order to get details from award_def.trigger).
However, all awards and triggers are separate from the API.
They can be found in init.lua and triggers.lua
## Triggers
Callbacks (register a function to be run) Callbacks (register a function to be run)
"dig", "place", "craft", "death", "chat", "join" or "eat"
* dig type: Dig a node. * dig type: Dig a node.
* node: the dug node type. If nil, all dug nodes are counted * node: the dug node type. If nil, all dug nodes are counted
* place type: Place a node. * place type: Place a node.
* node: the placed node type. If nil, all placed nodes are counted * node: the placed node type. If nil, all placed nodes are counted
* eat type: Eat an item.
* item: the eaten item type. If nil, all eaten items are counted
* craft type: Craft something. * craft type: Craft something.
* item: the crafted item type. If nil, all crafted items are counted * item: the crafted item type. If nil, all crafted items are counted
* death type: Die. * death type: Die.
@ -104,72 +231,81 @@ Callbacks (register a function to be run)
or nil for total deaths. or nil for total deaths.
* chat type: Write a chat message. * chat type: Write a chat message.
* join type: Join the server. * join type: Join the server.
* (for all types) target - how many times to dig/place/craft/etc. * eat type: Eat an item.
* See Triggers * 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 ### dig
trigger = { ```lua
type = "dig", trigger = {
node = "default:dirt", type = "dig",
target = 50, node = "default:dirt", -- item, alias, or group
} target = 50,
}
```
### place ### place
trigger = { ```lua
type = "place", trigger = {
node = "default:dirt", type = "place",
target = 50, node = "default:dirt", -- item, alias, or group
} target = 50,
}
```
### craft
```lua
trigger = {
type = "craft",
node = "default:dirt", -- item, alias, or group
target = 50,
}
```
### death ### death
trigger = { ```lua
type = "death", trigger = {
reason = "fall", type = "death",
target = 5, reason = "fall",
} target = 5,
}
```
### chat ### chat
trigger = { ```lua
type = "chat", trigger = {
target = 100, type = "chat",
} target = 100,
}
```
### join ### join
trigger = { ```lua
type = "join", trigger = {
target = 100, type = "join",
} target = 100,
}
```
### eat ### eat
trigger = { ```lua
type = "eat", trigger = {
item = "default:apple", type = "eat",
target = 100, item = "default:apple",
} target = 100,
}
## Callbacks relating to triggers ```
* awards.register_on_dig(func(player, data))
* data is player data (see below)
* return award name or null
* awards.register_on_place(func(player, data))
* data is player data (see below)
* return award name or null
* awards.register_on_eat(func(player, data))
* data is player data (see below)
* return award name or null
* awards.register_on_death(func(player, data))
* data is player data (see below)
* return award name or null
* awards.register_on_chat(func(player, data))
* data is player data (see below)
* return award name or null
* awards.register_on_join(func(player, data)
* data is player data (see below)
* return award name or null

47
api.lua
View File

@ -51,12 +51,14 @@ local function convert_data()
local ret = {} local ret = {}
local count = 0 local count = 0
for modname, items in pairs(data[from]) do if data[from] then
for itemname, value in pairs(items) do for modname, items in pairs(data[from]) do
itemname = modname .. ":" .. itemname for itemname, value in pairs(items) do
local key = minetest.registered_aliases[itemname] or itemname itemname = modname .. ":" .. itemname
ret[key] = value local key = minetest.registered_aliases[itemname] or itemname
count = count + value ret[key] = value
count = count + value
end
end end
end end
@ -67,8 +69,6 @@ local function convert_data()
awards.players[name] = data awards.players[name] = data
end end
print(dump(awards.players))
end end
function awards.load() function awards.load()
@ -162,7 +162,6 @@ function awards.register_trigger(tname, tdef)
assert(player and player.is_player and player:is_player()) assert(player and player.is_player and player:is_player())
local name = player:get_player_name() local name = player:get_player_name()
local data = awards.player(name) local data = awards.player(name)
print(dump(data))
-- Increment counter -- Increment counter
local currentVal = (data[tname] or 0) + 1 local currentVal = (data[tname] or 0) + 1
@ -179,8 +178,14 @@ function awards.register_trigger(tname, tdef)
awards["notify_" .. tname] = tdef.notify awards["notify_" .. tname] = tdef.notify
elseif tdef.type == "counted_key" then elseif tdef.type == "counted_key" then
if tdef.key_is_item then
tdef.watched_groups = {}
end
-- On award register
local old_reg = tdef.on_register local old_reg = tdef.on_register
function tdef:on_register(def) function tdef:on_register(def)
-- Register trigger
local tmp = { local tmp = {
award = def.name, award = def.name,
key = tdef:get_key(def), key = tdef:get_key(def),
@ -188,6 +193,12 @@ function awards.register_trigger(tname, tdef)
} }
tdef.register(tmp) tdef.register(tmp)
-- If group, add it to watch list
if tdef.key_is_item and tmp.key and tmp.key:sub(1, 6) == "group:" then
tdef.watched_groups[tmp.key:sub(7, #tmp.key)] = true
end
-- Called to get progress values and labels
function def.getProgress(_, data) function def.getProgress(_, data)
local done local done
data[tname] = data[tname] or {} data[tname] = data[tname] or {}
@ -202,6 +213,7 @@ function awards.register_trigger(tname, tdef)
} }
end end
-- Build description if none is specificed by the award
function def.getDefaultDescription(_) function def.getDefaultDescription(_)
local n = def.trigger.target local n = def.trigger.target
if tmp.key then if tmp.key then
@ -214,6 +226,7 @@ function awards.register_trigger(tname, tdef)
end end
end end
-- Call on_register in trigger type definition
if old_reg then if old_reg then
return old_reg(tdef, def) return old_reg(tdef, def)
end end
@ -222,16 +235,28 @@ function awards.register_trigger(tname, tdef)
function tdef.notify(player, key, n) function tdef.notify(player, key, n)
n = n or 1 n = n or 1
if tdef.key_is_item and key:sub(1, 6) ~= "group:" then
local itemdef = minetest.registered_items[key]
if itemdef then
for groupname, _ in pairs(itemdef.groups or {}) do
if tdef.watched_groups[groupname] then
tdef.notify(player, "group:" .. groupname, n)
end
end
end
end
assert(player and player.is_player and player:is_player() and key) assert(player and player.is_player and player:is_player() and key)
local name = player:get_player_name() local name = player:get_player_name()
local data = awards.player(name) local data = awards.player(name)
print(dump(data))
-- Increment counter -- Increment counter
data[tname] = data[tname] or {} data[tname] = data[tname] or {}
local currentVal = (data[tname][key] or 0) + n local currentVal = (data[tname][key] or 0) + n
data[tname][key] = currentVal data[tname][key] = currentVal
data[tname].__total = (data[tname].__total or 0) + n if key:sub(1, 6) ~= "group:" then
data[tname].__total = (data[tname].__total or 0) + n
end
tdef:run_callbacks(player, data, function(entry) tdef:run_callbacks(player, data, function(entry)
local current local current

View File

@ -87,6 +87,7 @@ if minetest.get_modpath("default") then
title = S("Light It Up"), title = S("Light It Up"),
description = S("Place 100 torches."), description = S("Place 100 torches."),
icon = "awards_novicebuilder.png^awards_level1.png", icon = "awards_novicebuilder.png^awards_level1.png",
difficulty = 0.01,
trigger = { trigger = {
type = "place", type = "place",
node = "default:torch", node = "default:torch",
@ -97,8 +98,9 @@ if minetest.get_modpath("default") then
-- Light ALL the things! -- Light ALL the things!
awards.register_award("award_well_lit",{ awards.register_award("award_well_lit",{
title = S("Well Lit"), title = S("Well Lit"),
description = S("Place 1,000 torches."),
icon = "awards_novicebuilder.png^awards_level2.png", icon = "awards_novicebuilder.png^awards_level2.png",
description = S("Place 1,000 torches."),
difficulty = 0.01,
trigger = { trigger = {
type = "place", type = "place",
node = "default:torch", node = "default:torch",
@ -110,6 +112,7 @@ if minetest.get_modpath("default") then
title = S("Really Well Lit"), title = S("Really Well Lit"),
description = S("Craft 10 mese lamps."), description = S("Craft 10 mese lamps."),
icon = "default_meselamp.png", icon = "default_meselamp.png",
difficulty = 0.2,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:meselamp", item = "default:meselamp",
@ -121,6 +124,7 @@ if minetest.get_modpath("default") then
title = S("Outpost"), title = S("Outpost"),
description = S("Craft 200 stone bricks."), description = S("Craft 200 stone bricks."),
icon = "default_stone_brick.png^awards_level1.png", icon = "default_stone_brick.png^awards_level1.png",
difficulty = 0.08,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:stonebrick", item = "default:stonebrick",
@ -132,6 +136,7 @@ if minetest.get_modpath("default") then
title = S("Watchtower"), title = S("Watchtower"),
description = S("Craft 800 stone bricks."), description = S("Craft 800 stone bricks."),
icon = "default_stone_brick.png^awards_level2.png", icon = "default_stone_brick.png^awards_level2.png",
difficulty = 0.08,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:stonebrick", item = "default:stonebrick",
@ -143,6 +148,7 @@ if minetest.get_modpath("default") then
title = S("Fortress"), title = S("Fortress"),
description = S("Craft 3,200 stone bricks."), description = S("Craft 3,200 stone bricks."),
icon = "default_stone_brick.png^awards_level3.png", icon = "default_stone_brick.png^awards_level3.png",
difficulty = 0.08,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:stonebrick", item = "default:stonebrick",
@ -154,6 +160,7 @@ if minetest.get_modpath("default") then
title = S("Desert Dweller"), title = S("Desert Dweller"),
description = S("Craft 400 desert stone bricks."), description = S("Craft 400 desert stone bricks."),
icon = "default_desert_stone_brick.png", icon = "default_desert_stone_brick.png",
difficulty = 0.09,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:desert_stonebrick", item = "default:desert_stonebrick",
@ -165,6 +172,7 @@ if minetest.get_modpath("default") then
title = S("Pharaoh"), title = S("Pharaoh"),
description = S("Craft 100 sandstone bricks."), description = S("Craft 100 sandstone bricks."),
icon = "default_sandstone_brick.png", icon = "default_sandstone_brick.png",
difficulty = 0.09,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:sandstonebrick", item = "default:sandstonebrick",
@ -176,6 +184,7 @@ if minetest.get_modpath("default") then
title = S("Little Library"), title = S("Little Library"),
description = S("Craft 7 bookshelves."), description = S("Craft 7 bookshelves."),
icon = "default_bookshelf.png", icon = "default_bookshelf.png",
difficulty = 0.2,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:bookshelf", item = "default:bookshelf",
@ -188,6 +197,7 @@ if minetest.get_modpath("default") then
description = S("Mine your first obsidian."), description = S("Mine your first obsidian."),
icon = "default_obsidian.png^awards_level1.png", icon = "default_obsidian.png^awards_level1.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 1.5,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:obsidian", node = "default:obsidian",
@ -201,6 +211,7 @@ if minetest.get_modpath("default") then
description = S("Mine 50 obsidian."), description = S("Mine 50 obsidian."),
icon = "default_obsidian.png^awards_level2.png", icon = "default_obsidian.png^awards_level2.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 1.5,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:obsidian", node = "default:obsidian",
@ -214,6 +225,7 @@ if minetest.get_modpath("default") then
description = S("Mine any block while being very close to lava."), description = S("Mine any block while being very close to lava."),
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
icon = "default_lava.png", icon = "default_lava.png",
difficulty = 1,
}) })
awards.register_on_dig(function(player,data) awards.register_on_dig(function(player,data)
local pos = player:get_pos() local pos = player:get_pos()
@ -229,6 +241,7 @@ if minetest.get_modpath("default") then
title = S("On The Way"), title = S("On The Way"),
description = S("Place 100 rails."), description = S("Place 100 rails."),
icon = "carts_rail_straight.png", icon = "carts_rail_straight.png",
difficulty = 0.1,
trigger = { trigger = {
type = "place", type = "place",
node = "default:rail", node = "default:rail",
@ -240,6 +253,7 @@ if minetest.get_modpath("default") then
title = S("First Day in the Woods"), title = S("First Day in the Woods"),
description = S("Dig 6 tree blocks."), description = S("Dig 6 tree blocks."),
icon = "default_tree.png^awards_level1.png", icon = "default_tree.png^awards_level1.png",
difficulty = 0.03,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:tree", node = "default:tree",
@ -252,6 +266,7 @@ if minetest.get_modpath("default") then
title = S("Lumberjack"), title = S("Lumberjack"),
description = S("Dig 36 tree blocks."), description = S("Dig 36 tree blocks."),
icon = "default_tree.png^awards_level2.png", icon = "default_tree.png^awards_level2.png",
difficulty = 0.03,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:tree", node = "default:tree",
@ -264,6 +279,7 @@ if minetest.get_modpath("default") then
title = S("Semi-pro Lumberjack"), title = S("Semi-pro Lumberjack"),
description = S("Dig 216 tree blocks."), description = S("Dig 216 tree blocks."),
icon = "default_tree.png^awards_level3.png", icon = "default_tree.png^awards_level3.png",
difficulty = 0.03,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:tree", node = "default:tree",
@ -276,6 +292,7 @@ if minetest.get_modpath("default") then
title = S("Professional Lumberjack"), title = S("Professional Lumberjack"),
description = S("Dig 1,296 tree blocks."), description = S("Dig 1,296 tree blocks."),
icon = "default_tree.png^awards_level4.png", icon = "default_tree.png^awards_level4.png",
difficulty = 0.03,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:tree", node = "default:tree",
@ -288,6 +305,7 @@ if minetest.get_modpath("default") then
title = S("Junglebaby"), title = S("Junglebaby"),
description = S("Dig 100 jungle tree blocks."), description = S("Dig 100 jungle tree blocks."),
icon = "default_jungletree.png^awards_level1.png", icon = "default_jungletree.png^awards_level1.png",
difficulty = 0.05,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:jungletree", node = "default:jungletree",
@ -300,6 +318,7 @@ if minetest.get_modpath("default") then
title = S("Jungleman"), title = S("Jungleman"),
description = S("Dig 1,000 jungle tree blocks."), description = S("Dig 1,000 jungle tree blocks."),
icon = "default_jungletree.png^awards_level2.png", icon = "default_jungletree.png^awards_level2.png",
difficulty = 0.05,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:jungletree", node = "default:jungletree",
@ -313,6 +332,7 @@ if minetest.get_modpath("default") then
description = S("Mine your first mese ore."), description = S("Mine your first mese ore."),
icon = "default_stone.png^default_mineral_mese.png", icon = "default_stone.png^default_mineral_mese.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 1,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone_with_mese", node = "default:stone_with_mese",
@ -327,6 +347,7 @@ if minetest.get_modpath("default") then
description = S("Mine a mese block."), description = S("Mine a mese block."),
icon = "default_mese_block.png", icon = "default_mese_block.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 1.1,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:mese", node = "default:mese",
@ -340,6 +361,7 @@ if minetest.get_modpath("default") then
description = S("Dig 1,000 copper ores."), description = S("Dig 1,000 copper ores."),
icon = "default_stone.png^default_mineral_copper.png", icon = "default_stone.png^default_mineral_copper.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 0.2,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone_with_copper", node = "default:stone_with_copper",
@ -353,6 +375,7 @@ if minetest.get_modpath("default") then
description = S("Dig 100 stone blocks."), description = S("Dig 100 stone blocks."),
icon = "awards_miniminer.png^awards_level1.png", icon = "awards_miniminer.png^awards_level1.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 0.02,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone", node = "default:stone",
@ -366,6 +389,7 @@ if minetest.get_modpath("default") then
description = S("Dig 1,000 stone blocks."), description = S("Dig 1,000 stone blocks."),
icon = "awards_miniminer.png^awards_level2.png", icon = "awards_miniminer.png^awards_level2.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 0.02,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone", node = "default:stone",
@ -379,6 +403,7 @@ if minetest.get_modpath("default") then
description = S("Dig 10,000 stone blocks."), description = S("Dig 10,000 stone blocks."),
icon = "awards_miniminer.png^awards_level3.png", icon = "awards_miniminer.png^awards_level3.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 0.02,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone", node = "default:stone",
@ -392,6 +417,7 @@ if minetest.get_modpath("default") then
description = S("Dig 1,000 sand."), description = S("Dig 1,000 sand."),
icon = "default_sand.png", icon = "default_sand.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 0.05,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:sand", node = "default:sand",
@ -403,6 +429,7 @@ if minetest.get_modpath("default") then
title = S("Crafter of Sticks"), title = S("Crafter of Sticks"),
description = S("Craft 100 sticks."), description = S("Craft 100 sticks."),
icon = "default_stick.png", icon = "default_stick.png",
difficulty = 0.01,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:stick", item = "default:stick",
@ -414,6 +441,7 @@ if minetest.get_modpath("default") then
title = S("Jungle Discoverer"), title = S("Jungle Discoverer"),
description = S("Mine your first jungle grass."), description = S("Mine your first jungle grass."),
icon = "default_junglegrass.png", icon = "default_junglegrass.png",
difficulty = 0.009,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:junglegrass", node = "default:junglegrass",
@ -425,6 +453,7 @@ if minetest.get_modpath("default") then
title = S("Grasslands Discoverer"), title = S("Grasslands Discoverer"),
description = S("Mine some grass."), description = S("Mine some grass."),
icon = "default_grass_3.png", icon = "default_grass_3.png",
difficulty = 0.009,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:grass_1", node = "default:grass_1",
@ -436,6 +465,7 @@ if minetest.get_modpath("default") then
title = S("Savannah Discoverer"), title = S("Savannah Discoverer"),
description = S("Mine some dry grass."), description = S("Mine some dry grass."),
icon = "default_dry_grass_3.png", icon = "default_dry_grass_3.png",
difficulty = 0.009,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:dry_grass_3", node = "default:dry_grass_3",
@ -447,6 +477,7 @@ if minetest.get_modpath("default") then
title = S("Desert Discoverer"), title = S("Desert Discoverer"),
description = S("Mine your first cactus."), description = S("Mine your first cactus."),
icon = "default_cactus_side.png", icon = "default_cactus_side.png",
difficulty = 0.03,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:cactus", node = "default:cactus",
@ -458,6 +489,7 @@ if minetest.get_modpath("default") then
title = S("Far Lands"), title = S("Far Lands"),
description = S("Mine your first dry shrub."), description = S("Mine your first dry shrub."),
icon = "default_dry_shrub.png", icon = "default_dry_shrub.png",
difficulty = 0.009,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:dry_shrub", node = "default:dry_shrub",
@ -469,6 +501,7 @@ if minetest.get_modpath("default") then
title = S("Glacier Discoverer"), title = S("Glacier Discoverer"),
description = S("Mine your first ice."), description = S("Mine your first ice."),
icon = "default_ice.png", icon = "default_ice.png",
difficulty = 0.02,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:ice", node = "default:ice",
@ -481,6 +514,7 @@ if minetest.get_modpath("default") then
title = S("Very Simple Snow Man"), title = S("Very Simple Snow Man"),
description = S("Place two snow blocks."), description = S("Place two snow blocks."),
icon = "default_snow.png", icon = "default_snow.png",
difficulty = 0.02,
trigger = { trigger = {
type = "place", type = "place",
node = "default:snowblock", node = "default:snowblock",
@ -493,6 +527,7 @@ if minetest.get_modpath("default") then
description = S("Mine your first gold ore."), description = S("Mine your first gold ore."),
icon = "default_stone.png^default_mineral_gold.png^awards_level1.png", icon = "default_stone.png^default_mineral_gold.png^awards_level1.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 0.9,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone_with_gold", node = "default:stone_with_gold",
@ -505,6 +540,7 @@ if minetest.get_modpath("default") then
description = S("Mine 45 gold ores."), description = S("Mine 45 gold ores."),
icon = "default_stone.png^default_mineral_gold.png^awards_level2.png", icon = "default_stone.png^default_mineral_gold.png^awards_level2.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 0.9,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone_with_gold", node = "default:stone_with_gold",
@ -516,6 +552,7 @@ if minetest.get_modpath("default") then
title = S("Wow, I am Diamonds!"), title = S("Wow, I am Diamonds!"),
description = S("Mine your first diamond ore."), description = S("Mine your first diamond ore."),
icon = "default_stone.png^default_mineral_diamond.png^awards_level1.png", icon = "default_stone.png^default_mineral_diamond.png^awards_level1.png",
difficulty = 1,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone_with_diamond", node = "default:stone_with_diamond",
@ -528,6 +565,7 @@ if minetest.get_modpath("default") then
description = S("Mine 18 diamond ores."), description = S("Mine 18 diamond ores."),
icon = "default_stone.png^default_mineral_diamond.png^awards_level2.png", icon = "default_stone.png^default_mineral_diamond.png^awards_level2.png",
background = "awards_bg_mining.png", background = "awards_bg_mining.png",
difficulty = 1,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:stone_with_diamond", node = "default:stone_with_diamond",
@ -539,6 +577,7 @@ if minetest.get_modpath("default") then
title = S("Hardest Block on Earth"), title = S("Hardest Block on Earth"),
description = S("Craft a diamond block."), description = S("Craft a diamond block."),
icon = "default_diamond_block.png", icon = "default_diamond_block.png",
difficulty = 1.1,
trigger = { trigger = {
type = "craft", type = "craft",
item = "default:diamondblock", item = "default:diamondblock",
@ -550,6 +589,7 @@ if minetest.get_modpath("default") then
title = S("In the Dungeon"), title = S("In the Dungeon"),
description = S("Mine a mossy cobblestone."), description = S("Mine a mossy cobblestone."),
icon = "default_mossycobble.png", icon = "default_mossycobble.png",
difficulty = 0.9,
trigger = { trigger = {
type = "dig", type = "dig",
node = "default:mossycobble", node = "default:mossycobble",
@ -561,6 +601,7 @@ if minetest.get_modpath("default") then
title = S("Smelter"), title = S("Smelter"),
description = S("Craft 10 furnaces."), description = S("Craft 10 furnaces."),
icon = "default_furnace_front.png", icon = "default_furnace_front.png",
difficulty = 0.08,
trigger = { trigger = {
type = "craft", type = "craft",
item= "default:furnace", item= "default:furnace",
@ -572,6 +613,7 @@ if minetest.get_modpath("default") then
title = S("Treasurer"), title = S("Treasurer"),
description = S("Craft 15 chests."), description = S("Craft 15 chests."),
icon = "default_chest_front.png", icon = "default_chest_front.png",
difficulty = 0.08,
trigger = { trigger = {
type = "craft", type = "craft",
item= "default:chest", item= "default:chest",
@ -583,6 +625,7 @@ if minetest.get_modpath("default") then
title = S("Bankier"), title = S("Bankier"),
description = S("Craft 30 locked chests."), description = S("Craft 30 locked chests."),
icon = "default_chest_lock.png", icon = "default_chest_lock.png",
difficulty = 0.08,
trigger = { trigger = {
type = "craft", type = "craft",
item= "default:chest_locked", item= "default:chest_locked",
@ -594,6 +637,7 @@ if minetest.get_modpath("default") then
title = S("Bricker"), title = S("Bricker"),
description = S("Craft 200 brick blocks."), description = S("Craft 200 brick blocks."),
icon = "default_brick.png", icon = "default_brick.png",
difficulty = 0.03,
trigger = { trigger = {
type = "craft", type = "craft",
item= "default:brick", item= "default:brick",
@ -605,6 +649,7 @@ if minetest.get_modpath("default") then
title = S("House of Obsidian"), title = S("House of Obsidian"),
description = S("Craft 100 obsidian bricks."), description = S("Craft 100 obsidian bricks."),
icon = "default_obsidian_brick.png", icon = "default_obsidian_brick.png",
difficulty = 0.4,
trigger = { trigger = {
type = "craft", type = "craft",
item= "default:obsidianbrick", item= "default:obsidianbrick",
@ -616,6 +661,7 @@ if minetest.get_modpath("default") then
title = S("Build a Cave"), title = S("Build a Cave"),
description = S("Place 100 stone."), description = S("Place 100 stone."),
icon = "default_stone.png", icon = "default_stone.png",
difficulty = 0.1,
trigger = { trigger = {
type = "place", type = "place",
node = "default:stone", node = "default:stone",
@ -627,6 +673,7 @@ if minetest.get_modpath("default") then
title = S("Long Ladder"), title = S("Long Ladder"),
description = S("Place 400 wooden ladders."), description = S("Place 400 wooden ladders."),
icon = "default_ladder_wood.png", icon = "default_ladder_wood.png",
difficulty = 0.1,
trigger = { trigger = {
type = "place", type = "place",
node = "default:ladder_wood", node = "default:ladder_wood",
@ -638,6 +685,7 @@ if minetest.get_modpath("default") then
title = S("Industrial Age"), title = S("Industrial Age"),
description = S("Place 40 steel ladders."), description = S("Place 40 steel ladders."),
icon = "default_ladder_steel.png", icon = "default_ladder_steel.png",
difficulty = 1,
trigger = { trigger = {
type = "place", type = "place",
node = "default:ladder_steel", node = "default:ladder_steel",
@ -649,6 +697,7 @@ if minetest.get_modpath("default") then
title = S("Yummy!"), title = S("Yummy!"),
description = S("Eat 80 apples."), description = S("Eat 80 apples."),
icon = "default_apple.png", icon = "default_apple.png",
difficulty = 0.1,
trigger = { trigger = {
type = "eat", type = "eat",
item = "default:apple", item = "default:apple",

10
gui.lua
View File

@ -13,9 +13,13 @@ local function order_awards(name)
if def then if def then
hash_is_unlocked[awardname] = true hash_is_unlocked[awardname] = true
local score = -100000 local score = -100000
local difficulty = def.difficulty or 1
if def.trigger and def.trigger.target then if def.trigger and def.trigger.target then
score = score + def.trigger.target difficulty = difficulty * def.trigger.target
end end
score = score + difficulty
retval[#retval + 1] = { retval[#retval + 1] = {
name = awardname, name = awardname,
def = def, def = def,
@ -30,12 +34,12 @@ local function order_awards(name)
for _, def in pairs(awards.registered_awards) do for _, def in pairs(awards.registered_awards) do
if not hash_is_unlocked[def.name] and def:can_unlock(data) then if not hash_is_unlocked[def.name] and def:can_unlock(data) then
local started = false local started = false
local score local score = def.difficulty or 1
if def.secret then if def.secret then
score = 1000000 score = 1000000
elseif def.trigger and def.trigger.target and def.getProgress then elseif def.trigger and def.trigger.target and def.getProgress then
local progress = def:getProgress(data).perc local progress = def:getProgress(data).perc
score = (1 - progress) * def.trigger.target score = score * (1 - progress) * def.trigger.target
if progress < 0.001 then if progress < 0.001 then
score = score + 100 score = score + 100
else else

View File

@ -64,7 +64,8 @@ awards.register_trigger("dig", {
auto_description_total = { "Mine @1 block.", "Mine @1 blocks." }, auto_description_total = { "Mine @1 block.", "Mine @1 blocks." },
get_key = function(self, def) get_key = function(self, def)
return minetest.registered_aliases[def.trigger.node] or def.trigger.node return minetest.registered_aliases[def.trigger.node] or def.trigger.node
end end,
key_is_item = true,
}) })
minetest.register_on_dignode(function(pos, node, player) minetest.register_on_dignode(function(pos, node, player)
if not player or not pos or not node then if not player or not pos or not node then
@ -84,7 +85,8 @@ awards.register_trigger("place", {
auto_description_total = { "Place @1 block.", "Place @1 blocks." }, auto_description_total = { "Place @1 block.", "Place @1 blocks." },
get_key = function(self, def) get_key = function(self, def)
return minetest.registered_aliases[def.trigger.node] or def.trigger.node return minetest.registered_aliases[def.trigger.node] or def.trigger.node
end end,
key_is_item = true,
}) })
minetest.register_on_placenode(function(pos, node, player) minetest.register_on_placenode(function(pos, node, player)
if not player or not pos or not node then if not player or not pos or not node then
@ -104,7 +106,8 @@ awards.register_trigger("craft", {
auto_description_total = { "Craft @1 item", "Craft @1 items." }, auto_description_total = { "Craft @1 item", "Craft @1 items." },
get_key = function(self, def) get_key = function(self, def)
return minetest.registered_aliases[def.trigger.item] or def.trigger.item return minetest.registered_aliases[def.trigger.item] or def.trigger.item
end end,
key_is_item = true,
}) })
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv) minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
if not player or itemstack:is_empty() then if not player or itemstack:is_empty() then
@ -124,7 +127,8 @@ awards.register_trigger("eat", {
auto_description_total = { "Eat @1 item", "Eat @1 items." }, auto_description_total = { "Eat @1 item", "Eat @1 items." },
get_key = function(self, def) get_key = function(self, def)
return minetest.registered_aliases[def.trigger.item] or def.trigger.item return minetest.registered_aliases[def.trigger.item] or def.trigger.item
end end,
key_is_item = true,
}) })
minetest.register_on_item_eat(function(_, _, itemstack, player, _) minetest.register_on_item_eat(function(_, _, itemstack, player, _)
if not player or itemstack:is_empty() then if not player or itemstack:is_empty() then