This commit is contained in:
kay27 2021-05-02 00:29:39 +04:00
commit b12367b500
107 changed files with 7199 additions and 3368 deletions

View File

@ -1,3 +1,5 @@
# (Currently in feature freeze)
# MineClone 2 # MineClone 2
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB. Developed by many people. Not developed or endorsed by Mojang AB.

View File

@ -532,6 +532,10 @@ function mcl_util.get_object_name(object)
else else
local luaentity = object:get_luaentity() local luaentity = object:get_luaentity()
if not luaentity then
return ""
end
return luaentity.nametag and luaentity.nametag ~= "" and luaentity.nametag or luaentity.description or luaentity.name return luaentity.nametag and luaentity.nametag ~= "" and luaentity.nametag or luaentity.description or luaentity.name
end end
end end

View File

@ -502,20 +502,6 @@ and damages any entity caught inside the blast radius. Protection will limit
node destruction but not entity damage. node destruction but not entity damage.
mobs:capture_mob
----------------
mobs:capture_mob(...)
Does nothing and returns false.
This function is provided for compability with Mobs Redo for an attempt to
capture a mob.
Mobs cannot be captured in MineClone 2.
In Mobs Redo, this is generally called inside the on_rightclick section of the mob
api code, it provides a chance of capturing the mob. See Mobs Redo documentation
of parameters.
Feeding and Taming/Breeding Feeding and Taming/Breeding
--------------------------- ---------------------------
@ -535,19 +521,6 @@ Will return true when mob is fed with item it likes.
them up them up
Protecting Mobs
---------------
mobs:protect(self, clicker)
This function can be used to right-click any tamed mob with mobs:protector item,
this will protect the mob from harm inside of a protected area from other
players. Will return true when mob right-clicked with mobs:protector item.
'self' mob information
'clicker' player information
Riding Mobs Riding Mobs
----------- -----------
@ -605,7 +578,7 @@ Note: animation names above are from the pre-defined animation lists inside mob
registry without extensions. registry without extensions.
mobs:set_animation(self, name) mobs.set_mob_animation(self, name)
This function sets the current animation for mob, defaulting to "stand" if not This function sets the current animation for mob, defaulting to "stand" if not
found. found.
@ -781,8 +754,5 @@ mobs:register_mob("mob_horse:horse", {
inv:remove_item("main", "mobs:saddle") inv:remove_item("main", "mobs:saddle")
end end
end end
-- used to capture horse with magic lasso
mobs:capture_mob(self, clicker, 0, 0, 80, false, nil)
end end
}) })

View File

@ -0,0 +1,761 @@
-- API for Mobs Redo: MineClone 2 Delux 2.0 DRM Free Early Access Super Extreme Edition
-- mobs library
mobs = {}
-- lua locals - can grab from this to easily plop them into the api lua files
--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
-- 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
-- localize vector functions
local vector_new = vector.new
local vector_add = vector.add
local vector_length = vector.length
local vector_direction = vector.direction
local vector_normalize = vector.normalize
local vector_multiply = vector.multiply
local vector_divide = vector.divide
-- 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
local GRAVITY = minetest_settings:get("movement_gravity")-- + 9.81
local MOB_CAP = {}
MOB_CAP.hostile = 70
MOB_CAP.passive = 10
MOB_CAP.ambient = 15
MOB_CAP.water = 15
-- Load main settings
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)
-- 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
-- random locals I found
local los_switcher = false
local height_switcher = false
-- Get translator
local S = minetest.get_translator("mcl_mobs")
-- CMI support check
local use_cmi = minetest.global_exists("cmi")
-- Invisibility mod check
mobs.invis = {}
if minetest.global_exists("invisibility") then
mobs.invis = invisibility
end
-- creative check
function mobs.is_creative(name)
return minetest_is_creative_enabled(name)
end
local atan = function(x)
if not x or x ~= x then
return 0
else
return math_atan(x)
end
end
-- Shows helpful debug info above each mob
local mobs_debug = minetest_settings:get_bool("mobs_debug", false)
-- Peaceful mode message so players will know there are no monsters
if minetest_settings:get_bool("only_peaceful_mobs", false) then
minetest.register_on_joinplayer(function(player)
minetest.chat_send_player(player:get_player_name(),
S("Peaceful mode active! No monsters will spawn."))
end)
end
local api_path = minetest.get_modpath(minetest.get_current_modname()).."/api/mob_functions/"
--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")
dofile(api_path .. "attack_type_instructions.lua")
dofile(api_path .. "sound_handling.lua")
dofile(api_path .. "death_logic.lua")
dofile(api_path .. "mob_effects.lua")
dofile(api_path .. "projectile_handling.lua")
dofile(api_path .. "breeding.lua")
dofile(api_path .. "head_logic.lua")
mobs.spawning_mobs = {}
-- register mob entity
function mobs:register_mob(name, def)
local collisionbox = def.collisionbox or {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25}
-- 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.
if collisionbox[5] < 0.79 then
collisionbox[5] = 0.79
end
mobs.spawning_mobs[name] = true
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)
end
end
minetest.register_entity(name, {
description = def.description,
use_texture_alpha = def.use_texture_alpha,
stepheight = def.stepheight or 0.6,
stepheight_backup = def.stepheight or 0.6,
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),
xp_min = def.xp_min or 1,
xp_max = def.xp_max or 5,
breath_max = def.breath_max or 6,
breathes_in_water = def.breathes_in_water or false,
physical = true,
collisionbox = collisionbox,
collide_with_objects = def.collide_with_objects or false,
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,
_cmi_is_mob = true,
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
automatic_face_movement_max_rotation_per_sec = 360, --degrees
backface_culling = true,
walk_timer = 0,
stand_timer = 0,
current_animation = "",
gravity = GRAVITY,
swim = def.swim,
swim_in = def.swim_in or {mobs_mc.items.water_source, "mcl_core:water_flowing", mobs_mc.items.river_water_source},
pitch_switch = "static",
jump_only = def.jump_only,
hostile = def.hostile,
neutral = def.neutral,
attacking = nil,
visual_size_origin = def.visual_size or {x = 1, y = 1, z = 1},
punch_timer_cooloff = def.punch_timer_cooloff or 0.5,
death_animation_timer = 0,
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,
skittish = def.skittish,
minimum_follow_distance = def.minimum_follow_distance or 0.5, --make mobs not freak out when underneath
memory = 0, -- memory timer if chasing/following
fly_random_while_attack = def.fly_random_while_attack,
--for spiders
always_climb = def.always_climb,
--despawn mechanic variables
lifetimer_reset = 30, --30 seconds
lifetimer = 30, --30 seconds
--breeding stuff
breed_timer = 0,
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)
bred = false,
follow = def.follow, --this item is also used for the breeding mechanism
follow_distance = def.follow_distance or 2,
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
special_breed_timer = 0, --this is used for the AHEM AHEM part of breeding
backup_visual_size = def.visual_size,
backup_collisionbox = collisionbox,
backup_selectionbox = def.selectionbox or def.collisionbox,
--fire timer
burn_timer = 0,
ignores_cobwebs = def.ignores_cobwebs,
breath = def.breath_max or 6,
random_sound_timer_min = 3,
random_sound_timer_max = 10,
--head code variables
--defaults are for the cow's default
--because I don't know what else to set them
--to :P
has_head = def.has_head or false,
head_bone = def.head_bone,
--you must use these to adjust the mob's head positions
--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
head_bone_pos_y = def.head_bone_pos_y or 3.6,
head_bone_pos_z = def.head_bone_pos_z or -0.6,
head_pitch_modifier = def.head_pitch_modifier or 0,
--these variables are switches in case the model
--moves the wrong way
swap_y_with_x = def.swap_y_with_x or false,
reverse_head_yaw = def.reverse_head_yaw or false,
--END HEAD CODE VARIABLES
--end j4i stuff
-- MCL2 extensions
teleport = mobs.teleport,
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,
--can_despawn = can_despawn,
child = def.child or false,
texture_mods = {},
shoot_arrow = def.shoot_arrow,
sounds_child = def.sounds_child,
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,
eye_height = def.eye_height or 1.5,
defuse_reach = def.defuse_reach or 4,
-- End of MCL2 extensions
on_spawn = def.on_spawn,
--on_blast = def.on_blast or do_tnt,
on_step = mobs.mob_step,
--do_punch = def.do_punch,
on_punch = mobs.mob_punch,
--on_breed = def.on_breed,
--on_grown = def.on_grown,
--on_detach_child = mob_detach_child,
on_activate = function(self, staticdata, dtime)
self.object:set_acceleration(vector_new(0,-GRAVITY, 0))
return mobs.mob_activate(self, staticdata, def, dtime)
end,
get_staticdata = function(self)
return mobs.mob_staticdata(self)
end,
--harmed_by_heal = def.harmed_by_heal,
})
if minetest_get_modpath("doc_identifier") ~= nil then
doc.sub.identifier.register_object(name, "basics", "mobs")
end
end -- END mobs:register_mob function
-- register arrow for shoot attack
function mobs:register_arrow(name, def)
-- errorcheck
if not name or not def then
print("failed to register arrow entity")
return
end
minetest.register_entity(name.."_entity", {
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,
hit_mob = def.hit_mob,
hit_object = def.hit_object,
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,
rotate = def.rotate,
speed = def.speed or nil,
on_step = function(self)
local vel = self.object:get_velocity()
local pos = self.object:get_pos()
if self.timer > 150
or not mobs.within_limits(pos, 0) then
mcl_burning.extinguish(self.object)
self.object:remove();
return
end
-- does arrow have a tail (fireball)
if def.tail
and def.tail == 1
and def.tail_texture then
--do this to prevent clipping through main entity sprite
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)
minetest.add_particle({
pos = new_pos,
velocity = {x = 0, y = 0, z = 0},
acceleration = {x = 0, y = 0, z = 0},
expirationtime = def.expire or 0.25,
collisiondetection = false,
texture = def.tail_texture,
size = def.tail_size or 5,
glow = def.glow or 0,
})
end
if self.hit_node then
local node = minetest_get_node(pos).name
if minetest_registered_nodes[node].walkable then
self.hit_node(self, pos, node)
if self.drop == true then
pos.y = pos.y + 1
self.lastpos = (self.lastpos or pos)
minetest_add_item(self.lastpos, self.object:get_luaentity().name)
end
self.object:remove();
return
end
end
if self.hit_player or self.hit_mob or self.hit_object then
for _,player in pairs(minetest_get_objects_inside_radius(pos, 1.5)) do
if self.hit_player
and player:is_player() then
if self.hit_player then
self.hit_player(self, player)
else
mobs.arrow_hit(self, player)
end
self.object:remove();
return
end
--[[
local entity = player:get_luaentity()
if entity
and self.hit_mob
and entity._cmi_is_mob == true
and tostring(player) ~= self.owner_id
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)
self.object:remove();
return
end
]]--
--[[
if entity
and self.hit_object
and (not entity._cmi_is_mob)
and tostring(player) ~= self.owner_id
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)
self.object:remove();
return
end
]]--
end
end
self.lastpos = pos
end
})
end
-- 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)
function mobs:register_egg(mob, desc, background, addegg, no_creative)
local grp = {spawn_egg = 1}
-- do NOT add this egg to creative inventory (e.g. dungeon master)
if no_creative == true then
grp.not_in_creative_inventory = 1
end
local invimg = background
if addegg == 1 then
invimg = "mobs_chicken_egg.png^(" .. invimg ..
"^[mask:mobs_chicken_egg_overlay.png)"
end
-- register old stackable mob egg
minetest.register_craftitem(mob, {
description = desc,
inventory_image = invimg,
groups = grp,
_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."),
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above
-- am I clicking on something with existing on_rightclick function?
local under = minetest_get_node(pointed_thing.under)
local def = minetest_registered_nodes[under.name]
if def and def.on_rightclick then
return def.on_rightclick(pointed_thing.under, under, placer, itemstack)
end
if pos
--and within_limits(pos, 0)
and not minetest_is_protected(pos, placer:get_player_name()) then
local name = placer:get_player_name()
local privs = minetest.get_player_privs(name)
if mod_mobspawners and under.name == "mcl_mobspawners:spawner" then
if minetest_is_protected(pointed_thing.under, name) then
minetest.record_protection_violation(pointed_thing.under, name)
return itemstack
end
if not privs.maphack then
minetest.chat_send_player(name, S("You need the “maphack” privilege to change the mob spawner."))
return itemstack
end
mcl_mobspawners.setup_spawner(pointed_thing.under, itemstack:get_name())
if not mobs.is_creative(name) then
itemstack:take_item()
end
return itemstack
end
if not minetest_registered_entities[mob] then
return itemstack
end
if minetest_settings:get_bool("only_peaceful_mobs", false)
and minetest_registered_entities[mob].type == "monster" then
minetest.chat_send_player(name, S("Only peaceful mobs allowed!"))
return itemstack
end
local mob = minetest_add_entity(pos, mob)
minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos))
local ent = mob:get_luaentity()
-- don't set owner if monster or sneak pressed
--[[
if ent.type ~= "monster"
and not placer:get_player_control().sneak then
ent.owner = placer:get_player_name()
ent.tamed = true
end
]]--
-- 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
-- if not in creative then take item
if not mobs.is_creative(placer:get_player_name()) then
itemstack:take_item()
end
end
return itemstack
end,
})
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,259 @@
local math_pi = math.pi
local math_floor = math.floor
local math_random = math.random
local HALF_PI = math_pi/2
local vector_direction = vector.direction
local vector_distance = vector.distance
local vector_new = vector.new
local minetest_dir_to_yaw = minetest.dir_to_yaw
-- set defined animation
mobs.set_mob_animation = function(self, anim, fixed_frame)
if not self.animation or not anim then
return
end
if self.state == "die" and anim ~= "die" and anim ~= "stand" then
return
end
if (not self.animation[anim .. "_start"] or not self.animation[anim .. "_end"]) then
return
end
--animations break if they are constantly set
--so we put this return gate to check if it is
--already at the animation we are trying to implement
if self.current_animation == anim then
return
end
local a_start = self.animation[anim .. "_start"]
local a_end
if fixed_frame then
a_end = a_start
else
a_end = self.animation[anim .. "_end"]
end
self.object:set_animation({
x = a_start,
y = a_end},
self.animation[anim .. "_speed"] or self.animation.speed_normal or 15,
0, self.animation[anim .. "_loop"] ~= false)
self.current_animation = anim
end
mobs.death_effect = function(pos, yaw, collisionbox, rotate)
local min, max
if collisionbox then
min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]}
max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]}
else
min = { x = -0.5, y = 0, z = -0.5 }
max = { x = 0.5, y = 0.5, z = 0.5 }
end
if rotate then
min = vector.rotate(min, {x=0, y=yaw, z=math_pi/2})
max = vector.rotate(max, {x=0, y=yaw, z=math_pi/2})
min, max = vector.sort(min, max)
min = vector.multiply(min, 0.5)
max = vector.multiply(max, 0.5)
end
minetest_add_particlespawner({
amount = 50,
time = 0.001,
minpos = vector.add(pos, min),
maxpos = vector.add(pos, max),
minvel = vector_new(-5,-5,-5),
maxvel = vector_new(5,5,5),
minexptime = 1.1,
maxexptime = 1.5,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "mcl_particles_mob_death.png^[colorize:#000000:255",
})
minetest_sound_play("mcl_mobs_mob_poof", {
pos = pos,
gain = 1.0,
max_hear_distance = 8,
}, true)
end
--this allows auto facedir rotation while making it so mobs
--don't look like wet noodles flopping around
mobs.movement_rotation_lock = function(self)
local current_engine_yaw = self.object:get_yaw()
local current_lua_yaw = self.yaw
if current_engine_yaw > math.pi * 2 then
current_engine_yaw = current_engine_yaw - (math.pi * 2)
end
if math.abs(current_engine_yaw - current_lua_yaw) <= 0.05 and self.object:get_properties().automatic_face_movement_dir then
self.object:set_properties{automatic_face_movement_dir = false}
elseif math.abs(current_engine_yaw - current_lua_yaw) > 0.05 and self.object:get_properties().automatic_face_movement_dir == false then
self.object:set_properties{automatic_face_movement_dir = self.rotate}
end
end
--this is used when a mob is chasing a player
mobs.set_yaw_while_attacking = function(self)
if self.object:get_properties().automatic_face_movement_dir then
self.object:set_properties{automatic_face_movement_dir = false}
end
--turn positions into pseudo 2d vectors
local pos1 = self.object:get_pos()
pos1.y = 0
local pos2 = self.attacking:get_pos()
pos2.y = 0
local new_direction = vector_direction(pos1,pos2)
local new_yaw = minetest_dir_to_yaw(new_direction)
self.object:set_yaw(new_yaw)
self.yaw = new_yaw
end
--this is used to unlock a mob's yaw after attacking
mobs.unlock_yaw = function(self)
if self.object:get_properties().automatic_face_movement_dir == false then
self.object:set_properties{automatic_face_movement_dir = self.rotate}
end
end
--this is used to lock a mob's yaw when they're standing
mobs.lock_yaw = function(self)
if self.object:get_properties().automatic_face_movement_dir then
self.object:set_properties{automatic_face_movement_dir = false}
end
end
local calculate_pitch = function(self)
local pos = self.object:get_pos()
local pos2 = self.old_pos
if pos == nil or pos2 == nil then
return false
end
return(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)) + HALF_PI)
end
--this is a helper function used to make mobs pitch rotation dynamically flow when flying/swimming
mobs.set_dynamic_pitch = function(self)
local pitch = calculate_pitch(self)
if not pitch then
return
end
local current_rotation = self.object:get_rotation()
current_rotation.x = pitch
self.object:set_rotation(current_rotation)
self.pitch_switch = "dynamic"
end
--this is a helper function used to make mobs pitch rotation reset when flying/swimming
mobs.set_static_pitch = function(self)
if self.pitch_switch == "static" then
return
end
local current_rotation = self.object:get_rotation()
current_rotation.x = 0
self.object:set_rotation(current_rotation)
self.pitch_switch = "static"
end
--this is a helper function for mobs explosion animation
mobs.handle_explosion_animation = function(self)
--secondary catch-all
if not self.explosion_animation then
self.explosion_animation = 0
end
--the timer works from 0 for sense of a 0 based counting
--but this just bumps it up so it's usable in here
local explosion_timer_adjust = self.explosion_animation + 1
local visual_size_modified = table.copy(self.visual_size_origin)
visual_size_modified.x = visual_size_modified.x * (explosion_timer_adjust ^ 3)
visual_size_modified.y = visual_size_modified.y * explosion_timer_adjust
self.object:set_properties({visual_size = visual_size_modified})
end
--this is used when a mob is following player
mobs.set_yaw_while_following = function(self)
if self.object:get_properties().automatic_face_movement_dir then
self.object:set_properties{automatic_face_movement_dir = false}
end
--turn positions into pseudo 2d vectors
local pos1 = self.object:get_pos()
pos1.y = 0
local pos2 = self.following_person:get_pos()
pos2.y = 0
local new_direction = vector_direction(pos1,pos2)
local new_yaw = minetest_dir_to_yaw(new_direction)
self.object:set_yaw(new_yaw)
self.yaw = new_yaw
end
--this is used for when mobs breed
mobs.set_yaw_while_breeding = function(self, mate)
if self.object:get_properties().automatic_face_movement_dir then
self.object:set_properties{automatic_face_movement_dir = false}
end
--turn positions into pseudo 2d vectors
local pos1 = self.object:get_pos()
pos1.y = 0
local pos2 = mate:get_pos()
pos2.y = 0
local new_direction = vector_direction(pos1,pos2)
local new_yaw = minetest_dir_to_yaw(new_direction)
self.object:set_yaw(new_yaw)
self.yaw = new_yaw
end

View File

