more mods

This commit is contained in:
2026-09-12 07:03:41 -06:00
parent cc0fa41e3b
commit bac6ac94a3
1742 changed files with 115814 additions and 1 deletions
+9
View File
@@ -0,0 +1,9 @@
This mod adds library for automobiles
licence of code
MIT
physics_lib.lua - MIT by TheTermos
licence of the media:
licence CC0
Binary file not shown.
Binary file not shown.
Binary file not shown.
+233
View File
@@ -0,0 +1,233 @@
--global constants
automobiles_lib.vector_up = vector.new(0, 1, 0)
function automobiles_lib.check_road_is_ok(obj, max_acc_factor)
local pos_below = obj:get_pos()
pos_below.y = pos_below.y - 0.1
local node_below = core.get_node(pos_below).name
--core.chat_send_all(node_below)
local nodedef = core.registered_nodes[node_below]
if nodedef.liquidtype == "none" then
local slow_nodes = {
['default:ice '] = 0.01,
['default:cave_ice'] = 0.01,
}
local acc = slow_nodes[node_below]
if acc == nil then acc = max_acc_factor end
return acc
else
return 0
end
end
function automobiles_lib.set_yaw_by_mouse(self, dir, steering_limit)
local rotation = self.object:get_rotation()
local rot_y = math.deg(rotation.y)
local total = math.abs(math.floor(rot_y/360))
if rot_y < 0 then rot_y = rot_y + (360*total) end
if rot_y > 360 then rot_y = rot_y - (360*total) end
if rot_y >= 270 and dir <= 90 then dir = dir + 360 end
if rot_y <= 90 and dir >= 270 then dir = dir - 360 end
local intensity = 2
if self._intensity then intensity = self._intensity end
local command = (rot_y - dir) * intensity
if command < -90 then command = -90
elseif command > 90 then command = 90 end
--core.chat_send_all("rotation y: "..rot_y.." - dir: "..dir.." - command: "..(rot_y - dir))
--core.chat_send_all("rotation y: "..rot_y.." - dir: "..dir.." - command: "..command)
return (-command * steering_limit)/90
end
function automobiles_lib.control(self, dtime, hull_direction, longit_speed, longit_drag, later_drag, accel, max_acc_factor, max_speed, steering_limit, steering_speed)
self._last_time_command = self._last_time_command + dtime
hull_direction = hull_direction or 0
longit_speed = longit_speed or 0
longit_drag = longit_drag or 0
later_drag = later_drag or 0
max_acc_factor = max_acc_factor or 0
max_acc_factor = max_acc_factor
max_speed = max_speed or 0
max_speed = math.min(max_speed,automobiles_lib.speed_limit)
steering_limit = steering_limit or 0
steering_speed = steering_speed or 0
if self._last_time_command > 1 then self._last_time_command = 1 end
local player = core.get_player_by_name(self.driver_name)
local retval_accel = accel;
local stop = false
-- player control
if player then
local ctrl = player:get_player_control()
local rot_x = player:get_look_vertical()
local pi = math.pi
local ang_min = -pi / 32
local ang_max = pi / 64
local gap = pi / 128
if self._one_hand == true then
if rot_x < (ang_min - gap)then
player:set_look_vertical(ang_min - gap)
end
if rot_x > (ang_max + gap) then
player:set_look_vertical(ang_max + gap)
end
end
local acc = 0
if self._energy > 0 then
if self._one_hand == true then
if rot_x <= ang_min then
if longit_speed < max_speed then
--get acceleration factor
acc = automobiles_lib.check_road_is_ok(self.object, max_acc_factor)
--core.chat_send_all('engineacc: '.. engineacc)
if acc > 1 and acc < max_acc_factor and longit_speed > 0 then
--improper road will reduce speed
acc = -1
end
end
end
else
if longit_speed < max_speed and ctrl.up then
--get acceleration factor
acc = automobiles_lib.check_road_is_ok(self.object, max_acc_factor)
--core.chat_send_all('engineacc: '.. engineacc)
if acc > 1 and acc < max_acc_factor and longit_speed > 0 then
--improper road will reduce speed
acc = -1
end
end
end
--reversing
if self._one_hand == true then
if rot_x >= ang_max then
acc = -2
end
else
if ctrl.sneak and longit_speed <= 1.0 and longit_speed > -1.0 then
acc = -2
end
end
end
--break
if self._one_hand == true then
if rot_x >= ang_max and not ctrl.LMB then
if longit_speed > 0 then
acc = -5
end
if longit_speed < 0 then
acc = 5
if (longit_speed + acc) > 0 then
acc = longit_speed * -1
end
end
if math.abs(longit_speed) < 1 then
stop = true
end
end
else
if ctrl.down or ctrl.jump then
--[[if math.abs(longit_speed) > 0 then
acc = -5 / (longit_speed / 2) -- lets set a brake efficience based on speed
end]]--
--total stop
--wheel break
if longit_speed > 0 then
acc = -5
--[[if (longit_speed + acc) < 0 then
acc = longit_speed * -1
end]]--
end
if longit_speed < 0 then
acc = 5
if (longit_speed + acc) > 0 then
acc = longit_speed * -1
end
end
if math.abs(longit_speed) < 1 then
stop = true
end
end
end
if acc then retval_accel=vector.add(accel,vector.multiply(hull_direction,acc)) end
if ctrl.aux1 then
if self._one_hand == true then
local formspec_f = automobiles_lib.driver_formspec
if self._formspec_function then formspec_f = self._formspec_function end
formspec_f(self.driver_name)
end
--[[
--sets the engine running - but sets a delay also, cause keypress
if self._last_time_command > 0.3 then
self._last_time_command = 0
if self._engine_running then
self._engine_running = false
-- sound and animation
if self.sound_handle then
core.sound_stop(self.sound_handle)
self.sound_handle = nil
end
--self.engine:set_animation_frame_speed(0)
elseif self._engine_running == false and self._energy > 0 then
self._engine_running = true
-- sound and animation
self.sound_handle = core.sound_play({name = "engine"},
{object = self.object, gain = 2.0, pitch = 1.0, max_hear_distance = 32, loop = true,})
--self.engine:set_animation_frame_speed(30)
end
end]]--
end
-- yaw
local yaw_cmd = 0
if self._yaw_by_mouse == true or self._one_hand == true then
local rot_y = math.deg(player:get_look_horizontal())
self._steering_angle = automobiles_lib.set_yaw_by_mouse(self, rot_y, steering_limit)
else
-- steering
if ctrl.right then
self._steering_angle = math.max(self._steering_angle-steering_speed*dtime,-steering_limit)
elseif ctrl.left then
self._steering_angle = math.min(self._steering_angle+steering_speed*dtime,steering_limit)
else
--center steering
if longit_speed > 0 then
local factor = 1
if self._steering_angle > 0 then factor = -1 end
local correction = (steering_limit*(longit_speed/75)) * factor
local before_correction = self._steering_angle
self._steering_angle = self._steering_angle + correction
if math.sign(before_correction) ~= math.sign(self._steering_angle) then self._steering_angle = 0 end
end
end
end
local angle_factor = self._steering_angle / 60
if angle_factor < 0 then angle_factor = angle_factor * -1 end
local deacc_on_curve = longit_speed * angle_factor
deacc_on_curve = deacc_on_curve * -1
if deacc_on_curve then retval_accel=vector.add(retval_accel,vector.multiply(hull_direction,deacc_on_curve)) end
end
return retval_accel, stop
end
+95
View File
@@ -0,0 +1,95 @@
function automobiles_lib.physics(self)
local friction = self._ground_friction or 0.99
local vel=self.object:get_velocity()
local new_velocity = vector.new()
--buoyancy
local surface = nil
local surfnodename = nil
local spos = automobiles_lib.get_stand_pos(self)
if not spos then return end
spos.y = spos.y+0.01
-- get surface height
local snodepos = automobiles_lib.get_node_pos(spos)
local surfnode = automobiles_lib.nodeatpos(spos)
while surfnode and (surfnode.drawtype == 'liquid' or surfnode.drawtype == 'flowingliquid') do
surfnodename = surfnode.name
surface = snodepos.y +0.5
if surface > spos.y+self.height then break end
snodepos.y = snodepos.y+1
surfnode = automobiles_lib.nodeatpos(snodepos)
end
self.isinliquid = surfnodename
if surface then -- standing in liquid
self.isinliquid = true
end
local last_accel = vector.new()
if self._last_accel then
last_accel = vector.new(self._last_accel)
end
if self.isinliquid then
self.water_drag = 0.2
self.isinliquid = true
local height = self.height
local submergence = math.min(surface-spos.y,height)/height
-- local balance = self.buoyancy*self.height
local buoyacc = automobiles_lib.gravity*(-1)*(self.buoyancy-submergence)
--local buoyacc = self._baloon_buoyancy*(self.buoyancy-submergence)
local accell = {
x=-vel.x*self.water_drag,
y=buoyacc-(vel.y*math.abs(vel.y)*0.4),
z=-vel.z*self.water_drag
}
if self.buoyancy >= 1 then self._engine_running = false end
if last_accel then
accell = vector.add(accell,last_accel)
end
new_velocity = vector.multiply(accell,self.dtime)
else
self.isinliquid = false
new_velocity = vector.multiply(last_accel,self.dtime)
end
if self.isonground and not self.isinliquid then
--dumb friction
new_velocity = {x=new_velocity.x*friction,
y=new_velocity.y,
z=new_velocity.z*friction}
--core.chat_send_all(dump(friction))
-- bounciness
if self.springiness and self.springiness > 0 and self.buoyancy >= 1 then
local vnew = vector.new(new_velocity)
if not self.collided then -- ugly workaround for inconsistent collisions
for _,k in ipairs({'y','z','x'}) do
if new_velocity[k]==0 and math.abs(self.lastvelocity[k])> 0.1 then
vnew[k]=-self.lastvelocity[k]*self.springiness
end
end
end
if not vector.equals(new_velocity,vnew) then
self.collided = true
else
if self.collided then
vnew = vector.new(self.lastvelocity)
end
self.collided = false
end
new_velocity = vnew
end
--fix bug with unexpected moving
if not self.driver_name and math.abs(vel.x) < 0.2 and math.abs(vel.z) < 0.2 then
self.object:set_velocity({x=0,y=automobiles_lib.gravity*(-1)*self.dtime,z=0})
if self.wheels then self.wheels:set_animation_frame_speed(0) end
return
end
end
self.object:add_velocity(new_velocity)
end
@@ -0,0 +1,865 @@
minetest.register_entity('automobiles_lib:pivot_mesh',{
initial_properties = {
physical = false,
collide_with_objects=false,
pointable=false,
visual = "mesh",
mesh = "automobiles_pivot_mesh.b3d",
textures = {"automobiles_alpha.png",},
},
on_activate = function(self,std)
self.sdata = minetest.deserialize(std) or {}
if self.sdata.remove then self.object:remove() end
self.object:set_armor_groups({immortal=1})
end,
get_staticdata=function(self)
self.sdata.remove=true
return minetest.serialize(self.sdata)
end,
})
minetest.register_entity('automobiles_lib:pointer',{
initial_properties = {
physical = false,
collide_with_objects=false,
pointable=false,
visual = "mesh",
mesh = "automobiles_pointer.b3d",
visual_size = {x = 0.5, y = 0.5, z = 0.5},
textures = {"automobiles_white.png"},
},
on_activate = function(self,std)
self.sdata = minetest.deserialize(std) or {}
if self.sdata.remove then self.object:remove() end
self.object:set_armor_groups({immortal=1})
end,
get_staticdata=function(self)
self.sdata.remove=true
return minetest.serialize(self.sdata)
end,
})
function automobiles_lib.on_rightclick (self, clicker)
if not clicker or not clicker:is_player() then
--return
end
local name = clicker:get_player_name()
--[[if self.owner and self.owner ~= name and self.owner ~= "" then return end]]--
if self.owner == "" then
self.owner = name
end
if name == self.driver_name then
local formspec_f = automobiles_lib.driver_formspec
if self._formspec_function then formspec_f = self._formspec_function end
formspec_f(name)
else
if name == self.owner or
(self.driver_name == nil and
( minetest.check_player_privs(clicker, "valet_parking") or minetest.check_player_privs(clicker, {server=true}) )
) then
if clicker:get_player_control().aux1 == true then
automobiles_lib.show_vehicle_trunk_formspec(self, clicker, self._trunk_slots)
else
--is the owner, okay, lets attach
local attach_driver_f = automobiles_lib.attach_driver
if self._attach then attach_driver_f = self._attach end
attach_driver_f(self, clicker)
-- sound
local base_pitch = 1
if self._base_pitch then base_pitch = self._base_pitch end
self.sound_handle = minetest.sound_play({name = self._engine_sound},
{object = self.object, gain = 1, pitch = base_pitch, max_hear_distance = 30, loop = true,})
end
else
--minetest.chat_send_all("clicou")
--a passenger
if (automobiles_lib.is_minetest and not player_api.player_attached[name]) or
(automobiles_lib.is_mcl and not mcl_player.player_attached[name]) then
--there is no passenger, so lets attach
if self.driver_name then
local attach_pax_f = automobiles_lib.attach_pax
if self._attach_pax then attach_pax_f = self._attach_pax end
attach_pax_f(self, clicker, true)
end
else
--there is a passenger
--if you are the passenger, so deattach
local dettach_pax_f = automobiles_lib.dettach_pax
if self._dettach_pax then dettach_pax_f = self._dettach_pax end
dettach_pax_f(self, clicker)
end
end
end
end
function automobiles_lib.on_punch (self, puncher, ttime, toolcaps, dir, damage)
if not puncher or not puncher:is_player() then
return
end
local name = puncher:get_player_name()
--[[if self.owner and self.owner ~= name and self.owner ~= "" then return end]]--
if self.owner == nil then
self.owner = name
end
if self.driver_name and self.driver_name ~= name then
-- do not allow other players to remove the object while there is a driver
return
end
local is_attached = false
local obj_attach = puncher:get_attach()
if obj_attach == self.driver_seat or obj_attach == self.object then is_attached = true end
local itmstck=puncher:get_wielded_item()
local item_name = ""
if itmstck then item_name = itmstck:get_name() end
--refuel procedure
--[[
refuel works it car is stopped and engine is off
]]--
local velocity = self.object:get_velocity()
local speed = automobiles_lib.get_hipotenuse_value(vector.new(), velocity)
--if math.abs(speed) <= 0.1 then
local was_refueled = automobiles_lib.loadFuel(self, puncher:get_player_name(), false, self._max_fuel)
if was_refueled then
return
end
--end
-- end refuel
if is_attached == false then
-- deal with painting or destroying
if itmstck then
--race status restart
if item_name == "checkpoints:status_restarter" and self._engine_running == false then
--restart race current status
self._last_checkpoint = ""
self._total_laps = -1
self._race_id = ""
return
end
local paint_f = automobiles_lib.set_paint
if self._painting_function then paint_f = self._painting_function end
if paint_f(self, puncher, itmstck) == false then
local is_admin = false
is_admin = minetest.check_player_privs(puncher, {server=true})
--minetest.chat_send_all('owner '.. self.owner ..' - name '.. name)
if not self.driver and (self.owner == name or is_admin == true) and toolcaps and
toolcaps.damage_groups and toolcaps.damage_groups.fleshy then
self.hp = self.hp - 10
minetest.sound_play("automobiles_collision", {
object = self.object,
max_hear_distance = 5,
gain = 1.0,
fade = 0.0,
pitch = 1.0,
})
end
end
end
if self.hp <= 0 then
local destroy_f = automobiles_lib.destroy
if self._destroy_function then destroy_f = self._destroy_function end
destroy_f(self)
end
end
end
function automobiles_lib.get_staticdata(self)
return minetest.serialize({
stored_owner = self.owner,
stored_hp = self.hp,
stored_color = self._color,
stored_det_color = self._det_color,
stored_steering = self._steering_angle,
stored_energy = self._energy,
stored_rag = self._show_rag,
stored_pitch = self._pitch,
stored_light_old_pos = self._light_old_pos,
stored_inv_id = self._inv_id,
stored_car_type = self._car_type,
stored_car_gravity = self._car_gravity,
stored_scale = self._vehicle_scale or 1,
stored_power_scale = self._vehicle_power_scale or 1,
--race data
stored_last_checkpoint = self._last_checkpoint,
stored_total_laps = self._total_laps,
stored_race_id = self._race_id,
})
end
local function scale_entity(self, scale)
scale = scale or 1
local initial_properties = automobiles_lib.properties_copy(self.initial_properties)
local new_properties = automobiles_lib.properties_copy(initial_properties)
--[[if initial_properties.collisionbox then
for i, value in ipairs(initial_properties.collisionbox) do
new_properties.collisionbox[i] = value * scale
--core.log("action", new_properties.collisionbox[i])
end
end
if initial_properties.selectionbox then
for i, value in ipairs(initial_properties.selectionbox) do
new_properties.selectionbox[i] = value * scale
end
end]]--
if initial_properties.stepheight then
new_properties.stepheight = initial_properties.stepheight * scale
end
new_properties.visual_size = {x=scale, y=scale}
self.object:set_properties(new_properties)
end
function automobiles_lib.on_activate(self, staticdata, dtime_s)
if staticdata ~= "" and staticdata ~= nil then
local data = minetest.deserialize(staticdata) or {}
self.owner = data.stored_owner
self.hp = data.stored_hp
self._color = data.stored_color
self._det_color = data.stored_det_color
self._steering_angle = data.stored_steering
self._energy = data.stored_energy
--minetest.debug("loaded: ", self.energy)
--race data
self._last_checkpoint = data.stored_last_checkpoint
self._total_laps = data.stored_total_laps
self._race_id = data.stored_race_id
self._show_rag = data.stored_rag
self._pitch = data.stored_pitch
self._light_old_pos = data.stored_light_old_pos
self._inv_id = data.stored_inv_id
self._car_type = data.stored_car_type
self._car_gravity = data.stored_car_gravity or -automobiles_lib.gravity
self._vehicle_scale = data.stored_scale or 1
self._vehicle_power_scale = data.stored_power_scale or 1
automobiles_lib.setText(self, self._vehicle_name)
if data.remove then
automobiles_lib.destroy_inventory(self)
self.object:remove()
return
end
end
scale_entity(self, self._vehicle_scale)
if self._painting_load then
self._painting_load(self, self._color)
else
automobiles_lib.paint(self, self._color)
end
local pos = self.object:get_pos()
local front_suspension=minetest.add_entity(self.object:get_pos(),self._front_suspension_ent)
if front_suspension then
front_suspension:set_attach(self.object,'',self._front_suspension_pos,{x=0,y=0,z=0})
self.front_suspension = front_suspension
end
if self._front_wheel_ent then
local lf_wheel=minetest.add_entity(pos,self._front_wheel_ent)
if lf_wheel then
lf_wheel:set_attach(self.front_suspension,'',{x=-self._front_wheel_xpos,y=0,z=0},{x=0,y=0,z=0})
-- set the animation once and later only change the speed
lf_wheel:set_animation(self._front_wheel_frames, 0, 0, true)
self.lf_wheel = lf_wheel
end
local rf_wheel=minetest.add_entity(pos,self._front_wheel_ent)
if rf_wheel then
rf_wheel:set_attach(self.front_suspension,'',{x=self._front_wheel_xpos,y=0,z=0},{x=0,y=180,z=0})
-- set the animation once and later only change the speed
rf_wheel:set_animation(self._front_wheel_frames, 0, 0, true)
self.rf_wheel = rf_wheel
end
end
local rear_suspension=minetest.add_entity(self.object:get_pos(),self._rear_suspension_ent)
if rear_suspension then
rear_suspension:set_attach(self.object,'',self._rear_suspension_pos,{x=0,y=0,z=0})
self.rear_suspension = rear_suspension
end
if self._rear_wheel_ent then
local lr_wheel=minetest.add_entity(pos,self._rear_wheel_ent)
if lr_wheel then
lr_wheel:set_attach(self.rear_suspension,'',{x=-self._rear_wheel_xpos,y=0,z=0},{x=0,y=0,z=0})
-- set the animation once and later only change the speed
lr_wheel:set_animation(self._rear_wheel_frames, 0, 0, true)
self.lr_wheel = lr_wheel
end
local rr_wheel=minetest.add_entity(pos,self._rear_wheel_ent)
if rr_wheel then
rr_wheel:set_attach(self.rear_suspension,'',{x=self._rear_wheel_xpos,y=0,z=0},{x=0,y=180,z=0})
-- set the animation once and later only change the speed
rr_wheel:set_animation(self._rear_wheel_frames, 0, 0, true)
self.rr_wheel = rr_wheel
end
end
if self._steering_ent then
local steering_axis=minetest.add_entity(pos,'automobiles_lib:pivot_mesh')
if steering_axis then
steering_axis:set_attach(self.object,'',self._drive_wheel_pos,{x=self._drive_wheel_angle,y=0,z=0})
if steering_axis then
self.steering_axis = steering_axis
local steering=minetest.add_entity(self.steering_axis:get_pos(), self._steering_ent)
steering:set_attach(self.steering_axis,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
self.steering = steering
end
end
end
if self._rag_retracted_ent then
local rag_rect=minetest.add_entity(self.object:get_pos(),self._rag_retracted_ent)
if rag_rect then
rag_rect:set_attach(self.object,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
self.rag_rect = rag_rect
self.rag_rect:set_properties({is_visible=false})
end
end
if self._rag_extended_ent then
local rag=minetest.add_entity(self.object:get_pos(),self._rag_extended_ent)
if rag then
rag:set_attach(self.object,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
self.rag = rag
end
end
automobiles_lib.seats_create(self)
local pointer_entity = 'automobiles_lib:pointer'
if self._gauge_pointer_ent then pointer_entity = self._gauge_pointer_ent end
if self._fuel_gauge_pos then
local fuel_gauge=minetest.add_entity(pos, pointer_entity)
if fuel_gauge then
fuel_gauge:set_attach(self.object,'',self._fuel_gauge_pos,{x=0,y=0,z=0})
self.fuel_gauge = fuel_gauge
end
end
if self._front_lights then
local lights = minetest.add_entity(pos,self._front_lights)
if lights then
lights:set_attach(self.object,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
self.lights = lights
self.lights:set_properties({is_visible=true})
end
end
if self._rear_lights then
local r_lights = minetest.add_entity(pos,self._rear_lights)
if r_lights then
r_lights:set_attach(self.object,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
self.r_lights = r_lights
self.r_lights:set_properties({is_visible=true})
end
end
if self._reverse_lights then
local reverse_lights = minetest.add_entity(pos,self._reverse_lights)
if reverse_lights then
reverse_lights:set_attach(self.object,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
self.reverse_lights = reverse_lights
self.reverse_lights:set_properties({is_visible=true})
end
end
if self._turn_left_lights then
local turn_l_light = minetest.add_entity(pos,self._turn_left_lights)
if turn_l_light then
turn_l_light:set_attach(self.object,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
self.turn_l_light = turn_l_light
self.turn_l_light:set_properties({is_visible=true})
end
end
if self._turn_right_lights then
local turn_r_light = minetest.add_entity(pos,self._turn_right_lights)
if turn_r_light then
turn_r_light:set_attach(self.object,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
self.turn_r_light = turn_r_light
self.turn_r_light:set_properties({is_visible=true})
end
end
if self._extra_items_function then
self._extra_items_function(self)
end
self.object:set_armor_groups({immortal=1})
local inv = minetest.get_inventory({type = "detached", name = self._inv_id})
-- if the game was closed the inventories have to be made anew, instead of just reattached
if not inv then
automobiles_lib.create_inventory(self, self._trunk_slots)
else
self.inv = inv
end
automobiles_lib.actfunc(self, staticdata, dtime_s)
end
function checkIsFinite(mynumber)
if math.isfinite(mynumber) then
return mynumber
end
return 0
end
function automobiles_lib.on_step(self, dtime)
automobiles_lib.stepfunc(self, dtime)
--[[sound play control]]--
self._last_time_collision_snd = self._last_time_collision_snd + dtime
if self._last_time_collision_snd > 1 then self._last_time_collision_snd = 1 end
self._last_time_drift_snd = self._last_time_drift_snd + dtime
if self._last_time_drift_snd > 2.0 then self._last_time_drift_snd = 2.0 end
--[[end sound control]]--
--in case it's not declared
self._max_acc_factor = self._max_acc_factor or 1
self._vehicle_scale = self._vehicle_scale or 1
self._vehicle_power_scale = self._vehicle_power_scale or self._vehicle_scale
local rotation = self.object:get_rotation()
local yaw = rotation.y
local newyaw=yaw
local pitch = rotation.x
local hull_direction = minetest.yaw_to_dir(yaw)
local nhdir = {x=hull_direction.z,y=0,z=-hull_direction.x} -- lateral unit vector
local velocity = self.object:get_velocity()
local longit_speed = automobiles_lib.dot(velocity,hull_direction)
local fuel_weight_factor = (5 - self._energy)/5000
local longit_drag = vector.multiply(hull_direction,(longit_speed*longit_speed) *
(self._LONGIT_DRAG_FACTOR - fuel_weight_factor) * -1 * automobiles_lib.sign(longit_speed))
local later_speed = automobiles_lib.dot(velocity,nhdir)
local dynamic_later_drag = self._LATER_DRAG_FACTOR
if longit_speed > 2 then dynamic_later_drag = 2.0 end
if longit_speed > 8 then dynamic_later_drag = 0.5 end
--core.chat_send_all(dump(longit_speed))
if automobiles_lib.extra_drift and longit_speed > (4*self._vehicle_power_scale) then
dynamic_later_drag = dynamic_later_drag/(longit_speed*2)
end
local later_drag = vector.new()
if self._is_motorcycle == true then
later_drag = vector.multiply(nhdir,later_speed*
later_speed*self._LATER_DRAG_FACTOR*-1*automobiles_lib.sign(later_speed))
else
later_drag = vector.multiply(nhdir,later_speed*
later_speed*dynamic_later_drag*-1*automobiles_lib.sign(later_speed))
end
local accel = vector.add(longit_drag,later_drag)
local stop = nil
local curr_pos = self.object:get_pos()
if self._show_rag == true then
if self._windshield_pos and self._windshield_ext_rotation then
self.object:set_bone_position("windshield", self._windshield_pos, self._windshield_ext_rotation) --extended
end
if self.rag_rect then self.rag_rect:set_properties({is_visible=true}) end
if self.rag then self.rag:set_properties({is_visible=false}) end
else
if self._windshield_pos then
self.object:set_bone_position("windshield", self._windshield_pos, {x=0, y=0, z=0}) --retracted
end
if self.rag_rect then self.rag_rect:set_properties({is_visible=false}) end
if self.rag then self.rag:set_properties({is_visible=true}) end
end
local player = nil
local is_attached = false
if self.driver_name then
player = minetest.get_player_by_name(self.driver_name)
if player then
local player_attach = player:get_attach()
if player_attach then
if self.driver_seat then
if player_attach == self.driver_seat or player_attach == self.object then is_attached = true end
end
end
end
end
--for flying
if self._setmode then
self._setmode(self, is_attached, curr_pos, velocity, player, dtime)
end
local is_braking = false
if is_attached then
local ctrl = player:get_player_control()
if ctrl.jump then
dynamic_later_drag = 0.2
end
if ctrl.aux1 then
--sets the engine running - but sets a delay also, cause keypress
if self._last_time_command > 0.8 then
self._last_time_command = 0
local horn_sound = "automobiles_horn"
if self._horn_sound then horn_sound = self._horn_sound end
minetest.sound_play({name = horn_sound},
{object = self.object, gain = 0.6, pitch = 1.0, max_hear_distance = 32, loop = false,})
end
end
if ctrl.down then
is_braking = true
if self.r_lights then self.r_lights:set_properties({textures={"automobiles_rear_lights_full.png"}, glow=15}) end
end
if self.reverse_lights then
if ctrl.sneak then
self.reverse_lights:set_properties({textures={"automobiles_white.png"}, glow=15})
else
self.reverse_lights:set_properties({textures={"automobiles_grey.png"}, glow=0})
end
end
end
self._last_light_move = self._last_light_move + dtime
if self._last_light_move > 0.15 then
self._last_light_move = 0
if self.lights then
if self._show_lights == true then
--self.lights:set_properties({is_visible=true})
self.lights:set_properties({textures={"automobiles_front_lights.png"}, glow=15})
if is_braking == false then
if self.r_lights then self.r_lights:set_properties({textures={"automobiles_rear_lights.png"}, glow=10}) end
end
automobiles_lib.put_light(self)
else
--self.lights:set_properties({is_visible=false})
self.lights:set_properties({textures={"automobiles_grey.png"}, glow=0})
if is_braking == false then
if self.r_lights then self.r_lights:set_properties({textures={"automobiles_rear_lights_off.png"}, glow=0}) end
end
automobiles_lib.remove_light(self)
end
end
end
-- impacts and control
if is_attached then --and self.driver_name == self.owner then
local impact = automobiles_lib.get_hipotenuse_value(velocity, self.lastvelocity)
if impact > 1 then
--self.damage = self.damage + impact --sum the impact value directly to damage meter
if self._last_time_collision_snd > 0.3 then
self._last_time_collision_snd = 0
minetest.sound_play("collision", {
to_player = self.driver_name,
--pos = curr_pos,
--max_hear_distance = 5,
gain = 1.0,
fade = 0.0,
pitch = 1.0,
})
end
--[[if self.damage > 100 then --if acumulated damage is greater than 100, adieu
automobiles_lib.destroy(self)
end]]--
end
--control
local steering_angle_max = 40
local steering_speed = 40
if math.abs(longit_speed) > 3*self._vehicle_scale then
local mid_speed = (steering_speed/2)
steering_speed = (mid_speed + (mid_speed / math.abs(longit_speed*0.25))*self._vehicle_scale)
end
--adjust engine parameter (transmission emulation)
local acc_factor = self._max_acc_factor
local transmission_state = automobiles_lib.get_transmission_state(self, longit_speed, self._max_speed)
local target_acc_factor = acc_factor
if self._have_transmission ~= false then
if transmission_state == 1 then
target_acc_factor = (acc_factor/3)
end
if transmission_state == 2 then
target_acc_factor = (acc_factor/2)
end
self._transmission_state = transmission_state
end
--core.chat_send_all(transmission_state)
--control
local control = automobiles_lib.control
if self._control_function then
control = self._control_function
end
accel, stop = control(self, dtime, hull_direction, longit_speed, longit_drag, later_drag, accel, target_acc_factor, self._max_speed, steering_angle_max, steering_speed)
--accel = vector.multiply(accel, self._vehicle_power_scale)
else
self._show_lights = false
if self.sound_handle ~= nil then
minetest.sound_stop(self.sound_handle)
self.sound_handle = nil
end
end
local angle_factor = self._steering_angle / 10
--whell turn
if self.lf_wheel and self.rf_wheel and self.lr_wheel and self.rr_wheel and self._is_flying ~= 1 then
self.lf_wheel:set_attach(self.front_suspension,'',{x=-self._front_wheel_xpos,y=0,z=0},{x=0,y=-self._steering_angle-angle_factor,z=0})
self.rf_wheel:set_attach(self.front_suspension,'',{x=self._front_wheel_xpos,y=0,z=0},{x=0,y=(-self._steering_angle+angle_factor)+180,z=0})
self.lr_wheel:set_attach(self.rear_suspension,'',{x=-self._rear_wheel_xpos,y=0,z=0},{x=0,y=0,z=0})
self.rr_wheel:set_attach(self.rear_suspension,'',{x=self._rear_wheel_xpos,y=0,z=0},{x=0,y=180,z=0})
end
--check if the tyres is touching the pavement
local noded = automobiles_lib.nodeatpos(automobiles_lib.pos_shift(curr_pos,{y=self.initial_properties.collisionbox[2]-0.5}))
if (noded and noded.drawtype ~= 'airlike') then
if noded.drawtype ~= 'liquid' then
local wheel_compensation = longit_speed * (self._wheel_compensation or 1)
if self.lf_wheel then self.lf_wheel:set_animation_frame_speed( wheel_compensation * (12 - angle_factor)) end
if self.rf_wheel then self.rf_wheel:set_animation_frame_speed(-wheel_compensation * (12 + angle_factor)) end
if self.lr_wheel then self.lr_wheel:set_animation_frame_speed( wheel_compensation * (12 - angle_factor)) end
if self.rr_wheel then self.rr_wheel:set_animation_frame_speed(-wheel_compensation * (12 + angle_factor)) end
end
else
--is flying
if self.lf_wheel then self.lf_wheel:set_animation_frame_speed(0) end
if self.rf_wheel then self.rf_wheel:set_animation_frame_speed(0) end
if self.lr_wheel then self.lr_wheel:set_animation_frame_speed(0) end
if self.rr_wheel then self.rr_wheel:set_animation_frame_speed(0) end
end
--drive wheel turn
if self._steering_ent then
self.steering:set_attach(self.steering_axis,'',{x=0,y=0,z=0},{x=0,y=0,z=self._steering_angle*2})
else
self.object:set_bone_position("drive_wheel", {x=-0, y=0, z=0}, {x=0, y=0, z=-self._steering_angle*2})
end
if math.abs(self._steering_angle)>5 then
local turn_rate = math.rad(40)
newyaw = yaw + dtime*(1 - 1 / (math.abs(longit_speed) + 1)) *
self._steering_angle / 30 * turn_rate * automobiles_lib.sign(longit_speed)
end
--turn light
if self.turn_l_light and self.turn_r_light then
self._turn_light_timer = self._turn_light_timer + dtime
if math.abs(self._steering_angle) > 15 and self._turn_light_timer >= 1 then
self._turn_light_timer = 0
--set turn light
--minetest.chat_send_all(self._steering_angle)
local textures_l = self._textures_turn_lights_on or {"automobiles_rear_lights_full.png"}
if self._steering_angle < 0 then
--minetest.chat_send_all("direita")
self.turn_r_light:set_properties({textures=textures_l, glow=20})
end
if self._steering_angle > 0 then
--minetest.chat_send_all("esquerda")
self.turn_l_light:set_properties({textures=textures_l, glow=20})
end
end
if self._turn_light_timer > 0.5 then
local textures_l = self._textures_turn_lights_off or {"automobiles_rear_lights_off.png"}
self.turn_l_light:set_properties({textures=textures_l, glow=0})
self.turn_r_light:set_properties({textures=textures_l, glow=0})
end
if self._turn_light_timer > 1 then
self._turn_light_timer = 1
end
end
--if it's not NaN, add accel
accel.x = checkIsFinite(accel.x)
accel.y = checkIsFinite(accel.y)
accel.z = checkIsFinite(accel.z)
--[[
accell correction
under some circunstances the acceleration exceeds the max value accepted by set_acceleration and
the game crashes with an overflow, so limiting the max acceleration in each axis prevents the crash
]]--
local max_factor = 25
local acc_adjusted = 0
if accel.x > max_factor then accel.x = acc_adjusted end
if accel.x < -max_factor then accel.x = -acc_adjusted end
if accel.z > max_factor then accel.z = acc_adjusted end
if accel.z < -max_factor then accel.z = -acc_adjusted end
-- end correction
-- calculate energy consumption --
----------------------------------
if self._energy > 0 then
local zero_reference = vector.new()
local acceleration = automobiles_lib.get_hipotenuse_value(accel, zero_reference)
--minetest.chat_send_all(acceleration)
if automobiles_lib.is_drift_game == false then
local consumption = 40000
if self._consumption_divisor then
consumption = self._consumption_divisor
end
local consumed_power = acceleration/consumption
self._energy = self._energy - consumed_power;
else
self._energy = 5
end
end
if self._energy <= 0 then
self._engine_running = false
self._is_flying = 0
if self.sound_handle then
minetest.sound_stop(self.sound_handle)
self.sound_handle = nil
minetest.chat_send_player(self.driver_name, "Out of fuel")
end
else
self._last_engine_sound_update = self._last_engine_sound_update + dtime
if self._last_engine_sound_update > 0.300 then
self._last_engine_sound_update = 0
automobiles_lib.engine_set_sound_and_animation(self, longit_speed)
end
end
local energy_indicator_angle = automobiles_lib.get_gauge_angle(self._energy)
if self.fuel_gauge then
self.fuel_gauge:set_attach(self.object,'',self._fuel_gauge_pos,{x=0,y=0,z=energy_indicator_angle})
end
----------------------------
-- end energy consumption --
--gravity works
if not self._is_flying or self._is_flying == 0 then
accel.y = -automobiles_lib.gravity
else
local time_correction = (self.dtime/automobiles_lib.ideal_step)
local y_accel = self._car_gravity*time_correction
accel.y = y_accel --sets the anti gravity
end
if stop == true then
self._last_accel = vector.new() --self.object:get_acceleration()
self.object:set_acceleration({x=0,y=0,z=0})
self.object:set_velocity({x=0,y=0,z=0})
else
self.object:move_to(curr_pos)
--automobiles_lib.set_acceleration(self.object, new_accel)
local limit = (self._max_speed/self.dtime)
if accel.y > limit then accel.y = limit end --it isn't a rocket :/
self._last_accel = accel
end
self._last_ground_check = self._last_ground_check + dtime
if self._last_ground_check > 0.18 then
self._last_ground_check = 0
automobiles_lib.ground_get_distances(self, 0.372*self._vehicle_scale, (self._front_suspension_pos.z*self._vehicle_scale)/10)
end
local newpitch = self._pitch --velocity.y * math.rad(6)
local newroll = self._roll or 0
if self._is_flying == 1 then
newpitch = 0
local turn_effect_speed = longit_speed
if turn_effect_speed > 10 then turn_effect_speed = 10 end
newroll = (-self._steering_angle/100)*(turn_effect_speed/10)
if math.abs(self._steering_angle) < 1 then newroll = 0 end
--pitch
local max_pitch = 6
local h_vel_compensation = (((longit_speed * 2) * 100)/max_pitch)/100
if h_vel_compensation < 0 then h_vel_compensation = 0 end
if h_vel_compensation > max_pitch then h_vel_compensation = max_pitch end
newpitch = newpitch + (velocity.y * math.rad(max_pitch - h_vel_compensation))
else
local turn_effect_speed = longit_speed
if self._is_motorcycle then
if turn_effect_speed > 20 then turn_effect_speed = 20 end
newroll = (-self._steering_angle/100)*(turn_effect_speed/10)
if is_attached == false and stop == true then
newroll = self._stopped_roll
end
else
if turn_effect_speed > 10 then turn_effect_speed = 10 end
if math.abs(longit_speed) > 0 then
--local tilt_effect = (-self._steering_angle/100)*(turn_effect_speed/30)
local max_tilt = 10
local tilt_effect = (-later_speed/12)*(turn_effect_speed/30)
local tire_burn = false
if tilt_effect > max_tilt then
tilt_effect = max_tilt
end
if tilt_effect < -max_tilt then
tilt_effect = -max_tilt
end
newroll = tilt_effect * -1
self.front_suspension:set_rotation({x=0,y=0,z=tilt_effect})
self.rear_suspension:set_rotation({x=0,y=0,z=tilt_effect})
newroll = newroll + (self._roll or 0)
if (noded and noded.drawtype ~= 'airlike') then
if noded.drawtype ~= 'liquid' then
local min_later_speed = self._min_later_speed or 3
local speed_for_smoke = min_later_speed / 2
if (later_speed > speed_for_smoke or later_speed < -speed_for_smoke) and not self._is_motorcycle then
automobiles_lib.add_smoke(self, curr_pos, yaw, self._rear_wheel_xpos*self._vehicle_scale)
if automobiles_lib.extra_drift == false then --disables the sound when playing drift game.. it's annoying
if self._last_time_drift_snd >= 2.0 and (later_speed > min_later_speed or later_speed < -min_later_speed) then
self._last_time_drift_snd = 0
minetest.sound_play("automobiles_drifting", {
pos = curr_pos,
max_hear_distance = 20,
gain = 3.0,
fade = 0.0,
pitch = 1.0,
ephemeral = true,
})
end
end
end
end
end
else
if self.front_suspension then self.front_suspension:set_rotation({x=0,y=0,z=0}) end
if self.rear_suspension then self.rear_suspension:set_rotation({x=0,y=0,z=0}) end
end
end
end
self.object:set_rotation({x=newpitch,y=newyaw,z=newroll})
self._longit_speed = longit_speed
end
@@ -0,0 +1,93 @@
local S = automobiles_lib.S
function automobiles_lib.getCarFromPlayer(player, self)
local seat = player:get_attach()
if seat then
local car = seat:get_attach()
if car then
return car
else
return seat
end
end
return nil
end
function automobiles_lib.driver_formspec(name)
local player = minetest.get_player_by_name(name)
if player then
local vehicle_obj = automobiles_lib.getCarFromPlayer(player)
if vehicle_obj == nil then
return
end
local ent = vehicle_obj:get_luaentity()
if ent then
local yaw = "false"
local one_hand = "false"
if ent._yaw_by_mouse then yaw = "true" end
if ent._one_hand then one_hand = "true" end
local basic_form = table.concat({
"formspec_version[3]",
"size[6,7]",
}, "")
basic_form = basic_form.."button[1,1.0;4,1;go_out;" .. S("Go Offboard") .. "]"
basic_form = basic_form.."button[1,2.5;4,1;lights;" .. S("Lights") .. "]"
basic_form = basic_form.."checkbox[1,5.5;yaw;" .. S("Direction by mouse") .. ";"..yaw.."]"
basic_form = basic_form.."checkbox[1,6.2;one_hand;" .. S("One Hand Driving\n(open menu using AUX)") .. ";"..one_hand.."]"
minetest.show_formspec(name, "automobiles_lib:driver_main", basic_form)
end
end
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "automobiles_lib:driver_main" then
local name = player:get_player_name()
local car_obj = automobiles_lib.getCarFromPlayer(player)
if car_obj then
local ent = car_obj:get_luaentity()
if ent then
if fields.go_out then
if ent._passenger then --any pax?
local pax_obj = minetest.get_player_by_name(ent._passenger)
local dettach_pax_f = automobiles_lib.dettach_pax
if ent._dettach_pax then dettach_pax_f = ent._dettach_pax end
dettach_pax_f(ent, pax_obj)
end
ent._is_flying = 0
local dettach_f = automobiles_lib.dettach_driver
if ent._dettach then dettach_f = ent._dettach end
dettach_f(ent, player)
end
if fields.lights then
if ent._show_lights == true then
ent._show_lights = false
else
ent._show_lights = true
end
end
if fields.yaw then
if ent._yaw_by_mouse == true then
ent._yaw_by_mouse = false
else
ent._yaw_by_mouse = true
end
end
if fields.one_hand then
if ent._one_hand == true then
ent._one_hand = false
else
ent._one_hand = true
core.chat_send_player(name,core.colorize('#00ff00', S(" >>> Use AUX or key \"E\" to open the menu")))
end
end
end
end
minetest.close_formspec(name, "automobiles_lib:driver_main")
end
end)
+44
View File
@@ -0,0 +1,44 @@
--
-- fuel
--
function automobiles_lib.contains(table, val)
for k,v in pairs(table) do
if k == val then
return v
end
end
return false
end
function automobiles_lib.loadFuel(self, player_name, free, max_fuel)
free = free or false
local player = minetest.get_player_by_name(player_name)
local inv = player:get_inventory()
local itmstck=player:get_wielded_item()
local item_name = ""
if itmstck then item_name = itmstck:get_name() end
local fuel = automobiles_lib.contains(automobiles_lib.fuel, item_name)
--minetest.chat_send_all(dump(fuel))
if fuel or free == true then
local stack = ItemStack(item_name .. " 1")
if self._energy < max_fuel then
itmstck:set_count(1)
if free == false then inv:remove_item("main", itmstck) end
if fuel then
self._energy = self._energy + fuel
end
if self._energy > max_fuel then self._energy = max_fuel end
automobiles_lib.last_fuel_display = 0
if self._energy == max_fuel then minetest.chat_send_player(player_name, "Full tank!") end
end
return true
end
return false
end
@@ -0,0 +1,278 @@
function automobiles_lib.putAngleOnRange(angle)
local n_angle = angle/360
n_angle = (n_angle - math.floor(n_angle))*360
if n_angle < -180 then n_angle = n_angle + 360 end
if n_angle > 180 then n_angle = n_angle - 360 end
return n_angle
end
function automobiles_lib.pid_controller(current_value, setpoint, last_error, delta_t, kp, ki, kd)
kp = kp or 0
ki = ki or 0.00000000000001
kd = kd or 0.05
delta_t = delta_t or 0.100;
ti = kp/ki
td = kd/kp
local _error = setpoint - current_value
local derivative = _error - last_error
--local output = kpv*erro + (kpv/Tiv)*I + kpv*Tdv*((erro - erro_passado)/delta_t);
if integrative == nil then integrative = 0 end
integrative = integrative + (((_error + last_error)/delta_t)/2);
local output = kp*_error + (kp/ti)*integrative + kp * td*((_error - last_error)/delta_t)
last_error = _error
return output, last_error
end
-- Função para calcular ângulos de pitch e roll
local function get_vehicle_pitch_roll(pos, wheels, yaw)
local world = vector.new()
--core.chat_send_all(dump(wheels))
--rotacionando as posições das rodas
for i = 1,4,1 do
local orig_x = wheels[i].x
local orig_z = wheels[i].z
wheels[i].x = (orig_x * math.cos(yaw)) - (orig_z * math.sin(yaw))
wheels[i].z = (orig_x * math.sin(yaw)) + (orig_z * math.cos(yaw))
end
--core.chat_send_all(dump(wheels))
local points = {}
-- Obter altura do terreno para cada roda
for i, wheel in ipairs(wheels) do
world.x = pos.x + wheel.x
world.y = pos.y + wheel.y
world.z = pos.z + wheel.z
local height = automobiles_lib.get_obstacle({x=world.x,y=world.y,z=world.z}).y or 0
table.insert(points, {x = world.x, y = height, z = world.z})
end
-- Calcular os coeficientes do plano Ax + By + Cz + D = 0
local x1, y1, z1 = points[1].x, points[1].y, points[1].z
local x2, y2, z2 = points[2].x, points[2].y, points[2].z
local x3, y3, z3 = points[3].x, points[3].y, points[3].z
local x4, y4, z4 = points[4].x, points[4].y, points[4].z
-- Criamos dois vetores a partir das quatro rodas
local v1 = {x = x2 - x1, y = y2 - y1, z = z2 - z1}
local v2 = {x = x3 - x1, y = y3 - y1, z = z3 - z1}
local v3 = {x = x4 - x1, y = y4 - y1, z = z4 - z1}
-- Tiramos a média do produto vetorial entre os três vetores
local normal1 = {
x = v1.y * v2.z - v1.z * v2.y,
y = v1.z * v2.x - v1.x * v2.z,
z = v1.x * v2.y - v1.y * v2.x
}
local normal2 = {
x = v1.y * v3.z - v1.z * v3.y,
y = v1.z * v3.x - v1.x * v3.z,
z = v1.x * v3.y - v1.y * v3.x
}
-- Média das duas normais para melhor precisão
local normal = {
x = (normal1.x + normal2.x) / 2,
y = (normal1.y + normal2.y) / 2,
z = (normal1.z + normal2.z) / 2
}
-- Normalizar o vetor normal
local magnitude = math.sqrt(normal.x^2 + normal.y^2 + normal.z^2)
if magnitude == 0 then
return 0, 0 -- Retorna ângulos neutros se o cálculo falhar
end
normal.x = normal.x / magnitude
normal.y = normal.y / magnitude
normal.z = normal.z / magnitude
--core.chat_send_all("normal2 "..dump(normal).."\nmagnitude: "..magnitude)
-- Criar um vetor de direção do veículo (da traseira para a frente)
local forward = {
x = (wheels[1].x + wheels[2].x) / 2 - (wheels[3].x + wheels[4].x) / 2,
z = (wheels[1].z + wheels[2].z) / 2 - (wheels[3].z + wheels[4].z) / 2
}
-- Normalizar o vetor de direção
local magnitude_forward = math.sqrt(forward.x^2 + forward.z^2)
forward.x = forward.x / magnitude_forward
forward.z = forward.z / magnitude_forward
-- Descobrir se o veículo está apontando para frente ou para trás no eixo Z
local direction_z = forward.z >= 0 and -1 or 1
-- Descobrir se o veículo está apontando para direita/esquerda no eixo X
local direction_x = forward.x >= 0 and -1 or 1
-- Verificar qual eixo está "apontado para frente"
local dominantX = math.abs(forward.x) > math.abs(forward.z)
local pitch, roll
local m, n
if dominantX then
-- Calcular ângulos de pitch e roll
m = normal.x/normal.y
pitch = math.atan(m) * direction_x
if pitch ~= pitch then pitch = 0 end
n = normal.z/normal.y
roll = math.atan(n) * direction_x
if roll ~= roll then roll = 0 end
else
-- Calcular ângulos de pitch e roll
m = normal.z/normal.y
pitch = math.atan(m) * direction_z
if pitch ~= pitch then pitch = 0 end
n = normal.x/normal.y
roll = math.atan(n) * direction_z * -1
if roll ~= roll then roll = 0 end
end
--core.chat_send_all(dump("pitch "..math.deg(pitch).." - roll "..math.deg(roll)))
return pitch, roll
end
local function get_nodedef_field(nodename, fieldname)
if not minetest.registered_nodes[nodename] then
return nil
end
return minetest.registered_nodes[nodename][fieldname]
end
--lets assume that the rear axis is at object center, so we will use the distance only for front wheels
function automobiles_lib.ground_get_distances(self, radius, axis_distance)
--local mid_axis = (axis_length / 2)/10
local hip = axis_distance
--minetest.chat_send_all("entre-eixo "..hip)
local pitch = self._pitch --+90 for the calculations
local yaw = self.object:get_yaw()
local deg_yaw = math.deg(yaw)
local yaw_turns = math.floor(deg_yaw / 360)
deg_yaw = deg_yaw - (yaw_turns * 360)
yaw = math.rad(deg_yaw)
local pos = self.object:get_pos()
local front_wheel_x = self._front_wheel_xpos / 10
if math.abs(front_wheel_x) < 0.01 then front_wheel_x = 0.01 end --pra não anular as normals
local rear_wheel_x = self._rear_wheel_xpos / 10
if math.abs(rear_wheel_x) < 0.01 then rear_wheel_x = 0.01 end --pra não anular as normals
local wheels = {
{x = -front_wheel_x, y = 0, z = axis_distance}, -- Roda frontal esquerda
{x = front_wheel_x, y = 0, z = axis_distance}, -- Roda frontal direita
{x = -rear_wheel_x, y = 0, z = -0}, -- Roda traseira esquerda
{x = rear_wheel_x, y = 0, z = -0} -- Roda traseira direita
}
--retornando pitch e roll
local pitch, roll = get_vehicle_pitch_roll(pos, wheels, yaw)
if not self._last_pitch then self._last_pitch = pitch end
--[[
* `minetest.raycast(pos1, pos2, objects, liquids)`: returns `Raycast`
* Creates a `Raycast` object.
* `pos1`: start of the ray
* `pos2`: end of the ray
* `objects`: if false, only nodes will be returned. Default is `true`.
* `liquids`: if false, liquid nodes won't be returned. Default is `false`.
]]--
if 1 then
local pos_y_elevation = 1.6
local pos_elevation = (math.tan(pitch)*axis_distance) + pos_y_elevation
--core.chat_send_all(dump(pos_elevation))
local f_x, f_z = automobiles_lib.get_xz_from_hipotenuse(pos.x, pos.z, yaw, axis_distance)
local f_y = pos.y + pos_elevation
local end_pos = {x=f_x, y=f_y, z=f_z}
local initial_pos = vector.new(pos)
initial_pos.y = initial_pos.y + pos_elevation
local cast = minetest.raycast(initial_pos, end_pos, true, false)
local thing = cast:next()
while thing do
if thing.type == "node" then
local pos = thing.intersection_point
if pos then
local nodename = minetest.get_node(thing.under).name
local drawtype = get_nodedef_field(nodename, "drawtype")
if drawtype ~= "plantlike" then
self.object:set_acceleration({x=0,y=0,z=0})
local oldvel = self.object:get_velocity()
self.object:add_velocity(vector.subtract(vector.new(), oldvel))
pitch = math.rad(0)
break
end
end
end
thing = cast:next()
end
end
self._pitch = pitch -- math.rad(90)
self._roll = roll -- math.rad(90)
--core.chat_send_all(dump("pitch "..pitch.." - roll "..roll))
end
function automobiles_lib.get_obstacle(ref_pos, ammount)
ammount = ammount or -3
--lets clone the table
local retval = {x=ref_pos.x, y=ref_pos.y, z=ref_pos.z}
--minetest.chat_send_all("aa y: " .. dump(retval.y))
local i_pos = {x=ref_pos.x, y=ref_pos.y + 1, z=ref_pos.z}
--minetest.chat_send_all("bb y: " .. dump(i_pos.y))
local y = automobiles_lib.eval_interception(i_pos, {x=i_pos.x, y=ref_pos.y + ammount, z=i_pos.z})
if y then
retval.y = y
end
--minetest.chat_send_all("y: " .. dump(ref_pos.y) .. " ye: ".. dump(retval.y))
return retval
end
function automobiles_lib.eval_interception(initial_pos, end_pos)
local ret_y = nil
local cast = minetest.raycast(initial_pos, end_pos, true, false)
local thing = cast:next()
while thing do
if thing.type == "node" then
local pos = thing.intersection_point
if pos then
local nodename = minetest.get_node(thing.under).name
local drawtype = get_nodedef_field(nodename, "drawtype")
if drawtype ~= "plantlike" and drawtype ~= nil then
if initial_pos.y >= pos.y then
ret_y = pos.y
--minetest.chat_send_all("ray intercection: " .. dump(pos.y) .. " -- " .. nodename)
end
break
end
end
end
thing = cast:next()
end
return ret_y
end
function automobiles_lib.get_node_below(pos, dist)
local node = minetest.get_node(pos)
local pos_below = pos
pos_below.y = pos_below.y - (dist + 0.1)
local node_below = minetest.get_node(pos_below)
return node_below
end
+937
View File
@@ -0,0 +1,937 @@
-- Minetest 5.4.1 : automobiles
automobiles_lib = {
storage = minetest.get_mod_storage()
}
automobiles_lib.S = nil
if(minetest.get_translator ~= nil) then
automobiles_lib.S = minetest.get_translator(minetest.get_current_modname())
else
automobiles_lib.S = function ( s ) return s end
end
local S = automobiles_lib.S
local storage = automobiles_lib.storage
automobiles_lib.is_minetest = core.get_modpath("player_api")
automobiles_lib.is_mcl = core.get_modpath("mcl_player")
automobiles_lib.is_repixture = core.get_modpath("rp_player")
automobiles_lib.fuel = {['biofuel:biofuel'] = 1,['biofuel:bottle_fuel'] = 1,
['biofuel:phial_fuel'] = 0.25, ['biofuel:fuel_can'] = 10,
['airutils:biofuel'] = 1,}
automobiles_lib.gravity = 9.8
automobiles_lib.ideal_step = 0.2
automobiles_lib.is_creative = minetest.settings:get_bool("creative_mode", false)
automobiles_lib.can_collect_car = minetest.settings:get_bool("collect_automobiles", true)
automobiles_lib.is_drift_game = false
automobiles_lib.extra_drift = false
if minetest.registered_nodes["dg_mapgen:stone"] then
automobiles_lib.is_drift_game = true
automobiles_lib.extra_drift = true
end
local load_noob_mode = core.settings:get_bool("noob_mode", false) -- or storage:get_int("noob_mode")
automobiles_lib.noob_mode = false
automobiles_lib.extra_stepheight = 0
-- 1 == true ---- 2 == false
if load_noob_mode == true then
automobiles_lib.load_noob_mode = true
automobiles_lib.extra_stepheight = 1
end
local new_speed_limit = core.settings:get("speed_limit")
automobiles_lib.speed_limit = tonumber(new_speed_limit) or 500
automobiles_lib.speed_limit = math.floor(automobiles_lib.speed_limit)
local motorcycle_anim_mode = minetest.settings:get_bool("motorcycle_anim_mode", true)
automobiles_lib.mot_anim_mode = true
if motorcycle_anim_mode == false or automobiles_lib.is_mcl then --disable for mcl too -- TODO
automobiles_lib.mot_anim_mode = false
end
--cars colors
automobiles_lib.colors ={
black='#2b2b2b',
blue='#0063b0',
brown='#8c5922',
cyan='#07B6BC',
dark_green='#567a42',
dark_grey='#6d6d6d',
green='#4ee34c',
grey='#9f9f9f',
magenta='#ff0098',
orange='#ff8b0e',
pink='#ff62c6',
red='#dc1818',
violet='#a437ff',
white='#FFFFFF',
yellow='#ffe400',
-- NEW: Mineclonia colors that were missing (thanks PsyMops)
light_blue = "#258ec9", -- Light blue dye
lime = "#60ac19", -- Lime dye (bright green)
purple = "#6821a0", -- Purple dye (similar to violet)
silver = "#818177", -- Silver/light grey dye
}
local eye_height_plus_value = 6.5
local base_eie_height = -4
if automobiles_lib.is_mcl then
base_eie_height = -5.5
end
--
-- helpers and co.
--
function automobiles_lib.get_hipotenuse_value(point1, point2)
return math.sqrt((point1.x - point2.x) ^ 2 + (point1.y - point2.y) ^ 2 + (point1.z - point2.z) ^ 2)
end
function automobiles_lib.dot(v1,v2)
return (v1.x*v2.x)+(v1.y*v2.y)+(v1.z*v2.z)
end
function automobiles_lib.sign(n)
return n>=0 and 1 or -1
end
function automobiles_lib.minmax(v,m)
return math.min(math.abs(v),m)*minekart.sign(v)
end
function automobiles_lib.properties_copy(origin_table)
local tablecopy = {}
for k, v in pairs(origin_table) do
tablecopy[k] = v
end
return tablecopy
end
local function smoke_particle(self, pos)
minetest.add_particle({
pos = pos,
velocity = {x = 0, y = 0, z = 0},
acceleration = {x = 0, y = 0, z = 0},
expirationtime = 0.25,
size = 2.8*(self._vehicle_scale or 1),
collisiondetection = false,
collision_removal = false,
vertical = false,
texture = "automobiles_smoke.png",
})
end
function automobiles_lib.add_smoke(self, pos, yaw, rear_wheel_xpos)
local direction = yaw
--right
local move = rear_wheel_xpos/10
local smk_pos = vector.new(pos)
smk_pos.x = smk_pos.x + move * math.cos(direction)
smk_pos.z = smk_pos.z + move * math.sin(direction)
smoke_particle(self, smk_pos)
--left
direction = direction - math.rad(180)
smk_pos = vector.new(pos)
smk_pos.x = smk_pos.x + move * math.cos(direction)
smk_pos.z = smk_pos.z + move * math.sin(direction)
smoke_particle(self, smk_pos)
end
--returns 0 for old, 1 for new
function automobiles_lib.detect_player_api(player)
local player_proterties = player:get_properties()
--local mesh = "character.b3d"
--if player_proterties.mesh == mesh then
if core.get_modpath("player_api") then
local models = player_api.registered_models
local character = models[player_proterties.mesh]
--core.chat_send_all(dump(character));
if character and character.animations and character.animations.sit then
if character.animations.sit.eye_height then
--core.chat_send_all(dump(character.animations.sit.eye_height));
if character.animations.sit.eye_height == 0.8 then
--core.chat_send_all("new model");
return 1
else
--core.chat_send_all("new height");
return 2 --strange bug with armor ands skins returning 1.47
end
else
--core.chat_send_all("old model");
return 0
end
end
elseif core.get_modpath("mcl_player") then
return 1
end
return 0
end
function automobiles_lib.seats_create(self)
if self.object then
local pos = self.object:get_pos()
self._passengers_base = {}
self._passengers = {}
if self._seat_pos then
local max_seats = table.getn(self._seat_pos)
for i=1, max_seats do
self._passengers_base[i] = minetest.add_entity(pos,'automobiles_lib:pivot_mesh')
if self._passengers_base[i] then
if not self._seats_rot then
self._passengers_base[i]:set_attach(self.object,'',self._seat_pos[i],{x=0,y=0,z=0})
else
self._passengers_base[i]:set_attach(self.object,'',self._seat_pos[i],{x=0,y=self._seats_rot[i],z=0})
end
end
end
self.driver_seat = self._passengers_base[1] --sets pilot seat reference
self.passenger_seat = self._passengers_base[2] --sets copilot seat reference
end
end
end
function automobiles_lib.sit(player)
--set_animation(frame_range, frame_speed, frame_blend, frame_loop)
player:set_animation({x = 81, y = 160},30, 0, true)
if core.get_modpath("emote") then emote.start(player:get_player_name(), "sit") end
end
-- attach player
function automobiles_lib.attach_driver(self, player)
local name = player:get_player_name()
self.driver_name = name
if not self.driver_seat then return end
-- attach the driver
player:set_attach(self.driver_seat, "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
local eye_y = base_eie_height
if automobiles_lib.detect_player_api(player) == 1 then
eye_y = eye_y + eye_height_plus_value
end
eye_y = eye_y*self._vehicle_scale
player:set_eye_offset({x = 0, y = eye_y, z = 0}, {x = 0, y = eye_y, z = -30})
if automobiles_lib.is_minetest then
player_api.player_attached[name] = true
player_api.set_animation(player, "sit")
elseif automobiles_lib.is_mcl then
mcl_player.player_attached[name] = true
mcl_player.player_set_animation(player, "sit" , 30)
automobiles_lib.sit(player)
end
-- make the driver sit
minetest.after(1, function()
if player then
--minetest.chat_send_all("okay")
automobiles_lib.sit(player)
--apply_physics_override(player, {speed=0,gravity=0,jump=0})
end
end)
end
function automobiles_lib.dettach_driver(self, player)
local name = self.driver_name
--self._engine_running = false
-- driver clicked the object => driver gets off the vehicle
self.driver_name = nil
if self._engine_running then
self._engine_running = false
end
-- sound and animation
if self.sound_handle then
minetest.sound_stop(self.sound_handle)
self.sound_handle = nil
end
-- detach the player
if player.set_detach then
--automobiles_lib.remove_hud(player)
--player:set_properties({physical=true})
player:set_detach()
player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
if automobiles_lib.is_minetest then
if player_api.player_attached[name] then
player_api.player_attached[name] = nil
end
player_api.set_animation(player, "stand")
elseif automobiles_lib.is_mcl then
if mcl_player.player_attached[name] then
mcl_player.player_attached[name] = nil
end
mcl_player.player_set_animation(player, "stand")
end
end
self.driver = nil
end
-- attach passenger
function automobiles_lib.attach_pax(self, player, onside)
local onside = onside or false
local name = player:get_player_name()
local eye_y = base_eie_height
if automobiles_lib.detect_player_api(player) == 1 then
eye_y = eye_y + eye_height_plus_value
end
eye_y = eye_y*self._vehicle_scale
if self._passenger == nil then
self._passenger = name
-- attach the pax
player:set_attach(self.passenger_seat, "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
player:set_eye_offset({x = 0, y = eye_y, z = 0}, {x = 0, y = eye_y, z = -30})
if automobiles_lib.is_minetest then
player_api.player_attached[name] = true
player_api.set_animation(player, "sit")
elseif automobiles_lib.is_mcl then
mcl_player.player_attached[name] = true
mcl_player.player_set_animation(player, "sit" , 30)
automobiles_lib.sit(player)
end
-- make the pax sit
minetest.after(0.2, function()
if player then
--minetest.chat_send_all("okay")
automobiles_lib.sit(player)
--apply_physics_override(player, {speed=0,gravity=0,jump=0})
end
end)
else
--randomize the seat
local max_seats = table.getn(self._seat_pos) --driver and front passenger
t = {} -- new array
for i=1, max_seats do --(the first are for the driver
t[i] = i
end
for i = 1, #t*2 do
local a = math.random(#t)
local b = math.random(#t)
t[a],t[b] = t[b],t[a]
end
for k,v in ipairs(t) do
i = t[k]
if self._passengers[i] == nil and i > 2 then
--core.chat_send_all(self.driver_name)
self._passengers[i] = name
player:set_attach(self._passengers_base[i], "", {x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
player:set_eye_offset({x = 0, y = eye_y, z = 0}, {x = 0, y = 3, z = -30})
if automobiles_lib.is_minetest then
player_api.player_attached[name] = true
player_api.set_animation(player, "sit")
elseif automobiles_lib.is_mcl then
mcl_player.player_attached[name] = true
mcl_player.player_set_animation(player, "sit" , 30)
automobiles_lib.sit(player)
end
-- make the pax sit
minetest.after(0.2, function()
if player then
--minetest.chat_send_all("okay")
automobiles_lib.sit(player)
--apply_physics_override(player, {speed=0,gravity=0,jump=0})
end
end)
break
end
end
end
end
function automobiles_lib.dettach_pax(self, player)
if not player then return end
local name = player:get_player_name() --self._passenger
-- passenger clicked the object => driver gets off the vehicle
if self._passenger == name then
self._passenger = nil
self._passengers[2] = nil
else
local max_seats = table.getn(self._seat_pos)
for i = max_seats,1,-1
do
if self._passengers[i] == name then
self._passengers[i] = nil
break
end
end
end
-- detach the player
if player then
local pos = player:get_pos()
player:set_detach()
if automobiles_lib.is_minetest then
if player_api.player_attached[name] then
player_api.player_attached[name] = nil
end
player_api.set_animation(player, "stand")
elseif automobiles_lib.is_mcl then
if mcl_player.player_attached[name] then
mcl_player.player_attached[name] = nil
end
mcl_player.player_set_animation(player, "stand")
end
player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
--remove_physics_override(player, {speed=1,gravity=1,jump=1})
end
end
function automobiles_lib.get_gauge_angle(value, initial_angle)
initial_angle = initial_angle or 90
local angle = value * 18
angle = angle - initial_angle
angle = angle * -1
return angle
end
function automobiles_lib.setText(self, vehicle_name)
local properties = self.object:get_properties()
local formatted = ""
if self.hp_max then
formatted = S(" Current hp: ") .. string.format(
"%.2f", self.hp_max
)
end
if properties then
properties.infotext = S("Nice @1 of @2.@3", vehicle_name, self.owner, formatted)
self.object:set_properties(properties)
end
end
function automobiles_lib.get_xz_from_hipotenuse(orig_x, orig_z, yaw, distance)
--cara, o minetest é bizarro, ele considera o eixo no sentido ANTI-HORÁRIO... Então pra equação funcionar, subtrair o angulo de 360 antes
yaw = math.rad(360) - yaw
local z = (math.cos(yaw)*distance) + orig_z
local x = (math.sin(yaw)*distance) + orig_x
return x, z
end
function automobiles_lib.remove_light(self)
if self._light_old_pos then
--force the remotion of the last light
minetest.add_node(self._light_old_pos, {name="air"})
self._light_old_pos = nil
end
end
function automobiles_lib.swap_node(self, pos)
local target_pos = pos
local have_air = false
local node = nil
local count = 0
while have_air == false and count <= 3 do
node = minetest.get_node(target_pos)
if node.name == "air" then
have_air = true
break
end
count = count + 1
target_pos.y = target_pos.y + 1
end
if have_air then
minetest.set_node(target_pos, {name='automobiles_lib:light'})
automobiles_lib.remove_light(self)
self._light_old_pos = target_pos
--remove after one second
--[[minetest.after(1,function(target_pos)
local node = minetest.get_node_or_nil(target_pos)
if node and node.name == "automobiles_lib:light" then
minetest.swap_node(target_pos, {name="air"})
end
end, target_pos)]]--
return true
end
return false
end
function automobiles_lib.put_light(self)
local pos = self.object:get_pos()
pos.y = pos.y + 1
local yaw = self.object:get_yaw()
local lx, lz = automobiles_lib.get_xz_from_hipotenuse(pos.x, pos.z, yaw, 10)
local light_pos = {x=lx, y=pos.y, z=lz}
local cast = minetest.raycast(pos, light_pos, false, false)
local thing = cast:next()
local was_set = false
while thing do
if thing.type == "node" then
local ipos = thing.intersection_point
if ipos then
was_set = automobiles_lib.swap_node(self, ipos)
end
end
thing = cast:next()
end
if was_set == false then
local n = minetest.get_node_or_nil(light_pos)
if n and n.name == 'air' then
automobiles_lib.swap_node(self, light_pos)
end
end
--[[local n = minetest.get_node_or_nil(light_pos)
--minetest.chat_send_player(name, n.name)
if n and n.name == 'air' then
minetest.set_node(pos, {name='automobiles_lib:light'})
--local timer = minetest.get_node_timer(pos)
--timer:set(10, 0)
minetest.after(0.3,function(pos)
local node = minetest.get_node_or_nil(pos)
if node and node.name == "automobiles_lib:light" then
minetest.swap_node(pos, {name="air"})
end
end, pos)
end]]--
end
function automobiles_lib.seats_destroy(self)
local max_seats = table.getn(self._passengers_base)
for i=1, max_seats do
if self._passengers_base[i] then self._passengers_base[i]:remove() end
end
end
function automobiles_lib.destroy(self, puncher)
automobiles_lib.remove_light(self)
if self.sound_handle then
minetest.sound_stop(self.sound_handle)
self.sound_handle = nil
end
if self.driver_name then
-- detach the driver first (puncher must be driver)
if puncher then
puncher:set_detach()
puncher:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
if automobiles_lib.is_minetest then
if player_api.player_attached[self.driver_name] then
player_api.player_attached[self.driver_name] = nil
end
player_api.set_animation(player, "stand")
elseif automobiles_lib.is_mcl then
if mcl_player.player_attached[self.driver_name] then
mcl_player.player_attached[self.driver_name] = nil
end
mcl_player.player_set_animation(player, "stand")
end
end
self.driver_name = nil
end
local pos = self.object:get_pos()
if self.front_suspension then self.front_suspension:remove() end
if self.lf_wheel then self.lf_wheel:remove() end
if self.rf_wheel then self.rf_wheel:remove() end
if self.rear_suspension then self.rear_suspension:remove() end
if self.lr_wheel then self.lr_wheel:remove() end
if self.rr_wheel then self.rr_wheel:remove() end
if self.steering then self.steering:remove() end
if self.steering_axis then self.steering_axis:remove() end
if self.driver_seat then self.driver_seat:remove() end
if self.passenger_seat then self.passenger_seat:remove() end
if self.fuel_gauge then self.fuel_gauge:remove() end
if self.lights then self.lights:remove() end
if self.r_lights then self.r_lights:remove() end
if self.reverse_lights then self.reverse_lights:remove() end
if self.turn_l_light then self.turn_l_light:remove() end
if self.turn_r_light then self.turn_r_light:remove() end
if self.rag then self.rag:remove() end --for buggy
if self.back_seat then self.back_seat:remove() end --for catrelle
if self.instruments then self.instruments:remove() end --for delorean
if self.normal_kit then self.normal_kit:remove() end
if self.rag_rect then self.rag_rect:remove() end --for roadster
automobiles_lib.seats_destroy(self)
automobiles_lib.destroy_inventory(self)
pos.y=pos.y+2
if automobiles_lib.can_collect_car == false then
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},'automobiles_lib:engine')
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},'automobiles_lib:wheel')
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},'automobiles_lib:wheel')
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},'automobiles_lib:wheel')
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},'automobiles_lib:wheel')
else
local lua_ent = self.object:get_luaentity()
local staticdata = lua_ent:get_staticdata(self)
local obj_name = lua_ent.name
local player = puncher
local stack = ItemStack(obj_name)
local stack_meta = stack:get_meta()
stack_meta:set_string("staticdata", staticdata)
if player then
local inv = player:get_inventory()
if inv then
if inv:room_for_item("main", stack) then
inv:add_item("main", stack)
else
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5}, stack)
end
end
else
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5}, stack)
end
end
self.object:remove()
end
function automobiles_lib.engine_set_sound_and_animation(self, _longit_speed)
--minetest.chat_send_all('test1 ' .. dump(self._engine_running) )
local abs_curr_long_speed = math.abs(self._longit_speed)
local abs_long_speed = math.abs(_longit_speed)
local scale = self._vehicle_power_scale
local range_spacing = 0.01
if self.sound_handle then
if (abs_curr_long_speed*scale > (abs_long_speed + range_spacing)*scale)
or ((abs_curr_long_speed + range_spacing)*scale < abs_long_speed*scale) then
--minetest.chat_send_all('test2')
automobiles_lib.engineSoundPlay(self)
end
end
end
function automobiles_lib.engineSoundPlay(self)
--sound
if self.sound_handle then minetest.sound_stop(self.sound_handle) end
if self.object then
local base_pitch = 1
if self._base_pitch then base_pitch = self._base_pitch end
local divisor = 6 --3 states, so 6 to make it more smooth
local multiplier = self._transmission_state or 1
local snd_pitch = base_pitch + ((base_pitch/divisor)*multiplier) + ((self._longit_speed/10)/2)
if self._transmission_state == 1 then
snd_pitch = base_pitch + (self._longit_speed/10)
end
self.sound_handle = minetest.sound_play({name = self._engine_sound},
{object = self.object, gain = 4,
pitch = snd_pitch,
max_hear_distance = 15,
loop = true,})
end
end
minetest.register_node("automobiles_lib:light", {
drawtype = "airlike",
--tile_images = {"automobiles_light.png"},
inventory_image = minetest.inventorycube("automobiles_light.png"),
paramtype = "light",
walkable = false,
is_ground_content = true,
light_propagates = true,
sunlight_propagates = true,
light_source = 14,
selection_box = {
type = "fixed",
fixed = {0, 0, 0, 0, 0, 0},
},
})
function automobiles_lib.set_paint(self, puncher, itmstck)
local is_admin = false
is_admin = minetest.check_player_privs(puncher, {server=true})
if not (self.owner == puncher:get_player_name() or is_admin == true) then
return false
end
local item_name = ""
if itmstck then item_name = itmstck:get_name() end
if item_name == "bike:painter" then
--painting with bike painter
local meta = itmstck:get_meta()
local colstr = meta:get_string("paint_color")
automobiles_lib.paint(self, colstr)
return true
else
--painting with dyes
local split = string.split(item_name, ":")
local color, indx, _
if split[1] then _,indx = split[1]:find('dye') end
--minetest.chat_send_all("item " .. dump(item_name))
if indx then
--[[for clr,_ in pairs(automobiles_lib.colors) do
local _,x = split[2]:find(clr)
if x then color = clr end
end]]--
--lets paint!!!!
local color = split[2] --(item_name:sub(indx+1)):gsub(":", "")
local colstr = automobiles_lib.colors[color]
--minetest.chat_send_all(color ..' '.. dump(colstr))
if colstr then
automobiles_lib.paint(self, colstr)
itmstck:set_count(itmstck:get_count()-1)
puncher:set_wielded_item(itmstck)
return true
end
-- end painting
end
end
return false
end
--painting
function automobiles_lib.paint(self, colstr, target_texture, second_painting_texture)
target_texture = target_texture or "automobiles_painting.png"
second_painting_texture = second_painting_texture or "automobiles_painting2.png"
if colstr then
self._color = colstr
local l_textures = self.initial_properties.textures
for _, texture in ipairs(l_textures) do
local indx = texture:find(target_texture)
if indx then
l_textures[_] = target_texture.."^[multiply:".. colstr
end
indx = texture:find(second_painting_texture)
if indx then
l_textures[_] = second_painting_texture.."^[multiply:".. colstr
end
end
self.object:set_properties({textures=l_textures})
end
end
function automobiles_lib.paint_with_mask(self, colstr, mask_colstr, target_texture, mask_texture)
--"("..steampunk_blimp.canvas_texture.."^[mask:steampunk_blimp_rotor_mask2.png)^(default_wood.png^[mask:steampunk_blimp_rotor_mask.png)"
target_texture = target_texture or "automobiles_painting.png"
if colstr then
self._color = colstr
self._det_color = mask_colstr
local l_textures = self.initial_properties.textures
for _, texture in ipairs(l_textures) do
local indx = texture:find(target_texture)
if indx then
--"("..target_texture.."^[mask:"..mask_texture..")"
l_textures[_] = "("..target_texture.."^[multiply:".. colstr..")^("..target_texture.."^[multiply:".. mask_colstr.."^[mask:"..mask_texture..")"
end
end
self.object:set_properties({textures=l_textures})
end
end
-- very basic transmission emulation for the car
function automobiles_lib.get_transmission_state(self, curr_speed, max_speed)
local retVal = 1
max_speed = max_speed or 100
max_speed = max_speed*self._vehicle_scale
curr_speed = curr_speed*self._vehicle_scale
if curr_speed >= (max_speed/4) then retVal = 2 end
if curr_speed >= (max_speed/2) then retVal = 3 end
return retVal
end
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "physics_lib.lua")
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "custom_physics.lua")
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "control.lua")
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "fuel_management.lua")
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "ground_detection.lua")
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "painter.lua")
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "inventory_management.lua")
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "formspecs.lua")
dofile(minetest.get_modpath("automobiles_lib") .. DIR_DELIM .. "entities.lua")
-- engine
minetest.register_craftitem("automobiles_lib:engine",{
description = S("Car Engine"),
inventory_image = "automobiles_engine.png",
})
-- engine
minetest.register_craftitem("automobiles_lib:wheel",{
description = S("Car Wheel"),
inventory_image = "automobiles_wheel_icon.png",
})
if minetest.get_modpath("default") then
minetest.register_craft({
output = "automobiles_lib:engine",
recipe = {
{"default:steel_ingot","default:steel_ingot","default:steel_ingot"},
{"default:steelblock","default:mese_block", "default:steelblock"},
}
})
minetest.register_craft({
output = "automobiles_lib:wheel",
recipe = {
{"default:tin_ingot", "default:steel_ingot", "default:tin_ingot"},
{"default:steel_ingot","default:steelblock", "default:steel_ingot"},
{"default:tin_ingot", "default:steel_ingot", "default:tin_ingot"},
}
})
end
minetest.register_entity('automobiles_lib:wheel',{
initial_properties = {
physical = false,
collide_with_objects=false,
pointable=false,
visual = "mesh",
mesh = "automobiles_wheel.b3d",
backface_culling = false,
textures = {"automobiles_black.png", "automobiles_metal.png"},
},
on_activate = function(self,std)
self.sdata = minetest.deserialize(std) or {}
if self.sdata.remove then self.object:remove() end
end,
get_staticdata=function(self)
self.sdata.remove=true
return minetest.serialize(self.sdata)
end,
})
minetest.register_privilege("valet_parking", {
description = S("Gives a valet parking priv for a player"),
give_to_singleplayer = true
})
minetest.register_chatcommand("transfer_vehicle", {
params = "<new_owner>",
description = S("Transfer the property of a vehicle to another player"),
privs = {interact=true},
func = function(name, param)
local player = minetest.get_player_by_name(name)
local target_player = minetest.get_player_by_name(param)
local attached_to = player:get_attach()
if attached_to ~= nil then
if target_player ~= nil then
local seat = attached_to:get_attach()
if seat ~= nil then
local entity = seat:get_luaentity()
if entity then
if entity.owner == name or minetest.check_player_privs(name, {protection_bypass=true}) then
entity.owner = param
minetest.chat_send_player(name,core.colorize('#00ff00', S(" >>> This vehicle now is property of: ")..param))
automobiles_lib.setText(entity, "vehicle")
else
minetest.chat_send_player(name,core.colorize('#ff0000', S(" >>> only the owner or moderators can transfer this vehicle")))
end
end
end
else
minetest.chat_send_player(name,core.colorize('#ff0000', S(" >>> the target player must be logged in")))
end
else
minetest.chat_send_player(name,core.colorize('#ff0000', S(" >>> you are not inside a vehicle to perform the command")))
end
end
})
--[[minetest.register_chatcommand("noobfy_the_vehicles", {
params = "<true/false>",
description = S("Enable/disable the NOOB mode for the vehicles"),
privs = {server=true},
func = function(name, param)
local command = param
if command == "false" then
automobiles_lib.noob_mode = false
automobiles_lib.extra_stepheight = 0
minetest.chat_send_player(name, S(">>> Noob mode is disabled - A restart is required to changes take full effect"))
else
automobiles_lib.noob_mode = true
automobiles_lib.extra_stepheight = 1
minetest.chat_send_player(name, S(">>> Noob mode is enabled - A restart is required to changes take full effect"))
end
local save = 2
if automobiles_lib.noob_mode == true then save = 1 end
storage:set_int("noob_mode", save)
end,
})]]--
-- Give to new player
if automobiles_lib.is_drift_game == true then
minetest.register_on_joinplayer(function(player)
local inv = player:get_inventory()
local car = "automobiles_beetle:beetle"
if core.get_modpath("automobiles_beetle") and not inv:contains_item("main", car) then inv:add_item("main", car) end
car = "automobiles_buggy:buggy"
if core.get_modpath("automobiles_buggy") and not inv:contains_item("main", car) then inv:add_item("main", car) end
car = "automobiles_catrelle:catrelle_4f"
if core.get_modpath("automobiles_catrelle") and not inv:contains_item("main", car) then inv:add_item("main", car) end
car = "automobiles_coupe:coupe"
if core.get_modpath("automobiles_coupe") and not inv:contains_item("main", car) then inv:add_item("main", car) end
car = "automobiles_delorean:delorean"
if core.get_modpath("automobiles_delorean") and not inv:contains_item("main", car) then inv:add_item("main", car) end
car = "automobiles_delorean:time_machine"
if core.get_modpath("automobiles_delorean") and not inv:contains_item("main", car) then inv:add_item("main", car) end
car = "automobiles_trans_am:trans_am"
if core.get_modpath("automobiles_trans_am") and not inv:contains_item("main", car) then inv:add_item("main", car) end
car = "automobiles_beetle:beetle_conv"
if core.get_modpath("automobiles_beetle") and not inv:contains_item("main", car) then inv:add_item("main", car) end
end)
end
local old_entities = {
"automobiles_buggy:pivot_mesh",
"automobiles_buggy:pointer",
"automobiles_catrelle:pivot_mesh",
"automobiles_catrelle:pointer",
"automobiles_catrelle:catrelle_tl",
"automobiles_coupe:pivot_mesh",
"automobiles_coupe:pointer",
"automobiles_delorean:pivot_mesh",
"automobiles_delorean:pointer",
"automobiles_roadster:pivot_mesh",
"automobiles_trans_am:pivot_mesh",
"automobiles_trans_am:pointer",
"automobiles_buggy:steering",
"automobiles_vespa:pivot_mesh",
"automobiles_motorcycle:pivot_mesh",
}
for _,entity_name in ipairs(old_entities) do
minetest.register_entity(":"..entity_name, {
on_activate = function(self, staticdata)
self.object:remove()
end,
})
end
@@ -0,0 +1,208 @@
local storage = automobiles_lib.storage
automobiles_lib.modname = core.get_current_modname()
--function to format formspec for mineclone. In case of minetest, just returns an empty string
local function get_itemslot_bg(a, b, c, d)
if automobiles_lib.is_mcl then
if mcl_formspec then
return mcl_formspec.get_itemslot_bg(a,b,c,d)
end
end
return ""
end
local function get_formspec_by_size(self, size)
local background = ""
local hotbar = ""
local is_minetest_game = automobiles_lib.is_minetest or false
if is_minetest_game then
background = background .. default.gui_bg .. default.gui_bg_img .. default.gui_slots
hotbar = default.get_hotbar_bg(0,4.85)
end
local default_inventory_formspecs = {
["2"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;3.0,0;3,1;]" .. get_itemslot_bg(3.0, 0, 2, 1) ..
"list[current_player;main;0,2;8,4;]" .. get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["3"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;2.5,0;3,1;]" .. get_itemslot_bg(2.5, 0, 3, 1) ..
"list[current_player;main;0,2;8,4;]" .. get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["4"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;2,0;4,1;]" .. get_itemslot_bg(2.0, 0, 4, 1) ..
"list[current_player;main;0,2;8,4;]" .. get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["6"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;1,0;6,1;]".. get_itemslot_bg(1.0, 0, 6, 1) ..
"list[current_player;main;0,2;8,4;]" .. get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["8"]="size[8,6]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0;8,1;]".. get_itemslot_bg(0, 0, 8, 1) ..
"list[current_player;main;0,2;8,4;]" .. get_itemslot_bg(0, 2, 8, 4) ..
"listring[]",
["12"]="size[8,7]".. background ..
"list[detached:" .. self._inv_id .. ";main;1,0;6,2;]".. get_itemslot_bg(1, 0, 6, 2) ..
"list[current_player;main;0,3;8,4;]" .. get_itemslot_bg(0, 3, 8, 4) ..
"listring[]",
["16"]="size[8,7]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0;8,2;]".. get_itemslot_bg(0, 0, 8, 2) ..
"list[current_player;main;0,3;8,4;]" .. get_itemslot_bg(0, 3, 8, 4) ..
"listring[]",
["24"]="size[8,8]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0;8,3;]".. get_itemslot_bg(0, 0, 8, 3) ..
"list[current_player;main;0,4;8,4;]" .. get_itemslot_bg(0, 4, 8, 4) ..
"listring[]",
["32"]="size[8,9]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0.3;8,4;]".. get_itemslot_bg(0, 0.3, 8, 4) ..
"list[current_player;main;0,5;8,4;]".. get_itemslot_bg(0, 5, 8, 4) ..
"listring[]" ..
hotbar,
["50"]="size[10,10]".. background ..
"list[detached:" .. self._inv_id .. ";main;0,0;10,5;]".. get_itemslot_bg(0, 0, 10, 5) ..
"list[current_player;main;1,6;8,4;]" .. get_itemslot_bg(1, 6, 8, 4) ..
"listring[]",
}
local formspec = default_inventory_formspecs[tostring(size)]
return formspec
end
local function inventory_id(maker_name)
local id= automobiles_lib.modname .. "_" .. maker_name .. "_"
for i=0,5 do
id=id..(math.random(0,9))
end
return id
end
function automobiles_lib.load_inventory(self)
if self._inv then
local inv_content = minetest.deserialize(storage:get_string(self._inv_id))
if inv_content then
self._inv:set_list("main", inv_content)
end
end
end
function automobiles_lib.save_inventory(self)
if self._inv then
local inv_content = self._inv:get_list("main")
if inv_content then
for k, v in pairs(inv_content) do
inv_content[k] = v:to_string()
end
local inv_content = minetest.serialize(inv_content)
storage:set_string(self._inv_id, inv_content)
end
end
end
function automobiles_lib.remove_inventory(self)
local inventory = automobiles_lib.get_inventory(self)
if inventory then
if inventory:is_empty("main") then
return minetest.remove_detached_inventory(self._inv_id)
else
local inv_content = inventory:get_list("main")
if inv_content then
local pos = self.object:get_pos()
for k, v in pairs(inv_content) do
local count = 0
for i = 0,v:get_count()-1,1
do
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},v:get_name())
count = count + 1
if count >= 5 then break end
end
end
end
return minetest.remove_detached_inventory(self._inv_id)
end
end
return false
end
function automobiles_lib.destroy_inventory(self)
automobiles_lib.remove_inventory(self)
storage:set_string(self._inv_id, nil)
end
--show inventory form to user
function automobiles_lib.show_vehicle_trunk_formspec(self, player, size)
if size then
local form = get_formspec_by_size(self, size)
if form then
minetest.show_formspec(player:get_player_name(), automobiles_lib.modname .. ":inventory",
form
)
end
end
end
function automobiles_lib.create_inventory(self, size, owner)
owner = owner or ""
if owner == "" then owner = self.owner end
if owner ~= nil and owner ~= "" then
if self._inv_id == "" then
self._inv_id = inventory_id(owner)
end
local vehicle_inv = minetest.create_detached_inventory(self._inv_id, {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
return count -- allow moving
end,
allow_put = function(inv, listname, index, stack, player)
return stack:get_count() -- allow putting
end,
allow_take = function(inv, listname, index, stack, player)
return stack:get_count() -- allow taking
end,
on_put = function(inv, toList, toIndex, stack, player)
automobiles_lib.save_inventory(self)
end,
on_take = function(inv, toList, toIndex, stack, player)
automobiles_lib.save_inventory(self)
end,
on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
automobiles_lib.save_inventory(self)
end,
})
if size >= 8 then
if vehicle_inv:set_size("main", size) then
vehicle_inv:set_width("main", 8)
end
else
vehicle_inv:set_size("main", size)
end
self._inv = vehicle_inv
automobiles_lib.load_inventory(self)
end
end
function automobiles_lib.get_inventory(self)
if self._inv then
return minetest.get_inventory({type="detached", name=self._inv_id})
end
return nil
end
function automobiles_lib.list_inventory(self)
local inventory = automobiles_lib.get_inventory(self)
if inventory then
local list = inventory.get_list("main")
minetest.chat_send_all(dump(list))
end
end
@@ -0,0 +1,25 @@
# textdomain: automobiles_lib
### init.lua ###
Go Offboard=Aussteigen
Lights=Lichter
Direction by mouse=Lenken mit Maus
Current hp: = Aktuelle Lp:
Nice @1 of @2.@3=Schöne(r) @1 von @2.@3
Car Engine=Motor
Car Wheel=Autoreifen
Gives a valet parking priv for a player=Gibt einen Parkservice für einen Spieler
Transfer the property of a vehicle to another player=Überträgt das Eigentum des Fahrzeuges an einem anderen Spieler
>>> This vehicle now is property of: = >>> Dieses Fahrzeug ist nun Eigentum von:
>>> only the owner or moderators can transfer this vehicle= >>> Nur der Eigentümer oder Moderator kann das Eigentum des Fahrzeuges übertragen
>>> the target player must be logged in= >>> der Zielspieler muß dafür eingeloggt sein.
>>> you are not inside a vehicle to perform the command= >>> du sitzt in keinem Fahrzeug um das Kommando auszuführen
Enable/disable the NOOB mode for the vehicles=Ein/Ausschalten des NOOB Moduses für die Fahrzeuge
>>> Noob mode is disabled - A restart is required to changes take full effect= >>> Noob Modus ist ausgeschalten - Ein Neustart für die Änderungen ist erforderlich
>>> Noob mode is enabled - A restart is required to changes take full effect= >>> Noob Modus ist eingeschalten - Ein Neustart für die Änderungen ist erforderlich
Preview=Vorschau
Set Hex=Gib Hexzahl
Set Color=Gib Farbe
Cancel=Abbrechen
### painter.lua ###
Automobiles Painter= Automobil Pinsel
Only the owner can paint this entity.=Nur der Eigentümer kann dieses Objekt einfärben.
@@ -0,0 +1,25 @@
# textdomain: automobiles_lib
### init.lua ###
Go Offboard=
Lights=
Direction by mouse=
Current hp: =
Nice @1 of @2.@3=
Car Engine=Aŭta Motoro
Car Wheel=Aŭta Rado
Gives a valet parking priv for a player=
Transfer the property of a vehicle to another player=
>>> This vehicle now is property of: =
>>> only the owner or moderators can transfer this vehicle=
>>> the target player must be logged in=
>>> you are not inside a vehicle to perform the command=
Enable/disable the NOOB mode for the vehicles=
>>> Noob mode is disabled - A restart is required to changes take full effect=
>>> Noob mode is enabled - A restart is required to changes take full effect=
Preview=
Set Hex=
Set Color=
Cancel=
### painter.lua ###
Automobiles Painter=Aŭta Pentrilo
Only the owner can paint this entity.=
@@ -0,0 +1,25 @@
# textdomain: automobiles_lib
### init.lua ###
Go Offboard=
Lights=
Direction by mouse=
Current hp: =
Nice @1 of @2.@3=
Car Engine=
Car Wheel=
Gives a valet parking priv for a player=
Transfer the property of a vehicle to another player=
>>> This vehicle now is property of: =
>>> only the owner or moderators can transfer this vehicle=
>>> the target player must be logged in=
>>> you are not inside a vehicle to perform the command=
Enable/disable the NOOB mode for the vehicles=
>>> Noob mode is disabled - A restart is required to changes take full effect=
>>> Noob mode is enabled - A restart is required to changes take full effect=
Preview=
Set Hex=
Set Color=
Cancel=
### painter.lua ###
Automobiles Painter=
Only the owner can paint this entity.=
+3
View File
@@ -0,0 +1,3 @@
name = automobiles_lib
depends=
optional_depends=player_api, mcl_formspec, mcl_player, emote, biofuel, dg_mapgen
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,181 @@
--[[
Copyright (C) 2022 Alexsandro Percy
Copyright (C) 2018 Hume2
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
]]--
local S = automobiles_lib.S
local function is_hex(color)
if not color or color:len() ~= 7 then return end
return color:match("#%x%x%x%x%x%x")
end
-- hex translation
local function hex_to_rgb(hex_value)
hex_value = hex_value:gsub("#","")
local rgb = {
r = tonumber("0x"..hex_value:sub(1,2)),
g = tonumber("0x"..hex_value:sub(3,4)),
b = tonumber("0x"..hex_value:sub(5,6)),
}
return rgb
end
local function rgb_to_hex(rgb)
return string.format("#%02X%02X%02X", rgb.r, rgb.g, rgb.b)
end
-- Painter formspec
local function painter_form(player, rgb)
local color = rgb_to_hex(rgb)
minetest.show_formspec(player:get_player_name(), "automobiles_lib:painter",
-- Init formspec
"formspec_version[3]" .. -- Minetest 5.2+
"size[5.6,5.2;true]" ..
"position[0.5,0.45]" ..
-- Color preview
"image[0.2,0.2;2,2;automobiles_painting.png^[colorize:" .. color .. ":255]" ..
"label[0.3,1.2;" .. S("Preview") .. "]" ..
-- Hex field
"field_close_on_enter[hex;false]" ..
"field[2.4,0.2;3,0.8;hex;;" .. color .. "]" ..
"button[2.4,1;3,0.8;set_hex;" .. S("Set Hex") .. "]" ..
-- RGB sliders
"container[0,2.4]" ..
"scrollbaroptions[min=0;max=255;smallstep=20]" ..
"box[0.4,0;4.77,0.38;red]" ..
"label[0.2,0.2;-]" ..
"scrollbar[0.4,0;4.8,0.4;horizontal;r;" .. rgb.r .."]" ..
"label[5.2,0.2;+]" ..
"box[0.4,0.6;4.77,0.38;green]" ..
"label[0.2,0.8;-]" ..
"scrollbar[0.4,0.6;4.8,0.4;horizontal;g;" .. rgb.g .."]" ..
"label[5.2,0.8;+]" ..
"box[0.4,1.2;4.77,0.38;blue]" ..
"label[0.2,1.4;-]" ..
"scrollbar[0.4,1.2;4.8,0.4;horizontal;b;" .. rgb.b .. "]" ..
"label[5.2,1.4;+]" ..
"container_end[]" ..
-- Bottom buttons
"button_exit[0.2,4.2;2.8,0.8;set_color;" .. S("Set Color") .. "]" ..
"button_exit[3.2,4.2;2.2,0.8;quit;" .. S("Cancel") .. "]"
)
end
local automobiles_being_painted = {}
local formspec_timers = {}
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "automobiles_lib:painter" then
if formspec_timers[player] then
formspec_timers[player]:cancel()
formspec_timers[player] = nil
end
local function parse_scrollbar_field(value)
value = value or ""
local num = math.floor(tonumber((value:gsub(".*:", ""))) or 0)
if num > 255 or num < 0 then num = 0 end
return num
end
local rgb = {
r = parse_scrollbar_field(fields.r),
g = parse_scrollbar_field(fields.g),
b = parse_scrollbar_field(fields.b),
}
if fields.set_hex or fields.key_enter then
if is_hex(fields.hex) then
painter_form(player, hex_to_rgb(fields.hex))
else
painter_form(player, rgb)
end
elseif fields.set_color then
local object_ref = automobiles_being_painted[player]
if object_ref and object_ref:get_pos() then
local luaentity = object_ref:get_luaentity()
luaentity:_change_color(rgb_to_hex(rgb))
end
automobiles_being_painted[player] = nil
elseif fields.r and fields.r:find("^CHG") or
fields.g and fields.g:find("^CHG") or
fields.b and fields.b:find("^CHG") then -- Has a scrollbar changed?
formspec_timers[player] = minetest.after(0.2, function(itemstack, name)
local player = minetest.get_player_by_name(name)
if player then
painter_form(player, rgb)
end
formspec_timers[player] = nil
end, itemstack, player:get_player_name())
end
if fields.quit then
automobiles_being_painted[player] = nil
end
return true
end
end)
-- Make the actual thingy
minetest.register_tool("automobiles_lib:painter", {
description = S("Automobiles Painter"),
inventory_image = "automobiles_painter.png",
wield_scale = {x = 2, y = 2, z = 1},
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type == "object" and not pointed_thing.ref:is_player() then
local luaentity = pointed_thing.ref:get_luaentity()
if luaentity and type(luaentity._change_color) == "function" then
local player_name = user:get_player_name()
if not luaentity.owner or luaentity.owner == player_name then
automobiles_being_painted[user] = pointed_thing.ref
local color = luaentity._color
local rgb = is_hex(color) and hex_to_rgb(color) or {r = 0, g = 0, b = 0}
painter_form(user, rgb)
else
minetest.chat_send_player(player_name, S("Only the owner can paint this entity."))
end
end
end
end
})
minetest.register_on_leaveplayer(function(player, timed_out)
automobiles_being_painted[player] = nil
end)
minetest.register_craft({
output = "automobiles_lib:painter",
recipe = {
{"", "default:steel_ingot", ""},
{"dye:red", "dye:green", "dye:blue"},
{"", "default:steel_ingot", ""},
},
})
+175
View File
@@ -0,0 +1,175 @@
local abs = math.abs
local pi = math.pi
local floor = math.floor
local ceil = math.ceil
local random = math.random
local sqrt = math.sqrt
local max = math.max
local min = math.min
local tan = math.tan
local pow = math.pow
local sign = function(x)
return (x<0) and -1 or 1
end
function automobiles_lib.rot_to_dir(rot) -- keep rot within <-pi/2,pi/2>
local dir = minetest.yaw_to_dir(rot.y)
dir.y = dir.y+tan(rot.x)*vector.length(dir)
return vector.normalize(dir)
end
function automobiles_lib.dir_to_rot(v,rot)
rot = rot or {x=0,y=0,z=0}
return {x = (v.x==0 and v.y==0 and v.z==0) and rot.x or math.atan2(v.y,vector.length({x=v.x,y=0,z=v.z})),
y = (v.x==0 and v.z==0) and rot.y or minetest.dir_to_yaw(v),
z=rot.z}
end
function automobiles_lib.pos_shift(pos,vec) -- vec components can be omitted e.g. vec={y=1}
vec.x=vec.x or 0
vec.y=vec.y or 0
vec.z=vec.z or 0
return {x=pos.x+vec.x,
y=pos.y+vec.y,
z=pos.z+vec.z}
end
function automobiles_lib.get_stand_pos(thing) -- thing can be luaentity or objectref.
local pos = {}
local colbox = {}
if type(thing) == 'table' then
pos = thing.object:get_pos()
colbox = thing.object:get_properties().collisionbox
elseif type(thing) == 'userdata' then
pos = thing:get_pos()
colbox = thing:get_properties().collisionbox
else
return false
end
return automobiles_lib.pos_shift(pos,{y=colbox[2]+0.01}), pos
end
function automobiles_lib.get_node_pos(pos)
return {
x=floor(pos.x+0.5),
y=floor(pos.y+0.5),
z=floor(pos.z+0.5),
}
end
function automobiles_lib.nodeatpos(pos)
local node = minetest.get_node_or_nil(pos)
if node then return minetest.registered_nodes[node.name] end
end
function automobiles_lib.minmax(v,m)
return min(abs(v),m)*sign(v)
end
function automobiles_lib.set_acceleration(thing,vec,limit)
limit = limit or 100
if type(thing) == 'table' then thing=thing.object end
vec.x=automobiles_lib.minmax(vec.x,limit)
vec.y=automobiles_lib.minmax(vec.y,limit)
vec.z=automobiles_lib.minmax(vec.z,limit)
thing:set_acceleration(vec)
end
function automobiles_lib.actfunc(self, staticdata, dtime_s)
self.logic = self.logic or self.brainfunc
self.physics = self.physics or automobiles_lib.physics
self.lqueue = {}
self.hqueue = {}
self.nearby_objects = {}
self.nearby_players = {}
self.pos_history = {}
self.path_dir = 1
self.time_total = 0
self.water_drag = self.water_drag or 1
local sdata = minetest.deserialize(staticdata)
if sdata then
for k,v in pairs(sdata) do
self[k] = v
end
end
if self.textures==nil then
local prop_tex = self.object:get_properties().textures
if prop_tex then self.textures=prop_tex end
end
if not self.memory then -- this is the initial activation
self.memory = {}
-- texture variation
if #self.textures > 1 then self.texture_no = random(#self.textures) end
end
if self.timeout and ((self.timeout>0 and dtime_s > self.timeout and next(self.memory)==nil) or
(self.timeout<0 and dtime_s > abs(self.timeout))) then
self.object:remove()
end
-- apply texture
if self.textures and self.texture_no then
local props = {}
props.textures = {self.textures[self.texture_no]}
self.object:set_properties(props)
end
--hp
self.max_hp = self.max_hp or 10
self.hp = self.hp or self.max_hp
--armor
if type(self.armor_groups) ~= 'table' then
self.armor_groups={}
end
self.armor_groups.immortal = 1
self.object:set_armor_groups(self.armor_groups)
self.buoyancy = self.buoyancy or 0
self.oxygen = self.oxygen or self.lung_capacity
self.lastvelocity = {x=0,y=0,z=0}
end
function automobiles_lib.get_box_height(self)
if type(self) == 'table' then self = self.object end
local colbox = self:get_properties().collisionbox
local height = 0.1
if colbox then height = colbox[5]-colbox[2] end
return height > 0 and height or 0.1
end
function automobiles_lib.stepfunc(self,dtime,colinfo)
self.dtime = math.min(dtime,0.2)
self.colinfo = colinfo
self.height = automobiles_lib.get_box_height(self)
-- physics comes first
local vel = self.object:get_velocity()
if colinfo then
self.isonground = colinfo.touching_ground
else
if self.lastvelocity.y==0 and vel.y==0 then
self.isonground = true
else
self.isonground = false
end
end
self:physics()
if self.logic then
self:logic()
end
self.lastvelocity = self.object:get_velocity()
self.time_total=self.time_total+self.dtime
end
@@ -0,0 +1,8 @@
# all settings for client menu or in minetest.conf on servers
# make cars collectable
collect_automobiles (Collect vehicles to inventory) bool true
noob_mode (make automobiles climb entire blocks) bool false
motorcycle_anim_mode (enable motorcycle pilot animations) bool true
speed_limit (limit all vehicles to a speed - useful for lag servers) int 500
@@ -0,0 +1 @@
horn - SoundEffects by : https://youtu.be/FQc5zRy6wBU
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB