Merge pull request 'master' (#1) from MineClone5/MineClone5:master into master
Reviewed-on: NO11/MineClone5#1
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
local PARTICLES_COUNT_RAIN = 30
|
||||
local PARTICLES_COUNT_THUNDER = 45
|
||||
local PARTICLES_COUNT_RAIN = 100
|
||||
local PARTICLES_COUNT_THUNDER = 300
|
||||
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
|
||||
|
@ -19,6 +19,45 @@ mcl_weather.rain = {
|
|||
|
||||
init_done = false,
|
||||
}
|
||||
local update_sound={}
|
||||
local vel=math.random(0,3)
|
||||
local falling_speed=math.random(10,15)
|
||||
local size = math.random(1,3)
|
||||
local psdef= {
|
||||
amount = mcl_weather.rain.particles_count,
|
||||
time=0,
|
||||
minpos = vector.new(-6,3,-6),
|
||||
maxpos = vector.new(6,15,6),
|
||||
minvel = vector.new(-vel,-falling_speed,-vel),
|
||||
maxvel = math.random(vel,-falling_speed+vel,vel),
|
||||
minacc = vector.new(0,0,0),
|
||||
maxacc = vector.new(0,-0.4,0),
|
||||
minexptime = 0.5,
|
||||
maxexptime = 2,
|
||||
minsize = size,
|
||||
maxsize= size*2,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
}
|
||||
local psdef_backsplash= {
|
||||
amount = 10,
|
||||
time=0,
|
||||
minpos = vector.new(-3,-1,-3),
|
||||
maxpos = vector.new(3,0,3),
|
||||
minvel = vector.new(-vel,falling_speed*2,-vel),
|
||||
maxvel = math.random(vel,falling_speed*2+vel,vel),
|
||||
minacc = vector.new(0,0,0),
|
||||
maxacc = vector.new(0,0,0),
|
||||
minexptime = 0.1,
|
||||
maxexptime = 0.2,
|
||||
minsize = size*0.1,
|
||||
maxsize= size*0.5,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
}
|
||||
local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png", "weather_pack_rain_raindrop_1.png"}
|
||||
|
||||
function mcl_weather.rain.sound_handler(player)
|
||||
return minetest.sound_play("weather_rain", {
|
||||
|
@ -44,42 +83,18 @@ function mcl_weather.rain.set_sky_box()
|
|||
end
|
||||
end
|
||||
|
||||
-- creating manually parctiles instead of particles spawner because of easier to control
|
||||
-- spawn position.
|
||||
-- no no no NO NO f*.. no. no manual particle creatin' PLS!! this sends EVERY particle over the net.
|
||||
function mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.last_rp_count = 0
|
||||
for i=mcl_weather.rain.particles_count, 1,-1 do
|
||||
local random_pos_x, random_pos_y, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player)
|
||||
if mcl_weather.is_outdoor({x=random_pos_x, y=random_pos_y, z=random_pos_z}) then
|
||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1
|
||||
minetest.add_particle({
|
||||
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
|
||||
velocity = {x=0, y=-10, z=0},
|
||||
acceleration = {x=0, y=-30, z=0},
|
||||
expirationtime = 1.0,
|
||||
size = math.random(0.5, 3),
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
texture = mcl_weather.rain.get_texture(),
|
||||
playername = player:get_player_name()
|
||||
})
|
||||
end
|
||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.particles_count
|
||||
for k,v in pairs(textures) do
|
||||
psdef.texture=v
|
||||
mcl_weather.add_spawner_player(player,"rain"..k,psdef)
|
||||
end
|
||||
end
|
||||
|
||||
-- Simple random texture getter
|
||||
function mcl_weather.rain.get_texture()
|
||||
local texture_name
|
||||
local random_number = math.random()
|
||||
if random_number > 0.33 then
|
||||
texture_name = "weather_pack_rain_raindrop_1.png"
|
||||
elseif random_number > 0.66 then
|
||||
texture_name = "weather_pack_rain_raindrop_2.png"
|
||||
else
|
||||
texture_name = "weather_pack_rain_raindrop_3.png"
|
||||
psdef_backsplash.texture=textures[math.random(1,#textures)]
|
||||
local l=mcl_weather.add_spawner_player(player,"rainbacksplash",psdef_backsplash)
|
||||
if l then
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
return texture_name;
|
||||
end
|
||||
|
||||
-- register player for rain weather.
|
||||
|
@ -89,6 +104,7 @@ function mcl_weather.rain.add_player(player)
|
|||
local player_meta = {}
|
||||
player_meta.origin_sky = {player:get_sky()}
|
||||
mcl_weather.players[player:get_player_name()] = player_meta
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -99,6 +115,7 @@ function mcl_weather.rain.remove_player(player)
|
|||
if player_meta and player_meta.origin_sky then
|
||||
player:set_clouds({color="#FFF0F0E5"})
|
||||
mcl_weather.players[player:get_player_name()] = nil
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -119,6 +136,7 @@ end)
|
|||
-- have few seconds delay before each check to avoid on/off sound too often
|
||||
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
|
||||
function mcl_weather.rain.update_sound(player)
|
||||
if not update_sound[player:get_player_name()] then return end
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta then
|
||||
if player_meta.sound_updated and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
||||
|
@ -136,6 +154,7 @@ function mcl_weather.rain.update_sound(player)
|
|||
|
||||
player_meta.sound_updated = minetest.get_gametime()
|
||||
end
|
||||
update_sound[player:get_player_name()]=false
|
||||
end
|
||||
|
||||
-- rain sound removed from player.
|
||||
|
@ -158,7 +177,8 @@ function mcl_weather.rain.clear()
|
|||
for _, player in pairs(get_connected_players()) do
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
end
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
|
@ -177,8 +197,10 @@ function mcl_weather.rain.make_weather()
|
|||
end
|
||||
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
|
||||
local pos=player:get_pos()
|
||||
if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(pos) or not mcl_weather.is_outdoor(pos) then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
return false
|
||||
end
|
||||
mcl_weather.rain.add_player(player)
|
||||
|
@ -190,8 +212,12 @@ end
|
|||
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
|
||||
function mcl_weather.rain.set_particles_mode(mode)
|
||||
if mode == "thunder" then
|
||||
psdef.amount=PARTICLES_COUNT_THUNDER
|
||||
psdef_backsplash.amount=PARTICLES_COUNT_THUNDER
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
||||
else
|
||||
psdef.amount=PARTICLES_COUNT_RAIN
|
||||
psdef_backsplash.amount=PARTICLES_COUNT_RAIN
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,30 +5,25 @@ mcl_weather.snow = {}
|
|||
mcl_weather.snow.particles_count = 15
|
||||
mcl_weather.snow.init_done = false
|
||||
|
||||
-- calculates coordinates and draw particles for snow weather
|
||||
function mcl_weather.snow.add_snow_particles(player)
|
||||
mcl_weather.rain.last_rp_count = 0
|
||||
for i=mcl_weather.snow.particles_count, 1,-1 do
|
||||
local random_pos_x, _, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player)
|
||||
local random_pos_y = math.random() + math.random(player:get_pos().y - 1, player:get_pos().y + 7)
|
||||
if minetest.get_node_light({x=random_pos_x, y=random_pos_y, z=random_pos_z}, 0.5) == 15 then
|
||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1
|
||||
minetest.add_particle({
|
||||
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
|
||||
velocity = {x = math.random(-100,100)*0.001, y = math.random(-300,-100)*0.004, z = math.random(-100,100)*0.001},
|
||||
acceleration = {x = 0, y=0, z = 0},
|
||||
expirationtime = 8.0,
|
||||
size = 1,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
object_collision = false,
|
||||
vertical = false,
|
||||
texture = mcl_weather.snow.get_texture(),
|
||||
playername = player:get_player_name()
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
local psdef= {
|
||||
amount = 99,
|
||||
time = 0, --stay on til we turn it off
|
||||
minpos = vector.new(-15,-5,-15),
|
||||
maxpos =vector.new(15,10,15),
|
||||
minvel = vector.new(0,-1,0),
|
||||
maxvel = vector.new(0,-4,0),
|
||||
minacc = vector.new(0,-1,0),
|
||||
maxacc = vector.new(0,-4,0),
|
||||
minexptime = 1,
|
||||
maxexptime = 1,
|
||||
minsize = 0.5,
|
||||
maxsize = 5,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
object_collision = true,
|
||||
vertical = true,
|
||||
glow = 1
|
||||
}
|
||||
|
||||
function mcl_weather.snow.set_sky_box()
|
||||
mcl_weather.skycolor.add_layer(
|
||||
|
@ -48,6 +43,7 @@ end
|
|||
function mcl_weather.snow.clear()
|
||||
mcl_weather.skycolor.remove_layer("weather-pack-snow-sky")
|
||||
mcl_weather.snow.init_done = false
|
||||
mcl_weather.remove_all_spawners()
|
||||
end
|
||||
|
||||
-- Simple random texture getter
|
||||
|
@ -74,10 +70,14 @@ minetest.register_globalstep(function(dtime)
|
|||
end
|
||||
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
|
||||
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos()) or not mcl_weather.is_outdoor(player:get_pos())) then
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
return false
|
||||
end
|
||||
mcl_weather.snow.add_snow_particles(player)
|
||||
for i=1,2 do
|
||||
psdef.texture="weather_pack_snow_snowflake"..i..".png"
|
||||
mcl_weather.add_spawner_player(player,"snow"..i,psdef)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
|
|
@ -47,6 +47,35 @@ local function save_weather()
|
|||
end
|
||||
minetest.register_on_shutdown(save_weather)
|
||||
|
||||
local particlespawners={}
|
||||
function mcl_weather.add_spawner_player(pl,id,ps)
|
||||
local name=pl:get_player_name()
|
||||
if not particlespawners[name] then
|
||||
particlespawners[name] = {}
|
||||
end
|
||||
if not particlespawners[name][id] then
|
||||
ps.playername =name
|
||||
ps.attached = pl
|
||||
particlespawners[name][id]=minetest.add_particlespawner(ps)
|
||||
return particlespawners[name][id]
|
||||
end
|
||||
end
|
||||
function mcl_weather.remove_spawners_player(pl)
|
||||
local name=pl:get_player_name()
|
||||
if not particlespawners[name] then return end
|
||||
for k,v in pairs(particlespawners[name]) do
|
||||
minetest.delete_particlespawner(v)
|
||||
end
|
||||
particlespawners[name] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_weather.remove_all_spawners()
|
||||
for k,v in pairs(minetest.get_connected_players()) do
|
||||
mcl_weather.remove_spawners_player(v)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_weather.get_rand_end_time(min_duration, max_duration)
|
||||
local r
|
||||
if min_duration and max_duration then
|
||||
|
@ -92,36 +121,6 @@ function mcl_weather.is_underwater(player)
|
|||
return false
|
||||
end
|
||||
|
||||
-- trying to locate position for particles by player look direction for performance reason.
|
||||
-- it is costly to generate many particles around player so goal is focus mainly on front view.
|
||||
function mcl_weather.get_random_pos_by_player_look_dir(player)
|
||||
local look_dir = player:get_look_dir()
|
||||
local player_pos = player:get_pos()
|
||||
|
||||
local random_pos_x, random_pos_y, random_pos_z
|
||||
|
||||
if look_dir.x > 0 then
|
||||
if look_dir.z > 0 then
|
||||
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
|
||||
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
||||
else
|
||||
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
|
||||
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
|
||||
end
|
||||
else
|
||||
if look_dir.z > 0 then
|
||||
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
|
||||
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
||||
else
|
||||
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
|
||||
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
|
||||
end
|
||||
end
|
||||
|
||||
random_pos_y = math.random() + math.random(player_pos.y + 10, player_pos.y + 15)
|
||||
return random_pos_x, random_pos_y, random_pos_z
|
||||
end
|
||||
|
||||
local t, wci = 0, mcl_weather.check_interval
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
|
|
|
@ -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")).."]"..
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_offhand
|
||||
author = NO11
|
||||
depends = mcl_inventory
|
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 168 B |
|
@ -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)
|
||||
|
|
|
@ -248,7 +248,7 @@ function mcl_beds.register_bed(name, def)
|
|||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
-- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks!
|
||||
groups = {handy = 1, flammable = 3, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
|
||||
groups = {handy = 1, flammable = -1, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
|
||||
_mcl_hardness = 0.2,
|
||||
_mcl_blast_resistance = 1,
|
||||
sounds = def.sounds or default_sounds,
|
||||
|
@ -275,5 +275,3 @@ function mcl_beds.register_bed(name, def)
|
|||
|
||||
doc.add_entry_alias("nodes", name.."_bottom", "nodes", name.."_top")
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -116,7 +116,7 @@ end
|
|||
|
||||
-- Bow item, uncharged state
|
||||
minetest.register_tool("mcl_bows:crossbow", {
|
||||
description = S("Corssbow"),
|
||||
description = S("Crossbow"),
|
||||
_tt_help = S("Launches arrows"),
|
||||
_doc_items_longdesc = S("Bows are ranged weapons to shoot arrows at your foes.").."\n"..
|
||||
S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."),
|
||||
|
@ -151,11 +151,11 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
|
|||
})
|
||||
|
||||
minetest.register_tool("mcl_bows:crossbow_loaded", {
|
||||
description = S("Corssbow"),
|
||||
description = S("Crossbow"),
|
||||
_tt_help = S("Launches arrows"),
|
||||
_doc_items_longdesc = S("Corssbow are ranged weapons to shoot arrows at your foes.").."\n"..
|
||||
_doc_items_longdesc = S("Crossbow is a ranged weapon to shoot arrows at your foes.").."\n"..
|
||||
S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."),
|
||||
_doc_items_usagehelp = S("To use the corssbow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to load an arrow into the chamber, then to shoot press left mouse."),
|
||||
_doc_items_usagehelp = S("To use the crossbow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to load an arrow into the chamber, then to shoot press left mouse."),
|
||||
_doc_items_durability = BOW_DURABILITY,
|
||||
inventory_image = "mcl_bows_crossbow_3.png",
|
||||
wield_scale = mcl_vars.tool_wield_scale,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -37,7 +37,7 @@ local lava_fire=
|
|||
{ x = 1, y = 1, z = 0},
|
||||
{ x = 1, y = 1, z = 1}
|
||||
}
|
||||
local alldirs=
|
||||
local adjacents =
|
||||
{
|
||||
{ x =-1, y = 0, z = 0},
|
||||
{ x = 1, y = 0, z = 0},
|
||||
|
@ -87,7 +87,7 @@ else
|
|||
end
|
||||
|
||||
local function fire_timer(pos)
|
||||
minetest.get_node_timer(pos):start(math.random(3, 7))
|
||||
minetest.get_node_timer(pos):start(math.random(15, 45))
|
||||
end
|
||||
|
||||
local function spawn_fire(pos, age)
|
||||
|
@ -95,6 +95,23 @@ local function spawn_fire(pos, age)
|
|||
minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z})
|
||||
end
|
||||
|
||||
local function shuffle_adjacents()
|
||||
for i = #adjacents, 1, -1 do
|
||||
local r = math.random(i)
|
||||
adjacents[i], adjacents[r] = adjacents[r], adjacents[i]
|
||||
end
|
||||
end
|
||||
|
||||
local function has_flammable(pos)
|
||||
for k,v in pairs(adjacents) do
|
||||
local p=vector.add(pos,v)
|
||||
local n=minetest.get_node_or_nil(p)
|
||||
if n and minetest.get_item_group(n.name, "flammable") ~= 0 then
|
||||
return p
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("mcl_fire:fire", {
|
||||
description = S("Fire"),
|
||||
_doc_items_longdesc = fire_help,
|
||||
|
@ -125,80 +142,12 @@ minetest.register_node("mcl_fire:fire", {
|
|||
end
|
||||
end,
|
||||
on_timer = function(pos)
|
||||
local node = get_node(pos)
|
||||
-- Age is a number from 0 to 15 and is increased every timer step.
|
||||
-- "old" fire is more likely to be extinguished
|
||||
local age = node.param2
|
||||
local flammables = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
|
||||
local below = get_node({x=pos.x, y=pos.z-1, z=pos.z})
|
||||
local below_is_flammable = get_item_group(below.name, "flammable") > 0
|
||||
-- Extinguish fire
|
||||
if (not fire_enabled) and (math.random(1,3) == 1) then
|
||||
remove_node(pos)
|
||||
local p=has_flammable(pos)
|
||||
if not p or minetest.get_item_group(minetest.get_node(p).name, "flammable") == -1 then
|
||||
minetest.remove_node(pos)
|
||||
return
|
||||
end
|
||||
if age == 15 and not below_is_flammable then
|
||||
remove_node(pos)
|
||||
return
|
||||
elseif age > 3 and #flammables == 0 and not below_is_flammable and math.random(1,4) == 1 then
|
||||
remove_node(pos)
|
||||
return
|
||||
end
|
||||
local age_add = 1
|
||||
-- If fire spread is disabled, we have to skip the "destructive" code
|
||||
if (not fire_enabled) then
|
||||
if age + age_add <= 15 then
|
||||
node.param2 = age + age_add
|
||||
set_node(pos, node)
|
||||
end
|
||||
-- Restart timer
|
||||
fire_timer(pos)
|
||||
return
|
||||
end
|
||||
-- Spawn fire to nearby flammable nodes
|
||||
local is_next_to_flammable = find_node_near(pos, 2, {"group:flammable"}) ~= nil
|
||||
if is_next_to_flammable and math.random(1,2) == 1 then
|
||||
-- The fire we spawn copies the age of this fire.
|
||||
-- This prevents fire from spreading infinitely far as the fire fire dies off
|
||||
-- quicker the further it has spreaded.
|
||||
local age_next = math.min(15, age + math.random(0, 1))
|
||||
-- Select random type of fire spread
|
||||
local burntype = math.random(1,2)
|
||||
if burntype == 1 then
|
||||
-- Spawn fire in air
|
||||
local nodes = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
|
||||
while #nodes > 0 do
|
||||
local r = math.random(1, #nodes)
|
||||
if find_node_near(nodes[r], 1, {"group:flammable"}) then
|
||||
spawn_fire(nodes[r], age_next)
|
||||
break
|
||||
else
|
||||
table.remove(nodes, r)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Burn flammable block
|
||||
local nodes = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
|
||||
if #nodes > 0 then
|
||||
local r = math.random(1, #nodes)
|
||||
local nn = get_node(nodes[r]).name
|
||||
local ndef = minetest.registered_nodes[nn]
|
||||
local fgroup = get_item_group(nn, "flammable")
|
||||
if ndef and ndef._on_burn then
|
||||
ndef._on_burn(nodes[r])
|
||||
elseif fgroup ~= -1 then
|
||||
spawn_fire(nodes[r], age_next)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Regular age increase
|
||||
if age + age_add <= 15 then
|
||||
node.param2 = age + age_add
|
||||
set_node(pos, node)
|
||||
end
|
||||
-- Restart timer
|
||||
fire_timer(pos)
|
||||
return true --restart timer
|
||||
end,
|
||||
drop = "",
|
||||
sounds = {},
|
||||
|
@ -254,29 +203,8 @@ minetest.register_node("mcl_fire:eternal_fire", {
|
|||
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
|
||||
end
|
||||
end,
|
||||
on_timer = function(pos)
|
||||
if fire_enabled then
|
||||
local airs = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
|
||||
while #airs > 0 do
|
||||
local r = math.random(1, #airs)
|
||||
if find_node_near(airs[r], 1, {"group:flammable"}) then
|
||||
local node = get_node(airs[r])
|
||||
local age = node.param2
|
||||
local age_next = math.min(15, age + math.random(0, 1))
|
||||
spawn_fire(airs[r], age_next)
|
||||
break
|
||||
else
|
||||
table.remove(airs, r)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Restart timer
|
||||
fire_timer(pos)
|
||||
end,
|
||||
-- Start burning timer and light Nether portal (if possible)
|
||||
-- light Nether portal (if possible)
|
||||
on_construct = function(pos)
|
||||
fire_timer(pos)
|
||||
|
||||
if has_mcl_portals then --Calling directly minetest.get_modpath consumes 4x more compute time
|
||||
mcl_portals.light_nether_portal(pos)
|
||||
end
|
||||
|
@ -421,21 +349,39 @@ minetest.register_abm({
|
|||
end,
|
||||
})
|
||||
|
||||
--- Fire spread logic
|
||||
|
||||
-- Enable the following ABMs according to 'enable fire' setting
|
||||
-- A fire that is not adjacent to any flammable block does not spread, even to another flammable block within the normal range.
|
||||
-- A fire block can turn any air block that is adjacent to a flammable block into a fire block. This can happen at a distance of up to one block downward, one block sideways (including diagonals), and four blocks upward of the original fire block (not the block the fire is on/next to).
|
||||
-- Fire spreads from a still lava block similarly: any air block one above and up to one block sideways (including diagonals) or two above and two blocks sideways (including diagonals) that is adjacent to a flammable block may be turned into a fire block.
|
||||
-- https://minecraft.fandom.com/wiki/Fire#Spread
|
||||
|
||||
local function has_flammable(pos)
|
||||
local npos, node
|
||||
for n, v in ipairs(alldirs) do
|
||||
npos = vector.add(pos, v)
|
||||
node = get_node_or_nil(npos)
|
||||
if node and node.name and get_item_group(node.name, "flammable") ~= 0 then
|
||||
return npos
|
||||
end
|
||||
local function check_aircube(p1,p2)
|
||||
local nds=minetest.find_nodes_in_area(p1,p2,{"air"})
|
||||
for k,v in pairs(nds) do
|
||||
if has_flammable(v) then return v end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function get_ignitable(pos)
|
||||
return check_aircube(vector.add(pos,vector.new(-1,-1,-1)),vector.add(pos,vector.new(1,4,1)))
|
||||
end
|
||||
|
||||
local function get_ignitable_by_lava(pos)
|
||||
return check_aircube(vector.add(pos,vector.new(-1,1,-1)),vector.add(pos,vector.new(1,1,1))) or check_aircube(vector.add(pos,vector.new(-2,2,-2)),vector.add(pos,vector.new(2,2,2))) or nil
|
||||
end
|
||||
|
||||
local function add_fire_particle(pos,f)
|
||||
minetest.add_particle({
|
||||
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
|
||||
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.25), z=f.z-pos.z},
|
||||
expirationtime=1, size=1, collisiondetection=false,
|
||||
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
|
||||
})
|
||||
end
|
||||
|
||||
-- Enable the following ABMs according to 'enable fire' setting
|
||||
if not fire_enabled then
|
||||
|
||||
-- Occasionally remove fire if fire disabled
|
||||
|
@ -451,62 +397,70 @@ if not fire_enabled then
|
|||
|
||||
else -- Fire enabled
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Ignite flame",
|
||||
nodenames ={"mcl_fire:fire","mcl_fire:eternal_fire"},
|
||||
interval = 7,
|
||||
chance = 12,
|
||||
catch_up = false,
|
||||
action = function(pos)
|
||||
local p = get_ignitable(pos)
|
||||
if p then
|
||||
add_fire_particle(p,pos)
|
||||
spawn_fire(p)
|
||||
shuffle_adjacents()
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
-- Set fire to air nodes
|
||||
minetest.register_abm({
|
||||
label = "Ignite fire by lava",
|
||||
nodenames = {"group:lava"},
|
||||
neighbors = {"air"},
|
||||
nodenames = {"mcl_core:lava_source","mcl_nether:nether_lava_source"},
|
||||
neighbors = {"air","group:flammable"},
|
||||
interval = 7,
|
||||
chance = 3,
|
||||
catch_up = false,
|
||||
action = function(pos)
|
||||
local i, dir, target, node, i2, f
|
||||
i = math.random(1,9)
|
||||
dir = lava_fire[i]
|
||||
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
|
||||
node = get_node(target)
|
||||
if not node or node.name ~= "air" then
|
||||
i = ((i + math.random(0,7)) % 9) + 1
|
||||
dir = lava_fire[i]
|
||||
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
|
||||
node = get_node(target)
|
||||
if not node or node.name ~= "air" then
|
||||
return
|
||||
end
|
||||
end
|
||||
i2 = math.random(1,15)
|
||||
if i2 < 10 then
|
||||
local dir2, target2, node2
|
||||
dir2 = lava_fire[i2]
|
||||
target2 = {x=target.x+dir2.x, y=target.y+dir2.y, z=target.z+dir2.z}
|
||||
node2 = get_node(target2)
|
||||
if node2 and node2.name == "air" then
|
||||
f = has_flammable(target2)
|
||||
if f then
|
||||
minetest.after(1, spawn_fire, {x=target2.x, y=target2.y, z=target2.z})
|
||||
minetest.add_particle({
|
||||
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
|
||||
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.7), z=f.z-pos.z},
|
||||
expirationtime=1, size=1.5, collisiondetection=false,
|
||||
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
|
||||
})
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
f = has_flammable(target)
|
||||
if f then
|
||||
minetest.after(1, spawn_fire, {x=target.x, y=target.y, z=target.z})
|
||||
minetest.add_particle({
|
||||
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
|
||||
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.25), z=f.z-pos.z},
|
||||
expirationtime=1, size=1, collisiondetection=false,
|
||||
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
|
||||
})
|
||||
local p=get_ignitable_by_lava(pos)
|
||||
if p then
|
||||
add_fire_particle(p,pos)
|
||||
spawn_fire(p)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Remove flammable nodes around basic flame
|
||||
minetest.register_abm({
|
||||
label = "Remove flammable nodes",
|
||||
nodenames = {"mcl_fire:fire","mcl_fire:eternal_fire"},
|
||||
neighbors = {"group:flammable"},
|
||||
interval = 5,
|
||||
chance = 18,
|
||||
catch_up = false,
|
||||
action = function(pos)
|
||||
local p = has_flammable(pos)
|
||||
if not p then
|
||||
return
|
||||
end
|
||||
|
||||
local nn = minetest.get_node(p).name
|
||||
local def = minetest.registered_nodes[nn]
|
||||
local fgroup = minetest.get_item_group(nn, "flammable")
|
||||
|
||||
if def and def._on_burn then
|
||||
def._on_burn(p)
|
||||
elseif fgroup ~= -1 then
|
||||
add_fire_particle(p,pos)
|
||||
spawn_fire(p)
|
||||
fire_timer(p)
|
||||
minetest.check_for_falling(p)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
-- Set pointed_thing on (normal) fire.
|
||||
|
|
|
@ -0,0 +1,469 @@
|
|||
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)
|
||||
if privs.interact ~= interact then
|
||||
privs.interact = interact
|
||||
minetest.set_player_privs(player_name, privs)
|
||||
end
|
||||
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
|
||||
|
||||
local hf=player:hud_get_flags()
|
||||
if not hf.wielditem then
|
||||
player:hud_set_flags({wielditem = true})
|
||||
end
|
||||
|
||||
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)
|
|
@ -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
|
|
@ -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=
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_shields
|
||||
author = NO11
|
||||
depends = mcl_damage, mcl_enchanting, mcl_banners, mcl_util, playerphysics
|
|
@ -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
|
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 639 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 4.3 KiB |
|
@ -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
|
||||
|
|
|
@ -22,8 +22,10 @@ for _, action in pairs({"grant", "revoke"}) do
|
|||
minetest["register_on_priv_" .. action](function(name, _, priv)
|
||||
if priv == "fly" then
|
||||
local player = minetest.get_player_by_name(name)
|
||||
local meta = player:get_meta()
|
||||
meta:set_int("fly_changed", 1)
|
||||
if player then
|
||||
local meta = player:get_meta()
|
||||
meta:set_int("fly_changed", 1)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|