yl_snowball/internal.lua
2024-11-27 01:44:31 +03:00

243 lines
7.8 KiB
Lua

local v_new = vector.new
local v_rotate_around_axis = vector.rotate_around_axis
local v_multiply = vector.multiply
local v_dot = vector.dot
local modstorage = core.get_mod_storage()
yl_snowball.modstorage = modstorage
local get_player_participation = yl_snowball.get_player_participation
yl_snowball.COOLDOWN = 0.4 -- TODO make configurable
yl_snowball.SNOWBALL_SPEED = 17 -- 17 was good
yl_snowball.SNOWBALL_GRAVITY = -8 -- -8 was good
local player_last_throw_time = {}
core.register_on_leaveplayer(
function(player, _timed_out)
local player_name = player:get_player_name()
if player_name ~= "" then
player_last_throw_time[player_name] = nil
end
end
)
local function spawn_snow_puff(pos, normal)
local shift = normal * 0.1
local center = pos + shift
local def = {
pos = center,
amount = 20,
time = 0.01,
radius = { min = 0.01, max = 0.1, bias = -1 },
drag = 0.1,
attract = {
kind = "point",
strength = -14,
origin = center - shift,
},
acc = v_new(0, -8, 0),
exptime = 0.5,
size = 2,
collisiondetection = true,
collision_removal = true,
texture = {
name = "yl_snowball_snowflake.png",
--blend = "clip", -- does not work in 5.9?!?
},
--glow = 2,
}
core.add_particlespawner(def)
end
local function get_start_params(player)
local look = player:get_look_dir()
local eye_height = v_new(0, player:get_properties().eye_height, 0)
local eye_offset = player:get_eye_offset() * 0.1 -- Eye offset is in scaled coords
local yaw = player:get_look_horizontal()
local dir = v_multiply(look, 0.4) -- forward shift. TODO tweak constant
local p_pos = player:get_pos()
local up = v_new(0,1,0)
-- Initial projectile position: in front of camera, shifted little forward
local start = p_pos + eye_height + v_rotate_around_axis(eye_offset, up, yaw) + dir
local player_vel = futil.get_velocity(player)
-- vector pointing right
local right = v_rotate_around_axis(v_new(1,0,0), up, yaw)
-- horizonal velocity component
local horiz_vel = v_multiply(right, v_dot(player_vel, right))
-- Make projectile velocity influenced only by forward/back and up/down movement.
-- This makes you always shoot "straight"
local vel = player_vel - horiz_vel
-- vizlib.draw_line(p_pos, p_pos + v_multiply(player_vel,1.0)) -- velocity
-- vizlib.draw_line(p_pos, p_pos + v_multiply(look,3), {color = "green"}) -- look dir
-- vizlib.draw_line(p_pos, p_pos + v_multiply(vel,1.0), {color = "yellow"}) -- projectile vel
return start, look, vel
end
-- FIXME make this local
yl_snowball.on_use = function(itemstack, user, pointed_thing)
if (not user) or (not user:is_player()) then
return itemstack
end
local player = user
local player_name = player:get_player_name()
local current_time = core.get_us_time() --core.get_gametime() -- gametime seems to "lag"?
local diff = current_time - (player_last_throw_time[player_name] or 0)
if diff < yl_snowball.COOLDOWN * 1000000 then
-- too soon, don't shot, don't take items
return nil
end
player_last_throw_time[player_name] = current_time
local speed = yl_snowball.SNOWBALL_SPEED
local gravity = yl_snowball.SNOWBALL_GRAVITY
local start, look, p_vel = get_start_params(player)
-- projectile velocity points where we look + affected by player movement
local vel = (look * speed) + (p_vel * 0.3)
ballistics.shoot(
"yl_snowball:snowball_ent",
start,
vel,
v_new(0, gravity, 0),
player,
nil
)
yl_snowball.snowgame.register_shot(player_name)
if not core.check_player_privs(player, "creative") then
itemstack:take_item(1)
end
return itemstack
end
core.register_craftitem(
"yl_snowball:snowball",
{
description = "Throwable Snowball",
stack_max= 99,
inventory_image = "yl_snowball.png",
on_use = function(...) -- FIXME remove wrapper
return yl_snowball.on_use(...)
end,
}
)
local SIZE = 0.4
local SNOWBALL_DEF = {
parameters = {
punch = {
tool_capabilities = {
damage_groups = { fleshy = 1.0 },
},
},
particles = {
amount = 1,
time = 0.1,
--time = 4,
texture = "yl_snowball_snowflake.png",
glow = 1,
minvel = { x = 0, y = -0.1, z = 0 },
maxvel = { x = 0, y = -0.1, z = 0 },
minacc = { x = 0, y = -0.1, z = 0 },
maxacc = { x = 0, y = -0.1, z = 0 },
minexptime = 0.5,
maxexptime = 0.5,
minsize = 2,
maxsize = 2,
--_period = 0.09,
_period = 0.2,
},
hit_sound = {
spec = { name = "default_place_node" },
parameters = { gain = 0.8, pitch = 2.0 },
},
},
physical = false, -- FIXME I think enabling this will allow jumping on them?
visual = "sprite",
visual_size = {x=SIZE, y=SIZE},
textures = {'yl_snowball.png'},
collisionbox = {-SIZE/2, -SIZE/2, -SIZE/2, SIZE/2, SIZE/2, SIZE/2},
on_step = function(self, dtime, moveresult)
-- draw a snowflake trail
ballistics.on_step_particles(self, dtime, moveresult)
end,
on_hit_node = function(self, node_pos, node, above_pos, intersection_point, intersection_normal, box_id)
ballistics.on_hit_node_hit_sound_play(self, node_pos, node, above_pos, intersection_point, intersection_normal, box_id)
self.object:remove()
spawn_snow_puff(intersection_point, intersection_normal)
if y_bows and y_bows.util.bullseye_was_hit(self, node_pos, node, above_pos,
intersection_point, intersection_normal,
box_id) then
y_bows.on_bullseye_hit(node_pos, self._source_obj)
end
return true
end,
on_hit_object = function(self, target, intersection_point, intersection_normal, box_id)
spawn_snow_puff(intersection_point, intersection_normal)
ballistics.on_hit_object_hit_sound_play(self, target, intersection_point, intersection_normal, box_id)
self.object:remove()
if futil.is_player(target) then
local target_name = target:get_player_name()
local source = self._source_obj
if futil.is_player(source) then
local source_name = source:get_player_name()
local source_participates = get_player_participation(source_name)
local target_participates = get_player_participation(target_name)
-- register hit and play sounds only if both participate
if source_participates and target_participates then
yl_snowball.snowgame.register_hit(source_name, target_name)
local sound_name = "y_bows_arrow_successful_hit"
core.sound_play({ name = sound_name }, {
gain = 0.7,
to_player = source_name,
})
local take_hit_sound_name = "default_snow_footstep"
core.sound_play({ name = take_hit_sound_name }, {
gain = 0.7,
to_player = target_name,
})
end
end
else
ballistics.on_hit_object_punch(self, target, intersection_point, intersection_normal, box_id)
end
return true
end
}
ballistics.register_projectile("yl_snowball:snowball_ent", SNOWBALL_DEF)
core.register_craft({
type = "shapeless",
output = 'yl_snowball:snowball 3',
recipe = {'default:snow'},
})