yl_snowball/internal.lua
2024-11-23 18:22:19 +03:00

213 lines
6.4 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
yl_snowball.COOLDOWN = 0.1 -- TODO make configurable
yl_snowball.SNOWBALL_SPEED = 17
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 = os.clock() --core.get_gametime() -- gametime seems to "lag"?
if current_time - (player_last_throw_time[player_name] or 0) < yl_snowball.COOLDOWN 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 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, -8, 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
if not yl_snowball._registered then -- FIXME remove this
yl_snowball._registered = true -- register only on load
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 = {
particles = {
amount = 1,
time = 0.1,
--time = 4,
texture = "yl_snowball_snowflake.png",
animation = {
type = "vertical_frames",
aspect_w = 8,
aspect_h = 8,
length = 1,
},
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 ???
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_activate = function(self, staticdata)
-- self.object:remove()
-- end,
on_step = function(self, dtime, moveresult)
--print(dump(dtime), dump(dtime), dump(moveresult))
ballistics.on_step_particles(self, dtime, moveresult)
end,
on_hit_node = function(self, node_pos, node, above_pos, intersection_point, intersection_normal, box_id)
--print(dump(node_pos), dump(node))
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)
return true
end,
on_hit_object = function(self, target, intersection_point, intersection_normal, box_id)
-- core.chat_send_all(('%s hit %s'):format(os.clock(), dump(target:get_entity_name())))
-- print(dump(self))
spawn_snow_puff(intersection_point, intersection_normal)
self.object:remove()
if target:is_player() then
local target_name = target:get_player_name()
yl_snowball.snowgame.register_hit(self._source_player_name, target_name)
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'},
})
end