Initial commit
commit
a848727201
|
@ -0,0 +1,59 @@
|
|||
|
||||
Survival Mod API
|
||||
----------------
|
||||
This is the Application Program Interface for the Survival Lib.
|
||||
Please note that this API is still WIP, so it may change in the future.
|
||||
|
||||
Core
|
||||
----
|
||||
|
||||
survival.create_meter(name, meterdef)
|
||||
Creates a new custom meter. <name> must follow the `modname:itemname'
|
||||
naming convention.
|
||||
|
||||
meterdef = {
|
||||
description = "My Fabulous Meter"
|
||||
Description for the inventory.
|
||||
command = <metercmddef>
|
||||
Used to register a chat command to see the current value. See below.
|
||||
recipe = { <recipe table> }
|
||||
Recipe used to craft the meter item.
|
||||
image = "modname_texname.png"
|
||||
Image used both for wielding and in inventory.
|
||||
get_value = func(player)
|
||||
Must return the value to show both in the status message and in the
|
||||
meter item. Returned value must be in range [0..100].
|
||||
on_use = func(itemstack, user, pointed_thing)
|
||||
Callback for when the item is used. Same as for itemdef.
|
||||
}
|
||||
|
||||
metercmddef = {
|
||||
name = "foo"
|
||||
Name for the chat command.
|
||||
label = "Foo"
|
||||
Label for the chat command. If not specified defaults to <name>.
|
||||
Invoking /cmdname outputs the following:
|
||||
Label: [67%] ||||||
|
||||
}
|
||||
|
||||
survival.distance3d(p1, p2)
|
||||
Returns the distance between two 3D points. <p1> and <p2> are position
|
||||
tables ({x=X,y=Y,z=Z}).
|
||||
|
||||
Drowning Mod
|
||||
------------
|
||||
|
||||
survival.drowning.register_liquid(name)
|
||||
Registers the specified node name as liquid. Please rememeber you need
|
||||
to register BOTH the _source and _flowing variants! Liquids registered
|
||||
by this function are checked to see if the player is drowning, and are
|
||||
also checked by the air bubbles. The mod already registers water, lava,
|
||||
and oil (from the Oil Mod), both in source and flowing form.
|
||||
|
||||
Hunger Mod
|
||||
----------
|
||||
|
||||
survival.hunger.register_food(name)
|
||||
Registers a new item as food. Please note that the mod registers most
|
||||
known food items automatically, and also registers any item with the
|
||||
"food" and/or "eatable" groups.
|
|
@ -0,0 +1,57 @@
|
|||
|
||||
Unless otherwise noted, all code files fall under the BSD 2 clause license
|
||||
reproduced below:
|
||||
|
||||
--- START OF BSD LICENSE ---
|
||||
|
||||
Copyright (c) 2013, Diego Martínez
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--- END OF BSD LICENSE ---
|
||||
|
||||
Textures are released under WTFPL, reproduced below.
|
||||
|
||||
--- START OF WTFPL ---
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
--- END OF WTFPL ---
|
||||
|
||||
Sound files were obtained from various sites on the net. They were released
|
||||
under the Creative Commons Zero license.
|
||||
|
||||
See http://creativecommons.org/publicdomain/zero/1.0/legalcode
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
Survival Mod for Minetest
|
||||
-------------------------
|
||||
|
||||
Copyright (C) 2013 Diego Martínez <lkaezadl3@gmail.com>
|
||||
|
||||
This mod adds new hazards to the survival aspect of the game.
|
||||
Currently, this adds hunger and drowning. It's planned to add thirst,
|
||||
stamina (tiredness), and heat in the future.
|
||||
|
||||
See the file `LICENSE.txt' for information about distribution.
|
||||
|
||||
The survival_drowning mod is a modified version of the drowning mod by [who?].
|
||||
The survival_hunger mod was written from scratch inspired by the existing
|
||||
hunger mod by [who?].
|
||||
|
||||
Forum topic: [TODO: Reserve topic]
|
||||
Download: https://github.com/kaeza/minetest-survival_modpack/archive/master.zip
|
||||
Github Repo: https://github.com/kaeza/minetest-survival_modpack
|
||||
|
||||
INSTALLING
|
||||
----------
|
||||
Unpack the modpack into one of the directories where Minetest looks for mods.
|
||||
For more information, see http://wiki.minetest.com/wiki/Installing_mods
|
||||
|
||||
See the respective mods' README.txt for information about technical aspects
|
||||
of the implementation and known bugs.
|
||||
|
||||
CONFIGURING
|
||||
-----------
|
||||
The mod can be configured by means of a `survival_lib.conf' file. This file
|
||||
is read first from the survival_lib mod's directory, and then from the
|
||||
current world directory (so you can have different settings per world).
|
||||
Options set in `survival_lib/survival_lib.conf' override the defaults, and
|
||||
those set in `<worlddir>/survival_lib.conf' override these, so you can
|
||||
specify global defaults in the mod dir, and override those settings in the
|
||||
world dir.
|
||||
|
||||
See `survival_lib.conf.example' for an example of what can be configured.
|
|
@ -0,0 +1 @@
|
|||
# This is a modpack. YAY!
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
Drowning Mod for Minetest
|
||||
This mod is part of the Survival Modpack for Minetest.
|
||||
Copyright (C) 2013 Diego Martínez <lkaezadl3@gmail.com>
|
||||
Inspired by the existing drowning mod [TODO: who's the author?]
|
||||
|
||||
See the file `../LICENSE.txt' for information about distribution.
|
||||
|
||||
TECHNICAL NOTES
|
||||
---------------
|
||||
To detect if the player is under water (to restore the oxygen timer), this
|
||||
mod has to know about all the nodes considered "liquid". It currently handles
|
||||
water_{source|flowing}, lava_{source|flowing}, and oil_{source|flowing} from
|
||||
the Oil Mod.
|
||||
|
||||
The original drowning mod checked whether or not there was an air node at the
|
||||
player's head, but this was inaccurate as you could "drown" by standing
|
||||
"inside" a torch node, or other walkable nodes.
|
|
@ -0,0 +1,2 @@
|
|||
default
|
||||
survival_lib
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
drowning = { };
|
||||
|
||||
local players_under_water = { };
|
||||
|
||||
local START_DROWNING_TIME = survival.conf_getnum("drowning.damage_start_time", 20);
|
||||
local DROWNING_TIME = survival.conf_getnum("drowning.damage_interval", 2);
|
||||
local DROWNING_DAMAGE = survival.conf_getnum("drowning.damage", 1);
|
||||
local DTIME = survival.conf_getnum("drowning.check_interval", 0.5);
|
||||
|
||||
local timer = 0;
|
||||
|
||||
local liquids = { };
|
||||
|
||||
-- Boilerplate to support localized strings if intllib mod is installed.
|
||||
local S;
|
||||
if (minetest.get_modpath("intllib")) then
|
||||
dofile(minetest.get_modpath("intllib").."/intllib.lua");
|
||||
S = intllib.load_strings("survival_drowning");
|
||||
else
|
||||
S = function ( s ) return s; end
|
||||
end
|
||||
|
||||
minetest.register_entity("survival_drowning:bubbles", {
|
||||
physical = false;
|
||||
timer = 0;
|
||||
textures = { "survival_drowning_bubbles.png" };
|
||||
collisionbox = { 0, 0, 0, 0, 0, 0 };
|
||||
on_step = function ( self, dtime )
|
||||
self.timer = self.timer + dtime;
|
||||
if (self.timer > 0.5) then
|
||||
self.timer = self.timer - 0.5;
|
||||
local pos = self.object:getpos();
|
||||
pos.y = pos.y + 1;
|
||||
if (not liquids[minetest.env:get_node(pos).name]) then
|
||||
self.object:remove();
|
||||
end
|
||||
end
|
||||
end;
|
||||
});
|
||||
|
||||
if (minetest.setting_getbool("enable_damage") and survival.conf_getbool("drowning.enabled", true)) then
|
||||
print("survival_drowning: Drowning is enabled!");
|
||||
minetest.register_globalstep(function ( dtime )
|
||||
timer = timer + dtime;
|
||||
if (timer < DTIME) then
|
||||
return;
|
||||
end
|
||||
timer = timer - DTIME;
|
||||
for k, v in pairs(minetest.get_connected_players()) do
|
||||
name = v:get_player_name();
|
||||
if (not players_under_water[name]) then
|
||||
players_under_water[name] = { count=0, drowning=false };
|
||||
end
|
||||
local puw = players_under_water[name];
|
||||
local pos = v:getpos()
|
||||
pos.y = pos.y + 1;
|
||||
if (is_player_under_liquid(v)) then
|
||||
puw.count = puw.count + 0.5;
|
||||
if (math.random(1, 100) < 20) then
|
||||
if (not liquids[minetest.env:get_node({ x=pos.x; y=pos.y+8; z=pos.z}).name]) then
|
||||
local bub = minetest.env:add_entity(pos, "survival_drowning:bubbles");
|
||||
bub:setvelocity({ x=0; y=1; z=0 });
|
||||
end
|
||||
end
|
||||
if ((not puw.drowning) and (puw.count >= START_DROWNING_TIME)) then
|
||||
players_under_water[name] = {count=0, drowning=true}
|
||||
v:set_hp(v:get_hp() - DROWNING_DAMAGE);
|
||||
minetest.sound_play({ name="drowning_gurp"; }, { pos = pos; gain = 1.0; max_hear_distance = 16; });
|
||||
puw.drowning = true;
|
||||
puw.count = puw.count - START_DROWNING_TIME;
|
||||
minetest.chat_send_player(name, S("You are out of oxygen."));
|
||||
elseif (puw.drowning and (puw.count >= DROWNING_TIME)) then
|
||||
v:set_hp(v:get_hp() - DROWNING_DAMAGE);
|
||||
minetest.sound_play({ name="drowning_gurp"; }, { pos = pos; gain = 1.0; max_hear_distance = 16; });
|
||||
puw.count = puw.count - DROWNING_TIME;
|
||||
if (v:get_hp() <= 0) then
|
||||
minetest.chat_send_player(name, S("You drowned."));
|
||||
end
|
||||
end
|
||||
else
|
||||
if (puw.count > 0) then
|
||||
pos = v:getpos();
|
||||
pos.y = pos.y + 1;
|
||||
minetest.sound_play({ name="drowning_gasp" }, { pos = pos; gain = 1.0; max_hear_distance = 32; });
|
||||
end
|
||||
puw.count = 0;
|
||||
puw.drowning = false;
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function is_player_under_liquid(player)
|
||||
local pos = player:getpos()
|
||||
pos.y = pos.y + 1.5;
|
||||
|
||||
return (liquids[minetest.env:get_node(pos).name]);
|
||||
end
|
||||
|
||||
survival.drowning = { };
|
||||
|
||||
survival.drowning.register_liquid = function ( name )
|
||||
liquids[name] = true;
|
||||
end
|
||||
|
||||
survival.drowning.is_liquid = function ( name )
|
||||
return liquids[name];
|
||||
end
|
||||
|
||||
survival.drowning.is_liquid_at_pos = function ( pos )
|
||||
local name = minetest.env:get_node(pos).name;
|
||||
return liquids[name];
|
||||
end
|
||||
|
||||
survival.drowning.register_liquid("default:water_source");
|
||||
survival.drowning.register_liquid("default:water_flowing");
|
||||
survival.drowning.register_liquid("default:lava_source");
|
||||
survival.drowning.register_liquid("default:lava_flowing");
|
||||
survival.drowning.register_liquid("oil:oil_source");
|
||||
survival.drowning.register_liquid("oil:oil_flowing");
|
||||
|
||||
survival.create_meter("survival_drowning:meter", {
|
||||
description = S("Oxygen Meter");
|
||||
command = {
|
||||
name = "o2";
|
||||
label = S("Oxygen");
|
||||
};
|
||||
image = "survival_drowning_meter.png";
|
||||
get_value = function ( player )
|
||||
local name = player:get_player_name();
|
||||
if (players_under_water[name].drowning) then
|
||||
return 0.01;
|
||||
else
|
||||
return 100 * (START_DROWNING_TIME - players_under_water[name].count) / START_DROWNING_TIME;
|
||||
end
|
||||
end;
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
# Language: Español
|
||||
# Author: Diego Martínez <lkaezadl3@gmail.com>
|
||||
|
||||
You are out of oxygen.::Te has quedado sin oxigeno.
|
||||
You drowned.::Te has ahogado.
|
||||
Oxygen Meter::Medidor de Oxigeno
|
||||
Oxygen::Oxigeno
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 154 B |
Binary file not shown.
After Width: | Height: | Size: 179 B |
|
@ -0,0 +1,26 @@
|
|||
|
||||
Hunger Mod for Minetest
|
||||
This mod is part of the Survival Modpack for Minetest.
|
||||
Copyright (C) 2013 Diego Martínez <lkaezadl3@gmail.com>
|
||||
Inspired by the existing hunger mod [TODO: who's the author?]
|
||||
|
||||
See the file `../LICENSE.txt' for information about distribution.
|
||||
|
||||
TECHNICAL NOTES
|
||||
---------------
|
||||
In order to detect if the player ate an item (to restore the hunger timer),
|
||||
this mod overrides the on_use callback of all known food items, resetting the
|
||||
timer and calling the callback to perform the actual healing. This has the
|
||||
advantage that the hunger timer is reset whenever the player "eats" the item,
|
||||
but new food items must be explicitly listed on the script for the mod to
|
||||
"know" it's food.
|
||||
|
||||
At first, this was implemented by checking whether the player's HP increased
|
||||
since the last check, but this has several disadvantages:
|
||||
|
||||
- It's not possible to have separate "hunger" and "thirst" if the drink
|
||||
item increases HP, because this would also be taken as eating.
|
||||
- When the HP is at max, eating a food item does not reset the hunger timer
|
||||
since there was no increase in HP.
|
||||
- Other healing mechanisms (such as the medikit blocks) may interfere with
|
||||
the detection.
|
|
@ -0,0 +1,2 @@
|
|||
default
|
||||
survival_lib
|
|
@ -0,0 +1,154 @@
|
|||
|
||||
local START_HUNGER_TIME = survival.conf_getnum("hunger.damage_start_time", 720);
|
||||
local HUNGER_TIME = survival.conf_getnum("hunger.damage_interval", 30);
|
||||
local HUNGER_DAMAGE = survival.conf_getnum("hunger.damage", 4);
|
||||
local DTIME = survival.conf_getnum("hunger.check_interval", 0.5);
|
||||
|
||||
-- Boilerplate to support localized strings if intllib mod is installed.
|
||||
local S;
|
||||
if (minetest.get_modpath("intllib")) then
|
||||
dofile(minetest.get_modpath("intllib").."/intllib.lua");
|
||||
S = intllib.load_strings("survival_hunger");
|
||||
else
|
||||
S = function ( s ) return s; end
|
||||
end
|
||||
|
||||
local timer = 0;
|
||||
|
||||
local hungry_players = { };
|
||||
|
||||
if (minetest.setting_getbool("enable_damage") and survival.conf_getbool("hunger.enabled", true)) then
|
||||
minetest.register_globalstep(function ( dtime )
|
||||
timer = timer + dtime;
|
||||
if (timer < DTIME) then return; end
|
||||
timer = timer - DTIME;
|
||||
for i, v in ipairs(minetest.get_connected_players()) do
|
||||
local name = v:get_player_name();
|
||||
if (not hungry_players[name]) then
|
||||
hungry_players[name] = {
|
||||
count = 0;
|
||||
hungry = false;
|
||||
next = START_HUNGER_TIME;
|
||||
};
|
||||
end
|
||||
local hdata = hungry_players[name];
|
||||
hdata.count = hdata.count + DTIME;
|
||||
if ((v:get_hp() > 0) and (hdata.count >= hdata.next)) then
|
||||
v:set_hp(v:get_hp() - HUNGER_DAMAGE);
|
||||
if (v:get_hp() <= 0) then
|
||||
minetest.chat_send_player(name, S("You died from starvation."));
|
||||
end
|
||||
hdata.count = hdata.count - hdata.next;
|
||||
hdata.next = HUNGER_TIME;
|
||||
hdata.hungry = true;
|
||||
minetest.sound_play({ name="survival_hunger_stomach" }, {
|
||||
pos = v:getpos();
|
||||
gain = 1.0;
|
||||
max_hear_distance = 16;
|
||||
});
|
||||
end
|
||||
end
|
||||
end);
|
||||
end
|
||||
|
||||
survival.create_meter("survival_hunger:meter", {
|
||||
description = S("Hunger Meter");
|
||||
command = {
|
||||
name = "hunger";
|
||||
label = S("Hunger");
|
||||
};
|
||||
image = "survival_hunger_meter.png";
|
||||
get_value = function ( player )
|
||||
local name = player:get_player_name();
|
||||
if (hungry_players[name].hungry) then
|
||||
return 0;
|
||||
else
|
||||
return 100 * (START_HUNGER_TIME - hungry_players[name].count) / START_HUNGER_TIME;
|
||||
end
|
||||
end;
|
||||
});
|
||||
|
||||
-- Known food items (more suggestions are welcome)
|
||||
local known_foods = {
|
||||
|
||||
-- Default game --
|
||||
"default:apple",
|
||||
|
||||
-- PilzAdam's farming[_plus] --
|
||||
"farming:bread",
|
||||
"farming:pumpkin_bread",
|
||||
"farming_plus:orange_item",
|
||||
"farming_plus:tomato_item",
|
||||
"farming_plus:strawberry_item",
|
||||
"farming_plus:carrot_item",
|
||||
"farming_plus:banana",
|
||||
|
||||
-- rubenwardy's food --
|
||||
"food:cheese", "food:chocolate_dark", "food:chocolate_milk",
|
||||
"food:coffee", "food:hotchoco", "food:ms_chocolate", "food:bread_slice",
|
||||
"food:bun", "food:sw_meat", "food:sw_cheese", "food:cake",
|
||||
"food:cake_chocolate", "food:cake_carrot", "food:crumble_rhubarb",
|
||||
"food:banana_split", "food:bread", "food:strawberry", "food:carrot",
|
||||
"food:banana", "food:meat_raw", "food:milk",
|
||||
-- These will be better for thirst
|
||||
--"food:apple_juice", "food:cactus_juice",
|
||||
|
||||
-- GloopMaster's gloopores --
|
||||
-- "gloopores:kalite_lump", -- TODO: Should this be considered "food"?
|
||||
|
||||
-- Sapier's animals_modpack (MOB Framework) --
|
||||
"animalmaterials:meat_pork", "animalmaterials:meat_beef",
|
||||
"animalmaterials:meat_chicken", "animalmaterials:meat_lamb",
|
||||
"animalmaterials:meat_venison", "animalmaterials:meat_toxic",
|
||||
"animalmaterials:meat_ostrich", "animalmaterials:meat_undead",
|
||||
"animalmaterials:fish_bluewhite", "animalmaterials:fish_clownfish",
|
||||
"animalmaterials:milk",
|
||||
|
||||
};
|
||||
|
||||
local function override_on_use ( def )
|
||||
local on_use = def.on_use;
|
||||
def.on_use = function ( itemstack, user, pointed_thing )
|
||||
if (on_use) then
|
||||
local r = on_use(itemstack, user, pointed_thing);
|
||||
hungry_players[user:get_player_name()] = {
|
||||
count = 0;
|
||||
hungry = false;
|
||||
next = START_HUNGER_TIME;
|
||||
};
|
||||
minetest.sound_play({ name="survival_hunger_eat" }, {
|
||||
to_player = user:getpos();
|
||||
gain = 1.0;
|
||||
});
|
||||
return r;
|
||||
end
|
||||
return itemstack;
|
||||
end
|
||||
end
|
||||
|
||||
-- Try to override the on_use callback of as many food items as possible.
|
||||
minetest.after(1, function ( )
|
||||
|
||||
for _,name in ipairs(known_foods) do
|
||||
local def = minetest.registered_items[name] or minetest.registered_nodes[name];
|
||||
if (def) then
|
||||
override_on_use(def);
|
||||
end
|
||||
end
|
||||
|
||||
for name, def in pairs(minetest.registered_items) do
|
||||
if (def.groups and def.groups.food and (def.groups.food > 0)) then
|
||||
override_on_use(def);
|
||||
end
|
||||
end
|
||||
|
||||
end);
|
||||
|
||||
minetest.register_on_dieplayer(function ( player )
|
||||
local name = player:get_player_name();
|
||||
hungry_players[name] = {
|
||||
count = 0;
|
||||
hungry = false;
|
||||
next = START_HUNGER_TIME;
|
||||
};
|
||||
end);
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
# Language: Español
|
||||
# Author: Diego Martínez <lkaezadl3@gmail.com>
|
||||
|
||||
You died from starvation.::Has muerto de hambre.
|
||||
Hunger Meter::Medidor de Hambre
|
||||
Hunger::Hambre
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 284 B |
|
@ -0,0 +1,87 @@
|
|||
|
||||
local config;
|
||||
local config_modified;
|
||||
|
||||
local function do_load_config ( f )
|
||||
|
||||
for line in f:lines() do
|
||||
line = line:trim();
|
||||
local c1 = line:sub(1, 1);
|
||||
local eq_pos = line:find("=", 1, true);
|
||||
if ((c1 ~= "#") and (c1 ~= ";") and eq_pos) then
|
||||
local name = line:sub(1, eq_pos - 1):trim();
|
||||
local value = line:sub(eq_pos + 1):trim();
|
||||
config[name] = value;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local CONF_FILE = minetest.get_worldpath().."/survival_lib.conf";
|
||||
|
||||
local config_files = {
|
||||
minetest.get_modpath("survival_lib").."/survival_lib.conf",
|
||||
CONF_FILE,
|
||||
};
|
||||
|
||||
local function load_config ( )
|
||||
|
||||
config = { };
|
||||
|
||||
for _,file in ipairs(config_files) do
|
||||
local f = io.open(file);
|
||||
if (f) then
|
||||
do_load_config(f);
|
||||
f:close();
|
||||
print("survival_lib: Loaded config from `"..file.."'");
|
||||
end
|
||||
end
|
||||
|
||||
config_modified = false;
|
||||
|
||||
end
|
||||
|
||||
load_config();
|
||||
|
||||
survival.conf_set = function ( name, value )
|
||||
config[name] = tostring(value);
|
||||
config_modified = true;
|
||||
end
|
||||
|
||||
-- Just an alias
|
||||
survival.conf_setnum = survival.conf_set;
|
||||
|
||||
survival.conf_setbool = function ( name, value )
|
||||
config[name] = (value and "true") or "false";
|
||||
config_modified = true;
|
||||
end
|
||||
|
||||
survival.conf_setpos = function ( name, value )
|
||||
config[name] = minetest.pos_to_string(value);
|
||||
config_modified = true;
|
||||
end
|
||||
|
||||
survival.conf_get = function ( name, default )
|
||||
return (config[name] or default);
|
||||
end
|
||||
|
||||
survival.conf_getnum = function ( name, default )
|
||||
return (tonumber(config[name]) or default);
|
||||
end
|
||||
|
||||
survival.conf_getpos = function ( name, default )
|
||||
return ((config[name] and minetest.string_to_pos(config[name])) or default);
|
||||
end
|
||||
|
||||
survival.conf_getbool = function ( name, default )
|
||||
local val = config[name];
|
||||
if (not val) then return default; end
|
||||
val = val:lower();
|
||||
return (
|
||||
(val == "true")
|
||||
or (val == "on")
|
||||
or (val == "enabled")
|
||||
or (val == "yes")
|
||||
or (tonumber(val) and (tonumber(val) ~= 0))
|
||||
);
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
default
|
|
@ -0,0 +1,123 @@
|
|||
|
||||
local TESTING = false;
|
||||
|
||||
survival = { };
|
||||
|
||||
survival.meters = { };
|
||||
|
||||
survival.distance3d = function ( p1, p2 )
|
||||
local lenx = math.abs(p2.x - p1.x);
|
||||
local leny = math.abs(p2.y - p1.y);
|
||||
local lenz = math.abs(p2.z - p1.z);
|
||||
local hypotxz = math.sqrt((lenx * lenx) + (lenz * lenz));
|
||||
return math.sqrt((hypotxz * hypotxz) + (leny * leny));
|
||||
end
|
||||
|
||||
dofile(minetest.get_modpath("survival_lib").."/config.lua");
|
||||
|
||||
survival.create_meter = function ( name, def )
|
||||
minetest.register_tool(name, {
|
||||
description = def.description;
|
||||
inventory_image = def.image;
|
||||
on_use = def.on_use;
|
||||
});
|
||||
if (def.command and def.command.name) then
|
||||
local lbl = (def.command.label or def.command.name);
|
||||
def.command.func = function ( name, param )
|
||||
local ply = minetest.env:get_player_by_name(name);
|
||||
local val = math.floor(def.get_value(ply));
|
||||
local val2 = math.max(0, math.min(val / 10, 10));
|
||||
minetest.chat_send_player(name, lbl..": ["..val.."%] "..string.rep("|", val2));
|
||||
end;
|
||||
minetest.register_chatcommand(def.command.name, {
|
||||
params = "";
|
||||
description = "Display "..lbl;
|
||||
func = def.command.func;
|
||||
});
|
||||
end
|
||||
if (def.recipe) then
|
||||
minetest.register_craft({
|
||||
output = name;
|
||||
recipe = def.recipe;
|
||||
});
|
||||
end
|
||||
def.name = name;
|
||||
survival.meters[name] = def;
|
||||
survival.meters[#survival.meters + 1] = def;
|
||||
end
|
||||
|
||||
local chat_cmd_def = {
|
||||
params = "";
|
||||
description = "Display all player stats";
|
||||
func = function ( name, param )
|
||||
for i, def in ipairs(survival.meters) do
|
||||
if (def.command and def.command.func and (not def.command.not_in_plstats)) then
|
||||
def.command.func(name, "");
|
||||
end
|
||||
end
|
||||
end;
|
||||
};
|
||||
|
||||
minetest.register_chatcommand("plstats", chat_cmd_def);
|
||||
minetest.register_chatcommand("s", chat_cmd_def);
|
||||
|
||||
local timer = 0;
|
||||
local MAX_TIMER = 1;
|
||||
|
||||
minetest.register_globalstep(function ( dtime )
|
||||
|
||||
timer = timer + dtime;
|
||||
if (timer < MAX_TIMER) then return; end
|
||||
|
||||
timer = timer - MAX_TIMER;
|
||||
|
||||
for _,player in pairs(minetest.get_connected_players()) do
|
||||
local inv = player:get_inventory();
|
||||
for name, def in pairs(survival.meters) do
|
||||
if (def.on_step) then
|
||||
def.on_step(player);
|
||||
end
|
||||
if (survival.conf_getbool("meters_enabled", true)
|
||||
and inv:contains_item("main", ItemStack(name))) then
|
||||
for i = 1, inv:get_size("main") do
|
||||
local stack = inv:get_stack("main", i);
|
||||
if (stack:get_name() == name) then
|
||||
local value = (65535 * def.get_value(player) / 100);
|
||||
--local wear = stack:get_wear();
|
||||
inv:remove_item("main", stack);
|
||||
stack:add_wear(-65535);
|
||||
stack:add_wear(65534);
|
||||
stack:add_wear(-(value - 2));
|
||||
inv:set_stack("main", i, stack);
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end);
|
||||
|
||||
if (TESTING) then
|
||||
local ORIGIN = { x=0; y=0; z=0; };
|
||||
local RESOLUTION = 50;
|
||||
survival.create_meter("survival_lib:test_meter", {
|
||||
description = "Survival Lib Test";
|
||||
recipe = {
|
||||
{ "", "default:wood", "" },
|
||||
{ "default:wood", "", "default:wood" },
|
||||
{ "", "default:wood", "" },
|
||||
};
|
||||
image = "survival_utils_test_meter.png";
|
||||
get_value = function ( player )
|
||||
local dist = survival.distance3d(player:getpos(), ORIGIN);
|
||||
dist = math.min(dist, RESOLUTION);
|
||||
return 100 * dist / RESOLUTION;
|
||||
end;
|
||||
on_use = function ( itemstack, user, pointed_thing )
|
||||
local dist = survival.distance3d(user:getpos(), ORIGIN);
|
||||
minetest.chat_send_player(user:get_player_name(), "Distance to origin: "..dist);
|
||||
return itemstack;
|
||||
end;
|
||||
});
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
# ==================
|
||||
# ===== common =====
|
||||
# ==================
|
||||
|
||||
# Whether tool-based meters are enabled (boolean).
|
||||
meters_enabled = true
|
||||
|
||||
# Interval between meter updates (in seconds)
|
||||
meter_check_interval = 1
|
||||
|
||||
# ===========================
|
||||
# ===== survival_hunger =====
|
||||
# ===========================
|
||||
|
||||
# Time before player starts to take hunger damage (in seconds)
|
||||
hunger.damage_start_time = 720
|
||||
|
||||
# Interval before player takes damage again when hungry (in seconds)
|
||||
hunger.damage_interval = 30
|
||||
|
||||
# Damage inflicted by hunger (in half hearts)
|
||||
hunger.damage = 4
|
||||
|
||||
# Interval between state checks (in seconds)
|
||||
hunger.check_interval = 0.5
|
||||
|
||||
# =============================
|
||||
# ===== survival_drowning =====
|
||||
# =============================
|
||||
|
||||
# Time before player starts to take drowning damage (in seconds)
|
||||
drowning.damage_start_time = 20
|
||||
|
||||
# Interval before player takes damage again when drowning (in seconds)
|
||||
drowning.damage_interval = 2
|
||||
|
||||
# Damage inflicted by drowning (in half hearts)
|
||||
drowning.damage = 2
|
||||
|
||||
# Interval between state checks (in seconds)
|
||||
drowning.check_interval = 0.5
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
Hunger Mod for Minetest
|
||||
This mod is part of the Survival Modpack for Minetest.
|
||||
Copyright (C) 2013 Diego Martínez <lkaezadl3@gmail.com>
|
||||
Inspired by the existing hunger mod [TODO: who's the author?]
|
||||
|
||||
See the file `../LICENSE.txt' for information about distribution.
|
||||
|
||||
TECHNICAL NOTES
|
||||
---------------
|
||||
In order to detect if the player ate an item (to restore the hunger timer),
|
||||
this mod overrides the on_use callback of all known food items, resetting the
|
||||
timer and calling the callback to perform the actual healing. This has the
|
||||
advantage that the hunger timer is reset whenever the player "eats" the item,
|
||||
but new food items must be explicitly listed on the script for the mod to
|
||||
"know" it's food.
|
||||
|
||||
At first, this was implemented by checking whether the player's HP increased
|
||||
since the last check, but this has several disadvantages:
|
||||
|
||||
- It's not possible to have separate "hunger" and "thirst" if the drink
|
||||
item increases HP, because this would also be taken as eating.
|
||||
- When the HP is at max, eating a food item does not reset the hunger timer
|
||||
since there was no increase in HP.
|
||||
- Other healing mechanisms (such as the medikit blocks) may interfere with
|
||||
the detection.
|
|
@ -0,0 +1,2 @@
|
|||
default
|
||||
survival_lib
|
|
@ -0,0 +1,154 @@
|
|||
|
||||
local START_HUNGER_TIME = survival.conf_getnum("hunger.damage_start_time", 720);
|
||||
local HUNGER_TIME = survival.conf_getnum("hunger.damage_interval", 30);
|
||||
local HUNGER_DAMAGE = survival.conf_getnum("hunger.damage", 4);
|
||||
local DTIME = survival.conf_getnum("hunger.check_interval", 0.5);
|
||||
|
||||
-- Boilerplate to support localized strings if intllib mod is installed.
|
||||
local S;
|
||||
if (minetest.get_modpath("intllib")) then
|
||||
dofile(minetest.get_modpath("intllib").."/intllib.lua");
|
||||
S = intllib.load_strings("survival_hunger");
|
||||
else
|
||||
S = function ( s ) return s; end
|
||||
end
|
||||
|
||||
local timer = 0;
|
||||
|
||||
local hungry_players = { };
|
||||
|
||||
if (minetest.setting_getbool("enable_damage") and survival.conf_getbool("hunger.enabled", true)) then
|
||||
minetest.register_globalstep(function ( dtime )
|
||||
timer = timer + dtime;
|
||||
if (timer < DTIME) then return; end
|
||||
timer = timer - DTIME;
|
||||
for i, v in ipairs(minetest.get_connected_players()) do
|
||||
local name = v:get_player_name();
|
||||
if (not hungry_players[name]) then
|
||||
hungry_players[name] = {
|
||||
count = 0;
|
||||
hungry = false;
|
||||
next = START_HUNGER_TIME;
|
||||
};
|
||||
end
|
||||
local hdata = hungry_players[name];
|
||||
hdata.count = hdata.count + DTIME;
|
||||
if ((v:get_hp() > 0) and (hdata.count >= hdata.next)) then
|
||||
v:set_hp(v:get_hp() - HUNGER_DAMAGE);
|
||||
if (v:get_hp() <= 0) then
|
||||
minetest.chat_send_player(name, S("You died from starvation."));
|
||||
end
|
||||
hdata.count = hdata.count - hdata.next;
|
||||
hdata.next = HUNGER_TIME;
|
||||
hdata.hungry = true;
|
||||
minetest.sound_play({ name="survival_hunger_stomach" }, {
|
||||
pos = v:getpos();
|
||||
gain = 1.0;
|
||||
max_hear_distance = 16;
|
||||
});
|
||||
end
|
||||
end
|
||||
end);
|
||||
end
|
||||
|
||||
survival.create_meter("survival_hunger:meter", {
|
||||
description = S("Hunger Meter");
|
||||
command = {
|
||||
name = "hunger";
|
||||
label = S("Hunger");
|
||||
};
|
||||
image = "survival_hunger_meter.png";
|
||||
get_value = function ( player )
|
||||
local name = player:get_player_name();
|
||||
if (hungry_players[name].hungry) then
|
||||
return 0;
|
||||
else
|
||||
return 100 * (START_HUNGER_TIME - hungry_players[name].count) / START_HUNGER_TIME;
|
||||
end
|
||||
end;
|
||||
});
|
||||
|
||||
-- Known food items (more suggestions are welcome)
|
||||
local known_foods = {
|
||||
|
||||
-- Default game --
|
||||
"default:apple",
|
||||
|
||||
-- PilzAdam's farming[_plus] --
|
||||
"farming:bread",
|
||||
"farming:pumpkin_bread",
|
||||
"farming_plus:orange_item",
|
||||
"farming_plus:tomato_item",
|
||||
"farming_plus:strawberry_item",
|
||||
"farming_plus:carrot_item",
|
||||
"farming_plus:banana",
|
||||
|
||||
-- rubenwardy's food --
|
||||
"food:cheese", "food:chocolate_dark", "food:chocolate_milk",
|
||||
"food:coffee", "food:hotchoco", "food:ms_chocolate", "food:bread_slice",
|
||||
"food:bun", "food:sw_meat", "food:sw_cheese", "food:cake",
|
||||
"food:cake_chocolate", "food:cake_carrot", "food:crumble_rhubarb",
|
||||
"food:banana_split", "food:bread", "food:strawberry", "food:carrot",
|
||||
"food:banana", "food:meat_raw", "food:milk",
|
||||
-- These will be better for thirst
|
||||
--"food:apple_juice", "food:cactus_juice",
|
||||
|
||||
-- GloopMaster's gloopores --
|
||||
-- "gloopores:kalite_lump", -- TODO: Should this be considered "food"?
|
||||
|
||||
-- Sapier's animals_modpack (MOB Framework) --
|
||||
"animalmaterials:meat_pork", "animalmaterials:meat_beef",
|
||||
"animalmaterials:meat_chicken", "animalmaterials:meat_lamb",
|
||||
"animalmaterials:meat_venison", "animalmaterials:meat_toxic",
|
||||
"animalmaterials:meat_ostrich", "animalmaterials:meat_undead",
|
||||
"animalmaterials:fish_bluewhite", "animalmaterials:fish_clownfish",
|
||||
"animalmaterials:milk",
|
||||
|
||||
};
|
||||
|
||||
local function override_on_use ( def )
|
||||
local on_use = def.on_use;
|
||||
def.on_use = function ( itemstack, user, pointed_thing )
|
||||
if (on_use) then
|
||||
local r = on_use(itemstack, user, pointed_thing);
|
||||
hungry_players[user:get_player_name()] = {
|
||||
count = 0;
|
||||
hungry = false;
|
||||
next = START_HUNGER_TIME;
|
||||
};
|
||||
minetest.sound_play({ name="survival_hunger_eat" }, {
|
||||
to_player = user:getpos();
|
||||
gain = 1.0;
|
||||
});
|
||||
return r;
|
||||
end
|
||||
return itemstack;
|
||||
end
|
||||
end
|
||||
|
||||
-- Try to override the on_use callback of as many food items as possible.
|
||||
minetest.after(1, function ( )
|
||||
|
||||
for _,name in ipairs(known_foods) do
|
||||
local def = minetest.registered_items[name] or minetest.registered_nodes[name];
|
||||
if (def) then
|
||||
override_on_use(def);
|
||||
end
|
||||
end
|
||||
|
||||
for name, def in pairs(minetest.registered_items) do
|
||||
if (def.groups and def.groups.food and (def.groups.food > 0)) then
|
||||
override_on_use(def);
|
||||
end
|
||||
end
|
||||
|
||||
end);
|
||||
|
||||
minetest.register_on_dieplayer(function ( player )
|
||||
local name = player:get_player_name();
|
||||
hungry_players[name] = {
|
||||
count = 0;
|
||||
hungry = false;
|
||||
next = START_HUNGER_TIME;
|
||||
};
|
||||
end);
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
# Language: Español
|
||||
# Author: Diego Martínez <lkaezadl3@gmail.com>
|
||||
|
||||
You died from starvation.::Has muerto de hambre.
|
||||
Hunger Meter::Medidor de Hambre
|
||||
Hunger::Hambre
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 284 B |
Loading…
Reference in New Issue