diff --git a/mods/awards/LICENSE.txt b/mods/awards/LICENSE.txt new file mode 100644 index 0000000..b9bc22e --- /dev/null +++ b/mods/awards/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2013-8 rubenwardy + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/mods/awards/README.md b/mods/awards/README.md new file mode 100644 index 0000000..7759867 --- /dev/null +++ b/mods/awards/README.md @@ -0,0 +1,294 @@ +# Awards + +Adds awards/achievements to Minetest (plus a very good API). + +by [rubenwardy](https://rubenwardy.com), licensed under MIT. +With thanks to Wuzzy, kaeza, and MrIbby. + +Majority of awards are back ported from Calinou's old fork in Carbone, under same license. + + +# Introduction + +## Awards and Triggers + +An award is a single unlockable unit, registered like so: + +```lua +awards.register_award("mymod:award", { + description = "My Example Award", +}) +``` + +Awards are unlocked either using `awards.unlock()` or by a trigger being +fullfilled. A trigger is a condition which unlocks an award. Triggers are +registered at the same time as an award is registered: + +```lua +awards.register_award("mymod:award", { + description = "My Example Award", + trigger = { + type = "dig", + node = "default:stone", + target = 10, + }, +}) +``` + +The above trigger type is an example of a counted_key trigger: +rather than a single counter there's a counter per key - in this +case the key is the value of the `node` field. If you leave out +the key in a `counted_key` trigger, then the total will be used +instead. For example, here is an award which unlocks after you've +placed 10 nodes of any type: + +```lua +awards.register_award("mymod:award", { + description = "Place 10 nodes!", + trigger = { + type = "place", + target = 10, + }, +}) +``` + +You can also register an *Unlock Function*, which can return the name of an +award to unlock it: + +```lua +awards.register_award("mymod:award", { + title = "Lava Miner", + description = "Mine any block while being very close to lava.", +}) + +awards.register_on_dig(function(player, data) + local pos = player:get_pos() + if pos and (minetest.find_node_near(pos, 1, "default:lava_source") or + minetest.find_node_near(pos, 1, "default:lava_flowing")) then + return "mymod:award" + end + return nil +end) +``` + +The above is a bad example as you don't actually need the stats data given. +It would be better to register a `dignode` callback and call `awards.unlock()` +if the condition is met. + +## Trigger Types + +The trigger type is used to determine which event will cause the trigger will be +fulfilled. The awards mod comes with a number of predefined types, documented +in [Builtin Trigger Types](#builtin-trigger-types). + +Trigger types are registered like so: + +```lua +awards.register_trigger("chat", { + type = "counted", + progress = "@1/@2 chat messages", + auto_description = { "Send a chat message", "Chat @1 times" }, +}) + +minetest.register_on_chat_message(function(name, message) + local player = minetest.get_player_by_name(name) + if not player or string.find(message, "/") then + return + end + awards.notify_chat(player) +end) +``` + +A trigger type has a type as well, which determines how the data is stored and +also how the trigger is fulfilled. + +**Trigger Type Types:** + +* **custom** requires you handle the calling of awards.unlock() yourself. You also + need to implement on_register() yourself. You'll also probably want to implement + `on_register()` to catch awards registered with your trigger type. +* **counted** stores a single counter for each player which is incremented by calling + `trigger:notify(player)`. Good for homogenous actions like number of chat messages, + joins, and the like. +* **counted_key** stores a table of counters each indexed by a key. There is also + a total field (`__total`) which stores the sum of all counters. A counter is + incremented by calling `trigger:notify(player, key)`. This is good for things like + placing nodes or crafting items, where the key will be the item or node name. + If `key` is an item, then you should also add `key_is_item = true` to the + trigger type definition. + +As said, you could use a custom trigger if none of the other ones match your needs. +Here's an example. + +```lua +awards.register_trigger("foo", { + type = "custom", + progress = "@1/@2 foos", + auto_description = { "Do a foo", "Foo @1 times" }, +}) + +minetest.register_on_foo(function() + for _, trigger in pairs(awards.on.foo) do + -- trigger is either a trigger tables or + -- or an unlock function. + + -- some complex logic + if condition then + awards.unlock(trigger) + end + end +end) + +``` + +## Award Difficulty + +Difficulty is used to determine how awards are sorted in awards lists. + +If the award trigger is counted, ie: the trigger requires a `target` property, +then the difficulty multipler is timesd by `target` to get the overall difficulty. +If the award isn't a counted type then the difficulty multiplier is used as the +overal difficulty. Award difficulty affects how awards are sorted in a list - +more difficult awards are further down the list. + +In real terms, `difficulty` is a relative difficulty to do one unit of the trigger +if its counted, otherwise it's the relative difficulty of completely doing the +award (if not-counted). For the `dig` trigger type, 1 unit would be 1 node dug. + + +Actual code used to calculate award difficulty: + +```lua +local difficulty = def.difficulty or 1 +if def.trigger and def.trigger.target then + difficulty = difficulty * def.trigger.target +end +``` + + +# API + +* awards.register_award(name, def), the def table has the following fields: + * `title` - title of the award (defaults to name) + * `description` - longer description of the award, displayed in Awards tab + * `difficulty` - see [Award Difficulty](#award-difficulty). + * `requires` - list of awards that need to be unlocked before this one + is visible. + * `prizes` - list of items to give when you earn the award + * `secret` - boolean if this award is secret (i.e. showed on awards list) + * `sound` - ignored in RealTest + * `icon` - the icon image, use default otherwise. + * `background` - the background image, use default otherwise. + * `trigger` - trigger definition, see [Builtin Trigger Types](#builtin-trigger-types). + * `on_unlock(name, def)` - callback on unlock. +* awards.register_trigger(name, def), the def table has the following fields: + * `type` - see [Trigger Types](#trigger-types). + * `progress` - used to format progress, defaults to "%1/%2". + * `auto_description` - a table of two elements. Each element is a format string. Element 1 is singular, element 2 is plural. Used for the award description (not title) if none is given. + * `on_register(award_def)` - called when an award registers with this type. + * "counted_key" only: + * `auto_description_total` - Used if the trigger is for the total. + * `get_key(self, def)` - get key for particular award, return nil for a total. + * `key_is_item` - true if the key is an item name. On notify(), + any watched groups will also be notified as `group:groupname` keys. +* awards.register_on_unlock(func(name, def)) + * name is the player name + * def is the award def. + * return true to cancel HUD +* awards.unlock(name, award) + * gives an award to a player + * name is the player name + +## Builtin Trigger Types + +Callbacks (register a function to be run) + +* dig type: Dig a node. + * node: the dug node type. If nil, all dug nodes are counted +* place type: Place a node. + * node: the placed node type. If nil, all placed nodes are counted +* craft type: Craft something. + * item: the crafted item type. If nil, all crafted items are counted +* death type: Die. + * reason: the death reason, one of the types in PlayerHPChangeReason (see lua_api.txt) + or nil for total deaths. +* chat type: Write a chat message. +* join type: Join the server. +* eat type: Eat an item. + * item: the eaten item type. If nil, all eaten items are counted + +(for all types) target - how many times to dig/place/craft/etc. + +Each type has a register function like so: + +* awards.register_on_TRIGGERTYPE(func(player, data)) + * data is the player stats data + * return award name or null + +### dig + +```lua +trigger = { + type = "dig", + node = "default:dirt", -- item, alias, or group + target = 50, +} +``` + +### place + +```lua +trigger = { + type = "place", + node = "default:dirt", -- item, alias, or group + target = 50, +} +``` + +### craft + +```lua +trigger = { + type = "craft", + item = "default:dirt", -- item, alias, or group + target = 50, +} +``` + +### death + +```lua +trigger = { + type = "death", + reason = "fall", + target = 5, +} +``` + +### chat + +```lua +trigger = { + type = "chat", + target = 100, +} +``` + +### join + +```lua +trigger = { + type = "join", + target = 100, +} +``` + +### eat + +```lua +trigger = { + type = "eat", + item = "default:apple", + target = 100, +} +``` diff --git a/mods/awards/init.lua b/mods/awards/init.lua index 350c75b..654d876 100644 --- a/mods/awards/init.lua +++ b/mods/awards/init.lua @@ -1,280 +1,33 @@ --- AWARDS --- by Rubenwardy, CC-BY-SA -------------------------------------------------------- --- this is the init file for the award mod -------------------------------------------------------- +-- Copyright (c) 2013-18 rubenwardy. MIT. -dofile(minetest.get_modpath("awards").."/api.lua") +-- The global award namespace +awards = { + show_mode = "hud", + registered_triggers = {}, +} --- Light it up -awards.register_achievement("award_firstlight",{ - title = "First Light", - description = "You have placed a torch", - icon = "awards_novicebuilder.png", - trigger={ - type="place", - node="default:torch", - target=1, - }, -}) -awards.register_achievement("award_lightitup",{ - title = "Light It Up", - description = "You have placed 100 torches", - icon = "awards_novicebuilder.png", - trigger={ - type="place", - node="default:torch", - target=100, - }, -}) -awards.register_achievement("award_betterthantorch",{ - title = "Better Than Torch", - description = "You have placed a streetlight", - icon = minetest.inventorycube(""), - trigger={ - type="place", - node="light:streetlight", - target=1, - }, -}) +-- Load files +dofile(minetest.get_modpath("awards").."/src/data.lua") +dofile(minetest.get_modpath("awards").."/src/api_awards.lua") +dofile(minetest.get_modpath("awards").."/src/api_triggers.lua") +dofile(minetest.get_modpath("awards").."/src/chat_commands.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") --- Lumber Jack -awards.register_achievement("award_lumberjack_ash",{ - title = "Ash Lumber Jack", - description = "You have mined an ash log!", - icon = "trees_ash_log.png", - trigger={ - type="dig", - node="trees:ash_log", - target=1, - }, -}) -awards.register_achievement("award_lumberjack_aspen",{ - title = "Aspen Lumber Jack", - description = "You have mined an aspen log!", - icon = "trees_aspen_log.png", - trigger={ - type="dig", - node="trees:aspen_log", - target=1, - }, -}) -awards.register_achievement("award_lumberjack_birch",{ - title = "Birch Lumber Jack", - description = "You have mined a birch log!", - icon = "trees_birch_log.png", - trigger={ - type="dig", - node="trees:birch_log", - target=1, - }, -}) -awards.register_achievement("award_lumberjack_maple",{ - title = "Maple Lumber Jack", - description = "You have mined a maple log!", - icon = "trees_maple_log.png", - trigger={ - type="dig", - node="trees:maple_log", - target=1, - }, -}) -awards.register_achievement("award_lumberjack_chestnut",{ - title = "Chestnut Lumber Jack", - description = "You have mined a chestnut log!", - icon = "trees_chestnut_log.png", - trigger={ - type="dig", - node="trees:chestnut_log", - target=1, - }, -}) -awards.register_achievement("award_lumberjack_pine",{ - title = "Pine Lumber Jack", - description = "You have mined a pine log!", - icon = "trees_pine_log.png", - trigger={ - type="dig", - node="trees:pine_log", - target=1, - }, -}) -awards.register_achievement("award_lumberjack_spruce",{ - title = "Spruce Lumber Jack", - icon = "trees_spruce_log.png", - description = "You have mined a spruce log!", - trigger={ - type="dig", - node="trees:spruce_log", - target=1, - }, -}) +awards.load() +minetest.register_on_shutdown(awards.save) --- Placed a stone anvil -awards.register_achievement("award_anvil_stone",{ - title = "Smithery", - description = "Place a Stone Anvil", - icon = "awards_anvil.png", - trigger={ - type="place", - node="anvil:anvil_stone", - target=1, - }, -}) -awards.register_achievement("award_anvil_dstone",{ - title = "Desert Smithery", - description = "Place a Desert Stone Anvil", - icon = "awards_desert_anvil.png", - trigger={ - type="place", - node="anvil:anvil_desert_stone", - target=1, - }, -}) --- Just entered the mine -awards.register_achievement("award_mine1",{ - title = "Entering the mine", - description = "You have dug 10 stone", - icon = "awards_miniminer.png", - background = "awards_bg_mining.png", - trigger={ - type="dig", - node="default:stone", - target=10, - }, -}) - --- Mini Miner -awards.register_achievement("award_mine2",{ - title = "Mini Miner", - description = "You have dug 100 stone", - icon = "awards_miniminer.png", - background = "awards_bg_mining.png", - trigger={ - type="dig", - node="default:stone", - target=100, - }, -}) - --- Hardened Miner -awards.register_achievement("award_mine3",{ - title = "Hardened Miner", - description = "You have dug 1000 stone", - icon = "awards_miniminer.png", - background = "awards_bg_mining.png", - trigger={ - type="dig", - node="default:stone", - target=1000, - }, -}) - --- Master Miner -awards.register_achievement("award_mine4",{ - title = "Master Miner", - description = "You have dug 10000 stone", - icon = "awards_miniminer.png", - background = "awards_bg_mining.png", - trigger={ - type="dig", - node="default:stone", - target=10000, - }, -}) - --- First Death -awards.register_achievement("award_death1",{ - title = "First Death", - description = "You died. Oh well, it does not matter, you have more lives than a cat", - icon = "awards_death.png", - trigger={ - type="death", - target=1, - }, -}) - --- Spike Placement -awards.register_achievement("award_spike_ash",{ - title = "Spiky Ash!", - icon = "trees_ash_planks.png", - description = "You placed ash spikes!", - trigger={ - type="place", - node="spikes:spike_ash", - target=1, - }, -}) -awards.register_achievement("award_spike_aspen",{ - title = "Spiky Aspen!", - icon = "trees_aspen_planks.png", - description = "You placed aspen spikes!", - trigger={ - type="place", - node="spikes:spike_aspen", - target=1, - }, -}) -awards.register_achievement("award_spike_birch",{ - title = "Spiky Birch!", - description = "You placed birch spikes!", - icon = "trees_birch_planks.png", - trigger={ - type="place", - node="spikes:spike_birch", - target=1, - }, -}) -awards.register_achievement("award_spike_maple",{ - title = "Spiky Maple!", - description = "You placed maple spikes!", - icon = "trees_maple_planks.png", - trigger={ - type="place", - node="spikes:spike_maple", - target=1, - }, -}) -awards.register_achievement("award_spike_chestnut",{ - title = "Spiky Chestnut!", - icon = "trees_chestnut_planks.png", - description = "You placed chestnut spikes!", - trigger={ - type="place", - node="spikes:spike_chestnut", - target=1, - }, -}) -awards.register_achievement("award_spike_pine",{ - title = "Spiky Pine!", - icon = "trees_pine_planks.png", - description = "You placed pine spikes!", - trigger={ - type="place", - node="spikes:spike_pine", - target=1, - }, -}) -awards.register_achievement("award_spike_spruce",{ - title = "Spiky Spruce!", - icon = "trees_spruce_planks.png", - description = "You placed spruce spikes!", - trigger={ - type="place", - node="spikes:spike_spruce", - target=1, - }, -}) - ---Ants -awards.register_achievement("award_ants",{ - title = "ANTS!", - description = "You dug an anthill", - icon = "farming:anthill.png", - trigger={ - type="dig", - node="farming:ant_hill", - target=1, - }, -}) +-- Backwards compatibility +awards.give_achievement = awards.unlock +awards.getFormspec = awards.get_formspec +awards.showto = awards.show_to +awards.register_onDig = awards.register_on_dig +awards.register_onPlace = awards.register_on_place +awards.register_onDeath = awards.register_on_death +awards.register_onChat = awards.register_on_chat +awards.register_onJoin = awards.register_on_join +awards.register_onCraft = awards.register_on_craft +awards.def = awards.registered_awards +awards.register_achievement = awards.register_award diff --git a/mods/awards/mod.conf b/mods/awards/mod.conf new file mode 100644 index 0000000..1dae984 --- /dev/null +++ b/mods/awards/mod.conf @@ -0,0 +1,9 @@ +name = awards +title = Awards +author = rubenwardy +description = Adds awards to Minetest, and an API to register new ones. +optional_depends = sfinv,unified_inventory,default,stairs,farming,dye,beds,wool,vessels,moreblocks,fire,flowers,nyancat +license = MIT +forum = https://forum.minetest.net/viewtopic.php?t=4870 +version = 3.0.0 +release = 638 diff --git a/mods/awards/src/api_awards.lua b/mods/awards/src/api_awards.lua new file mode 100644 index 0000000..c0502a4 --- /dev/null +++ b/mods/awards/src/api_awards.lua @@ -0,0 +1,164 @@ +-- Copyright (c) 2013-18 rubenwardy. MIT. + +local S = minetest.get_translator("awards") + +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" + + 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 diff --git a/mods/awards/src/api_triggers.lua b/mods/awards/src/api_triggers.lua new file mode 100644 index 0000000..60031a8 --- /dev/null +++ b/mods/awards/src/api_triggers.lua @@ -0,0 +1,219 @@ +-- Copyright (c) 2013-18 rubenwardy. MIT. + +local S = minetest.get_translator("awards") +local NS = function(s) return s end + +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 diff --git a/mods/awards/src/awards.lua b/mods/awards/src/awards.lua new file mode 100644 index 0000000..645d1b4 --- /dev/null +++ b/mods/awards/src/awards.lua @@ -0,0 +1,272 @@ +-- Light it up +awards.register_award("award_firstlight",{ + title = "First Light", + description = "Place a torch", + icon = "awards_novicebuilder.png^awards_level1.png", + trigger={ + type="place", + node="default:torch", + target=1, + }, +}) +awards.register_award("award_lightitup",{ + title = "Light It Up", + description = "Place 100 torches", + icon = "awards_novicebuilder.png^awards_level2.png", + trigger={ + type="place", + node="default:torch", + target=100, + }, +}) +awards.register_award("award_betterthantorch",{ + title = "Better Than Torch", + description = "Place a streetlight", + icon = "light_streetlight.png", + trigger={ + type="place", + node="light:streetlight", + target=1, + }, +}) + +-- Lumber Jack +awards.register_award("award_lumberjack_ash",{ + title = "Ash Lumber Jack", + description = "Mine an ash log", + icon = "trees_ash_log.png", + trigger={ + type="dig", + node="trees:ash_log", + target=1, + }, +}) +awards.register_award("award_lumberjack_aspen",{ + title = "Aspen Lumber Jack", + description = "Mine an aspen log", + icon = "trees_aspen_log.png", + trigger={ + type="dig", + node="trees:aspen_log", + target=1, + }, +}) +awards.register_award("award_lumberjack_birch",{ + title = "Birch Lumber Jack", + description = "Mine a birch log", + icon = "trees_birch_log.png", + trigger={ + type="dig", + node="trees:birch_log", + target=1, + }, +}) +awards.register_award("award_lumberjack_maple",{ + title = "Maple Lumber Jack", + description = "Mine a maple log", + icon = "trees_maple_log.png", + trigger={ + type="dig", + node="trees:maple_log", + target=1, + }, +}) +awards.register_award("award_lumberjack_chestnut",{ + title = "Chestnut Lumber Jack", + description = "Mine a chestnut log", + icon = "trees_chestnut_log.png", + trigger={ + type="dig", + node="trees:chestnut_log", + target=1, + }, +}) +awards.register_award("award_lumberjack_pine",{ + title = "Pine Lumber Jack", + description = "Mine a pine log", + icon = "trees_pine_log.png", + trigger={ + type="dig", + node="trees:pine_log", + target=1, + }, +}) +awards.register_award("award_lumberjack_spruce",{ + title = "Spruce Lumber Jack", + icon = "trees_spruce_log.png", + description = "Mine a spruce log", + trigger={ + type="dig", + node="trees:spruce_log", + target=1, + }, +}) + +-- Placed a stone anvil +awards.register_award("award_anvil_stone",{ + title = "Smithery", + description = "Place a Stone Anvil", + icon = "awards_anvil.png", + trigger={ + type="place", + node="anvil:anvil_stone", + target=1, + }, +}) +awards.register_award("award_anvil_dstone",{ + title = "Desert Smithery", + description = "Place a Desert Stone Anvil", + icon = "awards_desert_anvil.png", + trigger={ + type="place", + node="anvil:anvil_desert_stone", + target=1, + }, +}) + +-- Just entered the mine +awards.register_award("award_mine1",{ + title = "Entering the mine", + description = "Dig 10 stone", + icon = "awards_miniminer.png^awards_level1.png", + background = "awards_bg_mining.png", + trigger={ + type="dig", + node="default:stone", + target=10, + }, +}) + +-- Mini Miner +awards.register_award("award_mine2",{ + title = "Mini Miner", + description = "Dig 100 stone", + icon = "awards_miniminer.png^awards_level2.png", + background = "awards_bg_mining.png", + trigger={ + type="dig", + node="default:stone", + target=100, + }, +}) + +-- Hardened Miner +awards.register_award("award_mine3",{ + title = "Hardened Miner", + description = "Dig 1000 stone", + icon = "awards_miniminer.png^awards_level3.png", + background = "awards_bg_mining.png", + trigger={ + type="dig", + node="default:stone", + target=1000, + }, +}) + +-- Master Miner +awards.register_award("award_mine4",{ + title = "Master Miner", + description = "Dig 10000 stone", + icon = "awards_miniminer.png^awards_level4.png", + background = "awards_bg_mining.png", + trigger={ + type="dig", + node="default:stone", + target=10000, + }, +}) + +-- First Death +awards.register_award("award_death1",{ + title = "First Death", + description = "Oh well, it does not matter, you have more lives than a cat", + icon = "awards_death.png", + trigger={ + type="death", + target=1, + }, +}) + +-- Spike Placement +awards.register_award("award_spike_ash",{ + title = "Spiky Ash!", + icon = "trees_ash_planks.png", + description = "Place ash spikes", + trigger={ + type="place", + node="spikes:spike_ash", + target=1, + }, +}) +awards.register_award("award_spike_aspen",{ + title = "Spiky Aspen!", + icon = "trees_aspen_planks.png", + description = "Place aspen spikes!", + trigger={ + type="place", + node="spikes:spike_aspen", + target=1, + }, +}) +awards.register_award("award_spike_birch",{ + title = "Spiky Birch!", + description = "Place birch spikes", + icon = "trees_birch_planks.png", + trigger={ + type="place", + node="spikes:spike_birch", + target=1, + }, +}) +awards.register_award("award_spike_maple",{ + title = "Spiky Maple!", + description = "Place maple spikes", + icon = "trees_maple_planks.png", + trigger={ + type="place", + node="spikes:spike_maple", + target=1, + }, +}) +awards.register_award("award_spike_chestnut",{ + title = "Spiky Chestnut!", + icon = "trees_chestnut_planks.png", + description = "Place chestnut spikes", + trigger={ + type="place", + node="spikes:spike_chestnut", + target=1, + }, +}) +awards.register_award("award_spike_pine",{ + title = "Spiky Pine!", + icon = "trees_pine_planks.png", + description = "Place pine spikes", + trigger={ + type="place", + node="spikes:spike_pine", + target=1, + }, +}) +awards.register_award("award_spike_spruce",{ + title = "Spiky Spruce!", + icon = "trees_spruce_planks.png", + description = "Place spruce spikes", + trigger={ + type="place", + node="spikes:spike_spruce", + target=1, + }, +}) + +--Ants +awards.register_award("award_ants",{ + title = "ANTS!", + description = "Dig an anthill", + icon = "farming_anthill.png", + trigger={ + type="dig", + node="farming:ant_hill", + target=1, + }, +}) diff --git a/mods/awards/src/chat_commands.lua b/mods/awards/src/chat_commands.lua new file mode 100644 index 0000000..4418dde --- /dev/null +++ b/mods/awards/src/chat_commands.lua @@ -0,0 +1,61 @@ +-- Copyright (c) 2013-18 rubenwardy. MIT. + +local S = minetest.get_translator("awards") + +minetest.register_chatcommand("awards", { + params = S("[c|clear|disable|enable]"), + description = S("Show, clear, disable or enable your awards"), + func = function(name, param) + if param == "clear" then + awards.clear_player(name) + minetest.chat_send_player(name, + S("All your awards and statistics have been cleared. You can now start again.")) + elseif param == "disable" then + awards.disable(name) + minetest.chat_send_player(name, S("You have disabled awards.")) + elseif param == "enable" then + awards.enable(name) + minetest.chat_send_player(name, S("You have enabled awards.")) + elseif param == "c" then + awards.show_to(name, name, nil, true) + else + awards.show_to(name, name, nil, false) + end + + if (param == "disable" or param == "enable") and minetest.global_exists("sfinv") then + local player = minetest.get_player_by_name(name) + if player then + sfinv.set_player_inventory_formspec(player) + end + end + end +}) + +minetest.register_chatcommand("awd", { + params = S(""), + description = S("Show details of an award"), + func = function(name, param) + local def = awards.registered_awards[param] + if def then + minetest.chat_send_player(name, string.format(S("%s: %s"), def.title, def.description)) + else + minetest.chat_send_player(name, S("Award not found.")) + end + end +}) + +minetest.register_chatcommand("awpl", { + privs = { + server = true + }, + params = S(""), + description = S("Get the awards statistics for the given player or yourself"), + func = function(name, param) + if not param or param == "" then + param = name + end + minetest.chat_send_player(name, param) + local player = awards.player(param) + minetest.chat_send_player(name, dump(player)) + end +}) diff --git a/mods/awards/src/data.lua b/mods/awards/src/data.lua new file mode 100644 index 0000000..27ae5e3 --- /dev/null +++ b/mods/awards/src/data.lua @@ -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 diff --git a/mods/awards/src/gui.lua b/mods/awards/src/gui.lua new file mode 100644 index 0000000..91900a5 --- /dev/null +++ b/mods/awards/src/gui.lua @@ -0,0 +1,285 @@ +-- Copyright (c) 2013-18 rubenwardy. MIT. + +local S = minetest.get_translator("awards") + +local function order_awards(name) + local hash_is_unlocked = {} + local retval = {} + + local data = awards.player(name) + if data and data.unlocked then + for awardname, _ in pairs(data.unlocked) do + local def = awards.registered_awards[awardname] + if def then + hash_is_unlocked[awardname] = true + local score = -100000 + + local difficulty = def.difficulty or 1 + if def.trigger and def.trigger.target then + difficulty = difficulty * def.trigger.target + end + score = score + difficulty + + retval[#retval + 1] = { + name = awardname, + def = def, + unlocked = true, + started = true, + score = score, + } + end + end + end + + for _, def in pairs(awards.registered_awards) do + if not hash_is_unlocked[def.name] and def:can_unlock(data) then + local started = false + local score = def.difficulty or 1 + if def.secret then + score = 1000000 + elseif def.trigger and def.trigger.target and def.getProgress then + local progress = def:getProgress(data).perc + score = score * (1 - progress) * def.trigger.target + if progress < 0.001 then + score = score + 100 + else + started = true + end + else + score = 100 + end + + retval[#retval + 1] = { + name = def.name, + def = def, + unlocked = false, + started = started, + score = score, + } + end + end + + table.sort(retval, function(a, b) + return a.score < b.score + end) + return retval +end + +function awards.get_formspec(name, to, sid) + local formspec = "" + local awards_list = order_awards(name) + local data = awards.player(name) + + if #awards_list == 0 then + formspec = formspec .. "label[3.9,1.5;"..minetest.formspec_escape(S("Error: No achivements available.")).."]" + formspec = formspec .. "button_exit[4.2,2.3;3,1;close;"..minetest.formspec_escape(S("OK")).."]" + return formspec + end + sid = awards_list[sid] and sid or 1 + + -- Sidebar + local sitem = awards_list[sid] + local sdef = sitem.def + if sdef and sdef.secret and not sitem.unlocked then + formspec = formspec .. "label[1,2.75;".. + minetest.formspec_escape(S("(Secret Award)")).."]".. + "image[1,0;3,3;awards_unknown.png]" + if sdef and sdef.description then + formspec = formspec .. "textarea[0.25,3.25;4.8,1.7;;".. + minetest.formspec_escape( + S("Unlock this award to find out what it is."))..";]" + end + else + local title = sitem.name + if sdef and sdef.title then + title = sdef.title + end + local status = "%s" + if sitem.unlocked then + status = S("%s (unlocked)") + end + + formspec = formspec .. "textarea[0.5,3.1;4.8,1.45;;" .. + string.format(status, minetest.formspec_escape(title)) .. + ";]" + + if sdef and sdef.icon then + formspec = formspec .. "image[0.6,0;3,3;" .. sdef.icon .. "]" + end + local barwidth = 3.95 + local perc = nil + local label = nil + if sdef.getProgress and data then + local res = sdef:getProgress(data) + perc = res.perc + label = res.label + end + if perc then + if perc > 1 then + perc = 1 + end + formspec = formspec .. "background[0,8.24;" .. barwidth ..",0.4;awards_progress_gray.png;false]" + formspec = formspec .. "background[0,8.24;" .. (barwidth * perc) ..",0.4;awards_progress_green.png;false]" + if label then + formspec = formspec .. "label[1.6,8.15;" .. minetest.formspec_escape(label) .. "]" + end + end + if sdef and sdef.description then + formspec = formspec .. "box[-0.05,3.75;3.9,4.2;#000]" + formspec = formspec .. "textarea[0.25,3.75;3.9,4.2;;" .. + minetest.formspec_escape(sdef.description) .. ";]" + end + end + + -- Create list box + formspec = formspec .. "textlist[4,0;3.8,8.6;awards;" + local first = true + for _, award in pairs(awards_list) do + local def = award.def + if def then + if not first then + formspec = formspec .. "," + end + first = false + + if def.secret and not award.unlocked then + formspec = formspec .. "#707070"..minetest.formspec_escape(S("(Secret Award)")) + else + local title = award.name + if def and def.title then + title = def.title + end + -- title = title .. " [" .. award.score .. "]" + if award.unlocked then + formspec = formspec .. minetest.formspec_escape(title) + elseif award.started then + formspec = formspec .. "#c0c0c0".. minetest.formspec_escape(title) + else + formspec = formspec .. "#a0a0a0".. minetest.formspec_escape(title) + end + end + end + end + return formspec .. ";"..sid.."]" +end + + +function awards.show_to(name, to, sid, text) + if name == "" or name == nil then + name = to + end + local data = awards.player(to) + if name == to and data.disabled then + minetest.chat_send_player(name, S("You've disabled awards. Type /awards enable to reenable.")) + return + end + if text then + local awards_list = order_awards(name) + if #awards_list == 0 then + minetest.chat_send_player(to, S("Error: No award available.")) + return + elseif not data or not data.unlocked then + minetest.chat_send_player(to, S("You have not unlocked any awards.")) + return + end + minetest.chat_send_player(to, string.format(S("%s’s awards:"), name)) + + for str, _ in pairs(data.unlocked) do + local def = awards.registered_awards[str] + if def then + if def.title then + if def.description then + minetest.chat_send_player(to, string.format(S("%s: %s"), def.title, def.description)) + else + minetest.chat_send_player(to, def.title) + end + else + minetest.chat_send_player(to, str) + end + end + end + else + local deco = "" + if minetest.global_exists("default") then + deco = default.gui_bg .. default.gui_bg_img + end + -- Show formspec to user + minetest.show_formspec(to,"awards:awards", + "size[8,8.6]" .. deco .. + awards.get_formspec(name, to, sid)) + 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 + sfinv.register_page("awards:awards", { + title = S("Awards"), + on_enter = function(self, player, context) + context.awards_idx = 1 + end, + is_in_nav = function(self, player, context) + local data = awards.player(player:get_player_name()) + return not data.disabled + end, + get = function(self, player, context) + local name = player:get_player_name() + return sfinv.make_formspec(player, context, + awards.get_formspec(name, name, context.awards_idx), + false) + end, + on_player_receive_fields = function(self, player, context, fields) + if fields.awards then + local event = minetest.explode_textlist_event(fields.awards) + if event.type == "CHG" then + context.awards_idx = event.index + sfinv.set_player_inventory_formspec(player, context) + 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 + +if minetest.get_modpath("unified_inventory") ~= nil then + unified_inventory.register_button("awards", { + type = "image", + image = "awards_ui_icon.png", + tooltip = S("Awards"), + action = function(player) + local name = player:get_player_name() + awards.show_to(name, name, nil, false) + end, + }) +end diff --git a/mods/awards/src/triggers.lua b/mods/awards/src/triggers.lua new file mode 100644 index 0000000..32a0b85 --- /dev/null +++ b/mods/awards/src/triggers.lua @@ -0,0 +1,141 @@ +-- AWARDS +-- +-- Copyright (C) 2013-2015 rubenwardy +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU Lesser General Public License as published by +-- the Free Software Foundation; either version 2.1 of the License, or +-- (at your option) any later version. +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Lesser General Public License for more details. +-- You should have received a copy of the GNU Lesser General Public License along +-- with this program; if not, write to the Free Software Foundation, Inc., +-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +-- + + +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) + + +awards.register_trigger("join", { + type = "counted", + progress = "@1/@2 joins", + auto_description = { "Join once", "Join @1 times" }, +}) +minetest.register_on_joinplayer(awards.notify_join) + + +awards.register_trigger("death", { + type = "counted_key", + progress = "@1/@2 deaths", + auto_description = { "Die once of @2", "Die @1 times of @2" }, + auto_description_total = { "Die @1 times.", "Mine @1 times" }, + get_key = function(self, def) + return def.trigger.reason + end, +}) +minetest.register_on_dieplayer(function(player, reason) + if reason then + reason = reason.type + else + reason = "unknown" + end + awards.notify_death(player, reason) +end) + + +awards.register_trigger("dig", { + type = "counted_key", + progress = "@1/@2 dug", + auto_description = { "Mine: @2", "Mine: @1×@2" }, + auto_description_total = { "Mine @1 block.", "Mine @1 blocks." }, + get_key = function(self, def) + return minetest.registered_aliases[def.trigger.node] or def.trigger.node + end, + key_is_item = true, +}) +minetest.register_on_dignode(function(pos, node, player) + if not player or not pos or not node then + return + end + + local node_name = node.name + node_name = minetest.registered_aliases[node_name] or node_name + awards.notify_dig(player, node_name) +end) + + +awards.register_trigger("place", { + type = "counted_key", + progress = "@1/@2 placed", + auto_description = { "Place: @2", "Place: @1×@2" }, + auto_description_total = { "Place @1 block.", "Place @1 blocks." }, + get_key = function(self, def) + return minetest.registered_aliases[def.trigger.node] or def.trigger.node + end, + key_is_item = true, +}) +minetest.register_on_placenode(function(pos, node, player) + if not player or not pos or not node then + return + end + + local node_name = node.name + node_name = minetest.registered_aliases[node_name] or node_name + awards.notify_place(player, node_name) +end) + + +awards.register_trigger("craft", { + type = "counted_key", + progress = "@1/@2 crafted", + auto_description = { "Craft: @2", "Craft: @1×@2" }, + auto_description_total = { "Craft @1 item", "Craft @1 items." }, + get_key = function(self, def) + return minetest.registered_aliases[def.trigger.item] or def.trigger.item + end, + key_is_item = true, +}) +minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv) + if not player or itemstack:is_empty() then + return + end + + local itemname = itemstack:get_name() + itemname = minetest.registered_aliases[itemname] or itemname + awards.notify_craft(player, itemname, itemstack:get_count()) +end) + + +awards.register_trigger("eat", { + type = "counted_key", + progress = "@1/@2 eaten", + auto_description = { "Eat @2", "Eat @1×@2" }, + auto_description_total = { "Eat @1 item", "Eat @1 items." }, + get_key = function(self, def) + return minetest.registered_aliases[def.trigger.item] or def.trigger.item + end, + key_is_item = true, +}) +minetest.register_on_item_eat(function(_, _, itemstack, player, _) + if not player or itemstack:is_empty() then + return + end + + local itemname = itemstack:get_name() + itemname = minetest.registered_aliases[itemname] or itemname + awards.notify_craft(player, itemname, itemstack:get_count()) +end) diff --git a/mods/awards/textures/awards_level1.png b/mods/awards/textures/awards_level1.png new file mode 100644 index 0000000..04688e9 Binary files /dev/null and b/mods/awards/textures/awards_level1.png differ diff --git a/mods/awards/textures/awards_level2.png b/mods/awards/textures/awards_level2.png new file mode 100644 index 0000000..ac81fed Binary files /dev/null and b/mods/awards/textures/awards_level2.png differ diff --git a/mods/awards/textures/awards_level3.png b/mods/awards/textures/awards_level3.png new file mode 100644 index 0000000..e2c79b0 Binary files /dev/null and b/mods/awards/textures/awards_level3.png differ diff --git a/mods/awards/textures/awards_level4.png b/mods/awards/textures/awards_level4.png new file mode 100644 index 0000000..7b43d13 Binary files /dev/null and b/mods/awards/textures/awards_level4.png differ diff --git a/mods/awards/textures/awards_level5.png b/mods/awards/textures/awards_level5.png new file mode 100644 index 0000000..de12568 Binary files /dev/null and b/mods/awards/textures/awards_level5.png differ diff --git a/mods/awards/textures/awards_level6.png b/mods/awards/textures/awards_level6.png new file mode 100644 index 0000000..97b8719 Binary files /dev/null and b/mods/awards/textures/awards_level6.png differ diff --git a/mods/awards/textures/awards_level7.png b/mods/awards/textures/awards_level7.png new file mode 100644 index 0000000..8caeb29 Binary files /dev/null and b/mods/awards/textures/awards_level7.png differ diff --git a/mods/awards/textures/awards_progress_gray.png b/mods/awards/textures/awards_progress_gray.png new file mode 100644 index 0000000..bac8765 Binary files /dev/null and b/mods/awards/textures/awards_progress_gray.png differ diff --git a/mods/awards/textures/awards_progress_green.png b/mods/awards/textures/awards_progress_green.png new file mode 100644 index 0000000..100e394 Binary files /dev/null and b/mods/awards/textures/awards_progress_green.png differ diff --git a/mods/awards/triggers.lua b/mods/awards/triggers.lua deleted file mode 100644 index 99cf8fb..0000000 --- a/mods/awards/triggers.lua +++ /dev/null @@ -1,175 +0,0 @@ --- AWARDS --- by Rubenwardy, CC-BY-SA -------------------------------------------------------- --- this is the trigger handler file for the awards mod -------------------------------------------------------- - --- Function and table holders for Triggers -awards.onDig={} -awards.onPlace={} -awards.onTick={} -awards.onDeath={} - --- Trigger Handles -minetest.register_on_dignode(function(pos, oldnode, digger) - if not digger or not pos or not oldnode then - return - end - local nodedug = string.split(oldnode.name, ":") - if #nodedug ~= 2 then - minetest.log("action", oldnode.name.." is in wrong format!") - return - end - local mod=nodedug[1] - local item=nodedug[2] - local playern = digger:get_player_name() - - if (not playern or not nodedug or not mod or not item) then - return - end - awards.assertPlayer(playern) - awards.tbv(awards.players[playern].count, mod) - awards.tbv(awards.players[playern].count[mod], item, 0 ) - - -- Increment counder - awards.players[playern].count[mod][item]=awards.players[playern].count[mod][item]+1 - minetest.log("info", "[awards] - "..mod..":"..item.." 's count is now "..(awards.players[playern].count[mod][item])) - - -- Run callbacks and triggers - local player=digger - local data=awards.players[playern] - - for i=1,# awards.onDig do - local res = nil - if type(awards.onDig[i]) == "function" then - -- Run trigger callback - res = awards.onDig[i](player,data) - elseif type(awards.onDig[i]) == "table" then - -- Handle table trigger - if not awards.onDig[i].node or not awards.onDig[i].target or not awards.onDig[i].award then - -- table running failed! - minetest.log("error", "awards - onDig trigger "..i.." is invalid!") - else - -- run the table - local tnodedug = string.split(awards.onDig[i].node, ":") - local tmod=tnodedug[1] - local titem=tnodedug[2] - if tmod==nil or titem==nil or not data.count[tmod] or not data.count[tmod][titem] then - -- table running failed! - elseif data.count[tmod][titem] > awards.onDig[i].target-1 then - res=awards.onDig[i].award - end - end - end - - if res then - awards.give_achievement(playern,res) - end - end -end) - -minetest.register_on_placenode(function(pos,node,digger) - if not digger or not pos or not node or not digger:get_player_name() or digger:get_player_name()=="" then - return - end - local nodedug = string.split(node.name, ":") - if #nodedug ~= 2 then - minetest.log("action", oldnode.name.." is in wrong format!") - return - end - local mod=nodedug[1] - local item=nodedug[2] - local playern = digger:get_player_name() - - -- Run checks - if (not playern or not nodedug or not mod or not item) then - return - end - awards.assertPlayer(playern) - awards.tbv(awards.players[playern].place, mod) - awards.tbv(awards.players[playern].place[mod], item, 0 ) - - -- Increment counder - awards.players[playern].place[mod][item] = awards.players[playern].place[mod][item]+1 - minetest.log("info", "[awards] - "..mod..":"..item.." 's place count is now "..(awards.players[playern].place[mod][item])) - - -- Run callbacks and triggers - local player = digger - local data = awards.players[playern] - for i=1,# awards.onPlace do - local res = nil - if type(awards.onPlace[i]) == "function" then - -- Run trigger callback - res = awards.onPlace[i](player,data) - elseif type(awards.onPlace[i]) == "table" then - -- Handle table trigger - if not awards.onPlace[i].node or not awards.onPlace[i].target or not awards.onPlace[i].award then - -- table running failed! - minetest.log("error", "awards - onPlace trigger "..i.." is invalid!") - else - -- run the table - local tnodedug = string.split(awards.onPlace[i].node, ":") - local tmod = tnodedug[1] - local titem = tnodedug[2] - if tmod==nil or titem==nil or not data.place[tmod] or not data.place[tmod][titem] then - -- table running failed! - elseif data.place[tmod][titem] > awards.onPlace[i].target-1 then - res = awards.onPlace[i].award - end - end - end - - if res then - awards.give_achievement(playern,res) - end - end -end) - -minetest.register_on_dieplayer(function(player) - -- Run checks - if not player or not player:get_player_name() or player:get_player_name()=="" then - return - end - local playern = player:get_player_name() - awards.assertPlayer(playern) - - - -- Increment counter - awards.players[player:get_player_name()].deaths = awards.players[player:get_player_name()].deaths + 1 - - -- Run callbacks and triggers - local data=awards.players[playern] - for i=1,# awards.onDeath do - local res=nil - if type(awards.onDeath[i]) == "function" then - -- Run trigger callback - res=awards.onDeath[i](player,data) - elseif type(awards.onDeath[i]) == "table" then - -- handle table here - if not awards.onDeath[i].target or not awards.onDeath[i].award then - -- table running failed! - minetest.log("error", "awards - onDeath trigger "..i.." is invalid!") - else - -- run the table - if not data.deaths then - -- table running failed! - elseif data.deaths > awards.onDeath[i].target-1 then - res=awards.onDeath[i].award - end - end - end - - if res~=nil then - awards.give_achievement(playern,res) - end - end -end) - -minetest.register_on_newplayer(function(player) - local playern = player:get_player_name() - awards.assertPlayer(playern) -end) - -minetest.register_on_shutdown(function() - awards.save() -end) diff --git a/mods/default/init.lua b/mods/default/init.lua index d05b4e2..80aac52 100644 --- a/mods/default/init.lua +++ b/mods/default/init.lua @@ -9,6 +9,8 @@ local LAVA_VISC = 7 -- Definitions made by this mod that other mods can use too default = {} +default.gui_bg = "" +default.gui_bg_img = "" -- Load other files dofile(minetest.get_modpath("default").."/mapgen.lua")