Merge pull request 'Add shields and offhand' (#137) from NO11/MineClone5:shields into master

Reviewed-on: MineClone5/MineClone5#137
This commit is contained in:
kay27 2022-01-24 19:13:43 +00:00
commit f55c8a5c86
66 changed files with 903 additions and 67 deletions

View File

@ -485,3 +485,16 @@ function mcl_util.replace_mob(obj, mob)
obj:set_yaw(rot)
return obj
end
function mcl_util.get_pointed_thing(player)
local pos = vector.offset(player:get_pos(), 0, player:get_properties().eye_height, 0)
local look_dir = vector.multiply(player:get_look_dir(), 5)
local pos2 = vector.add(pos, look_dir)
local ray = minetest.raycast(pos, pos2, false, true)
if ray then
for pointed_thing in ray do
return pointed_thing
end
end
end

View File

@ -525,7 +525,7 @@ if c("totem") then
inventory_image = "mcl_totems_totem.png",
wield_image = "mcl_totems_totem.png",
stack_max = 1,
groups = {combat_item=1},
groups = {combat_item = 1, offhand_item = 1},
})
end

View File

@ -363,6 +363,10 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
armor_slot_imgs = armor_slot_imgs .. "image[5.5,2.75;1,1;mcl_inventory_empty_armor_slot_boots.png]"
end
if inv:get_stack("offhand", 1):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[1.5,2.025;1,1;mcl_inventory_empty_armor_slot_shield.png]"
end
local stack_size = get_stack_size(player)
-- Survival inventory slots
@ -377,9 +381,13 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
mcl_formspec.get_itemslot_bg(2.5,2.75,1,1)..
mcl_formspec.get_itemslot_bg(5.5,1.3,1,1)..
mcl_formspec.get_itemslot_bg(5.5,2.75,1,1)..
"list[current_player;offhand;1.5,2.025;1,1]"..
mcl_formspec.get_itemslot_bg(1.5,2.025,1,1)..
armor_slot_imgs..
-- player preview
player_preview..
-- crafting guide button
"image_button[9,1;1,1;craftguide_book.png;__mcl_craftguide;]"..
"tooltip[__mcl_craftguide;"..F(S("Recipe book")).."]"..

View File

