mobs-redo #2

Merged
SumianVoice merged 457 commits from VoxeLibre/VoxeLibre:mobs-redo into mobs-redo 2022-07-20 00:23:43 +02:00
349 changed files with 7352 additions and 1288 deletions

2
API.md
View File

@ -42,7 +42,7 @@ A lot of things are possible by using one of the APIs in the mods. Note that not
* Buckets: `ITEMS/mcl_buckets`
* Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
## Mobs
### Mobs
* Mobs: `ENTITIES/mcl_mobs`
MineClone 2 uses its own mobs framework, called “Mobs Redo: MineClone 2 Edition” or “MRM” for short.

View File

@ -27,6 +27,10 @@
* Code-Sploit
* NO11
* kabou
* rudzik8
* chmodsayshello
* PrarieWind
* RandomLegoBrick
## Contributors
* Laurent Rocher
@ -71,6 +75,10 @@
* Sven792
* aldum
* Dieter44
* Pepebotella
* MrRar
* Lazerbeak12345
* mrminer
## MineClone5
* kay27
@ -78,10 +86,12 @@
* epCode
* NO11
* j45
* chmodsayshello
* 3raven
* PrarieWind
* Gustavo1
* CableGuy67
* MrRar
## Mineclonia
* erlehmann
@ -134,6 +144,9 @@
* yutyo
* NO11
* kay27
* MysticTempest
* RandomLegoBrick
* cora
## Translations
* Wuzzy
@ -143,6 +156,8 @@
* pitchum
* todoporlalibertad
* Marcin Serwin
* Pepebotella
* Emojigit
## Funders
* 40W
@ -150,5 +165,6 @@
## Special thanks
* celeron55 for creating Minetest
* Jordach for the jukebox music compilation from Big Freaking Dig
* wsor for working tirelessly in the shadows for the good of all of us, particularly helping with solving contentDB and copyright issues.
* The workaholics who spent way too much time writing for the Minecraft Wiki. It's an invaluable resource for creating this game
* Notch and Jeb for being the major forces behind Minecraft

View File

