2022-05-29 13:46:45 -03:00
|
|
|
airutils.gravity = -9.8
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2022-05-29 14:10:51 -03:00
|
|
|
local sign = function(x)
|
|
|
|
return (x<0) and -1 or 1
|
|
|
|
end
|
|
|
|
|
2022-05-29 13:46:45 -03:00
|
|
|
function airutils.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 airutils.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 airutils.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 airutils.get_stand_pos(thing) -- thing can be luaentity or objectref.
|
|
|
|
local pos = {}
|
|
|
|
local colbox = {}
|
|
|
|
if type(thing) == 'table' then
|
|
|
|
pos = thing.object:get_pos()
|
2023-08-24 20:14:00 -03:00
|
|
|
if not thing.object:get_properties() then return false end
|
2022-05-29 13:46:45 -03:00
|
|
|
colbox = thing.object:get_properties().collisionbox
|
|
|
|
elseif type(thing) == 'userdata' then
|
|
|
|
pos = thing:get_pos()
|
2023-08-24 20:14:00 -03:00
|
|
|
if not thing:get_properties() then return false end
|
2022-05-29 13:46:45 -03:00
|
|
|
colbox = thing:get_properties().collisionbox
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
return airutils.pos_shift(pos,{y=colbox[2]+0.01}), pos
|
|
|
|
end
|
|
|
|
|
|
|
|
function airutils.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 airutils.nodeatpos(pos)
|
2023-08-24 19:26:48 -03:00
|
|
|
if pos == nil then return end
|
2022-05-29 13:46:45 -03:00
|
|
|
local node = minetest.get_node_or_nil(pos)
|
|
|
|
if node then return minetest.registered_nodes[node.name] end
|
|
|
|
end
|
|
|
|
|
|
|
|
function airutils.minmax(v,m)
|
|
|
|
return min(abs(v),m)*sign(v)
|
|
|
|
end
|
|
|
|
|
|
|
|
function airutils.set_acceleration(thing,vec,limit)
|
|
|
|
limit = limit or 100
|
|
|
|
if type(thing) == 'table' then thing=thing.object end
|
|
|
|
vec.x=airutils.minmax(vec.x,limit)
|
|
|
|
vec.y=airutils.minmax(vec.y,limit)
|
|
|
|
vec.z=airutils.minmax(vec.z,limit)
|
|
|
|
|
|
|
|
thing:set_acceleration(vec)
|
|
|
|
end
|
|
|
|
|
|
|
|
function airutils.actfunc(self, staticdata, dtime_s)
|
|
|
|
|
|
|
|
self.logic = self.logic or self.brainfunc
|
|
|
|
self.physics = self.physics or airutils.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 airutils.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 airutils.stepfunc(self,dtime,colinfo)
|
|
|
|
self.dtime = min(dtime,0.2)
|
|
|
|
self.colinfo = colinfo
|
|
|
|
self.height = airutils.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
|
|
|
|
if self.view_range then self:sensefunc() end
|
|
|
|
self:logic()
|
|
|
|
execute_queues(self)
|
|
|
|
end
|
|
|
|
|
|
|
|
self.lastvelocity = self.object:get_velocity()
|
|
|
|
self.time_total=self.time_total+self.dtime
|
|
|
|
end
|