@ -76,6 +76,10 @@ local function set_inventory(player, armor_change_only)
end
end
if inv:get_stack("offhand", 1):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[3,2;1,1;mcl_inventory_empty_armor_slot_shield.png]"
end
local form = "size[9,8.75]"..
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]"..
player_preview..
@ -88,6 +92,8 @@ local function set_inventory(player, armor_change_only)
mcl_formspec.get_itemslot_bg(0,1,1,1)..
mcl_formspec.get_itemslot_bg(0,2,1,1)..
mcl_formspec.get_itemslot_bg(0,3,1,1)..
"list[current_player;offhand;3,2;1,1]"..
mcl_formspec.get_itemslot_bg(3,2,1,1)..
armor_slot_imgs..
-- craft and inventory
"label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))).."]"..
@ -112,6 +118,7 @@ local function set_inventory(player, armor_change_only)
-- achievements button
"image_button[7,3;1,1;mcl_achievements_button.png;__mcl_achievements;]"..
"tooltip[__mcl_achievements;"..F(S("Achievements")).."]"..
-- for shortcuts
"listring[current_player;main]"..
"listring[current_player;armor]"..
@ -148,8 +155,11 @@ end)
minetest.register_on_joinplayer(function(player)
--init inventory
player:get_inventory():set_width("main", 9)
player:get_inventory():set_size("main", 36)
local inv = player:get_inventory()
inv:set_width("main", 9)
inv:set_size("main", 36)
inv:set_size("offhand", 1)
--set hotbar size
player:hud_set_hotbar_itemcount(9)

View File

@ -0,0 +1,171 @@
local minetest, math = minetest, math
mcl_offhand = {}
local max_offhand_px = 128
-- only supports up to 128px textures
function mcl_offhand.get_offhand(player)
return player:get_inventory():get_stack("offhand", 1)
end
local function offhand_get_wear(player)
return mcl_offhand.get_offhand(player):get_wear()
end
local function offhand_get_count(player)
return mcl_offhand.get_offhand(player):get_count()
end
minetest.register_on_joinplayer(function(player, last_login)
mcl_offhand[player] = {
hud = {},
last_wear = offhand_get_wear(player),
last_count = offhand_get_count(player),
}
end)
local function remove_hud(player, hud)
local offhand_hud = mcl_offhand[player].hud[hud]
if offhand_hud then
player:hud_remove(offhand_hud)
mcl_offhand[player].hud[hud] = nil
end
end
function rgb_to_hex(r, g, b)
return string.format("%02x%02x%02x", r, g, b)
end
local function update_wear_bar(player, itemstack)
local wear_bar_percent = (65535 - offhand_get_wear(player)) / 65535
local color = {255, 255, 255}
local wear = itemstack:get_wear() / 65535;
local wear_i = math.min(math.floor(wear * 600), 511);
wear_i = math.min(wear_i + 10, 511);
if wear_i <= 255 then
color = {wear_i, 255, 0}
else
color = {255, 511 - wear_i, 0}
end
local wear_bar = mcl_offhand[player].hud.wear_bar
player:hud_change(wear_bar, "text", "mcl_wear_bar.png^[colorize:#" .. rgb_to_hex(color[1], color[2], color[3]))
player:hud_change(wear_bar, "scale", {x = 40 * wear_bar_percent, y = 3})
player:hud_change(wear_bar, "offset", {x = -320 - (20 - player:hud_get(wear_bar).scale.x / 2), y = -13})
end
minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do
local itemstack = mcl_offhand.get_offhand(player)
local offhand_item = itemstack:get_name()
local offhand_hud = mcl_offhand[player].hud
if offhand_item ~= "" then
local item_texture = minetest.registered_items[offhand_item].inventory_image .. "^[resize:" .. max_offhand_px .. "x" .. max_offhand_px
local position = {x = 0.5, y = 1}
local offset = {x = -320, y = -32}
if not offhand_hud.slot then
offhand_hud.slot = player:hud_add({
hud_elem_type = "image",
position = position,
offset = offset,
scale = {x = 2.75, y = 2.75},
text = "mcl_offhand_slot.png",
z_index = 0,
})
end
if not offhand_hud.item then
offhand_hud.item = player:hud_add({
hud_elem_type = "image",
position = position,
offset = offset,
scale = {x = 0.4, y = 0.4},
text = item_texture,
z_index = 1,
})
else
player:hud_change(offhand_hud.item, "text", item_texture)
end
if not offhand_hud.wear_bar_bg and minetest.registered_tools[offhand_item] then
if offhand_get_wear(player) > 0 then
local texture = "mcl_wear_bar.png^[colorize:#000000"
offhand_hud.wear_bar_bg = player:hud_add({
hud_elem_type = "image",
position = {x = 0.5, y = 1},
offset = {x = -320, y = -13},
scale = {x = 40, y = 3},
text = texture,
z_index = 2,
})
offhand_hud.wear_bar = player:hud_add({
hud_elem_type = "image",
position = {x = 0.5, y = 1},
offset = {x = -320, y = -13},
scale = {x = 10, y = 3},
text = texture,
z_index = 3,
})
update_wear_bar(player, itemstack)
end
end
if not offhand_hud.item_count and offhand_get_count(player) > 1 then
offhand_hud.item_count = player:hud_add({
hud_elem_type = "text",
position = {x = 0.5, y = 1},
offset = {x = -298, y = -18},
scale = {x = 1, y = 1},
alignment = {x = -1, y = 0},
text = offhand_get_count(player),
z_index = 4,
number = 0xFFFFFF,
})
end
if offhand_hud.wear_bar then
if offhand_hud.last_wear ~= offhand_get_wear(player) then
update_wear_bar(player, itemstack)
offhand_hud.last_wear = offhand_get_wear(player)
end
if offhand_get_wear(player) <= 0 or not minetest.registered_tools[offhand_item] then
remove_hud(player, "wear_bar_bg")
remove_hud(player, "wear_bar")
end
end
if offhand_hud.item_count then
if offhand_hud.last_count ~= offhand_get_count(player) then
player:hud_change(offhand_hud.item_count, "text", offhand_get_count(player))
offhand_hud.last_count = offhand_get_count(player)
end
if offhand_get_count(player) <= 1 then
remove_hud(player, "item_count")
end
end
elseif offhand_hud.slot then
for index, _ in pairs(mcl_offhand[player].hud) do
remove_hud(player, index)
end
end
end
end)
minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
if action == "move" and inventory_info.to_list == "offhand" then
local itemstack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index)
if not (minetest.get_item_group(itemstack:get_name(), "offhand_item") > 0) then
return 0
else
return itemstack:get_stack_max()
end
end
end)
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
local from_offhand = inventory_info.from_list == "offhand"
local to_offhand = inventory_info.to_list == "offhand"
if action == "move" and from_offhand or to_offhand then
mcl_inventory.update_inventory_formspec(player)
end
end)

View File

@ -0,0 +1,3 @@
name = mcl_offhand
author = NO11
depends = mcl_inventory

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

View File

