215 lines
5.1 KiB
Lua
215 lines
5.1 KiB
Lua
|
|
--[[
|
|
______ _
|
|
| ___| |
|
|
| |_ | |_ _
|
|
| _| | | | | |
|
|
| | | | |_| |
|
|
\_| |_|\__, |
|
|
__/ |
|
|
|___/
|
|
]]--
|
|
|
|
--[[
|
|
-- state switching logic (stand, walk, run, attacks)
|
|
local fly_state_list_wandering = {"stand", "fly"}
|
|
|
|
local function fly_state_switch(self, dtime)
|
|
|
|
if self.hostile and self.attacking then
|
|
self.state = "attack"
|
|
return
|
|
end
|
|
|
|
self.state_timer = self.state_timer - dtime
|
|
if self.state_timer <= 0 then
|
|
self.state_timer = math.random(4, 10) + math.random()
|
|
self.state = fly_state_list_wandering[math.random(1, #fly_state_list_wandering)]
|
|
end
|
|
end
|
|
|
|
--check if a mob needs to turn while flying
|
|
local function fly_turn_check(self, dtime)
|
|
|
|
local pos = self.object:get_pos()
|
|
pos.y = pos.y + 0.1
|
|
local dir = minetest.yaw_to_dir(self.yaw)
|
|
|
|
local collisionbox = self.object:get_properties().collisionbox
|
|
local radius = collisionbox[4] + 0.5
|
|
|
|
vector.multiply(dir, radius)
|
|
|
|
local test_dir = vector.add(pos,dir)
|
|
|
|
return minetest.get_item_group(minetest.get_node(test_dir).name, "solid") ~= 0
|
|
end
|
|
|
|
--this is to swap the built in engine acceleration modifier
|
|
local function fly_physics_swapper(self, inside_fly_node)
|
|
|
|
--should be flyming, gravity is applied, switch to floating
|
|
if inside_fly_node and self.object:get_acceleration().y ~= 0 then
|
|
self.object:set_acceleration(vector.new(0, 0, 0))
|
|
--not be fly, gravity isn't applied, switch to falling
|
|
elseif not inside_fly_node and self.object:get_acceleration().y == 0 then
|
|
self.pitch = 0
|
|
self.object:set_acceleration(vector.new(0, -self.gravity, 0))
|
|
end
|
|
end
|
|
|
|
local random_pitch_multiplier = {-1, 1}
|
|
-- states are executed here
|
|
local function fly_state_execution(self, dtime)
|
|
local pos = self.object:get_pos()
|
|
pos.y = pos.y + 0.1
|
|
local current_node = minetest.get_node(pos).name
|
|
local inside_fly_node = minetest.get_item_group(current_node, "solid") == 0
|
|
|
|
local float_now = false
|
|
--recheck if in water or lava
|
|
if minetest.get_item_group(current_node, "water") ~= 0 or minetest.get_item_group(current_node, "lava") ~= 0 then
|
|
inside_fly_node = false
|
|
float_now = true
|
|
end
|
|
|
|
--turn gravity on or off
|
|
fly_physics_swapper(self, inside_fly_node)
|
|
|
|
--fly properly if inside fly node
|
|
if inside_fly_node then
|
|
if self.state == "stand" then
|
|
|
|
--do animation
|
|
self:set_animation("stand")
|
|
|
|
self:set_fly_velocity(0)
|
|
|
|
if self.tilt_fly then
|
|
self:set_static_pitch()
|
|
end
|
|
|
|
self:lock_yaw()
|
|
|
|
elseif self.state == "fly" then
|
|
|
|
self.walk_timer = self.walk_timer - dtime
|
|
|
|
--reset the walk timer
|
|
if self.walk_timer <= 0 then
|
|
|
|
--re-randomize the walk timer
|
|
self.walk_timer = math.random(1, 6) + math.random()
|
|
|
|
--set the mob into a random direction
|
|
self.yaw = (math.random() * (math.pi * 2))
|
|
|
|
--create a truly random pitch, since there is no easy access to pitch math that I can find
|
|
self.pitch = math.random() * math.random(1, 3) * random_pitch_multiplier[math.random(1,2)]
|
|
end
|
|
|
|
--do animation
|
|
self:set_animation("walk")
|
|
|
|
--do a quick turn to make mob continuously move
|
|
--if in a bird cage or something
|
|
if fly_turn_check(self, dtime) then
|
|
quick_rotate(self, dtime)
|
|
end
|
|
|
|
if self.tilt_fly then
|
|
self:set_dynamic_pitch()
|
|
end
|
|
|
|
self:set_fly_velocity(self.walk_velocity)
|
|
|
|
--enable rotation locking
|
|
self:movement_rotation_lock()
|
|
|
|
elseif self.state == "attack" then
|
|
|
|
--execute mob attack type
|
|
--if self.attack_type == "explode" then
|
|
|
|
--mobs.explode_attack_fly(self, dtime)
|
|
|
|
--elseif self.attack_type == "punch" then
|
|
|
|
--mobs.punch_attack_fly(self,dtime)
|
|
|
|
if self.attack_type == "projectile" then
|
|
|
|
self:projectile_attack_fly(dtime)
|
|
|
|
end
|
|
end
|
|
else
|
|
--make the mob float
|
|
if self.floats and float_now then
|
|
self:set_velocity(0)
|
|
|
|
self:float()
|
|
|
|
if self.tilt_fly then
|
|
self:set_static_pitch()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- move mob in facing direction
|
|
--this has been modified to be internal
|
|
--internal = lua (self.yaw)
|
|
--engine = c++ (self.object:get_yaw())
|
|
mobs.set_fly_velocity = function(self, v)
|
|
|
|
local yaw = (self.yaw or 0)
|
|
local pitch = (self.pitch or 0)
|
|
|
|
if v == 0 then
|
|
pitch = 0
|
|
end
|
|
|
|
local current_velocity = self.object:get_velocity()
|
|
|
|
local goal_velocity = {
|
|
x = (math.sin(yaw) * -v),
|
|
y = pitch,
|
|
z = (math.cos(yaw) * v),
|
|
}
|
|
|
|
|
|
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
|
|
|
|
if vector.length(new_velocity_addition) > vector.length(goal_velocity) then
|
|
vector.multiply(new_velocity_addition, (vector.length(goal_velocity) / vector.length(new_velocity_addition)))
|
|
end
|
|
|
|
--smooths out mobs a bit
|
|
if vector.length(new_velocity_addition) >= 0.0001 then
|
|
self.object:add_velocity(new_velocity_addition)
|
|
end
|
|
end
|
|
|
|
--a quick and simple pitch calculation between two vector positions
|
|
mobs.calculate_pitch = function(pos1, pos2)
|
|
|
|
if pos1 == nil or pos2 == nil then
|
|
return false
|
|
end
|
|
|
|
return(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos1.x,0,pos1.z),vector.new(pos2.x,0,pos2.z)),0,pos1.y - pos2.y)) + HALF_PI)
|
|
end
|
|
|
|
--make mobs fly up or down based on their y difference
|
|
mobs.set_pitch_while_attacking = function(self)
|
|
local pos1 = self.object:get_pos()
|
|
local pos2 = self.attacking:get_pos()
|
|
|
|
local pitch = mobs.calculate_pitch(pos2,pos1)
|
|
|
|
self.pitch = pitch
|
|
end
|
|
]]--
|