381 lines
13 KiB
Lua
381 lines
13 KiB
Lua
--
|
|
-- entity
|
|
--
|
|
|
|
-- supported colors
|
|
local color_def = {
|
|
["#2b2b2b"] = "Black",
|
|
["#ffffff"] = "White",
|
|
["#9f9f9f"] = "Grey",
|
|
["#6d6d6d"] = "Dark Grey",
|
|
["#dc1818"] = "Red",
|
|
["#07b6bc"] = "Cyan",
|
|
["#8c5922"] = "Brown",
|
|
["#4ee34c"] = "Green",
|
|
["#567a42"] = "Dark Green",
|
|
["#ff62c6"] = "Pink",
|
|
["#ff8b0e"] = "Orange",
|
|
["#a437ff"] = "Violet",
|
|
["#ffe400"] = "Yellow",
|
|
["#ff0098"] = "Magenta",
|
|
}
|
|
|
|
minetest.register_entity("nss_helicopter:seat_base",{
|
|
initial_properties = {
|
|
physical = false,
|
|
collide_with_objects=false,
|
|
pointable=false,
|
|
visual = "mesh",
|
|
mesh = "seat_base.b3d",
|
|
textures = {"helicopter_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("nss_helicopter:heli", {
|
|
initial_properties = {
|
|
physical = true,
|
|
collide_with_objects = true,
|
|
collisionbox = {-1,0,-1, 1,0.3,1},
|
|
selectionbox = {-1,0,-1, 1,0.3,1},
|
|
visual = "mesh",
|
|
mesh = "helicopter_heli.b3d",
|
|
backface_culling = false,
|
|
textures = {"helicopter_interior_black.png", "helicopter_metal.png", "helicopter_strips.png",
|
|
"helicopter_painting.png", "helicopter_black.png", "helicopter_aluminum.png", "helicopter_glass.png",
|
|
"helicopter_interior.png", "helicopter_panel.png", "helicopter_colective.png", "helicopter_painting.png",
|
|
"helicopter_rotors.png", "helicopter_interior_black.png",},
|
|
},
|
|
|
|
driver_name = nil,
|
|
shaded = true,
|
|
show_on_minimap = true,
|
|
sound_handle = nil,
|
|
tilting = vector.new(),
|
|
energy = 0.001,
|
|
owner = "",
|
|
static_save = true,
|
|
infotext = "A nice helicopter",
|
|
last_vel = vector.new(),
|
|
hp_max = 50,
|
|
color = "#0063b0",
|
|
_passenger = nil,
|
|
_by_mouse = true, --helicopter.turn_player_look,
|
|
|
|
get_staticdata = function(self) -- unloaded/unloads ... is now saved
|
|
return minetest.serialize({
|
|
stored_energy = self.energy,
|
|
stored_owner = self.owner,
|
|
stored_hp = self.hp_max,
|
|
stored_color = self.color,
|
|
stored_driver_name = self.driver_name,
|
|
})
|
|
end,
|
|
|
|
on_activate = function(self, staticdata, dtime_s)
|
|
if staticdata ~= "" and staticdata ~= nil then
|
|
local data = minetest.deserialize(staticdata) or {}
|
|
self.energy = data.stored_energy
|
|
self.owner = data.stored_owner
|
|
self.hp_max = data.stored_hp
|
|
self.color = data.stored_color
|
|
self.driver_name = data.stored_driver_name
|
|
--minetest.debug("loaded: ", self.energy)
|
|
local properties = self.object:get_properties()
|
|
properties.infotext = data.stored_owner .. " nice helicopter"
|
|
self.object:set_properties(properties)
|
|
end
|
|
|
|
helicopter.paint(self, self.color)
|
|
local pos = self.object:get_pos()
|
|
local pointer=minetest.add_entity(pos,'nss_helicopter:pointer')
|
|
local energy_indicator_angle = ((self.energy * 18) - 90) * -1
|
|
pointer:set_attach(self.object,'',{x=0,y=11.26,z=9.37},{x=0,y=0,z=energy_indicator_angle})
|
|
self.pointer = pointer
|
|
|
|
local pilot_seat_base=minetest.add_entity(pos,'nss_helicopter:seat_base')
|
|
pilot_seat_base:set_attach(self.object,'',{x=4.2,y=10,z=2},{x=0,y=0,z=0})
|
|
self.pilot_seat_base = pilot_seat_base
|
|
|
|
local passenger_seat_base=minetest.add_entity(pos,'nss_helicopter:seat_base')
|
|
passenger_seat_base:set_attach(self.object,'',{x=-4.2,y=10,z=2},{x=0,y=0,z=0})
|
|
self.passenger_seat_base = passenger_seat_base
|
|
|
|
-- set the animation once and later only change the speed
|
|
self.object:set_animation({x = 0, y = 11}, 0, 0, true)
|
|
|
|
self.object:set_armor_groups({immortal=1})
|
|
|
|
local vector_up = vector.new(0, 1, 0)
|
|
self.object:set_acceleration(vector.multiply(vector_up, -helicopter.gravity))
|
|
end,
|
|
|
|
on_step = function(self, dtime)
|
|
helicopter.helicopter_last_time_command = helicopter.helicopter_last_time_command + dtime
|
|
if helicopter.helicopter_last_time_command > 1 then helicopter.helicopter_last_time_command = 1 end
|
|
local touching_ground, liquid_below
|
|
|
|
local vel = self.object:get_velocity()
|
|
|
|
touching_ground, liquid_below = helicopter.check_node_below(self.object)
|
|
vel = helicopter.heli_control(self, dtime, touching_ground, liquid_below, vel) or vel
|
|
|
|
if vel.x == 0 and vel.y == 0 and vel.z == 0 then
|
|
return
|
|
end
|
|
|
|
if touching_ground == nil then
|
|
touching_ground, liquid_below = helicopter.check_node_below(self.object)
|
|
end
|
|
|
|
-- quadratic and constant deceleration
|
|
local speedsq = helicopter.vector_length_sq(vel)
|
|
local fq, fc
|
|
if touching_ground then
|
|
fq, fc = helicopter.friction_land_quadratic, helicopter.friction_land_constant
|
|
elseif liquid_below then
|
|
fq, fc = helicopter.friction_water_quadratic, helicopter.friction_water_constant
|
|
else
|
|
fq, fc = helicopter.friction_air_quadratic, helicopter.friction_air_constant
|
|
end
|
|
vel = vector.apply(vel, function(a)
|
|
local s = math.sign(a)
|
|
a = math.abs(a)
|
|
a = math.max(0, a - fq * dtime * speedsq - fc * dtime)
|
|
return a * s
|
|
end)
|
|
|
|
--[[
|
|
collision detection
|
|
using velocity vector as virtually a point on space, we compare
|
|
if last velocity has a great distance difference (virtually 5) from current velocity
|
|
using some trigonometry (get_hipotenuse_value). If yes, we have an abrupt collision
|
|
]]--
|
|
|
|
local is_attached = false
|
|
if self.owner then
|
|
local player = minetest.get_player_by_name(self.owner)
|
|
|
|
if player then
|
|
local player_attach = player:get_attach()
|
|
if player_attach then
|
|
--XXXXXXXX
|
|
if player_attach == self.pilot_seat_base then is_attached = true end
|
|
--XXXXXXXX
|
|
end
|
|
end
|
|
end
|
|
|
|
if is_attached then
|
|
local impact = helicopter.get_hipotenuse_value(vel, self.last_vel)
|
|
if impact > 5 then
|
|
--self.damage = self.damage + impact --sum the impact value directly to damage meter
|
|
local curr_pos = self.object:get_pos()
|
|
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,
|
|
})
|
|
--[[if self.damage > 100 then --if acumulated damage is greater than 100, adieu
|
|
helicopter.destroy(self, player)
|
|
end]]--
|
|
end
|
|
|
|
--update hud
|
|
local player = minetest.get_player_by_name(self.driver_name)
|
|
if helicopter.helicopter_last_time_command > 0.3 then
|
|
helicopter.helicopter_last_time_command = 0
|
|
update_heli_hud(player)
|
|
end
|
|
else
|
|
-- for some error the player can be detached from the helicopter, so lets set him attached again
|
|
local can_stop = true
|
|
if self.owner and self.driver_name and touching_ground == false then
|
|
-- attach the driver again
|
|
local player = minetest.get_player_by_name(self.owner)
|
|
if player then
|
|
helicopter.attach(self, player)
|
|
can_stop = false
|
|
end
|
|
end
|
|
|
|
if can_stop then
|
|
--detach player
|
|
if self.sound_handle ~= nil then
|
|
minetest.sound_stop(self.sound_handle)
|
|
self.sound_handle = nil
|
|
|
|
--why its here? cause if the sound is attached, player must so
|
|
local player_owner = minetest.get_player_by_name(self.owner)
|
|
if player_owner then remove_heli_hud(player_owner) end
|
|
end
|
|
end
|
|
end
|
|
self.last_vel = vel --saves velocity for collision comparation
|
|
-- end collision detection
|
|
|
|
self.object:set_velocity(vel)
|
|
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 touching_ground, liquid_below = helicopter.check_node_below(self.object)
|
|
|
|
--XXXXXXXX
|
|
local is_attached = false
|
|
if puncher:get_attach() == self.pilot_seat_base then is_attached = true end
|
|
--XXXXXXXX
|
|
|
|
local itmstck=puncher:get_wielded_item()
|
|
local item_name = ""
|
|
if itmstck then item_name = itmstck:get_name() end
|
|
|
|
if is_attached == false then
|
|
if touching_ground then
|
|
if helicopter.loadFuel(self, self.owner) then return end
|
|
end
|
|
-- deal with painting or destroying
|
|
if itmstck then
|
|
local _,indx = item_name:find('dye:')
|
|
if indx then
|
|
|
|
--lets paint!!!!
|
|
local color = item_name:sub(indx+1)
|
|
local colstr = helicopter.colors[color]
|
|
--minetest.chat_send_all(color ..' '.. dump(colstr))
|
|
if colstr then
|
|
helicopter.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
|
|
--mobkit.hurt(self,toolcaps.damage_groups.fleshy - 1)
|
|
--mobkit.make_sound(self,'hit')
|
|
self.hp_max = self.hp_max - 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_max <= 0 then
|
|
if helicopter.punch_inv then
|
|
local pinv = puncher:get_inventory()
|
|
local stack = ItemStack("nss_helicopter:heli")
|
|
local imeta = stack:get_meta()
|
|
|
|
-- store fuel level & color
|
|
imeta:set_float("fuel", self.energy)
|
|
if self.color and self.color ~= "#0063b0" then -- don't store defult "blue"
|
|
imeta:set_string("color", self.color)
|
|
end
|
|
|
|
local color_name = color_def[self.color:lower()]
|
|
if color_name then
|
|
imeta:set_string("description", color_name .. " Helicopter")
|
|
end
|
|
|
|
if not pinv:room_for_item("main", stack) then
|
|
minetest.chat_send_player(puncher:get_player_name(),
|
|
"You do not have room in your inventory")
|
|
else
|
|
if self.pointer then self.pointer:remove() end
|
|
if self.pilot_seat_base then self.pilot_seat_base:remove() end
|
|
if self.passenger_seat_base then self.passenger_seat_base:remove() end
|
|
|
|
self.object:remove()
|
|
if not helicopter.creative or not pinv:contains_item("main", stack, true) then
|
|
pinv:add_item("main", stack)
|
|
end
|
|
end
|
|
else
|
|
helicopter.destroy(self, puncher)
|
|
end
|
|
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 == "" then
|
|
self.owner = name
|
|
end
|
|
|
|
if self.owner == name then
|
|
if name == self.driver_name then
|
|
-- driver clicked the object => driver gets off the vehicle
|
|
helicopter.dettach(self, clicker)
|
|
if self._passenger then
|
|
local passenger = minetest.get_player_by_name(self._passenger)
|
|
if passenger then
|
|
helicopter.dettach_pax(self, passenger)
|
|
end
|
|
end
|
|
elseif not self.driver_name then
|
|
local is_under_water = helicopter.check_is_under_water(self.object)
|
|
if is_under_water then return end
|
|
-- temporary------
|
|
self.hp_max = 50 -- why? cause I can desist from destroy
|
|
------------------
|
|
|
|
helicopter.attach(self, clicker)
|
|
end
|
|
else
|
|
--passenger section
|
|
--only can enter when the pilot is inside
|
|
if self.driver_name then
|
|
if self._passenger == nil then
|
|
helicopter.attach_pax(self, clicker)
|
|
else
|
|
helicopter.dettach_pax(self, clicker)
|
|
end
|
|
else
|
|
if self._passenger then
|
|
helicopter.dettach_pax(self, clicker)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
})
|