@ -88,6 +88,10 @@ for k,v in pairs(mcl_banners.colors) do
colors_reverse["mcl_banners:banner_item_"..v[1]] = k
end
function mcl_banners.color_reverse(itemname)
return colors_reverse[itemname]
end
-- Add pattern/emblazoning crafting recipes
dofile(modpath.."/patterncraft.lua")
@ -149,7 +153,7 @@ local function on_destruct_hanging_banner(pos)
return on_destruct_banner(pos, true)
end
local function make_banner_texture(base_color, layers)
function mcl_banners.make_banner_texture(base_color, layers)
local colorize
if mcl_banners.colors[base_color] then
colorize = mcl_banners.colors[base_color][4]
@ -171,11 +175,11 @@ local function make_banner_texture(base_color, layers)
finished_banner = finished_banner .. "^" .. layer
end
return { finished_banner }
return finished_banner
end
return { base }
return base
else
return { "mcl_banners_banner_base.png" }
return "mcl_banners_banner_base.png"
end
end
@ -192,7 +196,7 @@ local function spawn_banner_entity(pos, hanging, itemstack)
local imeta = itemstack:get_meta()
local layers_raw = imeta:get_string("layers")
local layers = minetest.deserialize(layers_raw)
local colorid = colors_reverse[itemstack:get_name()]
local colorid = mcl_banners.color_reverse(itemstack:get_name())
banner:get_luaentity():_set_textures(colorid, layers)
local mname = imeta:get_string("name")
if mname and mname ~= "" then
@ -604,7 +608,7 @@ local entity_standing = {
visual = "mesh",
mesh = "amc_banner.b3d",
visual_size = { x=2.499, y=2.499 },
textures = make_banner_texture(),
textures = {mcl_banners.make_banner_texture()},
pointable = false,
_base_color = nil, -- base color of banner
@ -624,7 +628,7 @@ local entity_standing = {
self._layers = inp._layers
self._name = inp._name
self.object:set_properties({
textures = make_banner_texture(self._base_color, self._layers),
textures = {mcl_banners.make_banner_texture(self._base_color, self._layers)},
})
end
-- Make banner slowly swing
@ -635,7 +639,7 @@ local entity_standing = {
-- Set the banner textures. This function can be used by external mods.
-- Meaning of parameters:
-- * self: Lua entity reference to entity.
-- * other parameters: Same meaning as in make_banner_texture
-- * other parameters: Same meaning as in mcl_banners.make_banner_texture
_set_textures = function(self, base_color, layers)
if base_color then
self._base_color = base_color
@ -643,7 +647,7 @@ local entity_standing = {
if layers then
self._layers = layers
end
self.object:set_properties({textures = make_banner_texture(self._base_color, self._layers)})
self.object:set_properties({textures = {mcl_banners.make_banner_texture(self._base_color, self._layers)}})
end,
}
minetest.register_entity("mcl_banners:standing_banner", entity_standing)

View File

@ -74,6 +74,7 @@ local ARROW_ENTITY={
_shooter=nil, -- ObjectRef of player or mob who shot it
_is_arrow = true,
_in_player = false,
_blocked = false,
_viscosity=0, -- Viscosity of node the arrow is currently in
_deflection_cooloff=0, -- Cooloff timer after an arrow deflection, to prevent many deflections in quick succession
}
@ -82,7 +83,7 @@ local ARROW_ENTITY={
local function spawn_item(self, pos)
if not minetest.is_creative_enabled("") then
local item = minetest.add_item(pos, "mcl_bows:arrow")
item:set_velocity({x=0, y=0, z=0})
item:set_velocity(vector.new(0, 0, 0))
item:set_yaw(self.object:get_yaw())
end
mcl_burning.extinguish(self.object)
@ -94,12 +95,10 @@ local function damage_particles(pos, is_critical)
minetest.add_particlespawner({
amount = 15,
time = 0.1,
minpos = {x=pos.x-0.5, y=pos.y-0.5, z=pos.z-0.5},
maxpos = {x=pos.x+0.5, y=pos.y+0.5, z=pos.z+0.5},
minvel = {x=-0.1, y=-0.1, z=-0.1},
maxvel = {x=0.1, y=0.1, z=0.1},
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minpos = vector.offset(pos, -0.5, -0.5, -0.5),
maxpos = vector.offset(pos, 0.5, 0.5, 0.5),
minvel = vector.new(-0.1, -0.1, -0.1),
maxvel = vector.new(0.1, 0.1, 0.1),
minexptime = 1,
maxexptime = 2,
minsize = 1.5,
@ -248,18 +247,19 @@ function ARROW_ENTITY.on_step(self, dtime)
-- Punch target object but avoid hurting enderman.
if not lua or lua.name ~= "mobs_mc:enderman" then
if self._in_player == false then
if not self._in_player then
damage_particles(self.object:get_pos(), self._is_critical)
end
if mcl_burning.is_burning(self.object) then
mcl_burning.set_on_fire(obj, 5)
end
if self._in_player == false then
if not self._in_player and not self._blocked then
obj:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self._damage},
}, self.object:get_velocity())
if obj:is_player() then
if not mcl_shields.is_blocking(obj) then
local placement
self._placement = math.random(1, 2)
if self._placement == 1 then
@ -291,7 +291,15 @@ function ARROW_ENTITY.on_step(self, dtime)
end
self._z_rotation = math.random(-30, 30)
self._y_rotation = math.random( -30, 30)
self.object:set_attach(obj, self._attach_parent, {x=self._x_position,y=self._y_position,z=random_arrow_positions("z", placement)}, {x=0,y=self._rotation_station + self._y_rotation,z=self._z_rotation})
self.object:set_attach(
obj, self._attach_parent,
vector.new(self._x_position, self._y_position, random_arrow_positions("z", placement)),
vector.new(0, self._rotation_station + self._y_rotation, self._z_rotation)
)
else
self._blocked = true
self.object:set_velocity(vector.multiply(self.object:get_velocity(), -0.25))
end
minetest.after(150, function()
self.object:remove()
end)
@ -301,7 +309,7 @@ function ARROW_ENTITY.on_step(self, dtime)
if is_player then
if self._shooter and self._shooter:is_player() and self._in_player == false then
if self._shooter and self._shooter:is_player() and not self._in_player and not self._blocked then
-- “Ding” sound for hitting another player
minetest.sound_play({name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter:get_player_name()}, true)
end
@ -318,7 +326,8 @@ function ARROW_ENTITY.on_step(self, dtime)
end
end
end
if self._in_player == false then
if not self._in_player and not self._blocked then
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
end
end
@ -344,9 +353,9 @@ function ARROW_ENTITY.on_step(self, dtime)
local dir
if math.abs(vel.y) < 0.00001 then
if self._lastpos.y < pos.y then
dir = {x=0, y=1, z=0}
dir = vector.new(0, 1, 0)
else
dir = {x=0, y=-1, z=0}
dir = vector.new(0, -1, 0)
end
else
dir = minetest.facedir_to_dir(minetest.dir_to_facedir(minetest.yaw_to_dir(self.object:get_yaw()-YAW_OFFSET)))
@ -374,8 +383,8 @@ function ARROW_ENTITY.on_step(self, dtime)
self._stucktimer = 0
self._stuckrechecktimer = 0
self.object:set_velocity({x=0, y=0, z=0})
self.object:set_acceleration({x=0, y=0, z=0})
self.object:set_velocity(vector.new(0, 0, 0))
self.object:set_acceleration(vector.new(0, 0, 0))
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
@ -420,7 +429,7 @@ function ARROW_ENTITY.on_step(self, dtime)
end
-- Update internal variable
self._lastpos={x=pos.x, y=pos.y, z=pos.z}
self._lastpos = pos
end
-- Force recheck of stuck arrows when punched.

View File

@ -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
depends = controls, mcl_particles, mcl_enchanting, mcl_init, mcl_shields
optional_depends = awards, mcl_achievements, mcl_core, mcl_mobitems, playerphysics, doc, doc_identifier, mesecons_button

View File

@ -388,6 +388,7 @@ mcl_experience.register_on_add_xp(function(player, xp)
{list = "armor", index = 3},
{list = "armor", index = 4},
{list = "armor", index = 5},
{list = "offhand", index = 1},
}
local final_candidates = {}

View File

@ -0,0 +1,461 @@
local minetest, math, vector = minetest, math, vector
local modname = minetest.get_current_modname()
local S = minetest.get_translator(modname)
mcl_shields = {
types = {
mob = true,
player = true,
arrow = true,
generic = true,
explosion = true, -- ghasts don't work
dragon_breath = true,
},
enchantments = {"mending", "unbreaking"},
players = {},
}
local interact_priv = minetest.registered_privileges.interact
interact_priv.give_to_singleplayer = false
interact_priv.give_to_admin = false
local overlay = mcl_enchanting.overlay
local hud = "mcl_shield_hud.png"
minetest.register_tool("mcl_shields:shield", {
description = S("Shield"),
_doc_items_longdesc = S("A shield is a tool used for protecting the player against attacks."),
inventory_image = "mcl_shield.png",
stack_max = 1,
groups = {
shield = 1,
weapon = 1,
enchantability = 1,
no_wieldview = 1,
offhand_item = 1,
},
sound = {breaks = "default_tool_breaks"},
_repair_material = "group:wood",
wield_scale = vector.new(2, 2, 2),
})
local function wielded_item(obj, i)
local itemstack = obj:get_wielded_item()
if i == 1 then
itemstack = obj:get_inventory():get_stack("offhand", 1)
end
return itemstack:get_name()
end
function mcl_shields.wielding_shield(obj, i)
return wielded_item(obj, i):find("mcl_shields:shield")
end
local function shield_is_enchanted(obj, i)
return mcl_enchanting.is_enchanted(wielded_item(obj, i))
end
minetest.register_entity("mcl_shields:shield_entity", {
initial_properties = {
visual = "mesh",
mesh = "mcl_shield.obj",
physical = false,
pointable = false,
collide_with_objects = false,
textures = {"mcl_shield_base_nopattern.png"},
visual_size = vector.new(1, 1, 1),
},
_blocking = false,
_shield_number = 2,
on_step = function(self, dtime, moveresult)
local player = self.object:get_attach()
if player then
local shield_texture = "mcl_shield_base_nopattern.png"
local i = self._shield_number
local item = wielded_item(player, i)
if item ~= "mcl_shields:shield" and item ~= "mcl_shields:shield_enchanted" then
local itemstack = player:get_wielded_item()
if i == 1 then
itemstack = player:get_inventory():get_stack("offhand", 1)
end
local meta_texture = itemstack:get_meta():get_string("mcl_shields:shield_custom_pattern_texture")
if meta_texture ~= "" then
shield_texture = meta_texture
else
local color = minetest.registered_items[item]._shield_color
if color then
shield_texture = "mcl_shield_base_nopattern.png^(mcl_shield_pattern_base.png^[colorize:" .. color .. ")"
end
end
end
if shield_is_enchanted(player, i) then
shield_texture = shield_texture .. overlay
end
self.object:set_properties({textures = {shield_texture}})
else
self.object:remove()
end
end,
})
for _, e in pairs(mcl_shields.enchantments) do
mcl_enchanting.enchantments[e].secondary.shield = true
end
function mcl_shields.is_blocking(obj)
local blocking = mcl_shields.players[obj].blocking
if blocking > 0 then
local shieldstack = obj:get_wielded_item()
if blocking == 1 then
shieldstack = obj:get_inventory():get_stack("offhand", 1)
end
return blocking, shieldstack
end
end
mcl_damage.register_modifier(function(obj, damage, reason)
local type = reason.type
local damager = reason.direct
local blocking, shieldstack = mcl_shields.is_blocking(obj)
if obj:is_player() and blocking and mcl_shields.types[type] and damager then
local entity = damager:get_luaentity()
if entity and (type == "arrow" or type == "generic") then
damager = entity._shooter
end
if vector.dot(obj:get_look_dir(), vector.subtract(damager:get_pos(), obj:get_pos())) >= 0 then
local durability = 336
local unbreaking = mcl_enchanting.get_enchantment(shieldstack, mcl_shields.enchantments[2])
if unbreaking > 0 then
durability = durability * (unbreaking + 1)
end
if not minetest.is_creative_enabled(obj:get_player_name()) and damage >= 3 then
shieldstack:add_wear(65535 / durability)
if blocking == 2 then
obj:set_wielded_item(shieldstack)
else
obj:get_inventory():set_stack("offhand", 1, shieldstack)
mcl_inventory.update_inventory_formspec(obj)
end
end
minetest.sound_play({name = "mcl_block"})
return 0
end
end
end)
local function modify_shield(player, vpos, vrot, i)
local arm = "Right"
if i == 1 then
arm = "Left"
end
local shield = mcl_shields.players[player].shields[i]
if shield then
shield:set_attach(player, "Arm_" .. arm, vpos, vrot, false)
end
end
local function set_shield(player, block, i)
if block then
if i == 1 then
modify_shield(player, vector.new(-9, 4, 0.5), vector.new(80, 100, 0), i) -- TODO
else
modify_shield(player, vector.new(-8, 4, -2.5), vector.new(80, 80, 0), i)
end
else
if i == 1 then
modify_shield(player, vector.new(-3, -5, 0), vector.new(0, 180, 0), i)
else
modify_shield(player, vector.new(3, -5, 0), vector.new(0, 0, 0), i)
end
end
local shield = mcl_shields.players[player].shields[i]
if shield then
shield:get_luaentity()._blocking = block
end
end
local function set_interact(player, interact)
local player_name = player:get_player_name()
local privs = minetest.get_player_privs(player_name)
privs.interact = interact
minetest.set_player_privs(player_name, privs)
end
local shield_hud = {}
local function remove_shield_hud(player)
if shield_hud[player] then
player:hud_remove(shield_hud[player])
shield_hud[player] = nil
set_shield(player, false, 1)
set_shield(player, false, 2)
end
player:hud_set_flags({wielditem = true})
playerphysics.remove_physics_factor(player, "speed", "shield_speed")
set_interact(player, true)
end
local function add_shield_entity(player, i)
local shield = minetest.add_entity(player:get_pos(), "mcl_shields:shield_entity")
shield:get_luaentity()._shield_number = i
mcl_shields.players[player].shields[i] = shield
set_shield(player, false, i)
end
local function remove_shield_entity(player, i)
local shields = mcl_shields.players[player].shields
if shields[i] then
shields[i]:remove()
shields[i] = nil
end
end
local function handle_blocking(player)
local player_shield = mcl_shields.players[player]
local rmb = player:get_player_control().RMB
if rmb then
local shield_in_offhand = mcl_shields.wielding_shield(player, 1)
local shield_in_hand = mcl_shields.wielding_shield(player)
local not_blocking = player_shield.blocking == 0
local pos = player:get_pos()
if shield_in_hand then
if not_blocking then
minetest.after(0.25, function()
if (not_blocking or not shield_in_offhand) and shield_in_hand and rmb then
player_shield.blocking = 2
set_shield(player, true, 2)
end
end)
elseif not shield_in_offhand then
player_shield.blocking = 2
end
elseif shield_in_offhand then
local offhand_can_block = (wielded_item(player) == "" or not mcl_util.get_pointed_thing(player))
if offhand_can_block then
if not_blocking then
minetest.after(0.25, function()
if (not_blocking or not shield_in_hand) and shield_in_offhand and rmb and offhand_can_block then
player_shield.blocking = 1
set_shield(player, true, 1)
end
end)
elseif not shield_in_hand then
player_shield.blocking = 1
end
end
else
player_shield.blocking = 0
end
else
player_shield.blocking = 0
end
end
local function update_shield_entity(player, blocking, i)
local shield = mcl_shields.players[player].shields[i]
if mcl_shields.wielding_shield(player, i) then
if not shield then
add_shield_entity(player, i)
else
if blocking == i then
if shield:get_luaentity() and not shield:get_luaentity()._blocking then
set_shield(player, true, i)
end
else
set_shield(player, false, i)
end
end
elseif shield then
remove_shield_entity(player, i)
end
end
minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do
handle_blocking(player)
local blocking, shieldstack = mcl_shields.is_blocking(player)
if blocking then
local shieldhud = shield_hud[player]
if not shieldhud then
local texture = hud
if mcl_enchanting.is_enchanted(shieldstack:get_name()) then
texture = texture .. overlay
end
local offset = 100
if blocking == 1 then
texture = texture .. "^[transform4"
offset = -100
else
player:hud_set_flags({wielditem = false})
end
shield_hud[player] = player:hud_add({
hud_elem_type = "image",
position = {x = 0.5, y = 0.5},
scale = {x = -101, y = -101},
offset = {x = offset, y = 0},
text = texture,
z_index = -200,
})
playerphysics.add_physics_factor(player, "speed", "shield_speed", 0.5)
set_interact(player, nil)
else
local wielditem = player:hud_get_flags().wielditem
if blocking == 1 then
if not wielditem then
player:hud_change(shieldhud, "text", hud .. "^[transform4")
player:hud_change(shieldhud, "offset", {x = -100, y = 0})
player:hud_set_flags({wielditem = true})
end
else
if wielditem then
player:hud_change(shieldhud, "text", hud)
player:hud_change(shieldhud, "offset", {x = 100, y = 0})
player:hud_set_flags({wielditem = false})
end
end
local image = player:hud_get(shieldhud).text
local enchanted = hud .. overlay
local enchanted1 = image == enchanted
local enchanted2 = image == enchanted .. "^[transform4"
if mcl_enchanting.is_enchanted(shieldstack:get_name()) then
if not enchanted1 and not enchanted2 then
if blocking == 1 then
player:hud_change(shieldhud, "text", hud .. overlay .. "^[transform4")
else
player:hud_change(shieldhud, "text", hud .. overlay)
end
end
elseif enchanted1 or enchanted2 then
if blocking == 1 then
player:hud_change(shieldhud, "text", hud .. "^[transform4")
else
player:hud_change(shieldhud, "text", hud)
end
end
end
else
remove_shield_hud(player)
end
for i = 1, 2 do
update_shield_entity(player, blocking, i)
end
end
end)
minetest.register_on_dieplayer(function(player)
remove_shield_hud(player)
if not minetest.settings:get_bool("mcl_keepInventory") then
remove_shield_entity(player, 1)
remove_shield_entity(player, 2)
end
end)
minetest.register_on_leaveplayer(function(player)
shield_hud[player] = nil
mcl_shields.players[player] = nil
end)
minetest.register_craft({
output = "mcl_shields:shield",
recipe = {
{"group:wood", "mcl_core:iron_ingot", "group:wood"},
{"group:wood", "group:wood", "group:wood"},
{"", "group:wood", ""},
}
})
for _, colortab in pairs(mcl_banners.colors) do
minetest.register_tool("mcl_shields:shield_" .. colortab[1], {
description = S(colortab[6] .. " Shield"),
_doc_items_longdesc = S("A shield is a tool used for protecting the player against attacks."),
inventory_image = "mcl_shield.png^(mcl_shield_item_overlay.png^[colorize:" .. colortab[4] ..")",
stack_max = 1,
groups = {
shield = 1,
weapon = 1,
enchantability = 1,
no_wieldview = 1,
not_in_creative_inventory = 1,
offhand_item = 1,
},
sound = {breaks = "default_tool_breaks"},
_repair_material = "group:wood",
wield_scale = vector.new(2, 2, 2),
_shield_color = colortab[4],
})
local banner = "mcl_banners:banner_item_" .. colortab[1]
minetest.register_craft({
type = "shapeless",
output = "mcl_shields:shield_" .. colortab[1],
recipe = {"mcl_shields:shield", banner},
})
end
local function to_shield_texture(banner_texture)
return banner_texture
:gsub("mcl_banners_base_inverted.png", "mcl_shield_base_nopattern.png^mcl_shield_pattern_base.png")
:gsub("mcl_banners_banner_base.png", "mcl_shield_base_nopattern.png^mcl_shield_pattern_base.png")
:gsub("mcl_banners_base", "mcl_shield_pattern_base")
:gsub("mcl_banners", "mcl_shield_pattern")
end
local function craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv)
if string.find(itemstack:get_name(), "mcl_shields:shield_") then
local shield_stack
for i = 1, player:get_inventory():get_size("craft") do
local stack = old_craft_grid[i]
local name = stack:get_name()
if name == "mcl_shields:shield" then
shield_stack = stack
break
end
end
for i = 1, player:get_inventory():get_size("craft") do
local banner_stack = old_craft_grid[i]
local banner_name = banner_stack:get_name()
if string.find(banner_name, "mcl_banners:banner") and shield_stack then
local banner_meta = banner_stack:get_meta()
local layers_meta = banner_meta:get_string("layers")
local new_shield_meta = itemstack:get_meta()
if layers_meta ~= "" then
local color = mcl_banners.color_reverse(banner_name)
local layers = minetest.deserialize(layers_meta)
local texture = mcl_banners.make_banner_texture(color, layers)
new_shield_meta:set_string("description", mcl_banners.make_advanced_banner_description(itemstack:get_description(), layers))
new_shield_meta:set_string("mcl_shields:shield_custom_pattern_texture", to_shield_texture(texture))
end
itemstack:set_wear(shield_stack:get_wear())
break
end
end
end
return itemstack
end
minetest.register_craft_predict(function(itemstack, player, old_craft_grid, craft_inv)
return craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv)
end)
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
return craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv)
end)
minetest.register_on_joinplayer(function(player)
mcl_shields.players[player] = {
shields = {},
blocking = 0,
}
mcl_shields.players[player].blocking = 0
remove_shield_hud(player)
end)

