Treasure chest squashed commit of previous work

This commit is contained in:
Zenon Seth 2022-11-17 21:05:51 +00:00
commit 4e63572b7c
10 changed files with 405 additions and 0 deletions

85
README.txt Normal file
View File

@ -0,0 +1,85 @@
== Treasure Chest mod for Minetest ==
01. What is it?
02. License Info
03. Current Version
04. Installation Instructions
05. Dependencies
06. Bugs/contact info
01. What is it?
===============
Treasure Chest is a small mod for the Minetest game that adds a kind of chest made for world designers.
The chest has no crafting recipe, so it has to be obtained by /giveme or other commands.
The intended use and original idea, comes from trying to design challenges in a survival world,
and having some way to automatically reward players who complete the challenges.
The rewards can be somewhat randomized, with a probability for each one,and can reset after
a specified time, on a per user basis, after being given out.
When the chest is used by someone without the "give" privilege, the chest will attempt to give
a copy of the items inside it (with some chance) to the user. The chest then records the last time
this user has tried to get the items, and the user will then have to wait for a timeout period to
expire before he/she can have a chance of obtaining the items again. This timeout period is per-user.
For someone with the "give" privilege, the chest will display a GUI that allows you to configure it.
- 1st input: Refresh Time: An integer value
The number of minutes of gametime that must pass before the chest can give its items out again.
This is on a per-user basis, so two users can always obtain the reward if they use the chest,
but if the same user tries to use it before the refresh timeout, he will get nothing.
- 2nd line: Six input: Integer values
Probabilities, ranging 0..100, of how likely a reward is to be given to a user. Randomly
determined each time the chest is used. Associated with the inventory slot below each one
- 3rd line: Six inventory slots
The items to be given out, as associated by the probabilities above them. Each slot can hold
a regular item stack. Items stacks are given out as a whole, so the user will get either the
whole item stack, or nothing from that slot. Item stacks in these slots are not taken by
regular users using the chest, instead they get copied.
02. License Info:
=================
License for Code
----------------
Copyright (C) 2017-2022 <Zenon.Seth@gmail.com>
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.
License for Textures, Models and Sounds
---------------------------------------
CC-BY-SA 3.0 UNPORTED. Created by Zenon Seth
03. Current Version
===================
v1.0 : Mod release
04. Installation Instructions
=============================
Copy the entire folder containing this file into your minetest/mods folder.
When running the game through GUI, configure world, select and enable the mod.
When running a server through command line, edit world.mt and mark this mod as 'true' to be loaded
05. Dependencies
================
Minetest engine and Minetest game (see https://www.minetest.net)
06. Bugs/contact info
=====================
Submit bugs on github: https://github.com/ZenonSeth/treasure_chest

1
depends.txt Normal file
View File

@ -0,0 +1 @@
default

238
init.lua Normal file
View File

@ -0,0 +1,238 @@
dofile(minetest.get_modpath("treasure_chest") .. "/utils.lua")
local openedTreasureChestConfigs = {};
local metaStrType = "type";
local metaExpectedType = "traesurechest";
local metaStrOwner = "owner";
local metaIntRefresh = "refresh";
local metaInt0p = "0p";
local metaInt1p = "1p";
local metaInt2p = "2p";
local metaInt3p = "3p";
local metaInt4p = "4p";
local metaInt5p = "5p";
local fieldRefresh = "refresh_interval";
local fieldI0P = "i0p";
local fieldI1P = "i1p";
local fieldI2P = "i2p";
local fieldI3P = "i3p";
local fieldI4P = "i4p";
local fieldI5P = "i5p";
local buttonExit = "exit";
local strDescription = "A chest that gives semi-randomized rewards per player";
local strOneTime = "This is a one-time use chest, and you already opened it!";
local strTooSoon = "To get another reward come back in ";
local strFromRefreshLabel = "Refresh time, in minutes, integer. E.g.: 60 = 1 hour, 1440 = 1 day, 10080 = 1 week";
local strProbabiltiesLabel = "Item probability of being given, integer, range 0..100: 0 = never, 100 = always";
minetest.register_node("treasure_chest:treasure_chest", {
description = strDescription,
tiles = {
"treasurechest_u.png",
"treasurechest_d.png",
"treasurechest_r.png",
"treasurechest_l.png",
"treasurechest_b.png",
"treasurechest_f.png"
},
groups = {cracky = 3},
drop = "",
paramtype2 = "facedir",
can_dig = function(pos, player)
local playerName = player:get_player_name();
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(playerName);
local owner = meta:get_string(metaStrOwner);
if player:get_player_name() == owner or privs.give then
return true;
else
return false;
end
end,
after_place_node =
function(pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta(pos);
meta:set_string(metaStrOwner, placer:get_player_name());
meta:set_int(metaIntRefresh, 1);
meta:set_string(metaStrType, metaExpectedType);
meta:set_int(metaInt0p, 100);
meta:set_int(metaInt1p, 100);
meta:set_int(metaInt2p, 100);
meta:set_int(metaInt3p, 100);
meta:set_int(metaInt4p, 100);
meta:set_int(metaInt5p, 100);
local inv = meta:get_inventory();
inv:set_size("main", 6);
end,
on_rightclick =
function(nodePos, node, player, itemstack, pointed_thing)
local playerName = player:get_player_name();
local spos = nodePos.x..","..nodePos.y..","..nodePos.z;
local gameTime = minetest.get_gametime();
local privs = minetest.get_player_privs(playerName);
local meta = minetest.get_meta(nodePos);
local owner = meta:get_string(metaStrOwner);
local refresh = meta:get_int(metaIntRefresh);
local i0p = meta:get_int(metaInt0p);
local i1p = meta:get_int(metaInt1p);
local i2p = meta:get_int(metaInt2p);
local i3p = meta:get_int(metaInt3p);
local i4p = meta:get_int(metaInt4p);
local i5p = meta:get_int(metaInt5p);
-- clean up some metadata
local tmp = meta:to_table()
local newMetaTable = tmp
if refresh > 0 then
for k,v in pairs(tmp["fields"]) do
if k ~= metaStrOwner
and k ~= metaStrType
and k ~= metaIntRefresh
and k ~= metaInt0p
and k ~= metaInt1p
and k ~= metaInt2p
and k ~= metaInt3p
and k ~= metaInt4p
and k ~= metaInt5p then
local tv = tonumber(v)
if tv then
diff = gameTime - tv
if diff > refresh * 60 then
newMetaTable["fields"] = table.removeKey(newMetaTable["fields"], k)
end
end
end
end
meta:from_table(newMetaTable)
end
-- end clean-up
if privs.server or owner == playerName then
openedTreasureChestConfigs[playerName] = nodePos;
minetest.show_formspec(playerName, "treasure_chest:setup_inventory",
"size[8,8]" ..
"field[0.2,0.2;7.0,0.9;"..fieldRefresh..";"..strFromRefreshLabel..";".. refresh .."]"..
"label[0.2,0.6;"..strProbabiltiesLabel.."]"..
"field[0.5,1.2;1,1;"..fieldI0P..";;"..i0p.."]"..
"field[1.5,1.2;1,1;"..fieldI1P..";;"..i1p.."]"..
"field[2.5,1.2;1,1;"..fieldI2P..";;"..i2p.."]"..
"field[3.5,1.2;1,1;"..fieldI3P..";;"..i3p.."]"..
"field[4.5,1.2;1,1;"..fieldI4P..";;"..i4p.."]"..
"field[5.5,1.2;1,1;"..fieldI5P..";;"..i5p.."]"..
"list[nodemeta:"..spos..";main;0.2,1.8;6.0,1.0;]"..
"button_exit[1.0,2.8;3.0,1.0;"..buttonExit..";Save & Close]"..
"list[current_player;main;0.0,4.0;8.0,4.0;]");
else
local lastTime = meta:get_int(playerName);
local diff;
if lastTime and lastTime > 0 then
diff = gameTime - lastTime;
else
diff = refresh*60 + 1;
end
local singleUseUsed = (lastTime ~= 0) and (refresh < 0);
local notSingleUseButUsed = (refresh > 0) and (lastTime ~= 0) and (diff <= refresh*60);
if singleUseUsed or notSingleUseButUsed then
local reason
if refresh < 0 then
reason = strOneTime
else
diff = (lastTime + refresh * 60) - gameTime
diff = math.floor(diff / 60 + 0.5)
local time = ""
if diff <= 1 then
time = "1 minute"
elseif diff < 60 then
time = diff .. " minutes"
elseif diff < 1440 then
time = math.floor(diff/60 + 0.5) .. " hours"
else
time = math.floor(diff/1440 + 0.5) .. " days"
end
reason = strTooSoon .. time
end
minetest.chat_send_player(playerName, reason);
else
local nodeInv = meta:get_inventory(); --minetest.get_inventory({type="node", pos=nodePos});
local playerInv = player:get_inventory();
local playerWieldedItem = player:get_wielded_item();
-- bit of hard-coding, relying we only have 6 slots. Consider that the formspec is also hardcoded, it's not a huge deal
for index=0,5,1 do
local metaAccessString = index.."p";
local probability = meta:get_int(metaAccessString);
print("wield list name = "..player:get_wield_list());
if (randomCheck(probability)) then
local itemStackToAdd = nodeInv:get_stack("main", index+1); -- +1 for inventory indexing begins at 1
itemStackToAdd = playerInv:add_item("main", itemStackToAdd);
if not itemStackToAdd:is_empty() then
minetest.item_drop(itemStackToAdd, player, player:get_pos());
end
end
end
meta:set_int(playerName, gameTime);
return playerInv:get_stack(player:get_wield_list(), player:get_wield_index()); -- the itemstack we have as input may no longer be valid due to the add_item call above
end
end
end
})
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "treasure_chest:setup_inventory" then
local playerName = player:get_player_name();
if (not fields[fieldRefresh]) then
-- User cancelled, quit now
return true;
end
local pos = openedTreasureChestConfigs[playerName];
if pos == nil then
return;
end
openedTreasureChestConfigs[playerName] = nil;
local meta = minetest.get_meta(pos);
if meta:get_string(metaStrType) ~= metaExpectedType then
return;
end
meta:set_int(metaIntRefresh, clamp(toNum(fields[fieldRefresh], meta:get_int(metaIntRefresh)), -1, nil) );
meta:set_int(metaInt0p, clamp(toNum(fields[fieldI0P], meta:get_int(metaInt0p)), 0, 100));
meta:set_int(metaInt1p, clamp(toNum(fields[fieldI1P], meta:get_int(metaInt1p)), 0, 100));
meta:set_int(metaInt2p, clamp(toNum(fields[fieldI2P], meta:get_int(metaInt2p)), 0, 100));
meta:set_int(metaInt3p, clamp(toNum(fields[fieldI3P], meta:get_int(metaInt3p)), 0, 100));
meta:set_int(metaInt4p, clamp(toNum(fields[fieldI4P], meta:get_int(metaInt4p)), 0, 100));
meta:set_int(metaInt5p, clamp(toNum(fields[fieldI5P], meta:get_int(metaInt5p)), 0, 100));
return true
end
return false
end)
minetest.register_on_leaveplayer(function(player)
local playerName = player:get_player_name()
openedTreasureChestConfigs[playerName] = nil;
end)

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

81
utils.lua Normal file
View File

@ -0,0 +1,81 @@
function table.removeKey(t, k)
local i = 0
local keys, values = {},{}
for k,v in pairs(t) do
i = i + 1
keys[i] = k
values[i] = v
end
while i>0 do
if keys[i] == k then
table.remove(keys, i)
table.remove(values, i)
break
end
i = i - 1
end
local a = {}
for i = 1,#keys do
a[keys[i]] = values[i]
end
return a
end
function splitStringToTable(inputString, splitter)
local ret = {};
local tmp;
if inputString == nil then return nil; end
if (splitter == nil) then
table.insert(ret, inputString);
return ret;
end
-- print("inputString: " .. inputString .. ", splitter:" .. splitter);
local found = true;
while found do
local s,e = inputString:find(splitter);
if s == nil then
table.insert(ret, inputString);
found = false;
else
-- print("s/e=" .. s .. "/" .. e);
tmp = inputString:sub(0,s - 1);
table.insert(ret, tmp);
inputString = inputString:sub(e + 1);
end
end
-- for k,v in pairs(ret) do print(k,v) end
return ret;
end
function tableLength(table)
if (table == nil) then return 0; end
local count = 0
for _ in pairs(table) do count = count + 1 end
return count
end
function clamp(value, min, max)
if value == nil then return nil; end
if max == nil and min == nil then return value; end
if min == nil then return math.min(value, max); end
if max == nil then return math.max(value, min); end
return math.max(math.min(value, max), min);
end
function toNum(number, default)
default = default or 0;
return tonumber(number) or default;
end
function randomCheck(normalizedIntProb, minValue, maxValue)
minValue = toNum(minValue, 1);
maxValue = toNum(maxValue, 100);
return math.random(1,100) <= toNum(normalizedIntProb);
end