1
0
Fork 0
MineClone2/mods/ENTITIES/mcl_mobs/api/mob_functions/ai.lua

325 lines
8.5 KiB
Lua
Raw Normal View History

local math_random = math.random
2021-04-15 19:34:07 +00:00
local vector_multiply = vector.multiply
2021-04-16 19:30:44 +00:00
local vector_add = vector.add
2021-04-17 01:43:02 +00:00
local vector_new = vector.new
2021-04-15 19:34:07 +00:00
local minetest_yaw_to_dir = minetest.yaw_to_dir
local minetest_get_item_group = minetest.get_item_group
local minetest_get_node = minetest.get_node
2021-04-16 19:30:44 +00:00
local minetest_line_of_sight = minetest.line_of_sight
2021-04-15 19:34:07 +00:00
2021-04-16 19:30:44 +00:00
local DOUBLE_PI = math.pi * 2
local THIRTY_SECONDTH_PI = DOUBLE_PI * 0.03125
2021-04-15 19:34:07 +00:00
2021-04-16 15:50:13 +00:00
2021-04-17 00:32:05 +00:00
--[[
_ _
| | | |
| | __ _ _ __ __| |
| | / _` | '_ \ / _` |
| |___| (_| | | | | (_| |
\_____/\__,_|_| |_|\__,_|
]]
2021-04-16 19:30:44 +00:00
--this is basically reverse jump_check
local cliff_check = function(self,dtime)
--mobs will flip out if they are falling without this
if self.object:get_velocity().y ~= 0 then
return false
end
2021-04-16 19:30:44 +00:00
local pos = self.object:get_pos()
local dir = minetest_yaw_to_dir(self.yaw)
local collisionbox = self.object:get_properties().collisionbox
local radius = collisionbox[4] + 0.5
dir = vector_multiply(dir,radius)
2021-04-16 19:30:44 +00:00
local free_fall, blocker = minetest_line_of_sight(
{x = pos.x + dir.x, y = pos.y, z = pos.z + dir.z},
{x = pos.x + dir.x, y = pos.y - self.fear_height, z = pos.z + dir.z})
return free_fall
end
--a simple helper function which is too small to move into movement.lua
local quick_rotate_45 = function(self,dtime)
self.yaw = self.yaw + THIRTY_SECONDTH_PI
2021-04-16 19:30:44 +00:00
if self.yaw > DOUBLE_PI then
self.yaw = self.yaw - DOUBLE_PI
end
end
2021-04-16 15:50:13 +00:00
--check if a mob needs to jump
local jump_check = function(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)
2021-04-16 19:49:03 +00:00
--only jump if there's a node and a non-solid node above it
2021-04-16 15:50:13 +00:00
local test_dir = vector.add(pos,dir)
2021-04-16 19:49:03 +00:00
local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0
test_dir.y = test_dir.y + 1
local green_flag_2 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") == 0
2021-04-16 23:35:19 +00:00
if green_flag_1 and green_flag_2 then
--can jump over node
return(1)
2021-04-16 23:35:19 +00:00
elseif green_flag_1 and not green_flag_2 then
--wall in front of mob
return(2)
2021-04-16 15:50:13 +00:00
end
--nothing to jump over
return(0)
2021-04-16 15:50:13 +00:00
end
-- state switching logic (stand, walk, run, attacks)
2021-04-17 00:32:05 +00:00
local land_state_list_wandering = {"stand", "walk"}
local land_state_switch = function(self, dtime)
self.state_timer = self.state_timer - dtime
if self.wandering and self.state_timer <= 0 then
self.state_timer = math.random(4,10) + math.random()
2021-04-17 00:32:05 +00:00
self.state = land_state_list_wandering[math.random(1,#land_state_list_wandering)]
end
2021-04-17 00:32:05 +00:00
end
2021-04-17 00:32:05 +00:00
-- states are executed here
local land_state_execution = function(self,dtime)
2021-04-16 15:50:13 +00:00
--local yaw = self.object:get_yaw() or 0
2021-04-17 00:32:05 +00:00
2021-04-16 15:50:13 +00:00
if self.state == "stand" then
2021-04-16 17:58:08 +00:00
--do animation
mobs.set_mob_animation(self, "stand")
--set the velocity of the mob
mobs.set_velocity(self,0)
2021-04-16 15:50:13 +00:00
elseif self.state == "walk" then
2021-04-16 15:50:13 +00:00
self.walk_timer = self.walk_timer - dtime
2021-04-16 15:50:13 +00:00
--reset the walk timer
if self.walk_timer <= 0 then
2021-04-16 15:50:13 +00:00
--re-randomize the walk timer
self.walk_timer = math.random(1,6) + math.random()
2021-04-16 15:50:13 +00:00
--set the mob into a random direction
self.yaw = (math_random() * (math.pi * 2))
end
2021-04-16 15:50:13 +00:00
--do animation
2021-04-16 17:58:08 +00:00
mobs.set_mob_animation(self, "walk")
2021-04-15 19:34:07 +00:00
2021-04-16 15:50:13 +00:00
--enable rotation locking
mobs.movement_rotation_lock(self)
2021-04-15 19:34:07 +00:00
2021-04-16 15:50:13 +00:00
--check for nodes to jump over
local node_in_front_of = jump_check(self)
if node_in_front_of == 1 then
mobs.jump(self)
2021-04-16 23:35:19 +00:00
2021-04-16 19:30:44 +00:00
--turn if on the edge of cliff
--(this is written like this because unlike
--jump_check which simply tells the mob to jump
--this requires a mob to turn, removing the
--ease of a full implementation for it in a single
--function)
elseif node_in_front_of == 2 or (self.fear_height ~= 0 and cliff_check(self,dtime)) then
2021-04-16 19:30:44 +00:00
--turn 45 degrees if so
quick_rotate_45(self,dtime)
2021-04-16 22:36:23 +00:00
--stop the mob so it doesn't fall off
mobs.set_velocity(self,0)
end
--only move forward if path is clear
if node_in_front_of == 0 or node_in_front_of == 1 then
--set the velocity of the mob
mobs.set_velocity(self,self.walk_velocity)
2021-04-16 19:30:44 +00:00
end
2021-04-16 15:50:13 +00:00
elseif self.state == "run" then
2021-04-15 19:34:07 +00:00
2021-04-16 15:50:13 +00:00
print("run")
2021-04-15 19:34:07 +00:00
2021-04-16 15:50:13 +00:00
elseif self.state == "attack" then
2021-04-15 19:34:07 +00:00
2021-04-16 15:50:13 +00:00
print("attack")
2021-04-15 19:34:07 +00:00
2021-04-16 15:50:13 +00:00
end
2021-04-15 19:34:07 +00:00
end
2021-04-17 00:32:05 +00:00
--[[
______ _ _ _______ _ _
| ___| | (_) / / ___| (_) (_)
| |_ | |_ _ _ _ __ __ _ / /\ `--.__ ___ _ __ ___ _ __ ___ _ _ __ __ _
| _| | | | | | | '_ \ / _` | / / `--. \ \ /\ / / | '_ ` _ \| '_ ` _ \| | '_ \ / _` |
| | | | |_| | | | | | (_| |/ / /\__/ /\ V V /| | | | | | | | | | | | | | | | (_| |
\_| |_|\__, |_|_| |_|\__, /_/ \____/ \_/\_/ |_|_| |_| |_|_| |_| |_|_|_| |_|\__, |
__/ | __/ | __/ |
|___/ |___/ |___/
]]--
-- state switching logic (stand, walk, run, attacks)
local fly_state_list_wandering = {"stand", "fly"}
2021-04-17 00:32:05 +00:00
local fly_state_switch = function(self, dtime)
self.state_timer = self.state_timer - dtime
if self.wandering and 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)]
2021-04-17 00:32:05 +00:00
end
end
--this is going to need some more logic gates because birds can flop around
local flop = function(self,dtime)
mobs.flop(self)
end
2021-04-17 01:43:02 +00:00
--this is to swap the built in engine acceleration modifier
local fly_physics_swapper = function(self,inside_fly_node)
--should be flying, gravity is applied, switch to floating
2021-04-17 16:01:27 +00:00
if inside_fly_node and self.object:get_acceleration().y ~= 0 then
2021-04-17 01:43:02 +00:00
self.object:set_acceleration(vector_new(0,0,0))
--not be flying, gravity isn't applied, switch to falling
2021-04-17 16:01:27 +00:00
elseif not inside_fly_node and self.object:get_acceleration().y == 0 then
2021-04-17 01:43:02 +00:00
self.pitch = 0
self.object:set_acceleration(vector_new(0,-self.gravity,0))
end
end
2021-04-17 00:32:05 +00:00
2021-04-17 01:43:02 +00:00
local random_pitch_multiplier = {-1,1}
-- states are executed here
2021-04-17 00:32:05 +00:00
local fly_state_execution = function(self,dtime)
local pos = self.object:get_pos()
2021-04-17 01:43:02 +00:00
pos.y = pos.y + self.object:get_properties().collisionbox[5]
local current_node = minetest_get_node(pos).name
local inside_fly_node = false
2021-04-17 00:32:05 +00:00
--quick scan everything to see if inside fly node
for _,id in pairs(self.fly_in) do
if id == current_node then
inside_fly_node = true
break
end
end
2021-04-17 00:32:05 +00:00
2021-04-17 01:43:02 +00:00
--turn gravity on or off
fly_physics_swapper(self,inside_fly_node)
--fly properly if inside fly node
if inside_fly_node then
2021-04-17 01:43:02 +00:00
if self.state == "stand" then
--do animation
--mobs.set_mob_animation(self, "stand")
--set the velocity of the mob
--mobs.set_velocity(self,0)
--print("standing")
2021-04-17 01:43:02 +00:00
mobs.set_fly_velocity(self,0)
elseif self.state == "fly" then
2021-04-17 01:43:02 +00:00
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))
2021-04-17 01:43:02 +00:00
--create a truly random pitch, since there is no easy access to pitch math that I can find
self.pitch = math_random() * random_pitch_multiplier[math_random(1,2)]
end
2021-04-17 01:43:02 +00:00
mobs.set_fly_velocity(self,self.walk_velocity)
end
--flop around if not inside fly node
else
--print("flopping")
flop(self,dtime)
end
2021-04-17 00:32:05 +00:00
end
2021-04-17 00:32:05 +00:00
--[[
___ ___ _ _ _
| \/ | (_) | | (_)
| . . | __ _ _ _ __ | | ___ __ _ _ ___
| |\/| |/ _` | | '_ \ | | / _ \ / _` | |/ __|
| | | | (_| | | | | | | |___| (_) | (_| | | (__
\_| |_/\__,_|_|_| |_| \_____/\___/ \__, |_|\___|
__/ |
|___/
]]
2021-04-15 19:34:07 +00:00
2021-04-17 00:06:55 +00:00
--the main loop
mobs.mob_step = function(self, dtime)
--do not continue if non-existent
if not self or not self.object or not self.object:get_luaentity() then
return false
end
--print(self.object:get_yaw())
2021-04-17 00:32:05 +00:00
--swimming/flying
if self.fly then
fly_state_switch(self, dtime)
fly_state_execution(self, dtime)
--regular mobs that walk around
else
land_state_switch(self, dtime)
land_state_execution(self,dtime)
end
-- can mob be pushed, if so calculate direction -- do this last (overrides everything)
if self.pushable then
mobs.collision(self)
end
2021-04-15 19:34:07 +00:00
self.old_velocity = self.object:get_velocity()
end