@ -2,7 +2,7 @@
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB.
Version: 0.75 (in development)
Version: 0.78 (in development)
### Gameplay
You start in a randomly-generated world made entirely of cubes. You can explore
@ -91,11 +91,11 @@ The MineClone2 repository is hosted at Mesehub. To contribute or report issues,
## Target
- Crucially, create a stable, moddable, free/libre clone of Minecraft
based on the Minetest engine with polished features, usable in both
singleplayer and multiplayer. Currently, most of **Minecraft Java
Edition 1.12.2** features are already implemented and polishing existing
singleplayer and multiplayer. Currently, a lot of **Minecraft Java
Edition** features are already implemented and polishing existing
features are prioritized over new feature requests.
- With lessened priority yet strictly, implement features targetting
**Minecraft version 1.17 + OptiFine** (OptiFine only as far as supported
**Current Minecraft versions + OptiFine** (OptiFine only as far as supported
by the Minetest Engine). This means features in parity with the listed
Minecraft experiences are prioritized over those that don't fulfill this
scope.
@ -108,8 +108,7 @@ playerbase on low spec computers, optimizations are hard to investigate.
This game is currently in **beta** stage.
It is playable, but not yet feature-complete.
Backwards-compability is not entirely guaranteed, updating your world might cause small bugs.
If you want to use the git version of MineClone2 in production, consider using the production branch.
It is updated weekly and contains relatively stable code for servers.
If you want to use the development version of MineClone2 in production, the master branch is usually relatively stable. The testing branch often features some experimental PRs and should be considered less stable.
The following main features are available:
@ -124,7 +123,7 @@ The following main features are available:
* Most blocks in the overworld
* Water and lava
* Weather
* 28 biomes
* 28 biomes + 5 Nether Biomes
* The Nether, a fiery underworld in another dimension
* Redstone circuits (partially)
* Minecarts (partial)
@ -162,7 +161,7 @@ The following features are incomplete:
* Special minecarts
* A couple of non-trivial blocks and items
Bonus features (not found in Minecraft 1.12):
Bonus features (not found in Minecraft):
* Built-in crafting guide which shows you crafting and smelting recipes
* In-game help system containing extensive help about gameplay basics, blocks, items and more
@ -175,6 +174,9 @@ Bonus features (not found in Minecraft 1.12):
* Nether Brick Fence Gate
* Red Nether Brick Fence
* Red Nether Brick Fence Gate
* Structure replacements - these small variants of Minecraft structures serve as replacements until we can get large structures working:
* Woodland Cabin (Mansions)
* Nether Outpost (Fortress)
Technical differences from Minecraft:

View File

@ -1,2 +1,2 @@
name = MineClone 2
title = MineClone 2
description = A survival sandbox game. Survive, gather, hunt, build, explore, and do much more.

View File

@ -110,9 +110,11 @@ end
local boat = {
physical = true,
pointable = true,
-- Warning: Do not change the position of the collisionbox top surface,
-- lowering it causes the boat to fall through the world if underwater
collisionbox = {-0.5, -0.35, -0.5, 0.5, 0.3, 0.5},
selectionbox = {-0.7, -0.35, -0.7, 0.7, 0.3, 0.7},
visual = "mesh",
mesh = "mcl_boats_boat.b3d",
textures = {"mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png"},

View File

@ -134,6 +134,7 @@ function mcl_burning.set_on_fire(obj, burn_time)
end
function mcl_burning.extinguish(obj)
if not obj:get_pos() then return end
if mcl_burning.is_burning(obj) then
local storage = mcl_burning.get_storage(obj)
if obj:is_player() then

View File

@ -1,66 +1,55 @@
-- Dripping Water Mod
-- by kddekadenz
local math = math
-- License of code, textures & sounds: CC0
local function register_drop(liquid, glow, sound, nodes)
minetest.register_entity("mcl_dripping:drop_" .. liquid, {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.01, 0.01, -0.01, 0.01, 0.01, 0.01},
glow = glow,
pointable = false,
visual = "sprite",
visual_size = {x = 0.1, y = 0.1},
textures = {""},
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
static_save = false,
_dropped = false,
on_activate = function(self)
self.object:set_properties({
textures = {"[combine:2x2:" .. -math.random(1, 16) .. "," .. -math.random(1, 16) .. "=default_" .. liquid .. "_source_animated.png"}
})
end,
on_step = function(self, dtime)
local k = math.random(1, 222)
local ownpos = self.object:get_pos()
if k == 1 then
self.object:set_acceleration(vector.new(0, -5, 0))
end
if minetest.get_node(vector.offset(ownpos, 0, 0.5, 0)).name == "air" then
self.object:set_acceleration(vector.new(0, -5, 0))
end
if minetest.get_node(vector.offset(ownpos, 0, -0.1, 0)).name ~= "air" then
local ent = self.object:get_luaentity()
if not ent._dropped then
ent._dropped = true
minetest.sound_play({name = "drippingwater_" .. sound .. "drip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
end
if k < 3 then
self.object:remove()
end
end
end,
})
local math = math
local function make_drop(pos,liquid,sound,interval)
local pt = {
velocity = vector.new(0,0,0),
collision_removal = false,
}
local t = math.random() + math.random(1, interval)
minetest.after(t,function()
local x, z = math.random(-45, 45) / 100, math.random(-45, 45) / 100
pt.pos = vector.offset(pos,x,-0.52,z)
pt.acceleration = vector.new(0,0,0)
pt.collisiondetection = false
pt.expirationtime = t
pt.texture="[combine:2x2:" .. -math.random(1, 16) .. "," .. -math.random(1, 16) .. "=default_" .. liquid .. "_source_animated.png"
minetest.add_particle(pt)
minetest.after(t,function()
pt.acceleration = vector.new(0,-5,0)
pt.collisiondetection = true
pt.expirationtime = math.random() + math.random(1, interval/2)
minetest.add_particle(pt)
minetest.sound_play({name = "drippingwater_" .. sound .. "drip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
end)
end)
end
local function register_drop(liquid, glow, sound, nodes, interval, chance)
minetest.register_abm({
label = "Create drops",
nodenames = nodes,
neighbors = {"group:" .. liquid},
interval = 2,
chance = 22,
interval = interval,
chance = chance,
action = function(pos)
if minetest.get_item_group(minetest.get_node(vector.offset(pos, 0, 1, 0)).name, liquid) ~= 0
and minetest.get_node(vector.offset(pos, 0, -1, 0)).name == "air" then
local x, z = math.random(-45, 45) / 100, math.random(-45, 45) / 100
minetest.add_entity(vector.offset(pos, x, -0.520, z), "mcl_dripping:drop_" .. liquid)
local r = math.ceil(interval / 20)
local nn=minetest.find_nodes_in_area(vector.offset(pos,-r,0,-r),vector.offset(pos,r,0,r),nodes)
--start a bunch of particle cycles to be able to get away
--with longer abm cycles
table.shuffle(nn)
for i=1,math.random(#nn) do
if minetest.get_item_group(minetest.get_node(vector.offset(nn[i], 0, 1, 0)).name, liquid) ~= 0
and minetest.get_node(vector.offset(nn[i], 0, -1, 0)).name == "air" then
make_drop(nn[i],liquid,sound,interval)
end
end
end,
})
end
register_drop("water", 1, "", {"group:opaque", "group:leaves"})
register_drop("lava", math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3), "lava", {"group:opaque"})
register_drop("water", 1, "", {"group:opaque", "group:leaves"},60,10)
register_drop("lava", math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3), "lava", {"group:opaque"},60,10)

View File

@ -59,6 +59,8 @@ mcl_item_entity.register_pickup_achievement("tree", "mcl:mineWood")
mcl_item_entity.register_pickup_achievement("mcl_mobitems:blaze_rod", "mcl:blazeRod")
mcl_item_entity.register_pickup_achievement("mcl_mobitems:leather", "mcl:killCow")
mcl_item_entity.register_pickup_achievement("mcl_core:diamond", "mcl:diamonds")
mcl_item_entity.register_pickup_achievement("mcl_core:crying_obsidian", "mcl:whosCuttingOnions")
mcl_item_entity.register_pickup_achievement("mcl_nether:ancient_debris", "mcl:hiddenInTheDepths")
local function check_pickup_achievements(object, player)
if has_awards then
@ -78,7 +80,6 @@ local function enable_physics(object, luaentity, ignore_check)
object:set_properties({
physical = true
})
object:set_velocity({x=0,y=0,z=0})
object:set_acceleration({x=0,y=-get_gravity(),z=0})
end
end
@ -536,9 +537,9 @@ minetest.register_entity(":__builtin:item", {
self.itemstring = data.itemstring
self.always_collect = data.always_collect
if data.age then
self.age = data.age + dtime_s
self.age = data.age
else
self.age = dtime_s
self.age = self.age
end
--remember collection data
-- If true, can collect item without delay
@ -774,8 +775,8 @@ minetest.register_entity(":__builtin:item", {
return
end
-- Move item around on flowing liquids
if def and def.liquidtype == "flowing" then
-- Move item around on flowing liquids; add 'source' check to allow items to continue flowing a bit in the source block of flowing water.
if def and def.liquidtype == "flowing" or def.liquidtype == "source" then
--[[ Get flowing direction (function call from flowlib), if there's a liquid.
NOTE: According to Qwertymine, flowlib.quickflow is only reliable for liquids with a flowing distance of 7.
@ -784,11 +785,11 @@ minetest.register_entity(":__builtin:item", {
-- Just to make sure we don't manipulate the speed for no reason
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
-- Minecraft Wiki: Flowing speed is "about 1.39 meters per second"
local f = 1.39
local f = 1.2
-- Set new item moving speed into the direciton of the liquid
local newv = vector.multiply(vec, f)
self.object:set_acceleration({x = 0, y = 0, z = 0})
self.object:set_velocity({x = newv.x, y = -0.22, z = newv.z})
-- Swap to acceleration instead of a static speed to better mimic MC mechanics.
self.object:set_acceleration({x = newv.x, y = -0.22, z = newv.z})
self.physical_state = true
self._flowing = true
@ -808,7 +809,7 @@ minetest.register_entity(":__builtin:item", {
local nn = minetest.get_node({x=p.x, y=p.y-0.5, z=p.z}).name
local v = self.object:get_velocity()
if not minetest.registered_nodes[nn] or minetest.registered_nodes[nn].walkable and v.y == 0 then
if not minetest.registered_nodes[nn] or minetest.registered_nodes[nn].walkable and not minetest.registered_nodes[nn].groups.slippery and v.y == 0 then
if self.physical_state then
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
-- Merge with close entities of the same item

View File

@ -21,7 +21,7 @@ local function register_rail(itemstring, tiles, def_extras, creative)
stack_max = 64,
groups = groups,
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 3.5,
_mcl_blast_resistance = 0.7,
_mcl_hardness = 0.7,
after_destruct = function(pos)
-- Scan for minecarts in this pos and force them to execute their "floating" check.

View File

@ -91,7 +91,7 @@ minetest.register_chatcommand("clearmobs",{
if o.is_mob then
if param == "all" or
( param == "nametagged" and o.nametag ) or
( param == "" and not o.nametag and not o.tamed ) or
( param == "" and ( not o.nametag or o.nametag == "" ) and not o.tamed ) or
( num and num > 0 and vector.distance(p:get_pos(),o.object:get_pos()) <= num ) then
o.object:remove()
end
@ -298,9 +298,13 @@ local function update_roll(self)
if is_Fleckenstein then
cbox[2], cbox[5] = -cbox[5], -cbox[2]
self.object:set_properties({collisionbox = cbox})
-- This leads to child mobs having the wrong collisionbox
-- and seeing as it seems to be nothing but an easter egg
-- i've put it inside the if. Which just makes it be upside
-- down lol.
end
self.object:set_properties({collisionbox = cbox})
end
-- set and return valid yaw
@ -363,6 +367,35 @@ local remove_texture_mod = function(self, mod)
self.object:set_texture_mod(full_mod)
end
-- are we flying in what we are suppose to? (taikedz)
local flight_check = function(self)
local nod = self.standing_in
local def = minetest.registered_nodes[nod]
if not def then return false end -- nil check
local fly_in
if type(self.fly_in) == "string" then
fly_in = { self.fly_in }
elseif type(self.fly_in) == "table" then
fly_in = self.fly_in
else
return false
end
for _,checknode in pairs(fly_in) do
if nod == checknode then
return true
elseif checknode == "__airlike" or def.walkable == false and
(def.liquidtype == "none" or minetest.get_item_group(nod, "fake_liquid") == 1) then
return true
end
end
return false
end
-- set defined animation
local set_animation = function(self, anim, fixed_frame)
if not self.animation or not anim then
@ -372,6 +405,8 @@ local set_animation = function(self, anim, fixed_frame)
return
end
if flight_check(self) and self.fly and anim == "walk" then anim = "fly" end
self.animation.current = self.animation.current or ""
if (anim == self.animation.current
@ -513,37 +548,6 @@ local line_of_sight = function(self, pos1, pos2, stepsize)
return false
end
-- are we flying in what we are suppose to? (taikedz)
local flight_check = function(self)
local nod = self.standing_in
local def = minetest.registered_nodes[nod]
if not def then return false end -- nil check
local fly_in
if type(self.fly_in) == "string" then
fly_in = { self.fly_in }
elseif type(self.fly_in) == "table" then
fly_in = self.fly_in
else
return false
end
for _,checknode in pairs(fly_in) do
if nod == checknode then
return true
elseif checknode == "__airlike" and def.walkable == false and
(def.liquidtype == "none" or minetest.get_item_group(nod, "fake_liquid") == 1) then
return true
end
end
return false
end
-- custom particle effects
local effect = function(pos, amount, texture, min_size, max_size, radius, gravity, glow, go_down)
@ -1901,13 +1905,11 @@ local specific_attack = function(list, what)
return false
end
-- monster find someone to attack
-- find someone to attack
local monster_attack = function(self)
if self.type ~= "monster"
or not damage_enabled
if not damage_enabled
or minetest.is_creative_enabled("")
or self.passive
or self.passive ~= false
or self.state == "attack"
or day_docile(self) then
return
@ -1923,10 +1925,9 @@ local monster_attack = function(self)
for n = 1, #objs do
if objs[n]:is_player() then
if mcl_mobs.invis[ objs[n]:get_player_name() ] or (not object_in_range(self, objs[n])) then
type = ""
else
elseif (self.type == "monster" or self._aggro) then
player = objs[n]
type = "player"
name = "player"
@ -2283,6 +2284,9 @@ end
local function go_to_pos(entity,b)
if not entity then return end
local s=entity.object:get_pos()
if not b then
--self.state = "stand"
return end
if vector.distance(b,s) < 1 then
--set_velocity(entity,0)
return true
@ -2305,15 +2309,52 @@ local function check_doors(self)
local def = minetest.registered_nodes[n.name]
local closed = n.name:find("_b_1")
if t < 0.3 or t > 0.8 then
if not closed then def.on_rightclick(d,n,self) end
if not closed and def.on_rightclick then def.on_rightclick(d,n,self) end
else
if closed then def.on_rightclick(d,n,self) end
if closed and def.on_rightclick then def.on_rightclick(d,n,self) end
end
end
end
end
local gowp_etime = 0
local function check_gowp(self,dtime)
gowp_etime = gowp_etime + dtime
if gowp_etime < 0.2 then return end
gowp_etime = 0
local p = self.object:get_pos()
if not p or not self._target then return end
if vector.distance(p,self._target) < 1 then
self.waypoints = nil
self._target = nil
self.current_target = nil
self.state = "stand"
if self.callback_arrived then return self.callback_arrived(self) end
return true
end
if self.waypoints and ( not self.current_target or vector.distance(p,self.current_target) < 2 ) then
self.current_target = table.remove(self.waypoints, 1)
--minetest.log("nextwp:".. tostring(self.current_target) )
go_to_pos(self,self.current_target)
return
elseif self.current_target then
go_to_pos(self,self.current_target)
end
if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then
self.waypoints=minetest.find_path(p,self._target,150,1,4)
if not self.waypoints then self.state = "walk" end --give up
self.current_target = nil
return
end
if not self.current_target then
--minetest.log("no path")
self.state = "walk"
end
end
-- execute current state (stand, walk, run, attacks)
-- returns true if mob has died
local do_states = function(self, dtime)
@ -2326,9 +2367,8 @@ local do_states = function(self, dtime)
local s = self.object:get_pos()
local objs = minetest.get_objects_inside_radius(s, 3)
local lp
for n = 1, #objs do
if objs[n]:is_player() then
lp = objs[n]:get_pos()
break
@ -2336,7 +2376,7 @@ local do_states = function(self, dtime)
end
-- look at any players nearby, otherwise turn randomly
if self.look_at_players then
if lp and self.look_at_players then
local vec = {
x = lp.x - s.x,
@ -2372,32 +2412,7 @@ local do_states = function(self, dtime)
end
elseif self.state == "gowp" then
local p = self.object:get_pos()
if not p or not self._target then return end
if vector.distance(p,self._target) < 2 or ( self.waypoints and #self.waypoints == 0 ) then
self.waypoints = nil
self._target = nil
self.current_target = nil
self.state = "walk"
if self.callback_arrived then return self.callback_arrived(self) end
return true
end
if self.waypoints and ( not self.current_target or vector.distance(p,self.current_target) < 1.5 ) then
self.current_target = table.remove(self.waypoints, 1)
--minetest.log("nextwp:".. tostring(self.current_target) )
elseif self.current_target then
go_to_pos(self,self.current_target)
end
if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then
self.waypoints=minetest.find_path(p,self._target,150,1,4)
self.current_target = nil
return
end
if not self.current_target then
--minetest.log("no path")
self.state = "walk"
end
check_gowp(self,dtime)
elseif self.state == "walk" then
local s = self.object:get_pos()
@ -2908,7 +2923,12 @@ local plane_adjacents = {
vector.new(0,0,-1),
}
local gopath_last = os.time()
function mcl_mobs:gopath(self,target,callback_arrived)
if os.time() - gopath_last < 15 then return end
gopath_last = os.time()
--minetest.log("gowp")
local p = self.object:get_pos()
local t = vector.offset(target,0,1,0)
local wp = minetest.find_path(p,t,150,1,4)
@ -2928,11 +2948,15 @@ function mcl_mobs:gopath(self,target,callback_arrived)
if wp and #wp > 0 then
self._target = t
self.callback_arrived = callback_arrived
table.remove(wp,1)
self.waypoints = wp
self.state = "gowp"
return true
else
--minetest.log("no path found")
self.state = "walk"
self.waypoints = nil
self.current_target = nil
-- minetest.log("no path found")
end
end
@ -2964,7 +2988,7 @@ local function damage_mob(self,reason,damage)
if damage > 0 then
self.health = self.health - damage
effect(pos, 5, "mcl_particles_smoke.png", 1, 2, 2, nil)
effect(self.object:get_pos(), 5, "mcl_particles_smoke.png", 1, 2, 2, nil)
if check_for_death(self, reason, {type = reason}) then
return true
@ -3210,35 +3234,36 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
local die = false
-- 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
-- weapon sounds
if weapon:get_definition().sounds ~= nil then
if damage >= 0 then
-- 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
-- weapon sounds
if weapon:get_definition().sounds ~= nil then
local s = random(0, #weapon:get_definition().sounds)
local s = random(0, #weapon:get_definition().sounds)
minetest.sound_play(weapon:get_definition().sounds[s], {
object = self.object, --hitter,
max_hear_distance = 8
}, true)
else
minetest.sound_play("default_punch", {
object = self.object,
max_hear_distance = 5
}, true)
minetest.sound_play(weapon:get_definition().sounds[s], {
object = self.object, --hitter,
max_hear_distance = 8
}, true)
else
minetest.sound_play("default_punch", {
object = self.object,
max_hear_distance = 5
}, true)
end
damage_effect(self, damage)
-- do damage
self.health = self.health - damage
-- skip future functions if dead, except alerting others
if check_for_death(self, "hit", {type = "punch", puncher = hitter}) then
die = true
end
end
damage_effect(self, damage)
-- do damage
self.health = self.health - damage
-- skip future functions if dead, except alerting others
if check_for_death(self, "hit", {type = "punch", puncher = hitter}) then
die = true
end
-- knock back effect (only on full punch)
if not die
and self.knock_back
@ -3318,11 +3343,11 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
and (self.child == false or self.type == "monster")
and hitter:get_player_name() ~= self.owner
and not mcl_mobs.invis[ name ] then
if not die then
-- attack whoever punched mob
self.state = ""
do_attack(self, hitter)
self._aggro= true
end
-- alert others to the attack
@ -3334,7 +3359,6 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
obj = objs[n]:get_luaentity()
if obj then
-- only alert members of same mob or friends
if obj.group_attack
and obj.state ~= "attack"
@ -3344,6 +3368,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
elseif type(obj.group_attack) == "table" then
for i=1, #obj.group_attack do
if obj.name == obj.group_attack[i] then
obj._aggro = true
do_attack(obj, hitter)
break
end
@ -3570,10 +3595,23 @@ local mob_activate = function(self, staticdata, def, dtime)
end
end
local function check_aggro(self,dtime)
if not self._aggro or not self.attack then return end
if not self._check_aggro_timer or self._check_aggro_timer > 5 then
self._check_aggro_timer = 0
if not self.attack:get_pos() or vector.distance(self.attack:get_pos(),self.object:get_pos()) > 128 then
self._aggro = nil
self.attack = nil
self.state = "stand"
end
end
self._check_aggro_timer = self._check_aggro_timer + dtime
end
-- main mob function
local mob_step = function(self, dtime)
check_item_pickup(self)
check_aggro(self,dtime)
if not self.fire_resistant then
mcl_burning.tick(self.object, dtime, self)
end
@ -3904,7 +3942,7 @@ minetest.register_entity(name, {
xp_max = def.xp_max or 0,
xp_timestamp = 0,
breath_max = def.breath_max or 15,
breathes_in_water = def.breathes_in_water or false,
breathes_in_water = def.breathes_in_water or false,
physical = true,
collisionbox = collisionbox,
selectionbox = def.selectionbox or def.collisionbox,
@ -4008,6 +4046,8 @@ minetest.register_entity(name, {
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,
spawn_in_group = def.spawn_in_group,
spawn_in_group_min = def.spawn_in_group_min,
-- End of MCL2 extensions
on_spawn = def.on_spawn,
@ -4333,77 +4373,74 @@ end
-- feeding, taming and breeding (thanks blert2112)
function mcl_mobs:feed_tame(self, clicker, feed_count, breed, tame)
function mcl_mobs:feed_tame(self, clicker, feed_count, breed, tame, notake)
if not self.follow then
return false
end
-- can eat/tame with item in hand
if self.nofollow or follow_holding(self, clicker) then
local consume_food = false
-- if not in creative then take item
if not minetest.is_creative_enabled(clicker:get_player_name()) then
-- tame if not still a baby
local item = clicker:get_wielded_item()
item:take_item()
clicker:set_wielded_item(item)
if tame and not self.child then
if not self.owner or self.owner == "" then
self.tamed = true
self.owner = clicker:get_player_name()
consume_food = true
end
end
mob_sound(self, "eat", nil, true)
-- increase health
self.health = self.health + 4
if self.health >= self.hp_max then
self.health = self.hp_max
if self.health < self.hp_max and not consume_food then
consume_food = true
self.health = min(self.health + 4, self.hp_max)
if self.htimer < 1 then
self.htimer = 5
end
self.object:set_hp(self.health)
end
self.object:set_hp(self.health)
-- make children grow quicker
if not consume_food and self.child == true then
consume_food = true
-- deduct 10% of the time to adulthood
self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1)
end
-- breed animals
if breed and not consume_food and self.hornytimer == 0 and not self.horny then
self.food = (self.food or 0) + 1
consume_food = true
if self.food >= feed_count then
self.food = 0
self.horny = true
end
end
update_tag(self)
-- make children grow quicker
if self.child == true then
-- if not in creative then take item if it was used
if not minetest.is_creative_enabled(clicker:get_player_name()) and consume_food then
-- deduct 10% of the time to adulthood
self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1)
local item = clicker:get_wielded_item()
return true
end
-- feed and tame
self.food = (self.food or 0) + 1
if self.food >= feed_count then
self.food = 0
if breed and self.hornytimer == 0 then
self.horny = true
end
if tame then
self.tamed = true
if not self.owner or self.owner == "" then
self.owner = clicker:get_player_name()
end
if not notake then
item:take_item()
mob_sound(self, "eat", nil, true)
end
clicker:set_wielded_item(item)
else
-- make sound when fed so many times
mob_sound(self, "random", true)
end
return true
end
return false
end

View File

@ -15,7 +15,7 @@ local math_cos = math.cos
local math_sin = math.sin
local math_round = function(x) return (x > 0) and math_floor(x + 0.5) or math_ceil(x - 0.5) end
--local vector_distance = vector.distance
local vector_distance = vector.distance
local vector_new = vector.new
local vector_floor = vector.floor
@ -25,7 +25,15 @@ local table_remove = table.remove
local pairs = pairs
-- range for mob count
local aoc_range = 32
local aoc_range = 136
local mob_cap = {
monster = 70,
animal =10,
ambient =15,
water = 5, --currently unused
water_ambient = 20, --currently unused
}
--do mobs spawn?
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
@ -153,6 +161,10 @@ local list_of_all_biomes = {
-- dimension biome:
"Nether",
"BasaltDelta",
"CrimsonForest",
"WarpedForest",
"SoulsandValley",
"End",
-- Overworld regular:
@ -162,6 +174,8 @@ local list_of_all_biomes = {
"Swampland",
"Taiga",
"ExtremeHills",
"ExtremeHillsM",
"ExtremeHills+_snowtop",
"Jungle",
"Savanna",
"BirchForest",
@ -180,7 +194,6 @@ local list_of_all_biomes = {
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
@ -192,11 +205,26 @@ local list_of_all_biomes = {
}
-- count how many mobs are in an area
local function count_mobs(pos)
local function count_mobs(pos,r,mob_type)
local num = 0
for _,object in pairs(get_objects_inside_radius(pos, aoc_range)) do
if object and object:get_luaentity() and object:get_luaentity().is_mob then
num = num + 1
for _,l in pairs(minetest.luaentities) do
if l and l.is_mob and (mob_type == nil or l.type == mob_type) then
local p = l.object:get_pos()
if p and vector_distance(p,pos) < r then
num = num + 1
end
end
end
return num
end
local function count_mobs_total(mob_type)
local num = 0
for _,l in pairs(minetest.luaentities) do
if l.is_mob then
if mob_type == nil or l.type == mob_type then
num = num + 1
end
end
end
return num
@ -289,7 +317,7 @@ function mcl_mobs:spawn_setup(def)
spawn_dictionary[#spawn_dictionary + 1] = {
name = name,
dimension = dimension,
type_of_spawning = type_of_spawning,
type_of_spawning = type_of_spawning,
biomes = biomes,
min_light = min_light,
max_light = max_light,
@ -376,11 +404,52 @@ local function is_farm_animal(n)
return n == "mobs_mc:pig" or n == "mobs_mc:cow" or n == "mobs_mc:sheep" or n == "mobs_mc:chicken" or n == "mobs_mc:horse" or n == "mobs_mc:donkey"
end
local function get_water_spawn(p)
local nn = minetest.find_nodes_in_area(vector.offset(p,-2,-1,-2),vector.offset(p,2,-15,2),{"group:water"})
if nn and #nn > 0 then
return nn[math.random(#nn)]
end
end
local dbg_spawn_attempts = 0
local dbg_spawn_succ = 0
local function spawn_group(p,mob,spawn_on,group_max,group_min)
if not group_min then group_min = 1 end
local nn= minetest.find_nodes_in_area_under_air(vector.offset(p,-5,-3,-5),vector.offset(p,5,3,5),spawn_on)
local o
if not nn or #nn < 1 then
nn = {}
table.insert(nn,p)
end
for i = 1, math.random(group_min,group_max) do
local sp = vector.offset(nn[math.random(#nn)],0,1,0)
if mob.type_of_spawning == "water" then
sp = get_water_spawn(sp)
end
o = minetest.add_entity(sp,mob.name)
if o then dbg_spawn_succ = dbg_spawn_succ + 1 end
end
return o
end
minetest.register_chatcommand("mobstats",{
privs = { debug = true },
func = function(n,param)
local pos = minetest.get_player_by_name(n):get_pos()
minetest.chat_send_player(n,"mobs within 32 radius of player:"..count_mobs(pos,32))
minetest.chat_send_player(n,"total mobs:"..count_mobs_total())
minetest.chat_send_player(n,"spawning attempts since server start:"..dbg_spawn_attempts)
minetest.chat_send_player(n,"successful spawns since server start:"..dbg_spawn_succ)
end
})
if mobs_spawn then
local perlin_noise
local function spawn_a_mob(pos, dimension, y_min, y_max)
dbg_spawn_attempts = dbg_spawn_attempts + 1
local dimension = dimension or mcl_worlds.pos_to_dimension(pos)
local goal_pos = get_next_mob_spawn_pos(pos)
local spawning_position_list = find_nodes_in_area_under_air(
@ -391,9 +460,6 @@ if mobs_spawn then
if #spawning_position_list <= 0 then return end
local spawning_position = spawning_position_list[math_random(1, #spawning_position_list)]
--hard code mob limit in area to 5 for now
if count_mobs(spawning_position) >= 5 then return end
local gotten_node = get_node(spawning_position).name
local gotten_biome = minetest.get_biome_data(spawning_position)
if not gotten_node or not gotten_biome then return end
@ -407,6 +473,8 @@ if mobs_spawn then
local is_water = get_item_group(gotten_node, "water") ~= 0
local is_lava = get_item_group(gotten_node, "lava") ~= 0
local is_leaf = get_item_group(gotten_node, "leaves") ~= 0
local is_bedrock = gotten_node == "mcl_core:bedrock"
local is_ground = not (is_water or is_lava)
local is_grass = minetest.get_item_group(gotten_node,"grass_block") ~= 0
local has_bed = minetest.find_node_near(pos,25,{"group:bed"})
@ -426,6 +494,7 @@ if mobs_spawn then
perlin_noise = perlin_noise or minetest_get_perlin(noise_params)
local noise = perlin_noise:get_3d(spawning_position)
local current_summary_chance = summary_chance
table.shuffle(mob_library_worker_table)
while #mob_library_worker_table > 0 do
local mob_chance_offset = (math_round(noise * current_summary_chance + 12345) % current_summary_chance) + 1
local mob_index = 1
@ -438,7 +507,12 @@ if mobs_spawn then
end
local mob_def = mob_library_worker_table[mob_index]
local mob_type = minetest.registered_entities[mob_def.name].type
local spawn_in_group = minetest.registered_entities[mob_def.name].spawn_in_group or 4
local mob_count_wide = count_mobs(pos,aoc_range,mob_type)
local mob_count = count_mobs(spawning_position,32,mob_type)
if mob_def
and mob_count_wide < (mob_cap[mob_type] or 15)
and mob_count < 5
and spawning_position.y >= mob_def.min_height
and spawning_position.y <= mob_def.max_height
and mob_def.dimension == dimension
@ -446,14 +520,29 @@ if mobs_spawn then
and gotten_light >= mob_def.min_light
and gotten_light <= mob_def.max_light
and (is_ground or mob_def.type_of_spawning ~= "ground")
and (mob_def.type_of_spawning ~= "ground" or not is_leaf)
and (mob_def.check_position and mob_def.check_position(spawning_position) or true)
and (not is_farm_animal(mob_def.name) or is_grass)
and (mob_type ~= "npc" or has_bed)
and (mob_def.type_of_spawning ~= "water" or is_water)
and not is_bedrock
then
if mob_def.type_of_spawning == "water" then
spawning_position = get_water_spawn(spawning_position)
if not spawning_position then
return
end
end
--everything is correct, spawn mob
local object = minetest.add_entity(spawning_position, mob_def.name)
local object
if spawn_in_group then
object = spawn_group(spawning_position,mob_def,{gotten_node},spawn_in_group,spawn_in_group_min)
else object = minetest.add_entity(spawning_position, mob_def.name)
end
if object then
return mob_def.on_spawn and mob_def.on_spawn(object, pos)
return mob_def.on_spawn and mob_def.on_spawn(object, spawning_position)
end
end
current_summary_chance = current_summary_chance - mob_chance

View File

@ -46,6 +46,9 @@ end
local wither_head = minetest.registered_nodes["mcl_heads:wither_skeleton"]
local old_on_place = wither_head.on_place
function wither_head.on_place(itemstack, placer, pointed)
minetest.after(0, wither_spawn, pointed.above)
old_on_place(itemstack, placer, pointed)
local n = minetest.get_node(vector.offset(pointed.above,0,-1,0))
if n and n.name == "mcl_nether:soul_sand" then
minetest.after(0, wither_spawn, pointed.above)
end
return old_on_place(itemstack, placer, pointed)
end

View File

@ -7,6 +7,7 @@ mcl_mobs:register_mob("mobs_mc:bat", {
type = "animal",
spawn_class = "ambient",
can_despawn = true,
spawn_in_group = 8,
passive = true,
hp_min = 6,
hp_max = 6,

View File

@ -16,6 +16,8 @@ mcl_mobs:register_mob("mobs_mc:blaze", {
description = S("Blaze"),
type = "monster",
spawn_class = "hostile",
spawn_in_group_min = 2,
spawn_in_group = 3,
hp_min = 20,
hp_max = 20,
xp_min = 10,

View File

@ -74,7 +74,7 @@ mcl_mobs:register_mob("mobs_mc:chicken", {
fear_height = 4,
on_rightclick = function(self, clicker)
if mcl_mobs:feed_tame(self, clicker, 1, true, true) then return end
if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
if mcl_mobs:protect(self, clicker) then return end
if mcl_mobs:capture_mob(self, clicker, 0, 60, 5, false, nil) then return end
end,
@ -122,8 +122,6 @@ mcl_mobs:spawn_specific(
"ExtremeHills_beach",
"ExtremeHillsM",
"ExtremeHills+",
"ExtremeHills+_snowtop",
"StoneBeach",
"Plains",
"Plains_beach",
"SunflowerPlains",

View File

@ -0,0 +1,274 @@
--MCmobs v0.4
--maikerumine
--made for MC like Survival game
--License for code WTFPL and otherwise stated in readmes
local pi = math.pi
local atann = math.atan
local atan = function(x)
if not x or x ~= x then
return 0
else
return atann(x)
end
end
local dir_to_pitch = function(dir)
local dir2 = vector.normalize(dir)
local xz = math.abs(dir.x) + math.abs(dir.z)
return -math.atan2(-dir.y, xz)
end
local function degrees(rad)
return rad * 180.0 / math.pi
end
local S = minetest.get_translator(minetest.get_current_modname())
--###################
--################### cod
--###################
local cod = {
type = "animal",
spawn_class = "water",
can_despawn = true,
passive = true,
hp_min = 3,
hp_max = 3,
xp_min = 1,
xp_max = 3,
armor = 100,
rotate = 180,
spawn_in_group_min = 3,
spawn_in_group = 8,
tilt_swim = true,
collisionbox = {-0.3, 0.0, -0.3, 0.3, 0.79, 0.3},
visual = "mesh",
mesh = "extra_mobs_cod.b3d",
textures = {
{"extra_mobs_cod.png"}
},
sounds = {
},
animation = {
stand_start = 1,
stand_end = 20,
walk_start = 1,
walk_end = 20,
run_start = 1,
run_end = 20,
},
drops = {
{name = "mcl_fishing:fish_raw",
chance = 1,
min = 1,
max = 1,},
{name = "mcl_dye:white",
chance = 20,
min = 1,
max = 1,},
},
visual_size = {x=3, y=3},
makes_footstep_sound = false,
fly = true,
fly_in = { "mcl_core:water_source", "mclx_core:river_water_source" },
breathes_in_water = true,
jump = false,
view_range = 16,
runaway = true,
fear_height = 4,
do_custom = function(self)
--[[ this is supposed to make them jump out the water but doesn't appear to work very well
self.object:set_bone_position("body", vector.new(0,1,0), vector.new(degrees(dir_to_pitch(self.object:get_velocity())) * -1 + 90,0,0))
if minetest.get_item_group(self.standing_in, "water") ~= 0 then
if self.object:get_velocity().y < 5 then
self.object:add_velocity({ x = 0 , y = math.random(-.007, .007), z = 0 })
end
end
--]]
for _,object in pairs(minetest.get_objects_inside_radius(self.object:get_pos(), 10)) do
local lp = object:get_pos()
local s = self.object:get_pos()
local vec = {
x = lp.x - s.x,
y = lp.y - s.y,
z = lp.z - s.z
}
if object and not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "mobs_mc:cod" then
self.state = "runaway"
self.object:set_rotation({x=0,y=(atan(vec.z / vec.x) + 3 * pi / 2) - self.rotate,z=0})
end
end
end,
on_rightclick = function(self, clicker)
if clicker:get_wielded_item():get_name() == "mcl_buckets:bucket_water" then
self.object:remove()
clicker:set_wielded_item("mcl_fishing:bucket_cod")
awards.unlock(clicker:get_player_name(), "mcl:tacticalFishing")
end
end
}
mcl_mobs:register_mob("mobs_mc:cod", cod)
--spawning TODO: in schools
local water = 0
mcl_mobs:spawn_specific(
"mobs_mc:cod",
"overworld",
"water",
{
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
"FlowerForest_beach",
"Forest_beach",
"StoneBeach",
"ColdTaiga_beach_water",
"Taiga_beach",
"Savanna_beach",
"Plains_beach",
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",
"MesaPlateauF_sandlevel",
"MesaBryce_sandlevel",
"Mesa_sandlevel",
"RoofedForest_ocean",
"JungleEdgeM_ocean",
"BirchForestM_ocean",
"BirchForest_ocean",
"IcePlains_deep_ocean",
"Jungle_deep_ocean",
"Savanna_ocean",
"MesaPlateauF_ocean",
"ExtremeHillsM_deep_ocean",
"Savanna_deep_ocean",
"SunflowerPlains_ocean",
"Swampland_deep_ocean",
"Swampland_ocean",
"MegaSpruceTaiga_deep_ocean",
"ExtremeHillsM_ocean",
"JungleEdgeM_deep_ocean",
"SunflowerPlains_deep_ocean",
"BirchForest_deep_ocean",
"IcePlainsSpikes_ocean",
"Mesa_ocean",
"StoneBeach_ocean",
"Plains_deep_ocean",
"JungleEdge_deep_ocean",
"SavannaM_deep_ocean",
"Desert_deep_ocean",
"Mesa_deep_ocean",
"ColdTaiga_deep_ocean",
"Plains_ocean",
"MesaPlateauFM_ocean",
"Forest_deep_ocean",
"JungleM_deep_ocean",
"FlowerForest_deep_ocean",
"MushroomIsland_ocean",
"MegaTaiga_ocean",
"StoneBeach_deep_ocean",
"IcePlainsSpikes_deep_ocean",
"ColdTaiga_ocean",
"SavannaM_ocean",
"MesaPlateauF_deep_ocean",
"MesaBryce_deep_ocean",
"ExtremeHills+_deep_ocean",
"ExtremeHills_ocean",
"MushroomIsland_deep_ocean",
"Forest_ocean",
"MegaTaiga_deep_ocean",
"JungleEdge_ocean",
"MesaBryce_ocean",
"MegaSpruceTaiga_ocean",
"ExtremeHills+_ocean",
"Jungle_ocean",
"RoofedForest_deep_ocean",
"IcePlains_ocean",
"FlowerForest_ocean",
"ExtremeHills_deep_ocean",
"MesaPlateauFM_deep_ocean",
"Desert_ocean",
"Taiga_ocean",
"BirchForestM_deep_ocean",
"Taiga_deep_ocean",
"JungleM_ocean",
"FlowerForest_underground",
"JungleEdge_underground",
"StoneBeach_underground",
"MesaBryce_underground",
"Mesa_underground",
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",
"ExtremeHills_underground",
"MegaSpruceTaiga_underground",
"BirchForestM_underground",
"SavannaM_underground",
"MesaPlateauFM_underground",
"Desert_underground",
"Savanna_underground",
"Forest_underground",
"SunflowerPlains_underground",
"ColdTaiga_underground",
"IcePlains_underground",
"IcePlainsSpikes_underground",
"MegaTaiga_underground",
"Taiga_underground",
"ExtremeHills+_underground",
"JungleM_underground",
"ExtremeHillsM_underground",
"JungleEdgeM_underground",
},
0,
minetest.LIGHT_MAX+1,
30,
4000,
3,
water-16,
water+1)
--spawn egg
mcl_mobs:register_egg("mobs_mc:cod", S("Cod"), "extra_mobs_spawn_icon_cod.png", 0)

View File

@ -48,7 +48,7 @@ local cow_def = {
run_end = 40,
},
on_rightclick = function(self, clicker)
if mcl_mobs:feed_tame(self, clicker, 1, true, true) then return end
if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
if mcl_mobs:protect(self, clicker) then return end
if self.child then
@ -83,9 +83,11 @@ mcl_mobs:register_mob("mobs_mc:cow", cow_def)
local mooshroom_def = table.copy(cow_def)
mooshroom_def.description = S("Mooshroom")
mooshroom_def.mesh = "mobs_mc_cow.b3d"
mooshroom_def.spawn_in_group_min = 4
mooshroom_def.spawn_in_group = 8
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)
if mcl_mobs:feed_tame(self, clicker, 1, true, true) then return end
if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
if mcl_mobs:protect(self, clicker) then return end
if self.child then
@ -151,17 +153,12 @@ mcl_mobs:spawn_specific(
"ground",
{
"flat",
"IcePlainsSpikes",
"ColdTaiga",
"ColdTaiga_beach",
"ColdTaiga_beach_water",
"MegaTaiga",
"MegaSpruceTaiga",
"ExtremeHills",
"ExtremeHills_beach",
"ExtremeHillsM",
"ExtremeHills+",
"ExtremeHills+_snowtop",
"StoneBeach",
"Plains",
"Plains_beach",

View File

@ -274,7 +274,6 @@ mcl_mobs:spawn_specific(
"Plains",
"Desert",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
@ -301,7 +300,6 @@ mcl_mobs:spawn_specific(
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",
@ -340,7 +338,6 @@ mcl_mobs:spawn_specific(
"Forest_deep_ocean",
"JungleM_deep_ocean",
"FlowerForest_deep_ocean",
"MushroomIsland_ocean",
"MegaTaiga_ocean",
"StoneBeach_deep_ocean",
"IcePlainsSpikes_deep_ocean",
@ -350,7 +347,6 @@ mcl_mobs:spawn_specific(
"MesaBryce_deep_ocean",
"ExtremeHills+_deep_ocean",
"ExtremeHills_ocean",
"MushroomIsland_deep_ocean",
"Forest_ocean",
"MegaTaiga_deep_ocean",
"JungleEdge_ocean",
@ -376,7 +372,6 @@ mcl_mobs:spawn_specific(
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",

View File

@ -0,0 +1,253 @@
--MCmobs v0.4
--maikerumine
--made for MC like Survival game
--License for code WTFPL and otherwise stated in readmes
local pi = math.pi
local atann = math.atan
local atan = function(x)
if not x or x ~= x then
return 0
else
return atann(x)
end
end
local dir_to_pitch = function(dir)
local dir2 = vector.normalize(dir)
local xz = math.abs(dir.x) + math.abs(dir.z)
return -math.atan2(-dir.y, xz)
end
local function degrees(rad)
return rad * 180.0 / math.pi
end
local S = minetest.get_translator(minetest.get_current_modname())
--###################
--################### dolphin
--###################
local dolphin = {
type = "animal",
spawn_class = "water",
can_despawn = true,
passive = true,
hp_min = 10,
hp_max = 10,
xp_min = 1,
xp_max = 3,
armor = 100,
walk_chance = 100,
breath_max = 120,
rotate = 180,
spawn_in_group_min = 3,
spawn_in_group = 5,
tilt_swim = true,
collisionbox = {-0.3, 0.0, -0.3, 0.3, 0.79, 0.3},
visual = "mesh",
mesh = "extra_mobs_dolphin.b3d",
textures = {
{"extra_mobs_dolphin.png"}
},
sounds = {
},
animation = {
stand_start = 20,
stand_end = 20,
walk_start = 0,
walk_end = 15,
run_start = 30,
run_end = 45,
},
drops = {
{name = "mcl_fishing:fish_raw",
chance = 1,
min = 0,
max = 1,},
},
visual_size = {x=3, y=3},
makes_footstep_sound = false,
fly = true,
fly_in = { "mcl_core:water_source", "mclx_core:river_water_source" },
breathes_in_water = true,
jump = false,
view_range = 16,
fear_height = 4,
walk_velocity = 3,
run_velocity = 6,
reach = 2,
damage = 2.5,
attack_type = "dogfight",
do_custom = function(self,dtime)
--[[ this is supposed to make them jump out the water but doesn't appear to work very well
self.object:set_bone_position("body", vector.new(0,1,0), vector.new(degrees(dir_to_pitch(self.object:get_velocity())) * -1 + 90,0,0))
if minetest.get_item_group(self.standing_in, "water") ~= 0 then
if self.object:get_velocity().y < 5 then
self.object:add_velocity({ x = 0 , y = math.random(-.007, .007), z = 0 })
end
end
--]]
end,
}
mcl_mobs:register_mob("mobs_mc:dolphin", dolphin)
--spawning TO DO: in schools
local water = 0
mcl_mobs:spawn_specific(
"mobs_mc:dolphin",
"overworld",
"water",
{
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
"FlowerForest_beach",
"Forest_beach",
"StoneBeach",
"Taiga_beach",
"Savanna_beach",
"Plains_beach",
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",
"MesaPlateauF_sandlevel",
"MesaBryce_sandlevel",
"Mesa_sandlevel",
"RoofedForest_ocean",
"JungleEdgeM_ocean",
"BirchForestM_ocean",
"BirchForest_ocean",
"IcePlains_deep_ocean",
"Jungle_deep_ocean",
"Savanna_ocean",
"MesaPlateauF_ocean",
"ExtremeHillsM_deep_ocean",
"Savanna_deep_ocean",
"SunflowerPlains_ocean",
"Swampland_deep_ocean",
"Swampland_ocean",
"MegaSpruceTaiga_deep_ocean",
"ExtremeHillsM_ocean",
"JungleEdgeM_deep_ocean",
"SunflowerPlains_deep_ocean",
"BirchForest_deep_ocean",
"IcePlainsSpikes_ocean",
"Mesa_ocean",
"StoneBeach_ocean",
"Plains_deep_ocean",
"JungleEdge_deep_ocean",
"SavannaM_deep_ocean",
"Desert_deep_ocean",
"Mesa_deep_ocean",
"ColdTaiga_deep_ocean",
"Plains_ocean",
"MesaPlateauFM_ocean",
"Forest_deep_ocean",
"JungleM_deep_ocean",
"FlowerForest_deep_ocean",
"MushroomIsland_ocean",
"MegaTaiga_ocean",
"StoneBeach_deep_ocean",
"IcePlainsSpikes_deep_ocean",
"ColdTaiga_ocean",
"SavannaM_ocean",
"MesaPlateauF_deep_ocean",
"MesaBryce_deep_ocean",
"ExtremeHills+_deep_ocean",
"ExtremeHills_ocean",
"MushroomIsland_deep_ocean",
"Forest_ocean",
"MegaTaiga_deep_ocean",
"JungleEdge_ocean",
"MesaBryce_ocean",
"MegaSpruceTaiga_ocean",
"ExtremeHills+_ocean",
"Jungle_ocean",
"RoofedForest_deep_ocean",
"IcePlains_ocean",
"FlowerForest_ocean",
"ExtremeHills_deep_ocean",
"MesaPlateauFM_deep_ocean",
"Desert_ocean",
"Taiga_ocean",
"BirchForestM_deep_ocean",
"Taiga_deep_ocean",
"JungleM_ocean",
"FlowerForest_underground",
"JungleEdge_underground",
"StoneBeach_underground",
"MesaBryce_underground",
"Mesa_underground",
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",
"ExtremeHills_underground",
"MegaSpruceTaiga_underground",
"BirchForestM_underground",
"SavannaM_underground",
"MesaPlateauFM_underground",
"Desert_underground",
"Savanna_underground",
"Forest_underground",
"SunflowerPlains_underground",
"ColdTaiga_underground",
"IcePlains_underground",
"IcePlainsSpikes_underground",
"MegaTaiga_underground",
"Taiga_underground",
"ExtremeHills+_underground",
"JungleM_underground",
"ExtremeHillsM_underground",
"JungleEdgeM_underground",
},
0,
minetest.LIGHT_MAX+1,
30,
4000,
3,
water-16,
water+1)
--spawn egg
mcl_mobs:register_egg("mobs_mc:dolphin", S("Dolphin"), "extra_mobs_spawn_icon_dolphin.png", 0)

View File

@ -35,6 +35,7 @@ mcl_mobs:register_mob("mobs_mc:enderdragon", {
},
physical = true,
damage = 10,
knock_back = false,
jump = true,
jump_height = 14,
fly = true,

View File

@ -627,7 +627,6 @@ mcl_mobs:spawn_specific(
"Plains",
"Desert",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
@ -654,7 +653,6 @@ mcl_mobs:spawn_specific(
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",
@ -693,7 +691,6 @@ mcl_mobs:spawn_specific(
"Forest_deep_ocean",
"JungleM_deep_ocean",
"FlowerForest_deep_ocean",
"MushroomIsland_ocean",
"MegaTaiga_ocean",
"StoneBeach_deep_ocean",
"IcePlainsSpikes_deep_ocean",
@ -703,7 +700,6 @@ mcl_mobs:spawn_specific(
"MesaBryce_deep_ocean",
"ExtremeHills+_deep_ocean",
"ExtremeHills_ocean",
"MushroomIsland_deep_ocean",
"Forest_ocean",
"MegaTaiga_deep_ocean",
"JungleEdge_ocean",
@ -729,7 +725,6 @@ mcl_mobs:spawn_specific(
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",
@ -766,15 +761,32 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"Nether",
"SoulsandVall3ey",
},
0,
7,
11,
30,
27500,
4,
mcl_vars.mg_nether_min,
mcl_vars.mg_nether_max)
-- Warped Forest spawn (common)
mcl_mobs:spawn_specific(
"mobs_mc:enderman",
"nether",
"ground",
{
"WarpedForest"
},
0,
11,
30,
5000,
4,
mcl_vars.mg_nether_min,
mcl_vars.mg_nether_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:enderman", S("Enderman"), "mobs_mc_spawn_icon_enderman.png", 0)

View File

@ -23,6 +23,7 @@ mcl_mobs:register_mob("mobs_mc:ghast", {
collisionbox = {-2, 5, -2, 2, 9, 2},
visual = "mesh",
mesh = "mobs_mc_ghast.b3d",
spawn_in_group = 1,
textures = {
{"mobs_mc_ghast.png"},
},
@ -81,12 +82,14 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"Nether",
"SoulsandValley",
"BasaltDelta",
},
0,
minetest.LIGHT_MAX+1,
7,
30,
18000,
72000,
2,
mcl_vars.mg_nether_min,
mcl_vars.mg_nether_max)
@ -105,7 +108,12 @@ mcl_mobs:register_arrow("mobs_mc:fireball", {
full_punch_interval = 1.0,
damage_groups = {fleshy = 6},
}, nil)
mcl_mobs:boom(self, self.object:get_pos(), 1, true)
local p = self.object:get_pos()
if p then
mcl_mobs:boom(self, p, 1, true)
else
mcl_mobs:boom(self, player:get_pos(), 1, true)
end
end,
hit_mob = function(self, mob)

View File

@ -8,12 +8,14 @@ mcl_mobs:register_mob("mobs_mc:guardian", {
description = S("Guardian"),
type = "monster",
spawn_class = "hostile",
spawn_in_group_min = 2,
spawn_in_group = 4,
hp_min = 30,
hp_max = 30,
xp_min = 10,
xp_max = 10,
breath_max = -1,
passive = false,
passive = false,
attack_type = "dogfight",
pathfinding = 1,
view_range = 16,

View File

@ -81,11 +81,27 @@ for b=1, #horse_base do
end
end
-- in e7898352d890c2414af653eba624939df9c0b8b4 (0.76-dev) all items from mobs_mc were moved to mcl_mobitems
-- this results in existing horses wearing armor would still have the old texture filename in their
-- properties this function updates them. It should be removed some time in the future when we can be
-- reasonably sure all horses that want it get the new nexture.
local function update_textures(self)
local old = "mobs_mc_horse_armor_"
local txt = self.object:get_properties().textures
if txt[2]:find(old) then
txt[2] = txt[2]:gsub(old,"mcl_mobitems_horse_armor_")
self.object:set_properties({textures=txt})
return
end
end
-- Horse
local horse = {
description = S("Horse"),
type = "animal",
spawn_class = "passive",
spawn_in_group_min = 2,
spawn_in_group = 6,
visual = "mesh",
mesh = "mobs_mc_horse.b3d",
visual_size = {x=3.0, y=3.0},
@ -138,7 +154,7 @@ local horse = {
max = 2,
looting = "common",},
},
on_spawn = update_textures,
do_custom = function(self, dtime)
-- set needed values if not already present
@ -476,6 +492,8 @@ local d = 0.86 -- donkey scale
local donkey = table.copy(horse)
donkey.description = S("Donkey")
donkey.textures = {{"blank.png", "mobs_mc_donkey.png", "blank.png"}}
donkey.spawn_in_group = 3
donkey.spawn_in_group_min = 1
donkey.animation = {
speed_normal = 25,
stand_start = 0, stand_end = 0,
@ -528,41 +546,14 @@ mcl_mobs:spawn_specific(
"ground",
{
"flat",
"IcePlainsSpikes",
"ColdTaiga",
"ColdTaiga_beach",
"ColdTaiga_beach_water",
"MegaTaiga",
"MegaSpruceTaiga",
"ExtremeHills",
"ExtremeHills_beach",
"ExtremeHillsM",
"ExtremeHills+",
"ExtremeHills+_snowtop",
"StoneBeach",
"Plains",
"Plains_beach",
"SunflowerPlains",
"Taiga",
"Taiga_beach",
"Forest",
"Forest_beach",
"FlowerForest",
"FlowerForest_beach",
"BirchForest",
"BirchForestM",
"RoofedForest",
"Savanna",
"Savanna_beach",
"SavannaM",
"Jungle",
"Jungle_shore",
"JungleM",
"JungleM_shore",
"JungleEdge",
"JungleEdgeM",
"Swampland",
"Swampland_shore"
"Savanna_beach",
"Plains_beach",
},
0,
minetest.LIGHT_MAX+1,
@ -572,20 +563,22 @@ minetest.LIGHT_MAX+1,
mobs_mc.water_level+3,
mcl_vars.mg_overworld_max)
mcl_mobs:spawn_specific(
"mobs_mc:donkey",
"overworld",
"ground",
{
"Mesa",
"MesaPlateauFM_grasstop",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"flat",
"Plains",
"Plains_beach",
"SunflowerPlains",
"Savanna",
"Savanna_beach",
"SavannaM",
"Savanna_beach",
"Plains_beach",
},
0,
9,
minetest.LIGHT_MAX+1,
30,
15000,

View File

@ -142,3 +142,7 @@ dofile(path .. "/slime+magma_cube.lua") -- Wuzzy
dofile(path .. "/spider.lua") -- Spider by AspireMint (fishyWET (CC-BY-SA 3.0 license for texture)
dofile(path .. "/vex.lua") -- KrupnoPavel
dofile(path .. "/wither.lua") -- Mesh and animation by toby109tt / https://github.com/22i
dofile(path .. "/cod.lua")
dofile(path .. "/salmon.lua")
dofile(path .. "/dolphin.lua")

View File

@ -37,6 +37,7 @@ mcl_mobs:register_mob("mobs_mc:iron_golem", {
run_velocity = 1.2,
-- Approximation
damage = 14,
knock_back = false,
reach = 3,
group_attack = true,
attacks_monsters = true,

View File

@ -28,11 +28,17 @@ mcl_mobs:register_mob("mobs_mc:llama", {
description = S("Llama"),
type = "animal",
spawn_class = "passive",
passive = false,
attack_type = "shoot",
shoot_interval = 5.5,
arrow = "mobs_mc:llamaspit",
shoot_offset = 1, --3.5 *would* be a good value visually but it somehow messes with the projectiles trajectory
spawn_in_group_min = 4,
spawn_in_group = 6,
hp_min = 15,
hp_max = 30,
xp_min = 1,
xp_max = 3,
passive = false,
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.86, 0.45},
visual = "mesh",
mesh = "mobs_mc_llama.b3d",
@ -45,7 +51,7 @@ mcl_mobs:register_mob("mobs_mc:llama", {
},
visual_size = {x=3, y=3},
makes_footstep_sound = true,
runaway = true,
runaway = false,
walk_velocity = 1,
run_velocity = 4.4,
follow_velocity = 4.4,
@ -211,24 +217,46 @@ mcl_mobs:register_mob("mobs_mc:llama", {
})
-- spit arrow (weapon)
mcl_mobs:register_arrow("mobs_mc:llamaspit", {
visual = "sprite",
visual_size = {x = 0.10, y = 0.10},
textures = {"mobs_mc_llama_spit.png"},
velocity = 5,
hit_player = function(self, player)
player:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = 1},
}, nil)
end,
hit_mob = function(self, mob)
mob:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = 1},
}, nil)
end,
hit_node = function(self, pos, node)
end
})
--spawn
mcl_mobs:spawn_specific(
"mobs_mc:llama",
"overworld",
"ground",
{
"Mesa",
"MesaPlateauFM_grasstop",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"Jungle",
"Jungle_shore",
"JungleM",
"JungleM_shore",
"Savanna",
"SavannaM",
"SavannaM_beach",
"Savanna_beach",
"Savanna_ocean",
"JungleEdge",
"JungleEdgeM",
"ExtremeHills",
"ExtremeHills_beach",
"ExtremeHillsM",
},
0,
minetest.LIGHT_MAX+1,

View File

@ -1,64 +1,58 @@
# textdomain: mobs_mc
Agent=Agente
Bat=Murciélago
Blaze=Blaze
Chicken=Pollo
Cod=Bacalao
Cow=Vaca
Mooshroom=Champiñaca
Mooshroom=Champivaca
Creeper=Creeper
Ender Dragon=Enderdragón
Dolphin=Delfín
Ender Dragon=Ender Dragon
Enderman=Enderman
Endermite=Endermite
Ghast=Ghast
Elder Guardian=Gran guardián
Guardian=Guardián
Horse=Caballo
Skeleton Horse=Caballo esquelético
Zombie Horse=Caballo zombie
Elder Guardian=Guardián Anciano
Donkey=Burro
Horse=Caballo
Mule=Mula
Skeleton Horse=Caballo esqueleto
Zombie Horse=Caballo zombi
Iron Golem=Golem de hierro
Llama=Llama
Cat=Gato
Ocelot=Ocelote
Parrot=Loro
Pig=Cerdo
Polar Bear=Oso polar
Rabbit=Conejo
Killer Bunny=Conejo asesino
Rabbit=Conejo
Salmon=Salmón
Sheep=Oveja
Shulker=Shulker
Silverfish=Lepisma
Skeleton=Esqueleto
Stray=Esqueleto
Wither Skeleton=Esqueleto wither
Stray=Esqueleto glacial
Wither Skeleton=Esqueleto del Wither
Magma Cube=Cubo de Magma
Slime=Slime
Snow Golem=Golem de nieve
Spider=Araña
Cave Spider=Araña de las cuevas
Spider=Araña
Squid=Calamar
Vex=Ánima
Master=Maestro
Villager=Aldeano
Evoker=Invocador
Illusioner=Illusionista
Villager=Aldeano
Vindicator=Vindicador
Zombie Villager=Aldeano zombie
Zombie Villager=Aldeano zombi
Witch=Bruja
Wither=Wither
Wolf=Lobo
Husk=Husk
Zombie=Zombie
Zombie Pigman=Cerdo Zombie
Farmer=Granjero
Fisherman=Pescador
Fletcher=Flechador
Shepherd=Sacerdote
Librarian=Bibliotecario
Cartographer=Cartógrafo
Armorer=Armero
Leatherworker=Peletero
Butcher=Carnicero
Weapon Smith=Herrero de Armas
Tool Smith=Herrero de Herramientas
Cleric=Sacerdote
Nitwit=Simple
Baby Husk=Bebé Zombi Momificado
Baby Zombie=Bebé Zombi
Husk=Zombi Momificado
Zombie=Zombi
Baby Zombie Pigman=Bebé Hombrecerdo Zombi
Zombie Pigman=Hombrecerdo Zombi

View File

@ -62,3 +62,6 @@ Weapon Smith=
Tool Smith=
Cleric=
Nitwit=
Cod=
Salmon=
Dolphin=

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -30,6 +30,8 @@ local ocelot = {
type = "animal",
spawn_class = "passive",
can_despawn = true,
spawn_in_group = 3,
spawn_in_group_min = 1,
hp_min = 10,
hp_max = 10,
xp_min = 1,

View File

@ -8,8 +8,113 @@ local S = minetest.get_translator("mobs_mc")
--###################
--################### PARROT
--###################
local shoulders = {
left = vector.new(-3.75,10.5,0),
right = vector.new(3.75,10.5,0)
}
local function get_random_mob_sound()
local t = table.copy(minetest.registered_entities)
table.shuffle(t)
for _,e in pairs(t) do
if e.is_mob and e.sounds then
return e.sounds[math.random(#e.sounds)]
end
end
return minetest.registered_entities["mobs_mc:parrot"].sounds.random
end
local function imitate_mob_sound(self,mob)
local snd = mob.sounds.random
if not snd or mob.name == "mobs_mc:parrot" or math.random(20) == 1 then
snd = get_random_mob_sound()
end
return minetest.sound_play(snd, {
pos = self.object:get_pos(),
gain = 1.0,
pitch = 2.5,
max_hear_distance = self.sounds and self.sounds.distance or 32
}, true)
end
local function check_mobimitate(self,dtime)
if not self._mobimitate_timer or self._mobimitate_timer > 30 then
self._mobimitate_timer = 0
for _,o in pairs(minetest.get_objects_inside_radius(self.object:get_pos(),20)) do
local l = o:get_luaentity()
if l and l.is_mob and l.name ~= "mobs_mc:parrot" then
imitate_mob_sound(self,l)
return
end
end
end
self._mobimitate_timer = self._mobimitate_timer + dtime
end
--find a free shoulder or return nil
local function get_shoulder(player)
local sh = "left"
for _,o in pairs(player:get_children()) do
local l = o:get_luaentity()
if l and l.name == "mobs_mc:parrot" then
local _,_,a = l.object:get_attach()
for _,s in pairs(shoulders) do
if a and vector.equals(a,s) then
if sh == "left" then
sh = "right"
else
return
end
end
end
end
end
return shoulders[sh]
end
local function perch(self,player)
if self.tamed and player:get_player_name() == self.owner and not self.object:get_attach() then
local shoulder = get_shoulder(player)
if not shoulder then return true end
self.object:set_attach(player,"",shoulder,vector.new(0,0,0),true)
mcl_mobs:set_animation(self, "stand")
end
end
local function check_perch(self,dtime)
if self.object:get_attach() then
for _,p in pairs(minetest.get_connected_players()) do
for _,o in pairs(p:get_children()) do
local l = o:get_luaentity()
if l and l.name == "mobs_mc:parrot" then
local n1 = minetest.get_node(vector.offset(p:get_pos(),0,-0.6,0)).name
local n2 = minetest.get_node(vector.offset(p:get_pos(),0,0,0)).name
local n3 = minetest.get_node(vector.offset(p:get_pos(),0,1,0)).name
if n1 == "air" or minetest.get_item_group(n2,"water") > 0 or minetest.get_item_group(n2,"lava") > 0 then
o:set_detach()
self.detach_timer = 0
return
end
end
end
end
elseif not self.detach_timer then
for _,p in pairs(minetest.get_connected_players()) do
if vector.distance(self.object:get_pos(),p:get_pos()) < 0.5 then
perch(self,p)
return
end
end
elseif self.detach_timer then
if self.detach_timer > 1 then
self.detach_timer = nil
else
self.detach_timer = self.detach_timer + dtime
end
end
end
mcl_mobs:register_mob("mobs_mc:parrot", {
description = S("Parrot"),
@ -45,12 +150,12 @@ mcl_mobs:register_mob("mobs_mc:parrot", {
stand_speed = 50,
walk_speed = 50,
fly_speed = 50,
stand_start = 30,
stand_end = 45,
stand_start = 0,
stand_end = 0,
fly_start = 30,
fly_end = 45,
walk_start = 30,
walk_end = 45,
walk_start = 0,
walk_end = 20,
-- TODO: actual walk animation
--walk_start = 0,
--walk_end = 20,
@ -87,13 +192,19 @@ mcl_mobs:register_mob("mobs_mc:parrot", {
end
return
end
-- Feed to tame, but not breed
if mcl_mobs:feed_tame(self, clicker, 1, false, true) then return end
if mcl_mobs:protect(self, clicker) then return end
if mcl_mobs:capture_mob(self, clicker, 0, 50, 80, false, nil) then return end
perch(self,clicker)
end,
do_custom = function(self,dtime)
check_perch(self,dtime)
check_mobimitate(self,dtime)
end,
do_punch = function(self,puncher) --do_punch is the mcl_mobs_redo variant - it gets called by on_punch later....
if self.object:get_attach() == puncher then
return false --return false explicitly here. mcl_mobs checks for that
end
end,
})
-- Parrots spawn rarely in jungles. TODO: Also check for jungle *biome* <- I'll get to this eventually -j4i

View File

@ -99,7 +99,7 @@ mcl_mobs:register_mob("mobs_mc:pig", {
local wielditem = clicker:get_wielded_item()
-- Feed pig
if wielditem:get_name() ~= "mcl_mobitems:carrot_on_a_stick" then
if mcl_mobs:feed_tame(self, clicker, 1, true, true) then return end
if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
end
if mcl_mobs:protect(self, clicker) then return end
@ -194,17 +194,12 @@ mcl_mobs:spawn_specific(
"ground",
{
"flat",
"IcePlainsSpikes",
"ColdTaiga",
"ColdTaiga_beach",
"ColdTaiga_beach_water",
"MegaTaiga",
"MegaSpruceTaiga",
"ExtremeHills",
"ExtremeHills_beach",
"ExtremeHillsM",
"ExtremeHills+",
"ExtremeHills+_snowtop",
"StoneBeach",
"Plains",
"Plains_beach",

View File

@ -76,7 +76,6 @@ mcl_mobs:spawn_specific(
"ColdTaiga",
"IcePlainsSpikes",
"IcePlains",
"ExtremeHills+_snowtop",
},
0,
minetest.LIGHT_MAX+1,

View File

@ -6,9 +6,10 @@ local rabbit = {
description = S("Rabbit"),
type = "animal",
spawn_class = "passive",
spawn_in_group_min = 2,
spawn_in_group = 3,
passive = true,
reach = 1,
hp_min = 3,
hp_max = 3,
xp_min = 1,
@ -74,7 +75,7 @@ local rabbit = {
},
on_rightclick = function(self, clicker)
-- Feed, tame protect or capture
if mcl_mobs:feed_tame(self, clicker, 1, true, true) then return end
if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
if mcl_mobs:protect(self, clicker) then return end
if mcl_mobs:capture_mob(self, clicker, 0, 50, 80, false, nil) then return end
end,
@ -132,18 +133,9 @@ mcl_mobs:spawn_specific(
"Desert",
"FlowerForest",
"Taiga",
"ExtremeHills",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Plains",
"ColdTaiga",
"SunflowerPlains",
"RoofedForest",
"MesaPlateauFM_grasstop",
"ExtremeHillsM",
"BirchForestM",
},
9,
minetest.LIGHT_MAX+1,

View File

@ -0,0 +1,228 @@
--MCmobs v0.4
--maikerumine
--made for MC like Survival game
--License for code WTFPL and otherwise stated in readmes
local S = minetest.get_translator(minetest.get_current_modname())
--###################
--################### salmon
--###################
local salmon = {
type = "animal",
spawn_class = "water",
can_despawn = true,
passive = true,
hp_min = 3,
hp_max = 3,
xp_min = 1,
xp_max = 3,
armor = 100,
spawn_in_group = 5,
tilt_swim = true,
collisionbox = {-0.4, 0.0, -0.4, 0.4, 0.79, 0.4},
visual = "mesh",
mesh = "extra_mobs_salmon.b3d",
textures = {
{"extra_mobs_salmon.png"}
},
sounds = {
},
animation = {
stand_start = 1,
stand_end = 20,
walk_start = 1,
walk_end = 20,
run_start = 1,
run_end = 20,
},
drops = {
{name = "mcl_fishing:salmon_raw",
chance = 1,
min = 1,
max = 1,},
{name = "mcl_dye:white",
chance = 20,
min = 1,
max = 1,},
},
visual_size = {x=3, y=3},
makes_footstep_sound = false,
swim = true,
fly = true,
fly_in = "mcl_core:water_source",
breathes_in_water = true,
jump = false,
view_range = 16,
runaway = true,
fear_height = 4,
on_rightclick = function(self, clicker)
if clicker:get_wielded_item():get_name() == "mcl_buckets:bucket_water" then
self.object:remove()
clicker:set_wielded_item("mcl_fishing:bucket_salmon")
awards.unlock(clicker:get_player_name(), "mcl:tacticalFishing")
end
end
}
mcl_mobs:register_mob("mobs_mc:salmon", salmon)
--spawning TODO: in schools
local water = 0
mcl_mobs:spawn_specific(
"mobs_mc:salmon",
"overworld",
"water",
{
"Mesa",
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"Jungle",
"Savanna",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"Desert",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
"RoofedForest",
"ExtremeHills+_snowtop",
"MesaPlateauFM_grasstop",
"JungleEdgeM",
"ExtremeHillsM",
"JungleM",
"BirchForestM",
"MesaPlateauF",
"MesaPlateauFM",
"MesaPlateauF_grasstop",
"MesaBryce",
"JungleEdge",
"SavannaM",
"FlowerForest_beach",
"Forest_beach",
"StoneBeach",
"ColdTaiga_beach_water",
"Taiga_beach",
"Savanna_beach",
"Plains_beach",
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",
"MesaPlateauF_sandlevel",
"MesaBryce_sandlevel",
"Mesa_sandlevel",
"RoofedForest_ocean",
"JungleEdgeM_ocean",
"BirchForestM_ocean",
"BirchForest_ocean",
"IcePlains_deep_ocean",
"Jungle_deep_ocean",
"Savanna_ocean",
"MesaPlateauF_ocean",
"ExtremeHillsM_deep_ocean",
"Savanna_deep_ocean",
"SunflowerPlains_ocean",
"Swampland_deep_ocean",
"Swampland_ocean",
"MegaSpruceTaiga_deep_ocean",
"ExtremeHillsM_ocean",
"JungleEdgeM_deep_ocean",
"SunflowerPlains_deep_ocean",
"BirchForest_deep_ocean",
"IcePlainsSpikes_ocean",
"Mesa_ocean",
"StoneBeach_ocean",
"Plains_deep_ocean",
"JungleEdge_deep_ocean",
"SavannaM_deep_ocean",
"Desert_deep_ocean",
"Mesa_deep_ocean",
"ColdTaiga_deep_ocean",
"Plains_ocean",
"MesaPlateauFM_ocean",
"Forest_deep_ocean",
"JungleM_deep_ocean",
"FlowerForest_deep_ocean",
"MushroomIsland_ocean",
"MegaTaiga_ocean",
"StoneBeach_deep_ocean",
"IcePlainsSpikes_deep_ocean",
"ColdTaiga_ocean",
"SavannaM_ocean",
"MesaPlateauF_deep_ocean",
"MesaBryce_deep_ocean",
"ExtremeHills+_deep_ocean",
"ExtremeHills_ocean",
"MushroomIsland_deep_ocean",
"Forest_ocean",
"MegaTaiga_deep_ocean",
"JungleEdge_ocean",
"MesaBryce_ocean",
"MegaSpruceTaiga_ocean",
"ExtremeHills+_ocean",
"Jungle_ocean",
"RoofedForest_deep_ocean",
"IcePlains_ocean",
"FlowerForest_ocean",
"ExtremeHills_deep_ocean",
"MesaPlateauFM_deep_ocean",
"Desert_ocean",
"Taiga_ocean",
"BirchForestM_deep_ocean",
"Taiga_deep_ocean",
"JungleM_ocean",
"FlowerForest_underground",
"JungleEdge_underground",
"StoneBeach_underground",
"MesaBryce_underground",
"Mesa_underground",
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",
"ExtremeHills_underground",
"MegaSpruceTaiga_underground",
"BirchForestM_underground",
"SavannaM_underground",
"MesaPlateauFM_underground",
"Desert_underground",
"Savanna_underground",
"Forest_underground",
"SunflowerPlains_underground",
"ColdTaiga_underground",
"IcePlains_underground",
"IcePlainsSpikes_underground",
"MegaTaiga_underground",
"Taiga_underground",
"ExtremeHills+_underground",
"JungleM_underground",
"ExtremeHillsM_underground",
"JungleEdgeM_underground",
},
0,
minetest.LIGHT_MAX+1,
30,
4000,
3,
water-16,
water+1)
--spawn egg
mcl_mobs:register_egg("mobs_mc:salmon", S("Salmon"), "extra_mobs_spawn_icon_salmon.png", 0)

View File

@ -70,6 +70,8 @@ mcl_mobs:register_mob("mobs_mc:sheep", {
color = "unicolor_white",
makes_footstep_sound = true,
walk_velocity = 1,
runaway = true,
runaway_from = {"mobs_mc:wolf"},
drops = {
{name = "mcl_mobitems:mutton",
chance = 1,
@ -195,7 +197,7 @@ mcl_mobs:register_mob("mobs_mc:sheep", {
on_rightclick = function(self, clicker)
local item = clicker:get_wielded_item()
if mcl_mobs:feed_tame(self, clicker, 1, true, true) then return end
if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
if mcl_mobs:protect(self, clicker) then return end
if item:get_name() == "mcl_tools:shears" and not self.gotten and not self.child then
@ -346,7 +348,7 @@ mcl_mobs:spawn_specific(
"Swampland",
"Swampland_shore"
},
0,
9,
minetest.LIGHT_MAX+1,
30,
15000,

View File

@ -33,6 +33,7 @@ mcl_mobs:register_mob("mobs_mc:shulker", {
-- TODO: Make shulker dye-able
visual_size = {x=3, y=3},
walk_chance = 0,
knock_back = false,
jump = false,
drops = {
{name = "mcl_mobitems:shulker_shell",

View File

@ -162,7 +162,6 @@ mcl_mobs:spawn_specific(
"Plains",
"Desert",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
@ -189,7 +188,6 @@ mcl_mobs:spawn_specific(
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",
@ -228,7 +226,6 @@ mcl_mobs:spawn_specific(
"Forest_deep_ocean",
"JungleM_deep_ocean",
"FlowerForest_deep_ocean",
"MushroomIsland_ocean",
"MegaTaiga_ocean",
"StoneBeach_deep_ocean",
"IcePlainsSpikes_deep_ocean",
@ -238,7 +235,6 @@ mcl_mobs:spawn_specific(
"MesaBryce_deep_ocean",
"ExtremeHills+_deep_ocean",
"ExtremeHills_ocean",
"MushroomIsland_deep_ocean",
"Forest_ocean",
"MegaTaiga_deep_ocean",
"JungleEdge_ocean",
@ -264,7 +260,6 @@ mcl_mobs:spawn_specific(
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",
@ -302,10 +297,10 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"SoulsandValley",
},
0,
7,
minetest.LIGHT_MAX+1,
30,
10000,
3,

View File

@ -101,7 +101,8 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"Nether",
"SoulsandValley",
},
0,
7,

View File

@ -402,7 +402,8 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"Nether",
"BasaltDelta",
},
0,
minetest.LIGHT_MAX+1,
@ -418,7 +419,8 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"Nether",
"BasaltDelta",
},
0,
minetest.LIGHT_MAX+1,
@ -433,7 +435,8 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"Nether",
"BasaltDelta",
},
0,
minetest.LIGHT_MAX+1,
@ -443,11 +446,6 @@ minetest.LIGHT_MAX+1,
mmin,
mmax)
--mcl_mobs:spawn_specific("mobs_mc:magma_cube_tiny", { "mcl_nether:nether_brick", "mcl_nether:netherrack" }, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11000, 4, mmin, mmax)
--mcl_mobs:spawn_specific("mobs_mc:magma_cube_small", { "mcl_nether:nether_brick", "mcl_nether:netherrack" }, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11100, 4, mmin, mmax)
--mcl_mobs:spawn_specific("mobs_mc:magma_cube_big", { "mcl_nether:nether_brick", "mcl_nether:netherrack" }, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11200, 4, mmin, mmax)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:magma_cube_big", S("Magma Cube"), "mobs_mc_spawn_icon_magmacube.png")
mcl_mobs:register_egg("mobs_mc:slime_big", S("Slime"), "mobs_mc_spawn_icon_slime.png")

View File

@ -109,7 +109,6 @@ mcl_mobs:spawn_specific(
"Plains",
"Desert",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
@ -136,7 +135,6 @@ mcl_mobs:spawn_specific(
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",
@ -175,7 +173,6 @@ mcl_mobs:spawn_specific(
"Forest_deep_ocean",
"JungleM_deep_ocean",
"FlowerForest_deep_ocean",
"MushroomIsland_ocean",
"MegaTaiga_ocean",
"StoneBeach_deep_ocean",
"IcePlainsSpikes_deep_ocean",
@ -185,7 +182,6 @@ mcl_mobs:spawn_specific(
"MesaBryce_deep_ocean",
"ExtremeHills+_deep_ocean",
"ExtremeHills_ocean",
"MushroomIsland_deep_ocean",
"Forest_ocean",
"MegaTaiga_deep_ocean",
"JungleEdge_ocean",
@ -211,7 +207,6 @@ mcl_mobs:spawn_specific(
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 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.

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

View File

@ -136,8 +136,7 @@ local professions = {
{
{ { "mcl_fishing:fish_raw", 6, 15,}, E1 },
{ { "mcl_fishing:salmon_raw", 6, 6, "mcl_core:emerald", 1, 1 },{ "mcl_fishing:salmon_cooked", 6, 6 } },
-- FIXME missing campfire
-- {{ "mcl_core:emerald", 1, 2 },{"mcl_campfires:campfire",1,1} },
{ { "mcl_core:emerald", 1, 2 },{"mcl_campfires:campfire_lit",1,1} },
},
{
{ { "mcl_fishing:salmon_raw", 6, 13,}, E1 },
@ -427,7 +426,7 @@ local professions = {
"mobs_mc_villager_weaponsmith.png",
"mobs_mc_villager_weaponsmith.png",
},
jobsite = "mcl_furnaces:furnace", --FIXME: grindstone
jobsite = "mcl_grindstone:grindstone",
trades = {
{
{ { "mcl_core:coal_lump", 15, 15 }, E1 },
@ -458,7 +457,7 @@ local professions = {
"mobs_mc_villager_toolsmith.png",
"mobs_mc_villager_toolsmith.png",
},
jobsite = "mcl_anvils:anvil", --FIXME: smithing table
jobsite = "mcl_smithing_table:table",
trades = {
{
{ { "mcl_core:coal_lump", 15, 15 }, E1 },
@ -613,6 +612,8 @@ local function employ(self,jobsite_pos)
end
local function look_for_job(self)
if self.last_jobhunt and os.time() - self.last_jobhunt < 360 then return end
self.last_jobhunt = os.time() + math.random(0,60)
local p = self.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48),jobsites)
for _,n in pairs(nn) do
@ -628,14 +629,24 @@ local function look_for_job(self)
end
local function get_a_job(self)
if self.child then return end
local p = self.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-8,-8,-8),vector.offset(p,8,8,8),jobsites)
for _,n in pairs(nn) do
if n and employ(self,n) then return true end
end
local n = minetest.find_node_near(p,1,jobsites)
if n and employ(self,n) then return true end
if self.state ~= "gowp" then look_for_job(self) end
end
local function check_jobsite(self)
if self._traded or not self._jobsite then return end
local n = mcl_vars.get_node(self._jobsite)
local m = minetest.get_meta(self._jobsite)
if m:get_string("villager") ~= self._id then
self._profession = "unemployed"
self._trades = nil
set_textures(self)
end
end
local function update_max_tradenum(self)
if not self._trades then
return
@ -724,7 +735,10 @@ local function set_trade(trader, player, inv, concrete_tradenum)
local trade = trades[concrete_tradenum]
inv:set_stack("wanted", 1, ItemStack(trade.wanted[1]))
local offered = ItemStack(trade.offered)
mcl_enchanting.load_enchantments(offered)
-- Only load enchantments for enchanted items; fixes unnecessary metadata being applied to regular items from villagers.
if mcl_enchanting.is_enchanted(offered:get_name()) then
mcl_enchanting.load_enchantments(offered)
end
inv:set_stack("offered", 1, offered)
if trade.wanted[2] then
local wanted2 = ItemStack(trade.wanted[2])
@ -982,6 +996,11 @@ local trade_inventory = {
elseif listname == "output" then
if not trader_exists(player:get_player_name()) then
return 0
-- Begin Award Code
-- May need to be moved if award gets unlocked in the wrong cases.
elseif trader_exists(player:get_player_name()) then
awards.unlock(player:get_player_name(), "mcl:whatAdeal")
-- End Award Code
end
-- Only allow taking full stack
local count = stack:get_count()
@ -1094,6 +1113,7 @@ local trade_inventory = {
local trader = player_trading_with[name]
local tradenum = player_tradenum[name]
local trades
trader._traded = true
if trader and trader._trades then
trades = minetest.deserialize(trader._trades)
end
@ -1224,6 +1244,7 @@ mcl_mobs:register_mob("mobs_mc:villager", {
-- TODO: sounds
sounds = {
random = "mobs_mc_villager",
damage = "mobs_mc_villager_hurt",
distance = 10,
},
animation = {
@ -1236,10 +1257,12 @@ mcl_mobs:register_mob("mobs_mc:villager", {
run_speed = 25,
run_start = 0,
run_end = 40,
die_speed = 15,
die_start = 210,
die_end = 220,
die_loop = false,
head_shake_start = 210,
head_shake_end = 220,
head_shake_loop = false,
head_nod_start = 210,
head_nod_end = 220,
head_nod_loop = false,
},
follow = pick_up,
nofollow = true,
@ -1261,13 +1284,12 @@ mcl_mobs:register_mob("mobs_mc:villager", {
end
end
if clicker then
mcl_mobs:feed_tame(self, clicker, 1, true, false)
mcl_mobs:feed_tame(self, clicker, 1, true, false, true)
return
end
return true --do not pick up
end,
on_rightclick = function(self, clicker)
local trg=vector.new(0,9,0)
if self._jobsite then
mcl_mobs:gopath(self,self._jobsite,function()
--minetest.log("arrived at jobsite")
@ -1344,20 +1366,24 @@ mcl_mobs:register_mob("mobs_mc:villager", {
end
if self._profession == "unemployed" then
get_a_job(self)
else
check_jobsite(self)
end
end
end,
on_spawn = function(self)
if not self._profession then
self._profession = "unemployed"
if math.random(100) == 1 then
self._profession = "nitwit"
end
end
if self._id then
set_textures(self)
return
end
self._id=minetest.sha1(minetest.get_gametime()..minetest.pos_to_string(self.object:get_pos())..tostring(math.random()))
self._profession = "unemployed"
if math.random(100) == 1 then
self._profession = "nitwit"
end
set_textures(self)
end,
on_die = function(self, pos)
@ -1376,7 +1402,8 @@ mcl_mobs:register_mob("mobs_mc:villager", {
})
--[[
Villager spawning in mcl_villages
mcl_mobs:spawn_specific(
"mobs_mc:villager",
"overworld",
@ -1406,6 +1433,6 @@ minetest.LIGHT_MAX+1,
4,
mobs_mc.water_level+1,
mcl_vars.mg_overworld_max)
--]]
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:villager", S("Villager"), "mobs_mc_spawn_icon_villager.png", 0)

View File

@ -29,6 +29,7 @@ mcl_mobs:register_mob("mobs_mc:villager_zombie", {
description = S("Zombie Villager"),
type = "monster",
spawn_class = "hostile",
spawn_in_group = 1,
hp_min = 20,
hp_max = 20,
xp_min = 5,
@ -119,20 +120,7 @@ mcl_mobs:register_mob("mobs_mc:villager_zombie", {
villager_obj:set_yaw(yaw)
villager.target_yaw = yaw
villager.nametag = self.nametag
local texture = self.base_texture[1]:gsub("zombie", "villager")
if texture == "mobs_mc_villager_villager.png" then
texture = "mobs_mc_villager.png"
end
local textures = {texture}
villager.base_texture = textures
villager_obj:set_properties({textures = textures})
local matches = {}
for prof, tex in pairs(professions) do
if texture == tex then
table.insert(matches, prof)
end
end
villager._profession = matches[math.random(#matches)]
villager._profession = "unemployed"
self._curing = nil
mcl_burning.extinguish(obj)
obj:remove()
@ -160,7 +148,6 @@ mcl_mobs:spawn_specific(
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",
@ -197,7 +184,6 @@ mcl_mobs:spawn_specific(
"Plains",
"Desert",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
@ -224,7 +210,6 @@ mcl_mobs:spawn_specific(
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",

View File

@ -18,6 +18,7 @@ local wolf = {
xp_max = 3,
passive = false,
group_attack = true,
spawn_in_group = 8,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 0.84, 0.3},
visual = "mesh",
mesh = "mobs_mc_wolf.b3d",
@ -232,29 +233,22 @@ dog.on_rightclick = function(self, clicker)
end
mcl_mobs:register_mob("mobs_mc:dog", dog)
-- Spawn
mcl_mobs:spawn_specific(
"mobs_mc:wolf",
"overworld",
"ground",
{
"FlowerForest",
"Swampland",
"Taiga",
"ExtremeHills",
"BirchForest",
"MegaSpruceTaiga",
"MegaTaiga",
"ExtremeHills+",
"Forest",
"Plains",
"ColdTaiga",
"SunflowerPlains",
"RoofedForest",
"MesaPlateauFM_grasstop",
"ExtremeHillsM",
"BirchForestM",
"Taiga",
"MegaSpruceTaiga",
"MegaTaiga",
"Forest",
"ColdTaiga",
"FlowerForest_beach",
"Forest_beach",
"ColdTaiga_beach_water",
"Taiga_beach",
"ColdTaiga_beach",
},
0,
minetest.LIGHT_MAX+1,

View File

@ -162,7 +162,6 @@ mcl_mobs:spawn_specific(
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",
@ -198,7 +197,6 @@ mcl_mobs:spawn_specific(
"Forest",
"Plains",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
@ -225,7 +223,6 @@ mcl_mobs:spawn_specific(
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",
@ -254,7 +251,6 @@ mcl_mobs:spawn_specific(
"RoofedForest_underground",
"Jungle_underground",
"Swampland_underground",
"MushroomIsland_underground",
"BirchForest_underground",
"Plains_underground",
"MesaPlateauF_underground",
@ -290,7 +286,6 @@ mcl_mobs:spawn_specific(
"Forest",
"Plains",
"ColdTaiga",
"MushroomIsland",
"IcePlainsSpikes",
"SunflowerPlains",
"IcePlains",
@ -317,7 +312,6 @@ mcl_mobs:spawn_specific(
"ExtremeHills_beach",
"ColdTaiga_beach",
"Swampland_shore",
"MushroomIslandShore",
"JungleM_shore",
"Jungle_shore",
"MesaPlateauFM_sandlevel",

View File

@ -118,7 +118,8 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"Nether",
"CrimsonForest",
},
0,
minetest.LIGHT_MAX+1,
@ -133,7 +134,8 @@ mcl_mobs:spawn_specific(
"nether",
"ground",
{
"Nether"
"Nether",
"CrimsonForest",
},
0,
minetest.LIGHT_MAX+1,

View File

@ -238,8 +238,8 @@ after(5, function(dtime)
end)
minetest.register_chatcommand("lightning", {
params = "[<X> <Y> <Z>]",
description = S("Let lightning strike at the specified position or yourself"),
params = "[<X> <Y> <Z> | <player name>]",
description = S("Let lightning strike at the specified position or player. No parameter will strike yourself."),
privs = { maphack = true },
func = function(name, param)
local pos = {}
@ -247,21 +247,21 @@ minetest.register_chatcommand("lightning", {
pos.x = tonumber(pos.x)
pos.y = tonumber(pos.y)
pos.z = tonumber(pos.z)
local player_to_strike
if not (pos.x and pos.y and pos.z) then
pos = nil
player_to_strike = minetest.get_player_by_name(param)
if not player_to_strike and param == "" then
player_to_strike = minetest.get_player_by_name(name)
end
end
if name == "" and pos == nil then
if not player_to_strike and pos == nil then
return false, "No position specified and unknown player"
end
if pos then
lightning.strike(pos)
else
local player = minetest.get_player_by_name(name)
if player then
lightning.strike(player:get_pos())
else
return false, S("No position specified and unknown player")
end
elseif player_to_strike then
lightning.strike(player_to_strike:get_pos())
end
return true
end,

View File

@ -1,4 +1,3 @@
# textdomain: lightning
@1 was struck by lightning.=
Let lightning strike at the specified position or yourself=
Let lightning strike at the specified position or player. No parameter will strike yourself.=
No position specified and unknown player=

View File

@ -1,8 +1,10 @@
mcl_weather.nether_dust = {}
mcl_weather.nether_dust.particlespawners = {}
local PARTICLES_COUNT_NETHER_DUST = tonumber(minetest.settings:get("mcl_weather_dust_particles")) or 150
local psdef= {
amount = 150,
amount = PARTICLES_COUNT_NETHER_DUST,
time = 0,
minpos = vector.new(-15,-15,-15),
maxpos =vector.new(15,15,15),

View File

@ -1,5 +1,5 @@
local PARTICLES_COUNT_RAIN = 100
local PARTICLES_COUNT_THUNDER = 300
local PARTICLES_COUNT_RAIN = tonumber(minetest.settings:get("mcl_weather_rain_particles")) or 500
local PARTICLES_COUNT_THUNDER = tonumber(minetest.settings:get("mcl_weather_thunder_particles")) or 900
local get_connected_players = minetest.get_connected_players
@ -20,44 +20,26 @@ mcl_weather.rain = {
init_done = false,
}
local update_sound={}
local vel=math.random(0,3)
local falling_speed=math.random(10,15)
local size = math.random(1,3)
local psdef= {
amount = mcl_weather.rain.particles_count,
time=0,
minpos = vector.new(-6,3,-6),
maxpos = vector.new(6,15,6),
minvel = vector.new(-vel,-falling_speed,-vel),
maxvel = vector.new(vel,-falling_speed+vel,vel),
minpos = vector.new(-15,20,-15),
maxpos = vector.new(15,25,15),
minvel = vector.new(-2,-17,-2),
maxvel = vector.new(2,-8,2),
minacc = vector.new(0,0,0),
maxacc = vector.new(0,-0.4,0),
minexptime = 0.5,
maxexptime = 2,
minsize = size,
maxsize= size*2,
maxacc = vector.new(0,-0.5,0),
minexptime = 1,
maxexptime = 4,
minsize = 4,
maxsize= 8,
collisiondetection = true,
collision_removal = true,
vertical = true,
}
local psdef_backsplash= {
amount = 10,
time=0,
minpos = vector.new(-3,-1,-3),
maxpos = vector.new(3,0,3),
minvel = vector.new(-vel,falling_speed*2,-vel),
maxvel = vector.new(vel,falling_speed*2+vel,vel),
minacc = vector.new(0,0,0),
maxacc = vector.new(0,0,0),
minexptime = 0.1,
maxexptime = 0.2,
minsize = size*0.1,
maxsize= size*0.5,
collisiondetection = true,
collision_removal = true,
vertical = true,
}
local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png", "weather_pack_rain_raindrop_1.png"}
local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png"}
function mcl_weather.rain.sound_handler(player)
return minetest.sound_play("weather_rain", {
@ -86,12 +68,11 @@ end
-- no no no NO NO f*.. no. no manual particle creatin' PLS!! this sends EVERY particle over the net.
function mcl_weather.rain.add_rain_particles(player)
mcl_weather.rain.last_rp_count = mcl_weather.rain.particles_count
local l = false
for k,v in pairs(textures) do
psdef.texture=v
mcl_weather.add_spawner_player(player,"rain"..k,psdef)
l = l or mcl_weather.add_spawner_player(player,"rain"..k,psdef)
end
psdef_backsplash.texture=textures[math.random(1,#textures)]
local l=mcl_weather.add_spawner_player(player,"rainbacksplash",psdef_backsplash)
if l then
update_sound[player:get_player_name()]=true
end
@ -185,14 +166,14 @@ function mcl_weather.rain.make_weather()
for _, player in pairs(get_connected_players()) do
local pos=player:get_pos()
if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(pos) or not mcl_weather.is_outdoor(pos) then
if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(pos) then
mcl_weather.rain.remove_sound(player)
mcl_weather.remove_spawners_player(player)
return false
else
mcl_weather.rain.add_player(player)
mcl_weather.rain.add_rain_particles(player)
mcl_weather.rain.update_sound(player)
end
mcl_weather.rain.add_player(player)
mcl_weather.rain.add_rain_particles(player)
mcl_weather.rain.update_sound(player)
end
end
@ -200,11 +181,9 @@ end
function mcl_weather.rain.set_particles_mode(mode)
if mode == "thunder" then
psdef.amount=PARTICLES_COUNT_THUNDER
psdef_backsplash.amount=PARTICLES_COUNT_THUNDER
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
else
psdef.amount=PARTICLES_COUNT_RAIN
psdef_backsplash.amount=PARTICLES_COUNT_RAIN
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
end
end

View File

@ -146,8 +146,25 @@ mcl_weather.skycolor = {
player:set_stars({visible = false})
mcl_weather.skycolor.override_day_night_ratio(player, 0.5)
elseif dim == "nether" then
player:set_sky({ type = "plain",
base_color = "#300808",
local nether_sky = {
Nether = "#300808",
BasaltDelta = "#685F70",
SoulsandValley = "#1B4745",
CrimsonForest = "#330303",
WarpedForest = "#1A051A"
}
local biometint = nether_sky[minetest.get_biome_name(minetest.get_biome_data(player:get_pos()).biome)]
player:set_sky({
type = "regular",
sky_color = {
day_sky = "#300808",
day_horizon = biometint,
dawn_sky = "#300808",
dawn_horizon = biometint,
night_sky = "#300808",
night_horizon = biometint,
},
clouds = false,
})
player:set_sun({visible = false , sunrise_visible = false})

View File

@ -2,21 +2,21 @@ local get_connected_players = minetest.get_connected_players
mcl_weather.snow = {}
mcl_weather.snow.particles_count = 15
local PARTICLES_COUNT_SNOW = tonumber(minetest.settings:get("mcl_weather_snow_particles")) or 100
mcl_weather.snow.init_done = false
local psdef= {
amount = 99,
amount = PARTICLES_COUNT_SNOW,
time = 0, --stay on til we turn it off
minpos = vector.new(-15,-5,-15),
maxpos =vector.new(15,10,15),
minvel = vector.new(0,-1,0),
maxvel = vector.new(0,-4,0),
minpos = vector.new(-25,20,-25),
maxpos =vector.new(25,25,25),
minvel = vector.new(-0.2,-1,-0.2),
maxvel = vector.new(0.2,-4,0.2),
minacc = vector.new(0,-1,0),
maxacc = vector.new(0,-4,0),
minexptime = 1,
maxexptime = 1,
minsize = 0.5,
minexptime = 3,
maxexptime = 5,
minsize = 2,
maxsize = 5,
collisiondetection = true,
collision_removal = true,
@ -70,13 +70,13 @@ minetest.register_globalstep(function(dtime)
end
for _, player in pairs(get_connected_players()) do
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos()) or not mcl_weather.is_outdoor(player:get_pos())) then
if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos()) then
mcl_weather.remove_spawners_player(player)
return false
end
for i=1,2 do
psdef.texture="weather_pack_snow_snowflake"..i..".png"
mcl_weather.add_spawner_player(player,"snow"..i,psdef)
else
for i=1,2 do
psdef.texture="weather_pack_snow_snowflake"..i..".png"
mcl_weather.add_spawner_player(player,"snow"..i,psdef)
end
end
end
end)

View File

@ -101,6 +101,17 @@ awards.register_achievement("mcl:bookcase", {
}
})
awards.register_achievement("mcl:buildIronPickaxe", {
title = S("Isn't It Iron Pick"),
description = S("Craft a iron pickaxe using sticks and iron."),
icon = "default_tool_steelpick.png",
trigger = {
type = "craft",
item = "mcl_tools:pick_iron",
target = 1
}
})
-- Item pickup achievements: These are awarded when picking up a certain item.
-- The achivements are manually given in the mod mcl_item_entity.
awards.register_achievement("mcl:diamonds", {
@ -125,6 +136,18 @@ awards.register_achievement("mcl:mineWood", {
icon = "default_tree.png",
})
awards.register_achievement("mcl:whosCuttingOnions", {
title = S("Who is Cutting Onions?"),
description = S("Pick up a crying obsidian from the floor."),
icon = "default_obsidian.png^mcl_core_crying_obsidian.png",
})
awards.register_achievement("mcl:hiddenInTheDepths", {
title = S("Hidden in the Depths"),
description = S("Pick up an Ancient Debris from the floor."),
icon = "mcl_nether_ancient_debris_side.png",
})
-- Smelting achivements: These are awarded when picking up an item from a furnace
-- output. They are given in mcl_furnaces.
awards.register_achievement("mcl:acquireIron", {
@ -158,9 +181,89 @@ awards.register_achievement("mcl:snipeSkeleton", {
-- Triggered in mcl_portals
awards.register_achievement("mcl:buildNetherPortal", {
title = S("Into the Nether"),
title = S("We Need to Go Deeper"),
description = S("Use obsidian and a fire starter to construct a Nether portal."),
icon = "default_obsidian.png",
icon = "mcl_fire_flint_and_steel.png",
})
awards.register_achievement("mcl:enterEndPortal", {
title = S("The End?"),
description = S("Or the beginning?\nHint: Enter an end portal."),
icon = "mcl_end_end_stone.png",
})
awards.register_achievement("mcl:theNether", {
title = S("The Nether"),
description = S("Bring summer clothes.\nHint: Enter the Nether."),
icon = "mcl_nether_netherrack.png",
})
-- Triggered in mcl_totems
awards.register_achievement("mcl:postMortal", {
title = S("Postmortal"),
description = S("Use a Totem of Undying to cheat death."),
icon = "mcl_totems_totem.png",
})
-- Triggered in mcl_beds
awards.register_achievement("mcl:sweetDreams", {
title = S("Sweet Dreams"),
description = S("Sleep in a bed to change your respawn point."),
icon = "mcl_beds_bed_red.png",
})
awards.register_achievement("mcl:notQuiteNineLives", {
title = S('Not Quite "Nine" Lives'),
description = S("Charge a Respawn Anchor to the maximum."),
icon = "respawn_anchor_side4.png",
})
-- Triggered in mobs_mc
awards.register_achievement("mcl:whatAdeal", {
title = S("What A Deal!"),
description = S("Successfully trade with a Villager."),
icon = "mcl_core_emerald.png",
})
awards.register_achievement("mcl:tacticalFishing", {
title = S("Tactical Fishing"),
description = S("Catch a fish... without a fishing rod!"),
icon = "pufferfish_bucket.png",
})
-- Triggered in mcl_fishing
awards.register_achievement("mcl:fishyBusiness", {
title = S("Fishy Business"),
description = S("Catch a fish.\nHint: Catch a fish, salmon, clownfish, or pufferfish."),
icon = "mcl_fishing_fishing_rod.png",
})
-- Triggered in mcl_compass
awards.register_achievement("mcl:countryLode", {
title = S("Country Lode,\nTake Me Home"),
description = S("Use a compass on a Lodestone."),
icon = "lodestone_side4.png",
})
-- Triggered in mcl_smithing_table
awards.register_achievement("mcl:seriousDedication", {
title = S("Serious Dedication"),
description = S("Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices."),
icon = "farming_tool_netheritehoe.png",
})
-- Triggered in mcl_brewing
awards.register_achievement("mcl:localBrewery", {
title = S("Local Brewery"),
description = S("Brew a Potion.\nHint: Take a potion or glass bottle out of the brewing stand."),
icon = "mcl_potions_potion_overlay.png^[colorize:#F82423:"..tostring(127).."^mcl_potions_potion_bottle.png",
})
-- Triggered in mcl_enchanting
awards.register_achievement("mcl:enchanter", {
title = S("Enchanter"),
description = S("Enchant an item using an Enchantment Table."),
icon = "mcl_enchanting_book_enchanted.png",
})
-- NON-PC ACHIEVEMENTS (XBox, Pocket Edition, etc.)

View File

@ -19,7 +19,7 @@ Getting an Upgrade=
Hit a skeleton, wither skeleton or stray by bow and arrow from a distance of at least 20 meters.=
Hot Topic=
Into Fire=
Into the Nether=
We Need to Go Deeper=
Iron Belly=
Librarian=
Mine emerald ore.=
@ -47,3 +47,29 @@ Use a crafting table to craft a wooden hoe from wooden planks and sticks.=
Use a crafting table to craft a wooden pickaxe from wooden planks and sticks.=
Use obsidian and a fire starter to construct a Nether portal.=
Use wheat to craft a bread.=
Who is Cutting Onions?=
Pick up a crying obsidian from the floor.=
Hidden in the Depths=
Pick up an Ancient Debris from the floor.=
The Nether=
Bring summer clothes.@nHint: Enter the Nether.=
Isn't It Iron Pick=
Craft a iron pickaxe using sticks and iron.=
Postmortal=
Use a Totem of Undying to cheat death.=
Sweet Dreams=
Sleep in a bed to change your respawn point.=
Not Quite "Nine" Lives=
Charge a Respawn Anchor to the maximum.=
What A Deal!=
Successfully trade with a Villager.=
Fishy Business=
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=
Country Lode,@nTake Me Home=
Use a compass on a Lodestone.=
Serious Dedication=
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=
Local Brewery=
Brew a Potion.@nHint: Take a potion or glass bottle out of the brewing stand.=
Enchanter=
Enchant an item using an Enchantment Table.=

View File

@ -156,33 +156,20 @@ function mcl_experience.throw_xp(pos, total_xp)
end
end
function mcl_experience.update(player)
local xp = mcl_experience.get_xp(player)
local cache = caches[player]
cache.level = xp_to_level(xp)
if not minetest.is_creative_enabled(player:get_player_name()) then
player:hud_change(hud_bars[player], "text", "mcl_experience_bar_background.png^[lowpart:"
.. math.floor(math.floor(xp_to_bar(xp, cache.level) * 18) / 18 * 100)
.. ":mcl_experience_bar.png^[transformR270"
)
if cache.level == 0 then
player:hud_change(hud_levels[player], "text", "")
else
player:hud_change(hud_levels[player], "text", tostring(cache.level))
end
function mcl_experience.remove_hud(player)
if hud_bars[player] then
player:hud_remove(hud_bars[player])
hud_bars[player] = nil
end
if hud_levels[player] then
player:hud_remove(hud_levels[player])
hud_levels[player] = nil
end
end
function mcl_experience.register_on_add_xp(func, priority)
table.insert(mcl_experience.on_add_xp, {func = func, priority = priority or 0})
end
-- callbacks
minetest.register_on_joinplayer(function(player)
function mcl_experience.setup_hud(player)
if hud_bars[player] and hud_levels[player] then return end
mcl_experience.remove_hud(player)
caches[player] = {
last_time = get_time(),
}
@ -205,7 +192,39 @@ minetest.register_on_joinplayer(function(player)
z_index = 12,
})
end
end
function mcl_experience.update(player)
local xp = mcl_experience.get_xp(player)
local cache = caches[player]
cache.level = xp_to_level(xp)
if not minetest.is_creative_enabled(player:get_player_name()) then
if not hud_bars[player] then
mcl_experience.setup_hud(player)
end
player:hud_change(hud_bars[player], "text", "mcl_experience_bar_background.png^[lowpart:"
.. math.floor(math.floor(xp_to_bar(xp, cache.level) * 18) / 18 * 100)
.. ":mcl_experience_bar.png^[transformR270"
)
if cache.level == 0 then
player:hud_change(hud_levels[player], "text", "")
else
player:hud_change(hud_levels[player], "text", tostring(cache.level))
end
end
end
function mcl_experience.register_on_add_xp(func, priority)
table.insert(mcl_experience.on_add_xp, {func = func, priority = priority or 0})
end
-- callbacks
minetest.register_on_joinplayer(function(player)
mcl_experience.setup_hud(player)
mcl_experience.update(player)
end)

View File

@ -206,6 +206,12 @@ local gamemodes = {
function mcl_inventory.player_set_gamemode(p,g)
local m = p:get_meta()
m:set_string("gamemode",g)
if g == "survival" then
mcl_experience.setup_hud(p)
mcl_experience.update(p)
elseif g == "creative" then
mcl_experience.remove_hud(p)
end
set_inventory(p)
end

View File

@ -59,8 +59,9 @@ minetest.register_globalstep(function(dtime)
local itemstack = mcl_offhand.get_offhand(player)
local offhand_item = itemstack:get_name()
local offhand_hud = mcl_offhand[player].hud
if offhand_item ~= "" then
local item_texture = minetest.registered_items[offhand_item].inventory_image .. "^[resize:" .. max_offhand_px .. "x" .. max_offhand_px
local item = minetest.registered_items[offhand_item]
if offhand_item ~= "" and item then
local item_texture = item.inventory_image .. "^[resize:" .. max_offhand_px .. "x" .. max_offhand_px
local position = {x = 0.5, y = 1}
local offset = {x = -320, y = -32}

View File

@ -117,7 +117,6 @@ for _, def in pairs(bud_def) do
walkable = false,
light_source = def.light_source,
groups = {
dig_by_water = 1,
destroy_by_lava_flow = 1,
dig_by_piston = 1,
pickaxey = 1,
@ -162,7 +161,6 @@ minetest.register_node("mcl_amethyst:amethyst_cluster",{
walkable = false,
light_source = 7,
groups = {
dig_by_water = 1,
destroy_by_lava_flow = 1,
dig_by_piston = 1,
pickaxey = 1,

View File

@ -84,6 +84,19 @@ local function distinguish_tool_and_material(input1, input2)
end
end
-- Helper function to make sure update_anvil_slots NEVER overstacks the output slot
local function fix_stack_size(stack)
if not stack or stack == "" then return "" end
local count = stack:get_count()
local max_count = stack:get_stack_max()
if count > max_count then
stack:set_count(max_count)
count = max_count
end
return count
end
-- Update the inventory slots of an anvil node.
-- meta: Metadata of anvil node
local function update_anvil_slots(meta)
@ -213,6 +226,7 @@ local function update_anvil_slots(meta)
-- Set the new output slot
if new_output then
fix_stack_size(new_output)
inv:set_stack("output", 1, new_output)
end
end

View File

@ -114,6 +114,10 @@ function mcl_armor.register_set(def)
for k, v in pairs(element_groups) do
groups[k] = v
end
local upgrade_item = nil
if def._mcl_upgradable and def._mcl_upgrade_item_material then
upgrade_item = itemstring:gsub("_[%l%d]*$",def._mcl_upgrade_item_material)
end
minetest.register_tool(itemstring, {
description = S(def.description .. " " .. (descriptions[name] or element.description)),
@ -133,6 +137,8 @@ function mcl_armor.register_set(def)
_on_break = on_break_callbacks[name] or def.on_break,
_mcl_armor_element = name,
_mcl_armor_texture = textures[name] or modname .. "_" .. itemname .. ".png",
_mcl_upgradable = def._mcl_upgradable,
_mcl_upgrade_item = upgrade_item
})
if def.craft_material then

View File

@ -49,6 +49,8 @@ mcl_armor.register_set({
},
repair_material = "mcl_core:iron_ingot",
cook_material = "mcl_core:iron_nugget",
sound_equip = "mcl_armor_equip_iron",
sound_unequip = "mcl_armor_unequip_iron",
})
mcl_armor.register_set({
@ -64,6 +66,8 @@ mcl_armor.register_set({
},
craft_material = "mcl_core:iron_ingot",
cook_material = "mcl_core:iron_nugget",
sound_equip = "mcl_armor_equip_iron",
sound_unequip = "mcl_armor_unequip_iron",
})
mcl_armor.register_set({
@ -79,6 +83,27 @@ mcl_armor.register_set({
},
toughness = 2,
craft_material = "mcl_core:diamond",
sound_equip = "mcl_armor_equip_diamond",
sound_unequip = "mcl_armor_unequip_diamond",
_mcl_upgradable = true,
_mcl_upgrade_item_material = "_netherite",
})
mcl_armor.register_set({
name = "netherite",
description = "Netherite",
durability = 555,
enchantability = 10,
points = {
head = 3,
torso = 8,
legs = 6,
feet = 3,
},
toughness = 2,
craft_material = "mcl_nether:netherite_ingot",
sound_equip = "mcl_armor_equip_diamond",
sound_unequip = "mcl_armor_unequip_diamond",
})
mcl_armor.register_protection_enchantment({

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

View File

@ -76,6 +76,7 @@ local function lay_down(player, pos, bed_pos, state, skip)
-- save respawn position when entering bed
if spawn_mod and mcl_spawn.set_spawn_pos(player, bed_pos, nil) then
minetest.chat_send_player(name, S("New respawn position set!"))
awards.unlock(player:get_player_name(), "mcl:sweetDreams")
end
-- No sleeping if too far away

View File

@ -39,6 +39,9 @@ for i=0,4 do
elseif string.match(node.name, "mcl_beds:respawn_anchor_charged_") then
minetest.chat_send_player(player.get_player_name(player), S"New respawn position set!")
mcl_spawn.set_spawn_pos(player, pos, nil)
if i == 4 then
awards.unlock(player:get_player_name(), "mcl:notQuiteNineLives")
end
end
end
@ -88,11 +91,11 @@ for i=0,4 do
end
minetest.register_craft({ --TODO: Please change this crafting recipe once crying obsidian is implemented!
minetest.register_craft({
output = "mcl_beds:respawn_anchor",
recipe = {
{"mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian"},
{"mcl_core:crying_obsidian", "mcl_core:crying_obsidian", "mcl_core:crying_obsidian"},
{"mcl_nether:glowstone", "mcl_nether:glowstone", "mcl_nether:glowstone"},
{"mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian"}
{"mcl_core:crying_obsidian", "mcl_core:crying_obsidian", "mcl_core:crying_obsidian"}
}
})

View File

@ -35,10 +35,14 @@ minetest.register_node("mcl_bells:bell", {
is_ground_content = false,
groups = {pickaxey=2, deco_block=1 },
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_blast_resistance = 5,
_mcl_hardness = 5,
on_rightclick = mcl_bells.ring_once,
use_texture_alpha = "clip",
mesecons = {effector = {
action_on = mcl_bells.ring_once,
rules = mesecon.rules.flat,
}},
})
if has_mcl_wip then

View File

@ -1,2 +1,3 @@
name = mcl_bells
optional_depends = mcl_wip
depends = mesecons
optional_depends = mcl_wip

View File

@ -13,8 +13,8 @@ minetest.register_node("mcl_blackstone:blackstone", {
sounds = mcl_sounds.node_sound_stone_defaults(),
is_ground_content = false,
groups = {cracky = 3, pickaxey=2, material_stone=1, cobble=1},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_blast_resistance = 6,
_mcl_hardness = 1.5,
})
minetest.register_node("mcl_blackstone:blackstone_gilded", {
description = S("Gilded Blackstone"),
@ -53,8 +53,8 @@ minetest.register_node("mcl_blackstone:nether_gold", {
{items = {"mcl_blackstone:nether_gold"}, rarity = 8},
}
},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_blast_resistance = 3,
_mcl_hardness = 3,
_mcl_silk_touch_drop = true,
_mcl_fortune_drop = mcl_core.fortune_drop_ore,
})
@ -67,8 +67,8 @@ minetest.register_node("mcl_blackstone:basalt_polished", {
on_rotate = on_rotate,
is_ground_content = false,
groups = {cracky = 3, pickaxey=2, material_stone=1},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_blast_resistance = 4.2,
_mcl_hardness = 1.25,
})
minetest.register_node("mcl_blackstone:basalt", {
description = S("Basalt"),
@ -79,8 +79,17 @@ minetest.register_node("mcl_blackstone:basalt", {
on_rotate = on_rotate,
is_ground_content = false,
groups = {cracky = 3, pickaxey=2, material_stone=1},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_blast_resistance = 4.2,
_mcl_hardness = 1.25,
})
minetest.register_node("mcl_blackstone:basalt_smooth", {
description = S("Smooth Basalt"),
tiles = {"mcl_blackstone_basalt_smooth.png"},
sounds = mcl_sounds.node_sound_stone_defaults(),
is_ground_content = false,
groups = {cracky = 3, pickaxey=2, material_stone=1},
_mcl_blast_resistance = 4.2,
_mcl_hardness = 1.25,
})
minetest.register_node("mcl_blackstone:blackstone_polished", {
description = S("Polished Blackstone"),
@ -88,7 +97,7 @@ minetest.register_node("mcl_blackstone:blackstone_polished", {
sounds = mcl_sounds.node_sound_stone_defaults(),
is_ground_content = false,
groups = {cracky = 3, pickaxey=2, material_stone=1},
_mcl_blast_resistance = 2,
_mcl_blast_resistance = 6,
_mcl_hardness = 2,
})
minetest.register_node("mcl_blackstone:blackstone_chiseled_polished", {
@ -97,8 +106,8 @@ minetest.register_node("mcl_blackstone:blackstone_chiseled_polished", {
sounds = mcl_sounds.node_sound_stone_defaults(),
is_ground_content = false,
groups = {cracky = 3, pickaxey=2, material_stone=1},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_blast_resistance = 6,
_mcl_hardness = 1.5,
})
minetest.register_node("mcl_blackstone:blackstone_brick_polished", {
description = S("Polished Blackstone Bricks"),
@ -106,8 +115,8 @@ minetest.register_node("mcl_blackstone:blackstone_brick_polished", {
sounds = mcl_sounds.node_sound_stone_defaults(),
is_ground_content = false,
groups = {cracky = 3, pickaxey=2, material_stone=1},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_blast_resistance = 6,
_mcl_hardness = 1.5,
})
minetest.register_node("mcl_blackstone:quartz_brick", {
description = S("Quartz Bricks"),
@ -116,8 +125,8 @@ minetest.register_node("mcl_blackstone:quartz_brick", {
is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(),
groups = {cracky = 3, pickaxey=2, material_stone=1},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_blast_resistance = 0.8,
_mcl_hardness = 0.8,
})
minetest.register_node("mcl_blackstone:soul_soil", {
description = S("Soul Soil"),
@ -314,36 +323,7 @@ for s=1, #specialstones do
end
if minetest.settings:get_bool("mcl_generate_ores", true) then
minetest.register_ore({
ore_type = "scatter",
ore = "mcl_blackstone:blackstone_gilded",
wherein = "mcl_blackstone:blackstone",
clust_scarcity = 4775,
clust_num_ores = 2,
clust_size = 2,
y_min = mcl_vars.mg_nether_min,
y_max = mcl_vars.mg_nether_max,
})
minetest.register_ore({
ore_type = "scatter",
ore = "mcl_blackstone:nether_gold",
wherein = "mcl_nether:netherrack",
clust_scarcity = 830,
clust_num_ores = 5,
clust_size = 3,
y_min = mcl_vars.mg_nether_min,
y_max = mcl_vars.mg_nether_max,
})
minetest.register_ore({
ore_type = "scatter",
ore = "mcl_blackstone:nether_gold",
wherein = "mcl_nether:netherrack",
clust_scarcity = 1660,
clust_num_ores = 4,
clust_size = 2,
y_min = mcl_vars.mg_nether_min,
y_max = mcl_vars.mg_nether_max,
})
end
--]]
--soul torch

View File

@ -288,7 +288,8 @@ local function blast_furnace_node_timer(pos, elapsed)
-- Cooking
--
local el = elapsed_game_time
-- Run the blast_furnace at twice the speed of a furnace.
local el = elapsed_game_time * 2
-- Check if we have cookable content: cookable
local aftercooked
@ -329,13 +330,12 @@ local function blast_furnace_node_timer(pos, elapsed)
elseif active then
el = math.min(el, fuel_totaltime - fuel_time)
-- The furnace is currently active and has enough fuel
fuel_time = (fuel_time + el) *2 --multiply speed of fuel consumption to match proper output
fuel_time = fuel_time + el
end
-- If there is a cookable item then check if it is ready yet
if cookable and active then
-- In the src_time variable, the *2 is the multiplication that makes the blast furnace work faster than a normal furnace.
src_time = (src_time + el)*2
src_time = src_time + el
-- Place result in dst list if done
if src_time >= cooked.time then
inv:add_item("dst", cooked.item)

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