@ -0,0 +1,351 @@
local vector_direction = vector.direction
local minetest_dir_to_yaw = minetest.dir_to_yaw
local vector_distance = vector.distance
local vector_multiply = vector.multiply
local math_random = math.random
--[[
_ _ _ _
| | | | | | | |
| | | | __ _ _ __ __| | | |
| | | | / _` | '_ \ / _` | | |
|_| | |___| (_| | | | | (_| | |_|
(_) \_____/\__,_|_| |_|\__,_| (_)
]]--
--[[
_____ _ _
| ___| | | | |
| |____ ___ __ | | ___ __| | ___
| __\ \/ / '_ \| |/ _ \ / _` |/ _ \
| |___> <| |_) | | (_) | (_| | __/
\____/_/\_\ .__/|_|\___/ \__,_|\___|
| |
|_|
]]--
mobs.explode_attack_walk = function(self,dtime)
--this needs an exception
if self.attacking == nil or not self.attacking:is_player() then
self.attacking = nil
return
end
mobs.set_yaw_while_attacking(self)
local distance_from_attacking = vector_distance(self.object:get_pos(), self.attacking:get_pos())
--make mob walk up to player within 2 nodes distance then start exploding
if distance_from_attacking >= self.reach and
--don't allow explosion to cancel unless out of the reach boundary
not (self.explosion_animation ~= nil and self.explosion_animation > 0 and distance_from_attacking <= self.defuse_reach) then
mobs.set_velocity(self, self.run_velocity)
mobs.set_mob_animation(self,"run")
mobs.reverse_explosion_animation(self,dtime)
else
mobs.set_velocity(self,0)
--this is the only way I can reference this without dumping extra data on all mobs
if not self.explosion_animation then
self.explosion_animation = 0
end
--play ignite sound
if self.explosion_animation == 0 then
mobs.play_sound(self,"attack")
end
mobs.set_mob_animation(self,"stand")
mobs.handle_explosion_animation(self)
self.explosion_animation = self.explosion_animation + (dtime/2.5)
end
--make explosive mobs jump
--check for nodes to jump over
--explosive mobs will just ride against walls for now
local node_in_front_of = mobs.jump_check(self)
if node_in_front_of == 1 then
mobs.jump(self)
end
--do biggening explosion thing
if self.explosion_animation and self.explosion_animation > self.explosion_timer then
mcl_explosions.explode(self.object:get_pos(), self.explosion_strength,{ drop_chance = 1.0 })
self.object:remove()
end
end
--this is a small helper function to make working with explosion animations easier
mobs.reverse_explosion_animation = function(self,dtime)
--if explosion animation was greater than 0 then reverse it
if self.explosion_animation ~= nil and self.explosion_animation > 0 then
self.explosion_animation = self.explosion_animation - dtime
if self.explosion_animation < 0 then
self.explosion_animation = 0
end
end
mobs.handle_explosion_animation(self)
end
--[[
______ _
| ___ \ | |
| |_/ / _ _ __ ___| |__
| __/ | | | '_ \ / __| '_ \
| | | |_| | | | | (__| | | |
\_| \__,_|_| |_|\___|_| |_|
]]--
mobs.punch_attack_walk = function(self,dtime)
--this needs an exception
if self.attacking == nil or not self.attacking:is_player() then
self.attacking = nil
return
end
local distance_from_attacking = mobs.get_2d_distance(self.object:get_pos(), self.attacking:get_pos())
if distance_from_attacking >= self.minimum_follow_distance then
mobs.set_velocity(self, self.run_velocity)
mobs.set_mob_animation(self, "run")
else
mobs.set_velocity(self, 0)
mobs.set_mob_animation(self, "stand")
end
mobs.set_yaw_while_attacking(self)
--make punchy mobs jump
--check for nodes to jump over
--explosive mobs will just ride against walls for now
local node_in_front_of = mobs.jump_check(self)
if node_in_front_of == 1 then
mobs.jump(self)
end
--mobs that can climb over stuff
if self.always_climb and node_in_front_of > 0 then
mobs.climb(self)
end
--auto reset punch_timer
if not self.punch_timer then
self.punch_timer = 0
end
if self.punch_timer > 0 then
self.punch_timer = self.punch_timer - dtime
end
end
mobs.punch_attack = function(self)
self.attacking:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = self.damage}
}, nil)
self.punch_timer = self.punch_timer_cooloff
--knockback
local pos1 = self.object:get_pos()
pos1.y = 0
local pos2 = self.attacking:get_pos()
pos2.y = 0
local dir = vector_direction(pos1,pos2)
dir = vector_multiply(dir,3)
if self.attacking:get_velocity().y <= 1 then
dir.y = 5
end
self.attacking:add_velocity(dir)
end
--[[
______ _ _ _ _
| ___ \ (_) | | (_) |
| |_/ / __ ___ _ ___ ___| |_ _| | ___
| __/ '__/ _ \| |/ _ \/ __| __| | |/ _ \
| | | | | (_) | | __/ (__| |_| | | __/
\_| |_| \___/| |\___|\___|\__|_|_|\___|
_/ |
|__/
]]--
mobs.projectile_attack_walk = function(self,dtime)
--this needs an exception
if self.attacking == nil or not self.attacking:is_player() then
self.attacking = nil
return
end
mobs.set_yaw_while_attacking(self)
local distance_from_attacking = vector_distance(self.object:get_pos(), self.attacking:get_pos())
if distance_from_attacking >= self.reach then
mobs.set_velocity(self, self.run_velocity)
mobs.set_mob_animation(self,"run")
else
mobs.set_velocity(self,0)
mobs.set_mob_animation(self,"stand")
end
--do this to not load data into other mobs
if not self.projectile_timer then
self.projectile_timer = math_random(self.projectile_cooldown_min, self.projectile_cooldown_max)
end
--run projectile timer
if self.projectile_timer > 0 then
self.projectile_timer = self.projectile_timer - dtime
--shoot
if self.projectile_timer <= 0 then
--reset timer
self.projectile_timer = math_random(self.projectile_cooldown_min, self.projectile_cooldown_max)
mobs.shoot_projectile(self)
end
end
--make shooty mobs jump
--check for nodes to jump over
--explosive mobs will just ride against walls for now
local node_in_front_of = mobs.jump_check(self)
if node_in_front_of == 1 then
mobs.jump(self)
end
end
--[[
_ ______ _ _
| | | ___| | | |
| | | |_ | |_ _ | |
| | | _| | | | | | | |
|_| | | | | |_| | |_|
(_) \_| |_|\__, | (_)
__/ |
|___/
]]--
--[[
______ _ _ _ _
| ___ \ (_) | | (_) |
| |_/ / __ ___ _ ___ ___| |_ _| | ___
| __/ '__/ _ \| |/ _ \/ __| __| | |/ _ \
| | | | | (_) | | __/ (__| |_| | | __/
\_| |_| \___/| |\___|\___|\__|_|_|\___|
_/ |
|__/
]]--
local random_pitch_multiplier = {-1,1}
mobs.projectile_attack_fly = function(self, dtime)
--this needs an exception
if self.attacking == nil or not self.attacking:is_player() then
self.attacking = nil
return
end
--this is specifically for random ghast movement
if self.fly_random_while_attack then
--enable rotation locking
mobs.movement_rotation_lock(self)
self.walk_timer = self.walk_timer - dtime
--reset the walk timer
if self.walk_timer <= 0 then
--re-randomize the walk timer
self.walk_timer = math.random(1,6) + math.random()
--set the mob into a random direction
self.yaw = (math_random() * (math.pi * 2))
--create a truly random pitch, since there is no easy access to pitch math that I can find
self.pitch = math_random() * math.random(1,3) * random_pitch_multiplier[math_random(1,2)]
end
mobs.set_fly_velocity(self, self.run_velocity)
else
mobs.set_yaw_while_attacking(self)
local distance_from_attacking = vector_distance(self.object:get_pos(), self.attacking:get_pos())
if distance_from_attacking >= self.reach then
mobs.set_pitch_while_attacking(self)
mobs.set_fly_velocity(self, self.run_velocity)
mobs.set_mob_animation(self,"run")
else
mobs.set_pitch_while_attacking(self)
mobs.set_fly_velocity(self, 0)
mobs.set_mob_animation(self,"stand")
end
end
--do this to not load data into other mobs
if not self.projectile_timer then
self.projectile_timer = math_random(self.projectile_cooldown_min, self.projectile_cooldown_max)
end
--run projectile timer
if self.projectile_timer > 0 then
self.projectile_timer = self.projectile_timer - dtime
--shoot
if self.projectile_timer <= 0 then
if self.fly_random_while_attack then
mobs.set_yaw_while_attacking(self)
self.walk_timer = 0
end
--reset timer
self.projectile_timer = math_random(self.projectile_cooldown_min, self.projectile_cooldown_max)
mobs.shoot_projectile(self)
end
end
end

View File

@ -0,0 +1,184 @@
local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius
local vector_distance = vector.distance
--check to see if someone nearby has some tasty food
mobs.check_following = function(self) -- returns true or false
--ignore
if not self.follow then
self.following_person = nil
return(false)
end
--hey look, this thing works for passive mobs too!
local follower = mobs.detect_closest_player_within_radius(self,true,self.view_range,self.eye_height)
--check if the follower is a player incase they log out
if follower and follower:is_player() then
local stack = follower:get_wielded_item()
--safety check
if not stack then
self.following_person = nil
return(false)
end
local item_name = stack:get_name()
--all checks have passed, that guy has some good looking food
if item_name == self.follow then
self.following_person = follower
return(true)
end
end
--everything failed
self.following_person = nil
return(false)
end
--a function which attempts to make mobs enter
--the breeding state
mobs.enter_breed_state = function(self,clicker)
--do not breed if baby
if self.baby then
return(false)
end
--do not do anything if looking for mate or
--if cooling off from breeding
if self.breed_lookout_timer > 0 or self.breed_timer > 0 then
return(false)
end
--if this is caught, that means something has gone
--seriously wrong
if not clicker or not clicker:is_player() then
return(false)
end
local stack = clicker:get_wielded_item()
--safety check
if not stack then
return(false)
end
local item_name = stack:get_name()
--all checks have passed, that guy has some good looking food
if item_name == self.follow then
if not minetest.is_creative_enabled(clicker:get_player_name()) then
stack:take_item()
clicker:set_wielded_item(stack)
end
self.breed_lookout_timer = self.breed_lookout_timer_goal
self.bred = true
mobs.play_sound_specific(self,"mobs_mc_animal_eat_generic")
return(true)
end
--everything failed
return(false)
end
--find the closest mate in the area
mobs.look_for_mate = function(self)
local pos1 = self.object:get_pos()
pos1.y = pos1.y + self.eye_height
local mates_in_area = {}
local winner_mate = nil
local mates_detected = 0
local radius = self.view_range
--get mates in radius
for _,mate in pairs(minetest_get_objects_inside_radius(pos1, radius)) do
--look for a breeding mate
if mate and mate:get_luaentity()
and mate:get_luaentity()._cmi_is_mob
and mate:get_luaentity().name == self.name
and mate:get_luaentity().breed_lookout_timer > 0
and mate:get_luaentity() ~= self then
local pos2 = mate:get_pos()
local distance = vector_distance(pos1,pos2)
if distance <= radius then
if line_of_sight then
--must add eye height or stuff breaks randomly because of
--seethrough nodes being a blocker (like grass)
if minetest_line_of_sight(
vector_new(pos1.x, pos1.y, pos1.z),
vector_new(pos2.x, pos2.y + mate:get_properties().eye_height, pos2.z)
) then
mates_detected = mates_detected + 1
mates_in_area[mate] = distance
end
else
mates_detected = mates_detected + 1
mates_in_area[mate] = distance
end
end
end
end
--return if there's no one near by
if mates_detected <= 0 then --handle negative numbers for some crazy error that could possibly happen
return nil
end
--do a default radius max
local shortest_distance = radius + 1
--sort through mates and find the closest mate
for mate,distance in pairs(mates_in_area) do
if distance < shortest_distance then
shortest_distance = distance
winner_mate = mate
end
end
return(winner_mate)
end
--make the baby grow up
mobs.baby_grow_up = function(self)
self.baby = nil
self.visual_size = self.backup_visual_size
self.collisionbox = self.backup_collisionbox
self.selectionbox = self.backup_selectionbox
self.object:set_properties(self)
end
--makes the baby grow up faster with diminishing returns
mobs.make_baby_grow_faster = function(self,clicker)
if clicker and clicker:is_player() then
local stack = clicker:get_wielded_item()
--safety check
if not stack then
return(false)
end
local item_name = stack:get_name()
--all checks have passed, that guy has some good looking food
if item_name == self.follow then
self.grow_up_timer = self.grow_up_timer - (self.grow_up_timer * 0.10) --take 10 percent off - diminishing returns
if not minetest.is_creative_enabled(clicker:get_player_name()) then
stack:take_item()
clicker:set_wielded_item(stack)
end
mobs.play_sound_specific(self,"mobs_mc_animal_eat_generic")
return(true)
end
end
return(false)
end

View File

@ -0,0 +1,140 @@
local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius
local math_random = math.random
local vector_multiply = vector.multiply
local vector_direction = vector.direction
local integer_test = {-1,1}
mobs.collision = function(self)
local pos = self.object:get_pos()
if not self or not self.object or not self.object:get_luaentity() then
return
end
--do collision detection from the base of the mob
local collisionbox = self.object:get_properties().collisionbox
pos.y = pos.y + collisionbox[2]
local collision_boundary = collisionbox[4]
local radius = collision_boundary
if collisionbox[5] > collision_boundary then
radius = collisionbox[5]
end
local collision_count = 0
local check_for_attack = false
if self.attack_type == "punch" and self.hostile and self.attacking then
check_for_attack = true
end
for _,object in ipairs(minetest_get_objects_inside_radius(pos, radius*1.25)) do
if object and object ~= self.object and (object:is_player() or (object:get_luaentity() and object:get_luaentity()._cmi_is_mob == true and object:get_luaentity().health > 0)) 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
--mob cramming
if collision_count > 30 then
self.health = -20
break
end
local pos2 = object:get_pos()
local object_collisionbox = object:get_properties().collisionbox
pos2.y = pos2.y + object_collisionbox[2]
local 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
local y_base_diff = (pos2.y + object_collisionbox[5]) - pos.y
local y_top_diff = (pos.y + collisionbox[5]) - pos2.y
local 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
local dir = vector.direction(pos,pos2)
dir.y = 0
--eliminate mob being stuck in corners
if dir.x == 0 and dir.z == 0 then
--slightly adjust mob position to prevent equal length
--corner/wall sticking
dir.x = dir.x + ((math_random()/10)*integer_test[math.random(1,2)])
dir.z = dir.z + ((math_random()/10)*integer_test[math.random(1,2)])
end
local velocity = dir
--0.5 is the max force multiplier
local force = 0.5 - (0.5 * distance / (collision_boundary + object_collision_boundary))
local vel1 = vector.multiply(velocity, -1.5)
local vel2 = vector.multiply(velocity, 1.5)
vel1 = vector.multiply(vel1, force * 10)
vel2 = vector.multiply(vel2, force)
if object:is_player() then
vel2 = vector_multiply(vel2, 2.5)
--integrate mob punching into collision detection
if check_for_attack and self.punch_timer <= 0 then
if object == self.attacking then
mobs.punch_attack(self)
end
end
end
self.object:add_velocity(vel1)
object:add_velocity(vel2)
end
end
end
end
--this is used for arrow collisions
mobs.arrow_hit = function(self, player)
player:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = self._damage}
}, nil)
--knockback
local pos1 = self.object:get_pos()
pos1.y = 0
local pos2 = player:get_pos()
pos2.y = 0
local dir = vector_direction(pos1,pos2)
dir = vector_multiply(dir,3)
if player:get_velocity().y <= 1 then
dir.y = 5
end
player:add_velocity(dir)
end

View File

@ -0,0 +1,154 @@
local minetest_add_item = minetest.add_item
local minetest_sound_play = minetest.sound_play
local math_pi = math.pi
local math_random = math.random
local math_floor = math.floor
local HALF_PI = math_pi / 2
local vector_new = vector.new
-- drop items
local item_drop = function(self, cooked, looting_level)
looting_level = looting_level or 0
-- no drops for child mobs (except monster)
if (self.child and self.type ~= "monster") then
return
end
local obj, item, num
local pos = self.object:get_pos()
self.drops = self.drops or {} -- nil check
for n = 1, #self.drops do
local dropdef = self.drops[n]
local chance = 1 / dropdef.chance
local looting_type = dropdef.looting
if looting_level > 0 then
local chance_function = dropdef.looting_chance_function
if chance_function then
chance = chance_function(looting_level)
elseif looting_type == "rare" then
chance = chance + (dropdef.looting_factor or 0.01) * looting_level
end
end
local num = 0
local do_common_looting = (looting_level > 0 and looting_type == "common")
if math_random() < chance then
num = math_random(dropdef.min or 1, dropdef.max or 1)
elseif not dropdef.looting_ignore_chance then
do_common_looting = false
end
if do_common_looting then
num = num + math_floor(math_random(0, looting_level) + 0.5)
end
if num > 0 then
item = dropdef.name
-- cook items when true
if cooked then
local output = minetest_get_craft_result({
method = "cooking", width = 1, items = {item}})
if output and output.item and not output.item:is_empty() then
item = output.item:get_name()
end
end
-- add item if it exists
for x = 1, num do
obj = minetest_add_item(pos, ItemStack(item .. " " .. 1))
end
if obj and obj:get_luaentity() then
obj:set_velocity({
x = math_random(-10, 10) / 9,
y = 6,
z = math_random(-10, 10) / 9,
})
elseif obj then
obj:remove() -- item does not exist
end
end
end
self.drops = {}
end
mobs.death_logic = function(self, dtime)
self.death_animation_timer = self.death_animation_timer + dtime
--get all attached entities and sort through them
local attached_entities = self.object:get_children()
if #attached_entities > 0 then
for _,entity in pairs(attached_entities) do
--kick the player off
if entity:is_player() then
mobs.detach(entity)
--kick mobs off
--if there is scaling issues, this needs an additional check
else
entity:set_detach()
end
end
end
--stop mob from getting in the way of other mobs you're fighting
if self.object:get_properties().pointable then
self.object:set_properties({pointable = false})
end
--the final POOF of a mob despawning
if self.death_animation_timer >= 1.25 then
item_drop(self,false,1)
mobs.death_effect(self)
mcl_experience.throw_experience(self.object:get_pos(), math_random(self.xp_min, self.xp_max))
self.object:remove()
return
end
--I'm sure there's a more efficient way to do this
--but this is the easiest, easier to work with 1 variable synced
--this is also not smooth
local death_animation_roll = self.death_animation_timer * 2 -- * 2 to make it faster
if death_animation_roll > 1 then
death_animation_roll = 1
end
local rot = self.object:get_rotation() --(no pun intended)
rot.z = death_animation_roll * HALF_PI
self.object:set_rotation(rot)
mobs.set_mob_animation(self,"stand", true)
--flying and swimming mobs just fall down
if self.fly or self.swim then
if self.object:get_acceleration().y ~= -self.gravity then
self.object:set_acceleration(vector_new(0,-self.gravity,0))
end
end
--when landing allow mob to slow down and just fall if in air
if self.pause_timer <= 0 then
mobs.set_velocity(self,0)
end
end

View File

@ -0,0 +1,260 @@
local minetest_line_of_sight = minetest.line_of_sight
local minetest_dir_to_yaw = minetest.dir_to_yaw
local minetest_yaw_to_dir = minetest.yaw_to_dir
local minetest_get_node = minetest.get_node
local minetest_get_item_group = minetest.get_item_group
local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius
local minetest_get_node_or_nil = minetest.get_node_or_nil
local minetest_registered_nodes = minetest.registered_nodes
local minetest_get_connected_players = minetest.get_connected_players
local vector_new = vector.new
local vector_add = vector.add
local vector_multiply = vector.multiply
local vector_distance = vector.distance
local table_copy = table.copy
local math_abs = math.abs
-- default function when mobs are blown up with TNT
local do_tnt = function(obj, damage)
obj.object:punch(obj.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = damage},
}, nil)
return false, true, {}
end
--a fast function to be able to detect only players without using objects_in_radius
mobs.detect_closest_player_within_radius = function(self, line_of_sight, radius, object_height_adder)
local pos1 = self.object:get_pos()
local players_in_area = {}
local winner_player = nil
local players_detected = 0
--get players in radius
for _,player in pairs(minetest.get_connected_players()) do
if player and player:get_hp() > 0 then
local pos2 = player:get_pos()
local distance = vector_distance(pos1,pos2)
if distance <= radius then
if line_of_sight then
--must add eye height or stuff breaks randomly because of
--seethrough nodes being a blocker (like grass)
if minetest_line_of_sight(
vector_new(pos1.x, pos1.y + object_height_adder, pos1.z),
vector_new(pos2.x, pos2.y + player:get_properties().eye_height, pos2.z)
) then
players_detected = players_detected + 1
players_in_area[player] = distance
end
else
players_detected = players_detected + 1
players_in_area[player] = distance
end
end
end
end
--return if there's no one near by
if players_detected <= 0 then --handle negative numbers for some crazy error that could possibly happen
return nil
end
--do a default radius max
local shortest_distance = radius + 1
--sort through players and find the closest player
for player,distance in pairs(players_in_area) do
if distance < shortest_distance then
shortest_distance = distance
winner_player = player
end
end
return(winner_player)
end
--check if a mob needs to jump
mobs.jump_check = function(self,dtime)
local pos = self.object:get_pos()
pos.y = pos.y + 0.1
local dir = minetest_yaw_to_dir(self.yaw)
local collisionbox = self.object:get_properties().collisionbox
local radius = collisionbox[4] + 0.5
vector_multiply(dir, radius)
--only jump if there's a node and a non-solid node above it
local test_dir = vector_add(pos,dir)
local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0
test_dir.y = test_dir.y + 1
local green_flag_2 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") == 0
if green_flag_1 and green_flag_2 then
--can jump over node
return(1)
elseif green_flag_1 and not green_flag_2 then
--wall in front of mob
return(2)
end
--nothing to jump over
return(0)
end
-- a helper function to quickly turn neutral passive mobs hostile
local turn_hostile = function(self,detected_mob)
--drop in variables for attacking (stops crash)
detected_mob.punch_timer = 0
--set to hostile
detected_mob.hostile = true
--hostile_cooldown timer is initialized here
detected_mob.hostile_cooldown_timer = detected_mob.hostile_cooldown
--set target to the same
detected_mob.attacking = self.attacking
end
--allow hostile mobs to signal to other mobs
--to switch from neutal passive to neutral hostile
mobs.group_attack_initialization = function(self)
--get basic data
local friends_list
if self.group_attack == true then
friends_list = {self.name}
else
friends_list = table_copy(self.group_attack)
end
local objects_in_area = minetest_get_objects_inside_radius(self.object:get_pos(), self.view_range)
--get the player's name
local name = self.attacking:get_player_name()
--re-use local variable
local detected_mob
--run through mobs in viewing distance
for _,object in pairs(objects_in_area) do
if object and object:get_luaentity() then
detected_mob = object:get_luaentity()
-- only alert members of same mob or friends
if detected_mob._cmi_is_mob and detected_mob.state ~= "attack" and detected_mob.owner ~= name then
if detected_mob.name == self.name then
turn_hostile(self,detected_mob)
else
for _,id in pairs(friends_list) do
if detected_mob.name == id then
turn_hostile(self,detected_mob)
break
end
end
end
end
--THIS NEEDS TO BE RE-IMPLEMENTED AS A GLOBAL HIT IN MOB_PUNCH!!
-- have owned mobs attack player threat
--if obj.owner == name and obj.owner_loyal then
-- do_attack(obj, self.object)
--end
end
end
end
-- check if within physical map limits (-30911 to 30927)
-- within_limits, wmin, wmax = nil, -30913, 30928
mobs.within_limits = function(pos, radius)
if mcl_vars then
if mcl_vars.mapgen_edge_min and mcl_vars.mapgen_edge_max then
wmin, wmax = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max
within_limits = function(pos, radius)
return pos
and (pos.x - radius) > wmin and (pos.x + radius) < wmax
and (pos.y - radius) > wmin and (pos.y + radius) < wmax
and (pos.z - radius) > wmin and (pos.z + radius) < wmax
end
end
end
return pos
and (pos.x - radius) > wmin and (pos.x + radius) < wmax
and (pos.y - radius) > wmin and (pos.y + radius) < wmax
and (pos.z - radius) > wmin and (pos.z + radius) < wmax
end
-- get node but use fallback for nil or unknown
mobs.node_ok = function(pos, fallback)
fallback = fallback or mobs.fallback_node
local node = minetest_get_node_or_nil(pos)
if node and minetest_registered_nodes[node.name] then
return node
end
return minetest_registered_nodes[fallback]
end
--a teleport functoin
mobs.teleport = function(self, target)
if self.do_teleport then
if self.do_teleport(self, target) == false then
return
end
end
end
--a function used for despawning mobs
mobs.check_for_player_within_area = function(self, radius)
local pos1 = self.object:get_pos()
--get players in radius
for _,player in pairs(minetest_get_connected_players()) do
if player and player:get_hp() > 0 then
local pos2 = player:get_pos()
local distance = vector_distance(pos1,pos2)
if distance < radius then
--found a player
return(true)
end
end
end
--did not find a player
return(false)
end
--a simple helper function for mobs following
mobs.get_2d_distance = function(pos1,pos2)
pos1.y = 0
pos2.y = 0
return(vector_distance(pos1, pos2))
end
-- fall damage onto solid ground
mobs.calculate_fall_damage = function(self)
if self.old_velocity and self.old_velocity.y < -7 and self.object:get_velocity().y == 0 then
local vel = self.object:get_velocity()
if vel then
local damage = math_abs(self.old_velocity.y + 7) * 2
self.pause_timer = 0.4
self.health = self.health - damage
end
end
end

