Add x_enchanting support for bows

This commit is contained in:
Juraj Vajda 2022-11-13 16:28:22 +00:00
commit 13298c7352
8 changed files with 103 additions and 19 deletions

View File

@ -204,4 +204,4 @@ Modified by SaKeL (added quiver):
## Installation ## Installation
see: http://wiki.minetest.com/wiki/Installing_Mods see: https://wiki.minetest.net/Installing_Mods

65
api.lua
View File

@ -185,7 +185,7 @@ function XBows.register_bow(self, name, def, override)
def.short_description = def.short_description def.short_description = def.short_description
def.description = override and def.short_description or (def.description or name) def.description = override and def.short_description or (def.description or name)
def.custom.uses = def.custom.uses or 150 def.custom.uses = def.custom.uses or 150
def.groups = mergeTables({ bow = 1, flammable = 1 }, def.groups or {}) def.groups = mergeTables({ bow = 1, flammable = 1, enchantability = 1 }, def.groups or {})
def.custom.groups_charged = mergeTables( def.custom.groups_charged = mergeTables(
{ bow_charged = 1, flammable = 1, not_in_creative_inventory = 1 }, { bow_charged = 1, flammable = 1, not_in_creative_inventory = 1 },
def.groups or {} def.groups or {}
@ -683,6 +683,9 @@ function XBows.shoot(self, itemstack, user, pointed_thing)
local _tool_capabilities = x_bows_registered_arrow_def.custom.tool_capabilities local _tool_capabilities = x_bows_registered_arrow_def.custom.tool_capabilities
local quiver_xbows_def = x_bows_registered_quiver_def local quiver_xbows_def = x_bows_registered_quiver_def
---X Enchanting
local x_enchanting = minetest.deserialize(meta:get_string('x_enchanting')) or {}
---@type EnityStaticDataAttrDef ---@type EnityStaticDataAttrDef
local staticdata = { local staticdata = {
_arrow_name = arrow_name, _arrow_name = arrow_name,
@ -691,7 +694,8 @@ function XBows.shoot(self, itemstack, user, pointed_thing)
_is_critical_hit = false, _is_critical_hit = false,
_tool_capabilities = _tool_capabilities, _tool_capabilities = _tool_capabilities,
_tflp = tflp, _tflp = tflp,
_add_damage = 0 _add_damage = 0,
_x_enchanting = x_enchanting
} }
---crits, only on full punch interval ---crits, only on full punch interval
@ -722,7 +726,8 @@ function XBows.shoot(self, itemstack, user, pointed_thing)
local wield_item = user:get_wielded_item() local wield_item = user:get_wielded_item()
if wield_item:get_count() > 0 and wield_item:get_name() == itemstack:get_name() then if wield_item:get_count() > 0 and wield_item:get_name() == itemstack:get_name() then
user:set_wielded_item(ItemStack({ name = bow_name, wear = itemstack:get_wear() })) local new_stack = ItemStack(mergeTables(itemstack:to_table(), { name = bow_name }))
user:set_wielded_item(new_stack)
end end
end) end)
@ -906,6 +911,9 @@ function XBowsEntityDef.on_activate(self, selfObj, staticdata, dtime_s)
local bow_strength_min = x_bows_registered_bow_def.custom.strength_min local bow_strength_min = x_bows_registered_bow_def.custom.strength_min
local bow_strength_max = x_bows_registered_bow_def.custom.strength_max local bow_strength_max = x_bows_registered_bow_def.custom.strength_max
---X Enchanting
selfObj._x_enchanting = _staticdata._x_enchanting
---acceleration ---acceleration
selfObj._player_look_dir = selfObj._user:get_look_dir() selfObj._player_look_dir = selfObj._user:get_look_dir()
@ -958,7 +966,7 @@ function XBowsEntityDef.on_activate(self, selfObj, staticdata, dtime_s)
---idle animation ---idle animation
if x_bows_registered_entity_def and x_bows_registered_entity_def._custom.animations.idle then if x_bows_registered_entity_def and x_bows_registered_entity_def._custom.animations.idle then
selfObj.object:set_animation(unpack(x_bows_registered_entity_def._custom.animations.idle)) selfObj.object:set_animation(unpack(x_bows_registered_entity_def._custom.animations.idle)--[[@as table]] )
end end
---counter, e.g. for initial values set `on_step` ---counter, e.g. for initial values set `on_step`
@ -983,6 +991,11 @@ function XBowsEntityDef.on_death(self, selfObj, killer)
return return
end end
-- Infinity enchantment - arrows cannot be retrieved
if selfObj._x_enchanting.infinity and selfObj._x_enchanting.infinity.value > 0 then
return
end
minetest.item_drop(ItemStack(selfObj._arrow_name), nil, vector.round(selfObj._old_pos)) minetest.item_drop(ItemStack(selfObj._arrow_name), nil, vector.round(selfObj._old_pos))
end end
@ -1115,9 +1128,15 @@ function XBowsEntityDef.on_step(self, selfObj, dtime)
local _damage = 0 local _damage = 0
if selfObj._add_damage then if selfObj._add_damage then
-- add damage from quiver
_damage = _damage + selfObj._add_damage _damage = _damage + selfObj._add_damage
end end
if selfObj._x_enchanting.power then
-- add damage from enchantment
_damage = _damage + _damage * (selfObj._x_enchanting.power.value / 100)
end
for group, base_damage in pairs(selfObj._tool_capabilities.damage_groups) do for group, base_damage in pairs(selfObj._tool_capabilities.damage_groups) do
_damage = _damage _damage = _damage
+ base_damage + base_damage
@ -1146,11 +1165,23 @@ function XBowsEntityDef.on_step(self, selfObj, dtime)
_damage _damage
) )
if selfObj._x_enchanting.punch then
-- add knockback from enchantment
-- the `punch.value` multiplier is too strong so divide it by half
knockback = knockback * (selfObj._x_enchanting.punch.value / 2)
pointed_thing.ref:add_velocity({ pointed_thing.ref:add_velocity({
x = dir.x * knockback * -1, x = dir.x * knockback * -1,
y = 7, y = 7,
z = dir.z * knockback * -1 z = dir.z * knockback * -1
}) })
else
pointed_thing.ref:add_velocity({
x = dir.x * knockback * -1,
y = 5,
z = dir.z * knockback * -1
})
end
pointed_thing.ref:punch( pointed_thing.ref:punch(
selfObj.object, selfObj.object,
@ -1161,7 +1192,7 @@ function XBowsEntityDef.on_step(self, selfObj, dtime)
}, },
{ {
x = dir.x * -1, x = dir.x * -1,
y = 7, y = -7,
z = dir.z * -1 z = dir.z * -1
} }
) )
@ -1368,7 +1399,9 @@ function XBowsEntityDef.on_step(self, selfObj, dtime)
---Wiggle ---Wiggle
local x_bows_registered_entity_def = self.registered_entities[selfObj.name] local x_bows_registered_entity_def = self.registered_entities[selfObj.name]
if x_bows_registered_entity_def and x_bows_registered_entity_def._custom.animations.on_hit_node then if x_bows_registered_entity_def and x_bows_registered_entity_def._custom.animations.on_hit_node then
selfObj.object:set_animation(unpack(x_bows_registered_entity_def._custom.animations.on_hit_node)) selfObj.object:set_animation(
unpack(x_bows_registered_entity_def._custom.animations.on_hit_node)--[[@as table]]
)
end end
---API callbacks ---API callbacks
@ -1593,7 +1626,12 @@ function XBowsQuiver.get_itemstack_arrow_from_quiver(self, player)
found_arrow_stack = qst:take_item() found_arrow_stack = qst:take_item()
found_arrow_stack_idx = j found_arrow_stack_idx = j
if not self:is_creative(player_name) then ---X Enchanting
local wielded_stack_meta = wielded_stack:get_meta()
local is_infinity = wielded_stack_meta:get_float('is_infinity')
if not self:is_creative(player_name) and is_infinity == 0 then
-- take item will be set
detached_inv:set_list('main', detached_inv_list) detached_inv:set_list('main', detached_inv_list)
self:save(detached_inv, player, true) self:save(detached_inv, player, true)
end end
@ -2168,16 +2206,17 @@ function XBowsQuiver.sfinv_register_page(self)
'listring[current_player;main]', 'listring[current_player;main]',
} }
local player_inv = player:get_inventory() local player_inv = player:get_inventory() --[[@as InvRef]]
context._itemstack_arrow = player_inv:get_stack('x_bows:arrow_inv', 1) context._itemstack_arrow = player_inv:get_stack('x_bows:arrow_inv', 1)
context._itemstack_quiver = player_inv:get_stack('x_bows:quiver_inv', 1) context._itemstack_quiver = player_inv:get_stack('x_bows:quiver_inv', 1)
if context._itemstack_arrow and not context._itemstack_arrow:is_empty() then if context._itemstack_arrow and not context._itemstack_arrow:is_empty() then
local x_bows_registered_arrow_def = self.registered_arrows[context._itemstack_arrow:get_name()] local x_bows_registered_arrow_def = self.registered_arrows[context._itemstack_arrow:get_name()]
local short_description = context._itemstack_arrow:get_short_description()
if x_bows_registered_arrow_def then if x_bows_registered_arrow_def and short_description then
formspec[#formspec + 1] = 'label[0,1.5;' .. formspec[#formspec + 1] = 'label[0,1.5;' ..
minetest.formspec_escape(context._itemstack_arrow:get_short_description()) .. '\n' .. minetest.formspec_escape(short_description) .. '\n' ..
minetest.formspec_escape(x_bows_registered_arrow_def.custom.description_abilities) .. ']' minetest.formspec_escape(x_bows_registered_arrow_def.custom.description_abilities) .. ']'
end end
end end
@ -2186,10 +2225,14 @@ function XBowsQuiver.sfinv_register_page(self)
if context._itemstack_quiver and not context._itemstack_quiver:is_empty() then if context._itemstack_quiver and not context._itemstack_quiver:is_empty() then
local st_meta = context._itemstack_quiver:get_meta() local st_meta = context._itemstack_quiver:get_meta()
local quiver_id = st_meta:get_string('quiver_id') local quiver_id = st_meta:get_string('quiver_id')
local short_description = context._itemstack_quiver:get_short_description()
---description ---description
if short_description then
formspec[#formspec + 1] = 'label[3.5,1.5;' .. formspec[#formspec + 1] = 'label[3.5,1.5;' ..
minetest.formspec_escape(context._itemstack_quiver:get_short_description()) .. ']' minetest.formspec_escape(short_description) .. ']'
end
formspec[#formspec + 1] = 'list[detached:' .. quiver_id .. ';main;4.5,0.5;3,1;]' formspec[#formspec + 1] = 'list[detached:' .. quiver_id .. ';main;4.5,0.5;3,1;]'
formspec[#formspec + 1] = 'listring[detached:' .. quiver_id .. ';main]' formspec[#formspec + 1] = 'listring[detached:' .. quiver_id .. ';main]'
formspec[#formspec + 1] = 'listring[current_player;main]' formspec[#formspec + 1] = 'listring[current_player;main]'

View File

@ -28,6 +28,7 @@
---@field on_pickup fun(itemstack: ItemStack, picker: ObjectRef|nil, pointed_thing?: PointedThingDef, time_from_last_punch?: number|integer, rest?: any): ItemStack|nil Called when a dropped item is punched by a player. Shall pick-up the item and return the leftover itemstack or nil to not modify the dropped item. `rest` are other parameters from `luaentity:on_punch`. default: `minetest.item_pickup` ---@field on_pickup fun(itemstack: ItemStack, picker: ObjectRef|nil, pointed_thing?: PointedThingDef, time_from_last_punch?: number|integer, rest?: any): ItemStack|nil Called when a dropped item is punched by a player. Shall pick-up the item and return the leftover itemstack or nil to not modify the dropped item. `rest` are other parameters from `luaentity:on_punch`. default: `minetest.item_pickup`
---@field on_use fun(itemstack: ItemStack, user: ObjectRef|nil, pointed_thing: PointedThingDef): ItemStack|nil default: nil. When user pressed the 'punch/mine' key with the item in hand. Function must return either nil if inventory shall not be modified, or an itemstack to replace the original itemstack. e.g. itemstack:take_item(); return itemstack. Otherwise, the function is free to do what it wants. The user may be any ObjectRef or nil. The default functions handle regular use cases. ---@field on_use fun(itemstack: ItemStack, user: ObjectRef|nil, pointed_thing: PointedThingDef): ItemStack|nil default: nil. When user pressed the 'punch/mine' key with the item in hand. Function must return either nil if inventory shall not be modified, or an itemstack to replace the original itemstack. e.g. itemstack:take_item(); return itemstack. Otherwise, the function is free to do what it wants. The user may be any ObjectRef or nil. The default functions handle regular use cases.
---@field after_use fun(itemstack: ItemStack, user: ObjectRef|nil, node: NodeDef, digparams: DigParamsDef): ItemStack|nil default: nil. If defined, should return an itemstack and will be called instead of wearing out the item (if tool). If returns nil, does nothing. ---@field after_use fun(itemstack: ItemStack, user: ObjectRef|nil, node: NodeDef, digparams: DigParamsDef): ItemStack|nil default: nil. If defined, should return an itemstack and will be called instead of wearing out the item (if tool). If returns nil, does nothing.
---@field soil table Only for farming
---Tool capabilities definition ---Tool capabilities definition
---@class ToolCapabilitiesDef ---@class ToolCapabilitiesDef

View File

@ -40,7 +40,7 @@
---@field get_item_group fun(name: string, group): any returns a rating. Get rating of a group of an item. (`0` means: not in group) ---@field get_item_group fun(name: string, group): any returns a rating. Get rating of a group of an item. (`0` means: not in group)
---@field get_biome_data fun(pos: Vector): BiomeData|nil ---@field get_biome_data fun(pos: Vector): BiomeData|nil
---@field get_biome_name fun(biome_id: string|number|integer): string|nil Returns the biome name string for the provided biome id, or `nil` on failure. If no biomes have been registered, such as in mgv6, returns `default`. ---@field get_biome_name fun(biome_id: string|number|integer): string|nil Returns the biome name string for the provided biome id, or `nil` on failure. If no biomes have been registered, such as in mgv6, returns `default`.
---@field find_nodes_in_area fun(pos1: Vector, pos2: Vector, nodenames: string|string[], grouped?: boolean): table `pos1` and `pos2` are the min and max positions of the area to search. `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` If `grouped` is true the return value is a table indexed by node name which contains lists of positions. If `grouped` is false or absent the return values are as follows: first value: Table with all node positions, second value: Table with the count of each node with the node name as index, Area volume is limited to 4,096,000 nodes ---@field find_nodes_in_area fun(pos1: Vector, pos2: Vector, nodenames: string|string[], grouped?: boolean): Vector[] `pos1` and `pos2` are the min and max positions of the area to search. `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` If `grouped` is true the return value is a table indexed by node name which contains lists of positions. If `grouped` is false or absent the return values are as follows: first value: Table with all node positions, second value: Table with the count of each node with the node name as index, Area volume is limited to 4,096,000 nodes
---@field find_nodes_in_area_under_air fun(pos1: Vector, pos2: Vector, nodenames: string|string[]): table returns a list of positions. `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`. Return value: Table with all node positions with a node air above. Area volume is limited to 4,096,000 nodes. ---@field find_nodes_in_area_under_air fun(pos1: Vector, pos2: Vector, nodenames: string|string[]): table returns a list of positions. `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`. Return value: Table with all node positions with a node air above. Area volume is limited to 4,096,000 nodes.
---@field registered_decorations table<any, DecorationDef> Map of registered decoration definitions, indexed by the `name` field. If `name` is nil, the key is the object handle returned by `minetest.register_schematic`. ---@field registered_decorations table<any, DecorationDef> Map of registered decoration definitions, indexed by the `name` field. If `name` is nil, the key is the object handle returned by `minetest.register_schematic`.
---@field swap_node fun(pos: Vector, node: NodeDef): nil Set node at position, but don't remove metadata ---@field swap_node fun(pos: Vector, node: NodeDef): nil Set node at position, but don't remove metadata
@ -76,6 +76,16 @@
---@field formspec_escape fun(str: string): string returns a string, escapes the characters "[", "]", "\", "," and ";", which can not be used in formspecs. ---@field formspec_escape fun(str: string): string returns a string, escapes the characters "[", "]", "\", "," and ";", which can not be used in formspecs.
---@field get_translator fun(textdomain: string): any ---@field get_translator fun(textdomain: string): any
---@field get_current_modname fun(): string returns the currently loading mod's name, when loading a mod. ---@field get_current_modname fun(): string returns the currently loading mod's name, when loading a mod.
---@field get_pointed_thing_position fun(pointed_thing: PointedThingDef, above?: boolean): Vector | nil Returns the position of a `pointed_thing` or `nil` if the `pointed_thing` does not refer to a node or entity. If the optional `above` parameter is true and the `pointed_thing` refers to a node, then it will return the `above` position of the `pointed_thing`.
---@field item_place fun(itemstack: ItemStack, placer: ObjectRef, pointed_thing: PointedThingDef, param2?: string|number): ItemStack Wrapper that calls `minetest.item_place_node` if appropriate. Calls `on_rightclick` of `pointed_thing.under` if defined instead **Note**: is not called when wielded item overrides `on_place`, `param2` overrides facedir and wallmounted `param2`, returns `itemstack, position`, `position`: the location the node was placed to. `nil` if nothing was placed.
---@field node_dig fun(pos: Vector, node: NodeDef, digger: ObjectRef): nil Checks if node can be dug, puts item into inventory, removes node. Calls functions registered by `minetest.registered_on_dignodes()`
---@field delete_particlespawner fun(id: number, player?: ObjectRef): nil Delete `ParticleSpawner` with `id` (return value from `minetest.add_particlespawner`). If playername is specified, only deletes on the player's client, otherwise on all clients.
---@field is_area_protected fun(pos1: Vector, pos2: Vector, player_name: ObjectRef, interval: number): Vector | boolean Returns the position of the first node that `player_name` may not modify in the specified cuboid between `pos1` and `pos2`. Returns `false` if no protections were found. Applies `is_protected()` to a 3D lattice of points in the defined volume. The points are spaced evenly throughout the volume and have a spacing similar to, but no larger than, `interval`. All corners and edges of the defined volume are checked. `interval` defaults to 4. `interval` should be carefully chosen and maximised to avoid an excessive number of points being checked. Like `minetest.is_protected`, this function may be extended or overwritten by mods to provide a faster implementation to check the cuboid for intersections.
---@field is_protected fun(pos: Vector, name: string): boolean Returning `true` restricts the player `name` from modifying (i.e. digging, placing) the node at position `pos`. `name` will be `""` for non-players or unknown players. This function should be overridden by protection mods. It is highly recommended to grant access to players with the `protection_bypass` privilege. Cache and call the old version of this function if the position is not protected by the mod. This will allow using multiple protection mods.
---@field register_on_mods_loaded fun(func: fun(): nil): nil Called after mods have finished loading and before the media is cached or the aliases handled.
---@field register_on_leaveplayer fun(func: fun(player: ObjectRef, timed_out: number): nil): nil Called when a player leaves the game `timed_out`: True for timeout, false for other reasons.
---@field place_node fun(pos: Vector, node: SetNodeTable): nil Place node with the same effects that a player would cause
---@field add_particle fun(def: ParticleDef): nil
---Minetest settings ---Minetest settings
---@class MinetestSettings ---@class MinetestSettings
@ -136,3 +146,23 @@
---@field max_hear_distance number|integer ---@field max_hear_distance number|integer
---@field object ObjectRef ---@field object ObjectRef
---@field exclude_player string Name ---@field exclude_player string Name
---Partcile definition
---@class ParticleDef
---@field pos Vector
---@field velocity Vector
---@field acceleration Vector Spawn particle at pos with velocity and acceleration
---@field expirationtime number Disappears after expirationtime seconds
---@field size number Scales the visual size of the particle texture. If `node` is set, size can be set to 0 to spawn a randomly-sized particle (just like actual node dig particles).
---@field collisiondetection boolean If true collides with `walkable` nodes and, depending on the `object_collision` field, objects too.
---@field collision_removal boolean If true particle is removed when it collides. Requires collisiondetection = true to have any effect.
---@field object_collision boolean If true particle collides with objects that are defined as `physical = true,` and `collide_with_objects = true,`. Requires collisiondetection = true to have any effect.
---@field vertical boolean If true faces player using y axis only
---@field texture string The texture of the particle v5.6.0 and later: also supports the table format described in the following section
---@field playername string | nil Optional, if specified spawns particle only on the player's client
---@field animation TileAnimationDef | nil Optional, specifies how to animate the particle texture
---@field glow number | nil Optional, specify particle self-luminescence in darkness. Values 0-14.
---@field node {["name"]: string, ["param2"]: number} | nil Optional, if specified the particle will have the same appearance as node dig particles for the given node. `texture` and `animation` will be ignored if this is set.
---@field node_tile number | nil Optional, only valid in combination with `node` If set to a valid number 1-6, specifies the tile from which the particle texture is picked. Otherwise, the default behavior is used. (currently: any random tile)
---@field drag Vector | nil v5.6.0 and later: Optional drag value, consult the following section
---@field bounce {["min"]: number, ["max"]: number, ["bias"]: number} | nil v5.6.0 and later: Optional bounce range, consult the following section

View File

@ -30,6 +30,7 @@
---@field node_sound_glass_defaults fun(table?: NodeSoundDef): NodeSoundDef ---@field node_sound_glass_defaults fun(table?: NodeSoundDef): NodeSoundDef
---@field node_sound_metal_defaults fun(table?: NodeSoundDef): NodeSoundDef ---@field node_sound_metal_defaults fun(table?: NodeSoundDef): NodeSoundDef
---@field node_sound_ice_defaults fun(table?: NodeSoundDef): NodeSoundDef ---@field node_sound_ice_defaults fun(table?: NodeSoundDef): NodeSoundDef
---@field node_sound_gravel_defaults fun(table?: NodeSoundDef): NodeSoundDef
---@field get_hotbar_bg fun(x: number, y: number): nil Get the hotbar background as string, containing the formspec elements. x: Horizontal position in the formspec, y: Vertical position in the formspec. ---@field get_hotbar_bg fun(x: number, y: number): nil Get the hotbar background as string, containing the formspec elements. x: Horizontal position in the formspec, y: Vertical position in the formspec.
--- Leaf decay definition --- Leaf decay definition

View File

@ -2,6 +2,11 @@
---https://github.com/sumneko/lua-language-server/wiki ---https://github.com/sumneko/lua-language-server/wiki
---Minetest game farming mod ---Minetest game farming mod
---@class MtgFarming
---@field hoe_on_use fun(itemstack: ItemStack, user: ObjectRef, pointed_thing: PointedThingDef, uses: number): ItemStack | nil
---@field place_seed fun(itemstack: ItemStack, placer: ObjectRef, pointed_thing: PointedThingDef, plantname: string): ItemStack Seed placement
---@field grow_plant fun(pos: Vector, elapsed: number): nil
---@field register_plant fun(name: string, def: table): nil
----Node definition. Used by `minetest.register_node`. ----Node definition. Used by `minetest.register_node`.
---@class NodeDefMtgFarming ---@class NodeDefMtgFarming

View File

@ -18,6 +18,8 @@
---@field liquid_viscosity number|integer Controls speed at which the liquid spreads/flows (max. 7). ---@field liquid_viscosity number|integer Controls speed at which the liquid spreads/flows (max. 7).
-- 0 is fastest, 7 is slowest. By default, this also slows down movement of players inside the node (can be overridden using `move_resistance`) -- 0 is fastest, 7 is slowest. By default, this also slows down movement of players inside the node (can be overridden using `move_resistance`)
---@field walkable boolean If true, objects collide with node. ---@field walkable boolean If true, objects collide with node.
---@field after_dig_node fun(pos: Vector, oldnode: NodeDef, oldmetadata: table, digger: ObjectRef): nil oldmetadata is in table format. Called after destructing node when node was dug using minetest.node_dig / minetest.dig_node., default: nil
---@field paramtype2 string
---Textures of node; +Y, -Y, +X, -X, +Z, -Z. List can be shortened to needed length. ---Textures of node; +Y, -Y, +X, -X, +Z, -Z. List can be shortened to needed length.
---@class NodeTilesDef ---@class NodeTilesDef

View File

@ -195,6 +195,7 @@
---@field name string ---@field name string
---@field _rotation_factor number | fun(): number ---@field _rotation_factor number | fun(): number
---@field _step_count number ---@field _step_count number
---@field _x_enchanting table<string, {["value"]: number | nil}>
---Staticdata attributes ---Staticdata attributes
---@class EnityStaticDataAttrDef ---@class EnityStaticDataAttrDef
@ -206,3 +207,4 @@
---@field _tflp number ---@field _tflp number
---@field _add_damage number ---@field _add_damage number
---@field _faster_arrows_multiplier number | nil ---@field _faster_arrows_multiplier number | nil
---@field _x_enchanting table<string, {["value"]: number | nil}>