Merge branch 'rootyjr_enderman' of https://git.minetest.land/Wuzzy/MineClone2 into rootyjr_enderman

This commit is contained in:
Wuzzy 2020-06-13 19:32:41 +02:00
commit 34645d290b
9 changed files with 263 additions and 77 deletions

@ -2581,6 +2581,14 @@ local falling = function(self, pos)
end end
end end
local teleport = function(self, target)
if self.do_teleport then
if self.do_teleport(self, target) == false then
return
end
end
end
-- deal damage and effects when mob punched -- deal damage and effects when mob punched
local mob_punch = function(self, hitter, tflp, tool_capabilities, dir) local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
@ -3393,6 +3401,8 @@ minetest.register_entity(name, {
_cmi_is_mob = true, _cmi_is_mob = true,
-- MCL2 extensions -- MCL2 extensions
teleport = teleport,
do_teleport = def.do_teleport,
spawn_class = def.spawn_class, spawn_class = def.spawn_class,
ignores_nametag = def.ignores_nametag or false, ignores_nametag = def.ignores_nametag or false,
rain_damage = def.rain_damage or 0, rain_damage = def.rain_damage or 0,

@ -10,6 +10,21 @@
-- and they are provoked by looking directly at them. -- and they are provoked by looking directly at them.
-- TODO: Implement MC behaviour. -- TODO: Implement MC behaviour.
-- Rootyjr
-----------------------------
-- implemented ability to detect when seen / break eye contact and aggressive response
-- implemented teleport to avoid arrows.
-- implemented teleport to avoid rain.
-- implemented teleport to chase.
-- added enderman particles.
-- drew mcl_portal_particle1.png
-- drew mcl_portal_particle2.png
-- drew mcl_portal_particle3.png
-- drew mcl_portal_particle4.png
-- drew mcl_portal_particle5.png
-- added rain damage.
-- fixed the grass_with_dirt issue.
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
--################### --###################
@ -163,13 +178,13 @@ local select_enderman_animation = function(animation_type)
end end
end end
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
mobs:register_mob("mobs_mc:enderman", { mobs:register_mob("mobs_mc:enderman", {
-- TODO: Endermen should be classified as passive -- TODO: Endermen should be classified as passive
type = "monster", type = "monster",
spawn_class = "passive", spawn_class = "passive",
passive = false, passive = true,
pathfinding = 1, pathfinding = 1,
hp_min = 40, hp_min = 40,
hp_max = 40, hp_max = 40,
@ -197,7 +212,116 @@ mobs:register_mob("mobs_mc:enderman", {
}, },
animation = select_enderman_animation("normal"), animation = select_enderman_animation("normal"),
_taken_node = "", _taken_node = "",
-- TODO: Teleport enderman on damage, etc.
do_custom = function(self, dtime) do_custom = function(self, dtime)
-- PARTICLE BEHAVIOUR HERE.
local enderpos = self.object:get_pos()
local chanceOfParticle = math.random(0, 1)
if chanceOfParticle == 1 then
minetest.add_particle({
pos = {x=enderpos.x+math.random(-1,1)*math.random()/2,y=enderpos.y+math.random(0,3),z=enderpos.z+math.random(-1,1)*math.random()/2},
velocity = {x=math.random(-.25,.25), y=math.random(-.25,.25), z=math.random(-.25,.25)},
acceleration = {x=math.random(-.5,.5), y=math.random(-.5,.5), z=math.random(-.5,.5)},
expirationtime = math.random(),
size = math.random(),
collisiondetection = true,
vertical = false,
texture = "mcl_portals_particle"..math.random(1, 5)..".png",
})
end
-- RAIN DAMAGE / EVASIVE WARP BEHAVIOUR HERE.
if mcl_weather.state == "rain" or mcl_weather.state == "lightning" then
local damage = true
local enderpos = self.object:get_pos()
enderpos.y = enderpos.y+2.89
local height = {x=enderpos.x, y=enderpos.y+512,z=enderpos.z}
local ray = minetest.raycast(enderpos, height, true)
-- Check for blocks above enderman.
for pointed_thing in ray do
if pointed_thing.type == "node" then
local nn = minetest.get_node(minetest.get_pointed_thing_position(pointed_thing)).name
local def = minetest.registered_nodes[nn]
if (not def) or def.walkable then
-- There's a node in the way. Delete arrow without damage
damage = false
break
end
end
end
if damage == true then
self.state = ""
--rain hurts enderman
self.object:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self._damage},
}, nil)
--randomly teleport hopefully under something.
self:teleport(nil)
end
end
-- AGRESSIVELY WARP/CHASE PLAYER BEHAVIOUR HERE.
if self.state == "attack" then
target = self.attack
if vector.distance(self.object:get_pos(), target:get_pos()) > 10 then
self:teleport(target)
end
end
-- ARROW AVOIDANCE BEHAVIOUR HERE.
-- Check for arrows nearby.
local enderpos = self.object:get_pos()
local objs = minetest.get_objects_inside_radius(enderpos, 4)
for n = 1, #objs do
obj = objs[n]
if obj then
lua = obj:get_luaentity()
if lua then
if lua.name == "mcl_bows:arrow_entity" then
self:teleport(nil)
end
end
end
end
-- PROVOKED BEHAVIOUR HERE.
local enderpos = self.object:get_pos()
if self.provoked == "broke_contact" then
self.provoked = "false"
self.state = 'attack'
end
-- Check to see if people are near by enough to look at us.
local objs = minetest.get_objects_inside_radius(enderpos, 64)
for n = 1, #objs do
obj = objs[n]
if obj then
if minetest.is_player(obj) then
-- Check if they are looking at us.
local player_pos = obj:get_pos()
local look_dir_not_normalized = obj:get_look_dir()
local look_dir = vector.normalize(look_dir_not_normalized)
local look_pos = vector.new({x = look_dir.x+player_pos.x, y = look_dir.y+player_pos.y + 1.5, z = look_dir.z+player_pos.z}) -- Arbitrary value (1.5) is head level according to player info mod.
-- Cast up to 64 to see if player is looking at enderman.
for n = 1,64,.25 do
local node = minetest.get_node(look_pos)
if node.name ~= "air" then
break
end
if look_pos.x-1<enderpos.x and look_pos.x+1>enderpos.x and look_pos.y-2.89<enderpos.y and look_pos.y-2>enderpos.y and look_pos.z-1<enderpos.z and look_pos.z+1>enderpos.z then
self.provoked = "staring"
self.attack = minetest.get_player_by_name(obj:get_player_name())
break
else
if self.provoked == "staring" then
self.provoked = "broke_contact"
end
end
look_pos.x = look_pos.x + (.25 * look_dir.x)
look_pos.y = look_pos.y + (.25 * look_dir.y)
look_pos.z = look_pos.z + (.25 * look_dir.z)
end
end
end
end
-- TAKE AND PLACE STUFF BEHAVIOUR BELOW.
if not mobs_griefing then if not mobs_griefing then
return return
end end
@ -218,44 +342,47 @@ mobs:register_mob("mobs_mc:enderman", {
local r = pr:next(1, #takable_nodes) local r = pr:next(1, #takable_nodes)
local take_pos = takable_nodes[r] local take_pos = takable_nodes[r]
local node = minetest.get_node(take_pos) local node = minetest.get_node(take_pos)
local dug = minetest.dig_node(take_pos) -- Don't destroy protected stuff.
if dug then if not minetest.is_protected(take_pos, "") then
if mobs_mc.enderman_replace_on_take[node.name] then local dug = minetest.dig_node(take_pos)
self._taken_node = mobs_mc.enderman_replace_on_take[node.name] if dug then
else if mobs_mc.enderman_replace_on_take[node.name] then
self._taken_node = node.name self._taken_node = mobs_mc.enderman_replace_on_take[node.name]
end else
local def = minetest.registered_nodes[self._taken_node] self._taken_node = node.name
-- Update animation and texture accordingly (adds visibly carried block) end
local block_type local def = minetest.registered_nodes[self._taken_node]
-- Cube-shaped -- Update animation and texture accordingly (adds visibly carried block)
if def.drawtype == "normal" or local block_type
def.drawtype == "nodebox" or -- Cube-shaped
def.drawtype == "liquid" or if def.drawtype == "normal" or
def.drawtype == "flowingliquid" or def.drawtype == "nodebox" or
def.drawtype == "glasslike" or def.drawtype == "liquid" or
def.drawtype == "glasslike_framed" or def.drawtype == "flowingliquid" or
def.drawtype == "glasslike_framed_optional" or def.drawtype == "glasslike" or
def.drawtype == "allfaces" or def.drawtype == "glasslike_framed" or
def.drawtype == "allfaces_optional" or def.drawtype == "glasslike_framed_optional" or
def.drawtype == nil then def.drawtype == "allfaces" or
block_type = "cube" def.drawtype == "allfaces_optional" or
elseif def.drawtype == "plantlike" then def.drawtype == nil then
-- Flowers and stuff block_type = "cube"
block_type = "plantlike45" elseif def.drawtype == "plantlike" then
elseif def.drawtype == "airlike" then -- Flowers and stuff
-- Just air block_type = "plantlike45"
block_type = nil elseif def.drawtype == "airlike" then
else -- Just air
-- Fallback for complex drawtypes block_type = nil
block_type = "unknown" else
end -- Fallback for complex drawtypes
self.base_texture = create_enderman_textures(block_type, self._taken_node) block_type = "unknown"
self.object:set_properties({ textures = self.base_texture }) end
self.animation = select_enderman_animation("block") self.base_texture = create_enderman_textures(block_type, self._taken_node)
mobs:set_animation(self, self.animation.current) self.object:set_properties({ textures = self.base_texture })
if def.sounds and def.sounds.dug then self.animation = select_enderman_animation("block")
minetest.sound_play(def.sounds.dug, {pos = take_pos, max_hear_distance = 16}, true) mobs:set_animation(self, self.animation.current)
if def.sounds and def.sounds.dug then
minetest.sound_play(def.sounds.dug, {pos = take_pos, max_hear_distance = 16}, true)
end
end end
end end
end end
@ -267,7 +394,8 @@ mobs:register_mob("mobs_mc:enderman", {
local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
-- Place node at looking direction -- Place node at looking direction
local place_pos = vector.subtract(pos, minetest.facedir_to_dir(minetest.dir_to_facedir(minetest.yaw_to_dir(yaw)))) local place_pos = vector.subtract(pos, minetest.facedir_to_dir(minetest.dir_to_facedir(minetest.yaw_to_dir(yaw))))
if minetest.get_node(place_pos).name == "air" then -- Also check to see if protected.
if minetest.get_node(place_pos).name == "air" and not minetest.is_protected(place_pos, "") then
-- ... but only if there's a free space -- ... but only if there's a free space
local success = minetest.place_node(place_pos, {name = self._taken_node}) local success = minetest.place_node(place_pos, {name = self._taken_node})
if success then if success then
@ -283,33 +411,61 @@ mobs:register_mob("mobs_mc:enderman", {
end end
end end
end, end,
-- TODO: Teleport enderman on damage, etc. do_teleport = function(self, target)
_do_teleport = function(self) if target ~= nil then
-- Attempt to randomly teleport enderman local target_pos = target:get_pos()
local pos = self.object:get_pos() -- Find all solid nodes below air in a 10×10×10 cuboid centered on the target
-- Find all solid nodes below air in a 65×65×65 cuboid centered on the enderman local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(target_pos, 5), vector.add(target_pos, 5), {"group:solid", "group:cracky", "group:crumbly"})
local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(pos, 32), vector.add(pos, 32), {"group:solid", "group:cracky", "group:crumbly"}) local telepos
local telepos if #nodes > 0 then
if #nodes > 0 then -- Up to 64 attempts to teleport
-- Up to 64 attempts to teleport for n=1, math.min(64, #nodes) do
for n=1, math.min(64, #nodes) do local r = pr:next(1, #nodes)
local r = pr:next(1, #nodes) local nodepos = nodes[r]
local nodepos = nodes[r] local node_ok = true
local node_ok = true -- Selected node needs to have 3 nodes of free space above
-- Selected node needs to have 3 nodes of free space above for u=1, 3 do
for u=1, 3 do local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z})
local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z}) if minetest.registered_nodes[node.name].walkable then
if minetest.registered_nodes[node.name].walkable then node_ok = false
node_ok = false break
break end
end
if node_ok then
telepos = {x=nodepos.x, y=nodepos.y+1, z=nodepos.z}
end end
end end
if node_ok then if telepos then
telepos = {x=nodepos.x, y=nodepos.y+1, z=nodepos.z} self.object:set_pos(telepos)
end end
end end
if telepos then else
self.object:set_pos(telepos) -- Attempt to randomly teleport enderman
local pos = self.object:get_pos()
-- Find all solid nodes below air in a 65×65×65 cuboid centered on the enderman
local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(pos, 32), vector.add(pos, 32), {"group:solid", "group:cracky", "group:crumbly"})
local telepos
if #nodes > 0 then
-- Up to 64 attempts to teleport
for n=1, math.min(64, #nodes) do
local r = pr:next(1, #nodes)
local nodepos = nodes[r]
local node_ok = true
-- Selected node needs to have 3 nodes of free space above
for u=1, 3 do
local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z})
if minetest.registered_nodes[node.name].walkable then
node_ok = false
break
end
end
if node_ok then
telepos = {x=nodepos.x, y=nodepos.y+1, z=nodepos.z}
end
end
if telepos then
self.object:set_pos(telepos)
end
end end
end end
end, end,
@ -319,10 +475,16 @@ mobs:register_mob("mobs_mc:enderman", {
minetest.add_item(pos, self._taken_node) minetest.add_item(pos, self._taken_node)
end end
end, end,
do_punch = function(self, hitter, tflp, tool_caps, dir)
-- damage from rain caused by itself so we don't want it to attack itself.
if hitter ~= self.object then
self:teleport(hitter)
self.state="attack"
self.attack=hitter
end
end,
water_damage = 8, water_damage = 8,
-- TODO: Increase view range when it detects being seen view_range = 64,
-- Low view range to emulate that behaviour somehow
view_range = 4,
fear_height = 4, fear_height = 4,
attack_type = "dogfight", attack_type = "dogfight",
}) })

@ -177,11 +177,6 @@ mobs_mc.override.enderman_takable = {
"group:enderman_takable", "group:enderman_takable",
} }
mobs_mc.override.enderman_replace_on_take = { mobs_mc.override.enderman_replace_on_take = {
-- Turn covered dirt blocks to normal dirt.
-- This is a workaround because the dirt with grass texture fails when held by the enderman
-- (because of the node coloring).
-- FIXME: Remove these lines as soon we support rendering dirt with grass
["mcl_core:dirt_with_grass"] = "mcl_core:dirt",
} }
mobs_mc.override.misc = { mobs_mc.override.misc = {
totem_fail_nodes = { "mcl_core:void", "mcl_core:realm_barrier" }, totem_fail_nodes = { "mcl_core:void", "mcl_core:realm_barrier" },
@ -200,8 +195,18 @@ for i=1, 6 do
end end
table.insert(ctable, cbackground .. "^" .. last) table.insert(ctable, cbackground .. "^" .. last)
end end
mobs_mc.override.enderman_block_texture_overrides = { mobs_mc.override.enderman_block_texture_overrides = {
["mcl_core:cactus"] = ctable, ["mcl_core:cactus"] = ctable,
-- FIXME: replace colorize colors with colors from palette
["mcl_core:dirt_with_grass"] =
{
"mcl_core_grass_block_top.png^[colorize:green:90",
"default_dirt.png",
"default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)",
"default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)",
"default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)",
"default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)"}
} }
-- List of nodes on which mobs can spawn -- List of nodes on which mobs can spawn

@ -215,11 +215,20 @@ ARROW_ENTITY.on_step = function(self, dtime)
end end
end end
-- Punch target object -- Punch target object but avoid hurting enderman.
obj:punch(self.object, 1.0, { if lua then
full_punch_interval=1.0, if lua.name ~= "mobs_mc:enderman" then
damage_groups={fleshy=self._damage}, obj:punch(self.object, 1.0, {
}, nil) full_punch_interval=1.0,
damage_groups={fleshy=self._damage},
}, nil)
end
else
obj:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self._damage},
}, nil)
end
if is_player then if is_player then
if self._shooter and self._shooter:is_player() then if self._shooter and self._shooter:is_player() then

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B