Merge testing into production

This commit is contained in:
kay27 2022-01-26 02:20:58 +04:00
commit 014a2872e2
74 changed files with 1229 additions and 106 deletions

View File

@ -43,6 +43,7 @@
* Laurent Rocher
* Li0n
* Marcin Serwin
* Mental-Inferno
* Midgard
* MysticTempest
* Nicholas Niro

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

@ -10,6 +10,7 @@ This mod adds mobs which closely resemble the mobs from the game Minecraft, vers
* [22i](https://github.com/22i): Models (done in Blender) and mob icons for spawn eggs
* [XSSheep](https://www.planetminecraft.com/member/xssheep/): Mob and item textures (from [Pixel Perfection](https://www.planetminecraft.com/texture_pack/131pixel-perfection/))
* MysticTempest: More mob textures
* [Mental-Inferno](https://github.com/Mental-Inferno): Code
* See `LICENSE_media.md` for detailed credits about each file
## Licensing

View File

@ -1 +1,2 @@
mcl_mobs
mcl_mobs
mcl_potions

View File

@ -76,7 +76,122 @@ local spider = {
}
mobs:register_mob("mobs_mc:spider", spider)
-- Cave spider
--Cave Spider
local cave_spider = {
description = S("Cave Spider"),
type = "monster",
spawn_class = "hostile",
passive = false,
hostile = true,
always_climb = true,
docile_by_day = true,
rotate = 270,
--[[work-around for poison until punch augmentations are added to mob API
works functionally but the jump while punching animation in gone--]]
reach = 0.5, --makes it look like it's biting
attack_type = "projectile",
arrow = "spider_venom", --ultra short range projectile to inflict poison effect + punch damage
projectile_cooldown_min = 1,
projectile_cooldown_max = 1,
shoot_arrow = function(self, pos, dir)
local dmg = 2
mobs.shoot_projectile_handling("mobs_mc:spider_venom", pos, dir, self.object:get_yaw(), self.object, 1, dmg,nil,nil,nil,-0.6)
end,
hp_min = 12, --reflect Minecraft health
hp_max = 12,
ignores_cobwebs = true,
xp_min = 5,
xp_max = 5,
eye_height = 0.475,
armor = {fleshy = 100, arthropod = 100},
collisionbox = {-0.35, -0.01, -0.35, 0.35, 0.49, 0.35},
visual = "mesh",
mesh = "mobs_mc_spider.b3d",
textures = {
{"mobs_mc_cave_spider.png^(mobs_mc_spider_eyes.png^[makealpha:0,0,0)"},
},
visual_size = {x=1.66666, y=1.5},
makes_footstep_sound = false,
sounds = {
random = "mobs_mc_spider_random",
attack = "mobs_mc_spider_attack",
damage = "mobs_mc_spider_hurt",
death = "mobs_mc_spider_death",
-- TODO: sounds: walk
distance = 16,
},
base_pitch = 1.25,
walk_velocity = 1.3,
run_velocity = 3.5, --Compenstaing for the loss of aility to leap while attacking
jump = true,
jump_height = 4,
view_range = 16,
floats = 1,
drops = {
{name = mobs_mc.items.string, chance = 1, min = 0, max = 2, looting = "common"},
{name = mobs_mc.items.spider_eye, chance = 3, min = 1, max = 1, looting = "common", looting_chance_function = function(lvl)
return 1 - 2 / (lvl + 3)
end},
},
specific_attack = { "player", "mobs_mc:iron_golem" },
fear_height = 4,
animation = {
stand_speed = 10,
walk_speed = 25,
run_speed = 50,
stand_start = 20,
stand_end = 40,
walk_start = 0,
walk_end = 20,
run_start = 0,
run_end = 20,
},
}
mobs:register_mob("mobs_mc:cave_spider", cave_spider)
-- spider_venom (projectile)
mobs:register_arrow("mobs_mc:spider_venom", {
visual = "sprite",
visual_size = {x = 0.1, y = 0.1},
textures = {"hbhunger_icon_health_poison.png"},
velocity = 1,
collisionbox = {-.5, -.5, -.5, .5, .5, .5},
tail = 0,
hit_player = function(self, player)
player:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = self._damage},
}, nil)
mcl_potions.poison_func(player, 0.5, 8) --modified cuz MC rate is an unessesarily bad fraction
local vel = player:get_velocity()
player:add_velocity({x=(vel.x * -1.5), y=6, z=(vel.z * -1.5)}) --"chaos knockback" effect (Temporary until I understand how to implement knockback for a projectile)
end,
hit_mob = function(self, mob)
if mob ~= self then --due to low power of attack, spider can shoot itself while chasing a target
mob:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = self._damage},
}, nil)
if ((mob ~= "mobs_mc:cave_spider") and (mob ~= "mobs_mc:spider")) then --spider's don't have automatic immunity to poison yet so this is a stop gap solution
mcl_potions.poison_func(mob, 0.5, 8) --modified cuz MC rate is an unessesarily bad fraction
end
local vel = mob:get_velocity()
mob:add_velocity({x=(-1 * vel.z), y=6, z=(-1 * vel.x)}) --"chaos knockback" effect (Temporary until I understand how to implement knockback for a projectile)
end
end,
})
--[[ Cave spider (Previous code)
local cave_spider = table.copy(spider)
cave_spider.description = S("Cave Spider")
cave_spider.textures = { {"mobs_mc_cave_spider.png^(mobs_mc_spider_eyes.png^[makealpha:0,0,0)"} }
@ -91,7 +206,7 @@ cave_spider.walk_velocity = 1.3
cave_spider.run_velocity = 3.2
cave_spider.sounds = table.copy(spider.sounds)
cave_spider.sounds.base_pitch = 1.25
mobs:register_mob("mobs_mc:cave_spider", cave_spider)
mobs:register_mob("mobs_mc:cave_spider", cave_spider)--]]
mobs:spawn_specific(

View File

@ -362,6 +362,10 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
if inv:get_stack("armor", 5):is_empty() then
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)
@ -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

@ -544,6 +544,16 @@ for s=1, #specialstones do
clust_size = 3,
y_min = mcl_vars.mg_nether_min,
y_max = mcl_vars.mg_nether_max,
noise_params = {
offset = 0,
scale = 1,
spread = {x=250, y=250, z=250},
seed = 12345,
octaves = 3,
persist = 0.6,
lacunarity = 2,
flags = "defaults",
},
})
minetest.register_ore({
ore_type = "blob",
@ -554,6 +564,16 @@ for s=1, #specialstones do
clust_size = 5,
y_min = mcl_vars.mg_nether_min,
y_max = mcl_vars.mg_nether_max,
noise_params = {
offset = 0,
scale = 1,
spread = {x=250, y=250, z=250},
seed = 12345,
octaves = 3,
persist = 0.6,
lacunarity = 2,
flags = "defaults",
},
})
end

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,50 +247,59 @@ 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
local placement
self._placement = math.random(1, 2)
if self._placement == 1 then
placement = "front"
if not mcl_shields.is_blocking(obj) then
local placement
self._placement = math.random(1, 2)
if self._placement == 1 then
placement = "front"
else
placement = "back"
end
self._in_player = true
if self._placement == 2 then
self._rotation_station = 90
else
self._rotation_station = -90
end
self._y_position = random_arrow_positions("y", placement)
self._x_position = random_arrow_positions("x", placement)
if self._y_position > 6 and self._x_position < 2 and self._x_position > -2 then
self._attach_parent = "Head"
self._y_position = self._y_position - 6
elseif self._x_position > 2 then
self._attach_parent = "Arm_Right"
self._y_position = self._y_position - 3
self._x_position = self._x_position - 2
elseif self._x_position < -2 then
self._attach_parent = "Arm_Left"
self._y_position = self._y_position - 3
self._x_position = self._x_position + 2
else
self._attach_parent = "Body"
end
self._z_rotation = math.random(-30, 30)
self._y_rotation = math.random( -30, 30)
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
placement = "back"
self._blocked = true
self.object:set_velocity(vector.multiply(self.object:get_velocity(), -0.25))
end
self._in_player = true
if self._placement == 2 then
self._rotation_station = 90
else
self._rotation_station = -90
end
self._y_position = random_arrow_positions("y", placement)
self._x_position = random_arrow_positions("x", placement)
if self._y_position > 6 and self._x_position < 2 and self._x_position > -2 then
self._attach_parent = "Head"
self._y_position = self._y_position - 6
elseif self._x_position > 2 then
self._attach_parent = "Arm_Right"
self._y_position = self._y_position - 3
self._x_position = self._x_position - 2
elseif self._x_position < -2 then
self._attach_parent = "Arm_Left"
self._y_position = self._y_position - 3
self._x_position = self._x_position + 2
else
self._attach_parent = "Body"
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})
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,462 @@
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 not shield then return end
local luaentity = shield:get_luaentity()
if not luaentity then return end
luaentity._blocking = block
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,7 +36,12 @@ mcl_damage.register_modifier(function(obj, damage, reason)
if not minetest.is_creative_enabled(obj:get_player_name()) then
wield:take_item()
obj:set_wielded_item(wield)
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

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

@ -120,6 +120,114 @@ end
local node_stand, node_stand_below, node_head, node_feet
local function roundN(n, d)
if type(n) ~= "number" then return n end
local m = 10^d
return math.floor(n * m + 0.5) / m
end
local function close_enough(a,b)
local rt=true
if type(a) == "table" and type(b) == "table" then
for k,v in pairs(a) do
if roundN(v,2) ~= roundN(b[k],2) then
rt=false
break
end
end
else
rt = roundN(a,2) == roundN(b,2)
end
return rt
end
local function props_changed(props,oldprops)
local changed=false
local p={}
for k,v in pairs(props) do
if not close_enough(v,oldprops[k]) then
p[k]=v
changed=true
end
end
return changed,p
end
--test if assert works
assert(true)
assert(not false)
--test data for == and ~=
local test_equal1=42
local test_equal2=42.0
local test_equal3=42.1
assert(test_equal1==test_equal1)
assert(test_equal1==test_equal2)
assert(test_equal1~=test_equal3)
--testdata for roundN
local test_round1=15
local test_round2=15.00199999999
local test_round3=15.00111111
local test_round4=15.00999999
assert(roundN(test_round1,2)==roundN(test_round1,2)) --test again if basic equality works because wth not
assert(roundN(test_round1,2)==roundN(test_round2,2))
assert(roundN(test_round1,2)==roundN(test_round3,2))
assert(roundN(test_round1,2)~=roundN(test_round4,2))
-- tests for close_enough
local test_cb = {-0.35,0,-0.35,0.35,0.8,0.35} --collisionboxes
local test_cb_close = {-0.351213,0,-0.35,0.35,0.8,0.351212}
local test_cb_diff = {-0.35,0,-1.35,0.35,0.8,0.35}
local test_eh = 1.65 --eye height
local test_eh_close = 1.65123123
local test_eh_diff = 1.35
local test_nt = { r = 225, b = 225, a = 225, g = 225 } --nametag
local test_nt_diff = { r = 225, b = 225, a = 0, g = 225 }
assert(close_enough(test_cb,test_cb_close))
assert(not close_enough(test_cb,test_cb_diff))
assert(close_enough(test_eh,test_eh_close))
assert(not close_enough(test_eh,test_eh_diff))
assert(not close_enough(test_nt,test_nt_diff)) --no floats involved here
--tests for props_changed
local test_properties_set1={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}
local test_properties_set2={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}
local test_p1,p=props_changed(test_properties_set1,test_properties_set1)
local test_p2,p=props_changed(test_properties_set1,test_properties_set2)
assert(not test_p1)
assert(test_p2)
-- we still don't really know if lua is lying to us! but at least everything *seems* to be ok
local function set_properties_conditional(player,props)
local changed,p=props_changed(props,player:get_properties())
if changed then
player:set_properties(p)
end
end
local function set_bone_position_conditional(player,b,p,r) --bone,position,rotation
local oldp,oldr=player:get_bone_position(b)
if vector.equals(vector.round(oldp),vector.round(p)) and vector.equals(vector.round(oldr),vector.round(r)) then
return
end
player:set_bone_position(b,p,r)
end
minetest.register_globalstep(function(dtime)
time = time + dtime
@ -214,78 +322,82 @@ minetest.register_globalstep(function(dtime)
end
if wielded_def and wielded_def._mcl_toollike_wield then
player:set_bone_position("Wield_Item", vector.new(0,3.9,1.3), vector.new(90,0,0))
set_bone_position_conditional(player,"Wield_Item", vector.new(0,3.9,1.3), vector.new(90,0,0))
elseif string.find(wielded:get_name(), "mcl_bows:bow") then
player:set_bone_position("Wield_Item", vector.new(.5,4.5,-1.6), vector.new(90,0,20))
set_bone_position_conditional(player,"Wield_Item", vector.new(.5,4.5,-1.6), vector.new(90,0,20))
elseif string.find(wielded:get_name(), "mcl_bows:crossbow_loaded") then
player:set_bone_position("Wield_Item", vector.new(-1.5,5.7,1.8), vector.new(64,90,0))
set_bone_position_conditional(player,"Wield_Item", vector.new(-1.5,5.7,1.8), vector.new(64,90,0))
elseif string.find(wielded:get_name(), "mcl_bows:crossbow") then
player:set_bone_position("Wield_Item", vector.new(-1.5,5.7,1.8), vector.new(90,90,0))
set_bone_position_conditional(player,"Wield_Item", vector.new(-1.5,5.7,1.8), vector.new(90,90,0))
else
player:set_bone_position("Wield_Item", vector.new(-1.5,4.9,1.8), vector.new(135,0,90))
set_bone_position_conditional(player,"Wield_Item", vector.new(-1.5,4.9,1.8), vector.new(135,0,90))
end
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
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35))
player:set_bone_position("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 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
elseif string.find(wielded:get_name(), "mcl_bows:crossbow_loaded") then
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35))
player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35))
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 loading a crossbow
elseif string.find(wielded:get_name(), "mcl_bows:crossbow_") then
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(45,-20,25))
player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(55,20,-45))
set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(45,-20,25))
set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(55,20,-45))
-- when punching
elseif control.LMB and not parent then
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0))
player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0))
set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0))
set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0))
-- when holding an item.
elseif wielded:get_name() ~= "" then
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(20,0,0))
player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0))
set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(20,0,0))
set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0))
-- resets arms pitch
else
player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0))
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0))
set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0))
set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0))
end
if elytra.active then
-- set head pitch and yaw when flying
player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0))
set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0))
-- sets eye height, and nametag color accordingly
player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }})
set_properties_conditional(player,{collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }})
-- control body bone when flying
player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0))
set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0))
elseif parent then
local parent_yaw = degrees(parent:get_yaw())
player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }})
player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch, -limit_vel_yaw(yaw, parent_yaw) + parent_yaw, 0))
player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0))
set_properties_conditional(player,{collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }})
set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch, -limit_vel_yaw(yaw, parent_yaw) + parent_yaw, 0))
set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0,0,0))
elseif control.sneak then
-- controls head pitch when sneaking
player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, player_vel_yaw - yaw))
set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, player_vel_yaw - yaw))
-- sets eye height, and nametag color accordingly
player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }})
set_properties_conditional(player,{collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }})
-- sneaking body conrols
player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0))
set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0))
elseif get_item_group(mcl_playerinfo[name].node_head, "water") ~= 0 and is_sprinting(name) == true then
-- set head pitch and yaw when swimming
player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0))
set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0))
-- sets eye height, and nametag color accordingly
player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,0.8,0.312}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }})
set_properties_conditional(player,{collisionbox = {-0.312,0,-0.312,0.312,0.8,0.312}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }})
-- control body bone when swimming
player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0))
set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0))
else
-- sets eye height, and nametag color accordingly
player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }})
set_properties_conditional(player,{collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }})
player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, 0))
player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0))
set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, 0))
set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0))
end
-- Update jump status immediately since we need this info in real time.

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

@ -0,0 +1,28 @@
# Status Effect Refresh for Mineclone 5
This allows the use of status effect function from mcl_potions and prevents them
from continuing their effect after player respawn
## Licensing
MIT License
Copyright (c) 2022 Mental-Inferno
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,3 @@
minetest.register_on_respawnplayer(function(player)
mcl_potions._reset_player_effects(player, true)
end)

View File

@ -0,0 +1,4 @@
name = mcl_refresh_status
author = Mental-Inferno
description = Resets status-effects inflicted on player when player respawns
depends = mcl_potions

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
@ -41,14 +41,19 @@ function mcl_wieldview.update_wielded_item(player)
local def = mcl_wieldview.players[player]
if def.item == itemname then
if def and (def.item == itemname) then
return
end
def.item = itemname
def.texture = mcl_wieldview.get_item_texture(itemname) or "blank.png"
local texture = mcl_wieldview.get_item_texture(itemname) or "blank.png"
mcl_player.player_set_wielditem(player, def.texture)
local new_def = {
item = itemname,
texture = texture,
}
mcl_wieldview.players[player] = new_def
mcl_player.player_set_wielditem(player, texture)
end
minetest.register_on_joinplayer(function(player)
@ -113,6 +118,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