summaryrefslogtreecommitdiff
path: root/playeranim
diff options
context:
space:
mode:
Diffstat (limited to 'playeranim')
-rw-r--r--playeranim/LICENSE.md23
-rw-r--r--playeranim/README.md47
-rw-r--r--playeranim/depends.txt2
-rw-r--r--playeranim/description.txt1
-rw-r--r--playeranim/init.lua301
-rw-r--r--playeranim/mod.conf3
-rw-r--r--playeranim/model.lua99
-rw-r--r--playeranim/screenshot.pngbin0 -> 88380 bytes
-rw-r--r--playeranim/settingtypes.txt18
9 files changed, 494 insertions, 0 deletions
diff --git a/playeranim/LICENSE.md b/playeranim/LICENSE.md
new file mode 100644
index 0000000..5957b8c
--- /dev/null
+++ b/playeranim/LICENSE.md
@@ -0,0 +1,23 @@
+Copyright (c) 2013-2014, Diego Martínez
+Copyright (c) 2016-2018, Rui
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/playeranim/README.md b/playeranim/README.md
new file mode 100644
index 0000000..9938d60
--- /dev/null
+++ b/playeranim/README.md
@@ -0,0 +1,47 @@
+# playeranim
+
+Makes the head, and the right arm when you're mining, face the way you're facing, similar to Minecraft. Compatible with [3d_armor](https://github.com/stujones11/minetest-3d_armor). This is an ugly hack. Forked from [Kaeza's animplus mod](https://github.com/kaeza/minetest-animplus).
+
+The head only turns up and down relative to the body, except it turns slightly to the right/left when you strafe right/left. When you turn the body turns with the head.
+Works in both singleplayer and multiplayer.
+
+Created by [Rui](https://github.com/Rui-Minetest), this document was written by [sloantothebone](https://github.com/sloantothebone).
+
+## Configuration
+
+### Version of player model
+
+Player models supported by this mod:
+- `MTG_4_Jun_2017` (minetest_game after 4 Jun 2017, 0.4.16)
+- `MTG_4_Nov_2017` (minetest_game after 4 Nov 2017, 0.5.0)
+
+As there is no automatic way to determine which version is used, this must be configured with advanced settings menu, or by manually editing `playeranim.model_version` entry in minetest.conf.
+The default value is `MTG_4_Jun_2017`.
+
+Symptoms of having configured the incorrect player model:
+- In rest, arms are raised up, and are either detached from the body, or are too close to the body
+- Cape (if visible) points upward
+
+### The delay of sideways body rotation
+
+Configure `playeranim.body_rotation_delay`.
+It's the number of frame delay of sideways body rotation.
+The default value is `7`.
+
+### Lengthways body rotation in sneaking
+
+Configure `playeranim.body_x_rotation_sneak`.
+It's the degrees of the body's X-axis rotation in sneaking.
+The default value is `6.0`.
+
+### The speed of an animation
+
+Configure `playeranim.animation_speed`.
+It's the number of stepping per seconds.
+The default value is `2.4`.
+
+### The speed of an animation in sneaking
+
+Configure `playeranim.animation_speed_sneak`.
+It's the number of stepping per seconds in sneaking.
+The default value is `0.8`.
diff --git a/playeranim/depends.txt b/playeranim/depends.txt
new file mode 100644
index 0000000..9bcff68
--- /dev/null
+++ b/playeranim/depends.txt
@@ -0,0 +1,2 @@
+default?
+player_api?
diff --git a/playeranim/description.txt b/playeranim/description.txt
new file mode 100644
index 0000000..0c1198d
--- /dev/null
+++ b/playeranim/description.txt
@@ -0,0 +1 @@
+Adds animations to the players' head and right arm. \ No newline at end of file
diff --git a/playeranim/init.lua b/playeranim/init.lua
new file mode 100644
index 0000000..e6730e2
--- /dev/null
+++ b/playeranim/init.lua
@@ -0,0 +1,301 @@
+local ANIMATION_SPEED = tonumber(minetest.settings:get("playeranim.animation_speed")) or 2.4
+local ANIMATION_SPEED_SNEAK = tonumber(minetest.settings:get("playeranim.animation_speed_sneak")) or 0.8
+local BODY_ROTATION_DELAY = math.max(math.floor(tonumber(minetest.settings:get("playeranim.body_rotation_delay")) or 7), 1)
+local BODY_X_ROTATION_SNEAK = tonumber(minetest.settings:get("playeranim.body_x_rotation_sneak")) or 6.0
+
+local BONE_POSITION, BONE_ROTATION = (function()
+ local modname = minetest.get_current_modname()
+ local modpath = minetest.get_modpath(modname)
+ return dofile(modpath .. "/model.lua")
+end)()
+
+local get_animation = player_api and player_api.get_animation or default.player_get_animation
+if not get_animation then
+ error("player_api.get_animation or default.player_get_animation is not found")
+end
+
+local function get_animation_speed(player)
+ if player:get_player_control().sneak then
+ return ANIMATION_SPEED_SNEAK
+ end
+ return ANIMATION_SPEED
+end
+
+local math_deg = math.deg
+local function get_pitch_deg(player)
+ return math_deg(player:get_look_vertical())
+end
+
+local players_animation_data = setmetatable({}, {
+ __index = {
+ init_player = function(self, player)
+ self[player] = {
+ time = 0,
+ yaw_history = {},
+ bone_rotations = {},
+ bone_positions = {},
+ previous_animation = 0,
+ }
+ end,
+
+ -- time
+ get_time = function(self, player)
+ return self[player].time
+ end,
+
+ increment_time = function(self, player, dtime)
+ self[player].time = self:get_time(player) + dtime
+ end,
+
+ reset_time = function(self, player)
+ self[player].time = 0
+ end,
+
+ -- yaw_history
+ get_yaw_history = function(self, player)
+ return self[player].yaw_history -- Return mutable reference
+ end,
+
+ add_yaw_to_history = function(self, player)
+ local yaw = player:get_look_horizontal()
+ local history = self:get_yaw_history(player)
+ history[#history + 1] = yaw
+ end,
+
+ clear_yaw_history = function(self, player)
+ if #self[player].yaw_history > 0 then
+ self[player].yaw_history = {}
+ end
+ end,
+
+ -- bone_rotations
+ get_bone_rotation = function(self, player, bone)
+ return self[player].bone_rotations[bone]
+ end,
+
+ set_bone_rotation = function(self, player, bone, rotation)
+ self[player].bone_rotations[bone] = rotation
+ end,
+
+ -- bone_positions
+ get_bone_position = function(self, player, bone)
+ return self[player].bone_positions[bone]
+ end,
+
+ set_bone_position = function(self, player, bone, position)
+ self[player].bone_positions[bone] = position
+ end,
+
+ -- previous_animation
+ get_previous_animation = function(self, player)
+ return self[player].previous_animation
+ end,
+
+ set_previous_animation = function(self, player, animation)
+ self[player].previous_animation = animation
+ end,
+ }
+})
+
+minetest.register_on_joinplayer(function(player)
+ players_animation_data:init_player(player)
+end)
+
+local vector_add, vector_equals = vector.add, vector.equals
+local function rotate_bone(player, bone, rotation, position_optional)
+ local previous_rotation = players_animation_data:get_bone_rotation(player, bone)
+ local rotation = vector_add(rotation, BONE_ROTATION[bone])
+
+ local previous_position = players_animation_data:get_bone_position(player, bone)
+ local position = BONE_POSITION[bone]
+ if position_optional then
+ position = vector_add(position, position_optional)
+ end
+
+ if not previous_rotation
+ or not previous_position
+ or not vector_equals(rotation, previous_rotation)
+ or not vector_equals(position, previous_position) then
+ player:set_bone_position(bone, position, rotation)
+ players_animation_data:set_bone_rotation(player, bone, rotation)
+ players_animation_data:set_bone_position(player, bone, position)
+ end
+end
+
+-- Animation alias
+local STAND = 1
+local WALK = 2
+local MINE = 3
+local WALK_MINE = 4
+local SIT = 5
+local LAY = 6
+
+-- Bone alias
+local BODY = "Body"
+local HEAD = "Head"
+local CAPE = "Cape"
+local LARM = "Arm_Left"
+local RARM = "Arm_Right"
+local LLEG = "Leg_Left"
+local RLEG = "Leg_Right"
+
+local math_sin, math_cos, math_pi = math.sin, math.cos, math.pi
+local ANIMATIONS = {
+ [STAND] = function(player, _time)
+ rotate_bone(player, BODY, {x = 0, y = 0, z = 0})
+ rotate_bone(player, CAPE, {x = 0, y = 0, z = 0})
+ rotate_bone(player, LARM, {x = 0, y = 0, z = 0})
+ rotate_bone(player, RARM, {x = 0, y = 0, z = 0})
+ rotate_bone(player, LLEG, {x = 0, y = 0, z = 0})
+ rotate_bone(player, RLEG, {x = 0, y = 0, z = 0})
+ end,
+
+ [LAY] = function(player, _time)
+ rotate_bone(player, HEAD, {x = 0, y = 0, z = 0})
+ rotate_bone(player, CAPE, {x = 0, y = 0, z = 0})
+ rotate_bone(player, LARM, {x = 0, y = 0, z = 0})
+ rotate_bone(player, RARM, {x = 0, y = 0, z = 0})
+ rotate_bone(player, LLEG, {x = 0, y = 0, z = 0})
+ rotate_bone(player, RLEG, {x = 0, y = 0, z = 0})
+ rotate_bone(player, BODY, BONE_ROTATION.body_lay, BONE_POSITION.body_lay)
+ end,
+
+ [SIT] = function(player, _time)
+ rotate_bone(player, LARM, {x = 0, y = 0, z = 0})
+ rotate_bone(player, RARM, {x = 0, y = 0, z = 0})
+ rotate_bone(player, LLEG, {x = 90, y = 0, z = 0})
+ rotate_bone(player, RLEG, {x = 90, y = 0, z = 0})
+ rotate_bone(player, BODY, BONE_ROTATION.body_sit, BONE_POSITION.body_sit)
+ end,
+
+ [WALK] = function(player, time)
+ local speed = get_animation_speed(player)
+ local sin = math_sin(time * speed * math_pi)
+
+ rotate_bone(player, CAPE, {x = -35 * sin - 35, y = 0, z = 0})
+ rotate_bone(player, LARM, {x = -55 * sin, y = 0, z = 0})
+ rotate_bone(player, RARM, {x = 55 * sin, y = 0, z = 0})
+ rotate_bone(player, LLEG, {x = 55 * sin, y = 0, z = 0})
+ rotate_bone(player, RLEG, {x = -55 * sin, y = 0, z = 0})
+ end,
+
+ [MINE] = function(player, time)
+ local speed = get_animation_speed(player)
+
+ local cape_sin = math_sin(time * speed * math_pi)
+ local rarm_sin = math_sin(2 * time * speed * math_pi)
+ local rarm_cos = -math_cos(2 * time * speed * math_pi)
+ local pitch = 90 - get_pitch_deg(player)
+
+ rotate_bone(player, CAPE, {x = -5 * cape_sin - 5, y = 0, z = 0})
+ rotate_bone(player, LARM, {x = 0, y = 0, z = 0})
+ rotate_bone(player, RARM, {x = 10 * rarm_sin + pitch, y = 10 * rarm_cos, z = 0})
+ rotate_bone(player, LLEG, {x = 0, y = 0, z = 0})
+ rotate_bone(player, RLEG, {x = 0, y = 0, z = 0})
+ end,
+
+ [WALK_MINE] = function(player, time)
+ local speed = get_animation_speed(player)
+
+ local sin = math_sin(time * speed * math_pi)
+ local rarm_sin = math_sin(2 * time * speed * math_pi)
+ local rarm_cos = -math_cos(2 * time * speed * math_pi)
+ local pitch = 90 - get_pitch_deg(player)
+
+ rotate_bone(player, CAPE, {x = -35 * sin - 35, y = 0, z = 0})
+ rotate_bone(player, LARM, {x = -55 * sin, y = 0, z = 0})
+ rotate_bone(player, RARM, {x = 10 * rarm_sin + pitch, y = 10 * rarm_cos, z = 0})
+ rotate_bone(player, LLEG, {x = 55 * sin, y = 0, z = 0})
+ rotate_bone(player, RLEG, {x = -55 * sin, y = 0, z = 0})
+ end,
+}
+
+local function set_animation(player, animation, force_animate)
+ local animation_changed
+ = (players_animation_data:get_previous_animation(player) ~= animation)
+
+ if force_animate or animation_changed then
+ players_animation_data:set_previous_animation(player, animation)
+ ANIMATIONS[animation](player, players_animation_data:get_time(player))
+ end
+end
+
+local function rotate_head(player)
+ local head_x_rotation = -get_pitch_deg(player)
+ rotate_bone(player, HEAD, {x = head_x_rotation, y = 0, z = 0})
+end
+
+local table_remove, math_deg = table.remove, math.deg
+local function rotate_body_and_head(player)
+ local body_x_rotation = (function()
+ local sneak = player:get_player_control().sneak
+ return sneak and BODY_X_ROTATION_SNEAK or 0
+ end)()
+
+ local body_y_rotation = (function()
+ local yaw_history = players_animation_data:get_yaw_history(player)
+ if #yaw_history > BODY_ROTATION_DELAY then
+ local body_yaw = table_remove(yaw_history, 1)
+ local player_yaw = player:get_look_horizontal()
+ return math_deg(player_yaw - body_yaw)
+ end
+ return 0
+ end)()
+
+ rotate_bone(player, BODY, {x = body_x_rotation, y = body_y_rotation, z = 0})
+
+ local head_x_rotation = -get_pitch_deg(player)
+ rotate_bone(player, HEAD, {x = head_x_rotation, y = -body_y_rotation, z = 0})
+end
+
+
+local function animate_player(player, dtime)
+ local animation = get_animation(player).animation
+
+ -- Yaw history
+ if animation == "lay" or animation == "sit" then
+ players_animation_data:clear_yaw_history(player)
+ else
+ players_animation_data:add_yaw_to_history(player)
+ end
+
+ -- Increment animation time
+ if animation == "walk"
+ or animation == "mine"
+ or animation == "walk_mine" then
+ players_animation_data:increment_time(player, dtime)
+ else
+ players_animation_data:reset_time(player)
+ end
+
+ -- Set animation
+ if animation == "stand" then
+ set_animation(player, STAND)
+ elseif animation == "lay" then
+ set_animation(player, LAY)
+ elseif animation == "sit" then
+ set_animation(player, SIT)
+ elseif animation == "walk" then
+ set_animation(player, WALK, true)
+ elseif animation == "mine" then
+ set_animation(player, MINE, true)
+ elseif animation == "walk_mine" then
+ set_animation(player, WALK_MINE, true)
+ end
+
+ -- Rotate body and head
+ if animation == "lay" then
+ -- Do nothing
+ elseif animation == "sit" then
+ rotate_head(player)
+ else
+ rotate_body_and_head(player)
+ end
+end
+
+local minetest_get_connected_players = minetest.get_connected_players
+minetest.register_globalstep(function(dtime)
+ for _, player in ipairs(minetest_get_connected_players()) do
+ animate_player(player, dtime)
+ end
+end)
diff --git a/playeranim/mod.conf b/playeranim/mod.conf
new file mode 100644
index 0000000..3e162f0
--- /dev/null
+++ b/playeranim/mod.conf
@@ -0,0 +1,3 @@
+name = playeranim
+description = Adds animations to the players' head and right arm.
+optional_depends = player_api, default
diff --git a/playeranim/model.lua b/playeranim/model.lua
new file mode 100644
index 0000000..717382c
--- /dev/null
+++ b/playeranim/model.lua
@@ -0,0 +1,99 @@
+-- Bone alias
+local BODY = "Body"
+local HEAD = "Head"
+local CAPE = "Cape"
+local LARM = "Arm_Left"
+local RARM = "Arm_Right"
+local LLEG = "Leg_Left"
+local RLEG = "Leg_Right"
+
+-- Version of player model
+local DEFAULT_PLAYER_MODEL_VERSION = "MTG_4_Jun_2017"
+
+local VALID_PLAYER_MODEL_VERSIONS = {
+ MTG_4_Jun_2017 = true,
+ MTG_4_Nov_2017 = true,
+}
+
+local LEGACY_PLAYER_MODEL_VERSIONS = {
+ default_character_v1 = true,
+ default_character_v2 = true,
+ default_character_v3 = true,
+}
+
+local BONE_POSITIONS = {
+ MTG_4_Jun_2017 = {
+ [BODY] = {x = 0, y = -3.5, z = 0},
+ [HEAD] = {x = 0, y = 6.5, z = 0},
+ [CAPE] = {x = 0, y = 6.5, z = 1.2},
+ [LARM] = {x = 3, y = 5.5, z = 0},
+ [RARM] = {x = -3, y = 5.5, z = 0},
+ [LLEG] = {x = 1, y = 0, z = 0},
+ [RLEG] = {x = -1, y = 0, z = 0},
+
+ body_sit = {x = 0, y = -5.5, z = 0},
+ body_lay = {x = 0, y = -5.5, z = 0},
+ },
+ MTG_4_Nov_2017 = {
+ [BODY] = {x = 0, y = 6.25, z = 0},
+ [HEAD] = {x = 0, y = 6.5, z = 0},
+ [CAPE] = {x = 0, y = 6.5, z = 1.2},
+ [LARM] = {x = 3, y = 5.5, z = 0},
+ [RARM] = {x = -3, y = 5.5, z = 0},
+ [LLEG] = {x = 1, y = 0, z = 0},
+ [RLEG] = {x = -1, y = 0, z = 0},
+
+ body_sit = {x = 0, y = -5, z = 0},
+ body_lay = {x = 0, y = -5, z = 0},
+ },
+}
+
+local BONE_ROTATIONS = {
+ MTG_4_Jun_2017 = {
+ [BODY] = {x = 0, y = 0, z = 0},
+ [HEAD] = {x = 0, y = 0, z = 0},
+ [CAPE] = {x = 0, y = 0, z = 0},
+ [LARM] = {x = 0, y = 0, z = 0},
+ [RARM] = {x = 0, y = 0, z = 0},
+ [LLEG] = {x = 0, y = 0, z = 0},
+ [RLEG] = {x = 0, y = 0, z = 0},
+
+ body_sit = {x = 0, y = 0, z = 0},
+ body_lay = {x = 270, y = 0, z = 0},
+ },
+ MTG_4_Nov_2017 = {
+ [BODY] = {x = 0, y = 0, z = 0},
+ [HEAD] = {x = 0, y = 0, z = 0},
+ [CAPE] = {x = 0, y = 0, z = 0},
+ [LARM] = {x = 0, y = 0, z = 0},
+ [RARM] = {x = 0, y = 0, z = 0},
+ [LLEG] = {x = 0, y = 0, z = 0},
+ [RLEG] = {x = 0, y = 0, z = 0},
+
+ body_sit = {x = 0, y = 0, z = 0},
+ body_lay = {x = 270, y = 0, z = 0},
+ },
+}
+
+local PLAYER_MODEL_VERSION = (function()
+ local version = minetest.settings:get("playeranim.model_version")
+ if version == nil or version == "" then
+ version = DEFAULT_PLAYER_MODEL_VERSION
+ end
+
+ if LEGACY_PLAYER_MODEL_VERSIONS[version] then
+ error("The model version '" .. version .. "' is no longer suppported")
+ elseif not VALID_PLAYER_MODEL_VERSIONS[version] then
+ error("Invalid value for playeranim.model_version in minetest.conf: " .. version)
+ end
+
+ return version
+end)()
+
+local BONE_POSITION = BONE_POSITIONS[PLAYER_MODEL_VERSION]
+local BONE_ROTATION = BONE_ROTATIONS[PLAYER_MODEL_VERSION]
+if not BONE_POSITION or not BONE_ROTATION then
+ error("Internal error: invalid player_model_version: " .. PLAYER_MODEL_VERSION)
+end
+
+return BONE_POSITION, BONE_ROTATION
diff --git a/playeranim/screenshot.png b/playeranim/screenshot.png
new file mode 100644
index 0000000..57aeefe
--- /dev/null
+++ b/playeranim/screenshot.png
Binary files differ
diff --git a/playeranim/settingtypes.txt b/playeranim/settingtypes.txt
new file mode 100644
index 0000000..a36322f
--- /dev/null
+++ b/playeranim/settingtypes.txt
@@ -0,0 +1,18 @@
+# Version of player model.
+#
+# Player models supported by this mod:
+# . -- `MTG_4_Jun_2017` (minetest_game after 4 Jun 2017, 0.4.16)
+# . -- `MTG_4_Nov_2017` (minetest_game after 4 Nov 2017, 0.5.0)
+playeranim.model_version (Version of player model) enum MTG_4_Jun_2017 MTG_4_Jun_2017,MTG_4_Nov_2017
+
+# The number of frame delay of sideways body rotation. (between 1 and 20).
+playeranim.body_rotation_delay (The delay of sideways body rotation) int 7 1 20
+
+# The degrees of the body's X-axis rotation in sneaking.
+playeranim.body_x_rotation_sneak (Lengthways body rotation in sneaking) float 6.0
+
+# The number of stepping per seconds.
+playeranim.animation_speed (The speed of an animation) float 2.4
+
+# The number of stepping per seconds in sneaking.
+playeranim.animation_speed_sneak (The speed of an animation in sneaking) float 0.8