View File

@ -0,0 +1,112 @@
local vector_new = vector.new
--converts yaw to degrees
local degrees = function(yaw)
return(yaw*180.0/math.pi)
end
mobs.do_head_logic = function(self,dtime)
local player = minetest.get_player_by_name("singleplayer")
local look_at = player:get_pos()
look_at.y = look_at.y + player:get_properties().eye_height
local pos = self.object:get_pos()
local body_yaw = self.object:get_yaw()
local body_dir = minetest.yaw_to_dir(body_yaw)
pos.y = pos.y + self.head_height_offset
local head_offset = vector.multiply(body_dir, self.head_direction_offset)
pos = vector.add(pos, head_offset)
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 = "default_dirt.png",
})
local bone_pos = vector_new(0,0,0)
--(horizontal)
bone_pos.y = self.head_bone_pos_y
--(vertical)
bone_pos.z = self.head_bone_pos_z
--print(yaw)
--local _, bone_rot = self.object:get_bone_position("head")
--bone_rot.x = bone_rot.x + (dtime * 10)
--bone_rot.z = bone_rot.z + (dtime * 10)
local head_yaw
head_yaw = minetest.dir_to_yaw(vector.direction(pos,look_at)) - body_yaw
if self.reverse_head_yaw then
head_yaw = head_yaw * -1
end
--over rotation protection
--stops radians from going out of spec
if head_yaw > math.pi then
head_yaw = head_yaw - (math.pi * 2)
elseif head_yaw < -math.pi then
head_yaw = head_yaw + (math.pi * 2)
end
local check_failed = false
--upper check + 90 degrees or upper math.radians (3.14/2)
if head_yaw > math.pi - (math.pi/2) then
head_yaw = 0
check_failed = true
--lower check - 90 degrees or lower negative math.radians (-3.14/2)
elseif head_yaw < -math.pi + (math.pi/2) then
head_yaw = 0
check_failed = true
end
local head_pitch = 0
--DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
--head_yaw = 0
--DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
if not check_failed then
head_pitch = minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(look_at.x,0,look_at.z)),0,pos.y-look_at.y))+(math.pi/2)
end
if self.head_pitch_modifier then
head_pitch = head_pitch + self.head_pitch_modifier
end
if self.swap_y_with_x then
self.object:set_bone_position(self.head_bone, bone_pos, vector_new(degrees(head_pitch),degrees(head_yaw),0))
else
self.object:set_bone_position(self.head_bone, bone_pos, vector_new(degrees(head_pitch),0,degrees(head_yaw)))
end
--set_bone_position([bone, position, rotation])
end

View File

@ -0,0 +1,291 @@
local minetest_after = minetest.after
local minetest_sound_play = minetest.sound_play
local minetest_dir_to_yaw = minetest.dir_to_yaw
local math_floor = math.floor
local math_min = math.min
local math_random = math.random
local vector_direction = vector.direction
local vector_multiply = vector.multiply
local MAX_MOB_NAME_LENGTH = 30
mobs.feed_tame = function(self)
return nil
end
-- Code to execute before custom on_rightclick handling
local on_rightclick_prefix = function(self, clicker)
local item = clicker:get_wielded_item()
-- Name mob with nametag
if not self.ignores_nametag and item:get_name() == "mcl_mobs:nametag" then
local tag = item:get_meta():get_string("name")
if tag ~= "" then
if string.len(tag) > MAX_MOB_NAME_LENGTH then
tag = string.sub(tag, 1, MAX_MOB_NAME_LENGTH)
end
self.nametag = tag
mobs.update_tag(self)
if not mobs.is_creative(clicker:get_player_name()) then
item:take_item()
clicker:set_wielded_item(item)
end
return true
end
end
return false
end
-- I have no idea what this does
mobs.create_mob_on_rightclick = function(on_rightclick)
return function(self, clicker)
--don't allow rightclicking dead mobs
if self.health <= 0 then
return
end
local stop = on_rightclick_prefix(self, clicker)
if (not stop) and (on_rightclick) then
on_rightclick(self, clicker)
end
end
end
-- deal damage and effects when mob punched
mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
--don't do anything if the mob is already dead
if self.health <= 0 then
return
end
--neutral passive mobs switch to neutral hostile
if self.neutral then
--drop in variables for attacking (stops crash)
self.attacking = hitter
self.punch_timer = 0
self.hostile = true
--hostile_cooldown timer is initialized here
self.hostile_cooldown_timer = self.hostile_cooldown
--initialize the group attack (check for other mobs in area, make them neutral hostile)
if self.group_attack then
mobs.group_attack_initialization(self)
end
end
--turn skittish mobs away and RUN
if self.skittish then
self.state = "run"
self.run_timer = 5 --arbitrary 5 seconds
local pos1 = self.object:get_pos()
pos1.y = 0
local pos2 = hitter:get_pos()
pos2.y = 0
local dir = vector_direction(pos2,pos1)
local yaw = minetest_dir_to_yaw(dir)
self.yaw = yaw
end
-- custom punch function
if self.do_punch then
-- when false skip going any further
if self.do_punch(self, hitter, tflp, tool_capabilities, dir) == false then
return
end
end
--don't do damage until pause timer resets
if self.pause_timer > 0 then
return
end
-- error checking when mod profiling is enabled
if not tool_capabilities then
minetest.log("warning", "[mobs_mc] Mod profiling enabled, damage not enabled")
return
end
local is_player = hitter:is_player()
-- punch interval
local weapon = hitter:get_wielded_item()
local punch_interval = 1.4
-- exhaust attacker
if mod_hunger and is_player then
mcl_hunger.exhaust(hitter:get_player_name(), mcl_hunger.EXHAUST_ATTACK)
end
-- calculate mob damage
local damage = 0
local armor = self.object:get_armor_groups() or {}
local tmp
--calculate damage groups
for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do
damage = damage + (tool_capabilities.damage_groups[group] or 0) * ((armor[group] or 0) / 100.0)
end
if weapon then
local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect")
if fire_aspect_level > 0 then
mcl_burning.set_on_fire(self.object, fire_aspect_level * 4)
end
end
-- check for tool immunity or special damage
for n = 1, #self.immune_to do
if self.immune_to[n][1] == weapon:get_name() then
damage = self.immune_to[n][2] or 0
break
end
end
-- healing
if damage <= -1 then
self.health = self.health - math_floor(damage)
return
end
if tool_capabilities then
punch_interval = tool_capabilities.full_punch_interval or 1.4
end
-- add weapon wear manually
-- Required because we have custom health handling ("health" property)
--minetest_is_creative_enabled("") ~= true --removed for now
if tool_capabilities then
if tool_capabilities.punch_attack_uses then
-- Without this delay, the wear does not work. Quite hacky ...
minetest_after(0, function(name)
local player = minetest.get_player_by_name(name)
if not player then return end
local weapon = hitter:get_wielded_item(player)
local def = weapon:get_definition()
if def.tool_capabilities and def.tool_capabilities.punch_attack_uses then
local wear = math_floor(65535/tool_capabilities.punch_attack_uses)
weapon:add_wear(wear)
hitter:set_wielded_item(weapon)
end
end, hitter:get_player_name())
end
end
--if player is falling multiply damage by 1.5
--critical hit
if hitter:get_velocity().y < 0 then
damage = damage * 1.5
mobs.critical_effect(self)
end
-- only play hit sound and show blood effects if damage is 1 or over; lower to 0.1 to ensure armor works appropriately.
if damage >= 0.1 then
minetest_sound_play("default_punch", {
object = self.object,
max_hear_distance = 16
}, true)
-- do damage
self.health = self.health - damage
--0.4 seconds until you can hurt the mob again
self.pause_timer = 0.4
--don't do knockback from a rider
for _,obj in pairs(self.object:get_children()) do
if obj == hitter then
return
end
end
-- knock back effect
local velocity = self.object:get_velocity()
--2d direction
local pos1 = self.object:get_pos()
pos1.y = 0
local pos2 = hitter:get_pos()
pos2.y = 0
local dir = vector.direction(pos2,pos1)
local up = 3
-- if already in air then dont go up anymore when hit
if velocity.y ~= 0 then
up = 0
end
--0.75 for perfect distance to not be too easy, and not be too hard
local multiplier = 0.75
-- check if tool already has specific knockback value
local knockback_enchant = mcl_enchanting.get_enchantment(hitter:get_wielded_item(), "knockback")
if knockback_enchant and knockback_enchant > 0 then
multiplier = knockback_enchant + 1 --(starts from 1, 1 would be no change)
end
--do this to sure you can punch a mob back when
--it's coming for you
if self.hostile then
multiplier = multiplier + 2
end
dir = vector_multiply(dir,multiplier)
dir.y = up
--add the velocity
self.object:add_velocity(dir)
end
end
--do internal per mob projectile calculations
mobs.shoot_projectile = function(self)
local pos1 = self.object:get_pos()
--add mob eye height
pos1.y = pos1.y + self.eye_height
local pos2 = self.attacking:get_pos()
--add player eye height
pos2.y = pos2.y + self.attacking:get_properties().eye_height
--get direction
local dir = vector_direction(pos1,pos2)
--call internal shoot_arrow function
self.shoot_arrow(self,pos1,dir)
end
mobs.update_tag = function(self)
self.object:set_properties({
nametag = self.nametag,
})
end

View File

@ -0,0 +1,152 @@
local minetest_add_particlespawner = minetest.add_particlespawner
mobs.death_effect = function(self)
local pos = self.object:get_pos()
local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox
local min, max
if collisionbox then
min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]}
max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]}
end
minetest_add_particlespawner({
amount = 50,
time = 0.0001,
minpos = vector.add(pos, min),
maxpos = vector.add(pos, max),
minvel = vector.new(-0.5,0.5,-0.5),
maxvel = vector.new(0.5,1,0.5),
minexptime = 1.1,
maxexptime = 1.5,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "mcl_particles_mob_death.png", -- this particle looks strange
})
end
mobs.critical_effect = function(self)
local pos = self.object:get_pos()
local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox
local min, max
if collisionbox then
min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]}
max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]}
end
minetest_add_particlespawner({
amount = 10,
time = 0.0001,
minpos = vector.add(pos, min),
maxpos = vector.add(pos, max),
minvel = vector.new(-1,1,-1),
maxvel = vector.new(1,3,1),
minexptime = 0.7,
maxexptime = 1,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "heart.png^[colorize:black:255",
})
end
--when feeding a mob
mobs.feed_effect = function(self)
local pos = self.object:get_pos()
local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox
local min, max
if collisionbox then
min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]}
max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]}
end
minetest_add_particlespawner({
amount = 10,
time = 0.0001,
minpos = vector.add(pos, min),
maxpos = vector.add(pos, max),
minvel = vector.new(-1,1,-1),
maxvel = vector.new(1,3,1),
minexptime = 0.7,
maxexptime = 1,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "heart.png^[colorize:gray:255",
})
end
--hearts when tamed
mobs.tamed_effect = function(self)
local pos = self.object:get_pos()
local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox
local min, max
if collisionbox then
min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]}
max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]}
end
minetest_add_particlespawner({
amount = 30,
time = 0.0001,
minpos = vector.add(pos, min),
maxpos = vector.add(pos, max),
minvel = vector.new(-1,1,-1),
maxvel = vector.new(1,3,1),
minexptime = 0.7,
maxexptime = 1,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "heart.png",
})
end
--hearts when breeding
mobs.breeding_effect = function(self)
local pos = self.object:get_pos()
local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox
local min, max
if collisionbox then
min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]}
max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]}
end
minetest_add_particlespawner({
amount = 2,
time = 0.0001,
minpos = vector.add(pos, min),
maxpos = vector.add(pos, max),
minvel = vector.new(-1,1,-1),
maxvel = vector.new(1,3,1),
minexptime = 0.7,
maxexptime = 1,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "heart.png",
})
end

View File

@ -0,0 +1,391 @@
local math_pi = math.pi
local math_sin = math.sin
local math_cos = math.cos
local math_random = math.random
local HALF_PI = math_pi / 2
local DOUBLE_PI = math_pi * 2
-- localize vector functions
local vector_new = vector.new
local vector_length = vector.length
local vector_multiply = vector.multiply
local vector_distance = vector.distance
local vector_normalize = vector.normalize
local minetest_yaw_to_dir = minetest.yaw_to_dir
local minetest_dir_to_yaw = minetest.dir_to_yaw
local DEFAULT_JUMP_HEIGHT = 5
local DEFAULT_FLOAT_SPEED = 4
local DEFAULT_CLIMB_SPEED = 3
mobs.stick_in_cobweb = function(self)
local current_velocity = self.object:get_velocity()
local goal_velocity = vector_multiply(vector_normalize(current_velocity), 0.4)
goal_velocity.y = -0.5
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
--smooths out mobs a bit
if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition)
end
end
--this is a generic float function
mobs.float = function(self)
if self.object:get_acceleration().y ~= 0 then
self.object:set_acceleration(vector_new(0,0,0))
end
local current_velocity = self.object:get_velocity()
local goal_velocity = {
x = 0,
y = DEFAULT_FLOAT_SPEED,
z = 0,
}
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
new_velocity_addition.x = 0
new_velocity_addition.z = 0
--smooths out mobs a bit
if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition)
end
end
--this is a generic climb function
mobs.climb = function(self)
local current_velocity = self.object:get_velocity()
local goal_velocity = {
x = 0,
y = DEFAULT_CLIMB_SPEED,
z = 0,
}
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
new_velocity_addition.x = 0
new_velocity_addition.z = 0
--smooths out mobs a bit
if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition)
end
end
--[[
_ _
| | | |
| | __ _ _ __ __| |
| | / _` | '_ \ / _` |
| |___| (_| | | | | (_| |
\_____/\__,_|_| |_|\__,_|
]]
-- move mob in facing direction
--this has been modified to be internal
--internal = lua (self.yaw)
--engine = c++ (self.object:get_yaw())
mobs.set_velocity = function(self, v)
local yaw = (self.yaw or 0)
local current_velocity = self.object:get_velocity()
local goal_velocity = {
x = (math_sin(yaw) * -v),
y = 0,
z = (math_cos(yaw) * v),
}
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end
new_velocity_addition.y = 0
--smooths out mobs a bit
if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition)
end
end
-- calculate mob velocity
mobs.get_velocity = function(self)
local v = self.object:get_velocity()
v.y = 0
if v then
return vector_length(v)
end
return 0
end
--make mobs jump
mobs.jump = function(self, velocity)
if self.object:get_velocity().y ~= 0 or not self.old_velocity or (self.old_velocity and self.old_velocity.y > 0) then
return
end
--fallback velocity to allow modularity
velocity = velocity or DEFAULT_JUMP_HEIGHT
self.object:add_velocity(vector_new(0,velocity,0))
end
--make mobs fall slowly
mobs.mob_fall_slow = function(self)
local current_velocity = self.object:get_velocity()
local goal_velocity = {
x = 0,
y = -2,
z = 0,
}
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
new_velocity_addition.x = 0
new_velocity_addition.z = 0
if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end
new_velocity_addition.x = 0
new_velocity_addition.z = 0
--smooths out mobs a bit
if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition)
end
end
--[[
_____ _
/ ___| (_)
\ `--.__ ___ _ __ ___
`--. \ \ /\ / / | '_ ` _ \
/\__/ /\ V V /| | | | | | |
\____/ \_/\_/ |_|_| |_| |_|
]]--
--make mobs flop
mobs.flop = function(self, velocity)
if self.object:get_velocity().y ~= 0 or not self.old_velocity or (self.old_velocity and self.old_velocity.y > 0) then
return false
end
mobs.set_velocity(self, 0)
--fallback velocity to allow modularity
velocity = velocity or DEFAULT_JUMP_HEIGHT
--create a random direction (2d yaw)
local dir = DOUBLE_PI * math_random()
--create a random force value
local force = math_random(0,3) + math_random()
--convert the yaw to a direction vector then multiply it times the force
local final_additional_force = vector_multiply(minetest_yaw_to_dir(dir), force)
--place in the "flop" velocity to make the mob flop
final_additional_force.y = velocity
self.object:add_velocity(final_additional_force)
return true
end
-- move mob in facing direction
--this has been modified to be internal
--internal = lua (self.yaw)
--engine = c++ (self.object:get_yaw())
mobs.set_swim_velocity = function(self, v)
local yaw = (self.yaw or 0)
local pitch = (self.pitch or 0)
if v == 0 then
pitch = 0
end
local current_velocity = self.object:get_velocity()
local goal_velocity = {
x = (math_sin(yaw) * -v),
y = pitch,
z = (math_cos(yaw) * v),
}
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end
--smooths out mobs a bit
if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition)
end
end
--[[
______ _
| ___| |
| |_ | |_ _
| _| | | | | |
| | | | |_| |
\_| |_|\__, |
__/ |
|___/
]]--
-- move mob in facing direction
--this has been modified to be internal
--internal = lua (self.yaw)
--engine = c++ (self.object:get_yaw())
mobs.set_fly_velocity = function(self, v)
local yaw = (self.yaw or 0)
local pitch = (self.pitch or 0)
if v == 0 then
pitch = 0
end
local current_velocity = self.object:get_velocity()
local goal_velocity = {
x = (math_sin(yaw) * -v),
y = pitch,
z = (math_cos(yaw) * v),
}
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end
--smooths out mobs a bit
if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition)
end
end
--a quick and simple pitch calculation between two vector positions
mobs.calculate_pitch = function(pos1, pos2)
if pos1 == nil or pos2 == nil then
return false
end
return(minetest_dir_to_yaw(vector_new(vector_distance(vector_new(pos1.x,0,pos1.z),vector_new(pos2.x,0,pos2.z)),0,pos1.y - pos2.y)) + HALF_PI)
end
--make mobs fly up or down based on their y difference
mobs.set_pitch_while_attacking = function(self)
local pos1 = self.object:get_pos()
local pos2 = self.attacking:get_pos()
local pitch = mobs.calculate_pitch(pos2,pos1)
self.pitch = pitch
end
--[[
___
|_ |
| |_ _ _ __ ___ _ __
| | | | | '_ ` _ \| '_ \
/\__/ / |_| | | | | | | |_) |
\____/ \__,_|_| |_| |_| .__/
| |
|_|
]]--
--special mob jump movement
mobs.jump_move = function(self, velocity)
if self.object:get_velocity().y ~= 0 or not self.old_velocity or (self.old_velocity and self.old_velocity.y > 0) then
return
end
--make the mob stick for a split second
mobs.set_velocity(self,0)
--fallback velocity to allow modularity
jump_height = DEFAULT_JUMP_HEIGHT
local yaw = (self.yaw or 0)
local current_velocity = self.object:get_velocity()
local goal_velocity = {
x = (math_sin(yaw) * -velocity),
y = jump_height,
z = (math_cos(yaw) * velocity),
}
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end
--smooths out mobs a bit
if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition)
end
end
--make it so mobs do not glitch out and freak out
--when moving around over nodes
mobs.swap_auto_step_height_adjust = function(self)
local y_vel = self.object:get_velocity().y
if y_vel == 0 and self.stepheight ~= self.stepheight_backup then
self.stepheight = self.stepheight_backup
elseif y_vel ~= 0 and self.stepheight ~= 0 then
self.stepheight = 0
end
end

