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

18 Commits

Author SHA1 Message Date
fb1670abc6 Fix typo in documentation for craft trigger 2018-09-14 10:59:59 +01:00
38b7d9aa91 Fix progress exceeding target 2018-09-14 10:55:55 +01:00
805720b4af Fix sfinv page not updating on award unlock 2018-09-13 17:39:52 +01:00
29a1b97b38 Improve code structure and awards formspec size 2018-09-13 17:33:04 +01:00
b856aea54d Fix typo in custom trigger type example 2018-08-22 15:26:24 +01:00
570fd3a206 Fix incorrect description documentation 2018-08-22 15:19:38 +01:00
417ac0fe46 Fix mistakes in award definition documentation 2018-08-22 15:17:14 +01:00
1ab08d68c9 Add portuguese translations 2018-08-03 12:35:18 +01:00
32150bdd66 Fix crash for invalid award index selection 2018-07-15 13:17:06 +01:00
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
12 changed files with 1714 additions and 677 deletions

302
README.md
View File

@ -7,96 +7,207 @@ 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 = "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.
## 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:
* `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)) * 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 +215,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
trigger = {
type = "dig", type = "dig",
node = "default:dirt", node = "default:dirt", -- item, alias, or group
target = 50, target = 50,
} }
```
### place ### place
trigger = { ```lua
trigger = {
type = "place", type = "place",
node = "default:dirt", node = "default:dirt", -- item, alias, or group
target = 50, target = 50,
} }
```
### craft
```lua
trigger = {
type = "craft",
item = "default:dirt", -- item, alias, or group
target = 50,
}
```
### death ### death
trigger = { ```lua
trigger = {
type = "death", type = "death",
reason = "fall", reason = "fall",
target = 5, target = 5,
} }
```
### chat ### chat
trigger = { ```lua
trigger = {
type = "chat", type = "chat",
target = 100, target = 100,
} }
```
### join ### join
trigger = { ```lua
trigger = {
type = "join", type = "join",
target = 100, target = 100,
} }
```
### eat ### eat
trigger = { ```lua
trigger = {
type = "eat", type = "eat",
item = "default:apple", item = "default:apple",
target = 100, 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

504
api.lua
View File

@ -1,504 +0,0 @@
-- Copyright (c) 2013-18 rubenwardy. MIT.
local S, NS = awards.gettext, awards.ngettext
awards.registered_awards = {}
awards.on = {}
awards.on_unlock = {}
local storage = minetest.get_mod_storage()
-- Table Save Load Functions
function awards.save()
storage:set_string("player_data", minetest.write_json(awards.players))
end
local function convert_data()
minetest.log("warning", "Importing awards data from previous version")
local old_players = awards.players
awards.players = {}
for name, data in pairs(old_players) do
while name.name do
name = name.name
end
data.name = name
print("Converting data for " .. name)
-- Just rename counted
local counted = {
chats = "chat",
deaths = "death",
joins = "join",
}
for from, to in pairs(counted) do
data[to] = data[from]
data[from] = nil
end
data.death = {
unknown = data.death,
__total = data.death,
}
-- Convert item db to new format
local counted_items = {
count = "dig",
place = "place",
craft = "craft",
}
for from, to in pairs(counted_items) do
local ret = {}
local count = 0
for modname, items in pairs(data[from]) do
for itemname, value in pairs(items) do
itemname = modname .. ":" .. itemname
local key = minetest.registered_aliases[itemname] or itemname
ret[key] = value
count = count + value
end
end
ret.__total = count
data[from] = nil
data[to] = ret
end
awards.players[name] = data
end
print(dump(awards.players))
end
function awards.load()
local old_save_path = minetest.get_worldpath().."/awards.txt"
local file = io.open(old_save_path, "r")
if file then
local table = minetest.deserialize(file:read("*all"))
if type(table) == "table" then
awards.players = table
convert_data()
else
awards.players = {}
end
file:close()
os.rename(old_save_path, minetest.get_worldpath().."/awards.bk.txt")
awards.save()
else
awards.players = minetest.parse_json(storage:get_string("player_data")) or {}
end
end
function awards.player(name)
assert(type(name) == "string")
local data = awards.players[name] or {}
awards.players[name] = data
data.name = data.name or name
data.unlocked = data.unlocked or {}
return data
end
function awards.player_or_nil(name)
return awards.players[name]
end
local default_def = {}
function default_def:run_callbacks(player, data, table_func)
for i = 1, #self.on do
local res = nil
local entry = self.on[i]
if type(entry) == "function" then
res = entry(player, data)
elseif type(entry) == "table" and entry.award then
res = table_func(entry)
end
if res then
awards.unlock(player:get_player_name(), res)
end
end
end
function awards.register_trigger(tname, tdef)
assert(type(tdef) == "table",
"Passing a callback to register_trigger is not supported in 3.0")
tdef.name = tname
for key, value in pairs(default_def) do
tdef[key] = value
end
if tdef.type == "counted" then
local old_reg = tdef.on_register
function tdef:on_register(def)
local tmp = {
award = def.name,
target = def.trigger.target,
}
tdef.register(tmp)
function def.getProgress(_, data)
local done = data[tname] or 0
return {
perc = done / tmp.target,
label = S(tdef.progress, done, tmp.target),
}
end
function def.getDefaultDescription(_)
local n = def.trigger.target
return NS(tdef.auto_description[1], tdef.auto_description[2], n, n)
end
if old_reg then
return old_reg(tdef, def)
end
end
function tdef.notify(player)
assert(player and player.is_player and player:is_player())
local name = player:get_player_name()
local data = awards.player(name)
print(dump(data))
-- Increment counter
local currentVal = (data[tname] or 0) + 1
data[tname] = currentVal
tdef:run_callbacks(player, data, function(entry)
if entry.target and entry.award and currentVal and
currentVal >= entry.target then
return entry.award
end
end)
end
awards["notify_" .. tname] = tdef.notify
elseif tdef.type == "counted_key" then
local old_reg = tdef.on_register
function tdef:on_register(def)
local tmp = {
award = def.name,
key = tdef:get_key(def),
target = def.trigger.target,
}
tdef.register(tmp)
function def.getProgress(_, data)
local done
data[tname] = data[tname] or {}
if tmp.key then
done = data[tname][tmp.key] or 0
else
done = data[tname].__total or 0
end
return {
perc = done / tmp.target,
label = S(tdef.progress, done, tmp.target),
}
end
function def.getDefaultDescription(_)
local n = def.trigger.target
if tmp.key then
local nname = tmp.key
return NS(tdef.auto_description[1],
tdef.auto_description[2], n, n, nname)
else
return NS(tdef.auto_description_total[1],
tdef.auto_description_total[2], n, n)
end
end
if old_reg then
return old_reg(tdef, def)
end
end
function tdef.notify(player, key, n)
n = n or 1
assert(player and player.is_player and player:is_player() and key)
local name = player:get_player_name()
local data = awards.player(name)
print(dump(data))
-- Increment counter
data[tname] = data[tname] or {}
local currentVal = (data[tname][key] or 0) + n
data[tname][key] = currentVal
data[tname].__total = (data[tname].__total or 0) + n
tdef:run_callbacks(player, data, function(entry)
local current
if entry.key == key then
current = currentVal
elseif entry.key == nil then
current = data[tname].__total
else
return
end
if current >= entry.target then
return entry.award
end
end)
end
awards["notify_" .. tname] = tdef.notify
elseif tdef.type and tdef.type ~= "custom" then
error("Unrecognised trigger type " .. tdef.type)
end
awards.registered_triggers[tname] = tdef
tdef.on = {}
tdef.register = function(func)
table.insert(tdef.on, func)
end
-- Backwards compat
awards.on[tname] = tdef.on
awards['register_on_' .. tname] = tdef.register
return tdef
end
function awards.increment_item_counter(data, field, itemname, count)
itemname = minetest.registered_aliases[itemname] or itemname
data[field][itemname] = (data[field][itemname] or 0) + 1
end
function awards.get_item_count(data, field, itemname)
itemname = minetest.registered_aliases[itemname] or itemname
return data[field][itemname] or 0
end
function awards.get_total_keyed_count(data, field)
return data[field].__total or 0
end
function awards.register_on_unlock(func)
table.insert(awards.on_unlock, func)
end
function awards.register_award(name, def)
def.name = name
-- Add Triggers
if def.trigger and def.trigger.type then
local tdef = awards.registered_triggers[def.trigger.type]
assert(tdef, "Trigger not found: " .. def.trigger.type)
tdef:on_register(def)
end
function def:can_unlock(data)
if not self.requires then
return true
end
for i=1, #self.requires do
if not data.unlocked[self.requires[i]] then
return false
end
end
return true
end
-- Add Award
awards.registered_awards[name] = def
local tdef = awards.registered_awards[name]
if def.description == nil and tdef.getDefaultDescription then
def.description = tdef:getDefaultDescription()
end
end
function awards.enable(name)
local data = awards.player(name)
if data then
data.disabled = nil
end
end
function awards.disable(name)
local data = awards.player(name)
if data then
data.disabled = true
end
end
function awards.clear_player(name)
awards.players[name] = {}
end
-- This function is called whenever a target condition is met.
-- It checks if a player already has that award, and if they do not,
-- it gives it to them
----------------------------------------------
--awards.unlock(name, award)
-- name - the name of the player
-- award - the name of the award to give
function awards.unlock(name, award)
-- Access Player Data
local data = awards.player(name)
local awdef = awards.registered_awards[award]
assert(awdef, "Unable to unlock an award which doesn't exist!")
if data.disabled or
(data.unlocked[award] and data.unlocked[award] == award) then
return
end
if not awdef:can_unlock(data) then
minetest.log("warning", "can_unlock returned false in unlock of " ..
award .. " for " .. name)
return
end
-- Unlock Award
minetest.log("action", name.." has unlocked award "..name)
data.unlocked[award] = award
awards.save()
-- Give Prizes
if awdef and awdef.prizes then
for i = 1, #awdef.prizes do
local itemstack = ItemStack(awdef.prizes[i])
if not itemstack:is_empty() then
local receiverref = minetest.get_player_by_name(name)
if receiverref then
receiverref:get_inventory():add_item("main", itemstack)
end
end
end
end
-- Run callbacks
if awdef.on_unlock and awdef.on_unlock(name, awdef) then
return
end
for _, callback in pairs(awards.on_unlock) do
if callback(name, awdef) then
return
end
end
-- Get Notification Settings
local title = awdef.title or award
local desc = awdef.description or ""
local background = awdef.background or "awards_bg_default.png"
local icon = awdef.icon or "awards_unknown.png"
local sound = awdef.sound
if sound == nil then
-- Explicit check for nil because sound could be `false` to disable it
sound = {name="awards_got_generic", gain=0.25}
end
-- Do Notification
if sound then
-- Enforce sound delay to prevent sound spamming
local lastsound = data.lastsound
if lastsound == nil or os.difftime(os.time(), lastsound) >= 1 then
minetest.sound_play(sound, {to_player=name})
data.lastsound = os.time()
end
end
if awards.show_mode == "chat" then
local chat_announce
if awdef.secret then
chat_announce = S("Secret Award Unlocked: %s")
else
chat_announce = S("Award Unlocked: %s")
end
-- use the chat console to send it
minetest.chat_send_player(name, string.format(chat_announce, title))
if desc~="" then
minetest.chat_send_player(name, desc)
end
else
local player = minetest.get_player_by_name(name)
local one = player:hud_add({
hud_elem_type = "image",
name = "award_bg",
scale = {x = 2, y = 1},
text = background,
position = {x = 0.5, y = 0.05},
offset = {x = 0, y = 138},
alignment = {x = 0, y = -1}
})
local hud_announce
if awdef.secret then
hud_announce = S("Secret Award Unlocked!")
else
hud_announce = S("Award Unlocked!")
end
local two = player:hud_add({
hud_elem_type = "text",
name = "award_au",
number = 0xFFFFFF,
scale = {x = 100, y = 20},
text = hud_announce,
position = {x = 0.5, y = 0.05},
offset = {x = 0, y = 45},
alignment = {x = 0, y = -1}
})
local three = player:hud_add({
hud_elem_type = "text",
name = "award_title",
number = 0xFFFFFF,
scale = {x = 100, y = 20},
text = title,
position = {x = 0.5, y = 0.05},
offset = {x = 0, y = 100},
alignment = {x = 0, y = -1}
})
local four = player:hud_add({
hud_elem_type = "image",
name = "award_icon",
scale = {x = 4, y = 4},
text = icon,
position = {x = 0.5, y = 0.05},
offset = {x = -200.5, y = 126},
alignment = {x = 0, y = -1}
})
minetest.after(4, function()
local player2 = minetest.get_player_by_name(name)
if player2 then
player2:hud_remove(one)
player2:hud_remove(two)
player2:hud_remove(three)
player2:hud_remove(four)
end
end)
end
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "awards:awards" then
return false
end
if fields.quit then
return true
end
local name = player:get_player_name()
if fields.awards then
local event = minetest.explode_textlist_event(fields.awards)
if event.type == "CHG" then
awards.show_to(name, name, event.index, false)
end
end
return true
end)
awards.load()
minetest.register_on_shutdown(function()
awards.save()
end)

View File

@ -7,14 +7,20 @@ awards = {
} }
-- Internationalization support. -- Internationalization support.
awards.gettext, awards.ngettext = dofile(minetest.get_modpath("awards").."/intllib.lua") awards.gettext, awards.ngettext = dofile(minetest.get_modpath("awards").."/src/intllib.lua")
-- Load files -- Load files
dofile(minetest.get_modpath("awards").."/api.lua") dofile(minetest.get_modpath("awards").."/src/data.lua")
dofile(minetest.get_modpath("awards").."/chat_commands.lua") dofile(minetest.get_modpath("awards").."/src/api_awards.lua")
dofile(minetest.get_modpath("awards").."/gui.lua") dofile(minetest.get_modpath("awards").."/src/api_triggers.lua")
dofile(minetest.get_modpath("awards").."/triggers.lua") dofile(minetest.get_modpath("awards").."/src/chat_commands.lua")
dofile(minetest.get_modpath("awards").."/awards.lua") dofile(minetest.get_modpath("awards").."/src/gui.lua")
dofile(minetest.get_modpath("awards").."/src/triggers.lua")
dofile(minetest.get_modpath("awards").."/src/awards.lua")
awards.load()
minetest.register_on_shutdown(awards.save)
-- Backwards compatibility -- Backwards compatibility
awards.give_achievement = awards.unlock awards.give_achievement = awards.unlock

819
locale/pt.po Normal file
View File

@ -0,0 +1,819 @@
# Portuguese translations for Awards package.
# Copyright (C) 2018
# This file is distributed under the same license as the Awards package.
# FIRST AUTHOR borgesdossantosbruno@gmail.com, 2018.
# BrunoMine, 2018
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-21 05:50-0300\n"
"PO-Revision-Date: 2018-08-01 16:16-0300\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.0.6\n"
"Last-Translator: BrunoMine\n"
"Language: pt\n"
#: api.lua
msgid "Secret Achievement Unlocked:"
msgstr "Conquista Secreta Desbloqueada:"
#: api.lua
msgid "Achievement Unlocked:"
msgstr "Conquista Desbloqueada:"
#: api.lua
#, lua-format
msgid "Secret Achievement Unlocked: %s"
msgstr "Conquista Secreta Desbloqueada: %s"
#: api.lua
#, lua-format
msgid "Achievement Unlocked: %s"
msgstr "Conquista Desbloqueada: %s"
#: api.lua
msgid "Secret Achievement Unlocked!"
msgstr "Conquista Secreta Desbloqueada!"
#: api.lua
msgid "Achievement Unlocked!"
msgstr "Conquista Desbloqueada!"
#: api.lua
msgid "Error: No awards available."
msgstr "Erro: Nenhuma conquista encontrada."
#: api.lua
msgid "OK"
msgstr "OK"
#: api.lua
msgid "(Secret Award)"
msgstr "(Conquista Secreta)"
#: api.lua
msgid "Unlock this award to find out what it is."
msgstr "Desbloqueie essa conquista para descobrir o que significa."
#: api.lua
#, lua-format
msgid "%s (got)"
msgstr "%s (obtido)"
#: api.lua
msgid "You've disabled awards. Type /awards enable to reenable."
msgstr "Desabilitaste as conquistas. Digite /awards enable para reabilitar."
#: api.lua
msgid "You have not unlocked any awards."
msgstr "Nenhuma conquista desbloqueada ainda."
#: api.lua
#, lua-format
msgid "%ss awards:"
msgstr "%s das conquistas:"
#: api.lua chat_commands.lua
#, lua-format
msgid "%s: %s"
msgstr "%s: %s"
#: sfinv.lua unified_inventory.lua
msgid "Awards"
msgstr "Conquistas"
#: triggers.lua
msgid "@1/@2 dug"
msgstr "@1 de @2 obtidos"
#. Translators: @1 is count, @2 is description.
#: triggers.lua
msgid "Mine: @2"
msgid_plural "Mine: @1×@2"
msgstr[0] "Cavar: @2"
msgstr[1] "Minar: @1×@2"
#: triggers.lua
msgid "Mine @1 block."
msgid_plural "Mine @1 blocks."
msgstr[0] "Cavar um bloco."
msgstr[1] "Cavar @1 blocos."
#: triggers.lua
msgid "@1/@2 placed"
msgstr "@1 de @2 colocados"
#. Translators: @1 is count, @2 is description.
#: triggers.lua
msgid "Place: @2"
msgid_plural "Place: @1×@2"
msgstr[0] "Colocar: @2"
msgstr[1] "Place: @1×@2"
#: triggers.lua
msgid "Place a block."
msgid_plural "Place @1 blocks."
msgstr[0] "Colocar um bloco."
msgstr[1] "Colocar @1 blocos."
#: triggers.lua
msgid "@1/@2 eaten"
msgstr "@1 de @2 consumidos"
#. Translators: @1 is count, @2 is description.
#: triggers.lua
msgid "Eat: @2"
msgid_plural "Eat: @1×@2"
msgstr[0] "Consumir: @2"
msgstr[1] "Consumir: @1×@2"
#: triggers.lua
msgid "Eat an item."
msgid_plural "Eat @1 items."
msgstr[0] "Consumir um item."
msgstr[1] "Consumir @1 itens."
#: triggers.lua
msgid "@1/@2 deaths"
msgstr "@1 de @2 mortes"
#: triggers.lua
msgid "Die."
msgid_plural "Die @1 times."
msgstr[0] "Morrer."
msgstr[1] "Morrer @1 vezes."
#: triggers.lua
msgid "@1/@2 chat messages"
msgstr "@1 de @2"
#: triggers.lua
msgid "Write something in chat."
msgid_plural "Write @1 chat messages."
msgstr[0] "Escrever algo no bate papo."
msgstr[1] "Escrever @1 mensagens no bate papo."
#: triggers.lua
msgid "@1/@2 game joins"
msgstr "@1 de @2"
#: triggers.lua
msgid "Join the game."
msgid_plural "Join the game @1 times."
msgstr[0] "Entre no jogo."
msgstr[1] "Entre no jogo @1 vezes."
#: triggers.lua
msgid "@1/@2 crafted"
msgstr "@1 de @2 feitos"
#. Translators: @1 is count, @2 is description.
#: triggers.lua
msgid "Craft: @2"
msgid_plural "Craft: @1×@2"
msgstr[0] "Fazer @2"
msgstr[1] "Montar @2 @1 vezes"
#: triggers.lua
msgid "Craft an item."
msgid_plural "Craft @1 items."
msgstr[0] "Fazer um item."
msgstr[1] "Fazer @1 itens."
#: init.lua
msgid "Saint-Maclou"
msgstr "Saint-Maclou"
#: init.lua
msgid "Place 20 coal checkers."
msgstr ""
#: init.lua
msgid "Castorama"
msgstr ""
#: init.lua
msgid "Place 20 iron checkers."
msgstr ""
#: init.lua
msgid "Sam the Trapper"
msgstr ""
#: init.lua
msgid "Place 2 trap stones."
msgstr ""
#: init.lua
msgid "Backpacker"
msgstr ""
#: init.lua
msgid "Craft 4 large bags."
msgstr ""
#: init.lua
msgid "Pyromaniac"
msgstr "Piromaníaco"
#: init.lua
msgid "Craft 8 times flint and steel."
msgstr "Montar acendedor de Ferro e Pederneira 8 vezes."
#: init.lua
msgid "Firefighter"
msgstr "Bombeiro"
#: init.lua
msgid "Put out 1000 fires."
msgstr "Apagar fogo 1000 vezes."
#: init.lua
msgid "Light It Up"
msgstr "Ilumine Isso"
#: init.lua
msgid "Place 100 torches."
msgstr "Colocar 100 tochas."
#: init.lua
msgid "Well Lit"
msgstr "Bem Iluminado"
#: init.lua
msgid "Place 1,000 torches."
msgstr "Colocar 1.000 tochas."
#: init.lua
msgid "Really Well Lit"
msgstr "Realmente Bem Iluminado"
#: init.lua
msgid "Craft 10 mese lamps."
msgstr "Fazer 10 lâmpadas de mese."
#: init.lua
msgid "Outpost"
msgstr "Posto Avançado"
#: init.lua
msgid "Craft 200 stone bricks."
msgstr "Fazer 200 tijolos de pedra."
#: init.lua
msgid "Watchtower"
msgstr "Sentinela"
#: init.lua
msgid "Craft 800 stone bricks."
msgstr "Fazer 800 tijolos de pedra."
#: init.lua
msgid "Fortress"
msgstr "Fortaleza"
#: init.lua
msgid "Craft 3,200 stone bricks."
msgstr "Fazer 3.200 tijolos de pedra."
#: init.lua
msgid "Desert Dweller"
msgstr "Morador do Deserto"
#: init.lua
msgid "Craft 400 desert stone bricks."
msgstr "Fazer 400 Tijolos de pedra do deserto."
#: init.lua
msgid "Pharaoh"
msgstr "Faraó"
#: init.lua
msgid "Craft 100 sandstone bricks."
msgstr "Fazer 100 tijolos de arenito."
#: init.lua
msgid "Little Library"
msgstr "Pequena Biblioteca"
#: init.lua
msgid "Craft 7 bookshelves."
msgstr "Fazer 7 estantes de livros."
#: init.lua
msgid "Lava and Water"
msgstr "Lava e Água"
#: init.lua
msgid "Mine your first obsidian."
msgstr "Cavar sua primeira obsidiana."
#: init.lua
msgid "Obsessed with Obsidian"
msgstr "Obcecado por Obsidiana"
#: init.lua
msgid "Mine 50 obsidian."
msgstr "Minerar 50 obsidianas."
#: init.lua
msgid "Lava Miner"
msgstr "Minerador de Lava"
#: init.lua
msgid "Mine any block while being very close to lava."
msgstr "Minerar qualquer bloco enquanto estiver mergulhado em lava."
#: init.lua
msgid "On The Way"
msgstr "No Caminho"
#: init.lua
msgid "Place 100 rails."
msgstr "Colocar 100 trilhos."
#: init.lua
msgid "First Day in the Woods"
msgstr "Primeiro dia na Floresta"
#: init.lua
msgid "Dig 6 tree blocks."
msgstr "Cortar 6 blocos de árvore."
#: init.lua
msgid "Lumberjack"
msgstr "Lenhador"
#: init.lua
msgid "Dig 36 tree blocks."
msgstr "Cortar 36 blocos de árvore."
#: init.lua
msgid "Semi-pro Lumberjack"
msgstr "Lenhador Semi-Profissional"
#: init.lua
msgid "Dig 216 tree blocks."
msgstr "Cortar 216 blocos de árvore."
#: init.lua
msgid "Professional Lumberjack"
msgstr "Lenhador Profissional"
#: init.lua
msgid "Dig 1,296 tree blocks."
msgstr "Cortar 1.296 blocos de árvore."
#: init.lua
msgid "Junglebaby"
msgstr "Bebê Selvagem"
#: init.lua
msgid "Dig 100 jungle tree blocks."
msgstr "Cortar 100 blocos de árvore selvagem."
#: init.lua
msgid "Jungleman"
msgstr "Homem Selvagem"
#: init.lua
msgid "Dig 1,000 jungle tree blocks."
msgstr "Cortar 1.000 blocos de árvore selvagem."
#: init.lua
msgid "First Mese Find"
msgstr "Primeiro Mese"
#: init.lua
msgid "Mine your first mese ore."
msgstr "Cavar seu primeiro mese."
#: init.lua
msgid "Mese Mastery"
msgstr "Mestre do Mese"
#: init.lua
msgid "Mine a mese block."
msgstr "Cavar um bloco de mese."
#: init.lua
msgid "Youre a copper"
msgstr "Sou um Cobre"
#: init.lua
msgid "Dig 1,000 copper ores."
msgstr "Minerar 1.000 cobres."
#: init.lua
msgid "A Cat in a Pop-Tart?!"
msgstr "Um Gato em um Pop-Tart?!"
#: init.lua
msgid "Mine a nyan cat."
msgstr "Capturar um gato nyan."
#: init.lua
msgid "Mini Miner"
msgstr "Mini Minerador"
#: init.lua
msgid "Dig 100 stone blocks."
msgstr "Minerar 100 blocos de pedra."
#: init.lua
msgid "Hardened Miner"
msgstr "Minerador Avançado"
#: init.lua
msgid "Dig 1,000 stone blocks."
msgstr "Minerar 1.000 blocos de pedra."
#: init.lua
msgid "Master Miner"
msgstr "Minerador Mestre"
#: init.lua
msgid "Dig 10,000 stone blocks."
msgstr "Minerar 10.000 blocos de pedra."
#: init.lua
msgid "Marchand De Sable"
msgstr "Vendedor de Areia"
#: init.lua
msgid "Dig 1,000 sand."
msgstr "Cavar 1.000 blocos de areia."
#: init.lua
msgid "Crafter of Sticks"
msgstr "Rachador de Lenha"
#: init.lua
msgid "Craft 100 sticks."
msgstr "Lenhar 100 gravetos."
#: init.lua
msgid "Jungle Discoverer"
msgstr "Desbravador Selvagem"
#: init.lua
msgid "Mine your first jungle grass."
msgstr "Cortar seu primeiro mato selvagem."
#: init.lua
msgid "Grasslands Discoverer"
msgstr "Descobridor do Gramado"
#: init.lua
msgid "Mine some grass."
msgstr "Minerar algum mato"
#: init.lua
msgid "Savannah Discoverer"
msgstr "Descobridor da Savana"
#: init.lua
msgid "Mine some dry grass."
msgstr "Minerar algum mato seco."
#: init.lua
msgid "Desert Discoverer"
msgstr "Descobridor do Deserto"
#: init.lua
msgid "Mine your first cactus."
msgstr "Cortar seu primeiro cacto."
#: init.lua
msgid "Far Lands"
msgstr "Terras Distantes"
#: init.lua
msgid "Mine your first dry shrub."
msgstr "Minerar seu primeiro arbusto seco."
#: init.lua
msgid "Glacier Discoverer"
msgstr "Descobridor Glacial"
#: init.lua
msgid "Mine your first ice."
msgstr "Quebrar seu primeiro bloco de gelo."
#: init.lua
msgid "Very Simple Snow Man"
msgstr "Homem de Neve Muito Simples"
#: init.lua
msgid "Place two snow blocks."
msgstr "Colocar 2 blocos de neve."
#: init.lua
msgid "First Gold Find"
msgstr "Achei Ouro"
#: init.lua
msgid "Mine your first gold ore."
msgstr "Minerar sua primeira de ouro."
#: init.lua
msgid "Gold Rush"
msgstr "Corriga do Ouro"
#: init.lua
msgid "Mine 45 gold ores."
msgstr "Minerar 45 de ouro."
#: init.lua
msgid "Wow, I am Diamonds!"
msgstr "Uau, Diamante!"
#: init.lua
msgid "Mine your first diamond ore."
msgstr "Minerar seu primeiro diamante."
#: init.lua
msgid "Girl's Best Friend"
msgstr "Melhor Amigo da Menina"
#: init.lua
msgid "Mine 18 diamond ores."
msgstr "Minere 18 diamantes."
#: init.lua
msgid "Hardest Block on Earth"
msgstr "O Bloco mais Duro da Terra"
#: init.lua
msgid "Craft a diamond block."
msgstr "Montar um bloco de diamante."
#: init.lua
msgid "In the Dungeon"
msgstr "Na Masmorra"
#: init.lua
msgid "Mine a mossy cobblestone."
msgstr "Minerar um pedregulho com musgo."
#: init.lua
msgid "Smelter"
msgstr "Fundidor"
#: init.lua
msgid "Craft 10 furnaces."
msgstr "Montar 10 fornos."
#: init.lua
msgid "Treasurer"
msgstr "Tesoureiro"
#: init.lua
msgid "Craft 15 chests."
msgstr "Montar 10 baús."
#: init.lua
msgid "Bankier"
msgstr "Banqueiro"
#: init.lua
msgid "Craft 30 locked chests."
msgstr "Montar 30 baús trancados."
#: init.lua
msgid "Bricker"
msgstr "Tijoleiro"
#: init.lua
msgid "Craft 200 brick blocks."
msgstr "Fazer 200 blocos de tijolo."
#: init.lua
msgid "House of Obsidian"
msgstr "Casa de Obsidiana"
#: init.lua
msgid "Craft 100 obsidian bricks."
msgstr "Montar 100 tijolos de obsidiana."
#: init.lua
msgid "Build a Cave"
msgstr "Montar uma Caverna"
#: init.lua
msgid "Place 100 stone."
msgstr "Colocar 100 pedras."
#: init.lua
msgid "Long Ladder"
msgstr "Longa Escadaria"
#: init.lua
msgid "Place 400 wooden ladders."
msgstr "Colocar 400 escadas de madeira."
#: init.lua
msgid "Industrial Age"
msgstr "Era Industrial"
#: init.lua
msgid "Place 40 steel ladders."
msgstr "Colocar 40 escadas de ferro."
#: init.lua
msgid "Yummy!"
msgstr "Humm!"
#: init.lua
msgid "Eat 80 apples."
msgstr "Comer 80 maçãs."
#: init.lua
msgid "Glasser"
msgstr "Vidraceiro"
#: init.lua
msgid "Craft 14 vessels shelves."
msgstr "Montar 14 estantes de frascos."
#: init.lua
msgid "Farming Skills Acquired"
msgstr "Conhecimento de Cultivo Adquirido"
#: init.lua
msgid "Harvest a fully grown wheat plant."
msgstr "Colher um trigo totalmente crescido."
#: init.lua
msgid "Field Worker"
msgstr "Trabalhador do Campo"
#: init.lua
msgid "Harvest 25 fully grown wheat plants."
msgstr "Colher 25 plantas trigos totalmente crescidos."
#: init.lua
msgid "Aspiring Farmer"
msgstr "Fazendeiro Aspirante"
#: init.lua
msgid "Harvest 125 fully grown wheat plants."
msgstr "Colher 125 plantas trigos totalmente crescidos."
#: init.lua
msgid "Wheat Magnate"
msgstr "Magnata do Trigo"
#: init.lua
msgid "Harvest 625 fully grown wheat plants."
msgstr "Colher 625 plantas trigos totalmente crescidos."
#: init.lua
msgid "Baker"
msgstr "Padeiro"
#: init.lua
msgid "Eat 10 loaves of bread."
msgstr "Comer 10 pães."
#: init.lua
msgid "Wool Over Your Eyes"
msgstr "Lã Sobre Meus Olhos"
#: init.lua
msgid "Craft 250 white wool."
msgstr "Tecer 250 lãs branca."
#: init.lua
msgid "Hotelier"
msgstr "Hoteleiro"
#: init.lua
msgid "Craft 15 fancy beds."
msgstr "Montar 15 camas chiques."
#: init.lua
msgid "Filthy Rich"
msgstr "Muito Rico"
#: init.lua
msgid "Craft 24 gold block stairs."
msgstr "Montar 24 escadas de bloco de ouro."
#: init.lua
msgid "Roses Are Red"
msgstr "Rosas São Vermelhas"
#: init.lua
msgid "Craft 400 red dyes."
msgstr "Fazer 400 tintas vermelhas."
#: init.lua
msgid "Dandelions are Yellow"
msgstr "Dentes-de-Leões são Amarelos"
#: init.lua
msgid "Craft 400 yellow dyes."
msgstr "Fazer 400 tintas amarelas."
#: init.lua
msgid "Geraniums are Blue"
msgstr "Gerânios são Azuis"
#: init.lua
msgid "Craft 400 blue dyes."
msgstr "Fazer 400 tintas azuis."
#: init.lua
msgid "White Color Stock"
msgstr "Estoque de Cor Branca"
#: init.lua
msgid "Craft 100 white dyes."
msgstr "Fazer 100 tintas brancas."
#: init.lua
msgid "Tasty Mushrooms"
msgstr "Cogumelos Deliciosos"
#: init.lua
msgid "Eat 3 brown mushrooms."
msgstr "Comer 3 cogumelos marrons."
#: init.lua
msgid "Mushroom Lover"
msgstr "Amante de Cogumelo"
#: init.lua
msgid "Eat 33 brown mushrooms."
msgstr "Comer 33 cogumelos marrons."
#: init.lua
msgid "Underground Mushroom Farmer"
msgstr "Fazendeiro Subterrâneo de Cogumelos"
#: init.lua
msgid "Eat 333 brown mushrooms."
msgstr "Comer 333 cogumelos marrons."
#: init.lua
msgid "Builder"
msgstr "Construtor"
#: init.lua
msgid "Constructor"
msgstr "Empreiteiro"
#: init.lua
msgid "Architect"
msgstr "Arquiteto"
#: init.lua
msgid "Master Architect"
msgstr "Arquiteto Mestre"
#: chat_commands.lua
msgid "[c|clear|disable|enable]"
msgstr "[c|clear|disable|enable]"
#: chat_commands.lua
msgid "Show, clear, disable or enable your achievements"
msgstr "Exibir, limpar, desabilitar ou habilitar suas conquistas"
#: chat_commands.lua
msgid "All your awards and statistics have been cleared. You can now start again."
msgstr "Todas as suas conquistas e estatísticas foram limpas. Agora podes iniciar novamente."
#: chat_commands.lua
msgid "You have disabled your achievements."
msgstr "Suas conquistas foram desabilitadas."
#: chat_commands.lua
msgid "You have enabled your achievements."
msgstr "Suas conquistas foram habilitadas."
#: chat_commands.lua
msgid "<achievement ID>"
msgstr "<ID da conquista>"
#: chat_commands.lua
msgid "Show details of an achievement"
msgstr "Mostra detalhes de uma conquista"
#: chat_commands.lua
msgid "Achievement not found."
msgstr "Conquista não encontrada."
#: chat_commands.lua
msgid "<name>"
msgstr "<jogador>"
#: chat_commands.lua
msgid "Get the achievements statistics for the given player or yourself"
msgstr "Ver as estatísticas de conquistas de um jogador ou suas próprias"

179
src/api_awards.lua Normal file
View File

@ -0,0 +1,179 @@
-- Copyright (c) 2013-18 rubenwardy. MIT.
local S = awards.gettext
function awards.register_award(name, def)
def.name = name
-- Add Triggers
if def.trigger and def.trigger.type then
local tdef = awards.registered_triggers[def.trigger.type]
assert(tdef, "Trigger not found: " .. def.trigger.type)
tdef:on_register(def)
end
function def:can_unlock(data)
if not self.requires then
return true
end
for i=1, #self.requires do
if not data.unlocked[self.requires[i]] then
return false
end
end
return true
end
-- Add Award
awards.registered_awards[name] = def
local tdef = awards.registered_awards[name]
if def.description == nil and tdef.getDefaultDescription then
def.description = tdef:getDefaultDescription()
end
end
-- This function is called whenever a target condition is met.
-- It checks if a player already has that award, and if they do not,
-- it gives it to them
----------------------------------------------
--awards.unlock(name, award)
-- name - the name of the player
-- award - the name of the award to give
function awards.unlock(name, award)
-- Access Player Data
local data = awards.player(name)
local awdef = awards.registered_awards[award]
assert(awdef, "Unable to unlock an award which doesn't exist!")
if data.disabled or
(data.unlocked[award] and data.unlocked[award] == award) then
return
end
if not awdef:can_unlock(data) then
minetest.log("warning", "can_unlock returned false in unlock of " ..
award .. " for " .. name)
return
end
-- Unlock Award
minetest.log("action", name.." has unlocked award "..name)
data.unlocked[award] = award
awards.save()
-- Give Prizes
if awdef and awdef.prizes then
for i = 1, #awdef.prizes do
local itemstack = ItemStack(awdef.prizes[i])
if not itemstack:is_empty() then
local receiverref = minetest.get_player_by_name(name)
if receiverref then
receiverref:get_inventory():add_item("main", itemstack)
end
end
end
end
-- Run callbacks
if awdef.on_unlock and awdef.on_unlock(name, awdef) then
return
end
for _, callback in pairs(awards.on_unlock) do
if callback(name, awdef) then
return
end
end
-- Get Notification Settings
local title = awdef.title or award
local desc = awdef.description or ""
local background = awdef.background or "awards_bg_default.png"
local icon = awdef.icon or "awards_unknown.png"
local sound = awdef.sound
if sound == nil then
-- Explicit check for nil because sound could be `false` to disable it
sound = {name="awards_got_generic", gain=0.25}
end
-- Do Notification
if sound then
-- Enforce sound delay to prevent sound spamming
local lastsound = data.lastsound
if lastsound == nil or os.difftime(os.time(), lastsound) >= 1 then
minetest.sound_play(sound, {to_player=name})
data.lastsound = os.time()
end
end
if awards.show_mode == "chat" then
local chat_announce
if awdef.secret then
chat_announce = S("Secret Award Unlocked: %s")
else
chat_announce = S("Award Unlocked: %s")
end
-- use the chat console to send it
minetest.chat_send_player(name, string.format(chat_announce, title))
if desc~="" then
minetest.chat_send_player(name, desc)
end
else
local player = minetest.get_player_by_name(name)
local one = player:hud_add({
hud_elem_type = "image",
name = "award_bg",
scale = {x = 2, y = 1},
text = background,
position = {x = 0.5, y = 0.05},
offset = {x = 0, y = 138},
alignment = {x = 0, y = -1}
})
local hud_announce
if awdef.secret then
hud_announce = S("Secret Award Unlocked!")
else
hud_announce = S("Award Unlocked!")
end
local two = player:hud_add({
hud_elem_type = "text",
name = "award_au",
number = 0xFFFFFF,
scale = {x = 100, y = 20},
text = hud_announce,
position = {x = 0.5, y = 0.05},
offset = {x = 0, y = 45},
alignment = {x = 0, y = -1}
})
local three = player:hud_add({
hud_elem_type = "text",
name = "award_title",
number = 0xFFFFFF,
scale = {x = 100, y = 20},
text = title,
position = {x = 0.5, y = 0.05},
offset = {x = 0, y = 100},
alignment = {x = 0, y = -1}
})
local four = player:hud_add({
hud_elem_type = "image",
name = "award_icon",
scale = {x = 4, y = 4},
text = icon,
position = {x = 0.5, y = 0.05},
offset = {x = -200.5, y = 126},
alignment = {x = 0, y = -1}
})
minetest.after(4, function()
local player2 = minetest.get_player_by_name(name)
if player2 then
player2:hud_remove(one)
player2:hud_remove(two)
player2:hud_remove(three)
player2:hud_remove(four)
end
end)
end
end

218
src/api_triggers.lua Normal file
View File

@ -0,0 +1,218 @@
-- Copyright (c) 2013-18 rubenwardy. MIT.
local S, NS = awards.gettext, awards.ngettext
awards.registered_awards = {}
awards.on = {}
awards.on_unlock = {}
local default_def = {}
function default_def:run_callbacks(player, data, table_func)
for i = 1, #self.on do
local res = nil
local entry = self.on[i]
if type(entry) == "function" then
res = entry(player, data)
elseif type(entry) == "table" and entry.award then
res = table_func(entry)
end
if res then
awards.unlock(player:get_player_name(), res)
end
end
end
function awards.register_trigger(tname, tdef)
assert(type(tdef) == "table",
"Passing a callback to register_trigger is not supported in 3.0")
tdef.name = tname
for key, value in pairs(default_def) do
tdef[key] = value
end
if tdef.type == "counted" then
local old_reg = tdef.on_register
function tdef:on_register(def)
local tmp = {
award = def.name,
target = def.trigger.target,
}
tdef.register(tmp)
function def.getProgress(_, data)
local done = math.min(data[tname] or 0, tmp.target)
return {
perc = done / tmp.target,
label = S(tdef.progress, done, tmp.target),
}
end
function def.getDefaultDescription(_)
local n = def.trigger.target
return NS(tdef.auto_description[1], tdef.auto_description[2], n, n)
end
if old_reg then
return old_reg(tdef, def)
end
end
function tdef.notify(player)
assert(player and player.is_player and player:is_player())
local name = player:get_player_name()
local data = awards.player(name)
-- Increment counter
local currentVal = (data[tname] or 0) + 1
data[tname] = currentVal
tdef:run_callbacks(player, data, function(entry)
if entry.target and entry.award and currentVal and
currentVal >= entry.target then
return entry.award
end
end)
end
awards["notify_" .. tname] = tdef.notify
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
function tdef:on_register(def)
-- Register trigger
local tmp = {
award = def.name,
key = tdef:get_key(def),
target = def.trigger.target,
}
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)
data[tname] = data[tname] or {}
local done
if tmp.key then
done = data[tname][tmp.key] or 0
else
done = data[tname].__total or 0
end
done = math.min(done, tmp.target)
return {
perc = done / tmp.target,
label = S(tdef.progress, done, tmp.target),
}
end
-- Build description if none is specificed by the award
function def.getDefaultDescription(_)
local n = def.trigger.target
if tmp.key then
local nname = tmp.key
return NS(tdef.auto_description[1],
tdef.auto_description[2], n, n, nname)
else
return NS(tdef.auto_description_total[1],
tdef.auto_description_total[2], n, n)
end
end
-- Call on_register in trigger type definition
if old_reg then
return old_reg(tdef, def)
end
end
function tdef.notify(player, key, n)
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)
local name = player:get_player_name()
local data = awards.player(name)
-- Increment counter
data[tname] = data[tname] or {}
local currentVal = (data[tname][key] or 0) + n
data[tname][key] = currentVal
if key:sub(1, 6) ~= "group:" then
data[tname].__total = (data[tname].__total or 0) + n
end
tdef:run_callbacks(player, data, function(entry)
local current
if entry.key == key then
current = currentVal
elseif entry.key == nil then
current = data[tname].__total
else
return
end
if current >= entry.target then
return entry.award
end
end)
end
awards["notify_" .. tname] = tdef.notify
elseif tdef.type and tdef.type ~= "custom" then
error("Unrecognised trigger type " .. tdef.type)
end
awards.registered_triggers[tname] = tdef
tdef.on = {}
tdef.register = function(func)
table.insert(tdef.on, func)
end
-- Backwards compat
awards.on[tname] = tdef.on
awards['register_on_' .. tname] = tdef.register
return tdef
end
function awards.increment_item_counter(data, field, itemname, count)
itemname = minetest.registered_aliases[itemname] or itemname
data[field][itemname] = (data[field][itemname] or 0) + 1
end
function awards.get_item_count(data, field, itemname)
itemname = minetest.registered_aliases[itemname] or itemname
return data[field][itemname] or 0
end
function awards.get_total_keyed_count(data, field)
return data[field].__total or 0
end
function awards.register_on_unlock(func)
table.insert(awards.on_unlock, func)
end

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",

111
src/data.lua Normal file
View File

@ -0,0 +1,111 @@
local storage = minetest.get_mod_storage()
local __player_data
-- Table Save Load Functions
function awards.save()
storage:set_string("player_data", minetest.write_json(__player_data))
end
local function convert_data()
minetest.log("warning", "Importing awards data from previous version")
local old_players = __player_data
__player_data = {}
for name, data in pairs(old_players) do
while name.name do
name = name.name
end
data.name = name
print("Converting data for " .. name)
-- Just rename counted
local counted = {
chats = "chat",
deaths = "death",
joins = "join",
}
for from, to in pairs(counted) do
data[to] = data[from]
data[from] = nil
end
data.death = {
unknown = data.death,
__total = data.death,
}
-- Convert item db to new format
local counted_items = {
count = "dig",
place = "place",
craft = "craft",
}
for from, to in pairs(counted_items) do
local ret = {}
local count = 0
if data[from] then
for modname, items in pairs(data[from]) do
for itemname, value in pairs(items) do
itemname = modname .. ":" .. itemname
local key = minetest.registered_aliases[itemname] or itemname
ret[key] = value
count = count + value
end
end
end
ret.__total = count
data[from] = nil
data[to] = ret
end
__player_data[name] = data
end
end
function awards.load()
local old_save_path = minetest.get_worldpath().."/awards.txt"
local file = io.open(old_save_path, "r")
if file then
local table = minetest.deserialize(file:read("*all"))
if type(table) == "table" then
__player_data = table
convert_data()
else
__player_data = {}
end
file:close()
os.rename(old_save_path, minetest.get_worldpath().."/awards.bk.txt")
awards.save()
else
__player_data = minetest.parse_json(storage:get_string("player_data")) or {}
end
end
function awards.player(name)
assert(type(name) == "string")
local data = __player_data[name] or {}
__player_data[name] = data
data.name = data.name or name
data.unlocked = data.unlocked or {}
return data
end
function awards.player_or_nil(name)
return __player_data[name]
end
function awards.enable(name)
awards.player(name).disabled = nil
end
function awards.disable(name)
awards.player(name).disabled = true
end
function awards.clear_player(name)
__player_data[name] = {}
end

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
@ -71,43 +75,42 @@ function awards.get_formspec(name, to, sid)
formspec = formspec .. "button_exit[4.2,2.3;3,1;close;"..minetest.formspec_escape(S("OK")).."]" formspec = formspec .. "button_exit[4.2,2.3;3,1;close;"..minetest.formspec_escape(S("OK")).."]"
return formspec return formspec
end end
sid = awards_list[sid] and sid or 1
-- Sidebar -- Sidebar
if sid then local sitem = awards_list[sid]
local item = awards_list[sid+0] local sdef = sitem.def
local def = item.def if sdef and sdef.secret and not sitem.unlocked then
if def and def.secret and not item.unlocked then
formspec = formspec .. "label[1,2.75;".. formspec = formspec .. "label[1,2.75;"..
minetest.formspec_escape(S("(Secret Award)")).."]".. minetest.formspec_escape(S("(Secret Award)")).."]"..
"image[1,0;3,3;awards_unknown.png]" "image[1,0;3,3;awards_unknown.png]"
if def and def.description then if sdef and sdef.description then
formspec = formspec .. "textarea[0.25,3.25;4.8,1.7;;".. formspec = formspec .. "textarea[0.25,3.25;4.8,1.7;;"..
minetest.formspec_escape( minetest.formspec_escape(
S("Unlock this award to find out what it is."))..";]" S("Unlock this award to find out what it is."))..";]"
end end
else else
local title = item.name local title = sitem.name
if def and def.title then if sdef and sdef.title then
title = def.title title = sdef.title
end end
local status = "%s" local status = "%s"
if item.unlocked then if sitem.unlocked then
status = S("%s (unlocked)") status = S("%s (unlocked)")
end end
formspec = formspec .. "textarea[0.5,2.7;4.8,1.45;;" .. formspec = formspec .. "textarea[0.5,3.1;4.8,1.45;;" ..
string.format(status, minetest.formspec_escape(title)) .. string.format(status, minetest.formspec_escape(title)) ..
";]" ";]"
if def and def.icon then if sdef and sdef.icon then
formspec = formspec .. "image[1,0;3,3;" .. def.icon .. "]" formspec = formspec .. "image[0.6,0;3,3;" .. sdef.icon .. "]"
end end
local barwidth = 4.6 local barwidth = 3.95
local perc = nil local perc = nil
local label = nil local label = nil
if def.getProgress and data then if sdef.getProgress and data then
local res = def:getProgress(data) local res = sdef:getProgress(data)
perc = res.perc perc = res.perc
label = res.label label = res.label
end end
@ -115,20 +118,21 @@ function awards.get_formspec(name, to, sid)
if perc > 1 then if perc > 1 then
perc = 1 perc = 1
end end
formspec = formspec .. "background[0,4.80;" .. barwidth ..",0.25;awards_progress_gray.png;false]" formspec = formspec .. "background[0,8.24;" .. barwidth ..",0.4;awards_progress_gray.png;false]"
formspec = formspec .. "background[0,4.80;" .. (barwidth * perc) ..",0.25;awards_progress_green.png;false]" formspec = formspec .. "background[0,8.24;" .. (barwidth * perc) ..",0.4;awards_progress_green.png;false]"
if label then if label then
formspec = formspec .. "label[1.75,4.63;" .. minetest.formspec_escape(label) .. "]" formspec = formspec .. "label[1.6,8.15;" .. minetest.formspec_escape(label) .. "]"
end end
end end
if def and def.description then if sdef and sdef.description then
formspec = formspec .. "textarea[0.25,3.75;4.8,1.7;;"..minetest.formspec_escape(def.description)..";]" formspec = formspec .. "box[-0.05,3.75;3.9,4.2;#000]"
end formspec = formspec .. "textarea[0.25,3.75;3.9,4.2;;" ..
minetest.formspec_escape(sdef.description) .. ";]"
end end
end end
-- Create list box -- Create list box
formspec = formspec .. "textlist[4.75,0;6,5;awards;" formspec = formspec .. "textlist[4,0;3.8,8.6;awards;"
local first = true local first = true
for _, award in pairs(awards_list) do for _, award in pairs(awards_list) do
local def = award.def local def = award.def
@ -195,20 +199,35 @@ function awards.show_to(name, to, sid, text)
end end
end end
else else
if sid == nil or sid < 1 then
sid = 1
end
local deco = "" local deco = ""
if minetest.global_exists("default") then if minetest.global_exists("default") then
deco = default.gui_bg .. default.gui_bg_img deco = default.gui_bg .. default.gui_bg_img
end end
-- Show formspec to user -- Show formspec to user
minetest.show_formspec(to,"awards:awards", minetest.show_formspec(to,"awards:awards",
"size[11,5]" .. deco .. "size[8,8.6]" .. deco ..
awards.get_formspec(name, to, sid)) awards.get_formspec(name, to, sid))
end end
end end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "awards:awards" then
return false
end
if fields.quit then
return true
end
local name = player:get_player_name()
if fields.awards then
local event = minetest.explode_textlist_event(fields.awards)
if event.type == "CHG" then
awards.show_to(name, name, event.index, false)
end
end
return true
end)
if minetest.get_modpath("sfinv") then if minetest.get_modpath("sfinv") then
sfinv.register_page("awards:awards", { sfinv.register_page("awards:awards", {
title = S("Awards"), title = S("Awards"),
@ -222,8 +241,8 @@ if minetest.get_modpath("sfinv") then
get = function(self, player, context) get = function(self, player, context)
local name = player:get_player_name() local name = player:get_player_name()
return sfinv.make_formspec(player, context, return sfinv.make_formspec(player, context,
awards.get_formspec(name, name, context.awards_idx or 1), awards.get_formspec(name, name, context.awards_idx),
false, "size[11,5]") false)
end, end,
on_player_receive_fields = function(self, player, context, fields) on_player_receive_fields = function(self, player, context, fields)
if fields.awards then if fields.awards then
@ -235,6 +254,22 @@ if minetest.get_modpath("sfinv") then
end end
end end
}) })
local function check_and_reshow(name)
local player = minetest.get_player_by_name(name)
if not player then
return
end
local context = sfinv.get_or_create_context(player)
if context.page ~= "awards:awards" then
return
end
sfinv.set_player_inventory_formspec(player, context)
end
awards.register_on_unlock(check_and_reshow)
end end
if minetest.get_modpath("unified_inventory") ~= nil then if minetest.get_modpath("unified_inventory") ~= nil then

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