Compare commits

...

23 Commits

Author SHA1 Message Date
teknomunk 73c5c2ffa6 Get settings GUI implemented and functional 2024-09-28 09:41:46 -05:00
teknomunk 3e55207b78 Start GUI 2024-09-28 09:41:46 -05:00
teknomunk 2855cc9750 Fix typo in variable name 2024-09-28 09:41:46 -05:00
teknomunk 5ba9e91c0d Implement showDeathMessages gamerule 2024-09-28 09:41:44 -05:00
teknomunk f8f6398661 Implement respawnBlocksExplode gamerule 2024-09-28 09:41:03 -05:00
teknomunk 9af61bd342 Implement doMobLoot gamerule 2024-09-28 09:41:03 -05:00
teknomunk c65cf67a46 Add fireDamage game rule (fallDamage and drowningDamage don't work in mcl_damage) 2024-09-28 09:41:03 -05:00
teknomunk 4cf4cdebf0 Add additional gamerules for damage types 2024-09-28 09:41:03 -05:00
teknomunk 9d42f6391b Fix typo 2024-09-28 09:41:03 -05:00
teknomunk e40dddbb04 Add gamerule naturalRegeneration and make mcl_health_regen_delay a tunable setting 2024-09-28 09:41:03 -05:00
teknomunk 2b16244640 Change handling of mcl_showAdvancementMessages 2024-09-28 09:41:03 -05:00
teknomunk e1494ff773 Nether portal delay settings 2024-09-28 09:41:03 -05:00
teknomunk 5e8b1e068c Add settings file 2024-09-28 09:41:03 -05:00
teknomunk 3185eb1314 Implement doVinesSpread 2024-09-28 09:41:03 -05:00
teknomunk b2b0075cbb Add gamerule keepInventory and migrate existing setting value from mcl_keepInvetory 2024-09-28 09:41:03 -05:00
teknomunk 8d6dbc3235 Add setting for damage_enabled 2024-09-28 09:41:03 -05:00
teknomunk 16726d8df7 Implement doDaylightCycle, add on_change hook for tunables and make sure they are not called when loaded 2024-09-28 09:41:03 -05:00
teknomunk 488670dd4f Remove debug print(), add game rules maxEntityCramming, snowAccumulationHeight 2024-09-28 09:41:03 -05:00
teknomunk 6815119f85 Fix default value handling during set (allows bool settings to be set to false), add game rules: doMobSpawning, disableRaids, doWeatherCycle, doFireTick 2024-09-28 09:41:03 -05:00
teknomunk 27b088074b Change API so most parameters are in a definition table, add /gamerule chatcommand, implement gamerule announceAdvancements 2024-09-28 09:41:03 -05:00
teknomunk 731a144e07 Make awards use the notification delay setting 2024-09-28 09:41:03 -05:00
teknomunk cbee3e3346 Finish initial implementation of setting tuning with get/set commands 2024-09-28 09:41:03 -05:00
teknomunk c48873e695 Start implementing dynamic rules/tuning 2024-09-28 09:41:03 -05:00
40 changed files with 466 additions and 61 deletions

View File

@ -34,7 +34,18 @@ mcl_damage = {
} }
} }
local damage_enabled = minetest.settings:get_bool("enabled_damage",true) local damage_enabled = vl_tuning.setting("damage_enabled", "bool",{
default = minetest.settings:get_bool("enabled_damage",true)
})
local fall_damage_enabled = vl_tuning.setting("gamerule:fallDamage", "bool", {
default = true
})
local drowning_damage_enabled = vl_tuning.setting("gamerule:drowningDamage", "bool", {
default = true
})
local fire_damage_enabled = vl_tuning.setting("gamerule:fireDamage", "bool", {
default = true
})
function mcl_damage.register_modifier(func, priority) function mcl_damage.register_modifier(func, priority)
table.insert(mcl_damage.modifiers, {func = func, priority = priority or 0}) table.insert(mcl_damage.modifiers, {func = func, priority = priority or 0})
@ -142,7 +153,7 @@ function mcl_damage.register_type(name, def)
end end
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason) minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
if not damage_enabled then return 0 end if not damage_enabled[1] then return 0 end
if hp_change < 0 then if hp_change < 0 then
if player:get_hp() <= 0 then if player:get_hp() <= 0 then
return 0 return 0
@ -153,10 +164,18 @@ minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
end, true) end, true)
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason) minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
if not damage_enabled then return 0 end -- Check if damage is enabled
if not damage_enabled[1] then return 0 end
local mcl_reason = mcl_damage.from_mt(mt_reason)
if not fire_damage_enabled[1] and mcl_reason.type == "fire" then return 0 end
--if not drowning_damage_enabled[1] and mcl_reason.type == "drown" then return 0 end
--if not fall_damage_enabled[1] and mcl_reason.type == "fall" then return 0 end
--minetest.log("action", "mcl_reason = "..dump(mcl_reason)..", mt_reason = "..dump(mt_reason))
if player:get_hp() > 0 then if player:get_hp() > 0 then
if hp_change < 0 then if hp_change < 0 then
mcl_damage.run_damage_callbacks(player, -hp_change, mcl_damage.from_mt(mt_reason)) mcl_damage.run_damage_callbacks(player, -hp_change, mcl_reason)
end end
end end
end, false) end, false)

View File

@ -1,3 +1,4 @@
name = mcl_damage name = mcl_damage
author = Fleckenstein author = Fleckenstein
description = Minecraft-like damage reason system description = Minecraft-like damage reason system
depends = vl_tuning

View File