View File

@ -0,0 +1,44 @@
local GRAVITY = minetest.settings:get("movement_gravity")-- + 9.81
mobs.shoot_projectile_handling = function(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable, gravity)
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity")
if power == nil then
power = 19
end
if damage == nil then
damage = 3
end
gravity = gravity or -GRAVITY
local knockback
if bow_stack then
local enchantments = mcl_enchanting.get_enchantments(bow_stack)
if enchantments.power then
damage = damage + (enchantments.power + 1) / 4
end
if enchantments.punch then
knockback = enchantments.punch * 3
end
if enchantments.flame then
mcl_burning.set_on_fire(obj, math.huge)
end
end
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
obj:set_acceleration({x=0, y=gravity, z=0})
obj:set_yaw(yaw-math.pi/2)
local le = obj:get_luaentity()
le._shooter = shooter
le._damage = damage
le._is_critical = is_critical
le._startpos = pos
le._knockback = knockback
le._collectable = collectable
--play custom shoot sound
if shooter ~= nil and shooter.shoot_sound then
minetest.sound_play(shooter.shoot_sound, {pos=pos, max_hear_distance=16}, true)
end
return obj
end

View File

@ -0,0 +1,226 @@
local math_random = math.random
local minetest_settings = minetest.settings
-- get entity staticdata
mobs.mob_staticdata = function(self)
--despawn mechanism
--don't despawned tamed or bred mobs
if not self.tamed and not self.bred then
if not mobs.check_for_player_within_area(self, 64) then
--print("removing SERIALIZED!")
self.object:remove()
return
end
end
self.remove_ok = true
self.attack = nil
self.following = nil
if use_cmi then
self.serialized_cmi_components = cmi.serialize_components(self._cmi_components)
end
local tmp = {}
for _,stat in pairs(self) do
local t = type(stat)
if t ~= "function"
and t ~= "nil"
and t ~= "userdata"
and _ ~= "_cmi_components" then
tmp[_] = self[_]
end
end
return minetest.serialize(tmp)
end
-- activate mob and reload settings
mobs.mob_activate = function(self, staticdata, def, dtime)
-- remove monsters in peaceful mode
if self.type == "monster" and minetest_settings:get_bool("only_peaceful_mobs", false) then
mcl_burning.extinguish(self.object)
self.object:remove()
return
end
-- load entity variables
local tmp = minetest.deserialize(staticdata)
if tmp then
for _,stat in pairs(tmp) do
self[_] = stat
end
end
--set up wandering
if not self.wandering then
self.wandering = true
end
--clear animation
self.current_animation = nil
-- select random texture, set model and size
if not self.base_texture then
-- compatiblity with old simple mobs textures
if type(def.textures[1]) == "string" then
def.textures = {def.textures}
end
self.base_texture = def.textures[math_random(1, #def.textures)]
self.base_mesh = def.mesh
self.base_size = self.visual_size
self.base_colbox = self.collisionbox
self.base_selbox = self.selectionbox
end
-- for current mobs that dont have this set
if not self.base_selbox then
self.base_selbox = self.selectionbox or self.base_colbox
end
-- set texture, model and size
local textures = self.base_texture
local mesh = self.base_mesh
local vis_size = self.base_size
local colbox = self.base_colbox
local selbox = self.base_selbox
-- specific texture if gotten
if self.gotten == true
and def.gotten_texture then
textures = def.gotten_texture
end
-- specific mesh if gotten
if self.gotten == true
and def.gotten_mesh then
mesh = def.gotten_mesh
end
-- set baby mobs to half size
if self.baby == true then
vis_size = {
x = self.base_size.x * self.baby_size,
y = self.base_size.y * self.baby_size,
}
if def.child_texture then
textures = def.child_texture[1]
end
colbox = {
self.base_colbox[1] * self.baby_size,
self.base_colbox[2] * self.baby_size,
self.base_colbox[3] * self.baby_size,
self.base_colbox[4] * self.baby_size,
self.base_colbox[5] * self.baby_size,
self.base_colbox[6] * self.baby_size
}
selbox = {
self.base_selbox[1] * self.baby_size,
self.base_selbox[2] * self.baby_size,
self.base_selbox[3] * self.baby_size,
self.base_selbox[4] * self.baby_size,
self.base_selbox[5] * self.baby_size,
self.base_selbox[6] * self.baby_size
}
end
--stop mobs from reviving
if not self.dead and not self.health then
self.health = math_random (self.hp_min, self.hp_max)
end
if not self.random_sound_timer then
self.random_sound_timer = math_random(self.random_sound_timer_min,self.random_sound_timer_max)
end
if self.breath == nil then
self.breath = self.breath_max
end
-- pathfinding init
self.path = {}
self.path.way = {} -- path to follow, table of positions
self.path.lastpos = {x = 0, y = 0, z = 0}
self.path.stuck = false
self.path.following = false -- currently following path?
self.path.stuck_timer = 0 -- if stuck for too long search for path
-- Armor groups
-- immortal=1 because we use custom health
-- handling (using "health" property)
local armor
if type(self.armor) == "table" then
armor = table.copy(self.armor)
armor.immortal = 1
else
armor = {immortal=1, fleshy = self.armor}
end
self.object:set_armor_groups(armor)
self.old_y = self.object:get_pos().y
self.old_health = self.health
self.sounds.distance = self.sounds.distance or 10
self.textures = textures
self.mesh = mesh
self.collisionbox = colbox
self.selectionbox = selbox
self.visual_size = vis_size
self.standing_in = "ignore"
self.standing_on = "ignore"
self.jump_sound_cooloff = 0 -- used to prevent jump sound from being played too often in short time
self.opinion_sound_cooloff = 0 -- used to prevent sound spam of particular sound types
self.texture_mods = {}
self.v_start = false
self.timer = 0
self.blinktimer = 0
self.blinkstatus = false
--continue mob effect on server restart
if self.dead or self.health <= 0 then
self.object:set_texture_mod("^[colorize:red:120")
else
self.object:set_texture_mod("")
end
-- set anything changed above
self.object:set_properties(self)
--update_tag(self)
--mobs.set_animation(self, "stand")
-- run on_spawn function if found
if self.on_spawn and not self.on_spawn_run then
if self.on_spawn(self) then
self.on_spawn_run = true -- if true, set flag to run once only
end
end
-- run after_activate
if def.after_activate then
def.after_activate(self, staticdata, def, dtime)
end
if use_cmi then
self._cmi_components = cmi.activate_components(self.serialized_cmi_components)
cmi.notify_activate(self.object, dtime)
end
end

View File

@ -0,0 +1,59 @@
local math_random = math.random
--generic call for sound handler for mobs (data access)
mobs.play_sound = function(self,sound)
local soundinfo = self.sounds
if not soundinfo then
return
end
local play_sound = soundinfo[sound]
if not play_sound then
return
end
mobs.play_sound_handler(self, play_sound)
end
--generic sound handler for mobs
mobs.play_sound_handler = function(self, sound)
local pitch = (100 + math_random(-15,15) + math_random()) / 100
local distance = self.sounds.distance or 16
minetest.sound_play(sound, {
object = self.object,
gain = 1.0,
max_hear_distance = distance,
pitch = pitch,
}, true)
end
--random sound timing handler
mobs.random_sound_handling = function(self,dtime)
self.random_sound_timer = self.random_sound_timer - dtime
--play sound and reset timer
if self.random_sound_timer <= 0 then
mobs.play_sound(self,"random")
self.random_sound_timer = math_random(self.random_sound_timer_min,self.random_sound_timer_max)
end
end
--used for playing a non-mob internal sound at random pitches
mobs.play_sound_specific = function(self,soundname)
local pitch = (100 + math_random(-15,15) + math_random()) / 100
local distance = self.sounds.distance or 16
minetest.sound_play(soundname, {
object = self.object,
gain = 1.0,
max_hear_distance = distance,
pitch = pitch,
}, true)
end

View File

@ -206,21 +206,30 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
-- move forwards -- move forwards
if ctrl.up then if ctrl.up then
entity.v = entity.v + entity.accel / 10 mobs.set_velocity(entity, entity.run_velocity)
mobs.set_mob_animation(entity, moving_anim)
-- move backwards -- move backwards
elseif ctrl.down then elseif ctrl.down then
if entity.max_speed_reverse == 0 and entity.v == 0 then mobs.set_velocity(entity, -entity.run_velocity)
return
end
entity.v = entity.v - entity.accel / 10 mobs.set_mob_animation(entity, moving_anim)
--halt
else
mobs.set_velocity(entity, 0)
mobs.set_mob_animation(entity, stand_anim)
end end
-- fix mob rotation -- mob rotation
entity.object:set_yaw(entity.driver:get_look_horizontal() - entity.rotate) entity.object:set_yaw(entity.driver:get_look_horizontal() - entity.rotate)
entity.yaw = entity.driver:get_look_horizontal() - entity.rotate
--[[
if can_fly then if can_fly then
-- fly up -- fly up
@ -244,32 +253,21 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end end
else else
]]--
-- jump -- jump
if ctrl.jump then if ctrl.jump then
if velo.y == 0 then mobs.jump(entity)
velo.y = velo.y + entity.jump_height
acce_y = acce_y + (acce_y * 3) + 1
end
end
end
end
-- if not moving then set animation and return
if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
if stand_anim then
mobs:set_animation(entity, stand_anim)
end end
return --end
end end
--[[
-- set moving animation -- set moving animation
if moving_anim then if moving_anim then
mobs:set_animation(entity, moving_anim) mobs:set_mob_animation(entity, moving_anim)
end end
-- Stop! -- Stop!
@ -383,6 +381,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end end
entity.v2 = v entity.v2 = v
]]--
end end
@ -390,6 +389,10 @@ end
function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim) function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
if true then
print("succ")
return
end
local ctrl = entity.driver:get_player_control() local ctrl = entity.driver:get_player_control()
local velo = entity.object:get_velocity() local velo = entity.object:get_velocity()
local dir = entity.driver:get_look_dir() local dir = entity.driver:get_look_dir()
@ -440,9 +443,9 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
-- change animation if stopped -- change animation if stopped
if velo.x == 0 and velo.y == 0 and velo.z == 0 then if velo.x == 0 and velo.y == 0 and velo.z == 0 then
mobs:set_animation(entity, stand_anim) mobs:set_mob_animation(entity, stand_anim)
else else
-- moving animation -- moving animation
mobs:set_animation(entity, moving_anim) mobs:set_mob_animation(entity, moving_anim)
end end
end end

View File

@ -1,17 +1,30 @@
--lua locals --lua locals
local get_node = minetest.get_node local get_node = minetest.get_node
local get_item_group = minetest.get_item_group local get_item_group = minetest.get_item_group
local get_node_light = minetest.get_node_light local get_node_light = minetest.get_node_light
local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
local new_vector = vector.new local get_biome_name = minetest.get_biome_name
local get_objects_inside_radius = minetest.get_objects_inside_radius
local math_random = math.random local math_random = math.random
local get_biome_name = minetest.get_biome_name local math_floor = math.floor
local max = math.max local max = math.max
local get_objects_inside_radius = minetest.get_objects_inside_radius
local vector_distance = vector.distance local vector_distance = vector.distance
local vector_new = vector.new
local vector_floor = vector.floor
local table_copy = table.copy
local table_remove = table.remove
-- range for mob count -- range for mob count
local aoc_range = 32 local aoc_range = 48
--do mobs spawn?
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
--[[ --[[
THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs
@ -153,28 +166,14 @@ Overworld regular:
-- count how many mobs are in an area
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false local count_mobs = function(pos)
-- count how many mobs of one type are inside an area
local count_mobs = function(pos,mobtype)
local num = 0 local num = 0
local objs = get_objects_inside_radius(pos, aoc_range) for _,object in pairs(get_objects_inside_radius(pos, aoc_range)) do
for n = 1, #objs do if object and object:get_luaentity() and object:get_luaentity()._cmi_is_mob then
local obj = objs[n]:get_luaentity() num = num + 1
if obj and obj.name and obj._cmi_is_mob then
-- count hostile mobs only
if mobtype == "hostile" then
if obj.spawn_class == "hostile" then
num = num + 1
end
-- count passive mobs only
else
num = num + 1
end
end end
end end
return num return num
end end
@ -484,23 +483,23 @@ end
local axis local axis
--inner and outer part of square donut radius --inner and outer part of square donut radius
local inner = 1 local inner = 15
local outer = 65 local outer = 64
local int = {-1,1} local int = {-1,1}
local position_calculation = function(pos) local position_calculation = function(pos)
pos = vector.floor(pos) pos = vector_floor(pos)
--this is used to determine the axis buffer from the player --this is used to determine the axis buffer from the player
axis = math.random(0,1) axis = math_random(0,1)
--cast towards the direction --cast towards the direction
if axis == 0 then --x if axis == 0 then --x
pos.x = pos.x + math.random(inner,outer)*int[math.random(1,2)] pos.x = pos.x + math_random(inner,outer)*int[math_random(1,2)]
pos.z = pos.z + math.random(-outer,outer) pos.z = pos.z + math_random(-outer,outer)
else --z else --z
pos.z = pos.z + math.random(inner,outer)*int[math.random(1,2)] pos.z = pos.z + math_random(inner,outer)*int[math_random(1,2)]
pos.x = pos.x + math.random(-outer,outer) pos.x = pos.x + math_random(-outer,outer)
end end
return(pos) return(pos)
end end
@ -516,7 +515,7 @@ local decypher_limits_dictionary = {
local function decypher_limits(posy) local function decypher_limits(posy)
--local min_max_table = decypher_limits_dictionary[dimension] --local min_max_table = decypher_limits_dictionary[dimension]
--return min_max_table[1],min_max_table[2] --return min_max_table[1],min_max_table[2]
posy = math.floor(posy) posy = math_floor(posy)
return posy - 32, posy + 32 return posy - 32, posy + 32
end end
@ -539,108 +538,169 @@ if mobs_spawn then
local timer = 0 local timer = 0
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
timer = timer + dtime timer = timer + dtime
if timer >= 8 then if timer >= 10 then
timer = 0 timer = 0
for _,player in pairs(minetest.get_connected_players()) do for _,player in pairs(minetest.get_connected_players()) do
for i = 1,math_random(3,8) do -- after this line each "break" means "continue"
repeat -- after this line each "break" means "continue" local do_mob_spawning = true
local player_pos = player:get_pos() repeat
--don't need to get these variables more than once
--they happen in a single server step
local _,dimension = mcl_worlds.y_to_layer(player_pos.y) local player_pos = player:get_pos()
local _,dimension = mcl_worlds.y_to_layer(player_pos.y)
if dimension == "void" or dimension == "default" then if dimension == "void" or dimension == "default" then
break -- ignore void and unloaded area break -- ignore void and unloaded area
end end
local min,max = decypher_limits(player_pos.y) local min,max = decypher_limits(player_pos.y)
local goal_pos = position_calculation(player_pos) for i = 1,math_random(1,4) do
-- after this line each "break" means "continue"
local do_mob_algorithm = true
repeat
local spawning_position_list = find_nodes_in_area_under_air(new_vector(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"group:solid", "group:water", "group:lava"}) local goal_pos = position_calculation(player_pos)
local spawning_position_list = find_nodes_in_area_under_air(vector_new(goal_pos.x,min,goal_pos.z), vector_new(goal_pos.x,max,goal_pos.z), {"group:solid", "group:water", "group:lava"})
--couldn't find node
if #spawning_position_list <= 0 then
break
end
local spawning_position = spawning_position_list[math_random(1,#spawning_position_list)]
--Prevent strange behavior --- this is commented out: /too close to player --fixed with inner circle
if not spawning_position then -- or vector_distance(player_pos, spawning_position) < 15
break
end
--hard code mob limit in area to 5 for now
if count_mobs(spawning_position) >= 5 then
break
end
local gotten_node = get_node(spawning_position).name
if not gotten_node or gotten_node == "air" then --skip air nodes
break
end
local gotten_biome = minetest.get_biome_data(spawning_position)
if not gotten_biome then
break --skip if in unloaded area
end
gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with
--add this so mobs don't spawn inside nodes
spawning_position.y = spawning_position.y + 1
--only need to poll for node light if everything else worked
local gotten_light = get_node_light(spawning_position)
local is_water = get_item_group(gotten_node, "water") ~= 0
local is_lava = get_item_group(gotten_node, "lava") ~= 0
local mob_def = nil
--create a disconnected clone of the spawn dictionary
--prevents memory leak
local mob_library_worker_table = table_copy(spawn_dictionary)
--grab mob that fits into the spawning location
--randomly grab a mob, don't exclude any possibilities
local repeat_mob_search = true
repeat
--do not infinite loop
if #mob_library_worker_table <= 0 then
--print("breaking infinite loop")
break
end
local skip = false
--use this for removing table elements of mobs that do not match
local temp_index = math_random(1,#mob_library_worker_table)
local temp_def = mob_library_worker_table[temp_index]
--skip if something ridiculous happens (nil mob def)
--something truly horrible has happened if skip gets
--activated at this point
if not temp_def then
skip = true
end
if not skip and (spawning_position.y < temp_def.min_height or spawning_position.y > temp_def.max_height) then
skip = true
end
--skip if not correct dimension
if not skip and (temp_def.dimension ~= dimension) then
skip = true
end
--skip if not in correct biome
if not skip and (not biome_check(temp_def.biomes, gotten_biome)) then
skip = true
end
--don't spawn if not in light limits
if not skip and (gotten_light < temp_def.min_light or gotten_light > temp_def.max_light) then
skip = true
end
--skip if not in correct spawning type
if not skip and (temp_def.type_of_spawning == "ground" and is_water) then
skip = true
end
if not skip and (temp_def.type_of_spawning == "ground" and is_lava) then
skip = true
end
--found a mob, exit out of loop
if not skip then
--minetest.log("warning", "found mob:"..temp_def.name)
--print("found mob:"..temp_def.name)
mob_def = table_copy(temp_def)
break
else
--minetest.log("warning", "deleting temp index "..temp_index)
--print("deleting temp index")
table_remove(mob_library_worker_table, temp_index)
end
until repeat_mob_search == false --this is needed to sort through mobs randomly
--catch if went through all mobs and something went horribly wrong
--could not find a valid mob to spawn that fits the environment
if not mob_def then
break
end
--adjust the position for water and lava mobs
if mob_def.type_of_spawning == "water" or mob_def.type_of_spawning == "lava" then
spawning_position.y = spawning_position.y - 1
end
--print("spawning: " .. mob_def.name)
--everything is correct, spawn mob
minetest.add_entity(spawning_position, mob_def.name)
--couldn't find node
if #spawning_position_list <= 0 then
break break
end until do_mob_algorithm == false --this is a safety catch
end
local spawning_position = spawning_position_list[math_random(1,#spawning_position_list)] break
until do_mob_spawning == false --this is a performance catch
--Prevent strange behavior/too close to player
if not spawning_position or vector_distance(player_pos, spawning_position) < 15 then
break
end
local gotten_node = get_node(spawning_position).name
if not gotten_node or gotten_node == "air" then --skip air nodes
break
end
local gotten_biome = minetest.get_biome_data(spawning_position)
if not gotten_biome then
break --skip if in unloaded area
end
gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with
--grab random mob
local mob_def = spawn_dictionary[math.random(1,#spawn_dictionary)]
if not mob_def then
break --skip if something ridiculous happens (nil mob def)
end
--skip if not correct dimension
if mob_def.dimension ~= dimension then
break
end
--skip if not in correct biome
if not biome_check(mob_def.biomes, gotten_biome) then
break
end
--add this so mobs don't spawn inside nodes
spawning_position.y = spawning_position.y + 1
if spawning_position.y < mob_def.min_height or spawning_position.y > mob_def.max_height then
break
end
--only need to poll for node light if everything else worked
local gotten_light = get_node_light(spawning_position)
--don't spawn if not in light limits
if gotten_light < mob_def.min_light or gotten_light > mob_def.max_light then
break
end
local is_water = get_item_group(gotten_node, "water") ~= 0
local is_lava = get_item_group(gotten_node, "lava") ~= 0
if mob_def.type_of_spawning == "ground" and is_water then
break
end
if mob_def.type_of_spawning == "ground" and is_lava then
break
end
--finally do the heavy check (for now) of mobs in area
if count_mobs(spawning_position, mob_def.spawn_class) >= mob_def.aoc then
break
end
--adjust the position for water and lava mobs
if mob_def.type_of_spawning == "water" or mob_def.type_of_spawning == "lava" then
spawning_position.y = spawning_position.y - 1
end
--everything is correct, spawn mob
minetest.add_entity(spawning_position, mob_def.name)
until true --this is a safety catch
end
end end
end end
end) end)

View File

@ -1,14 +1,16 @@
local path = minetest.get_modpath(minetest.get_current_modname()) local path = minetest.get_modpath(minetest.get_current_modname())
local api_path = path.."/api"
-- Mob API -- Mob API
dofile(path .. "/api.lua") dofile(api_path .. "/api.lua")
-- Spawning Algorithm -- Spawning Algorithm
dofile(path .. "/spawning.lua") dofile(api_path .. "/spawning.lua")
-- Rideable Mobs -- Rideable Mobs
dofile(path .. "/mount.lua") dofile(api_path .. "/mount.lua")
-- Mob Items -- Mob Items
dofile(path .. "/crafts.lua") dofile(path .. "/crafts.lua")

View File

@ -1,8 +0,0 @@
if minetest.get_modpath("lucky_block") then
lucky_block:add_blocks({
{"dro", {"mcl_mobs:nametag"}, 1},
{"lig"},
})
end

View File

@ -0,0 +1,4 @@
default_punch.1 = https://freesound.org/people/Merrick079/sounds/566436/
default_punch.2 = https://freesound.org/people/Merrick079/sounds/566435/
default_punch.3 = https://freesound.org/people/Merrick079/sounds/566434/

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
--use vector.distance to count down mob despawn timer

View File

@ -81,7 +81,9 @@ mobs_mc.items = {
gunpowder = "tnt:gunpowder", gunpowder = "tnt:gunpowder",
flint_and_steel = "fire:flint_and_steel", flint_and_steel = "fire:flint_and_steel",
water_source = "default:water_source", water_source = "default:water_source",
water_flowing = "default:water_flowing",
river_water_source = "default:river_water_source", river_water_source = "default:river_water_source",
water_flowing = "default:river_water_flowing",
black_dye = "dye:black", black_dye = "dye:black",
poppy = "flowers:rose", poppy = "flowers:rose",
dandelion = "flowers:dandelion_yellow", dandelion = "flowers:dandelion_yellow",

View File

@ -8,6 +8,9 @@ mobs:register_mob("mobs_mc:bat", {
spawn_class = "ambient", spawn_class = "ambient",
can_despawn = true, can_despawn = true,
passive = true, passive = true,
rotate = 270,
tilt_fly = true,
fly = true,
hp_min = 6, hp_min = 6,
hp_max = 6, hp_max = 6,
collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25}, collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25},
@ -45,9 +48,7 @@ mobs:register_mob("mobs_mc:bat", {
fall_damage = 0, fall_damage = 0,
view_range = 16, view_range = 16,
fear_height = 0, fear_height = 0,
jump = false, jump = false,
fly = true,
makes_footstep_sound = false, makes_footstep_sound = false,
}) })

View File

@ -18,6 +18,9 @@ mobs:register_mob("mobs_mc:blaze", {
hp_max = 20, hp_max = 20,
xp_min = 10, xp_min = 10,
xp_max = 10, xp_max = 10,
tilt_fly = false,
hostile = true,
rotate = 270,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3},
rotate = -180, rotate = -180,
visual = "mesh", visual = "mesh",
@ -36,7 +39,7 @@ mobs:register_mob("mobs_mc:blaze", {
walk_velocity = .8, walk_velocity = .8,
run_velocity = 1.6, run_velocity = 1.6,
damage = 6, damage = 6,
reach = 2, reach = 4, -- don't want blaze getting too close
pathfinding = 1, pathfinding = 1,
drops = { drops = {
{name = mobs_mc.items.blaze_rod, {name = mobs_mc.items.blaze_rod,
@ -64,7 +67,7 @@ mobs:register_mob("mobs_mc:blaze", {
fall_speed = -2.25, fall_speed = -2.25,
light_damage = 0, light_damage = 0,
view_range = 16, view_range = 16,
attack_type = "dogshoot", attack_type = "projectile",
arrow = "mobs_mc:blaze_fireball", arrow = "mobs_mc:blaze_fireball",
shoot_interval = 3.5, shoot_interval = 3.5,
shoot_offset = 1.0, shoot_offset = 1.0,
@ -76,9 +79,18 @@ mobs:register_mob("mobs_mc:blaze", {
fear_height = 0, fear_height = 0,
glow = 14, glow = 14,
fire_resistant = true, fire_resistant = true,
eye_height = 0.75,
projectile_cooldown_min = 2,
projectile_cooldown_max = 3,
shoot_arrow = function(self, pos, dir)
-- 2-4 damage per arrow
local dmg = math.random(2,4)
mobs.shoot_projectile_handling("mobs_mc:blaze_fireball", pos, dir, self.object:get_yaw(), self.object, 7, dmg,nil,nil,nil,-0.4)
end,
do_custom = function(self) do_custom = function(self)
if self.state == "attack" and vector.distance(self.object:get_pos(), self.attack:get_pos()) < 1.2 then if self.attacking and self.state == "attack" and vector.distance(self.object:get_pos(), self.attacking:get_pos()) < 1.2 then
mcl_burning.set_on_fire(self.attack, 5) mcl_burning.set_on_fire(self.attacking, 5)
end end
local pos = self.object:get_pos() local pos = self.object:get_pos()
minetest.add_particle({ minetest.add_particle({
@ -148,6 +160,11 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
visual_size = {x = 0.3, y = 0.3}, visual_size = {x = 0.3, y = 0.3},
textures = {"mcl_fire_fire_charge.png"}, textures = {"mcl_fire_fire_charge.png"},
velocity = 15, velocity = 15,
speed = 5,
tail = 1,
tail_texture = "mobs_mc_spit.png^[colorize:black:255", --repurpose spit texture
tail_size = 2,
tail_distance_divider = 3,
_is_fireball = true, _is_fireball = true,
-- Direct hit, no fire... just plenty of pain -- Direct hit, no fire... just plenty of pain
@ -155,7 +172,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
mcl_burning.set_on_fire(player, 5) mcl_burning.set_on_fire(player, 5)
player:punch(self.object, 1.0, { player:punch(self.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = 5}, damage_groups = {fleshy = self._damage},
}, nil) }, nil)
end, end,
@ -163,7 +180,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
mcl_burning.set_on_fire(mob, 5) mcl_burning.set_on_fire(mob, 5)
mob:punch(self.object, 1.0, { mob:punch(self.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = 5}, damage_groups = {fleshy = self._damage},
}, nil) }, nil)
end, end,
@ -178,7 +195,9 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
-- Node hit, make fire -- Node hit, make fire
hit_node = function(self, pos, node) hit_node = function(self, pos, node)
if node.name == "air" then if node.name ~= "air" then
local pos_above = table.copy(pos)
pos_above.y = pos_above.y + 1
minetest.set_node(pos_above, {name=mobs_mc.items.fire}) minetest.set_node(pos_above, {name=mobs_mc.items.fire})
else else
local v = self.object:get_velocity() local v = self.object:get_velocity()

View File

@ -18,7 +18,8 @@ mobs:register_mob("mobs_mc:chicken", {
xp_min = 1, xp_min = 1,
xp_max = 3, xp_max = 3,
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2}, collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2},
runaway = true, skittish = true,
fall_slow = true,
floats = 1, floats = 1,
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_chicken.b3d", mesh = "mobs_mc_chicken.b3d",
@ -26,9 +27,10 @@ mobs:register_mob("mobs_mc:chicken", {
{"mobs_mc_chicken.png"}, {"mobs_mc_chicken.png"},
}, },
visual_size = {x=2.2, y=2.2}, visual_size = {x=2.2, y=2.2},
rotate = 270,
makes_footstep_sound = true, makes_footstep_sound = true,
walk_velocity = 1, walk_velocity = 1,
run_velocity = 3,
drops = { drops = {
{name = mobs_mc.items.chicken_raw, {name = mobs_mc.items.chicken_raw,
chance = 1, chance = 1,
@ -64,14 +66,25 @@ mobs:register_mob("mobs_mc:chicken", {
run_start = 0, run_end = 40, run_start = 0, run_end = 40,
}, },
follow = mobs_mc.follow.chicken, follow = "mcl_farming:wheat_seeds",
breed_distance = 1.5,
baby_size = 0.5,
follow_distance = 2,
view_range = 16, view_range = 16,
fear_height = 4, fear_height = 4,
--why do chickend breed if they lay eggs??
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 1, true, true) then return end --attempt to enter breed state
if mobs:protect(self, clicker) then return end if mobs.enter_breed_state(self,clicker) then
if mobs:capture_mob(self, clicker, 0, 60, 5, false, nil) then return end return
end
--make baby grow faster
if self.baby then
mobs.make_baby_grow_faster(self,clicker)
return
end
end, end,
do_custom = function(self, dtime) do_custom = function(self, dtime)
@ -98,6 +111,21 @@ mobs:register_mob("mobs_mc:chicken", {
}, true) }, true)
end, end,
--head code
has_head = true,
head_bone = "head",
swap_y_with_x = false,
reverse_head_yaw = false,
head_bone_pos_y = 1.675,
head_bone_pos_z = 0,
head_height_offset = 0.55,
head_direction_offset = 0.0925,
head_pitch_modifier = -math.pi/2,
--end head code
}) })
--spawn --spawn
@ -106,22 +134,53 @@ mobs:spawn_specific(
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest_beach",
"Swampland", "Forest_beach",
"Taiga", "StoneBeach",
"ExtremeHills", "ColdTaiga_beach_water",
"BirchForest", "Taiga_beach",
"MegaSpruceTaiga", "Savanna_beach",
"MegaTaiga", "Plains_beach",
"ExtremeHills+", "ExtremeHills_beach",
"Forest", "ColdTaiga_beach",
"Plains", "Swampland_shore",
"ColdTaiga", "JungleM_shore",
"SunflowerPlains", "Jungle_shore",
"RoofedForest", "MesaPlateauFM_sandlevel",
"MesaPlateauFM_grasstop", "MesaPlateauF_sandlevel",
"ExtremeHillsM", "MesaBryce_sandlevel",
"BirchForestM", "Mesa_sandlevel",
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,

View File

@ -10,6 +10,7 @@ local cow_def = {
hp_max = 10, hp_max = 10,
xp_min = 1, xp_min = 1,
xp_max = 3, xp_max = 3,
rotate = 270,
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45}, collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45},
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_cow.b3d", mesh = "mobs_mc_cow.b3d",
@ -20,6 +21,7 @@ local cow_def = {
visual_size = {x=2.8, y=2.8}, visual_size = {x=2.8, y=2.8},
makes_footstep_sound = true, makes_footstep_sound = true,
walk_velocity = 1, walk_velocity = 1,
run_velocity = 3,
drops = { drops = {
{name = mobs_mc.items.beef_raw, {name = mobs_mc.items.beef_raw,
chance = 1, chance = 1,
@ -32,7 +34,7 @@ local cow_def = {
max = 2, max = 2,
looting = "common",}, looting = "common",},
}, },
runaway = true, skittish = true,
sounds = { sounds = {
random = "mobs_mc_cow", random = "mobs_mc_cow",
damage = "mobs_mc_cow_hurt", damage = "mobs_mc_cow_hurt",
@ -47,12 +49,17 @@ local cow_def = {
walk_end = 40, run_start = 0, walk_end = 40, run_start = 0,
run_end = 40, run_end = 40,
}, },
follow = mobs_mc.follow.cow, --follow = mobs_mc.follow.cow,
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 1, true, true) then return end
if mobs:protect(self, clicker) then return end
if self.child then --attempt to enter breed state
if mobs.enter_breed_state(self,clicker) then
return
end
--make baby grow faster
if self.baby then
mobs.make_baby_grow_faster(self,clicker)
return return
end end
@ -71,11 +78,28 @@ local cow_def = {
end end
return return
end end
mobs:capture_mob(self, clicker, 0, 5, 60, false, nil)
end, end,
breed_distance = 1.5,
baby_size = 0.5,
follow_distance = 2,
follow = mobs_mc.items.wheat, follow = mobs_mc.items.wheat,
view_range = 10, view_range = 10,
fear_height = 4, fear_height = 4,
--head code
has_head = true,
head_bone = "head",
swap_y_with_x = false,
reverse_head_yaw = false,
head_bone_pos_y = 3.6,
head_bone_pos_z = -0.6,
head_height_offset = 1.0525,
head_direction_offset = 0.5,
head_pitch_modifier = 0,
--end head code
} }
mobs:register_mob("mobs_mc:cow", cow_def) mobs:register_mob("mobs_mc:cow", cow_def)
@ -86,12 +110,17 @@ mooshroom_def.description = S("Mooshroom")
mooshroom_def.mesh = "mobs_mc_cow.b3d" mooshroom_def.mesh = "mobs_mc_cow.b3d"
mooshroom_def.textures = { {"mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png"}, {"mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } } mooshroom_def.textures = { {"mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png"}, {"mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } }
mooshroom_def.on_rightclick = function(self, clicker) mooshroom_def.on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 1, true, true) then return end --attempt to enter breed state
if mobs:protect(self, clicker) then return end if mobs.enter_breed_state(self,clicker) then
if self.child then
return return
end end
--make baby grow faster
if self.baby then
mobs.make_baby_grow_faster(self,clicker)
return
end
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
-- Use shears to get mushrooms and turn mooshroom into cow -- Use shears to get mushrooms and turn mooshroom into cow
if item:get_name() == mobs_mc.items.shears then if item:get_name() == mobs_mc.items.shears then
@ -140,7 +169,6 @@ mooshroom_def.on_rightclick = function(self, clicker)
minetest.add_item(pos, {name = mobs_mc.items.mushroom_stew}) minetest.add_item(pos, {name = mobs_mc.items.mushroom_stew})
end end
end end
mobs:capture_mob(self, clicker, 0, 5, 60, false, nil)
end end
mobs:register_mob("mobs_mc:mooshroom", mooshroom_def) mobs:register_mob("mobs_mc:mooshroom", mooshroom_def)
@ -151,22 +179,53 @@ mobs:spawn_specific(
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest_beach",
"Swampland", "Forest_beach",
"Taiga", "StoneBeach",
"ExtremeHills", "ColdTaiga_beach_water",
"BirchForest", "Taiga_beach",
"MegaSpruceTaiga", "Savanna_beach",
"MegaTaiga", "Plains_beach",
"ExtremeHills+", "ExtremeHills_beach",
"Forest", "ColdTaiga_beach",
"Plains", "Swampland_shore",
"ColdTaiga", "JungleM_shore",
"SunflowerPlains", "Jungle_shore",
"RoofedForest", "MesaPlateauFM_sandlevel",
"MesaPlateauFM_grasstop", "MesaPlateauF_sandlevel",
"ExtremeHillsM", "MesaBryce_sandlevel",
"BirchForestM", "Mesa_sandlevel",
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,

View File

@ -12,6 +12,8 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:creeper", { mobs:register_mob("mobs_mc:creeper", {
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hostile = true,
rotate = 270,
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
xp_min = 5, xp_min = 5,
@ -33,23 +35,39 @@ mobs:register_mob("mobs_mc:creeper", {
explode = "tnt_explode", explode = "tnt_explode",
distance = 16, distance = 16,
}, },
makes_footstep_sound = true, makes_footstep_sound = false,
walk_velocity = 1.05, walk_velocity = 1.05,
run_velocity = 2.1, run_velocity = 3.25,
runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" }, runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" },
attack_type = "explode", attack_type = "explode",
eye_height = 1.25,
--hssssssssssss --hssssssssssss
explosion_strength = 3, explosion_strength = 10,
explosion_radius = 3.5, explosion_radius = 4,
explosion_damage_radius = 3.5, explosion_damage_radius = 6,
explosiontimer_reset_radius = 6, explosiontimer_reset_radius = 6,
reach = 3, reach = 1.5,
explosion_timer = 1.5, defuse_reach = 4,
explosion_timer = 0.3,
allow_fuse_reset = true, allow_fuse_reset = true,
stop_to_explode = true, stop_to_explode = true,
--head code
has_head = true,
head_bone = "head",
swap_y_with_x = true,
reverse_head_yaw = true,
head_bone_pos_y = 2.4,
head_bone_pos_z = 0,
head_height_offset = 1.1,
head_direction_offset = 0,
head_pitch_modifier = 0,
--end head code
-- Force-ignite creeper with flint and steel and explode after 1.5 seconds. -- Force-ignite creeper with flint and steel and explode after 1.5 seconds.
-- TODO: Make creeper flash after doing this as well. -- TODO: Make creeper flash after doing this as well.
-- TODO: Test and debug this code. -- TODO: Test and debug this code.
@ -149,6 +167,7 @@ mobs:register_mob("mobs_mc:creeper_charged", {
"mobs_mc_creeper_charge.png"}, "mobs_mc_creeper_charge.png"},
}, },
visual_size = {x=3, y=3}, visual_size = {x=3, y=3},
rotate = 270,
sounds = { sounds = {
attack = "tnt_ignite", attack = "tnt_ignite",
death = "mobs_mc_creeper_death", death = "mobs_mc_creeper_death",
@ -157,18 +176,19 @@ mobs:register_mob("mobs_mc:creeper_charged", {
explode = "tnt_explode", explode = "tnt_explode",
distance = 16, distance = 16,
}, },
makes_footstep_sound = true, makes_footstep_sound = false,
walk_velocity = 1.05, walk_velocity = 1.05,
run_velocity = 2.1, run_velocity = 2.1,
runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" }, runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" },
attack_type = "explode", attack_type = "explode",
explosion_strength = 6, explosion_strength = 24,
explosion_radius = 8, explosion_radius = 12,
explosion_damage_radius = 8, explosion_damage_radius = 18,
explosiontimer_reset_radius = 6, explosiontimer_reset_radius = 10,
reach = 3, reach = 1.5,
explosion_timer = 1.5, defuse_reach = 4,
explosion_timer = 0.3,
allow_fuse_reset = true, allow_fuse_reset = true,
stop_to_explode = true, stop_to_explode = true,

View File

@ -8,14 +8,22 @@ mobs:register_mob("mobs_mc:enderdragon", {
description = S("Ender Dragon"), description = S("Ender Dragon"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
pathfinding = 1,
attacks_animals = true, attacks_animals = true,
walk_chance = 100, walk_chance = 100,
rotate = 270,
tilt_fly = true,
hostile = true,
shoot_arrow = function(self, pos, dir)
-- 2-4 damage per arrow
local dmg = math.random(2,4)
mobs.shoot_projectile_handling("mobs_mc:dragon_fireball", pos, dir, self.object:get_yaw(), self.object, nil, dmg)
end,
hp_max = 200, hp_max = 200,
hp_min = 200, hp_min = 200,
xp_min = 500, xp_min = 500,
xp_max = 500, xp_max = 500,
collisionbox = {-2, 3, -2, 2, 5, 2}, collisionbox = {-2, 0, -2, 2, 2, 2},
eye_height = 1,
physical = false, physical = false,
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_dragon.b3d", mesh = "mobs_mc_dragon.b3d",
@ -24,6 +32,7 @@ mobs:register_mob("mobs_mc:enderdragon", {
}, },
visual_size = {x=3, y=3}, visual_size = {x=3, y=3},
view_range = 35, view_range = 35,
reach = 20,
walk_velocity = 6, walk_velocity = 6,
run_velocity = 6, run_velocity = 6,
can_despawn = false, can_despawn = false,
@ -47,7 +56,7 @@ mobs:register_mob("mobs_mc:enderdragon", {
lava_damage = 0, lava_damage = 0,
fire_damage = 0, fire_damage = 0,
on_rightclick = nil, on_rightclick = nil,
attack_type = "dogshoot", attack_type = "projectile",
arrow = "mobs_mc:dragon_fireball", arrow = "mobs_mc:dragon_fireball",
shoot_interval = 0.5, shoot_interval = 0.5,
shoot_offset = -1.0, shoot_offset = -1.0,
@ -133,10 +142,11 @@ mobs:register_arrow("mobs_mc:dragon_fireball", {
-- node hit, explode -- node hit, explode
hit_node = function(self, pos, node) hit_node = function(self, pos, node)
mobs:boom(self, pos, 2) --mobs:boom(self, pos, 2)
mcl_explosions.explode(self.object:get_pos(), 2,{ drop_chance = 1.0 })
end end
}) })
mobs:register_egg("mobs_mc:enderdragon", S("Ender Dragon"), "mobs_mc_spawn_icon_dragon.png", 0, true) mobs:register_egg("mobs_mc:enderdragon", S("Ender Dragon"), "mobs_mc_spawn_icon_dragon.png", 0, true)
mcl_wip.register_wip_item("mobs_mc:enderdragon") --mcl_wip.register_wip_item("mobs_mc:enderdragon")

View File

@ -193,18 +193,19 @@ mobs:register_mob("mobs_mc:enderman", {
description = S("Enderman"), description = S("Enderman"),
type = "monster", type = "monster",
spawn_class = "passive", spawn_class = "passive",
passive = true, neutral = true,
pathfinding = 1,
hp_min = 40, hp_min = 40,
hp_max = 40, hp_max = 40,
xp_min = 5, xp_min = 5,
xp_max = 5, xp_max = 5,
rotate = 270,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 2.89, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 2.89, 0.3},
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_enderman.b3d", mesh = "mobs_mc_enderman.b3d",
textures = create_enderman_textures(), textures = create_enderman_textures(),
visual_size = {x=3, y=3}, visual_size = {x=3, y=3},
makes_footstep_sound = true, makes_footstep_sound = true,
eye_height = 2.5,
sounds = { sounds = {
-- TODO: Custom war cry sound -- TODO: Custom war cry sound
war_cry = "mobs_sandmonster", war_cry = "mobs_sandmonster",
@ -213,8 +214,8 @@ mobs:register_mob("mobs_mc:enderman", {
random = {name="mobs_mc_enderman_random", gain=0.5}, random = {name="mobs_mc_enderman_random", gain=0.5},
distance = 16, distance = 16,
}, },
walk_velocity = 0.2, walk_velocity = 1,
run_velocity = 3.4, run_velocity = 4,
damage = 7, damage = 7,
reach = 2, reach = 2,
drops = { drops = {
@ -224,6 +225,22 @@ mobs:register_mob("mobs_mc:enderman", {
max = 1, max = 1,
looting = "common"}, looting = "common"},
}, },
--head code
has_head = false,
head_bone = "head.low",
swap_y_with_x = false,
reverse_head_yaw = false,
head_bone_pos_y = 2.4,
head_bone_pos_z = 0,
head_height_offset = 1.1,
head_direction_offset = 0,
head_pitch_modifier = 0,
--end head code
animation = select_enderman_animation("normal"), animation = select_enderman_animation("normal"),
_taken_node = "", _taken_node = "",
do_custom = function(self, dtime) do_custom = function(self, dtime)
@ -282,8 +299,8 @@ mobs:register_mob("mobs_mc:enderman", {
--self:teleport(nil) --self:teleport(nil)
--self.state = "" --self.state = ""
--else --else
if self.attack then if self.attacking then
local target = self.attack local target = self.attacking
local pos = target:get_pos() local pos = target:get_pos()
if pos ~= nil then if pos ~= nil then
if vector.distance(self.object:get_pos(), target:get_pos()) > 10 then if vector.distance(self.object:get_pos(), target:get_pos()) > 10 then
@ -360,11 +377,16 @@ mobs:register_mob("mobs_mc:enderman", {
--if looking in general head position, turn hostile --if looking in general head position, turn hostile
if minetest.line_of_sight(ender_eye_pos, look_pos_base) and vector.distance(look_pos, ender_eye_pos) <= 0.4 then if minetest.line_of_sight(ender_eye_pos, look_pos_base) and vector.distance(look_pos, ender_eye_pos) <= 0.4 then
self.provoked = "staring" self.provoked = "staring"
self.attack = minetest.get_player_by_name(obj:get_player_name()) self.state = "stand"
self.hostile = false
break break
else -- I'm not sure what this part does, but I don't want to break anything - jordan4ibanez --begin attacking the player
else
if self.provoked == "staring" then if self.provoked == "staring" then
self.provoked = "broke_contact" self.provoked = "broke_contact"
self.hostile = true
self.state = "attack"
self.attacking = obj
end end
end end
@ -430,7 +452,7 @@ mobs:register_mob("mobs_mc:enderman", {
self.base_texture = create_enderman_textures(block_type, self._taken_node) self.base_texture = create_enderman_textures(block_type, self._taken_node)
self.object:set_properties({ textures = self.base_texture }) self.object:set_properties({ textures = self.base_texture })
self.animation = select_enderman_animation("block") self.animation = select_enderman_animation("block")
mobs:set_animation(self, self.animation.current) mobs.set_mob_animation(self, self.animation.current)
if def.sounds and def.sounds.dug then if def.sounds and def.sounds.dug then
minetest.sound_play(def.sounds.dug, {pos = take_pos, max_hear_distance = 16}, true) minetest.sound_play(def.sounds.dug, {pos = take_pos, max_hear_distance = 16}, true)
end end
@ -453,7 +475,7 @@ mobs:register_mob("mobs_mc:enderman", {
local def = minetest.registered_nodes[self._taken_node] local def = minetest.registered_nodes[self._taken_node]
-- Update animation accordingly (removes visible block) -- Update animation accordingly (removes visible block)
self.animation = select_enderman_animation("normal") self.animation = select_enderman_animation("normal")
mobs:set_animation(self, self.animation.current) mobs.set_mob_animation(self, self.animation.current)
if def.sounds and def.sounds.place then if def.sounds and def.sounds.place then
minetest.sound_play(def.sounds.place, {pos = place_pos, max_hear_distance = 16}, true) minetest.sound_play(def.sounds.place, {pos = place_pos, max_hear_distance = 16}, true)
end end
@ -557,7 +579,7 @@ mobs:register_mob("mobs_mc:enderman", {
water_damage = 8, water_damage = 8,
view_range = 64, view_range = 64,
fear_height = 4, fear_height = 4,
attack_type = "dogfight", attack_type = "punch",
}) })

View File

@ -9,12 +9,15 @@ mobs:register_mob("mobs_mc:endermite", {
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
passive = false, passive = false,
rotate = 270,
hostile = true,
hp_min = 8, hp_min = 8,
hp_max = 8, hp_max = 8,
xp_min = 3, xp_min = 3,
xp_max = 3, xp_max = 3,
armor = {fleshy = 100, arthropod = 100}, armor = {fleshy = 100, arthropod = 100},
group_attack = true, group_attack = true,
attack_type = "punch",
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.29, 0.2}, collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.29, 0.2},
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_endermite.b3d", mesh = "mobs_mc_endermite.b3d",

View File

@ -14,13 +14,17 @@ mobs:register_mob("mobs_mc:ghast", {
description = S("Ghast"), description = S("Ghast"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
pathfinding = 1,
group_attack = true, group_attack = true,
hostile = true,
fly_random_while_attack = true,
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,
rotate = 270,
xp_min = 5, xp_min = 5,
xp_max = 5, xp_max = 5,
collisionbox = {-2, 5, -2, 2, 9, 2}, reach = 20,
eye_height = 2.5,
collisionbox = {-2, 0, -2, 2, 4, 2},
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_ghast.b3d", mesh = "mobs_mc_ghast.b3d",
textures = { textures = {
@ -36,8 +40,10 @@ mobs:register_mob("mobs_mc:ghast", {
-- TODO: damage -- TODO: damage
-- TODO: better death -- TODO: better death
}, },
walk_velocity = 1.6, walk_velocity = 1.6,
run_velocity = 3.2, run_velocity = 3.2,
drops = { drops = {
{name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2, looting = "common"}, {name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2, looting = "common"},
{name = mobs_mc.items.ghast_tear, chance = 10/6, min = 0, max = 1, looting = "common", looting_ignore_chance = true}, {name = mobs_mc.items.ghast_tear, chance = 10/6, min = 0, max = 1, looting = "common", looting_ignore_chance = true},
@ -48,22 +54,23 @@ mobs:register_mob("mobs_mc:ghast", {
walk_start = 0, walk_end = 40, walk_start = 0, walk_end = 40,
run_start = 0, run_end = 40, run_start = 0, run_end = 40,
}, },
fall_damage = 0, fall_damage = 0,
view_range = 100, view_range = 28,
attack_type = "dogshoot", attack_type = "projectile",
arrow = "mobs_mc:fireball", arrow = "mobs_mc:ghast_fireball",
shoot_interval = 3.5,
shoot_offset = -5,
dogshoot_switch = 1,
dogshoot_count_max =1,
passive = false,
jump = true,
jump_height = 4,
floats=1, floats=1,
fly = true, fly = true,
makes_footstep_sound = false, makes_footstep_sound = false,
instant_death = true,
fire_resistant = true, fire_resistant = true,
projectile_cooldown_min = 5,
projectile_cooldown_max = 7,
shoot_arrow = function(self, pos, dir)
-- 2-4 damage per arrow
local dmg = math.random(2,4)
mobs.shoot_projectile_handling("mobs_mc:ghast_fireball", pos, dir, self.object:get_yaw(), self.object, 11, dmg,nil,nil,nil,-0.6)
end,
--[[
do_custom = function(self) do_custom = function(self)
if self.firing == true then if self.firing == true then
self.base_texture = {"mobs_mc_ghast_firing.png"} self.base_texture = {"mobs_mc_ghast_firing.png"}
@ -73,6 +80,7 @@ mobs:register_mob("mobs_mc:ghast", {
self.object:set_properties({textures=self.base_texture}) self.object:set_properties({textures=self.base_texture})
end end
end, end,
]]--
}) })
@ -92,32 +100,40 @@ mobs_mc.spawn_height.nether_min,
mobs_mc.spawn_height.nether_max) mobs_mc.spawn_height.nether_max)
-- fireball (projectile) -- fireball (projectile)
mobs:register_arrow("mobs_mc:fireball", { mobs:register_arrow("mobs_mc:ghast_fireball", {
visual = "sprite", visual = "sprite",
visual_size = {x = 1, y = 1}, visual_size = {x = 1, y = 1},
textures = {"mcl_fire_fire_charge.png"}, textures = {"mcl_fire_fire_charge.png"},
velocity = 15, velocity = 15,
collisionbox = {-.5, -.5, -.5, .5, .5, .5}, collisionbox = {-.5, -.5, -.5, .5, .5, .5},
tail = 1,
tail_texture = "mobs_mc_spit.png^[colorize:black:255", --repurpose spit texture
tail_size = 5,
_is_fireball = true, _is_fireball = true,
hit_player = function(self, player) hit_player = function(self, player)
--[[
player:punch(self.object, 1.0, { player:punch(self.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = 6}, damage_groups = {fleshy = 6},
}, nil) }, nil)
mobs:boom(self, self.object:get_pos(), 1, true) ]]--
--mobs:boom(self, self.object:get_pos(), 1, true)
mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 })
end, end,
hit_mob = function(self, mob) hit_mob = function(self, mob)
mob:punch(self.object, 1.0, { mob:punch(self.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = 6}, damage_groups = {fleshy = self._damage},
}, nil) }, nil)
mobs:boom(self, self.object:get_pos(), 1, true) --mobs:boom(self, self.object:get_pos(), 1, true)
mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 })
end, end,
hit_node = function(self, pos, node) hit_node = function(self, pos, node)
mobs:boom(self, pos, 1, true) --mobs:boom(self, pos, 1, true)
mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 })
end end
}) })

View File

@ -14,7 +14,7 @@ mobs:register_mob("mobs_mc:guardian", {
xp_max = 10, xp_max = 10,
breath_max = -1, breath_max = -1,
passive = false, passive = false,
attack_type = "dogfight", attack_type = "punch",
pathfinding = 1, pathfinding = 1,
view_range = 16, view_range = 16,
walk_velocity = 2, walk_velocity = 2,

View File

@ -16,7 +16,7 @@ mobs:register_mob("mobs_mc:guardian_elder", {
xp_max = 10, xp_max = 10,
breath_max = -1, breath_max = -1,
passive = false, passive = false,
attack_type = "dogfight", attack_type = "punch",
pathfinding = 1, pathfinding = 1,
view_range = 16, view_range = 16,
walk_velocity = 2, walk_velocity = 2,

View File

@ -88,6 +88,10 @@ local horse = {
spawn_class = "passive", spawn_class = "passive",
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_horse.b3d", mesh = "mobs_mc_horse.b3d",
rotate = 270,
walk_velocity = 1,
run_velocity = 8,
skittish = true,
visual_size = {x=3.0, y=3.0}, visual_size = {x=3.0, y=3.0},
collisionbox = {-0.69825, -0.01, -0.69825, 0.69825, 1.59, 0.69825}, collisionbox = {-0.69825, -0.01, -0.69825, 0.69825, 1.59, 0.69825},
animation = { animation = {
@ -97,7 +101,7 @@ local horse = {
walk_speed = 25, walk_speed = 25,
walk_start = 0, walk_start = 0,
walk_end = 40, walk_end = 40,
run_speed = 60, run_speed = 120,
run_start = 0, run_start = 0,
run_end = 40, run_end = 40,
}, },
@ -114,7 +118,8 @@ local horse = {
fly = false, fly = false,
walk_chance = 60, walk_chance = 60,
view_range = 16, view_range = 16,
follow = mobs_mc.follow.horse, follow = "mcl_farming:wheat_item",
follow_distance = 3,
passive = true, passive = true,
hp_min = 15, hp_min = 15,
hp_max = 30, hp_max = 30,
@ -182,7 +187,7 @@ local horse = {
-- if driver present and horse has a saddle allow control of horse -- if driver present and horse has a saddle allow control of horse
if self.driver and self._saddle then if self.driver and self._saddle then
mobs.drive(self, "walk", "stand", false, dtime) mobs.drive(self, "run", "stand", false, dtime)
return false -- skip rest of mob functions return false -- skip rest of mob functions
end end
@ -214,6 +219,21 @@ local horse = {
local iname = item:get_name() local iname = item:get_name()
local heal = 0 local heal = 0
--sneak click to breed the horse/feed it
if self.owner and self.owner == clicker:get_player_name() then
--attempt to enter breed state
if mobs.enter_breed_state(self,clicker) then
return
end
end
--don't do any other logic with the baby
--make baby grow faster
if self.baby then
mobs.make_baby_grow_faster(self,clicker)
return
end
-- Taming -- Taming
self.temper = self.temper or (math.random(1,100)) self.temper = self.temper or (math.random(1,100))
@ -239,6 +259,7 @@ local horse = {
self.buck_off_time = 40 -- TODO how long does it take in minecraft? self.buck_off_time = 40 -- TODO how long does it take in minecraft?
if self.temper > 100 then if self.temper > 100 then
self.tamed = true -- NOTE taming can only be finished by riding the horse self.tamed = true -- NOTE taming can only be finished by riding the horse
mobs.tamed_effect(self)
if not self.owner or self.owner == "" then if not self.owner or self.owner == "" then
self.owner = clicker:get_player_name() self.owner = clicker:get_player_name()
end end
@ -253,6 +274,14 @@ local horse = {
-- If nothing happened temper_increase = 0 and addition does nothing -- If nothing happened temper_increase = 0 and addition does nothing
self.temper = self.temper + temper_increase self.temper = self.temper + temper_increase
--give the player some kind of idea
--of what's happening with the horse's temper
if self.temper <= 100 then
mobs.feed_effect(self)
else
mobs.tamed_effect(self)
end
return return
end end
@ -282,10 +311,6 @@ local horse = {
return return
end end
if mobs:protect(self, clicker) then
return
end
-- Make sure tamed horse is mature and being clicked by owner only -- Make sure tamed horse is mature and being clicked by owner only
if self.tamed and not self.child and self.owner == clicker:get_player_name() then if self.tamed and not self.child and self.owner == clicker:get_player_name() then
@ -357,9 +382,6 @@ local horse = {
self.object:set_properties({stepheight = 1.1}) self.object:set_properties({stepheight = 1.1})
mobs.attach(self, clicker) mobs.attach(self, clicker)
-- Used to capture horse
elseif not self.driver and iname ~= "" then
mobs:capture_mob(self, clicker, 0, 5, 60, false, nil)
end end
end end
end, end,
@ -520,22 +542,53 @@ mobs:spawn_specific(
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest_beach",
"Swampland", "Forest_beach",
"Taiga", "StoneBeach",
"ExtremeHills", "ColdTaiga_beach_water",
"BirchForest", "Taiga_beach",
"MegaSpruceTaiga", "Savanna_beach",
"MegaTaiga", "Plains_beach",
"ExtremeHills+", "ExtremeHills_beach",
"Forest", "ColdTaiga_beach",
"Plains", "Swampland_shore",
"ColdTaiga", "JungleM_shore",
"SunflowerPlains", "Jungle_shore",
"RoofedForest", "MesaPlateauFM_sandlevel",
"MesaPlateauFM_grasstop", "MesaPlateauF_sandlevel",
"ExtremeHillsM", "MesaBryce_sandlevel",
"BirchForestM", "Mesa_sandlevel",
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,

View File

@ -16,8 +16,11 @@ mobs:register_mob("mobs_mc:iron_golem", {
type = "npc", type = "npc",
spawn_class = "passive", spawn_class = "passive",
passive = true, passive = true,
rotate = 270,
hp_min = 100, hp_min = 100,
hp_max = 100, hp_max = 100,
protect = true,
neutral = true,
breath_max = -1, breath_max = -1,
collisionbox = {-0.7, -0.01, -0.7, 0.7, 2.69, 0.7}, collisionbox = {-0.7, -0.01, -0.7, 0.7, 2.69, 0.7},
visual = "mesh", visual = "mesh",
@ -40,7 +43,7 @@ mobs:register_mob("mobs_mc:iron_golem", {
reach = 3, reach = 3,
group_attack = true, group_attack = true,
attacks_monsters = true, attacks_monsters = true,
attack_type = "dogfight", attack_type = "punch",
drops = { drops = {
{name = mobs_mc.items.iron_ingot, {name = mobs_mc.items.iron_ingot,
chance = 1, chance = 1,

View File

@ -28,6 +28,15 @@ mobs:register_mob("mobs_mc:llama", {
description = S("Llama"), description = S("Llama"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
rotate = 270,
neutral = true,
group_attack = true,
attack_type = "projectile",
shoot_arrow = function(self, pos, dir)
-- 2-4 damage per arrow
local dmg = 1
mobs.shoot_projectile_handling("mobs_mc:spit", pos, dir, self.object:get_yaw(), self.object, nil, dmg)
end,
hp_min = 15, hp_min = 15,
hp_max = 30, hp_max = 30,
xp_min = 1, xp_min = 1,
@ -50,7 +59,11 @@ mobs:register_mob("mobs_mc:llama", {
walk_velocity = 1, walk_velocity = 1,
run_velocity = 4.4, run_velocity = 4.4,
follow_velocity = 4.4, follow_velocity = 4.4,
breed_distance = 1.5,
baby_size = 0.5,
follow_distance = 2,
floats = 1, floats = 1,
reach = 6,
drops = { drops = {
{name = mobs_mc.items.leather, {name = mobs_mc.items.leather,
chance = 1, chance = 1,
@ -83,7 +96,7 @@ mobs:register_mob("mobs_mc:llama", {
look_start = 78, look_start = 78,
look_end = 108, look_end = 108,
}, },
follow = mobs_mc.follow.llama, follow = mobs_mc.items.hay_bale,
view_range = 16, view_range = 16,
do_custom = function(self, dtime) do_custom = function(self, dtime)
@ -126,30 +139,71 @@ mobs:register_mob("mobs_mc:llama", {
return return
end end
local item = clicker:get_wielded_item() --owner is broken for this
if item:get_name() == mobs_mc.items.hay_bale then --we'll make the owner this guy
-- Breed with hay bale --attempt to enter breed state
if mobs:feed_tame(self, clicker, 1, true, false) then return end if mobs.enter_breed_state(self,clicker) then
else self.tamed = true
-- Feed with anything else self.owner = clicker:get_player_name()
if mobs:feed_tame(self, clicker, 1, false, true) then return end return
end end
if mobs:protect(self, clicker) then return end
--ignore other logic
--make baby grow faster
if self.baby then
mobs.make_baby_grow_faster(self,clicker)
return
end
-- Make sure tamed llama is mature and being clicked by owner only -- Make sure tamed llama is mature and being clicked by owner only
if self.tamed and not self.child and self.owner == clicker:get_player_name() then if self.tamed and not self.child and self.owner == clicker:get_player_name() then
local item = clicker:get_wielded_item()
--safety catch
if not item then
return
end
--put chest on carpeted llama
if self.carpet and not self.chest and item:get_name() == "mcl_chests:chest" then
if not minetest.is_creative_enabled(clicker:get_player_name()) then
item:take_item()
clicker:set_wielded_item(item)
end
self.base_texture = table.copy(self.base_texture)
self.base_texture[1] = "mobs_mc_llama_chest.png"
self.object:set_properties({
textures = self.base_texture,
})
self.chest = true
return --don't attempt to ride
end
-- Place carpet -- Place carpet
--[[ TODO: Re-enable this code when carpet textures arrived. --TODO: Re-enable this code when carpet textures arrived.
if minetest.get_item_group(item:get_name(), "carpet") == 1 and not self.carpet then if minetest.get_item_group(item:get_name(), "carpet") == 1 then
for group, carpetdata in pairs(carpets) do for group, carpetdata in pairs(carpets) do
if minetest.get_item_group(item:get_name(), group) == 1 then if minetest.get_item_group(item:get_name(), group) == 1 then
if not minetest.is_creative_enabled(clicker:get_player_name()) then if not minetest.is_creative_enabled(clicker:get_player_name()) then
item:take_item() item:take_item()
clicker:set_wielded_item(item) clicker:set_wielded_item(item)
--shoot off old carpet
if self.carpet then
minetest.add_item(self.object:get_pos(), self.carpet)
end
end end
local substr = carpetdata[2] local substr = carpetdata[2]
local tex_carpet = "mobs_mc_llama_decor_"..substr..".png" local tex_carpet = "mobs_mc_llama_decor_"..substr..".png"
self.base_texture = table.copy(self.base_texture) self.base_texture = table.copy(self.base_texture)
self.base_texture[2] = tex_carpet self.base_texture[2] = tex_carpet
self.object:set_properties({ self.object:set_properties({
@ -170,23 +224,21 @@ mobs:register_mob("mobs_mc:llama", {
end end
end end
end end
]]
-- detatch player already riding llama if self.carpet then
if self.driver and clicker == self.driver then -- detatch player already riding llama
if self.driver and clicker == self.driver then
mobs.detach(clicker, {x = 1, y = 0, z = 1}) mobs.detach(clicker, {x = 1, y = 0, z = 1})
-- attach player to llama -- attach player to llama
elseif not self.driver then elseif not self.driver then
self.object:set_properties({stepheight = 1.1}) self.object:set_properties({stepheight = 1.1})
mobs.attach(self, clicker) mobs.attach(self, clicker)
end
end end
-- Used to capture llama
elseif not self.driver and clicker:get_wielded_item():get_name() ~= "" then
mobs:capture_mob(self, clicker, 0, 5, 60, false, nil)
end end
end, end,
@ -240,3 +292,38 @@ mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs
mobs:register_egg("mobs_mc:llama", S("Llama"), "mobs_mc_spawn_icon_llama.png", 0) mobs:register_egg("mobs_mc:llama", S("Llama"), "mobs_mc_spawn_icon_llama.png", 0)
-- llama spit
mobs:register_arrow("mobs_mc:spit", {
visual = "sprite",
visual_size = {x = 0.3, y = 0.3},
textures = {"mobs_mc_spit.png"},
velocity = 1,
speed = 1,
tail = 1,
tail_texture = "mobs_mc_spit.png",
tail_size = 2,
tail_distance_divider = 4,
hit_player = function(self, player)
if rawget(_G, "armor") and armor.last_damage_types then
armor.last_damage_types[player:get_player_name()] = "spit"
end
player:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = self._damage},
}, nil)
end,
hit_mob = function(self, mob)
mob:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = _damage},
}, nil)
end,
hit_node = function(self, pos, node)
--does nothing
end
})

View File

@ -0,0 +1 @@
Ghast fixed by epCode - Thanks!

View File

@ -31,6 +31,8 @@ local ocelot = {
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
can_despawn = true, can_despawn = true,
rotate = 270,
skittish = true,
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,
xp_min = 1, xp_min = 1,
@ -43,7 +45,7 @@ local ocelot = {
makes_footstep_sound = true, makes_footstep_sound = true,
walk_chance = default_walk_chance, walk_chance = default_walk_chance,
walk_velocity = 1, walk_velocity = 1,
run_velocity = 3, run_velocity = 10,
follow_velocity = 1, follow_velocity = 1,
floats = 1, floats = 1,
runaway = true, runaway = true,
@ -57,7 +59,7 @@ local ocelot = {
}, },
animation = { animation = {
speed_normal = 25, speed_normal = 25,
run_speed = 50, run_speed = 150,
stand_start = 0, stand_start = 0,
stand_end = 0, stand_end = 0,
walk_start = 0, walk_start = 0,
@ -123,8 +125,6 @@ cat.sounds = {
} }
cat.on_rightclick = function(self, clicker) cat.on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 1, true, false) then return end if mobs:feed_tame(self, clicker, 1, true, false) then return end
if mobs:capture_mob(self, clicker, 0, 60, 5, false, nil) then return end
if mobs:protect(self, clicker) then return end
if self.child then return end if self.child then return end

View File

@ -20,11 +20,14 @@ mobs:register_mob("mobs_mc:parrot", {
hp_max = 6, hp_max = 6,
xp_min = 1, xp_min = 1,
xp_max = 3, xp_max = 3,
collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25}, tilt_fly = true,
collisionbox = {-0.25, 0, -0.25, 0.25, 0.9, 0.25},
eye_height = 0.45,
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_parrot.b3d", mesh = "mobs_mc_parrot.b3d",
textures = {{"mobs_mc_parrot_blue.png"},{"mobs_mc_parrot_green.png"},{"mobs_mc_parrot_grey.png"},{"mobs_mc_parrot_red_blue.png"},{"mobs_mc_parrot_yellow_blue.png"}}, textures = {{"mobs_mc_parrot_blue.png"},{"mobs_mc_parrot_green.png"},{"mobs_mc_parrot_grey.png"},{"mobs_mc_parrot_red_blue.png"},{"mobs_mc_parrot_yellow_blue.png"}},
visual_size = {x=3, y=3}, visual_size = {x=3, y=3},
rotate = 270,
walk_velocity = 3, walk_velocity = 3,
run_velocity = 5, run_velocity = 5,
sounds = { sounds = {
@ -85,8 +88,6 @@ mobs:register_mob("mobs_mc:parrot", {
-- Feed to tame, but not breed -- Feed to tame, but not breed
if mobs:feed_tame(self, clicker, 1, false, true) then return end if mobs:feed_tame(self, clicker, 1, false, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 0, 50, 80, false, nil) then return end
end, end,
}) })

View File

@ -6,7 +6,8 @@ mobs:register_mob("mobs_mc:pig", {
description = S("Pig"), description = S("Pig"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
runaway = true, skittish = true,
rotate = 270,
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,
xp_min = 1, xp_min = 1,
@ -19,11 +20,30 @@ mobs:register_mob("mobs_mc:pig", {
"mobs_mc_pig.png", -- base "mobs_mc_pig.png", -- base
"blank.png", -- saddle "blank.png", -- saddle
}}, }},
--head code
has_head = true,
head_bone = "head",
swap_y_with_x = false,
reverse_head_yaw = false,
head_bone_pos_y = 2.4,
head_bone_pos_z = 0,
head_height_offset = 1.1,
head_direction_offset = 0,
head_pitch_modifier = 0,
--end head code
visual_size = {x=2.5, y=2.5}, visual_size = {x=2.5, y=2.5},
makes_footstep_sound = true, makes_footstep_sound = true,
walk_velocity = 1, walk_velocity = 1,
run_velocity = 3, run_velocity = 3,
follow_velocity = 3.4, follow_velocity = 3.4,
breed_distance = 1.5,
baby_size = 0.5,
follow_distance = 2,
drops = { drops = {
{name = mobs_mc.items.porkchop_raw, {name = mobs_mc.items.porkchop_raw,
chance = 1, chance = 1,
@ -50,7 +70,7 @@ mobs:register_mob("mobs_mc:pig", {
run_start = 0, run_start = 0,
run_end = 40, run_end = 40,
}, },
follow = mobs_mc.follow.pig, follow = "mcl_farming:carrot_item",
view_range = 8, view_range = 8,
do_custom = function(self, dtime) do_custom = function(self, dtime)
@ -91,12 +111,17 @@ mobs:register_mob("mobs_mc:pig", {
return return
end end
local wielditem = clicker:get_wielded_item() --attempt to enter breed state
-- Feed pig if mobs.enter_breed_state(self,clicker) then
if wielditem:get_name() ~= mobs_mc.items.carrot_on_a_stick then return
if mobs:feed_tame(self, clicker, 1, true, true) then return end end
--ignore other logic
--make baby grow faster
if self.baby then
mobs.make_baby_grow_faster(self,clicker)
return
end end
if mobs:protect(self, clicker) then return end
if self.child then if self.child then
return return
@ -104,6 +129,8 @@ mobs:register_mob("mobs_mc:pig", {
-- Put saddle on pig -- Put saddle on pig
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
local wielditem = item
if item:get_name() == mobs_mc.items.saddle and self.saddle ~= "yes" then if item:get_name() == mobs_mc.items.saddle and self.saddle ~= "yes" then
self.base_texture = { self.base_texture = {
"blank.png", -- baby "blank.png", -- baby
@ -164,10 +191,6 @@ mobs:register_mob("mobs_mc:pig", {
inv:set_stack("main",self.driver:get_wield_index(), wielditem) inv:set_stack("main",self.driver:get_wield_index(), wielditem)
end end
return return
-- Capture pig
elseif not self.driver and clicker:get_wielded_item():get_name() ~= "" then
mobs:capture_mob(self, clicker, 0, 5, 60, false, nil)
end end
end, end,
@ -188,22 +211,53 @@ mobs:spawn_specific(
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest_beach",
"Swampland", "Forest_beach",
"Taiga", "StoneBeach",
"ExtremeHills", "ColdTaiga_beach_water",
"BirchForest", "Taiga_beach",
"MegaSpruceTaiga", "Savanna_beach",
"MegaTaiga", "Plains_beach",
"ExtremeHills+", "ExtremeHills_beach",
"Forest", "ColdTaiga_beach",
"Plains", "Swampland_shore",
"ColdTaiga", "JungleM_shore",
"SunflowerPlains", "Jungle_shore",
"RoofedForest", "MesaPlateauFM_sandlevel",
"MesaPlateauFM_grasstop", "MesaPlateauF_sandlevel",
"ExtremeHillsM", "MesaBryce_sandlevel",
"BirchForestM", "Mesa_sandlevel",
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,

View File

@ -31,7 +31,7 @@ mobs:register_mob("mobs_mc:polar_bear", {
walk_velocity = 1.2, walk_velocity = 1.2,
run_velocity = 2.4, run_velocity = 2.4,
group_attack = true, group_attack = true,
attack_type = "dogfight", attack_type = "punch",
drops = { drops = {
-- 3/4 chance to drop raw fish (poor approximation) -- 3/4 chance to drop raw fish (poor approximation)
{name = mobs_mc.items.fish_raw, {name = mobs_mc.items.fish_raw,

View File

@ -8,7 +8,7 @@ local rabbit = {
spawn_class = "passive", spawn_class = "passive",
passive = true, passive = true,
reach = 1, reach = 1,
rotate = 270,
hp_min = 3, hp_min = 3,
hp_max = 3, hp_max = 3,
xp_min = 1, xp_min = 1,
@ -62,8 +62,6 @@ local rabbit = {
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
-- Feed, tame protect or capture -- Feed, tame protect or capture
if mobs:feed_tame(self, clicker, 1, true, true) then return end if mobs:feed_tame(self, clicker, 1, true, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 0, 50, 80, false, nil) then return end
end, end,
do_custom = function(self) do_custom = function(self)
-- Easter egg: Change texture if rabbit is named “Toast” -- Easter egg: Change texture if rabbit is named “Toast”
@ -116,22 +114,53 @@ mobs:spawn_specific(
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest_beach",
"Swampland", "Forest_beach",
"Taiga", "StoneBeach",
"ExtremeHills", "ColdTaiga_beach_water",
"BirchForest", "Taiga_beach",
"MegaSpruceTaiga", "Savanna_beach",
"MegaTaiga", "Plains_beach",
"ExtremeHills+", "ExtremeHills_beach",
"Forest", "ColdTaiga_beach",
"Plains", "Swampland_shore",
"ColdTaiga", "JungleM_shore",
"SunflowerPlains", "Jungle_shore",
"RoofedForest", "MesaPlateauFM_sandlevel",
"MesaPlateauFM_grasstop", "MesaPlateauF_sandlevel",
"ExtremeHillsM", "MesaBryce_sandlevel",
"BirchForestM", "Mesa_sandlevel",
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,

View File

@ -63,8 +63,13 @@ mobs:register_mob("mobs_mc:sheep", {
hp_max = 8, hp_max = 8,
xp_min = 1, xp_min = 1,
xp_max = 3, xp_max = 3,
skittish = true,
breed_distance = 1.5,
baby_size = 0.5,
follow_distance = 2,
follow = mobs_mc.items.wheat,
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.29, 0.45}, collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.29, 0.45},
rotate = 270,
visual = "mesh", visual = "mesh",
visual_size = {x=3, y=3}, visual_size = {x=3, y=3},
mesh = "mobs_mc_sheepfur.b3d", mesh = "mobs_mc_sheepfur.b3d",
@ -73,6 +78,23 @@ mobs:register_mob("mobs_mc:sheep", {
color = "unicolor_white", color = "unicolor_white",
makes_footstep_sound = true, makes_footstep_sound = true,
walk_velocity = 1, walk_velocity = 1,
run_velocity = 3,
--head code
has_head = true,
head_bone = "head",
swap_y_with_x = false,
reverse_head_yaw = false,
head_bone_pos_y = 3.6,
head_bone_pos_z = -0.6,
head_height_offset = 1.0525,
head_direction_offset = 0.5,
head_pitch_modifier = 0,
--end head code
drops = { drops = {
{name = mobs_mc.items.mutton_raw, {name = mobs_mc.items.mutton_raw,
chance = 1, chance = 1,
@ -99,7 +121,6 @@ mobs:register_mob("mobs_mc:sheep", {
walk_start = 0, walk_end = 40, walk_start = 0, walk_end = 40,
run_start = 0, run_end = 40, run_start = 0, run_end = 40,
}, },
follow = mobs_mc.follow.sheep,
view_range = 12, view_range = 12,
-- Eat grass -- Eat grass
@ -195,8 +216,16 @@ mobs:register_mob("mobs_mc:sheep", {
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
if mobs:feed_tame(self, clicker, 1, true, true) then return end --attempt to enter breed state
if mobs:protect(self, clicker) then return end if mobs.enter_breed_state(self,clicker) then
return
end
--make baby grow faster
if self.baby then
mobs.make_baby_grow_faster(self,clicker)
return
end
if item:get_name() == mobs_mc.items.shears and not self.gotten and not self.child then if item:get_name() == mobs_mc.items.shears and not self.gotten and not self.child then
self.gotten = true self.gotten = true
@ -252,7 +281,6 @@ mobs:register_mob("mobs_mc:sheep", {
end end
return return
end end
if mobs:capture_mob(self, clicker, 0, 5, 70, false, nil) then return end
end, end,
on_breed = function(parent1, parent2) on_breed = function(parent1, parent2)
-- Breed sheep and choose a fur color for the child. -- Breed sheep and choose a fur color for the child.
@ -309,22 +337,53 @@ mobs:spawn_specific(
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest_beach",
"Swampland", "Forest_beach",
"Taiga", "StoneBeach",
"ExtremeHills", "ColdTaiga_beach_water",
"BirchForest", "Taiga_beach",
"MegaSpruceTaiga", "Savanna_beach",
"MegaTaiga", "Plains_beach",
"ExtremeHills+", "ExtremeHills_beach",
"Forest", "ColdTaiga_beach",
"Plains", "Swampland_shore",
"ColdTaiga", "JungleM_shore",
"SunflowerPlains", "Jungle_shore",
"RoofedForest", "MesaPlateauFM_sandlevel",
"MesaPlateauFM_grasstop", "MesaPlateauF_sandlevel",
"ExtremeHillsM", "MesaBryce_sandlevel",
"BirchForestM", "Mesa_sandlevel",
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
@ -336,3 +395,4 @@ mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs
mobs:register_egg("mobs_mc:sheep", S("Sheep"), "mobs_mc_spawn_icon_sheep.png", 0) mobs:register_egg("mobs_mc:sheep", S("Sheep"), "mobs_mc_spawn_icon_sheep.png", 0)

View File

@ -15,7 +15,7 @@ mobs:register_mob("mobs_mc:shulker", {
description = S("Shulker"), description = S("Shulker"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
attack_type = "shoot", attack_type = "projectile",
shoot_interval = 0.5, shoot_interval = 0.5,
arrow = "mobs_mc:shulkerbullet", arrow = "mobs_mc:shulkerbullet",
shoot_offset = 0.5, shoot_offset = 0.5,

View File

@ -44,7 +44,7 @@ mobs:register_mob("mobs_mc:silverfish", {
run_start = 0, run_end = 20, run_start = 0, run_end = 20,
}, },
view_range = 16, view_range = 16,
attack_type = "dogfight", attack_type = "punch",
damage = 1, damage = 1,
reach = 1, reach = 1,
}) })

View File

@ -16,11 +16,15 @@ local skeleton = {
description = S("Skeleton"), description = S("Skeleton"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hostile = true,
rotate = 270,
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
xp_min = 6, xp_min = 6,
xp_max = 6, xp_max = 6,
breath_max = -1, breath_max = -1,
eye_height = 1.5,
projectile_cooldown = 1.5,
armor = {undead = 100, fleshy = 100}, armor = {undead = 100, fleshy = 100},
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.98, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.98, 0.3},
pathfinding = 1, pathfinding = 1,
@ -31,6 +35,22 @@ local skeleton = {
"mcl_bows_bow_0.png", -- bow "mcl_bows_bow_0.png", -- bow
"mobs_mc_skeleton.png", -- skeleton "mobs_mc_skeleton.png", -- skeleton
} }, } },
--head code
has_head = false,
head_bone = "head",
swap_y_with_x = true,
reverse_head_yaw = true,
head_bone_pos_y = 2.4,
head_bone_pos_z = 0,
head_height_offset = 1.1,
head_direction_offset = 0,
head_pitch_modifier = 0,
--end head code
visual_size = {x=1, y=1}, visual_size = {x=1, y=1},
makes_footstep_sound = true, makes_footstep_sound = true,
textures = { textures = {
@ -43,7 +63,7 @@ local skeleton = {
walk_velocity = 1.2, walk_velocity = 1.2,
run_velocity = 2.4, run_velocity = 2.4,
damage = 2, damage = 2,
reach = 2, reach = 3,
drops = { drops = {
{name = mobs_mc.items.arrow, {name = mobs_mc.items.arrow,
chance = 1, chance = 1,
@ -75,6 +95,8 @@ local skeleton = {
walk_speed = 15, walk_speed = 15,
walk_start = 40, walk_start = 40,
walk_end = 60, walk_end = 60,
run_start = 40,
run_end = 60,
run_speed = 30, run_speed = 30,
shoot_start = 70, shoot_start = 70,
shoot_end = 90, shoot_end = 90,
@ -86,13 +108,13 @@ local skeleton = {
ignited_by_sunlight = true, ignited_by_sunlight = true,
view_range = 16, view_range = 16,
fear_height = 4, fear_height = 4,
attack_type = "dogshoot", attack_type = "projectile",
arrow = "mcl_bows:arrow_entity", arrow = "mcl_bows:arrow_entity",
shoot_arrow = function(self, pos, dir) shoot_arrow = function(self, pos, dir)
if mod_bows then if mod_bows then
-- 2-4 damage per arrow -- 2-4 damage per arrow
local dmg = math.max(4, math.random(2, 8)) local dmg = math.random(2,4)
mcl_bows.shoot_arrow("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) mobs.shoot_projectile_handling("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg)
end end
end, end,
shoot_interval = 2, shoot_interval = 2,

View File

@ -87,7 +87,7 @@ mobs:register_mob("mobs_mc:witherskeleton", {
fire_damage = 0, fire_damage = 0,
light_damage = 0, light_damage = 0,
view_range = 16, view_range = 16,
attack_type = "dogfight", attack_type = "punch",
dogshoot_switch = 1, dogshoot_switch = 1,
dogshoot_count_max =0.5, dogshoot_count_max =0.5,
fear_height = 4, fear_height = 4,

View File

@ -64,6 +64,7 @@ local slime_big = {
hp_max = 16, hp_max = 16,
xp_min = 4, xp_min = 4,
xp_max = 4, xp_max = 4,
rotate = 270,
collisionbox = {-1.02, -0.01, -1.02, 1.02, 2.03, 1.02}, collisionbox = {-1.02, -0.01, -1.02, 1.02, 2.03, 1.02},
visual_size = {x=12.5, y=12.5}, visual_size = {x=12.5, y=12.5},
textures = {{"mobs_mc_slime.png", "mobs_mc_slime.png"}}, textures = {{"mobs_mc_slime.png", "mobs_mc_slime.png"}},
@ -95,8 +96,9 @@ local slime_big = {
}, },
fall_damage = 0, fall_damage = 0,
view_range = 16, view_range = 16,
attack_type = "dogfight", attack_type = "jump_punch",
passive = false, passive = false,
jump_only = true,
jump = true, jump = true,
walk_velocity = 2.5, walk_velocity = 2.5,
run_velocity = 2.5, run_velocity = 2.5,
@ -309,6 +311,7 @@ local magma_cube_big = {
}, },
walk_velocity = 4, walk_velocity = 4,
run_velocity = 4, run_velocity = 4,
rotate = 270,
damage = 6, damage = 6,
reach = 3, reach = 3,
armor = 53, armor = 53,
@ -332,12 +335,13 @@ local magma_cube_big = {
}, },
water_damage = 0, water_damage = 0,
lava_damage = 0, lava_damage = 0,
fire_damage = 0, fire_damage = 0,
light_damage = 0, light_damage = 0,
fall_damage = 0, fall_damage = 0,
view_range = 16, view_range = 16,
attack_type = "dogfight", attack_type = "jump_punch",
passive = false, passive = false,
jump_only = true,
jump = true, jump = true,
jump_height = 8, jump_height = 8,
walk_chance = 0, walk_chance = 0,

View File

@ -17,17 +17,22 @@ local spider = {
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
passive = false, passive = false,
hostile = true,
always_climb = true,
docile_by_day = true, docile_by_day = true,
attack_type = "dogfight", attack_type = "punch",
pathfinding = 1, punch_timer_cooloff = 0.5,
rotate = 270,
damage = 2, damage = 2,
reach = 2, reach = 2,
hp_min = 16, hp_min = 16,
hp_max = 16, hp_max = 16,
ignores_cobwebs = true,
xp_min = 5, xp_min = 5,
xp_max = 5, xp_max = 5,
eye_height = 0.475,
armor = {fleshy = 100, arthropod = 100}, armor = {fleshy = 100, arthropod = 100},
collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.89, 0.7}, collisionbox = {-0.45, 0, -0.45, 0.45, 0.9, 0.45},
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_spider.b3d", mesh = "mobs_mc_spider.b3d",
textures = { textures = {
@ -44,7 +49,7 @@ local spider = {
distance = 16, distance = 16,
}, },
walk_velocity = 1.3, walk_velocity = 1.3,
run_velocity = 2.8, run_velocity = 2.75, --spider can become extremely difficult if any higher
jump = true, jump = true,
jump_height = 4, jump_height = 4,
view_range = 16, view_range = 16,

View File

@ -17,6 +17,8 @@ mobs:register_mob("mobs_mc:squid", {
xp_min = 1, xp_min = 1,
xp_max = 3, xp_max = 3,
armor = 100, armor = 100,
rotate = 270,
tilt_swim = true,
-- FIXME: If the squid is near the floor, it turns black -- FIXME: If the squid is near the floor, it turns black
collisionbox = {-0.4, 0.0, -0.4, 0.4, 0.9, 0.4}, collisionbox = {-0.4, 0.0, -0.4, 0.4, 0.9, 0.4},
visual = "mesh", visual = "mesh",
@ -48,8 +50,7 @@ mobs:register_mob("mobs_mc:squid", {
}, },
visual_size = {x=3, y=3}, visual_size = {x=3, y=3},
makes_footstep_sound = false, makes_footstep_sound = false,
fly = true, swim = true,
fly_in = { mobs_mc.items.water_source, mobs_mc.items.river_water_source },
breathes_in_water = true, breathes_in_water = true,
jump = false, jump = false,
view_range = 16, view_range = 16,

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

View File

@ -15,7 +15,7 @@ mobs:register_mob("mobs_mc:vex", {
spawn_class = "hostile", spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,
passive = false, passive = false,
attack_type = "dogfight", attack_type = "punch",
physical = false, physical = false,
hp_min = 14, hp_min = 14,
hp_max = 14, hp_max = 14,

View File

@ -962,14 +962,18 @@ mobs:register_mob("mobs_mc:villager", {
}, },
}, },
visual_size = {x=2.75, y=2.75}, visual_size = {x=2.75, y=2.75},
rotate = 270,
skittish = true,
makes_footstep_sound = true, makes_footstep_sound = true,
walk_velocity = 1.2, walk_velocity = 1.2,
run_velocity = 2.4, run_velocity = 3,
drops = {}, drops = {},
can_despawn = false, can_despawn = false,
-- TODO: sounds -- TODO: sounds
sounds = { sounds = {
random = "mobs_mc_villager", random = "mobs_mc_villager",
damage = "mobs_mc_villager_hurt",
death = "mobs_mc_villager_hurt",
distance = 10, distance = 10,
}, },
animation = { animation = {

View File

@ -35,7 +35,7 @@ mobs:register_mob("mobs_mc:evoker", {
walk_velocity = 0.2, walk_velocity = 0.2,
run_velocity = 1.4, run_velocity = 1.4,
group_attack = true, group_attack = true,
attack_type = "dogfight", attack_type = "punch",
-- Summon vexes -- Summon vexes
custom_attack = function(self, to_attack) custom_attack = function(self, to_attack)
local r = pr:next(2,4) local r = pr:next(2,4)

View File

@ -10,7 +10,7 @@ mobs:register_mob("mobs_mc:illusioner", {
description = S("Illusioner"), description = S("Illusioner"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
attack_type = "shoot", attack_type = "projectile",
shoot_interval = 2.5, shoot_interval = 2.5,
shoot_offset = 1.5, shoot_offset = 1.5,
arrow = "mcl_bows:arrow_entity", arrow = "mcl_bows:arrow_entity",
@ -18,7 +18,7 @@ mobs:register_mob("mobs_mc:illusioner", {
if mod_bows then if mod_bows then
-- 1-4 damage per arrow -- 1-4 damage per arrow
local dmg = math.random(1, 4) local dmg = math.random(1, 4)
mcl_bows.shoot_arrow("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) mobs.shoot_projectile_handling("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg)
end end
end, end,
hp_min = 32, hp_min = 32,

View File

@ -37,7 +37,7 @@ mobs:register_mob("mobs_mc:vindicator", {
reach = 2, reach = 2,
walk_velocity = 1.2, walk_velocity = 1.2,
run_velocity = 2.4, run_velocity = 2.4,
attack_type = "dogfight", attack_type = "punch",
drops = { drops = {
{name = mobs_mc.items.emerald, {name = mobs_mc.items.emerald,
chance = 1, chance = 1,

View File

@ -29,6 +29,9 @@ mobs:register_mob("mobs_mc:villager_zombie", {
description = S("Zombie Villager"), description = S("Zombie Villager"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hostile = true,
rotate = 270,
eye_height = 1.65,
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
xp_min = 5, xp_min = 5,
@ -51,8 +54,8 @@ mobs:register_mob("mobs_mc:villager_zombie", {
damage = 3, damage = 3,
reach = 2, reach = 2,
walk_velocity = 1.2, walk_velocity = 1.2,
run_velocity = 2.4, run_velocity = 3.5,
attack_type = "dogfight", attack_type = "punch",
group_attack = true, group_attack = true,
drops = { drops = {
{name = mobs_mc.items.rotten_flesh, {name = mobs_mc.items.rotten_flesh,

View File

@ -34,7 +34,7 @@ mobs:register_mob("mobs_mc:witch", {
run_velocity = 2.4, run_velocity = 2.4,
pathfinding = 1, pathfinding = 1,
group_attack = true, group_attack = true,
attack_type = "dogshoot", attack_type = "projectile",
arrow = "mobs_mc:potion_arrow", arrow = "mobs_mc:potion_arrow",
shoot_interval = 2.5, shoot_interval = 2.5,
shoot_offset = 1, shoot_offset = 1,

View File

@ -53,7 +53,7 @@ mobs:register_mob("mobs_mc:wither", {
}, },
lava_damage = 0, lava_damage = 0,
fire_damage = 0, fire_damage = 0,
attack_type = "dogshoot", attack_type = "projectile",
explosion_strength = 8, explosion_strength = 8,
dogshoot_stop = true, dogshoot_stop = true,
arrow = "mobs_mc:wither_skull", arrow = "mobs_mc:wither_skull",

View File

@ -23,13 +23,31 @@ local wolf = {
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
can_despawn = true, can_despawn = true,
neutral = true,
hp_min = 8, hp_min = 8,
hp_max = 8, hp_max = 8,
xp_min = 1, xp_min = 1,
xp_max = 3, xp_max = 3,
rotate = 270,
passive = false, passive = false,
group_attack = true, group_attack = true,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 0.84, 0.3},
--head code
has_head = false,
head_bone = "head",
swap_y_with_x = false,
reverse_head_yaw = false,
head_bone_pos_y = 3.6,
head_bone_pos_z = -0.6,
head_height_offset = 1.0525,
head_direction_offset = 0.5,
head_pitch_modifier = 0,
--end head code
collisionbox = {-0.3, -0.00, -0.3, 0.3, 0.85, 0.3},
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_wolf.b3d", mesh = "mobs_mc_wolf.b3d",
textures = { textures = {
@ -53,7 +71,7 @@ local wolf = {
run_velocity = 3, run_velocity = 3,
damage = 4, damage = 4,
reach = 2, reach = 2,
attack_type = "dogfight", attack_type = "punch",
fear_height = 4, fear_height = 4,
follow = mobs_mc.follow.wolf, follow = mobs_mc.follow.wolf,
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
@ -75,6 +93,7 @@ local wolf = {
dog:set_yaw(yaw) dog:set_yaw(yaw)
ent = dog:get_luaentity() ent = dog:get_luaentity()
ent.owner = clicker:get_player_name() ent.owner = clicker:get_player_name()
ent.tamed = true
-- cornfirm taming -- cornfirm taming
minetest.sound_play("mobs_mc_wolf_bark", {object=dog, max_hear_distance=16}, true) minetest.sound_play("mobs_mc_wolf_bark", {object=dog, max_hear_distance=16}, true)
-- Replace wolf -- Replace wolf
@ -142,17 +161,29 @@ dog.owner_loyal = true
dog.follow_velocity = 3.2 dog.follow_velocity = 3.2
-- Automatically teleport dog to owner -- Automatically teleport dog to owner
dog.do_custom = mobs_mc.make_owner_teleport_function(12) dog.do_custom = mobs_mc.make_owner_teleport_function(12)
dog.follow = mobs_mc.follow.dog
dog.attack_animals = nil dog.attack_animals = nil
dog.specific_attack = nil dog.specific_attack = nil
dog.breed_distance = 1.5
dog.baby_size = 0.5
dog.follow_distance = 2
dog.follow = "mcl_mobitems:beef"
dog.on_rightclick = function(self, clicker) dog.on_rightclick = function(self, clicker)
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
if mobs:protect(self, clicker) then --owner is broken for this
--attempt to enter breed state
if mobs.enter_breed_state(self,clicker) then
return return
elseif item:get_name() ~= "" and mobs:capture_mob(self, clicker, 0, 2, 80, false, nil) then end
--make baby grow faster
if self.baby then
mobs.make_baby_grow_faster(self,clicker)
return return
elseif is_food(item:get_name()) then end
if is_food(item:get_name()) then
-- Feed to increase health -- Feed to increase health
local hp = self.health local hp = self.health
local hp_add = 0 local hp_add = 0

View File

@ -49,6 +49,8 @@ local zombie = {
description = S("Zombie"), description = S("Zombie"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hostile = true,
rotate = 270,
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
xp_min = 5, xp_min = 5,
@ -74,8 +76,25 @@ local zombie = {
damage = "mobs_mc_zombie_hurt", damage = "mobs_mc_zombie_hurt",
distance = 16, distance = 16,
}, },
walk_velocity = .8,
run_velocity = 1.6, --head code
has_head = false,
head_bone = "Head",
swap_y_with_x = true,
reverse_head_yaw = true,
head_bone_pos_y = 2.4,
head_bone_pos_z = 0,
head_height_offset = 1.1,
head_direction_offset = 0,
head_pitch_modifier = 0,
--end head code
eye_height = 1.65,
walk_velocity = 1,
run_velocity = 3.5,
damage = 3, damage = 3,
reach = 2, reach = 2,
fear_height = 4, fear_height = 4,
@ -93,7 +112,8 @@ local zombie = {
ignited_by_sunlight = true, ignited_by_sunlight = true,
sunlight_damage = 2, sunlight_damage = 2,
view_range = 16, view_range = 16,
attack_type = "dogfight", attack_type = "punch",
punch_timer_cooloff = 0.5,
harmed_by_heal = true, harmed_by_heal = true,
} }

View File

@ -15,13 +15,16 @@ local pigman = {
-- type="animal", passive=false: This combination is needed for a neutral mob which becomes hostile, if attacked -- type="animal", passive=false: This combination is needed for a neutral mob which becomes hostile, if attacked
type = "animal", type = "animal",
passive = false, passive = false,
neutral = true,
rotate = 270,
spawn_class = "passive", spawn_class = "passive",
hostile_cooldown = 15, --seconds
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
xp_min = 6, xp_min = 6,
xp_max = 6, xp_max = 6,
armor = {undead = 90, fleshy = 90}, armor = {undead = 90, fleshy = 90},
attack_type = "dogfight", attack_type = "punch",
group_attack = { "mobs_mc:pigman", "mobs_mc:baby_pigman" }, group_attack = { "mobs_mc:pigman", "mobs_mc:baby_pigman" },
damage = 9, damage = 9,
reach = 2, reach = 2,
@ -41,6 +44,22 @@ local pigman = {
damage = "mobs_mc_zombiepig_hurt", damage = "mobs_mc_zombiepig_hurt",
distance = 16, distance = 16,
}, },
--head code
has_head = false,
head_bone = "head",
swap_y_with_x = true,
reverse_head_yaw = true,
head_bone_pos_y = 2.4,
head_bone_pos_z = 0,
head_height_offset = 1.1,
head_direction_offset = 0,
head_pitch_modifier = 0,
--end head code
jump = true, jump = true,
makes_footstep_sound = true, makes_footstep_sound = true,
walk_velocity = .8, walk_velocity = .8,

View File

@ -76,9 +76,8 @@ This block connects to these blocks: @1.=Dieser Block verbindet sich mit den fol
This block connects to this block: @1.=Dieser Block verbindet sich mit diesem Block: @1. This block connects to this block: @1.=Dieser Block verbindet sich mit diesem Block: @1.
This block decreases your breath and causes a drowning damage of @1 hit point every 2 seconds.=Dieser Block reduziert Ihren Atem und verursacht beim Ertrinken einen Schaden von @1 Trefferpunkt alle 2 Sekunden. This block decreases your breath and causes a drowning damage of @1 hit point every 2 seconds.=Dieser Block reduziert Ihren Atem und verursacht beim Ertrinken einen Schaden von @1 Trefferpunkt alle 2 Sekunden.
This block decreases your breath and causes a drowning damage of @1 hit points every 2 seconds.=Dieser Block reduziert Ihren Atem und verursacht beim Ertrinken einen Schaden von @1 Trefferpunkten alle 2 Sekunden. This block decreases your breath and causes a drowning damage of @1 hit points every 2 seconds.=Dieser Block reduziert Ihren Atem und verursacht beim Ertrinken einen Schaden von @1 Trefferpunkten alle 2 Sekunden.
This block glows faintly. It is barely noticable.=Dieser Block leuchtet schwach. Es ist kaum merklich.
This block is a light source with a light level of @1.=Dieser Block ist eine Lichtquelle mit einer Helligkeitsstufe von @1. This block is a light source with a light level of @1.=Dieser Block ist eine Lichtquelle mit einer Helligkeitsstufe von @1.
This block glows faintly with a light level of @1.=Dieser Block leuchtet schwach mit einer Helligkeitsstufe von @1. This block glows faintly with a light level of @1.=Dieser Block leuchtet schwach mit einer Helligkeitsstufe von @1.
This block is a building block for creating various buildings.=Dieser Block ist für den Bau diverser Gebäude vorgesehen. This block is a building block for creating various buildings.=Dieser Block ist für den Bau diverser Gebäude vorgesehen.
This block is a liquid with these properties:=Dieser Block ist eine Flüssigkeit mit folgenden Eigenschaften: This block is a liquid with these properties:=Dieser Block ist eine Flüssigkeit mit folgenden Eigenschaften:
This block is affected by gravity and can fall.=Dieser Block wird von der Schwerkraft beeinflusst und kann fallen. This block is affected by gravity and can fall.=Dieser Block wird von der Schwerkraft beeinflusst und kann fallen.

View File

@ -2,7 +2,7 @@
Using it as fuel turns it into: @1.= Using it as fuel turns it into: @1.=
@1 seconds= @1 seconds=
# Item count times item name # Item count times item name
%@1×@2= @1×@2=
# Itemname (25%) # Itemname (25%)
@1 (@2%)= @1 (@2%)=
# Itemname (<0.5%) # Itemname (<0.5%)

View File

@ -1,7 +1,7 @@
# textdomain:awards # textdomain:awards
@1: @2=@1: @2 @1: @2=@1: @2
@1 (got)=@1 (erhalten) @1 (got)=@1 (erhalten)
@1s awards:=Auszeichnungen von @1: @1s awards:=Auszeichnungen von @:
(Secret Award)=(Geheime Auszeichnung) (Secret Award)=(Geheime Auszeichnung)
Achievement gotten!=Auszeichnung erhalten! Achievement gotten!=Auszeichnung erhalten!
Achievement gotten:=Auszeichnung erhalten: Achievement gotten:=Auszeichnung erhalten:
@ -27,7 +27,6 @@ Awards=Auszeichnungen
@1/@2 deaths=@1/@2 Tode @1/@2 deaths=@1/@2 Tode
@1/@2 dug=@1/@2 abgebaut @1/@2 dug=@1/@2 abgebaut
@1/@2 game joins=@1/@2 Spielen beigetreten @1/@2 game joins=@1/@2 Spielen beigetreten
@1/@2 lines of chat=@1/@2 Chatzeilen
@1/@2 placed=@1/@2 platziert @1/@2 placed=@1/@2 platziert
Die @1 times.=Sterben Sie @1 mal. Die @1 times.=Sterben Sie @1 mal.
Die.=Sterben Sie. Die.=Sterben Sie.
@ -58,3 +57,7 @@ Invalid action.=Ungültige Aktion.
Player is not online.=Spieler ist nicht online. Player is not online.=Spieler ist nicht online.
Done.=Fertig. Done.=Fertig.
Achievement “@1” does not exist.=Auszeichnung »@1« existiert nicht. Achievement “@1” does not exist.=Auszeichnung »@1« existiert nicht.
@1 has made the achievement @2=@1 hat die Auszeichnung @2 erhalten
Write something in chat.=Schreiben Sie etwas in den Chat.
Write @1 chat messages.=Schreiben Sie @1 Chatnachrichten.
@1/@2 chat messages=@1/@2 Chatnachrichten

View File

@ -6,12 +6,11 @@
@1/@2 game joins= @1/@2 game joins=
@1/@2 placed= @1/@2 placed=
@1 (got)= @1 (got)=
@1: @1= @1: @2=
@1s awards:= @1s awards:=
(Secret Award)= (Secret Award)=
<achievement ID>= <achievement ID>=
<name>= <name>=
A Cat in a Pop-Tart?!=
Achievement gotten!= Achievement gotten!=
Achievement gotten:= Achievement gotten:=
Achievement gotten: @1= Achievement gotten: @1=
@ -28,9 +27,9 @@ Join the game.=
List awards in chat (deprecated)= List awards in chat (deprecated)=
Place a block: @1= Place a block: @1=
Place blocks: @1×@2= Place blocks: @1×@2=
Secret Achievement gotten!= Secret achievement gotten!=
Secret Achievement gotten:= Secret achievement gotten:=
Secret Achievement gotten: @1= Secret achievement gotten: @1=
Show details of an achievement= Show details of an achievement=
Show, clear, disable or enable your achievements= Show, clear, disable or enable your achievements=
Get this achievement to find out what it is.= Get this achievement to find out what it is.=
@ -60,3 +59,5 @@ Player is not online.=
Done.= Done.=
Achievement “@1” does not exist.= Achievement “@1” does not exist.=
@1 has made the achievement @2= @1 has made the achievement @2=
Mine a block: @1=
Mine blocks: @1×@2=

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 B

After

Width:  |  Height:  |  Size: 144 B

View File

@ -263,7 +263,7 @@ function mcl_experience.add_experience(player, experience)
local can = final_candidates[math.random(#final_candidates)] local can = final_candidates[math.random(#final_candidates)]
local stack, list, index, wear = can.stack, can.list, can.index, can.wear local stack, list, index, wear = can.stack, can.list, can.index, can.wear
local unbreaking_level = mcl_enchanting.get_enchantment(stack, "unbreaking") local unbreaking_level = mcl_enchanting.get_enchantment(stack, "unbreaking")
local uses = mcl_util.calculate_durability(itemstack) local uses = mcl_util.calculate_durability(stack)
local multiplier = 2 * 65535 / uses local multiplier = 2 * 65535 / uses
local repair = experience * multiplier local repair = experience * multiplier
local new_wear = wear - repair local new_wear = wear - repair

View File

@ -92,9 +92,11 @@ function mcl_armor.register_set(def)
local groups = def.groups or {} local groups = def.groups or {}
local on_equip_callbacks = def.on_equip_callbacks or {} local on_equip_callbacks = def.on_equip_callbacks or {}
local on_unequip_callbacks = def.on_unequip_callbacks or {} local on_unequip_callbacks = def.on_unequip_callbacks or {}
local on_break_callbacks = def.on_break_callbacks or {}
local textures = def.textures or {} local textures = def.textures or {}
local previews = def.previews or {} local previews = def.previews or {}
local durabilities = def.durabilities or {} local durabilities = def.durabilities or {}
local element_groups = def.element_groups or {}
for name, element in pairs(mcl_armor.elements) do for name, element in pairs(mcl_armor.elements) do
local itemname = element.name .. "_" .. def.name local itemname = element.name .. "_" .. def.name
@ -110,6 +112,10 @@ function mcl_armor.register_set(def)
groups.mcl_armor_uses = (durabilities[name] or math.floor(def.durability * element.durability)) + 1 groups.mcl_armor_uses = (durabilities[name] or math.floor(def.durability * element.durability)) + 1
groups.enchantability = def.enchantability groups.enchantability = def.enchantability
for k, v in pairs(element_groups) do
groups[k] = v
end
minetest.register_tool(itemstring, { minetest.register_tool(itemstring, {
description = S(def.description .. " " .. (descriptions[name] or element.description)), description = S(def.description .. " " .. (descriptions[name] or element.description)),
_doc_items_longdesc = mcl_armor.longdesc, _doc_items_longdesc = mcl_armor.longdesc,
@ -125,6 +131,7 @@ function mcl_armor.register_set(def)
on_secondary_use = mcl_armor.equip_on_use, on_secondary_use = mcl_armor.equip_on_use,
_on_equip = on_equip_callbacks[name] or def.on_equip, _on_equip = on_equip_callbacks[name] or def.on_equip,
_on_unequip = on_unequip_callbacks[name] or def.on_unequip, _on_unequip = on_unequip_callbacks[name] or def.on_unequip,
_on_break = on_break_callbacks[name] or def.on_break,
_mcl_armor_element = name, _mcl_armor_element = name,
_mcl_armor_texture = textures[name] or modname .. "_" .. itemname .. ".png", _mcl_armor_texture = textures[name] or modname .. "_" .. itemname .. ".png",
_mcl_armor_preview = previews[name] or modname .. "_" .. itemname .. "_preview.png", _mcl_armor_preview = previews[name] or modname .. "_" .. itemname .. "_preview.png",
@ -203,12 +210,26 @@ function mcl_armor.update(obj)
if not itemstack:is_empty() then if not itemstack:is_empty() then
local def = itemstack:get_definition() local def = itemstack:get_definition()
if def._mcl_armor_texture then local texture = def._mcl_armor_texture
info.texture = "(" .. def._mcl_armor_texture .. ")" .. (info.texture and "^" .. info.texture or "")
if texture then
if type(texture) == "function" then
texture = texture(obj, itemstack)
end
if texture then
info.texture = "(" .. texture .. ")" .. (info.texture and "^" .. info.texture or "")
end
end end
if obj:is_player() and def._mcl_armor_preview then local preview = def._mcl_armor_preview
info.preview = "(player.png^[opacity:0^" .. def._mcl_armor_preview .. ")" .. (info.preview and "^" .. info.preview or "" )
if obj:is_player() and preview then
if type(preview) == "function" then
preview = preview(obj, itemstack)
end
if preview then
info.preview = "(player.png^[opacity:0^" .. def._mcl_armor_preview .. ")" .. (info.preview and "^" .. info.preview or "" )
end
end end
info.points = info.points + minetest.get_item_group(itemname, "mcl_armor_points") info.points = info.points + minetest.get_item_group(itemname, "mcl_armor_points")

Some files were not shown because too many files have changed in this diff Show More