minetest-mm/mods/mobs_redo/mount.lua

490 lines
10 KiB
Lua
Raw Normal View History

2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
-- lib_mount by Blert2112 (edited by TenPlus1)
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
local is_mc2 = minetest.get_modpath("mcl_mobs") -- MineClone2 check
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
-- one of these is needed to ride mobs, otherwise no riding for you
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
if not minetest.get_modpath("player_api") and not is_mc2 then
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
function mobs.attach() end
function mobs.detach() end
function mobs.fly() end
function mobs.drive() end
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
return
2020-10-26 17:38:53 +01:00
end
2024-12-19 12:55:40 +01:00
-- Localise some functions
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
local abs, cos, floor, sin, sqrt, pi =
math.abs, math.cos, math.floor, math.sin, math.sqrt, math.pi
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
-- helper functions
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
local function node_is(entity)
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
if not entity.standing_on then return "other" end
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
if entity.standing_on == "air" then return "air" end
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
local def = minetest.registered_nodes[entity.standing_on]
if def.groups.lava then return "lava" end
if def.groups.liquid then return "liquid" end
if def.groups.walkable then return "walkable" end
2020-10-26 17:38:53 +01:00
return "other"
end
local function get_sign(i)
2024-12-19 12:55:40 +01:00
if not i or i == 0 then return 0 end
return i / abs(i)
2020-10-26 17:38:53 +01:00
end
local function get_velocity(v, yaw, y)
2024-12-19 12:55:40 +01:00
2021-01-23 12:24:04 +01:00
local x = -sin(yaw) * v
local z = cos(yaw) * v
2020-10-26 17:38:53 +01:00
return {x = x, y = y, z = z}
end
local function get_v(v)
2021-01-23 12:24:04 +01:00
return sqrt(v.x * v.x + v.z * v.z)
2020-10-26 17:38:53 +01:00
end
local function force_detach(player)
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
local attached_to = player and player:get_attach()
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
if not attached_to then return end
2020-10-26 17:38:53 +01:00
local entity = attached_to:get_luaentity()
2024-12-19 12:55:40 +01:00
if entity and entity.driver and entity.driver == player then
2020-10-26 17:38:53 +01:00
entity.driver = nil
end
player:set_detach()
2024-12-19 12:55:40 +01:00
local name = player:get_player_name()
if is_mc2 then
mcl_player.player_attached[player:get_player_name()] = false
mcl_player.player_set_animation(player, "stand", 30)
else
player_api.player_attached[name] = false
player_api.set_animation(player, "stand", 30)
end
2020-10-26 17:38:53 +01:00
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
2021-01-23 12:24:04 +01:00
player:set_properties({visual_size = {x = 1, y = 1}})
2020-10-26 17:38:53 +01:00
end
2024-12-19 12:55:40 +01:00
-- detach player on leaving
2020-10-26 17:38:53 +01:00
minetest.register_on_leaveplayer(function(player)
force_detach(player)
end)
2024-12-19 12:55:40 +01:00
-- detatch all players on shutdown
2020-10-26 17:38:53 +01:00
minetest.register_on_shutdown(function()
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
local players = minetest.get_connected_players()
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
for i = 1, #players do
force_detach(players[i])
end
end)
2024-12-19 12:55:40 +01:00
-- detatch player when dead
2020-10-26 17:38:53 +01:00
minetest.register_on_dieplayer(function(player)
force_detach(player)
return true
end)
2024-12-19 12:55:40 +01:00
-- find free position to detach player
2020-10-26 17:38:53 +01:00
2021-01-23 12:24:04 +01:00
local function find_free_pos(pos)
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
local check = {
2024-12-19 12:55:40 +01:00
{x = 1, y = 0, z = 0}, {x = 1, y = 1, z = 0}, {x = -1, y = 0, z = 0},
{x = -1, y = 1, z = 0}, {x = 0, y = 0, z = 1}, {x = 0, y = 1, z = 1},
{x = 0, y = 0, z = -1}, {x = 0, y = 1, z = -1}
2021-01-23 12:24:04 +01:00
}
for _, c in pairs(check) do
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
local npos = {x = pos.x + c.x, y = pos.y + c.y, z = pos.z + c.z}
local node = minetest.get_node_or_nil(npos)
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
if node and node.name then
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
local def = minetest.registered_nodes[node.name]
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
if def and not def.walkable and def.liquidtype == "none" then
2021-01-23 12:24:04 +01:00
return npos
end
end
end
2020-10-26 17:38:53 +01:00
2021-01-23 12:24:04 +01:00
return pos
end
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
-- are we a real player ?
local function is_player(player)
if player and type(player) == "userdata" and minetest.is_player(player) then
return true
end
end
-- attach player to mob entity
2021-01-23 12:24:04 +01:00
function mobs.attach(entity, player)
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
if not player then return end
2020-10-26 17:38:53 +01:00
entity.player_rotation = entity.player_rotation or {x = 0, y = 0, z = 0}
entity.driver_attach_at = entity.driver_attach_at or {x = 0, y = 0, z = 0}
entity.driver_eye_offset = entity.driver_eye_offset or {x = 0, y = 0, z = 0}
entity.driver_scale = entity.driver_scale or {x = 1, y = 1}
local rot_view = 0
2024-12-19 12:55:40 +01:00
if entity.player_rotation.y == 90 then rot_view = pi / 2 end
2020-10-26 17:38:53 +01:00
2021-01-23 12:24:04 +01:00
local attach_at = entity.driver_attach_at
local eye_offset = entity.driver_eye_offset
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
entity.driver = player
force_detach(player)
2024-12-19 12:55:40 +01:00
if is_mc2 then
mcl_player.player_attached[player:get_player_name()] = true
else
player_api.player_attached[player:get_player_name()] = true
end
2020-10-26 17:38:53 +01:00
player:set_attach(entity.object, "", attach_at, entity.player_rotation)
player:set_eye_offset(eye_offset, {x = 0, y = 0, z = 0})
player:set_properties({
2024-12-19 12:55:40 +01:00
visual_size = {x = entity.driver_scale.x, y = entity.driver_scale.y}
2020-10-26 17:38:53 +01:00
})
2021-01-23 12:24:04 +01:00
minetest.after(0.2, function()
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
if is_player(player) then
if is_mc2 then
mcl_player.player_set_animation(player, "sit_mount" , 30)
else
player_api.set_animation(player, "sit", 30)
end
2020-10-26 17:38:53 +01:00
end
2021-01-23 12:24:04 +01:00
end)
2020-10-26 17:38:53 +01:00
player:set_look_horizontal(entity.object:get_yaw() - rot_view)
end
2024-12-19 12:55:40 +01:00
-- detatch player from mob
2020-10-26 17:38:53 +01:00
2021-01-23 12:24:04 +01:00
function mobs.detach(player)
2024-12-19 12:55:40 +01:00
2020-10-26 17:38:53 +01:00
force_detach(player)
2021-01-23 12:24:04 +01:00
minetest.after(0.1, function()
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
if player and player:is_player() then
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
local pos = find_free_pos(player:get_pos())
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
pos.y = pos.y + 0.5
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
player:set_pos(pos)
end
2021-01-23 12:24:04 +01:00
end)
2020-10-26 17:38:53 +01:00
end
2024-12-19 12:55:40 +01:00
-- vars
local damage_counter = 0
-- ride mob like car or horse
2020-10-26 17:38:53 +01:00
function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
2021-06-12 20:20:04 +02:00
local yaw = entity.object:get_yaw() or 0
2021-01-23 12:24:04 +01:00
local rot_view = 0
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
if entity.player_rotation.y == 90 then rot_view = pi / 2 end
2020-10-26 17:38:53 +01:00
local acce_y = 0
2022-01-04 16:19:55 +01:00
local velo = entity.object:get_velocity() ; if not velo then return end
2020-10-26 17:38:53 +01:00
entity.v = get_v(velo) * get_sign(entity.v)
-- process controls
if entity.driver then
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
local ctrl = entity.driver:get_player_control()
2024-12-19 12:55:40 +01:00
if ctrl.up then -- move forwards
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
entity.v = entity.v + entity.accel * dtime
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
elseif ctrl.down then -- move backwards
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
if entity.max_speed_reverse == 0 and entity.v == 0 then return end
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
entity.v = entity.v - entity.accel * dtime
2020-10-26 17:38:53 +01:00
end
2021-01-23 12:24:04 +01:00
-- mob rotation
local horz
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
if entity.alt_turn == true then
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
horz = yaw
2024-12-19 12:55:40 +01:00
if ctrl.left then horz = horz + 0.05
elseif ctrl.right then horz = horz - 0.05 end
2021-01-23 12:24:04 +01:00
else
horz = entity.driver:get_look_horizontal() or 0
end
2020-10-26 17:38:53 +01:00
entity.object:set_yaw(horz - entity.rotate)
if can_fly then
2024-12-19 12:55:40 +01:00
if ctrl.jump then -- fly up
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
velo.y = velo.y + 1
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
if velo.y > entity.accel then velo.y = entity.accel end
elseif velo.y > 0 then
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
velo.y = velo.y - dtime
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
if velo.y < 0 then velo.y = 0 end
end
2024-12-19 12:55:40 +01:00
if ctrl.sneak then -- fly down
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
velo.y = velo.y - 1
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
if velo.y < -entity.accel then velo.y = -entity.accel end
elseif velo.y < 0 then
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
velo.y = velo.y + dtime
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
if velo.y > 0 then velo.y = 0 end
end
else
2024-12-19 12:55:40 +01:00
if ctrl.jump then -- jump (only when standing on solid surface)
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
if velo.y == 0
and entity.standing_on ~= "air" and entity.standing_on ~= "ignore"
and minetest.get_item_group(entity.standing_on, "liquid") == 0 then
2020-10-26 17:38:53 +01:00
velo.y = velo.y + entity.jump_height
acce_y = acce_y + (acce_y * 3) + 1
end
end
end
end
2024-12-19 12:55:40 +01:00
local ni = node_is(entity)
-- env damage
if ni == "liquid" or ni == "lava" then
damage_counter = damage_counter + dtime
if damage_counter > 1 then
local damage = 0
if entity.lava_damage > 0 and ni == "lava" then
damage = entity.lava_damage
elseif entity.water_damage > 0 and ni == "liquid" then
damage = entity.water_damage
end
if damage >= 1 then
entity.object:punch(entity.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = damage}
}, nil)
end
damage_counter = 0
end
end
2020-10-26 17:38:53 +01:00
-- if not moving then set animation and return
if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
if stand_anim then entity:set_animation(stand_anim) end
2020-10-26 17:38:53 +01:00
return
end
-- set moving animation
2024-12-19 12:55:40 +01:00
if moving_anim then entity:set_animation(moving_anim) end
2020-10-26 17:38:53 +01:00
-- Stop!
local s = get_sign(entity.v)
entity.v = entity.v - 0.02 * s
if s ~= get_sign(entity.v) then
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
entity.object:set_velocity({x = 0, y = 0, z = 0})
entity.v = 0
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
return
end
-- enforce speed limit forward and reverse
2024-12-19 12:55:40 +01:00
if entity.v > entity.max_speed_forward then
entity.v = entity.max_speed_forward
elseif entity.v < -entity.max_speed_reverse then
entity.v = -entity.max_speed_reverse
2020-10-26 17:38:53 +01:00
end
-- Set position, velocity and acceleration
local p = entity.object:get_pos()
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
if not p then return end
2024-12-19 12:55:40 +01:00
local new_acce = {x = 0, y = entity.fall_speed, z = 0}
2020-10-26 17:38:53 +01:00
p.y = p.y - 0.5
local v = entity.v
if ni == "air" then
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
if can_fly then new_acce.y = 0 ; acce_y = 0 end
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
elseif ni == "liquid" or ni == "lava" then
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
local terrain_type = entity.terrain_type
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
if terrain_type == 2 or terrain_type == 3 then
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
new_acce.y = 0
p.y = p.y + 1
2024-12-19 12:55:40 +01:00
if minetest.get_item_group(entity.standing_in, "liquid") ~= 0 then
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
if velo.y >= 5 then
velo.y = 5
elseif velo.y < 0 then
new_acce.y = 20
else
new_acce.y = 5
end
else
2021-01-23 12:24:04 +01:00
if abs(velo.y) < 1 then
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
local pos = entity.object:get_pos()
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
if not pos then return end
pos.y = floor(pos.y) + 0.5
2020-10-26 17:38:53 +01:00
entity.object:set_pos(pos)
velo.y = 0
end
end
else
v = v * 0.25
end
end
2021-01-23 12:24:04 +01:00
local new_velo = get_velocity(v, yaw - rot_view, velo.y)
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
new_acce.y = new_acce.y + acce_y
entity.object:set_velocity(new_velo)
entity.object:set_acceleration(new_acce)
entity.v2 = v
end
2024-12-19 12:55:40 +01:00
-- fly mob in facing direction (by D00Med, edited by TenPlus1)
2020-10-26 17:38:53 +01:00
2021-01-23 12:24:04 +01:00
function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim)
2021-06-12 20:20:04 +02:00
2022-01-04 16:19:55 +01:00
local ctrl = entity.driver:get_player_control() ; if not ctrl then return end
2024-12-19 12:55:40 +01:00
local velo = entity.object:get_velocity() ; if not velo then return end
2020-10-26 17:38:53 +01:00
local dir = entity.driver:get_look_dir()
2024-12-19 12:55:40 +01:00
local yaw = entity.driver:get_look_horizontal() ; if not yaw then return end
2020-10-26 17:38:53 +01:00
2024-12-19 12:55:40 +01:00
yaw = yaw + 1.57 -- fix from get_yaw to get_look_horizontal
2021-05-22 19:45:55 +02:00
2020-10-26 17:38:53 +01:00
if ctrl.up then
2024-12-19 12:55:40 +01:00
entity.object:set_velocity(
{x = dir.x * speed, y = dir.y * speed + 2, z = dir.z * speed})
2020-10-26 17:38:53 +01:00
elseif ctrl.down then
2021-06-12 20:20:04 +02:00
2024-12-19 12:55:40 +01:00
entity.object:set_velocity(
{x = -dir.x * speed, y = dir.y * speed + 2, z = -dir.z * speed})
2020-10-26 17:38:53 +01:00
elseif not ctrl.down or ctrl.up or ctrl.jump then
entity.object:set_velocity({x = 0, y = -2, z = 0})
end
2021-01-23 12:24:04 +01:00
entity.object:set_yaw(yaw + pi + pi / 2 - entity.rotate)
2020-10-26 17:38:53 +01:00
-- firing arrows
if ctrl.LMB and ctrl.sneak and shoots then
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
local pos = entity.object:get_pos()
local obj = minetest.add_entity({
x = pos.x + 0 + dir.x * 2.5,
y = pos.y + 1.5 + dir.y,
z = pos.z + 0 + dir.z * 2.5}, arrow)
local ent = obj:get_luaentity()
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
if ent then
2021-06-12 20:20:04 +02:00
2020-10-26 17:38:53 +01:00
ent.switch = 1 -- for mob specific arrows
2024-12-19 12:55:40 +01:00
ent.owner_id = tostring(entity.object) -- so arrows dont hurt mob
2020-10-26 17:38:53 +01:00
local vec = {x = dir.x * 6, y = dir.y * 6, z = dir.z * 6}
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
yaw = entity.driver:get_look_horizontal()
2021-06-12 20:20:04 +02:00
2021-01-23 12:24:04 +01:00
obj:set_yaw(yaw + pi / 2)
2020-10-26 17:38:53 +01:00
obj:set_velocity(vec)
else
obj:remove()
end
end
if velo.x == 0 and velo.y == 0 and velo.z == 0 then
2024-12-19 12:55:40 +01:00
entity:set_animation(stand_anim) -- stopped animation
2020-10-26 17:38:53 +01:00
else
2024-12-19 12:55:40 +01:00
entity:set_animation(moving_anim) -- moving animation
2020-10-26 17:38:53 +01:00
end
end