View File

@ -0,0 +1,19 @@
# textdomain: mcl_shields
Shield=Schild
A shield is a tool used for protecting the player against attacks.=Der Schild ist eine Schutzwaffe, die den Spieler vor Angriffen schützt.
White Shield=Weißer Schild
Grey Shield=Grauer Schild
Light Grey Shield=Hellgrauer Schild
Black Shield=Schwarzer Schild
Red Shield=Roter Schild
Yellow Shield=Gelber Schild
Green Shield=Grüner Schild
Cyan Shield=Türkiser Schild
Blue Shield=Blauer Schild
Magenta Shield=Magenta Schild
Orange Shield=Oranger Schild
Purple Shield=Violetter Schild
Brown Shield=Brauner Schild
Pink Shield=Rosa Schild
Lime Shield=Hellgrüner Schild
Light Blue Shield=Hellblauer Schild

View File

@ -0,0 +1,19 @@
# textdomain: mcl_shields
Shield=
A shield is a tool used for protecting the player against attacks.=
White Shield=
Grey Shield=
Light Grey Shield=
Black Shield=
Red Shield=
Yellow Shield=
Green Shield=
Cyan Shield=
Blue Shield=
Magenta Shield=
Orange Shield=
Purple Shield=
Brown Shield=
Pink Shield=
Lime Shield=
Light Blue Shield=

