2021-04-11 16:52:31 +00:00
-- API for Mobs Redo: MineClone 2 Delux 2.0 DRM Free Early Access Super Extreme Edition
2021-04-15 19:04:55 +00:00
-- mobs library
mobs = { }
-- lua locals - can grab from this to easily plop them into the api lua files
2021-04-11 16:52:31 +00:00
2021-04-12 12:47:07 +00:00
--localize minetest functions
local minetest_settings = minetest.settings
local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius
local minetest_get_modpath = minetest.get_modpath
local minetest_registered_nodes = minetest.registered_nodes
local minetest_get_node = minetest.get_node
local minetest_get_item_group = minetest.get_item_group
local minetest_registered_entities = minetest.registered_entities
local minetest_line_of_sight = minetest.line_of_sight
local minetest_after = minetest.after
local minetest_sound_play = minetest.sound_play
local minetest_add_particlespawner = minetest.add_particlespawner
local minetest_registered_items = minetest.registered_items
local minetest_set_node = minetest.set_node
local minetest_add_item = minetest.add_item
local minetest_get_craft_result = minetest.get_craft_result
local minetest_find_path = minetest.find_path
local minetest_is_protected = minetest.is_protected
local minetest_is_creative_enabled = minetest.is_creative_enabled
local minetest_find_node_near = minetest.find_node_near
local minetest_find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
local minetest_raycast = minetest.raycast
local minetest_get_us_time = minetest.get_us_time
local minetest_add_entity = minetest.add_entity
local minetest_get_natural_light = minetest.get_natural_light
local minetest_get_node_or_nil = minetest.get_node_or_nil
2021-04-11 16:52:31 +00:00
-- localize math functions
local math_pi = math.pi
local math_sin = math.sin
local math_cos = math.cos
local math_abs = math.abs
local math_min = math.min
local math_max = math.max
local math_atan = math.atan
local math_random = math.random
local math_floor = math.floor
2021-04-13 11:39:57 +00:00
-- localize vector functions
2021-04-14 15:50:22 +00:00
local vector_new = vector.new
2021-04-23 18:43:00 +00:00
local vector_add = vector.add
2021-04-14 15:50:22 +00:00
local vector_length = vector.length
2021-04-21 19:08:35 +00:00
local vector_direction = vector.direction
local vector_normalize = vector.normalize
local vector_multiply = vector.multiply
2021-04-23 18:50:38 +00:00
local vector_divide = vector.divide
2021-04-13 11:39:57 +00:00
2021-04-12 12:47:07 +00:00
-- mob constants
local BREED_TIME = 30
local BREED_TIME_AGAIN = 300
local CHILD_GROW_TIME = 60 * 20
local DEATH_DELAY = 0.5
local DEFAULT_FALL_SPEED = - 10
local FLOP_HEIGHT = 5.0
local FLOP_HOR_SPEED = 1.5
2021-04-19 01:22:21 +00:00
local GRAVITY = minetest_settings : get ( " movement_gravity " ) -- + 9.81
2021-04-16 20:37:15 +00:00
2021-04-12 12:47:07 +00:00
local MOB_CAP = { }
2020-04-11 00:46:03 +00:00
MOB_CAP.hostile = 70
MOB_CAP.passive = 10
MOB_CAP.ambient = 15
2021-04-12 12:47:07 +00:00
MOB_CAP.water = 15
2020-04-11 00:46:03 +00:00
2021-04-13 12:20:11 +00:00
-- Load main settings
2021-04-13 12:08:29 +00:00
local damage_enabled = minetest_settings : get_bool ( " enable_damage " )
local disable_blood = minetest_settings : get_bool ( " mobs_disable_blood " )
local mobs_drop_items = minetest_settings : get_bool ( " mobs_drop_items " ) ~= false
local mobs_griefing = minetest_settings : get_bool ( " mobs_griefing " ) ~= false
local spawn_protected = minetest_settings : get_bool ( " mobs_spawn_protected " ) ~= false
local remove_far = true
local difficulty = tonumber ( minetest_settings : get ( " mob_difficulty " ) ) or 1.0
local show_health = false
local max_per_block = tonumber ( minetest_settings : get ( " max_objects_per_block " ) or 64 )
local mobs_spawn_chance = tonumber ( minetest_settings : get ( " mobs_spawn_chance " ) or 2.5 )
2021-04-13 12:20:11 +00:00
-- pathfinding settings
local enable_pathfinding = true
local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching
local stuck_path_timeout = 10 -- how long will mob follow path before giving up
-- default nodes
local node_ice = " mcl_core:ice "
local node_snowblock = " mcl_core:snowblock "
local node_snow = " mcl_core:snow "
mobs.fallback_node = minetest.registered_aliases [ " mapgen_dirt " ] or " mcl_core:dirt "
local mod_weather = minetest_get_modpath ( " mcl_weather " ) ~= nil
local mod_explosions = minetest_get_modpath ( " mcl_explosions " ) ~= nil
local mod_mobspawners = minetest_get_modpath ( " mcl_mobspawners " ) ~= nil
local mod_hunger = minetest_get_modpath ( " mcl_hunger " ) ~= nil
local mod_worlds = minetest_get_modpath ( " mcl_worlds " ) ~= nil
local mod_armor = minetest_get_modpath ( " mcl_armor " ) ~= nil
local mod_experience = minetest_get_modpath ( " mcl_experience " ) ~= nil
2021-04-13 12:07:32 +00:00
-- random locals I found
2021-04-13 12:20:11 +00:00
local los_switcher = false
2021-04-13 12:07:32 +00:00
local height_switcher = false
2021-04-13 12:20:11 +00:00
-- Get translator
2019-03-07 19:43:39 +00:00
local S = minetest.get_translator ( " mcl_mobs " )
2017-05-25 08:33:19 +00:00
2017-07-04 23:52:39 +00:00
-- CMI support check
local use_cmi = minetest.global_exists ( " cmi " )
2017-11-03 23:22:43 +00:00
2017-01-16 16:40:08 +00:00
-- Invisibility mod check
mobs.invis = { }
2017-11-03 23:22:43 +00:00
if minetest.global_exists ( " invisibility " ) then
2017-01-16 16:40:08 +00:00
mobs.invis = invisibility
end
2017-11-03 23:22:43 +00:00
-- creative check
function mobs . is_creative ( name )
2021-04-22 23:12:02 +00:00
return minetest_is_creative_enabled ( name )
2017-11-03 23:22:43 +00:00
end
2017-01-16 16:40:08 +00:00
local atan = function ( x )
2017-05-25 08:33:19 +00:00
if not x or x ~= x then
2017-01-16 16:40:08 +00:00
return 0
else
2021-04-11 16:52:31 +00:00
return math_atan ( x )
2017-01-16 16:40:08 +00:00
end
end
2021-04-13 12:08:29 +00:00
2017-11-03 23:22:43 +00:00
2020-12-05 00:30:16 +00:00
-- Shows helpful debug info above each mob
2021-04-12 12:47:07 +00:00
local mobs_debug = minetest_settings : get_bool ( " mobs_debug " , false )
2020-12-05 00:30:16 +00:00
2017-11-03 23:22:43 +00:00
-- Peaceful mode message so players will know there are no monsters
2021-04-12 12:47:07 +00:00
if minetest_settings : get_bool ( " only_peaceful_mobs " , false ) then
2017-11-03 23:22:43 +00:00
minetest.register_on_joinplayer ( function ( player )
minetest.chat_send_player ( player : get_player_name ( ) ,
2019-03-07 19:43:39 +00:00
S ( " Peaceful mode active! No monsters will spawn. " ) )
2017-11-03 23:22:43 +00:00
end )
end
2017-01-16 16:40:08 +00:00
2021-04-14 00:00:38 +00:00
2021-04-15 19:04:55 +00:00
local api_path = minetest.get_modpath ( minetest.get_current_modname ( ) ) .. " /api/mob_functions/ "
2017-01-16 16:40:08 +00:00
2021-04-15 19:04:55 +00:00
--ignite all parts of the api
dofile ( api_path .. " ai.lua " )
dofile ( api_path .. " animation.lua " )
dofile ( api_path .. " collision.lua " )
dofile ( api_path .. " environment.lua " )
dofile ( api_path .. " interaction.lua " )
dofile ( api_path .. " movement.lua " )
dofile ( api_path .. " set_up.lua " )
2021-04-21 00:19:55 +00:00
dofile ( api_path .. " attack_type_instructions.lua " )
2021-04-21 01:34:18 +00:00
dofile ( api_path .. " sound_handling.lua " )
2021-04-23 00:30:50 +00:00
dofile ( api_path .. " death_logic.lua " )
2021-04-23 02:08:54 +00:00
dofile ( api_path .. " mob_effects.lua " )
2021-04-23 18:10:12 +00:00
dofile ( api_path .. " projectile_handling.lua " )
2021-04-24 01:14:23 +00:00
dofile ( api_path .. " breeding.lua " )
2021-04-25 05:45:35 +00:00
dofile ( api_path .. " head_logic.lua " )
2017-01-16 16:40:08 +00:00
2021-04-15 19:04:55 +00:00
mobs.spawning_mobs = { }
2017-01-16 16:40:08 +00:00
2021-04-15 19:04:55 +00:00
-- register mob entity
function mobs : register_mob ( name , def )
2017-01-16 16:40:08 +00:00
2021-04-15 19:04:55 +00:00
local collisionbox = def.collisionbox or { - 0.25 , - 0.25 , - 0.25 , 0.25 , 0.25 , 0.25 }
2017-01-16 16:40:08 +00:00
2021-04-15 19:04:55 +00:00
-- Workaround for <https://github.com/minetest/minetest/issues/5966>:
-- Increase upper Y limit to avoid mobs glitching through solid nodes.
-- FIXME: Remove workaround if it's no longer needed.
2017-01-16 16:40:08 +00:00
2021-04-15 19:04:55 +00:00
if collisionbox [ 5 ] < 0.79 then
collisionbox [ 5 ] = 0.79
2019-10-02 16:28:28 +00:00
end
2017-01-16 16:40:08 +00:00
2021-04-15 19:04:55 +00:00
mobs.spawning_mobs [ name ] = true
2017-01-16 16:40:08 +00:00
2021-04-15 19:04:55 +00:00
local function scale_difficulty ( value , default , min , special )
if ( not value ) or ( value == default ) or ( value == special ) then
return default
else
return math_max ( min , value * difficulty )
2017-11-03 23:22:43 +00:00
end
end
2021-04-15 19:04:55 +00:00
minetest.register_entity ( name , {
2021-04-27 16:56:48 +00:00
description = def.description ,
2021-04-15 19:04:55 +00:00
use_texture_alpha = def.use_texture_alpha ,
stepheight = def.stepheight or 0.6 ,
2021-04-25 08:03:06 +00:00
stepheight_backup = def.stepheight or 0.6 ,
2021-04-15 19:04:55 +00:00
name = name ,
type = def.type ,
attack_type = def.attack_type ,
fly = def.fly ,
fly_in = def.fly_in or { " air " , " __airlike " } ,
owner = def.owner or " " ,
order = def.order or " " ,
on_die = def.on_die ,
spawn_small_alternative = def.spawn_small_alternative ,
do_custom = def.do_custom ,
jump_height = def.jump_height or 4 , -- was 6
rotate = def.rotate or 0 , -- 0=front, 90=side, 180=back, 270=side2
hp_min = scale_difficulty ( def.hp_min , 5 , 1 ) ,
hp_max = scale_difficulty ( def.hp_max , 10 , 1 ) ,
2021-04-25 02:28:26 +00:00
xp_min = def.xp_min or 1 ,
xp_max = def.xp_max or 5 ,
2021-04-25 04:06:12 +00:00
breath_max = def.breath_max or 6 ,
2021-04-17 00:32:05 +00:00
breathes_in_water = def.breathes_in_water or false ,
2021-04-15 19:04:55 +00:00
physical = true ,
collisionbox = collisionbox ,
2021-04-16 17:58:08 +00:00
collide_with_objects = def.collide_with_objects or false ,
2021-04-15 19:04:55 +00:00
selectionbox = def.selectionbox or def.collisionbox ,
visual = def.visual ,
visual_size = def.visual_size or { x = 1 , y = 1 } ,
mesh = def.mesh ,
makes_footstep_sound = def.makes_footstep_sound or false ,
view_range = def.view_range or 16 ,
walk_velocity = def.walk_velocity or 1 ,
run_velocity = def.run_velocity or 2 ,
damage = scale_difficulty ( def.damage , 0 , 0 ) ,
light_damage = def.light_damage or 0 ,
sunlight_damage = def.sunlight_damage or 0 ,
water_damage = def.water_damage or 0 ,
lava_damage = def.lava_damage or 8 ,
fire_damage = def.fire_damage or 1 ,
suffocation = def.suffocation or true ,
fall_damage = def.fall_damage or 1 ,
fall_speed = def.fall_speed or DEFAULT_FALL_SPEED , -- must be lower than -2
drops = def.drops or { } ,
armor = def.armor or 100 ,
on_rightclick = mobs.create_mob_on_rightclick ( def.on_rightclick ) ,
arrow = def.arrow ,
shoot_interval = def.shoot_interval ,
sounds = def.sounds or { } ,
animation = def.animation ,
jump = def.jump ~= false ,
walk_chance = def.walk_chance or 50 ,
attacks_monsters = def.attacks_monsters or false ,
group_attack = def.group_attack or false ,
passive = def.passive or false ,
knock_back = def.knock_back ~= false ,
shoot_offset = def.shoot_offset or 0 ,
floats = def.floats or 1 , -- floats in water by default
floats_on_lava = def.floats_on_lava or 0 ,
replace_rate = def.replace_rate ,
replace_what = def.replace_what ,
replace_with = def.replace_with ,
replace_offset = def.replace_offset or 0 ,
on_replace = def.on_replace ,
timer = 0 ,
state_timer = 0 ,
env_damage_timer = 0 ,
tamed = false ,
pause_timer = 0 ,
gotten = false ,
reach = def.reach or 3 ,
htimer = 0 ,
texture_list = def.textures ,
child_texture = def.child_texture ,
docile_by_day = def.docile_by_day or false ,
time_of_day = 0.5 ,
fear_height = def.fear_height or 0 ,
runaway = def.runaway ,
runaway_timer = 0 ,
pathfinding = def.pathfinding ,
immune_to = def.immune_to or { } ,
explosion_radius = def.explosion_radius , -- LEGACY
explosion_damage_radius = def.explosion_damage_radius , -- LEGACY
explosiontimer_reset_radius = def.explosiontimer_reset_radius ,
explosion_timer = def.explosion_timer or 3 ,
allow_fuse_reset = def.allow_fuse_reset ~= false ,
stop_to_explode = def.stop_to_explode ~= false ,
custom_attack = def.custom_attack ,
double_melee_attack = def.double_melee_attack ,
dogshoot_switch = def.dogshoot_switch ,
dogshoot_count = 0 ,
dogshoot_count_max = def.dogshoot_count_max or 5 ,
dogshoot_count2_max = def.dogshoot_count2_max or ( def.dogshoot_count_max or 5 ) ,
attack_animals = def.attack_animals or false ,
specific_attack = def.specific_attack ,
runaway_from = def.runaway_from ,
owner_loyal = def.owner_loyal ,
facing_fence = false ,
2021-04-19 01:22:21 +00:00
2021-04-15 19:04:55 +00:00
_cmi_is_mob = true ,
2021-04-19 01:22:21 +00:00
2021-04-15 19:04:55 +00:00
pushable = def.pushable or true ,
--j4i stuff
yaw = 0 ,
automatic_face_movement_dir = def.rotate or 0 , -- 0=front, 90=side, 180=back, 270=side2
2021-04-15 19:55:10 +00:00
automatic_face_movement_max_rotation_per_sec = 360 , --degrees
2021-04-15 19:04:55 +00:00
backface_culling = true ,
walk_timer = 0 ,
stand_timer = 0 ,
2021-04-16 17:58:08 +00:00
current_animation = " " ,
2021-04-16 20:37:15 +00:00
gravity = GRAVITY ,
2021-04-17 16:28:07 +00:00
swim = def.swim ,
swim_in = def.swim_in or { mobs_mc.items . water_source , " mcl_core:water_flowing " , mobs_mc.items . river_water_source } ,
2021-04-17 20:23:38 +00:00
pitch_switch = " static " ,
2021-04-17 22:21:33 +00:00
jump_only = def.jump_only ,
2021-04-20 18:55:22 +00:00
hostile = def.hostile ,
neutral = def.neutral ,
2021-04-21 00:19:55 +00:00
attacking = nil ,
visual_size_origin = def.visual_size or { x = 1 , y = 1 , z = 1 } ,
2021-04-21 02:30:34 +00:00
punch_timer_cooloff = def.punch_timer_cooloff or 0.5 ,
2021-04-23 01:36:42 +00:00
death_animation_timer = 0 ,
2021-04-23 18:34:59 +00:00
hostile_cooldown = def.hostile_cooldown or 15 ,
tilt_fly = def.tilt_fly ,
tilt_swim = def.tilt_swim ,
fall_slow = def.fall_slow ,
projectile_cooldown_min = def.projectile_cooldown_min or 2 ,
projectile_cooldown_max = def.projectile_cooldown_max or 6 ,
2021-04-23 21:10:44 +00:00
skittish = def.skittish ,
2021-04-25 00:27:37 +00:00
minimum_follow_distance = def.minimum_follow_distance or 0.5 , --make mobs not freak out when underneath
2021-04-25 01:15:42 +00:00
memory = 0 , -- memory timer if chasing/following
2021-04-25 02:14:25 +00:00
fly_random_while_attack = def.fly_random_while_attack ,
2021-04-25 01:15:42 +00:00
2021-04-25 00:27:37 +00:00
--for spiders
always_climb = def.always_climb ,
--despawn mechanic variables
2021-04-23 23:49:35 +00:00
lifetimer_reset = 30 , --30 seconds
lifetimer = 30 , --30 seconds
2021-04-24 01:59:42 +00:00
2021-04-24 03:56:59 +00:00
--breeding stuff
2021-04-24 01:59:42 +00:00
breed_timer = 0 ,
2021-04-24 03:56:59 +00:00
breed_lookout_timer = 0 ,
breed_distance = def.breed_distance or 1.5 , --how far away mobs have to be to begin actual breeding
breed_lookout_timer_goal = 30 , --30 seconds (this timer is for how long the mob looks for a mate)
breed_timer_cooloff = 5 * 60 , -- 5 minutes (this timer is for how long the mob has to wait before being bred again)
2021-04-24 01:59:42 +00:00
bred = false ,
2021-04-24 03:56:59 +00:00
follow = def.follow , --this item is also used for the breeding mechanism
2021-04-24 01:59:42 +00:00
follow_distance = def.follow_distance or 2 ,
2021-04-24 03:56:59 +00:00
baby_size = def.baby_size or 0.5 ,
baby = false ,
grow_up_timer = 0 ,
grow_up_goal = 20 * 60 , --in 20 minutes the mob grows up
2021-04-24 03:59:35 +00:00
special_breed_timer = 0 , --this is used for the AHEM AHEM part of breeding
2021-04-24 03:56:59 +00:00
backup_visual_size = def.visual_size ,
backup_collisionbox = collisionbox ,
backup_selectionbox = def.selectionbox or def.collisionbox ,
2021-04-25 03:15:40 +00:00
--fire timer
burn_timer = 0 ,
2021-04-25 03:29:56 +00:00
ignores_cobwebs = def.ignores_cobwebs ,
2021-04-25 04:06:12 +00:00
breath = def.breath_max or 6 ,
2021-04-25 05:14:48 +00:00
random_sound_timer_min = 3 ,
random_sound_timer_max = 10 ,
2021-04-25 05:45:35 +00:00
--head code variables
2021-04-25 23:44:15 +00:00
--defaults are for the cow's default
--because I don't know what else to set them
--to :P
2021-04-25 05:45:35 +00:00
has_head = def.has_head or false ,
head_bone = def.head_bone ,
2021-04-25 22:24:10 +00:00
--you must use these to adjust the mob's head positions
2021-04-25 23:44:15 +00:00
--has_head is used as a logic gate (quick easy check)
has_head = def.has_head or false ,
--head_bone is the actual bone in the model which the head
--is attached to for animation
head_bone = def.head_bone or " head " ,
--this part controls the base position of the head calculations
--localized to the mob's visual yaw when gotten (self.object:get_yaw())
--you can enable the debug in /mob_functions/head_logic.lua by uncommenting the
--particle spawner code
head_height_offset = def.head_height_offset or 1.0525 ,
head_direction_offset = def.head_direction_offset or 0.5 ,
--this part controls the visual of the head
2021-04-25 22:24:10 +00:00
head_bone_pos_y = def.head_bone_pos_y or 3.6 ,
head_bone_pos_z = def.head_bone_pos_z or - 0.6 ,
2021-04-26 00:08:45 +00:00
head_pitch_modifier = def.head_pitch_modifier or 0 ,
2021-04-25 23:44:15 +00:00
--these variables are switches in case the model
--moves the wrong way
2021-04-25 22:24:10 +00:00
swap_y_with_x = def.swap_y_with_x or false ,
reverse_head_yaw = def.reverse_head_yaw or false ,
2021-04-25 23:44:15 +00:00
--END HEAD CODE VARIABLES
2021-04-15 19:04:55 +00:00
--end j4i stuff
-- MCL2 extensions
2021-04-23 17:27:17 +00:00
teleport = mobs.teleport ,
2021-04-15 19:04:55 +00:00
do_teleport = def.do_teleport ,
spawn_class = def.spawn_class ,
ignores_nametag = def.ignores_nametag or false ,
rain_damage = def.rain_damage or 0 ,
glow = def.glow ,
2021-04-23 23:49:35 +00:00
--can_despawn = can_despawn,
2021-04-15 19:04:55 +00:00
child = def.child or false ,
texture_mods = { } ,
shoot_arrow = def.shoot_arrow ,
2021-04-16 20:37:15 +00:00
sounds_child = def.sounds_child ,
2021-04-15 19:04:55 +00:00
explosion_strength = def.explosion_strength ,
suffocation_timer = 0 ,
follow_velocity = def.follow_velocity or 2.4 ,
instant_death = def.instant_death or false ,
fire_resistant = def.fire_resistant or false ,
fire_damage_resistant = def.fire_damage_resistant or false ,
ignited_by_sunlight = def.ignited_by_sunlight or false ,
2021-04-21 02:58:39 +00:00
eye_height = def.eye_height or 1.5 ,
2021-04-21 14:20:31 +00:00
defuse_reach = def.defuse_reach or 4 ,
2021-04-15 19:04:55 +00:00
-- End of MCL2 extensions
on_spawn = def.on_spawn ,
2021-04-16 17:58:08 +00:00
--on_blast = def.on_blast or do_tnt,
2021-04-15 19:04:55 +00:00
2021-04-16 17:58:08 +00:00
on_step = mobs.mob_step ,
2021-04-15 19:04:55 +00:00
2021-04-16 17:58:08 +00:00
--do_punch = def.do_punch,
2021-04-15 19:04:55 +00:00
2021-04-21 14:53:20 +00:00
on_punch = mobs.mob_punch ,
2021-04-15 19:04:55 +00:00
2021-04-16 17:58:08 +00:00
--on_breed = def.on_breed,
2021-04-15 19:04:55 +00:00
2021-04-16 17:58:08 +00:00
--on_grown = def.on_grown,
2021-04-15 19:04:55 +00:00
2021-04-16 17:58:08 +00:00
--on_detach_child = mob_detach_child,
2021-04-15 19:04:55 +00:00
on_activate = function ( self , staticdata , dtime )
2021-04-16 20:37:15 +00:00
self.object : set_acceleration ( vector_new ( 0 , - GRAVITY , 0 ) )
2021-04-15 19:04:55 +00:00
return mobs.mob_activate ( self , staticdata , def , dtime )
end ,
get_staticdata = function ( self )
return mobs.mob_staticdata ( self )
end ,
2021-04-16 17:58:08 +00:00
--harmed_by_heal = def.harmed_by_heal,
2021-04-15 19:04:55 +00:00
} )
2021-04-13 11:39:57 +00:00
2021-04-15 19:04:55 +00:00
if minetest_get_modpath ( " doc_identifier " ) ~= nil then
doc.sub . identifier.register_object ( name , " basics " , " mobs " )
2019-10-02 16:28:28 +00:00
end
2019-01-27 23:04:12 +00:00
2017-01-16 16:40:08 +00:00
end -- END mobs:register_mob function
2017-05-25 08:33:19 +00:00
2021-04-15 14:05:24 +00:00
2017-01-16 16:40:08 +00:00
-- register arrow for shoot attack
2015-06-29 17:55:56 +00:00
function mobs : register_arrow ( name , def )
2017-01-16 16:40:08 +00:00
2021-04-21 19:08:35 +00:00
-- errorcheck
if not name or not def then
print ( " failed to register arrow entity " )
return
end
2017-01-16 16:40:08 +00:00
2021-04-21 19:08:35 +00:00
minetest.register_entity ( name .. " _entity " , {
2017-01-16 16:40:08 +00:00
2015-06-29 17:55:56 +00:00
physical = false ,
visual = def.visual ,
visual_size = def.visual_size ,
textures = def.textures ,
velocity = def.velocity ,
hit_player = def.hit_player ,
hit_node = def.hit_node ,
2017-01-16 16:40:08 +00:00
hit_mob = def.hit_mob ,
2020-01-30 22:11:16 +00:00
hit_object = def.hit_object ,
2017-01-16 16:40:08 +00:00
drop = def.drop or false , -- drops arrow as registered item when true
collisionbox = { 0 , 0 , 0 , 0 , 0 , 0 } , -- remove box around arrows
timer = 0 ,
switch = 0 ,
owner_id = def.owner_id ,
2017-05-25 08:33:19 +00:00
rotate = def.rotate ,
2021-04-21 19:08:35 +00:00
speed = def.speed or nil ,
on_step = function ( self )
2021-04-04 01:07:51 +00:00
local vel = self.object : get_velocity ( )
2017-01-16 16:40:08 +00:00
2021-04-21 19:08:35 +00:00
local pos = self.object : get_pos ( )
2021-04-27 16:56:48 +00:00
2021-04-21 19:08:35 +00:00
if self.timer > 150
or not mobs.within_limits ( pos , 0 ) then
2021-01-02 09:56:40 +00:00
mcl_burning.extinguish ( self.object )
2018-06-02 22:56:29 +00:00
self.object : remove ( ) ;
2015-06-29 17:55:56 +00:00
return
end
2017-01-16 16:40:08 +00:00
-- does arrow have a tail (fireball)
if def.tail
and def.tail == 1
and def.tail_texture then
2021-04-23 18:43:00 +00:00
--do this to prevent clipping through main entity sprite
2021-04-23 18:50:38 +00:00
local pos_adjustment = vector_multiply ( vector_normalize ( vel ) , - 1 )
local divider = def.tail_distance_divider or 1
pos_adjustment = vector_divide ( pos_adjustment , divider )
local new_pos = vector_add ( pos , pos_adjustment )
2017-05-25 08:33:19 +00:00
minetest.add_particle ( {
2021-04-23 18:43:00 +00:00
pos = new_pos ,
2017-05-25 08:33:19 +00:00
velocity = { x = 0 , y = 0 , z = 0 } ,
acceleration = { x = 0 , y = 0 , z = 0 } ,
expirationtime = def.expire or 0.25 ,
collisiondetection = false ,
2017-01-16 16:40:08 +00:00
texture = def.tail_texture ,
2017-05-25 08:33:19 +00:00
size = def.tail_size or 5 ,
glow = def.glow or 0 ,
2017-01-16 16:40:08 +00:00
} )
end
if self.hit_node then
2021-04-21 19:08:35 +00:00
local node = minetest_get_node ( pos ) . name
2017-01-16 16:40:08 +00:00
2021-04-12 12:47:07 +00:00
if minetest_registered_nodes [ node ] . walkable then
2017-01-16 16:40:08 +00:00
self.hit_node ( self , pos , node )
if self.drop == true then
pos.y = pos.y + 1
self.lastpos = ( self.lastpos or pos )
2021-04-12 12:47:07 +00:00
minetest_add_item ( self.lastpos , self.object : get_luaentity ( ) . name )
2017-01-16 16:40:08 +00:00
end
2018-06-02 22:56:29 +00:00
self.object : remove ( ) ;
2017-01-16 16:40:08 +00:00
2015-06-29 17:55:56 +00:00
return
end
end
2017-01-16 16:40:08 +00:00
2020-01-30 22:11:16 +00:00
if self.hit_player or self.hit_mob or self.hit_object then
2017-01-16 16:40:08 +00:00
2021-04-12 12:47:07 +00:00
for _ , player in pairs ( minetest_get_objects_inside_radius ( pos , 1.5 ) ) do
2017-01-16 16:40:08 +00:00
if self.hit_player
and player : is_player ( ) then
2021-04-23 02:40:16 +00:00
if self.hit_player then
self.hit_player ( self , player )
else
mobs.arrow_hit ( self , player )
end
2021-04-21 19:08:35 +00:00
2018-06-02 22:56:29 +00:00
self.object : remove ( ) ;
2017-01-16 16:40:08 +00:00
return
end
2021-04-21 19:08:35 +00:00
--[[
2017-01-16 16:40:08 +00:00
local entity = player : get_luaentity ( )
2017-07-25 02:30:23 +00:00
if entity
and self.hit_mob
and entity._cmi_is_mob == true
2017-01-16 16:40:08 +00:00
and tostring ( player ) ~= self.owner_id
2021-04-21 19:08:35 +00:00
and entity.name ~= self.object : get_luaentity ( ) . name
and ( self._shooter and entity.name ~= self._shooter : get_luaentity ( ) . name ) then
--self.hit_mob(self, player)
2018-06-02 22:56:29 +00:00
self.object : remove ( ) ;
2020-01-30 22:11:16 +00:00
return
end
2021-04-21 19:08:35 +00:00
] ] --
2017-01-16 16:40:08 +00:00
2021-04-21 19:08:35 +00:00
--[[
2020-01-30 22:11:16 +00:00
if entity
and self.hit_object
and ( not entity._cmi_is_mob )
and tostring ( player ) ~= self.owner_id
2021-04-21 19:08:35 +00:00
and entity.name ~= self.object : get_luaentity ( ) . name
and ( self._shooter and entity.name ~= self._shooter : get_luaentity ( ) . name ) then
--self.hit_object(self, player)
2020-01-30 22:11:16 +00:00
self.object : remove ( ) ;
2017-01-16 16:40:08 +00:00
return
end
2021-04-21 19:08:35 +00:00
] ] --
2017-01-16 16:40:08 +00:00
end
end
self.lastpos = pos
2015-06-29 17:55:56 +00:00
end
} )
end
2017-07-04 23:52:39 +00:00
-- Register spawn eggs
-- Note: This also introduces the “spawn_egg” group:
-- * spawn_egg=1: Spawn egg (generic mob, no metadata)
-- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata)
2017-01-16 16:40:08 +00:00
function mobs : register_egg ( mob , desc , background , addegg , no_creative )
2017-07-04 23:52:39 +00:00
local grp = { spawn_egg = 1 }
2017-01-16 16:40:08 +00:00
-- do NOT add this egg to creative inventory (e.g. dungeon master)
2020-07-10 14:46:47 +00:00
if no_creative == true then
2017-07-04 23:52:39 +00:00
grp.not_in_creative_inventory = 1
2017-01-16 16:40:08 +00:00
end
local invimg = background
if addegg == 1 then
invimg = " mobs_chicken_egg.png^( " .. invimg ..
" ^[mask:mobs_chicken_egg_overlay.png) "
end
2017-05-25 08:33:19 +00:00
-- register old stackable mob egg
minetest.register_craftitem ( mob , {
description = desc ,
inventory_image = invimg ,
groups = grp ,
2018-03-30 22:18:40 +00:00
2019-03-07 19:43:39 +00:00
_doc_items_longdesc = S ( " This allows you to place a single mob. " ) ,
_doc_items_usagehelp = S ( " Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns. " ) ,
2018-01-07 15:53:25 +00:00
2017-05-25 08:33:19 +00:00
on_place = function ( itemstack , placer , pointed_thing )
2017-01-16 16:40:08 +00:00
local pos = pointed_thing.above
2017-05-25 08:33:19 +00:00
-- am I clicking on something with existing on_rightclick function?
2021-04-12 12:47:07 +00:00
local under = minetest_get_node ( pointed_thing.under )
local def = minetest_registered_nodes [ under.name ]
2017-08-06 10:49:13 +00:00
if def and def.on_rightclick then
2017-05-25 08:33:19 +00:00
return def.on_rightclick ( pointed_thing.under , under , placer , itemstack )
end
2017-01-16 16:40:08 +00:00
if pos
2021-04-13 12:20:11 +00:00
--and within_limits(pos, 0)
2021-04-12 12:47:07 +00:00
and not minetest_is_protected ( pos , placer : get_player_name ( ) ) then
2017-01-16 16:40:08 +00:00
2018-01-07 15:53:25 +00:00
local name = placer : get_player_name ( )
local privs = minetest.get_player_privs ( name )
2018-05-31 00:47:37 +00:00
if mod_mobspawners and under.name == " mcl_mobspawners:spawner " then
2021-04-12 12:47:07 +00:00
if minetest_is_protected ( pointed_thing.under , name ) then
2019-02-08 21:17:51 +00:00
minetest.record_protection_violation ( pointed_thing.under , name )
return itemstack
end
2019-02-08 16:55:14 +00:00
if not privs.maphack then
2019-03-07 19:43:39 +00:00
minetest.chat_send_player ( name , S ( " You need the “maphack” privilege to change the mob spawner. " ) )
2019-02-08 16:55:14 +00:00
return itemstack
end
2018-01-07 15:53:25 +00:00
mcl_mobspawners.setup_spawner ( pointed_thing.under , itemstack : get_name ( ) )
2020-07-10 14:08:40 +00:00
if not mobs.is_creative ( name ) then
2018-01-07 15:53:25 +00:00
itemstack : take_item ( )
end
return itemstack
end
2021-04-12 12:47:07 +00:00
if not minetest_registered_entities [ mob ] then
2018-05-29 15:00:30 +00:00
return itemstack
2018-01-26 17:06:32 +00:00
end
2021-04-12 12:47:07 +00:00
if minetest_settings : get_bool ( " only_peaceful_mobs " , false )
and minetest_registered_entities [ mob ] . type == " monster " then
2020-01-06 12:46:43 +00:00
minetest.chat_send_player ( name , S ( " Only peaceful mobs allowed! " ) )
return itemstack
end
2021-04-12 12:47:07 +00:00
local mob = minetest_add_entity ( pos , mob )
2020-12-08 21:42:01 +00:00
minetest.log ( " action " , " Mob spawned: " .. name .. " at " .. minetest.pos_to_string ( pos ) )
2017-01-16 16:40:08 +00:00
local ent = mob : get_luaentity ( )
2017-11-03 23:22:43 +00:00
-- don't set owner if monster or sneak pressed
2021-04-21 15:42:01 +00:00
--[[
2017-07-04 23:52:39 +00:00
if ent.type ~= " monster "
2017-08-06 10:49:13 +00:00
and not placer : get_player_control ( ) . sneak then
2017-05-25 08:33:19 +00:00
ent.owner = placer : get_player_name ( )
ent.tamed = true
2017-01-16 16:40:08 +00:00
end
2021-04-21 15:42:01 +00:00
] ] --
2018-05-29 15:00:30 +00:00
2018-02-04 06:11:44 +00:00
-- set nametag
local nametag = itemstack : get_meta ( ) : get_string ( " name " )
if nametag ~= " " then
if string.len ( nametag ) > MAX_MOB_NAME_LENGTH then
nametag = string.sub ( nametag , 1 , MAX_MOB_NAME_LENGTH )
end
ent.nametag = nametag
update_tag ( ent )
end
2017-01-16 16:40:08 +00:00
-- if not in creative then take item
2017-11-03 23:22:43 +00:00
if not mobs.is_creative ( placer : get_player_name ( ) ) then
2017-01-16 16:40:08 +00:00
itemstack : take_item ( )
end
end
return itemstack
end ,
} )
2017-05-25 08:33:19 +00:00
2017-01-16 16:40:08 +00:00
end
2017-05-25 08:33:19 +00:00