mirror of
https://codeberg.org/tenplus1/mobs_redo.git
synced 2025-09-07 08:35:23 +02:00
Compare commits
54 Commits
be7b6bc5fe
...
e8e774566b
Author | SHA1 | Date | |
---|---|---|---|
|
e8e774566b | ||
|
e55bf4d951 | ||
|
f1b5a66049 | ||
|
26215cd221 | ||
|
29314186b3 | ||
|
dce2abfcfe | ||
|
e561864e82 | ||
|
59c19fca98 | ||
|
a8297e6a8e | ||
|
bc6b8931da | ||
|
3e24677649 | ||
|
57d6859b93 | ||
|
1f6867bf25 | ||
|
b1da38456d | ||
|
341f92f118 | ||
|
c3d74394a7 | ||
|
964451fd78 | ||
|
ef9f492bad | ||
|
79c85e0551 | ||
|
cc14704651 | ||
|
8115f61ac9 | ||
|
77b53b9054 | ||
|
fc7269cc8c | ||
|
fb2a247d31 | ||
|
03fbe477c3 | ||
|
91be60be9b | ||
|
e11f383589 | ||
|
313382dcaa | ||
|
1536b9a5fc | ||
|
be2d630fdf | ||
|
99bea53af3 | ||
|
d20dfa0b41 | ||
|
e9180febc6 | ||
|
c4561a2207 | ||
|
998637fc3d | ||
|
de0914312c | ||
|
5a6ec7080f | ||
|
129b24b159 | ||
|
35cc60c355 | ||
|
903b1e34df | ||
|
87d13c857f | ||
|
17dafff8ef | ||
|
95f3e98867 | ||
|
b3b89e6dea | ||
|
822e78fd32 | ||
|
dd9b3d7add | ||
|
d4a25064ea | ||
|
70118fc8da | ||
|
7c7a7345af | ||
|
ceefbcec39 | ||
|
97771f8e65 | ||
|
1cacb02a6a | ||
|
47e91b9b6b | ||
|
a6a3b44c96 |
175
api.txt
175
api.txt
@@ -83,6 +83,8 @@ functions needed for the mob to work properly which contains the following:
|
||||
'lava_damage' holds the damage per second inflicted to mobs when standing
|
||||
in lava.
|
||||
'fire_damage' holds the damage per second inflicted to mobs when standing
|
||||
'node_damage' True by default, will harm mobs when inside damage_per_second
|
||||
nodes.
|
||||
in fire.
|
||||
|
||||
'light_damage' holds the damage per second inflicted to mobs when light
|
||||
@@ -109,6 +111,7 @@ functions needed for the mob to work properly which contains the following:
|
||||
'attack_animals' when true mob will attack animals.
|
||||
'attack_npcs' when true mob will attack npcs within range.
|
||||
'attack_players' when true mob will attack players nearby.
|
||||
'attack_ignore' string or table of mob names not to attack.
|
||||
'owner_loyal' when true non-docile tamed mobs attack anything player
|
||||
punches when nearby.
|
||||
'group_attack' when true has same mob type grouping together to attack
|
||||
@@ -333,6 +336,8 @@ enhance mob functionality and have them do many interesting things:
|
||||
is returned normal attack function continued.
|
||||
'on_die' a function that is called when mob is killed (self, pos), also
|
||||
has access to self.cause_of_death table.
|
||||
'on_death' Official engine version of above when mob killed (self, killer),
|
||||
'killer' is only returned if player killed the mob.
|
||||
'on_flop' function called when flying or swimmimng mob is no longer in
|
||||
air/water, (self) paramater and return true to skip the built
|
||||
in api flop feature.
|
||||
@@ -340,6 +345,17 @@ enhance mob functionality and have them do many interesting things:
|
||||
active and which has access to all of the self.* variables
|
||||
e.g. (self.health for health or self.standing_in for node
|
||||
status), return with 'false' to skip remainder of mob API.
|
||||
'on_sound' (self, def) called when mob is inside the hearing distance of
|
||||
a sound, passes a def table containing:
|
||||
'sound' the sound being played,
|
||||
'pos' position the sound originated,
|
||||
'gain' original gain of sound,
|
||||
'distance' distance of mob from sound source,
|
||||
'loudness' how loud sound is to mob (0 = cant hear, 1.0 = near sound), this
|
||||
would be used as the main value inside on_sound function,
|
||||
'player' player name sound originated,
|
||||
'object' object reference sound originated,
|
||||
'max_hear_distance' max distance sound can be heard from source.
|
||||
|
||||
|
||||
Internal Variables
|
||||
@@ -397,7 +413,8 @@ Each mob contains a set of functions that can be called for use internally or fr
|
||||
another mod entirely, replace mob_class with the mob entity variable:
|
||||
|
||||
mob_class:mob_sound(sound) -- play sound at mob position
|
||||
mob_class:do_attack(player) -- if not already attacking, attack object given
|
||||
mob_class:do_attack(player [, force]) -- if not already attacking, attack object given,
|
||||
forced being true stops attacking current target and focuses on one given
|
||||
mob_class:stop_attack() -- stops mob attacking
|
||||
mob_class:collision() -- checks for player collision with mob and returns {x, z} vector
|
||||
mob_class:set_velocity(velocity) -- move at velocity in the facing direction
|
||||
@@ -414,7 +431,9 @@ mob_class:day_docile() -- return True if mob docile during current daytime
|
||||
mob_class:mob_expire(pos, dtime) -- check if mob is to despawn
|
||||
mob_class:get_nodes() -- get specific nodes around mob
|
||||
mob_class:on_blast(damage) -- function called when mob in blast area
|
||||
mob_class:is_inside(itemtable) -- returns True is mob collisionbox inside any node/group in table
|
||||
mob_class:is_inside(itemtable) -- returns True is mob collisionbox inside any node/group
|
||||
in table
|
||||
mob_class:go_to(pos) -- makes mob go to that position or nearby
|
||||
|
||||
|
||||
Adding Mobs in World
|
||||
@@ -541,7 +560,9 @@ This function registers a arrow for mobs with the attack type shoot.
|
||||
'textures' same is in minetest.register_entity()
|
||||
'collide_with_objects' same as above
|
||||
'velocity' the velocity of the arrow
|
||||
'drop' if set to true any arrows hitting a node will drop as item
|
||||
'drop' if set to true any arrows hitting a node will drop as item,
|
||||
if number given then chance (1/num) of item dropping will
|
||||
be used. arrow "mymob:myarrow" will use item of same name.
|
||||
'hit_player' a function that is called when the arrow hits a player;
|
||||
this function should hurt the player, the parameters are
|
||||
(self, player)
|
||||
@@ -811,6 +832,7 @@ External Settings for "minetest.conf"
|
||||
'mobs_drop_items' when false mobs no longer drop items when they die.
|
||||
'mobs_griefing' when false mobs cannot break blocks when using either
|
||||
pathfinding level 2, replace functions or mobs:boom
|
||||
'mobs_can_hear' True by default, allows mobs to hear sound around them.
|
||||
function.
|
||||
'mob_nospawn_range' Minimum range a mob can spawn near player (def: 12)
|
||||
'mob_active_limit' Number of active mobs in game, 0 for unlimited
|
||||
@@ -821,7 +843,6 @@ External Settings for "minetest.conf"
|
||||
'mob_height_fix' Enabled by default, increases smaller mob heights so they wont
|
||||
glitch through certain nodes.
|
||||
'mob_pathfinding_enable' Enable pathfinding.
|
||||
'mob_pathfinder_enable' Use pathfinder mod if available.
|
||||
'mob_pathfinding_stuck_timeout' How long before stuck mobs start searching. (default 3.0)
|
||||
'mob_pathfinding_stuck_path_timeout' How long will mob follow path before giving up. (default 5.0)
|
||||
'mob_pathfinding_algorithm' Which pathfinding algorithm to use Dijkstra (default), A*_noprefetch (AStar_noprefetch) or A* (AStar)
|
||||
@@ -844,130 +865,28 @@ mobs_animal:cow = 8000,4 <-- 4 cows per mapblock at 8000 spawn chance
|
||||
mobs_monster:dirt_monster = ,20 <-- 20 dirt monsters per mapblock
|
||||
|
||||
|
||||
Node Sounds
|
||||
-----------
|
||||
|
||||
Mobs Redo will detect wether the Default mod or MineClone/VoxeLibre mod is active and
|
||||
store whichever sound set is available inside the following to save any mob mobs
|
||||
having to detect it themselves:
|
||||
|
||||
mobs.node_sound_defaults()
|
||||
mobs.node_sound_stone_defaults()
|
||||
mobs.node_sound_dirt_defaults()
|
||||
mobs.node_sound_sand_defaults()
|
||||
mobs.node_sound_gravel_defaults()
|
||||
mobs.node_sound_wood_defaults()
|
||||
mobs.node_sound_leaves_defaults()
|
||||
mobs.node_sound_ice_defaults()
|
||||
mobs.node_sound_metal_defaults()
|
||||
mobs.node_sound_water_defaults()
|
||||
mobs.node_sound_snow_defaults()
|
||||
mobs.node_sound_glass_defaults()
|
||||
|
||||
|
||||
Rideable Horse Example Mob
|
||||
--------------------------
|
||||
|
||||
mobs:register_mob("mob_horse:horse", {
|
||||
type = "animal",
|
||||
visual = "mesh",
|
||||
visual_size = {x = 1.20, y = 1.20},
|
||||
mesh = "mobs_horse.x",
|
||||
collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.25, 0.4},
|
||||
animation = {
|
||||
speed_normal = 15,
|
||||
speed_run = 30,
|
||||
stand_start = 25,
|
||||
stand_end = 75,
|
||||
walk_start = 75,
|
||||
walk_end = 100,
|
||||
run_start = 75,
|
||||
run_end = 100,
|
||||
},
|
||||
textures = {
|
||||
{"mobs_horse.png"},
|
||||
{"mobs_horsepeg.png"},
|
||||
{"mobs_horseara.png"}
|
||||
},
|
||||
fear_height = 3,
|
||||
runaway = true,
|
||||
fly = false,
|
||||
walk_chance = 60,
|
||||
view_range = 5,
|
||||
follow = {"farming:wheat"},
|
||||
passive = true,
|
||||
hp_min = 12,
|
||||
hp_max = 16,
|
||||
armor = 200,
|
||||
lava_damage = 5,
|
||||
fall_damage = 5,
|
||||
water_damage = 1,
|
||||
makes_footstep_sound = true,
|
||||
drops = {
|
||||
{name = "mobs:meat_raw", chance = 1, min = 2, max = 3}
|
||||
},
|
||||
sounds = {
|
||||
random = "horse_neigh.ogg",
|
||||
damage = "horse_whinney.ogg",
|
||||
},
|
||||
|
||||
do_custom = function(self, dtime)
|
||||
|
||||
-- set needed values if not already present
|
||||
if not self.v2 then
|
||||
self.v2 = 0
|
||||
self.max_speed_forward = 6
|
||||
self.max_speed_reverse = 2
|
||||
self.accel = 6
|
||||
self.terrain_type = 3
|
||||
self.driver_attach_at = {x = 0, y = 20, z = -2}
|
||||
self.driver_eye_offset = {x = 0, y = 3, z = 0}
|
||||
self.driver_scale = {x = 1, y = 1}
|
||||
end
|
||||
|
||||
-- if driver present allow control of horse
|
||||
if self.driver then
|
||||
|
||||
mobs.drive(self, "walk", "stand", false, dtime)
|
||||
|
||||
return false -- skip rest of mob functions
|
||||
end
|
||||
|
||||
return true
|
||||
end,
|
||||
|
||||
on_die = function(self, pos)
|
||||
|
||||
-- drop saddle when horse is killed while riding
|
||||
-- also detach from horse properly
|
||||
if self.driver then
|
||||
minetest.add_item(pos, "mobs:saddle")
|
||||
mobs.detach(self.driver, {x = 1, y = 0, z = 1})
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
|
||||
-- make sure player is clicking
|
||||
if not clicker or not clicker:is_player() then
|
||||
return
|
||||
end
|
||||
|
||||
-- feed, tame or heal horse
|
||||
if mobs:feed_tame(self, clicker, 10, true, true) then
|
||||
return
|
||||
end
|
||||
|
||||
-- make sure tamed horse is being clicked by owner only
|
||||
if self.tamed and self.owner == clicker:get_player_name() then
|
||||
|
||||
local inv = clicker:get_inventory()
|
||||
|
||||
-- detatch player already riding horse
|
||||
if self.driver and clicker == self.driver then
|
||||
|
||||
mobs.detach(clicker, {x = 1, y = 0, z = 1})
|
||||
|
||||
-- add saddle back to inventory
|
||||
if inv:room_for_item("main", "mobs:saddle") then
|
||||
inv:add_item("main", "mobs:saddle")
|
||||
else
|
||||
minetest.add_item(clicker.get_pos(), "mobs:saddle")
|
||||
end
|
||||
|
||||
-- attach player to horse
|
||||
elseif not self.driver
|
||||
and clicker:get_wielded_item():get_name() == "mobs:saddle" then
|
||||
|
||||
self.object:set_properties({stepheight = 1.1})
|
||||
mobs.attach(self, clicker)
|
||||
|
||||
-- take saddle from inventory
|
||||
inv:remove_item("main", "mobs:saddle")
|
||||
end
|
||||
end
|
||||
|
||||
-- used to capture horse with magic lasso
|
||||
mobs:capture_mob(self, clicker, 0, 0, 80, false, nil)
|
||||
end
|
||||
})
|
||||
See mob_horse mod https://codeberg.org/tenplus1/mob_horse
|
||||
|
215
crafts.lua
215
crafts.lua
@@ -1,9 +1,48 @@
|
||||
|
||||
local S = mobs.translate
|
||||
local S = minetest.get_translator("mobs")
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
local mc2 = minetest.get_modpath("mcl_core")
|
||||
local mod_def = minetest.get_modpath("default")
|
||||
|
||||
-- determine which sounds to use, default or mcl_sounds
|
||||
|
||||
local function sound_helper(snd)
|
||||
|
||||
mobs[snd] = (mod_def and default[snd]) or (mc2 and mcl_sounds[snd])
|
||||
or function() return {} end
|
||||
end
|
||||
|
||||
sound_helper("node_sound_defaults")
|
||||
sound_helper("node_sound_stone_defaults")
|
||||
sound_helper("node_sound_dirt_defaults")
|
||||
sound_helper("node_sound_sand_defaults")
|
||||
sound_helper("node_sound_gravel_defaults")
|
||||
sound_helper("node_sound_wood_defaults")
|
||||
sound_helper("node_sound_leaves_defaults")
|
||||
sound_helper("node_sound_ice_defaults")
|
||||
sound_helper("node_sound_metal_defaults")
|
||||
sound_helper("node_sound_water_defaults")
|
||||
sound_helper("node_sound_snow_defaults")
|
||||
sound_helper("node_sound_glass_defaults")
|
||||
|
||||
-- helper function to add {eatable} group to food items
|
||||
|
||||
function mobs.add_eatable(item, hp)
|
||||
|
||||
local def = minetest.registered_items[item]
|
||||
|
||||
if def then
|
||||
|
||||
local groups = table.copy(def.groups) or {}
|
||||
|
||||
groups.eatable = hp ; groups.flammable = 2
|
||||
|
||||
minetest.override_item(item, {groups = groups})
|
||||
end
|
||||
end
|
||||
|
||||
-- recipe items
|
||||
|
||||
local items = {
|
||||
paper = mc2 and "mcl_core:paper" or "default:paper",
|
||||
dye_black = mc2 and "mcl_dye:black" or "dye:black",
|
||||
@@ -22,8 +61,9 @@ local items = {
|
||||
}
|
||||
|
||||
-- name tag
|
||||
|
||||
minetest.register_craftitem("mobs:nametag", {
|
||||
description = S("Name Tag"),
|
||||
description = S("Name Tag") .. " " .. S("\nRight-click Mobs Redo mob to apply"),
|
||||
inventory_image = "mobs_nametag.png",
|
||||
groups = {flammable = 2, nametag = 1}
|
||||
})
|
||||
@@ -36,6 +76,7 @@ minetest.register_craft({
|
||||
})
|
||||
|
||||
-- leather
|
||||
|
||||
minetest.register_craftitem("mobs:leather", {
|
||||
description = S("Leather"),
|
||||
inventory_image = "mobs_leather.png",
|
||||
@@ -43,21 +84,27 @@ minetest.register_craftitem("mobs:leather", {
|
||||
})
|
||||
|
||||
-- raw meat
|
||||
|
||||
minetest.register_craftitem("mobs:meat_raw", {
|
||||
description = S("Raw Meat"),
|
||||
inventory_image = "mobs_meat_raw.png",
|
||||
on_use = minetest.item_eat(3),
|
||||
groups = {food_meat_raw = 1, flammable = 2}
|
||||
groups = {food_meat_raw = 1}
|
||||
})
|
||||
|
||||
mobs.add_eatable("mobs:meat_raw", 3)
|
||||
|
||||
-- cooked meat
|
||||
|
||||
minetest.register_craftitem("mobs:meat", {
|
||||
description = S("Meat"),
|
||||
inventory_image = "mobs_meat.png",
|
||||
on_use = minetest.item_eat(8),
|
||||
groups = {food_meat = 1, flammable = 2}
|
||||
groups = {food_meat = 1}
|
||||
})
|
||||
|
||||
mobs.add_eatable("mobs:meat", 8)
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = "mobs:meat",
|
||||
@@ -66,6 +113,7 @@ minetest.register_craft({
|
||||
})
|
||||
|
||||
-- lasso
|
||||
|
||||
minetest.register_tool("mobs:lasso", {
|
||||
description = S("Lasso (right-click animal to put in inventory)"),
|
||||
inventory_image = "mobs_magic_lasso.png",
|
||||
@@ -84,6 +132,7 @@ minetest.register_craft({
|
||||
minetest.register_alias("mobs:magic_lasso", "mobs:lasso")
|
||||
|
||||
-- net
|
||||
|
||||
minetest.register_tool("mobs:net", {
|
||||
description = S("Net (right-click animal to put in inventory)"),
|
||||
inventory_image = "mobs_net.png",
|
||||
@@ -100,6 +149,7 @@ minetest.register_craft({
|
||||
})
|
||||
|
||||
-- shears (right click to shear animal)
|
||||
|
||||
minetest.register_tool("mobs:shears", {
|
||||
description = S("Steel Shears (right-click to shear)"),
|
||||
inventory_image = "mobs_shears.png",
|
||||
@@ -115,6 +165,7 @@ minetest.register_craft({
|
||||
})
|
||||
|
||||
-- protection rune
|
||||
|
||||
minetest.register_craftitem("mobs:protector", {
|
||||
description = S("Mob Protection Rune"),
|
||||
inventory_image = "mobs_protector.png",
|
||||
@@ -130,7 +181,8 @@ minetest.register_craft({
|
||||
}
|
||||
})
|
||||
|
||||
-- level 2 protection rune
|
||||
-- protection rune (level 2)
|
||||
|
||||
minetest.register_craftitem("mobs:protector2", {
|
||||
description = S("Mob Protection Rune (Level 2)"),
|
||||
inventory_image = "mobs_protector2.png",
|
||||
@@ -147,6 +199,7 @@ minetest.register_craft({
|
||||
})
|
||||
|
||||
-- saddle
|
||||
|
||||
minetest.register_craftitem("mobs:saddle", {
|
||||
description = S("Saddle"),
|
||||
inventory_image = "mobs_saddle.png",
|
||||
@@ -156,55 +209,42 @@ minetest.register_craftitem("mobs:saddle", {
|
||||
minetest.register_craft({
|
||||
output = "mobs:saddle",
|
||||
recipe = {
|
||||
{"mobs:leather", "mobs:leather", "mobs:leather"},
|
||||
{"mobs:leather", items.steel_ingot, "mobs:leather"},
|
||||
{"mobs:leather", items.steel_ingot, "mobs:leather"}
|
||||
{"group:leather", "group:leather", "group:leather"},
|
||||
{"group:leather", items.steel_ingot, "group:leather"},
|
||||
{"group:leather", items.steel_ingot, "group:leather"}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
-- make sure we can register fences
|
||||
local mod_def = minetest.get_modpath("default")
|
||||
-- register mob fence if default found
|
||||
|
||||
if mod_def and default.register_fence then
|
||||
|
||||
-- mob fence (looks like normal fence but collision is 2 high)
|
||||
default.register_fence("mobs:fence_wood", {
|
||||
description = S("Mob Fence"),
|
||||
texture = "default_wood.png",
|
||||
material = "default:fence_wood",
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
|
||||
sounds = mod_def and default.node_sound_wood_defaults(),
|
||||
collision_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, 0.5, 1.9, 0.5},
|
||||
-- mob fence (looks like normal fence but collision is 2 high)
|
||||
default.register_fence("mobs:fence_wood", {
|
||||
description = S("Mob Fence"),
|
||||
texture = "default_wood.png",
|
||||
material = "default:fence_wood",
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
|
||||
sounds = mobs.node_sound_wood_defaults(),
|
||||
collision_box = {
|
||||
type = "fixed", fixed = {{-0.5, -0.5, -0.5, 0.5, 1.9, 0.5}}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
end
|
||||
|
||||
-- mob fence top (has enlarged collisionbox to stop mobs getting over)
|
||||
|
||||
minetest.register_node("mobs:fence_top", {
|
||||
description = S("Mob Fence Top"),
|
||||
drawtype = "nodebox",
|
||||
tiles = {"default_wood.png"},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
|
||||
sounds = mod_def and default.node_sound_wood_defaults(),
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2}
|
||||
},
|
||||
collision_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.4, -1.5, -0.4, 0.4, 0, 0.4}
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.4, -1.5, -0.4, 0.4, 0, 0.4}
|
||||
}
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2, axey = 1},
|
||||
sounds = mobs.node_sound_wood_defaults(),
|
||||
node_box = {type = "fixed", fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2}},
|
||||
collision_box = {type = "fixed", fixed = {-0.4, -1.5, -0.4, 0.4, 0, 0.4}},
|
||||
selection_box = {type = "fixed", fixed = {-0.4, -1.5, -0.4, 0.4, 0, 0.4}}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
@@ -215,49 +255,15 @@ minetest.register_craft({
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
-- items that can be used as fuel
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mobs:nametag",
|
||||
burntime = 3
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mobs:lasso",
|
||||
burntime = 7
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mobs:net",
|
||||
burntime = 8
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mobs:leather",
|
||||
burntime = 4
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mobs:saddle",
|
||||
burntime = 7
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mobs:fence_wood",
|
||||
burntime = 7
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mobs:fence_top",
|
||||
burntime = 2
|
||||
})
|
||||
minetest.register_craft({type = "fuel", recipe = "mobs:nametag", burntime = 3})
|
||||
minetest.register_craft({type = "fuel", recipe = "mobs:lasso", burntime = 7})
|
||||
minetest.register_craft({type = "fuel", recipe = "mobs:net", burntime = 8})
|
||||
minetest.register_craft({type = "fuel", recipe = "mobs:leather", burntime = 4})
|
||||
minetest.register_craft({type = "fuel", recipe = "mobs:saddle", burntime = 7})
|
||||
minetest.register_craft({type = "fuel", recipe = "mobs:fence_wood", burntime = 7})
|
||||
minetest.register_craft({type = "fuel", recipe = "mobs:fence_top", burntime = 2})
|
||||
|
||||
|
||||
-- this tool spawns same mob and adds owner, protected, nametag info
|
||||
@@ -274,12 +280,9 @@ minetest.register_tool(":mobs:mob_reset_stick", {
|
||||
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
|
||||
if pointed_thing.type ~= "object" then
|
||||
return
|
||||
end
|
||||
if pointed_thing.type ~= "object" then return end
|
||||
|
||||
local obj = pointed_thing.ref
|
||||
|
||||
local control = user:get_player_control()
|
||||
local sneak = control and control.sneak
|
||||
|
||||
@@ -319,9 +322,7 @@ minetest.register_tool(":mobs:mob_reset_stick", {
|
||||
-- get base texture
|
||||
local bt = tex_obj:get_luaentity().base_texture[1]
|
||||
|
||||
if type(bt) ~= "string" then
|
||||
bt = ""
|
||||
end
|
||||
if type(bt) ~= "string" then bt = "" end
|
||||
|
||||
local name = user:get_player_name()
|
||||
|
||||
@@ -337,27 +338,18 @@ minetest.register_tool(":mobs:mob_reset_stick", {
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
|
||||
-- right-clicked with nametag and name entered?
|
||||
if formname == "mobs_texture"
|
||||
and fields.name
|
||||
and fields.name ~= "" then
|
||||
if formname == "mobs_texture" and fields.name and fields.name ~= "" then
|
||||
|
||||
-- does mob still exist?
|
||||
if not tex_obj
|
||||
or not tex_obj:get_luaentity() then
|
||||
return
|
||||
end
|
||||
if not tex_obj or not tex_obj:get_luaentity() then return end
|
||||
|
||||
-- make sure nametag is being used to name mob
|
||||
local item = player:get_wielded_item()
|
||||
|
||||
if item:get_name() ~= "mobs:mob_reset_stick" then
|
||||
return
|
||||
end
|
||||
if item:get_name() ~= "mobs:mob_reset_stick" then return end
|
||||
|
||||
-- limit name entered to 64 characters long
|
||||
if fields.name:len() > 64 then
|
||||
fields.name = fields.name:sub(1, 64)
|
||||
end
|
||||
if fields.name:len() > 64 then fields.name = fields.name:sub(1, 64) end
|
||||
|
||||
-- update texture
|
||||
local self = tex_obj:get_luaentity()
|
||||
@@ -371,18 +363,23 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
-- Meat Block
|
||||
|
||||
minetest.register_node("mobs:meatblock", {
|
||||
description = S("Meat Block"),
|
||||
tiles = {"mobs_meat_top.png", "mobs_meat_bottom.png", "mobs_meat_side.png"},
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy = 1, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
sounds = mod_def and default.node_sound_leaves_defaults(),
|
||||
groups = {choppy = 1, oddly_breakable_by_hand = 1, axey = 1, handy = 1},
|
||||
is_ground_content = false,
|
||||
sounds = mobs.node_sound_dirt_defaults(),
|
||||
on_place = minetest.rotate_node,
|
||||
on_use = minetest.item_eat(20)
|
||||
on_use = minetest.item_eat(20),
|
||||
_mcl_hardness = 0.8,
|
||||
_mcl_blast_resistance = 1
|
||||
})
|
||||
|
||||
mobs.add_eatable("mobs:meatblock", 20)
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mobs:meatblock",
|
||||
recipe = {
|
||||
@@ -393,16 +390,22 @@ minetest.register_craft({
|
||||
})
|
||||
|
||||
-- Meat Block (raw)
|
||||
|
||||
minetest.register_node("mobs:meatblock_raw", {
|
||||
description = S("Raw Meat Block"),
|
||||
tiles = {"mobs_meat_raw_top.png", "mobs_meat_raw_bottom.png", "mobs_meat_raw_side.png"},
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy = 1, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
sounds = mod_def and default.node_sound_leaves_defaults(),
|
||||
groups = {choppy = 1, oddly_breakable_by_hand = 1, axey = 1, handy = 1},
|
||||
is_ground_content = false,
|
||||
sounds = mobs.node_sound_dirt_defaults(),
|
||||
on_place = minetest.rotate_node,
|
||||
on_use = minetest.item_eat(20)
|
||||
on_use = minetest.item_eat(20),
|
||||
_mcl_hardness = 0.8,
|
||||
_mcl_blast_resistance = 1
|
||||
})
|
||||
|
||||
mobs.add_eatable("mobs:meatblock_raw", 20)
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mobs:meatblock_raw",
|
||||
recipe = {
|
||||
|
28
init.lua
28
init.lua
@@ -1,29 +1,35 @@
|
||||
|
||||
local path = minetest.get_modpath("mobs")
|
||||
-- peaceful player privilege
|
||||
|
||||
-- Peaceful player privilege
|
||||
minetest.register_privilege("peaceful_player", {
|
||||
description = "Prevents Mobs Redo mobs from attacking player",
|
||||
give_to_singleplayer = false
|
||||
})
|
||||
|
||||
-- fallback node
|
||||
|
||||
-- Mob API
|
||||
dofile(path .. "/api.lua")
|
||||
minetest.register_node("mobs:fallback_node", {
|
||||
description = "Fallback Node",
|
||||
tiles = {"mobs_fallback.png"},
|
||||
is_ground_content = false,
|
||||
groups = {handy = 1, crumbly = 3, not_in_creative_inventory = 1},
|
||||
drop = ""
|
||||
})
|
||||
|
||||
-- Rideable Mobs
|
||||
dofile(path .. "/mount.lua")
|
||||
local path = minetest.get_modpath("mobs")
|
||||
|
||||
-- Mob Items
|
||||
dofile(path .. "/crafts.lua")
|
||||
dofile(path .. "/api.lua") -- mob API
|
||||
|
||||
-- Mob Spawner
|
||||
dofile(path .. "/spawner.lua")
|
||||
dofile(path .. "/mount.lua") -- rideable mobs
|
||||
|
||||
dofile(path .. "/crafts.lua") -- items and crafts
|
||||
|
||||
dofile(path .. "/spawner.lua") -- mob spawner
|
||||
|
||||
-- Lucky Blocks
|
||||
|
||||
if minetest.get_modpath("lucky_block") then
|
||||
dofile(path .. "/lucky_block.lua")
|
||||
end
|
||||
|
||||
|
||||
print("[MOD] Mobs Redo loaded")
|
||||
|
@@ -23,6 +23,8 @@ THE SOFTWARE.
|
||||
|
||||
Textures under CC0 license by TenPlus1
|
||||
|
||||
mobs_fallback.png is dirt texture from original Minetest (CC-BY SA 3.0)
|
||||
|
||||
|
||||
ShadowNinja (CC BY-SA 3.0):
|
||||
tnt_smoke.png
|
||||
|
@@ -26,7 +26,7 @@ Mob Fence=Kreaturen Zaun
|
||||
Mob Fence Top=Kreaturen Zaun Oberteil
|
||||
Mob Reset Stick=Kreatur reset Stock
|
||||
Meat Block=Fleischblock
|
||||
Raw Meat Block=Rohfleisch Blokc
|
||||
Raw Meat Block=Roher Fleischblock
|
||||
Enter texture:=Textur eingeben:
|
||||
Change=Ändern
|
||||
Mob Spawner=Kreaturenspawner
|
||||
|
@@ -1,4 +1,8 @@
|
||||
|
||||
local S = minetest.get_translator("mobs")
|
||||
|
||||
-- add lucky blocks
|
||||
|
||||
lucky_block:add_blocks({
|
||||
{"dro", {"mobs:meat_raw"}, 5},
|
||||
{"dro", {"mobs:meat"}, 5},
|
||||
@@ -13,3 +17,81 @@ lucky_block:add_blocks({
|
||||
{"dro", {"mobs:fence_top"}, 12},
|
||||
{"lig"}
|
||||
})
|
||||
|
||||
-- pint sized rune, use on tamed mob to shrink to half-size
|
||||
|
||||
minetest.register_craftitem(":mobs:pint_sized_rune", {
|
||||
description = S("Pint Sized Rune"),
|
||||
inventory_image = "mobs_pint_sized_rune.png",
|
||||
groups = {flammable = 2},
|
||||
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
|
||||
if pointed_thing.type ~= "object" then return end
|
||||
|
||||
local name = user and user:get_player_name() or ""
|
||||
local tool = user and user:get_wielded_item()
|
||||
local tool_name = tool:get_name()
|
||||
|
||||
if tool_name ~= "mobs:pint_sized_rune" then return end
|
||||
|
||||
local self = pointed_thing.ref:get_luaentity()
|
||||
|
||||
if not self._cmi_is_mob then
|
||||
minetest.chat_send_player(name, S("Not a Mobs Redo mob!"))
|
||||
return
|
||||
end
|
||||
|
||||
if not self.tamed then
|
||||
minetest.chat_send_player(name, S("Not tamed!"))
|
||||
return
|
||||
end
|
||||
|
||||
if self.pint_size_potion then
|
||||
minetest.chat_send_player(name, S("Potion already applied!"))
|
||||
return
|
||||
end
|
||||
|
||||
if not mobs.is_creative(user:get_player_name()) then
|
||||
tool:take_item() -- take 1 rune
|
||||
user:set_wielded_item(tool)
|
||||
end
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
local prop = self.object:get_properties()
|
||||
|
||||
vis_size = {x = self.base_size.x * .5, y = self.base_size.y * .5}
|
||||
|
||||
self.base_size = vis_size
|
||||
|
||||
colbox = {
|
||||
self.base_colbox[1] * .5, self.base_colbox[2] * .5,
|
||||
self.base_colbox[3] * .5, self.base_colbox[4] * .5,
|
||||
self.base_colbox[5] * .5, self.base_colbox[6] * .5}
|
||||
|
||||
self.base_colbox = colbox
|
||||
|
||||
selbox = {
|
||||
self.base_selbox[1] * .5, self.base_selbox[2] * .5,
|
||||
self.base_selbox[3] * .5, self.base_selbox[4] * .5,
|
||||
self.base_selbox[5] * .5, self.base_selbox[6] * .5}
|
||||
|
||||
self.base_selbox = selbox
|
||||
|
||||
self.object:set_properties(
|
||||
{visual_size = vis_size, collisionbox = colbox, selectionbox = selbox})
|
||||
|
||||
self.pint_size_potion = true
|
||||
|
||||
pos.y = pos.y + prop.collisionbox[5]
|
||||
|
||||
mobs:effect(pos, 25, "mobs_protect_particle.png", 0.5, 4, 2, 15)
|
||||
|
||||
self:mob_sound("mobs_spell")
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "lucky_block:pint_sized_rune",
|
||||
recipe = {{"lucky_block:pint_sized_potion", "mobs:protector"}}
|
||||
})
|
||||
|
2
mod.conf
2
mod.conf
@@ -1,4 +1,4 @@
|
||||
name = mobs
|
||||
description = Adds a mob api for mods to add animals or monsters etc.
|
||||
optional_depends = default, tnt, invisibility, lucky_block, cmi, toolranks, pathfinder, player_api, mtobjid, visual_harm_1ndicators
|
||||
optional_depends = default, tnt, invisibility, lucky_block, cmi, toolranks, pathfinder, player_api, mtobjid, visual_harm_1ndicators, mcl_sounds
|
||||
min_minetest_version = 5.0
|
||||
|
114
mount.lua
114
mount.lua
@@ -1,8 +1,10 @@
|
||||
|
||||
-- lib_mount by Blert2112 (edited by TenPlus1)
|
||||
|
||||
local is_mc2 = minetest.get_modpath("mcl_mobs") -- MineClone2 check
|
||||
|
||||
-- one of these is needed to ride mobs, otherwise no riding for you
|
||||
|
||||
if not minetest.get_modpath("player_api") and not is_mc2 then
|
||||
|
||||
function mobs.attach() end
|
||||
@@ -14,12 +16,11 @@ if not minetest.get_modpath("player_api") and not is_mc2 then
|
||||
end
|
||||
|
||||
-- Localise some functions
|
||||
|
||||
local abs, cos, floor, sin, sqrt, pi =
|
||||
math.abs, math.cos, math.floor, math.sin, math.sqrt, math.pi
|
||||
|
||||
--
|
||||
-- Helper functions
|
||||
--
|
||||
-- helper functions
|
||||
|
||||
local node_ok = function(pos, fallback)
|
||||
|
||||
@@ -27,9 +28,7 @@ local node_ok = function(pos, fallback)
|
||||
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
|
||||
if node and minetest.registered_nodes[node.name] then
|
||||
return node
|
||||
end
|
||||
if node and minetest.registered_nodes[node.name] then return node end
|
||||
|
||||
return {name = fallback}
|
||||
end
|
||||
@@ -39,9 +38,7 @@ local function node_is(entity)
|
||||
|
||||
if not entity.standing_on then return "other" end
|
||||
|
||||
if entity.standing_on == "air" then
|
||||
return "air"
|
||||
end
|
||||
if entity.standing_on == "air" then return "air" end
|
||||
|
||||
if minetest.get_item_group(entity.standing_on, "lava") ~= 0 then
|
||||
return "lava"
|
||||
@@ -61,13 +58,9 @@ end
|
||||
|
||||
local function get_sign(i)
|
||||
|
||||
i = i or 0
|
||||
if not i or i == 0 then return 0 end
|
||||
|
||||
if i == 0 then
|
||||
return 0
|
||||
else
|
||||
return i / abs(i)
|
||||
end
|
||||
return i / abs(i)
|
||||
end
|
||||
|
||||
|
||||
@@ -89,9 +82,7 @@ local function force_detach(player)
|
||||
|
||||
local attached_to = player and player:get_attach()
|
||||
|
||||
if not attached_to then
|
||||
return
|
||||
end
|
||||
if not attached_to then return end
|
||||
|
||||
local entity = attached_to:get_luaentity()
|
||||
|
||||
@@ -115,11 +106,13 @@ local function force_detach(player)
|
||||
player:set_properties({visual_size = {x = 1, y = 1}})
|
||||
end
|
||||
|
||||
-- detach player on leaving
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
force_detach(player)
|
||||
end)
|
||||
|
||||
-- detatch all players on shutdown
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
|
||||
@@ -130,25 +123,21 @@ minetest.register_on_shutdown(function()
|
||||
end
|
||||
end)
|
||||
|
||||
-- detatch player when dead
|
||||
|
||||
minetest.register_on_dieplayer(function(player)
|
||||
force_detach(player)
|
||||
return true
|
||||
end)
|
||||
|
||||
-- find free position to detach player
|
||||
|
||||
-- Just for correct detaching
|
||||
local function find_free_pos(pos)
|
||||
|
||||
local check = {
|
||||
{x = 1, y = 0, z = 0},
|
||||
{x = 1, y = 1, z = 0},
|
||||
{x = -1, y = 0, z = 0},
|
||||
{x = -1, y = 1, z = 0},
|
||||
{x = 0, y = 0, z = 1},
|
||||
{x = 0, y = 1, z = 1},
|
||||
{x = 0, y = 0, z = -1},
|
||||
{x = 0, y = 1, z = -1}
|
||||
{x = 1, y = 0, z = 0}, {x = 1, y = 1, z = 0}, {x = -1, y = 0, z = 0},
|
||||
{x = -1, y = 1, z = 0}, {x = 0, y = 0, z = 1}, {x = 0, y = 1, z = 1},
|
||||
{x = 0, y = 0, z = -1}, {x = 0, y = 1, z = -1}
|
||||
}
|
||||
|
||||
for _, c in pairs(check) do
|
||||
@@ -169,8 +158,8 @@ local function find_free_pos(pos)
|
||||
return pos
|
||||
end
|
||||
|
||||
|
||||
-- are we a real player ?
|
||||
|
||||
local function is_player(player)
|
||||
|
||||
if player and type(player) == "userdata" and minetest.is_player(player) then
|
||||
@@ -178,6 +167,7 @@ local function is_player(player)
|
||||
end
|
||||
end
|
||||
|
||||
-- attach player to mob entity
|
||||
|
||||
function mobs.attach(entity, player)
|
||||
|
||||
@@ -190,9 +180,7 @@ function mobs.attach(entity, player)
|
||||
|
||||
local rot_view = 0
|
||||
|
||||
if entity.player_rotation.y == 90 then
|
||||
rot_view = pi / 2
|
||||
end
|
||||
if entity.player_rotation.y == 90 then rot_view = pi / 2 end
|
||||
|
||||
local attach_at = entity.driver_attach_at
|
||||
local eye_offset = entity.driver_eye_offset
|
||||
@@ -211,10 +199,7 @@ function mobs.attach(entity, player)
|
||||
player:set_eye_offset(eye_offset, {x = 0, y = 0, z = 0})
|
||||
|
||||
player:set_properties({
|
||||
visual_size = {
|
||||
x = entity.driver_scale.x,
|
||||
y = entity.driver_scale.y
|
||||
}
|
||||
visual_size = {x = entity.driver_scale.x, y = entity.driver_scale.y}
|
||||
})
|
||||
|
||||
minetest.after(0.2, function()
|
||||
@@ -232,6 +217,7 @@ function mobs.attach(entity, player)
|
||||
player:set_look_horizontal(entity.object:get_yaw() - rot_view)
|
||||
end
|
||||
|
||||
-- detatch player from mob
|
||||
|
||||
function mobs.detach(player)
|
||||
|
||||
@@ -250,15 +236,14 @@ function mobs.detach(player)
|
||||
end)
|
||||
end
|
||||
|
||||
-- ride mob like car or horse
|
||||
|
||||
function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||
|
||||
local yaw = entity.object:get_yaw() or 0
|
||||
local rot_view = 0
|
||||
|
||||
if entity.player_rotation.y == 90 then
|
||||
rot_view = pi / 2
|
||||
end
|
||||
if entity.player_rotation.y == 90 then rot_view = pi / 2 end
|
||||
|
||||
local acce_y = 0
|
||||
local velo = entity.object:get_velocity() ; if not velo then return end
|
||||
@@ -276,9 +261,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||
|
||||
elseif ctrl.down then -- move backwards
|
||||
|
||||
if entity.max_speed_reverse == 0 and entity.v == 0 then
|
||||
return
|
||||
end
|
||||
if entity.max_speed_reverse == 0 and entity.v == 0 then return end
|
||||
|
||||
entity.v = entity.v - entity.accel * dtime
|
||||
end
|
||||
@@ -290,12 +273,8 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||
|
||||
horz = yaw
|
||||
|
||||
if ctrl.left then
|
||||
horz = horz + 0.05
|
||||
|
||||
elseif ctrl.right then
|
||||
horz = horz - 0.05
|
||||
end
|
||||
if ctrl.left then horz = horz + 0.05
|
||||
elseif ctrl.right then horz = horz - 0.05 end
|
||||
else
|
||||
horz = entity.driver:get_look_horizontal() or 0
|
||||
end
|
||||
@@ -333,8 +312,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||
if ctrl.jump then -- jump (only when standing on solid surface)
|
||||
|
||||
if velo.y == 0
|
||||
and entity.standing_on ~= "air"
|
||||
and entity.standing_on ~= "ignore"
|
||||
and entity.standing_on ~= "air" and entity.standing_on ~= "ignore"
|
||||
and minetest.get_item_group(entity.standing_on, "liquid") == 0 then
|
||||
velo.y = velo.y + entity.jump_height
|
||||
acce_y = acce_y + (acce_y * 3) + 1
|
||||
@@ -346,17 +324,13 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||
-- if not moving then set animation and return
|
||||
if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
|
||||
|
||||
if stand_anim then
|
||||
entity:set_animation(stand_anim)
|
||||
end
|
||||
if stand_anim then entity:set_animation(stand_anim) end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- set moving animation
|
||||
if moving_anim then
|
||||
entity:set_animation(moving_anim)
|
||||
end
|
||||
if moving_anim then entity:set_animation(moving_anim) end
|
||||
|
||||
-- Stop!
|
||||
local s = get_sign(entity.v)
|
||||
@@ -392,9 +366,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||
|
||||
if ni == "air" then
|
||||
|
||||
if can_fly == true then
|
||||
new_acce.y = 0
|
||||
end
|
||||
if can_fly == true then new_acce.y = 0 end
|
||||
|
||||
elseif ni == "liquid" or ni == "lava" then
|
||||
|
||||
@@ -441,30 +413,26 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||
entity.v2 = v
|
||||
end
|
||||
|
||||
-- fly mob in facing direction (by D00Med, edited by TenPlus1)
|
||||
|
||||
-- directional flying routine by D00Med (edited by TenPlus1)
|
||||
function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim)
|
||||
|
||||
local ctrl = entity.driver:get_player_control() ; if not ctrl then return end
|
||||
local velo = entity.object:get_velocity() ; if not velo then return end
|
||||
local dir = entity.driver:get_look_dir()
|
||||
local yaw = entity.driver:get_look_horizontal() + 1.57
|
||||
local yaw = entity.driver:get_look_horizontal() ; if not yaw then return end
|
||||
|
||||
yaw = yaw + 1.57 -- fix from get_yaw to get_look_horizontal
|
||||
|
||||
if ctrl.up then
|
||||
|
||||
entity.object:set_velocity({
|
||||
x = dir.x * speed,
|
||||
y = dir.y * speed + 2,
|
||||
z = dir.z * speed
|
||||
})
|
||||
entity.object:set_velocity(
|
||||
{x = dir.x * speed, y = dir.y * speed + 2, z = dir.z * speed})
|
||||
|
||||
elseif ctrl.down then
|
||||
|
||||
entity.object:set_velocity({
|
||||
x = -dir.x * speed,
|
||||
y = dir.y * speed + 2,
|
||||
z = -dir.z * speed
|
||||
})
|
||||
entity.object:set_velocity(
|
||||
{x = -dir.x * speed, y = dir.y * speed + 2, z = -dir.z * speed})
|
||||
|
||||
elseif not ctrl.down or ctrl.up or ctrl.jump then
|
||||
entity.object:set_velocity({x = 0, y = -2, z = 0})
|
||||
@@ -499,11 +467,9 @@ function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim)
|
||||
end
|
||||
end
|
||||
|
||||
-- change animation if stopped
|
||||
if velo.x == 0 and velo.y == 0 and velo.z == 0 then
|
||||
entity:set_animation(stand_anim)
|
||||
entity:set_animation(stand_anim) -- stopped animation
|
||||
else
|
||||
-- moving animation
|
||||
entity:set_animation(moving_anim)
|
||||
entity:set_animation(moving_anim) -- moving animation
|
||||
end
|
||||
end
|
||||
|
11
readme.MD
11
readme.MD
@@ -24,6 +24,14 @@ https://forum.minetest.net/viewtopic.php?f=11&t=9917
|
||||
|
||||
## Changelog
|
||||
|
||||
### Version 1.62
|
||||
|
||||
* Added ability for mobs to hear using self.on_sound() function
|
||||
* Added 'mobs_can_hear' setting to turn above feature on/off
|
||||
* Added {eatable} group to food items and HP in description
|
||||
* Fixed timer bug when attacking
|
||||
* Fixed fall damage check when riding mob
|
||||
|
||||
### Version 1.61
|
||||
|
||||
* Fixed mob damage when riding mobs
|
||||
@@ -31,6 +39,9 @@ https://forum.minetest.net/viewtopic.php?f=11&t=9917
|
||||
* Added self.attack_patience value so mobs stop attacking unseen players
|
||||
* Added self.homing so that arrows follow player when visible
|
||||
* Added support for Visual Harm 1ndicators mod to show health bars
|
||||
* Added self.node_damage flag which is true by default to enable damage_per_second node damage
|
||||
* Added check for on_death() function before using mob api's own on_die() one
|
||||
* Added mobs:fallback_node for when current [game] hasn't defined mapgen_dirt node
|
||||
|
||||
### Version 1.60
|
||||
|
||||
|
@@ -60,11 +60,12 @@ mob_height_fix (Fix Mob Height) bool true
|
||||
|
||||
mob_log_spawn (Log Mob Spawning) bool false
|
||||
|
||||
# Mob hearing, when enabled will override minetest.sound_play for mobs to hear
|
||||
mobs_can_hear (Enable Mob hearing) bool true
|
||||
|
||||
[Pathfinding]
|
||||
# Enable pathfinding (default Enabled)
|
||||
mob_pathfinding_enable (Enable pathfinding) bool true
|
||||
# Use pathfinder mod if available (default Enabled)
|
||||
mob_pathfinder_enable (Use pathfinder mod if available) bool true
|
||||
# How long before stuck mobs starts searching (default 3.0)
|
||||
mob_pathfinding_stuck_timeout (How long before stuck mobs start searching) float 3.0
|
||||
# How long will mob follow path before giving up (default 5.0)
|
||||
|
95
spawner.lua
95
spawner.lua
@@ -1,8 +1,9 @@
|
||||
|
||||
local S = mobs.translate
|
||||
local S = minetest.get_translator("mobs")
|
||||
local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99)
|
||||
|
||||
-- helper functions
|
||||
|
||||
-- are we a real player ?
|
||||
local function is_player(player)
|
||||
|
||||
if player and type(player) == "userdata" and minetest.is_player(player) then
|
||||
@@ -10,8 +11,19 @@ local function is_player(player)
|
||||
end
|
||||
end
|
||||
|
||||
local square = math.sqrt
|
||||
|
||||
local get_distance = function(a, b)
|
||||
|
||||
if not a or not b then return 50 end -- nil check and default distance
|
||||
|
||||
local x, y, z = a.x - b.x, a.y - b.y, a.z - b.z
|
||||
|
||||
return square(x * x + y * y + z * z)
|
||||
end
|
||||
|
||||
-- mob spawner
|
||||
|
||||
local spawner_default = "mobs_animal:pumba 10 15 0 0 0"
|
||||
|
||||
minetest.register_node("mobs:spawner", {
|
||||
@@ -20,7 +32,11 @@ minetest.register_node("mobs:spawner", {
|
||||
paramtype = "light",
|
||||
walkable = true,
|
||||
description = S("Mob Spawner"),
|
||||
groups = {cracky = 1},
|
||||
groups = {cracky = 1, pickaxey = 3},
|
||||
is_ground_content = false,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 5,
|
||||
sounds = mobs.node_sound_stone_defaults(),
|
||||
|
||||
on_construct = function(pos)
|
||||
|
||||
@@ -42,16 +58,12 @@ minetest.register_node("mobs:spawner", {
|
||||
|
||||
on_right_click = function(pos, placer)
|
||||
|
||||
if minetest.is_protected(pos, placer:get_player_name()) then
|
||||
return
|
||||
end
|
||||
if minetest.is_protected(pos, placer:get_player_name()) then return end
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
|
||||
if not fields.text or fields.text == "" then
|
||||
return
|
||||
end
|
||||
if not fields.text or fields.text == "" then return end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local comm = fields.text:split(" ")
|
||||
@@ -62,35 +74,31 @@ minetest.register_node("mobs:spawner", {
|
||||
return
|
||||
end
|
||||
|
||||
local mob = comm[1] -- mob to spawn
|
||||
local mob = comm[1] or "" -- mob to spawn
|
||||
local mlig = tonumber(comm[2]) -- min light
|
||||
local xlig = tonumber(comm[3]) -- max light
|
||||
local num = tonumber(comm[4]) -- total mobs in area
|
||||
local pla = tonumber(comm[5]) -- player distance (0 to disable)
|
||||
local yof = tonumber(comm[6]) or 0 -- Y offset to spawn mob
|
||||
|
||||
if mob and mob ~= "" and mobs.spawning_mobs[mob]
|
||||
and num and num >= 0 and num <= 10
|
||||
and mlig and mlig >= 0 and mlig <= 15
|
||||
and xlig and xlig >= 0 and xlig <= 15
|
||||
and pla and pla >= 0 and pla <= 20
|
||||
and yof and yof > -10 and yof < 10 then
|
||||
if mob ~= "" and mobs.spawning_mobs[mob] and num and num >= 0 and num <= 10
|
||||
and mlig and mlig >= 0 and mlig <= 15 and xlig and xlig >= 0 and xlig <= 15
|
||||
and pla and pla >= 0 and pla <= 20 and yof and yof > -10 and yof < 10 then
|
||||
|
||||
meta:set_string("command", fields.text)
|
||||
meta:set_string("infotext", S("Spawner Active (@1)", mob))
|
||||
|
||||
else
|
||||
minetest.chat_send_player(name, S("Mob Spawner settings failed!"))
|
||||
minetest.chat_send_player(name,
|
||||
S("Syntax: “name min_light[0-14] max_light[0-14] max_mobs_in_area[0 to disable] player_distance[1-20] y_offset[-10 to 10]”"))
|
||||
S("Syntax: “name min_light[0-14] max_light[0-14] "
|
||||
.. "max_mobs_in_area[0 to disable] player_distance[1-20] "
|
||||
.. "y_offset[-10 to 10]”"))
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99)
|
||||
|
||||
-- spawner abm
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Mob spawner node",
|
||||
nodenames = {"mobs:spawner"},
|
||||
@@ -101,9 +109,7 @@ minetest.register_abm({
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
|
||||
-- return if too many entities already
|
||||
if active_object_count_wider >= max_per_block then
|
||||
return
|
||||
end
|
||||
if active_object_count_wider >= max_per_block then return end
|
||||
|
||||
-- get meta and command
|
||||
local meta = minetest.get_meta(pos)
|
||||
@@ -118,9 +124,7 @@ minetest.register_abm({
|
||||
local yof = tonumber(comm[6]) or 0
|
||||
|
||||
-- if amount is 0 then do nothing
|
||||
if num == 0 then
|
||||
return
|
||||
end
|
||||
if num == 0 then return end
|
||||
|
||||
-- are we spawning a registered mob?
|
||||
if not mobs.spawning_mobs[mob] then
|
||||
@@ -138,49 +142,43 @@ minetest.register_abm({
|
||||
|
||||
ent = obj:get_luaentity()
|
||||
|
||||
if ent and ent.name and ent.name == mob then
|
||||
count = count + 1
|
||||
end
|
||||
if ent and ent.name and ent.name == mob then count = count + 1 end
|
||||
end
|
||||
|
||||
-- is there too many of same type?
|
||||
if count >= num then
|
||||
return
|
||||
end
|
||||
if count >= num then return end
|
||||
|
||||
-- spawn mob if player detected and in range
|
||||
-- when player distance above 0, spawn mob if player detected and in range
|
||||
if pla > 0 then
|
||||
|
||||
local in_range = 0
|
||||
local objsp = minetest.get_objects_inside_radius(pos, pla)
|
||||
local in_range, player
|
||||
local players = minetest.get_connected_players()
|
||||
|
||||
for _, oir in pairs(objsp) do
|
||||
for i = 1, #players do
|
||||
|
||||
if is_player(oir) then
|
||||
player = players[i]
|
||||
|
||||
in_range = 1
|
||||
if get_distance(player:get_pos(), pos) <= pla then
|
||||
|
||||
in_range = true
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- player not found
|
||||
if in_range == 0 then
|
||||
return
|
||||
end
|
||||
if not in_range then return end
|
||||
end
|
||||
|
||||
-- set medium mob usually spawns in (defaults to air)
|
||||
local reg = minetest.registered_entities[mob].fly_in
|
||||
|
||||
if not reg or type(reg) == "string" then
|
||||
reg = {(reg or "air")}
|
||||
end
|
||||
if not reg or type(reg) == "string" then reg = {(reg or "air")} end
|
||||
|
||||
-- find air blocks within 5 nodes of spawner
|
||||
local air = minetest.find_nodes_in_area(
|
||||
{x = pos.x - 5, y = pos.y + yof, z = pos.z - 5},
|
||||
{x = pos.x + 5, y = pos.y + yof, z = pos.z + 5}, reg)
|
||||
{x = pos.x - 5, y = pos.y + yof, z = pos.z - 5},
|
||||
{x = pos.x + 5, y = pos.y + yof, z = pos.z + 5}, reg)
|
||||
|
||||
-- spawn in random air block
|
||||
if air and #air > 0 then
|
||||
@@ -191,8 +189,7 @@ minetest.register_abm({
|
||||
pos2.y = pos2.y + 0.5
|
||||
|
||||
-- only if light levels are within range
|
||||
if lig >= mlig and lig <= xlig
|
||||
and minetest.registered_entities[mob] then
|
||||
if lig >= mlig and lig <= xlig and minetest.registered_entities[mob] then
|
||||
minetest.add_entity(pos2, mob)
|
||||
end
|
||||
end
|
||||
|
BIN
textures/mobs_fallback.png
Normal file
BIN
textures/mobs_fallback.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 821 B |
Binary file not shown.
Before Width: | Height: | Size: 247 B After Width: | Height: | Size: 186 B |
BIN
textures/mobs_pint_sized_rune.png
Normal file
BIN
textures/mobs_pint_sized_rune.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 160 B |
Reference in New Issue
Block a user