first
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 APercy
|
||||
|
||||
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.
|
|
@ -1 +1,21 @@
|
|||
# minekart
|
||||
Minetest 5.2 mod: MineKart
|
||||
========================================
|
||||
|
||||
This is the "MineKart", a mod that provides a little race car.
|
||||
It can be painted using dye of any color you want, you must punch the seat with the dye.
|
||||
|
||||
like explaned at checkpoints mod:
|
||||
Your kart starts with no fuel. If you are not in a race or your car was reseted by the black white flag, you can put biofuel on it. You need to attach himself to the car with the right button and punch the car with the biofuel gallon. Ok. But when you are in a race, you can only refuel at a refuel zone, marked by the fuel pistol icon. This zones have a radius of 5 blocks. To refuel you need stop, turn the engine off and punch the gallon against the kart. So you turn engine running again and go to the victory... or not!
|
||||
|
||||
-----------------------
|
||||
It uses some code from Sailing Kit (by TheTermos)
|
||||
|
||||
License of source code:
|
||||
MIT (see file LICENSE)
|
||||
|
||||
License of media (textures and sounds):
|
||||
---------------------------------------
|
||||
engine.ogg, drift.ogg and collision.ogg by APercy. See License file
|
||||
|
||||
Kart model by APercy. See License file
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
default
|
||||
biofuel
|
|
@ -0,0 +1,672 @@
|
|||
--
|
||||
-- constants
|
||||
--
|
||||
minekart={}
|
||||
minekart.LONGIT_DRAG_FACTOR = 0.16*0.16
|
||||
minekart.LATER_DRAG_FACTOR = 30.0
|
||||
minekart.gravity = (tonumber(minetest.settings:get("movement_gravity")) or 9.8)
|
||||
|
||||
--two variables to control sound event
|
||||
minekart.last_time_collision_snd = 0
|
||||
minekart.last_time_drift_snd =0
|
||||
minekart.last_fuel_display =0
|
||||
|
||||
--kart colors
|
||||
minekart.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',
|
||||
}
|
||||
|
||||
dofile(minetest.get_modpath("minekart") .. DIR_DELIM .. "minekart_control.lua")
|
||||
dofile(minetest.get_modpath("minekart") .. DIR_DELIM .. "minekart_fuel_management.lua")
|
||||
|
||||
--
|
||||
-- helpers and co.
|
||||
--
|
||||
|
||||
local creative_exists = minetest.global_exists("creative")
|
||||
|
||||
function minekart.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 minekart.dot(v1,v2)
|
||||
return (v1.x*v2.x)+(v1.y*v2.y)+(v1.z*v2.z)
|
||||
end
|
||||
|
||||
function minekart.sign(n)
|
||||
return n>=0 and 1 or -1
|
||||
end
|
||||
|
||||
function minekart.minmax(v,m)
|
||||
return math.min(math.abs(v),m)*minekart.sign(v)
|
||||
end
|
||||
|
||||
--painting
|
||||
function minekart.paint(self, colstr)
|
||||
if colstr then
|
||||
self._color = colstr
|
||||
local l_textures = self.initial_properties.textures
|
||||
for _, texture in ipairs(l_textures) do
|
||||
local i,indx = texture:find('kart_painting.png')
|
||||
if indx then
|
||||
l_textures[_] = "kart_painting.png^[multiply:".. colstr
|
||||
end
|
||||
end
|
||||
self.object:set_properties({textures=l_textures})
|
||||
end
|
||||
end
|
||||
|
||||
-- destroy the kart
|
||||
function minekart.destroy(self, puncher)
|
||||
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)
|
||||
puncher:set_detach()
|
||||
puncher:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
||||
player_api.player_attached[self.driver_name] = nil
|
||||
-- player should stand again
|
||||
player_api.set_animation(puncher, "stand")
|
||||
self.driver_name = nil
|
||||
end
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
if self.l_wheel then self.l_wheel:remove() end
|
||||
if self.r_wheel then self.r_wheel:remove() end
|
||||
if self.steering_base then self.steering_base:remove() end
|
||||
if self.steering then self.steering:remove() end
|
||||
if self.dir_bar then self.dir_bar:remove() end
|
||||
|
||||
self.object:remove()
|
||||
|
||||
pos.y=pos.y+2
|
||||
|
||||
minetest.add_item({x=pos.x+math.random()-0.5,y=pos.y,z=pos.z+math.random()-0.5},'minekart:kart')
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- entity
|
||||
--
|
||||
|
||||
minetest.register_entity('minekart:left_wheel',{
|
||||
initial_properties = {
|
||||
physical = false,
|
||||
collide_with_objects=false,
|
||||
pointable=false,
|
||||
visual = "mesh",
|
||||
mesh = "kart_left_wheel.b3d",
|
||||
textures = {"kart_black.png", "kart_black.png", "kart_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_entity('minekart:right_wheel',{
|
||||
initial_properties = {
|
||||
physical = false,
|
||||
collide_with_objects=false,
|
||||
pointable=false,
|
||||
visual = "mesh",
|
||||
mesh = "kart_right_wheel.b3d",
|
||||
textures = {"kart_black.png", "kart_black.png", "kart_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_entity('minekart:steering_wheel_axis',{
|
||||
initial_properties = {
|
||||
physical = false,
|
||||
collide_with_objects=false,
|
||||
pointable=false,
|
||||
visual = "mesh",
|
||||
mesh = "kart_steering_base.b3d",
|
||||
textures = {"kart_black.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_entity('minekart:steering_wheel',{
|
||||
initial_properties = {
|
||||
physical = false,
|
||||
collide_with_objects=false,
|
||||
pointable=false,
|
||||
visual = "mesh",
|
||||
mesh = "kart_steering.b3d",
|
||||
textures = {"kart_u_black.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_entity('minekart:dir_bar',{
|
||||
initial_properties = {
|
||||
physical = false,
|
||||
collide_with_objects=false,
|
||||
pointable=false,
|
||||
visual = "mesh",
|
||||
mesh = "kart_dir_bar.b3d",
|
||||
textures = {"kart_black.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_entity("minekart:kart", {
|
||||
initial_properties = {
|
||||
physical = true,
|
||||
collide_with_objects = true,
|
||||
collisionbox = {-0.6, 0.0, -0.6, 0.6, 1, 0.6},
|
||||
selectionbox = {-0.8, 0.0, -0.8, 0.8, 0.1, 0.8},
|
||||
stepheight = 0.5,
|
||||
visual = "mesh",
|
||||
mesh = "kart_body.b3d",
|
||||
textures = {"kart_black.png", "kart_painting.png", "kart_painting.png", "kart_red.png", "kart_black.png", "kart_white.png", "kart_black.png", "kart_black.png", "kart_black.png", "kart_black.png", "kart_metal.png", "kart_black.png", "kart_black.png", "kart_metal.png", "kart_black.png", "kart_metal.png",},
|
||||
},
|
||||
--textures = {},
|
||||
driver_name = nil,
|
||||
sound_handle = nil,
|
||||
owner = "",
|
||||
static_save = true,
|
||||
infotext = "A very nice kart!",
|
||||
hp = 50,
|
||||
_lastvelocity = vector.new(),
|
||||
_color = "#FFFFFF",
|
||||
_steering_angle = 0,
|
||||
_engine_running = false,
|
||||
_last_checkpoint = "",
|
||||
_total_laps = -1,
|
||||
_race_id = "",
|
||||
_energy = 0.001,
|
||||
|
||||
get_staticdata = function(self) -- unloaded/unloads ... is now saved
|
||||
return minetest.serialize({
|
||||
--stored_owner = self.owner,
|
||||
stored_hp = self.hp,
|
||||
stored_color = self._color,
|
||||
stored_steering = self._steering_angle,
|
||||
stored_energy = self._energy,
|
||||
--race data
|
||||
stored_last_checkpoint = self._last_checkpoint,
|
||||
stored_total_laps = self._total_laps,
|
||||
stored_race_id = self._race_id,
|
||||
})
|
||||
end,
|
||||
|
||||
on_activate = function(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._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
|
||||
end
|
||||
|
||||
self.object:set_animation({x = 1, y = 8}, 0, 0, true)
|
||||
|
||||
minekart.paint(self, self._color)
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
local l_wheel=minetest.add_entity(pos,'minekart:left_wheel')
|
||||
l_wheel:set_attach(self.object,'',{x=-6,y=2.1,z=10.7},{x=0,y=0,z=0})
|
||||
-- set the animation once and later only change the speed
|
||||
l_wheel:set_animation({x = 1, y = 8}, 0, 0, true)
|
||||
self.l_wheel = l_wheel
|
||||
|
||||
local r_wheel=minetest.add_entity(pos,'minekart:right_wheel')
|
||||
r_wheel:set_attach(self.object,'',{x=6,y=2.1,z=10.7},{x=0,y=0,z=0})
|
||||
-- set the animation once and later only change the speed
|
||||
r_wheel:set_animation({x = 1, y = 8}, 0, 0, true)
|
||||
self.r_wheel = r_wheel
|
||||
|
||||
local steering_axis=minetest.add_entity(pos,'minekart:steering_wheel_axis')
|
||||
steering_axis:set_attach(self.object,'',{x=0,y=7.49,z=7},{x=45,y=0,z=0})
|
||||
self.steering_axis = steering_axis
|
||||
|
||||
local steering=minetest.add_entity(self.steering_axis:get_pos(),'minekart:steering_wheel')
|
||||
steering:set_attach(self.steering_axis,'',{x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||
self.steering = steering
|
||||
|
||||
local dir_bar=minetest.add_entity(self.object:get_pos(),'minekart:dir_bar')
|
||||
dir_bar:set_attach(self.object,'',{x=0,y=0,z=-4},{x=0,y=0,z=0})
|
||||
self.dir_bar = dir_bar
|
||||
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
|
||||
self.object:set_acceleration(vector.multiply(minekart.vector_up, -minekart.gravity))
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
--[[sound play control]]--
|
||||
minekart.last_time_collision_snd = minekart.last_time_collision_snd + dtime
|
||||
if minekart.last_time_collision_snd > 1 then minekart.last_time_collision_snd = 1 end
|
||||
minekart.last_time_drift_snd = minekart.last_time_drift_snd + dtime
|
||||
if minekart.last_time_drift_snd > 1 then minekart.last_time_drift_snd = 1 end
|
||||
--[[end sound control]]--
|
||||
|
||||
local accel_y = self.object:get_acceleration().y
|
||||
local rotation = self.object:get_rotation()
|
||||
local yaw = rotation.y
|
||||
local newyaw=yaw
|
||||
local pitch = rotation.x
|
||||
local newpitch = pitch
|
||||
local roll = rotation.z
|
||||
local newroll=roll
|
||||
|
||||
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 = minekart.dot(velocity,hull_direction)
|
||||
local fuel_weight_factor = (5 - self._energy)/5000
|
||||
local longit_drag = vector.multiply(hull_direction,(longit_speed*longit_speed) * (minekart.LONGIT_DRAG_FACTOR - fuel_weight_factor) * -1 * minekart.sign(longit_speed))
|
||||
|
||||
local later_speed = minekart.dot(velocity,nhdir)
|
||||
local later_drag = vector.multiply(nhdir,later_speed*later_speed*minekart.LATER_DRAG_FACTOR*-1*minekart.sign(later_speed))
|
||||
|
||||
local accel = vector.add(longit_drag,later_drag)
|
||||
|
||||
local vel = self.object:get_velocity()
|
||||
|
||||
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 player_attach == self.object then is_attached = true end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if is_attached then --and self.driver_name == self.owner then
|
||||
local curr_pos = self.object:get_pos()
|
||||
local impact = minekart.get_hipotenuse_value(vel, self._lastvelocity)
|
||||
if impact > 1 then
|
||||
--self.damage = self.damage + impact --sum the impact value directly to damage meter
|
||||
if minekart.last_time_collision_snd > 0.3 then
|
||||
minekart.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
|
||||
minekart.destroy(self)
|
||||
end]]--
|
||||
end
|
||||
|
||||
local min_later_speed = 0.9
|
||||
if (later_speed > min_later_speed or later_speed < -min_later_speed) and minekart.last_time_drift_snd > 0.6 then
|
||||
minekart.last_time_drift_snd = 0
|
||||
minetest.sound_play("drifting", {
|
||||
to_player = self.driver_name,
|
||||
pos = curr_pos,
|
||||
max_hear_distance = 5,
|
||||
gain = 1.0,
|
||||
fade = 0.0,
|
||||
pitch = 1.0,
|
||||
ephemeral = true,
|
||||
})
|
||||
end
|
||||
|
||||
--control
|
||||
accel = minekart.kart_control(self, dtime, hull_direction, longit_speed, longit_drag, later_drag, accel) or vel
|
||||
else
|
||||
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
|
||||
self.object:set_animation_frame_speed(longit_speed * 10)
|
||||
self.l_wheel:set_animation_frame_speed(longit_speed * (10 - angle_factor))
|
||||
self.r_wheel:set_animation_frame_speed(longit_speed * (10 + angle_factor))
|
||||
|
||||
self.steering:set_attach(self.steering_axis,'',{x=0,y=0,z=0},{x=0,y=0,z=self._steering_angle*2})
|
||||
self.l_wheel:set_attach(self.object,'',{x=-6,y=2.1,z=10.7},{x=0,y=-self._steering_angle-angle_factor,z=0})
|
||||
self.dir_bar:set_attach(self.object,'',{x=(-1*(self._steering_angle / 25)),y=0,z=-4},{x=0,y=0,z=0})
|
||||
self.r_wheel:set_attach(self.object,'',{x= 6,y=2.1,z=10.7},{x=0,y=-self._steering_angle+angle_factor,z=0})
|
||||
|
||||
if math.abs(self._steering_angle)>5 then
|
||||
local turn_rate = math.rad(60)
|
||||
newyaw = yaw + dtime*(1 - 1 / (math.abs(longit_speed) + 1)) * self._steering_angle / 30 * turn_rate * minekart.sign(longit_speed)
|
||||
end
|
||||
|
||||
--[[if player and is_attached then
|
||||
player:set_look_horizontal(newyaw)
|
||||
end]]--
|
||||
|
||||
newpitch = velocity.y * math.rad(6)
|
||||
|
||||
--add gravity accell
|
||||
accel = vector.add(accel, vector.multiply(minekart.vector_up, -minekart.gravity)) -- * dtime))
|
||||
|
||||
--[[
|
||||
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 = 10
|
||||
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
|
||||
|
||||
self.object:set_acceleration(accel)
|
||||
|
||||
if newyaw~=yaw or newpitch~=pitch then self.object:set_rotation({x=newpitch,y=newyaw,z=0}) end
|
||||
|
||||
--saves last velocity for collision detection (abrupt stop)
|
||||
self._lastvelocity = self.object:get_velocity()
|
||||
|
||||
-- calculate energy consumption --
|
||||
----------------------------------
|
||||
if self._energy > 0 and self._engine_running then
|
||||
local zero_reference = vector.new()
|
||||
local acceleration = minekart.get_hipotenuse_value(accel, zero_reference)
|
||||
local consumed_power = acceleration/200000
|
||||
self._energy = self._energy - consumed_power;
|
||||
|
||||
--report fuel
|
||||
if self._energy < 0.75 and minekart.last_fuel_display == 0 then
|
||||
minekart.last_fuel_display = 50
|
||||
minetest.chat_send_player(self.driver_name, "fuel now bellow 75%")
|
||||
end
|
||||
if self._energy < 0.5 and minekart.last_fuel_display == 50 then
|
||||
minekart.last_fuel_display = 25
|
||||
minetest.chat_send_player(self.driver_name, "fuel now bellow 50%")
|
||||
end
|
||||
if self._energy < 0.25 and minekart.last_fuel_display == 25 then
|
||||
minekart.last_fuel_display = 10
|
||||
minetest.chat_send_player(self.driver_name, "fuel now bellow 25%")
|
||||
end
|
||||
if self._energy < 0.1 and minekart.last_fuel_display == 10 then
|
||||
minekart.last_fuel_display = 0
|
||||
minetest.chat_send_player(self.driver_name, "Danger! Fuel now bellow 10%")
|
||||
end
|
||||
end
|
||||
if self._energy <= 0 and self._engine_running then
|
||||
self._engine_running = false
|
||||
if self.sound_handle then minetest.sound_stop(self.sound_handle) end
|
||||
minetest.chat_send_player(self.driver_name, "Out of fuel")
|
||||
end
|
||||
----------------------------
|
||||
-- end energy consumption --
|
||||
end,
|
||||
|
||||
on_punch = function(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
|
||||
if puncher:get_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 in 2 situations:
|
||||
1- if my car doesn't have a race_id, ok, punch it anywhere with bio fuel while player attached and ok
|
||||
2- if it have a race_id, you must stop near a "checkpoints:refuel" node to punch with the biofuel
|
||||
]]--
|
||||
local velocity = self.object:get_velocity()
|
||||
local speed = minekart.get_hipotenuse_value(vector.new(), velocity)
|
||||
if is_attached == true and item_name == "biofuel:biofuel" and self._engine_running == false and speed <= 0.1 then
|
||||
local pos = self.object:get_pos()
|
||||
if minetest.find_node_near(pos, 5, {"checkpoints:refuel"}) ~= nil then
|
||||
minekart_load_fuel(self, puncher:get_player_name())
|
||||
else
|
||||
if self._race_id == "" then
|
||||
minekart_load_fuel(self, puncher:get_player_name())
|
||||
end
|
||||
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
|
||||
|
||||
--painting
|
||||
local _,indx = item_name:find('dye:')
|
||||
if indx then
|
||||
|
||||
--lets paint!!!!
|
||||
local color = item_name:sub(indx+1)
|
||||
local colstr = minekart.colors[color]
|
||||
--minetest.chat_send_all(color ..' '.. dump(colstr))
|
||||
if colstr then
|
||||
minekart.paint(self, colstr)
|
||||
itmstck:set_count(itmstck:get_count()-1)
|
||||
puncher:set_wielded_item(itmstck)
|
||||
end
|
||||
-- end painting
|
||||
|
||||
else -- deal damage
|
||||
if not self.driver and toolcaps and toolcaps.damage_groups and toolcaps.damage_groups.fleshy then
|
||||
self.hp = self.hp - 10
|
||||
minetest.sound_play("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
|
||||
minekart.destroy(self)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
on_rightclick = function(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
|
||||
self._engine_running = false
|
||||
|
||||
-- driver clicked the object => driver gets off the vehicle
|
||||
self.driver_name = nil
|
||||
-- sound and animation
|
||||
if self.sound_handle then
|
||||
minetest.sound_stop(self.sound_handle)
|
||||
self.sound_handle = nil
|
||||
end
|
||||
|
||||
self.object:set_animation_frame_speed(0)
|
||||
|
||||
-- detach the player
|
||||
clicker:set_detach()
|
||||
player_api.player_attached[name] = nil
|
||||
clicker:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||
player_api.set_animation(clicker, "stand")
|
||||
self.driver = nil
|
||||
self.object:set_acceleration(vector.multiply(minekart.vector_up, -minekart.gravity))
|
||||
|
||||
elseif not self.driver_name then
|
||||
-- no driver => clicker is new driver
|
||||
self.driver_name = name
|
||||
|
||||
-- temporary------
|
||||
self.hp = 50 -- why? cause I can desist from destroy
|
||||
------------------
|
||||
|
||||
-- attach the driver
|
||||
clicker:set_attach(self.object, "", {x = 0, y = 3, z = 2}, {x = 0, y = 0, z = 0})
|
||||
clicker:set_eye_offset({x = 0, y = 0, z = 2.5}, {x = 0, y = 0, z = -14})
|
||||
player_api.player_attached[name] = true
|
||||
-- make the driver sit
|
||||
minetest.after(0.2, function()
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player then
|
||||
player_api.set_animation(player, "sit")
|
||||
end
|
||||
end)
|
||||
self.object:set_acceleration(vector.multiply(minekart.vector_up, -minekart.gravity))
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
--
|
||||
-- items
|
||||
--
|
||||
|
||||
-- Kart
|
||||
minetest.register_craftitem("minekart:kart", {
|
||||
description = "Kart",
|
||||
inventory_image = "motorboat_inv.png",
|
||||
liquids_pointable = false,
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return
|
||||
end
|
||||
|
||||
local pointed_pos = pointed_thing.above
|
||||
local node_below = minetest.get_node(pointed_pos).name
|
||||
local nodedef = minetest.registered_nodes[node_below]
|
||||
--pointed_pos.y=pointed_pos.y+0.2
|
||||
local kart = minetest.add_entity(pointed_pos, "minekart:kart")
|
||||
if kart and placer then
|
||||
--[[local ent = kart:get_luaentity()
|
||||
local owner = placer:get_player_name()
|
||||
ent.owner = owner]]--
|
||||
kart:set_yaw(placer:get_look_horizontal())
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
--
|
||||
-- crafting
|
||||
--
|
||||
|
||||
if minetest.get_modpath("default") then
|
||||
minetest.register_craft({
|
||||
output = "minekart:kart",
|
||||
recipe = {
|
||||
{"default:obsidian_block", "default:steel_ingot", "default:obsidian_block"},
|
||||
{"default:steel_ingot", "default:mese_block", "default:steel_ingot"},
|
||||
{"default:obsidian_block", "default:steel_ingot", "default:obsidian_block"},
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
--global constants
|
||||
|
||||
minekart.karttest_last_time_command = 0
|
||||
minekart.vector_up = vector.new(0, 1, 0)
|
||||
minekart.max_acc_factor = 8.5
|
||||
minekart.max_speed = 25
|
||||
|
||||
function minekart.check_road_is_ok(obj)
|
||||
local pos_below = obj:get_pos()
|
||||
pos_below.y = pos_below.y - 0.1
|
||||
local node_below = minetest.get_node(pos_below).name
|
||||
--minetest.chat_send_all(node_below)
|
||||
local nodedef = minetest.registered_nodes[node_below]
|
||||
if nodedef.liquidtype == "none" then
|
||||
local slow_nodes = {['default:dirt'] = 0.3,
|
||||
['default:dirt_with_rainforest_litter'] = 0.3,
|
||||
['default:dirt_with_coniferous_litter'] = 0.3,
|
||||
['default:permafrost'] = 0.3,
|
||||
['default:permafrost_with_moss'] = 0.3,
|
||||
['default:permafrost_with_stones'] = 0.3,
|
||||
['default:dirt_with_grass'] = 0.2,
|
||||
['farming:soil'] = 0.2,
|
||||
['farming:soil_wet'] = 0.2,
|
||||
['farming:desert_sand_soil'] = 0.2,
|
||||
['farming:desert_sand_soil_wet'] = 0.2,
|
||||
['farming:dry_soil'] = 0.2,
|
||||
['farming:dry_soil_wet'] = 0.2,
|
||||
['default:sand'] = 0.1,
|
||||
['default:desert_sand'] = 0.1,
|
||||
['default:silver_sand'] = 0.1,
|
||||
['default:snow'] = 0.07,
|
||||
['default:dirt_with_snow'] = 0.07,
|
||||
['default:ice '] = 0.01,
|
||||
['default:cave_ice'] = 0.01,
|
||||
}
|
||||
local acc = slow_nodes[node_below]
|
||||
if acc == nil then acc = minekart.max_acc_factor end
|
||||
return acc
|
||||
else
|
||||
return 0
|
||||
end
|
||||
return minekart.max_acc_factor
|
||||
end
|
||||
|
||||
function minekart.kart_control(self, dtime, hull_direction, longit_speed, longit_drag, later_drag, accel)
|
||||
minekart.karttest_last_time_command = minekart.karttest_last_time_command + dtime
|
||||
if minekart.karttest_last_time_command > 1 then minekart.karttest_last_time_command = 1 end
|
||||
|
||||
local player = minetest.get_player_by_name(self.driver_name)
|
||||
local retval_accel = accel;
|
||||
local zero = vector.new()
|
||||
|
||||
-- player control
|
||||
if player then
|
||||
local ctrl = player:get_player_control()
|
||||
|
||||
local acc = 0
|
||||
if self._engine_running then
|
||||
--running
|
||||
if longit_speed < minekart.max_speed and ctrl.up then
|
||||
--get acceleration factor
|
||||
acc = minekart.check_road_is_ok(self.object)
|
||||
--minetest.chat_send_all('engineacc: '.. engineacc)
|
||||
if acc > 1 and acc < minekart.max_acc_factor and longit_speed > 0 then
|
||||
--improper road will reduce speed
|
||||
acc = -1
|
||||
end
|
||||
end
|
||||
else
|
||||
--slow maneuver
|
||||
if longit_speed < 1.0 and ctrl.up then
|
||||
--get acceleration factor
|
||||
acc = minekart.check_road_is_ok(self.object)
|
||||
--minetest.chat_send_all('engineacc: '.. engineacc)
|
||||
if acc > 1 and acc < minekart.max_acc_factor and longit_speed > 0 then
|
||||
--improper road will reduce speed
|
||||
acc = -1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--reversing
|
||||
if ctrl.sneak and longit_speed <= 1.0 and longit_speed > -1.0 then
|
||||
acc = -1
|
||||
end
|
||||
|
||||
--break
|
||||
if longit_speed > 0 and ctrl.down then
|
||||
acc = -5 / (longit_speed / 2) -- lets set a brake efficience based on speed
|
||||
end
|
||||
|
||||
--total stop
|
||||
if longit_speed <= 0.1 and ctrl.down then
|
||||
-- do not like it here, but worked better
|
||||
acc = 0
|
||||
self.object:set_velocity(zero)
|
||||
--self.object:set_acceleration(zero)
|
||||
end
|
||||
|
||||
if acc then retval_accel=vector.add(accel,vector.multiply(hull_direction,acc)) end
|
||||
|
||||
if ctrl.jump then
|
||||
--sets the engine running - but sets a delay also, cause keypress
|
||||
if minekart.karttest_last_time_command > 0.3 then
|
||||
minekart.karttest_last_time_command = 0
|
||||
if self._engine_running then
|
||||
self._engine_running = false
|
||||
-- sound and animation
|
||||
if self.sound_handle then
|
||||
minetest.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 = minetest.sound_play({name = "engine"},
|
||||
{object = self.object, gain = 2.0, max_hear_distance = 32, loop = true,})
|
||||
--self.engine:set_animation_frame_speed(30)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- steering
|
||||
local steering_limit = 30
|
||||
if ctrl.right then
|
||||
self._steering_angle = math.max(self._steering_angle-80*dtime,-steering_limit)
|
||||
elseif ctrl.left then
|
||||
self._steering_angle = math.min(self._steering_angle+80*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/100)) * factor
|
||||
self._steering_angle = self._steering_angle + correction
|
||||
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
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
--
|
||||
-- fuel
|
||||
--
|
||||
|
||||
function minekart_load_fuel(self, player_name)
|
||||
if self._energy < 0.90 then
|
||||
local player = minetest.get_player_by_name(player_name)
|
||||
local inv = player:get_inventory()
|
||||
local inventory_fuel = "biofuel:biofuel"
|
||||
|
||||
if inv:contains_item("main", inventory_fuel) then
|
||||
local stack = ItemStack(inventory_fuel .. " 1")
|
||||
local taken = inv:remove_item("main", stack)
|
||||
|
||||
self._energy = self._energy + 1
|
||||
if self._energy > 1 then self._energy = 1 end
|
||||
minekart.last_fuel_display = 0
|
||||
minetest.chat_send_player(player_name, "Full tank!")
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(player_name, "No refuel for you! You have more than 90% of fuel in the tank.")
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
name = minekart
|
||||
depends = default,biofuel
|
||||
author = APercy
|
||||
description = Adds a craftable kart
|
||||
title = MineKart
|
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 382 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.5 KiB |