Implement trading tier unlocking
[MineClone/MineClone2.git] / mods / ENTITIES / mcl_mobs / mount.lua
blob04050eb0e6e9c809c994ca6ec228fa8a28b40b64
2 -- lib_mount by Blert2112 (edited by TenPlus1)
4 local enable_crash = false
5 local crash_threshold = 6.5 -- ignored if enable_crash=false
7 ------------------------------------------------------------------------------
9 --
10 -- Helper functions
13 local node_ok = function(pos, fallback)
15 fallback = fallback or mobs.fallback_node
17 local node = minetest.get_node_or_nil(pos)
19 if node and minetest.registered_nodes[node.name] then
20 return node
21 end
23 return {name = fallback}
24 end
27 local function node_is(pos)
29 local node = node_ok(pos)
31 if node.name == "air" then
32 return "air"
33 end
35 if minetest.get_item_group(node.name, "lava") ~= 0 then
36 return "lava"
37 end
39 if minetest.get_item_group(node.name, "liquid") ~= 0 then
40 return "liquid"
41 end
43 if minetest.registered_nodes[node.name].walkable == true then
44 return "walkable"
45 end
47 return "other"
48 end
51 local function get_sign(i)
53 i = i or 0
55 if i == 0 then
56 return 0
57 else
58 return i / math.abs(i)
59 end
60 end
63 local function get_velocity(v, yaw, y)
65 local x = -math.sin(yaw) * v
66 local z = math.cos(yaw) * v
68 return {x = x, y = y, z = z}
69 end
72 local function get_v(v)
73 return math.sqrt(v.x * v.x + v.z * v.z)
74 end
77 local function force_detach(player)
79 local attached_to = player:get_attach()
81 if not attached_to then
82 return
83 end
85 local entity = attached_to:get_luaentity()
87 if entity.driver
88 and entity.driver == player then
90 entity.driver = nil
91 end
93 player:set_detach()
94 mcl_player.player_attached[player:get_player_name()] = false
95 player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
96 mcl_player.player_set_animation(player, "stand" , 30)
97 player:set_properties({visual_size = {x = 1, y = 1} })
99 end
101 -------------------------------------------------------------------------------
104 minetest.register_on_leaveplayer(function(player)
105 force_detach(player)
106 end)
108 minetest.register_on_shutdown(function()
109 local players = minetest.get_connected_players()
110 for i = 1, #players do
111 force_detach(players[i])
113 end)
115 minetest.register_on_dieplayer(function(player)
116 force_detach(player)
117 return true
118 end)
120 -------------------------------------------------------------------------------
122 function mobs.attach(entity, player)
124 local attach_at, eye_offset = {}, {}
126 entity.player_rotation = entity.player_rotation or {x = 0, y = 0, z = 0}
127 entity.driver_attach_at = entity.driver_attach_at or {x = 0, y = 0, z = 0}
128 entity.driver_eye_offset = entity.driver_eye_offset or {x = 0, y = 0, z = 0}
129 entity.driver_scale = entity.driver_scale or {x = 1, y = 1}
131 local rot_view = 0
133 if entity.player_rotation.y == 90 then
134 rot_view = math.pi/2
137 attach_at = entity.driver_attach_at
138 eye_offset = entity.driver_eye_offset
139 entity.driver = player
141 force_detach(player)
143 player:set_attach(entity.object, "", attach_at, entity.player_rotation)
144 mcl_player.player_attached[player:get_player_name()] = true
145 player:set_eye_offset(eye_offset, {x = 0, y = 0, z = 0})
147 player:set_properties({
148 visual_size = {
149 x = entity.driver_scale.x,
150 y = entity.driver_scale.y
154 minetest.after(0.2, function(name)
155 local player = minetest.get_player_by_name(name)
156 if player then
157 mcl_player.player_set_animation(player, "sit" , 30)
159 end, player:get_player_name())
161 player:set_look_horizontal(entity.object:get_yaw() - rot_view)
165 function mobs.detach(player, offset)
167 force_detach(player)
169 mcl_player.player_set_animation(player, "stand" , 30)
171 local pos = player:get_pos()
173 pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z}
175 minetest.after(0.1, function(name, pos)
176 local player = minetest.get_player_by_name(name)
177 if player then
178 player:set_pos(pos)
180 end, player:get_player_name(), pos)
184 function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
186 local rot_steer, rot_view = math.pi/2, 0
188 if entity.player_rotation.y == 90 then
189 rot_steer, rot_view = 0, math.pi/2
192 local acce_y = 0
193 local velo = entity.object:getvelocity()
195 entity.v = get_v(velo) * get_sign(entity.v)
197 -- process controls
198 if entity.driver then
200 local ctrl = entity.driver:get_player_control()
202 -- move forwards
203 if ctrl.up then
205 entity.v = entity.v + entity.accel / 10
207 -- move backwards
208 elseif ctrl.down then
210 if entity.max_speed_reverse == 0 and entity.v == 0 then
211 return
214 entity.v = entity.v - entity.accel / 10
217 -- fix mob rotation
218 entity.object:setyaw(entity.driver:get_look_horizontal() - entity.rotate)
220 if can_fly then
222 -- fly up
223 if ctrl.jump then
224 velo.y = velo.y + 1
225 if velo.y > entity.accel then velo.y = entity.accel end
227 elseif velo.y > 0 then
228 velo.y = velo.y - 0.1
229 if velo.y < 0 then velo.y = 0 end
232 -- fly down
233 if ctrl.sneak then
234 velo.y = velo.y - 1
235 if velo.y < -entity.accel then velo.y = -entity.accel end
237 elseif velo.y < 0 then
238 velo.y = velo.y + 0.1
239 if velo.y > 0 then velo.y = 0 end
242 else
244 -- jump
245 if ctrl.jump then
247 if velo.y == 0 then
248 velo.y = velo.y + entity.jump_height
249 acce_y = acce_y + (acce_y * 3) + 1
256 -- if not moving then set animation and return
257 if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
259 if stand_anim then
260 mobs:set_animation(entity, stand_anim)
263 return
266 -- set moving animation
267 if moving_anim then
268 mobs:set_animation(entity, moving_anim)
271 -- Stop!
272 local s = get_sign(entity.v)
274 entity.v = entity.v - 0.02 * s
276 if s ~= get_sign(entity.v) then
278 entity.object:setvelocity({x = 0, y = 0, z = 0})
279 entity.v = 0
280 return
283 -- enforce speed limit forward and reverse
284 local max_spd = entity.max_speed_reverse
286 if get_sign(entity.v) >= 0 then
287 max_spd = entity.max_speed_forward
290 if math.abs(entity.v) > max_spd then
291 entity.v = entity.v - get_sign(entity.v)
294 -- Set position, velocity and acceleration
295 local p = entity.object:get_pos()
296 local new_velo = {x = 0, y = 0, z = 0}
297 local new_acce = {x = 0, y = -9.8, z = 0}
299 p.y = p.y - 0.5
301 local ni = node_is(p)
302 local v = entity.v
304 if ni == "air" then
306 if can_fly == true then
307 new_acce.y = 0
310 elseif ni == "liquid" or ni == "lava" then
312 if ni == "lava" and entity.lava_damage ~= 0 then
314 entity.lava_counter = (entity.lava_counter or 0) + dtime
316 if entity.lava_counter > 1 then
318 minetest.sound_play("default_punch", {
319 object = entity.object,
320 max_hear_distance = 5
323 entity.object:punch(entity.object, 1.0, {
324 full_punch_interval = 1.0,
325 damage_groups = {fleshy = entity.lava_damage}
326 }, nil)
328 entity.lava_counter = 0
332 if entity.terrain_type == 2
333 or entity.terrain_type == 3 then
335 new_acce.y = 0
336 p.y = p.y + 1
338 if node_is(p) == "liquid" then
340 if velo.y >= 5 then
341 velo.y = 5
342 elseif velo.y < 0 then
343 new_acce.y = 20
344 else
345 new_acce.y = 5
347 else
348 if math.abs(velo.y) < 1 then
349 local pos = entity.object:get_pos()
350 pos.y = math.floor(pos.y) + 0.5
351 entity.object:setpos(pos)
352 velo.y = 0
355 else
356 v = v * 0.25
360 new_velo = get_velocity(v, entity.object:get_yaw() - rot_view, velo.y)
361 new_acce.y = new_acce.y + acce_y
363 entity.object:setvelocity(new_velo)
364 entity.object:setacceleration(new_acce)
366 -- CRASH!
367 if enable_crash then
369 local intensity = entity.v2 - v
371 if intensity >= crash_threshold then
373 entity.object:punch(entity.object, 1.0, {
374 full_punch_interval = 1.0,
375 damage_groups = {fleshy = intensity}
376 }, nil)
381 entity.v2 = v
385 -- directional flying routine by D00Med (edited by TenPlus1)
387 function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
389 local ctrl = entity.driver:get_player_control()
390 local velo = entity.object:getvelocity()
391 local dir = entity.driver:get_look_dir()
392 local yaw = entity.driver:get_look_horizontal() + 1.57 -- offset fix between old and new commands
393 local rot_steer, rot_view = math.pi / 2, 0
395 if entity.player_rotation.y == 90 then
396 rot_steer, rot_view = 0, math.pi / 2
399 if ctrl.up then
400 entity.object:setvelocity({
401 x = dir.x * speed,
402 y = dir.y * speed + 2,
403 z = dir.z * speed
406 elseif ctrl.down then
407 entity.object:setvelocity({
408 x = -dir.x * speed,
409 y = dir.y * speed + 2,
410 z = -dir.z * speed
413 elseif not ctrl.down or ctrl.up or ctrl.jump then
414 entity.object:setvelocity({x = 0, y = -2, z = 0})
417 entity.object:setyaw(yaw + math.pi + math.pi / 2 - entity.rotate)
419 -- firing arrows
420 if ctrl.LMB and ctrl.sneak and shoots then
422 local pos = entity.object:get_pos()
423 local obj = minetest.add_entity({
424 x = pos.x + 0 + dir.x * 2.5,
425 y = pos.y + 1.5 + dir.y,
426 z = pos.z + 0 + dir.z * 2.5}, arrow)
428 local ent = obj:get_luaentity()
429 if ent then
430 ent.switch = 1 -- for mob specific arrows
431 ent.owner_id = tostring(entity.object) -- so arrows dont hurt entity you are riding
432 local vec = {x = dir.x * 6, y = dir.y * 6, z = dir.z * 6}
433 local yaw = entity.driver:get_look_horizontal()
434 obj:setyaw(yaw + math.pi / 2)
435 obj:setvelocity(vec)
436 else
437 obj:remove()
441 -- change animation if stopped
442 if velo.x == 0 and velo.y == 0 and velo.z == 0 then
444 mobs:set_animation(entity, stand_anim)
445 else
446 -- moving animation
447 mobs:set_animation(entity, moving_anim)