--- player/init.lua
-
-dofile(minetest.get_modpath("player_api") .. "/api.lua")
-
--- Default player appearance
-player_api.register_model("character.b3d", {
- animation_speed = 24,
- textures = {"player.png", },
- animations = {
- -- Standard animations.
- stand = {x = 0, y = 0},
- die = {x = 0, y = 0},
- lay = {x = 162, y = 162},
- walk = {x = 168, y = 187},
- mine = {x = 189, y = 198},
- run = {x = 189, y = 198},
- walk_mine = {x = 200, y = 219},
- run_mine = {x = 200, y = 219},
- sit = {x = 81, y = 160},
- sneak = {x = 60, y = 60},
- sneak_mine_stand = {x=20,y=30},
- sneak_walk= {x = 60, y = 80},
- sneak_mine_walk= {x = 40, y = 59},
+local minetest,math = minetest,math
+local pool = {}
+
+-- player physical data constant
+local player_constant = {
+ visual = "mesh" ,
+ mesh = "player.b3d" ,
+ animation_speed = 24 ,
+ visual_size = {x = 1, y = 1, z = 1},
+ textures = {
+ "player.png" ,
+ "blank_skin.png",
+ },
+ current_animation = "stand",
+ swimming = false,
+ collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
+ old_controls = {},
+ stepheight = 0.6 ,
+ eye_height = 1.47 ,
+ attached = false,
+ wield_item = nil ,
+}
+
+-- set player wield item
+local name
+local temp_pool
+local item
+local object
+local entity
+local object_string
+local update_wield_item = function(player)
+ name = player:get_player_name()
+ temp_pool = pool[name]
+
+ object = temp_pool.wield_item
+
+ item = player:get_wielded_item():get_name()
+
+ if not object or (object and not object:get_luaentity()) then
+
+ object = minetest.add_entity(player:get_pos(),"player_api:item")
+
+ entity = object:get_luaentity()
+
+ if entity then
+
+ entity.set_item(entity,item)
+
+ entity.wielder = name
+
+ object:set_attach(player, "Right_Hand", vector.new(0,0,0), vector.new(0, 0, 0))
+
+ temp_pool.wield_item = object
+ end
+
+ return -- catch it
+ end
+
+ entity = object:get_luaentity()
+ object_string = entity.itemstring
+
+ if object_string ~= item then
+ entity.itemstring = item
+ entity.set_item(entity,item)
+ end
+end
+
+-- easy way to allocate new players
+local data
+local name
+local temp_pool
+
+local set_all_properties = function(player)
+ name = player:get_player_name()
+ pool[name] = {}
+ temp_pool = pool[name]
+ data = {}
+
+ temp_pool.visual = player_constant.visual
+ temp_pool.mesh = player_constant.mesh
+ temp_pool.textures = player_constant.textures
+ temp_pool.collisionbox = player_constant.collisionbox
+ temp_pool.eye_height = player_constant.eye_height
+ temp_pool.stepheight = player_constant.stepheight
+ temp_pool.visual_size = player_constant.visual_size
+ temp_pool.attached = false
+ temp_pool.sleeping = false
+ player:set_properties(temp_pool)
+end
+
+-- easy way to set textures
+local set_textures = function(player, textures)
+ player:set_properties({textures = textures})
+end
+
+
+local animation_list = {
+ stand = { x = 5 , y = 5 },
+ lay = { x = 162, y = 162 },
+ walk = { x = 168, y = 187 },
+ mine = { x = 189, y = 198 },
+ walk_mine = { x = 200, y = 219 },
+ sit = { x = 81 , y = 160 },
+ sneak = { x = 60 , y = 60 },
+ sneak_mine_stand = { x = 20 , y = 30 },
+ sneak_walk = { x = 60 , y = 80 },
+ sneak_mine_walk = { x = 40 , y = 59 },
+ swim = { x = 221, y = 241 },
+ swim_still = { x = 226, y = 226 },
+ die = { x = 242, y = 253 },
+}
+
+-- easy way to set animation
+local name
+local temp_pool
+local current_animation
+
+local set_animation = function(player, animation_name, speed, loop)
+ name = player:get_player_name()
+ temp_pool = pool[name]
+ current_animation = temp_pool.animation
+
+ if current_animation == animation_name then
+ return
+ end
+ temp_pool.animation = animation_name
+ player:set_animation(animation_list[animation_name], speed, 0, loop)
+end
+
+-- allows mods to force update animation
+local name
+force_update_animation = function(player)
+ name = player:get_player_name()
+ pool[name].force_update = true
+end
+
+-- force updates the player
+local name
+local create_force_update = function(player)
+ name = player:get_player_name()
+ pool[name].force_update = true
+end
+
+-- allows other mods to set animations per player
+set_player_animation = function(player,animation,speed,loop)
+ set_animation(player, animation, speed, loop)
+end
+
+local name
+player_is_attached = function(player,truth)
+ name = player:get_player_name()
+ pool[name].attached = truth
+end
+
+local name
+get_if_player_attached = function(player)
+ name = player:get_player_name()
+ return(pool[name].attached)
+end
+
+
+local name
+player_is_sleeping = function(player,truth)
+ name = player:get_player_name()
+ pool[name].sleeping = truth
+end
+
+local name
+get_if_player_sleeping = function(player)
+ name = player:get_player_name()
+ return(pool[name].sleeping)
+end
+
+
+-- toggles nametag visibility
+local opacity
+local show_nametag = function(player,boolean)
+ if boolean then
+ opacity = 255
+ else
+ opacity = 0
+ end
+
+ player:set_nametag_attributes({
+ color = {
+ r = 255,
+ b = 255,
+ a = opacity,
+ g = 255
+ }
+ })
+end
+
+-- remove all player data
+local name
+minetest.register_on_leaveplayer(function(player)
+ name = player:get_player_name()
+ pool[name] = nil
+end)
+
+
+-- converts yaw to degrees
+local degrees = function(yaw)
+ return(yaw*180.0/math.pi)
+end
+
+-- controls head bone
+local state
+local swimming
+local pitch
+local pitch_look = function(player,sneak)
+ state = get_player_state(player)
+ swimming = is_player_swimming(player)
+ pitch = degrees(player:get_look_vertical()) * -1
+ if swimming then
+ pitch = pitch + 90
+ elseif sneak then
+ pitch = pitch + 15
+ end
+
+ player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch,0,0))
+end
+
+-- checks if the player has done anything with their keyboard/mouse
+local name
+local temp_pool
+local old_control
+
+local control_check = function(player,control_table)
+ name = player:get_player_name()
+ temp_pool = pool[name]
+
+ if not temp_pool.old_controls then
+ temp_pool.old_controls = control_table
+ return(true)
+ end
+
+ if temp_pool.force_update then
+ temp_pool.old_controls = control_table
+ return(true)
+ end
+
+ for i,k in pairs(temp_pool.old_controls) do
+ if control_table[i] ~= k then
+ temp_pool.old_controls = control_table
+ return(true)
+ end
+ end
+
+ temp_pool.old_controls = control_table
+ return(false)
+end
+
+-- movement to animation translations
+local translation_table = {
+ ["walk"] = {
+ ["keys"] = { -- required keys
+ up = true,
+ down = true,
+ left = true,
+ right = true,
+ },
+ ["states" ] = { -- states
+ [false] = { -- mouse input
+ [0] = {animation = "walk", speed = 24},
+ [1] = {animation = "walk", speed = 36},
+ [2] = {animation = "walk", speed = 42},
+ },
+ [true ] = {
+ [0] = {animation = "walk_mine", speed = 24},
+ [1] = {animation = "walk_mine", speed = 36},
+ [2] = {animation = "walk_mine", speed = 42},
+ }
+ }
},
- collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
- stepheight = 0.6,
- eye_height = 1.47,
-})
+
+ ["sneak"] = {
+ ["keys"] = {
+ up = true,
+ down = true,
+ left = true,
+ right = true,
+ },
+ ["states" ] = {
+ [true ] = { -- moving
+ --mouse input
+ [false] = {animation = "sneak_walk" , speed = 24},
+ [true ] = {animation = "sneak_mine_walk", speed = 24},
+ },
+ [false] = { -- moving
+ --mouse input
+ [false] = {animation = "sneak" , speed = 0 },
+ [true ] = {animation = "sneak_mine_stand", speed = 24},
+ }
+ }
+ },
+
+ ["stand"] = {
+ [true ] = {animation = "mine" , speed = 24},
+ [false] = {animation = "stand", speed = 0 },
+ },
+
+ ["swim"] = {
+ ["keys"] = { -- required keys
+ up = true,
+ down = true,
+ left = true,
+ right = true,
+ },
+ ["states"] = {
+ [true ] = {animation = "swim" , speed = 24},
+ [false] = {animation = "swim_still", speed = 0 },
+ }
+ }
+}
+
+-- translate input and combine with state
+local name
+local temp_pool
+local state
+--local swimming
+local mouse
+local translated
+local control_translation = function(player,control)
+ name = player:get_player_name()
+ temp_pool = pool[name]
+
+ state = get_player_state(player)
+ swimming = is_player_swimming(player)
+
+ mouse = (control.LMB or control.RMB)
+ if swimming then
+ for k,i in pairs(control) do
+ if i and translation_table.swim.keys[k] then
+ translated = translation_table.swim.states[true]
+ set_animation(player, translated.animation, translated.speed)
+ return
+ end
+ end
+ translated = translation_table.swim.states[false]
+ set_animation(player, translated.animation, translated.speed)
+ return
+ else
+ if control.sneak then
+ for k,i in pairs(control) do
+ if i and translation_table.sneak.keys[k] then
+ translated = translation_table.sneak.states[true][mouse]
+ set_animation(player, translated.animation, translated.speed)
+ return
+ end
+ end
+ translated = translation_table.sneak.states[false][mouse]
+ set_animation(player, translated.animation, translated.speed)
+ return
+ else
+ for k,i in pairs(control) do
+ if i and translation_table.walk.keys[k] then
+ translated = translation_table.walk.states[mouse][state]
+ if translated then
+ set_animation(player, translated.animation, translated.speed)
+ return
+ end
+ end
+ end
+ end
+
+ translated = translation_table.stand[mouse]
+ set_animation(player, translated.animation, translated.speed)
+ end
+end
+
+-- translates player movement to animation
+local control_table
+local update
+local name
+local temp_pool
+local do_animations = function(player)
+ name = player:get_player_name()
+ temp_pool = pool[name]
+
+ control_table = player:get_player_control()
+ pitch_look(player,control_table.sneak)
+
+ if player:get_hp() <= 0 then
+ set_animation(player,"die",40,false)
+ elseif not temp_pool.sleeping and (not temp_pool.attached or not player:get_attach()) then
+ temp_pool.attached = false
+ update = control_check(player,control_table)
+ update_wield_item(player)
+ if update and player:get_hp() > 0 then
+ control_translation(player,control_table)
+ end
+ end
+end
+
+
-- Update appearance when the player joins
minetest.register_on_joinplayer(function(player)
- player_api.player_attached[player:get_player_name()] = false
- player_api.set_model(player, "character.b3d")
- player:set_local_animation(
- {x = 0, y = 79},
- {x = 168, y = 187},
- {x = 189, y = 198},
- {x = 200, y = 219},
- 24
- )
+ set_all_properties(player)
+end)
+
+minetest.register_on_respawnplayer(function(player)
+ create_force_update(player)
end)
+-- inject into global loop
+minetest.register_globalstep(function()
+ for _,player in ipairs(minetest.get_connected_players()) do
+ do_animations(player)
+ end
+end)
+
+
+local stack
+local itemname
+local def
+local set_item = function(self, item)
+ stack = ItemStack(item or self.itemstring)
+ self.itemstring = stack:to_string()
+
+ itemname = stack:is_known() and stack:get_name() or "unknown"
+ def = minetest.registered_nodes[itemname]
+ local tooldef = minetest.registered_tools[itemname]
+
+ self.object:set_properties({
+ textures = {itemname},
+ wield_item = self.itemstring,
+ glow = def and def.light_source,
+ })
+
+ local parent, bone, offset, rotation, forced_visible = self.object:get_attach()
+
+ if not parent then
+ return
+ end
+
+ if tooldef then
+ rotation = vector.new(90, 45, 90)
+ else
+ rotation = vector.new(0, 0, 0)
+ end
+
+ self.object:set_attach(parent, bone, offset, rotation, forced_visible)
+end
+
+minetest.register_entity("player_api:item", {
+ initial_properties = {
+ hp_max = 1,
+ visual = "wielditem",
+ physical = false,
+ textures = {""},
+ automatic_rotate = 1.5,
+ is_visible = true,
+ pointable = false,
+
+ collide_with_objects = false,
+ collisionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
+ selectionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
+ visual_size = {x = 0.21, y = 0.21},
+ },
+
+ itemstring = "",
+
+ set_item = set_item,
+
+ on_step = function(self, dtime)
+ if not self.wielder or (self.wielder and not minetest.get_player_by_name(self.wielder)) then
+ self.object:remove()
+ end
+ end,
+})