diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index c2ae5391e..b6fd71673 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -1,5 +1,7 @@ mcl_util = {} +dofile(minetest.get_modpath(minetest.get_current_modname()).."/roman_numerals.lua") + -- Updates all values in t using values from to*. function table.update(t, ...) for _, to in ipairs {...} do @@ -436,10 +438,11 @@ function mcl_util.generate_on_place_plant_function(condition) if not def_under or not def_above then return itemstack end - if def_under.buildable_to then + if def_under.buildable_to and def_under.name ~= itemstack:get_name() then place_pos = pointed_thing.under - elseif def_above.buildable_to then + elseif def_above.buildable_to and def_above.name ~= itemstack:get_name() then place_pos = pointed_thing.above + pointed_thing.under = pointed_thing.above else return itemstack end diff --git a/mods/CORE/mcl_util/roman_numerals.lua b/mods/CORE/mcl_util/roman_numerals.lua new file mode 100644 index 000000000..a808e43f1 --- /dev/null +++ b/mods/CORE/mcl_util/roman_numerals.lua @@ -0,0 +1,30 @@ +local converter = { + {1000, "M"}, + {900, "CM"}, + {500, "D"}, + {400, "CD"}, + {100, "C"}, + {90, "XC"}, + {50, "L"}, + {40, "XL"}, + {10, "X"}, + {9, "IX"}, + {5, "V"}, + {4, "IV"}, + {1, "I"} +} + +mcl_util.to_roman = function(number) + local r = "" + local a = number + local i = 1 + while a > 0 do + if a >= converter[i][1] then + a = a - converter[i][1] + r = r.. converter[i][2] + else + i = i + 1 + end + end + return r +end diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index 19e91b460..2cb506450 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -127,6 +127,7 @@ local function try_object_pickup(player, inv, object, checkpos) -- Add what we can to the inventory local itemstack = ItemStack(le.itemstring) + tt.reload_itemstack_description(itemstack) local leftovers = inv:add_item("main", itemstack ) check_pickup_achievements(object, player) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 8ebdddcac..873d05bf2 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -96,15 +96,23 @@ function mob_class:get_staticdata() local tmp = {} - for _,stat in pairs(self) do + for tag, stat in pairs(self) do local t = type(stat) if t ~= "function" and t ~= "nil" and t ~= "userdata" - and _ ~= "_cmi_components" then - tmp[_] = self[_] + and tag ~= "_cmi_components" then + tmp[tag] = self[tag] + end + end + + tmp._mcl_potions = self._mcl_potions + if tmp._mcl_potions then + for name_raw, data in pairs(tmp._mcl_potions) do + local def = mcl_potions.registered_effects[name_raw:match("^_EF_(.+)$")] + if def and def.on_save_effect then def.on_save_effect(self.object) end end end @@ -306,7 +314,10 @@ function mob_class:mob_activate(staticdata, def, dtime) self._run_armor_init = true end - + if not self._mcl_potions then + self._mcl_potions = {} + end + mcl_potions._load_entity_effects(self) if def.after_activate then diff --git a/mods/ENTITIES/mcl_mobs/breeding.lua b/mods/ENTITIES/mcl_mobs/breeding.lua index 7b5d91119..90e625db8 100644 --- a/mods/ENTITIES/mcl_mobs/breeding.lua +++ b/mods/ENTITIES/mcl_mobs/breeding.lua @@ -78,6 +78,7 @@ function mob_class:feed_tame(clicker, feed_count, breed, tame, notake) self.food = 0 self.horny = true self.persistent = true + self._luck = mcl_luck.get_luck(clicker:get_player_name()) end end @@ -273,7 +274,7 @@ function mob_class:check_breeding() return end - mcl_experience.throw_xp(pos, math.random(1, 7)) + mcl_experience.throw_xp(pos, math.random(1, 7) + (parent1._luck or 0) + (parent2._luck or 0)) -- custom breed function if parent1.on_breed then diff --git a/mods/ENTITIES/mcl_mobs/combat.lua b/mods/ENTITIES/mcl_mobs/combat.lua index 4bbfcd119..d9df817e4 100644 --- a/mods/ENTITIES/mcl_mobs/combat.lua +++ b/mods/ENTITIES/mcl_mobs/combat.lua @@ -21,8 +21,6 @@ local function atan(x) end end -mcl_mobs.effect_functions = {} - -- check if daytime and also if mob is docile during daylight hours function mob_class:day_docile() @@ -534,6 +532,8 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir) if self.protected and minetest.is_protected(mob_pos, hitter:get_player_name()) then return end + + mcl_potions.update_haste_and_fatigue(hitter) end local time_now = minetest.get_us_time() @@ -605,6 +605,13 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir) * tmp * ((armor[group] or 0) / 100.0) end + -- strength and weakness effects + local strength = mcl_potions.get_effect(hitter, "strength") + local weakness = mcl_potions.get_effect(hitter, "weakness") + local str_fac = strength and strength.factor or 1 + local weak_fac = weakness and weakness.factor or 1 + damage = damage * str_fac * weak_fac + if weapon then local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect") if fire_aspect_level > 0 then @@ -1144,9 +1151,8 @@ function mob_class:do_states_attack (dtime) damage_groups = {fleshy = self.damage} }, nil) if self.dealt_effect then - mcl_mobs.effect_functions[self.dealt_effect.name]( - self.attack, self.dealt_effect.factor, self.dealt_effect.dur - ) + mcl_potions.give_effect_by_level(self.dealt_effect.name, self.attack, + self.dealt_effect.level, self.dealt_effect.dur) end end else diff --git a/mods/ENTITIES/mcl_mobs/init.lua b/mods/ENTITIES/mcl_mobs/init.lua index 2b18a6775..3a2e18872 100644 --- a/mods/ENTITIES/mcl_mobs/init.lua +++ b/mods/ENTITIES/mcl_mobs/init.lua @@ -325,6 +325,7 @@ function mcl_mobs.register_mob(name, def) attack_exception = def.attack_exception or function(p) return false end, _spawner = def._spawner, + _mcl_potions = {}, } if minetest.get_modpath("doc_identifier") ~= nil then diff --git a/mods/ENTITIES/mcl_mobs/mod.conf b/mods/ENTITIES/mcl_mobs/mod.conf index 9c10e9a2b..927c1c905 100644 --- a/mods/ENTITIES/mcl_mobs/mod.conf +++ b/mods/ENTITIES/mcl_mobs/mod.conf @@ -1,5 +1,5 @@ name = mcl_mobs author = PilzAdam description = Adds a mob API for mods to add animals or monsters, etc. -depends = mcl_particles +depends = mcl_particles, mcl_luck optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience, mcl_sculk diff --git a/mods/ENTITIES/mcl_mobs/physics.lua b/mods/ENTITIES/mcl_mobs/physics.lua index 705b22dbb..73aefb509 100644 --- a/mods/ENTITIES/mcl_mobs/physics.lua +++ b/mods/ENTITIES/mcl_mobs/physics.lua @@ -684,7 +684,7 @@ function mob_class:do_env_damage() self.object:set_velocity({x = 0, y = 0, z = 0}) -- wither rose effect elseif self.standing_in == "mcl_flowers:wither_rose" then - mcl_potions.withering_func(self.object, 1, 2) + mcl_potions.give_effect_by_level("withering", self.object, 2, 2) end local nodef = minetest.registered_nodes[self.standing_in] diff --git a/mods/ENTITIES/mcl_mobs/spawning.lua b/mods/ENTITIES/mcl_mobs/spawning.lua old mode 100755 new mode 100644 index b0e6260aa..8a8a42281 --- a/mods/ENTITIES/mcl_mobs/spawning.lua +++ b/mods/ENTITIES/mcl_mobs/spawning.lua @@ -565,6 +565,9 @@ function mcl_mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ return end + assert(min_height) + assert(max_height) + -- chance/spawn number override in minetest.conf for registered mob local numbers = minetest.settings:get(name) diff --git a/mods/ENTITIES/mobs_mc/guardian.lua b/mods/ENTITIES/mobs_mc/guardian.lua index f2addbfa0..ab4051626 100644 --- a/mods/ENTITIES/mobs_mc/guardian.lua +++ b/mods/ENTITIES/mobs_mc/guardian.lua @@ -99,9 +99,7 @@ mcl_mobs.register_mob("mobs_mc:guardian", { view_range = 16, }) --- Spawning disabled due to size issues --- TODO: Re-enable spawning ---mcl_mobs:spawn_specific("mobs_mc:guardian", { "mcl_core:water_source", "mclx_core:river_water_source" }, { "mcl_core:water_source", "mclx_core:river_water_source" }, 0, minetest.LIGHT_MAX+1, 30, 25000, 2, mcl_vars.mg_overworld_min, mobs_mc.water_level - 10) +mcl_mobs:spawn_specific("mobs_mc:guardian", { "mcl_core:water_source", "mclx_core:river_water_source" }, { "mcl_core:water_source", "mclx_core:river_water_source" }, 0, minetest.LIGHT_MAX+1, 30, 25000, 2, mcl_vars.mg_overworld_min, mobs_mc.water_level - 10, mobs_mc.water_level) mcl_mobs:non_spawn_specific("mobs_mc:guardian","overworld",0,minetest.LIGHT_MAX+1) -- spawn eggs mcl_mobs.register_egg("mobs_mc:guardian", S("Guardian"), "#5a8272", "#f17d31", 0) diff --git a/mods/ENTITIES/mobs_mc/guardian_elder.lua b/mods/ENTITIES/mobs_mc/guardian_elder.lua index 094c0513c..be787216c 100644 --- a/mods/ENTITIES/mobs_mc/guardian_elder.lua +++ b/mods/ENTITIES/mobs_mc/guardian_elder.lua @@ -105,11 +105,14 @@ mcl_mobs.register_mob("mobs_mc:guardian_elder", { fly_in = { "mcl_core:water_source", "mclx_core:river_water_source" }, jump = false, view_range = 16, + dealt_effect = { + name = "fatigue", + level = 3, + dur = 30, + }, }) --- Spawning disabled due to size issues <- what do you mean? -j4i --- TODO: Re-enable spawning --- mcl_mobs:spawn_specific("mobs_mc:guardian_elder", { "mcl_core:water_source", "mclx_core:river_water_source" }, { "mcl_core:water_source", "mclx_core:river_water_source" }, 0, minetest.LIGHT_MAX+1, 30, 40000, 2, mcl_vars.mg_overworld_min, mobs_mc.water_level-18) +mcl_mobs:spawn_specific("mobs_mc:guardian_elder", { "mcl_core:water_source", "mclx_core:river_water_source" }, { "mcl_core:water_source", "mclx_core:river_water_source" }, 0, minetest.LIGHT_MAX+1, 30, 40000, 2, mcl_vars.mg_overworld_min, mobs_mc.water_level-18, mobs_mc.water_level) -- spawn eggs mcl_mobs.register_egg("mobs_mc:guardian_elder", S("Elder Guardian"), "#ceccba", "#747693", 0) diff --git a/mods/ENTITIES/mobs_mc/skeleton+stray.lua b/mods/ENTITIES/mobs_mc/skeleton+stray.lua index f41d57fd3..8ea4d9ced 100644 --- a/mods/ENTITIES/mobs_mc/skeleton+stray.lua +++ b/mods/ENTITIES/mobs_mc/skeleton+stray.lua @@ -113,7 +113,8 @@ local skeleton = { self.object:set_yaw(minetest.dir_to_yaw(vector.direction(self.object:get_pos(), self.attack:get_pos()))) end local dmg = math.random(2, 4) - mcl_bows.shoot_arrow("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) + local arrow = self.arrow:match("^(.+)_entity$") + mcl_bows.shoot_arrow(arrow, pos, dir, self.object:get_yaw(), self.object, nil, dmg) end end, shoot_interval = 2, @@ -140,10 +141,10 @@ stray.textures = { "mcl_bows_bow_0.png", }, } +stray.arrow = "mcl_potions:frost_arrow_entity" -- TODO: different sound (w/ echo) --- TODO: stray's arrow inflicts slowness status table.insert(stray.drops, { - name = "mcl_potions:slowness_arrow", + name = "mcl_potions:frost_arrow", chance = 2, min = 1, max = 1, @@ -152,13 +153,20 @@ table.insert(stray.drops, { local chance = 0.5 for i = 1, lvl do if chance > 1 then - return 1 + return 1 -- TODO verify this logic, I think this is not how chance works end chance = chance + (1 - chance) / 2 end return chance end, }) +table.insert(stray.drops, { + name = "mcl_mobitems:shiny_ice_crystal", + chance = 3, + min = 1, + max = 2, + looting = "rare", +}) mcl_mobs.register_mob("mobs_mc:stray", stray) diff --git a/mods/ENTITIES/mobs_mc/skeleton_wither.lua b/mods/ENTITIES/mobs_mc/skeleton_wither.lua index c39104f4b..b01fb4b96 100644 --- a/mods/ENTITIES/mobs_mc/skeleton_wither.lua +++ b/mods/ENTITIES/mobs_mc/skeleton_wither.lua @@ -98,7 +98,7 @@ mcl_mobs.register_mob("mobs_mc:witherskeleton", { fire_resistant = true, dealt_effect = { name = "withering", - factor = 1, + level = 1, dur = 10, }, }) diff --git a/mods/ENTITIES/mobs_mc/spider.lua b/mods/ENTITIES/mobs_mc/spider.lua index 16f802c09..d01c7afbe 100644 --- a/mods/ENTITIES/mobs_mc/spider.lua +++ b/mods/ENTITIES/mobs_mc/spider.lua @@ -138,7 +138,7 @@ cave_spider.sounds = table.copy(spider.sounds) cave_spider.sounds.base_pitch = 1.25 cave_spider.dealt_effect = { name = "poison", - factor = 2.5, + level = 2, dur = 7, } mcl_mobs.register_mob("mobs_mc:cave_spider", cave_spider) diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index 2897650c8..b1e291037 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -608,6 +608,8 @@ local professions = { { { { "mcl_nether:nether_wart_item", 22, 22 }, E1 }, { { "mcl_core:emerald", 3, 3 }, { "mcl_experience:bottle", 1, 1 } }, + { { "mcl_core:emerald", 15, 15 }, { "mcl_mobitems:aery_charge", 1, 1 } }, -- TODO reconsider + { { "mcl_core:emerald", 15, 15 }, { "mcl_mobitems:earthen_ash", 1, 1 } }, -- TODO reconsider }, }, }, diff --git a/mods/ENTITIES/mobs_mc/wither.lua b/mods/ENTITIES/mobs_mc/wither.lua index f1e1e6e78..252873629 100644 --- a/mods/ENTITIES/mobs_mc/wither.lua +++ b/mods/ENTITIES/mobs_mc/wither.lua @@ -349,7 +349,7 @@ mcl_mobs.register_mob("mobs_mc:wither", { mcl_util.deal_damage(objs[n], 8, {type = "magic"}) hit_some = true end - mcl_mobs.effect_functions["withering"](objs[n], 0.5, 10) + mcl_potions.give_effect("withering", objs[n], 2, 10) end if hit_some then mcl_mobs.effect(pos, 32, "mcl_particles_soul_fire_flame.png", 5, 10, self.reach, 1, 0) @@ -469,7 +469,7 @@ mcl_mobs.register_arrow("mobs_mc:wither_skull", { -- direct hit hit_player = function(self, player) local pos = vector.new(self.object:get_pos()) - mcl_mobs.effect_functions["withering"](player, 0.5, 10) + mcl_potions.give_effect("withering", player, 2, 10) player:punch(self.object, 1.0, { full_punch_interval = 0.5, damage_groups = {fleshy = 8}, @@ -484,7 +484,7 @@ mcl_mobs.register_arrow("mobs_mc:wither_skull", { hit_mob = function(self, mob) local pos = vector.new(self.object:get_pos()) - mcl_mobs.effect_functions["withering"](mob, 0.5, 10) + mcl_potions.give_effect("withering", mob, 2, 10) mob:punch(self.object, 1.0, { full_punch_interval = 0.5, damage_groups = {fleshy = 8}, @@ -522,7 +522,7 @@ mcl_mobs.register_arrow("mobs_mc:wither_skull_strong", { -- direct hit hit_player = function(self, player) local pos = vector.new(self.object:get_pos()) - mcl_mobs.effect_functions["withering"](player, 0.5, 10) + mcl_potions.give_effect("withering", player, 2, 10) player:punch(self.object, 1.0, { full_punch_interval = 0.5, damage_groups = {fleshy = 12}, @@ -541,7 +541,7 @@ mcl_mobs.register_arrow("mobs_mc:wither_skull_strong", { hit_mob = function(self, mob) local pos = vector.new(self.object:get_pos()) - mcl_mobs.effect_functions["withering"](mob, 0.5, 10) + mcl_potions.give_effect("withering", mob, 2, 10) mob:punch(self.object, 1.0, { full_punch_interval = 0.5, damage_groups = {fleshy = 12}, diff --git a/mods/ENVIRONMENT/mcl_raids/init.lua b/mods/ENVIRONMENT/mcl_raids/init.lua index 8e7c644ae..1b762b0e9 100644 --- a/mods/ENVIRONMENT/mcl_raids/init.lua +++ b/mods/ENVIRONMENT/mcl_raids/init.lua @@ -104,11 +104,11 @@ function mcl_raids.promote_to_raidcaptain(c) -- object mcl_raids.drop_obanner(pos) if cmi_cause and cmi_cause.type == "punch" and cmi_cause.puncher:is_player() then awards.unlock(cmi_cause.puncher:get_player_name(), "mcl:voluntary_exile") - local lv = mcl_potions.player_get_effect(cmi_cause.puncher, "bad_omen") + local lv = mcl_potions.get_effect_level(cmi_cause.puncher, "bad_omen") if not lv then lv = 0 else lv = lv.factor end lv = math.max(5,lv + 1) - mcl_potions.bad_omen_func(cmi_cause.puncher,lv,6000) + mcl_potions.give_effect_by_level("bad_omen", cmi_cause.puncher, lv, 6000) end end if old_ondie then return old_ondie(self,pos,cmi_cause) end @@ -296,7 +296,7 @@ mcl_events.register_event("raid",{ --minetest.log("Cond start raid") local r = {} for _,p in pairs(minetest.get_connected_players()) do - if mcl_potions.player_has_effect(p,"bad_omen") then + if mcl_potions.has_effect(p,"bad_omen") then local raid_pos = mcl_raids.find_village(p:get_pos()) if raid_pos then --minetest.log("We have a raid position. Start raid") @@ -310,7 +310,7 @@ mcl_events.register_event("raid",{ self.mobs = {} self.health_max = 1 self.health = 0 - local lv = mcl_potions.player_get_effect(minetest.get_player_by_name(self.player), "bad_omen") + local lv = mcl_potions.get_effect_level(minetest.get_player_by_name(self.player), "bad_omen") if lv and lv.factor and lv.factor > 1 then self.max_stage = 6 end end, cond_progress = function(self) @@ -331,7 +331,7 @@ mcl_events.register_event("raid",{ end, on_complete = function(self) awards.unlock(self.player,"mcl:hero_of_the_village") - mcl_potions.player_clear_effect(minetest.get_player_by_name(self.player),"bad_omen") + mcl_potions.clear_effect(minetest.get_player_by_name(self.player),"bad_omen") make_firework(self.pos,os.time()) end, }) diff --git a/mods/ENVIRONMENT/mcl_weather/skycolor.lua b/mods/ENVIRONMENT/mcl_weather/skycolor.lua index 6d9efd47a..87952845b 100644 --- a/mods/ENVIRONMENT/mcl_weather/skycolor.lua +++ b/mods/ENVIRONMENT/mcl_weather/skycolor.lua @@ -120,20 +120,26 @@ mcl_weather.skycolor = { override_day_night_ratio = function(player, ratio) local meta = player:get_meta() local has_night_vision = meta:get_int("night_vision") == 1 + local has_darkness = meta:get_int("darkness") == 1 local is_visited_shepherd = meta:get_int("mcl_shepherd:special") == 1 local arg - -- Apply night vision only for dark sky - local is_dark = minetest.get_timeofday() > 0.8 or minetest.get_timeofday() < 0.2 or mcl_weather.state ~= "none" - local pos = player:get_pos() - local dim = mcl_worlds.pos_to_dimension(pos) - if (has_night_vision or is_visited_shepherd) and is_dark and dim ~= "nether" and dim ~= "end" then - if ratio == nil then - arg = NIGHT_VISION_RATIO - else - arg = math.max(ratio, NIGHT_VISION_RATIO) - end + if has_darkness and not is_visited_shepherd then + if has_night_vision then arg = 0.1 + else arg = 0 end else - arg = ratio + -- Apply night vision only for dark sky + local is_dark = minetest.get_timeofday() > 0.8 or minetest.get_timeofday() < 0.2 or mcl_weather.state ~= "none" + local pos = player:get_pos() + local dim = mcl_worlds.pos_to_dimension(pos) + if (has_night_vision or is_visited_shepherd) and is_dark and dim ~= "nether" and dim ~= "end" then + if ratio == nil then + arg = NIGHT_VISION_RATIO + else + arg = math.max(ratio, NIGHT_VISION_RATIO) + end + else + arg = ratio + end end player:override_day_night_ratio(arg) end, diff --git a/mods/HELP/mcl_tt/locale/mcl_tt.pl.tr b/mods/HELP/mcl_tt/locale/mcl_tt.pl.tr index 7eb8f4c77..912c98ac7 100644 --- a/mods/HELP/mcl_tt/locale/mcl_tt.pl.tr +++ b/mods/HELP/mcl_tt/locale/mcl_tt.pl.tr @@ -45,4 +45,4 @@ Durability: @1=Wytrzymałość: @1 Block breaking strength: @1=Siła niszczenia bloku: @1 @1 uses=@1 użyć Unlimited uses=Nielimitowane użycia - +...stacks=...kumuluje się diff --git a/mods/HELP/mcl_tt/locale/template.txt b/mods/HELP/mcl_tt/locale/template.txt index 3e3b4d300..15076ec24 100644 --- a/mods/HELP/mcl_tt/locale/template.txt +++ b/mods/HELP/mcl_tt/locale/template.txt @@ -45,3 +45,4 @@ Block breaking strength: @1= @1 uses= Unlimited uses= Durability: @1= +...stacks= diff --git a/mods/HELP/mcl_tt/mod.conf b/mods/HELP/mcl_tt/mod.conf index e442e1320..b9ca12379 100644 --- a/mods/HELP/mcl_tt/mod.conf +++ b/mods/HELP/mcl_tt/mod.conf @@ -1,4 +1,4 @@ name = mcl_tt author = Wuzzy description = Add MCL2 tooltips -depends = tt, mcl_enchanting, mcl_colors +depends = tt, mcl_enchanting, mcl_colors, mcl_util diff --git a/mods/HELP/mcl_tt/snippets_mcl.lua b/mods/HELP/mcl_tt/snippets_mcl.lua index 14fcc1719..639422295 100644 --- a/mods/HELP/mcl_tt/snippets_mcl.lua +++ b/mods/HELP/mcl_tt/snippets_mcl.lua @@ -121,3 +121,58 @@ tt.register_snippet(function(itemstring, _, itemstack) return S("Durability: @1", S("@1 uses", remaining_use .."/".. use)) end end) + + +-- Potions info +tt.register_snippet(function(itemstring, _, itemstack) + if not itemstack then return end + local def = itemstack:get_definition() + if def.groups._mcl_potion ~= 1 then return end + + local s = "" + local meta = itemstack:get_meta() + local potency = meta:get_int("mcl_potions:potion_potent") + local plus = meta:get_int("mcl_potions:potion_plus") + local sl_factor = 1 + if def.groups.splash_potion == 1 then + sl_factor = mcl_potions.SPLASH_FACTOR + elseif def.groups.ling_potion == 1 then + sl_factor = mcl_potions.LINGERING_FACTOR + end + if def._dynamic_tt then s = s.. def._dynamic_tt((potency+1)*sl_factor).. "\n" end + local effects = def._effect_list + if effects then + local effect + local dur + local timestamp + local ef_level + local roman_lvl + local factor + local ef_tt + for name, details in pairs(effects) do + effect = mcl_potions.registered_effects[name] + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, plus) * sl_factor + if potency > 0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, potency) + end + else + dur = details.dur + end + timestamp = math.floor(dur/60)..string.format(":%02d",math.floor(dur % 60)) + if details.uses_level then + ef_level = details.level + details.level_scaling * (potency) + else + ef_level = details.level + end + if ef_level > 1 then roman_lvl = " ".. mcl_util.to_roman(ef_level) + else roman_lvl = "" end + s = s.. effect.description.. roman_lvl.. " (".. timestamp.. ")\n" + if effect.uses_factor then factor = effect.level_to_factor(ef_level) end + if effect.get_tt then ef_tt = minetest.colorize("grey", effect.get_tt(factor)) else ef_tt = "" end + if ef_tt ~= "" then s = s.. ef_tt.. "\n" end + if details.effect_stacks then s = s.. minetest.colorize("grey", S("...stacks")).. "\n" end + end + end + return s:trim() +end) diff --git a/mods/HELP/tt/init.lua b/mods/HELP/tt/init.lua index b3f2b8d55..8cc893d47 100644 --- a/mods/HELP/tt/init.lua +++ b/mods/HELP/tt/init.lua @@ -74,6 +74,22 @@ function tt.reload_itemstack_description(itemstack) local orig_desc = def._tt_original_description or def.description if meta:get_string("name") ~= "" then orig_desc = minetest.colorize(tt.NAME_COLOR, meta:get_string("name")) + elseif def.groups._mcl_potion == 1 then + local potency = meta:get_int("mcl_potions:potion_potent") + local plus = meta:get_int("mcl_potions:potion_plus") + if potency > 0 then + local sym_potency = mcl_util.to_roman(potency+1) + orig_desc = orig_desc.. " ".. sym_potency + end + if plus > 0 then + local sym_plus = " " + local i = plus + while i>0 do + i = i - 1 + sym_plus = sym_plus.. "+" + end + orig_desc = orig_desc.. sym_plus + end end local desc = apply_snippets(orig_desc, itemstring, toolcaps or def.tool_capabilities, itemstack) if desc == def.description and meta:get_string("description") == "" then return end diff --git a/mods/HELP/tt/mod.conf b/mods/HELP/tt/mod.conf index 2a260772d..7c4902418 100644 --- a/mods/HELP/tt/mod.conf +++ b/mods/HELP/tt/mod.conf @@ -1,4 +1,4 @@ name = tt author = Wuzzy description = Support for custom tooltip extensions for items -depends = mcl_colors +depends = mcl_colors, mcl_util diff --git a/mods/HUD/hudbars/init.lua b/mods/HUD/hudbars/init.lua index 505ff403b..7f86a959d 100644 --- a/mods/HUD/hudbars/init.lua +++ b/mods/HUD/hudbars/init.lua @@ -521,7 +521,9 @@ end local function update_health(player) local hp_max = player:get_properties().hp_max - hb.change_hudbar(player, "health", player:get_hp(), hp_max) + local hp = player:get_hp() + if hp > hp_max then hp = hp_max end + hb.change_hudbar(player, "health", hp, hp_max) end -- update built-in HUD bars diff --git a/mods/HUD/mcl_achievements/init.lua b/mods/HUD/mcl_achievements/init.lua old mode 100755 new mode 100644 diff --git a/mods/HUD/mcl_experience/bottle.lua b/mods/HUD/mcl_experience/bottle.lua index 62a3fb9ca..50f96656f 100644 --- a/mods/HUD/mcl_experience/bottle.lua +++ b/mods/HUD/mcl_experience/bottle.lua @@ -14,7 +14,7 @@ minetest.register_entity("mcl_experience:bottle",{ local n = node.name if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and minetest.get_item_group(n, "liquid") == 0 then minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1}) - mcl_experience.throw_xp(pos, math.random(3, 11)) + mcl_experience.throw_xp(pos, math.random(3, 11) + (self._luck or 0)) minetest.add_particlespawner({ amount = 50, time = 0.1, @@ -40,13 +40,18 @@ minetest.register_entity("mcl_experience:bottle",{ end, }) -local function throw_xp_bottle(pos, dir, velocity) +local function throw_xp_bottle(pos, dir, velocity, user) minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true) local obj = minetest.add_entity(pos, "mcl_experience:bottle") obj:set_velocity(vector.multiply(dir, velocity)) local acceleration = vector.multiply(dir, -3) acceleration.y = -9.81 obj:set_acceleration(acceleration) + if user then + local ent = obj:get_luaentity() + local luck = mcl_luck.get_luck(user:get_player_name()) + ent._luck = luck + end end minetest.register_craftitem("mcl_experience:bottle", { @@ -55,7 +60,7 @@ minetest.register_craftitem("mcl_experience:bottle", { wield_image = "mcl_experience_bottle.png", stack_max = 64, on_use = function(itemstack, placer, pointed_thing) - throw_xp_bottle(vector.add(placer:get_pos(), vector.new(0, 1.5, 0)), placer:get_look_dir(), 10) + throw_xp_bottle(vector.add(placer:get_pos(), vector.new(0, 1.5, 0)), placer:get_look_dir(), 10, placer) if not minetest.is_creative_enabled(placer:get_player_name()) then itemstack:take_item() end diff --git a/mods/HUD/mcl_experience/mod.conf b/mods/HUD/mcl_experience/mod.conf index a8e992c06..1e0c09c31 100644 --- a/mods/HUD/mcl_experience/mod.conf +++ b/mods/HUD/mcl_experience/mod.conf @@ -1,4 +1,4 @@ name = mcl_experience author = oilboi description = eXPerience mod -depends = mcl_gamemode +depends = mcl_gamemode, mcl_luck diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index 1288bc1d5..4898423b0 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -105,7 +105,13 @@ minetest.register_on_mods_loaded(function() nonmisc = true end if def.groups.brewitem then - table.insert(inventory_lists["brew"], name) + local str = name + if def.groups._mcl_potion == 1 then + local stack = ItemStack(name) + tt.reload_itemstack_description(stack) + str = stack:to_string() + end + table.insert(inventory_lists["brew"], str) nonmisc = true end if def.groups.craftitem then @@ -117,6 +123,23 @@ minetest.register_on_mods_loaded(function() table.insert(inventory_lists["misc"], name) end + if def.groups._mcl_potion == 1 then + if def.has_potent then + local stack = ItemStack(name) + local potency = def._default_potent_level - 1 + stack:get_meta():set_int("mcl_potions:potion_potent", potency) + tt.reload_itemstack_description(stack) + table.insert(inventory_lists["brew"], stack:to_string()) + end + if def.has_plus then + local stack = ItemStack(name) + local extend = def._default_extend_level + stack:get_meta():set_int("mcl_potions:potion_plus", extend) + tt.reload_itemstack_description(stack) + table.insert(inventory_lists["brew"], stack:to_string()) + end + end + table.insert(inventory_lists["all"], name) end end diff --git a/mods/HUD/mcl_inventory/mod.conf b/mods/HUD/mcl_inventory/mod.conf index 66f175c3b..fc10fe32a 100644 --- a/mods/HUD/mcl_inventory/mod.conf +++ b/mods/HUD/mcl_inventory/mod.conf @@ -2,4 +2,4 @@ name = mcl_inventory author = BlockMen description = Adds the player inventory and creative inventory. depends = mcl_init, mcl_formspec, mcl_enchanting, mcl_gamemode -optional_depends = mcl_armor, mcl_brewing, mcl_potions, mcl_enchanting, mcl_craftguide, mcl_player +optional_depends = mcl_armor, mcl_brewing, mcl_potions, mcl_enchanting, mcl_craftguide, mcl_player, tt diff --git a/mods/ITEMS/mcl_beacons/init.lua b/mods/ITEMS/mcl_beacons/init.lua index 9941e9e50..953d036d3 100644 --- a/mods/ITEMS/mcl_beacons/init.lua +++ b/mods/ITEMS/mcl_beacons/init.lua @@ -4,8 +4,12 @@ there are strings in meta, which are being used to see which effect will be give Valid strings: swiftness leaping - strenght + strength regeneration + haste + resistance + slow_falling + absorption ]]-- mcl_beacons = { @@ -122,10 +126,17 @@ local formspec_string= "image[1,4.5;1,1;custom_beacom_symbol_2.png]".. "image[1,6;1,1;custom_beacom_symbol_1.png]".. - "image_button[5.2,1.5;1,1;mcl_potions_effect_swift.png;swiftness;]".. + "image_button[5.2,1.5;1,1;mcl_potions_effect_swiftness.png;swiftness;]".. + "image_button[8.5,1.5;1,1;mcl_potions_effect_haste.png;haste;]".. + "image_button[5.2,3;1,1;mcl_potions_effect_leaping.png;leaping;]".. - "image_button[5.2,4.5;1,1;mcl_potions_effect_strong.png;strenght;]".. - "image_button[5.2,6;1,1;mcl_potions_effect_regenerating.png;regeneration;]".. + "image_button[8.5,3;1,1;mcl_potions_effect_resistance.png;resistance;]".. + + "image_button[5.2,4.5;1,1;mcl_potions_effect_strength.png;strength;]".. + "image_button[8.5,4.5;1,1;mcl_potions_effect_absorption.png;absorption;]".. + + "image_button[5.2,6;1,1;mcl_potions_effect_regeneration.png;regeneration;]".. + "image_button[8.5,6;1,1;mcl_potions_effect_slow_falling.png;slow_falling;]".. "item_image[1,7;1,1;mcl_core:diamond]".. "item_image[2.2,7;1,1;mcl_core:emerald]".. @@ -197,15 +208,7 @@ end local function effect_player(effect,pos,power_level, effect_level,player) local distance = vector.distance(player:get_pos(), pos) if distance > (power_level+1)*10 then return end - if effect == "swiftness" then - mcl_potions.swiftness_func(player,effect_level,16) - elseif effect == "leaping" then - mcl_potions.leaping_func(player, effect_level, 16) - elseif effect == "strenght" then - mcl_potions.strength_func(player, effect_level, 16) - elseif effect == "regeneration" then - mcl_potions.regeneration_func(player, effect_level, 16) - end + mcl_potions.give_effect_by_level(effect, player, effect_level, 16) end local function apply_effects_to_all_players(pos) @@ -254,7 +257,8 @@ minetest.register_node("mcl_beacons:beacon", { remove_beacon_beam(pos) end, on_receive_fields = function(pos, formname, fields, sender) - if fields.swiftness or fields.regeneration or fields.leaping or fields.strenght then + if fields.swiftness or fields.regeneration or fields.leaping or fields.strenght + or fields.haste or fields.resistance or fields.absorption or fields.slow_falling then local sender_name = sender:get_player_name() local power_level = beacon_blockcheck(pos) if minetest.is_protected(pos, sender_name) then @@ -293,6 +297,14 @@ minetest.register_node("mcl_beacons:beacon", { end minetest.get_meta(pos):set_string("effect","swiftness") successful = true + elseif fields.haste then + if power_level == 4 then + minetest.get_meta(pos):set_int("effect_level",2) + else + minetest.get_meta(pos):set_int("effect_level",1) + end + minetest.get_meta(pos):set_string("effect","haste") + successful = true elseif fields.leaping and power_level >= 2 then if power_level == 4 then minetest.get_meta(pos):set_int("effect_level",2) @@ -301,18 +313,38 @@ minetest.register_node("mcl_beacons:beacon", { end minetest.get_meta(pos):set_string("effect","leaping") successful = true + elseif fields.resistance and power_level >= 2 then + if power_level == 4 then + minetest.get_meta(pos):set_int("effect_level",2) + else + minetest.get_meta(pos):set_int("effect_level",1) + end + minetest.get_meta(pos):set_string("effect","resistance") + successful = true elseif fields.strenght and power_level >= 3 then if power_level == 4 then minetest.get_meta(pos):set_int("effect_level",2) else minetest.get_meta(pos):set_int("effect_level",1) end - minetest.get_meta(pos):set_string("effect","strenght") + minetest.get_meta(pos):set_string("effect","strength") + successful = true + elseif fields.absorption and power_level >= 3 then + if power_level == 4 then + minetest.get_meta(pos):set_int("effect_level",2) + else + minetest.get_meta(pos):set_int("effect_level",1) + end + minetest.get_meta(pos):set_string("effect","absorption") successful = true elseif fields.regeneration and power_level == 4 then minetest.get_meta(pos):set_int("effect_level",2) minetest.get_meta(pos):set_string("effect","regeneration") successful = true + elseif fields.slow_falling and power_level == 4 then + minetest.get_meta(pos):set_int("effect_level",2) + minetest.get_meta(pos):set_string("effect","slow_falling") + successful = true end if successful then if power_level == 4 then diff --git a/mods/ITEMS/mcl_bows/bow.lua b/mods/ITEMS/mcl_bows/bow.lua index 3d22c6df6..9f381f501 100644 --- a/mods/ITEMS/mcl_bows/bow.lua +++ b/mods/ITEMS/mcl_bows/bow.lua @@ -270,10 +270,10 @@ controls.register_on_release(function(player, key, time) local is_critical = false if charge >= BOW_CHARGE_TIME_FULL then speed = BOW_MAX_SPEED - local r = math.random(1,5) - if r == 1 then - -- 20% chance for critical hit - damage = 10 + local r = math.random(1,5) + mcl_luck.get_luck(player:get_player_name()) + if r > 4 then + -- 20% chance for critical hit (by default) + damage = 10 + math.floor((r-5)/5) -- mega crit (over crit) with high luck is_critical = true else damage = 9 diff --git a/mods/ITEMS/mcl_bows/crossbow.lua b/mods/ITEMS/mcl_bows/crossbow.lua index 54c6d7da2..c1cb7f8be 100644 --- a/mods/ITEMS/mcl_bows/crossbow.lua +++ b/mods/ITEMS/mcl_bows/crossbow.lua @@ -322,10 +322,10 @@ controls.register_on_press(function(player, key, time) -- Fully charged local is_critical = false speed = BOW_MAX_SPEED - local r = math.random(1,5) - if r == 1 then - -- 20% chance for critical hit - damage = 10 + local r = math.random(1,5) + mcl_luck.get_luck(player:get_player_name()) + if r > 4 then + -- 20% chance for critical hit (by default) + damage = 10 + math.floor((r-5)/5) -- mega crit (over crit) with high luck is_critical = true else damage = 9 diff --git a/mods/ITEMS/mcl_bows/mod.conf b/mods/ITEMS/mcl_bows/mod.conf index 0fdd666a3..61fb52ddb 100644 --- a/mods/ITEMS/mcl_bows/mod.conf +++ b/mods/ITEMS/mcl_bows/mod.conf @@ -1,6 +1,6 @@ name = mcl_bows author = Arcelmi description = This mod adds bows and arrows for MineClone 2. -depends = controls, mcl_particles, mcl_enchanting, mcl_init, mcl_util, mcl_shields, mcl_fovapi +depends = controls, mcl_particles, mcl_enchanting, mcl_init, mcl_util, mcl_shields, mcl_fovapi, mcl_luck optional_depends = awards, mcl_achievements, mcl_core, mcl_mobitems, playerphysics, doc, doc_identifier, mesecons_button diff --git a/mods/ITEMS/mcl_brewing/init.lua b/mods/ITEMS/mcl_brewing/init.lua index 306129320..cdac3429e 100644 --- a/mods/ITEMS/mcl_brewing/init.lua +++ b/mods/ITEMS/mcl_brewing/init.lua @@ -82,7 +82,7 @@ local function brewable(inv) for i=1,stand_size do - bottle = inv:get_stack("stand", i):get_name() + bottle = inv:get_stack("stand", i) alchemy = mcl_potions.get_alchemy(ingredient, bottle) if alchemy then diff --git a/mods/ITEMS/mcl_campfires/api.lua b/mods/ITEMS/mcl_campfires/api.lua index 7fa495edb..98318f3f1 100644 --- a/mods/ITEMS/mcl_campfires/api.lua +++ b/mods/ITEMS/mcl_campfires/api.lua @@ -380,7 +380,7 @@ minetest.register_globalstep(function(dtime) etime = 0 for _,pl in pairs(minetest.get_connected_players()) do local armor_feet = pl:get_inventory():get_stack("armor", 5) - if pl and pl:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.player_has_effect(pl, "fire_proof")) then + if pl and pl:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.has_effect(pl, "fire_resistance")) then return end burn_in_campfire(pl) diff --git a/mods/ITEMS/mcl_core/craftitems.lua b/mods/ITEMS/mcl_core/craftitems.lua index e89fe124a..f95d42ad2 100644 --- a/mods/ITEMS/mcl_core/craftitems.lua +++ b/mods/ITEMS/mcl_core/craftitems.lua @@ -167,17 +167,17 @@ local function eat_gapple(itemstack, placer, pointed_thing) return itemstack end - local regen_duration, absorbtion_factor = 5, 1 + local regen_duration, absorption = 5, 1 if itemstack:get_name() == "mcl_core:apple_gold_enchanted" then - regen_duration, absorbtion_factor = 20, 4 - mcl_potions.fire_resistance_func(placer, 1, 300) - mcl_potions.leaping_func(placer, 1, 300) + regen_duration, absorption = 20, 4 + mcl_potions.give_effect("fire_resistance", placer, 1, 300) + mcl_potions.give_effect_by_level("leaping", placer, 1, 300) if enable_fapples then - mcl_potions.swiftness_func(placer, absorbtion_factor, 120) + mcl_potions.give_effect_by_level("swiftness", placer, absorption, 120) end end - -- TODO: Absorbtion - mcl_potions.regeneration_func(placer, 2, regen_duration) + mcl_potions.give_effect_by_level("absorption", placer, absorption, 120) + mcl_potions.give_effect_by_level("regeneration", placer, 2, regen_duration) return gapple_hunger_restore(itemstack, placer, pointed_thing) end @@ -206,17 +206,17 @@ local function eat_gapple_delayed(itemstack, placer, pointed_thing) return itemstack end - local regen_duration, absorbtion_factor = 5, 1 + local regen_duration, absorption = 5, 1 if itemstack:get_name() == "mcl_core:apple_gold_enchanted" then - regen_duration, absorbtion_factor = 20, 4 - mcl_potions.fire_resistance_func(placer, 1, 300) - mcl_potions.leaping_func(placer, 1, 300) + regen_duration, absorption = 20, 4 + mcl_potions.give_effect("fire_resistance", placer, 1, 300) + mcl_potions.give_effect_by_level("leaping", placer, 1, 300) if enable_fapples then - mcl_potions.swiftness_func(placer, absorbtion_factor, 120) + mcl_potions.give_effect_by_level("swiftness", placer, absorption, 120) end end - -- TODO: Absorbtion - mcl_potions.regeneration_func(placer, 2, regen_duration) + mcl_potions.give_effect_by_level("absorption", placer, absorption, 120) + mcl_potions.give_effect_by_level("regeneration", placer, 2, regen_duration) --return gapple_hunger_restore(itemstack, placer, pointed_thing) end diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 67ef72056..dd01d5950 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -56,7 +56,7 @@ end function mcl_enchanting.get_enchantment_description(enchantment, level) local enchantment_def = mcl_enchanting.enchantments[enchantment] return enchantment_def.name .. - (enchantment_def.max_level == 1 and "" or " " .. mcl_enchanting.roman_numerals.toRoman(level)) + (enchantment_def.max_level == 1 and "" or " " .. mcl_util.to_roman(level)) end function mcl_enchanting.get_colorized_enchantment_description(enchantment, level) diff --git a/mods/ITEMS/mcl_enchanting/init.lua b/mods/ITEMS/mcl_enchanting/init.lua index 9f9fbd271..02ed1ee85 100644 --- a/mods/ITEMS/mcl_enchanting/init.lua +++ b/mods/ITEMS/mcl_enchanting/init.lua @@ -11,7 +11,6 @@ mcl_enchanting = { book_animation_steps = {0, 640, 680, 700, 740}, book_animation_loop = {["open"] = true, ["close"] = true}, book_animation_speed = 40, - roman_numerals = dofile(modpath .. "/roman_numerals.lua"), -- https://exercism.io/tracks/lua/exercises/roman-numerals/solutions/73c2fb7521e347209312d115f872fa49 enchantments = {}, overlay = "^[colorize:purple:50", --overlay = "^[invert:rgb^[multiply:#4df44d:50^[invert:rgb", diff --git a/mods/ITEMS/mcl_enchanting/mod.conf b/mods/ITEMS/mcl_enchanting/mod.conf index 610492857..d163fcd55 100644 --- a/mods/ITEMS/mcl_enchanting/mod.conf +++ b/mods/ITEMS/mcl_enchanting/mod.conf @@ -1,5 +1,5 @@ name = mcl_enchanting description = Enchanting for MineClone2 -depends = tt, walkover, mcl_sounds, mcl_colors, mcl_experience +depends = tt, walkover, mcl_sounds, mcl_colors, mcl_experience, mcl_util optional_depends = screwdriver author = Fleckenstein diff --git a/mods/ITEMS/mcl_enchanting/roman_numerals.lua b/mods/ITEMS/mcl_enchanting/roman_numerals.lua deleted file mode 100644 index f40c65406..000000000 --- a/mods/ITEMS/mcl_enchanting/roman_numerals.lua +++ /dev/null @@ -1,34 +0,0 @@ --------------------------------------------------------------------- ---! @file ---! @brief Convert from normal numbers to Roman Numerals ---------------------------------------------------------------------- -local conversionTable = { - { number = 1000, symbol = "M" }, - { number = 900, symbol = "CM" }, - { number = 500, symbol = "D" }, - { number = 400, symbol = "CD" }, - { number = 100, symbol = "C" }, - { number = 90, symbol = "XC" }, - { number = 50, symbol = "L" }, - { number = 40, symbol = "XL" }, - { number = 10, symbol = "X" }, - { number = 9, symbol = "IX" }, - { number = 5, symbol = "V" }, - { number = 4, symbol = "IV" }, - { number = 1, symbol = "I" } -} - -return{ - toRoman = function(number) - local romanNumeral = "" - - for _,table in pairs (conversionTable) do - while(number >= table.number) do - romanNumeral = romanNumeral .. table.symbol - number = number - table.number - end - end - - return romanNumeral - end -} diff --git a/mods/ITEMS/mcl_end/eye_of_ender.lua b/mods/ITEMS/mcl_end/eye_of_ender.lua index b5adc7cb6..065d7657e 100644 --- a/mods/ITEMS/mcl_end/eye_of_ender.lua +++ b/mods/ITEMS/mcl_end/eye_of_ender.lua @@ -28,8 +28,8 @@ minetest.register_entity("mcl_end:ender_eye", { self._age = self._age + dtime if self._age >= 3 then -- End of life - local r = math.random(1,5) - if r == 1 then + local r = math.random(1,15) + self._luck + if r <= 3 then -- 20% chance to get destroyed completely. -- 100% if in Creative Mode self.object:remove() @@ -85,11 +85,12 @@ minetest.register_craftitem("mcl_end:ender_eye", { if user == nil then return end + local player_name = user:get_player_name() local origin = user:get_pos() origin.y = origin.y + 1.5 local strongholds = mcl_structures.registered_structures["end_shrine"].static_pos local dim = mcl_worlds.pos_to_dimension(origin) - local is_creative = minetest.is_creative_enabled(user:get_player_name()) + local is_creative = minetest.is_creative_enabled(player_name) -- Just drop the eye of ender if there are no strongholds if #strongholds <= 0 or dim ~= "overworld" then @@ -124,6 +125,8 @@ minetest.register_craftitem("mcl_end:ender_eye", { -- Throw it! local obj = minetest.add_entity(origin, "mcl_end:ender_eye") local dir + local ent = obj:get_luaentity() + ent._luck = mcl_luck.get_luck(player_name) if lowest_dist <= 25 then local velocity = 4 diff --git a/mods/ITEMS/mcl_end/mod.conf b/mods/ITEMS/mcl_end/mod.conf index 3547074cf..3666ace19 100644 --- a/mods/ITEMS/mcl_end/mod.conf +++ b/mods/ITEMS/mcl_end/mod.conf @@ -1,2 +1,2 @@ name = mcl_end -depends = screwdriver, mcl_sounds, mcl_util, doc_items, mcl_worlds, mcl_structures, mcl_stonecutter +depends = screwdriver, mcl_sounds, mcl_util, doc_items, mcl_worlds, mcl_structures, mcl_stonecutter, mcl_luck diff --git a/mods/ITEMS/mcl_farming/potatoes.lua b/mods/ITEMS/mcl_farming/potatoes.lua index d3f4e4fc0..66c5169c4 100644 --- a/mods/ITEMS/mcl_farming/potatoes.lua +++ b/mods/ITEMS/mcl_farming/potatoes.lua @@ -142,7 +142,7 @@ minetest.register_on_item_eat(function (hp_change, replace_with_item, itemstack, -- 60% chance of poisoning with poisonous potato if itemstack:get_name() == "mcl_farming:potato_item_poison" then if math.random(1,10) >= 6 then - mcl_potions.poison_func(user, 1, 5) + mcl_potions.give_effect_by_level("poison", user, 1, 5) end end diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index ca9c3b2e3..f381ffefc 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -62,8 +62,8 @@ local fish = function(itemstack, player, pointed_thing) local junk_values = {10, 8.1, 6.1, 4.2} local luck_of_the_sea = math.min(mcl_enchanting.get_enchantment(itemstack, "luck_of_the_sea"), 3) local index = luck_of_the_sea + 1 - local fish_value = fish_values[index] - local junk_value = junk_values[index] + fish_value + local fish_value = fish_values[index] - mcl_luck.get_luck(ent.player) + local junk_value = junk_values[index] + fish_value - mcl_luck.get_luck(ent.player) if r <= fish_value then -- Fish items = mcl_loot.get_loot({ @@ -114,6 +114,8 @@ local fish = function(itemstack, player, pointed_thing) { itemstring = "mcl_mobitems:saddle", }, { itemstring = "mcl_flowers:waterlily", }, { itemstring = "mcl_mobitems:nautilus_shell", }, + { itemstring = "mcl_mobitems:spectre_membrane", }, + { itemstring = "mcl_mobitems:crystalline_drop", }, }, stacks_min = 1, stacks_max = 1, @@ -519,7 +521,8 @@ minetest.register_craftitem("mcl_fishing:pufferfish_raw", { minetest.register_on_item_eat(function (hp_change, replace_with_item, itemstack, user, pointed_thing) if itemstack:get_name() == "mcl_fishing:pufferfish_raw" then - mcl_potions.poison_func(user, 1/3, 60) + mcl_potions.give_effect_by_level("poison", user, 3, 60) + mcl_potions.give_effect_by_level("nausea", user, 2, 20) end end ) diff --git a/mods/ITEMS/mcl_fishing/mod.conf b/mods/ITEMS/mcl_fishing/mod.conf index 71bde6146..1af715aaf 100644 --- a/mods/ITEMS/mcl_fishing/mod.conf +++ b/mods/ITEMS/mcl_fishing/mod.conf @@ -1,3 +1,3 @@ name = mcl_fishing description = Adds fish and fishing poles to go fishing. -depends = mcl_core, mcl_sounds, mcl_loot, mcl_mobs, mcl_enchanting, mcl_throwing, mcl_colors, mcl_buckets +depends = mcl_core, mcl_sounds, mcl_loot, mcl_mobs, mcl_enchanting, mcl_throwing, mcl_colors, mcl_buckets, mcl_luck diff --git a/mods/ITEMS/mcl_flowers/init.lua b/mods/ITEMS/mcl_flowers/init.lua index 7c1fa1de4..85a65a165 100644 --- a/mods/ITEMS/mcl_flowers/init.lua +++ b/mods/ITEMS/mcl_flowers/init.lua @@ -194,8 +194,8 @@ def_clover.mesh = "mcl_clover_3leaf.obj" def_clover.tiles = { "mcl_flowers_clover.png" } def_clover.inventory_image = "mcl_flowers_clover_inv.png" def_clover.wield_image = "mcl_flowers_clover_inv.png" -def_clover.drop = nil def_clover.use_texture_alpha = "clip" +def_clover.drop = "mcl_flowers:clover" def_clover.selection_box = { type = "fixed", fixed = { -4/16, -0.5, -4/16, 4/16, 0, 4/16 }, @@ -212,6 +212,7 @@ def_4l_clover.tiles = { "mcl_flowers_fourleaf_clover.png" } def_4l_clover.inventory_image = "mcl_flowers_fourleaf_clover_inv.png" def_4l_clover.wield_image = "mcl_flowers_fourleaf_clover_inv.png" def_4l_clover.use_texture_alpha = "clip" +def_4l_clover.drop = "mcl_flowers:fourleaf_clover" minetest.register_node("mcl_flowers:fourleaf_clover", def_4l_clover) diff --git a/mods/ITEMS/mcl_mobitems/init.lua b/mods/ITEMS/mcl_mobitems/init.lua index 182bc8ced..4d92c2d43 100644 --- a/mods/ITEMS/mcl_mobitems/init.lua +++ b/mods/ITEMS/mcl_mobitems/init.lua @@ -154,7 +154,7 @@ local function drink_milk_delayed(itemstack, player, pointed_thing) ) then mcl_hunger.stop_poison(player) end - mcl_potions._reset_player_effects(player) + mcl_potions._reset_effects(player) end -- Wrapper for handling mcl_hunger delayed eating @@ -231,6 +231,46 @@ minetest.register_craftitem("mcl_mobitems:string",{ groups = { craftitem = 1 }, }) +minetest.register_craftitem("mcl_mobitems:spectre_membrane",{ + description = S("Spectre Membrane"), + _doc_items_longdesc = S("This is a crafting component dropped from dead spectres."), + inventory_image = "vl_mobitems_spectre_membrane.png", + groups = { craftitem = 1, brewitem = 1 }, + stack_max = 64, +}) + +minetest.register_craftitem("mcl_mobitems:shiny_ice_crystal",{ + description = S("Shiny Ice Crystal"), + _doc_items_longdesc = S("This item is mainly used for crafting."), + inventory_image = "vl_mobitems_ice_crystal.png", + groups = { craftitem = 1, brewitem = 1 }, + stack_max = 64, +}) + +minetest.register_craftitem("mcl_mobitems:aery_charge",{ + description = S("Aery Charge"), + _doc_items_longdesc = S("This item is mainly used for crafting."), -- TODO shoot? + inventory_image = "vl_mobitems_aery_charge.png", + groups = { craftitem = 1, brewitem = 1 }, + stack_max = 64, +}) + +minetest.register_craftitem("mcl_mobitems:crystalline_drop",{ + description = S("Crystalline Drop"), + _doc_items_longdesc = S("This item is mainly used for crafting."), -- TODO other uses? + inventory_image = "vl_mobitems_crystalline_drop.png", + groups = { craftitem = 1, brewitem = 1 }, + stack_max = 64, +}) + +minetest.register_craftitem("mcl_mobitems:earthen_ash",{ + description = S("Earthen Ash"), + _doc_items_longdesc = S("This item is mainly used for crafting."), -- TODO other uses? + inventory_image = "vl_mobitems_earthen_ash.png", + groups = { craftitem = 1, brewitem = 1 }, + stack_max = 64, +}) + minetest.register_craftitem("mcl_mobitems:blaze_rod", { description = S("Blaze Rod"), _doc_items_longdesc = S("This is a crafting component dropped from dead blazes."), @@ -580,6 +620,6 @@ minetest.register_craft({ minetest.register_on_item_eat(function (hp_change, replace_with_item, itemstack, user, pointed_thing) -- poisoning with spider eye if itemstack:get_name() == "mcl_mobitems:spider_eye" then - mcl_potions.poison_func(user, 1, 4) + mcl_potions.give_effect_by_level("poison", user, 1, 4) end end) diff --git a/mods/ITEMS/mcl_mobitems/locale/mcl_mobitems.pl.tr b/mods/ITEMS/mcl_mobitems/locale/mcl_mobitems.pl.tr index a58bfb474..484bc2d61 100644 --- a/mods/ITEMS/mcl_mobitems/locale/mcl_mobitems.pl.tr +++ b/mods/ITEMS/mcl_mobitems/locale/mcl_mobitems.pl.tr @@ -58,6 +58,12 @@ This item is dropped by dead squids. Squid ink can be used to as an ingredient String=Nić Strings are used in crafting.=Nić jest użyteczna w wytwarzaniu. +Spectre Membrane=Błona Widma +This is a crafting component dropped from dead spectres.=Jest to materiał do wytwarzania wypadający z martwych widm. +Shiny Ice Crystal=Lśniący Kryształ Lodu +Aery Charge=Powietrzny Ładunek +Crystalline Drop=Krystaliczna Kropla +Earthen Ash=Ziemny Popiół Blaze Rod=Płomienna różdżka This is a crafting component dropped from dead blazes.=Jest to materiał do wytwarzania wypadający z martwych płomyków. Blaze Powder=Płomienny proszek diff --git a/mods/ITEMS/mcl_nether/init.lua b/mods/ITEMS/mcl_nether/init.lua index 252768df5..b69355d5d 100644 --- a/mods/ITEMS/mcl_nether/init.lua +++ b/mods/ITEMS/mcl_nether/init.lua @@ -135,7 +135,7 @@ minetest.register_node("mcl_nether:magma", { -- From walkover mod on_walk_over = function(loc, nodeiamon, player) local armor_feet = player:get_inventory():get_stack("armor", 5) - if player and player:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.player_has_effect(player, "fire_proof")) then + if player and player:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.has_effect(player, "fire_resistance")) then return end -- Hurt players standing on top of this block diff --git a/mods/ITEMS/mcl_potions/API.md b/mods/ITEMS/mcl_potions/API.md new file mode 100644 index 000000000..be0784e22 --- /dev/null +++ b/mods/ITEMS/mcl_potions/API.md @@ -0,0 +1,318 @@ +## Potions and Effects API + + +* [Potions and Effects API](#potions-and-effects-api) + * [Namespace](#namespace) + * [Effects](#effects) + * [Functions](#functions) + * [Deprecated Functions](#deprecated-functions) + * [Tables](#tables) + * [Internally registered effects](#internally-registered-effects) + * [Constants](#constants) + * [Effect Definition](#effect-definition) + * [HP Hudbar Modifiers](#hp-hudbar-modifiers) + * [Functions](#functions) + * [HP Hudbar Modifier Definition](#hp-hudbar-modifier-definition) + * [Potions](#potions) + * [Functions](#functions) + * [Tables](#tables) + * [Internally registered potions](#internally-registered-potions) + * [Constants](#constants) + * [Potion Definition](#potion-definition) + * [Brewing](#brewing) + * [Functions](#functions) + * [Miscellaneous Functions](#miscellaneous-functions) + + +### Namespace +All of the API is defined in the `mcl_potions` namespace. + +### Effects +This section describes parts of the API related to defining and managing effects on players and entities. The mod defines a bunch of effects internally using the same API as described below. + +#### Functions +`mcl_potions.register_effect(def)` – takes an effect definition (`def`) and registers an effect if the definition is valid, and adds the known parts of the definition as well as the outcomes of processing of some parts of the definition to the `mcl_potions.registered_effects` table. This should only be used at load time. + + +`mcl_potions.apply_haste_fatigue(toolcaps, h_fac, f_fac)` – takes a table of tool capabilities (`toolcaps`) and modifies it using the provided haste factor (`h_fac`) and fatigue factor (`f_fac`). The factors default to no-op values. + + +`mcl_potions.hf_update_internal(hand, object)` – returns the `hand` of the `object` updated according to their combined haste and fatigue. **This doesn't change anything by itself!** Manual update of the hand with the hand returned by this function has to be done. This should only be called in situations that are *directly* impacted by haste and/or fatigue, and therefore require an update of the hand. + + +`mcl_potions.update_haste_and_fatigue(player)` – updates haste and fatigue on a `player` (described by an ObjectRef). This should be called whenever an update of the haste-type and fatigue-type effects is desired. + + +`mcl_potions._reset_haste_fatigue_item_meta(player)` – resets the item meta changes caused by haste-type and fatigue-type effects throughout the inventory of the `player` described by an ObjectRef. + + +`mcl_potions._clear_cached_effect_data(object)` – clears cashed effect data for the `object`. This shouldn't be used for resetting effects. + + +`mcl_potions._reset_effects(object, set_hud)` – actually resets the effects for the `object`. It also updates HUD if `set_hud` is `true` or undefined (`nil`). + + +`mcl_potions._save_player_effects(player)` – saves all effects of the `player` described by an ObjectRef to metadata. + + +`mcl_potions._load_player_effects(player)` – loads all effects from the metadata of the `player` described by an ObjectRef. + + +`mcl_potions._load_entity_effects(entity)` – loads all effects from the `entity` (a LuaEntity). + + +`mcl_potions.has_effect(object, effect_name)` – returns `true` if `object` (described by an ObjectRef) has the effect of the ID `effect_name`, `false` otherwise. + + +`mcl_potions.get_effect(object, effect_name)` - returns a table containing values of the effect of the ID `effect_name` on the `object` if the object has the named effect, `false` otherwise. + + +`mcl_potions.get_effect_level(object, effect_name)` – returns the level of the effect of the ID `effect_name` on the `object`. If the effect has no levels, returns `1`. If the object doesn't have the effect, returns `0`. If the effect is not registered, returns `nil`. + + +`mcl_potions.get_total_haste(object)` – returns the total haste of the `object` (from all haste-type effects). + + +`mcl_potions.get_total_fatigue(object)` – returns the total fatigue of the `object` (from all fatigue-type effects). + + +`mcl_potions.clear_effect(object, effect)` – attempts to remove the effect of the ID `effect` from the `object`. If the effect is not registered, logs a warning and returns `false`. Otherwise, returns `nil`. + + +`mcl_potions.make_invisible(obj_ref, hide)` – makes the object going by the `obj_ref` invisible if `hide` is true, visible otherwise. + + +`mcl_potions.register_generic_resistance_predicate(predicate)` – registers an arbitrary effect resistance predicate. This can be used e.g. to make some entity resistant to all (or some) effects under specific conditions. + +* `predicate` – `function(object, effect_name)` - return `true` if `object` resists effect of the ID `effect_name` + + +`mcl_potions.give_effect(name, object, factor, duration, no_particles)` – attempts to give effect of the ID `name` to the `object` with the provided `factor` and `duration`. If `no_particles` is `true`, no particles will be emitted from the object when under the effect. If the effect is not registered, target is invalid (or resistant), or the same effect with more potency is already applied to the target, this function does nothing and returns `false`. On success, this returns `true`. + + +`mcl_potions.give_effect_by_level(name, object, level, duration, no_particles)` – attempts to give effect of the ID `name` to the `object` with the provided `level` and `duration`. If `no_particles` is `true`, no particles will be emitted from the object when under the effect. This converts `level` to factor and calls `mcl_potions.give_effect()` internally, returning the return value of that function. `level` equal to `0` is no-op. + + +`mcl_potions.healing_func(object, hp)` – attempts to heal the `object` by `hp`. Negative `hp` harms magically instead. + + +#### Deprecated functions +**Don't use the following functions, use the above API instead!** The following are only provided for backwards compatibility and will be removed later. They all call `mcl_potions.give_effect()` internally. + +* `mcl_potions.strength_func(object, factor, duration)` +* `mcl_potions.leaping_func(object, factor, duration)` +* `mcl_potions.weakness_func(object, factor, duration)` +* `mcl_potions.swiftness_func(object, factor, duration)` +* `mcl_potions.slowness_func(object, factor, duration)` +* `mcl_potions.withering_func(object, factor, duration)` +* `mcl_potions.poison_func(object, factor, duration)` +* `mcl_potions.regeneration_func(object, factor, duration)` +* `mcl_potions.invisiblility_func(object, null, duration)` +* `mcl_potions.water_breathing_func(object, null, duration)` +* `mcl_potions.fire_resistance_func(object, null, duration)` +* `mcl_potions.night_vision_func(object, null, duration)` +* `mcl_potions.bad_omen_func(object, factor, duration)` + + + +#### Tables +`mcl_potions.registered_effects` – contains all effects that have been registered. You can read from it various data about the effects. You can overwrite the data and alter the effects' definitions too, but this is discouraged, i.e. only do this if you really know what you are doing. You shouldn't add effects directly to this table, as this would skip important setup; instead use the `mcl_potions.register_effect()` function, which is described above. + +#### Internally registered effects +You can't register effects going by these names, because they are already used: +* `invisibility` +* `poison` +* `regeneration` +* `strength` +* `weakness` +* `weakness` +* `dolphin_grace` +* `leaping` +* `slow_falling` +* `swiftness` +* `slowness` +* `levitation` +* `night_vision` +* `darkness` +* `glowing` +* `health_boost` +* `absorption` +* `fire_resistance` +* `resistance` +* `luck` +* `bad_luck` +* `bad_omen` +* `hero_of_village` +* `withering` +* `frost` +* `blindness` +* `nausea` +* `food_poisoning` +* `saturation` +* `haste` +* `fatigue` +* `conduit_power` + +#### Constants +`mcl_potions.LONGEST_MINING_TIME` – longest mining time of one block that can be achieved by slowing down the mining by fatigue-type effects. + +`mcl_potions.LONGEST_PUNCH_INTERVAL` – longest punch interval that can be achieved by slowing down the punching by fatigue-type effects. + +#### Effect Definition +```lua +def = { +-- required parameters in def: + name = string -- effect name in code (unique ID) - can't be one of the reserved words ("list", "heal", "remove", "clear") + description = S(string) -- actual effect name in game +-- optional parameters in def: + get_tt = function(factor) -- returns tooltip description text for use with potions + icon = string -- file name of the effect icon in HUD - defaults to one based on name + res_condition = function(object) -- returning true if target is to be resistant to the effect + on_start = function(object, factor) -- called when dealing the effect + on_load = function(object, factor) -- called on_joinplayer and on_activate + on_step = function(dtime, object, factor, duration) -- running every step for all objects with this effect + on_hit_timer = function(object, factor, duration) -- if defined runs a hit_timer depending on timer_uses_factor value + on_end = function(object) -- called when the effect wears off + after_end = function(object) -- called when the effect wears off, after purging the data of the effect + on_save_effect = function(object -- called when the effect is to be serialized for saving (supposed to do cleanup) + particle_color = string -- colorstring for particles - defaults to #3000EE + uses_factor = bool -- whether factor affects the effect + lvl1_factor = number -- factor for lvl1 effect - defaults to 1 if uses_factor + lvl2_factor = number -- factor for lvl2 effect - defaults to 2 if uses_factor + timer_uses_factor = bool -- whether hit_timer uses factor (uses_factor must be true) or a constant value (hit_timer_step must be defined) + hit_timer_step = float -- interval between hit_timer hits + damage_modifier = string -- damage flag of which damage is changed as defined by modifier_func, pass empty string for all damage + dmg_mod_is_type = bool -- damage_modifier string is used as type instead of flag of damage, defaults to false + modifier_func = function(damage, effect_vals) -- see damage_modifier, if not defined damage_modifier defaults to 100% resistance + modifier_priority = integer -- priority passed when registering damage_modifier - defaults to -50 + affects_item_speed = table +-- -- if provided, effect gets added to the item_speed_effects table, this should be true if the effect affects item speeds, +-- -- otherwise it won't work properly with other such effects (like haste and fatigue) +-- -- -- factor_is_positive - bool - whether values of factor between 0 and 1 should be considered +factor% or speed multiplier +-- -- -- - obviously +factor% is positive and speed multiplier is negative interpretation +-- -- -- - values of factor higher than 1 will have a positive effect regardless +-- -- -- - values of factor lower than 0 will have a negative effect regardless +} +``` + +### HP Hudbar Modifiers +This part of the API allows complex modification of the HP hudbar. It is mainly required here, so it is defined here. It may be moved to a different mod in the future. + +#### Functions +`mcl_potions.register_hp_hudbar_modifier(def)` – this function takes a modifier definition (`def`, described below) and registers a HP hudbar modifier if the definition is valid. + +#### HP Hudbar Modifier Definition +```lua +def = { +-- required parameters in def: + predicate = function(player) -- returns true if player fulfills the requirements (eg. has the effects) for the hudbar look + icon = string -- name of the icon to which the modifier should change the HP hudbar heart + priority = signed_int -- lower gets checked first, and first fulfilled predicate applies its modifier +} +``` + +### Potions +Magic! + +#### Functions +`mcl_potions.register_potion(def)` – takes a potion definition (`def`) and registers a potion if the definition is valid, and adds the known parts of the definition as well as the outcomes of processing of some parts of the definition to the `mcl_potions.registered_effects` table. This, depending on some fields of the definition, may as well register the corresponding splash potion, lingering potion and tipped arrow. This should only be used at load time. + +`mcl_potions.register_splash(name, descr, color, def)` – registers a splash potion (item and entity when thrown). This is mostly part of the internal API and probably shouldn't be used from outside, therefore not providing exact description. This is used by `mcl_potions.register_potion()`. + +`mcl_potions.register_lingering(name, descr, color, def)` – registers a lingering potion (item and entity when thrown). This is mostly part of the internal API and probably shouldn't be used from outside, therefore not providing exact description. This is used by `mcl_potions.register_potion()`. + +`mcl_potions.register_arrow(name, desc, color, def)` – registers a tipped arrow (item and entity when shot). This is mostly part of the internal API and probably shouldn't be used from outside, therefore not providing exact description. This is used by `mcl_potions.register_potion()`. + +#### Tables +`mcl_potions.registered_potions` – contains all potions that have been registered. You can read from it various data about the potions. You can overwrite the data and alter the definitions too, but this is discouraged, i.e. only do this if you really know what you are doing. You shouldn't add potions directly to this table, because they have to be registered as items too; instead use the `mcl_potions.register_potion()` function, which is described above. Some brewing recipes are autofilled based on this table after the loading of all the mods is done. + +#### Constants +* `mcl_potions.POTENT_FACTOR = 2` +* `mcl_potions.PLUS_FACTOR = 8/3` +* `mcl_potions.INV_FACTOR = 0.50` +* `mcl_potions.DURATION = 180` +* `mcl_potions.DURATION_INV = mcl_potions.DURATION * mcl_potions.INV_FACTOR` +* `mcl_potions.DURATION_POISON = 45` +* `mcl_potions.II_FACTOR = mcl_potions.POTENT_FACTOR` – **DEPRECATED** +* `mcl_potions.DURATION_PLUS = mcl_potions.DURATION * mcl_potions.PLUS_FACTOR` – **DEPRECATED** +* `mcl_potions.DURATION_2 = mcl_potions.DURATION / mcl_potions.II_FACTOR` – **DEPRECATED** +* `mcl_potions.SPLASH_FACTOR = 0.75` +* `mcl_potions.LINGERING_FACTOR = 0.25` + +#### Potion Definition +```lua +def = { +-- required parameters in def: + name = string, -- potion name in code +-- optional parameters in def: + desc_prefix = S(string), -- part of visible potion name, comes before the word "Potion" + desc_suffix = S(string), -- part of visible potion name, comes after the word "Potion" + _tt = S(string), -- custom tooltip text + _dynamic_tt = function(level), -- returns custom tooltip text dependent on potion level + _longdesc = S(string), -- text for in=game documentation + stack_max = int, -- max stack size - defaults to 1 + image = string, -- name of a custom texture of the potion icon + color = string, -- colorstring for potion icon when image is not defined - defaults to #0000FF + groups = table, -- item groups definition for the regular potion, not splash or lingering - +-- - must contain _mcl_potion=1 for tooltip to include dynamic_tt and effects +-- - defaults to {brewitem=1, food=3, can_eat_when_full=1, _mcl_potion=1} + nocreative = bool, -- adds a not_in_creative_inventory=1 group - defaults to false + _effect_list = {, -- all the effects dealt by the potion in the format of tables +-- -- the name of each sub-table should be a name of a registered effect, and fields can be the following: + uses_level = bool, -- whether the level of the potion affects the level of the effect - +-- -- -- - defaults to the uses_factor field of the effect definition + level = int, -- used as the effect level if uses_level is false and for lvl1 potions - defaults to 1 + level_scaling = int, -- used as the number of effect levels added per potion level - defaults to 1 - +-- -- -- - this has no effect if uses_level is false + dur = float, -- duration of the effect in seconds - defaults to mcl_potions.DURATION + dur_variable = bool, -- whether variants of the potion should have the length of this effect changed - +-- -- -- - defaults to true +-- -- -- - if at least one effect has this set to true, the potion has a "plus" variant + effect_stacks = bool, -- whether the effect stacks - defaults to false + } + uses_level = bool, -- whether the potion should come at different levels - +-- - defaults to true if uses_level is true for at least one effect, else false + drinkable = bool, -- defaults to true + has_splash = bool, -- defaults to true + has_lingering = bool, -- defaults to true + has_arrow = bool, -- defaults to false + has_potent = bool, -- whether there is a potent (e.g. II) variant - defaults to the value of uses_level + default_potent_level = int, -- potion level used for the default potent variant - defaults to 2 + default_extend_level = int, -- extention level (amount of +) used for the default extended variant - defaults to 1 + custom_on_use = function(user, level), -- called when the potion is drunk, returns true on success + custom_effect = function(object, level, plus), -- called when the potion effects are applied, returns true on success + custom_splash_effect = function(pos, level), -- called when the splash potion explodes, returns true on success + custom_linger_effect = function(pos, radius, level), -- called on the lingering potion step, returns true on success +} +``` + +### Brewing +Functions supporting brewing potions, used by the `mcl_brewing` module, which calls `mcl_potions.get_alchemy()`. + +#### Functions +`mcl_potions.register_ingredient_potion(input, out_table)` – registers a potion (`input`, item string) that can be combined with multiple ingredients for different outcomes; `out_table` contains the recipes for those outcomes + +`mcl_potions.register_water_brew(ingr, potion)` – registers a `potion` (item string) brewed from water with a specific ingredient (`ingr`) + +`mcl_potions.register_awkward_brew(ingr, potion)` – registers a `potion` (item string) brewed from an awkward potion with a specific ingredient (`ingr`) + +`mcl_potions.register_mundane_brew(ingr, potion)` – registers a `potion` (item string) brewed from a mundane potion with a specific ingredient (`ingr`) + +`mcl_potions.register_thick_brew(ingr, potion)` – registers a `potion` (item string) brewed from a thick potion with a specific ingredient (`ingr`) + +`mcl_potions.register_table_modifier(ingr, modifier)` – registers a brewing recipe altering the potion using a table; this is supposed to substitute one item with another + +`mcl_potions.register_inversion_recipe(input, output)` – what it says + +`mcl_potions.register_meta_modifier(ingr, mod_func)` – registers a brewing recipe altering the potion using a function; this is supposed to be a recipe that changes metadata only + +`mcl_potions.get_alchemy(ingr, pot)` – finds an alchemical recipe for given ingredient and potion; returns outcome + +### Miscellaneous Functions +`mcl_potions._extinguish_nearby_fire(pos, radius)` – attempts to extinguish fires in an area, both on objects and nodes. + +`mcl_potions._add_spawner(obj, color)` – adds a particle spawner denoting an effect being in action. + +`mcl_potions._use_potion(obj, color)` – visual and sound effects of drinking a potion. + +`mcl_potions.is_obj_hit(self, pos)` – determines if an object is hit (by a thrown potion). diff --git a/mods/ITEMS/mcl_potions/commands.lua b/mods/ITEMS/mcl_potions/commands.lua index 10bf86311..1c2cd7347 100644 --- a/mods/ITEMS/mcl_potions/commands.lua +++ b/mods/ITEMS/mcl_potions/commands.lua @@ -8,23 +8,9 @@ local S = minetest.get_translator(minetest.get_current_modname()) -- ░╚════╝░╚═╝░░╚═╝╚═╝░░╚═╝░░░╚═╝░░░  ░╚════╝░░╚════╝░╚═╝░░░░░╚═╝╚═╝░░░░░╚═╝╚═╝░░╚═╝╚═╝░░╚══╝╚═════╝░╚═════╝░ -local get_chat_function = {} - -get_chat_function["poison"] = mcl_potions.poison_func -get_chat_function["regeneration"] = mcl_potions.regeneration_func -get_chat_function["invisibility"] = mcl_potions.invisiblility_func -get_chat_function["fire_resistance"] = mcl_potions.fire_resistance_func -get_chat_function["night_vision"] = mcl_potions.night_vision_func -get_chat_function["water_breathing"] = mcl_potions.water_breathing_func -get_chat_function["leaping"] = mcl_potions.leaping_func -get_chat_function["swiftness"] = mcl_potions.swiftness_func -get_chat_function["heal"] = mcl_potions.healing_func -get_chat_function["bad_omen"] = mcl_potions.bad_omen_func -get_chat_function["withering"] = mcl_potions.withering_func - minetest.register_chatcommand("effect",{ - params = S(" []"), - description = S("Add a status effect to yourself. Arguments: : name of status effect, e.g. poison. : duration in seconds. : effect strength multiplier (1 = 100%)"), + params = S("|heal|list|clear|remove |INF [] [] [NOPART]"), + description = S("Add a status effect to yourself. Arguments: : name of status effect. Passing \"list\" as effect name lists available effects. Passing \"heal\" as effect name heals (or harms) by amount designed by the next parameter. Passing \"clear\" as effect name removes all effects. Passing \"remove\" as effect name removes the effect named by the next parameter. : duration in seconds. Passing \"INF\" as duration makes the effect infinite. (: amount of healing when the effect is \"heal\", passing a negative value subtracts health. : name of a status effect to be removed when using \"remove\" as the previous parameter.) : effect power determinant, bigger level results in more powerful effect for effects that depend on the level (no changes for other effects), defaults to 1, pass F to use low-level factor instead. : effect strength modifier, can mean different things depending on the effect, no changes for effects that do not depend on level/factor. NOPART at the end means no particles will be shown for this effect."), privs = {server = true}, func = function(name, params) @@ -37,22 +23,93 @@ minetest.register_chatcommand("effect",{ if not P[1] then return false, S("Missing effect parameter!") - elseif not tonumber(P[2]) then + elseif P[1] == "list" then + local effects = "heal" + for effect, _ in pairs(mcl_potions.registered_effects) do + effects = effects .. ", " .. effect + end + return true, effects + elseif P[1] == "heal" then + local hp = tonumber(P[2]) + if not hp or hp == 0 then + return false, S("Missing or invalid heal amount parameter!") + else + mcl_potions.healing_func(minetest.get_player_by_name(name), hp) + if hp > 0 then + if hp < 1 then hp = 1 end + return true, S("Player @1 healed by @2 HP.", name, hp) + else + if hp > -1 then hp = -1 end + return true, S("Player @1 harmed by @2 HP.", name, hp) + end + end + elseif P[1] == "clear" then + mcl_potions._reset_effects(minetest.get_player_by_name(name)) + return true, S("Effects cleared for player @1", name) + elseif P[1] == "remove" then + if not P[2] then + return false, S("Missing effect parameter!") + end + if mcl_potions.registered_effects[P[2]] then + mcl_potions.clear_effect(minetest.get_player_by_name(name), P[2]) + return true, S("Removed effect @1 from player @2", P[2], name) + else + return false, S("@1 is not an available status effect.", P[2]) + end + elseif not tonumber(P[2]) and P[2] ~= "INF" then return false, S("Missing or invalid duration parameter!") - elseif P[3] and not tonumber(P[3]) then - return false, S("Invalid factor parameter!") - end - -- Default factor = 1 - if not P[3] then - P[3] = 1.0 + elseif P[3] and not tonumber(P[3]) and P[3] ~= "F" and P[3] ~= "NOPART" then + return false, S("Invalid level parameter!") + elseif P[3] and P[3] == "F" and not P[4] then + return false, S("Missing or invalid factor parameter when level is F!") end - if get_chat_function[P[1]] then - get_chat_function[P[1]](minetest.get_player_by_name(name), tonumber(P[3]), tonumber(P[2])) - return true + -- Default level = 1 + if not P[3] then + P[3] = 1 + elseif P[3] == "NOPART" then + P[3] = 1 + P[4] = "NOPART" + end + + local inf = P[2] == "INF" + + local nopart = false + if P[3] == "F" then + nopart = P[5] == "NOPART" + else + nopart = P[4] == "NOPART" + end + + local def = mcl_potions.registered_effects[P[1]] + if def then + if P[3] == "F" then + local given = mcl_potions.give_effect(P[1], minetest.get_player_by_name(name), tonumber(P[4]), inf and "INF" or tonumber(P[2]), nopart) + if given then + if def.uses_factor then + return true, S("@1 effect given to player @2 for @3 seconds with factor of @4.", def.description, name, P[2], P[4]) + else + return true, S("@1 effect given to player @2 for @3 seconds.", def.description, name, P[2]) + end + else + return false, S("Giving effect @1 to player @2 failed.", def.description, name) + end + else + local given = mcl_potions.give_effect_by_level(P[1], minetest.get_player_by_name(name), tonumber(P[3]), inf and "INF" or tonumber(P[2]), nopart) + if given then + if def.uses_factor then + return true, S("@1 effect on level @2 given to player @3 for @4 seconds.", def.description, P[3], name, P[2]) + else + return true, S("@1 effect given to player @2 for @3 seconds.", def.description, name, P[2]) + end + else + return false, S("Giving effect @1 to player @2 failed.", def.description, name) + end + end else return false, S("@1 is not an available status effect.", P[1]) end end, }) + diff --git a/mods/ITEMS/mcl_potions/functions.lua b/mods/ITEMS/mcl_potions/functions.lua index 24aa2e402..460a1cb8f 100644 --- a/mods/ITEMS/mcl_potions/functions.lua +++ b/mods/ITEMS/mcl_potions/functions.lua @@ -1,47 +1,1221 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + local EF = {} -EF.invisible = {} -EF.poisoned = {} -EF.regenerating = {} -EF.strong = {} -EF.weak = {} -EF.water_breathing = {} -EF.leaping = {} -EF.swift = {} -- for swiftness AND slowness -EF.night_vision = {} -EF.fire_proof = {} -EF.bad_omen = {} -EF.withering = {} +mcl_potions.registered_effects = {} +local registered_effects = mcl_potions.registered_effects -- shorthand ref + +-- effects affecting item speed utilize numerous hacks, so they have to be counted separately +local item_speed_effects = {} local EFFECT_TYPES = 0 -for _,_ in pairs(EF) do - EFFECT_TYPES = EFFECT_TYPES + 1 +minetest.register_on_mods_loaded(function() + for _,_ in pairs(EF) do + EFFECT_TYPES = EFFECT_TYPES + 1 + end +end) + +-- ██████╗░███████╗░██████╗░██╗░██████╗████████╗███████╗██████╗ +-- ██╔══██╗██╔════╝██╔════╝░██║██╔════╝╚══██╔══╝██╔════╝██╔══██╗ +-- ██████╔╝█████╗░░██║░░██╗░██║╚█████╗░░░░██║░░░█████╗░░██████╔╝ +-- ██╔══██╗██╔══╝░░██║░░╚██╗██║░╚═══██╗░░░██║░░░██╔══╝░░██╔══██╗ +-- ██║░░██║███████╗╚██████╔╝██║██████╔╝░░░██║░░░███████╗██║░░██║ +-- ╚═╝░░╚═╝╚══════╝░╚═════╝░╚═╝╚═════╝░░░░╚═╝░░░╚══════╝╚═╝░░╚═╝ +-- +-- ███████╗███████╗███████╗███████╗░█████╗░████████╗░██████╗ +-- ██╔════╝██╔════╝██╔════╝██╔════╝██╔══██╗╚══██╔══╝██╔════╝ +-- █████╗░░█████╗░░█████╗░░█████╗░░██║░░╚═╝░░░██║░░░╚█████╗░ +-- ██╔══╝░░██╔══╝░░██╔══╝░░██╔══╝░░██║░░██╗░░░██║░░░░╚═══██╗ +-- ███████╗██║░░░░░██║░░░░░███████╗╚█████╔╝░░░██║░░░██████╔╝ +-- ╚══════╝╚═╝░░░░░╚═╝░░░░░╚══════╝░╚════╝░░░░╚═╝░░░╚═════╝░ + +local function generate_linear_lvl_to_fac(l1, l2) + local a = l2 - l1 + local b = 2*l1 - l2 + return function(level) + return (a*level + b) + end +end + +local function generate_linear_fac_to_lvl(l1, l2) + local a = 1/(l2 - l1) + local b = -(2*l1 - l2) * a + return function(factor) + return math.round(a*factor + b) + end +end + +local function generate_rational_lvl_to_fac(l1, l2) + local a = (l1 - l2) * 2 + local b = 2*l2 - l1 + return function(level) + if level == 0 then return 0 end + return (a/level + b) + end +end + +local function generate_rational_fac_to_lvl(l1, l2) + local a = (l1 - l2) * 2 + local b = 2*l2 - l1 + return function(factor) + if (factor - b) == 0 then return math.huge end + return math.round(a/(factor - b)) + end +end + +local function generate_modifier_func(name, dmg_flag, mod_func, is_type) + if dmg_flag == "" then return function(object, damage, reason) + if EF[name][object] and not reason.flags.bypasses_magic then + return mod_func and mod_func(damage, EF[name][object]) or 0 + end + end + elseif is_type then return function(object, damage, reason) + if EF[name][object] and not reason.flags.bypasses_magic and reason.type == dmg_flag then + return mod_func and mod_func(damage, EF[name][object]) or 0 + end + end + else return function(object, damage, reason) + if EF[name][object] and not reason.flags.bypasses_magic and reason.flags[dmg_flag] then + return mod_func and mod_func(damage, EF[name][object]) or 0 + end + end end +end + +-- API - registers an effect +-- required parameters in def: +-- name - string - effect name in code +-- description - translated string - actual effect name in game +-- optional parameters in def: +-- get_tt - function(factor) - returns tooltip description text for use with potions +-- icon - string - file name of the effect icon in HUD - defaults to one based on name +-- res_condition - function(object) - returning true if target is to be resistant to the effect +-- on_start - function(object, factor) - called when dealing the effect +-- on_load - function(object, factor) - called on_joinplayer and on_activate +-- on_step - function(dtime, object, factor, duration) - running every step for all objects with this effect +-- on_hit_timer - function(object, factor, duration) - if defined runs a hit_timer depending on timer_uses_factor value +-- on_end - function(object) - called when the effect wears off +-- after_end - function(object) - called when the effect wears off, after purging the data of the effect +-- on_save_effect - function(object - called when the effect is to be serialized for saving (supposed to do cleanup) +-- particle_color - string - colorstring for particles - defaults to #3000EE +-- uses_factor - bool - whether factor affects the effect +-- lvl1_factor - number - factor for lvl1 effect - defaults to 1 if uses_factor +-- lvl2_factor - number - factor for lvl2 effect - defaults to 2 if uses_factor +-- timer_uses_factor - bool - whether hit_timer uses factor (uses_factor must be true) or a constant value (hit_timer_step must be defined) +-- hit_timer_step - float - interval between hit_timer hits +-- damage_modifier - string - damage flag of which damage is changed as defined by modifier_func, pass empty string for all damage +-- dmg_mod_is_type - bool - damage_modifier string is used as type instead of flag of damage, defaults to false +-- modifier_func - function(damage, effect_vals) - see damage_modifier, if not defined damage_modifier defaults to 100% resistance +-- modifier_priority - integer - priority passed when registering damage_modifier - defaults to -50 +-- affects_item_speed - table +-- -- if provided, effect gets added to the item_speed_effects table, this should be true if the effect affects item speeds, +-- -- otherwise it won't work properly with other such effects (like haste and fatigue) +-- -- -- factor_is_positive - bool - whether values of factor between 0 and 1 should be considered +factor% or speed multiplier +-- -- -- - obviously +factor% is positive and speed multiplier is negative interpretation +-- -- -- - values of factor higher than 1 will have a positive effect regardless +-- -- -- - values of factor lower than 0 will have a negative effect regardless +-- -- -- - open an issue on our tracker if you have a usage that isn't supported by this API +function mcl_potions.register_effect(def) + local modname = minetest.get_current_modname() + local name = def.name + if name == nil then + error("Unable to register effect: name is nil") + end + if type(name) ~= "string" then + error("Unable to register effect: name is not a string") + end + if name == "list" or name == "heal" or name == "remove" or name == "clear" then + error("Unable to register effect: " .. name .. " is a reserved word") + end + if registered_effects[name] then + error("Effect named "..name.." already registered!") + end + if not def.description or type(def.description) ~= "string" then + error("Unable to register effect: description is not a string") + end + local pdef = {} + pdef.description = def.description + if not def.icon then + pdef.icon = modname.."_effect_"..name..".png" + else + pdef.icon = def.icon + end + pdef.get_tt = def.get_tt + pdef.res_condition = def.res_condition + pdef.on_start = def.on_start + pdef.on_load = def.on_load + pdef.on_step = def.on_step + pdef.on_hit_timer = def.on_hit_timer + pdef.on_end = def.on_end + pdef.on_save_effect = def.on_save_effect + if not def.particle_color then + pdef.particle_color = "#3000EE" + else + pdef.particle_color = def.particle_color + end + if def.uses_factor then + pdef.uses_factor = true + local l1 = def.lvl1_factor or 1 + local l2 = def.lvl2_factor or 2*l1 + if l1 < l2 then + pdef.level_to_factor = generate_linear_lvl_to_fac(l1, l2) + pdef.factor_to_level = generate_linear_fac_to_lvl(l1, l2) + pdef.inv_factor = false + elseif l1 > l2 then + pdef.level_to_factor = generate_rational_lvl_to_fac(l1, l2) + pdef.factor_to_level = generate_rational_fac_to_lvl(l1, l2) + pdef.inv_factor = true + else + error("Can't extrapolate levels from lvl1 and lvl2 bearing the same factor") + end + else + pdef.uses_factor = false + end + if def.on_hit_timer then + if def.timer_uses_factor then + if not def.uses_factor then error("Uses factor but does not use factor?") end + pdef.timer_uses_factor = true + else + if not def.hit_timer_step then error("If hit_timer does not use factor, hit_timer_step must be defined") end + pdef.timer_uses_factor = false + pdef.hit_timer_step = def.hit_timer_step + end + end + if def.damage_modifier then + mcl_damage.register_modifier( + generate_modifier_func(name, def.damage_modifier, def.modifier_func, def.dmg_mod_is_type), + def.modifier_priority or -50 + ) + end + registered_effects[name] = pdef + EF[name] = {} + item_speed_effects[name] = def.affects_item_speed +end + +mcl_potions.register_effect({ + name = "invisibility", + description = S("Invisiblity"), + get_tt = function(factor) + return S("body is invisible") + end, + on_start = function(object, factor) + mcl_potions.make_invisible(object, true) + end, + on_load = function(object, factor) + mcl_potions.make_invisible(object, true) + end, + on_end = function(object) + mcl_potions.make_invisible(object, false) + end, + particle_color = "#7F8392", + uses_factor = false, +}) + +mcl_potions.register_effect({ + name = "poison", + description = S("Poison"), + get_tt = function(factor) + return S("-1 HP / @1 s", factor) + end, + res_condition = function(object) + local entity = object:get_luaentity() + return (entity and (entity.harmed_by_heal or string.find(entity.name, "spider"))) + end, + on_hit_timer = function(object, factor, duration) + if mcl_util.get_hp(object) - 1 > 0 then + mcl_util.deal_damage(object, 1, {type = "magic"}) + end + end, + particle_color = "#4E9331", + uses_factor = true, + lvl1_factor = 1.25, + lvl2_factor = 0.6, + timer_uses_factor = true, +}) + +mcl_potions.register_effect({ + name = "regeneration", + description = S("Regeneration"), + get_tt = function(factor) + return S("+1 HP / @1 s", factor) + end, + res_condition = function(object) + local entity = object:get_luaentity() + return (entity and entity.harmed_by_heal) + end, + on_hit_timer = function(object, factor, duration) + local entity = object:get_luaentity() + if object:is_player() then + object:set_hp(math.min(object:get_properties().hp_max or 20, object:get_hp() + 1), { type = "set_hp", other = "regeneration" }) + elseif entity and entity.is_mob then + entity.health = math.min(entity.hp_max, entity.health + 1) + end + end, + particle_color = "#CD5CAB", + uses_factor = true, + lvl1_factor = 2.5, + lvl2_factor = 1.25, + timer_uses_factor = true, +}) + +mcl_potions.register_effect({ + name = "strength", + description = S("Strength"), + get_tt = function(factor) + return S("+@1% melee damage", 100*(factor-1)) + end, + particle_color = "#932423", + uses_factor = true, + lvl1_factor = 1.3, + lvl2_factor = 1.6, +}) + +mcl_potions.register_effect({ + name = "weakness", + description = S("Weakness"), + get_tt = function(factor) + return S("-@1% melee damage", 100*(1-factor)) + end, + particle_color = "#485D48", + uses_factor = true, + lvl1_factor = 0.8, + lvl2_factor = 0.6, +}) + +-- implementation of strength and weakness effects +-- mobs have this implemented in mcl_mobs/combat.lua in mob_class:on_punch() +mcl_damage.register_modifier(function(object, damage, reason) + if reason.direct and reason.direct == reason.source then + local hitter = reason.direct + local strength = EF.strength[hitter] + local weakness = EF.weakness[hitter] + if not strength and not weakness then return end + local str_fac = strength and strength.factor or 1 + local weak_fac = weakness and weakness.factor or 1 + return damage * str_fac * weak_fac + end +end, 0) + +mcl_potions.register_effect({ + name = "water_breathing", + description = S("Water Breathing"), + get_tt = function(factor) + return S("limitless breathing under water") + end, + res_condition = function(object) + return (not object:is_player()) -- TODO add support for breath setting for mobs + end, + on_step = function(dtime, object, factor, duration) + if object:get_breath() then + hb.hide_hudbar(object, "breath") + if object:get_breath() < 10 then object:set_breath(10) end + end + end, + particle_color = "#2E5299", + uses_factor = false, +}) + +mcl_potions.register_effect({ + name = "dolphin_grace", + description = S("Dolphin's Grace"), + get_tt = function(factor) + return S("swimming gracefully") + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob physics factor API + end, + on_hit_timer = function(object, factor, duration) + local node = minetest.get_node_or_nil(object:get_pos()) + if node and minetest.registered_nodes[node.name] + and minetest.get_item_group(node.name, "liquid") ~= 0 then + playerphysics.add_physics_factor(object, "speed", "mcl_potions:dolphin", 2) + else + playerphysics.remove_physics_factor(object, "speed", "mcl_potions:dolphin", 2) + end + end, + particle_color = "#6AABFD", + uses_factor = false, + timer_uses_factor = false, + hit_timer_step = 1, +}) + +mcl_potions.register_effect({ + name = "leaping", + description = S("Leaping"), + get_tt = function(factor) + if factor > 0 then return S("+@1% jumping power", math.floor(factor*100)) end + return S("-@1% jumping power", math.floor(-factor*100)) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob physics factor API + end, + on_start = function(object, factor) + playerphysics.add_physics_factor(object, "jump", "mcl_potions:leaping", 1+factor) + end, + on_end = function(object) + playerphysics.remove_physics_factor(object, "jump", "mcl_potions:leaping") + end, + particle_color = "#22FF4C", + uses_factor = true, + lvl1_factor = 0.5, + lvl2_factor = 1, +}) + +mcl_potions.register_effect({ + name = "slow_falling", + description = S("Slow Falling"), + get_tt = function(factor) + return S("decreases gravity effects") + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob physics factor API + end, + on_start = function(object, factor) + playerphysics.add_physics_factor(object, "gravity", "mcl_potions:slow_falling", 0.5) + end, + on_step = function(dtime, object, factor, duration) + local vel = object:get_velocity().y + if vel < -3 then object:add_velocity(vector.new(0,-3-vel,0)) end + end, + on_end = function(object) + playerphysics.remove_physics_factor(object, "gravity", "mcl_potions:slow_falling") + end, + particle_color = "#ACCCFF", +}) + +mcl_potions.register_effect({ + name = "swiftness", + description = S("Swiftness"), + get_tt = function(factor) + return S("+@1% running speed", math.floor(factor*100)) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob physics factor API + end, + on_start = function(object, factor) + playerphysics.add_physics_factor(object, "speed", "mcl_potions:swiftness", 1+factor) + end, + on_end = function(object) + playerphysics.remove_physics_factor(object, "speed", "mcl_potions:swiftness") + end, + particle_color = "#7CAFC6", + uses_factor = true, + lvl1_factor = 0.2, + lvl2_factor = 0.4, +}) + +mcl_potions.register_effect({ + name = "slowness", + description = S("Slowness"), + get_tt = function(factor) + return S("-@1% running speed", math.floor(factor*100)) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob physics factor API + end, + on_start = function(object, factor) + playerphysics.add_physics_factor(object, "speed", "mcl_potions:slowness", 1-factor) + end, + on_end = function(object) + playerphysics.remove_physics_factor(object, "speed", "mcl_potions:slowness") + end, + particle_color = "#5A6C81", + uses_factor = true, + lvl1_factor = 0.15, + lvl2_factor = 0.3, +}) + +mcl_potions.register_effect({ + name = "levitation", + description = S("Levitation"), + get_tt = function(factor) + return S("moves body upwards at @1 nodes/s", factor) + end, + on_step = function(dtime, object, factor, duration) + local vel = object:get_velocity().y + if vel 0.6 then EF.darkness[object].flashdir = false end + flash = EF.darkness[object].flashdir and (flash + dtime) or (flash - dtime) + object:set_sky({fog = { + fog_start = flash, + }}) + EF.darkness[object].flash = flash + else + object:set_sky({fog = { + fog_start = 0.9, + }}) + end + mcl_weather.skycolor.update_sky_color({object}) + end, + on_end = function(object) + object:get_meta():set_int("darkness", 0) + mcl_weather.skycolor.update_sky_color({object}) + object:set_sky({fog = { + fog_distance = -1, + fog_start = -1, + }}) + end, + particle_color = "#000000", + uses_factor = true, + lvl1_factor = 30, + lvl2_factor = 20, +}) + +local GLOW_DISTANCE = 30 +local CLOSE_GLOW_LIMIT = 3 +local MIN_GLOW_SCALE = 1 +local MAX_GLOW_SCALE = 4 +local SCALE_DIFF = MAX_GLOW_SCALE - MIN_GLOW_SCALE +local SCALE_FACTOR = (GLOW_DISTANCE - CLOSE_GLOW_LIMIT) / SCALE_DIFF +local abs = math.abs +mcl_potions.register_effect({ + name = "glowing", + description = S("Glowing"), + get_tt = function(factor) + return S("more visible at all times") + end, + on_start = function(object, factor) + EF.glowing[object].waypoints = {} + end, + on_step = function(dtime, object, factor, duration) + local pos = object:get_pos() + if not pos then return end + local x, y, z = pos.x, pos.y, pos.z + for _, player in pairs(minetest.get_connected_players()) do + local pp = player:get_pos() + if pp and player ~= object then + local hud_id = EF.glowing[object].waypoints[player] + if abs(pp.x-x) < GLOW_DISTANCE and abs(pp.y-y) < GLOW_DISTANCE + and abs(pp.z-z) < GLOW_DISTANCE then + local distance = vector.distance(pos, pp) + local scale + if distance <= CLOSE_GLOW_LIMIT then scale = MAX_GLOW_SCALE + elseif distance >= GLOW_DISTANCE then scale = MIN_GLOW_SCALE + else scale = (GLOW_DISTANCE - distance) / SCALE_FACTOR + MIN_GLOW_SCALE end + if hud_id then + player:hud_change(hud_id, "world_pos", pos) + player:hud_change(hud_id, "scale", {x = scale, y = scale}) + else + EF.glowing[object].waypoints[player] = player:hud_add({ + hud_elem_type = "image_waypoint", + position = {x = 0.5, y = 0.5}, + scale = {x = scale, y = scale}, + text = "mcl_potions_glow_waypoint.png", + alignment = {x = 0, y = -1}, + world_pos = pos, + }) + end + elseif hud_id then + player:hud_remove(hud_id) + EF.glowing[object].waypoints[player] = nil + end + end + end + end, + on_end = function(object) + for player, hud_id in pairs(EF.glowing[object].waypoints) do + if player:get_pos() then player:hud_remove(hud_id) end + end + end, + on_save_effect = function(object) + for player, hud_id in pairs(EF.glowing[object].waypoints) do + if player:get_pos() then player:hud_remove(hud_id) end + end + EF.glowing[object].waypoints = {} + end, + particle_color = "#FFFF77", + uses_factor = false, +}) + +mcl_potions.register_effect({ + name = "health_boost", + description = S("Health Boost"), + get_tt = function(factor) + return S("HP increased by @1", factor) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob HP modifier API? + end, + on_start = function(object, factor) + object:set_properties({hp_max = minetest.PLAYER_MAX_HP_DEFAULT+factor}) + end, + on_end = function(object) + object:set_properties({hp_max = minetest.PLAYER_MAX_HP_DEFAULT}) + end, + particle_color = "#FF2222", + uses_factor = true, + lvl1_factor = 4, + lvl2_factor = 8, +}) + +mcl_potions.register_effect({ + name = "absorption", + description = S("Absorption"), + get_tt = function(factor) + return S("absorbs up to @1 incoming damage", factor) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO dmg modifiers don't work for mobs + end, + on_start = function(object, factor) + hb.change_hudbar(object, "absorption", factor, (math.floor(factor/20-0.05)+1)*20) + EF.absorption[object].absorb = factor + end, + on_load = function(object, factor) + minetest.after(0, function() hb.change_hudbar(object, "absorption", nil, (math.floor(factor/20-0.05)+1)*20) end) + end, + on_step = function(dtime, object, factor, duration) + hb.change_hudbar(object, "absorption", EF.absorption[object].absorb) + end, + on_end = function(object) + hb.change_hudbar(object, "absorption", 0) + end, + particle_color = "#B59500", + uses_factor = true, + lvl1_factor = 4, + lvl2_factor = 8, + damage_modifier = "", + modifier_func = function(damage, effect_vals) + local absorb = effect_vals.absorb + local carryover = 0 + if absorb > damage then + effect_vals.absorb = absorb - damage + else + carryover = damage - absorb + effect_vals.absorb = 0 + end + return carryover + end, +}) + +mcl_potions.register_effect({ + name = "fire_resistance", + description = S("Fire Resistance"), + get_tt = function(factor) + return S("resistance to fire damage") + end, + res_condition = function(object) + return (not object:is_player()) -- TODO dmg modifiers don't work for mobs + end, + particle_color = "#E49A3A", + uses_factor = false, + damage_modifier = "is_fire", +}) + +mcl_potions.register_effect({ + name = "resistance", + description = S("Resistance"), + get_tt = function(factor) + return S("resist @1% of incoming damage", math.floor(factor*100)) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO dmg modifiers don't work for mobs + end, + particle_color = "#2552A5", + uses_factor = true, + lvl1_factor = 0.2, + lvl2_factor = 0.4, + damage_modifier = "", + modifier_func = function(damage, effect_vals) + return damage - (effect_vals.factor)*damage + end, +}) + +mcl_potions.register_effect({ + name = "luck", + description = S("Luck"), + particle_color = "#7BFF42", + res_condition = function(object) + return (not object:is_player()) -- TODO what should it do for mobs? + end, + on_start = function(object, factor) + mcl_luck.apply_luck_modifier(object:get_player_name(), "mcl_potions:luck", factor) + end, + on_load = function(object, factor) + mcl_luck.apply_luck_modifier(object:get_player_name(), "mcl_potions:luck", factor) + end, + on_end = function(object) + mcl_luck.remove_luck_modifier(object:get_player_name(), "mcl_potions:luck") + end, + uses_factor = true, +}) + +mcl_potions.register_effect({ + name = "bad_luck", + description = S("Bad Luck"), + particle_color = "#887343", + res_condition = function(object) + return (not object:is_player()) -- TODO what should it do for mobs? + end, + on_start = function(object, factor) + mcl_luck.apply_luck_modifier(object:get_player_name(), "mcl_potions:bad_luck", -factor) + end, + on_load = function(object, factor) + mcl_luck.apply_luck_modifier(object:get_player_name(), "mcl_potions:bad_luck", -factor) + end, + on_end = function(object) + mcl_luck.remove_luck_modifier(object:get_player_name(), "mcl_potions:bad_luck") + end, + uses_factor = true, +}) + +mcl_potions.register_effect({ + name = "bad_omen", + description = S("Bad Omen"), + get_tt = function(factor) + return S("danger is imminent") + end, + particle_color = "#472331", + uses_factor = true, +}) + +mcl_potions.register_effect({ + name = "hero_of_village", + description = S("Hero of the Village"), + particle_color = "#006D2A", +}) + +mcl_potions.register_effect({ + name = "withering", + description = S("Withering"), + get_tt = function(factor) + return S("-1 HP / @1 s, can kill", factor) + end, + res_condition = function(object) + local entity = object:get_luaentity() + return (entity and string.find(entity.name, "wither")) + end, + on_hit_timer = function(object, factor, duration) + if object:is_player() or object:get_luaentity() then + mcl_util.deal_damage(object, 1, {type = "magic"}) + end + end, + particle_color = "#292929", + uses_factor = true, + lvl1_factor = 2, + lvl2_factor = 1, + timer_uses_factor = true, +}) + +mcl_potions.register_effect({ + name = "frost", + description = S("Frost"), + get_tt = function(factor) + return S("-1 HP / 1 s, can kill, -@1% running speed", math.floor(factor*100)) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob physics factor API + end, + on_start = function(object, factor) + mcl_burning.extinguish(object) + playerphysics.add_physics_factor(object, "speed", "mcl_potions:frost", 1-factor) + if EF.frost[object].vignette then return end + EF.frost[object].vignette = object:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 0.5}, + scale = {x = -101, y = -101}, + text = "mcl_potions_frost_hud.png", + z_index = -400 + }) + end, + on_load = function(object, factor) + EF.frost[object].vignette = object:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 0.5}, + scale = {x = -101, y = -101}, + text = "mcl_potions_frost_hud.png", + z_index = -400 + }) + end, + on_hit_timer = function(object, factor, duration) + if object:is_player() or object:get_luaentity() then + mcl_util.deal_damage(object, 1, {type = "magic"}) + end + end, + on_end = function(object) + playerphysics.remove_physics_factor(object, "speed", "mcl_potions:frost") + if not EF.frost[object] then return end + object:hud_remove(EF.frost[object].vignette) + end, + particle_color = "#5B7DAA", + uses_factor = true, + lvl1_factor = 0.1, + lvl2_factor = 0.2, + timer_uses_factor = false, + hit_timer_step = 1, + damage_modifier = "is_fire", + modifier_func = function(damage, effect_vals) + effect_vals.timer = effect_vals.dur + return 0 + end, +}) + +mcl_potions.register_effect({ + name = "blindness", + description = "Blindness", + get_tt = function(factor) + return S("impaired sight") + end, + res_condition = function(object) + return (not object:is_player()) -- TODO what should it do for mobs? + end, + on_start = function(object, factor) + EF.blindness[object].vignette = object:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 0.5}, + scale = {x = -101, y = -101}, + text = "mcl_potions_blindness_hud.png", + z_index = -401 + }) + mcl_fovapi.apply_modifier(object, "mcl_potions:blindness") + end, + on_load = function(object, factor) + EF.blindness[object].vignette = object:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 0.5}, + scale = {x = -101, y = -101}, + text = "mcl_potions_blindness_hud.png", + z_index = -401 + }) + mcl_fovapi.apply_modifier(object, "mcl_potions:blindness") + end, + on_end = function(object) + mcl_fovapi.remove_modifier(object, "mcl_potions:blindness") + if not EF.blindness[object] then return end + object:hud_remove(EF.blindness[object].vignette) + end, + particle_color = "#686868", + uses_factor = false, +}) +mcl_fovapi.register_modifier({ + name = "mcl_potions:blindness", + fov_factor = 0.6, + time = 1, +}) + +mcl_potions.register_effect({ + name = "nausea", + description = S("Nausea"), + get_tt = function(factor) + return S("not feeling very well...").."\n"..S("frequency: @1 / 1 s", factor) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO what should it do for mobs? + end, + on_start = function(object, factor) + object:set_lighting({ + saturation = -1.0, + }) + end, + on_hit_timer = function(object, factor, duration) + if EF.nausea[object].high then + mcl_fovapi.remove_modifier(object, "mcl_potions:nausea_high", factor) + mcl_fovapi.apply_modifier(object, "mcl_potions:nausea_low", factor) + EF.nausea[object].high = false + else + mcl_fovapi.apply_modifier(object, "mcl_potions:nausea_high", factor) + mcl_fovapi.remove_modifier(object, "mcl_potions:nausea_low", factor) + EF.nausea[object].high = true + end + end, + on_end = function(object) + object:set_lighting({ + saturation = 1.0, + }) + mcl_fovapi.remove_modifier(object, "mcl_potions:nausea_high") + mcl_fovapi.remove_modifier(object, "mcl_potions:nausea_low") + end, + particle_color = "#60AA30", + uses_factor = true, + lvl1_factor = 2, + lvl2_factor = 1, + timer_uses_factor = true, +}) +mcl_fovapi.register_modifier({ + name = "mcl_potions:nausea_high", + fov_factor = 2.2, + time = 1, +}) +mcl_fovapi.register_modifier({ + name = "mcl_potions:nausea_low", + fov_factor = 0.2, + time = 1, +}) + +mcl_potions.register_effect({ + name = "food_poisoning", + description = S("Food Poisoning"), + get_tt = function(factor) + return S("exhausts by @1 per second", factor) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO what should it do for mobs? + end, + on_start = function(object, factor) + hb.change_hudbar(object, "hunger", nil, nil, "mcl_hunger_icon_foodpoison.png", nil, "mcl_hunger_bar_foodpoison.png") + if mcl_hunger.debug then + hb.change_hudbar(object, "exhaustion", nil, nil, nil, nil, "mcl_hunger_bar_foodpoison.png") + end + end, + on_load = function(object, factor) -- TODO refactor and add hunger bar modifier API + hb.change_hudbar(object, "hunger", nil, nil, "mcl_hunger_icon_foodpoison.png", nil, "mcl_hunger_bar_foodpoison.png") + if mcl_hunger.debug then + hb.change_hudbar(object, "exhaustion", nil, nil, nil, nil, "mcl_hunger_bar_foodpoison.png") + end + end, + on_step = function(dtime, object, factor, duration) + mcl_hunger.exhaust(object:get_player_name(), dtime*factor) + end, + on_end = function(object) + mcl_hunger.reset_bars_poison_hunger(object) + end, + particle_color = "#83A061", + uses_factor = true, + lvl1_factor = 100, + lvl2_factor = 200, +}) + +mcl_potions.register_effect({ + name = "saturation", + description = S("Saturation"), + get_tt = function(factor) + return S("saturates by @1 per second", factor) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO what should it do for mobs? + end, + on_step = function(dtime, object, factor, duration) + mcl_hunger.set_hunger(object, math.min(mcl_hunger.get_hunger(object)+dtime*factor, 20)) + mcl_hunger.saturate(object:get_player_name(), dtime*factor) + end, + particle_color = "#CEAE29", + uses_factor = true, +}) + +-- constants relevant for effects altering mining and attack speed +local LONGEST_MINING_TIME = 300 +local LONGEST_PUNCH_INTERVAL = 10 +mcl_potions.LONGEST_MINING_TIME = LONGEST_MINING_TIME +mcl_potions.LONGEST_PUNCH_INTERVAL = LONGEST_PUNCH_INTERVAL + +function mcl_potions.apply_haste_fatigue(toolcaps, h_fac, f_fac) + if f_fac == 0 then + local fpi = toolcaps.full_punch_interval + toolcaps.full_punch_interval = fpi > LONGEST_PUNCH_INTERVAL and fpi or LONGEST_PUNCH_INTERVAL + else + toolcaps.full_punch_interval = toolcaps.full_punch_interval / (1+h_fac) / f_fac + end + for name, group in pairs(toolcaps.groupcaps) do + local t = group.times + for i=1, #t do + if f_fac == 0 then + t[i] = t[i] > LONGEST_MINING_TIME and t[i] or LONGEST_MINING_TIME + else + local old_time = t[i] + t[i] = t[i] / (1+h_fac) / f_fac + if old_time < LONGEST_MINING_TIME and t[i] > LONGEST_MINING_TIME then + t[i] = LONGEST_MINING_TIME + end + end + end + end + return toolcaps +end + +function mcl_potions.hf_update_internal(hand, object) + -- TODO add a check for creative mode? + local meta = hand:get_meta() + local h_fac = mcl_potions.get_total_haste(object) + local f_fac = mcl_potions.get_total_fatigue(object) + local toolcaps = hand:get_tool_capabilities() + meta:set_tool_capabilities(mcl_potions.apply_haste_fatigue(toolcaps, h_fac, f_fac)) + return hand +end + +local function haste_fatigue_hand_update(object) + local inventory = object:get_inventory() + if not inventory or inventory:get_size("hand") < 1 then return end + local hand = inventory:get_stack("hand", 1) + inventory:set_stack("hand", 1, mcl_potions.hf_update_internal(hand, object)) +end + +mcl_potions.register_effect({ + name = "haste", + description = S("Haste"), + get_tt = function(factor) + return S("+@1% mining and attack speed", math.floor(factor*100)) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob API support + end, + on_start = haste_fatigue_hand_update, + after_end = function(object) + haste_fatigue_hand_update(object) + mcl_potions._reset_haste_fatigue_item_meta(object) + end, + particle_color = "#FFFF00", + uses_factor = true, + lvl1_factor = 0.2, + lvl2_factor = 0.4, + affects_item_speed = {factor_is_positive = true}, +}) + +mcl_potions.register_effect({ + name = "fatigue", + description = S("Fatigue"), + get_tt = function(factor) + return S("-@1% mining and attack speed", math.floor((1-factor)*100)) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob API support + end, + on_start = haste_fatigue_hand_update, + after_end = function(object) + haste_fatigue_hand_update(object) + mcl_potions._reset_haste_fatigue_item_meta(object) + end, + particle_color = "#64643D", + uses_factor = true, + lvl1_factor = 0.3, + lvl2_factor = 0.09, + affects_item_speed = {}, +}) + +mcl_potions.register_effect({ + name = "conduit_power", + description = S("Conduit Power"), + get_tt = function(factor) + return S("+@1% mining and attack speed in water").."\n"..S("limitless breathing under water", math.floor(factor*100)) + end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob API support + end, + on_start = haste_fatigue_hand_update, + on_step = function(dtime, object, factor, duration) + if not object:is_player() then return end + local node = minetest.get_node_or_nil(object:get_pos()) + if node and minetest.registered_nodes[node.name] + and minetest.get_item_group(node.name, "liquid") ~= 0 + and minetest.get_item_group(node.name, "water") ~= 0 then + EF.conduit_power[object].blocked = nil + if object:get_breath() then + hb.hide_hudbar(object, "breath") + if object:get_breath() < 10 then object:set_breath(10) end + end + -- TODO implement improved underwater vision with this effect + else + EF.conduit_power[object].blocked = true + end + end, + after_end = function(object) + haste_fatigue_hand_update(object) + mcl_potions._reset_haste_fatigue_item_meta(object) + end, + particle_color = "#1FB1BA", + uses_factor = true, + lvl1_factor = 0.2, + lvl2_factor = 0.4, + affects_item_speed = {factor_is_positive = true}, +}) + +-- implementation of haste and fatigue effects +function mcl_potions.update_haste_and_fatigue(player) + if mcl_gamemode.get_gamemode(player) == "creative" then return end + local item = player:get_wielded_item() + local meta = item:get_meta() + local item_haste = meta:get_float("mcl_potions:haste") + local item_fatig = 1 - meta:get_float("mcl_potions:fatigue") + local h_fac = mcl_potions.get_total_haste(player) + local f_fac = mcl_potions.get_total_fatigue(player) + if item_haste ~= h_fac or item_fatig ~= f_fac then + if h_fac ~= 0 then meta:set_float("mcl_potions:haste", h_fac) + else meta:set_string("mcl_potions:haste", "") end + if f_fac ~= 1 then meta:set_float("mcl_potions:fatigue", 1 - f_fac) + else meta:set_string("mcl_potions:fatigue", "") end + meta:set_tool_capabilities() + mcl_enchanting.update_groupcaps(item) + if h_fac == 0 and f_fac == 1 then + player:set_wielded_item(item) + return + end + local toolcaps = item:get_tool_capabilities() + meta:set_tool_capabilities(mcl_potions.apply_haste_fatigue(toolcaps, h_fac, f_fac)) + player:set_wielded_item(item) + end + haste_fatigue_hand_update(player, h_fac, f_fac) +end +minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing) + mcl_potions.update_haste_and_fatigue(puncher) +end) +minetest.register_on_punchplayer(function(player, hitter) + if not hitter:is_player() then return end -- TODO implement haste and fatigue support for mobs? + mcl_potions.update_haste_and_fatigue(hitter) +end) +-- update when hitting mob implemented in mcl_mobs/combat.lua + + + +-- ██╗░░░██╗██████╗░██████╗░░█████╗░████████╗███████╗ +-- ██║░░░██║██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝ +-- ██║░░░██║██████╔╝██║░░██║███████║░░░██║░░░█████╗░░ +-- ██║░░░██║██╔═══╝░██║░░██║██╔══██║░░░██║░░░██╔══╝░░ +-- ╚██████╔╝██║░░░░░██████╦╝██║░░██║░░░██║░░░███████╗ +-- ░╚═════╝░╚═╝░░░░░╚═════╝░╚═╝░░╚═╝░░░╚═╝░░░╚══════╝ +-- +-- ██╗░░██╗██╗░░░██╗██████╗░ +-- ██║░░██║██║░░░██║██╔══██╗ +-- ███████║██║░░░██║██║░░██║ +-- ██╔══██║██║░░░██║██║░░██║ +-- ██║░░██║╚██████╔╝██████╦╝ +-- ╚═╝░░╚═╝░╚═════╝░╚═════╝░ + +hb.register_hudbar("absorption", 0xFFFFFF, S("Absorption"), {bar = "[fill:2x16:#B59500", icon = "mcl_potions_icon_absorb.png"}, 0, 0, 0, false) + +local hp_hudbar_modifiers = {} + +-- API - registers a HP hudbar modifier +-- required parameters in def: +-- predicate - function(player) - returns true if player fulfills the requirements (eg. has the effects) for the hudbar look +-- icon - string - name of the icon to which the modifier should change the HP hudbar heart +-- priority - signed int - lower gets checked first, and first fulfilled predicate applies its modifier +function mcl_potions.register_hp_hudbar_modifier(def) + if type(def.predicate) ~= "function" then error("Predicate must be a function") end + if not def.icon then error("No icon provided") end + if not def.priority then error("No priority provided") end + table.insert(hp_hudbar_modifiers, { + predicate = def.predicate, + icon = def.icon, + priority = def.priority, + }) + table.sort(hp_hudbar_modifiers, function(a, b) return a.priority <= b.priority end) +end + +mcl_potions.register_hp_hudbar_modifier({ + predicate = function(player) + if EF.withering[player] and EF.regeneration[player] then return true end + end, + icon = "mcl_potions_icon_regen_wither.png", + priority = -30, +}) + +mcl_potions.register_hp_hudbar_modifier({ + predicate = function(player) + if EF.withering[player] then return true end + end, + icon = "mcl_potions_icon_wither.png", + priority = -20, +}) + +mcl_potions.register_hp_hudbar_modifier({ + predicate = function(player) + if EF.poison[player] and EF.regeneration[player] then return true end + end, + icon = "hbhunger_icon_regen_poison.png", + priority = -10, +}) + +mcl_potions.register_hp_hudbar_modifier({ + predicate = function(player) + if EF.poison[player] then return true end + end, + icon = "hbhunger_icon_health_poison.png", + priority = 0, +}) + +mcl_potions.register_hp_hudbar_modifier({ + predicate = function(player) + if EF.frost[player] and EF.regeneration[player] then return true end + end, + icon = "mcl_potions_icon_regen_frost.png", + priority = 10, +}) + +mcl_potions.register_hp_hudbar_modifier({ + predicate = function(player) + if EF.frost[player] then return true end + end, + icon = "mcl_potions_icon_frost.png", + priority = 20, +}) + +mcl_potions.register_hp_hudbar_modifier({ + predicate = function(player) + if EF.regeneration[player] then return true end + end, + icon = "hudbars_icon_regenerate.png", + priority = 30, +}) + +local function potions_set_hudbar(player) + for _, mod in pairs(hp_hudbar_modifiers) do + if mod.predicate(player) then + hb.change_hudbar(player, "health", nil, nil, mod.icon, nil, "hudbars_bar_health.png") + return + end + end + hb.change_hudbar(player, "health", nil, nil, "hudbars_icon_health.png", nil, "hudbars_bar_health.png") end local icon_ids = {} -local function potions_set_hudbar(player) - if EF.withering[player] and EF.regenerating[player] then - hb.change_hudbar(player, "health", nil, nil, "mcl_potions_icon_regen_wither.png", nil, "hudbars_bar_health.png") - elseif EF.withering[player] then - hb.change_hudbar(player, "health", nil, nil, "mcl_potions_icon_wither.png", nil, "hudbars_bar_health.png") - elseif EF.poisoned[player] and EF.regenerating[player] then - hb.change_hudbar(player, "health", nil, nil, "hbhunger_icon_regen_poison.png", nil, "hudbars_bar_health.png") - elseif EF.poisoned[player] then - hb.change_hudbar(player, "health", nil, nil, "hbhunger_icon_health_poison.png", nil, "hudbars_bar_health.png") - elseif EF.regenerating[player] then - hb.change_hudbar(player, "health", nil, nil, "hudbars_icon_regenerate.png", nil, "hudbars_bar_health.png") - else - hb.change_hudbar(player, "health", nil, nil, "hudbars_icon_health.png", nil, "hudbars_bar_health.png") - end - -end - local function potions_init_icons(player) local name = player:get_player_name() icon_ids[name] = {} for e=1, EFFECT_TYPES do local x = -52 * e - 2 - local id = player:hud_add({ + local id = {} + id.img = player:hud_add({ hud_elem_type = "image", text = "blank.png", position = { x = 1, y = 0 }, @@ -50,8 +1224,31 @@ local function potions_init_icons(player) alignment = { x = 1, y = 1 }, z_index = 100, }) + id.label = player:hud_add({ + hud_elem_type = "text", + text = "", + position = { x = 1, y = 0 }, + offset = { x = x+22, y = 50 }, + scale = { x = 50, y = 15 }, + alignment = { x = 0, y = 1 }, + z_index = 100, + style = 1, + number = 0xFFFFFF, + }) + id.timestamp = player:hud_add({ + hud_elem_type = "text", + text = "", + position = { x = 1, y = 0 }, + offset = { x = x+22, y = 65 }, + scale = { x = 50, y = 15 }, + alignment = { x = 0, y = 1 }, + z_index = 100, + style = 1, + number = 0xFFFFFF, + }) table.insert(icon_ids[name], id) end + hb.init_hudbar(player, "absorption") end local function potions_set_icons(player) @@ -62,30 +1259,49 @@ local function potions_set_icons(player) local active_effects = {} for effect_name, effect in pairs(EF) do if effect[player] then - table.insert(active_effects, effect_name) + active_effects[effect_name] = effect[player] end end - for i=1, EFFECT_TYPES do - local icon = icon_ids[name][i] - local effect_name = active_effects[i] - if effect_name == "swift" and EF.swift[player].is_slow then - effect_name = "slow" - end - if effect_name == nil then - player:hud_change(icon, "text", "blank.png") - else - player:hud_change(icon, "text", "mcl_potions_effect_"..effect_name..".png^[resize:128x128") + local i = 1 + for effect_name, def in pairs(registered_effects) do + local icon = icon_ids[name][i].img + local label = icon_ids[name][i].label + local timestamp = icon_ids[name][i].timestamp + local vals = active_effects[effect_name] + if vals then + player:hud_change(icon, "text", def.icon .. "^[resize:128x128") + if def.uses_factor then + local level = def.factor_to_level(vals.factor) + if level > 3000 or level == math.huge then level = "∞" + elseif level < 0 then level = "???" + elseif level == 0 then level = "0" + else level = mcl_util.to_roman(level) end + player:hud_change(label, "text", level) + else + player:hud_change(label, "text", "") + end + if vals.dur == math.huge then + player:hud_change(timestamp, "text", "∞") + else + local dur = math.round(vals.dur-vals.timer) + player:hud_change(timestamp, "text", math.floor(dur/60)..string.format(":%02d",math.floor(dur % 60))) + end + EF[effect_name][player].hud_index = i + i = i + 1 end end - + while i < EFFECT_TYPES do + player:hud_change(icon_ids[name][i].img, "text", "blank.png") + player:hud_change(icon_ids[name][i].label, "text", "") + player:hud_change(icon_ids[name][i].timestamp, "text", "") + i = i + 1 + end end local function potions_set_hud(player) - potions_set_hudbar(player) potions_set_icons(player) - end @@ -103,315 +1319,54 @@ end -- ╚█████╔╝██║░░██║███████╗╚█████╔╝██║░╚██╗███████╗██║░░██║ -- ░╚════╝░╚═╝░░╚═╝╚══════╝░╚════╝░╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝ -local is_player, entity, meta - minetest.register_globalstep(function(dtime) + for name, effect in pairs(registered_effects) do + for object, vals in pairs(EF[name]) do + if vals.dur ~= math.huge then EF[name][object].timer = vals.timer + dtime end - -- Check for invisible players - for player, vals in pairs(EF.invisible) do - - EF.invisible[player].timer = EF.invisible[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#7F8392") end - - if EF.invisible[player].timer >= EF.invisible[player].dur then - mcl_potions.make_invisible(player, false) - EF.invisible[player] = nil - if player:is_player() then - meta = player:get_meta() - meta:set_string("_is_invisible", minetest.serialize(EF.invisible[player])) + if object:get_pos() and not vals.no_particles then mcl_potions._add_spawner(object, effect.particle_color) end + if effect.on_step then effect.on_step(dtime, object, vals.factor, vals.dur) end + if effect.on_hit_timer then + EF[name][object].hit_timer = (vals.hit_timer or 0) + dtime + if EF[name][object].hit_timer >= vals.step then + effect.on_hit_timer(object, vals.factor, vals.dur) + if EF[name][object] then EF[name][object].hit_timer = 0 end + end end - potions_set_hud(player) + if not object or not EF[name][object] or EF[name][object].timer >= vals.dur or not object:get_pos() then + if effect.on_end then effect.on_end(object) end + EF[name][object] = nil + if effect.after_end then effect.after_end(object) end + if object:is_player() then + meta = object:get_meta() + meta:set_string("mcl_potions:_EF_"..name, "") + potions_set_hud(object) + else + local ent = object:get_luaentity() + if ent then + ent._mcl_potions["_EF_"..name] = nil + end + end + elseif object:is_player() then + if vals.dur == math.huge then + object:hud_change(icon_ids[object:get_player_name()][vals.hud_index].timestamp, + "text", "∞") + else + local dur = math.round(vals.dur-vals.timer) + object:hud_change(icon_ids[object:get_player_name()][vals.hud_index].timestamp, + "text", math.floor(dur/60)..string.format(":%02d",math.floor(dur % 60))) + end + else + local ent = object:get_luaentity() + if ent then + ent._mcl_potions["_EF_"..name] = EF[name][object] + end + end end - end - - -- Check for withering players - for player, vals in pairs(EF.withering) do - - is_player = player:is_player() - entity = player:get_luaentity() - - EF.withering[player].timer = EF.withering[player].timer + dtime - EF.withering[player].hit_timer = (EF.withering[player].hit_timer or 0) + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#000000") end - - if EF.withering[player].hit_timer >= EF.withering[player].step then - if is_player or entity then mcl_util.deal_damage(player, 1, {type = "magic"}) end - if EF.withering[player] then EF.withering[player].hit_timer = 0 end - end - - if EF.withering[player] and EF.withering[player].timer >= EF.withering[player].dur then - EF.withering[player] = nil - if is_player then - meta = player:get_meta() - meta:set_string("_is_withering", minetest.serialize(EF.withering[player])) - potions_set_hud(player) - end - end - - end - - -- Check for poisoned players - for player, vals in pairs(EF.poisoned) do - - is_player = player:is_player() - entity = player:get_luaentity() - - EF.poisoned[player].timer = EF.poisoned[player].timer + dtime - EF.poisoned[player].hit_timer = (EF.poisoned[player].hit_timer or 0) + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#4E9331") end - - if EF.poisoned[player].hit_timer >= EF.poisoned[player].step then - if mcl_util.get_hp(player) - 1 > 0 then - mcl_util.deal_damage(player, 1, {type = "magic"}) - end - EF.poisoned[player].hit_timer = 0 - end - - if EF.poisoned[player] and EF.poisoned[player].timer >= EF.poisoned[player].dur then - EF.poisoned[player] = nil - if is_player then - meta = player:get_meta() - meta:set_string("_is_poisoned", minetest.serialize(EF.poisoned[player])) - potions_set_hud(player) - end - end - - end - - -- Check for regenerating players - for player, vals in pairs(EF.regenerating) do - - is_player = player:is_player() - entity = player:get_luaentity() - - EF.regenerating[player].timer = EF.regenerating[player].timer + dtime - EF.regenerating[player].heal_timer = (EF.regenerating[player].heal_timer or 0) + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#CD5CAB") end - - if EF.regenerating[player].heal_timer >= EF.regenerating[player].step then - - if is_player then - player:set_hp(math.min(player:get_properties().hp_max or 20, player:get_hp() + 1), { type = "set_hp", other = "regeneration" }) - EF.regenerating[player].heal_timer = 0 - elseif entity and entity.is_mob then - entity.health = math.min(entity.hp_max, entity.health + 1) - EF.regenerating[player].heal_timer = 0 - else -- stop regenerating if not a player or mob - EF.regenerating[player] = nil - end - - end - - if EF.regenerating[player] and EF.regenerating[player].timer >= EF.regenerating[player].dur then - EF.regenerating[player] = nil - if is_player then - meta = player:get_meta() - meta:set_string("_is_regenerating", minetest.serialize(EF.regenerating[player])) - potions_set_hud(player) - end - end - - end - - -- Check for water breathing players - for player, vals in pairs(EF.water_breathing) do - - if player:is_player() then - - EF.water_breathing[player].timer = EF.water_breathing[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#2E5299") end - - if player:get_breath() then - hb.hide_hudbar(player, "breath") - if player:get_breath() < 10 then player:set_breath(10) end - end - - if EF.water_breathing[player].timer >= EF.water_breathing[player].dur then - meta = player:get_meta() - meta:set_string("_is_water_breathing", minetest.serialize(EF.water_breathing[player])) - EF.water_breathing[player] = nil - end - potions_set_hud(player) - - else - EF.water_breathing[player] = nil - end - - end - - -- Check for leaping players - for player, vals in pairs(EF.leaping) do - - if player:is_player() then - - EF.leaping[player].timer = EF.leaping[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#22FF4C") end - - if EF.leaping[player].timer >= EF.leaping[player].dur then - playerphysics.remove_physics_factor(player, "jump", "mcl_potions:leaping") - EF.leaping[player] = nil - meta = player:get_meta() - meta:set_string("_is_leaping", minetest.serialize(EF.leaping[player])) - end - potions_set_hud(player) - - else - EF.leaping[player] = nil - end - - end - - -- Check for swift players - for player, vals in pairs(EF.swift) do - - if player:is_player() then - - EF.swift[player].timer = EF.swift[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#7CAFC6") end - - if EF.swift[player].timer >= EF.swift[player].dur then - playerphysics.remove_physics_factor(player, "speed", "mcl_potions:swiftness") - EF.swift[player] = nil - meta = player:get_meta() - meta:set_string("_is_swift", minetest.serialize(EF.swift[player])) - end - potions_set_hud(player) - - else - EF.swift[player] = nil - end - - end - - -- Check for Night Vision equipped players - for player, vals in pairs(EF.night_vision) do - - if player:is_player() then - - EF.night_vision[player].timer = EF.night_vision[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#1F1FA1") end - - if EF.night_vision[player].timer >= EF.night_vision[player].dur then - EF.night_vision[player] = nil - meta = player:get_meta() - meta:set_string("_is_cat", minetest.serialize(EF.night_vision[player])) - meta:set_int("night_vision", 0) - end - mcl_weather.skycolor.update_sky_color({player}) - potions_set_hud(player) - - else - EF.night_vision[player] = nil - end - - end - - -- Check for Fire Proof players - for player, vals in pairs(EF.fire_proof) do - - if player:is_player() then - - player = player or player:get_luaentity() - - EF.fire_proof[player].timer = EF.fire_proof[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#E49A3A") end - - if EF.fire_proof[player].timer >= EF.fire_proof[player].dur then - EF.fire_proof[player] = nil - meta = player:get_meta() - meta:set_string("_is_fire_proof", minetest.serialize(EF.fire_proof[player])) - end - potions_set_hud(player) - - else - EF.fire_proof[player] = nil - end - - end - - -- Check for Weak players - for player, vals in pairs(EF.weak) do - - if player:is_player() then - - EF.weak[player].timer = EF.weak[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#484D48") end - - if EF.weak[player].timer >= EF.weak[player].dur then - EF.weak[player] = nil - meta = player:get_meta() - meta:set_string("_is_weak", minetest.serialize(EF.weak[player])) - end - - else - EF.weak[player] = nil - end - - end - - -- Check for Strong players - for player, vals in pairs(EF.strong) do - - if player:is_player() then - - EF.strong[player].timer = EF.strong[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#932423") end - - if EF.strong[player].timer >= EF.strong[player].dur then - EF.strong[player] = nil - meta = player:get_meta() - meta:set_string("_is_strong", minetest.serialize(EF.strong[player])) - end - - else - EF.strong[player] = nil - end - - end - - -- Check for Bad Omen - for player, vals in pairs(EF.bad_omen) do - - is_player = player:is_player() - - EF.bad_omen[player].timer = EF.bad_omen[player].timer + dtime - - if player:get_pos() then mcl_potions._add_spawner(player, "#0b6138") end - - if EF.bad_omen[player] and EF.bad_omen[player].timer >= EF.bad_omen[player].dur then - EF.bad_omen[player] = nil - if is_player then - meta = player:get_meta() - meta:set_string("_has_bad_omen", minetest.serialize(EF.bad_omen[player])) - potions_set_hud(player) - end - end - - end - end) --- Prevent damage to player with Fire Resistance enabled -mcl_damage.register_modifier(function(obj, damage, reason) - if EF.fire_proof[obj] and not reason.flags.bypasses_magic and reason.flags.is_fire then - return 0 - end -end, -50) - - -- ███████╗███████╗███████╗███████╗░█████╗░████████╗ -- ██╔════╝██╔════╝██╔════╝██╔════╝██╔══██╗╚══██╔══╝ @@ -427,169 +1382,244 @@ end, -50) -- ███████╗╚█████╔╝██║░░██║██████╔╝██╔╝░░░██████╔╝██║░░██║░░╚██╔╝░░███████╗ -- ╚══════╝░╚════╝░╚═╝░░╚═╝╚═════╝░╚═╝░░░░╚═════╝░╚═╝░░╚═╝░░░╚═╝░░░╚══════╝ -function mcl_potions._clear_cached_player_data(player) - EF.invisible[player] = nil - EF.poisoned[player] = nil - EF.regenerating[player] = nil - EF.strong[player] = nil - EF.weak[player] = nil - EF.water_breathing[player] = nil - EF.leaping[player] = nil - EF.swift[player] = nil - EF.night_vision[player] = nil - EF.fire_proof[player] = nil - EF.bad_omen[player] = nil - EF.withering[player] = nil +function mcl_potions._reset_haste_fatigue_item_meta(player) + local inv = player:get_inventory() + if not inv then return end + local lists = inv:get_lists() + for _, list in pairs(lists) do + for _, item in pairs(list) do + local meta = item:get_meta() + meta:set_string("mcl_potions:haste", "") + meta:set_string("mcl_potions:fatigue", "") + meta:set_tool_capabilities() + mcl_enchanting.update_groupcaps(item) + end + end + inv:set_lists(lists) +end +mcl_gamemode.register_on_gamemode_change(mcl_potions._reset_haste_fatigue_item_meta) - meta = player:get_meta() +function mcl_potions._clear_cached_effect_data(object) + for name, effect in pairs(EF) do + effect[object] = nil + end + if not object:is_player() then return end + local meta = object:get_meta() meta:set_int("night_vision", 0) end -function mcl_potions._reset_player_effects(player, set_hud) - - if not player:is_player() then - return +function mcl_potions._reset_effects(object, set_hud) + local set_hud = set_hud + if not object:is_player() then + set_hud = false end - mcl_potions.make_invisible(player, false) + local removed_effects = {} + for name, effect in pairs(registered_effects) do + if EF[name][object] and effect.on_end then effect.on_end(object) end + if effect.after_end then table.insert(removed_effects, effect.after_end) end + end - playerphysics.remove_physics_factor(player, "jump", "mcl_potions:leaping") + mcl_potions._clear_cached_effect_data(object) - playerphysics.remove_physics_factor(player, "speed", "mcl_potions:swiftness") - - mcl_weather.skycolor.update_sky_color({player}) - - mcl_potions._clear_cached_player_data(player) + for i=1, #removed_effects do + removed_effects[i](object) + end if set_hud ~= false then - potions_set_hud(player) + potions_set_hud(object) end end function mcl_potions._save_player_effects(player) - if not player:is_player() then return end - meta = player:get_meta() - - meta:set_string("_is_invisible", minetest.serialize(EF.invisible[player])) - meta:set_string("_is_poisoned", minetest.serialize(EF.poisoned[player])) - meta:set_string("_is_regenerating", minetest.serialize(EF.regenerating[player])) - meta:set_string("_is_strong", minetest.serialize(EF.strong[player])) - meta:set_string("_is_weak", minetest.serialize(EF.weak[player])) - meta:set_string("_is_water_breathing", minetest.serialize(EF.water_breathing[player])) - meta:set_string("_is_leaping", minetest.serialize(EF.leaping[player])) - meta:set_string("_is_swift", minetest.serialize(EF.swift[player])) - meta:set_string("_is_cat", minetest.serialize(EF.night_vision[player])) - meta:set_string("_is_fire_proof", minetest.serialize(EF.fire_proof[player])) - meta:set_string("_has_bad_omen", minetest.serialize(EF.bad_omen[player])) - meta:set_string("_is_withering", minetest.serialize(EF.withering[player])) + local meta = player:get_meta() + for name, effect in pairs(registered_effects) do + if effect.on_save_effect and EF[name][player] then effect.on_save_effect(player) end + meta:set_string("mcl_potions:_EF_"..name, minetest.serialize(EF[name][player])) + end end function mcl_potions._load_player_effects(player) - if not player:is_player() then return end - meta = player:get_meta() + local meta = player:get_meta() - if minetest.deserialize(meta:get_string("_is_invisible")) then - EF.invisible[player] = minetest.deserialize(meta:get_string("_is_invisible")) - mcl_potions.make_invisible(player, true) + -- handle legacy meta strings + local legacy_invisible = minetest.deserialize(meta:get_string("_is_invisible")) + local legacy_poisoned = minetest.deserialize(meta:get_string("_is_poisoned")) + local legacy_regenerating = minetest.deserialize(meta:get_string("_is_regenerating")) + local legacy_strong = minetest.deserialize(meta:get_string("_is_strong")) + local legacy_weak = minetest.deserialize(meta:get_string("_is_weak")) + local legacy_water_breathing = minetest.deserialize(meta:get_string("_is_water_breathing")) + local legacy_leaping = minetest.deserialize(meta:get_string("_is_leaping")) + local legacy_swift = minetest.deserialize(meta:get_string("_is_swift")) + local legacy_night_vision = minetest.deserialize(meta:get_string("_is_cat")) + local legacy_fireproof = minetest.deserialize(meta:get_string("_is_fire_proof")) + local legacy_bad_omen = minetest.deserialize(meta:get_string("_has_bad_omen")) + local legacy_withering = minetest.deserialize(meta:get_string("_is_withering")) + if legacy_invisible then + EF.invisibility[player] = legacy_invisible + meta:set_string("_is_invisible", "") + end + if legacy_poisoned then + EF.poison[player] = legacy_poisoned + meta:set_string("_is_poisoned", "") + end + if legacy_regenerating then + EF.regeneration[player] = legacy_regenerating + meta:set_string("_is_regenerating", "") + end + if legacy_strong then + EF.strength[player] = legacy_strong + meta:set_string("_is_strong", "") + end + if legacy_weak then + EF.weakness[player] = legacy_weak + meta:set_string("_is_weak", "") + end + if legacy_water_breathing then + EF.water_breathing[player] = legacy_water_breating + meta:set_string("_is_water_breating", "") + end + if legacy_leaping then + EF.leaping[player] = legacy_leaping + meta:set_string("_is_leaping", "") + end + if legacy_swift then + EF.swiftness[player] = legacy_swift + meta:set_string("_is_swift", "") + end + if legacy_night_vision then + EF.night_vision[player] = legacy_night_vision + meta:set_string("_is_cat", "") + end + if legacy_fireproof then + EF.fire_resistance[player] = legacy_fireproof + meta:set_string("_is_fire_proof", "") + end + if legacy_bad_omen then + EF.bad_omen[player] = legacy_bad_omen + meta:set_string("_has_bad_omen", "") + end + if legacy_withering then + EF.withering[player] = legacy_withering + meta:set_string("_is_withering", "") end - if minetest.deserialize(meta:get_string("_is_poisoned")) then - EF.poisoned[player] = minetest.deserialize(meta:get_string("_is_poisoned")) + -- new API effects + on_load for loaded legacy effects + for name, effect in pairs(registered_effects) do + local loaded = minetest.deserialize(meta:get_string("mcl_potions:_EF_"..name)) + if loaded then + EF[name][player] = loaded + if effect.on_load then + effect.on_load(player, EF[name][player].factor) + end + end end - - if minetest.deserialize(meta:get_string("_is_regenerating")) then - EF.regenerating[player] = minetest.deserialize(meta:get_string("_is_regenerating")) - end - - if minetest.deserialize(meta:get_string("_is_strong")) then - EF.strong[player] = minetest.deserialize(meta:get_string("_is_strong")) - end - - if minetest.deserialize(meta:get_string("_is_weak")) then - EF.weak[player] = minetest.deserialize(meta:get_string("_is_weak")) - end - - if minetest.deserialize(meta:get_string("_is_water_breathing")) then - EF.water_breathing[player] = minetest.deserialize(meta:get_string("_is_water_breathing")) - end - - if minetest.deserialize(meta:get_string("_is_leaping")) then - EF.leaping[player] = minetest.deserialize(meta:get_string("_is_leaping")) - end - - if minetest.deserialize(meta:get_string("_is_swift")) then - EF.swift[player] = minetest.deserialize(meta:get_string("_is_swift")) - end - - if minetest.deserialize(meta:get_string("_is_cat")) then - EF.night_vision[player] = minetest.deserialize(meta:get_string("_is_cat")) - end - - if minetest.deserialize(meta:get_string("_is_fire_proof")) then - EF.fire_proof[player] = minetest.deserialize(meta:get_string("_is_fire_proof")) - end - - if minetest.deserialize(meta:get_string("_has_bad_omen")) then - EF.bad_omen[player] = minetest.deserialize(meta:get_string("_has_bad_omen")) - end - - if minetest.deserialize(meta:get_string("_is_withering")) then - EF.withering[player] = minetest.deserialize(meta:get_string("_is_withering")) - end - end --- Returns true if player has given effect -function mcl_potions.player_has_effect(player, effect_name) +function mcl_potions._load_entity_effects(entity) + if not entity or not entity._mcl_potions or entity._mcl_potions == {} then + return + end + local object = entity.object + if not object or not object:get_pos() then return end + for name, effect in pairs(registered_effects) do + local loaded = entity._mcl_potions["_EF_"..name] + if loaded then + EF[name][object] = loaded + if effect.on_load then + effect.on_load(object, EF[name][object].factor) + end + end + end +end + +-- Returns true if object has given effect +function mcl_potions.has_effect(object, effect_name) if not EF[effect_name] then return false end - return EF[effect_name][player] ~= nil + return EF[effect_name][object] ~= nil end -function mcl_potions.player_get_effect(player, effect_name) - if not EF[effect_name] or not EF[effect_name][player] then +function mcl_potions.get_effect(object, effect_name) + if not EF[effect_name] or not EF[effect_name][object] then return false end - return EF[effect_name][player] + return EF[effect_name][object] end -function mcl_potions.player_clear_effect(player,effect) - EF[effect][player] = nil - potions_set_icons(player) +function mcl_potions.get_effect_level(object, effect_name) + if not EF[effect_name] then return end + local effect = EF[effect_name][object] + if not effect then return 0 end + if not registered_effects[effect_name].uses_factor then return 1 end + return registered_effects[effect_name].factor_to_level(effect.factor) +end + +function mcl_potions.get_total_haste(object) + local accum_factor = 1 + for name, def in pairs(item_speed_effects) do + if EF[name][object] and not EF[name][object].blocked then + local factor = EF[name][object].factor + if def.factor_is_positive then factor = factor + 1 end + if factor > 1 then accum_factor = accum_factor * factor end + end + end + return accum_factor - 1 +end + +function mcl_potions.get_total_fatigue(object) + local accum_factor = 1 + for name, def in pairs(item_speed_effects) do + if EF[name][object] and not EF[name][object].blocked then + local factor = EF[name][object].factor + if def.factor_is_positive then factor = factor + 1 end + if factor <= 0 then return 0 end + if factor < 1 then accum_factor = accum_factor * factor end + end + end + return accum_factor +end + +function mcl_potions.clear_effect(object, effect) + if not EF[effect] then + minetest.log("warning", "[mcl_potions] Tried to remove an effect that is not registered: " .. dump(effect)) + return false + end + local def = registered_effects[effect] + if EF[effect][object] then + if def.on_end then def.on_end(object) end + EF[effect][object] = nil + if def.after_end then def.after_end(object) end + end + if not object:is_player() then return end + potions_set_hud(object) end minetest.register_on_leaveplayer( function(player) mcl_potions._save_player_effects(player) - mcl_potions._clear_cached_player_data(player) -- clearout the buffer to prevent looking for a player not there + mcl_potions._clear_cached_effect_data(player) -- clear the buffer to prevent looking for a player not there icon_ids[player:get_player_name()] = nil end) minetest.register_on_dieplayer( function(player) - mcl_potions._reset_player_effects(player) + mcl_potions._reset_effects(player) potions_set_hud(player) end) minetest.register_on_joinplayer( function(player) - mcl_potions._reset_player_effects(player, false) -- make sure there are no wierd holdover effects + mcl_potions._reset_effects(player, false) -- make sure there are no weird holdover effects mcl_potions._load_player_effects(player) + mcl_potions._reset_haste_fatigue_item_meta(player) potions_init_icons(player) - -- .after required because player:hud_change doesn't work when called - -- in same tick as player:hud_add - -- (see ) - -- FIXME: Remove minetest.after - minetest.after(3, function(player) - if player and player:is_player() then - potions_set_hud(player) - end - end, player) + potions_set_hud(player) end) minetest.register_on_shutdown(function() @@ -597,10 +1627,8 @@ minetest.register_on_shutdown(function() for _,player in pairs(minetest.get_connected_players()) do mcl_potions._save_player_effects(player) end - end) - -- ░██████╗██╗░░░██╗██████╗░██████╗░░█████╗░██████╗░████████╗██╗███╗░░██╗░██████╗░ -- ██╔════╝██║░░░██║██╔══██╗██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██║████╗░██║██╔════╝░ -- ╚█████╗░██║░░░██║██████╔╝██████╔╝██║░░██║██████╔╝░░░██║░░░██║██╔██╗██║██║░░██╗░ @@ -649,16 +1677,16 @@ function mcl_potions.make_invisible(obj_ref, hide) else if hide then local luaentity = obj_ref:get_luaentity() - EF.invisible[obj_ref].old_size = luaentity.visual_size + EF.invisibility[obj_ref].old_size = luaentity.visual_size obj_ref:set_properties({ visual_size = { x = 0, y = 0 } }) else - obj_ref:set_properties({ visual_size = EF.invisible[obj_ref].old_size }) + obj_ref:set_properties({ visual_size = EF.invisibility[obj_ref].old_size }) end end end -function mcl_potions._use_potion(item, obj, color) +function mcl_potions._use_potion(obj, color) local d = 0.1 local pos = obj:get_pos() minetest.sound_play("mcl_potions_drinking", {pos = pos, max_hear_distance = 6, gain = 1}) @@ -727,14 +1755,88 @@ end -- ██║░░░░░╚██████╔╝██║░╚███║╚█████╔╝░░░██║░░░██║╚█████╔╝██║░╚███║██████╔╝ -- ╚═╝░░░░░░╚═════╝░╚═╝░░╚══╝░╚════╝░░░░╚═╝░░░╚═╝░╚════╝░╚═╝░░╚══╝╚═════╝░ +local registered_res_predicates = {} +-- API +-- This is supposed to add custom resistance functions independent of effects +-- E.g. some entity could be resistant to all (or some) effects under specific conditions +-- predicate - function(object, effect_name) - return true if resists effect +function mcl_potions.register_generic_resistance_predicate(predicate) + if type(predicate) == "function" then + table.insert(registered_res_predicates, predicate) + else + error("Attempted to register non-function as a predicate") + end +end -function mcl_potions.healing_func(player, hp) +local function target_valid(object, name) + if not object or object:get_hp() <= 0 then return false end - if not player or player:get_hp() <= 0 then return false end + local entity = object:get_luaentity() + if entity and entity.is_boss then return false end - local obj = player:get_luaentity() + for i=1, #registered_res_predicates do + if registered_res_predicates[i](object, name) then return false end + end - if obj and obj.harmed_by_heal then hp = -hp end + if not (registered_effects[name].res_condition + and registered_effects[name].res_condition(object)) then return true end +end + +function mcl_potions.give_effect(name, object, factor, duration, no_particles) + local edef = registered_effects[name] + if not edef or not target_valid(object, name) then return false end + if not EF[name][object] then + local vals = {dur = duration, timer = 0, no_particles = no_particles} + if edef.uses_factor then vals.factor = factor end + if edef.on_hit_timer then + if edef.timer_uses_factor then vals.step = factor + else vals.step = edef.hit_timer_step end + end + if duration == "INF" then + vals.dur = math.huge + end + EF[name][object] = vals + if edef.on_start then edef.on_start(object, factor) end + else + local present = EF[name][object] + present.no_particles = no_particles + if not edef.uses_factor or (edef.uses_factor and + (not edef.inv_factor and factor >= present.factor + or edef.inv_factor and factor <= present.factor)) then + present.dur = math.max(duration, present.dur - present.timer) + present.timer = 0 + if edef.uses_factor then + present.factor = factor + if edef.timer_uses_factor then present.step = factor end + if edef.on_start then edef.on_start(object, factor) end + end + if duration == "INF" then + present.dur = math.huge + end + else + return false + end + end + + if object:is_player() then potions_set_hud(object) end + + return true +end + +function mcl_potions.give_effect_by_level(name, object, level, duration, no_particles) + if level == 0 then return false end + if not registered_effects[name].uses_factor then + return mcl_potions.give_effect(name, object, 0, duration, no_particles) + end + local factor = registered_effects[name].level_to_factor(level) + return mcl_potions.give_effect(name, object, factor, duration, no_particles) +end + +function mcl_potions.healing_func(object, hp) + if not object or object:get_hp() <= 0 then return false end + local ent = object:get_luaentity() + + if ent and ent.harmed_by_heal then hp = -hp end if hp > 0 then -- at least 1 HP @@ -742,10 +1844,10 @@ function mcl_potions.healing_func(player, hp) hp = 1 end - if obj and obj.is_mob then - obj.health = math.max(obj.health + hp, obj.hp_max) - elseif player:is_player() then - player:set_hp(math.min(player:get_hp() + hp, player:get_properties().hp_max), { type = "set_hp", other = "healing" }) + if ent and ent.is_mob then + ent.health = math.min(ent.health + hp, ent.hp_max) + elseif object:is_player() then + object:set_hp(math.min(object:get_hp() + hp, object:get_properties().hp_max), { type = "set_hp", other = "healing" }) end elseif hp < 0 then @@ -753,330 +1855,57 @@ function mcl_potions.healing_func(player, hp) hp = -1 end - mcl_util.deal_damage(player, -hp, {type = "magic"}) + mcl_util.deal_damage(object, -hp, {type = "magic"}) end - end -function mcl_potions.swiftness_func(player, factor, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and entity.is_boss then return false end - - if not player:get_meta() then - return false - end - - if not EF.swift[player] then - - EF.swift[player] = {dur = duration, timer = 0, is_slow = factor < 1} - playerphysics.add_physics_factor(player, "speed", "mcl_potions:swiftness", factor) - - else - - local victim = EF.swift[player] - - playerphysics.add_physics_factor(player, "speed", "mcl_potions:swiftness", factor) - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - victim.is_slow = factor < 1 - - end - - if player:is_player() then - potions_set_icons(player) - end - +function mcl_potions.strength_func(object, factor, duration) + return mcl_potions.give_effect("strength", object, factor, duration) +end +function mcl_potions.leaping_func(object, factor, duration) + return mcl_potions.give_effect("leaping", object, factor, duration) +end +function mcl_potions.weakness_func(object, factor, duration) + return mcl_potions.give_effect("weakness", object, factor, duration) +end +function mcl_potions.swiftness_func(object, factor, duration) + return mcl_potions.give_effect("swiftness", object, factor, duration) +end +function mcl_potions.slowness_func(object, factor, duration) + return mcl_potions.give_effect("slowness", object, factor, duration) end -function mcl_potions.leaping_func(player, factor, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and entity.is_boss then return false end - - if not player:get_meta() then - return false - end - - if not EF.leaping[player] then - - EF.leaping[player] = {dur = duration, timer = 0} - playerphysics.add_physics_factor(player, "jump", "mcl_potions:leaping", factor) - - else - - local victim = EF.leaping[player] - - playerphysics.add_physics_factor(player, "jump", "mcl_potions:leaping", factor) - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_icons(player) - end - +function mcl_potions.withering_func(object, factor, duration) + return mcl_potions.give_effect("withering", object, factor, duration) end -function mcl_potions.weakness_func(player, factor, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and entity.is_boss then return false end - - if not EF.weak[player] then - - EF.weak[player] = {dur = duration, timer = 0, factor = factor} - - else - - local victim = EF.weak[player] - - victim.factor = factor - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_icons(player) - end - +function mcl_potions.poison_func(object, factor, duration) + return mcl_potions.give_effect("poison", object, factor, duration) end -function mcl_potions.strength_func(player, factor, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and entity.is_boss then return false end - - if not EF.strong[player] then - - EF.strong[player] = {dur = duration, timer = 0, factor = factor} - - else - - local victim = EF.strong[player] - - victim.factor = factor - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_icons(player) - end - +function mcl_potions.regeneration_func(object, factor, duration) + return mcl_potions.give_effect("regeneration", object, factor, duration) end -function mcl_potions.withering_func(player, factor, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and (entity.is_boss or string.find(entity.name, "wither")) then return false end - - if not EF.withering[player] then - - EF.withering[player] = {step = factor, dur = duration, timer = 0} - - else - - local victim = EF.withering[player] - - victim.step = math.min(victim.step, factor) - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_hud(player) - end +function mcl_potions.invisiblility_func(object, null, duration) + return mcl_potions.give_effect("invisibility", object, null, duration) +end +function mcl_potions.water_breathing_func(object, null, duration) + return mcl_potions.give_effect("water_breathing", object, null, duration) end -function mcl_potions.poison_func(player, factor, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and (entity.is_boss or entity.harmed_by_heal or string.find(entity.name, "spider")) then return false end - - if not EF.poisoned[player] then - - EF.poisoned[player] = {step = factor, dur = duration, timer = 0} - - else - - local victim = EF.poisoned[player] - - victim.step = math.min(victim.step, factor) - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_hud(player) - end - +function mcl_potions.fire_resistance_func(object, null, duration) + return mcl_potions.give_effect("fire_resistance", object, null, duration) end -function mcl_potions.regeneration_func(player, factor, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and (entity.is_boss or entity.harmed_by_heal) then return false end - - if not EF.regenerating[player] then - - EF.regenerating[player] = {step = factor, dur = duration, timer = 0} - - else - - local victim = EF.regenerating[player] - - victim.step = math.min(victim.step, factor) - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_hud(player) - end - -end - - -function mcl_potions.invisiblility_func(player, null, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and entity.is_boss then return false end - - if not EF.invisible[player] then - - EF.invisible[player] = {dur = duration, timer = 0} - mcl_potions.make_invisible(player, true) - - else - - local victim = EF.invisible[player] - - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_icons(player) - end - -end - -function mcl_potions.water_breathing_func(player, null, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and entity.is_boss then return false end - - if not EF.water_breathing[player] then - - EF.water_breathing[player] = {dur = duration, timer = 0} - - else - - local victim = EF.water_breathing[player] - - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_icons(player) - end - -end - - -function mcl_potions.fire_resistance_func(player, null, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and entity.is_boss then return false end - - if not EF.fire_proof[player] then - - EF.fire_proof[player] = {dur = duration, timer = 0} - - else - - local victim = EF.fire_proof[player] - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - if player:is_player() then - potions_set_icons(player) - end - -end - - -function mcl_potions.night_vision_func(player, null, duration) - - if not player or player:get_hp() <= 0 then return false end - - local entity = player:get_luaentity() - if entity and entity.is_boss then return false end - - meta = player:get_meta() - if not EF.night_vision[player] then - - EF.night_vision[player] = {dur = duration, timer = 0} - - else - - local victim = EF.night_vision[player] - - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - - end - - is_player = player:is_player() - if is_player then - meta:set_int("night_vision", 1) - else - return -- Do not attempt to set night_vision on mobs - end - mcl_weather.skycolor.update_sky_color({player}) - - if player:is_player() then - potions_set_icons(player) - end - +function mcl_potions.night_vision_func(object, null, duration) + return mcl_potions.give_effect("night_vision", object, null, duration) end function mcl_potions._extinguish_nearby_fire(pos, radius) @@ -1130,17 +1959,6 @@ function mcl_potions._extinguish_nearby_fire(pos, radius) return exting end -function mcl_potions.bad_omen_func(player, factor, duration) - if not EF.bad_omen[player] then - EF.bad_omen[player] = {dur = duration, timer = 0, factor = factor} - else - local victim = EF.bad_omen[player] - victim.dur = math.max(duration, victim.dur - victim.timer) - victim.timer = 0 - victim.factor = factor - end - - if player:is_player() then - potions_set_icons(player) - end +function mcl_potions.bad_omen_func(object, factor, duration) + mcl_potions.give_effect("bad_omen", object, factor, duration) end diff --git a/mods/ITEMS/mcl_potions/init.lua b/mods/ITEMS/mcl_potions/init.lua index 8e4c53cad..446f6ef16 100644 --- a/mods/ITEMS/mcl_potions/init.lua +++ b/mods/ITEMS/mcl_potions/init.lua @@ -8,14 +8,18 @@ mcl_potions = {} -- duration effects of glowstone are a time factor of 1/2 -- splash potion duration effects are reduced by a factor of 3/4 -mcl_potions.II_FACTOR = 2 +mcl_potions.POTENT_FACTOR = 2 mcl_potions.PLUS_FACTOR = 8/3 +mcl_potions.INV_FACTOR = 0.50 mcl_potions.DURATION = 180 -mcl_potions.DURATION_PLUS = mcl_potions.DURATION * mcl_potions.PLUS_FACTOR -mcl_potions.DURATION_2 = mcl_potions.DURATION / mcl_potions.II_FACTOR +mcl_potions.DURATION_INV = mcl_potions.DURATION * mcl_potions.INV_FACTOR +mcl_potions.DURATION_POISON = 45 + +mcl_potions.II_FACTOR = mcl_potions.POTENT_FACTOR -- TODO remove at some point +mcl_potions.DURATION_PLUS = mcl_potions.DURATION * mcl_potions.PLUS_FACTOR -- TODO remove at some point +mcl_potions.DURATION_2 = mcl_potions.DURATION / mcl_potions.II_FACTOR -- TODO remove at some point -mcl_potions.INV_FACTOR = 0.50 mcl_potions.SPLASH_FACTOR = 0.75 mcl_potions.LINGERING_FACTOR = 0.25 @@ -25,6 +29,7 @@ dofile(modpath .. "/splash.lua") dofile(modpath .. "/lingering.lua") dofile(modpath .. "/tipped_arrow.lua") dofile(modpath .. "/potions.lua") +local potions = mcl_potions.registered_potions minetest.register_craftitem("mcl_potions:fermented_spider_eye", { description = S("Fermented Spider Eye"), @@ -332,9 +337,28 @@ minetest.register_craft({ }) + +local output_table = { } + +-- API +-- registers a potion that can be combined with multiple ingredients for different outcomes +-- out_table contains the recipes for those outcomes +function mcl_potions.register_ingredient_potion(input, out_table) + if output_table[input] then + error("Attempt to register the same ingredient twice!") + end + if type(input) ~= "string" then + error("Invalid argument! input must be a string") + end + if type(out_table) ~= "table" then + error("Invalid argument! out_table must be a table") + end + output_table[input] = out_table +end + local water_table = { ["mcl_nether:nether_wart_item"] = "mcl_potions:awkward", - -- ["mcl_potions:fermented_spider_eye"] = "mcl_potions:weakness", + ["mcl_potions:fermented_spider_eye"] = "mcl_potions:weakness", ["mcl_potions:speckled_melon"] = "mcl_potions:mundane", ["mcl_core:sugar"] = "mcl_potions:mundane", ["mcl_mobitems:magma_cream"] = "mcl_potions:mundane", @@ -346,134 +370,270 @@ local water_table = { ["mcl_nether:glowstone_dust"] = "mcl_potions:thick", ["mcl_mobitems:gunpowder"] = "mcl_potions:water_splash" } +-- API +-- register a potion recipe brewed from water +function mcl_potions.register_water_brew(ingr, potion) + if water_table[ingr] then + error("Attempt to register the same ingredient twice!") + end + if type(ingr) ~= "string" then + error("Invalid argument! ingr must be a string") + end + if type(potion) ~= "string" then + error("Invalid argument! potion must be a string") + end + water_table[ingr] = potion +end +mcl_potions.register_ingredient_potion("mcl_potions:river_water", water_table) +mcl_potions.register_ingredient_potion("mcl_potions:water", water_table) local awkward_table = { ["mcl_potions:speckled_melon"] = "mcl_potions:healing", ["mcl_farming:carrot_item_gold"] = "mcl_potions:night_vision", ["mcl_core:sugar"] = "mcl_potions:swiftness", ["mcl_mobitems:magma_cream"] = "mcl_potions:fire_resistance", - -- ["mcl_mobitems:blaze_powder"] = "mcl_potions:strength", + ["mcl_mobitems:blaze_powder"] = "mcl_potions:strength", ["mcl_fishing:pufferfish_raw"] = "mcl_potions:water_breathing", ["mcl_mobitems:ghast_tear"] = "mcl_potions:regeneration", ["mcl_mobitems:spider_eye"] = "mcl_potions:poison", ["mcl_flowers:wither_rose"] = "mcl_potions:withering", ["mcl_mobitems:rabbit_foot"] = "mcl_potions:leaping", + + ["mcl_flowers:fourleaf_clover"] = "mcl_potions:luck", + ["mcl_farming:potato_item_poison"] = "mcl_potions:nausea", + ["mcl_mobitems:spectre_membrane"] = "mcl_potions:slow_falling", + ["mcl_core:apple_gold"] = "mcl_potions:resistance", + ["mcl_mobitems:aery_charge"] = "mcl_potions:haste", + ["mcl_mobitems:crystalline_drop"] = "mcl_potions:absorption", + ["mcl_mobitems:earthen_ash"] = "mcl_potions:stone_cloak", + ["mcl_mobitems:shiny_ice_crystal"] = "mcl_potions:frost", + + -- TODO darkness - sculk? } +-- API +-- register a potion recipe brewed from awkward potion +function mcl_potions.register_awkward_brew(ingr, potion) + if awkward_table[ingr] then + error("Attempt to register the same ingredient twice!") + end + if type(ingr) ~= "string" then + error("Invalid argument! ingr must be a string") + end + if type(potion) ~= "string" then + error("Invalid argument! potion must be a string") + end + awkward_table[ingr] = potion +end +mcl_potions.register_ingredient_potion("mcl_potions:awkward", awkward_table) -local output_table = { - ["mcl_potions:river_water"] = water_table, - ["mcl_potions:water"] = water_table, - ["mcl_potions:awkward"] = awkward_table, +local mundane_table = { + ["mcl_potions:fermented_spider_eye"] = "mcl_potions:weakness", } - - -local enhancement_table = {} -local extension_table = {} -local potions = {} - -for i, potion in ipairs({"healing","harming","swiftness","slowness", - "leaping","poison","regeneration","invisibility","fire_resistance", - -- "weakness","strength", - "water_breathing","night_vision", "withering"}) do - - table.insert(potions, potion) - - if potion ~= "invisibility" and potion ~= "night_vision" and potion ~= "weakness" and potion ~= "water_breathing" and potion ~= "fire_resistance" then - enhancement_table["mcl_potions:"..potion] = "mcl_potions:"..potion.."_2" - enhancement_table["mcl_potions:"..potion.."_splash"] = "mcl_potions:"..potion.."_2_splash" - table.insert(potions, potion.."_2") +-- API +-- register a potion recipe brewed from mundane potion +function mcl_potions.register_mundane_brew(ingr, potion) + if mundane_table[ingr] then + error("Attempt to register the same ingredient twice!") end - - if potion ~= "healing" and potion ~= "harming" then - extension_table["mcl_potions:"..potion.."_splash"] = "mcl_potions:"..potion.."_plus_splash" - extension_table["mcl_potions:"..potion] = "mcl_potions:"..potion.."_plus" - table.insert(potions, potion.."_plus") + if type(ingr) ~= "string" then + error("Invalid argument! ingr must be a string") end - + if type(potion) ~= "string" then + error("Invalid argument! potion must be a string") + end + mundane_table[ingr] = potion end +mcl_potions.register_ingredient_potion("mcl_potions:mundane", mundane_table) -for i, potion in ipairs({"awkward", "mundane", "thick", "water"}) do - table.insert(potions, potion) +local thick_table = { + ["mcl_crimson:shroomlight"] = "mcl_potions:glowing", + ["mcl_mobitems:nether_star"] = "mcl_potions:ominous", + ["mcl_mobitems:ink_sac"] = "mcl_potions:blindness", + ["mcl_farming:carrot_item_gold"] = "mcl_potions:saturation", +} +-- API +-- register a potion recipe brewed from thick potion +function mcl_potions.register_thick_brew(ingr, potion) + if thick_table[ingr] then + error("Attempt to register the same ingredient twice!") + end + if type(ingr) ~= "string" then + error("Invalid argument! ingr must be a string") + end + if type(potion) ~= "string" then + error("Invalid argument! potion must be a string") + end + thick_table[ingr] = potion end +mcl_potions.register_ingredient_potion("mcl_potions:thick", thick_table) +local mod_table = { } + +-- API +-- registers a brewing recipe altering the potion using a table +-- this is supposed to substitute one item with another +function mcl_potions.register_table_modifier(ingr, modifier) + if mod_table[ingr] then + error("Attempt to register the same ingredient twice!") + end + if type(ingr) ~= "string" then + error("Invalid argument! ingr must be a string") + end + if type(modifier) ~= "table" then + error("Invalid argument! modifier must be a table") + end + mod_table[ingr] = modifier +end + local inversion_table = { ["mcl_potions:healing"] = "mcl_potions:harming", - ["mcl_potions:healing_2"] = "mcl_potions:harming_2", ["mcl_potions:swiftness"] = "mcl_potions:slowness", - ["mcl_potions:swiftness_plus"] = "mcl_potions:slowness_plus", ["mcl_potions:leaping"] = "mcl_potions:slowness", - ["mcl_potions:leaping_plus"] = "mcl_potions:slowness_plus", ["mcl_potions:night_vision"] = "mcl_potions:invisibility", - ["mcl_potions:night_vision_plus"] = "mcl_potions:invisibility_plus", ["mcl_potions:poison"] = "mcl_potions:harming", - ["mcl_potions:poison_2"] = "mcl_potions:harming_2", - ["mcl_potions:healing_splash"] = "mcl_potions:harming_splash", - ["mcl_potions:healing_2_splash"] = "mcl_potions:harming_2_splash", - ["mcl_potions:swiftness_splash"] = "mcl_potions:slowness_splash", - ["mcl_potions:swiftness_plus_splash"] = "mcl_potions:slowness_plus_splash", - ["mcl_potions:leaping_splash"] = "mcl_potions:slowness_splash", - ["mcl_potions:leaping_plus_splash"] = "mcl_potions:slowness_plus_splash", - ["mcl_potions:night_vision_splash"] = "mcl_potions:invisibility_splash", - ["mcl_potions:night_vision_plus_splash"] = "mcl_potions:invisibility_plus_splash", - ["mcl_potions:poison_splash"] = "mcl_potions:harming_splash", - ["mcl_potions:poison_2_splash"] = "mcl_potions:harming_2_splash", + ["mcl_potions:luck"] = "mcl_potions:bad_luck", + ["mcl_potions:haste"] = "mcl_potions:fatigue", + ["mcl_potions:saturation"] = "mcl_potions:food_poisoning", + ["mcl_potions:slow_falling"] = "mcl_potions:levitation", + ["mcl_potions:absorption"] = "mcl_potions:health_boost", + ["mcl_potions:glowing"] = "mcl_potions:darkness", -- TODO remove after adding a direct recipe? } - +-- API +function mcl_potions.register_inversion_recipe(input, output) + if inversion_table[input] then + error("Attempt to register the same input twice!") + end + if type(input) ~= "string" then + error("Invalid argument! input must be a string") + end + if type(output) ~= "string" then + error("Invalid argument! output must be a string") + end + inversion_table[input] = output +end +local function fill_inversion_table() -- autofills with splash and lingering inversion recipes + local filling_table = { } + for input, output in pairs(inversion_table) do + if potions[input].has_splash and potions[output].has_splash then + filling_table[input.."_splash"] = output .. "_splash" + if potions[input].has_lingering and potions[output].has_lingering then + filling_table[input.."_lingering"] = output .. "_lingering" + end + end + end + table.update(inversion_table, filling_table) + mcl_potions.register_table_modifier("mcl_potions:fermented_spider_eye", inversion_table) +end +minetest.register_on_mods_loaded(fill_inversion_table) local splash_table = {} local lingering_table = {} +for potion, def in pairs(potions) do + if def.has_splash then + splash_table[potion] = potion.."_splash" + if def.has_lingering then + lingering_table[potion.."_splash"] = potion.."_lingering" + end + end +end +mcl_potions.register_table_modifier("mcl_mobitems:gunpowder", splash_table) +mcl_potions.register_table_modifier("mcl_potions:dragon_breath", lingering_table) -for i, potion in ipairs(potions) do - splash_table["mcl_potions:"..potion] = "mcl_potions:"..potion.."_splash" - lingering_table["mcl_potions:"..potion.."_splash"] = "mcl_potions:"..potion.."_lingering" + +local meta_mod_table = { } + +-- API +-- registers a brewing recipe altering the potion using a function +-- this is supposed to be a recipe that changes metadata only +function mcl_potions.register_meta_modifier(ingr, mod_func) + if meta_mod_table[ingr] then + error("Attempt to register the same ingredient twice!") + end + if type(ingr) ~= "string" then + error("Invalid argument! ingr must be a string") + end + if type(mod_func) ~= "function" then + error("Invalid argument! mod_func must be a function") + end + meta_mod_table[ingr] = mod_func end +local function extend_dur(potionstack) + local def = potions[potionstack:get_name()] + if not def then return false end + if not def.has_plus then return false end -- bail out if can't be extended + local potionstack = ItemStack(potionstack) + local meta = potionstack:get_meta() + local potent = meta:get_int("mcl_potions:potion_potent") + local plus = meta:get_int("mcl_potions:potion_plus") + if plus == 0 then + if potent ~= 0 then + meta:set_int("mcl_potions:potion_potent", 0) + end + meta:set_int("mcl_potions:potion_plus", def._default_extend_level) + tt.reload_itemstack_description(potionstack) + return potionstack + end + return false +end +mcl_potions.register_meta_modifier("mesecons:wire_00000000_off", extend_dur) -local mod_table = { - ["mesecons:wire_00000000_off"] = extension_table, - ["mcl_potions:fermented_spider_eye"] = inversion_table, - ["mcl_nether:glowstone_dust"] = enhancement_table, - ["mcl_mobitems:gunpowder"] = splash_table, - ["mcl_potions:dragon_breath"] = lingering_table, -} +local function enhance_pow(potionstack) + local def = potions[potionstack:get_name()] + if not def then return false end + if not def.has_potent then return false end -- bail out if has no potent variant + local potionstack = ItemStack(potionstack) + local meta = potionstack:get_meta() + local potent = meta:get_int("mcl_potions:potion_potent") + local plus = meta:get_int("mcl_potions:potion_plus") + if potent == 0 then + if plus ~= 0 then + meta:set_int("mcl_potions:potion_plus", 0) + end + meta:set_int("mcl_potions:potion_potent", def._default_potent_level-1) + tt.reload_itemstack_description(potionstack) + return potionstack + end + return false +end +mcl_potions.register_meta_modifier("mcl_nether:glowstone_dust", enhance_pow) --- Compare two ingredients for compatable alchemy + +-- Find an alchemical recipe for given ingredient and potion +-- returns outcome function mcl_potions.get_alchemy(ingr, pot) - if output_table[pot] then + local brew_selector = output_table[pot:get_name()] + if brew_selector and brew_selector[ingr] then + local meta = pot:get_meta():to_table() + local alchemy = ItemStack(brew_selector[ingr]) + local metaref = alchemy:get_meta() + metaref:from_table(meta) + tt.reload_itemstack_description(alchemy) + return alchemy + end - local brew_table = output_table[pot] - - if brew_table[ingr] then - return brew_table[ingr] + brew_selector = mod_table[ingr] + if brew_selector then + local brew = brew_selector[pot:get_name()] + if brew then + local meta = pot:get_meta():to_table() + local alchemy = ItemStack(brew) + local metaref = alchemy:get_meta() + metaref:from_table(meta) + tt.reload_itemstack_description(alchemy) + return alchemy end end - if mod_table[ingr] then - - local brew_table = mod_table[ingr] - - if brew_table[pot] then - return brew_table[pot] - end - + if meta_mod_table[ingr] then + local brew_func = meta_mod_table[ingr] + if brew_func then return brew_func(pot) end end return false end -mcl_mobs.effect_functions["poison"] = mcl_potions.poison_func -mcl_mobs.effect_functions["regeneration"] = mcl_potions.regeneration_func -mcl_mobs.effect_functions["invisibility"] = mcl_potions.invisiblility_func -mcl_mobs.effect_functions["fire_resistance"] = mcl_potions.fire_resistance_func -mcl_mobs.effect_functions["night_vision"] = mcl_potions.night_vision_func -mcl_mobs.effect_functions["water_breathing"] = mcl_potions.water_breathing_func -mcl_mobs.effect_functions["leaping"] = mcl_potions.leaping_func -mcl_mobs.effect_functions["swiftness"] = mcl_potions.swiftness_func -mcl_mobs.effect_functions["heal"] = mcl_potions.healing_func -mcl_mobs.effect_functions["bad_omen"] = mcl_potions.bad_omen_func -mcl_mobs.effect_functions["withering"] = mcl_potions.withering_func - -- give withering to players in a wither rose local etime = 0 minetest.register_globalstep(function(dtime) @@ -488,10 +648,6 @@ minetest.register_globalstep(function(dtime) end) mcl_wip.register_wip_item("mcl_potions:night_vision") -mcl_wip.register_wip_item("mcl_potions:night_vision_plus") mcl_wip.register_wip_item("mcl_potions:night_vision_splash") -mcl_wip.register_wip_item("mcl_potions:night_vision_plus_splash") mcl_wip.register_wip_item("mcl_potions:night_vision_lingering") -mcl_wip.register_wip_item("mcl_potions:night_vision_plus_lingering") mcl_wip.register_wip_item("mcl_potions:night_vision_arrow") -mcl_wip.register_wip_item("mcl_potions:night_vision_plus_arrow") diff --git a/mods/ITEMS/mcl_potions/lingering.lua b/mods/ITEMS/mcl_potions/lingering.lua index 46d94cad3..0eeb40b50 100644 --- a/mods/ITEMS/mcl_potions/lingering.lua +++ b/mods/ITEMS/mcl_potions/lingering.lua @@ -11,8 +11,8 @@ end local lingering_effect_at = {} -local function add_lingering_effect(pos, color, def, is_water, instant) - lingering_effect_at[pos] = {color = color, timer = 30, def = def, is_water = is_water} +local function add_lingering_effect(pos, color, def, is_water, potency, plus) + lingering_effect_at[pos] = {color = color, timer = 30, def = def, is_water = is_water, potency = potency, plus = plus} end local function linger_particles(pos, d, texture, color) @@ -55,23 +55,56 @@ minetest.register_globalstep(function(dtime) end linger_particles(pos, d, texture, vals.color) - -- Extinguish fire if water bottle - if vals.is_water then - if mcl_potions._extinguish_nearby_fire(pos, d) then - vals.timer = vals.timer - 3.25 - end +-- -- Extinguish fire if water bottle +-- if vals.is_water then +-- if mcl_potions._extinguish_nearby_fire(pos, d) then +-- vals.timer = vals.timer - 3.25 +-- end +-- end + + if vals.def.while_lingering and vals.def.while_lingering(pos, d, vals.potency+1) then + vals.timer = vals.timer - 3.25 end -- Affect players and mobs for _, obj in pairs(minetest.get_objects_inside_radius(pos, d)) do local entity = obj:get_luaentity() - if obj:is_player() or entity.is_mob then + if obj:is_player() or entity and entity.is_mob then + local applied = false + if vals.def._effect_list then + local ef_level + local dur + for name, details in pairs(vals.def._effect_list) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (vals.potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, vals.plus) + if vals.potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, vals.potency) + end + dur = dur * mcl_potions.LINGERING_FACTOR + else + dur = details.dur + end + if details.effect_stacks then + ef_level = ef_level + mcl_potions.get_effect_level(obj, name) + end + if mcl_potions.give_effect_by_level(name, obj, ef_level, dur) then + applied = true + end + end + end - vals.def.potion_fun(obj) - -- TODO: Apply timer penalty only if the potion effect was acutally applied - vals.timer = vals.timer - 3.25 + if vals.def.custom_effect + and vals.def.custom_effect(obj, (vals.potency+1) * mcl_potions.LINGERING_FACTOR, plus) then + applied = true + end + if applied then vals.timer = vals.timer - 3.25 end end end @@ -87,31 +120,44 @@ end) function mcl_potions.register_lingering(name, descr, color, def) - local id = "mcl_potions:"..name.."_lingering" - local longdesc = def.longdesc + local longdesc = def._longdesc if not def.no_effect then - longdesc = S("A throwable potion that will shatter on impact, where it creates a magic cloud that lingers around for a while. Any player or mob inside the cloud will receive the potion's effect, possibly repeatedly.") + longdesc = S("A throwable potion that will shatter on impact, where it creates a magic cloud that lingers around for a while. Any player or mob inside the cloud will receive the potion's effect or set of effects, possibly repeatedly.") if def.longdesc then - longdesc = longdesc .. "\n" .. def.longdesc + longdesc = longdesc .. "\n" .. def._longdesc end end + local groups = {brewitem=1, bottle=1, ling_potion=1, _mcl_potion=1} + if def.nocreative then groups.not_in_creative_inventory = 1 end minetest.register_craftitem(id, { description = descr, - _tt_help = def.tt, + _tt_help = def._tt, + _dynamic_tt = def._dynamic_tt, _doc_items_longdesc = longdesc, _doc_items_usagehelp = S("Use the “Punch” key to throw it."), + stack_max = def.stack_max, + _effect_list = def._effect_list, + uses_level = def.uses_level, + has_potent = def.has_potent, + has_plus = def.has_plus, + _default_potent_level = def._default_potent_level, + _default_extend_level = def._default_extend_level, inventory_image = lingering_image(color), - groups = {brewitem=1, not_in_creative_inventory=0, bottle=1}, + groups = groups, on_use = function(item, placer, pointed_thing) local velocity = 10 local dir = placer:get_look_dir(); local pos = placer:getpos(); minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true) local obj = minetest.add_entity({x=pos.x+dir.x,y=pos.y+2+dir.y,z=pos.z+dir.z}, id.."_flying") - obj:setvelocity({x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}) - obj:setacceleration({x=dir.x*-3, y=-9.8, z=dir.z*-3}) - obj:get_luaentity()._thrower = placer:get_player_name() + obj:set_velocity({x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}) + obj:set_acceleration({x=dir.x*-3, y=-9.8, z=dir.z*-3}) + local ent = obj:get_luaentity() + ent._thrower = placer:get_player_name() + ent._potency = item:get_meta():get_int("mcl_potions:potion_potent") + ent._plus = item:get_meta():get_int("mcl_potions:potion_plus") + ent._effect_list = def._effect_list if not minetest.is_creative_enabled(placer:get_player_name()) then item:take_item() end @@ -126,6 +172,10 @@ function mcl_potions.register_lingering(name, descr, color, def) local velocity = 22 obj:set_velocity({x=dropdir.x*velocity,y=dropdir.y*velocity,z=dropdir.z*velocity}) obj:set_acceleration({x=dropdir.x*-3, y=-9.8, z=dropdir.z*-3}) + local ent = obj:get_luaentity() + ent._potency = item:get_meta():get_int("mcl_potions:potion_potent") + ent._plus = item:get_meta():get_int("mcl_potions:potion_plus") + ent._effect_list = def._effect_list end }) @@ -148,7 +198,9 @@ function mcl_potions.register_lingering(name, descr, color, def) end if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1}) - add_lingering_effect(pos, color, def, name == "water") + local potency = self._potency or 0 + local plus = self._plus or 0 + add_lingering_effect(pos, color, def, name == "water", potency, plus) local texture if name == "water" then texture = "mcl_particles_droplet_bottle.png" @@ -160,9 +212,7 @@ function mcl_potions.register_lingering(name, descr, color, def) end end linger_particles(pos, d, texture, color) - if name == "water" then - mcl_potions._extinguish_nearby_fire(pos, d) - end + if def.on_splash then def.on_splash(pos, potency+1) end self.object:remove() end end, diff --git a/mods/ITEMS/mcl_potions/locale/mcl_potions.pl.tr b/mods/ITEMS/mcl_potions/locale/mcl_potions.pl.tr index abf61d4d3..db835bd9e 100644 --- a/mods/ITEMS/mcl_potions/locale/mcl_potions.pl.tr +++ b/mods/ITEMS/mcl_potions/locale/mcl_potions.pl.tr @@ -1,115 +1,294 @@ # textdomain: mcl_potions - []= [] +Invisibility=Niewidzialność +body is invisible=ciało jest niewidzialne + +Poison=Trucizna +-1 HP / @1 s=-1 PŻ / @1 s + +Regeneration=Regeneracja ++1 HP / @1 s=+1 PŻ / @1 s + +Strength=Siła ++@1% melee damage=+@1% obrażeń w walce wręcz + +Weakness=Osłabienie +-@1% melee damage=-@1% obrażeń w walce wręcz + +Water Breathing=Oddychanie pod Wodą +limitless breathing under water=nieograniczone oddychanie pod wodą + +Dolphin's Grace=Gracja Delfina +swimming gracefully=pływanie z gracją + +Leaping=Zwiększony Skok ++@1% jumping power=+@1% siły skoku +-@1% jumping power=-@1% siły skoku + +Slow Falling=Powolne Opadanie +decreases gravity effects=zmniejsza skutki grawitacji + +Swiftness=Szybkość ++@1% running speed=+@1% prędkości w biegu + +Slowness=Spowolnienie +-@1% running speed=-@1% prędkości w biegu + +Levitation=Lewitacja +moves body upwards at @1 nodes/s=porusza ciało w górę z prędkością @1 bloków/s + +Night Vision=Noktowizja +improved vision during the night=poprawione widzenie w nocy + +Darkness=Ciemność +surrounded by darkness=otoczony ciemnością +not seeing anything beyond @1 nodes=nie widzi nic poza @1 blokami + +Glowing=Blask +more visible at all times=bardziej widoczny przez cały czas + +Health Boost=Zwiększone Zdrowie +HP increased by @1=PŻ zwiększone o @1 + +Absorption=Absorpcja +absorbs up to @1 incoming damage=pochłania do @1 otrzymywanych obrażeń + +Fire Resistance=Odporność na Ogień +resistance to fire damage=odporność na szkody od ognia + +Resistance=Odporność +resist @1% of incoming damage=zmniejsza otrzymywane obrażenia o @1% + +Luck=Szczęście + +Bad Luck=Pech + +Bad Omen=Zły Omen +danger is imminent=zagrożenie jest blisko + +Hero of the Village=Bohater Wioski + +Withering=Obumieranie +-1 HP / @1 s, can kill=-1 PŻ / @1 s, może zabić + +Frost=Mróz +-1 HP / 1 s, can kill, -@1% running speed=-1 PŻ / 1 s, może zabić, -@1% prędkości w biegu + +Blindness=Ślepota +impaired sight=upośledzony wzrok + +Nausea=Nudności +not feeling very well...=nie czuje się zbyt dobrze +frequency: @1 / 1 s=częstotliwość: @1 / 1 s + +Food Poisoning=Zatrucie Pokarmowe +exhausts by @1 per second=wyczerpuje o @1 na sekundę + +Saturation=Nasycenie +saturates by @1 per second=nasyca o @1 na sekundę + +Haste=Pośpiech ++@1% mining and attack speed=+@1% prędkości kopania i ataku + +Fatigue=Zmęczenie +-@1% mining and attack speed=-@1% prędkości kopania i ataku + +Conduit Power=Moc Przewodni ++@1% mining and attack speed in water=+@1% prędkości kopania i ataku w wodzie + + +|heal|list|clear|remove |INF [] [] [NOPART]=|heal|list|clear|remove |INF [] [] [NOPART] + +Add a status effect to yourself. Arguments: : name of status effect. Passing "list" as effect name lists available effects. Passing "heal" as effect name heals (or harms) by amount designed by the next parameter. Passing "clear" as effect name removes all effects. Passing "remove" as effect name removes the effect named by the next parameter. : duration in seconds. Passing "INF" as duration makes the effect infinite. (: amount of healing when the effect is "heal", passing a negative value subtracts health. : name of a status effect to be removed when using "remove" as the previous parameter.) : effect power determinant, bigger level results in more powerful effect for effects that depend on the level (no changes for other effects), defaults to 1, pass F to use low-level factor instead. : effect strength modifier, can mean different things depending on the effect, no changes for effects that do not depend on level/factor. NOPART at the end means no particles will be shown for this effect.=Nadaj efekt statusu dla samego siebie. Argumenty: : nazwa efektu statusu (po angielsku). Przekazanie "list" jako nazwa efektu wypisuje dostępne nazwy efektów. Przekazanie "heal" jako nazwa efektu leczy (albo krzywdzi) o ilość określoną następnym parametrem. Przekazanie "clear" jako nazwy efektu usuwa wszystkie efekty. Przekazanie "remove" jako nazwy efektu usuwa efekt określony następnym parametrem. : czas trwania w sekundach. Przekazanie "INF" jako czas trwania czyni efekt nieskończonym. (: ilość leczenia kiedy ID-efektu to "heal", przekazanie liczby ujemnej zabiera zdrowie. : nazwa efektu statusu do usunięcia używając "remove" jako poprzedniego parametru.) : wyznacznik siły efektu, wyższy poziom skutkuje potężniejszym efektem prze efektach zależnych od poziomu (brak zmiany przy pozostałych), domyślnie 1, przekaż F żeby użyć niskopoziomowego współczynnika zamiast poziomu. : modyfikator siły efektu, może oznaczać różne rzeczy dla różnych efektów, nie wpływa na efekty, które nie zależą od poziomu/współczynnika. NOPART na końcu oznacza, że cząsteczki nie będą wyświetlane wokół ciebie dla tego efektu. + +Missing effect parameter!=Brakujący ID efektu! +Missing or invalid heal amount parameter!=Brakująca lub niewłaściwa ilość leczenia! +Player @1 healed by @2 HP.=Gracz @1 wyleczony o @2 PŻ. +Player @1 harmed by @2 HP.=Gracz @1 skrzywdzony o @2 PŻ. +Effects cleared for player @1=Efekty wyczyszczone dla gracza @1 +Removed effect @1 from player @2=Usunięto efekt @1 z gracza @2 +@1 is not an available status effect.=@1 nie jest dostępnym efektem. +Missing or invalid duration parameter!=Brakujący lub niewłaściwy czas trwania! +Invalid level parameter!=Niewłaściwy parametr poziomu! +Missing or invalid factor parameter when level is F!=Brakujący lub niewłaściwy współczynnik kiedy poziom to F! + +@1 effect given to player @2 for @3 seconds with factor of @4.=Efekt @1 nadany dla gracza @2 na @3 sekund ze współczynnikiem @4. +@1 effect given to player @2 for @3 seconds.=Efekt @1 nadany dla gracza @2 na #3 sekund. +Giving effect @1 to player @2 failed.=Nadawanie efektu @1 dla gracza @2 nie powiodło się. +@1 effect on level @2 given to player @3 for @4 seconds.=Efekt @1 na poziomie @2 nadany dla gracza @3 na @4 sekund. + + +A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect or a set of status effects.=Mikstura, którą można rzucić, a rozbije się przy uderzeniu, wystawiając wszystkich pobliskich graczy i moby na skutki jej działania. +Use the “Punch” key to throw it.=Użyj przycisku "Uderz" by rzucić. + + +A throwable potion that will shatter on impact, where it creates a magic cloud that lingers around for a while. Any player or mob inside the cloud will receive the potion's effect or set of effects, possibly repeatedly.=Mikstura, którą można rzucić, a roztrzaska się przy uderzeniu, tworząc magiczne opary pozostające przez chwilę na ziemi. Jakikolwiek gracz lub mob wewnątrz oparów będzie wystawiony na skutki mikstury, być może wielokrotnie. + + +This particular arrow is tipped and will give an effect when it hits a player or mob.=Czubek tej strzały jest zanurzony w miksturze, co wystawi jej cel na skutki jej działania. + + +Use the “Place” key to drink it.=Użyj przycisku "Postaw" by wypić. +Drinking a potion gives you a particular effect or set of effects.=Wypicie mikstury wywoła u ciebie określone skutki. + +@1 Potion @2=@1 Mikstura @2 +@1 Potion=@1 Mikstura +Potion @1=Mikstura @1 +Strange Potion=Dziwna Mikstura + +Splash @1=Miotana @1 +Lingering @1=Trwała @1 +@1 Arrow @2=@1 Strzała @2 +@1 Arrow=@1 Strzała +Arrow @1=Strzała @1 +Strange Tipped Arrow=Strzała z Dziwnym Grotem + +Mighty=Potężna +of Trolling=Trollowania + +Dragon's Breath=Oddech Smoka +This item is used in brewing and can be combined with splash potions to create lingering potions.=Ten przedmiot jest używany przy warzeniu i może zostać dodany do miotanych mikstur, aby uczynić je trwałymi. + +Awkward=Klarowna +No effect=Brak efektu +Has an awkward taste and is used for brewing potions.=Ma dziwny smak i jest używana do warzenia mikstur. + +Mundane=Mdła +Has a terrible taste and is not really useful for brewing potions.=Ma ohydny smak i nie jest zbyt użyteczna przy warzeniu mikstur. + +Thick=Gęsta +Has a bitter taste and may be useful for brewing potions.=Ma cierpki smak i może być użyteczna przy warzeniu mikstur. + +of Healing=Leczenia ++@1 HP=+@1 PŻ +Instantly heals.=Natychmiast leczy. + +of Harming=Krzywdy +-@1 HP=-@1 PŻ +Instantly deals damage.=Natychmiast zadaje obrażenia. + +of Night Vision=Noktowizji +Increases the perceived brightness of light under a dark sky.=Zwiększa postrzeganą jasność przy ciemnym niebie. + +of Swiftness=Szybkości +Increases walking speed.=Zwiększa prędkość ruchu. + +of Slowness=Spowolnienia +Decreases walking speed.=Zmniejsza prędkość ruchu. + +of Leaping=Zwiększonego Skoku +Increases jump strength.=Zwiększa siłę skoku. + +of Withering=Obumierania +Applies the withering effect which deals damage at a regular interval and can kill.=Zadaje efekt obumierania, zadający obrażenia w regularnych odstępach czasu i mogący zabić. + +of Poison=Trucizny +Applies the poison effect which deals damage at a regular interval.=Zadaje efekt trucizny, zadający obrażenia w regularnych odstępach czasu. + +of Regeneration=Regeneracji +Regenerates health over time.=Regeneruje życie z upływem czasu. + +of Invisibility=Niewidzialności +Grants invisibility.=Daje niewidzialność. + +of Water Breathing=Oddychania pod Wodą +Grants limitless breath underwater.=Daje nieograniczony oddech pod wodą. + +of Fire Resistance=Odporności na Ogień +Grants immunity to damage from heat sources like fire.=Daje odporność na obrażenia od źródeł ciepła takich jak ogień. + +of Strength=Siły +Increases attack power.=Zwiększa siłę ataku. + +of Weakness=Osłabienia +Decreases attack power.=Zmniejsza siłę ataku. + +of Slow Falling=Powolnego Opadania +Instead of falling, you descend gracefully.=Zamiast spadać, zstępujesz delikatnie. + +of Levitation=Lewitacji +Floats body slowly upwards.=Ciało powoli dryfuje w górę. + +of Darkness=Ciemności +Surrounds with darkness.=Otacza ciemnością. + +of Glowing=Blasku +Highlights for others to see.=Podświetla dla innych do dostrzeżenia. + +of Health Boost=Zwiększonego Zdrowia +Increases health.=Zwiększa zdrowie. + +of Absorption=Absorpcji +Absorbs some incoming damage.=Pochłania trochę otrzymywanych obrażeń. + +of Resistance=Odporności +Decreases damage taken.=Zmniejsza otrzymywane obrażenia. + +of Stone Cloak=Kamiennego Płaszcza +Decreases damage taken at the cost of speed.=Zmniejsza otrzymywane obrażenia kosztem prędkości. + +of Luck=Szczęścia +Increases luck.=Zwiększa szczęście. + +of Bad Luck=Pecha +Decreases luck.=Zmniejsza szczęście. + +of Frost=Mrozu +Freezes...=Zamraża... + +of Blindness=Ślepoty +Impairs sight.=Upośledza wzrok. + +of Nausea=Nudności +Disintegrates senses.=Dezintegruje zmysły. + +of Food Poisoning=Zatrucia Pokarmowego +Moves bowels too fast.=Porusza jelitami zbyt szybko. + +of Saturation=Nasycenia +Satisfies hunger.=Zaspokaja głód. + +of Haste=Pośpiechu +Increases digging and attack speed.=Zwiększa prędkość kopania i ataku. + +of Fatigue=Zmęczenia +Decreases digging and attack speed.=Zmniejsza prędkość kopania i ataku. + +Ominous=Złowieszcza +Attracts danger.=Przyciąga zagrożenie. + +Unknown Potion=Nieznana Mikstura +Right-click to identify=Kliknij prawym przyciskiem myszy, aby zidentyfikować +Unknown Tipped Arrow=Strzała z Nieznanym Grotem -Add a status effect to yourself. Arguments: : name of status effect, e.g. poison. : duration in seconds. : effect strength multiplier (1 @= 100%)=Dodaj status na siebie. Argumenty: : nazwa efektu statusu, np. trucizna. : czas trwania w sekundach. : czynnik siły efektu (1 @= 100%) -Missing effect parameter!=Brak parametru efektu! -Missing or invalid duration parameter!=Brak lub nieprawidłowy parametr czasu trwania! -Invalid factor parameter!=Nieprawidłowy parametr czynnika! -@1 is not an available status effect.=@1 nie jest dostępnym efektem statusu. Fermented Spider Eye=Fermentowane oko pająka +Try different combinations to create potions.=Wypróbuj różne kombinacje, by stworzyć mikstury. + Glass Bottle=Szklana butelka -Liquid container=Pojemnik na płyn +Liquid container=Zbiornik na ciecz A glass bottle is used as a container for liquids and can be used to collect water directly.=Szklana butelka jest używana jako pojemnik na płyny i może być wykorzystana bezpośrednio do pozyskiwania wody. - To collect water, use it on a cauldron with water (which removes a level of water) or any water source (which removes no water).=Aby pozyskać wodę użyj jej na kotle z wodą (co usunie jeden poziom wody) lub jakimkolwiek źródle wody (co nie usunie wody). Water Bottle=Butelka wody -Water bottles can be used to fill cauldrons. Drinking water has no effect.=Butelka wody może być wykorzystana do napełniania kotłów. Picie wody nie ma żadnych efektów. +Water bottles can be used to fill cauldrons. Drinking water has no effect.=Butelka wody może być wykorzystana do napełniania kotłów. Picie wody nie ma żadnych skutków. Use the “Place” key to drink. Place this item on a cauldron to pour the water into the cauldron.=Użyj przycisku do stawiania aby pić. Postaw ten przedmiot na kotle aby wylać wodę do kotła. River Water Bottle=Butelka wody rzecznej -River water bottles can be used to fill cauldrons. Drinking it has no effect.=Butelka wody rzecznej może być wykorzystana do napełniania kotłów. Picie jej nie ma żadnego efektu. +River water bottles can be used to fill cauldrons. Drinking it has no effect.=Butelka wody rzecznej może być wykorzystana do napełniania kotłów. Picie jej nie ma żadnego skutku. Use the “Place” key to drink. Place this item on a cauldron to pour the river water into the cauldron.=Użyj przycisku do stawiania aby pić. Postaw ten przedmiot na kotle aby wylać wodę rzeczną do kotła. Splash Water Bottle=Miotana butelka wody Extinguishes fire and hurts some mobs=Gasi ogień i rani niektóre moby -A throwable water bottle that will shatter on impact, where it extinguishes nearby fire and hurts mobs that are vulnerable to water.=Butelka wody którą można rzucać i roztrzaska się przy uderzeniu, gdzie ugasi ogień i rani moby podatne na wodę. +A throwable water bottle that will shatter on impact, where it extinguishes nearby fire and hurts mobs that are vulnerable to water.=Butelka wody, którą można rzucić, a roztrzaska się przy uderzeniu, gdzie ugasi ogień i zrani moby podatne na wodę. Lingering Water Bottle=Trwała miotana butelka wody -A throwable water bottle that will shatter on impact, where it creates a cloud of water vapor that lingers on the ground for a while. This cloud extinguishes fire and hurts mobs that are vulnerable to water.=Butelka wody którą można rzucać i roztrzaska się przy uderzeniu tworząc opary wody pozostające przez chwilę na ziemi. Opary te gaszą ogień i ranią moby podatne na wodę. +A throwable water bottle that will shatter on impact, where it creates a cloud of water vapor that lingers on the ground for a while. This cloud extinguishes fire and hurts mobs that are vulnerable to water.=Butelka wody którą można rzucić, a roztrzaska się przy uderzeniu, tworząc opary wody pozostające przez chwilę na ziemi. Opary te gaszą ogień i ranią moby podatne na wodę. Glistering Melon=Błyszczący arbuz This shiny melon is full of tiny gold nuggets and would be nice in an item frame. It isn't edible and not useful for anything else.=Ten błyszczący arbuz jest pełen tycich odłamków złota i wygląda ładnie w ramkach na przedmioty. Nie jest jadalny ani użyteczny do innych rzeczy. - -A throwable potion that will shatter on impact, where it creates a magic cloud that lingers around for a while. Any player or mob inside the cloud will receive the potion's effect, possibly repeatedly.=Mikstura którą można rzucać i roztrzaska się przy uderzeniu tworząc magiczne opary pozostające przez chwilę na ziemi. Jakikolwiek gracz lub mob wewnątrz oparów będzie wystawiony na efekt mikstury. - -Use the “Punch” key to throw it.=Użyj przycisku "Uderz" by rzucić. -Use the “Place” key to drink it.=Użyj przycisku "Postaw" by wypić. -Drinking a potion gives you a particular effect.=Wypicie mikstury sprawi, że będziesz wystawiona na jej efekty. -1 HP/@1s | @2=1 HP/@1s | @2 -@1 HP=@1 HP -@1 Potion=Mikstura @1 -Splash @1 Potion=Miotana mikstura @1 -Lingering @1 Potion=Trwała miotana mikstura @1 -Arrow of @1=Strzała @1 - II= II - IV= IV -@1 Potion@2=Mikstura @1@2 -Splash @1@2 Potion=Miotana mikstura @1@2 -Lingering @1@2 Potion=Trwała miotana mikstura @1@2 -Arrow of @1@2=Strzała @1@2 -@1 + Potion=Mikstura @1 + -Splash @1 + Potion=Miotana mikstura @1 + -Lingering @1 + Potion=Trwała miotana mikstura @1 + -Arrow of @1 +=Strzała @1 + -Awkward Potion=Klarowna mikstura -Awkward Splash Potion=Klarowna miotana mikstura -Awkward Lingering Potion=Klarowna trwała miotana mikstura -Has an awkward taste and is used for brewing potions.=Ma dziwny smak i jest użyteczna przy warzenia mikstur. -Mundane Potion=Mdła mikstura -Mundane Splash Potion=Mdła miotana mikstura -Mundane Lingering Potion=Mdła trwała miotana mikstura -Has a terrible taste and is not useful for brewing potions.=Ma ohydny smak i nie jest użyteczna przy warzenia mikstur. -Thick Potion=Gęsta mikstura -Thick Splash Potion=Gęsta miotana mikstura -Thick Lingering Potion=Gęsta trwała miotana mikstura -Has a bitter taste and is not useful for brewing potions.=Ma cierpki smak i nie jest użyteczna przy warzenia mikstur. -Dragon's Breath=Oddech smoka - -This item is used in brewing and can be combined with splash potions to create lingering potions.=Ten przedmiot jest używany przy warzeniu i może zostać dodany do miotanych mikstur aby uczynić je trwałymi. - -Healing=leczenia -+4 HP=+4 HP -+8 HP=+8 HP -Instantly heals.=Natychmiastowo leczy. -Harming=obrażeń --6 HP=-6 HP --12 HP=-12 HP -Instantly deals damage.=Natychmiastowo zadaje obrażenia. -Night Vision=widzenia w ciemności -Increases the perceived brightness of light under a dark sky.=Zwiększa postrzeganą jasność przy ciemnym niebie. -Swiftness=prędkości -Increases walking speed.=Zwiększa prędkość poruszania. -Slowness=spowolnienia -Decreases walking speed.=Zmniejsza prędkość poruszania. -Leaping=skakania -Increases jump strength.=Zwiększa siłę skoku. -Poison=trucizny -Applies the poison effect which deals damage at a regular interval.=Aplikuje efekt trucizny zadający obrażenia w regularnych odstępach czasu. -Regeneration=regeneracji -Regenerates health over time.=Regeneruje życie przez pewien czas. -Invisibility=niewidzialności -Grants invisibility.=Sprawia, że cel jest niewidzialny. -Water Breathing=oddychania pod wodą -Grants limitless breath underwater.=Sprawia, że cel może oddychać pod wodą. -Fire Resistance=odporności na ogień -Grants immunity to damage from heat sources like fire.=Sprawia, że cel jest odporny na obrażenia od źródeł ciepła takich jak ogień. -Weakness=słabości -Weakness +=słabości + -Strength=siły -Strength II=siły II -Strength +=siły + -Try different combinations to create potions.=Spróbuj innej kombinacji aby stworzyć miksturę. -No effect=Brak efektu - -A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect.=Mikstura, którą można rzucić i rozbije się przy uderzeniu wystawiając wszystkich pobliskich graczy i moby na efekt jej działania. - -This particular arrow is tipped and will give an effect when it hits a player or mob.=Czubek tej strzały jest zanurzony w miksturze co wystawi jej cel na efekt jej działania. - diff --git a/mods/ITEMS/mcl_potions/locale/template.txt b/mods/ITEMS/mcl_potions/locale/template.txt index 1420dabee..39cd18f31 100644 --- a/mods/ITEMS/mcl_potions/locale/template.txt +++ b/mods/ITEMS/mcl_potions/locale/template.txt @@ -1,13 +1,269 @@ # textdomain: mcl_potions - []= +Invisibility= +body is invisible= -Add a status effect to yourself. Arguments: : name of status effect, e.g. poison. : duration in seconds. : effect strength multiplier (1 @= 100%)= +Poison= +-1 HP / @1 s= + +Regeneration= ++1 HP / @1 s= + +Strength= ++@1% melee damage= + +Weakness= +-@1% melee damage= + +Water Breathing= +limitless breathing under water= + +Dolphin's Grace= +swimming gracefully= + +Leaping= ++@1% jumping power= +-@1% jumping power= + +Slow Falling= +decreases gravity effects= + +Swiftness= ++@1% running speed= + +Slowness= +-@1% running speed= + +Levitation= +moves body upwards at @1 nodes/s= + +Night Vision= +improved vision during the night= + +Darkness= +surrounded by darkness= +not seeing anything beyond @1 nodes= + +Glowing= +more visible at all times= + +Health Boost= +HP increased by @1= + +Absorption= +absorbs up to @1 incoming damage= + +Fire Resistance= +resistance to fire damage= + +Resistance= +resist @1% of incoming damage= + +Luck= + +Bad Luck= + +Bad Omen= +danger is imminent= + +Hero of the Village= + +Withering= +-1 HP / @1 s, can kill= + +Frost= +-1 HP / 1 s, can kill, -@1% running speed= + +Blindness= +impaired sight= + +Nausea= +not feeling very well...= +frequency: @1 / 1 s= + +Food Poisoning= +exhausts by @1 per second= + +Saturation= +saturates by @1 per second= + +Haste= ++@1% mining and attack speed= + +Fatigue= +-@1% mining and attack speed= + +Conduit Power= ++@1% mining and attack speed in water= + + +|heal|list|clear|remove |INF [] [] [NOPART]= + +Add a status effect to yourself. Arguments: : name of status effect. Passing "list" as effect name lists available effects. Passing "heal" as effect name heals (or harms) by amount designed by the next parameter. Passing "clear" as effect name removes all effects. Passing "remove" as effect name removes the effect named by the next parameter. : duration in seconds. Passing "INF" as duration makes the effect infinite. (: amount of healing when the effect is "heal", passing a negative value subtracts health. : name of a status effect to be removed when using "remove" as the previous parameter.) : effect power determinant, bigger level results in more powerful effect for effects that depend on the level (no changes for other effects), defaults to 1, pass F to use low-level factor instead. : effect strength modifier, can mean different things depending on the effect, no changes for effects that do not depend on level/factor. NOPART at the end means no particles will be shown for this effect.= Missing effect parameter!= -Missing or invalid duration parameter!= -Invalid factor parameter!= +Missing or invalid heal amount parameter!= +Player @1 healed by @2 HP.= +Player @1 harmed by @2 HP.= +Effects cleared for player @1= +Removed effect @1 from player @2= @1 is not an available status effect.= +Missing or invalid duration parameter!= +Invalid level parameter!= +Missing or invalid factor parameter when level is F!= + +@1 effect given to player @2 for @3 seconds with factor of @4.= +@1 effect given to player @2 for @3 seconds.= +Giving effect @1 to player @2 failed.= +@1 effect on level @2 given to player @3 for @4 seconds.= + + +A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect or a set of status effects.= +Use the “Punch” key to throw it.= + + +A throwable potion that will shatter on impact, where it creates a magic cloud that lingers around for a while. Any player or mob inside the cloud will receive the potion's effect or set of effects, possibly repeatedly.= + + +This particular arrow is tipped and will give an effect when it hits a player or mob.= + + +Use the “Place” key to drink it.= +Drinking a potion gives you a particular effect or set of effects.= + +@1 Potion @2= +@1 Potion= +Potion @1= +Strange Potion= + +Splash @1= +Lingering @1= +@1 Arrow @2= +@1 Arrow= +Arrow @1= +Strange Tipped Arrow= + +Mighty= +of Trolling= + +Dragon's Breath= +This item is used in brewing and can be combined with splash potions to create lingering potions.= + +Awkward= +No effect= +Has an awkward taste and is used for brewing potions.= + +Mundane= +Has a terrible taste and is not really useful for brewing potions.= + +Thick= +Has a bitter taste and may be useful for brewing potions.= + +of Healing= ++@1 HP= +Instantly heals.= + +of Harming= +-@1 HP= +Instantly deals damage.= + +of Night Vision= +Increases the perceived brightness of light under a dark sky.= + +of Swiftness= +Increases walking speed.= + +of Slowness= +Decreases walking speed.= + +of Leaping= +Increases jump strength.= + +of Withering= +Applies the withering effect which deals damage at a regular interval and can kill.= + +of Poison= +Applies the poison effect which deals damage at a regular interval.= + +of Regeneration= +Regenerates health over time.= + +of Invisibility= +Grants invisibility.= + +of Water Breathing= +Grants limitless breath underwater.= + +of Fire Resistance= +Grants immunity to damage from heat sources like fire.= + +of Strength= +Increases attack power.= + +of Weakness= +Decreases attack power.= + +of Slow Falling= +Instead of falling, you descend gracefully.= + +of Levitation= +Floats body slowly upwards.= + +of Darkness= +Surrounds with darkness.= + +of Glowing= +Highlights for others to see.= + +of Health Boost= +Increases health.= + +of Absorption= +Absorbs some incoming damage.= + +of Resistance= +Decreases damage taken.= + +of Stone Cloak= +Decreases damage taken at the cost of speed.= + +of Luck= +Increases luck.= + +of Bad Luck= +Decreases luck.= + +of Frost= +Freezes...= + +of Blindness= +Impairs sight.= + +of Nausea= +Disintegrates senses.= + +of Food Poisoning= +Moves bowels too fast.= + +of Saturation= +Satisfies hunger.= + +of Haste= +Increases digging and attack speed.= + +of Fatigue= +Decreases digging and attack speed.= + +Ominous= +Attracts danger.= + +Unknown Potion= +Right-click to identify= +Unknown Tipped Arrow= + + Fermented Spider Eye= +Try different combinations to create potions.= + Glass Bottle= Liquid container= @@ -37,79 +293,3 @@ A throwable water bottle that will shatter on impact, where it creates a cloud o Glistering Melon= This shiny melon is full of tiny gold nuggets and would be nice in an item frame. It isn't edible and not useful for anything else.= - -A throwable potion that will shatter on impact, where it creates a magic cloud that lingers around for a while. Any player or mob inside the cloud will receive the potion's effect, possibly repeatedly.= - -Use the “Punch” key to throw it.= -Use the “Place” key to drink it.= -Drinking a potion gives you a particular effect.= -1 HP/@1s | @2= -@1 HP= -@1 Potion= -Splash @1 Potion= -Lingering @1 Potion= -Arrow of @1= - II= - IV= -@1 Potion@2= -Splash @1@2 Potion= -Lingering @1@2 Potion= -Arrow of @1@2= -@1 + Potion= -Splash @1 + Potion= -Lingering @1 + Potion= -Arrow of @1 += -Awkward Potion= -Awkward Splash Potion= -Awkward Lingering Potion= -Has an awkward taste and is used for brewing potions.= -Mundane Potion= -Mundane Splash Potion= -Mundane Lingering Potion= -Has a terrible taste and is not useful for brewing potions.= -Thick Potion= -Thick Splash Potion= -Thick Lingering Potion= -Has a bitter taste and is not useful for brewing potions.= -Dragon's Breath= - -This item is used in brewing and can be combined with splash potions to create lingering potions.= - -Healing= -+4 HP= -+8 HP= -Instantly heals.= -Harming= --6 HP= --12 HP= -Instantly deals damage.= -Night Vision= -Increases the perceived brightness of light under a dark sky.= -Swiftness= -Increases walking speed.= -Slowness= -Decreases walking speed.= -Leaping= -Increases jump strength.= -Poison= -Applies the poison effect which deals damage at a regular interval.= -Regeneration= -Regenerates health over time.= -Invisibility= -Grants invisibility.= -Water Breathing= -Grants limitless breath underwater.= -Fire Resistance= -Grants immunity to damage from heat sources like fire.= -Weakness= -Weakness += -Strength= -Strength II= -Strength += -Try different combinations to create potions.= -No effect= - -A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect.= - -This particular arrow is tipped and will give an effect when it hits a player or mob.= - diff --git a/mods/ITEMS/mcl_potions/potions.lua b/mods/ITEMS/mcl_potions/potions.lua index fd9240b92..c8de4353e 100644 --- a/mods/ITEMS/mcl_potions/potions.lua +++ b/mods/ITEMS/mcl_potions/potions.lua @@ -1,5 +1,8 @@ local S = minetest.get_translator(minetest.get_current_modname()) ---local brewhelp = S("Try different combinations to create potions.") + +mcl_potions.registered_potions = {} +-- shorthand +local registered_potions = mcl_potions.registered_potions local function potion_image(colorstring, opacity) if not opacity then @@ -9,7 +12,7 @@ local function potion_image(colorstring, opacity) end local how_to_drink = S("Use the “Place” key to drink it.") -local potion_intro = S("Drinking a potion gives you a particular effect.") +local potion_intro = S("Drinking a potion gives you a particular effect or set of effects.") local function time_string(dur) if not dur then @@ -45,365 +48,297 @@ end -- ╚═╝░░░░░░╚════╝░░░░╚═╝░░░╚═╝░╚════╝░╚═╝░░╚══╝╚═════╝░ -function return_on_use(def, effect, dur) - return function (itemstack, user, pointed_thing) +local function generate_on_use(effects, color, on_use, custom_effect) + return function(itemstack, user, pointed_thing) if pointed_thing.type == "node" then if user and not user:get_player_control().sneak then - -- Use pointed node's on_rightclick function first, if present local node = minetest.get_node(pointed_thing.under) - if user and not user:get_player_control().sneak then - if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then - return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack - end + if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then + return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack end end elseif pointed_thing.type == "object" then return itemstack end - --def.on_use(user, effect, dur) -- Will do effect immediately but not reduce item count until eating delay ends which makes it exploitable by deliberately not finishing delay - -- Wrapper for handling mcl_hunger delayed eating - local name = user:get_player_name() - mcl_hunger.eat_internal[name]._custom_itemstack = itemstack -- Used as comparison to make sure the custom wrapper executes only when the same item is eaten - mcl_hunger.eat_internal[name]._custom_var = { + local player_name = user:get_player_name() + mcl_hunger.eat_internal[player_name]._custom_itemstack = itemstack -- Used as comparison to make sure the custom wrapper executes only when the same item is eaten + mcl_hunger.eat_internal[player_name]._custom_var = { user = user, - effect = effect, - dur = dur, + effects = effects, + on_use = on_use, + custom_effect = custom_effect, } - mcl_hunger.eat_internal[name]._custom_func = def.on_use - mcl_hunger.eat_internal[name]._custom_wrapper = function(name) + mcl_hunger.eat_internal[player_name]._custom_func = function(itemstack, user, effects, on_use, custom_effect) + local potency = itemstack:get_meta():get_int("mcl_potions:potion_potent") + local plus = itemstack:get_meta():get_int("mcl_potions:potion_plus") + local ef_level + local dur + for name, details in pairs(effects) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, plus) + if potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, potency) + end + else + dur = details.dur + end + if details.effect_stacks then + ef_level = ef_level + mcl_potions.get_effect_level(user, name) + end + mcl_potions.give_effect_by_level(name, user, ef_level, dur) + end - mcl_hunger.eat_internal[name]._custom_func( - mcl_hunger.eat_internal[name]._custom_var.user, - mcl_hunger.eat_internal[name]._custom_var.effect, - mcl_hunger.eat_internal[name]._custom_var.dur + if on_use then on_use(user, potency+1) end + if custom_effect then custom_effect(user, potency+1, plus) end + end + mcl_hunger.eat_internal[player_name]._custom_wrapper = function(player_name) + mcl_hunger.eat_internal[player_name]._custom_func( + mcl_hunger.eat_internal[player_name]._custom_itemstack, + mcl_hunger.eat_internal[player_name]._custom_var.user, + mcl_hunger.eat_internal[player_name]._custom_var.effects, + mcl_hunger.eat_internal[player_name]._custom_var.on_use, + mcl_hunger.eat_internal[player_name]._custom_var.custom_effect ) end - local old_name, old_count = itemstack:get_name(), itemstack:get_count() itemstack = minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) - if old_name ~= itemstack:get_name() or old_count ~= itemstack:get_count() then - mcl_potions._use_potion(itemstack, user, def.color) - end + if itemstack then mcl_potions._use_potion(user, color) end + return itemstack end end - -local function register_potion(def) - - local dur = mcl_potions.DURATION - - if def.is_inv then - dur = dur * mcl_potions.INV_FACTOR +-- API - registers a potion +-- required parameters in def: +-- name - string - potion name in code +-- optional parameters in def: +-- desc_prefix - translated string - part of visible potion name, comes before the word "Potion" +-- desc_suffix - translated string - part of visible potion name, comes after the word "Potion" +-- _tt - translated string - custom tooltip text +-- _dynamic_tt - function(level) - returns custom tooltip text dependent on potion level +-- _longdesc - translated string - text for in-game documentation +-- stack_max - int - max stack size - defaults to 1 +-- image - string - name of a custom texture of the potion icon +-- color - string - colorstring for potion icon when image is not defined - defaults to #0000FF +-- groups - table - item groups definition for the regular potion, not splash or lingering - +-- - must contain _mcl_potion=1 for tooltip to include dynamic_tt and effects +-- - defaults to {brewitem=1, food=3, can_eat_when_full=1, _mcl_potion=1} +-- nocreative - bool - adds a not_in_creative_inventory=1 group - defaults to false +-- _effect_list - table - all the effects dealt by the potion in the format of tables +-- -- the name of each sub-table should be a name of a registered effect, and fields can be the following: +-- -- -- uses_level - bool - whether the level of the potion affects the level of the effect - +-- -- -- - defaults to the uses_factor field of the effect definition +-- -- -- level - int - used as the effect level if uses_level is false and for lvl1 potions - defaults to 1 +-- -- -- level_scaling - int - used as the number of effect levels added per potion level - defaults to 1 - +-- -- -- - this has no effect if uses_level is false +-- -- -- dur - float - duration of the effect in seconds - defaults to mcl_potions.DURATION +-- -- -- dur_variable - bool - whether variants of the potion should have the length of this effect changed - +-- -- -- - defaults to true +-- -- -- - if at least one effect has this set to true, the potion has a "plus" variant +-- -- -- effect_stacks - bool - whether the effect stacks - defaults to false +-- uses_level - bool - whether the potion should come at different levels - +-- - defaults to true if uses_level is true for at least one effect, else false +-- drinkable - bool - defaults to true +-- has_splash - bool - defaults to true +-- has_lingering - bool - defaults to true +-- has_arrow - bool - defaults to false +-- has_potent - bool - whether there is a potent (e.g. II) variant - defaults to the value of uses_level +-- default_potent_level - int - potion level used for the default potent variant - defaults to 2 +-- default_extend_level - int - extention level (amount of +) used for the default extended variant - defaults to 1 +-- custom_on_use - function(user, level) - called when the potion is drunk, returns true on success +-- custom_effect - function(object, level, plus) - called when the potion effects are applied, returns true on success +-- custom_splash_effect - function(pos, level) - called when the splash potion explodes, returns true on success +-- custom_linger_effect - function(pos, radius, level) - called on the lingering potion step, returns true on success +function mcl_potions.register_potion(def) + local modname = minetest.get_current_modname() + local name = def.name + if name == nil then + error("Unable to register potion: name is nil") end - if def.name == "poison" or def.name == "regeneration" or def.name == "withering" then - dur = 45 + if type(name) ~= "string" then + error("Unable to register potion: name is not a string") end - - local on_use = nil - - if def.on_use then - on_use = return_on_use(def, def.effect, dur) - end - - local function get_tt(tt, effect, dur) - local _tt - if effect and def.is_dur then - _tt = perc_string(effect).." | "..time_string(dur) - if def.name == "poison" or def.name == "regeneration" or def.name == "withering" then - _tt = S("1 HP/@1s | @2", effect, time_string(dur)) - end - elseif def.name == "healing" or def.name == "harming" then - _tt = S("@1 HP", effect) - else - _tt = tt or time_string(dur) or S("No effect") - end - return _tt - end - - local function get_splash_fun(effect, sp_dur) - if def.is_dur then - return function(player, redx) def.on_use(player, effect, sp_dur*redx) end - elseif def.effect then - return function(player, redx) def.on_use(player, effect*redx, sp_dur) end - end - -- covers case of no effect (water, awkward, mundane) - return function() end - end - - local function get_lingering_fun(effect, ling_dur) - if def.is_dur then - return function(player) def.on_use(player, effect, ling_dur) end - elseif def.effect then - return function(player) def.on_use(player, effect*0.5, ling_dur) end - end - -- covers case of no effect (water, awkward, mundane) - return function() end - end - - local function get_arrow_fun(effect, dur) - if def.is_dur then - return function(player) def.on_use(player, effect, dur) end - elseif def.effect then - return function(player) def.on_use(player, effect, dur) end - end - -- covers case of no effect (water, awkward, mundane) - return function() end - end - - local desc - if not def.no_potion then - if def.description_potion then - desc = def.description_potion - else - desc = S("@1 Potion", def.description) - end + local pdef = {} + if def.desc_prefix and def.desc_suffix then + pdef.description = S("@1 Potion @2", def.desc_prefix, def.desc_suffix) + elseif def.desc_prefix then + pdef.description = S("@1 Potion", def.desc_prefix) + elseif def.desc_suffix then + pdef.description = S("Potion @1", def.desc_suffix) else - desc = def.description + pdef.description = S("Strange Potion") end + pdef._tt_help = def._tt + pdef._dynamic_tt = def._dynamic_tt local potion_longdesc = def._longdesc - if not def.no_effect then + if def._effect_list then potion_longdesc = potion_intro .. "\n" .. def._longdesc end - local potion_usagehelp - local basic_potion_tt - if def.name ~= "dragon_breath" then - potion_usagehelp = how_to_drink - basic_potion_tt = get_tt(def._tt, def.effect, dur) - end + pdef._doc_items_longdesc = potion_longdesc + if def.drinkable ~= false then pdef._doc_items_usagehelp = how_to_drink end + pdef.stack_max = def.stack_max or 1 + local color = def.color or "#0000FF" + pdef.inventory_image = def.image or potion_image(color) + pdef.wield_image = pdef.inventory_image + pdef.groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1, _mcl_potion=1} + if def.nocreative then pdef.groups.not_in_creative_inventory = 1 end - minetest.register_craftitem("mcl_potions:"..def.name, { - description = desc, - _tt_help = basic_potion_tt, - _doc_items_longdesc = potion_longdesc, - _doc_items_usagehelp = potion_usagehelp, - stack_max = def.stack_max or 1, - inventory_image = def.image or potion_image(def.color), - wield_image = def.image or potion_image(def.color), - groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1, bottle=1}, - on_place = on_use, - on_secondary_use = on_use, - }) - - -- Register Splash and Lingering - local splash_dur = dur * mcl_potions.SPLASH_FACTOR - local ling_dur = dur * mcl_potions.LINGERING_FACTOR - - local splash_def = { - tt = get_tt(def._tt, def.effect, splash_dur), - longdesc = def._longdesc, - potion_fun = get_splash_fun(def.effect, splash_dur), - no_effect = def.no_effect, - instant = def.instant, - } - - local ling_def - if def.name == "healing" or def.name == "harming" then - ling_def = { - tt = get_tt(def._tt, def.effect*mcl_potions.LINGERING_FACTOR, ling_dur), - longdesc = def._longdesc, - potion_fun = get_lingering_fun(def.effect*mcl_potions.LINGERING_FACTOR, ling_dur), - no_effect = def.no_effect, - instant = def.instant, - } - else - ling_def = { - tt = get_tt(def._tt, def.effect, ling_dur), - longdesc = def._longdesc, - potion_fun = get_lingering_fun(def.effect, ling_dur), - no_effect = def.no_effect, - instant = def.instant, - } - end - - local arrow_def = { - tt = get_tt(def._tt, def.effect, dur/8.), - longdesc = def._longdesc, - potion_fun = get_arrow_fun(def.effect, dur/8.), - no_effect = def.no_effect, - instant = def.instant, - } - - if def.color and not def.no_throwable then - local desc - if def.description_splash then - desc = def.description_splash - else - desc = S("Splash @1 Potion", def.description) - end - mcl_potions.register_splash(def.name, desc, def.color, splash_def) - if def.description_lingering then - desc = def.description_lingering - else - desc = S("Lingering @1 Potion", def.description) - end - mcl_potions.register_lingering(def.name, desc, def.color, ling_def) - if not def.no_arrow then - mcl_potions.register_arrow(def.name, S("Arrow of @1", def.description), def.color, arrow_def) - end - end - - if def.is_II then - - local desc_mod = S(" II") - - local effect_II - if def.name == "healing" or def.name == "harming" then - effect_II = def.effect*mcl_potions.II_FACTOR - elseif def.name == "poison" or def.name == "regeneration" then - effect_II = 1.2 - elseif def.name == "withering" then - effect_II = 2 - else - effect_II = def.effect^mcl_potions.II_FACTOR - end - - local dur_2 = dur / mcl_potions.II_FACTOR - if def.name == "poison" then dur_2 = dur_2 - 1 end - - if def.name == "slowness" then - dur_2 = 20 - effect_II = 0.40 - desc_mod = S(" IV") - end - - on_use = return_on_use(def, effect_II, dur_2) - - minetest.register_craftitem("mcl_potions:"..def.name.."_2", { - description = S("@1 Potion@2", def.description, desc_mod), - _tt_help = get_tt(def._tt_2, effect_II, dur_2), - _doc_items_longdesc = potion_longdesc, - _doc_items_usagehelp = potion_usagehelp, - stack_max = def.stack_max or 1, - inventory_image = def.image or potion_image(def.color), - wield_image = def.image or potion_image(def.color), - groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1, bottle=1}, - on_place = on_use, - on_secondary_use = on_use, - }) - - -- Register Splash and Lingering - local splash_dur_2 = dur_2 * mcl_potions.SPLASH_FACTOR - local ling_dur_2 = dur_2 * mcl_potions.LINGERING_FACTOR - - local splash_def_2 - if def.name == "healing" then - splash_def_2 = { - tt = get_tt(def._tt_2, 7, splash_dur_2), - longdesc = def._longdesc, - potion_fun = get_splash_fun(7, splash_dur_2), - no_effect = def.no_effect, - instant = def.instant, - } - else - splash_def_2 = { - tt = get_tt(def._tt_2, effect_II, splash_dur_2), - longdesc = def._longdesc, - potion_fun = get_splash_fun(effect_II, splash_dur_2), - no_effect = def.no_effect, - instant = def.instant, - } - end - - - local ling_def_2 - if def.name == "healing" or def.name == "harming" then - ling_def_2 = { - tt = get_tt(def._tt_2, effect_II*mcl_potions.LINGERING_FACTOR, ling_dur_2), - longdesc = def._longdesc, - potion_fun = get_lingering_fun(effect_II*mcl_potions.LINGERING_FACTOR, ling_dur_2), - no_effect = def.no_effect, - instant = def.instant, - } - else - ling_def_2 = { - tt = get_tt(def._tt_2, effect_II, ling_dur_2), - longdesc = def._longdesc, - potion_fun = get_lingering_fun(effect_II, ling_dur_2), - no_effect = def.no_effect, - instant = def.instant, - } - end - - local arrow_def_2 = { - tt = get_tt(def._tt_2, effect_II, dur_2/8.), - longdesc = def._longdesc, - potion_fun = get_arrow_fun(effect_II, dur_2/8.), - no_effect = def.no_effect, - instant = def.instant, - } - - if def.color and not def.no_throwable then - mcl_potions.register_splash(def.name.."_2", S("Splash @1@2 Potion", def.description, desc_mod), def.color, splash_def_2) - mcl_potions.register_lingering(def.name.."_2", S("Lingering @1@2 Potion", def.description, desc_mod), def.color, ling_def_2) - if not def.no_arrow then - mcl_potions.register_arrow(def.name.."_2", S("Arrow of @1@2", def.description, desc_mod), def.color, arrow_def_2) + pdef._effect_list = {} + local effect + local uses_level = false + local has_plus = false + if def._effect_list then + for name, details in pairs(def._effect_list) do + effect = mcl_potions.registered_effects[name] + if effect then + local ulvl + if details.uses_level ~= nil then ulvl = details.uses_level + else ulvl = effect.uses_factor end + if ulvl then uses_level = true end + local durvar = true + if details.dur_variable ~= nil then durvar = details.dur_variable end + if durvar then has_plus = true end + pdef._effect_list[name] = { + uses_level = ulvl, + level = details.level or 1, + level_scaling = details.level_scaling or 1, + dur = details.dur or mcl_potions.DURATION, + dur_variable = durvar, + effect_stacks = details.effect_stacks and true or false + } + else + error("Unable to register potion: effect not registered") end end + end + if def.uses_level ~= nil then uses_level = def.uses_level end + pdef.uses_level = uses_level + if def.has_potent ~= nil then pdef.has_potent = def.has_potent + else pdef.has_potent = uses_level end + pdef._default_potent_level = def.default_potent_level or 2 + pdef._default_extend_level = def.default_extend_level or 1 + pdef.has_plus = has_plus + local on_use + if def.drinkable ~= false then + on_use = generate_on_use(pdef._effect_list, color, def.custom_on_use, def.custom_effect) + end + pdef.on_place = on_use + pdef.on_secondary_use = on_use + local internal_def = table.copy(pdef) + minetest.register_craftitem(modname..":"..name, pdef) + + if def.has_splash or def.has_splash == nil then + local splash_desc = S("Splash @1", pdef.description) + local sdef = {} + sdef._tt = def._tt + sdef._dynamic_tt = def._dynamic_tt + sdef._longdesc = def._longdesc + sdef.nocreative = def.nocreative + sdef.stack_max = pdef.stack_max + sdef._effect_list = pdef._effect_list + sdef.uses_level = uses_level + sdef.has_potent = pdef.has_potent + sdef.has_plus = has_plus + sdef._default_potent_level = pdef._default_potent_level + sdef._default_extend_level = pdef._default_extend_level + sdef.custom_effect = def.custom_effect + sdef.on_splash = def.custom_splash_effect + if not def._effect_list then sdef.instant = true end + mcl_potions.register_splash(name, splash_desc, color, sdef) + internal_def.has_splash = true end - if def.is_plus then - - local dur_pl = dur * mcl_potions.PLUS_FACTOR - if def.name == "poison" or def.name == "regeneration" or def.name == "withering" then - dur_pl = 90 - end - - on_use = return_on_use(def, def.effect, dur_pl) - - minetest.register_craftitem("mcl_potions:"..def.name.."_plus", { - description = S("@1 + Potion", def.description), - _tt_help = get_tt(def._tt_plus, def.effect, dur_pl), - _doc_items_longdesc = potion_longdesc, - _doc_items_usagehelp = potion_usagehelp, - stack_max = 1, - inventory_image = def.image or potion_image(def.color), - wield_image = def.image or potion_image(def.color), - groups = def.groups or {brewitem=1, food=3, can_eat_when_full=1, bottle=1}, - on_place = on_use, - on_secondary_use = on_use, - }) - - -- Register Splash - local splash_dur_pl = dur_pl * mcl_potions.SPLASH_FACTOR - local ling_dur_pl = dur_pl * mcl_potions.LINGERING_FACTOR - - local splash_def_pl = { - tt = get_tt(def._tt_plus, def.effect, splash_dur_pl), - longdesc = def._longdesc, - potion_fun = get_splash_fun(def.effect, splash_dur_pl), - no_effect = def.no_effect, - instant = def.instant, - } - local ling_def_pl = { - tt = get_tt(def._tt_plus, def.effect, ling_dur_pl), - longdesc = def._longdesc, - potion_fun = get_lingering_fun(def.effect, ling_dur_pl), - no_effect = def.no_effect, - instant = def.instant, - } - local arrow_def_pl = { - tt = get_tt(def._tt_pl, def.effect, dur_pl/8.), - longdesc = def._longdesc, - potion_fun = get_arrow_fun(def.effect, dur_pl/8.), - no_effect = def.no_effect, - instant = def.instant, - } - if def.color and not def.no_throwable then - mcl_potions.register_splash(def.name.."_plus", S("Splash @1 + Potion", def.description), def.color, splash_def_pl) - mcl_potions.register_lingering(def.name.."_plus", S("Lingering @1 + Potion", def.description), def.color, ling_def_pl) - if not def.no_arrow then - mcl_potions.register_arrow(def.name.."_plus", S("Arrow of @1 +", def.description), def.color, arrow_def_pl) - end - end - + if def.has_lingering or def.has_lingering == nil then + local ling_desc = S("Lingering @1", pdef.description) + local ldef = {} + ldef._tt = def._tt + ldef._dynamic_tt = def._dynamic_tt + ldef._longdesc = def._longdesc + ldef.nocreative = def.nocreative + ldef.stack_max = pdef.stack_max + ldef._effect_list = pdef._effect_list + ldef.uses_level = uses_level + ldef.has_potent = pdef.has_potent + ldef.has_plus = has_plus + ldef._default_potent_level = pdef._default_potent_level + ldef._default_extend_level = pdef._default_extend_level + ldef.custom_effect = def.custom_effect + ldef.on_splash = def.custom_splash_effect + ldef.while_lingering = def.custom_linger_effect + if not def._effect_list then ldef.instant = true end + mcl_potions.register_lingering(name, ling_desc, color, ldef) + internal_def.has_lingering = true end + if def.has_arrow then + local arr_desc + if def.desc_prefix and def.desc_suffix then + arr_desc = S("@1 Arrow @2", def.desc_prefix, def.desc_suffix) + elseif def.desc_prefix then + arr_desc = S("@1 Arrow", def.desc_prefix) + elseif def.desc_suffix then + arr_desc = S("Arrow @1", def.desc_suffix) + else + arr_desc = S("Strange Tipped Arrow") + end + local adef = {} + adef._tt = def._tt + adef._dynamic_tt = def._dynamic_tt + adef._longdesc = def._longdesc + adef.nocreative = def.nocreative + adef._effect_list = pdef._effect_list + adef.uses_level = uses_level + adef.has_potent = pdef.has_potent + adef.has_plus = has_plus + adef._default_potent_level = pdef._default_potent_level + adef._default_extend_level = pdef._default_extend_level + adef.custom_effect = def.custom_effect + if not def._effect_list then adef.instant = true end + mcl_potions.register_arrow(name, arr_desc, color, adef) + internal_def.has_arrow = true + end + + mcl_potions.registered_potions[modname..":"..name] = internal_def end +mcl_potions.register_potion({ + name = "trolling", + desc_prefix = S("Mighty"), + desc_suffix = S("of Trolling"), + _tt = "trololo", + _dynamic_tt = function(level) + return "trolololoooololo" + end, + _longdesc = "Trolololololo", + stack_max = 2, + color = "#00AA00", + nocreative = true, + _effect_list = { + night_vision = {}, + strength = {}, + swiftness = { + uses_level = false, + level = 2, + }, + poison = { + dur = 10, + }, + }, + default_potent_level = 5, + default_extend_level = 3, + custom_splash_effect = mcl_potions._extinguish_nearby_fire, + has_arrow = true, +}) + + -- ██████╗░░█████╗░████████╗██╗░█████╗░███╗░░██╗ -- ██╔══██╗██╔══██╗╚══██╔══╝██║██╔══██╗████╗░██║ @@ -420,344 +355,525 @@ end -- ╚═════╝░╚══════╝╚═╝░░░░░╚═╝╚═╝░░╚══╝╚═╝░░░╚═╝░░░╚═╝░╚════╝░╚═╝░░╚══╝╚═════╝░ -local awkward_def = { - name = "awkward", - description_potion = S("Awkward Potion"), - description_splash = S("Awkward Splash Potion"), - description_lingering = S("Awkward Lingering Potion"), - no_arrow = true, - no_effect = true, - _tt = S("No effect"), - _longdesc = S("Has an awkward taste and is used for brewing potions."), - color = "#0000FF", - groups = {brewitem=1, food=3, can_eat_when_full=1, bottle=1}, - on_use = minetest.item_eat(0, "mcl_potions:glass_bottle"), -} - -local mundane_def = { - name = "mundane", - description_potion = S("Mundane Potion"), - description_splash = S("Mundane Splash Potion"), - description_lingering = S("Mundane Lingering Potion"), - no_arrow = true, - no_effect = true, - _tt = S("No effect"), - _longdesc = S("Has a terrible taste and is not useful for brewing potions."), - color = "#0000FF", - on_use = minetest.item_eat(0, "mcl_potions:glass_bottle"), -} - -local thick_def = { - name = "thick", - description_potion = S("Thick Potion"), - description_splash = S("Thick Splash Potion"), - description_lingering = S("Thick Lingering Potion"), - no_arrow = true, - no_effect = true, - _tt = S("No effect"), - _longdesc = S("Has a bitter taste and is not useful for brewing potions."), - color = "#0000FF", - on_use = minetest.item_eat(0, "mcl_potions:glass_bottle"), -} - -local dragon_breath_def = { - name = "dragon_breath", +minetest.register_craftitem("mcl_potions:dragon_breath", { description = S("Dragon's Breath"), - no_arrow = true, - no_potion = true, - no_throwable = true, - no_effect = true, _longdesc = S("This item is used in brewing and can be combined with splash potions to create lingering potions."), image = "mcl_potions_dragon_breath.png", groups = { brewitem = 1, bottle = 1 }, - on_use = nil, stack_max = 64, -} +}) -local healing_def = { +mcl_potions.register_potion({ + name = "awkward", + desc_prefix = S("Awkward"), + _tt = S("No effect"), + _longdesc = S("Has an awkward taste and is used for brewing potions."), + color = "#0000FF", +}) + +mcl_potions.register_potion({ + name = "mundane", + desc_prefix = S("Mundane"), + _tt = S("No effect"), + _longdesc = S("Has a terrible taste and is not really useful for brewing potions."), + color = "#0000FF", +}) + +mcl_potions.register_potion({ + name = "thick", + desc_prefix = S("Thick"), + _tt = S("No effect"), + _longdesc = S("Has a bitter taste and may be useful for brewing potions."), + color = "#0000FF", +}) + +mcl_potions.register_potion({ name = "healing", - description = S("Healing"), - _tt = S("+4 HP"), - _tt_2 = S("+8 HP"), + desc_suffix = S("of Healing"), + _dynamic_tt = function(level) + return S("+@1 HP", 4 * level) + end, _longdesc = S("Instantly heals."), color = "#F82423", - effect = 4, - instant = true, - on_use = mcl_potions.healing_func, - is_II = true, -} + uses_level = true, + has_arrow = true, + custom_effect = function(object, level) + return mcl_potions.healing_func(object, 4 * level) + end, +}) - -local harming_def = { +mcl_potions.register_potion({ name = "harming", - description = S("Harming"), - _tt = S("-6 HP"), - _tt_II = S("-12 HP"), + desc_suffix = S("of Harming"), + _dynamic_tt = function(level) + return S("-@1 HP", 6 * level) + end, _longdesc = S("Instantly deals damage."), color = "#430A09", - effect = -6, - instant = true, - on_use = mcl_potions.healing_func, - is_II = true, - is_inv = true, -} + uses_level = true, + has_arrow = true, + custom_effect = function(object, level) + return mcl_potions.healing_func(object, -6 * level) + end, +}) -local night_vision_def = { +mcl_potions.register_potion({ name = "night_vision", - description = S("Night Vision"), + desc_suffix = S("of Night Vision"), _tt = nil, _longdesc = S("Increases the perceived brightness of light under a dark sky."), color = "#1F1FA1", - effect = nil, - is_dur = true, - on_use = mcl_potions.night_vision_func, - is_plus = true, -} + _effect_list = { + night_vision = {}, + }, + has_arrow = true, +}) -local swiftness_def = { +mcl_potions.register_potion({ name = "swiftness", - description = S("Swiftness"), + desc_suffix = S("of Swiftness"), _tt = nil, _longdesc = S("Increases walking speed."), color = "#7CAFC6", - effect = 1.2, - is_dur = true, - on_use = mcl_potions.swiftness_func, - is_II = true, - is_plus = true, -} + _effect_list = { + swiftness = {}, + }, + has_arrow = true, +}) -local slowness_def = { +mcl_potions.register_potion({ name = "slowness", - description = S("Slowness"), + desc_suffix = S("of Slowness"), _tt = nil, _longdesc = S("Decreases walking speed."), color = "#5A6C81", - effect = 0.85, - is_dur = true, - on_use = mcl_potions.swiftness_func, - is_II = true, - is_plus = true, - is_inv = true, -} + _effect_list = { + slowness = {dur=mcl_potions.DURATION_INV}, + }, + default_potent_level = 4, + has_arrow = true, +}) -local leaping_def = { +mcl_potions.register_potion({ name = "leaping", - description = S("Leaping"), + desc_suffix = S("of Leaping"), _tt = nil, _longdesc = S("Increases jump strength."), color = "#22FF4C", - effect = 1.15, - is_dur = true, - on_use = mcl_potions.leaping_func, - is_II = true, - is_plus = true, -} + _effect_list = { + leaping = {}, + }, + has_arrow = true, +}) -local withering_def = { +mcl_potions.register_potion({ name = "withering", - description = S("Withering"), + desc_suffix = S("of Withering"), _tt = nil, _longdesc = S("Applies the withering effect which deals damage at a regular interval and can kill."), - color = "#000000", - effect = 4, - is_dur = true, - on_use = mcl_potions.withering_func, - is_II = true, - is_plus = true, - is_inv = true, -} + color = "#292929", + _effect_list = { + withering = {dur=mcl_potions.DURATION_POISON}, + }, + has_arrow = true, +}) -local poison_def = { +mcl_potions.register_potion({ name = "poison", - description = S("Poison"), + desc_suffix = S("of Poison"), _tt = nil, _longdesc = S("Applies the poison effect which deals damage at a regular interval."), color = "#4E9331", - effect = 2.5, - is_dur = true, - on_use = mcl_potions.poison_func, - is_II = true, - is_plus = true, - is_inv = true, -} + _effect_list = { + poison = {dur=mcl_potions.DURATION_POISON}, + }, + has_arrow = true, +}) -local regeneration_def = { +mcl_potions.register_potion({ name = "regeneration", - description = S("Regeneration"), + desc_suffix = S("of Regeneration"), _tt = nil, _longdesc = S("Regenerates health over time."), color = "#CD5CAB", - effect = 2.5, - is_dur = true, - on_use = mcl_potions.regeneration_func, - is_II = true, - is_plus = true, -} + _effect_list = { + regeneration = {dur=mcl_potions.DURATION_POISON}, + }, + has_arrow = true, +}) -local invisibility_def = { +mcl_potions.register_potion({ name = "invisibility", - description = S("Invisibility"), + desc_suffix = S("of Invisibility"), _tt = nil, _longdesc = S("Grants invisibility."), color = "#7F8392", - is_dur = true, - on_use = mcl_potions.invisiblility_func, - is_plus = true, -} + _effect_list = { + invisibility = {}, + }, + has_arrow = true, +}) -local water_breathing_def = { +mcl_potions.register_potion({ name = "water_breathing", - description = S("Water Breathing"), + desc_suffix = S("of Water Breathing"), _tt = nil, _longdesc = S("Grants limitless breath underwater."), color = "#2E5299", - is_dur = true, - on_use = mcl_potions.water_breathing_func, - is_plus = true, -} + _effect_list = { + water_breathing = {}, + }, + has_arrow = true, +}) -local fire_resistance_def = { +mcl_potions.register_potion({ name = "fire_resistance", - description = S("Fire Resistance"), + desc_suffix = S("of Fire Resistance"), _tt = nil, _longdesc = S("Grants immunity to damage from heat sources like fire."), color = "#E49A3A", - is_dur = true, - on_use = mcl_potions.fire_resistance_func, - is_plus = true, + _effect_list = { + fire_resistance = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "strength", + desc_suffix = S("of Strength"), + _tt = nil, + _longdesc = S("Increases attack power."), + color = "#932423", + _effect_list = { + strength = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "weakness", + desc_suffix = S("of Weakness"), + _tt = nil, + _longdesc = S("Decreases attack power."), + color = "#484D48", + _effect_list = { + weakness = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "slow_falling", + desc_suffix = S("of Slow Falling"), + _tt = nil, + _longdesc = S("Instead of falling, you descend gracefully."), + color = "#ACCCFF", + _effect_list = { + slow_falling = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "levitation", + desc_suffix = S("of Levitation"), + _tt = nil, + _longdesc = S("Floats body slowly upwards."), + color = "#420E7E", + _effect_list = { + levitation = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "darkness", + desc_suffix = S("of Darkness"), + _tt = nil, + _longdesc = S("Surrounds with darkness."), + color = "#000000", + _effect_list = { + darkness = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "glowing", + desc_suffix = S("of Glowing"), + _tt = nil, + _longdesc = S("Highlights for others to see."), + color = "#FFFF77", + _effect_list = { + glowing = {}, + }, + has_arrow = false, -- TODO add a spectral arrow instead (in mcl_bows?) +}) + +mcl_potions.register_potion({ + name = "health_boost", + desc_suffix = S("of Health Boost"), + _tt = nil, + _longdesc = S("Increases health."), + color = "#BE1919", + _effect_list = { + health_boost = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "absorption", + desc_suffix = S("of Absorption"), + _tt = nil, + _longdesc = S("Absorbs some incoming damage."), + color = "#B59500", + _effect_list = { + absorption = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "resistance", + desc_suffix = S("of Resistance"), + _tt = nil, + _longdesc = S("Decreases damage taken."), + color = "#2552A5", + _effect_list = { + resistance = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "stone_cloak", + desc_suffix = S("of Stone Cloak"), + _tt = nil, + _longdesc = S("Decreases damage taken at the cost of speed."), + color = "#255235", + _effect_list = { + resistance = { + level = 3, + dur = 20, + }, + slowness = { + level = 4, + level_scaling = 2, + dur = 20, + }, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "luck", + desc_suffix = S("of Luck"), + _tt = nil, + _longdesc = S("Increases luck."), + color = "#7BFF42", + _effect_list = { + luck = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "bad_luck", + desc_suffix = S("of Bad Luck"), + _tt = nil, + _longdesc = S("Decreases luck."), + color = "#887343", + _effect_list = { + bad_luck = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "frost", + desc_suffix = S("of Frost"), + _tt = nil, + _longdesc = S("Freezes..."), + color = "#5B7DAA", + _effect_list = { + frost = { + dur = mcl_potions.DURATION_POISON, + effect_stacks = true, + }, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "blindness", + desc_suffix = S("of Blindness"), + _tt = nil, + _longdesc = S("Impairs sight."), + color = "#586868", + _effect_list = { + blindness = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "nausea", + desc_suffix = S("of Nausea"), + _tt = nil, + _longdesc = S("Disintegrates senses."), + color = "#715C7F", + _effect_list = { + nausea = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "food_poisoning", + desc_suffix = S("of Food Poisoning"), + _tt = nil, + _longdesc = S("Moves bowels too fast."), + color = "#83A061", + _effect_list = { + food_poisoning = { + dur = mcl_potions.DURATION_POISON, + effect_stacks = true, + }, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "saturation", + desc_suffix = S("of Saturation"), + _tt = nil, + _longdesc = S("Satisfies hunger."), + color = "#CEAE29", + _effect_list = { + saturation = {dur=mcl_potions.DURATION_POISON}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "haste", + desc_suffix = S("of Haste"), + _tt = nil, + _longdesc = S("Increases digging and attack speed."), + color = "#FFFF00", + _effect_list = { + haste = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "fatigue", + desc_suffix = S("of Fatigue"), + _tt = nil, + _longdesc = S("Decreases digging and attack speed."), + color = "#64643D", + _effect_list = { + fatigue = {}, + }, + has_arrow = true, +}) + +mcl_potions.register_potion({ + name = "ominous", + desc_prefix = S("Ominous"), + _tt = nil, + _longdesc = S("Attracts danger."), + image = table.concat({ + "(mcl_potions_potion_overlay.png^[colorize:red:100)", + "^mcl_potions_splash_overlay.png^[colorize:black:100", + "^mcl_potions_potion_bottle.png", + }), + _effect_list = { + bad_omen = {dur = 6000}, + }, + has_splash = false, + has_lingering = false, +}) + + + + +-- COMPAT CODE +local function replace_legacy_potion(itemstack) + local name = itemstack:get_name() + local suffix = "" + local bare_name = name:match("^(.+)_splash$") + if bare_name then + suffix = "_splash" + else + bare_name = name:match("^(.+)_lingering$") + if bare_name then + suffix = "_lingering" + else + bare_name = name:match("^(.+)_arrow$") + if bare_name then + suffix = "_arrow" + else + bare_name = name + end + end + end + local new_name = bare_name:match("^(.+)_plus$") + local new_stack + if new_name then + new_stack = ItemStack(new_name..suffix) + new_stack:get_meta():set_int("mcl_potions:potion_plus", + registered_potions[new_name]._default_extend_level) + new_stack:set_count(itemstack:get_count()) + tt.reload_itemstack_description(new_stack) + end + new_name = bare_name:match("^(.+)_2$") + if new_name then + new_stack = ItemStack(new_name..suffix) + new_stack:get_meta():set_int("mcl_potions:potion_potent", + registered_potions[new_name]._default_potent_level-1) + new_stack:set_count(itemstack:get_count()) + tt.reload_itemstack_description(new_stack) + end + return new_stack +end +local compat = "mcl_potions:compat_potion" +local compat_arrow = "mcl_potions:compat_arrow" +minetest.register_craftitem(compat, { + description = S("Unknown Potion"), + _tt_help = S("Right-click to identify"), + image = "mcl_potions_potion_overlay.png^[colorize:#00F:127^mcl_potions_potion_bottle.png^vl_unknown.png", + on_secondary_use = replace_legacy_potion, + on_place = replace_legacy_potion, +}) +minetest.register_craftitem(compat_arrow, { + description = S("Unknown Tipped Arrow"), + _tt_help = S("Right-click to identify"), + image = "mcl_bows_arrow_inv.png^(mcl_potions_arrow_inv.png^[colorize:#FFF:100)^vl_unknown.png", + on_secondary_use = replace_legacy_potion, + on_place = replace_legacy_potion, +}) + +local old_potions_plus = { + "fire_resistance", "water_breathing", "invisibility", "regeneration", "poison", + "withering", "leaping", "slowness", "swiftness", "night_vision" +} +local old_potions_2 = { + "healing", "harming", "swiftness", "slowness", "leaping", + "withering", "poison", "regeneration" } - - -local defs = { awkward_def, mundane_def, thick_def, dragon_breath_def, - healing_def, harming_def, night_vision_def, swiftness_def, - slowness_def, leaping_def, withering_def, poison_def, regeneration_def, - invisibility_def, water_breathing_def, fire_resistance_def} - -for _, def in ipairs(defs) do - register_potion(def) +for _, name in pairs(old_potions_2) do + minetest.register_alias("mcl_potions:" .. name .. "_2", compat) + minetest.register_alias("mcl_potions:" .. name .. "_2_splash", compat) + minetest.register_alias("mcl_potions:" .. name .. "_2_lingering", compat) + minetest.register_alias("mcl_potions:" .. name .. "_2_arrow", compat_arrow) +end +for _, name in pairs(old_potions_plus) do + minetest.register_alias("mcl_potions:" .. name .. "_plus", compat) + minetest.register_alias("mcl_potions:" .. name .. "_plus_splash", compat) + minetest.register_alias("mcl_potions:" .. name .. "_plus_lingering", compat) + minetest.register_alias("mcl_potions:" .. name .. "_plus_arrow", compat_arrow) end - - - - --- minetest.register_craftitem("mcl_potions:weakness", { --- description = S("Weakness"), --- _tt_help = TODO, --- _doc_items_longdesc = brewhelp, --- wield_image = potion_image("#484D48"), --- inventory_image = potion_image("#484D48"), --- groups = { brewitem=1, food=3, can_eat_when_full=1 }, --- stack_max = 1, --- --- on_place = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, -4, mcl_potions.DURATION*mcl_potions.INV_FACTOR) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#484D48") --- return itemstack --- end, --- --- on_secondary_use = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, -4, mcl_potions.DURATION*mcl_potions.INV_FACTOR) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#484D48") --- return itemstack --- end --- }) --- --- minetest.register_craftitem("mcl_potions:weakness_plus", { --- description = S("Weakness +"), --- _tt_help = TODO, --- _doc_items_longdesc = brewhelp, --- wield_image = potion_image("#484D48"), --- inventory_image = potion_image("#484D48"), --- groups = { brewitem=1, food=3, can_eat_when_full=1 }, --- stack_max = 1, --- --- on_place = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, -4, mcl_potions.DURATION_2*mcl_potions.INV_FACTOR) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#484D48") --- return itemstack --- end, --- --- on_secondary_use = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, -4, mcl_potions.DURATION_2*mcl_potions.INV_FACTOR) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#484D48") --- return itemstack --- end --- }) --- --- minetest.register_craftitem("mcl_potions:strength", { --- description = S("Strength"), --- _tt_help = TODO, --- _doc_items_longdesc = brewhelp, --- wield_image = potion_image("#932423"), --- inventory_image = potion_image("#932423"), --- groups = { brewitem=1, food=3, can_eat_when_full=1 }, --- stack_max = 1, --- --- on_place = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, 3, mcl_potions.DURATION) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#932423") --- return itemstack --- end, --- --- on_secondary_use = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, 3, mcl_potions.DURATION) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#932423") --- return itemstack --- end --- }) --- --- minetest.register_craftitem("mcl_potions:strength_2", { --- description = S("Strength II"), --- _tt_help = TODO, --- _doc_items_longdesc = brewhelp, --- wield_image = potion_image("#932423"), --- inventory_image = potion_image("#932423"), --- groups = { brewitem=1, food=3, can_eat_when_full=1 }, --- stack_max = 1, --- --- on_place = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, 6, mcl_potions.DURATION_2) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#932423") --- return itemstack --- end, --- --- on_secondary_use = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, 6, mcl_potions.DURATION_2) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#932423") --- return itemstack --- end --- }) --- --- minetest.register_craftitem("mcl_potions:strength_plus", { --- description = S("Strength +"), --- _tt_help = TODO, --- _doc_items_longdesc = brewhelp, --- wield_image = potion_image("#932423"), --- inventory_image = potion_image("#932423"), --- groups = { brewitem=1, food=3, can_eat_when_full=1 }, --- stack_max = 1, --- --- on_place = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, 3, mcl_potions.DURATION_PLUS) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#932423") --- return itemstack --- end, --- --- on_secondary_use = function(itemstack, user, pointed_thing) --- mcl_potions.weakness_func(user, 3, mcl_potions.DURATION_PLUS) --- minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing) --- mcl_potions._use_potion(itemstack, user, "#932423") --- return itemstack --- end --- }) diff --git a/mods/ITEMS/mcl_potions/splash.lua b/mods/ITEMS/mcl_potions/splash.lua index 0b8aedeab..3b9261458 100644 --- a/mods/ITEMS/mcl_potions/splash.lua +++ b/mods/ITEMS/mcl_potions/splash.lua @@ -13,20 +13,30 @@ end function mcl_potions.register_splash(name, descr, color, def) local id = "mcl_potions:"..name.."_splash" - local longdesc = def.longdesc + local longdesc = def._longdesc if not def.no_effect then - longdesc = S("A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect.") - if def.longdesc then - longdesc = longdesc .. "\n" .. def.longdesc + longdesc = S("A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect or a set of status effects.") + if def._longdesc then + longdesc = longdesc .. "\n" .. def._longdesc end end + local groups = {brewitem=1, bottle=1, splash_potion=1, _mcl_potion=1} + if def.nocreative then groups.not_in_creative_inventory = 1 end minetest.register_craftitem(id, { description = descr, - _tt_help = def.tt, + _tt_help = def._tt, + _dynamic_tt = def._dynamic_tt, _doc_items_longdesc = longdesc, _doc_items_usagehelp = S("Use the “Punch” key to throw it."), + stack_max = def.stack_max, + _effect_list = def._effect_list, + uses_level = def.uses_level, + has_potent = def.has_potent, + has_plus = def.has_plus, + _default_potent_level = def._default_potent_level, + _default_extend_level = def._default_extend_level, inventory_image = splash_image(color), - groups = {brewitem=1, not_in_creative_inventory=0, bottle=1}, + groups = groups, on_use = function(item, placer, pointed_thing) local velocity = 10 local dir = placer:get_look_dir(); @@ -35,7 +45,11 @@ function mcl_potions.register_splash(name, descr, color, def) local obj = minetest.add_entity({x=pos.x+dir.x,y=pos.y+2+dir.y,z=pos.z+dir.z}, id.."_flying") obj:set_velocity({x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}) obj:set_acceleration({x=dir.x*-3, y=-9.8, z=dir.z*-3}) - obj:get_luaentity()._thrower = placer:get_player_name() + local ent = obj:get_luaentity() + ent._thrower = placer:get_player_name() + ent._potency = item:get_meta():get_int("mcl_potions:potion_potent") + ent._plus = item:get_meta():get_int("mcl_potions:potion_plus") + ent._effect_list = def._effect_list if not minetest.is_creative_enabled(placer:get_player_name()) then item:take_item() end @@ -50,6 +64,10 @@ function mcl_potions.register_splash(name, descr, color, def) local velocity = 22 obj:set_velocity({x=dropdir.x*velocity,y=dropdir.y*velocity,z=dropdir.z*velocity}) obj:set_acceleration({x=dropdir.x*-3, y=-9.8, z=dropdir.z*-3}) + local ent = obj:get_luaentity() + ent._potency = item:get_meta():get_int("mcl_potions:potion_potent") + ent._plus = item:get_meta():get_int("mcl_potions:potion_plus") + ent._effect_list = def._effect_list end }) @@ -103,10 +121,10 @@ function mcl_potions.register_splash(name, descr, color, def) texture = texture.."^[colorize:"..color..":127" }) - if name == "water" then - mcl_potions._extinguish_nearby_fire(pos) - end - self.object:remove() + local potency = self._potency or 0 + local plus = self._plus or 0 + + if def.on_splash then def.on_splash(pos, potency+1) end for _,obj in pairs(minetest.get_objects_inside_radius(pos, 4)) do local entity = obj:get_luaentity() @@ -114,13 +132,47 @@ function mcl_potions.register_splash(name, descr, color, def) local pos2 = obj:get_pos() local rad = math.floor(math.sqrt((pos2.x-pos.x)^2 + (pos2.y-pos.y)^2 + (pos2.z-pos.z)^2)) - if rad > 0 then - def.potion_fun(obj, redux_map[rad]) - else - def.potion_fun(obj, 1) + + if def._effect_list then + local ef_level + local dur + for name, details in pairs(def._effect_list) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, plus) + if potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, potency) + end + dur = dur * mcl_potions.SPLASH_FACTOR + else + dur = details.dur + end + if details.effect_stacks then + ef_level = ef_level + mcl_potions.get_effect_level(obj, name) + end + if rad > 0 then + mcl_potions.give_effect_by_level(name, obj, ef_level, redux_map[rad]*dur) + else + mcl_potions.give_effect_by_level(name, obj, ef_level, dur) + end + end + end + + if def.custom_effect then + local power = (potency+1) * mcl_potions.SPLASH_FACTOR + if rad > 0 then + def.custom_effect(obj, redux_map[rad] * power, plus) + else + def.custom_effect(obj, power, plus) + end end end end + self.object:remove() end end, diff --git a/mods/ITEMS/mcl_potions/tipped_arrow.lua b/mods/ITEMS/mcl_potions/tipped_arrow.lua index c0def3983..1833e7169 100644 --- a/mods/ITEMS/mcl_potions/tipped_arrow.lua +++ b/mods/ITEMS/mcl_potions/tipped_arrow.lua @@ -37,16 +37,26 @@ local arrow_tt = minetest.registered_items["mcl_bows:arrow"]._tt_help or "" function mcl_potions.register_arrow(name, desc, color, def) - local longdesc = def.longdesc or "" + local longdesc = def._longdesc or "" + local tt = def._tt or "" + local groups = {ammo=1, ammo_bow=1, brewitem=1, _mcl_potion=1} + if def.nocreative then groups.not_in_creative_inventory = 1 end minetest.register_craftitem("mcl_potions:"..name.."_arrow", { description = desc, - _tt_help = arrow_tt .. "\n" .. def.tt, + _tt_help = arrow_tt .. "\n" .. tt, + _dynamic_tt = def._dynamic_tt, _doc_items_longdesc = arrow_longdesc .. "\n" .. S("This particular arrow is tipped and will give an effect when it hits a player or mob.") .. "\n" .. longdesc, _doc_items_usagehelp = how_to_shoot, + _effect_list = def._effect_list, + uses_level = def.uses_level, + has_potent = def.has_potent, + has_plus = def.has_plus, + _default_potent_level = def._default_potent_level, + _default_extend_level = def._default_extend_level, inventory_image = "mcl_bows_arrow_inv.png^(mcl_potions_arrow_inv.png^[colorize:"..color..":100)", - groups = { ammo=1, ammo_bow=1, brewitem=1}, + groups = groups, _on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir) -- Shoot arrow local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51)) @@ -264,6 +274,9 @@ function mcl_potions.register_arrow(name, desc, color, def) end end + local potency = self._potency or 0 + local plus = self._plus or 0 + -- Punch target object but avoid hurting enderman. if lua then if lua.name ~= "mobs_mc:rover" then @@ -271,14 +284,62 @@ function mcl_potions.register_arrow(name, desc, color, def) full_punch_interval=1.0, damage_groups={fleshy=self._damage}, }, nil) - def.potion_fun(obj) + if def._effect_list then + local ef_level + local dur + for name, details in pairs(def._effect_list) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, plus) + if potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, potency) + end + else + dur = details.dur + end + dur = dur * mcl_potions.SPLASH_FACTOR + if details.effect_stacks then + ef_level = ef_level + mcl_potions.get_effect_level(obj, name) + end + mcl_potions.give_effect_by_level(name, obj, ef_level, dur) + end + end + if def.custom_effect then def.custom_effect(obj, potency+1, plus) end end else obj:punch(self.object, 1.0, { full_punch_interval=1.0, damage_groups={fleshy=self._damage}, }, nil) - def.potion_fun(obj) + if def._effect_list then + local ef_level + local dur + for name, details in pairs(def._effect_list) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, plus) + if potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, potency) + end + else + dur = details.dur + end + dur = dur * mcl_potions.SPLASH_FACTOR + if details.effect_stacks then + ef_level = ef_level + mcl_potions.get_effect_level(obj, name) + end + mcl_potions.give_effect_by_level(name, obj, ef_level, dur) + end + end + if def.custom_effect then def.custom_effect(obj, potency+1, plus) end end if is_player then diff --git a/mods/ITEMS/mcl_sus_stew/init.lua b/mods/ITEMS/mcl_sus_stew/init.lua index d34dbbf00..8a88027ae 100644 --- a/mods/ITEMS/mcl_sus_stew/init.lua +++ b/mods/ITEMS/mcl_sus_stew/init.lua @@ -7,41 +7,63 @@ local eat = minetest.item_eat(6, "mcl_core:bowl") --6 hunger points, player rece local flower_effect = { [ "mcl_flowers:allium" ] = "fire_resistance", + [ "mcl_flowers:azure_bluet" ] = "blindness", [ "mcl_flowers:lily_of_the_valley" ] = "poison", - [ "mcl_flowers:blue_orchid" ] = "hunger", - [ "mcl_flowers:dandelion" ] = "hunger", + [ "mcl_flowers:blue_orchid" ] = "saturation", + [ "mcl_flowers:dandelion" ] = "saturation", [ "mcl_flowers:cornflower" ] = "jump", [ "mcl_flowers:oxeye_daisy" ] = "regeneration", - [ "mcl_flowers:poppy" ] = "night_vision" + [ "mcl_flowers:poppy" ] = "night_vision", + [ "mcl_flowers:wither_rose" ] = "withering", + [ "mcl_flowers:tulip_orange" ] = "weakness", + [ "mcl_flowers:tulip_pink" ] = "weakness", + [ "mcl_flowers:tulip_red" ] = "weakness", + [ "mcl_flowers:tulip_white" ] = "weakness", } local effects = { [ "fire_resistance" ] = function(itemstack, placer, pointed_thing) - mcl_potions.fire_resistance_func(placer, 1, 4) - return eat(itemstack, placer, pointed_thing) - end, - [ "poison" ] = function(itemstack, placer, pointed_thing) - mcl_potions.poison_func(placer, 1, 12) + mcl_potions.give_effect("fire_resistance", placer, 1, 4) return eat(itemstack, placer, pointed_thing) end, - [ "hunger" ] = function(itemstack, placer, pointed_thing, player) - mcl_hunger.item_eat(6, "mcl_core:bowl", 3.5, 0, 100) + [ "blindness" ] = function(itemstack, placer, pointed_thing) + mcl_potions.give_effect("blindness", placer, 1, 8) + return eat(itemstack, placer, pointed_thing) + end, + + [ "poison" ] = function(itemstack, placer, pointed_thing) + mcl_potions.give_effect_by_level("poison", placer, 1, 12) + return eat(itemstack, placer, pointed_thing) + end, + + [ "saturation" ] = function(itemstack, placer, pointed_thing, player) + mcl_potions.give_effect_by_level("saturation", placer, 1, 0.5) return eat(itemstack, placer, pointed_thing) end, ["jump"] = function(itemstack, placer, pointed_thing) - mcl_potions.leaping_func(placer, 1, 6) + mcl_potions.give_effect_by_level("leaping", placer, 1, 6) return eat(itemstack, placer, pointed_thing) end, ["regeneration"] = function(itemstack, placer, pointed_thing) - mcl_potions.regeneration_func(placer, 1, 8) + mcl_potions.give_effect_by_level("regeneration", placer, 1, 8) + return eat(itemstack, placer, pointed_thing) + end, + + ["withering"] = function(itemstack, placer, pointed_thing) + mcl_potions.give_effect_by_level("withering", placer, 1, 8) + return eat(itemstack, placer, pointed_thing) + end, + + ["weakness"] = function(itemstack, placer, pointed_thing) + mcl_potions.give_effect_by_level("weakness", placer, 1, 9) return eat(itemstack, placer, pointed_thing) end, ["night_vision"] = function(itemstack, placer, pointed_thing) - mcl_potions.night_vision_func(placer, 1, 5) + mcl_potions.give_effect("night_vision", placer, 1, 5) return eat(itemstack, placer, pointed_thing) end, } diff --git a/mods/PLAYER/mcl_criticals/init.lua b/mods/PLAYER/mcl_criticals/init.lua index 3e292d165..d30647004 100644 --- a/mods/PLAYER/mcl_criticals/init.lua +++ b/mods/PLAYER/mcl_criticals/init.lua @@ -23,7 +23,32 @@ mcl_damage.register_modifier(function(obj, damage, reason) texture = "mcl_particles_crit.png^[colorize:#bc7a57:127", }) minetest.sound_play("mcl_criticals_hit", {object = obj}) - return damage * math.random(1.5, 2.5) + local crit_mod + local CRIT_MIN = 1.5 + local CRIT_DIFF = 1 + if hitter:is_player() then + local luck = mcl_luck.get_luck(hitter:get_player_name()) + if luck ~= 0 then + local a, d + if luck > 0 then + d = -0.5 + a = d - math.abs(luck) + elseif luck < 0 then + a = -0.5 + d = a - math.abs(luck) + else + minetest.log("warning", "[mcl_criticals] luck is not a number") -- this technically can't happen, but want to catch such cases + end + if a then + local x = math.random() + crit_mod = CRIT_DIFF * (a * x) / (d - luck * x) + CRIT_MIN + end + end + end + if not crit_mod then + crit_mod = math.random(CRIT_MIN, CRIT_MIN + CRIT_DIFF) + end + return damage * crit_mod end end end, -100) diff --git a/mods/PLAYER/mcl_criticals/mod.conf b/mods/PLAYER/mcl_criticals/mod.conf index 5b0b91330..0ae588aa6 100644 --- a/mods/PLAYER/mcl_criticals/mod.conf +++ b/mods/PLAYER/mcl_criticals/mod.conf @@ -1,2 +1,2 @@ name = mcl_criticals -depends = mcl_damage +depends = mcl_damage, mcl_luck diff --git a/mods/PLAYER/mcl_fovapi/init.lua b/mods/PLAYER/mcl_fovapi/init.lua index 92815d833..43dcfe403 100644 --- a/mods/PLAYER/mcl_fovapi/init.lua +++ b/mods/PLAYER/mcl_fovapi/init.lua @@ -75,7 +75,7 @@ minetest.register_on_respawnplayer(function(player) mcl_fovapi.remove_all_modifiers(player) end) -function mcl_fovapi.apply_modifier(player, modifier_name) +function mcl_fovapi.apply_modifier(player, modifier_name, time_override) if not player or not modifier_name then return end @@ -106,13 +106,14 @@ function mcl_fovapi.apply_modifier(player, modifier_name) minetest.log("FOV::Modifier applied to player:" .. player_name .. " modifier: " .. modifier_name) end + local time = time_override or modifier.time -- modifier apply code. if modifier.exclusive == true then -- if exclusive, reset the player's fov, and apply the new fov. if modifier.is_multiplier then player:set_fov(0, false, 0) end - player:set_fov(modifier.fov_factor, modifier.is_multiplier, modifier.time) + player:set_fov(modifier.fov_factor, modifier.is_multiplier, time) else -- not exclusive? let's apply it in the mix. local fov_factor, is_mult = player:get_fov() @@ -126,15 +127,15 @@ function mcl_fovapi.apply_modifier(player, modifier_name) fov_factor = (fov_factor + modifier.fov_factor) / 2 end if modifier.is_multiplier and is_mult then - player:set_fov(fov_factor, true, modifier.time) + player:set_fov(fov_factor, true, time) else - player:set_fov(fov_factor, false, modifier.time) + player:set_fov(fov_factor, false, time) end end end -function mcl_fovapi.remove_modifier(player, modifier_name) +function mcl_fovapi.remove_modifier(player, modifier_name, time_override) if not player or not modifier_name then return end @@ -159,9 +160,10 @@ function mcl_fovapi.remove_modifier(player, modifier_name) applied[k] = mcl_fovapi.registered_modifiers[k] end + local time = time_override or modifier.reset_time local elem = next if elem(applied) == nil then - player:set_fov(0, false, modifier.reset_time) + player:set_fov(0, false, time) return end local exc = false @@ -191,7 +193,7 @@ function mcl_fovapi.remove_modifier(player, modifier_name) fov_factor = fov_factor * x.fov_factor end end - player:set_fov(fov_factor, not non_multiplier_added, modifier.reset_time) + player:set_fov(fov_factor, not non_multiplier_added, time) end if mcl_fovapi.registered_modifiers[modifier_name].on_end then diff --git a/mods/PLAYER/mcl_hunger/hunger.lua b/mods/PLAYER/mcl_hunger/hunger.lua index de6369359..2c29e1939 100644 --- a/mods/PLAYER/mcl_hunger/hunger.lua +++ b/mods/PLAYER/mcl_hunger/hunger.lua @@ -99,42 +99,6 @@ function mcl_hunger.reset_bars_poison_hunger(player) end end --- Poison player -local function poisonp(tick, time, time_left, damage, exhaustion, name) - if not mcl_hunger.active then - return - end - local player = minetest.get_player_by_name(name) - -- First check if player is still there - if not player then - return - end - -- Abort if food poisonings have been stopped - if mcl_hunger.poison_hunger[name] == 0 then - return - end - time_left = time_left + tick - if time_left < time then - minetest.after(tick, poisonp, tick, time, time_left, damage, exhaustion, name) - else - if exhaustion > 0 then - mcl_hunger.poison_hunger [name] = mcl_hunger.poison_hunger[name] - 1 - end - if mcl_hunger.poison_hunger[name] <= 0 then - mcl_hunger.reset_bars_poison_hunger(player) - end - end - - -- Deal damage and exhaust player - -- TODO: Introduce fatal poison at higher difficulties - if player:get_hp()-damage > 0 then - mcl_util.deal_damage(player, damage, {type = "hunger"}) - end - - mcl_hunger.exhaust(name, exhaustion) - -end - local poisonrandomizer = PseudoRandom(os.time()) function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poison, exhaust, poisonchance, sound) @@ -186,15 +150,8 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso do_poison = true end if do_poison then - -- Set food poison bars - if exhaust and exhaust > 0 then - hb.change_hudbar(user, "hunger", nil, nil, "mcl_hunger_icon_foodpoison.png", nil, "mcl_hunger_bar_foodpoison.png") - if mcl_hunger.debug then - hb.change_hudbar(user, "exhaustion", nil, nil, nil, nil, "mcl_hunger_bar_foodpoison.png") - end - mcl_hunger.poison_hunger[name] = mcl_hunger.poison_hunger[name] + 1 - end - poisonp(1, poisontime, 0, poison, exhaust, user:get_player_name()) + local level = mcl_potions.get_effect_level(user, "food_poisoning") + mcl_potions.give_effect_by_level("food_poisoning", user, level+exhaust, poisontime) end end diff --git a/mods/PLAYER/mcl_hunger/init.lua b/mods/PLAYER/mcl_hunger/init.lua index 45606cd61..03cd2a0a3 100644 --- a/mods/PLAYER/mcl_hunger/init.lua +++ b/mods/PLAYER/mcl_hunger/init.lua @@ -247,13 +247,13 @@ minetest.register_globalstep(function(dtime) food_tick_timer = 0 -- let hunger work always - if player_health > 0 and player_health <= 20 then + if player_health > 0 then --mcl_hunger.exhaust(player_name, mcl_hunger.EXHAUST_HUNGER) -- later for hunger status effect mcl_hunger.update_exhaustion_hud(player) end if food_level >= 18 then -- slow regeneration - if player_health > 0 and player_health < 20 then + if player_health > 0 and player_health < player:get_properties().hp_max then player:set_hp(player_health+1) mcl_hunger.exhaust(player_name, mcl_hunger.EXHAUST_REGEN) mcl_hunger.update_exhaustion_hud(player) @@ -270,7 +270,7 @@ minetest.register_globalstep(function(dtime) end elseif food_tick_timer > max_tick_timer and food_level == 20 and food_saturation_level > 0 then -- fast regeneration - if player_health > 0 and player_health < 20 then + if player_health > 0 and player_health < player:get_properties().hp_max then food_tick_timer = 0 player:set_hp(player_health+1) mcl_hunger.exhaust(player_name, mcl_hunger.EXHAUST_REGEN) diff --git a/mods/PLAYER/mcl_hunger/register_foods.lua b/mods/PLAYER/mcl_hunger/register_foods.lua index a68dde1c1..ee33e9332 100644 --- a/mods/PLAYER/mcl_hunger/register_foods.lua +++ b/mods/PLAYER/mcl_hunger/register_foods.lua @@ -1,7 +1,7 @@ -- Apply food poisoning effect as long there are no real status effect. --- TODO: Remove this when food poisoning a status effect in mcl_potions. +-- TODO: Sanitize this now that Food Poisoning is now an effect in mcl_potions -- Normal poison damage is set to 0 because it's handled elsewhere. -mcl_hunger.register_food("mcl_mobitems:rotten_flesh", 4, "", 30, 0, 100, 80) -mcl_hunger.register_food("mcl_mobitems:chicken", 2, "", 30, 0, 100, 30) -mcl_hunger.register_food("mcl_fishing:pufferfish_raw", 1, "", 15, 0, 300) +mcl_hunger.register_food("mcl_mobitems:rotten_flesh", 4, "", 30, 0, 1, 80) +mcl_hunger.register_food("mcl_mobitems:chicken", 2, "", 30, 0, 1, 30) +mcl_hunger.register_food("mcl_fishing:pufferfish_raw", 1, "", 15, 0, 3) diff --git a/mods/PLAYER/mcl_luck/init.lua b/mods/PLAYER/mcl_luck/init.lua new file mode 100644 index 000000000..275cea52f --- /dev/null +++ b/mods/PLAYER/mcl_luck/init.lua @@ -0,0 +1,33 @@ +mcl_luck = {} + +-- table indexed by player name +-- each entry for each player contains list of modifiers applied to the player +-- modifiers are listed by their name (defined when applying them) +-- all modifiers are dynamic (they are removed when the player leaves game and on server shutdown) +local applied_luck = {} + +function mcl_luck.apply_luck_modifier(player_name, modifier_name, amount) + applied_luck[player_name][modifier_name] = amount +end + +function mcl_luck.remove_luck_modifier(player_name, modifier_name) + applied_luck[player_name][modifier_name] = nil +end + +function mcl_luck.get_luck(player_name) + local luck = 0 + for _, amount in pairs(applied_luck[player_name]) do + luck = luck + amount + end + return luck +end + +minetest.register_on_joinplayer(function(player) + local player_name = player:get_player_name() + applied_luck[player_name] = {} +end) + +minetest.register_on_leaveplayer(function(player) + local player_name = player:get_player_name() + applied_luck[player_name] = nil +end) diff --git a/mods/PLAYER/mcl_luck/mod.conf b/mods/PLAYER/mcl_luck/mod.conf new file mode 100644 index 000000000..395c888bb --- /dev/null +++ b/mods/PLAYER/mcl_luck/mod.conf @@ -0,0 +1,3 @@ +name = mcl_luck +author = Herowl +description = An API for handling luck, it can be polled by random events. diff --git a/mods/PLAYER/mcl_meshhand/init.lua b/mods/PLAYER/mcl_meshhand/init.lua index c42ff8081..44eb3e2b9 100644 --- a/mods/PLAYER/mcl_meshhand/init.lua +++ b/mods/PLAYER/mcl_meshhand/init.lua @@ -76,13 +76,16 @@ else end function mcl_meshhand.update_player(player) + local hand if mcl_skins_enabled then local node_id = mcl_skins.get_node_id_by_player(player) - player:get_inventory():set_stack("hand", 1, "mcl_meshhand:" .. node_id) + hand = ItemStack("mcl_meshhand:" .. node_id) else local creative = minetest.is_creative_enabled(player:get_player_name()) - player:get_inventory():set_stack("hand", 1, "mcl_meshhand:hand" .. (creative and "_crea" or "_surv")) + hand = ItemStack("mcl_meshhand:hand" .. (creative and "_crea" or "_surv")) end + if not mcl_potions then player:get_inventory():set_stack("hand", 1, hand) end + player:get_inventory():set_stack("hand", 1, mcl_potions.hf_update_internal(hand, player)) end minetest.register_on_joinplayer(function(player) diff --git a/textures/mcl_potions_blindness_hud.png b/textures/mcl_potions_blindness_hud.png new file mode 100644 index 000000000..ac5be885b Binary files /dev/null and b/textures/mcl_potions_blindness_hud.png differ diff --git a/textures/mcl_potions_effect_absorption.png b/textures/mcl_potions_effect_absorption.png new file mode 100644 index 000000000..114f64e2d Binary files /dev/null and b/textures/mcl_potions_effect_absorption.png differ diff --git a/textures/mcl_potions_effect_bad_luck.png b/textures/mcl_potions_effect_bad_luck.png new file mode 100644 index 000000000..f950d489f Binary files /dev/null and b/textures/mcl_potions_effect_bad_luck.png differ diff --git a/textures/mcl_potions_effect_bad_omen.png b/textures/mcl_potions_effect_bad_omen.png index 4293aed22..e652e6c5c 100644 Binary files a/textures/mcl_potions_effect_bad_omen.png and b/textures/mcl_potions_effect_bad_omen.png differ diff --git a/textures/mcl_potions_effect_blindness.png b/textures/mcl_potions_effect_blindness.png new file mode 100644 index 000000000..b7f7d7340 Binary files /dev/null and b/textures/mcl_potions_effect_blindness.png differ diff --git a/textures/mcl_potions_effect_conduit_power.png b/textures/mcl_potions_effect_conduit_power.png new file mode 100644 index 000000000..a25536907 Binary files /dev/null and b/textures/mcl_potions_effect_conduit_power.png differ diff --git a/textures/mcl_potions_effect_darkness.png b/textures/mcl_potions_effect_darkness.png new file mode 100644 index 000000000..fc72daeb0 Binary files /dev/null and b/textures/mcl_potions_effect_darkness.png differ diff --git a/textures/mcl_potions_effect_dolphin_grace.png b/textures/mcl_potions_effect_dolphin_grace.png new file mode 100644 index 000000000..ac640819d Binary files /dev/null and b/textures/mcl_potions_effect_dolphin_grace.png differ diff --git a/textures/mcl_potions_effect_fatigue.png b/textures/mcl_potions_effect_fatigue.png new file mode 100644 index 000000000..13b724c2a Binary files /dev/null and b/textures/mcl_potions_effect_fatigue.png differ diff --git a/textures/mcl_potions_effect_fire_proof.png b/textures/mcl_potions_effect_fire_proof.png deleted file mode 100644 index effbefaa4..000000000 Binary files a/textures/mcl_potions_effect_fire_proof.png and /dev/null differ diff --git a/textures/mcl_potions_effect_fire_resistance.png b/textures/mcl_potions_effect_fire_resistance.png new file mode 100644 index 000000000..3be85391d Binary files /dev/null and b/textures/mcl_potions_effect_fire_resistance.png differ diff --git a/textures/mcl_potions_effect_food_poisoning.png b/textures/mcl_potions_effect_food_poisoning.png index f29be56a5..8fb969e6e 100644 Binary files a/textures/mcl_potions_effect_food_poisoning.png and b/textures/mcl_potions_effect_food_poisoning.png differ diff --git a/textures/mcl_potions_effect_frost.png b/textures/mcl_potions_effect_frost.png new file mode 100644 index 000000000..6a008d25c Binary files /dev/null and b/textures/mcl_potions_effect_frost.png differ diff --git a/textures/mcl_potions_effect_glowing.png b/textures/mcl_potions_effect_glowing.png new file mode 100644 index 000000000..83cd8b969 Binary files /dev/null and b/textures/mcl_potions_effect_glowing.png differ diff --git a/textures/mcl_potions_effect_haste.png b/textures/mcl_potions_effect_haste.png new file mode 100644 index 000000000..54dd34740 Binary files /dev/null and b/textures/mcl_potions_effect_haste.png differ diff --git a/textures/mcl_potions_effect_health_boost.png b/textures/mcl_potions_effect_health_boost.png new file mode 100644 index 000000000..a20ae5ccc Binary files /dev/null and b/textures/mcl_potions_effect_health_boost.png differ diff --git a/textures/mcl_potions_effect_hero_of_village.png b/textures/mcl_potions_effect_hero_of_village.png new file mode 100644 index 000000000..c0462a40f Binary files /dev/null and b/textures/mcl_potions_effect_hero_of_village.png differ diff --git a/textures/mcl_potions_effect_invisibility.png b/textures/mcl_potions_effect_invisibility.png new file mode 100644 index 000000000..138111efa Binary files /dev/null and b/textures/mcl_potions_effect_invisibility.png differ diff --git a/textures/mcl_potions_effect_invisible.png b/textures/mcl_potions_effect_invisible.png deleted file mode 100644 index db0afb575..000000000 Binary files a/textures/mcl_potions_effect_invisible.png and /dev/null differ diff --git a/textures/mcl_potions_effect_leaping.png b/textures/mcl_potions_effect_leaping.png index 8fbf25ae8..3b9d5500e 100644 Binary files a/textures/mcl_potions_effect_leaping.png and b/textures/mcl_potions_effect_leaping.png differ diff --git a/textures/mcl_potions_effect_levitation.png b/textures/mcl_potions_effect_levitation.png new file mode 100644 index 000000000..ca8b6db1d Binary files /dev/null and b/textures/mcl_potions_effect_levitation.png differ diff --git a/textures/mcl_potions_effect_luck.png b/textures/mcl_potions_effect_luck.png new file mode 100644 index 000000000..46df46a03 Binary files /dev/null and b/textures/mcl_potions_effect_luck.png differ diff --git a/textures/mcl_potions_effect_nausea.png b/textures/mcl_potions_effect_nausea.png new file mode 100644 index 000000000..1b291ee49 Binary files /dev/null and b/textures/mcl_potions_effect_nausea.png differ diff --git a/textures/mcl_potions_effect_night_vision.png b/textures/mcl_potions_effect_night_vision.png index f4263968a..e5d7f1a2d 100644 Binary files a/textures/mcl_potions_effect_night_vision.png and b/textures/mcl_potions_effect_night_vision.png differ diff --git a/textures/mcl_potions_effect_poison.png b/textures/mcl_potions_effect_poison.png new file mode 100644 index 000000000..014b4314c Binary files /dev/null and b/textures/mcl_potions_effect_poison.png differ diff --git a/textures/mcl_potions_effect_poisoned.png b/textures/mcl_potions_effect_poisoned.png deleted file mode 100644 index 9d8cd5815..000000000 Binary files a/textures/mcl_potions_effect_poisoned.png and /dev/null differ diff --git a/textures/mcl_potions_effect_regenerating.png b/textures/mcl_potions_effect_regenerating.png deleted file mode 100644 index dfb82bba9..000000000 Binary files a/textures/mcl_potions_effect_regenerating.png and /dev/null differ diff --git a/textures/mcl_potions_effect_regeneration.png b/textures/mcl_potions_effect_regeneration.png new file mode 100644 index 000000000..1c5b7d502 Binary files /dev/null and b/textures/mcl_potions_effect_regeneration.png differ diff --git a/textures/mcl_potions_effect_resistance.png b/textures/mcl_potions_effect_resistance.png new file mode 100644 index 000000000..e81acfd45 Binary files /dev/null and b/textures/mcl_potions_effect_resistance.png differ diff --git a/textures/mcl_potions_effect_saturation.png b/textures/mcl_potions_effect_saturation.png new file mode 100644 index 000000000..13bbd41e8 Binary files /dev/null and b/textures/mcl_potions_effect_saturation.png differ diff --git a/textures/mcl_potions_effect_slow.png b/textures/mcl_potions_effect_slow.png deleted file mode 100644 index 464d270a9..000000000 Binary files a/textures/mcl_potions_effect_slow.png and /dev/null differ diff --git a/textures/mcl_potions_effect_slow_falling.png b/textures/mcl_potions_effect_slow_falling.png new file mode 100644 index 000000000..5e82afc91 Binary files /dev/null and b/textures/mcl_potions_effect_slow_falling.png differ diff --git a/textures/mcl_potions_effect_slowness.png b/textures/mcl_potions_effect_slowness.png new file mode 100644 index 000000000..eafff9d35 Binary files /dev/null and b/textures/mcl_potions_effect_slowness.png differ diff --git a/textures/mcl_potions_effect_strength.png b/textures/mcl_potions_effect_strength.png new file mode 100644 index 000000000..54da79ed0 Binary files /dev/null and b/textures/mcl_potions_effect_strength.png differ diff --git a/textures/mcl_potions_effect_strong.png b/textures/mcl_potions_effect_strong.png deleted file mode 100644 index 515b5777a..000000000 Binary files a/textures/mcl_potions_effect_strong.png and /dev/null differ diff --git a/textures/mcl_potions_effect_swift.png b/textures/mcl_potions_effect_swift.png deleted file mode 100644 index cf9e4b95c..000000000 Binary files a/textures/mcl_potions_effect_swift.png and /dev/null differ diff --git a/textures/mcl_potions_effect_swiftness.png b/textures/mcl_potions_effect_swiftness.png new file mode 100644 index 000000000..cf5d6b4d9 Binary files /dev/null and b/textures/mcl_potions_effect_swiftness.png differ diff --git a/textures/mcl_potions_effect_water_breathing.png b/textures/mcl_potions_effect_water_breathing.png index 3ced75eba..80a1054f7 100644 Binary files a/textures/mcl_potions_effect_water_breathing.png and b/textures/mcl_potions_effect_water_breathing.png differ diff --git a/textures/mcl_potions_effect_weak.png b/textures/mcl_potions_effect_weak.png deleted file mode 100644 index 398c161ab..000000000 Binary files a/textures/mcl_potions_effect_weak.png and /dev/null differ diff --git a/textures/mcl_potions_effect_weakness.png b/textures/mcl_potions_effect_weakness.png new file mode 100644 index 000000000..62c2e3e12 Binary files /dev/null and b/textures/mcl_potions_effect_weakness.png differ diff --git a/textures/mcl_potions_frost_hud.png b/textures/mcl_potions_frost_hud.png new file mode 100644 index 000000000..282c713f1 Binary files /dev/null and b/textures/mcl_potions_frost_hud.png differ diff --git a/textures/mcl_potions_glow_waypoint.png b/textures/mcl_potions_glow_waypoint.png new file mode 100644 index 000000000..1e5afedfb Binary files /dev/null and b/textures/mcl_potions_glow_waypoint.png differ diff --git a/textures/mcl_potions_icon_absorb.png b/textures/mcl_potions_icon_absorb.png new file mode 100644 index 000000000..f1f671f6b Binary files /dev/null and b/textures/mcl_potions_icon_absorb.png differ diff --git a/textures/mcl_potions_icon_frost.png b/textures/mcl_potions_icon_frost.png new file mode 100644 index 000000000..f9edd0d7c Binary files /dev/null and b/textures/mcl_potions_icon_frost.png differ diff --git a/textures/mcl_potions_icon_regen_frost.png b/textures/mcl_potions_icon_regen_frost.png new file mode 100644 index 000000000..0a604ec55 Binary files /dev/null and b/textures/mcl_potions_icon_regen_frost.png differ diff --git a/textures/vl_mobitems_aery_charge.png b/textures/vl_mobitems_aery_charge.png new file mode 100644 index 000000000..51608d922 Binary files /dev/null and b/textures/vl_mobitems_aery_charge.png differ diff --git a/textures/vl_mobitems_crystalline_drop.png b/textures/vl_mobitems_crystalline_drop.png new file mode 100644 index 000000000..42ecb6d6d Binary files /dev/null and b/textures/vl_mobitems_crystalline_drop.png differ diff --git a/textures/vl_mobitems_earthen_ash.png b/textures/vl_mobitems_earthen_ash.png new file mode 100644 index 000000000..63fd28bbf Binary files /dev/null and b/textures/vl_mobitems_earthen_ash.png differ diff --git a/textures/vl_mobitems_ice_crystal.png b/textures/vl_mobitems_ice_crystal.png new file mode 100644 index 000000000..a3138545f Binary files /dev/null and b/textures/vl_mobitems_ice_crystal.png differ diff --git a/textures/vl_mobitems_spectre_membrane.png b/textures/vl_mobitems_spectre_membrane.png new file mode 100644 index 000000000..0819e7532 Binary files /dev/null and b/textures/vl_mobitems_spectre_membrane.png differ diff --git a/textures/vl_unknown.png b/textures/vl_unknown.png new file mode 100644 index 000000000..279a4cdb0 Binary files /dev/null and b/textures/vl_unknown.png differ