forked from VoxeLibre/VoxeLibre
add head code and interaction code from crafter
This commit is contained in:
parent
0e797e2c3f
commit
796c45d4b3
|
@ -0,0 +1,56 @@
|
|||
local math,vector = math,vector
|
||||
|
||||
local speed
|
||||
local self_rotation
|
||||
local currentvel
|
||||
local goal = vector.new(0,0,0)
|
||||
local acceleration
|
||||
--
|
||||
mobs.create_animation_functions = function(def,mob_register)
|
||||
if def.movement_type ~= "jump" then
|
||||
mob_register.set_animation = function(self)
|
||||
if self.speed == 0 or vector.equals(self.direction,vector.new(0,0,0)) then
|
||||
self.current_animation = 0
|
||||
self.object:set_animation(def.standing_frame, 1, 0, true)
|
||||
else
|
||||
if self.current_animation ~= 1 then
|
||||
self.object:set_animation(def.moving_frame, 1, 0, true)
|
||||
self.current_animation = 1
|
||||
end
|
||||
|
||||
speed = self.object:get_velocity()
|
||||
speed.y = 0
|
||||
self.object:set_animation_frame_speed(vector.distance(vector.new(0,0,0),speed)*def.animation_multiplier)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--this makes the mob rotate and then die
|
||||
mob_register.manage_death_animation = function(self,dtime)
|
||||
if self.death_animation_timer >= 0 and self.dead == true then
|
||||
self.death_animation_timer = self.death_animation_timer - dtime
|
||||
|
||||
self_rotation = self.object:get_rotation()
|
||||
|
||||
if self.death_rotation == "x" then
|
||||
if self_rotation.x < math.pi/2 then
|
||||
self_rotation.x = self_rotation.x + (dtime*2)
|
||||
self.object:set_rotation(self_rotation)
|
||||
end
|
||||
elseif self.death_rotation == "z" then
|
||||
if self_rotation.z < math.pi/2 then
|
||||
self_rotation.z = self_rotation.z + (dtime*2)
|
||||
self.object:set_rotation(self_rotation)
|
||||
end
|
||||
end
|
||||
|
||||
--print(self.death_animation_timer)
|
||||
currentvel = self.object:get_velocity()
|
||||
acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
|
||||
acceleration = vector.multiply(acceleration, 0.05)
|
||||
self.object:add_velocity(acceleration)
|
||||
self.object:set_animation(def.standing_frame, 15, 0, true)
|
||||
end
|
||||
end
|
||||
return(mob_register)
|
||||
end
|
|
@ -0,0 +1,250 @@
|
|||
local minetest = minetest
|
||||
--class
|
||||
mobs = {}
|
||||
|
||||
local path = minetest.get_modpath(minetest.get_current_modname()).."/api/"
|
||||
dofile(path.."movement.lua")
|
||||
dofile(path.."interaction.lua")
|
||||
dofile(path.."data_handling.lua")
|
||||
dofile(path.."head_code.lua")
|
||||
dofile(path.."animation.lua")
|
||||
dofile(path.."timers.lua")
|
||||
|
||||
mobs.register_mob = function(def)
|
||||
|
||||
|
||||
|
||||
local mob_register = {}
|
||||
|
||||
register_mob_spawner(def.mobname,def.textures,def.mesh)
|
||||
|
||||
------------------------------------------------
|
||||
mob_register.initial_properties = {
|
||||
physical = def.physical,
|
||||
collide_with_objects = def.collide_with_objects,
|
||||
collisionbox = def.collisionbox,
|
||||
visual = def.visual,
|
||||
visual_size = def.visual_size,
|
||||
mesh = def.mesh,
|
||||
textures = def.textures,
|
||||
is_visible = def.is_visible,
|
||||
pointable = def.pointable,
|
||||
automatic_face_movement_dir = def.automatic_face_movement_dir,
|
||||
automatic_face_movement_max_rotation_per_sec = def.automatic_face_movement_max_rotation_per_sec,
|
||||
makes_footstep_sound = def.makes_footstep_sound,
|
||||
static_save = false,
|
||||
}
|
||||
|
||||
|
||||
mob_register.hp = def.hp
|
||||
mob_register.max_speed = def.max_speed
|
||||
mob_register.jump_timer = 0
|
||||
|
||||
|
||||
if def.head_bone then
|
||||
mob_register.head_bone = def.head_bone
|
||||
mobs.create_head_functions(def,mob_register)
|
||||
mob_register.debug_head_pos = def.debug_head_pos
|
||||
mob_register.head_directional_offset = def.head_directional_offset
|
||||
mob_register.head_height_offset = def.head_height_offset
|
||||
mob_register.head_rotation_offset = def.head_rotation_offset
|
||||
mob_register.head_position_correction = def.head_position_correction
|
||||
mob_register.head_coord = def.head_coord
|
||||
mob_register.flip_pitch = def.flip_pitch
|
||||
else
|
||||
--print("create some other functions to turn mob " .. def.mobname)
|
||||
end
|
||||
|
||||
mob_register.hurt_inside_timer = 0
|
||||
mob_register.death_animation_timer = 0
|
||||
mob_register.dead = false
|
||||
|
||||
mob_register.mob = true
|
||||
mob_register.mobname = def.mobname
|
||||
|
||||
mob_register.hostile = def.hostile
|
||||
if def.friendly_in_daylight == true then
|
||||
mob_register.friendly_in_daylight = def.friendly_in_daylight
|
||||
mob_register.friendly_in_daylight_timer = 0
|
||||
end
|
||||
|
||||
mob_register.hostile_cooldown = def.hostile_cooldown
|
||||
|
||||
mob_register.hostile_timer = 0
|
||||
mob_register.timer = 0
|
||||
|
||||
mob_register.state = def.state
|
||||
|
||||
mob_register.hunger = 200
|
||||
|
||||
mob_register.view_distance = def.view_distance
|
||||
|
||||
mob_register.punch_timer = 0
|
||||
mob_register.punched_timer = 0
|
||||
mob_register.group_attack = def.group_attack
|
||||
|
||||
mob_register.death_rotation = def.death_rotation
|
||||
|
||||
mob_register.head_mount = def.head_mount
|
||||
mob_register.rotational_correction = def.rotational_correction or 0
|
||||
|
||||
mob_register.hurt_sound = def.hurt_sound
|
||||
mob_register.die_sound = def.die_sound
|
||||
|
||||
mob_register.attack_type = def.attack_type
|
||||
if def.attack_type == "explode" then
|
||||
mob_register.tnt_tick_timer = 0
|
||||
mob_register.explosion_type = def.explosion_type
|
||||
end
|
||||
mob_register.explosion_radius = def.explosion_radius
|
||||
mob_register.explosion_power = def.explosion_power
|
||||
mob_register.tnt_timer = nil
|
||||
mob_register.explosion_time = def.explosion_time
|
||||
mob_register.explosion_blink_color = def.explosion_blink_color or "white"
|
||||
mob_register.explosion_blink_timer = def.explosion_blink_timer or 0.2
|
||||
|
||||
mob_register.custom_function_begin = def.custom_function_begin
|
||||
mob_register.custom_function = def.custom_function
|
||||
mob_register.custom_function_end = def.custom_function_end
|
||||
|
||||
mob_register.projectile_timer_cooldown = def.projectile_timer_cooldown
|
||||
mob_register.attacked_hostile = def.attacked_hostile
|
||||
if not def.hostile and not def.attacked_hostile then
|
||||
mob_register.scared = false
|
||||
mob_register.scared_timer = 0
|
||||
end
|
||||
mob_register.attack_damage = def.attack_damage
|
||||
|
||||
mob_register.projectile_timer = 0
|
||||
mob_register.projectile_type = def.projectile_type
|
||||
|
||||
mob_register.takes_fall_damage = def.takes_fall_damage or true
|
||||
mob_register.make_jump_noise = def.make_jump_noise
|
||||
mob_register.jump_animation = def.jump_animation
|
||||
mob_register.jumping_frame = def.jumping_frame
|
||||
|
||||
mob_register.item_drop = def.item_drop
|
||||
mob_register.item_minimum = def.item_minimum or 1
|
||||
mob_register.item_max = def.item_max
|
||||
|
||||
mob_register.die_in_light = def.die_in_light
|
||||
mob_register.die_in_light_level = def.die_in_light_level
|
||||
|
||||
mob_register.current_animation = 0
|
||||
mob_register.hurt_color_timer = 0
|
||||
mob_register.damage_color = def.damage_color or "red"
|
||||
mob_register.custom_on_death = def.custom_on_death
|
||||
|
||||
mob_register.custom_on_activate = def.custom_on_activate
|
||||
|
||||
mob_register.custom_on_punch = def.custom_on_punch
|
||||
|
||||
mob_register.c_mob_data = def.c_mob_data
|
||||
|
||||
mob_register.deactivating = false
|
||||
|
||||
mob_register.on_fire = false
|
||||
|
||||
mob_register.fire_table = def.fire_table
|
||||
|
||||
mob_register.sound_pitch_mod_min = def.sound_pitch_mod_min
|
||||
mob_register.sound_pitch_mod_max = def.sound_pitch_mod_max
|
||||
|
||||
mob_register.sound_pitch_mod_min_die = def.sound_pitch_mod_min_die
|
||||
mob_register.sound_pitch_mod_max_die = def.sound_pitch_mod_max_die
|
||||
|
||||
|
||||
if def.pathfinds then
|
||||
--mob_register.path = {}
|
||||
mob_register.pathfinding_timer = 0
|
||||
end
|
||||
|
||||
if def.custom_timer then
|
||||
mob_register.c_timer = 0
|
||||
mob_register.custom_timer = def.custom_timer
|
||||
mob_register.custom_timer_function = def.custom_timer_function
|
||||
end
|
||||
|
||||
mobs.create_movement_functions(def,mob_register)
|
||||
mobs.create_interaction_functions(def,mob_register)
|
||||
mobs.create_data_handling_functions(def,mob_register)
|
||||
mobs.create_animation_functions(def,mob_register)
|
||||
mobs.create_timer_functions(def,mob_register)
|
||||
|
||||
|
||||
mob_register.on_step = function(self, dtime,moveresult)
|
||||
if self.custom_function_begin then
|
||||
self.custom_function_begin(self,dtime)
|
||||
end
|
||||
|
||||
self.collision_detection(self)
|
||||
if self.fall_damage then
|
||||
self.fall_damage(self)
|
||||
end
|
||||
|
||||
if self.dead == false and self.death_animation_timer == 0 then
|
||||
if self.do_custom_timer then
|
||||
self.do_custom_timer(self,dtime)
|
||||
end
|
||||
|
||||
if self.custom_function then
|
||||
self.custom_function(self,dtime,moveresult)
|
||||
end
|
||||
|
||||
self.move(self,dtime,moveresult)
|
||||
|
||||
self.flow(self)
|
||||
--self.debug_nametag(self,dtime)
|
||||
|
||||
self.manage_hurt_color_timer(self,dtime)
|
||||
|
||||
if self.manage_scared_timer then
|
||||
self.manage_scared_timer(self,dtime)
|
||||
end
|
||||
|
||||
if self.set_animation then
|
||||
self.set_animation(self)
|
||||
end
|
||||
|
||||
if self.look_around then
|
||||
self.look_around(self,dtime)
|
||||
end
|
||||
|
||||
if self.pathfinding then
|
||||
self.pathfinding(self,dtime)
|
||||
end
|
||||
|
||||
if self.handle_friendly_in_daylight_timer then
|
||||
self.handle_friendly_in_daylight_timer(self,dtime)
|
||||
end
|
||||
|
||||
self.manage_punch_timer(self,dtime)
|
||||
else
|
||||
self.manage_death_animation(self,dtime)
|
||||
if self.move_head then
|
||||
self.move_head(self,nil,dtime)
|
||||
end
|
||||
end
|
||||
|
||||
--fix zombie state again
|
||||
if self.dead == true and self.death_animation_timer <= 0 then
|
||||
self.on_death(self)
|
||||
end
|
||||
|
||||
if self.tnt_timer then
|
||||
self.manage_explode_timer(self,dtime)
|
||||
end
|
||||
|
||||
if self.projectile_timer then
|
||||
self.manage_projectile_timer(self,dtime)
|
||||
end
|
||||
|
||||
if self.custom_function_end then
|
||||
self.custom_function_end(self,dtime)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_entity("mob:"..def.mobname, mob_register)
|
||||
------------------------------------------------
|
||||
|
||||
end
|
|
@ -0,0 +1,105 @@
|
|||
local
|
||||
vector,minetest,math,pairs
|
||||
=
|
||||
vector,minetest,math,pairs
|
||||
--
|
||||
mobs.create_data_handling_functions = function(def,mob_register)
|
||||
|
||||
--mob_register.get_staticdata = function(self)
|
||||
--[[
|
||||
return minetest.serialize({
|
||||
--range = self.range,
|
||||
hp = self.hp,
|
||||
hunger = self.hunger,
|
||||
hostile = self.hostile,
|
||||
hostile_timer = self.hostile_timer,
|
||||
death_animation_timer = self.death_animation_timer,
|
||||
dead = self.dead,
|
||||
tnt_timer = self.tnt_timer,
|
||||
tnt_tick_timer = self.tnt_tick_timer,
|
||||
tnt_mod_state = self.tnt_mod_state,
|
||||
punch_timer = self.punch_timer,
|
||||
projectile_timer = self.projectile_timer,
|
||||
scared = self.scared,
|
||||
scared_timer = self.scared_timer,
|
||||
c_mob_data = self.c_mob_data,
|
||||
on_fire = self.on_fire,
|
||||
})
|
||||
]]--
|
||||
--end
|
||||
|
||||
mob_register.on_activate = function(self)--, staticdata, dtime_s)
|
||||
--[[
|
||||
if string.sub(staticdata, 1, string.len("return")) == "return" then
|
||||
local data = minetest.deserialize(staticdata)
|
||||
if data and type(data) == "table" then
|
||||
--self.range = data.range
|
||||
self.hp = data.hp
|
||||
self.hunger = data.hunger
|
||||
self.hostile = data.hostile
|
||||
self.hostile_timer = data.hostile_timer
|
||||
self.death_animation_timer = data.death_animation_timer
|
||||
self.dead = data.dead
|
||||
self.tnt_timer = data.tnt_timer
|
||||
self.tnt_tick_timer = data.tnt_tick_timer
|
||||
self.tnt_mod_state = data.tnt_mod_state
|
||||
self.punch_timer = data.punch_timer
|
||||
self.projectile_timer = data.projectile_timer
|
||||
self.scared = data.scared
|
||||
self.scared_timer = data.scared_timer
|
||||
self.c_mob_data = data.c_mob_data
|
||||
self.on_fire = data.on_fire
|
||||
end
|
||||
end
|
||||
]]--
|
||||
--set up mob
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
--self.object:set_velocity({x = math.random(-5,5), y = 5, z = math.random(-5,5)})
|
||||
self.object:set_acceleration(def.gravity)
|
||||
self.object:set_animation(def.standing_frame, 0, 0, true)
|
||||
self.current_animation = 0
|
||||
self.object:set_hp(self.hp)
|
||||
self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
|
||||
|
||||
|
||||
--set the head up
|
||||
if self.head_bone then
|
||||
self.object:set_bone_position(self.head_bone, self.head_position_correction, vector.new(0,0,0))
|
||||
end
|
||||
self.is_mob = true
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
|
||||
if self.custom_on_activate then
|
||||
self.custom_on_activate(self)
|
||||
end
|
||||
|
||||
if self.on_fire == true then
|
||||
start_fire(self.object)
|
||||
end
|
||||
|
||||
--use this to handle the global mob table
|
||||
--minetest.after(0,function()
|
||||
-- self.deactivating = true
|
||||
--end)
|
||||
end
|
||||
|
||||
--this is the info on the mob
|
||||
mob_register.debug_nametag = function(self,dtime)
|
||||
--we're doing this to the child because the nametage breaks the
|
||||
--animation on the mob's body
|
||||
|
||||
--we add in items we want to see in this list
|
||||
local debug_items = {"hostile","hostile_timer"}
|
||||
local text = ""
|
||||
for _,item in pairs(debug_items) do
|
||||
if self[item] ~= nil then
|
||||
text = text..item..": "..tostring(self[item]).."\n"
|
||||
end
|
||||
end
|
||||
self.object:set_nametag_attributes({
|
||||
color = "white",
|
||||
text = text
|
||||
})
|
||||
end
|
||||
return(mob_register)
|
||||
end
|
|
@ -0,0 +1,287 @@
|
|||
local
|
||||
minetest,math,vector
|
||||
=
|
||||
minetest,math,vector
|
||||
|
||||
--converts the degrees to radians
|
||||
local degrees_to_radians = function(degrees)
|
||||
--print(d)
|
||||
return(degrees/180.0*math.pi)
|
||||
end
|
||||
|
||||
--converts yaw to degrees
|
||||
local degrees = function(yaw)
|
||||
return(yaw*180.0/math.pi)
|
||||
end
|
||||
|
||||
--rounds it up to an integer
|
||||
local degree_round = function(degree)
|
||||
return(degree + 0.5 - (degree + 0.5) % 1)
|
||||
end
|
||||
--turns radians into degrees - not redundant
|
||||
--doesn't add math.pi
|
||||
local radians_to_degrees = function(radians)
|
||||
return(radians*180.0/math.pi)
|
||||
end
|
||||
|
||||
--make sure this is redefined as shown below aka
|
||||
--don't run mob_rotation_degree_to_radians(rotation)
|
||||
--run local radians = mob_rotation_degree_to_radians(rotation)
|
||||
--or the mobs head rotation will become overwritten
|
||||
local head_rotation_to_radians = function(rotation)
|
||||
return{
|
||||
x = 0, --roll should never be changed
|
||||
y = degrees_to_radians(180 - rotation.y)*-1,
|
||||
z = degrees_to_radians(90 - rotation.z)
|
||||
}
|
||||
end
|
||||
|
||||
--
|
||||
|
||||
local pos
|
||||
local body_yaw
|
||||
local head_yaw
|
||||
local dir
|
||||
local head_position
|
||||
local head_rotation
|
||||
mcl_mobs.create_head_functions = function(def,mob_register)
|
||||
--a movement test to move the head
|
||||
mob_register.move_head = function(self,pos2,dtime)
|
||||
if self.head_bone then
|
||||
if self.head_coord == "horizontal" then
|
||||
--print(self.head_bone)
|
||||
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
|
||||
--[[ debug
|
||||
if rotation then
|
||||
--print("--------------------------------")
|
||||
--rotation.x = rotation.x + 1
|
||||
rotation.z = rotation.z + 1
|
||||
rotation.y = 0
|
||||
|
||||
if rotation.x > 90 then
|
||||
rotation.x = -90
|
||||
end
|
||||
if rotation.z > 90 then
|
||||
rotation.z = -90
|
||||
end
|
||||
|
||||
--print(rotation.x)
|
||||
self.object:set_bone_position(self.head_bone, head_position, rotation)
|
||||
end
|
||||
]]--
|
||||
|
||||
--if passed a direction to look
|
||||
pos = self.object:get_pos()
|
||||
body_yaw = self.object:get_yaw()-math.pi/2+self.rotational_correction
|
||||
|
||||
dir = vector.multiply(minetest.yaw_to_dir(body_yaw),self.head_directional_offset)
|
||||
|
||||
|
||||
body_yaw = minetest.dir_to_yaw(dir)
|
||||
|
||||
--pos is where the head actually is
|
||||
pos = vector.add(pos,dir)
|
||||
pos.y = pos.y + self.head_height_offset
|
||||
|
||||
--use this to literally look around
|
||||
--self.head_pos = pos
|
||||
|
||||
--if self.debug_head_pos == true then
|
||||
-- minetest.add_particle({
|
||||
-- pos = pos,
|
||||
-- velocity = {x=0, y=0, z=0},
|
||||
-- acceleration = {x=0, y=0, z=0},
|
||||
-- expirationtime = 0.2,
|
||||
-- size = 1,
|
||||
-- texture = "dirt.png",
|
||||
-- })
|
||||
--end
|
||||
|
||||
--if the function was given a pos
|
||||
if pos2 then
|
||||
--compare the head yaw to the body
|
||||
--we must do a bunch of calculations to correct
|
||||
--strange function returns
|
||||
--for some reason get_yaw is offset 90 degrees
|
||||
head_yaw = minetest.dir_to_yaw(vector.direction(pos,pos2))
|
||||
head_yaw = minetest.dir_to_yaw(minetest.yaw_to_dir(head_yaw))
|
||||
head_yaw = degrees(head_yaw)-degrees(body_yaw)
|
||||
|
||||
if head_yaw < -180 then
|
||||
head_yaw = head_yaw + 360
|
||||
elseif head_yaw > 180 then
|
||||
head_yaw = head_yaw - 360
|
||||
end
|
||||
|
||||
--if within range then do calculations
|
||||
if head_yaw >= -90 and head_yaw <= 90 then
|
||||
---begin pitch calculation
|
||||
--feed a 2D coordinate flipped into dir to yaw to calculate pitch
|
||||
head_rotation.x = degrees(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)),0,pos.y-pos2.y))+(math.pi/2))
|
||||
if self.flip_pitch then
|
||||
head_rotation.x = head_rotation.x * -1
|
||||
end
|
||||
head_rotation.z = head_yaw
|
||||
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
|
||||
return(true)
|
||||
--nothing to look at
|
||||
else
|
||||
self.return_head_to_origin(self,dtime)
|
||||
return(false)
|
||||
end
|
||||
|
||||
--if nothing to look at
|
||||
else
|
||||
self.return_head_to_origin(self,dtime)
|
||||
return(false)
|
||||
end
|
||||
|
||||
elseif self.head_coord == "vertical" then
|
||||
--print(self.head_bone)
|
||||
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
|
||||
--[[ debug
|
||||
if rotation then
|
||||
--print("--------------------------------")
|
||||
--rotation.x = rotation.x + 1
|
||||
rotation.z = rotation.z + 1
|
||||
rotation.y = 0
|
||||
|
||||
if rotation.x > 90 then
|
||||
rotation.x = -90
|
||||
end
|
||||
if rotation.z > 90 then
|
||||
rotation.z = -90
|
||||
end
|
||||
|
||||
--print(rotation.x)
|
||||
self.object:set_bone_position(self.head_bone, head_position, rotation)
|
||||
end
|
||||
]]--
|
||||
|
||||
--print(self.head_rotation.y)
|
||||
--if passed a direction to look
|
||||
pos = self.object:get_pos()
|
||||
body_yaw = self.object:get_yaw()-math.pi/2+self.rotational_correction
|
||||
|
||||
dir = vector.multiply(minetest.yaw_to_dir(body_yaw),self.head_directional_offset)
|
||||
|
||||
|
||||
body_yaw = minetest.dir_to_yaw(dir)
|
||||
|
||||
--pos is where the head actually is
|
||||
pos = vector.add(pos,dir)
|
||||
pos.y = pos.y + self.head_height_offset
|
||||
|
||||
--use this to literally look around
|
||||
--self.head_pos = pos
|
||||
|
||||
--if self.debug_head_pos == true then
|
||||
-- minetest.add_particle({
|
||||
-- pos = pos,
|
||||
-- velocity = {x=0, y=0, z=0},
|
||||
-- acceleration = {x=0, y=0, z=0},
|
||||
-- expirationtime = 0.2,
|
||||
-- size = 1,
|
||||
-- texture = "dirt.png",
|
||||
-- })
|
||||
--end
|
||||
|
||||
--if the function was given a pos
|
||||
if pos2 then
|
||||
--compare the head yaw to the body
|
||||
--we must do a bunch of calculations to correct
|
||||
--strange function returns
|
||||
--for some reason get_yaw is offset 90 degrees
|
||||
head_yaw = minetest.dir_to_yaw(vector.direction(pos,pos2))
|
||||
head_yaw = minetest.dir_to_yaw(minetest.yaw_to_dir(head_yaw))
|
||||
head_yaw = degrees(head_yaw)-degrees(body_yaw)
|
||||
|
||||
if head_yaw < -180 then
|
||||
head_yaw = head_yaw + 360
|
||||
elseif head_yaw > 180 then
|
||||
head_yaw = head_yaw - 360
|
||||
end
|
||||
|
||||
--if within range then do calculations
|
||||
if head_yaw >= -90 and head_yaw <= 90 then
|
||||
---begin pitch calculation
|
||||
--feed a 2D coordinate flipped into dir to yaw to calculate pitch
|
||||
head_rotation.x = degrees(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)),0,pos.y-pos2.y))+(math.pi/2))
|
||||
if self.flip_pitch then
|
||||
head_rotation.x = head_rotation.x * -1
|
||||
end
|
||||
head_rotation.y = -head_yaw
|
||||
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
|
||||
return(true)
|
||||
--nothing to look at
|
||||
else
|
||||
self.return_head_to_origin(self,dtime)
|
||||
return(false)
|
||||
end
|
||||
|
||||
--if nothing to look at
|
||||
else
|
||||
self.return_head_to_origin(self,dtime)
|
||||
return(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--this sets the mob to move it's head back to pointing forwards
|
||||
|
||||
mob_register.return_head_to_origin = function(self,dtime)
|
||||
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
|
||||
|
||||
if self.head_coord == "horizontal" then
|
||||
--make the head yaw move back
|
||||
if head_rotation.x > 0 then
|
||||
head_rotation.x = head_rotation.x - (dtime*100)
|
||||
elseif head_rotation.x < 0 then
|
||||
head_rotation.x = head_rotation.x + (dtime*100)
|
||||
end
|
||||
|
||||
if math.abs(head_rotation.x) < (dtime*100) then
|
||||
head_rotation.x = 0
|
||||
end
|
||||
|
||||
|
||||
--move up down (pitch) back to center
|
||||
if head_rotation.z > 0 then
|
||||
head_rotation.z = head_rotation.z - (dtime*100)
|
||||
elseif head_rotation.z < 0 then
|
||||
head_rotation.z = head_rotation.z + (dtime*100)
|
||||
end
|
||||
|
||||
if math.abs(head_rotation.z) < (dtime*100) then
|
||||
head_rotation.z = 0
|
||||
end
|
||||
elseif self.head_coord == "vertical" then
|
||||
--make the head yaw move back
|
||||
if head_rotation.x > 0 then
|
||||
head_rotation.x = head_rotation.x - (dtime*100)
|
||||
elseif head_rotation.x < 0 then
|
||||
head_rotation.x = head_rotation.x + (dtime*100)
|
||||
end
|
||||
|
||||
if math.abs(head_rotation.x) < (dtime*100) then
|
||||
head_rotation.x = 0
|
||||
end
|
||||
|
||||
|
||||
--move up down (pitch) back to center
|
||||
if head_rotation.y > 0 then
|
||||
head_rotation.y = head_rotation.y - (dtime*100)
|
||||
elseif head_rotation.y < 0 then
|
||||
head_rotation.y = head_rotation.y + (dtime*100)
|
||||
end
|
||||
|
||||
if math.abs(head_rotation.y) < (dtime*100) then
|
||||
head_rotation.y = 0
|
||||
end
|
||||
end
|
||||
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
|
||||
end
|
||||
return(mob_register)
|
||||
end
|
|
@ -0,0 +1,287 @@
|
|||
local
|
||||
minetest,math,vector
|
||||
=
|
||||
minetest,math,vector
|
||||
|
||||
--converts the degrees to radians
|
||||
local degrees_to_radians = function(degrees)
|
||||
--print(d)
|
||||
return(degrees/180.0*math.pi)
|
||||
end
|
||||
|
||||
--converts yaw to degrees
|
||||
local degrees = function(yaw)
|
||||
return(yaw*180.0/math.pi)
|
||||
end
|
||||
|
||||
--rounds it up to an integer
|
||||
local degree_round = function(degree)
|
||||
return(degree + 0.5 - (degree + 0.5) % 1)
|
||||
end
|
||||
--turns radians into degrees - not redundant
|
||||
--doesn't add math.pi
|
||||
local radians_to_degrees = function(radians)
|
||||
return(radians*180.0/math.pi)
|
||||
end
|
||||
|
||||
--make sure this is redefined as shown below aka
|
||||
--don't run mob_rotation_degree_to_radians(rotation)
|
||||
--run local radians = mob_rotation_degree_to_radians(rotation)
|
||||
--or the mobs head rotation will become overwritten
|
||||
local head_rotation_to_radians = function(rotation)
|
||||
return{
|
||||
x = 0, --roll should never be changed
|
||||
y = degrees_to_radians(180 - rotation.y)*-1,
|
||||
z = degrees_to_radians(90 - rotation.z)
|
||||
}
|
||||
end
|
||||
|
||||
--
|
||||
|
||||
local pos
|
||||
local body_yaw
|
||||
local head_yaw
|
||||
local dir
|
||||
local head_position
|
||||
local head_rotation
|
||||
mobs.create_head_functions = function(def,mob_register)
|
||||
--a movement test to move the head
|
||||
mob_register.move_head = function(self,pos2,dtime)
|
||||
if self.head_bone then
|
||||
if self.head_coord == "horizontal" then
|
||||
--print(self.head_bone)
|
||||
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
|
||||
--[[ debug
|
||||
if rotation then
|
||||
--print("--------------------------------")
|
||||
--rotation.x = rotation.x + 1
|
||||
rotation.z = rotation.z + 1
|
||||
rotation.y = 0
|
||||
|
||||
if rotation.x > 90 then
|
||||
rotation.x = -90
|
||||
end
|
||||
if rotation.z > 90 then
|
||||
rotation.z = -90
|
||||
end
|
||||
|
||||
--print(rotation.x)
|
||||
self.object:set_bone_position(self.head_bone, head_position, rotation)
|
||||
end
|
||||
]]--
|
||||
|
||||
--if passed a direction to look
|
||||
pos = self.object:get_pos()
|
||||
body_yaw = self.object:get_yaw()-math.pi/2+self.rotational_correction
|
||||
|
||||
dir = vector.multiply(minetest.yaw_to_dir(body_yaw),self.head_directional_offset)
|
||||
|
||||
|
||||
body_yaw = minetest.dir_to_yaw(dir)
|
||||
|
||||
--pos is where the head actually is
|
||||
pos = vector.add(pos,dir)
|
||||
pos.y = pos.y + self.head_height_offset
|
||||
|
||||
--use this to literally look around
|
||||
--self.head_pos = pos
|
||||
|
||||
--if self.debug_head_pos == true then
|
||||
-- minetest.add_particle({
|
||||
-- pos = pos,
|
||||
-- velocity = {x=0, y=0, z=0},
|
||||
-- acceleration = {x=0, y=0, z=0},
|
||||
-- expirationtime = 0.2,
|
||||
-- size = 1,
|
||||
-- texture = "dirt.png",
|
||||
-- })
|
||||
--end
|
||||
|
||||
--if the function was given a pos
|
||||
if pos2 then
|
||||
--compare the head yaw to the body
|
||||
--we must do a bunch of calculations to correct
|
||||
--strange function returns
|
||||
--for some reason get_yaw is offset 90 degrees
|
||||
head_yaw = minetest.dir_to_yaw(vector.direction(pos,pos2))
|
||||
head_yaw = minetest.dir_to_yaw(minetest.yaw_to_dir(head_yaw))
|
||||
head_yaw = degrees(head_yaw)-degrees(body_yaw)
|
||||
|
||||
if head_yaw < -180 then
|
||||
head_yaw = head_yaw + 360
|
||||
elseif head_yaw > 180 then
|
||||
head_yaw = head_yaw - 360
|
||||
end
|
||||
|
||||
--if within range then do calculations
|
||||
if head_yaw >= -90 and head_yaw <= 90 then
|
||||
---begin pitch calculation
|
||||
--feed a 2D coordinate flipped into dir to yaw to calculate pitch
|
||||
head_rotation.x = degrees(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)),0,pos.y-pos2.y))+(math.pi/2))
|
||||
if self.flip_pitch then
|
||||
head_rotation.x = head_rotation.x * -1
|
||||
end
|
||||
head_rotation.z = head_yaw
|
||||
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
|
||||
return(true)
|
||||
--nothing to look at
|
||||
else
|
||||
self.return_head_to_origin(self,dtime)
|
||||
return(false)
|
||||
end
|
||||
|
||||
--if nothing to look at
|
||||
else
|
||||
self.return_head_to_origin(self,dtime)
|
||||
return(false)
|
||||
end
|
||||
|
||||
elseif self.head_coord == "vertical" then
|
||||
--print(self.head_bone)
|
||||
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
|
||||
--[[ debug
|
||||
if rotation then
|
||||
--print("--------------------------------")
|
||||
--rotation.x = rotation.x + 1
|
||||
rotation.z = rotation.z + 1
|
||||
rotation.y = 0
|
||||
|
||||
if rotation.x > 90 then
|
||||
rotation.x = -90
|
||||
end
|
||||
if rotation.z > 90 then
|
||||
rotation.z = -90
|
||||
end
|
||||
|
||||
--print(rotation.x)
|
||||
self.object:set_bone_position(self.head_bone, head_position, rotation)
|
||||
end
|
||||
]]--
|
||||
|
||||
--print(self.head_rotation.y)
|
||||
--if passed a direction to look
|
||||
pos = self.object:get_pos()
|
||||
body_yaw = self.object:get_yaw()-math.pi/2+self.rotational_correction
|
||||
|
||||
dir = vector.multiply(minetest.yaw_to_dir(body_yaw),self.head_directional_offset)
|
||||
|
||||
|
||||
body_yaw = minetest.dir_to_yaw(dir)
|
||||
|
||||
--pos is where the head actually is
|
||||
pos = vector.add(pos,dir)
|
||||
pos.y = pos.y + self.head_height_offset
|
||||
|
||||
--use this to literally look around
|
||||
--self.head_pos = pos
|
||||
|
||||
--if self.debug_head_pos == true then
|
||||
-- minetest.add_particle({
|
||||
-- pos = pos,
|
||||
-- velocity = {x=0, y=0, z=0},
|
||||
-- acceleration = {x=0, y=0, z=0},
|
||||
-- expirationtime = 0.2,
|
||||
-- size = 1,
|
||||
-- texture = "dirt.png",
|
||||
-- })
|
||||
--end
|
||||
|
||||
--if the function was given a pos
|
||||
if pos2 then
|
||||
--compare the head yaw to the body
|
||||
--we must do a bunch of calculations to correct
|
||||
--strange function returns
|
||||
--for some reason get_yaw is offset 90 degrees
|
||||
head_yaw = minetest.dir_to_yaw(vector.direction(pos,pos2))
|
||||
head_yaw = minetest.dir_to_yaw(minetest.yaw_to_dir(head_yaw))
|
||||
head_yaw = degrees(head_yaw)-degrees(body_yaw)
|
||||
|
||||
if head_yaw < -180 then
|
||||
head_yaw = head_yaw + 360
|
||||
elseif head_yaw > 180 then
|
||||
head_yaw = head_yaw - 360
|
||||
end
|
||||
|
||||
--if within range then do calculations
|
||||
if head_yaw >= -90 and head_yaw <= 90 then
|
||||
---begin pitch calculation
|
||||
--feed a 2D coordinate flipped into dir to yaw to calculate pitch
|
||||
head_rotation.x = degrees(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)),0,pos.y-pos2.y))+(math.pi/2))
|
||||
if self.flip_pitch then
|
||||
head_rotation.x = head_rotation.x * -1
|
||||
end
|
||||
head_rotation.y = -head_yaw
|
||||
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
|
||||
return(true)
|
||||
--nothing to look at
|
||||
else
|
||||
self.return_head_to_origin(self,dtime)
|
||||
return(false)
|
||||
end
|
||||
|
||||
--if nothing to look at
|
||||
else
|
||||
self.return_head_to_origin(self,dtime)
|
||||
return(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--this sets the mob to move it's head back to pointing forwards
|
||||
|
||||
mob_register.return_head_to_origin = function(self,dtime)
|
||||
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
|
||||
|
||||
if self.head_coord == "horizontal" then
|
||||
--make the head yaw move back
|
||||
if head_rotation.x > 0 then
|
||||
head_rotation.x = head_rotation.x - (dtime*100)
|
||||
elseif head_rotation.x < 0 then
|
||||
head_rotation.x = head_rotation.x + (dtime*100)
|
||||
end
|
||||
|
||||
if math.abs(head_rotation.x) < (dtime*100) then
|
||||
head_rotation.x = 0
|
||||
end
|
||||
|
||||
|
||||
--move up down (pitch) back to center
|
||||
if head_rotation.z > 0 then
|
||||
head_rotation.z = head_rotation.z - (dtime*100)
|
||||
elseif head_rotation.z < 0 then
|
||||
head_rotation.z = head_rotation.z + (dtime*100)
|
||||
end
|
||||
|
||||
if math.abs(head_rotation.z) < (dtime*100) then
|
||||
head_rotation.z = 0
|
||||
end
|
||||
elseif self.head_coord == "vertical" then
|
||||
--make the head yaw move back
|
||||
if head_rotation.x > 0 then
|
||||
head_rotation.x = head_rotation.x - (dtime*100)
|
||||
elseif head_rotation.x < 0 then
|
||||
head_rotation.x = head_rotation.x + (dtime*100)
|
||||
end
|
||||
|
||||
if math.abs(head_rotation.x) < (dtime*100) then
|
||||
head_rotation.x = 0
|
||||
end
|
||||
|
||||
|
||||
--move up down (pitch) back to center
|
||||
if head_rotation.y > 0 then
|
||||
head_rotation.y = head_rotation.y - (dtime*100)
|
||||
elseif head_rotation.y < 0 then
|
||||
head_rotation.y = head_rotation.y + (dtime*100)
|
||||
end
|
||||
|
||||
if math.abs(head_rotation.y) < (dtime*100) then
|
||||
head_rotation.y = 0
|
||||
end
|
||||
end
|
||||
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
|
||||
end
|
||||
return(mob_register)
|
||||
end
|
|
@ -0,0 +1,506 @@
|
|||
local
|
||||
minetest,math,vector,ipairs
|
||||
=
|
||||
minetest,math,vector,ipairs
|
||||
--
|
||||
--for add sword wear
|
||||
local itemstack
|
||||
local wear
|
||||
--for collision detection
|
||||
local pos
|
||||
local collision_count
|
||||
local collisionbox
|
||||
local collision_boundary
|
||||
local radius
|
||||
local pos2
|
||||
local object_collisionbox
|
||||
local object_collision_boundary
|
||||
local y_base_diff
|
||||
local y_top_diff
|
||||
local distance
|
||||
local dir
|
||||
local velocity
|
||||
local vel1
|
||||
local vel2
|
||||
--for fall damage
|
||||
local vel
|
||||
local damage
|
||||
--for on_punch
|
||||
local hp
|
||||
local hurt
|
||||
local critical
|
||||
local puncher_vel
|
||||
--for item drop
|
||||
local item
|
||||
local data_item_amount
|
||||
--for look around
|
||||
local light_level
|
||||
local player_found
|
||||
local player_punch_timer
|
||||
local line_of_sight
|
||||
local obj
|
||||
local sound_max
|
||||
local sound_min
|
||||
local head_pos
|
||||
local light
|
||||
local fire_it_up
|
||||
mobs.create_interaction_functions = function(def,mob_register)
|
||||
|
||||
mob_register.flow = function(self)
|
||||
local flow_dir = flow(self.object:get_pos())
|
||||
if flow_dir then
|
||||
flow_dir = vector.multiply(flow_dir,10)
|
||||
local vel = self.object:get_velocity()
|
||||
local acceleration = vector.new(flow_dir.x-vel.x,flow_dir.y-vel.y,flow_dir.z-vel.z)
|
||||
acceleration = vector.multiply(acceleration, 0.01)
|
||||
self.object:add_velocity(acceleration)
|
||||
end
|
||||
end
|
||||
|
||||
--the pig will look for and at players
|
||||
mob_register.look_around = function(self,dtime)
|
||||
pos = self.object:get_pos()
|
||||
|
||||
if self.die_in_light then
|
||||
fire_it_up = false
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "extinguish") > 0 then
|
||||
fire_it_up = false
|
||||
else
|
||||
head_pos = table.copy(pos)
|
||||
head_pos.y = head_pos.y + self.object:get_properties().collisionbox[5]
|
||||
light = minetest.get_node_light(head_pos)
|
||||
if light and light == 15 then
|
||||
if weather_type == 2 then
|
||||
fire_it_up = false
|
||||
else
|
||||
fire_it_up = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if fire_it_up then
|
||||
start_fire(self.object)
|
||||
end
|
||||
end
|
||||
|
||||
if self.on_fire then
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "extinguish") > 0 then
|
||||
put_fire_out(self.object)
|
||||
else
|
||||
head_pos = table.copy(pos)
|
||||
head_pos.y = head_pos.y + self.object:get_properties().collisionbox[5]
|
||||
light = minetest.get_node_light(head_pos, 0.5)
|
||||
if light and light == 15 then
|
||||
if weather_type == 2 then
|
||||
put_fire_out(self.object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--STARE O_O
|
||||
--and follow!
|
||||
self.following = false
|
||||
player_found = false
|
||||
|
||||
for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.view_distance)) do
|
||||
if object:is_player() and player_found == false and object:get_hp() > 0 then
|
||||
--look at player's camera
|
||||
pos2 = object:get_pos()
|
||||
pos2.y = pos2.y + 1.625
|
||||
|
||||
player_found = true
|
||||
|
||||
if self.head_bone then
|
||||
self.move_head(self,pos2,dtime)
|
||||
end
|
||||
|
||||
--print(self.hostile)
|
||||
if self.hostile == true then
|
||||
distance = vector.distance(pos,pos2)
|
||||
self.following_pos = vector.new(pos2.x,pos2.y-1.625,pos2.z)
|
||||
|
||||
--punch the player
|
||||
if self.attack_type == "punch" then
|
||||
if distance < 2.5 and self.punch_timer <= 0 and object:get_hp() > 0 then
|
||||
if player_can_be_punched(object) then
|
||||
line_of_sight = minetest.line_of_sight(pos, pos2)
|
||||
if line_of_sight == true then
|
||||
self.punch_timer = 0.5
|
||||
object:punch(self.object, 2,
|
||||
{
|
||||
full_punch_interval=1.5,
|
||||
damage_groups = {damage=self.attack_damage},
|
||||
},vector.direction(pos,pos2))
|
||||
--light the player on fire
|
||||
if self.on_fire then
|
||||
start_fire(object)
|
||||
end
|
||||
if is_player_on_fire(object) then
|
||||
start_fire(self.object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif self.attack_type == "explode" then
|
||||
--mob will not explode if it cannot see you
|
||||
if distance < self.explosion_radius and minetest.line_of_sight(vector.new(pos.x,pos.y+self.object:get_properties().collisionbox[5],pos.z), pos2) then
|
||||
|
||||
if not self.tnt_timer then
|
||||
minetest.sound_play("tnt_ignite", {object = self.object, gain = 1.0,})
|
||||
self.tnt_timer = self.explosion_time
|
||||
self.tnt_tick_timer = 0.2
|
||||
self.tnt_mod_state = 1
|
||||
self.object:set_texture_mod("^[colorize:white:130")
|
||||
end
|
||||
end
|
||||
elseif self.attack_type == "projectile" then
|
||||
if not self.projectile_timer then
|
||||
self.projectile_timer = self.projectile_timer_cooldown
|
||||
end
|
||||
if self.projectile_timer <= 0 then
|
||||
self.projectile_timer = self.projectile_timer_cooldown
|
||||
|
||||
obj = minetest.add_entity(vector.new(pos.x,pos.y+self.object:get_properties().collisionbox[5],pos.z), self.projectile_type)
|
||||
if obj then
|
||||
dir = vector.multiply(vector.direction(pos,vector.new(pos2.x,pos2.y-3,pos2.z)), 50)
|
||||
obj:set_velocity(dir)
|
||||
obj:get_luaentity().timer = 2
|
||||
obj:get_luaentity().owner = self.object
|
||||
end
|
||||
end
|
||||
end
|
||||
--smart
|
||||
if self.path_data and table.getn(self.path_data) > 0 then
|
||||
self.direction = vector.direction(vector.new(pos.x,0,pos.z), vector.new(self.path_data[1].x,0,self.path_data[1].z))
|
||||
--dumb
|
||||
else
|
||||
self.direction = vector.direction(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z))
|
||||
end
|
||||
self.speed = self.max_speed
|
||||
self.following = true
|
||||
elseif self.scared == true then
|
||||
self.speed = self.max_speed
|
||||
self.direction = vector.direction(vector.new(pos2.x,0,pos2.z),vector.new(pos.x,0,pos.z))
|
||||
self.scared_timer = 10
|
||||
end
|
||||
--only look at one player
|
||||
break
|
||||
end
|
||||
end
|
||||
--stare straight if not found
|
||||
if player_found == false then
|
||||
if self.move_head then
|
||||
self.move_head(self,nil,dtime)
|
||||
end
|
||||
if self.following_pos then
|
||||
self.following_pos = nil
|
||||
end
|
||||
if self.manage_hostile_timer then
|
||||
self.manage_hostile_timer(self,dtime)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--this is what happens when a mob dies
|
||||
mob_register.on_death = function(self, killer)
|
||||
pos = self.object:get_pos()
|
||||
if def.hp then
|
||||
minetest.throw_experience(pos,math.ceil(def.hp/5)+math.random(0,1))
|
||||
end
|
||||
--pos.y = pos.y + 0.4
|
||||
minetest.sound_play("mob_die", {pos = pos, gain = 1.0})
|
||||
minetest.add_particlespawner({
|
||||
amount = 40,
|
||||
time = 0.001,
|
||||
minpos = pos,
|
||||
maxpos = pos,
|
||||
minvel = vector.new(-5,-5,-5),
|
||||
maxvel = vector.new(5,5,5),
|
||||
minacc = {x=0, y=0, z=0},
|
||||
maxacc = {x=0, y=0, z=0},
|
||||
minexptime = 1.1,
|
||||
maxexptime = 1.5,
|
||||
minsize = 1,
|
||||
maxsize = 2,
|
||||
collisiondetection = false,
|
||||
vertical = false,
|
||||
texture = "smoke.png",
|
||||
})
|
||||
|
||||
--only throw items if registered
|
||||
if self.item_drop then
|
||||
if type(self.item_drop) == "string" then
|
||||
item = self.item_drop
|
||||
elseif type(self.item_drop) == "table" then
|
||||
item = self.item_drop[math.random(1,table.getn(self.item_drop))]
|
||||
end
|
||||
--detect if multiple items are going to be added
|
||||
if self.item_max then
|
||||
data_item_amount = math.random(self.item_minimum, self.item_max)
|
||||
for i = 1 ,data_item_amount do
|
||||
minetest.throw_item(vector.new(pos.x,pos.y+0.1,pos.z),item)
|
||||
end
|
||||
else
|
||||
minetest.throw_item(vector.new(pos.x,pos.y+0.1,pos.z),item)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if self.custom_on_death then
|
||||
self.custom_on_death(self)
|
||||
end
|
||||
|
||||
self.object:remove()
|
||||
end
|
||||
--this controls what happens when the mob gets punched
|
||||
mob_register.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||
hp = self.hp
|
||||
vel = self.object:get_velocity()
|
||||
hurt = tool_capabilities.damage_groups.damage
|
||||
|
||||
if not hurt then
|
||||
hurt = 1
|
||||
end
|
||||
|
||||
critical = false
|
||||
|
||||
--criticals
|
||||
pos = self.object:get_pos()
|
||||
if puncher:is_player() then
|
||||
puncher_vel = puncher:get_player_velocity().y
|
||||
if puncher_vel < 0 then
|
||||
hurt = hurt * 1.5
|
||||
critical = true
|
||||
end
|
||||
end
|
||||
|
||||
hp = hp-hurt
|
||||
|
||||
if (self.punched_timer <= 0 and hp > 1) and not self.dead then
|
||||
self.object:set_texture_mod("^[colorize:"..self.damage_color..":130")
|
||||
self.hurt_color_timer = 0.25
|
||||
if puncher ~= self.object then
|
||||
self.punched_timer = 0.25
|
||||
if self.attacked_hostile then
|
||||
self.hostile = true
|
||||
self.hostile_timer = 20
|
||||
if self.group_attack == true then
|
||||
for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.view_distance)) do
|
||||
|
||||
if not object:is_player() and object:get_luaentity() and object:get_luaentity().mobname == self.mobname then
|
||||
object:get_luaentity().hostile = true
|
||||
object:get_luaentity().hostile_timer = 20
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
self.scared = true
|
||||
self.scared_timer = 10
|
||||
end
|
||||
if self.custom_on_punch then
|
||||
self.custom_on_punch(self)
|
||||
end
|
||||
end
|
||||
|
||||
--critical effect
|
||||
if critical == true then
|
||||
self.do_critical_particles(pos)
|
||||
minetest.sound_play("critical", {object=self.object, gain = 0.1, max_hear_distance = 10,pitch = math.random(80,100)/100})
|
||||
end
|
||||
|
||||
sound_min = self.sound_pitch_mod_min or 100
|
||||
sound_max = self.sound_pitch_mod_max or 140
|
||||
|
||||
minetest.sound_play(self.hurt_sound, {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(sound_min,sound_max)/100})
|
||||
|
||||
self.hp = hp
|
||||
|
||||
dir = vector.multiply(dir,10)
|
||||
if vel.y <= 0 then
|
||||
dir.y = 4
|
||||
else
|
||||
dir.y = 0
|
||||
end
|
||||
|
||||
|
||||
self.object:add_velocity(dir)
|
||||
self.add_sword_wear(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||
elseif (self.punched_timer <= 0 and self.death_animation_timer == 0) then
|
||||
self.object:set_texture_mod("^[colorize:"..self.damage_color..":130")
|
||||
self.hurt_color_timer = 0.25
|
||||
if puncher ~= self.object then
|
||||
self.punched_timer = 0.25
|
||||
if self.attacked_hostile then
|
||||
self.hostile = true
|
||||
self.hostile_timer = 20
|
||||
if self.group_attack == true then
|
||||
for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.view_distance)) do
|
||||
if not object:is_player() and object:get_luaentity() and object:get_luaentity().mobname == self.mobname then
|
||||
object:get_luaentity().hostile = true
|
||||
object:get_luaentity().hostile_timer = 20
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.custom_on_punch then
|
||||
self.custom_on_punch(self)
|
||||
end
|
||||
end
|
||||
self.death_animation_timer = 1
|
||||
self.dead = true
|
||||
|
||||
--critical effect
|
||||
if critical == true then
|
||||
self.do_critical_particles(pos)
|
||||
minetest.sound_play("critical", {object=self.object, gain = 0.1, max_hear_distance = 10,pitch = math.random(80,100)/100})
|
||||
end
|
||||
|
||||
sound_min = self.sound_pitch_mod_min_die or 80
|
||||
sound_max = self.sound_pitch_mod_max_die or 100
|
||||
|
||||
minetest.sound_play(self.die_sound, {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(sound_min,sound_max)/100})
|
||||
|
||||
self.add_sword_wear(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||
end
|
||||
end
|
||||
|
||||
mob_register.collision_detection = function(self)
|
||||
pos = self.object:get_pos()
|
||||
--do collision detection from the base of the mob
|
||||
|
||||
collisionbox = self.object:get_properties().collisionbox
|
||||
|
||||
pos.y = pos.y + collisionbox[2]
|
||||
|
||||
collision_boundary = collisionbox[4]
|
||||
|
||||
radius = collision_boundary
|
||||
|
||||
if collisionbox[5] > collision_boundary then
|
||||
radius = collisionbox[5]
|
||||
end
|
||||
collision_count = 0
|
||||
for _,object in ipairs(minetest.get_objects_inside_radius(pos, radius*1.25)) do
|
||||
if object ~= self.object and (object:is_player() or object:get_luaentity().mob == true) and
|
||||
--don't collide with rider, rider don't collide with thing
|
||||
(not object:get_attach() or (object:get_attach() and object:get_attach() ~= self.object)) and
|
||||
(not self.object:get_attach() or (self.object:get_attach() and self.object:get_attach() ~= object)) then
|
||||
--stop infinite loop
|
||||
collision_count = collision_count + 1
|
||||
if collision_count > 100 then
|
||||
break
|
||||
end
|
||||
pos2 = object:get_pos()
|
||||
|
||||
object_collisionbox = object:get_properties().collisionbox
|
||||
|
||||
pos2.y = pos2.y + object_collisionbox[2]
|
||||
|
||||
object_collision_boundary = object_collisionbox[4]
|
||||
|
||||
|
||||
--this is checking the difference of the object collided with's possision
|
||||
--if positive top of other object is inside (y axis) of current object
|
||||
y_base_diff = (pos2.y + object_collisionbox[5]) - pos.y
|
||||
|
||||
y_top_diff = (pos.y + collisionbox[5]) - pos2.y
|
||||
|
||||
|
||||
distance = vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z))
|
||||
|
||||
if distance <= collision_boundary + object_collision_boundary and y_base_diff >= 0 and y_top_diff >= 0 then
|
||||
|
||||
dir = vector.direction(pos,pos2)
|
||||
dir.y = 0
|
||||
|
||||
--eliminate mob being stuck in corners
|
||||
if dir.x == 0 and dir.z == 0 then
|
||||
dir = vector.new(math.random(-1,1)*math.random(),0,math.random(-1,1)*math.random())
|
||||
end
|
||||
|
||||
velocity = vector.multiply(dir,1.1)
|
||||
|
||||
vel1 = vector.multiply(velocity, -1)
|
||||
vel2 = velocity
|
||||
|
||||
self.object:add_velocity(vel1)
|
||||
|
||||
if object:is_player() then
|
||||
object:add_player_velocity(vel2)
|
||||
if self.on_fire then
|
||||
start_fire(object)
|
||||
end
|
||||
if is_player_on_fire(object) then
|
||||
start_fire(self.object)
|
||||
end
|
||||
else
|
||||
object:add_velocity(vel2)
|
||||
if self.on_fire then
|
||||
start_fire(object)
|
||||
end
|
||||
if object:get_luaentity().on_fire then
|
||||
start_fire(self.object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--the sword wear mechanic
|
||||
mob_register.add_sword_wear = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||
if puncher:is_player() then
|
||||
itemstack = puncher:get_wielded_item()
|
||||
wear = itemstack:get_definition().mob_hit_wear
|
||||
if wear then
|
||||
itemstack:add_wear(wear)
|
||||
if itemstack:get_name() == "" then
|
||||
minetest.sound_play("tool_break",{to_player = puncher:get_player_name(),gain=0.4})
|
||||
end
|
||||
puncher:set_wielded_item(itemstack)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--critical effect particles
|
||||
mob_register.do_critical_particles = function(pos)
|
||||
minetest.add_particlespawner({
|
||||
amount = 40,
|
||||
time = 0.001,
|
||||
minpos = pos,
|
||||
maxpos = pos,
|
||||
minvel = vector.new(-2,-2,-2),
|
||||
maxvel = vector.new(2,8,2),
|
||||
minacc = {x=0, y=4, z=0},
|
||||
maxacc = {x=0, y=12, z=0},
|
||||
minexptime = 1.1,
|
||||
maxexptime = 1.5,
|
||||
minsize = 1,
|
||||
maxsize = 2,
|
||||
collisiondetection = false,
|
||||
vertical = false,
|
||||
texture = "critical.png",
|
||||
})
|
||||
end
|
||||
|
||||
if def.takes_fall_damage == nil or def.takes_fall_damage == true then
|
||||
mob_register.fall_damage = function(self)
|
||||
vel = self.object:get_velocity()
|
||||
if vel and self.oldvel then
|
||||
if self.oldvel.y < -7 and vel.y == 0 then
|
||||
damage = math.abs(self.oldvel.y + 7)
|
||||
damage = math.floor(damage/1.5)
|
||||
self.object:punch(self.object, 2,
|
||||
{
|
||||
full_punch_interval=1.5,
|
||||
damage_groups = {damage=damage},
|
||||
})
|
||||
end
|
||||
end
|
||||
self.oldvel = vel
|
||||
end
|
||||
end
|
||||
|
||||
return(mob_register)
|
||||
end
|
|
@ -0,0 +1,400 @@
|
|||
local
|
||||
minetest,math,vector,pairs,table
|
||||
=
|
||||
minetest,math,vector,pairs,table
|
||||
|
||||
local pos
|
||||
local node
|
||||
local vel
|
||||
local goal
|
||||
local acceleration
|
||||
local hurt
|
||||
local fire
|
||||
local currentvel
|
||||
local goal
|
||||
local y
|
||||
local modifier
|
||||
local pos2
|
||||
local ray
|
||||
local pointed_thing
|
||||
|
||||
local acute_pos
|
||||
local height_diff
|
||||
local acute_following_pos
|
||||
local min
|
||||
local max
|
||||
local index_table
|
||||
local path
|
||||
local number
|
||||
local pos1
|
||||
local pos3
|
||||
local can_cut
|
||||
local _
|
||||
|
||||
--index all mods
|
||||
local all_walkable_nodes = {}
|
||||
minetest.register_on_mods_loaded(function()
|
||||
for name in pairs(minetest.registered_nodes) do
|
||||
if name ~= "air" and name ~= "ignore" then
|
||||
if minetest.get_nodedef(name,"walkable") then
|
||||
table.insert(all_walkable_nodes,name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
mobs.create_movement_functions = function(def,mob_register)
|
||||
--makes the mob swim
|
||||
mob_register.swim = function(self,dtime)
|
||||
pos = self.object:get_pos()
|
||||
pos.y = pos.y + 0.3
|
||||
node = minetest.get_node(pos).name
|
||||
self.swimming = false
|
||||
if node == "main:water" or node =="main:waterflow" then
|
||||
vel = self.object:get_velocity()
|
||||
goal = 3
|
||||
acceleration = vector.new(0,goal-vel.y,0)
|
||||
--jump out of the water
|
||||
if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
--else swim
|
||||
else
|
||||
self.object:add_velocity(acceleration)
|
||||
end
|
||||
self.swimming = true
|
||||
end
|
||||
end
|
||||
|
||||
mob_register.hurt_inside = function(self,dtime)
|
||||
if self.hp > 0 and self.hurt_inside_timer <= 0 then
|
||||
pos = self.object:get_pos()
|
||||
node = minetest.get_node(pos).name
|
||||
hurt = minetest.get_item_group(node, "hurt_inside")
|
||||
if hurt > 0 then
|
||||
self.object:punch(self.object, 2,
|
||||
{
|
||||
full_punch_interval=1.5,
|
||||
damage_groups = {damage=hurt},
|
||||
})
|
||||
end
|
||||
fire = minetest.get_item_group(node, "fire")
|
||||
if not self.on_fire and fire > 0 then
|
||||
start_fire(self.object)
|
||||
end
|
||||
self.hurt_inside_timer = 0.25
|
||||
else
|
||||
self.hurt_inside_timer = self.hurt_inside_timer - dtime
|
||||
end
|
||||
end
|
||||
|
||||
--This makes the mob walk at a certain speed and jump
|
||||
if def.movement_type == "walk" then
|
||||
mob_register.move = function(self,dtime,moveresult)
|
||||
self.manage_jump_timer(self,dtime)
|
||||
self.timer = self.timer - dtime
|
||||
|
||||
--jump
|
||||
self.jump(self,moveresult)
|
||||
|
||||
--swim
|
||||
self.swim(self,dtime)
|
||||
|
||||
--print(self.timer)
|
||||
--direction state change
|
||||
if self.timer <= 0 and not self.following == true then
|
||||
--print("changing direction")
|
||||
self.timer = math.random(2,7)
|
||||
self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
|
||||
--local yaw = self.object:get_yaw() + dtime
|
||||
self.speed = math.random(0,self.max_speed)
|
||||
--self.object:set_yaw(yaw)
|
||||
end
|
||||
|
||||
self.hurt_inside(self,dtime)
|
||||
|
||||
currentvel = self.object:get_velocity()
|
||||
goal = vector.multiply(self.direction,self.speed)
|
||||
acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
|
||||
if self.whip_turn then
|
||||
self.whip_turn = self.whip_turn - dtime
|
||||
if self.whip_turn <= 0 then
|
||||
self.whip_turn = nil
|
||||
end
|
||||
else
|
||||
acceleration = vector.multiply(acceleration, 0.05)
|
||||
end
|
||||
self.object:add_velocity(acceleration)
|
||||
end
|
||||
mob_register.jump = function(self,moveresult)
|
||||
if moveresult and moveresult.touching_ground and self.direction then
|
||||
pos = self.object:get_pos()
|
||||
pos.y = pos.y+0.1
|
||||
|
||||
if self.path_data and table.getn(self.path_data) > 0 then
|
||||
--smart jump
|
||||
y = math.floor(pos.y+0.5)
|
||||
vel = self.object:get_velocity()
|
||||
if y < self.path_data[1].y then
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
elseif self.path_data[2] and y < self.path_data[2].y then
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
elseif self.path_data[3] and y < self.path_data[3].y then
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
elseif ((vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0)) then
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
end
|
||||
else
|
||||
--assume collisionbox is even x and z
|
||||
modifier = self.object:get_properties().collisionbox[4]*3
|
||||
|
||||
|
||||
pos2 = vector.add(vector.multiply(self.direction,modifier),pos)
|
||||
|
||||
ray = minetest.raycast(pos, pos2, false, false)
|
||||
|
||||
pointed_thing = nil
|
||||
|
||||
if ray then
|
||||
pointed_thing = ray:next()
|
||||
end
|
||||
|
||||
if pointed_thing then
|
||||
if minetest.get_nodedef(minetest.get_node(pointed_thing.under).name, "walkable") then
|
||||
--print("jump")
|
||||
vel = self.object:get_velocity()
|
||||
--self.jump_timer = 1+math.random()
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
else
|
||||
--print("velocity check")
|
||||
vel = self.object:get_velocity()
|
||||
if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
end
|
||||
end
|
||||
else
|
||||
--print("velcheck 2")
|
||||
vel = self.object:get_velocity()
|
||||
if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif def.movement_type == "jump" then
|
||||
mob_register.move = function(self,dtime,moveresult)
|
||||
self.manage_jump_timer(self,dtime)
|
||||
self.timer = self.timer - dtime
|
||||
|
||||
--jump
|
||||
self.jump(self,moveresult)
|
||||
|
||||
--swim
|
||||
self.swim(self,dtime)
|
||||
|
||||
--direction state change
|
||||
if self.timer <= 0 and not self.following == true then
|
||||
--print("changing direction")
|
||||
self.timer = math.random(2,7)
|
||||
self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
|
||||
--local yaw = self.object:get_yaw() + dtime
|
||||
self.speed = math.random(0,self.max_speed)
|
||||
--self.object:set_yaw(yaw)
|
||||
end
|
||||
|
||||
self.hurt_inside(self,dtime)
|
||||
|
||||
currentvel = self.object:get_velocity()
|
||||
if currentvel.y ~= 0 then
|
||||
goal = vector.multiply(self.direction,self.speed)
|
||||
acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
|
||||
acceleration = vector.multiply(acceleration, 0.05)
|
||||
self.object:add_velocity(acceleration)
|
||||
end
|
||||
end
|
||||
|
||||
mob_register.jump = function(self,moveresult)
|
||||
if moveresult and moveresult.touching_ground and self.direction then
|
||||
if self.jump_timer <= 0 then
|
||||
if self.make_jump_noise then
|
||||
minetest.sound_play("slime_splat", {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(80,100)/100})
|
||||
end
|
||||
vel = self.object:get_velocity()
|
||||
self.object:set_velocity(vector.new(vel.x,5,vel.z))
|
||||
if self.following == true then
|
||||
self.jump_timer = 0.5
|
||||
else
|
||||
self.jump_timer = 1+math.random()
|
||||
end
|
||||
else
|
||||
self.object:set_velocity(vector.new(0,0,0))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if def.pathfinds then
|
||||
mob_register.pathfinding = function(self,dtime)
|
||||
acute_pos = vector.floor(vector.add(self.object:get_pos(),0.5))
|
||||
if self.following and self.following_pos then
|
||||
self.pathfinding_timer = self.pathfinding_timer + dtime
|
||||
height_diff = nil
|
||||
if self.object:get_pos().y > self.following_pos.y then
|
||||
height_diff = math.abs(self.object:get_pos().y-self.following_pos.y)
|
||||
elseif self.object:get_pos().y <= self.following_pos.y then
|
||||
height_diff = math.abs(self.following_pos.y-self.object:get_pos().y)
|
||||
end
|
||||
--delete path if height too far
|
||||
if self.path_data and height_diff > self.view_distance/2 then
|
||||
self.path_data = nil
|
||||
self.old_path_pos = nil
|
||||
self.old_acute_following_pos = nil
|
||||
return
|
||||
end
|
||||
|
||||
if self.pathfinding_timer >= 0.5 and height_diff <= self.view_distance/2 then
|
||||
acute_following_pos = vector.floor(vector.add(self.following_pos,0.5))
|
||||
|
||||
if (not self.old_path_pos or (self.old_path_pos and not vector.equals(acute_pos,self.old_path_pos))) and
|
||||
(not self.old_acute_following_pos or (self.old_acute_following_pos and vector.distance(self.old_acute_following_pos,acute_following_pos) > 2)) then
|
||||
|
||||
--if a player tries to hide in a node
|
||||
if minetest.get_nodedef(minetest.get_node(acute_following_pos).name, "walkable") then
|
||||
acute_following_pos.y = acute_following_pos.y + 1
|
||||
end
|
||||
|
||||
--if a player tries to stand off the side of a node
|
||||
if not minetest.get_nodedef(minetest.get_node(vector.new(acute_following_pos.x,acute_following_pos.y-1,acute_following_pos.z)).name, "walkable") then
|
||||
min = vector.subtract(acute_following_pos,1)
|
||||
max = vector.add(acute_following_pos,1)
|
||||
|
||||
index_table = minetest.find_nodes_in_area_under_air(min, max, all_walkable_nodes)
|
||||
--optimize this as much as possible
|
||||
for _,i_pos in pairs(index_table) do
|
||||
if minetest.get_nodedef(minetest.get_node(i_pos).name, "walkable") then
|
||||
acute_following_pos = vector.new(i_pos.x,i_pos.y+1,i_pos.z)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
path = minetest.find_path(acute_pos,acute_following_pos,self.view_distance,1,1,"A*_noprefetch")
|
||||
--if the path fails then raycast down to scare player or accidentally find new path
|
||||
--disabled for extreme cpu usage
|
||||
--[[
|
||||
if not path then
|
||||
local ray = minetest.raycast(acute_following_pos, vector.new(acute_following_pos.x,acute_following_pos.y-self.view_distance,acute_following_pos.z), false, false)
|
||||
for pointed_thing in ray do
|
||||
if pointed_thing.above then
|
||||
path = minetest.find_path(self.object:get_pos(),pointed_thing.above,self.view_distance,1,5,"A*_noprefetch")
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
]]--
|
||||
if path then
|
||||
self.whip_turn = 0.025
|
||||
self.path_data = path
|
||||
|
||||
--remove the first element of the list
|
||||
--shift whole list down
|
||||
for i = 2,table.getn(self.path_data) do
|
||||
self.path_data[i-1] = self.path_data[i]
|
||||
end
|
||||
self.path_data[table.getn(self.path_data)] = nil
|
||||
|
||||
--cut corners (go diagonal)
|
||||
if self.path_data and table.getn(self.path_data) >= 3 then
|
||||
number = 3
|
||||
for i = 3,table.getn(self.path_data) do
|
||||
pos1 = self.path_data[number-2]
|
||||
pos2 = self.path_data[number]
|
||||
|
||||
--print(number)
|
||||
--check if diagonal and has direct line of sight
|
||||
if pos1 and pos2 and pos1.x ~= pos2.x and pos1.z ~= pos2.z and pos1.y == pos2.y then
|
||||
pos3 = vector.divide(vector.add(pos1,pos2),2)
|
||||
pos3.y = pos3.y - 1
|
||||
can_cut,_ = minetest.line_of_sight(pos1, pos2)
|
||||
if can_cut then
|
||||
|
||||
if minetest.get_nodedef(minetest.get_node(pos3).name, "walkable") == true then
|
||||
--shift whole list down
|
||||
--print("removing"..number-1)
|
||||
for z = number-1,table.getn(self.path_data) do
|
||||
self.path_data[z-1] = self.path_data[z]
|
||||
end
|
||||
self.path_data[table.getn(self.path_data)] = nil
|
||||
number = number + 2
|
||||
else
|
||||
number = number + 1
|
||||
end
|
||||
else
|
||||
number = number + 1
|
||||
end
|
||||
if number > table.getn(self.path_data) then
|
||||
break
|
||||
end
|
||||
else
|
||||
number = number + 1
|
||||
end
|
||||
end
|
||||
--if self.path_data and table.getn(self.path_data) <= 2 then
|
||||
-- self.path_data = nil
|
||||
--end
|
||||
end
|
||||
end
|
||||
|
||||
self.old_path_pos = acute_pos
|
||||
self.old_acute_following_pos = acute_following_pos
|
||||
end
|
||||
end
|
||||
elseif (not self.following and self.path_data) or (self.path_data and height_diff > self.view_distance/2) then
|
||||
self.path_data = nil
|
||||
self.old_path_pos = nil
|
||||
self.old_acute_following_pos = nil
|
||||
end
|
||||
--[[
|
||||
if self.path_data then
|
||||
for index,pos_data in pairs(self.path_data) do
|
||||
--print(dump(pos_data))
|
||||
minetest.add_particle({
|
||||
pos = pos_data,
|
||||
velocity = {x=0, y=0, z=0},
|
||||
acceleration = {x=0, y=0, z=0},
|
||||
expirationtime = 0.01,
|
||||
size = 1,
|
||||
texture = "dirt.png",
|
||||
})
|
||||
end
|
||||
end
|
||||
]]--
|
||||
--this is the real time path deletion as it goes along it
|
||||
if self.swimming == true then
|
||||
self.path_data = nil
|
||||
end
|
||||
|
||||
if self.path_data and table.getn(self.path_data) > 0 then
|
||||
if vector.distance(acute_pos,self.path_data[1]) <= 1 then
|
||||
--shift whole list down
|
||||
for i = 2,table.getn(self.path_data) do
|
||||
self.path_data[i-1] = self.path_data[i]
|
||||
end
|
||||
self.path_data[table.getn(self.path_data)] = nil
|
||||
self.whip_turn = 0.01
|
||||
--if table.getn(self.path_data) == 0 then
|
||||
-- self.path_data = nil
|
||||
--end
|
||||
end
|
||||
end
|
||||
--charge at the player
|
||||
if self.path_data and table.getn(self.path_data) < 2 then
|
||||
self.path_data = nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return(mob_register)
|
||||
end
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
local
|
||||
minetest,math
|
||||
=
|
||||
minetest,math
|
||||
local pos
|
||||
local light
|
||||
mobs.create_timer_functions = function(def,mob_register)
|
||||
--this controls how fast the mob punches
|
||||
mob_register.manage_punch_timer = function(self,dtime)
|
||||
if self.punch_timer > 0 then
|
||||
self.punch_timer = self.punch_timer - dtime
|
||||
end
|
||||
--this controls how fast you can punch the mob (punched timer reset)
|
||||
if self.punched_timer > 0 then
|
||||
--print(self.punched_timer)
|
||||
self.punched_timer = self.punched_timer - dtime
|
||||
end
|
||||
end
|
||||
|
||||
--this controls the hostile state
|
||||
if def.hostile == true or def.attacked_hostile == true then
|
||||
if def.hostile_cooldown == true then
|
||||
mob_register.manage_hostile_timer = function(self,dtime)
|
||||
if self.hostile_timer > 0 then
|
||||
self.hostile_timer = self.hostile_timer - dtime
|
||||
end
|
||||
if self.hostile_timer <= 0 then
|
||||
self.hostile = false
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
mob_register.manage_scared_timer = function(self,dtime)
|
||||
if self.scared_timer > 0 then
|
||||
self.scared_timer = self.scared_timer - dtime
|
||||
end
|
||||
if self.scared_timer <= 0 then
|
||||
self.scared = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mob_register.manage_hurt_color_timer = function(self,dtime)
|
||||
if self.hurt_color_timer > 0 then
|
||||
self.hurt_color_timer = self.hurt_color_timer - dtime
|
||||
if self.hurt_color_timer <= 0 then
|
||||
self.hurt_color_timer = 0
|
||||
self.object:set_texture_mod("")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mob_register.manage_explode_timer = function(self,dtime)
|
||||
self.tnt_timer = self.tnt_timer - dtime
|
||||
self.tnt_tick_timer = self.tnt_tick_timer - dtime
|
||||
if self.tnt_tick_timer <= 0 and not self.dead then
|
||||
self.tnt_tick_timer = self.explosion_blink_timer
|
||||
self.tnt_mod_state = math.abs(self.tnt_mod_state-1)
|
||||
if self.tnt_mod_state == 0 then
|
||||
self.object:set_texture_mod("")
|
||||
else
|
||||
self.object:set_texture_mod("^[colorize:"..self.explosion_blink_color..":130")
|
||||
end
|
||||
--print(self.object:get_texture_mod())
|
||||
--self.object:set_texture_mod("^[colorize:red:130")
|
||||
end
|
||||
if self.tnt_timer <= 0 and not self.dead then
|
||||
|
||||
self.object:set_texture_mod("^[colorize:red:130")
|
||||
|
||||
pos = self.object:get_pos()
|
||||
self.object:remove()
|
||||
tnt(pos,self.explosion_power,self.explosion_type)
|
||||
end
|
||||
end
|
||||
|
||||
if def.custom_timer then
|
||||
mob_register.do_custom_timer = function(self,dtime)
|
||||
self.c_timer = self.c_timer + dtime
|
||||
if self.c_timer >= self.custom_timer then
|
||||
self.c_timer = 0
|
||||
self.custom_timer_function(self,dtime)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mob_register.manage_projectile_timer = function(self,dtime)
|
||||
self.projectile_timer = self.projectile_timer - dtime
|
||||
end
|
||||
|
||||
if def.friendly_in_daylight then
|
||||
mob_register.handle_friendly_in_daylight_timer = function(self,dtime)
|
||||
self.friendly_in_daylight_timer = self.friendly_in_daylight_timer + dtime
|
||||
if self.friendly_in_daylight_timer >= 2 then
|
||||
self.friendly_in_daylight_timer = 0
|
||||
pos = self.object:get_pos()
|
||||
light = minetest.get_node_light(pos)
|
||||
if pos and light and light >= 13 then --1 greater than torch light
|
||||
if self.following == false then
|
||||
self.hostile = false
|
||||
end
|
||||
else
|
||||
self.hostile = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--this stops the pig from flying into the air
|
||||
mob_register.manage_jump_timer = function(self,dtime)
|
||||
if self.jump_timer > 0 then
|
||||
self.jump_timer = self.jump_timer - dtime
|
||||
end
|
||||
end
|
||||
return(mob_register)
|
||||
end
|
Loading…
Reference in New Issue