]> git.lizzy.rs Git - Crafter.git/blob - mods/player_api/init.lua
Fix crashes
[Crafter.git] / mods / player_api / init.lua
1 local minetest,math = minetest,math
2 local pool = {}
3
4 -- player physical data constant
5 local player_constant = {
6         visual               = "mesh"       ,
7         mesh                 = "player.b3d" ,
8         animation_speed      = 24           ,
9         visual_size          = {x = 1, y = 1, z = 1},
10         textures             = {
11                                                         "player.png"    ,
12                                                         "blank_skin.png",
13                                                    },
14         current_animation    = "stand",
15         swimming             = false,
16         collisionbox         = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
17         old_controls         = {},
18         stepheight           = 0.6  ,
19         eye_height           = 1.47 ,
20         attached             = false,
21         wield_item           = nil  ,
22 }
23
24 -- set player wield item
25 local name
26 local temp_pool
27 local item
28 local object
29 local entity
30 local object_string
31 local update_wield_item = function(player)
32         name = player:get_player_name()
33         temp_pool = pool[name]
34
35         object = temp_pool.wield_item
36
37         item = player:get_wielded_item():get_name()
38
39         if not object or (object and not object:get_luaentity()) then
40                 
41                 object = minetest.add_entity(player:get_pos(),"player_api:item")
42
43                 entity = object:get_luaentity()
44
45                 if entity then
46
47                         entity.set_item(entity,item)
48                         
49                         entity.wielder = name
50                         
51                         object:set_attach(player, "Right_Hand", vector.new(0,0,0), vector.new(0,0,0))
52                         
53                         temp_pool.wield_item = object
54                 end
55
56                 return -- catch it
57         end
58         
59         entity = object:get_luaentity()
60         object_string = entity.itemstring
61         
62         if object_string ~= item then
63                 entity.itemstring = item
64                 entity.set_item(entity,item)
65         end
66 end
67
68 -- easy way to allocate new players
69 local data
70 local name
71 local temp_pool
72
73 local set_all_properties = function(player)
74         name = player:get_player_name()
75         pool[name] = {}
76         temp_pool = pool[name]
77         data = {}
78
79         temp_pool.visual       = player_constant.visual
80         temp_pool.mesh         = player_constant.mesh
81         temp_pool.textures     = player_constant.textures
82         temp_pool.collisionbox = player_constant.collisionbox
83         temp_pool.eye_height   = player_constant.eye_height
84         temp_pool.stepheight   = player_constant.stepheight
85         temp_pool.visual_size  = player_constant.visual_size
86
87         player:set_properties(temp_pool)
88 end
89
90 -- easy way to set textures
91 local set_textures = function(player, textures)
92         player:set_properties({textures = textures})
93 end
94
95
96 local animation_list = {
97         stand            = { x = 5  , y = 5   },
98         lay              = { x = 162, y = 162 },
99         walk             = { x = 168, y = 187 },
100         mine             = { x = 189, y = 198 },
101         walk_mine        = { x = 200, y = 219 },
102         sit              = { x = 81 , y = 160 },
103         sneak            = { x = 60 , y = 60  },
104         sneak_mine_stand = { x = 20 , y = 30  },
105         sneak_walk       = { x = 60 , y = 80  },
106         sneak_mine_walk  = { x = 40 , y = 59  },
107         swim             = { x = 221, y = 241 },
108         swim_still       = { x = 226, y = 226 },
109         die              = { x = 242, y = 253 },
110 }
111
112 -- easy way to set animation
113 local name
114 local temp_pool
115 local current_animation
116
117 local set_animation = function(player, animation_name, speed, loop)
118         name = player:get_player_name()
119         temp_pool = pool[name]
120         current_animation = temp_pool.animation
121
122         if current_animation == animation_name then
123                 return
124         end
125         temp_pool.animation = animation_name
126         player:set_animation(animation_list[animation_name], speed, 0, loop)
127 end
128
129 -- allows mods to force update animation
130 local name
131 force_update_animation = function(player)
132         name = player:get_player_name()
133         pool[name].force_update = true
134 end
135
136 -- force updates the player
137 local name
138 local create_force_update = function(player)
139         name = player:get_player_name()
140         pool[name].force_update = true
141 end
142
143
144 -- toggles nametag visibility
145 local opacity
146 local show_nametag = function(player,boolean)
147         if boolean then
148                 opacity = 255
149         else
150                 opacity = 0
151         end
152         
153         player:set_nametag_attributes({
154                 color = {
155                         r = 255,
156                         b = 255,
157                         a = opacity,
158                         g = 255
159                 }
160         })
161 end
162
163 -- remove all player data
164 local name
165 minetest.register_on_leaveplayer(function(player)
166         name = player:get_player_name()
167         pool[name] = nil
168 end)
169
170
171 -- converts yaw to degrees
172 local degrees = function(yaw)
173         return(yaw*180.0/math.pi)
174 end
175
176 -- controls head bone
177 local state
178 local swimming
179 local pitch
180 local pitch_look = function(player,sneak)
181         state = get_player_state(player)
182         swimming = is_player_swimming(player)
183         pitch = degrees(player:get_look_vertical()) * -1
184         if swimming then
185                 pitch = pitch + 90
186         elseif sneak then
187                 pitch = pitch + 15
188         end
189
190         player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch,0,0))
191 end
192
193 -- checks if the player has done anything with their keyboard/mouse
194 local name
195 local temp_pool
196 local old_control
197
198 local control_check = function(player,control_table)
199         name = player:get_player_name()
200         temp_pool = pool[name]
201
202         if not temp_pool.old_controls then
203                 temp_pool.old_controls = control_table
204                 return(true)
205         end
206
207         if temp_pool.force_update then
208                 temp_pool.old_controls = control_table
209                 return(true)
210         end
211
212         for i,k in pairs(temp_pool.old_controls) do
213                 if control_table[i] ~= k then
214                         temp_pool.old_controls = control_table
215                         return(true)
216                 end
217         end
218
219         temp_pool.old_controls = control_table
220         return(false)
221 end
222
223 -- movement to animation translations
224 local translation_table = {
225         ["walk"] = {
226                 ["keys"]    = { -- required keys
227                         up      = true,
228                         down    = true,
229                         left    = true,
230                         right   = true,
231                 },
232                 ["states" ] = { -- states
233                         [false] = { -- mouse input
234                                 [0] = {animation = "walk", speed = 24},
235                                 [1] = {animation = "walk", speed = 36},
236                                 [2] = {animation = "walk", speed = 42},
237                         },
238                         [true ] = {
239                                 [0] = {animation = "walk_mine", speed = 24},
240                                 [1] = {animation = "walk_mine", speed = 36},
241                                 [2] = {animation = "walk_mine", speed = 42},
242                         }
243                 }
244         },
245
246         ["sneak"] = {
247                 ["keys"]    = {
248                         up      = true,
249                         down    = true,
250                         left    = true,
251                         right   = true,
252                 },
253                 ["states" ] = {
254                         [true ] = { -- moving
255                                 --mouse input
256                                 [false] = {animation = "sneak_walk"     , speed = 24},
257                                 [true ] = {animation = "sneak_mine_walk", speed = 24},
258                         },
259                         [false] = { -- moving
260                                 --mouse input
261                                 [false] = {animation = "sneak"           , speed = 0 },
262                                 [true ] = {animation = "sneak_mine_stand", speed = 24},
263                         }
264                 }
265         },
266         
267         ["stand"]   = {
268                 [true ] = {animation = "mine" , speed = 24},
269                 [false] = {animation = "stand", speed = 0 },
270         },
271
272         ["swim"] = {
273                 ["keys"]    = { -- required keys
274                         up      = true,
275                         down    = true,
276                         left    = true,
277                         right   = true,
278                 },
279                 ["states"]  = {
280                         [true ] = {animation = "swim"      , speed = 24},
281                         [false] = {animation = "swim_still", speed = 0 },
282                 }
283         }
284 }
285
286 -- translate input and combine with state
287 local name
288 local temp_pool
289 local state
290 local swimming
291 local mouse
292 local translated
293 local control_translation = function(player,control)
294         name = player:get_player_name()
295         temp_pool = pool[name]
296
297         state = get_player_state(player)
298         swimming = is_player_swimming(player)
299
300         mouse = (control.LMB or control.RMB)
301
302         if swimming then
303                 for k,i in pairs(control) do
304                         if i and translation_table.swim.keys[k] then
305                                 translated = translation_table.swim.states[true]
306                                 set_animation(player, translated.animation, translated.speed)
307                                 return
308                         end
309                 end
310                 translated = translation_table.swim.states[false]
311                 set_animation(player, translated.animation, translated.speed)
312                 return
313         else
314                 if control.sneak then
315                         for k,i in pairs(control) do
316                                 if i and translation_table.sneak.keys[k] then
317                                         translated = translation_table.sneak.states[true][mouse]
318                                         set_animation(player, translated.animation, translated.speed)
319                                         return
320                                 end
321                         end
322                         translated = translation_table.sneak.states[false][mouse]
323                         set_animation(player, translated.animation, translated.speed)
324                         return
325                 else
326                         for k,i in pairs(control) do
327                                 if i and translation_table.walk.keys[k] then
328                                         translated = translation_table.walk.states[mouse][state]
329                                         if translated then
330                                                 set_animation(player, translated.animation, translated.speed)
331                                                 return
332                                         end
333                                 end
334                         end
335                 end
336
337                 translated = translation_table.stand[mouse]
338                 set_animation(player, translated.animation, translated.speed)
339         end
340 end
341
342 -- translates player movement to animation
343 local control_table
344 local update
345 local do_animations = function(player)
346         control_table = player:get_player_control()
347         update = control_check(player,control_table)
348         pitch_look(player,control_table.sneak)
349         update_wield_item(player)
350         if update and player:get_hp() > 0 then
351                 control_translation(player,control_table)
352         elseif player:get_hp() <= 0 then
353                 set_animation(player,"die",40,false)
354         end
355 end
356
357
358
359 -- Update appearance when the player joins
360 minetest.register_on_joinplayer(function(player)
361         set_all_properties(player)
362 end)
363
364 minetest.register_on_respawnplayer(function(player)
365         create_force_update(player)
366 end)
367
368 -- inject into global loop
369 minetest.register_globalstep(function()
370         for _,player in ipairs(minetest.get_connected_players()) do
371                 do_animations(player)
372         end
373 end)
374
375
376
377
378 minetest.register_entity("player_api:item", {
379         initial_properties = {
380                 hp_max = 1,
381                 physical = true,
382                 collide_with_objects = false,
383                 collisionbox = {0, 0, 0, 0, 0, 0},
384                 visual = "wielditem",
385                 visual_size = {x = 0.21, y = 0.21},
386                 textures = {""},
387                 spritediv = {x = 1, y = 1},
388                 initial_sprite_basepos = {x = 0, y = 0},
389                 is_visible = true,
390                 pointable = false,
391         },
392
393         itemstring = "",
394
395         set_item = function(self, item)
396                 local stack = ItemStack(item or self.itemstring)
397                 
398                 self.itemstring = stack:to_string()
399                 
400
401                 -- Backwards compatibility: old clients use the texture
402                 -- to get the type of the item
403                 local itemname = stack:is_known() and stack:get_name() or "unknown"
404
405                 local max_count = stack:get_stack_max()
406                 local count = math.min(stack:get_count(), max_count)
407
408                 local size = 0.21
409                 local coll_height = size * 0.75
410                 local def = minetest.registered_nodes[itemname]
411                 local glow = def and def.light_source
412
413                 local is_visible = true
414                 if self.itemstring == "" then
415                         -- item not yet known
416                         is_visible = false
417                 end
418
419                 self.object:set_properties({
420                         is_visible = is_visible,
421                         visual = "wielditem",
422                         textures = {itemname},
423                         visual_size = {x = size, y = size},
424                         collisionbox = {-size, -0.21, -size,
425                                 size, coll_height, size},
426                         selectionbox = {-size, -size, -size, size, size, size},
427                         --automatic_rotate = math.pi * 0.5 * 0.2 / size,
428                         wield_item = self.itemstring,
429                         glow = glow,
430                 })
431         end,
432
433         on_step = function(self, dtime)
434                 if not self.wielder then
435                         self.object:remove()
436                 end
437         end,
438 })