View File

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

View File

@ -0,0 +1,88 @@
# Blender v3.0.0 OBJ File: ''
# www.blender.org
mtllib mcl_shield.mtl
o Cube.002_Cube.003
v 4.663009 11.096291 6.387994
v 4.663009 4.596560 5.241916
v 5.213008 4.596560 5.241916
v 5.213008 11.096291 6.387994
v 5.213007 13.197435 -5.528180
v 5.213007 6.697705 -6.674258
v 4.663008 6.697705 -6.674258
v 4.663008 13.197435 -5.528180
v 4.663008 8.641873 -1.863572
v 4.663008 8.068833 1.386293
v 1.363008 8.068833 1.386294
v 1.363008 8.641873 -1.863572
v 1.363008 9.152122 1.577307
v 1.363008 9.725162 -1.672559
v 4.663008 9.152122 1.577306
v 4.663008 9.725162 -1.672559
vt 0.015625 0.984375
vt 0.203125 0.984375
vt 0.203125 1.000000
vt 0.015625 1.000000
vt 0.203125 0.640625
vt 0.203125 0.984375
vt 0.015625 0.984375
vt 0.015625 0.640625
vt 0.015625 0.984375
vt 0.015625 0.640625
vt -0.000000 0.640625
vt -0.000000 0.984375
vt 0.203125 0.984375
vt 0.390625 0.984375
vt 0.390625 1.000000
vt 0.203125 1.000000
vt 0.203125 0.984375
vt 0.203125 0.640625
vt 0.218750 0.640625
vt 0.218750 0.984375
vt 0.406250 0.640625
vt 0.406250 0.984375
vt 0.218750 0.984375
vt 0.218750 0.640625
vt 0.531250 0.812500
vt 0.625000 0.812500
vt 0.625000 0.906250
vt 0.531250 0.906250
vt 0.500000 0.906250
vt 0.500000 0.812500
vt 0.531250 0.812500
vt 0.531250 0.906250
vt 0.406250 0.812500
vt 0.500000 0.812500
vt 0.500000 0.906250
vt 0.406250 0.906250
vt 0.625000 0.812500
vt 0.656250 0.812500
vt 0.656250 0.906250
vt 0.625000 0.906250
vt 0.562500 1.000000
vt 0.531250 1.000000
vt 0.531250 0.906250
vt 0.562500 0.906250
vt 0.531250 1.000000
vt 0.500000 1.000000
vt 0.500000 0.906250
vt 0.531250 0.906250
vn 0.0000 -0.1736 0.9848
vn 1.0000 0.0000 -0.0000
vn 0.0000 -0.9848 -0.1736
vn 0.0000 0.1736 -0.9848
vn 0.0000 0.9848 0.1736
vn -1.0000 -0.0000 0.0000
usemtl Material.002
s 1
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 4/6/2 3/7/2 6/8/2
f 6/9/3 3/10/3 2/11/3 7/12/3
f 7/13/4 8/14/4 5/15/4 6/16/4
f 8/17/5 1/18/5 4/19/5 5/20/5
f 7/21/6 2/22/6 1/23/6 8/24/6
f 9/25/3 10/26/3 11/27/3 12/28/3
f 12/29/6 11/30/6 13/31/6 14/32/6
f 14/33/5 13/34/5 15/35/5 16/36/5
f 16/37/2 15/38/2 10/39/2 9/40/2
f 12/41/4 14/42/4 16/43/4 9/44/4
f 13/45/1 11/46/1 10/47/1 15/48/1

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -12,6 +12,14 @@ mcl_damage.register_modifier(function(obj, damage, reason)
local hp = obj:get_hp()
if hp - damage <= 0 then
local wield = obj:get_wielded_item()
local in_offhand = false
if not (wield:get_name() == "mobs_mc:totem") then
local inv = obj:get_inventory()
if inv then
wield = obj:get_inventory():get_stack("offhand", 1)
in_offhand = true
end
end
if wield:get_name() == "mobs_mc:totem" then
local ppos = obj:get_pos()
local pnname = minetest.get_node(ppos).name
@ -28,8 +36,13 @@ mcl_damage.register_modifier(function(obj, damage, reason)
if not minetest.is_creative_enabled(obj:get_player_name()) then
wield:take_item()
if in_offhand then
obj:get_inventory():set_stack("offhand", 1, wield)
mcl_inventory.update_inventory_formspec(obj)
else
obj:set_wielded_item(wield)
end
end
-- Effects
minetest.sound_play({name = "mcl_totems_totem", gain = 1}, {pos=ppos, max_hear_distance = 16}, true)

View File

@ -9,7 +9,8 @@ local animation_blend = 0
local function get_mouse_button(player)
local controls = player:get_player_control()
local get_wielded_item_name = player:get_wielded_item():get_name()
if controls.RMB and not string.find(get_wielded_item_name, "mcl_bows:bow") and not string.find(get_wielded_item_name, "mcl_bows:crossbow") or controls.LMB then
if controls.RMB and not string.find(get_wielded_item_name, "mcl_bows:bow") and not string.find(get_wielded_item_name, "mcl_bows:crossbow") and
not mcl_shields.wielding_shield(player, 1) and not mcl_shields.wielding_shield(player, 2) or controls.LMB then
return true
else
return false
@ -188,6 +189,9 @@ minetest.register_globalstep(function(dtime)
animation_speed_mod = animation_speed_mod / 2
end
if mcl_shields.is_blocking(player) then
animation_speed_mod = animation_speed_mod / 2
end
-- ask if player is swiming
@ -204,6 +208,8 @@ minetest.register_globalstep(function(dtime)
or walking and velocity.x < -0.35
or walking and velocity.z > 0.35
or walking and velocity.z < -0.35 then
local wielded_itemname = player:get_wielded_item():get_name()
local no_arm_moving = string.find(wielded_itemname, "mcl_bows:bow") or mcl_shields.wielding_shield(player, 1) or mcl_shields.wielding_shield(player, 2)
if player_sneak[name] ~= controls.sneak then
player_anim[name] = nil
player_sneak[name] = controls.sneak
@ -212,9 +218,9 @@ minetest.register_globalstep(function(dtime)
player_set_animation(player, "swim_walk_mine", animation_speed_mod)
elseif not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_walk", animation_speed_mod)
elseif string.find(player:get_wielded_item():get_name(), "mcl_bows:bow") and controls.RMB and controls.sneak or string.find(player:get_wielded_item():get_name(), "mcl_bows:crossbow_") and controls.sneak then
elseif no_arm_moving and controls.RMB and controls.sneak or string.find(wielded_itemname, "mcl_bows:crossbow_") and controls.sneak then
player_set_animation(player, "bow_sneak", animation_speed_mod)
elseif string.find(player:get_wielded_item():get_name(), "mcl_bows:bow") and controls.RMB or string.find(player:get_wielded_item():get_name(), "mcl_bows:crossbow_") then
elseif no_arm_moving and controls.RMB or string.find(wielded_itemname, "mcl_bows:crossbow_") then
player_set_animation(player, "bow_walk", animation_speed_mod)
elseif is_sprinting == true and get_mouse_button(player) == true and not controls.sneak and not head_in_water then
player_set_animation(player, "run_walk_mine", animation_speed_mod)

View File

@ -336,8 +336,12 @@ minetest.register_globalstep(function(dtime)
player_velocity_old = player:get_velocity() or player:get_player_velocity()
-- controls right and left arms pitch when shooting a bow
if string.find(wielded:get_name(), "mcl_bows:bow") and control.RMB then
-- controls right and left arms pitch when shooting a bow or blocking
if mcl_shields.is_blocking(player) == 2 then
set_bone_position_conditional(player, "Arm_Right_Pitch_Control", vector.new(-3, 5.785, 0), vector.new(20, -20, 0))
elseif mcl_shields.is_blocking(player) == 1 then
set_bone_position_conditional(player, "Arm_Left_Pitch_Control", vector.new(3, 5.785, 0), vector.new(20, 20, 0))
elseif string.find(wielded:get_name(), "mcl_bows:bow") and control.RMB then
set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35))
set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35))
-- controls right and left arms pitch when holing a loaded crossbow

View File

@ -1,5 +1,5 @@
name = mcl_playerplus
author = TenPlus1
description = Adds some simple player-related gameplay effects: Hurt by touching a cactus, suffocation and more.
depends = mcl_init, mcl_core, mcl_particles, mcl_hunger, playerphysics, mcl_playerinfo, mcl_weather, mcl_spawn, mcl_enchanting, mcl_damage, mcl_sprint
depends = mcl_init, mcl_core, mcl_particles, mcl_hunger, playerphysics, mcl_playerinfo, mcl_weather, mcl_spawn, mcl_enchanting, mcl_damage, mcl_sprint, mcl_shields

View File

@ -6,7 +6,7 @@ mcl_wieldview = {
}
function mcl_wieldview.get_item_texture(itemname)
if itemname == "" then
if itemname == "" or minetest.get_item_group(itemname, "no_wieldview") ~= 0 then
return
end
@ -113,6 +113,10 @@ minetest.register_entity("mcl_wieldview:wieldnode", {
self.object:set_properties({textures = {""}})
end
if minetest.get_item_group(itemstring, "no_wieldview") ~= 0 then
self.object:set_properties({textures = {""}})
end
self.itemstring = itemstring
end
else