motorbike/functions.lua

453 lines
13 KiB
Lua

local charset = {} do -- [A-Z]
for c = 65, 90 do table.insert(charset, string.char(c)) end
end
local numset = {} do -- [0-9]
for c = 48, 57 do table.insert(numset, string.char(c)) end
end
local function randomString(length)
local text = ""
local i = 0
if not length or length <= 0 then return text end
while i < length do
text = text..charset[math.random(1, #charset)]
i = i + 1
end
return text
end
local function randomNumber(length)
local text = ""
local i = 0
if not length or length <= 0 then return text end
while i < length do
text = text..numset[math.random(1, #numset)]
i = i + 1
end
return text
end
local function def_plate() return randomString(3).."-"..randomNumber(3) end
function biker.get_plate(name)
local custom_plates = {
Jely = {"Jely-"..randomNumber(2), def_plate()},
Elkien = {"Elk-"..randomNumber(3), def_plate(), "Sparks-"..randomNumber(3)},
Bob12 = {"Bob-"..randomNumber(3), "Boi-"..randomNumber(3), "MB-"..randomNumber(4), "N1nja-"..randomNumber(3), def_plate()},
Extex = {"Ex-"..randomNumber(4), "Bullet-"..randomNumber(2), def_plate(), "3xt3x-"..randomNumber(2)},
Merlok = {"Mer-"..randomNumber(3), "Nipe-"..randomNumber(2), "M3RL0k-"..randomNumber(2), "N1P3-"..randomNumber(2), def_plate(), "Snoopy-"..randomNumber(3)},
Nipe = {"Nipe-"..randomNumber(2), "Snoopy-"..randomNumber(3), def_plate()},
--"The-Black-Knight" = {"TBK-"..randomNumber(3), "Vike-"randomNumber(2), "Rock-"..randomNumber(2), def_plate()},
Queen_Vibe = {"QV-"..randomNumber(3), "Vibe-"..randomNumber(2), def_plate()},
Melkor = {"Creator", "ModelKing", "Melkor", def_plate()},
Hype = {"Hobo-"..randomNumber(2), "Hyper-"..randomNumber(1), def_plate()},
AidanLCB = {"LCB-"..randomNumber(3), def_plate(), "Gold-"..randomNumber(3)},
irondude = {"Iron-"..randomNumber(3), def_plate(), "Fox-"..randomNumber(3), "cndl-"..randomNumber(3)},
}
if custom_plates[name] then
return custom_plates[name][math.random(#custom_plates[name])]
end
return def_plate()
end
player_api.register_model("motorbike_biker.b3d", {
animation_speed = 30,
textures = {"character.png", "blank.png"},
animations = {
-- Standard animations.
stand = {x = 0, y = 79},
lay = {x = 162, y = 166},
walk = {x = 168, y = 187},
mine = {x = 189, y = 198},
walk_mine = {x = 200, y = 219},
sit = {x = 81, y = 160},
},
collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
stepheight = 0.6,
eye_height = 1.47,
})
local function repair(num, p)
p = p or 3
return math.floor(num*math.pow(10,p)+0.5) / math.pow(10,p)
end
local function node_is(pos)
local node = minetest.get_node(pos)
if node.name == "air" then
return "air"
end
if minetest.get_item_group(node.name, "liquid") ~= 0 then
return "liquid"
end
if minetest.get_item_group(node.name, "walkable") ~= 0 then
return "walkable"
end
if minetest.get_item_group(node.name, "crumbly") ~= 0 then
return "crumbly"
end
return "other"
end
local function shortAngleDist(a0,a1)
local max = math.pi*2
local da = (a1 - a0) % max
return 2*da % max - da
end
local function lerp(a, b, t)
return a + (a - b) * t
end
local function angleLerp(a0,a1,t)
local result = repair(a0 + shortAngleDist(a0,a1)*t)
if math.floor(result) == a1 then
return a1
end
return result
end
local function get_sign(i)
i = i or 0
if i == 0 then
return 0
else
return i / math.abs(i)
end
end
local function get_velocity(v, yaw, y)
local x = -math.sin(yaw) * v
local z = math.cos(yaw) * v
return {x = x, y = y, z = z}
end
local function get_v(v)
return math.sqrt(v.x ^ 2 + v.z ^ 2)
end
function biker.turn_check(lerp, dest, range)
if math.floor(lerp) <= (dest-(math.rad(90)))-range then return true end
if math.floor(lerp) >= (dest-(math.rad(90)))+range then return true end
return false
end
function biker.clamp(value, min, max)
return math.min(math.max(value, min), max)
end
function biker.dist(v1, v2)
--if v1 - v2 > -math.rad(45) and v1 - v2 < math.rad(45) then return v1 - v2 end
return biker.clamp(-shortAngleDist(v1, v2), math.rad(-55), math.rad(55))
end
local function force_detach(player)
local attached_to = player:get_attach()
if not player:is_player() then return end
if attached_to then
local entity = attached_to:get_luaentity()
if entity.driver and entity.driver == player then
entity.driver = nil
end
local name = player:get_player_name()
player:set_detach()
player:set_eye_offset({x=0, y=0, z=0}, {x=0, y=0, z=0})
if entity.info then
player_api.set_model(player, entity.info.model)
end
end
end
function biker.detach(player, crash)
force_detach(player)
player_api.player_attached[player:get_player_name()] = false
player_api.set_animation(player, "stand" , 30)
if crash then
end
end
function biker.wheelspeed(bike)
--if true then return end
if not bike then return end
if not bike.object then return end
if not bike.object:getvelocity() then return end
local direction = 1
if bike.v then
direction = get_sign(bike.v)
end
local v = get_v(bike.object:get_velocity())
local fps = v*4
bike.object:set_animation({x=1, y=20}, fps*direction, 0, true)
if v ~= 0 then
local i = 16
while true do
if i/fps > 1 then i = i/2 else break end
end
minetest.after(i/fps, biker.wheelspeed, bike)
end
end
function biker.attach(entity, player, is_passenger)
local attach_at, eye_offset = {}, {}
if not entity then
return
end
if entity.driver then return end
if not player:is_player() then
return
end
local name = player:get_player_name()
if not entity.driver_attach_at then
entity.driver_attach_at = {x=0, y=1.1, z=0.9}
end
if not entity.driver_eye_offset then
entity.driver_eye_offset = {x=0, y=-2.2, z=0.3}
end
attach_at = entity.driver_attach_at
eye_offset = entity.driver_eye_offset
entity.driver = player
local props = player:get_properties()
entity.info = {}
entity.info.model = player_api.get_animation(player).model
if props.textures[2] == nil then
props.textures[2] = "blank.png"
end
force_detach(player)
player:set_attach(entity.object, "", attach_at, entity.player_rotation)
player_api.player_attached[player:get_player_name()] = true
player:set_eye_offset(eye_offset, {x=0, y=0, z=0})
minetest.after(0.2, function()
player_api.set_model(player, "motorbike_biker.b3d")
end)
player:set_look_yaw(entity.object:getyaw())
end
local timer = 0
function biker.drive(entity, dtime)
timer = timer + dtime
local rot_steer, rot_view = math.pi/2, 0
local acce_y = 2
local velo = entity.object:getvelocity()
entity.v = get_v(velo) * get_sign(entity.v)
-- process controls
if entity.driver then
if entity.v then
local newv = entity.object:getvelocity()
if not entity.crash then entity.crash = false end
local crash = false
if math.abs(entity.lastv.x) > 5 and newv.x == 0 then crash = true end
if math.abs(entity.lastv.y) > 10 and newv.y == 0 then crash = true end
if math.abs(entity.lastv.z) > 5 and newv.z == 0 then crash = true end
if crash and not entity.crash then
entity.crash = true
minetest.after(.5, function()
entity.crash = false
end)
return
end
end
if not entity.wheelie then
entity.wheelie = 0
end
if not entity.lastv then
entity.lastv = {x=0,y=0,z=0}
end
local rots = entity.object:get_rotation()
local j = rots.y
local k = rots.x
local newrot = j
local rrot = entity.driver:get_look_yaw() - rot_steer
local ctrl = entity.driver:get_player_control()
if ctrl.up and not ctrl.sneak then
if get_sign(entity.v) >= 0 then
entity.v = entity.v + biker.acceleration/10
else
entity.v = entity.v + biker.acceleration/10
end
elseif ctrl.down then
if biker.max_reverse == 0 and entity.v == 0 then return end
if get_sign(entity.v) < 0 then
entity.v = entity.v - biker.acceleration/10
else
entity.v = entity.v - biker.braking/10
end
end
if ctrl.down and ctrl.sneak and not ctrl.jump and biker.turn_check(angleLerp(newrot, rrot, biker.turn_power)%math.rad(360), rrot, 3.2) then
if get_sign(entity.v) < 0 then
entity.v = entity.v - biker.acceleration/10
elseif get_sign(entity.v) > 0 and entity.v > (biker.max_speed/10)-1 then
entity.v = entity.v - biker.braking/10
local num = 1
local pos = entity.object:getpos()
local d = 0.2
for i = 0, 20, 1 do
local time = math.random(1, 2)
minetest.add_particle({
pos = {x=pos.x+math.random(-d, d),y = pos.y+math.random(0, d), z= pos.z+math.random(-d, d)},
velocity = {x=math.random(-num, num), y=math.random(0, num), z=math.random(-num, num)},
acceleration = {x=math.random(-num, num), y=math.random(0, num), z=math.random(-num, num)},
expirationtime = time,
glow = 20,
size = math.random(10, 20),
collisiondetection = false,
vertical = false,
texture = "motorbike_burnout.png",
animation = {
type = "vertical_frames",
aspect_w = 64,
aspect_h = 64,
length = time,
},
})
end
end
end
local l = rots.z
if ctrl.jump and entity.v > (biker.max_speed)/3 then
entity.driver:set_eye_offset({x=0, y=-6.0, z=0}, {x=0, y=0, z=0})
entity.wheelie = repair(angleLerp(k, 45, 0.1))
l = angleLerp(l, 0, 0.07)
entity.object:set_rotation({x=repair(entity.wheelie),y=repair(j),z=repair(l,3)})
elseif not ctrl.jump or entity.v < (biker.max_speed)/3 then
entity.driver:set_eye_offset({x=0, y=-7, z=0}, {x=0, y=0, z=0})
if entity.v > 1.2 and entity.wheelie == 0 then
newrot = angleLerp(newrot, rrot, biker.turn_power)%math.rad(360)
l = biker.dist(newrot+math.rad(360), rrot+math.rad(360))
elseif entity.v < 1.2 then
l = angleLerp(rots.z, 0, 0.2)
end
entity.wheelie = repair(angleLerp(k, 0 ,0.1))
entity.object:set_rotation({x=entity.wheelie, y=newrot, z=repair(l,3)})
end
if not ctrl.sneak then
local s = get_sign(entity.v)
entity.v = entity.v - 0.04 * s
if s ~= get_sign(entity.v) then
entity.object:setvelocity({x=0, y=0, z=0})
entity.v = 0
return
end
end
elseif not entity.driver then
entity.object:set_rotation({x=entity.object:get_rotation().x, y=entity.object:get_rotation().y, z=0})
end
-- Stop!
if not entity.driver then
local s = get_sign(entity.v)
entity.v = entity.v - 0.04 * s
if s ~= get_sign(entity.v) then
entity.object:setvelocity({x=0, y=0, z=0})
entity.v = 0
return
end
end
-- enforce speed limit forward and reverse
local p = entity.object:getpos()
local ni = node_is(p)
local uni = node_is(vector.add(p, {x=0, y=-1, z=0}))
--minetest.chat_send_all(node_is)
local max_spd = biker.max_reverse
if get_sign(entity.v) >= 0 and ni ~= "liquid" then
if uni == "crumbly" and uni ~= "other" then
max_spd = biker.crumbly_spd
else
max_spd = biker.max_speed
end
elseif ni == "liquid" then
max_spd = 2
end
if uni == "crumbly" and uni ~= "other" then
max_spd = biker.crumbly_spd
end
if math.abs(entity.v) > max_spd then
entity.v = entity.v - get_sign(entity.v)
end
--Set position, velocity and acceleration
local new_velo = {x=0, y=0, z=0}
local new_acce = {x=0, y=-9.8, z=0}
p.y = p.y - 0.5
new_velo = get_velocity(entity.v, entity.object:getyaw() - rot_view, velo.y)
new_acce.y = new_acce.y + acce_y
entity.object:setvelocity(new_velo)
entity.object:setacceleration(new_acce)
if entity.lastv and vector.length(entity.lastv) > 0 and math.abs(entity.v) == 0 then
biker.wheelspeed(entity)
if entity.wheelsound then
minetest.sound_fade(entity.wheelsound, 30, 0)
end
if entity.windsound then
minetest.sound_fade(entity.windsound, 30, 0)
end
end
if entity.lastv and vector.length(entity.lastv) == 0 and math.abs(entity.v) > 0 then
biker.wheelspeed(entity)
end
entity.lastv = entity.object:getvelocity()
--sound
if entity.v > 0 and entity.driver ~= nil then
entity.timer1 = entity.timer1 + dtime
if entity.timer1 > .1 then
local rpm = 1
if entity.v > 7 then
rpm = entity.v/7+.4
elseif entity.v > 3 then
rpm = entity.v/3+.3
else
rpm = entity.v/3+.2
end
minetest.sound_play("motoengine", {
max_hear_distance = 48,
pitch = rpm+.1,
object = entity.object
})
entity.timer1 = 0
end
end
entity.timer2 = entity.timer2 + dtime
local abs_v = math.abs(entity.v)
if entity.timer2 > 1.5-abs_v/max_spd*1.1 then
if abs_v > .2 then
if math.abs(velo.y) < .1 then
entity.wheelsound = minetest.sound_play("tyresound", {
max_hear_distance = 48,
object = entity.object,
pitch = 1.1 + (abs_v/max_spd)*.6,
gain = .5 + (abs_v/max_spd)*2
})
elseif entity.windsound then
minetest.sound_fade(entity.windsound, 30, 0)
end
entity.windsound = minetest.sound_play("wind", {
max_hear_distance = 10,
object = entity.object,
pitch = 1 + (abs_v/max_spd)*.6,
gain = 0 + (abs_v/max_spd)*4
})
end
entity.timer2 = 0
end
end
minetest.register_on_leaveplayer(function(player)
biker.detach(player)
end)
minetest.register_on_dieplayer(function(player)
biker.detach(player)
end)