diff --git a/.gitignore b/.gitignore index 4f8931c..073f0c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .DS_Store docs/build +*.blend1 +*.blend2 diff --git a/.luacheckrc b/.luacheckrc index bcca4f3..6d21f31 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -63,5 +63,8 @@ read_globals = { "default", "i3", "unified_inventory", - "player_api" + "player_api", + "u_skins", + "wardrobe", + "3d_armor" } diff --git a/api.lua b/api.lua index 3a6e86c..a5a28be 100644 --- a/api.lua +++ b/api.lua @@ -32,6 +32,9 @@ XBows = { player_monoids = minetest.get_modpath('player_monoids'), i3 = minetest.get_modpath('i3'), unified_inventory = minetest.get_modpath('unified_inventory'), + u_skins = minetest.get_modpath('u_skins'), + wardrobe = minetest.get_modpath('wardrobe'), + _3d_armor = minetest.get_modpath('3d_armor'), registered_bows = {}, registered_arrows = {}, registered_quivers = {}, @@ -2157,3 +2160,106 @@ function XBowsQuiver.ui_register_page(self) tooltip = 'X Bows', }) end + +function XBows.show_3d_quiver(self, player) + local p_name = player:get_player_name() + local player_textures + + if self._3d_armor then + minetest.after(0.1, function() + player_textures = { + armor.textures[p_name].skin, + armor.textures[p_name].armor, + armor.textures[p_name].wielditem, + 'x_bows_quiver_mesh.png' + } + + if player_textures then + player_api.set_textures(player, player_textures) + end + end) + + return + elseif self.u_skins then + local u_skin_texture = u_skins.u_skins[p_name] + + player_textures = { + u_skin_texture .. '.png', + 'x_bows_quiver_mesh.png' + } + elseif self.wardrobe and wardrobe.playerSkins and wardrobe.playerSkins[p_name] then + player_textures = { + wardrobe.playerSkins[p_name], + 'x_bows_quiver_mesh.png' + } + else + local textures = player_api.get_textures(player) + + ---cleanup + for index, value in ipairs(textures) do + if value == 'x_bows_quiver_empty_mesh.png' or value == 'x_bows_quiver_mesh.png' then + table.remove(textures, index) + end + end + + table.insert(textures, 'x_bows_quiver_mesh.png') + + player_textures = textures + end + + if player_textures then + player_api.set_textures(player, player_textures) + end +end + +function XBows.hide_3d_quiver(self, player) + local p_name = player:get_player_name() + local player_textures + + if self._3d_armor then + minetest.after(0.1, function() + player_textures = { + armor.textures[p_name].skin, + armor.textures[p_name].armor, + armor.textures[p_name].wielditem, + 'x_bows_quiver_empty_mesh.png' + } + + if player_textures then + player_api.set_textures(player, player_textures) + end + + end) + + return + elseif self.u_skins then + local u_skin_texture = u_skins.u_skins[p_name] + + player_textures = { + u_skin_texture .. '.png', + 'x_bows_quiver_empty_mesh.png' + } + elseif self.wardrobe and wardrobe.playerSkins and wardrobe.playerSkins[p_name] then + player_textures = { + wardrobe.playerSkins[p_name], + 'x_bows_quiver_empty_mesh.png' + } + else + local textures = player_api.get_textures(player) + + ---cleanup + for index, value in ipairs(textures) do + if value == 'x_bows_quiver_mesh.png' or value == 'x_bows_quiver_empty_mesh.png' then + table.remove(textures, index) + end + end + + table.insert(textures, 'x_bows_quiver_empty_mesh.png') + + player_textures = textures + end + + if player_textures then + player_api.set_textures(player, player_textures) + end +end diff --git a/init.lua b/init.lua index e1d2dba..71338cf 100644 --- a/init.lua +++ b/init.lua @@ -6,6 +6,8 @@ ItemStack = ItemStack--[[@as ItemStack]] vector = vector--[[@as Vector]] default = default--[[@as MtgDefault]] sfinv = sfinv--[[@as Sfinv]] +unified_inventory = unified_inventory--[[@as UnifiedInventory]] +player_api = player_api--[[@as MtgPlayerApi]] math.randomseed(tonumber(tostring(os.time()):reverse():sub(1, 9))--[[@as number]]) @@ -20,7 +22,6 @@ dofile(path .. '/arrow.lua') dofile(path .. '/items.lua') dofile(path .. '/quiver.lua') - if XBows.i3 then XBowsQuiver:i3_register_page() elseif XBows.unified_inventory then @@ -33,34 +34,48 @@ minetest.register_on_joinplayer(function(player) local inv_quiver = player:get_inventory()--[[@as InvRef]] local inv_arrow = player:get_inventory()--[[@as InvRef]] + if XBows._3d_armor then + player_api.set_model(player, 'x_bows_3d_armor_character.b3d') + else + player_api.set_model(player, 'x_bows_character.b3d') + end + inv_quiver:set_size('x_bows:quiver_inv', 1 * 1) inv_arrow:set_size('x_bows:arrow_inv', 1 * 1) - local quiver = player:get_inventory():get_stack('x_bows:quiver_inv', 1) + local quiver_stack = player:get_inventory():get_stack('x_bows:quiver_inv', 1) - if quiver and not quiver:is_empty() then - local st_meta = quiver:get_meta() + if quiver_stack and not quiver_stack:is_empty() then + local st_meta = quiver_stack:get_meta() local quiver_id = st_meta:get_string('quiver_id') + ---create detached inventory XBowsQuiver:get_or_create_detached_inv( quiver_id, player:get_player_name(), st_meta:get_string('quiver_items') ) + + ---set model textures + XBows:show_3d_quiver(player) + else + ---set model textures + XBows:hide_3d_quiver(player) end - player_api.set_model(player, 'x_bows_character.b3d') - - player_api.set_textures(player, { - 'character.png', - 'x_bows_quiver_mesh.png' - }) + XBows:reset_charged_bow(player, true) + XBowsQuiver:close_quiver(player) end) ----player api -player_api.register_model('x_bows_character.b3d', { +local model_name = 'x_bows_character.b3d' +if XBows._3d_armor then + ---3d armor + model_name = 'x_bows_3d_armor_character.b3d' +end + +player_api.register_model(model_name, { animation_speed = 30, - textures = {"character.png"}, + textures = {'character.png'}, animations = { -- Standard animations. stand = {x = 0, y = 79}, @@ -206,7 +221,11 @@ minetest.register_on_player_inventory_action(function(player, action, inventory, sfinv.set_player_inventory_formspec(player) end + ---set player visual + XBows:show_3d_quiver(player) elseif action == 'move' and inventory_info.from_list == 'x_bows:quiver_inv' then + local stack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index) + if XBows.i3 then i3.set_fs(player) elseif XBows.unified_inventory then @@ -214,6 +233,11 @@ minetest.register_on_player_inventory_action(function(player, action, inventory, else sfinv.set_player_inventory_formspec(player) end + + ---set player visual + if stack:is_empty() then + XBows:hide_3d_quiver(player) + end elseif action == 'put' and inventory_info.listname == 'x_bows:quiver_inv' then if XBows.i3 then i3.set_fs(player) @@ -236,11 +260,6 @@ end) ---backwards compatibility minetest.register_alias('x_bows:arrow_diamond_tipped_poison', 'x_bows:arrow_diamond') -minetest.register_on_joinplayer(function(player) - XBows:reset_charged_bow(player, true) - XBowsQuiver:close_quiver(player) -end) - -- sneak, fov adjustments when bow is charged minetest.register_globalstep(function(dtime) bow_charged_timer = bow_charged_timer + dtime diff --git a/mod.conf b/mod.conf index 096215d..fde9cfa 100644 --- a/mod.conf +++ b/mod.conf @@ -1,6 +1,6 @@ name = x_bows description = Adds bow and arrows to Minetest. depends = -optional_depends = default, farming, 3d_armor, mesecons, playerphysics, player_monoids, wool, i3, unified_inventory +optional_depends = default, farming, 3d_armor, mesecons, playerphysics, player_monoids, wool, i3, unified_inventory, simple_skins, u_skins, wardrobe supported_games = minetest_game min_minetest_version = 5.4 diff --git a/models/x_bows_3d_armor_character.b3d b/models/x_bows_3d_armor_character.b3d new file mode 100644 index 0000000..f93d41c Binary files /dev/null and b/models/x_bows_3d_armor_character.b3d differ diff --git a/models/x_bows_3d_armor_character.blend b/models/x_bows_3d_armor_character.blend new file mode 100644 index 0000000..2d38611 Binary files /dev/null and b/models/x_bows_3d_armor_character.blend differ diff --git a/models/x_bows_arrow.blend b/models/x_bows_arrow.blend new file mode 100644 index 0000000..01acca7 Binary files /dev/null and b/models/x_bows_arrow.blend differ diff --git a/models/x_bows_arrow_anim_bones.blend b/models/x_bows_arrow_anim_bones.blend deleted file mode 100644 index 8397347..0000000 Binary files a/models/x_bows_arrow_anim_bones.blend and /dev/null differ diff --git a/models/x_bows_character.b3d b/models/x_bows_character.b3d index ee7c9af..b6a18ae 100644 Binary files a/models/x_bows_character.b3d and b/models/x_bows_character.b3d differ diff --git a/models/x_bows_character.blend b/models/x_bows_character.blend new file mode 100644 index 0000000..b43946c Binary files /dev/null and b/models/x_bows_character.blend differ diff --git a/textures/x_bows_quiver_empty_mesh.png b/textures/x_bows_quiver_empty_mesh.png new file mode 100644 index 0000000..9e7ec19 Binary files /dev/null and b/textures/x_bows_quiver_empty_mesh.png differ diff --git a/types/mtg-player-api.type.lua b/types/mtg-player-api.type.lua new file mode 100644 index 0000000..c0d2b76 --- /dev/null +++ b/types/mtg-player-api.type.lua @@ -0,0 +1,32 @@ +---The player API can register player models and update the player's appearance. +---@class MtgPlayerApi +---@field globalstep fun(dtime: number, ...): nil The function called by the globalstep that controls player animations. You can override this to replace the globalstep with your own implementation. Receives all args that minetest.register_globalstep() passes +---@field register_model fun(name: string, def: MtgPlayerApiModelDef): nil Register a new model to be used by players, `name`: model filename such as "character.x", "foo.b3d", etc., `def`: see [#Model definition] Saved to player_api.registered_models +---@field registered_models string[] Get a model's definition, `name`: model filename See [#Model definition] +---@field set_model fun(player: ObjectRef, model_name: string): nil Change a player's model, `player`: PlayerRef, `model_name`: model registered with `player_api.register_model` +---@field set_animation fun(player: ObjectRef, anim_name: string, speed: number): nil Applies an animation to a player if speed or anim_name differ from the currently playing animation, `player`: PlayerRef, `anim_name`: name of the animation, `speed`: keyframes per second. If nil, the default from the model def is used +---@field set_textures fun(player: ObjectRef, textures: string[]): nil Sets player textures `player`: PlayerRef, `textures`: array of textures. If nil, the default from the model def is used +---@field set_texture fun(player: ObjectRef, index: number, texture: string): nil Sets one of the player textures, `player`: PlayerRef, `index`: Index into array of all textures, `texture`: the texture string +---@field get_textures fun(player: ObjectRef): string[] Returns player textures table +---@field get_animation fun(player: ObjectRef): {["model"]: string | nil, ["textures"]: string[] | nil, ["animation"]: table | nil} Returns a table containing fields `model`, `textures` and `animation`. Any of the fields of the returned table may be nil, `player`: PlayerRef +---@field player_attached table A table that maps a player name to a boolean. If the value for a given player is set to true, the default player animations (walking, digging, ...) will no longer be updated, and knockback from damage is prevented for that player. Example of usage: A mod sets a player's value to true when attached to a vehicle. + + +---Model Definition +---@class MtgPlayerApiModelDef +---@field animation_speed number Default: 30, animation speed, in keyframes per second +---@field textures string[] Default `{"character.png"}`, array of textures +---@field animations table +---@field visual_size {["x"]: number, ["y"]: number} +---@field collisionbox number[] +---@field stepheight number +---@field eye_height number + + +---Model Animation definition +---@class MtgPlayerApiAnimationDef +---@field x number start frame +---@field y number end frame +---@field collisionbox number[] | nil +---@field eye_height number | nil model eye height +---@field override_local boolean | nil suspend client side animations while this one is active (optional) diff --git a/types/unified_inventory.type.lua b/types/unified_inventory.type.lua new file mode 100644 index 0000000..1f1bfd0 --- /dev/null +++ b/types/unified_inventory.type.lua @@ -0,0 +1,7 @@ +---Base class Unified Inventory +---@class UnifiedInventory +---@field set_inventory_formspec fun(player: ObjectRef, formspecname: string): nil +---@field register_button fun(name: string, def: table): nil +---@field single_slot fun(x: number, y: number): nil +---@field register_page fun(name: string, def: table): nil +---@field style_full table