Skip to content

Commit

Permalink
Add bows and crossbows (closes #1861, #1858; patially #1523, #1863)
Browse files Browse the repository at this point in the history
Move the archery mods out of _experimental (closes #1774, #1775)
Added stable support for Throwable (closes #1866)
  • Loading branch information
Doloment committed Dec 27, 2024
1 parent b2143b6 commit 741554d
Show file tree
Hide file tree
Showing 99 changed files with 562 additions and 172 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ controls.on_release(function(player, key, hold_time)
local power = api.calculate_power(stack, hold_time)

local projectile_item = meta:get_string("loaded_projectile")
if projectile_item and api.projectile_shoot(player, projectile_item, power) then
if projectile_item and api.projectile_shoot(player, ItemStack(projectile_item), power) then
minetest.sound_play(stack:get_definition()["_sound_on_release"], { object = player })
local uses = api.reg_from_archery_item(stack:get_name()).definition.uses
stack:add_wear(65535/uses)
Expand Down Expand Up @@ -141,7 +141,7 @@ controls.on_press(function(player, key)

local projectile_item = meta:get_string("loaded_projectile")
local power = api.calculate_power(stack, nil, true)
if projectile_item and projectile_item ~= "" and api.projectile_shoot(player, projectile_item, power) then
if projectile_item and projectile_item ~= "" and api.projectile_shoot(player, ItemStack(projectile_item), power) then
minetest.sound_play(stack:get_definition()["_sound_on_release"], { object = player })
local uses = api.reg_from_archery_item(stack:get_name()).definition.uses
stack:add_wear(65535/uses)
Expand Down Expand Up @@ -216,17 +216,19 @@ controls.on_release(function(player, key, hold_time)
local wield_index = player:get_wield_index()

local power = api.calculate_power(stack, hold_time)
local new_stack = ItemStack(table.copy(stack:to_table()))

local uses = api.reg_from_archery_item(new_stack:get_name()).definition.uses
new_stack:add_wear(65535/uses)

local projectile_item = archery.get_throwables()[stack:get_name()].entity_name
if projectile_item and api.projectile_shoot(player, projectile_item, power, stack) then
if projectile_item and api.projectile_shoot(player, new_stack, power) then
minetest.sound_play(stack:get_definition()["_sound_on_release"], { object = player })
local uses = api.reg_from_archery_item(stack:get_name()).definition.uses
stack:add_wear(65535/uses)
stack:take_item(1)
end

api.player_reset_slowdown(player)
--inv:set_stack("main", wield_index, new_stack)
inv:set_stack("main", wield_index, stack)
end)

-- If the wielded item changed while bow was charging, discharge without shooting the arrow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ end
local function reg_from_archery_item(name)
local common_table = table.join(table.join(archery.get_bows(), archery.get_crossbows()), archery.get_throwables())
local reg = common_table[to_original_state(name)]
print(dump(reg))
return reg
end

Expand Down Expand Up @@ -70,13 +69,10 @@ local function player_reset_slowdown(player)
end

local function calculate_power(stack, hold_time, no_hold)
print(dump(reg_from_archery_item(stack:get_name())))
local charging_time = reg_from_archery_item(stack:get_name()).stage_conf.charging_time
local draw_power = reg_from_archery_item(stack:get_name()).definition.draw_power
local max_holding = charging_time[#charging_time]

print(reg_from_archery_item(stack:get_name()))

if no_hold then
return draw_power
end
Expand All @@ -96,35 +92,37 @@ local function calculate_power(stack, hold_time, no_hold)
power = 0.1
end

minetest.chat_send_all(dump({
--[[minetest.chat_send_all(dump({
["1power"] = power,
["2draw_power"] = draw_power,
["3hold_time"] = hold_time,
["4charging_time_1"] = charging_time[1],
["5max_holding"] = max_holding,
["6Coefficient"] = (hold_time-charging_time[1])/max_holding,
}))
}))]]
return power
end

--- @param player Player a player that shoots the projectile
--- @param projectile_item string itemstring of a projectile item to shoot
--- @param hold_time number the time the player was holding CONTROL_CHARGE down
--- @param throwable_item ItemStack item that was thrown
local function projectile_shoot(player, projectile_item, power, throwable_item)
--- @param player Player a player that shoots the projectile
--- @param projectile_stack temStack itemstack with item to shoot
--- @param hold_time number the time the player was holding CONTROL_CHARGE down
local function projectile_shoot(player, projectile_stack, power)

local look_dir = player:get_look_dir()
local player_pos = player:get_pos()
local projectile_pos = vector.new(player_pos.x, player_pos.y + 1.5, player_pos.z)
local projectile_item = projectile_stack:get_name()

local projectile_reg = projectiles.get_projectiles()[projectile_item]

local projectile_entity = minetest.add_entity(projectile_pos, projectile_reg.entity_name)
minetest.chat_send_all(projectile_reg.entity_reg.max_speed * power)
--minetest.chat_send_all(projectile_reg.entity_reg.max_speed * power)
projectile_entity:add_velocity(vector.multiply(look_dir, projectile_reg.entity_reg.max_speed * power))
projectile_entity:set_acceleration(vector.new(0, -GRAVITY, 0))
projectile_entity:get_luaentity()._shooter = player
projectile_entity:get_luaentity()._throwable_item = throwable_item
projectile_entity:get_luaentity()._projectile_stack = projectile_stack
projectile_entity:get_luaentity()._remove_on_object_hit = projectile_reg.entity_reg.remove_on_object_hit
projectile_entity:get_luaentity()._rotation_formula = projectile_reg.entity_reg.rotation_formula

return true
end
Expand Down
4 changes: 2 additions & 2 deletions mods/lord/Core/projectiles/src/projectiles/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ local entity = require("projectiles.entity")
--- @param not_register_item boolean whether to register craftitem or not (false/nil = register)
local function register_projectile(name, reg, not_register_item)
local def = reg.definition
reg.type = reg.type or "arrow"
reg.type = reg.type
reg.entity_name = reg.entity_name or name

registered_projectiles[name] = reg

entity.register_projectile_entity(reg.entity_name, name, reg.entity_reg)
entity.register_projectile_entity(reg.entity_name, reg.entity_reg)

if not_register_item then
return
Expand Down
97 changes: 58 additions & 39 deletions mods/lord/Core/projectiles/src/projectiles/entity.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@ local function update_life_timer(projectile, dtime)
end

-- Dealing the damage to the target
--- @param projectile LuaEntity projectile entity
--- @param target LuaEntity target entity
--- @param damage_groups table damage groups table
--- @param multipliers table damage multiplier table
local function punch_target(projectile, target, damage_groups, remove_after_punch, multipliers)
if remove_after_punch == nil then
remove_after_punch = true
--- @param projectile LuaEntity projectile entity
--- @param target LuaEntity target entity
--- @param damage_groups table damage groups table
--- @param remove_after_hit boolean true: remove after hit; false/nil: do nothing
--- @param multipliers table damage multiplier table
local function punch_target(projectile, target, damage_groups, remove_after_hit, multipliers)
minetest.chat_send_all("RoOH: "..tostring(remove_after_hit))
if remove_after_hit == nil then
remove_after_hit = true
end

minetest.chat_send_all("RoOH: "..tostring(remove_after_hit))

local multiplied = table.multiply_each_value(damage_groups, multipliers)

local new_damage_groups = table.map(multiplied, function(value)
Expand All @@ -37,16 +41,19 @@ local function punch_target(projectile, target, damage_groups, remove_after_punc
end
return math.ceil(value)
end)
minetest.chat_send_all(dump(damage_groups))
minetest.chat_send_all(dump(new_damage_groups))
--minetest.chat_send_all(dump(damage_groups))
--minetest.chat_send_all(dump(new_damage_groups))
target:punch(projectile.object, 1.4, {
full_punch_interval = 1.4,
damage_groups = new_damage_groups,
})

if remove_after_punch == true then
projectile.object:remove()
if remove_after_hit ~= true then
local pos = projectile.object:get_pos()
minetest.add_item(pos, projectile._projectile_stack)
end

projectile.object:remove()
end

--- @param entity LuaEntity entity to check if it is a projectile
Expand Down Expand Up @@ -79,7 +86,8 @@ end
local function hit_handling(projectile, target, damage_groups, velocity)
local function hit()
local damage = (vector.length(velocity)/GRAVITY)^(1/2)
punch_target(projectile, target, damage_groups, true, { fleshy = damage })
minetest.chat_send_all(dump(projectile))
return punch_target(projectile, target, damage_groups, projectile._remove_on_object_hit, { fleshy = damage })
end
-- Hit player
if target:is_player() then
Expand Down Expand Up @@ -138,8 +146,11 @@ end


--- @param projectile LuaEntity projectile entity
local function flight_processing(projectile, environment)
local function flight_processing(projectile, environment, rotation_formula)
local vel = projectile.object:get_velocity()
print(dump(projectiles.get_projectiles()[projectile._projectile_stack:get_name()]))
local projectile_type = projectiles.get_projectiles()[projectile._projectile_stack:get_name()].type
local particle_texture = "projectiles_"..projectile_type.."_trajectory_"..environment.."_particle.png"
if vel.y ~= 0 then
math.randomseed(os.clock())
if environment == "water" then
Expand All @@ -151,32 +162,41 @@ local function flight_processing(projectile, environment)
max = vector.new( 0.5, 0.5, 0.5),
-- when `bias` is 0, all random values are exactly as likely as any
},
texture = "projectiles_trajectory_"..environment.."_particle.png",
texture = particle_texture,
})
else
minetest.add_particlespawner({
attached = projectile.object,
texture = "projectiles_trajectory_"..environment.."_particle.png",
texture = particle_texture,
})
end
local rot = {
x = 0,
y = math_pi + math_arctan(vel.z, vel.x),
z = math_arctan(vel.y, math_sqrt(vel.z * vel.z + vel.x * vel.x))}
projectile.object:set_rotation(rot)
arrow = {
x = 0,
y = math_pi + math_arctan(vel.z, vel.x),
z = math_arctan(vel.y, math_sqrt(vel.z * vel.z + vel.x * vel.x))
},
axe = {
x = 0,
y = -math_pi*2 + math_arctan(vel.z, vel.x),
z = -math_arctan(vel.y, math_sqrt(vel.z * vel.z + vel.x * vel.x))
},
}
projectile.object:set_rotation(rot[rotation_formula or "arrow"])
end
end

local register_projectile_entity = function(name, item, entity_reg)
local register_projectile_entity = function(name, entity_reg)
local initial_properties = {
hp_max = 1,
physical = true,
collide_with_objects = true,
collisionbox = {-0.15, -0.15, -0.15, 0.15, 0.15, 0.15},
selectionbox = {-0.15, -0.15, -0.15, 0.15, 0.15, 0.15},
collisionbox = { -0.15, -0.15, -0.15, 0.15, 0.15, 0.15 },
selectionbox = { -0.15, -0.15, -0.15, 0.15, 0.15, 0.15 },
pointable = true,
visual = "item",
visual_size = {x = 1.5, y = 1.5, z = 1.5},
wield_item = "default:clay_brick",
visual_size = { x = 1.5, y = 1.5, z = 1.5 },
use_texture_alpha = true,
}
minetest.register_entity(name, {
Expand Down Expand Up @@ -204,40 +224,39 @@ local register_projectile_entity = function(name, item, entity_reg)
if (vector.length(self.object:get_velocity()) > 0 and moveresult.collides) or moveresult.standing_on_object then
self:_on_collision(moveresult)
elseif vector.length(self.object:get_velocity()) > 0 then
flight_processing(self, environment)
flight_processing(self, environment, self._rotation_formula)
end


if update_life_timer(self, dtime) then
minetest.add_item(pos, item)
minetest.add_item(pos, self._projectile_stack)
end
end,
on_punch = function(self, puncher)
if vector.length(self.object:get_velocity()) > 0 or self._shooter ~= puncher then
return
end
self.object:remove()
local item_to_give = ItemStack(item)
if self._throwable_item then
item_to_give = self._throwable_item
end
minetest.chat_send_all(dump(item_to_give))
minetest.give_or_drop(puncher, item_to_give)
minetest.give_or_drop(puncher, self._projectile_stack)
end,
on_activate = function(self, staticdata, dtime_s)
if staticdata == "_timer_is_started" then
self._timer_is_started = true
else
if not staticdata or staticdata == "" then
return
end
local staticdata_table = minetest.deserialize(staticdata)
print(dump(staticdata_table))
self._timer_is_started = staticdata_table._timer_is_started
self._projectile_stack = ItemStack(staticdata_table._projectile_stack)
update_life_timer(self, dtime_s)
end,
get_staticdata = function(self)
if self._timer_is_started then
return "_timer_is_started"
else
return ""
local staticdata_table = {}
staticdata_table._timer_is_started = self._timer_is_started
local projectile_stack = self._projectile_stack
if projectile_stack then
staticdata_table._projectile_stack = projectile_stack:to_table()
end
return minetest.serialize(staticdata_table)
end,
_on_collision = function(self, moveresult)
self._collision_count = self._collision_count + 1
Expand All @@ -249,7 +268,7 @@ local register_projectile_entity = function(name, item, entity_reg)
if self._collision_count >= 10 then
self.object:remove()
if self._shooter and self._shooter:is_player() then
minetest.add_item(pos, ItemStack(item))
minetest.add_item(pos, self._projectile_stack)
end
end
end
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
local config = require("lord_archery.config")

local function register_archery_items()
local function register_bows()
for name, registration in pairs(config.bows) do
archery.register_bow(name, registration)
end
end

local function register_crossbows()
for name, registration in pairs(config.crossbows) do
archery.register_crossbow(name, registration)
end
Expand All @@ -18,7 +21,8 @@ end

return {
init = function()
register_archery_items()
register_bows()
register_crossbows()
register_throwables()
end,
}
9 changes: 9 additions & 0 deletions mods/lord/Tools/lord_archery/src/lord_archery/config.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
local config_bows = require("lord_archery.config.bows")
local config_crossbows = require("lord_archery.config.crossbows")
local config_throwables = require("lord_archery.config.throwables")

return {
bows = config_bows,
crossbows = config_crossbows,
throwables = config_throwables,
}
Loading

0 comments on commit 741554d

Please sign in to comment.