@ -0,0 +1,99 @@
local modname = "vl_tuning"
local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname)
local F = function(f) return minetest.formspec_escape(S(f)) end
local FE = minetest.formspec_escape
local mod = vl_tuning
local function bool_to_string(value)
if value then return "true" end
return "false"
end
local function formspec_for_setting(y, name)
local setting = mod.registered_settings[name]
if not setting then return "" end
local setting_type = setting.setting_type
local fs = {}
table.insert(fs, "label[0,"..(y+0.15)..";"..FE(name).."]")
table.insert(fs, "hypertext[0.15,"..(y+0.25)..";14.85,0.65;;"..FE("<style color=black>"..(setting.description or "").."</style>").."]")
if setting_type == "bool" then
table.insert(fs, "checkbox[17,"..(y+0.15)..";"..FE(name)..";;"..bool_to_string(setting[1]).."]")
elseif setting_type == "number" then
table.insert(fs, "field[15,"..y..";2.5,0.75;"..FE(name)..";;"..string.format("%.4g", setting[1]).."]")
table.insert(fs, "field_close_on_enter["..FE(name)..";false]")
elseif setting_type == "string" then
end
return table.concat(fs)
end
function vl_tuning.show_formspec(player_name, tab)
if not tab then tab = "1" end
local settings = {}
local y = 0.5
for name,_ in pairs(vl_tuning.registered_settings) do
if name:sub(0,#"gamerule:") == "gamerule:" then
if tab == "1" then
table.insert(settings, formspec_for_setting(y,name))
y = y + 1
end
else
if tab == "2" then
table.insert(settings, formspec_for_setting(y,name))
y = y + 1
end
end
end
local formspec = table.concat({
"formspec_version[4]",
"size[20,10.5,true]",
"tabheader[0,0;tab;"..
F("Game Rules")..","..
F("Settings")..
";"..tab..";false;false]",
"field[0,0;0,0;old_tab;;"..tab.."]",
"scroll_container[1,0.5;18,9.25;settings;vertical;]",
table.concat(settings),
"scroll_container_end[]",
"scrollbaroptions[min=0;max="..tostring(10 * math.max(#settings - 9, 0))..";smallstep=1;largestep=1]",
"scrollbar[18.75,0.75;0.75,9.25;vertical;settings;0]",
})
minetest.show_formspec(player_name, "vl_tuning:settings", formspec)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "vl_tuning:settings" then return end
minetest.log("action",dump({
player = player,
fields = fields,
formname = formname,
}))
for k,value in pairs(fields) do
local setting = mod.registered_settings[k]
if setting then
setting:set(value)
end
end
if fields.quit or (not fields.tab or fields.old_tab == fields.tab) then return end
minetest.log("Seting settings formspec")
mod.show_formspec(player:get_player_name(), fields.tab)
end)
minetest.register_chatcommand("settings",{
func = function(player_name, param)
dofile(modpath.."/gui.lua")
mod.show_formspec(player_name)
end
})

View File

@ -0,0 +1,158 @@
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname)
local storage = minetest.get_mod_storage()
local mod = {}
vl_tuning = mod
-- All registered tunable parameters
local tunables = {}
vl_tuning.registered_settings = tunables
-- Supported variable types
local tunable_types = {
bool = {
to_string = tostring,
from_string = function(value)
return (value == "true")
end
},
number = {
to_string = tostring,
from_string = tonumber,
},
string = {
to_string = function(v) return v end,
from_string = function(v) return v end,
},
}
-- Tunable metatable functions
local tunable_class = {}
function tunable_class:set(value, no_hook)
local self_type = self.type
if type(value) == "string" then
local new_value = self_type.from_string(value)
if new_value == nil then new_value = self.default end
self[1] = new_value
else
self[1] = value
end
minetest.log("action", "[vl_tuning] Set "..self.setting.." to "..dump(self[1]))
-- Call on_change hook
if not no_hook then
local hook = self.on_change
if hook then hook(self) end
end
-- Persist value
storage:set_string(self.setting,self_type.to_string(self[1]))
end
function tunable_class:get_string()
return self.type.to_string(self[1])
end
function mod.setting(setting, setting_type, def )
-- return the existing setting if it was previously registered. Don't update the definition
local tunable = tunables[setting]
if tunable then return tunable end
assert(setting_type)
assert(def)
-- Setup the tunable data
tunable = table.copy(def)
tunable.setting = setting
tunable.type = tunable_types[setting_type]
tunable.setting_type = setting_type
tunable[1] = tunable.default
setmetatable(tunable, {__index=tunable_class})
-- Load the setting value from mod storage
local setting_value = storage:get_string(setting)
if setting_value and setting_value ~= "" then
tunable:set(setting_value, true)
minetest.log("action", "[vl_tuning] Loading "..setting.." = "..dump(setting_value).." ("..dump(tunable[1])..")")
end
-- Add to the list of all available settings
tunables[setting] = tunable
-- Provide it so that the current value in [1] can be accessed without having to call into this API again
return tunable
end
minetest.register_chatcommand("set_setting", {
description = S("Admin tool to tune settings and game rules"),
params = S("<setting> <value>"),
privs = { debug = true },
func = function(name, params_raw)
-- Split apart the params
local params = {}
for str in string.gmatch(params_raw, "([^ ]+)") do
params[#params + 1] = str
end
if #params ~= 2 then
return false, S("Usage: /tune <setting> <value>")
end
local tunable = tunables[params[1]]
if not tunable then
return false, S("Setting @1 doesn't exist", params[1])
end
minetest.log("action", "[vl_tuning] "..name.." set ".. params[1] .." to "..params[2])
tunable:set(params[2])
return true
end
})
minetest.register_chatcommand("get_setting", {
description = S("Admin tool to view settings and game rules"),
params = S("<setting>"),
privs = { debug = true },
func = function(name, param)
local tunable = tunables[param]
if tunable then
return true, tunable:get_string()
else
return false, S("Setting @1 doesn't exist", param)
end
end
})
minetest.register_chatcommand("gamerule", {
description = S("Display or set customizable options"),
params = S("<rule> [<value>]"),
privs = { server = true },
func = function(name, params_raw)
-- Split apart the params
local params = {}
for str in string.gmatch(params_raw, "([^ ]+)") do
params[#params + 1] = str
end
if #params < 1 or #params > 2 then
return false, S("Usage: /gamerule <rule> [<value>]")
end
local tunable = tunables["gamerule:"..params[1]]
if not tunable then
return false, S("Game rule @1 doesn't exist", params[1])
end
local value = params[2]
if value then
minetest.log("action", "[vl_tuning] Setting game rule "..params[1].." to "..params[2])
tunable:set(params[2])
return true
else
return true, tunable:get_string()
end
end
})
dofile(modpath.."/settings.lua")
dofile(modpath.."/gui.lua")

View File

@ -0,0 +1,3 @@
name = vl_tuning
author = teknomunk
description = Framework for dynamic tuning and game rules

View File

@ -0,0 +1,12 @@
local modname = minetest.get_current_modname()
local S = minetest.get_translator(modname)
local mod = vl_tuning
mod.keep_inventory = vl_tuning.setting("gamerule:keepInventory", "bool", {
default = minetest.settings:get_bool("mcl_keepInventory", false),
})
mod.respawn_blocks_explode = vl_tuning.setting("gamerule:respawnBlocksExplode", "bool", {
description = S("Prevents beds/respawn anchors from exploding in other dimensions."),
default = true,
})

View File

@ -1,5 +1,5 @@
name = mcl_mobs name = mcl_mobs
author = PilzAdam author = PilzAdam
description = Adds a mob API for mods to add animals or monsters, etc. description = Adds a mob API for mods to add animals or monsters, etc.
depends = mcl_particles, mcl_luck depends = mcl_particles, mcl_luck, vl_tuning
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience, mcl_sculk optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience, mcl_sculk

View File

@ -1,8 +1,18 @@
local modname = minetest.get_current_modname()
local S = minetest.get_translator(modname)
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
local mob_class = mcl_mobs.mob_class local mob_class = mcl_mobs.mob_class
local validate_vector = mcl_util.validate_vector local validate_vector = mcl_util.validate_vector
local ENTITY_CRAMMING_MAX = 24 local gamerule_maxEntityCramming = vl_tuning.setting("gamerule:maxEntityCramming", "number", {
description = S("The maximum number of pushable entities a mob or player can push, before taking 6♥♥♥ entity cramming damage per half-second."),
default = 24,
})
local gamerule_doMobLoot = vl_tuning.setting("gamerule:doMobLoot", "bool", {
description = S("Whether mobs should drop items and experience orbs."),
default = true,
})
local CRAMMING_DAMAGE = 3 local CRAMMING_DAMAGE = 3
local DEATH_DELAY = 0.5 local DEATH_DELAY = 0.5
local DEFAULT_FALL_SPEED = -9.81*1.5 local DEFAULT_FALL_SPEED = -9.81*1.5
@ -472,6 +482,8 @@ function mob_class:check_for_death(cause, cmi_cause)
-- TODO other env damage shouldn't drop xp -- TODO other env damage shouldn't drop xp
-- "rain", "water", "drowning", "suffocation" -- "rain", "water", "drowning", "suffocation"
if not gamerule_doMobLoot[1] then return end
-- dropped cooked item if mob died in fire or lava -- dropped cooked item if mob died in fire or lava
if cause == "lava" or cause == "fire" then if cause == "lava" or cause == "fire" then
self:item_drop(true, 0) self:item_drop(true, 0)
@ -501,13 +513,10 @@ function mob_class:check_for_death(cause, cmi_cause)
end end
end end
end end
end end
-- execute custom death function -- execute custom death function
if self.on_die then if self.on_die then
local pos = self.object:get_pos() local pos = self.object:get_pos()
local on_die_exit = self.on_die(self, pos, cmi_cause) local on_die_exit = self.on_die(self, pos, cmi_cause)
if on_die_exit ~= true then if on_die_exit ~= true then
@ -903,7 +912,7 @@ function mob_class:check_entity_cramming()
local l = o:get_luaentity() local l = o:get_luaentity()
if l and l.is_mob and l.health > 0 then table.insert(mobs,l) end if l and l.is_mob and l.health > 0 then table.insert(mobs,l) end
end end
local clear = #mobs < ENTITY_CRAMMING_MAX local clear = #mobs < gamerule_maxEntityCramming[1]
local ncram = {} local ncram = {}
for _,l in pairs(mobs) do for _,l in pairs(mobs) do
if l then if l then
@ -917,7 +926,7 @@ function mob_class:check_entity_cramming()
end end
end end
for i,l in pairs(ncram) do for i,l in pairs(ncram) do
if i > ENTITY_CRAMMING_MAX then if i > gamerule_maxEntityCramming[1] then
l.cram = true l.cram = true
else else
l.cram = nil l.cram = nil

View File

@ -1,7 +1,12 @@
--lua locals --lua locals
local S = minetest.get_translator("mcl_mobs")
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
local mob_class = mcl_mobs.mob_class local mob_class = mcl_mobs.mob_class
local gamerule_doMobSpawning = vl_tuning.setting("gamerule:doMobSpawning", "bool", {
description = S("Whether mobs should spawn naturally, or via global spawning logic, such as for cats, phantoms, patrols, wandering traders, or zombie sieges. Does not affect special spawning attempts, like monster spawners, raids, or iron golems."), default = true
})
local modern_lighting = minetest.settings:get_bool("mcl_mobs_modern_lighting", true) local modern_lighting = minetest.settings:get_bool("mcl_mobs_modern_lighting", true)
local nether_threshold = tonumber(minetest.settings:get("mcl_mobs_nether_threshold")) or 11 local nether_threshold = tonumber(minetest.settings:get("mcl_mobs_nether_threshold")) or 11
local end_threshold = tonumber(minetest.settings:get("mcl_mobs_end_threshold")) or 0 local end_threshold = tonumber(minetest.settings:get("mcl_mobs_end_threshold")) or 0
@ -728,8 +733,6 @@ end
mcl_mobs.spawn_group = spawn_group mcl_mobs.spawn_group = spawn_group
local S = minetest.get_translator("mcl_mobs")
minetest.register_chatcommand("spawn_mob",{ minetest.register_chatcommand("spawn_mob",{
privs = { debug = true }, privs = { debug = true },
description=S("spawn_mob is a chatcommand that allows you to type in the name of a mob without 'typing mobs_mc:' all the time like so; 'spawn_mob spider'. however, there is more you can do with this special command, currently you can edit any number, boolean, and string variable you choose with this format: spawn_mob 'any_mob:var<mobs_variable=variable_value>:'. any_mob being your mob of choice, mobs_variable being the variable, and variable value being the value of the chosen variable. and example of this format: \n spawn_mob skeleton:var<passive=true>:\n this would spawn a skeleton that wouldn't attack you. REMEMBER-THIS> when changing a number value always prefix it with 'NUM', example: \n spawn_mob skeleton:var<jump_height=NUM10>:\n this setting the skelly's jump height to 10. if you want to make multiple changes to a mob, you can, example: \n spawn_mob skeleton:var<passive=true>::var<jump_height=NUM10>::var<fly_in=air>::var<fly=true>:\n etc."), description=S("spawn_mob is a chatcommand that allows you to type in the name of a mob without 'typing mobs_mc:' all the time like so; 'spawn_mob spider'. however, there is more you can do with this special command, currently you can edit any number, boolean, and string variable you choose with this format: spawn_mob 'any_mob:var<mobs_variable=variable_value>:'. any_mob being your mob of choice, mobs_variable being the variable, and variable value being the value of the chosen variable. and example of this format: \n spawn_mob skeleton:var<passive=true>:\n this would spawn a skeleton that wouldn't attack you. REMEMBER-THIS> when changing a number value always prefix it with 'NUM', example: \n spawn_mob skeleton:var<jump_height=NUM10>:\n this setting the skelly's jump height to 10. if you want to make multiple changes to a mob, you can, example: \n spawn_mob skeleton:var<passive=true>::var<jump_height=NUM10>::var<fly_in=air>::var<fly=true>:\n etc."),
@ -1010,6 +1013,7 @@ if mobs_spawn then
local timer = 0 local timer = 0
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
if not gamerule_doMobSpawning[1] then return end
timer = timer + dtime timer = timer + dtime
if timer < WAIT_FOR_SPAWN_ATTEMPT then return end if timer < WAIT_FOR_SPAWN_ATTEMPT then return end

View File

@ -2,6 +2,10 @@
mcl_raids = {} mcl_raids = {}
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local gamerule_disableRaids = vl_tuning.setting("gamerule:disableRaids", "bool", {
description = S("Whether raids are disabled"), default = false,
})
-- Define the amount of illagers to spawn each wave. -- Define the amount of illagers to spawn each wave.
local waves = { local waves = {
{ {
@ -291,6 +295,8 @@ mcl_events.register_event("raid",{
exclusive_to_area = 128, exclusive_to_area = 128,
enable_bossbar = true, enable_bossbar = true,
cond_start = function(self) cond_start = function(self)
if gamerule_disableRaids[1] then return false end
--minetest.log("Cond start raid") --minetest.log("Cond start raid")
local r = {} local r = {}
for _,p in pairs(minetest.get_connected_players()) do for _,p in pairs(minetest.get_connected_players()) do

View File

@ -1,3 +1,3 @@
name = mcl_raids name = mcl_raids
author = PrairieWind author = PrairieWind
depends = mcl_events, mobs_mc, mcl_potions, mcl_bells, mcl_achievements depends = mcl_events, mobs_mc, mcl_potions, mcl_bells, mcl_achievements, vl_tuning

View File

@ -1,5 +1,5 @@
name = mcl_weather name = mcl_weather
author = xeranas author = xeranas
description = Weather and sky handling: Rain, snow, thunderstorm, End and Nether ambience description = Weather and sky handling: Rain, snow, thunderstorm, End and Nether ambience
depends = mcl_init, mcl_worlds, mcl_playerinfo, mcl_util depends = mcl_init, mcl_worlds, mcl_playerinfo, mcl_util, vl_tuning
optional_depends = lightning optional_depends = lightning

View File

@ -1,6 +1,9 @@
-- Constants -- Constants
local modname = minetest.get_current_modname() local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname) local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname)
local mods_loaded = false
local NIGHT_VISION_RATIO = 0.45 local NIGHT_VISION_RATIO = 0.45
-- Settings -- Settings
@ -9,6 +12,28 @@ local minimum_update_interval = { 250e3 }
-- Module state -- Module state
local mods_loaded = false local mods_loaded = false
-- Daylight cycle handling
local fixed_time = vl_tuning.setting("fixed_daylight_time", "number", {
description = S("Time of day to use when gamerule:doDaylightCycle == false"),
default = 0.5
})
local gamerule_doDaylightCycle = vl_tuning.setting("gamerule:doDaylightCycle", "bool",{
description = S("Whether the daylight cycle and moon phases progress"),
default = true,
on_change = function(self)
if not self[1] then
fixed_time:set(minetest.get_timeofday())
end
end
})
local function daylightCycle()
if not gamerule_doDaylightCycle[1] and fixed_time[1] then
minetest.set_timeofday(fixed_time[1])
end
minetest.after(1, daylightCycle)
end
minetest.after(1, daylightCycle)
function mcl_weather.set_sky_box_clear(player, sky, fog) function mcl_weather.set_sky_box_clear(player, sky, fog)
-- Make sure the player's head isn't in water before changing the skybox -- Make sure the player's head isn't in water before changing the skybox
local node_head = mcl_playerinfo[player:get_player_name()].node_head local node_head = mcl_playerinfo[player:get_player_name()].node_head

View File

@ -1,10 +1,16 @@
local get_connected_players = minetest.get_connected_players local get_connected_players = minetest.get_connected_players
local modname = minetest.get_current_modname()
local S = minetest.get_translator(modname)
mcl_weather.snow = {} mcl_weather.snow = {}
local PARTICLES_COUNT_SNOW = tonumber(minetest.settings:get("mcl_weather_snow_particles")) or 100 local PARTICLES_COUNT_SNOW = tonumber(minetest.settings:get("mcl_weather_snow_particles")) or 100
mcl_weather.snow.init_done = false mcl_weather.snow.init_done = false
local mgname = minetest.get_mapgen_setting("mg_name") local mgname = minetest.get_mapgen_setting("mg_name")
local gamerule_snowAccumulationHeight = vl_tuning.setting("gamerule:snowAccumulationHeight", "number", {
description = S("The maximum number of snow layers that can be accumulated on each block"),
default = 1, min = 0, max = 8
})
local snow_biomes = { local snow_biomes = {
"ColdTaiga_underground", "ColdTaiga_underground",
@ -139,14 +145,16 @@ minetest.register_abm({
if node.name:find("snow") then if node.name:find("snow") then
local l = node.name:sub(-1) local l = node.name:sub(-1)
l = tonumber(l) l = tonumber(l)
if node.name == "mcl_core:snow" then if l < gamerule_snowAccumulationHeight[1] then
nn={name = "mcl_core:snow_2"} if node.name == "mcl_core:snow" then
elseif l and l < 7 then nn={name = "mcl_core:snow_2"}
nn={name="mcl_core:snow_"..tostring(math.min(8,l + 1))} elseif l and l < 7 then
elseif l and l >= 7 then nn={name="mcl_core:snow_"..tostring(math.min(8,l + 1))}
nn={name = "mcl_core:snowblock"} elseif l and l >= 7 then
nn={name = "mcl_core:snowblock"}
end
if nn then minetest.set_node(pos,nn) end
end end
if nn then minetest.set_node(pos,nn) end
else else
minetest.set_node(above,{name = "mcl_core:snow"}) minetest.set_node(above,{name = "mcl_core:snow"})
end end

View File

@ -2,6 +2,10 @@ local S = minetest.get_translator(minetest.get_current_modname())
local math = math local math = math
local gamerule_doWeatherCycle = vl_tuning.setting("gamerule:doWeatherCycle", "bool", {
description = S("Whether the weather can change naturally. The /weather command can still change weather."), default = true
})
-- weather states, 'none' is default, other states depends from active mods -- weather states, 'none' is default, other states depends from active mods
mcl_weather.state = "none" mcl_weather.state = "none"
@ -126,6 +130,8 @@ end
local t, wci = 0, mcl_weather.check_interval local t, wci = 0, mcl_weather.check_interval
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
if not gamerule_doWeatherCycle[1] then return end
t = t + dtime t = t + dtime
if t < wci then return end if t < wci then return end
t = 0 t = 0

View File

@ -18,6 +18,15 @@ local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname) local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname) local S = minetest.get_translator(modname)
-- Tunable parameters
local notif_delay = vl_tuning.setting("award_display_time", "number", {
description = S("Amount of time award notification are displayed"), default = 3, min = 2, max = 10
})
local announce_in_chat = vl_tuning.setting("gamerule:announceAdvancements", "bool", {
description = S("Whether advancements should be announced in chat"),
default = minetest.settings:get_bool("mcl_showAdvancementMessages", true),
})
-- The global award namespace -- The global award namespace
awards = { awards = {
show_mode = "hud", show_mode = "hud",
@ -217,7 +226,7 @@ function awards.unlock(name, award)
-- Get award -- Get award
minetest.log("action", name.." has gotten award "..award) minetest.log("action", name.." has gotten award "..award)
if minetest.settings:get_bool("mcl_showAdvancementMessages", true) then if announce_in_chat[1] then
minetest.chat_send_all(S("@1 has made the advancement @2", name, minetest.colorize(mcl_colors.GREEN, "[" .. (awdef.title or award) .. "]"))) minetest.chat_send_all(S("@1 has made the advancement @2", name, minetest.colorize(mcl_colors.GREEN, "[" .. (awdef.title or award) .. "]")))
end end
data.unlocked[award] = award data.unlocked[award] = award
@ -362,7 +371,7 @@ function awards.unlock(name, award)
direction = 0, direction = 0,
z_index = 102, z_index = 102,
}) })
minetest.after(3, function(name) minetest.after(notif_delay[1], function(name)
local player = minetest.get_player_by_name(name) local player = minetest.get_player_by_name(name)
if not player then if not player then
return return

View File

@ -6,4 +6,4 @@ license = LGPL 2.1 or later
forum = https://forum.minetest.net/viewtopic.php?t=4870 forum = https://forum.minetest.net/viewtopic.php?t=4870
version = 2.3.0 version = 2.3.0
optional_depends = sfinv, unified_inventory optional_depends = sfinv, unified_inventory
depends = mcl_colors depends = mcl_colors, vl_tuning

View File

@ -1,6 +1,10 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local ASSIST_TIMEOUT_SEC = 5 local ASSIST_TIMEOUT_SEC = 5
local gamerule_showDeathMessages = vl_tuning.setting("gamerule:showDeathMessages", "bool", {
description = S("Whether death messages are put into chat when a player dies. Also affects whether a message is sent to the pet's owner when the pet dies."),
default = minetest.settings:get_bool("mcl_showDeathMessages", true),
})
mcl_death_messages = { mcl_death_messages = {
assist = {}, assist = {},
@ -204,9 +208,7 @@ local function fallback_translator(s)
end end
mcl_damage.register_on_death(function(obj, reason) mcl_damage.register_on_death(function(obj, reason)
if not minetest.settings:get_bool("mcl_showDeathMessages", true) then if not gamerule_showDeathMessages[1] then return end
return
end
local send_to local send_to

View File

@ -1,4 +1,4 @@
name = mcl_death_messages name = mcl_death_messages
author = 4Evergreen4 author = 4Evergreen4
description = Shows messages in chat when a player dies. description = Shows messages in chat when a player dies.
depends = mcl_colors, mcl_damage depends = mcl_colors, mcl_damage, vl_tuning

View File

@ -237,8 +237,9 @@ minetest.register_on_leaveplayer(function(player)
caches[player] = nil caches[player] = nil
end) end)
local keep_inventory = vl_tuning.setting("gamerule:keepInventory")
minetest.register_on_dieplayer(function(player) minetest.register_on_dieplayer(function(player)
if not minetest.settings:get_bool("mcl_keepInventory", false) then if not keep_inventory[1] then
mcl_experience.throw_xp(player:get_pos(), mcl_experience.get_xp(player)) mcl_experience.throw_xp(player:get_pos(), mcl_experience.get_xp(player))
mcl_experience.set_xp(player, 0) mcl_experience.set_xp(player, 0)
end end

View File

@ -1,4 +1,4 @@
name = mcl_experience name = mcl_experience
author = oilboi author = oilboi
description = eXPerience mod description = eXPerience mod
depends = mcl_gamemode, mcl_luck depends = mcl_gamemode, mcl_luck, vl_tuning

View File

@ -10,6 +10,8 @@ local explosions_mod = minetest.get_modpath("mcl_explosions")
local spawn_mod = minetest.get_modpath("mcl_spawn") local spawn_mod = minetest.get_modpath("mcl_spawn")
local pos_to_dim = minetest.get_modpath("mcl_worlds") and mcl_worlds.pos_to_dimension or function(pos) return "overworld" end local pos_to_dim = minetest.get_modpath("mcl_worlds") and mcl_worlds.pos_to_dimension or function(pos) return "overworld" end
local gamerule_respawnBlocksExplode = vl_tuning.respawn_blocks_explode
local function mcl_log (message) local function mcl_log (message)
mcl_util.mcl_log (message, "[Beds]") mcl_util.mcl_log (message, "[Beds]")
end end
@ -384,7 +386,7 @@ function mcl_beds.on_rightclick(pos, player, is_top)
minetest.remove_node(pos) minetest.remove_node(pos)
minetest.remove_node(string.sub(node.name, -4) == "_top" and vector.subtract(pos, dir) or vector.add(pos, dir)) minetest.remove_node(string.sub(node.name, -4) == "_top" and vector.subtract(pos, dir) or vector.add(pos, dir))
if explosions_mod then if explosions_mod and gamerule_respawnBlocksExplode[1] then
mcl_explosions.explode(pos, 5, {drop_chance = 1.0, fire = true}) mcl_explosions.explode(pos, 5, {drop_chance = 1.0, fire = true})
end end
return return

View File

@ -1,5 +1,5 @@
name = mcl_beds name = mcl_beds
author = BlockMen author = BlockMen
description = description =
depends = playerphysics depends = playerphysics, vl_tuning
optional_depends = mcl_sounds, mcl_worlds, mcl_wool, mcl_dye, mcl_explosions, mcl_weather, mcl_spawn, doc, mesecons optional_depends = mcl_sounds, mcl_worlds, mcl_wool, mcl_dye, mcl_explosions, mcl_weather, mcl_spawn, doc, mesecons

View File

@ -4,6 +4,7 @@
--Nether roof at y -28933 --Nether roof at y -28933
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
--local mod_doc = minetest.get_modpath("doc") -> maybe add documentation ? --local mod_doc = minetest.get_modpath("doc") -> maybe add documentation ?
local gamerule_respawnBlocksExplode = vl_tuning.respawn_blocks_explode
for i=0,4 do for i=0,4 do
@ -12,7 +13,7 @@ for i=0,4 do
minetest.set_node(pos, {name="mcl_beds:respawn_anchor_charged_" .. i+1}) minetest.set_node(pos, {name="mcl_beds:respawn_anchor_charged_" .. i+1})
itemstack:take_item() itemstack:take_item()
elseif mcl_worlds.pos_to_dimension(pos) ~= "nether" then elseif mcl_worlds.pos_to_dimension(pos) ~= "nether" then
if node.name ~= "mcl_beds:respawn_anchor" then --only charged respawn anchors are exploding in the overworld & end in minecraft if gamerule_respawnBlocksExplode[1] and node.name ~= "mcl_beds:respawn_anchor" then --only charged respawn anchors are exploding in the overworld & end in minecraft
mcl_explosions.explode(pos, 5, {drop_chance = 0, fire = true}) mcl_explosions.explode(pos, 5, {drop_chance = 0, fire = true})
end end
elseif string.match(node.name, "mcl_beds:respawn_anchor_charged_") then elseif string.match(node.name, "mcl_beds:respawn_anchor_charged_") then

View File

@ -2,7 +2,9 @@
-- Lava vs water interactions -- Lava vs water interactions
-- --
local modpath = minetest.get_modpath(minetest.get_current_modname()) local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname)
local mg_name = minetest.get_mapgen_setting("mg_name") local mg_name = minetest.get_mapgen_setting("mg_name")
@ -1278,12 +1280,17 @@ end
--------------------- ---------------------
-- Vine generating -- -- Vine generating --
--------------------- ---------------------
local do_vines_spread = vl_tuning.setting("gamerule:doVinesSpread", "bool", {
description = S("Whether vines can spread to other blocks. Cave vines, weeping vines, and twisting vines are not affected."),
default = true,
})
minetest.register_abm({ minetest.register_abm({
label = "Vines growth", label = "Vines growth",
nodenames = {"mcl_core:vine"}, nodenames = {"mcl_core:vine"},
interval = 47, interval = 47,
chance = 4, chance = 4,
action = function(pos, node, active_object_count, active_object_count_wider) action = function(pos, node, active_object_count, active_object_count_wider)
if not do_vines_spread[1] then return end
-- First of all, check if we are even supported, otherwise, let's die! -- First of all, check if we are even supported, otherwise, let's die!
if not mcl_core.check_vines_supported(pos, node) then if not mcl_core.check_vines_supported(pos, node) then

View File

@ -1,4 +1,4 @@
name = mcl_core name = mcl_core
description = Core items of MineClone 2: Basic biome blocks (dirt, sand, stones, etc.), derived items, glass, sugar cane, cactus, barrier, mining tools, hand, craftitems, and misc. items which don't really fit anywhere else. description = Core items of MineClone 2: Basic biome blocks (dirt, sand, stones, etc.), derived items, glass, sugar cane, cactus, barrier, mining tools, hand, craftitems, and misc. items which don't really fit anywhere else.
depends = mcl_autogroup, mcl_init, mcl_sounds, mcl_particles, mcl_util, mcl_worlds, doc_items, mcl_enchanting, mcl_colors, mcl_stonecutter depends = mcl_autogroup, mcl_init, mcl_sounds, mcl_particles, mcl_util, mcl_worlds, doc_items, mcl_enchanting, mcl_colors, mcl_stonecutter, vl_tuning
optional_depends = doc optional_depends = doc

View File

@ -1,3 +1,3 @@
name = mcl_farming name = mcl_farming
depends = mcl_core, mcl_sounds, mcl_wool, mcl_torches, mcl_weather, mobs_mc, mcl_colors, mcl_init depends = mcl_core, mcl_sounds, mcl_wool, mcl_torches, mcl_weather, mobs_mc, mcl_colors, mcl_init, vl_tuning
optional_depends = mcl_armor, doc optional_depends = mcl_armor, doc

View File

@ -169,8 +169,9 @@ if minetest.get_modpath("mcl_armor") then
add_pumpkin_hud(player) add_pumpkin_hud(player)
end end
end) end)
local keep_inventory = vl_tuning.setting("gamerule:keepInventory")
minetest.register_on_dieplayer(function(player) minetest.register_on_dieplayer(function(player)
if not minetest.settings:get_bool("mcl_keepInventory") then if not keep_inventory[1] then
remove_pumpkin_hud(player) remove_pumpkin_hud(player)
end end
end) end)

View File

@ -7,6 +7,9 @@ local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname) local S = minetest.get_translator(modname)
local has_mcl_portals = minetest.get_modpath("mcl_portals") local has_mcl_portals = minetest.get_modpath("mcl_portals")
local gamerule_doFireTick = vl_tuning.setting("gamerule:doFireTick", "bool", {
description = S("Whether fire should spread and naturally extinguish"), default = true
})
local set_node = minetest.set_node local set_node = minetest.set_node
local get_node = minetest.get_node local get_node = minetest.get_node
@ -366,6 +369,8 @@ else -- Fire enabled
chance = 12, chance = 12,
catch_up = false, catch_up = false,
action = function(pos) action = function(pos)
if not gamerule_doFireTick[1] then return end
local p = get_ignitable(pos) local p = get_ignitable(pos)
if p then if p then
spawn_fire(p) spawn_fire(p)
@ -383,6 +388,8 @@ else -- Fire enabled
chance = 9, chance = 9,
catch_up = false, catch_up = false,
action = function(pos) action = function(pos)
if not gamerule_doFireTick[1] then return end
local p=get_ignitable_by_lava(pos) local p=get_ignitable_by_lava(pos)
if p then if p then
spawn_fire(p) spawn_fire(p)
@ -397,6 +404,8 @@ else -- Fire enabled
chance = 3, chance = 3,
catch_up = false, catch_up = false,
action = function(pos) action = function(pos)
if not gamerule_doFireTick[1] then return end
local p=has_flammable(pos) local p=has_flammable(pos)
if p then if p then
local n=minetest.get_node_or_nil(p) local n=minetest.get_node_or_nil(p)
@ -418,6 +427,8 @@ else -- Fire enabled
chance = 18, chance = 18,
catch_up = false, catch_up = false,
action = function(pos) action = function(pos)
if not gamerule_doFireTick[1] then return end
local p = has_flammable(pos) local p = has_flammable(pos)
if not p then if not p then
return return

View File

@ -1,3 +1,3 @@
name = mcl_fire name = mcl_fire
depends = mcl_core, mcl_worlds, mcl_sounds, mcl_particles, mcl_util depends = mcl_core, mcl_worlds, mcl_sounds, mcl_particles, mcl_util
optional_depends = mcl_portals optional_depends = mcl_portals, vl_tuning

View File

@ -1,4 +1,4 @@
name = mcl_portals name = mcl_portals
description = Adds buildable portals to the Nether and End dimensions. description = Adds buildable portals to the Nether and End dimensions.
depends = mcl_nether, mcl_end, mcl_particles, mcl_spawn, mcl_credits, mcl_structures depends = mcl_nether, mcl_end, mcl_particles, mcl_spawn, mcl_credits, mcl_structures, vl_tuning
optional_depends = awards, doc optional_depends = awards, doc

View File

@ -85,7 +85,14 @@ local LIM_MIN, LIM_MAX = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max
local PLAYER_COOLOFF, MOB_COOLOFF = 3, 14 -- for this many seconds they won't teleported again local PLAYER_COOLOFF, MOB_COOLOFF = 3, 14 -- for this many seconds they won't teleported again
local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds
local CHATTER_US = TOUCH_CHATTER_TIME * 1000000 local CHATTER_US = TOUCH_CHATTER_TIME * 1000000
local DELAY = 3 -- seconds before teleporting in Nether portal in Survival mode (4 minus ABM interval time)
local nether_portal_creative_delay = vl_tuning.setting("gamerule:playersNetherPortalCreativeDelay", "number", {
default = 0,
})
local nether_portal_survival_delay = vl_tuning.setting("gamerule:playersNetherPortalDefaultDelay", "number", {
default = 4,
})
-- Speeds up the search by allowing some non-air nodes to be replaced when -- Speeds up the search by allowing some non-air nodes to be replaced when
-- looking for acceptable portal locations. Setting this lower means the -- looking for acceptable portal locations. Setting this lower means the
-- algorithm will do more searching. Even at 0, there is no risk of finding -- algorithm will do more searching. Even at 0, there is no risk of finding
@ -1477,12 +1484,16 @@ local function teleport(obj, portal_pos)
if cooloff[obj] then return end if cooloff[obj] then return end
local delay = math.max(0, nether_portal_survival_delay[1] - 1)
if minetest.is_creative_enabled(name) then if minetest.is_creative_enabled(name) then
teleport_no_delay(obj, portal_pos) delay = math.max(0, nether_portal_creative_delay[1] - 1)
return
end end
minetest.after(DELAY, teleport_no_delay, obj, portal_pos) if delay == 0 then
teleport_no_delay(obj, portal_pos)
else
minetest.after(delay, teleport_no_delay, obj, portal_pos)
end
end end
minetest.register_abm({ minetest.register_abm({

View File

@ -407,9 +407,10 @@ minetest.register_globalstep(function(dtime)
end end
end) end)
local keep_inventory = vl_tuning.setting("gamerule:keepInventory")
minetest.register_on_dieplayer(function(player) minetest.register_on_dieplayer(function(player)
remove_shield_hud(player) remove_shield_hud(player)
if not minetest.settings:get_bool("mcl_keepInventory") then if not keep_inventory[1] then
remove_shield_entity(player, 1) remove_shield_entity(player, 1)
remove_shield_entity(player, 2) remove_shield_entity(player, 2)
end end

View File

@ -1,3 +1,3 @@
name = mcl_shields name = mcl_shields
author = NO11 author = NO11
depends = mcl_damage, mcl_enchanting, mcl_banners, mcl_util, playerphysics depends = mcl_damage, mcl_enchanting, mcl_banners, mcl_util, playerphysics, vl_tuning

View File

@ -6,6 +6,8 @@ mcl_death_drop = {}
mcl_death_drop.registered_dropped_lists = {} mcl_death_drop.registered_dropped_lists = {}
local keep_inventory = vl_tuning.setting("gamerule:keepInventory")
function mcl_death_drop.register_dropped_list(inv, listname, drop) function mcl_death_drop.register_dropped_list(inv, listname, drop)
table.insert(mcl_death_drop.registered_dropped_lists, {inv = inv, listname = listname, drop = drop}) table.insert(mcl_death_drop.registered_dropped_lists, {inv = inv, listname = listname, drop = drop})
end end
@ -16,8 +18,7 @@ mcl_death_drop.register_dropped_list("PLAYER", "armor", true)
mcl_death_drop.register_dropped_list("PLAYER", "offhand", true) mcl_death_drop.register_dropped_list("PLAYER", "offhand", true)
minetest.register_on_dieplayer(function(player) minetest.register_on_dieplayer(function(player)
local keep = minetest.settings:get_bool("mcl_keepInventory", false) if not keep_inventory[1] then
if keep == false then
-- Drop inventory, crafting grid and armor -- Drop inventory, crafting grid and armor
local playerinv = player:get_inventory() local playerinv = player:get_inventory()
local pos = player:get_pos() local pos = player:get_pos()

View File

@ -1,4 +1,4 @@
name = mcl_death_drop name = mcl_death_drop
author = Wuzzy author = Wuzzy
description = Makes all items in inventory drop after player death. description = Makes all items in inventory drop after player death.
depends = mcl_armor, mcl_enchanting depends = mcl_armor, mcl_enchanting, vl_tuning

View File

@ -3,6 +3,13 @@ local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname) local S = minetest.get_translator(modname)
local max_tick_timer = vl_tuning.setting("health_regen_delay", "number", {
default = tonumber(minetest.settings:get("mcl_health_regen_delay")) or 0.5,
})
local natural_regeneration = vl_tuning.setting("gamerule:naturalRegeneration", "bool", {
default = true,
})
mcl_hunger = {} mcl_hunger = {}
--[[ This variable tells you if the hunger gameplay mechanic is active. --[[ This variable tells you if the hunger gameplay mechanic is active.
@ -241,7 +248,6 @@ minetest.register_globalstep(function(dtime)
local food_level = mcl_hunger.get_hunger(player) local food_level = mcl_hunger.get_hunger(player)
local food_saturation_level = mcl_hunger.get_saturation(player) local food_saturation_level = mcl_hunger.get_saturation(player)
local player_health = player:get_hp() local player_health = player:get_hp()
local max_tick_timer = tonumber(minetest.settings:get("mcl_health_regen_delay")) or 0.5
if food_tick_timer > 4 then if food_tick_timer > 4 then
food_tick_timer = 0 food_tick_timer = 0
@ -253,7 +259,7 @@ minetest.register_globalstep(function(dtime)
end end
if food_level >= 18 then -- slow regeneration if food_level >= 18 then -- slow regeneration
if player_health > 0 and player_health < player:get_properties().hp_max then if natural_regeneration[1] and player_health > 0 and player_health < player:get_properties().hp_max then
player:set_hp(player_health+1) player:set_hp(player_health+1)
mcl_hunger.exhaust(player_name, mcl_hunger.EXHAUST_REGEN) mcl_hunger.exhaust(player_name, mcl_hunger.EXHAUST_REGEN)
mcl_hunger.update_exhaustion_hud(player) mcl_hunger.update_exhaustion_hud(player)
@ -269,8 +275,8 @@ minetest.register_globalstep(function(dtime)
end end
end end
elseif food_tick_timer > max_tick_timer and food_level == 20 and food_saturation_level > 0 then -- fast regeneration elseif food_tick_timer > max_tick_timer[1] and food_level == 20 and food_saturation_level > 0 then -- fast regeneration
if player_health > 0 and player_health < player:get_properties().hp_max then if natural_regeneration[1] and player_health > 0 and player_health < player:get_properties().hp_max then
food_tick_timer = 0 food_tick_timer = 0
player:set_hp(player_health+1) player:set_hp(player_health+1)
mcl_hunger.exhaust(player_name, mcl_hunger.EXHAUST_REGEN) mcl_hunger.exhaust(player_name, mcl_hunger.EXHAUST_REGEN)

View File

@ -1,4 +1,4 @@
name = mcl_hunger name = mcl_hunger
author = BlockMen author = BlockMen
description = Adds a simple hunger meachanic with satiation, food poisoning and different healing. description = Adds a simple hunger meachanic with satiation, food poisoning and different healing.
depends = hudbars depends = hudbars, vl_tuning

View File

@ -735,8 +735,10 @@ end
init() init()
if not minetest.settings:get_bool("mcl_keepInventory", false) then local keep_inventory = vl_tuning.setting("gamerule:keepInventory")
minetest.register_on_respawnplayer(function(player) minetest.register_on_respawnplayer(function(player)
if not keep_inventory[1] then
mcl_skins.update_player_skin(player) -- ensures players have their cape again after dying with an elytra mcl_skins.update_player_skin(player) -- ensures players have their cape again after dying with an elytra
end) end
end end)

View File

@ -1,4 +1,4 @@
name = mcl_skins name = mcl_skins
author = MrRar author = MrRar
description = Advanced player skin customization. description = Advanced player skin customization.
depends = mcl_player depends = mcl_player, vl_tuning