Initial commit
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
## Generic ignorable patterns and files
|
||||
*~
|
||||
.*.swp
|
||||
*bak*
|
||||
tags
|
||||
*.vim
|
||||
*.orig
|
||||
*.rej
|
||||
|
8
README.txt
Normal file
@ -0,0 +1,8 @@
|
||||
Dungeon (Minetest Game)
|
||||
=======================
|
||||
|
||||
Implements a simple dungeon crawler on the Minetest Engine.
|
||||
|
||||
Stuff inside is licensed under WTFPL, CC0, and CC BY-SA; see mod directories
|
||||
for more info.
|
||||
|
2
minetest.conf
Normal file
@ -0,0 +1,2 @@
|
||||
# Default configuration for this game
|
||||
mg_name = singlenode
|
19
mods/animal_dm/License.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Licenses
|
||||
|
||||
CC0, Author Temperest
|
||||
models/dm.blend
|
||||
|
||||
CC0
|
||||
models/animal_dm.b3d
|
||||
sounds/animal_dm_fireball.ogg
|
||||
|
||||
Unknown (most likely CC0 but no guarantee)
|
||||
sounds/animal_dm_die.ogg
|
||||
sounds/animal_dm_hit.ogg
|
||||
sounds/animal_dm_random.ogg
|
||||
|
||||
Unknown, Author 4aiman
|
||||
models/DM.blend
|
||||
|
||||
Everything not mentioned:
|
||||
CC-BY-SA, Author sapier
|
3
mods/animal_dm/depends.txt
Normal file
@ -0,0 +1,3 @@
|
||||
default
|
||||
mobf
|
||||
fire
|
160
mods/animal_dm/init.lua
Normal file
@ -0,0 +1,160 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file init.lua
|
||||
--! @brief dungeonmaster implementation
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2013-01-27
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.log("action","MOD: animal_dm loading ...")
|
||||
local version = "0.0.15"
|
||||
|
||||
local dm_groups = {
|
||||
not_in_creative_inventory=1
|
||||
}
|
||||
|
||||
local selectionbox_dm = {-0.75, -1, -0.75, 0.75, 1, 0.75}
|
||||
|
||||
dm_prototype = {
|
||||
name="dm",
|
||||
modname="animal_dm",
|
||||
|
||||
generic = {
|
||||
description="Dungeonmaster (MOBF)",
|
||||
base_health=10,
|
||||
kill_result="",
|
||||
armor_groups= {
|
||||
fleshy=1,
|
||||
deamon=1,
|
||||
},
|
||||
groups = dm_groups,
|
||||
envid="simple_air"
|
||||
},
|
||||
movement = {
|
||||
min_accel=0.2,
|
||||
max_accel=0.4,
|
||||
max_speed=0.25,
|
||||
pattern="stop_and_go",
|
||||
canfly=false,
|
||||
follow_speedup=5,
|
||||
},
|
||||
combat = {
|
||||
angryness=0.99,
|
||||
starts_attack=true,
|
||||
sun_sensitive=true,
|
||||
melee = {
|
||||
maxdamage=3,
|
||||
range=5,
|
||||
speed=1,
|
||||
},
|
||||
distance = {
|
||||
attack="mobf:fireball_entity",
|
||||
range =15,
|
||||
speed = 1,
|
||||
},
|
||||
self_destruct = nil,
|
||||
},
|
||||
|
||||
spawning = {
|
||||
rate=0.02,
|
||||
density=750,
|
||||
algorithm="shadows_spawner",
|
||||
height=3,
|
||||
respawndelay = 60,
|
||||
},
|
||||
sound = {
|
||||
random = {
|
||||
name="animal_dm_random_1",
|
||||
min_delta = 30,
|
||||
chance = 0.5,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 5,
|
||||
},
|
||||
distance = {
|
||||
name="animal_dm_fireball",
|
||||
gain = 0.5,
|
||||
max_hear_distance = 7,
|
||||
},
|
||||
die = {
|
||||
name="animal_dm_die",
|
||||
gain = 0.7,
|
||||
max_hear_distance = 7,
|
||||
},
|
||||
melee = {
|
||||
name="animal_dm_hit",
|
||||
gain = 0.7,
|
||||
max_hear_distance = 5,
|
||||
},
|
||||
},
|
||||
animation = {
|
||||
walk = {
|
||||
start_frame = 31,
|
||||
end_frame = 60,
|
||||
},
|
||||
stand = {
|
||||
start_frame = 1,
|
||||
end_frame = 30,
|
||||
},
|
||||
combat = {
|
||||
start_frame = 61,
|
||||
end_frame = 90,
|
||||
},
|
||||
},
|
||||
states = {
|
||||
{
|
||||
name = "default",
|
||||
movgen = "none",
|
||||
chance = 0,
|
||||
animation = "stand",
|
||||
graphics_3d = {
|
||||
visual = "mesh",
|
||||
mesh = "animal_dm.b3d",
|
||||
textures = {"animal_dm_mesh.png"},
|
||||
collisionbox = selectionbox_dm,
|
||||
visual_size= {x=1,y=1,z=1},
|
||||
},
|
||||
graphics = {
|
||||
sprite_scale={x=4,y=4},
|
||||
sprite_div = {x=6,y=1},
|
||||
visible_height = 2,
|
||||
},
|
||||
typical_state_time = 30,
|
||||
},
|
||||
{
|
||||
name = "walking",
|
||||
movgen = "probab_mov_gen",
|
||||
chance = 0.25,
|
||||
animation = "walk",
|
||||
typical_state_time = 180,
|
||||
},
|
||||
{
|
||||
movgen="follow_mov_gen",
|
||||
name = "combat",
|
||||
chance = 0,
|
||||
animation = "combat",
|
||||
typical_state_time = 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dm_debug = function (msg)
|
||||
--minetest.log("action", "mobs: "..msg)
|
||||
--minetest.chat_send_all("mobs: "..msg)
|
||||
end
|
||||
|
||||
local modpath = minetest.get_modpath("animal_dm")
|
||||
dofile (modpath .. "/vault.lua")
|
||||
|
||||
--register with animals mod
|
||||
minetest.log("action", "adding mob "..dm_prototype.name)
|
||||
if mobf_add_mob(dm_prototype) then
|
||||
dofile (modpath .. "/vault.lua")
|
||||
end
|
||||
minetest.log("action","MOD: animal_dm mod version " .. version .. " loaded")
|
BIN
mods/animal_dm/models/DM.blend
Normal file
BIN
mods/animal_dm/models/animal_dm.b3d
Normal file
BIN
mods/animal_dm/models/animal_dm.blend
Normal file
BIN
mods/animal_dm/sounds/animal_dm_die.ogg
Normal file
BIN
mods/animal_dm/sounds/animal_dm_fireball.ogg
Normal file
BIN
mods/animal_dm/sounds/animal_dm_hit.ogg
Normal file
BIN
mods/animal_dm/sounds/animal_dm_random_1.ogg
Normal file
16
mods/animal_dm/sounds/soundlist.txt
Normal file
@ -0,0 +1,16 @@
|
||||
--dm--
|
||||
random:
|
||||
random_1.ogg
|
||||
hit:
|
||||
hit.ogg
|
||||
die:
|
||||
die.ogg
|
||||
melee:
|
||||
hit.ogg
|
||||
distance:
|
||||
fireball.ogg
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
mods/animal_dm/textures/animal_dm_dm.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
mods/animal_dm/textures/animal_dm_dm_item.png
Normal file
After Width: | Height: | Size: 384 B |
BIN
mods/animal_dm/textures/animal_dm_mesh.png
Normal file
After Width: | Height: | Size: 331 B |
BIN
mods/animal_dm/textures/animal_dm_mesh2.jpg
Normal file
After Width: | Height: | Size: 9.6 KiB |
529
mods/animal_dm/vault.lua
Normal file
@ -0,0 +1,529 @@
|
||||
--(c) Celeron55
|
||||
|
||||
|
||||
local vault = {}
|
||||
|
||||
function vault.cmp(v, w)
|
||||
return (
|
||||
v.x == w.x and
|
||||
v.y == w.y and
|
||||
v.z == w.z
|
||||
)
|
||||
end
|
||||
|
||||
function vault.add(v, w)
|
||||
return {
|
||||
x = v.x + w.x,
|
||||
y = v.y + w.y,
|
||||
z = v.z + w.z,
|
||||
}
|
||||
end
|
||||
|
||||
function vault.sub(v, w)
|
||||
return {
|
||||
x = v.x - w.x,
|
||||
y = v.y - w.y,
|
||||
z = v.z - w.z,
|
||||
}
|
||||
end
|
||||
|
||||
vault.make_vault_part = function(p, part, seed)
|
||||
local ns = nil
|
||||
local top_y = 2
|
||||
local mob = nil
|
||||
|
||||
--choose what to do at position
|
||||
if part == 'w' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'W' then
|
||||
top_y = 3
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'c' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'T' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='default:torch'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'f' then
|
||||
ns = {
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'l' then
|
||||
top_y = 3
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:lava_source'},
|
||||
}
|
||||
elseif part == 'm' then
|
||||
top_y = 3
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
mob = "animal_dm:dm__default"
|
||||
elseif part == 'C' then
|
||||
top_y = 3
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'S' then
|
||||
top_y = 3
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='default:bookshelf'},
|
||||
{name='default:bookshelf'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'd' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'a' then
|
||||
ns = {
|
||||
nil,
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
nil,
|
||||
}
|
||||
elseif part == 'A' then
|
||||
ns = {
|
||||
nil,
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 't' then
|
||||
local invcontent = {}
|
||||
local pr = PseudoRandom(seed)
|
||||
if pr:next(1,4) == 1 then
|
||||
table.insert(invcontent, 'default:apple '..tostring(pr:next(1,5)))
|
||||
end
|
||||
if pr:next(1,3) == 1 then
|
||||
table.insert(invcontent, 'bucket:bucket_empty 1')
|
||||
end
|
||||
if pr:next(1,4) == 1 then
|
||||
table.insert(invcontent, 'bucket:bucket_lava 1')
|
||||
end
|
||||
if pr:next(1,20) == 1 then
|
||||
table.insert(invcontent, 'bucket:bucket_water 1')
|
||||
end
|
||||
if pr:next(1,34) == 1 then
|
||||
table.insert(invcontent, 'bucket:nyancat 1')
|
||||
table.insert(invcontent, 'bucket:nyancat_rainbow '..tostring(pr:next(1,6)))
|
||||
end
|
||||
if pr:next(1,2) == 1 then
|
||||
table.insert(invcontent, 'default:gravel '..tostring(pr:next(1,10)))
|
||||
end
|
||||
if pr:next(1,3) == 1 then
|
||||
table.insert(invcontent, 'default:bookshelf '..tostring(pr:next(1,2)))
|
||||
end
|
||||
if pr:next(1,8) == 1 then
|
||||
table.insert(invcontent, 'default:cactus '..tostring(pr:next(1,2)))
|
||||
end
|
||||
if pr:next(1,4) == 1 then
|
||||
table.insert(invcontent, 'default:rail '..tostring(pr:next(1,10)))
|
||||
end
|
||||
if pr:next(1,5) == 1 then
|
||||
table.insert(invcontent, 'default:ladder '..tostring(pr:next(1,9)))
|
||||
end
|
||||
if pr:next(1,3) == 1 then
|
||||
table.insert(invcontent, 'default:sign_wall 1')
|
||||
end
|
||||
if pr:next(1,6) == 1 then
|
||||
table.insert(invcontent, 'default:steelblock '..tostring(pr:next(1,6)))
|
||||
end
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='default:chest', inv=invcontent},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
--for all nodes in definition
|
||||
for i=1,#ns do
|
||||
local dy = top_y + 1 - i
|
||||
local p2 = {x=p.x,y=p.y+dy,z=p.z}
|
||||
|
||||
--get node at position
|
||||
local oldn = minetest.env:get_node(p2)
|
||||
local n = ns[i]
|
||||
|
||||
--don't do anything if no new node is specified or
|
||||
--old node is air
|
||||
if n and oldn.name ~= "air" then
|
||||
--possibly add mossy if it's a cobble node
|
||||
if n.name == 'default:cobble' then
|
||||
local perlin = minetest.env:get_perlin(123, 2, 0.8, 2.0)
|
||||
if perlin:get3d(p2) >= 0.0 then
|
||||
n.name = 'default:mossycobble'
|
||||
end
|
||||
end
|
||||
|
||||
--set node
|
||||
--dm_debug("pos: " .. minetest.pos_to_string(p2) .. " replacing " .. oldn.name .. " by " .. n.name)
|
||||
minetest.env:set_node(p2, ns[i])
|
||||
|
||||
--special handling for chests
|
||||
if n.inv then
|
||||
dm_debug("adding chest at " .. minetest.pos_to_string(p2) )
|
||||
local meta = minetest.env:get_meta(p2)
|
||||
local inv = meta:get_inventory()
|
||||
for _,itemstring in ipairs(n.inv) do
|
||||
inv:add_item('main', itemstring)
|
||||
end
|
||||
end
|
||||
else
|
||||
--dm_debug("pos: " .. minetest.pos_to_string(p) .. " not replacing " .. oldn.name)
|
||||
end
|
||||
|
||||
end
|
||||
if mob then
|
||||
--dm_debug("adding dm at " .. minetest.pos_to_string({x=p.x,y=p.y+1,z=p.z}) )
|
||||
local newobject = minetest.env:add_entity({x=p.x,y=p.y+1,z=p.z}, mob)
|
||||
local newentity = mobf_find_entity(newobject)
|
||||
|
||||
if newentity and
|
||||
newentity.dynamic_data and
|
||||
newentity.dynamic_data.spawning then
|
||||
newentity.dynamic_data.spawning.player_spawned = playerspawned
|
||||
newentity.dynamic_data.spawning.spawner = "vault"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vault.generate_vault = function(vault_def, p, dir, seed)
|
||||
local dim_z = #vault_def
|
||||
assert(dim_z > 0)
|
||||
local dim_x = #vault_def[1]
|
||||
|
||||
--don't generate vault if entrance dir not z +1
|
||||
if not vault.cmp(dir, {x=0,y=0,z=1}) then
|
||||
--dm_debug("entrance direction wrong: " .. minetest.pos_to_string(p))
|
||||
return
|
||||
else
|
||||
dm_debug("generating vault at: " .. minetest.pos_to_string(p))
|
||||
end
|
||||
|
||||
--print("Making vault at "..minetest.pos_to_string(p))
|
||||
if dim_x >= 14 then
|
||||
--dm_debug("Making large vault at "..minetest.pos_to_string(p))
|
||||
else
|
||||
--dm_debug("Making vault at "..minetest.pos_to_string(p))
|
||||
end
|
||||
|
||||
-- Find door in definition
|
||||
local def_door_p = nil
|
||||
for dx=1,dim_x do
|
||||
for dz=1,dim_z do
|
||||
if vault_def[dim_z+1-dz][dx] == 'd' then
|
||||
def_door_p = {x=dx,y=0,z=dz}
|
||||
end
|
||||
if def_door_p then break end
|
||||
end
|
||||
if def_door_p then break end
|
||||
end
|
||||
--print("Vault door found at "..minetest.pos_to_string(def_door_p).." in definition")
|
||||
assert(def_door_p)
|
||||
local randseed = seed
|
||||
for dx=1,dim_x do
|
||||
for dz=1,dim_z do
|
||||
local p2 = vault.add(vault.sub(p, def_door_p), {x=dx, y=0, z=dz})
|
||||
local part = vault_def[dim_z+1-dz][dx]
|
||||
--dm_debug("Making vault part "..dump(part).." at "..minetest.pos_to_string(p2))
|
||||
vault.make_vault_part(p2, part, randseed)
|
||||
randseed = randseed + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Definition is for Z=up, X=right, dir={x=0,y=0,z=1}
|
||||
vault.vault_defs = {
|
||||
---[[
|
||||
{
|
||||
{'w','w','w','w','w','w','w','w','w','w'},
|
||||
{'w','c','c','c','c','c','C','C','c','w'},
|
||||
{'w','c','C','c','c','c','C','C','m','w'},
|
||||
{'w','C','C','C','w','w','C','C','c','w'},
|
||||
{'w','C','C','C','w','w','C','C','c','w'},
|
||||
{'w','T','C','c','w','w','C','w','w','w'},
|
||||
{'w','c','t','c','w','w','C','w','n','n'},
|
||||
{'w','w','w','w','w','w','C','w','n','n'},
|
||||
{'n','n','n','n','n','w','d','w','n','n'},
|
||||
{'n','n','n','n','n','n','A','n','n','n'},
|
||||
},
|
||||
--]]
|
||||
---[[
|
||||
{
|
||||
{'w','w','w','w','w','w','w','w'},
|
||||
{'w','c','c','c','m','C','c','w'},
|
||||
{'w','C','c','c','C','C','c','w'},
|
||||
{'w','C','w','w','C','C','c','w'},
|
||||
{'w','C','t','w','C','C','c','w'},
|
||||
{'w','C','t','w','C','w','d','w'},
|
||||
{'w','T','w','w','C','w','A','n'},
|
||||
{'w','c','C','C','C','w','n','n'},
|
||||
{'n','n','n','w','w','w','n','n'},
|
||||
},
|
||||
--]]
|
||||
---[[
|
||||
{
|
||||
{'W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W'},
|
||||
{'W','l','l','l','l','l','l','t','t','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','m','l','l','l','l','l','f','f','l','l','l','l','l','m','W'},
|
||||
{'W','c','l','l','l','l','l','f','f','l','l','l','l','l','c','W'},
|
||||
{'W','c','l','l','l','l','l','f','f','l','l','l','l','l','c','W'},
|
||||
{'W','c','l','l','l','l','l','f','f','l','l','l','l','l','c','W'},
|
||||
{'W','m','l','l','l','l','l','f','f','l','l','l','l','l','m','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','W','W','W','W','W','W','W','d','W','W','W','W','W','W','W'},
|
||||
{'n','n','n','n','n','n','n','n','A','n','n','n','n','n','n','n'},
|
||||
},
|
||||
--]]
|
||||
---[[
|
||||
{
|
||||
{'W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W'},
|
||||
{'W','f','f','f','f','l','l','t','l','l','l','l','l','l','l','W'},
|
||||
{'W','f','l','l','l','l','l','f','l','l','l','l','l','l','l','W'},
|
||||
{'W','f','l','l','f','l','l','l','l','l','l','l','l','l','l','W'},
|
||||
{'W','f','l','l','l','l','l','l','f','l','f','f','l','l','m','W'},
|
||||
{'W','f','l','l','l','l','f','l','l','l','l','l','f','l','c','W'},
|
||||
{'W','f','f','l','l','l','l','l','l','l','l','l','f','l','c','W'},
|
||||
{'W','c','f','l','l','l','l','l','l','l','l','l','f','l','c','W'},
|
||||
{'W','m','f','l','l','l','l','l','l','l','l','l','f','l','m','W'},
|
||||
{'W','l','f','l','l','l','l','f','f','l','f','f','f','l','l','W'},
|
||||
{'W','l','t','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','W','W','W','W','W','W','W','d','W','W','W','W','W','W','W'},
|
||||
{'n','n','n','n','n','n','n','n','A','n','n','n','n','n','n','n'},
|
||||
},
|
||||
--]]
|
||||
---[[
|
||||
{
|
||||
{'n','n','n','n','n','n','n','n','n','n','n','n','w','w','w','w','n','n','n','n'},
|
||||
{'n','n','n','n','n','n','n','n','w','w','w','w','w','c','c','w','w','w','w','n'},
|
||||
{'n','n','n','n','n','n','n','w','w','c','c','c','c','c','c','c','c','w','w','n'},
|
||||
{'n','n','n','n','n','n','w','w','c','c','c','c','c','c','c','c','c','c','W','W'},
|
||||
{'n','n','n','n','n','n','w','t','c','C','C','m','c','c','C','C','m','c','c','W'},
|
||||
{'n','n','n','n','n','n','w','t','c','C','C','c','c','c','C','C','c','c','c','W'},
|
||||
{'n','n','n','n','n','n','w','w','c','c','c','c','c','c','c','c','c','c','c','W'},
|
||||
{'n','n','n','n','n','n','n','w','w','c','c','c','C','C','C','C','C','C','C','W'},
|
||||
{'n','n','n','n','n','n','n','n','w','w','c','c','l','l','l','l','l','l','l','W'},
|
||||
{'n','n','n','n','n','n','n','n','W','W','l','l','l','l','l','l','l','l','l','W'},
|
||||
{'w','w','w','w','W','W','W','W','W','l','l','l','l','l','l','l','l','l','l','W'},
|
||||
{'w','w','c','c','C','S','S','C','C','l','l','l','l','l','l','l','l','l','l','W'},
|
||||
{'w','c','c','c','C','C','C','C','l','l','l','l','l','l','l','l','l','l','l','W'},
|
||||
{'w','c','c','C','C','C','C','C','l','l','l','l','m','C','l','l','l','l','l','W'},
|
||||
{'w','c','c','C','C','C','C','C','l','l','l','l','C','t','l','l','l','l','l','W'},
|
||||
{'w','c','c','C','C','l','l','l','l','l','l','l','l','l','l','l','l','l','l','W'},
|
||||
{'w','c','C','C','l','l','l','l','l','l','l','l','l','l','l','l','l','l','l','W'},
|
||||
{'w','W','C','C','l','l','l','l','l','l','l','l','l','l','l','l','l','l','W','W'},
|
||||
{'n','W','d','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','n'},
|
||||
{'n','n','A','n','n','n','n','n','n','n','n','n','n','n','n','n','n','n','n','n'},
|
||||
},
|
||||
--]]
|
||||
}
|
||||
|
||||
function vault.node_is_solid(n)
|
||||
return (n and n.name and minetest.registered_nodes[n.name] and
|
||||
minetest.registered_nodes[n.name].walkable)
|
||||
end
|
||||
|
||||
vault.generate_random_vault = function(p, dir, seed)
|
||||
|
||||
--random select of vault template
|
||||
local pr = PseudoRandom(seed+9322)
|
||||
local vault_def = vault.vault_defs[pr:next(1, #vault.vault_defs)]
|
||||
|
||||
--generate vault by template
|
||||
vault.generate_vault(vault_def, p, dir, seed)
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, seed)
|
||||
|
||||
--abort in case of dm disabled
|
||||
if minetest.registered_entities["animal_dm:dm"] == nil then
|
||||
return
|
||||
end
|
||||
|
||||
--abort in case of above sea level
|
||||
if maxp.y > -10 then
|
||||
return
|
||||
end
|
||||
|
||||
--calculate area of generated chunk
|
||||
local area = (maxp.x-minp.x+1)*(maxp.z-minp.z+1)
|
||||
|
||||
--initialize dungeon level with 2
|
||||
local dungeon_level_y = 2
|
||||
|
||||
--get random dungeon level within generated chunk
|
||||
if maxp.y < 2 then
|
||||
local pr = PseudoRandom(seed+932)
|
||||
dungeon_level_y = pr:next(minp.y, maxp.y)
|
||||
end
|
||||
|
||||
|
||||
--initialize check values
|
||||
local is_empty = false
|
||||
local light = nil
|
||||
local last_empty = false
|
||||
local last_light = nil
|
||||
local possible_entrances = {}
|
||||
local d = 4
|
||||
|
||||
|
||||
--loop through chunk using d frames in x direction
|
||||
for x=minp.x/d+1,maxp.x/d-1 do
|
||||
--set to unknown on start of x-loop (why?)
|
||||
local last_node_known = false
|
||||
|
||||
--loop through cunk in z direction
|
||||
for z=minp.z+1,maxp.z-1 do
|
||||
|
||||
--get information of current node to check
|
||||
local p = {x=x*d, y=dungeon_level_y, z=z}
|
||||
local n = minetest.env:get_node(p)
|
||||
|
||||
--save values from last loop
|
||||
last_empty = is_empty
|
||||
last_light = light
|
||||
|
||||
--get new values
|
||||
is_empty = not vault.node_is_solid(n)
|
||||
light = minetest.env:get_node_light(p, 0.5)
|
||||
|
||||
--if last node was known
|
||||
if last_node_known then
|
||||
|
||||
--initialize values
|
||||
local useful_light = nil
|
||||
|
||||
--save values
|
||||
if is_empty then
|
||||
useful_light = light
|
||||
else
|
||||
useful_light = last_light
|
||||
end
|
||||
|
||||
--if current node isn't solid,
|
||||
--last was solid and we're not at daylight
|
||||
if is_empty and not last_empty and useful_light < 15 then
|
||||
|
||||
--calculate ??? positions next to current pos
|
||||
local p1 = vault.add(p, {x=0, y=0, z=-1})
|
||||
local p2 = vault.add(p1, {x=0, y=2, z=-1})
|
||||
local p3 = vault.add(p1, {x=0, y=2, z=-8})
|
||||
local p4 = vault.add(p1, {x=-3, y=1, z=-2})
|
||||
local p5 = vault.add(p1, {x=3, y=1, z=-2})
|
||||
|
||||
--if all nodes are solid
|
||||
if vault.node_is_solid(minetest.env:get_node(p2)) and
|
||||
vault.node_is_solid(minetest.env:get_node(p3)) and
|
||||
vault.node_is_solid(minetest.env:get_node(p4)) and
|
||||
vault.node_is_solid(minetest.env:get_node(p5))
|
||||
then
|
||||
local entrance = {
|
||||
p = p1,
|
||||
dir = {x=0, y=0, z=-1},
|
||||
}
|
||||
--add to entrance table with direction z = -1
|
||||
table.insert(possible_entrances, entrance)
|
||||
end
|
||||
end
|
||||
|
||||
--if current node isn't solid,
|
||||
--last was solid and we're not at daylight
|
||||
if last_empty and not is_empty and useful_light < 15 then
|
||||
local p1 = vault.add(p, {x=0, y=0, z=0})
|
||||
local p2 = vault.add(p1, {x=0, y=2, z=1})
|
||||
local p3 = vault.add(p1, {x=0, y=2, z=8})
|
||||
local p4 = vault.add(p1, {x=-3, y=1, z=2})
|
||||
local p5 = vault.add(p1, {x=3, y=1, z=2})
|
||||
|
||||
--if all nodes are solid
|
||||
if vault.node_is_solid(minetest.env:get_node(p2)) and
|
||||
vault.node_is_solid(minetest.env:get_node(p3)) and
|
||||
vault.node_is_solid(minetest.env:get_node(p4)) and
|
||||
vault.node_is_solid(minetest.env:get_node(p5))
|
||||
then
|
||||
local entrance = {
|
||||
p = p1,
|
||||
dir = {x=0, y=0, z=1},
|
||||
}
|
||||
--add to entrance table with direction z = 1
|
||||
table.insert(possible_entrances, entrance)
|
||||
end
|
||||
end
|
||||
end
|
||||
last_node_known = true
|
||||
end
|
||||
end
|
||||
|
||||
--for _,entrance in ipairs(possible_entrances) do
|
||||
-- dm_debug("Possible entrance: "..dump(entrance))
|
||||
--end
|
||||
--calculate number of entrances to generate per area
|
||||
local num_entrances_to_generate = area/200
|
||||
|
||||
--check if there are enough possible entrances
|
||||
if num_entrances_to_generate > #possible_entrances then
|
||||
num_entrances_to_generate = #possible_entrances
|
||||
end
|
||||
|
||||
local pr = PseudoRandom(seed+9452)
|
||||
|
||||
--generate vault for max number of entraces to generate at random
|
||||
--selected possible entrances
|
||||
for entrances_generate_i=1,num_entrances_to_generate do
|
||||
local entrance_i = pr:next(1, #possible_entrances)
|
||||
local entrance = possible_entrances[entrance_i]
|
||||
--dm_debug("Entrance: "..dump(entrance))
|
||||
vault.generate_random_vault(entrance.p, entrance.dir, seed)
|
||||
end
|
||||
end)
|
3
mods/animal_rat/depends.txt
Normal file
@ -0,0 +1,3 @@
|
||||
default
|
||||
animalmaterials
|
||||
mobf
|
104
mods/animal_rat/init.lua
Normal file
@ -0,0 +1,104 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file init.lua
|
||||
--! @brief rat implementation
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2013-01-27
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.log("action","MOD: animal_rat loading ...")
|
||||
|
||||
local version = "0.0.8"
|
||||
|
||||
local selectionbox_rat = {-0.2, -0.0625, -0.2, 0.2, 0.125, 0.2}
|
||||
|
||||
local rat_groups = {
|
||||
not_in_creative_inventory=1
|
||||
}
|
||||
|
||||
rat_prototype = {
|
||||
name="rat",
|
||||
modname="animal_rat",
|
||||
|
||||
generic = {
|
||||
description="Rat (Animals)",
|
||||
base_health=2,
|
||||
kill_result="",
|
||||
armor_groups= {
|
||||
fleshy=3,
|
||||
},
|
||||
groups = rat_groups,
|
||||
envid="on_ground_1",
|
||||
},
|
||||
movement = {
|
||||
default_gen="probab_mov_gen",
|
||||
min_accel=0.4,
|
||||
max_accel=0.6,
|
||||
max_speed=2,
|
||||
pattern="run_and_jump_low",
|
||||
canfly=false,
|
||||
},
|
||||
catching = {
|
||||
tool="animalmaterials:net",
|
||||
consumed=true,
|
||||
},
|
||||
spawning = {
|
||||
rate=0.02,
|
||||
density=250,
|
||||
algorithm="forrest_mapgen",
|
||||
height=1
|
||||
},
|
||||
animation = {
|
||||
walk = {
|
||||
start_frame = 1,
|
||||
end_frame = 40,
|
||||
},
|
||||
stand = {
|
||||
start_frame = 41,
|
||||
end_frame = 80,
|
||||
},
|
||||
},
|
||||
states = {
|
||||
{
|
||||
name = "default",
|
||||
movgen = "none",
|
||||
chance = 0,
|
||||
animation = "stand",
|
||||
graphics_3d = {
|
||||
visual = "mesh",
|
||||
mesh = "animal_rat.b3d",
|
||||
textures = {"animal_rat_mesh.png"},
|
||||
collisionbox = selectionbox_rat,
|
||||
visual_size= {x=1,y=1,z=1},
|
||||
},
|
||||
graphics = {
|
||||
sprite_scale={x=1,y=1},
|
||||
sprite_div = {x=6,y=1},
|
||||
visible_height = 1,
|
||||
visible_width = 1,
|
||||
},
|
||||
typical_state_time = 10,
|
||||
},
|
||||
{
|
||||
name = "walking",
|
||||
movgen = "probab_mov_gen",
|
||||
chance = 0.75,
|
||||
animation = "walk",
|
||||
typical_state_time = 180,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
--register mod
|
||||
minetest.log("action","\tadding "..rat_prototype.name)
|
||||
mobf_add_mob(rat_prototype)
|
||||
minetest.log("action","MOD: animal_rat mod version " .. version .. " loaded")
|
BIN
mods/animal_rat/models/animal_rat.b3d
Normal file
BIN
mods/animal_rat/models/rat.blend
Normal file
BIN
mods/animal_rat/models/rat.xcf
Normal file
BIN
mods/animal_rat/textures/animal_rat_mesh.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
mods/animal_rat/textures/animal_rat_rat.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
mods/animal_rat/textures/animal_rat_rat_item.png
Normal file
After Width: | Height: | Size: 918 B |
8
mods/animal_vombie/License.txt
Normal file
@ -0,0 +1,8 @@
|
||||
Licenses
|
||||
|
||||
CCO
|
||||
sounds/animal_vombie_sun_damage.ogg
|
||||
sounds/animal_vombie_random_1.ogg
|
||||
|
||||
Everything not mentioned:
|
||||
CC-BY-SA, Author sapier
|
2
mods/animal_vombie/depends.txt
Normal file
@ -0,0 +1,2 @@
|
||||
default
|
||||
mobf
|
67
mods/animal_vombie/flame.lua
Normal file
@ -0,0 +1,67 @@
|
||||
--! @class vombie_flame
|
||||
--! @ingroup weapons
|
||||
--! @brief a plasmaball weapon entity
|
||||
vombie_flame = {
|
||||
physical = false,
|
||||
textures = {"animal_vombie_flames.png"},
|
||||
visual = "sprite",
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
spritediv = {x=1,y=16},
|
||||
--vizual_size = {x=0.1,y=0.1},
|
||||
|
||||
velocity = 1.0,
|
||||
gravity = -0.1,
|
||||
|
||||
damage = 8,
|
||||
|
||||
leveltime = 2.5,
|
||||
created = -1,
|
||||
leveldtime = 0,
|
||||
level = 0,
|
||||
}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: vombie_flame.on_activate = function(self, staticdata)
|
||||
--
|
||||
--! @brief onactivate callback for plasmaball
|
||||
--! @memberof vombie_flame
|
||||
--! @private
|
||||
--
|
||||
--! @param self fireball itself
|
||||
--! @param staticdata
|
||||
-------------------------------------------------------------------------------
|
||||
function vombie_flame.on_activate(self,staticdata)
|
||||
self.created = mobf_get_current_time()
|
||||
self.object:setsprite({x=0,y=self.level}, 1, 0, true)
|
||||
self.object:setvelocity({x=0,y=self.velocity,z=0})
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: vombie_flame.on_step = function(self, dtime)
|
||||
--
|
||||
--! @brief onstep callback for vombie flame
|
||||
--! @memberof vombie_flame
|
||||
--! @private
|
||||
--
|
||||
--! @param vombie_flame itself
|
||||
--! @param dtime time since last callback
|
||||
-------------------------------------------------------------------------------
|
||||
function vombie_flame.on_step(self, dtime)
|
||||
local pos = self.object:getpos()
|
||||
local node = minetest.env:get_node(pos)
|
||||
|
||||
self.leveldtime = self.leveldtime + dtime
|
||||
|
||||
if (self.leveldtime *10) > math.random()*self.leveltime then
|
||||
self.level = self.level +1
|
||||
|
||||
if (self.level < 16) then
|
||||
self.object:setsprite({x=0,y=self.level}, 1, 0, true)
|
||||
else
|
||||
self.object:remove()
|
||||
end
|
||||
self.leveldtime = 0
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_entity(":animal_vombie:vombie_flame", vombie_flame)
|
184
mods/animal_vombie/init.lua
Normal file
@ -0,0 +1,184 @@
|
||||
local version = "0.0.17"
|
||||
|
||||
minetest.log("action","MOD: loading animal_vombie ... ")
|
||||
|
||||
local vombie_groups = {
|
||||
not_in_creative_inventory=1
|
||||
}
|
||||
|
||||
local selectionbox_vombie = {-0.3, -1.2, -0.5, 0.3, 1, 0.5}
|
||||
|
||||
local modpath = minetest.get_modpath("animal_vombie")
|
||||
|
||||
dofile (modpath .. "/flame.lua")
|
||||
|
||||
function vombie_drop()
|
||||
local result = {}
|
||||
if math.random() < 0.05 then
|
||||
table.insert(result,"animalmaterials:bone 2")
|
||||
else
|
||||
table.insert(result,"animalmaterials:bone 1")
|
||||
end
|
||||
|
||||
table.insert(result,"animalmaterials:meat_undead 1")
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function vombie_on_step_handler(entity,now,dtime)
|
||||
local pos = entity.getbasepos(entity)
|
||||
local current_light = minetest.env:get_node_light(pos)
|
||||
|
||||
--print("vombie on step: current_light:" .. current_light .. " max light: " .. LIGHT_MAX .. " 3dmode:" .. dump(minetest.setting_getbool("disable_animals_3d_mode")))
|
||||
|
||||
if current_light ~= nil and
|
||||
current_light > LIGHT_MAX and
|
||||
minetest.setting_getbool("mobf_disable_3d_mode") ~= true and
|
||||
minetest.setting_getbool("vombie_3d_burn_animation_enabled") == true then
|
||||
|
||||
|
||||
local xdelta = (math.random()-0.5)
|
||||
local zdelta = (math.random()-0.5)
|
||||
--print("receiving sun damage: " .. xdelta .. " " .. zdelta)
|
||||
local newobject=minetest.env:add_entity( { x=pos.x + xdelta,
|
||||
y=pos.y,
|
||||
z=pos.z + zdelta },
|
||||
"animal_vombie:vombie_flame")
|
||||
|
||||
--add particles
|
||||
end
|
||||
end
|
||||
|
||||
function vombie_on_activate_handler(entity)
|
||||
|
||||
local pos = entity.object:getpos()
|
||||
|
||||
local current_light = minetest.env:get_node_light(pos)
|
||||
|
||||
if current_light == nil then
|
||||
minetest.log(LOGLEVEL_ERROR,"ANIMALS: Bug!!! didn't get a light value for ".. printpos(pos))
|
||||
return
|
||||
end
|
||||
--check if animal is in sunlight
|
||||
if ( current_light > LIGHT_MAX) then
|
||||
--don't spawn vombie in sunlight
|
||||
spawning.remove(entity)
|
||||
end
|
||||
end
|
||||
|
||||
vombie_prototype = {
|
||||
name="vombie",
|
||||
modname="animal_vombie",
|
||||
|
||||
generic = {
|
||||
description="Vombie",
|
||||
base_health=8,
|
||||
kill_result=vombie_drop,
|
||||
armor_groups= {
|
||||
fleshy=3,
|
||||
daemon=1,
|
||||
},
|
||||
groups = vombie_groups,
|
||||
envid="on_ground_1",
|
||||
custom_on_step_handler = vombie_on_step_handler,
|
||||
custom_on_activate_handler = vombie_on_activate_handler,
|
||||
},
|
||||
movement = {
|
||||
min_accel=0.3,
|
||||
max_accel=1.5,
|
||||
max_speed=2,
|
||||
pattern="stop_and_go",
|
||||
canfly=false,
|
||||
follow_speedup=10,
|
||||
},
|
||||
combat = {
|
||||
angryness=1,
|
||||
starts_attack=true,
|
||||
sun_sensitive=true,
|
||||
melee = {
|
||||
maxdamage=2,
|
||||
range=2,
|
||||
speed=1,
|
||||
},
|
||||
distance = nil,
|
||||
self_destruct = nil,
|
||||
},
|
||||
|
||||
spawning = {
|
||||
rate=0.05,
|
||||
density=30,
|
||||
algorithm="at_night_spawner",
|
||||
height=2,
|
||||
respawndelay=60,
|
||||
},
|
||||
sound = {
|
||||
random = {
|
||||
name="animal_vombie_random_1",
|
||||
min_delta = 10,
|
||||
chance = 0.5,
|
||||
gain = 0.05,
|
||||
max_hear_distance = 5,
|
||||
},
|
||||
sun_damage = {
|
||||
name="animal_vombie_sun_damage",
|
||||
gain = 0.25,
|
||||
max_hear_distance = 7,
|
||||
},
|
||||
},
|
||||
animation = {
|
||||
stand = {
|
||||
start_frame = 0,
|
||||
end_frame = 80,
|
||||
},
|
||||
walk = {
|
||||
start_frame = 168,
|
||||
end_frame = 188,
|
||||
},
|
||||
attack = {
|
||||
start_frame = 81,
|
||||
end_frame = 110,
|
||||
},
|
||||
},
|
||||
states = {
|
||||
{
|
||||
name = "default",
|
||||
movgen = "none",
|
||||
typical_state_time = 30,
|
||||
chance = 0,
|
||||
animation = "stand",
|
||||
graphics = {
|
||||
sprite_scale={x=4,y=4},
|
||||
sprite_div = {x=6,y=2},
|
||||
visible_height = 2.2,
|
||||
visible_width = 1,
|
||||
},
|
||||
graphics_3d = {
|
||||
visual = "mesh",
|
||||
mesh = "animal_vombie_vombie.b3d",
|
||||
textures = {"animal_vombie_vombie_mesh.png"},
|
||||
collisionbox = selectionbox_vombie,
|
||||
visual_size= {x=1,y=1,z=1},
|
||||
},
|
||||
},
|
||||
{
|
||||
name = "walking",
|
||||
movgen = "probab_mov_gen",
|
||||
typical_state_time = 120,
|
||||
chance = 0.5,
|
||||
animation = "walk",
|
||||
},
|
||||
{
|
||||
name = "combat",
|
||||
typical_state_time = 9999,
|
||||
chance = 0.0,
|
||||
animation = "attack",
|
||||
movgen="follow_mov_gen",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
--register with animals mod
|
||||
minetest.log("action","\tadding mob "..vombie_prototype.name)
|
||||
mobf_add_mob(vombie_prototype)
|
||||
minetest.log("action","MOD: animal_vombie mod version " .. version .. " loaded")
|
BIN
mods/animal_vombie/models/animal_vombie_vombie.b3d
Normal file
BIN
mods/animal_vombie/models/animal_vombie_vombie.xcf
Normal file
BIN
mods/animal_vombie/models/vombie.blend
Normal file
BIN
mods/animal_vombie/sounds/animal_vombie_random_1.ogg
Normal file
BIN
mods/animal_vombie/sounds/animal_vombie_sun_damage.ogg
Normal file
16
mods/animal_vombie/sounds/soundlist.txt
Normal file
@ -0,0 +1,16 @@
|
||||
--vombie--
|
||||
random:
|
||||
random_1.ogg
|
||||
hit:
|
||||
--missing--
|
||||
die:
|
||||
--missing--
|
||||
melee:
|
||||
hit.ogg
|
||||
sun_damage:
|
||||
sun_damage.ogg
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
mods/animal_vombie/textures/animal_vombie_flames.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
mods/animal_vombie/textures/animal_vombie_vombie.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
mods/animal_vombie/textures/animal_vombie_vombie_item.png
Normal file
After Width: | Height: | Size: 402 B |
BIN
mods/animal_vombie/textures/animal_vombie_vombie_mesh.png
Normal file
After Width: | Height: | Size: 47 KiB |
1
mods/animalmaterials/depends.txt
Normal file
@ -0,0 +1 @@
|
||||
default
|
299
mods/animalmaterials/init.lua
Normal file
@ -0,0 +1,299 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file init.lua
|
||||
--! @brief animalmaterials
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2013-01-27
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.log("action","MOD: animalmaterials loading ...")
|
||||
local version = "0.0.15"
|
||||
|
||||
|
||||
animalmaterialsdata = {}
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
-- Node definitions
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
-- Item definitions
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- deamondeath sword
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_tool("animalmaterials:sword_deamondeath", {
|
||||
description = "Sword (Deamondeath)",
|
||||
inventory_image = "default_tool_steelsword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 0.50,
|
||||
max_drop_level=1,
|
||||
groupcaps={
|
||||
fleshy={times={[1]=2.00, [2]=0.80, [3]=0.40}, uses=10, maxlevel=1},
|
||||
snappy={times={[2]=0.70, [3]=0.30}, uses=40, maxlevel=1},
|
||||
choppy={times={[3]=0.70}, uses=40, maxlevel=0},
|
||||
deamon={times={[1]=0.25, [2]=0.10, [3]=0.05}, uses=20, maxlevel=3},
|
||||
}
|
||||
}
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- scissors
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_tool("animalmaterials:scissors", {
|
||||
description = "Scissors",
|
||||
inventory_image = "animalmaterials_scissors.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
wool = {uses=20,maxlevel=1}
|
||||
}
|
||||
},
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- lasso
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:lasso", {
|
||||
description = "Lasso",
|
||||
image = "animalmaterials_lasso.png",
|
||||
stack_max=10,
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- net
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:net", {
|
||||
description = "Net",
|
||||
image = "animalmaterials_net.png",
|
||||
stack_max=10,
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- saddle
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:saddle", {
|
||||
description = "Saddle",
|
||||
image = "animalmaterials_saddle.png",
|
||||
stack_max=1
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- meat
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:meat_raw", {
|
||||
description = "Raw meat",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:meat_pork", {
|
||||
description = "Pork (raw)",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:meat_beef", {
|
||||
description = "Beef (raw)",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:meat_chicken", {
|
||||
description = "Chicken (raw)",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:meat_lamb", {
|
||||
description = "Lamb (raw)",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:meat_venison", {
|
||||
description = "Venison (raw)",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:meat_undead", {
|
||||
description = "Meat (not quite dead)",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(-2),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=5
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:meat_toxic", {
|
||||
description = "Toxic Meat",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(-5),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=5
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:meat_ostrich", {
|
||||
description = "Ostrich Meat",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(-5),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=5
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalmaterials:fish_bluewhite", {
|
||||
description = "Fish (bluewhite)",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=25
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalmaterials:fish_clownfish", {
|
||||
description = "Fish (clownfish)",
|
||||
image = "animalmaterials_meat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { meat=1, eatable=1 },
|
||||
stack_max=25
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- feather
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:feather", {
|
||||
description = "Feather",
|
||||
image = "animalmaterials_feather.png",
|
||||
stack_max=25
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- milk
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:milk", {
|
||||
description = "Milk",
|
||||
image = "animalmaterials_milk.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = { eatable=1 },
|
||||
stack_max=10
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- egg
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:egg", {
|
||||
description = "Egg",
|
||||
image = "animalmaterials_egg.png",
|
||||
stack_max=10
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalmaterials:egg_big", {
|
||||
description = "Egg (big)",
|
||||
image = "animalmaterials_egg_big.png",
|
||||
stack_max=5
|
||||
})
|
||||
|
||||
animalmaterialsdata["animalmaterials_egg"] = {
|
||||
graphics_3d = {
|
||||
visual = "mesh",
|
||||
mesh = "animalmaterials_egg_ent.b3d",
|
||||
textures = { "animalmaterials_egg_ent_mesh.png" },
|
||||
collisionbox = { -0.12,-0.125,-0.12,0.12,0.125,0.12 },
|
||||
visual_size = {x=1,y=1,z=1},
|
||||
}
|
||||
}
|
||||
|
||||
animalmaterialsdata["animalmaterials_egg_big"] = {
|
||||
graphics_3d = {
|
||||
visual = "mesh",
|
||||
mesh = "animalmaterials_egg_ent.b3d",
|
||||
textures = { "animalmaterials_egg_ent_mesh.png" },
|
||||
collisionbox = { -0.24,-0.25,-0.24,0.24,0.25,0.24 },
|
||||
visual_size = {x=2,y=2,z=2},
|
||||
}
|
||||
}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- bone
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:bone", {
|
||||
description = "Bone",
|
||||
image = "animalmaterials_bone.png",
|
||||
stack_max=25
|
||||
})
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- furs
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:fur", {
|
||||
description = "Fur",
|
||||
image = "animalmaterials_fur.png",
|
||||
stack_max=25
|
||||
})
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-- scale
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
minetest.register_craftitem("animalmaterials:scale_golden", {
|
||||
description = "Scale (golden)",
|
||||
image = "animalmaterials_scale_golden.png",
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:scale_white", {
|
||||
description = "Scale (white)",
|
||||
image = "animalmaterials_scale_white.png",
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:scale_grey", {
|
||||
description = "Scale (grey)",
|
||||
image = "animalmaterials_scale_grey.png",
|
||||
stack_max=25
|
||||
})
|
||||
minetest.register_craftitem("animalmaterials:scale_blue", {
|
||||
description = "Scale (blue)",
|
||||
image = "animalmaterials_scale_blue.png",
|
||||
stack_max=25
|
||||
})
|
||||
|
||||
minetest.log("action","MOD: animalmaterials mod version " .. version .. " loaded")
|
BIN
mods/animalmaterials/models/animalmaterials_egg_ent.b3d
Normal file
BIN
mods/animalmaterials/models/animalmaterials_egg_ent.xcf
Normal file
BIN
mods/animalmaterials/models/egg.blend
Normal file
BIN
mods/animalmaterials/textures/animalmaterials_bone.png
Normal file
After Width: | Height: | Size: 912 B |
BIN
mods/animalmaterials/textures/animalmaterials_egg.png
Normal file
After Width: | Height: | Size: 672 B |
BIN
mods/animalmaterials/textures/animalmaterials_egg_big.png
Normal file
After Width: | Height: | Size: 660 B |
BIN
mods/animalmaterials/textures/animalmaterials_egg_ent_mesh.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
mods/animalmaterials/textures/animalmaterials_feather.png
Normal file
After Width: | Height: | Size: 447 B |
BIN
mods/animalmaterials/textures/animalmaterials_fur.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
mods/animalmaterials/textures/animalmaterials_glass.png
Normal file
After Width: | Height: | Size: 564 B |
BIN
mods/animalmaterials/textures/animalmaterials_lasso.png
Normal file
After Width: | Height: | Size: 458 B |
BIN
mods/animalmaterials/textures/animalmaterials_meat_raw.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
mods/animalmaterials/textures/animalmaterials_milk.png
Normal file
After Width: | Height: | Size: 559 B |
BIN
mods/animalmaterials/textures/animalmaterials_net.png
Normal file
After Width: | Height: | Size: 432 B |
BIN
mods/animalmaterials/textures/animalmaterials_saddle.png
Normal file
After Width: | Height: | Size: 329 B |
BIN
mods/animalmaterials/textures/animalmaterials_scale_blue.png
Normal file
After Width: | Height: | Size: 668 B |
BIN
mods/animalmaterials/textures/animalmaterials_scale_golden.png
Normal file
After Width: | Height: | Size: 701 B |
BIN
mods/animalmaterials/textures/animalmaterials_scale_grey.png
Normal file
After Width: | Height: | Size: 557 B |
BIN
mods/animalmaterials/textures/animalmaterials_scale_white.png
Normal file
After Width: | Height: | Size: 634 B |
BIN
mods/animalmaterials/textures/animalmaterials_scissors.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
1
mods/dungeon/depends.txt
Normal file
@ -0,0 +1 @@
|
||||
default
|
560
mods/dungeon/init.lua
Normal file
@ -0,0 +1,560 @@
|
||||
-- minetest/dungeon: dungeon
|
||||
|
||||
local DUNGEON_Y = -1000
|
||||
|
||||
-- Define this so ores don't get placed on walls
|
||||
minetest.register_node("dungeon:stone", {
|
||||
description = "Dungeon Stone",
|
||||
tiles = {"default_stone.png"},
|
||||
groups = {},
|
||||
legacy_mineral = true,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_alias("mapgen_singlenode", "dungeon:stone")
|
||||
|
||||
-- Make chests not pickable up
|
||||
local def = minetest.registered_nodes["default:chest"]
|
||||
def.groups = {}
|
||||
minetest.register_node(":default:chest", def)
|
||||
|
||||
local v3 = {}
|
||||
function v3.new(x, y, z)
|
||||
if x == nil then
|
||||
return {
|
||||
x = 0,
|
||||
y = 0,
|
||||
z = 0
|
||||
}
|
||||
end
|
||||
if type(x) == "table" then
|
||||
return {
|
||||
x = x.x,
|
||||
y = x.y,
|
||||
z = x.z,
|
||||
}
|
||||
end
|
||||
return {
|
||||
x = x,
|
||||
y = y,
|
||||
z = z,
|
||||
}
|
||||
end
|
||||
function v3.floor(v)
|
||||
return {
|
||||
x = math.floor(v.x),
|
||||
y = math.floor(v.y),
|
||||
z = math.floor(v.z),
|
||||
}
|
||||
end
|
||||
function v3.cmp(v, w)
|
||||
return (
|
||||
v.x == w.x and
|
||||
v.y == w.y and
|
||||
v.z == w.z
|
||||
)
|
||||
end
|
||||
function v3.add(v, w)
|
||||
return {
|
||||
x = v.x + w.x,
|
||||
y = v.y + w.y,
|
||||
z = v.z + w.z,
|
||||
}
|
||||
end
|
||||
function v3.sub(v, w)
|
||||
return {
|
||||
x = v.x - w.x,
|
||||
y = v.y - w.y,
|
||||
z = v.z - w.z,
|
||||
}
|
||||
end
|
||||
function v3.mul(v, a)
|
||||
return {
|
||||
x = v.x * a,
|
||||
y = v.y * a,
|
||||
z = v.z * a,
|
||||
}
|
||||
end
|
||||
function v3.len(v)
|
||||
return math.sqrt(
|
||||
math.pow(v.x, 2) +
|
||||
math.pow(v.y, 2) +
|
||||
math.pow(v.z, 2)
|
||||
)
|
||||
end
|
||||
function v3.norm(v)
|
||||
return v3.mul(v, 1.0 / v3.len(v))
|
||||
end
|
||||
function v3.distance(v, w)
|
||||
return math.sqrt(
|
||||
math.pow(v.x - w.x, 2) +
|
||||
math.pow(v.y - w.y, 2) +
|
||||
math.pow(v.z - w.z, 2)
|
||||
)
|
||||
end
|
||||
|
||||
mobs = {}
|
||||
|
||||
mobs.make_vault_part = function(p, part, pr)
|
||||
local ns = nil
|
||||
local top_y = 2
|
||||
local mob_y = 0
|
||||
local mob = nil
|
||||
local item = nil
|
||||
if part == 'w' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'W' then
|
||||
top_y = 3
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'c' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'f' then
|
||||
ns = {
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'l' then
|
||||
top_y = 3
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:lava_source'},
|
||||
}
|
||||
elseif part == 'm' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
local a = pr:next(1,2)
|
||||
if a == 1 then
|
||||
mob = "animal_dm:dm__default"
|
||||
else
|
||||
mob = "animal_vombie:vombie__default"
|
||||
end
|
||||
elseif part == 'r' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
mob = "animal_rat:rat__default"
|
||||
elseif part == 'C' then
|
||||
top_y = 3
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'd' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'a' then
|
||||
ns = {
|
||||
nil,
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
nil,
|
||||
}
|
||||
elseif part == 'A' then
|
||||
ns = {
|
||||
nil,
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
elseif part == 'i' then
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='air'},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
if pr:next(1,4) == 1 then
|
||||
item = 'default:torch '..tostring(pr:next(1,15))
|
||||
elseif pr:next(1,4) == 1 then
|
||||
item = 'default:apple '..tostring(pr:next(1,3))
|
||||
elseif pr:next(1,6) == 1 then
|
||||
item = 'default:sword_stone '..tostring(pr:next(2,5)*100)
|
||||
end
|
||||
elseif part == 't' then
|
||||
local invcontent = {}
|
||||
if pr:next(1,4) == 1 then
|
||||
table.insert(invcontent, 'default:apple '..tostring(pr:next(1,5)))
|
||||
end
|
||||
if pr:next(1,3) == 1 then
|
||||
table.insert(invcontent, 'default:cobble '..tostring(pr:next(1,5)))
|
||||
end
|
||||
if pr:next(1,3) == 1 then
|
||||
table.insert(invcontent, 'default:torch '..tostring(pr:next(1,20)))
|
||||
end
|
||||
if pr:next(1,3) == 1 then
|
||||
table.insert(invcontent, 'default:sword_stone '..tostring(pr:next(400,655)*100))
|
||||
end
|
||||
if pr:next(1,10) == 1 then
|
||||
table.insert(invcontent, 'default:sword_steel '..tostring(pr:next(0,655)*100))
|
||||
end
|
||||
if pr:next(1,6) == 1 then
|
||||
table.insert(invcontent, 'bucket:bucket_empty 1')
|
||||
end
|
||||
if pr:next(1,8) == 1 then
|
||||
table.insert(invcontent, 'bucket:bucket_lava 1')
|
||||
end
|
||||
if pr:next(1,20) == 1 then
|
||||
table.insert(invcontent, 'bucket:bucket_water 1')
|
||||
end
|
||||
if pr:next(1,34) == 1 then
|
||||
table.insert(invcontent, 'bucket:nyancat 1')
|
||||
table.insert(invcontent, 'bucket:nyancat_rainbow '..tostring(pr:next(1,6)))
|
||||
end
|
||||
if pr:next(1,2) == 1 then
|
||||
table.insert(invcontent, 'default:gravel '..tostring(pr:next(1,10)))
|
||||
end
|
||||
if pr:next(1,30) == 1 then
|
||||
table.insert(invcontent, 'default:bookshelf '..tostring(pr:next(1,2)))
|
||||
end
|
||||
if pr:next(1,8) == 1 then
|
||||
table.insert(invcontent, 'default:cactus '..tostring(pr:next(1,2)))
|
||||
end
|
||||
if pr:next(1,40) == 1 then
|
||||
table.insert(invcontent, 'default:rail '..tostring(pr:next(1,10)))
|
||||
end
|
||||
if pr:next(1,5) == 1 then
|
||||
table.insert(invcontent, 'default:ladder '..tostring(pr:next(1,9)))
|
||||
end
|
||||
if pr:next(1,30) == 1 then
|
||||
table.insert(invcontent, 'default:sign_wall 1')
|
||||
end
|
||||
if pr:next(1,60) == 1 then
|
||||
table.insert(invcontent, 'default:steelblock '..tostring(pr:next(1,6)))
|
||||
end
|
||||
ns = {
|
||||
{name='default:cobble'},
|
||||
{name='air'},
|
||||
{name='default:chest', inv=invcontent},
|
||||
{name='default:cobble'},
|
||||
}
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
for i=1,#ns do
|
||||
local dy = top_y + 1 - i
|
||||
local p2 = v3.new(p)
|
||||
p2.y = p2.y + dy
|
||||
local oldn = minetest.env:get_node(p2)
|
||||
local n = ns[i]
|
||||
if n and oldn.name ~= "air" then
|
||||
if n.name == 'default:cobble' then
|
||||
local perlin = minetest.env:get_perlin(123, 2, 0.8, 2.0)
|
||||
if perlin:get3d(p2) >= 0.0 then
|
||||
n.name = 'default:mossycobble'
|
||||
end
|
||||
end
|
||||
minetest.env:set_node(p2, ns[i])
|
||||
if n.inv then
|
||||
local meta = minetest.env:get_meta(p2)
|
||||
local inv = meta:get_inventory()
|
||||
for _,itemstring in ipairs(n.inv) do
|
||||
inv:add_item('main', itemstring)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if mob then
|
||||
minetest.env:add_entity(v3.add(p, v3.new(0, mob_y, 0)), mob)
|
||||
end
|
||||
if item then
|
||||
minetest.env:add_item(v3.add(p, v3.new(0, mob_y, 0)), item)
|
||||
end
|
||||
end
|
||||
|
||||
mobs.generate_vault = function(vault_def, p, dir, seed)
|
||||
local dim_z = #vault_def
|
||||
assert(dim_z > 0)
|
||||
local dim_x = #vault_def[1]
|
||||
if not v3.cmp(dir, v3.new(0,0,1)) then return end
|
||||
--print("Making vault at "..minetest.pos_to_string(p))
|
||||
--if dim_x >= 14 then
|
||||
-- mobs.debug("Making large vault at "..minetest.pos_to_string(p))
|
||||
--else
|
||||
-- mobs.debug("Making vault at "..minetest.pos_to_string(p))
|
||||
--end
|
||||
-- Find door in definition
|
||||
local def_door_p = nil
|
||||
for dx=1,dim_x do
|
||||
for dz=1,dim_z do
|
||||
if vault_def[dim_z+1-dz][dx] == 'd' then
|
||||
def_door_p = v3.new(dx,0,dz)
|
||||
end
|
||||
if def_door_p then break end
|
||||
end
|
||||
if def_door_p then break end
|
||||
end
|
||||
--print("Vault door found at "..minetest.pos_to_string(def_door_p).." in definition")
|
||||
assert(def_door_p)
|
||||
local pr = PseudoRandom(seed)
|
||||
local randseed = seed
|
||||
for dx=1,dim_x do
|
||||
for dz=1,dim_z do
|
||||
local p2 = v3.add(v3.sub(p, def_door_p), v3.new(dx, 0, dz))
|
||||
local part = vault_def[dim_z+1-dz][dx]
|
||||
--print("Making vault part "..dump(part).." at "..minetest.pos_to_string(p2))
|
||||
mobs.make_vault_part(p2, part, pr)
|
||||
randseed = randseed + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Definition is for Z=up, X=right, dir={x=0,y=0,z=1}
|
||||
mobs.vault_defs = {
|
||||
{
|
||||
{'w','w','w','w','w','w','w','w','w','w'},
|
||||
{'w','c','c','c','c','c','C','C','c','w'},
|
||||
{'w','c','C','c','c','c','C','C','m','w'},
|
||||
{'w','C','C','C','w','w','C','C','c','w'},
|
||||
{'w','C','C','C','w','w','C','C','c','w'},
|
||||
{'w','r','C','c','w','w','C','w','w','w'},
|
||||
{'w','c','c','c','w','w','C','w',nil,nil},
|
||||
{'w','w','w','w','w','w','C','w',nil,nil},
|
||||
{nil,nil,nil,nil,nil,'w','d','w',nil,nil},
|
||||
{nil,nil,nil,nil,nil,nil,'A',nil,nil,nil},
|
||||
},
|
||||
{
|
||||
{'w','w','w','w','w','w','w','w'},
|
||||
{'w','c','c','c','c','C','c','w'},
|
||||
{'w','C','c','c','C','C','c','w'},
|
||||
{'w','C','c','c','C','C','c','w'},
|
||||
{'w','C','t','w','C','C','r','w'},
|
||||
{'w','C','c','w','C','w','d','w'},
|
||||
{'w','w','w','w','C','w','A',nil},
|
||||
{'w','w','w','w','C','w',nil,nil},
|
||||
{nil,nil,nil,'w','w','w',nil,nil},
|
||||
},
|
||||
{
|
||||
{'W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W'},
|
||||
{'W','l','l','l','l','l','l','c','i','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','c','l','l','l','l','l','f','f','l','l','l','l','l','m','W'},
|
||||
{'W','c','l','l','l','l','l','f','f','l','l','l','l','l','c','W'},
|
||||
{'W','c','l','l','t','f','f','f','f','l','l','l','l','l','c','W'},
|
||||
{'W','c','l','l','l','l','l','f','f','l','l','l','l','l','c','W'},
|
||||
{'W','m','l','l','l','l','l','f','f','l','l','l','l','l','c','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','l','l','l','l','l','l','f','f','l','l','l','l','l','l','W'},
|
||||
{'W','W','W','W','W','W','W','W','d','W','W','W','W','W','W','W'},
|
||||
{nil,nil,nil,nil,nil,nil,nil,nil,'A',nil,nil,nil,nil,nil,nil,nil},
|
||||
},
|
||||
{
|
||||
{'w','w','w','w','w','w','w','w'},
|
||||
{'w','c','c','c','m','C','c','w'},
|
||||
{'w','C','c','c','C','C','c','w'},
|
||||
{'w','C','C','C','C','C','C','w'},
|
||||
{'w','C','C','C','C','C','C','w'},
|
||||
{'w','C','C','C','C','C','C','w'},
|
||||
{'w','C','C','C','C','C','C','w'},
|
||||
{'w','C','c','c','C','C','r','w'},
|
||||
{'w','C','c','w','C','w','d','w'},
|
||||
{'w','c','w','w','C','w','A',nil},
|
||||
{'w','c','C','C','C','w',nil,nil},
|
||||
{nil,nil,nil,'w','w','w',nil,nil},
|
||||
},
|
||||
{
|
||||
{'w','w','w','w','w','w','w','w'},
|
||||
{'w','c','c','c','c','C','i','w'},
|
||||
{'w','C','c','c','C','C','c','w'},
|
||||
{'w','C','w','w','C','C','c','w'},
|
||||
{'w','C','c','c','C','C','c','w'},
|
||||
{'w','C','C','w','C','w','d','w'},
|
||||
{'w','c','C','C','C','w','A',nil},
|
||||
{'w','c','C','C','C','w',nil,nil},
|
||||
{'w','C','C','C','C','C','C','w'},
|
||||
{'w','C','C','C','C','C','C','w'},
|
||||
{nil,nil,nil,'w','w','w',nil,nil},
|
||||
},
|
||||
{
|
||||
{'w','w','w','w','w','w','w','w'},
|
||||
{'w','c','c','c','c','C','c','w'},
|
||||
{'w','C','c','c','w','C','c','w'},
|
||||
{'w','C','w','w','w','w','c','w'},
|
||||
{'w','C','C','C','C','C','c','w'},
|
||||
{'w','C','c','w','C','w','d','w'},
|
||||
{'w','i','w','w','C','w','A',nil},
|
||||
{'w','c','C','C','C','w',nil,nil},
|
||||
{nil,nil,nil,'w','w','w',nil,nil},
|
||||
},
|
||||
{
|
||||
{'w','w','w','w','w','w','w','w'},
|
||||
{'w','i','c','c','c','C','t','w'},
|
||||
{'w','C','w','c','C','C','c','w'},
|
||||
{'w','c','w','w','w','C','w','w'},
|
||||
{'w','C','w','c','C','C','C','w'},
|
||||
{'w','C','w','c','C','C','d','w'},
|
||||
{'w','c','w','w','w','C','A',nil},
|
||||
{'w','c','C','C','C','C',nil,nil},
|
||||
{nil,nil,nil,'w','w','w',nil,nil},
|
||||
},
|
||||
{
|
||||
{'W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','m','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','C','C','C','C','C','C','C','C','C','C','C','C','C','C','W'},
|
||||
{'W','W','W','W','W','W','W','W','d','W','W','W','W','W','W','W'},
|
||||
{nil,nil,nil,nil,nil,nil,nil,nil,'d',nil,nil,nil,nil,nil,nil,nil},
|
||||
},
|
||||
}
|
||||
|
||||
mobs.generate_random_vault = function(p, dir, pr)
|
||||
seed = pr:next()
|
||||
local vault_def = mobs.vault_defs[pr:next(1, #mobs.vault_defs)]
|
||||
mobs.generate_vault(vault_def, p, dir, seed)
|
||||
end
|
||||
|
||||
local generate_corridor = function(from, to, seed)
|
||||
local pr = PseudoRandom(seed+92384)
|
||||
local p = {x=from.x, y=from.y, z=from.z}
|
||||
local step = 0
|
||||
while p.x ~= to.x do
|
||||
if step >= 5 and minetest.env:get_node(p).name == "air" then
|
||||
return
|
||||
end
|
||||
step = step + 1
|
||||
mobs.make_vault_part(p, 'C', pr)
|
||||
if p.x > to.x then
|
||||
p.x = p.x - 1
|
||||
else
|
||||
p.x = p.x + 1
|
||||
end
|
||||
end
|
||||
local step = 0
|
||||
while p.z ~= to.z do
|
||||
if step >= 5 and minetest.env:get_node(p).name == "air" then
|
||||
return
|
||||
end
|
||||
step = step + 1
|
||||
mobs.make_vault_part(p, 'C', pr)
|
||||
if p.z > to.z then
|
||||
p.z = p.z - 1
|
||||
else
|
||||
p.z = p.z + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, seed)
|
||||
--[[if minp.x > maxp.x or minp.y > maxp.y or minp.z > maxp.z then
|
||||
mobs.debug"foo")
|
||||
return
|
||||
end--]]
|
||||
if minp.y > DUNGEON_Y or maxp.y < DUNGEON_Y then
|
||||
return
|
||||
end
|
||||
local area = (maxp.x-minp.x+1)*(maxp.z-minp.z+1)
|
||||
|
||||
local possible_entrances = {}
|
||||
|
||||
local entrance = {
|
||||
p = {x=0, y=-DUNGEON_Y, z=-5},
|
||||
dir = {x=0, y=0, z=1},
|
||||
}
|
||||
table.insert(possible_entrances, entrance)
|
||||
|
||||
local pr = PseudoRandom(seed+931)
|
||||
for i=0,area/300 do
|
||||
local p1 = {
|
||||
x = pr:next(minp.x, maxp.x),
|
||||
y = DUNGEON_Y,
|
||||
z = pr:next(minp.z, maxp.z),
|
||||
}
|
||||
local entrance = {
|
||||
p = p1,
|
||||
dir = {x=0, y=0, z=1},
|
||||
}
|
||||
table.insert(possible_entrances, entrance)
|
||||
end
|
||||
|
||||
local pr = PseudoRandom(seed+9322)
|
||||
local lastp = nil
|
||||
if minp.x < 0 and maxp.x > 0 and minp.z < 0 and maxp.z > 0 then
|
||||
lastp = {x=0, y=DUNGEON_Y, z=0}
|
||||
end
|
||||
for i,entrance in ipairs(possible_entrances) do
|
||||
--mobs.debug("Entrance: "..dump(entrance))
|
||||
mobs.generate_random_vault(entrance.p, entrance.dir, pr)
|
||||
if lastp then
|
||||
generate_corridor(lastp, entrance.p, pr:next())
|
||||
end
|
||||
lastp = entrance.p
|
||||
end
|
||||
if minp.x < 0 and maxp.x > 0 and minp.z < 0 and maxp.z > 0 then
|
||||
p = {x=0, y=DUNGEON_Y+2, z=0}
|
||||
minetest.env:set_node(p, {name="default:torch"})
|
||||
end
|
||||
end)
|
||||
|
||||
local function give_initial_stuff(player)
|
||||
player:get_inventory():add_item('main', 'default:torch 99')
|
||||
--player:get_inventory():add_item('main', 'default:shovel_steel')
|
||||
--player:get_inventory():add_item('main', 'default:sword_steel')
|
||||
--player:get_inventory():add_item('main', 'default:cobble 99')
|
||||
end
|
||||
|
||||
minetest.register_on_newplayer(function(player)
|
||||
player:setpos({x=0, y=DUNGEON_Y, z=0})
|
||||
give_initial_stuff(player)
|
||||
end)
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
player:setpos({x=0, y=DUNGEON_Y, z=0})
|
||||
player:get_inventory():set_list("main", {})
|
||||
player:get_inventory():set_list("craft", {})
|
||||
give_initial_stuff(player)
|
||||
return true
|
||||
end)
|
||||
|
632
mods/mobf/README
Normal file
@ -0,0 +1,632 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Mob Framework Mod (former animals mod) provides a framework for creating mobs
|
||||
|
||||
(c) sapier (code,some graphics)
|
||||
(c) rinoux (many 2D graphics)
|
||||
|
||||
Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
Big thanks to rinoux for providing graphics and all others for their
|
||||
suggestions too!
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
No what is in?
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--hostile mobs--
|
||||
Vombies
|
||||
Hostile mobs spawning at night in unlighted areas. They can't withstand the
|
||||
sun and will burn as sun rises
|
||||
|
||||
Dungeonmasters
|
||||
Just dungenmasters throwing fireballs they spawn in dark stony areas too.
|
||||
|
||||
Big Red
|
||||
They look like giant easter bunnys but beware of their plasma balls! Big red
|
||||
spawns in dark stony areas
|
||||
|
||||
Boombomb
|
||||
Don't get near they will explode
|
||||
|
||||
--slime--
|
||||
will bounce in large caves below surface
|
||||
|
||||
--semi hostile mobs --
|
||||
|
||||
Wolf
|
||||
A animal hiding in the woods that can be tamed to follow you
|
||||
|
||||
--friendly mobs --
|
||||
|
||||
Chicken
|
||||
Cicken droping egs now and then
|
||||
|
||||
Sheep
|
||||
Sheep that can be sheered, their wool will grow again. They randomly will
|
||||
spawn on willows
|
||||
|
||||
Cow
|
||||
Cows will spawn on willows and produce milk.
|
||||
|
||||
Deer
|
||||
Will spawn below trees.
|
||||
|
||||
Rat
|
||||
Just a small animal jumping around
|
||||
|
||||
Blue White Fish
|
||||
Just a swimming animal
|
||||
|
||||
Gull
|
||||
flys around over your head!
|
||||
|
||||
Clownfish
|
||||
A funny small quick fish swiming around
|
||||
|
||||
--npc trader--
|
||||
will sell goods
|
||||
|
||||
|
||||
What can you do with them?
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Sheep -> take scissors and sheer them
|
||||
Cow -> take an empty glass and get milk
|
||||
Chicken -> collect eggs
|
||||
Vombie -> drops bone on kill
|
||||
Clownfish -> drops golden scale on kill
|
||||
Wolf -> tame it!
|
||||
NPC trader -> trading of course
|
||||
|
||||
|
||||
How to catch mobs? Take a lasso or net to catch them, create a farm. Sheep,
|
||||
chicken and cow will even breed if there's a filled barn nearby
|
||||
|
||||
|
||||
Recieps:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Lasso
|
||||
|
||||
none wool none
|
||||
wool none wool
|
||||
none wool none
|
||||
|
||||
Scissors
|
||||
|
||||
none iron_ingot none
|
||||
none iron_ingot none
|
||||
stick none stick
|
||||
|
||||
Net
|
||||
|
||||
wool none wool
|
||||
none wool none
|
||||
wool none wool
|
||||
|
||||
Barn
|
||||
|
||||
stick stick stick
|
||||
wood wood wood
|
||||
|
||||
Small barn
|
||||
|
||||
stick stick
|
||||
wood wood
|
||||
|
||||
Vombie trap
|
||||
|
||||
wood wood wood
|
||||
wood scale_golden wood
|
||||
wood wood wood
|
||||
|
||||
Settings (it's recommended to use mobf_settings command to change settings):
|
||||
-------------------------------------------------------------------------------
|
||||
mobf_enable_socket_trace = true/false
|
||||
-->enable socket mod tracing
|
||||
|
||||
mobf_disable_3d_mode = true/false
|
||||
-->disable 3d models
|
||||
|
||||
disable_vombie_3d_burn_animation = true/false
|
||||
-->VOMBIE ONLY disable 3d burn animation
|
||||
|
||||
mobf_disable_animal_spawning = true/false
|
||||
-->disable spawning of animals
|
||||
|
||||
mobf_blacklist = <serialized table of animal names>
|
||||
-->disable all animals in table e.g.
|
||||
mobf_blacklist = return {animal_sheep:sheep}
|
||||
|
||||
mobf_animal_spawning_secondary = true/false
|
||||
-->enable/disable secondary spawning mechanism
|
||||
NOTE secondary mechanism may cause serious lag issues sometimes
|
||||
|
||||
mobf_log_removed_entities = true/false
|
||||
log removed mobs with reason of removal
|
||||
|
||||
vombie_3d_burn_animation_enabled = true/false
|
||||
show vombie burn animation (may cause huge lag)
|
||||
|
||||
mobf_log_bug_warnings = true/false
|
||||
show all mobf bug warnings
|
||||
|
||||
mobf_delete_disabled_mobs = true/false
|
||||
delete mobs and spawners if a mob is disabled
|
||||
|
||||
Changelog:
|
||||
-------------------------------------------------------------------------------
|
||||
Changes 2.0.5
|
||||
-fix bug in mobf_settings using settings_save instead of mobf_setting_save
|
||||
|
||||
Changes 2.0.4
|
||||
-fixed bug trader selling without pay if price1 or price 2 not set
|
||||
|
||||
Changes 2.0.3
|
||||
-fixed crash on typical state time not available
|
||||
-fixed bug mob_slime typical state time not set
|
||||
|
||||
Changes 2.0.2
|
||||
-fix crash with invalid targetpos in follow movgen
|
||||
|
||||
Changes 2.0.1
|
||||
-fix crash on teleport of wolf
|
||||
|
||||
Changes 2.0.0
|
||||
-documentation update
|
||||
-add more items for trader
|
||||
-fix price update bug in trader
|
||||
-new cow textures
|
||||
-improve sheep model
|
||||
|
||||
Changes 1.9.15
|
||||
-fixed crash when mob got spawned at unloaded pos
|
||||
-make mobf_version command available to all users
|
||||
-reduce chance for trader building by factor 5
|
||||
-code cleanup
|
||||
-add support for tracing mob removal reason
|
||||
-add clownfish mesh
|
||||
-fix fish blue white swiming in wrong direction
|
||||
|
||||
Changes 1.9.14
|
||||
-add vombie 3d mesh
|
||||
-fix crash when trying to access empty movgen
|
||||
-fix old default movgen definition was still used instead of default state
|
||||
movgen in state change handling
|
||||
-fixed deer model flying when lying
|
||||
-fix crash in changestate
|
||||
-fixed bug mobs disapearing as soon as attacking if spawned in slightly wrong
|
||||
positions
|
||||
-fixed boombomb and npc to use current api
|
||||
-added big_red mesh
|
||||
-fixed big_red not being agressive
|
||||
-fixed wolf missing combat movegen
|
||||
-added backtrace support
|
||||
|
||||
Changes 1.9.13
|
||||
-add gull 3d mesh
|
||||
-fix bug tamed wolf removed immediatly
|
||||
-fix bug ostich_f can't be spawned
|
||||
-revert accidentaly changed wolf to be not agressive
|
||||
-fix mobs following don't jump
|
||||
-fix height level check for flying mobs not working
|
||||
-stop movement of inactive mobs
|
||||
|
||||
Changes 1.9.12
|
||||
-rename debug class to avoid naming conflicts
|
||||
-improve environment definition
|
||||
-add ride support
|
||||
-fixed punch mob not pushing back animals correctly
|
||||
-fixed mobs don't respawn within torch ...
|
||||
-fixed crash on show npc inventory due to changed api
|
||||
-fixed drop avoidance not working if dropping to water (due to another fix)
|
||||
-improve house spawning
|
||||
-add ostrich
|
||||
-improve collision checking for pos_is_ok
|
||||
-add fish blue_white mesh
|
||||
-add chatcommand show version
|
||||
-add wolf mesh
|
||||
-add sheep mesh
|
||||
-fixed crash with secondary spawning enabled
|
||||
-fixed crash on listactivemobs
|
||||
-fixed boombomb still using abm based spawner
|
||||
-updated dm model to 4aiman version
|
||||
|
||||
Changes 1.9.11
|
||||
-added calf mesh
|
||||
-added rat mesh
|
||||
-replaced .x meshes by .b3d meshes
|
||||
-fixed bug 3d inventory mob not facing player correctly
|
||||
-fixed crash in random drop handling with incorrect dynamic_data
|
||||
-mobs will face player on combat now
|
||||
-improved follow behaviour (you can't get away that easy anymore)
|
||||
-reduced damage done by mobs
|
||||
|
||||
Changes 1.9.10
|
||||
-fixed group support for mobs
|
||||
-fixed sun damage handler resetting animation to "stand"
|
||||
-fix orientation not updated correct for mobs following new default state schema
|
||||
-fixed bug 2d sprites not shown correctly
|
||||
-fixed doku
|
||||
-added support for upright sprites
|
||||
-added 3d mesh model for dm
|
||||
-added 3d mesh models for chicken
|
||||
-added sounds for some mod
|
||||
-added license information
|
||||
-added support for mobf without fire mod
|
||||
-added non inventory_plus settings gui (requres core patch)
|
||||
-replaced custom debug chatcommand handlers by official minetest ones
|
||||
|
||||
Changes 1.9.9
|
||||
-added trader spawning
|
||||
-multiple fixes related to new state only modes
|
||||
-fixed doku
|
||||
|
||||
Changes 1.9.8
|
||||
-added trader support
|
||||
-fixed sheep not being sheered
|
||||
-added support for on_rightclick callbacks
|
||||
|
||||
Changes 1.9.7
|
||||
-fixed bug big_willow spawner not enabled
|
||||
-fixed bug steer not using big_willow spawner
|
||||
-make mobs more smart in avoiding dropping
|
||||
-make mobs more smart in avoiding falling into water
|
||||
|
||||
Changes 1.9.6
|
||||
-catch misspelled blacklist string
|
||||
-fix bug in barn crashing game
|
||||
-fix bug custom on step handler making minetest unresponsive
|
||||
-fixed crash on invalid blacklist
|
||||
-added check to warn on unrealistic count of callbacks
|
||||
-added statistics feature for mobf callback times
|
||||
-make vombies and boombomb spawn in desert too
|
||||
|
||||
Changes 1.9.5
|
||||
-fixed height level controling for fish and gulls (has been brocken for ages)
|
||||
-added spawner based spawning for any abm based spawning
|
||||
-"default" state is now mandatory for any mob!
|
||||
|
||||
Changes 1.9.4
|
||||
-fixed sound name collisions
|
||||
-fixed stereo->mono for some sounds
|
||||
-added jordan4ibanez movement generator
|
||||
|
||||
Changes 1.9.3
|
||||
-added lots of security checks to callback handlers
|
||||
-added new tracing facilitys mobf_core and mobf_core_helper
|
||||
-fixed additional bugs in entity replacement code of state changer
|
||||
-fixed bug mobf crashing on no good position beeing known for mob when needed
|
||||
|
||||
Changes 1.9.2
|
||||
-added workaround for lost dynamic data on saving of permanent data
|
||||
-don't drown mobs but move to last known good position
|
||||
-added animated 3d mesh cow and steer
|
||||
|
||||
Changes 1.9.1
|
||||
-increased spawn rates of wolf
|
||||
-drop correct meat
|
||||
-add support for multiple drops
|
||||
-fix lots of bugs in state change handling
|
||||
-add animation support
|
||||
-added experimental mob npc to demonstrate animation handling
|
||||
|
||||
Changes 1.9.0
|
||||
-preserve orientation on replacement of entity
|
||||
-add state support
|
||||
-don't generate vaults if dm is disabled
|
||||
-fix bug vaults generated above sea level
|
||||
-added support for mesh 3d models
|
||||
-use vessels drinking glass -> cow depends on vessels now!
|
||||
-add support for removing disabled animals unknown objects
|
||||
|
||||
Changes 1.4.6
|
||||
-added 3d dm
|
||||
-added 3d big red
|
||||
-added calfs
|
||||
-added chicks
|
||||
-added 3d Boombomb (was Creeper)
|
||||
-added 3d clownfish
|
||||
-added support for secondary spawning mechanisms
|
||||
-change animal behaviour in case of unable to find safe new accel
|
||||
-added on death callback support
|
||||
-added function to get mob description
|
||||
|
||||
Changes 1.4.5
|
||||
-added mobf registration of steer
|
||||
-added get version api
|
||||
-added support for blacklisting of animals
|
||||
|
||||
Changes 1.4.4
|
||||
-fixed bug in mob orientation calculation
|
||||
-improoved random movement generator
|
||||
->don't invert speed on collision
|
||||
->new random acceleration is dependent of old yaw now
|
||||
->mpattern stop and go reduce start stop chances drastically
|
||||
-added steer
|
||||
-added rooster
|
||||
-added breeding of cow and chicken
|
||||
|
||||
Changes 1.4.3
|
||||
-fixed bug in deep caves spawn algorithm tried to print nil value maxlight
|
||||
-fixed bug in walking through walkable nodes
|
||||
-added new config file option mobf_disable_animal_spawning to disable automatic animal spawning
|
||||
-added mapgen based willow spawn algorithm
|
||||
-added mapgen based in_forrest spawn algorithm
|
||||
|
||||
Changes 1.4.2
|
||||
-readded lost trap
|
||||
-fixed bug in inventory check
|
||||
|
||||
Changes 1.4.1
|
||||
-hopefully (haven't tested) fixed bug with mob killed by non player actor
|
||||
-added dropping of results in case of player inventory full
|
||||
-fixed bug in distance attack if distance attack is invalid
|
||||
-fixed dm having invalid distance attack
|
||||
-fixed big_red having invalid distance attack
|
||||
|
||||
Changes 1.4.0
|
||||
-rename core to MOBF
|
||||
-remove some dead code
|
||||
-fixed bug in random drops entities lifetime not save
|
||||
-fixed bug wrong parameter set to true on remove due to pop dens check
|
||||
-fixed bug mobs running around like crazy after on_step frequency increase
|
||||
-added spawn in deep caves spawn algorithm
|
||||
-added special movement gen none only applying y acceleration but stopping mob
|
||||
otherwise
|
||||
|
||||
Changes 1.3.5
|
||||
-make vault generation much more quiet
|
||||
-add function for adding movement pattern by external functions
|
||||
|
||||
Changes 1.3.4
|
||||
-increase check frequency to 4/s
|
||||
-fix jumpy cow and deer
|
||||
-fixed dm and big_red spawning in lighted areas
|
||||
-fixed bug harvest delay not enforced
|
||||
-make cow a little bit more slim
|
||||
-added vault generation code from celeron (slightly modified)
|
||||
-reduce sound distance dm/cow/sheep/vombie
|
||||
-fixed vombie model (was wrong direction)
|
||||
-made vombie agressive again
|
||||
-remove vombie at once if entity is activated at daytime
|
||||
|
||||
Changes 1.3.3
|
||||
-disable luatrace
|
||||
|
||||
Changes 1.3.2
|
||||
-split configuration of 2d 3d animals
|
||||
-more 3d animals
|
||||
-improoved base position checking
|
||||
-added warnings for long abms
|
||||
-added load/unload check
|
||||
-removed spawn point registry
|
||||
-removed minetest serialization
|
||||
-readded remove animals script(non working atm)
|
||||
|
||||
Changes 1.3.1
|
||||
-fixed regression unable to craft lasso and net
|
||||
-added doxygen style comments
|
||||
-added documentation
|
||||
-fixed lot of code style breakages
|
||||
-extracted environments from movement patterns
|
||||
-moved prototype for path based movement generator to own folder
|
||||
|
||||
Changes 1.3.0
|
||||
-added 3d fish blue white
|
||||
-fixed another yaw bug
|
||||
-fixed movement check bug
|
||||
-fixed position prediction
|
||||
-replaced animalmaterials:wool_? by wool:x
|
||||
-added fire effect for fireball
|
||||
-replaced custom serialization by new minetest function
|
||||
-added fire for self destruct
|
||||
-fix lasso and net recieps
|
||||
-added wolf
|
||||
|
||||
Changes 1.2.93:
|
||||
-added 3d barn
|
||||
-fixed bug animals have wrong orientation
|
||||
-fixed bug sheep get stuc in corner
|
||||
-fixed cow model
|
||||
|
||||
Changes 1.2.92:
|
||||
-added support for 3d animals
|
||||
-fix bug in probabilistic movement gen when handling min speed
|
||||
-fixed movement of stop_and_go animals
|
||||
-made Sheep 3D
|
||||
-made Cow 3D
|
||||
|
||||
|
||||
Changes 1.2.91:
|
||||
-fixed bugs in animals sheep
|
||||
-updated animalmaterials to new syntax
|
||||
|
||||
Changes 1.2.90:
|
||||
-added support for surface differentiation in good/ok/bad
|
||||
-added support for different movement generators
|
||||
-added fight mode movement generator change
|
||||
-fixed bug barn depending on vombie instead of sheep
|
||||
-reduced cpu load in normal movement loop
|
||||
-adjusted probability values to new check cycle
|
||||
|
||||
Changes 1.2.1:
|
||||
-use official health system
|
||||
-add group support for all animals
|
||||
-scissors get damaged by harvesting wool
|
||||
-add footstep sounds
|
||||
|
||||
Changes 1.2.0:
|
||||
-added sound support
|
||||
-(non working) path based movement gen stub
|
||||
|
||||
Changes 1.1.0:
|
||||
-support for prefered environment
|
||||
-performance improvements (mainly in spawning algorithms)
|
||||
-internal reorganization
|
||||
-added on_hit_callback and on_kill_callback in fighting subsystem
|
||||
|
||||
Changes 1.0.0:
|
||||
-added changes required for flying animals
|
||||
-added lifetime support (it's only used for breeding right now)
|
||||
-for any animal a item is created by default
|
||||
-added gull
|
||||
-added clownfish
|
||||
-added vombie trap
|
||||
-added barn (breed sheep!)
|
||||
|
||||
Changes 0.9.11:
|
||||
-animal definitions have been moved to different mods
|
||||
-player punch pushes back animal
|
||||
|
||||
Changes 0.9.9:
|
||||
-MAJOR code reorganization
|
||||
-fixed creeper
|
||||
-added collision boxes with correct height
|
||||
(width ain't possible as sprites are rotated automaticaly)
|
||||
-added some missing item graphics
|
||||
-fixed a lot of small bugs probably not even discovered
|
||||
-improoved big red graphic
|
||||
-added initial documentation
|
||||
|
||||
Changes 0.9.0:
|
||||
-changed harvesting to LMB
|
||||
-fixed bug making rats jump to high
|
||||
-adjusted to new git 20120122
|
||||
-make dungeon master more dangerous
|
||||
-added glass for harvesting milk
|
||||
|
||||
Changes 0.8.9:
|
||||
-added net
|
||||
-added fish support
|
||||
-added rat
|
||||
|
||||
Changes 0.8.3:
|
||||
-added creeper
|
||||
-added movement pattern support -> support for different movement styles
|
||||
-added lua script "remove_animals.lua" (rename to init.lua to remove all animals from your world)
|
||||
|
||||
Changes 0.8.2:
|
||||
-added cow graphics from rinoux
|
||||
-added some item images from rinoux
|
||||
-fixed unnecessary workaround in line of sight code by correct implementation
|
||||
|
||||
Changes 0.8.1:
|
||||
-bugfix for release error
|
||||
|
||||
Changes 0.8.0:
|
||||
-added deer graphics from rinoux
|
||||
-added distance attack support (inspired by jeija mod throwing)
|
||||
-added plasma and fireballs
|
||||
-added dungeonmaster
|
||||
|
||||
Changes 0.7.3:
|
||||
-fixed some issues with spawning to many animals in case of frequent server restarts
|
||||
-added chicken (big thanks to rinoux)
|
||||
-added new graphics for sheep (even more thanks to rinoux for providing them)
|
||||
|
||||
Changes 0.7.0:
|
||||
-added support for animals following target while fighting
|
||||
-make hostile animals even more agressive
|
||||
-add vampire spawning all over the world during night ;-)
|
||||
|
||||
Changes 0.6.0:
|
||||
-added support for looking directions
|
||||
-added support for animals attacking player on their own
|
||||
Latest git from 20120103 required!
|
||||
|
||||
Changes 0.5.0:
|
||||
-fixed bug animals disapearing if more than one animal is at same position
|
||||
-switched to new lua api
|
||||
Latest build 20120102 required!
|
||||
|
||||
Changes 0.4.5:
|
||||
-fixed spawn algorithms not correctly ensuring population density of animals
|
||||
|
||||
Changes 0.4.3:
|
||||
-added lasso for catching animals
|
||||
|
||||
Changes 0.4.2:
|
||||
-add scissors for harvesting wool
|
||||
|
||||
Changes 0.4.1:
|
||||
-fixed bug mod not running on stock 0.4 dev
|
||||
-big red now spawns in shadows only
|
||||
|
||||
Changes 0.4.0:
|
||||
-added support for animals spawning
|
||||
|
||||
Changes 0.3.0:
|
||||
-added support for animals fighting back
|
||||
|
||||
Changes 0.2.2:
|
||||
-animal may jump 1 block but only if it's a "natural" surface (to avoid jumping over fences, walls e.g.). Natural surfaces are by now dirt, sand, stone and clay.
|
||||
|
||||
Changes 0.2.1:
|
||||
-animal size increased
|
||||
|
||||
Changes 0.2.0:
|
||||
-added cow
|
||||
-added deer
|
||||
-fixed bugs in base functionality used by deer and cow
|
||||
|
||||
Changes 0.1.1:
|
||||
-fixed bug crashing server on rightclick
|
||||
|
||||
Changes 0.1.0:
|
||||
-Major improovements in motion generation code
|
||||
-switched to modular design (still needed to create a single file till next dev release of minetest, if you've already got the master minetest you may rename init_modular.lua to init)
|
||||
-added support for:
|
||||
*animals harvestable
|
||||
*animals transforming on harvest
|
||||
*animals retransforming after specified amount of time
|
||||
-prepared for:
|
||||
*animals harvestable when wearing special tool
|
||||
*animals harvestable by consuming special tool
|
||||
|
||||
Links:
|
||||
http://www.mediafire.com/?axsikpooji7hq16 Version 0.1.1 (there will be sheep)
|
||||
http://www.mediafire.com/?yo6b8cyq0rt6b51 Version 0.2.0 (diversity growing)
|
||||
http://www.mediafire.com/?v45fue5z6hidkjw Version 0.2.1 (no tiny animals)
|
||||
http://www.mediafire.com/?1l4cfj35kadjf1l Version 0.2.2 (let em jump)
|
||||
http://www.mediafire.com/?leyjbj5831gc6zm Version 0.3.0 (don't make them angry)
|
||||
http://www.mediafire.com/?ilslao0gi2ulwev Version 0.4.1 (big red is hiding)
|
||||
http://www.mediafire.com/?tkamh7a5r6mlsze Version 0.4.2 (let there be tools)
|
||||
http://www.mediafire.com/?ib5ax24vp54h938 Version 0.4.3 (catch em all)
|
||||
http://www.mediafire.com/?m9dfrqq6fdoamnz Version 0.4.5 (catch em all)
|
||||
http://www.mediafire.com/?22ex6fn8d49deoy Version 0.5.0 (none disappearing)
|
||||
http://www.mediafire.com/?a0g894d4b90acax Version 0.6.0 (be carefull)
|
||||
http://www.mediafire.com/?mym9dyjbnb98cmo Version 0.7.0 ( do you fear the night?)
|
||||
http://www.mediafire.com/?3lw27vuzxn7cyy8 Version 0.7.3 (still fear the night?)
|
||||
http://www.mediafire.com/?3ah17kl2uhg0437 Version 0.8.1 (stay distant!)
|
||||
http://www.mediafire.com/?j447z7q3rfim8iv Version 0.8.2 (stay distant!)
|
||||
http://www.mediafire.com/?1b9rcez7dbdnbuu Version 0.8.3 (stay distant!)
|
||||
http://www.mediafire.com/?r4jke39dfv218yj Version 0.8.9 (have a swim)
|
||||
http://www.mediafire.com/?5w9a5vc55az2dqq Version 0.9.0 (left "hand" harvesting)
|
||||
http://www.mediafire.com/?y8k42doeebo2c5o Version 0.9.9 (cleanup)
|
||||
http://www.mediafire.com/?hl37vzqb5kzra05 Version 0.9.11 (cleanup)
|
||||
http://www.mediafire.com/?zty2qzn9hjtxl1s Version 1.0.0 (let them breed)
|
||||
http://www.mediafire.com/?xax85pwsno1incc Version 1.1.0 (speed it up)
|
||||
http://www.mediafire.com/?ze274bvlxtjsk1c Version 1.1.1 (speed it up)
|
||||
http://www.mediafire.com/?gn0f1e005wtmsom Version 1.2.0 (make some noise)
|
||||
http://www.mediafire.com/?zkf54fckd7w2g3f Version 1.2.1 (hit them)
|
||||
http://www.mediafire.com/?7hm2xm51aoytbua Version 1.2.90 (loose weight)
|
||||
http://www.mediafire.com/?lnw1bcs5gq6au83 Version 1.2.91 (fix it)
|
||||
http://www.mediafire.com/?axuhv41wc2ch7yl Version 1.2.92 (enter the 3rd dimension)
|
||||
http://www.mediafire.com/?vldqym8hrasjbuk Version 1.2.93 (finding the right direction)
|
||||
http://www.mediafire.com/?1ne46d88ej6qlus Version 1.3.0 (let there be pets)
|
||||
http://www.mediafire.com/?vr9w97ac350u215 Version 1.3.1 (paperworks)
|
||||
http://www.mediafire.com/?25an9a14ty4ifat Version 1.3.3 (no trace)
|
||||
http://www.mediafire.com/?p8a3wkl3s936n6o Version 1.3.4 (finetuning)
|
||||
http://www.mediafire.com/?jmm1g4j2j4hp8d4 Version 1.4.0 (slimy)
|
||||
http://www.mediafire.com/?goyb9r7e94h8gwl Version 1.4.1 (dropper)
|
||||
http://www.mediafire.com/?63o9qgycaccb3q3 Version 1.4.2 (dropper)
|
||||
http://www.mediafire.com/?jcocc1vop19a3kj Version 1.4.3 (no respawn)
|
||||
http://www.mediafire.com/?b8hw3fo3599wbtd Version 1.4.4 (more breeding)
|
||||
http://www.mediafire.com/?5cuh2lz2m12915p Version 1.4.5 (more breeding)
|
||||
http://www.mediafire.com/?ds4g46v3dhnkdg9 Version 1.9.0 (sleeping sheep) --experimental
|
||||
http://www.mediafire.com/?umbcd1ptax9bbcb Version 1.9.1 (animating!) --experimental
|
||||
http://www.mediafire.com/?66v84hi9p43hw7o Version 1.9.6 (faster?) --experimental
|
||||
http://www.mediafire.com/?5z5wz2d329m849k Version 1.9.7 (frightened about water) --experimental
|
||||
|
188
mods/mobf/api.lua
Normal file
@ -0,0 +1,188 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file api.lua
|
||||
--! @brief api functions to be used by other mods
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-12-27
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_register_on_death_callback(callback)
|
||||
--
|
||||
--! @brief get version of mob framework
|
||||
--! @ingroup framework_mob
|
||||
--
|
||||
--! @param callback callback to register
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_register_on_death_callback(callback)
|
||||
return fighting.register_on_death_callback(callback)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_get_mob_definition(mobname)
|
||||
--
|
||||
--! @brief get COPY of mob definition
|
||||
--! @ingroup framework_mob
|
||||
--
|
||||
--! @return mobf version
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_get_mob_definition(mobname)
|
||||
|
||||
if mobf_rtd.registred_mob_data[mobname] ~= nil then
|
||||
local copy = minetest.serialize(mobf_rtd.registred_mob_data[mobname])
|
||||
return minetest.deserialize(copy)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_get_version()
|
||||
--
|
||||
--! @brief get version of mob framework
|
||||
--! @ingroup framework_mob
|
||||
--
|
||||
--! @return mobf version
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_get_version()
|
||||
return mobf_version
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- name: mobf_add_mob(mob)
|
||||
--
|
||||
--! @brief register a mob within mob framework
|
||||
--! @ingroup framework_mob
|
||||
--
|
||||
--! @param mob a mob declaration
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_add_mob(mob)
|
||||
|
||||
if mob.name == nil or
|
||||
mob.modname == nil then
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF: name and modname are mandatory for ALL mobs!")
|
||||
return false
|
||||
end
|
||||
|
||||
--check if mob may be added
|
||||
if mobf_contains(mobf_rtd.registred_mob,mob.modname.. ":"..mob.name) then
|
||||
mobf.blacklisthandling(mob)
|
||||
return false
|
||||
end
|
||||
|
||||
--if a random drop is specified for this mob register it
|
||||
if mob.random_drop ~= nil then
|
||||
random_drop.register(mob.random_drop)
|
||||
end
|
||||
|
||||
--create default entity
|
||||
minetest.log(LOGLEVEL_INFO,"MOBF: adding: " .. mob.name)
|
||||
mob_state.prepare_states(mob)
|
||||
|
||||
mobf.register_mob_item(mob.name,mob.modname,mob.generic.description)
|
||||
|
||||
--check if a movement pattern was specified
|
||||
if mobf_rtd.movement_patterns[mob.movement.pattern] == nil then
|
||||
minetest.log(LOGLEVEL_WARNING,"MOBF: no movement pattern specified!")
|
||||
end
|
||||
|
||||
--spawn mechanism handling
|
||||
if not minetest.setting_getbool("mobf_disable_animal_spawning") then
|
||||
--register spawn callback to world
|
||||
if environment_list[mob.generic.envid] ~= nil then
|
||||
local secondary_name = ""
|
||||
if mob.harvest ~= nil then
|
||||
secondary_name = mob.harvest.transforms_to
|
||||
end
|
||||
|
||||
dbg_mobf.mobf_core_lvl3("MOBGF: Environment to use: " .. tostring(mob.generic.envid))
|
||||
|
||||
if mobf_spawn_algorithms[mob.spawning.algorithm] ~= nil and
|
||||
type(mobf_spawn_algorithms[mob.spawning.algorithm].register_spawn) == "function" then
|
||||
mobf_spawn_algorithms[mob.spawning.algorithm].register_spawn(mob.modname..":"..mob.name,
|
||||
secondary_name,
|
||||
mob.spawning,
|
||||
environment_list[mob.generic.envid])
|
||||
else
|
||||
dbg_mobf.mobf_core_lvl2("MOBGF: " .. mob.name
|
||||
.. " no primary spawn algorithm defined: "
|
||||
.. tostring(mob.spawning.algorithm))
|
||||
end
|
||||
|
||||
if minetest.setting_getbool("mobf_animal_spawning_secondary") then
|
||||
if mob.spawning.algorithm_secondary ~= nil and
|
||||
type(mobf_spawn_algorithms[mob.spawning.algorithm_secondary].register_spawn) == "function" then
|
||||
mobf_spawn_algorithms[mob.spawning.algorithm_secondary].register_spawn(mob.modname..":"..mob.name,
|
||||
secondary_name,
|
||||
mob.spawning,
|
||||
environment_list[mob.generic.envid])
|
||||
end
|
||||
end
|
||||
else
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF: specified mob >" .. mob.name
|
||||
.. "< without environment!")
|
||||
end
|
||||
else
|
||||
dbg_mobf.mobf_core_lvl3("MOBF: MOB spawning disabled!")
|
||||
end
|
||||
|
||||
--register mob name to internal data structures
|
||||
table.insert(mobf_rtd.registred_mob,mob.modname.. ":"..mob.name)
|
||||
mobf_rtd.registred_mob_data[mob.modname.. ":"..mob.name] = mob;
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- name: mobf_is_known_mob(name)
|
||||
--
|
||||
--! @brief check if mob of name is known
|
||||
--! @ingroup framework_mob
|
||||
--
|
||||
--! @param name name to check if it's a mob
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_is_known_mob(name)
|
||||
for i,val in ipairs(mobf_rtd.registred_mob) do
|
||||
if name == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- name: mobf_register_environment(name,environment)
|
||||
--
|
||||
--! @brief register an environment to mob framework
|
||||
--! @ingroup framework_mob
|
||||
--
|
||||
--! @param name of environment
|
||||
--! @param environment specification
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_register_environment(name,environment)
|
||||
return environment.register(name,environment)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- name: mobf_probab_movgen_register_pattern(pattern)
|
||||
--
|
||||
--! @brief register an movement pattern for probabilistic movement gen
|
||||
--! @ingroup framework_mob
|
||||
--
|
||||
--! @param pattern to register (see pattern specification)
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_probab_movgen_register_pattern(pattern)
|
||||
return movement_gen.register_pattern(pattern)
|
||||
end
|
71
mods/mobf/compatibility.lua
Normal file
@ -0,0 +1,71 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file compatibility.lua
|
||||
--! @brief contains compatibility/transition code thats to be removed
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = { "animalmaterials:wool_white" },
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.env:remove_node(pos)
|
||||
minetest.env:add_node(pos,{name="wool:white"})
|
||||
end
|
||||
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = { "animalmaterials:wool_grey" },
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.env:remove_node(pos)
|
||||
minetest.env:add_node(pos,{name="wool:grey"})
|
||||
end
|
||||
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = { "animalmaterials:wool_brown" },
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.env:remove_node(pos)
|
||||
minetest.env:add_node(pos,{name="wool:brown"})
|
||||
end
|
||||
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = { "animalmaterials:wool_black" },
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.env:remove_node(pos)
|
||||
minetest.env:add_node(pos,{name="wool:black"})
|
||||
end
|
||||
|
||||
})
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- compatibility functions to make transition to new name easier
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function animals_add_animal(animal)
|
||||
mobf_add_mob(animal)
|
||||
end
|
264
mods/mobf/debug.lua
Normal file
@ -0,0 +1,264 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file debug.lua
|
||||
--! @brief contains debug functions for mob framework
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--!
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @defgroup debug_in_game In game debugging functions
|
||||
--! @brief debugging functions to be called from in game
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
|
||||
mobf_debug = {}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: print_usage(player,command,toadd)
|
||||
--
|
||||
--! @brief send errormessage to player
|
||||
--
|
||||
--! @param player name of player to print usage
|
||||
--! @param command display usage for this command
|
||||
--! @param toadd additional information to transfer to player
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_debug.print_usage(player, command, toadd)
|
||||
|
||||
if toadd == nil then
|
||||
toadd = ""
|
||||
end
|
||||
|
||||
if command == "spawnmob" then
|
||||
print("CMD: ".. player .."> ".. "Usage: /spawnmob <mobname> <X,Y,Z> " .. toadd)
|
||||
minetest.chat_send_player(player, "Usage: /spawnmob <mobname> <X,Y,Z> " .. toadd)
|
||||
end
|
||||
|
||||
if command == "ukn_mob" then
|
||||
print("CMD: ".. player .."> ".. "Unknown mob name "..toadd)
|
||||
minetest.chat_send_player(player, "Unknown mob name "..toadd)
|
||||
end
|
||||
|
||||
if command == "inv_pos" then
|
||||
print("CMD: ".. player .."> ".. "Invalid position "..toadd)
|
||||
minetest.chat_send_player(player, "Invalid position "..toadd)
|
||||
end
|
||||
|
||||
if command == "mob_spawned" then
|
||||
print("CMD: ".. player .."> ".. "Mob successfully spawned "..toadd)
|
||||
minetest.chat_send_player(player, "Mob successfully spawned "..toadd)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: spawn_mob(name,param)
|
||||
--
|
||||
--! @brief handle a spawn mob command
|
||||
--
|
||||
--! @param name name of player
|
||||
--! @param param parameters received
|
||||
------------------------------------------------------------------------------
|
||||
function mobf_debug.spawn_mob(name,param)
|
||||
print("name: " .. name .. " param: " .. dump(param))
|
||||
|
||||
local parameters = param:split(" ")
|
||||
|
||||
if #parameters ~= 2 then
|
||||
mobf_debug.print_usage(name,"spawnmob")
|
||||
return
|
||||
end
|
||||
|
||||
local pos_strings = parameters[2]:split(",")
|
||||
|
||||
if #pos_strings ~= 3 then
|
||||
mobf_debug.print_usage(name,"spawmob")
|
||||
return
|
||||
end
|
||||
|
||||
if mobf_is_known_mob(parameters[1]) ~= true then
|
||||
mobf_debug.print_usage(name,"ukn_mob", ">"..parameters[1].."<")
|
||||
return true
|
||||
end
|
||||
|
||||
local spawnpoint = {
|
||||
x=tonumber(pos_strings[1]),
|
||||
y=tonumber(pos_strings[2]),
|
||||
z=tonumber(pos_strings[3])
|
||||
}
|
||||
|
||||
if spawnpoint.x == nil or
|
||||
spawnpoint.y == nil or
|
||||
spawnpoint.z == nil then
|
||||
mobf_debug.print_usage(name,"spawnmob")
|
||||
return
|
||||
end
|
||||
|
||||
spawning.spawn_and_check(parameters[1],"__default",spawnpoint,"mobf_debug_spawner")
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: list_active_mobs(name,param)
|
||||
--
|
||||
--! @brief print list of all current active mobs
|
||||
--
|
||||
--! @param name name of player
|
||||
--! @param param parameters received
|
||||
------------------------------------------------------------------------------
|
||||
function mobf_debug.list_active_mobs(name,param)
|
||||
|
||||
local count = 1
|
||||
for index,value in pairs(minetest.luaentities) do
|
||||
if value.data ~= nil and value.data.name ~= nil then
|
||||
local tosend = count .. ": " .. value.data.name .. " at "
|
||||
.. printpos(value.object:getpos())
|
||||
print(tosend)
|
||||
minetest.chat_send_player(name,tosend)
|
||||
count = count +1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: add_tools(name,param)
|
||||
--
|
||||
--! @brief add toolset for testing
|
||||
--
|
||||
--! @param name name of player
|
||||
--! @param param parameters received
|
||||
------------------------------------------------------------------------------
|
||||
function mobf_debug.add_tools(name,param)
|
||||
local player = minetest.env:get_player_by_name(name)
|
||||
|
||||
if player ~= nil then
|
||||
player:get_inventory():add_item("main", "animalmaterials:lasso 20")
|
||||
player:get_inventory():add_item("main", "animalmaterials:net 20")
|
||||
player:get_inventory():add_item("main", "animalmaterials:scissors 1")
|
||||
player:get_inventory():add_item("main", "animalmaterials:glass 10")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: list_defined_mobs(name,param)
|
||||
--
|
||||
--! @brief list all registred mobs
|
||||
--
|
||||
--! @param name name of player
|
||||
--! @param param parameters received
|
||||
------------------------------------------------------------------------------
|
||||
function mobf_debug.list_defined_mobs(name,param)
|
||||
|
||||
local text = ""
|
||||
for i,val in ipairs(mobf_rtd.registred_mob) do
|
||||
text = text .. val .. " "
|
||||
end
|
||||
minetest.chat_send_player(name, "MOBF: "..text)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: init()
|
||||
--
|
||||
--! @brief initialize debug commands chat handler
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
function mobf_debug.init()
|
||||
|
||||
minetest.register_chatcommand("spawnmob",
|
||||
{
|
||||
params = "<name> <pos>",
|
||||
description = "spawn a mob at position" ,
|
||||
privs = {mobfw_admin=true},
|
||||
func = mobf_debug.spawn_mob
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("listactivemobs",
|
||||
{
|
||||
params = "",
|
||||
description = "list all currently active mobs" ,
|
||||
privs = {mobfw_admin=true},
|
||||
func = mobf_debug.list_active_mobs
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("listdefinedmobs",
|
||||
{
|
||||
params = "",
|
||||
description = "list all currently defined mobs" ,
|
||||
privs = {mobfw_admin=true},
|
||||
func = mobf_debug.list_defined_mobs
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("mob_add_tools",
|
||||
{
|
||||
params = "",
|
||||
description = "add some mob specific tools to player" ,
|
||||
privs = {mobfw_admin=true},
|
||||
func = mobf_debug.add_tools
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("mobf_version",
|
||||
{
|
||||
params = "",
|
||||
description = "show mobf version number" ,
|
||||
privs = {},
|
||||
func = function(name,param)
|
||||
minetest.chat_send_player(name,"MOBF version: " .. mobf_version)
|
||||
end
|
||||
})
|
||||
|
||||
if mobf_rtd.luatrace_enabled then
|
||||
minetest.register_chatcommand("traceon",
|
||||
{
|
||||
params = "",
|
||||
description = "start luatrace tracing" ,
|
||||
privs = {mobfw_admin=true},
|
||||
func = luatrace.tron()
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("traceon",
|
||||
{
|
||||
params = "",
|
||||
description = "stop luatrace tracing" ,
|
||||
privs = {mobfw_admin=true},
|
||||
func = luatrace.troff()
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: handle_spawnhouse(name,message)
|
||||
--
|
||||
--! @brief spawn small house
|
||||
--
|
||||
--! @param entity entity rightclicked
|
||||
--! @param player player doing rightclick
|
||||
------------------------------------------------------------------------------
|
||||
function mobf_debug.rightclick_callback(entity,player)
|
||||
local lifetime = mobf_get_current_time() - entity.dynamic_data.spawning.original_spawntime
|
||||
print("MOBF: " .. entity.data.name .. " is alive for " .. lifetime .. " seconds")
|
||||
print("MOBF: \tCurrent state: " .. entity.dynamic_data.state.current )
|
||||
print("MOBF: \tCurrent movgen: " .. entity.dynamic_data.current_movement_gen.name )
|
||||
if entity.dynamic_data.current_movement_gen.name == "follow_mov_gen" then
|
||||
local basepos = entity.getbasepos(entity)
|
||||
local targetpos = entity.dynamic_data.spawning.spawnpoint
|
||||
if entity.dynamic_data.movement.guardspawnpoint ~= true then
|
||||
targetpos = entity.dynamic_data.movement.target:getpos()
|
||||
end
|
||||
print("MOBF: \t\tmovement state: " .. mgen_follow.identify_movement_state(basepos,targetpos) )
|
||||
end
|
||||
print("MOBF: \tTime to state change: " .. entity.dynamic_data.state.time_to_next_change .. " seconds")
|
||||
print("MOBF: \tCurrent environmental state: " .. environment.pos_is_ok(entity.getbasepos(entity),entity))
|
||||
print("MOBF: \tCurrent accel: " .. printpos(entity.object:getacceleration()))
|
||||
print("MOBF: \tCurrent speed: " .. printpos(entity.object:getvelocity()))
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--!@}
|
96
mods/mobf/debug_trace.lua
Normal file
@ -0,0 +1,96 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file debug_trace.lua
|
||||
--! @brief contains switchable debug trace functions
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--!
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @defgroup debug_trace Debug trace functions
|
||||
--! @brief central configuration of trace functions
|
||||
--! @ingroup framework_int
|
||||
|
||||
--lvl1 excessive output
|
||||
--lvl2 medium output
|
||||
--lvl3 less output
|
||||
|
||||
--! @brief configuration of trace level to use for various components
|
||||
--! @ingroup debug_trace
|
||||
dbg_mobf = {
|
||||
|
||||
generic_lvl1 = function () end,
|
||||
generic_lvl2 = function () end,
|
||||
generic_lvl3 = function () end,
|
||||
|
||||
graphics_lvl1 = function () end,
|
||||
graphics_lvl2 = function () end,
|
||||
graphics_lvl3 = function () end,
|
||||
|
||||
spawning_lvl1 = function () end,
|
||||
spawning_lvl2 = function () end,
|
||||
spawning_lvl3 = function () end,
|
||||
|
||||
permanent_store_lvl1 = function () end,
|
||||
permanent_store_lvl2 = function () end,
|
||||
permanent_store_lvl3 = function () end,
|
||||
|
||||
movement_lvl1 = function () end,
|
||||
movement_lvl2 = function () end,
|
||||
movement_lvl3 = function () end,
|
||||
|
||||
pmovement_lvl1 = function () end,
|
||||
pmovement_lvl2 = function () end,
|
||||
pmovement_lvl3 = function () end,
|
||||
|
||||
fmovement_lvl1 = function () end,
|
||||
fmovement_lvl2 = function () end,
|
||||
fmovement_lvl3 = function () end,
|
||||
|
||||
fighting_lvl1 = function () end,
|
||||
fighting_lvl2 = function () end,
|
||||
fighting_lvl3 = function () end,
|
||||
|
||||
environment_lvl1 = function () end,
|
||||
environment_lvl2 = function () end,
|
||||
environment_lvl3 = function () end,
|
||||
|
||||
harvesting_lvl1 = function () end,
|
||||
harvesting_lvl2 = function () end,
|
||||
harvesting_lvl3 = function () end,
|
||||
|
||||
sound_lvl1 = function () end,
|
||||
sound_lvl2 = function () end,
|
||||
sound_lvl3 = function () end,
|
||||
|
||||
random_drop_lvl1 = function () end,
|
||||
random_drop_lvl2 = function () end,
|
||||
random_drop_lvl3 = function () end,
|
||||
|
||||
mob_state_lvl1 = function () end,
|
||||
mob_state_lvl2 = function () end,
|
||||
mob_state_lvl3 = function () end,
|
||||
|
||||
mobf_core_lvl1 = function () end,
|
||||
mobf_core_lvl2 = function () end,
|
||||
mobf_core_lvl3 = function () end,
|
||||
|
||||
mobf_core_helper_lvl1 = function () end,
|
||||
mobf_core_helper_lvl2 = function () end,
|
||||
mobf_core_helper_lvl3 = function () end,
|
||||
|
||||
trader_inv_lvl1 = function () end,
|
||||
trader_inv_lvl2 = function () end,
|
||||
trader_inv_lvl3 = function () end,
|
||||
|
||||
ride_lvl1 = function () end,
|
||||
ride_lvl2 = function () end,
|
||||
ride_lvl3 = function () end,
|
||||
}
|
2
mods/mobf/depends.txt
Normal file
@ -0,0 +1,2 @@
|
||||
default
|
||||
animalmaterials
|
1774
mods/mobf/doc/Doxyfile
Normal file
28
mods/mobf/doc/Testcases.txt
Normal file
@ -0,0 +1,28 @@
|
||||
Date 2012 01 28
|
||||
|
||||
testcases to check before release:
|
||||
|
||||
|
||||
Features:
|
||||
|
||||
-mobs moving
|
||||
-catching mobs with lasso
|
||||
-catching mobs with net
|
||||
-killing mobs
|
||||
-harvesting mobs
|
||||
-mobs doing meele attack
|
||||
-mobs transforming on harvest
|
||||
-mobs auto transform
|
||||
-mobs taking damage in sun
|
||||
-mobs self destruct
|
||||
-mobs honoring jump limitiations
|
||||
-mobs random dropping
|
||||
-mobs honoring movement medium
|
||||
-mobs doing random jumps
|
||||
-mobs level changing
|
||||
|
||||
|
||||
General:
|
||||
-version number correct?
|
||||
-readme correct?
|
||||
-debug output disabled?
|
46
mods/mobf/doc/mainpage_description.lua
Normal file
@ -0,0 +1,46 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file mainpage_description.lua
|
||||
--! @brief just a doc page
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2013-01-27
|
||||
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @mainpage Mob Framework Mod 2.0.x
|
||||
--!
|
||||
--! This documentation uses doxygen created from lua code. As some of you
|
||||
--! probably know doxygen doesn't support lua on it's own so some of the
|
||||
--! shown descriptions arent perfectly correct.\n
|
||||
--!
|
||||
--! On this page some of the caveats are explained:\n
|
||||
--! Lua doesn't support classes and structs but tables which ain't supported by
|
||||
--! doxygen.\n
|
||||
--!
|
||||
--! Mapping of classes and structs:
|
||||
--! \li \b classes are used to group (sub)components containing primary functions\n
|
||||
--! \li \b structs are result of parsing tables and containing configuration or
|
||||
--! temporary data
|
||||
--!
|
||||
--! Datatypes shown in doxygen and it's meaning:
|
||||
--! \li \b function this is a return value of function and can be nil too
|
||||
--! \li \b var a variable
|
||||
--! \li \b struct some table element
|
||||
--! \li \b anonymous_value a table element specified without a name
|
||||
--! \li \b parameter is a parameter declared in a function definition
|
||||
--!
|
||||
--!
|
||||
--! Keywords used in config parameter description
|
||||
--! \li \b MANDATORY some parameter required
|
||||
--! \li \b OPTIONAL parameter may be nill without causinh an error
|
||||
--! \li \b MOV_GEN_DEPENDENT parameter is required dependent of selected movement gen
|
||||
--! \li \b 2D MANDATORY parameter is required in case of 2D mob
|
||||
--! \li \b 3D MANDATORY parameter is required in case of 3D mob
|
||||
--! \li \b ALGORITHM \b DEPENDENT is required dependent on selected algorithm
|
361
mods/mobf/doc/mob_template.lua
Normal file
@ -0,0 +1,361 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file mob_template.lua
|
||||
--! @brief template for mob
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2013-01-27
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
-- WARNING this code might be not correct lua in order to get doxygen
|
||||
-- compatibility!
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
|
||||
--! @brief Template for creating mobs
|
||||
--!
|
||||
--! This template trys to describe all available configuration options
|
||||
--! in mob framework.
|
||||
--! @ingroup framework_mob
|
||||
local mob_template = {
|
||||
|
||||
--! @brief [MANDATORY] name of mob @b (alphanumeric and "_" only!!)
|
||||
name = "some name",
|
||||
--! @brief [MANDATORY] name of mod defining the mob
|
||||
modname = "name of mod",
|
||||
|
||||
--! @brief [MANDATORY] generic parameters for mob
|
||||
generic = {
|
||||
--! @brief [MANDATORY] description to show on mouse over in inventory
|
||||
description="Some mob",
|
||||
|
||||
--! @brief [MANDATORY] maximum health
|
||||
base_health=0,
|
||||
|
||||
--! @brief [MANDATORY] environment of mob to be
|
||||
envid="some environment id",
|
||||
|
||||
--! @brief [OPTIONAL] item description OR function all returning a item description of whats the result of a kill
|
||||
kill_result = nil,
|
||||
|
||||
--! @brief [OPTIONAL] armor groups of mob
|
||||
armor_groups = nil,
|
||||
|
||||
--! @brief [OPTIONAL] custom on_hit(entity,player) callback return true to skip normal fight callback
|
||||
on_hit_callback = nil,
|
||||
|
||||
--! @brief [OPTIONAL] custom on_kill(entity,player) callback return true to skip normal on kill handling
|
||||
on_kill_callback = nil,
|
||||
|
||||
--! @brief [OPTIONAL] custom on_place(entity, placer, pointed_thing) callback called after normal on place handling is done
|
||||
custom_on_place_handler = nil,
|
||||
|
||||
--! @brief [OPTIONAL] custom on_activate(entity) callback called after normal on_activate handling is done
|
||||
custom_on_activate_handler = nil,
|
||||
|
||||
--! @brief [OPTIONAL] custom on_step(entity) callback called after normal on_step handling is done
|
||||
custom_on_step_handler = nil,
|
||||
|
||||
},
|
||||
|
||||
--! @brief [MANDATORY] configuration of movement generator
|
||||
movement = {
|
||||
--! @brief [MANDATORY] is this a flying mob
|
||||
canfly=false,
|
||||
|
||||
--! @brief [MANDATORY] minumum acceleration of mob
|
||||
min_accel=0,
|
||||
|
||||
--! @brief [MANDATORY] maximum acceleration of mob
|
||||
max_accel=0,
|
||||
|
||||
--! @brief [MANDATORY] maximum absolute speed of mob
|
||||
max_speed=0,
|
||||
|
||||
--! @brief [OPTIONAL] minimum speed a mob shall move (if moving at all)
|
||||
min_speed=0,
|
||||
|
||||
--! @brief [MOV_GEN_DEPENDENT | MANDATORY] pattern based movement gen -> pattern to use for movement
|
||||
pattern="some pattern id",
|
||||
|
||||
--! @brief [MOV_GEN_DEPENDENT | OPTIONAL] follow movement gen -> does this mob guard it's spawnpoint
|
||||
guardspawnpoint = false,
|
||||
|
||||
--! @brief [MOV_GEN_DEPENDENT | OPTIONAL] follow movement gen -> time until this mob teleports to its target
|
||||
teleportdelay = 60,
|
||||
|
||||
},
|
||||
|
||||
--! @brief [OPTIONAL] if mob is harvestable configure it here
|
||||
harvest = {
|
||||
--! @brief [OPTIONAL] tool required for harvesting
|
||||
tool=nil,
|
||||
|
||||
--! @brief [OPTIONAL] is tool consuled by harvesting
|
||||
tool_consumed=false,
|
||||
|
||||
--! @brief [MANDATORY] result of harvest
|
||||
result="",
|
||||
|
||||
--! @brief [OPTIONAL] mob transforms to this mob on harvest
|
||||
transforms_to="",
|
||||
|
||||
--! @brief [MANDATORY] minimum time between two harvests (in case of transform set this to -1)
|
||||
min_delay=-1,
|
||||
},
|
||||
|
||||
--! @brief [OPTIONAL] configuration how to catch the mob
|
||||
catching = {
|
||||
--! @brief [MANDATORY] tool required to wear to catch the mob
|
||||
tool = "some item",
|
||||
--! @brief [MANDATORY] is tool consumed by catching
|
||||
consumed = true,
|
||||
},
|
||||
|
||||
--! @brief [OPTIONAL] does this mob do random drops
|
||||
random_drop = {
|
||||
|
||||
--! @brief [MANDATORY] item to be dropped
|
||||
result="some_material",
|
||||
|
||||
--! @brief [MANDATORY] minimum delay between two drops
|
||||
min_delay=60,
|
||||
|
||||
--! @brief [MANDATORY] chance per second to drop after min_delay has passed
|
||||
chance=0.2
|
||||
},
|
||||
|
||||
--! @brief [OPTIONAL] if this mob s intended to transform by its own configure it here
|
||||
auto_transform = {
|
||||
|
||||
--! @brief [MANDATORY] mob to transform to
|
||||
result="some_mob",
|
||||
|
||||
--! @brief [MANDATORY] time to transformation
|
||||
delay=1800
|
||||
},
|
||||
|
||||
--! @brief [OPTIONAL] combat settings for mob
|
||||
combat = {
|
||||
--! @brief [MANDATORY] does mob start an attack on its own?
|
||||
starts_attack=true,
|
||||
|
||||
--! @brief [MANDATORY] chance mob will attack (if starting attack on its own or beeing attacked)
|
||||
angryness=0.95,
|
||||
|
||||
--! @brief [OPTIONAL] is mob sensitive to sun?
|
||||
sun_sensitive=true,
|
||||
|
||||
--! @brief [OPTIONAL] configuration of meele attack
|
||||
melee = {
|
||||
--! @brief [MANDATORY] maximum damage mob does per hit
|
||||
maxdamage=4,
|
||||
--! @brief [MANDATORY] range mob will hit
|
||||
range=2,
|
||||
--! @brief [MANDATORY] minimum time between two hits
|
||||
speed=2,
|
||||
},
|
||||
--! @brief [OPTIONAL] configuration of distance attack
|
||||
distance = {
|
||||
--! @brief [MANDATORY] distance projectile to issue
|
||||
attack="some_entity",
|
||||
--! @brief [MANDATORY] distance to issue an attack
|
||||
range=10,
|
||||
--! @brief [MANDATORY] minimum time between two attacks
|
||||
speed=2,
|
||||
},
|
||||
|
||||
--! @brief [OPTIONAL] configuration for self destructing mob
|
||||
self_destruct = {
|
||||
--! [MANDATORY] maximum damage to be done on self destruct
|
||||
damage=15,
|
||||
--! [MANDATORY] maximum range to do damage
|
||||
range=5,
|
||||
--! [MANDATORY] range to destroy nodes on self destruction
|
||||
node_damage_range = 1.5,
|
||||
--! [MANDATORY] delay between self destruct triggering and explosion
|
||||
delay=5,
|
||||
},
|
||||
},
|
||||
--! @brief [MANDATORY] spawning configuration for mob
|
||||
spawning = {
|
||||
--! @brief [MANDATORY] rate this mob is spawned
|
||||
rate=0.01,
|
||||
--! @brief [MANDATORY] typical distance between two mobs of this type when spawend
|
||||
density=1000,
|
||||
--! @brief [MANDATORY] identifyer of spawn algorithm
|
||||
algorithm="some algorithm id",
|
||||
|
||||
--! @brief [ALGORITHM DEPENDENT] shadows minimum number of air blocks above pos
|
||||
height = 1,
|
||||
},
|
||||
|
||||
--! @brief [OPTIONAL] sounds to be played by mob
|
||||
sound = {
|
||||
--! @brief [OPTIONAL] random sound to be played
|
||||
random = {
|
||||
--! @brief [MANDATORY] basename of file
|
||||
name="random_1",
|
||||
--! @brief [MANDATORY] minimum time between playing sounds
|
||||
min_delta = 10,
|
||||
--! @brief [MANDATORY] chance per second to play sound after minimum time
|
||||
chance = 0.5,
|
||||
--! @brief [MANDATORY] amplify the sound by this value
|
||||
gain = 1,
|
||||
--! @brief [MANDATORY] maximum distance sound is heared
|
||||
max_hear_distance = 75,
|
||||
},
|
||||
--! @brief [OPTIONAL] sound played on self destruction
|
||||
self_destruct = {
|
||||
--! @brief [MANDATORY] basename of file
|
||||
name="bomb_explosion",
|
||||
--! @brief [MANDATORY] amplify the sound by this value
|
||||
gain = 2,
|
||||
--! @brief [MANDATORY] maximum distance sound is heared
|
||||
max_hear_distance = 1000,
|
||||
},
|
||||
--! @brief [OPTIONAL] sound played on harvest
|
||||
harvest = {
|
||||
--! @brief [MANDATORY] basename of file
|
||||
name="harvest",
|
||||
--! @brief [MANDATORY] amplify the sound by this value
|
||||
gain = 0.8,
|
||||
--! @brief [MANDATORY] maximum distance sound is heared
|
||||
max_hear_distance = 5,
|
||||
},
|
||||
--! @brief [OPTIONAL] sound played on distance attack
|
||||
distance = {
|
||||
--! @brief [MANDATORY] basename of file
|
||||
name="fireball",
|
||||
--! @brief [MANDATORY] amplify the sound by this value
|
||||
gain = 1,
|
||||
--! @brief [MANDATORY] maximum distance sound is heared
|
||||
max_hear_distance = 100,
|
||||
},
|
||||
--! @brief [OPTIONAL] sound played if mob dies
|
||||
die = {
|
||||
--! @brief [MANDATORY] basename of file
|
||||
name="die",
|
||||
--! @brief [MANDATORY] amplify the sound by this value
|
||||
gain = 1,
|
||||
--! @brief [MANDATORY] maximum distance sound is heared
|
||||
max_hear_distance = 100,
|
||||
},
|
||||
--! @brief [OPTIONAL] sound played if mob does meele attack
|
||||
melee = {
|
||||
--! @brief [MANDATORY] basename of file
|
||||
name="hit",
|
||||
--! @brief [MANDATORY] amplify the sound by this value
|
||||
gain = 1,
|
||||
--! @brief [MANDATORY] maximum distance sound is heared
|
||||
max_hear_distance = 100,
|
||||
},
|
||||
},
|
||||
--! @brief [OPTIONAL] used to specify different movement/model states,
|
||||
--! you may specify as many states as you like
|
||||
states = {
|
||||
{
|
||||
--! @brief [MANDATORY] (default state is MUST have!) name of state
|
||||
name = "default",
|
||||
--! @brief [MANDATORY] typical duration of this state
|
||||
typical_state_time = 180,
|
||||
--! @brief [MANDATORY] chance of state to be selected (SUM may not be > 1)
|
||||
chance = 0.5,
|
||||
--! @brief [MANDATORY] a special movement handler for this state
|
||||
movgen = "none",
|
||||
--! @brief [3D MANDATORY] a special model to be used for this state
|
||||
graphics_3d = {
|
||||
--! @brief [MANDATORY] this is the drawtype to use
|
||||
visual = "mesh",
|
||||
--! @brief [MANDATORY] this is the drawtype to use
|
||||
mesh = "mesh.x",
|
||||
--! @brief [MANDATORY] the model of the mob
|
||||
textures = {"some node declatation"},
|
||||
--! @brief [MANDATORY] collisionbox to use
|
||||
collisionbox = { "<selectionbox declatation>" },
|
||||
--! @brief [MANDATORY] xyz scale factors for the model
|
||||
visual_size = {x=1,y=1,z=1},
|
||||
},
|
||||
--! @brief [2D MANDATORY] a special sprite to be used for this state
|
||||
graphics_2d = {
|
||||
--! @brief [MANDATORY] scale of sprite
|
||||
sprite_scale={x=0,y=0},
|
||||
--! @brief [MANDATORY] description of multi dimensional sprites (e.g. containing burning/ differend view directions)
|
||||
sprite_div = {x=0,y=0},
|
||||
--! @brief [MANDATORY] height of sprite
|
||||
visible_height = 3.2,
|
||||
|
||||
},
|
||||
--! @brief [MANDATORY] a animation to be played while this state is active
|
||||
animation = "walk",
|
||||
},
|
||||
{
|
||||
--! @brief [MANDATORY] name of state
|
||||
name = "another_state_example",
|
||||
--! @brief [MANDATORY] typical duration of this state
|
||||
typical_state_time = 180,
|
||||
--! @brief [MANDATORY] chance of state to be selected (SUM may not be > 1)
|
||||
chance = 0.5,
|
||||
--! @brief [OPTIONAL] a function to check before switching to this state
|
||||
custom_preconhandler = nil,
|
||||
--! @brief [OPTIONAL] a special movement handler for this state
|
||||
movgen = "none",
|
||||
--! @brief [OPTIONAL] a special model to be used for this state
|
||||
graphics_3d = "<graphic definition as previous described>",
|
||||
--! @brief [OPTIONAL] a special sprite to be used for this state
|
||||
graphics_2d = "<graphic definition as previous described>",
|
||||
--! @brief [OPTIONAL] a animation to be played while this state is active
|
||||
animation = "name",
|
||||
},
|
||||
{
|
||||
|
||||
}
|
||||
},
|
||||
--! @brief [OPTIONAL] description of animations
|
||||
animation = {
|
||||
--! @brief [OPTIONAL] one or many animation descriptions
|
||||
animationname = {
|
||||
--! @brief [MANDATORY] start frame of animation
|
||||
start_frame = 1,
|
||||
--! @brief [MANDATORY] end frame of animation
|
||||
end_frame = 2,
|
||||
},
|
||||
},
|
||||
--! @brief [OPTIONAL] parameters for rideable mobs
|
||||
ride = {
|
||||
--! @brief [OPTIONAL] speed when walking
|
||||
walkspeed = 7.8,
|
||||
--! @brief [OPTIONAL] speed when sneaking
|
||||
sneakspeed = 0.8,
|
||||
--! @brief [OPTIONAL] inital jumpspeed
|
||||
jumpspeed = 58,
|
||||
--! @brief [OPTIONAL] offset to center player is put to
|
||||
attacheoffset = { x=0,y=2,z=0},
|
||||
--! @brief [OPTIONAL] texture modifier when player is attached
|
||||
texturemod = "^mob_ostrich_ostrich_saddle_mesh.png",
|
||||
--! @brief [OPTIONAL] animation to show when riding
|
||||
walk_anim = "walk"
|
||||
},
|
||||
--! @brief [OPTIONAL] configuration for a trader mob
|
||||
trader_inventory = {
|
||||
--! @brief [MANDATORY] goodlist to be sold
|
||||
goods = {
|
||||
--! @brief [MANDOTORY] first element in list
|
||||
{ "default:mese 1", "default:dirt 99", "default:cobble 50"},
|
||||
--! @brief [OPTIONAL] any further element
|
||||
{ "default:steel_ingot 1", "default:dirt 50", "default:cobble 20"},
|
||||
},
|
||||
--! @brief [MANDATORY] list of names randomly choosen for trader
|
||||
random_names = { "Name1","Name2","Name3"},
|
||||
}
|
||||
}
|
604
mods/mobf/environment.lua
Normal file
@ -0,0 +1,604 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--
|
||||
--! @file environment.lua
|
||||
--! @brief component for environment related functions
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @defgroup environment Environment subcomponent
|
||||
--! @brief Environment check functions used by different subcomponents
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
environment = {}
|
||||
|
||||
--! @brief list of known environments
|
||||
--! @memberof environment
|
||||
environment_list = {}
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_suitable_pos_same_level(pos_raw,maxsearcharea,entity)
|
||||
--
|
||||
--! @brief find a position suitable around a specific position
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param pos_raw position to look at
|
||||
--! @param maxsearcharea max range to look for suitable position
|
||||
--! @param entity mob to look for position
|
||||
--! @param accept_possible return position thats possible only too
|
||||
--! @return {x,y,z} position found or nil
|
||||
-------------------------------------------------------------------------------
|
||||
function environment.get_suitable_pos_same_level(pos_raw,maxsearcharea,entity,accept_possible)
|
||||
dbg_mobf.movement_lvl3("MOBF: --> get_suitable_pos_same_level "
|
||||
.. printpos(pos_raw))
|
||||
local pos = mobf_round_pos(pos_raw)
|
||||
|
||||
dbg_mobf.movement_lvl1("MOBF: Starting pos is "..printpos(pos)
|
||||
.." max search area is "..maxsearcharea)
|
||||
|
||||
local e1 = "|"
|
||||
local e2 = "|"
|
||||
local e3 = "|"
|
||||
local e4 = "|"
|
||||
|
||||
local possible_targets = {}
|
||||
|
||||
--search next position on solid ground
|
||||
for search=1, maxsearcharea,1 do
|
||||
--TODO randomize search order
|
||||
|
||||
--find along edge 1
|
||||
for current=-search,search,1 do
|
||||
local pos_tocheck = { x= pos.x + current,y=pos.y,z=pos.z -search}
|
||||
local pos_state = environment.pos_is_ok(pos_tocheck,entity)
|
||||
|
||||
dbg_mobf.movement_lvl1("MOBF: state of "..printpos(pos_tocheck).." is "
|
||||
.. pos_state)
|
||||
|
||||
if pos_state == "ok" then
|
||||
dbg_mobf.movement_lvl1("found new pos")
|
||||
table.insert(possible_targets, pos_tocheck)
|
||||
elseif pos_state == "possible_surface" and
|
||||
accept_possible then
|
||||
table.insert(possible_targets, pos_tocheck)
|
||||
-- elseif pos_state == "collision_jumpabe" then
|
||||
-- dbg_mobf.movement_lvl1("found new pos above")
|
||||
-- return {x=pos_tocheck.x,y=pos_tocheck.y+1,z=pos_tocheck.z}
|
||||
else
|
||||
e1 = e1..pos_state.."|"
|
||||
end
|
||||
end
|
||||
|
||||
--find along edge 2
|
||||
for current=-(search-1),(search-1),1 do
|
||||
local pos_tocheck = { x= pos.x + search,y=pos.y,z=pos.z + current}
|
||||
local pos_state = environment.pos_is_ok(pos_tocheck,entity)
|
||||
|
||||
dbg_mobf.movement_lvl1("MOBF: state of "..printpos(pos_tocheck).." is "
|
||||
.. pos_state)
|
||||
|
||||
if pos_state == "ok" then
|
||||
dbg_mobf.movement_lvl1("found new pos")
|
||||
table.insert(possible_targets, pos_tocheck)
|
||||
elseif pos_state == "possible_surface" and
|
||||
accept_possible then
|
||||
table.insert(possible_targets, pos_tocheck)
|
||||
else
|
||||
e2 = e2..pos_state.."|"
|
||||
end
|
||||
end
|
||||
|
||||
--find along edge 3
|
||||
|
||||
for current=search,-search,-1 do
|
||||
local pos_tocheck = { x= pos.x + current,y=pos.y,z=pos.z + search}
|
||||
local pos_state = environment.pos_is_ok(pos_tocheck,entity)
|
||||
|
||||
dbg_mobf.movement_lvl1("MOBF: state of "..printpos(pos_tocheck).." is "
|
||||
.. pos_state)
|
||||
|
||||
if pos_state == "ok" then
|
||||
dbg_mobf.movement_lvl1("found new pos")
|
||||
table.insert(possible_targets, pos_tocheck)
|
||||
elseif pos_state == "possible_surface" and
|
||||
accept_possible then
|
||||
table.insert(possible_targets, pos_tocheck)
|
||||
else
|
||||
e3 = e3..pos_state.."|"
|
||||
end
|
||||
end
|
||||
|
||||
--find along edge 4
|
||||
for current=(search-1),-(search-1),-1 do
|
||||
local pos_tocheck = { x= pos.x -search,y=pos.y,z=pos.z + current}
|
||||
local pos_state = environment.pos_is_ok(pos,entity)
|
||||
|
||||
dbg_mobf.movement_lvl1("MOBF: state of "..printpos(pos_tocheck).." is "
|
||||
.. pos_state)
|
||||
|
||||
if pos_state == "ok" then
|
||||
dbg_mobf.movement_lvl1("found new pos")
|
||||
table.insert(possible_targets, pos_tocheck)
|
||||
elseif pos_state == "possible_surface" and
|
||||
accept_possible then
|
||||
table.insert(possible_targets, pos_tocheck)
|
||||
else
|
||||
e4 = e4..pos_state.."|"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- print("MOBF: Bug !!! didn't find a suitable position to place mob")
|
||||
-- print("Surrounding of " .. printpos(pos_raw) .. "was:")
|
||||
-- print(e1)
|
||||
-- print(" " .. e2)
|
||||
-- print(e4)
|
||||
-- print(e3)
|
||||
|
||||
if #possible_targets > 0 then
|
||||
local i = math.random(1, #possible_targets)
|
||||
return possible_targets[i]
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: is_media_element(nodename,environment)
|
||||
--
|
||||
--! @brief check if nodename is in environment
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param nodename name to check
|
||||
--! @param media environment of mob
|
||||
--! @return true/false
|
||||
------------------------------------------------------------------------------
|
||||
function environment.is_media_element( nodename, media )
|
||||
|
||||
--security check
|
||||
if media == false then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF: BUG!!!! no environment specified!")
|
||||
return false
|
||||
end
|
||||
|
||||
for i,v in ipairs(media) do
|
||||
if v == nodename then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
dbg_mobf.environment_lvl2("MOBF: " .. nodename .. " is not within environment list:")
|
||||
|
||||
for i,v in ipairs(media) do
|
||||
dbg_mobf.environment_lvl3("MOBF: \t" .. v)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_absolute_min_max_pos(env, pos)
|
||||
--
|
||||
--! @brief check if nodename is in environment
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param env environment mob should be
|
||||
--! @param pos position it is currently
|
||||
--! @return { minpos,maxpos }
|
||||
------------------------------------------------------------------------------
|
||||
function environment.get_absolute_min_max_pos(env,pos)
|
||||
|
||||
local node = minetest.env:get_node(pos)
|
||||
|
||||
--if is not within environment it should be return current position
|
||||
--as min max
|
||||
if environment.is_media_element(node.name,env.media) == false then
|
||||
return pos.y,pos.y
|
||||
end
|
||||
|
||||
local min_y = env.min_height_above_ground
|
||||
local max_y = env.max_height_above_ground
|
||||
|
||||
|
||||
--a fully generic check isn't possible here so we need to use media
|
||||
--specific ways ... it's ugly but works
|
||||
if node.name == "air" then
|
||||
min_y = min_y + ( pos.y - mobf_surface_distance(pos))
|
||||
max_y = max_y + ( pos.y - mobf_surface_distance(pos))
|
||||
end
|
||||
|
||||
if node.name == "default:water" or
|
||||
node.name == "defailt:water_flowing" then
|
||||
-- water mobs do use min/max directly
|
||||
end
|
||||
|
||||
if node.name == "default:lava" or
|
||||
node.name == "default:lava_flowing" then
|
||||
--TODO e.g. lava fish
|
||||
--not implemented by now
|
||||
end
|
||||
|
||||
return min_y,max_y
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: is_jumpable_surface(name)
|
||||
--
|
||||
--! @brief check if name is a surface an mob may jump onto
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param name name to check
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function environment.is_jumpable_surface(name)
|
||||
|
||||
|
||||
if name == "default:dirt" or
|
||||
name == "default:dirt_with_grass" or
|
||||
name == "default:stone" or
|
||||
name == "default:sand" or
|
||||
name == "default:clay"
|
||||
then
|
||||
return true
|
||||
end
|
||||
|
||||
dbg_mobf.environment_lvl1("MOBF: is "..name.." a jumpable surface?")
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: checksurfacek(pos,surfaces)
|
||||
--
|
||||
--! @brief check if a position is suitable for an mob
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param pos position to check
|
||||
--! @param surface surfaces valid
|
||||
--! @return true on valid surface false if not
|
||||
-------------------------------------------------------------------------------
|
||||
function environment.checksurface(pos,surface)
|
||||
|
||||
--if no surfaces are specified any surface is treated as ok
|
||||
if surface == nil then
|
||||
return "ok"
|
||||
end
|
||||
|
||||
local pos_below = {x=pos.x,y=pos.y-1,z=pos.z}
|
||||
|
||||
local node_below = minetest.env:get_node(pos_below)
|
||||
|
||||
|
||||
if node_below == nil then
|
||||
return "ok"
|
||||
end
|
||||
|
||||
for i,v in ipairs(surface.good) do
|
||||
if node_below.name == v then
|
||||
return "ok"
|
||||
end
|
||||
end
|
||||
|
||||
if surface.possible ~= nil then
|
||||
for i,v in ipairs(surface.possible) do
|
||||
if node_below.name == v then
|
||||
return "possible_surface"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return "wrong_surface"
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_min_max_ground_dist(entity)
|
||||
--
|
||||
--! @brief calculate absolute minimum and maximum height for a mob
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param entity mob to check
|
||||
--! @return min y val,max y val
|
||||
-------------------------------------------------------------------------------
|
||||
function environment.get_min_max_ground_dist(entity)
|
||||
local min_ground_distance = 0
|
||||
local max_ground_distance = 0
|
||||
|
||||
if entity.environment.max_height_above_ground ~= nil then
|
||||
max_ground_distance = entity.environment.max_height_above_ground
|
||||
end
|
||||
|
||||
if entity.environment.min_height_above_ground ~= nil then
|
||||
min_ground_distance = entity.environment.min_height_above_ground
|
||||
end
|
||||
|
||||
if entity.data.movement.canfly == nil or
|
||||
entity.data.movement.canfly == false then
|
||||
max_ground_distance = 1
|
||||
end
|
||||
|
||||
return min_ground_distance,max_ground_distance
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: pos_is_ok(pos,entity)
|
||||
--
|
||||
--! @brief check if a position is suitable for an mob
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param pos position to check
|
||||
--! @param entity mob to check
|
||||
--! @param dont_do_jumpcheck
|
||||
--! @return suitability of position for mob values:
|
||||
--! -ok -@>position is ok
|
||||
--! -collision -@>position is within a node
|
||||
--! -collision_jumpable -@>position is within a node that can be jumped onto
|
||||
--! -drop -@>position is a drop
|
||||
--! -drop_above_water -@>position is to far above water
|
||||
--! -above_water -@>position is right over water
|
||||
--! -in_water -@>position is within a water node(source or flow)
|
||||
--! -in_air -@>position is in air
|
||||
--! -above_limit -@>position is above level limit
|
||||
--! -below_limit -@>position is below level limit
|
||||
--! -wrong_surface -@>position is above surface mob shouldn't be
|
||||
--! -invalid -@>unable to check position
|
||||
-------------------------------------------------------------------------------
|
||||
function environment.pos_is_ok(pos,entity,dont_do_jumpcheck)
|
||||
|
||||
local min_ground_distance,max_ground_distance = environment.get_min_max_ground_dist(entity)
|
||||
|
||||
local cornerpositions = {}
|
||||
|
||||
table.insert(cornerpositions,pos)
|
||||
--read positions at corners
|
||||
table.insert(cornerpositions,{x=pos.x + entity.collisionbox[4] -0.01,y=pos.y,z=pos.z + entity.collisionbox[6] -0.01})
|
||||
table.insert(cornerpositions,{x=pos.x + entity.collisionbox[4] -0.01,y=pos.y,z=pos.z + entity.collisionbox[3] +0.01})
|
||||
table.insert(cornerpositions,{x=pos.x + entity.collisionbox[1] +0.01,y=pos.y,z=pos.z + entity.collisionbox[6] -0.01})
|
||||
table.insert(cornerpositions,{x=pos.x + entity.collisionbox[1] +0.01,y=pos.y,z=pos.z + entity.collisionbox[3] +0.01})
|
||||
|
||||
local lastpos = nil
|
||||
|
||||
local retval = "temp_ok"
|
||||
|
||||
--check if mob at pos will be in correct environment
|
||||
for i=1,#cornerpositions,1 do
|
||||
if not mobf_pos_is_same(lastpos,cornerpositions[i]) then
|
||||
local node_to_check = minetest.env:get_node(cornerpositions[i])
|
||||
|
||||
if node_to_check == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF: BUG!!!! checking position with invalid node")
|
||||
retval = "invalid"
|
||||
break
|
||||
end
|
||||
|
||||
if not environment.is_media_element(node_to_check.name,entity.environment.media) == true then
|
||||
dbg_mobf.environment_lvl3("MOBF: " .. i .. ": " ..
|
||||
printpos(cornerpositions[i]) .. " -- " .. printpos(pos) ..
|
||||
" not within environment")
|
||||
|
||||
if mobf_pos_is_same(pos,cornerpositions[i]) then
|
||||
if node_to_check.name == "default:water_source" or
|
||||
node_to_check.name == "default:water_flowing" then
|
||||
retval = "in_water"
|
||||
break
|
||||
end
|
||||
|
||||
if node_to_check.name == "air" then
|
||||
retval = "in_air"
|
||||
break
|
||||
end
|
||||
|
||||
--TODO maybe replace by "invalid medium"
|
||||
else
|
||||
retval = "collision"
|
||||
end
|
||||
end
|
||||
end
|
||||
lastpos = cornerpositions[i]
|
||||
end
|
||||
|
||||
--
|
||||
if retval == "temp_ok" then
|
||||
dbg_mobf.environment_lvl2("MOBF: \tin environment")
|
||||
local ground_distance = mobf_ground_distance(pos,entity.environment.media)
|
||||
|
||||
--following return codes are only usefull for non flying
|
||||
if entity.data.movement.canfly == nil or
|
||||
entity.data.movement.canfly == false then
|
||||
|
||||
if mobf_above_water(pos) then
|
||||
|
||||
if ground_distance > max_ground_distance then
|
||||
dbg_mobf.environment_lvl2("MOBF: \tdropping above water")
|
||||
retval = "drop_above_water"
|
||||
end
|
||||
dbg_mobf.environment_lvl2("MOBF: \tabove water")
|
||||
retval = "above_water"
|
||||
end
|
||||
|
||||
if ground_distance > max_ground_distance then
|
||||
dbg_mobf.environment_lvl2("MOBF: \tdropping "
|
||||
.. ground_distance .. " / " .. max_ground_distance)
|
||||
retval = "drop"
|
||||
else
|
||||
dbg_mobf.environment_lvl2("MOBF: \tsurface dependent")
|
||||
retval = environment.checksurface(pos,entity.environment.surfaces)
|
||||
end
|
||||
else
|
||||
local miny,maxy = environment.get_absolute_min_max_pos(entity.environment,pos)
|
||||
dbg_mobf.environment_lvl2("MOBF: \tflying mob detected, min: "
|
||||
.. miny .. " max: " .. maxy .. " current: " .. pos.y)
|
||||
if pos.y < miny then
|
||||
retval = "below_limit"
|
||||
else if pos.y > maxy then
|
||||
retval = "above_limit"
|
||||
else
|
||||
retval = environment.checksurface(pos,entity.environment.surfaces)
|
||||
end end
|
||||
end
|
||||
end
|
||||
|
||||
if retval == "collision" and not dont_do_jumpcheck then
|
||||
dbg_mobf.environment_lvl2("MOBF: check if pos is jumpable")
|
||||
local upper_pos_state = environment.pos_is_ok({x=pos.x,
|
||||
y=pos.y+1,
|
||||
z=pos.z},
|
||||
entity,true)
|
||||
if upper_pos_state == "ok" then
|
||||
retval = "collision_jumpable"
|
||||
else
|
||||
dbg_mobf.environment_lvl2("MOBF: upper pos state was: " .. upper_pos_state)
|
||||
end
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_default_gravity(pos,environment,canfly)
|
||||
--
|
||||
--! @brief get default acceleration depending on mobs medium and pos
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param pos position where to check gravity
|
||||
--! @param media mobs movement medium
|
||||
--! @param canfly is mob capable of flying?
|
||||
--! @return y-acceleration
|
||||
------------------------------------------------------------------------------
|
||||
function environment.get_default_gravity(pos,media,canfly)
|
||||
|
||||
if pos == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
local node = minetest.env:get_node(pos)
|
||||
|
||||
--if an mob can't fly or isn't within it's medium default acceleration
|
||||
-- for it's current medium is applied
|
||||
if canfly == nil or
|
||||
canfly == false or
|
||||
environment.is_media_element(node.name,media) == false
|
||||
then
|
||||
if (node.name == "air") then
|
||||
return -9.81
|
||||
end
|
||||
|
||||
if node.name == "default:water_source" or
|
||||
node.name == "default:water_flowing" then
|
||||
return -2.5
|
||||
end
|
||||
|
||||
if node.name == "default:lava" then
|
||||
return 0.1
|
||||
end
|
||||
|
||||
--mob is at invalid position thus returning default air acceleration
|
||||
return -9.81
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: fix_base_pos(entity, middle_to_bottom)
|
||||
--
|
||||
--! @brief fix the mobs y position according to model or sprite height
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param entity mob to fix base position
|
||||
--! @param center_to_bottom distance from center of mob to its bottom (absolute value)
|
||||
--! @return new position set by function
|
||||
------------------------------------------------------------------------------
|
||||
function environment.fix_base_pos(entity, center_to_bottom)
|
||||
|
||||
if center_to_bottom > 0.5 then
|
||||
|
||||
local pos = entity.object:getpos()
|
||||
|
||||
local node_pos = minetest.env:get_node(pos)
|
||||
|
||||
local pos_to_check = {x=pos.x,y=pos.y-center_to_bottom+0.1,z=pos.z}
|
||||
local node_pos_check = minetest.env:get_node(pos_to_check)
|
||||
|
||||
if node_pos ~= nil and
|
||||
node_pos_check ~= nil then
|
||||
dbg_mobf.environment_lvl3("MOBF: fixing y position / base position required? "
|
||||
.. node_pos.name .. " " .. node_pos_check.name)
|
||||
if node_pos.name ~= node_pos_check.name then
|
||||
distance_to_ground = mobf_surface_distance(pos)
|
||||
|
||||
pos.y = pos.y + (center_to_bottom - distance_to_ground +0.5)
|
||||
dbg_mobf.environment_lvl2("MOBF: fixing y position of " .. entity.data.name
|
||||
.. " got distance " .. center_to_bottom .. " moving to " ..printpos(pos))
|
||||
entity.object:moveto(pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return entity.getbasepos(entity)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: register(name, environment)
|
||||
--
|
||||
--! @brief register an environment to mob framework
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param name id of environment
|
||||
--! @param environment description of environment
|
||||
--! @return true/false succesfully registred environment
|
||||
-------------------------------------------------------------------------------
|
||||
function environment.register(name, environment)
|
||||
|
||||
if environment_list[name] ~= nil then
|
||||
return false
|
||||
end
|
||||
|
||||
environment_list[name] = environment
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: pos_state_is_impossible(entity,pos)
|
||||
--
|
||||
--! @brief checks if a entity can be there (not if it would move there by its own)
|
||||
--! @ingroup environment
|
||||
--
|
||||
--! @param entity entity to check
|
||||
--! @param pos position to check
|
||||
--! @return true entity may be there, entity can never be there
|
||||
-------------------------------------------------------------------------------
|
||||
function environment.possible_pos(entity,pos)
|
||||
local state = environment.pos_is_ok(pos,entity)
|
||||
|
||||
if state == "collision" or
|
||||
state == "collision_jumpable" or
|
||||
state == "invalid" then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--!@}
|
||||
|
||||
dofile (mobf_modpath .. "/environments/general_env_sets.lua")
|
||||
dofile (mobf_modpath .. "/environments/flight_1.lua")
|
||||
dofile (mobf_modpath .. "/environments/meadow.lua")
|
||||
dofile (mobf_modpath .. "/environments/on_ground_1.lua")
|
||||
dofile (mobf_modpath .. "/environments/on_ground_2.lua")
|
||||
dofile (mobf_modpath .. "/environments/open_waters.lua")
|
||||
dofile (mobf_modpath .. "/environments/shallow_waters.lua")
|
||||
dofile (mobf_modpath .. "/environments/simple_air.lua")
|
33
mods/mobf/environments/flight_1.lua
Normal file
@ -0,0 +1,33 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file flight_1.lua
|
||||
--! @brief a environment description for in flight mobs
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup environments
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @struct env_flight_1
|
||||
--! @brief flying mobs in height between 13-23 blocks above surface
|
||||
env_flight_1 = {
|
||||
media = {
|
||||
"air"
|
||||
},
|
||||
surfaces = nil,
|
||||
--ground is first node above/below not beeing of media type
|
||||
max_height_above_ground = 23,
|
||||
min_height_above_ground = 13
|
||||
}
|
||||
|
||||
--!@}
|
||||
|
||||
environment.register("flight_1", env_flight_1)
|
37
mods/mobf/environments/general_env_sets.lua
Normal file
@ -0,0 +1,37 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file flight_1.lua
|
||||
--! @brief a environment description for in flight mobs
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2013-01-06
|
||||
--
|
||||
--! @addtogroup environments
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @addtogroup predev_env_sets
|
||||
--! @{
|
||||
mobf_env_placable_items = {
|
||||
"default:rail",
|
||||
"default:ladder",
|
||||
"default:torch",
|
||||
"default:sign_wall",
|
||||
}
|
||||
|
||||
|
||||
mobf_env_plants = {
|
||||
"default:junglegrass",
|
||||
"default:papyrus",
|
||||
"default:sapling",
|
||||
"default:apple"
|
||||
|
||||
}
|
||||
--@}
|
||||
--@}
|
48
mods/mobf/environments/meadow.lua
Normal file
@ -0,0 +1,48 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file meadow.lua
|
||||
--! @brief meadow environment description
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup environments
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @struct env_meadow
|
||||
--! @brief environment for mobs that prefere green meadows but may walk on
|
||||
--! dirt and sand too
|
||||
env_meadow = {
|
||||
media = {
|
||||
"air",
|
||||
},
|
||||
surfaces = {
|
||||
good = {
|
||||
"default:dirt_with_grass"
|
||||
},
|
||||
possible = {
|
||||
"default:dirt",
|
||||
"default:sand",
|
||||
},
|
||||
},
|
||||
}
|
||||
--!@}
|
||||
|
||||
table.foreach(mobf_env_placable_items,
|
||||
function(index)
|
||||
table.insert(env_meadow.media,mobf_env_placable_items[index])
|
||||
end)
|
||||
|
||||
table.foreach(mobf_env_plants,
|
||||
function(index)
|
||||
table.insert(env_meadow.media,mobf_env_plants[index])
|
||||
end)
|
||||
|
||||
environment.register("meadow", env_meadow)
|
38
mods/mobf/environments/on_ground_1.lua
Normal file
@ -0,0 +1,38 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file on_ground_1.lua
|
||||
--! @brief a environment description for mobs on ground
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup environments
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @struct env_on_ground_1
|
||||
--! @brief an environment for mobs capable of walking through junglegrass
|
||||
env_on_ground_1 = {
|
||||
media = {
|
||||
"air",
|
||||
}
|
||||
}
|
||||
--!@}
|
||||
|
||||
table.foreach(mobf_env_placable_items,
|
||||
function(index)
|
||||
table.insert(env_on_ground_1.media,mobf_env_placable_items[index])
|
||||
end)
|
||||
|
||||
table.foreach(mobf_env_plants,
|
||||
function(index)
|
||||
table.insert(env_on_ground_1.media,mobf_env_plants[index])
|
||||
end)
|
||||
|
||||
environment.register("on_ground_1", env_on_ground_1)
|
54
mods/mobf/environments/on_ground_2.lua
Normal file
@ -0,0 +1,54 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file on_ground_2.lua
|
||||
--! @brief a environment description for mobs on ground
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup environments
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--! @struct env_on_ground_2
|
||||
--! @brief an environment for mobs capable of walking through junglegrass
|
||||
--! and stay on natural surfaces
|
||||
env_on_ground_2 = {
|
||||
media = {
|
||||
"air",
|
||||
},
|
||||
surfaces = {
|
||||
good = {
|
||||
"default:dirt_with_grass",
|
||||
"default:dirt",
|
||||
"default:stone"
|
||||
},
|
||||
},
|
||||
|
||||
--TODO add support for light checks
|
||||
-- light = {
|
||||
-- min_light = 0,
|
||||
-- max_light = 0,
|
||||
-- }
|
||||
}
|
||||
|
||||
--!@}
|
||||
|
||||
table.foreach(mobf_env_placable_items,
|
||||
function(index)
|
||||
table.insert(env_on_ground_2.media,mobf_env_placable_items[index])
|
||||
end)
|
||||
|
||||
table.foreach(mobf_env_plants,
|
||||
function(index)
|
||||
table.insert(env_on_ground_2.media,mobf_env_plants[index])
|
||||
end)
|
||||
|
||||
environment.register("on_ground_2", env_on_ground_2)
|
33
mods/mobf/environments/open_waters.lua
Normal file
@ -0,0 +1,33 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file open_waters.lua
|
||||
--! @brief open waters
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup environments
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @struct env_open_waters
|
||||
--! @brief open waters from 4 to 30 blocks deep
|
||||
env_open_waters = {
|
||||
media = {
|
||||
"default:water_source",
|
||||
"default:water_flowing"
|
||||
},
|
||||
surfaces = nil,
|
||||
--ground is first node above/below not beeing of media type
|
||||
max_height_above_ground = -4,
|
||||
min_height_above_ground = -30
|
||||
}
|
||||
--!@}
|
||||
|
||||
environment.register("open_waters", env_open_waters)
|
33
mods/mobf/environments/shallow_waters.lua
Normal file
@ -0,0 +1,33 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file shallow_waters.lua
|
||||
--! @brief shallow waters
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup environments
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @struct env_shallow_waters
|
||||
--! @brief shallow waters not deeper than 10 blocks
|
||||
env_shallow_waters = {
|
||||
media = {
|
||||
"default:water_source",
|
||||
"default:water_flowing"
|
||||
},
|
||||
surfaces = nil,
|
||||
--ground is first node above/below not beeing of media type
|
||||
max_height_above_ground = -1,
|
||||
min_height_above_ground = -10
|
||||
}
|
||||
--!@}
|
||||
|
||||
environment.register("shallow_waters", env_shallow_waters)
|
39
mods/mobf/environments/simple_air.lua
Normal file
@ -0,0 +1,39 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file simple_air.lua
|
||||
--! @brief a very basic environment definition
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup environments
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @struct env_simple_air
|
||||
--! @brief simple environment only checking for air
|
||||
env_simple_air = {
|
||||
media = {
|
||||
"air",
|
||||
}
|
||||
}
|
||||
|
||||
--!@}
|
||||
|
||||
table.foreach(mobf_env_placable_items,
|
||||
function(index)
|
||||
table.insert(env_simple_air.media,mobf_env_placable_items[index])
|
||||
end)
|
||||
|
||||
table.foreach(mobf_env_plants,
|
||||
function(index)
|
||||
table.insert(env_simple_air.media,mobf_env_plants[index])
|
||||
end)
|
||||
|
||||
environment.register("simple_air", env_simple_air)
|
878
mods/mobf/fighting.lua
Normal file
@ -0,0 +1,878 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file fighting.lua
|
||||
--! @brief component for fighting related features
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @defgroup fighting Combat subcomponent
|
||||
--! @brief Component handling all fighting
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
-- Contact: sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @class fighting
|
||||
|
||||
--! @brief factor added to mob melee combat range to get its maximum agression radius
|
||||
MOBF_AGRESSION_FACTOR = 5
|
||||
|
||||
--!@}
|
||||
|
||||
--! @brief fighting class reference
|
||||
fighting = {}
|
||||
|
||||
--! @brief user defined on death callback
|
||||
--! @memberof fighting
|
||||
fighting.on_death_callbacks = {}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: register_on_death_callback(callback)
|
||||
--
|
||||
--! @brief register an additional callback to be called on death of a mob
|
||||
--! @memberof fighting
|
||||
--
|
||||
--! @param callback function to call
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.register_on_death_callback(callback)
|
||||
|
||||
if type(callback) == "function" then
|
||||
|
||||
table.insert(fighting.on_death_callbacks,callback)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: do_on_death_callback(entity,hitter)
|
||||
--
|
||||
--! @brief call all registred on_death callbacks
|
||||
--! @memberof fighting
|
||||
--
|
||||
--! @param entity to do callback for
|
||||
--! @param hitter object doing last punch
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.do_on_death_callback(entity,hitter)
|
||||
|
||||
for i,v in ipairs(fighting.on_death_callbacks) do
|
||||
v(entity.data.name,entity.getbasepos(),hitter)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: push_back(entity,player)
|
||||
--
|
||||
--! @brief move a mob backward if it's punched
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mobbeing punched
|
||||
--! @param dir direction to push back
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.push_back(entity,dir)
|
||||
--get some base information
|
||||
local mob_pos = entity.object:getpos()
|
||||
local mob_basepos = entity.getbasepos(entity)
|
||||
local dir_rad = mobf_calc_yaw(dir.x,dir.z)
|
||||
local posdelta = mobf_calc_vector_components(dir_rad,0.5)
|
||||
|
||||
--push back mob
|
||||
local new_pos = {
|
||||
x=mob_basepos.x + posdelta.x,
|
||||
y=mob_basepos.y,
|
||||
z=mob_basepos.z + posdelta.z
|
||||
}
|
||||
|
||||
local pos_valid = environment.possible_pos(entity,new_pos)
|
||||
new_pos.y = mob_pos.y
|
||||
local line_of_sight = mobf_line_of_sight(mob_pos,new_pos)
|
||||
|
||||
dbg_mobf.fighting_lvl2("MOBF: trying to punch mob from " .. printpos(mob_pos)
|
||||
.. " to ".. printpos(new_pos))
|
||||
if pos_valid and line_of_sight then
|
||||
dbg_mobf.fighting_lvl2("MOBF: punching back ")
|
||||
entity.object:moveto(new_pos)
|
||||
else
|
||||
dbg_mobf.fighting_lvl2("MOBF: not punching mob: " .. dump(pos_valid) .. " " ..dump(line_of_sight))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: hit(entity,player)
|
||||
--
|
||||
--! @brief handler for mob beeing hit
|
||||
--! @memberof fighting
|
||||
--
|
||||
--! @param entity mob being hit
|
||||
--! @param player player/object hitting the mob
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.hit(entity,player)
|
||||
|
||||
if entity.data.generic.on_hit_callback ~= nil and
|
||||
entity.data.generic.on_hit_callback(entity,player) == true
|
||||
then
|
||||
dbg_mobf.fighting_lvl2("MOBF: ".. entity.data.name .. " custom on hit handler superseeds generic handling")
|
||||
return
|
||||
end
|
||||
|
||||
--TODO calculate damage by players weapon
|
||||
--local damage = 1
|
||||
|
||||
--dbg_mobf.fighting_lvl2("MOBF: ".. entity.data.name .. " about to take ".. damage .. " damage")
|
||||
--entity.dynamic_data.generic.health = entity.dynamic_data.generic.health - damage
|
||||
|
||||
--entity.object:set_hp(entity.object:get_hp() - damage )
|
||||
|
||||
|
||||
--get some base information
|
||||
local mob_pos = entity.object:getpos()
|
||||
local mob_basepos = entity.getbasepos(entity)
|
||||
local playerpos = player:getpos()
|
||||
local dir = mobf_get_direction(playerpos,mob_basepos)
|
||||
|
||||
--update mob orientation
|
||||
if entity.mode == "3d" then
|
||||
entity.object:setyaw(mobf_calc_yaw(dir.x,dir.z)+math.pi)
|
||||
else
|
||||
entity.object:setyaw(mobf_calc_yaw(dir.x,dir.z)-math.pi)
|
||||
end
|
||||
|
||||
if entity.data.sound ~= nil then
|
||||
sound.play(mob_pos,entity.data.sound.hit);
|
||||
end
|
||||
|
||||
fighting.push_back(entity,dir)
|
||||
|
||||
-- make it die
|
||||
if entity.object:get_hp() < 1 then
|
||||
--if entity.dynamic_data.generic.health < 1 then
|
||||
local result = entity.data.generic.kill_result
|
||||
if type(entity.data.generic.kill_result) == "function" then
|
||||
result = entity.data.generic.kill_result()
|
||||
end
|
||||
|
||||
|
||||
--call on kill callback and superseed normal on kill handling
|
||||
if entity.data.generic.on_kill_callback == nil or
|
||||
entity.data.generic.on_kill_callback(entity,player) == false
|
||||
then
|
||||
|
||||
if entity.data.sound ~= nil then
|
||||
sound.play(mob_pos,entity.data.sound.die);
|
||||
end
|
||||
|
||||
if player:is_player() then
|
||||
if type(result) == "table" then
|
||||
for i=1,#result, 1 do
|
||||
if player:get_inventory():room_for_item("main", result[i]) then
|
||||
player:get_inventory():add_item("main", result[i])
|
||||
end
|
||||
end
|
||||
else
|
||||
if player:get_inventory():room_for_item("main", result) then
|
||||
player:get_inventory():add_item("main", result)
|
||||
end
|
||||
end
|
||||
else
|
||||
--todo check if spawning a stack is possible
|
||||
minetest.env:add_item(mob_pos,result)
|
||||
end
|
||||
spawning.remove(entity, "killed")
|
||||
else
|
||||
dbg_mobf.fighting_lvl2("MOBF: ".. entity.data.name
|
||||
.. " custom on kill handler superseeds generic handling")
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
--dbg_mobf.fighting_lvl2("MOBF: attack chance is ".. entity.data.combat.angryness)
|
||||
-- fight back
|
||||
if entity.data.combat ~= nil and
|
||||
entity.data.combat.angryness > 0 then
|
||||
dbg_mobf.fighting_lvl2("MOBF: mob with chance of fighting back attacked")
|
||||
--either the mob hasn't been attacked by now or a new player joined fight
|
||||
|
||||
local playername = player.get_player_name(player)
|
||||
|
||||
if entity.dynamic_data.combat.target ~= playername then
|
||||
dbg_mobf.fighting_lvl2("MOBF: new player started fight")
|
||||
--calculate chance of mob fighting back
|
||||
if math.random() < entity.data.combat.angryness then
|
||||
dbg_mobf.fighting_lvl2("MOBF: fighting back player "..playername)
|
||||
entity.dynamic_data.combat.target = playername
|
||||
|
||||
fighting.switch_to_combat_state(entity,mobf_get_current_time(),player)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: switch_to_combat_state(entity,now,target)
|
||||
--
|
||||
--! @brief switch to combat state
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to switch state
|
||||
--! @param now current time in seconds
|
||||
--! @param target the target to attack
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.switch_to_combat_state(entity,now,target)
|
||||
local combat_state = mob_state.get_state_by_name(entity,"combat")
|
||||
|
||||
if target == nil then
|
||||
dbg_mobf.fighting_lvl2("MOBF: no target for combat state change specified")
|
||||
return
|
||||
end
|
||||
|
||||
if combat_state == nil then
|
||||
dbg_mobf.fighting_lvl2("MOBF: no special combat state")
|
||||
return
|
||||
end
|
||||
|
||||
dbg_mobf.fighting_lvl2("MOBF: switching to combat state")
|
||||
|
||||
--make sure state is locked
|
||||
mob_state.lock(entity,true)
|
||||
|
||||
--backup dynamic movement data
|
||||
local backup = entity.dynamic_data.movement
|
||||
backup.current_state = mob_state.get_state_by_name(entity,entity.dynamic_data.state.current)
|
||||
|
||||
--switch state
|
||||
local newentity = mob_state.change_state(entity,combat_state)
|
||||
|
||||
if newentity ~= nil then
|
||||
entity = newentity
|
||||
end
|
||||
|
||||
--save old movement data to use on switching back
|
||||
entity.dynamic_data.movement.backup = backup
|
||||
|
||||
--set target
|
||||
entity.dynamic_data.movement.target = target
|
||||
|
||||
--make sure a fighting mob ain't teleporting to target
|
||||
entity.dynamic_data.movement.teleportsupport = false
|
||||
|
||||
--make sure we do follow our target
|
||||
entity.dynamic_data.movement.guardspawnpoint = false
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: restore_previous_state(entity,now)
|
||||
--
|
||||
--! @brief restore default movement generator of mob
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to restore movement generator
|
||||
--! @param now current time in seconds
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.restore_previous_state(entity,now)
|
||||
|
||||
--check if ther is anything we can restore
|
||||
if entity.dynamic_data.movement.backup ~= nil then
|
||||
local backup = entity.dynamic_data.movement.backup
|
||||
|
||||
local newentity = nil
|
||||
if backup.current_state ~= nil then
|
||||
newentity = mob_state.change_state(entity,backup.current_state)
|
||||
else
|
||||
minetest.log(LOGLEVEL_WARNING,"MOBF: unable to restore previous state switching to default")
|
||||
newentity = mob_state.change_state(entity,mob_state.get_state_by_name(entity,"default"))
|
||||
end
|
||||
|
||||
|
||||
if newentity ~= nil then
|
||||
entity = newentity
|
||||
end
|
||||
|
||||
--restore old movement data
|
||||
entity.dynamic_data.movement = backup
|
||||
|
||||
--make sure all remaining data is deleted
|
||||
entity.dynamic_data.movement.backup = nil
|
||||
entity.dynamic_data.movement.current_state = nil
|
||||
end
|
||||
|
||||
--make sure state is unlocked
|
||||
mob_state.lock(entity,false)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: combat(entity,now)
|
||||
--
|
||||
--! @brief periodic callback called to do mobs own combat related actions
|
||||
--! @memberof fighting
|
||||
--
|
||||
--! @param entity mob to do action
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.combat(entity,now)
|
||||
|
||||
--handle self destruct mobs
|
||||
if fighting.self_destruct_handler(entity,now) then
|
||||
return
|
||||
end
|
||||
|
||||
if entity.dynamic_data.combat ~= nil and
|
||||
entity.dynamic_data.combat.target ~= "" then
|
||||
|
||||
dbg_mobf.fighting_lvl1("MOBF: attacking player: "..entity.dynamic_data.combat.target)
|
||||
|
||||
local player = minetest.env:get_player_by_name(entity.dynamic_data.combat.target)
|
||||
|
||||
|
||||
--check if target is still valid
|
||||
if player == nil then
|
||||
dbg_mobf.fighting_lvl3("MOBF: not a valid player")
|
||||
|
||||
-- switch back to default movement gen
|
||||
fighting.restore_previous_state(entity,now)
|
||||
|
||||
--there is no player by that name, stop attack
|
||||
entity.dynamic_data.combat.target = ""
|
||||
return
|
||||
end
|
||||
|
||||
--calculate some basic data
|
||||
local mob_pos = entity.object:getpos()
|
||||
local playerpos = player:getpos()
|
||||
local distance = mobf_calc_distance(mob_pos,playerpos)
|
||||
|
||||
fighting.self_destruct_trigger(entity,distance,now)
|
||||
|
||||
--find out if player is next to mob
|
||||
if distance > entity.data.combat.melee.range * MOBF_AGRESSION_FACTOR then
|
||||
dbg_mobf.fighting_lvl2("MOBF: " .. entity.data.name .. " player >"
|
||||
.. entity.dynamic_data.combat.target .. "< to far away "
|
||||
.. distance .. " > " .. (entity.data.combat.melee.range * MOBF_AGRESSION_FACTOR )
|
||||
.. " stopping attack")
|
||||
|
||||
--switch back to default movement gen
|
||||
fighting.restore_previous_state(entity,now)
|
||||
|
||||
--there is no player by that name, stop attack
|
||||
entity.dynamic_data.combat.target = ""
|
||||
return
|
||||
end
|
||||
|
||||
--is mob near enough for any attack attack?
|
||||
if (entity.data.combat.melee == nil or
|
||||
distance > entity.data.combat.melee.range) and
|
||||
(entity.data.combat.distance == nil or
|
||||
distance > entity.data.combat.distance.range) then
|
||||
|
||||
if entity.data.combat.melee ~= nil or
|
||||
entity.data.combat.distance ~= nil then
|
||||
dbg_mobf.fighting_lvl2("MOBF: distance="..distance)
|
||||
|
||||
|
||||
if entity.data.combat.melee ~= nil then
|
||||
dbg_mobf.fighting_lvl2("MOBF: melee="..entity.data.combat.melee.range)
|
||||
end
|
||||
if entity.data.combat.distance ~= nil then
|
||||
dbg_mobf.fighting_lvl2("MOBF: distance="..entity.data.combat.distance.range)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if fighting.melee_attack_handler(entity,player,now,distance) == false then
|
||||
|
||||
if fighting.distance_attack_handler(entity,playerpos,mob_pos,now,distance) then
|
||||
|
||||
-- mob did an attack so give chance to stop attack
|
||||
|
||||
local rand_value = math.random()
|
||||
|
||||
if rand_value > entity.data.combat.angryness then
|
||||
dbg_mobf.fighting_lvl2("MOBF: rand=".. rand_value
|
||||
.. " angryness=" .. entity.data.combat.angryness)
|
||||
dbg_mobf.fighting_lvl2("MOBF: " .. entity.data.name .. " "
|
||||
.. now .. " random aborting attack at player "
|
||||
..entity.dynamic_data.combat.target)
|
||||
entity.dynamic_data.combat.target = ""
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--fight against generic enemy "sun"
|
||||
fighting.sun_damage_handler(entity,now)
|
||||
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_target(entity)
|
||||
--
|
||||
--! @brief find and possible target next to mob
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to look around
|
||||
--! @return target
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.get_target(entity)
|
||||
|
||||
local possible_targets = {}
|
||||
|
||||
if entity.data.combat.melee.range > 0 then
|
||||
local objectlist = minetest.env:get_objects_inside_radius(entity.object:getpos(),
|
||||
entity.data.combat.melee.range*MOBF_AGRESSION_FACTOR)
|
||||
|
||||
local count = 0
|
||||
|
||||
for i,v in ipairs(objectlist) do
|
||||
|
||||
local playername = v.get_player_name(v)
|
||||
|
||||
if playername ~= nil and
|
||||
playername ~= "" then
|
||||
count = count + 1
|
||||
table.insert(possible_targets,v)
|
||||
dbg_mobf.fighting_lvl3(playername .. " is next to a mob of type "
|
||||
.. entity.data.name);
|
||||
end
|
||||
|
||||
end
|
||||
dbg_mobf.fighting_lvl3("Found ".. count .. " objects within attack range of "
|
||||
.. entity.data.name)
|
||||
end
|
||||
|
||||
|
||||
local targets_within_sight = {}
|
||||
|
||||
for i,v in ipairs(possible_targets) do
|
||||
|
||||
local entity_pos = entity.object:getpos()
|
||||
local target_pos = v:getpos()
|
||||
|
||||
--is there a line of sight between mob and possible target
|
||||
--line of sight is calculated 1block above ground
|
||||
if mobf_line_of_sight({x=entity_pos.x,y=entity_pos.y+1,z=entity_pos.z},
|
||||
{x=target_pos.x,y=target_pos.y+1,z=target_pos.z}) then
|
||||
|
||||
table.insert(targets_within_sight,v)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local nearest_target = nil
|
||||
local min_distance = -1
|
||||
|
||||
for i,v in ipairs(targets_within_sight) do
|
||||
|
||||
local distance = mobf_calc_distance(entity.object:getpos(),v:getpos())
|
||||
|
||||
if min_distance < 0 or
|
||||
distance < min_distance then
|
||||
|
||||
nearest_target = v
|
||||
min_distance = distance
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return nearest_target
|
||||
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: aggression(entity)
|
||||
--
|
||||
--! @brief start attack in case of agressive mob
|
||||
--! @memberof fighting
|
||||
--
|
||||
--! @param entity mob to do action
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.aggression(entity,now)
|
||||
|
||||
--if no combat data is specified don't do anything
|
||||
if entity.data.combat == nil then
|
||||
return
|
||||
end
|
||||
|
||||
--mob is specified as self attacking
|
||||
if entity.data.combat.starts_attack and
|
||||
(entity.dynamic_data.combat.target == nil or
|
||||
entity.dynamic_data.combat.target == "") then
|
||||
dbg_mobf.fighting_lvl3("MOBF: ".. entity.data.name .. " " .. now
|
||||
.. " aggressive mob, is it time to attack?")
|
||||
if entity.dynamic_data.combat.ts_last_aggression_chance + 1 < now then
|
||||
dbg_mobf.fighting_lvl3("MOBF: ".. entity.data.name .. " " .. now
|
||||
.. " lazzy time over try to find an enemy")
|
||||
entity.dynamic_data.combat.ts_last_aggression_chance = now
|
||||
|
||||
if math.random() < entity.data.combat.angryness then
|
||||
|
||||
dbg_mobf.fighting_lvl3("MOBF: ".. entity.data.name .. " " .. now
|
||||
.. " really is angry")
|
||||
local target = fighting.get_target(entity)
|
||||
|
||||
if target ~= nil then
|
||||
local targetname = target.get_player_name(target)
|
||||
|
||||
if targetname ~= entity.dynamic_data.combat.target then
|
||||
|
||||
entity.dynamic_data.combat.target = targetname
|
||||
|
||||
fighting.switch_to_combat_state(entity,now,target)
|
||||
|
||||
dbg_mobf.fighting_lvl2("MOBF: ".. entity.data.name .. " "
|
||||
.. now .. " starting attack at player: " ..targetname)
|
||||
minetest.log(LOGLEVEL_INFO,"MOBF: starting attack at player "..targetname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: fighting.init_dynamic_data(entity)
|
||||
--
|
||||
--! @brief initialize all dynamic data on activate
|
||||
--! @memberof fighting
|
||||
--
|
||||
--! @param entity mob to do action
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.init_dynamic_data(entity,now)
|
||||
local targetstring = ""
|
||||
local data = {
|
||||
ts_last_sun_damage = now,
|
||||
ts_last_attack = now,
|
||||
ts_last_aggression_chance = now,
|
||||
ts_self_destruct_triggered = -1,
|
||||
|
||||
target = targetstring,
|
||||
}
|
||||
|
||||
entity.dynamic_data.combat = data
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: self_destruct_trigger(entity,distance)
|
||||
--
|
||||
--! @brief handle self destruct features
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to do action
|
||||
--! @param distance current distance to target
|
||||
--! @param now current time
|
||||
--! @return true/false if handled or not
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.self_destruct_trigger(entity,distance,now)
|
||||
if entity.data.combat ~= nil and
|
||||
entity.data.combat.self_destruct ~= nil then
|
||||
|
||||
dbg_mobf.fighting_lvl1("MOBF: checking for self destruct trigger " ..
|
||||
distance .. " " ..
|
||||
entity.dynamic_data.combat.ts_self_destruct_triggered ..
|
||||
" " .. now)
|
||||
|
||||
--trigger self destruct
|
||||
if distance <= entity.data.combat.self_destruct.range and
|
||||
entity.dynamic_data.combat.ts_self_destruct_triggered == -1 then
|
||||
dbg_mobf.fighting_lvl2("MOBF: self destruct triggered")
|
||||
entity.dynamic_data.combat.ts_self_destruct_triggered = now
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: self_destruct_handler(entity)
|
||||
--
|
||||
--! @brief handle self destruct features
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to do action
|
||||
--! @param now current time
|
||||
--! @return true/false if handled or not
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.self_destruct_handler(entity,now)
|
||||
--self destructing mob?
|
||||
if entity.data.combat ~= nil and
|
||||
entity.data.combat.self_destruct ~= nil then
|
||||
|
||||
|
||||
|
||||
local pos = entity.object:getpos()
|
||||
|
||||
dbg_mobf.fighting_lvl1("MOBF: checking for self destruct imminent")
|
||||
--do self destruct
|
||||
if entity.dynamic_data.combat.ts_self_destruct_triggered > 0 and
|
||||
entity.dynamic_data.combat.ts_self_destruct_triggered +
|
||||
entity.data.combat.self_destruct.delay
|
||||
<= now then
|
||||
|
||||
dbg_mobf.fighting_lvl2("MOBF: executing self destruct")
|
||||
|
||||
if entity.data.sound ~= nil then
|
||||
sound.play(pos,entity.data.sound.self_destruct);
|
||||
end
|
||||
|
||||
mobf_do_area_damage(pos,nil,
|
||||
entity.data.combat.self_destruct.damage,
|
||||
entity.data.combat.self_destruct.range)
|
||||
|
||||
--TODO determine block removal by damage and remove blocks
|
||||
mobf_do_node_damage(pos,{},
|
||||
entity.data.combat.self_destruct.node_damage_range,
|
||||
1 - 1/entity.data.combat.self_destruct.node_damage_range)
|
||||
|
||||
if mobf_rtd.fire_enabled then
|
||||
--Add fire
|
||||
for i=pos.x-entity.data.combat.self_destruct.range/2,
|
||||
pos.x+entity.data.combat.self_destruct.range/2, 1 do
|
||||
for j=pos.y-entity.data.combat.self_destruct.range/2,
|
||||
pos.y+entity.data.combat.self_destruct.range/2, 1 do
|
||||
for k=pos.z-entity.data.combat.self_destruct.range/2,
|
||||
pos.z+entity.data.combat.self_destruct.range/2, 1 do
|
||||
|
||||
local current = minetest.env:get_node({x=i,y=j,z=k})
|
||||
|
||||
if (current.name == "air") then
|
||||
minetest.env:set_node({x=i,y=j,z=k}, {name="fire:basic_flame"})
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
minetest.log(LOGLEVEL_NOTICE,"MOBF: self destruct without fire isn't really impressive!")
|
||||
end
|
||||
spawning.remove(entity, "self destruct")
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: melee_attack_handler(entity,now)
|
||||
--
|
||||
--! @brief handle melee attack
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to do action
|
||||
--! @param player player to attack
|
||||
--! @param now current time
|
||||
--! @param distance distance to player
|
||||
--! @return true/false if handled or not
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.melee_attack_handler(entity,player,now,distance)
|
||||
|
||||
if entity.data.combat.melee == nil then
|
||||
dbg_mobf.fighting_lvl2("MOBF: no meele attack specified")
|
||||
return false
|
||||
end
|
||||
|
||||
local time_of_next_attack_chance = entity.dynamic_data.combat.ts_last_attack
|
||||
+ entity.data.combat.melee.speed
|
||||
--check if mob is ready to attack
|
||||
if now < time_of_next_attack_chance then
|
||||
dbg_mobf.fighting_lvl1("MOBF: to early for meele attack " ..
|
||||
now .. " >= " .. time_of_next_attack_chance)
|
||||
return false
|
||||
end
|
||||
|
||||
if distance <= entity.data.combat.melee.range
|
||||
then
|
||||
|
||||
--save time of attack
|
||||
entity.dynamic_data.combat.ts_last_attack = now
|
||||
|
||||
if entity.data.sound ~= nil then
|
||||
sound.play(entity.object:getpos(),entity.data.sound.melee);
|
||||
end
|
||||
|
||||
--calculate damage to be done
|
||||
local damage_done = math.floor(math.random(0,entity.data.combat.melee.maxdamage)) + 1
|
||||
|
||||
local player_health = player:get_hp()
|
||||
|
||||
--do damage
|
||||
player:set_hp(player_health -damage_done)
|
||||
|
||||
dbg_mobf.fighting_lvl2("MOBF: ".. entity.data.name ..
|
||||
" doing melee attack damage=" .. damage_done)
|
||||
return true
|
||||
end
|
||||
dbg_mobf.fighting_lvl1("MOBF: not within meele range " ..
|
||||
distance .. " > " .. entity.data.combat.melee.range)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: distance_attack_handler(entity,now)
|
||||
--
|
||||
--! @brief handle distance attack
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to do action
|
||||
--! @param playerpos position of target
|
||||
--! @param mob_pos position of mob
|
||||
--! @param now current time
|
||||
--! @param distance distance between target and player
|
||||
--! @return true/false if handled or not
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.distance_attack_handler(entity,playerpos,mob_pos,now,distance)
|
||||
if entity.data.combat.distance == nil then
|
||||
dbg_mobf.fighting_lvl2("MOBF: no distance attack specified")
|
||||
return false
|
||||
end
|
||||
|
||||
local time_of_next_attack_chance = entity.dynamic_data.combat.ts_last_attack
|
||||
+ entity.data.combat.distance.speed
|
||||
|
||||
--check if mob is ready to attack
|
||||
if now < time_of_next_attack_chance then
|
||||
dbg_mobf.fighting_lvl1("MOBF: to early for distance attack " ..
|
||||
now .. " >= " .. time_of_next_attack_chance)
|
||||
return false
|
||||
end
|
||||
|
||||
if distance <= entity.data.combat.distance.range
|
||||
then
|
||||
|
||||
dbg_mobf.fighting_lvl2("MOBF: ".. entity.data.name .. " doing distance attack")
|
||||
|
||||
--save time of attack
|
||||
entity.dynamic_data.combat.ts_last_attack = now
|
||||
|
||||
local dir = mobf_get_direction({ x=mob_pos.x,
|
||||
y=mob_pos.y+1,
|
||||
z=mob_pos.z
|
||||
},
|
||||
playerpos)
|
||||
|
||||
if entity.data.sound ~= nil then
|
||||
sound.play(mob_pos,entity.data.sound.distance);
|
||||
end
|
||||
|
||||
local newobject=minetest.env:add_entity({ x=mob_pos.x+dir.x,
|
||||
y=mob_pos.y+dir.y+1,
|
||||
z=mob_pos.z+dir.z
|
||||
},
|
||||
entity.data.combat.distance.attack
|
||||
)
|
||||
|
||||
local thrown_entity = mobf_find_entity(newobject)
|
||||
|
||||
--TODO add random disturbance based on accuracy
|
||||
|
||||
if thrown_entity ~= nil then
|
||||
local vel_trown = {
|
||||
x=dir.x*thrown_entity.velocity,
|
||||
y=dir.y*thrown_entity.velocity + math.random(0,0.25),
|
||||
z=dir.z*thrown_entity.velocity
|
||||
}
|
||||
|
||||
dbg_mobf.fighting_lvl2("MOBF: throwing with velocity: " .. printpos(vel_trown))
|
||||
|
||||
newobject:setvelocity(vel_trown)
|
||||
|
||||
newobject:setacceleration({x=0, y=-thrown_entity.gravity, z=0})
|
||||
thrown_entity.owner = entity.object
|
||||
|
||||
dbg_mobf.fighting_lvl2("MOBF: distance attack issued")
|
||||
else
|
||||
minetest.log(LOGLEVEL_ERROR, "MOBF: unable to find entity for distance attack")
|
||||
end
|
||||
return true
|
||||
end
|
||||
dbg_mobf.fighting_lvl1("MOBF: not within distance range " ..
|
||||
distance .. " > " .. entity.data.combat.distance.range)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: sun_damage_handler(entity,now)
|
||||
--
|
||||
--! @brief handle damage done by sun
|
||||
--! @memberof fighting
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to do action
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function fighting.sun_damage_handler(entity,now)
|
||||
if entity.data.combat ~= nil and
|
||||
entity.data.combat.sun_sensitive then
|
||||
|
||||
local pos = entity.object:getpos()
|
||||
local current_state = mob_state.get_state_by_name(entity,entity.dynamic_data.state.current)
|
||||
local current_light = minetest.env:get_node_light(pos)
|
||||
|
||||
if current_light == nil then
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF: Bug!!! didn't get a light value for "
|
||||
.. printpos(pos))
|
||||
return
|
||||
end
|
||||
--check if mob is in sunlight
|
||||
if ( current_light > LIGHT_MAX) then
|
||||
dbg_mobf.fighting_lvl1("MOBF: " .. entity.data.name ..
|
||||
" health at start:" .. entity.object:get_hp())
|
||||
|
||||
if current_state.animation ~= nil and
|
||||
entity.data.animation ~= nil and
|
||||
entity.data.animation[current_state.animation .. "__burning"] ~= nil then
|
||||
graphics.set_animation(entity,current_state.animation .. "burning")
|
||||
else
|
||||
graphics.set_animation(entity,"burning")
|
||||
end
|
||||
|
||||
|
||||
if entity.dynamic_data.combat.ts_last_sun_damage +1 < now then
|
||||
local damage = (1 + math.floor(entity.data.generic.base_health/15))
|
||||
dbg_mobf.fighting_lvl1("Mob ".. entity.data.name .. " takes "
|
||||
..damage .." damage because of sun")
|
||||
|
||||
entity.object:set_hp(entity.object:get_hp() - damage)
|
||||
|
||||
if entity.data.sound ~= nil then
|
||||
sound.play(mob_pos,entity.data.sound.sun_damage);
|
||||
end
|
||||
|
||||
if entity.object:get_hp() <= 0 then
|
||||
--if entity.dynamic_data.generic.health <= 0 then
|
||||
dbg_mobf.fighting_lvl2("Mob ".. entity.data.name .. " died of sun")
|
||||
spawning.remove(entity,"died by sun")
|
||||
return
|
||||
end
|
||||
entity.dynamic_data.combat.ts_last_sun_damage = now
|
||||
end
|
||||
else
|
||||
--use last sun damage to avoid setting animation over and over even if nothing changed
|
||||
if entity.dynamic_data.combat.ts_last_sun_damage ~= -1 and
|
||||
current_state.animation ~= nil then
|
||||
graphics.set_animation(entity,current_state.animation)
|
||||
entity.dynamic_data.combat.ts_last_sun_damage = -1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
908
mods/mobf/generic_functions.lua
Normal file
@ -0,0 +1,908 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file generic_functions.lua
|
||||
--! @brief generic functions used in many different places
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--!
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @defgroup gen_func Generic functions
|
||||
--! @brief functions for various tasks
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
|
||||
if minetest.setting_getbool("mobf_enable_socket_trace") then
|
||||
require "socket"
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_bug_warning()
|
||||
--
|
||||
--! @brief make bug warnings configurable
|
||||
--
|
||||
--! @param level bug severity level to use for minetest.log
|
||||
--! @param text data to print to log
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_bug_warning(level,text)
|
||||
if minetest.setting_getbool("mobf_log_bug_warnings") then
|
||||
minetest.log(level,text)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_get_time_ms()
|
||||
--
|
||||
--! @brief get current time in ms
|
||||
--
|
||||
--! @return current time in ms
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_get_time_ms()
|
||||
if minetest.setting_getbool("mobf_enable_socket_trace") then
|
||||
return socket.gettime()*1000
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_contains(cur_table,element)
|
||||
--
|
||||
--! @brief check if element is in table
|
||||
--
|
||||
--! @param cur_table table to look in
|
||||
--! @param element element to look for
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_contains(cur_table,element)
|
||||
|
||||
if cur_table == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
for i,v in ipairs(cur_table) do
|
||||
if v == element then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: MIN(a,b)
|
||||
--
|
||||
--! @brief minimum of two numbers
|
||||
--
|
||||
--! @param a number 1
|
||||
--! @param b number 2
|
||||
--! @return minimum
|
||||
-------------------------------------------------------------------------------
|
||||
function MIN(a,b)
|
||||
if a > b then
|
||||
return b
|
||||
else
|
||||
return a
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: MAX(a,b)
|
||||
--
|
||||
--! @brief maximum of two numbers
|
||||
--
|
||||
--! @param a number 1
|
||||
--! @param b number 2
|
||||
--! @return maximum
|
||||
-------------------------------------------------------------------------------
|
||||
function MAX(a,b)
|
||||
if a > b then
|
||||
return a
|
||||
else
|
||||
return b
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_is_walkable(node)
|
||||
--
|
||||
--! @brief check if walkable flag is set for a node
|
||||
--
|
||||
--! @param node to check
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_is_walkable(node)
|
||||
return (node and node.name and minetest.registered_nodes[node.name] and
|
||||
minetest.registered_nodes[node.name].walkable == false)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: printpos(pos)
|
||||
--
|
||||
--! @brief convert pos to string of type "(X,Y,Z)"
|
||||
--
|
||||
--! @param pos position to convert
|
||||
--! @return string with coordinates of pos
|
||||
-------------------------------------------------------------------------------
|
||||
function printpos(pos)
|
||||
if pos ~= nil then
|
||||
if pos.y ~= nil then
|
||||
return "("..pos.x..","..pos.y..","..pos.z..")"
|
||||
else
|
||||
return "("..pos.x..", ? ,"..pos.z..")"
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_get_current_time()
|
||||
--
|
||||
--! @brief alias to get current time
|
||||
--
|
||||
--! @return current time in seconds
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_get_current_time()
|
||||
return os.time(os.date('*t'))
|
||||
--return minetest.get_time()
|
||||
end
|
||||
|
||||
callback_statistics = {}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_warn_long_fct(starttime,fctname,facility)
|
||||
--
|
||||
--! @brief alias to get current time
|
||||
--
|
||||
--! @param starttime time fct started
|
||||
--! @param fctname name of function
|
||||
--! @param facility name of facility to add time to
|
||||
--
|
||||
--! @return current time in seconds
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_warn_long_fct(starttime,fctname,facility)
|
||||
local currenttime = mobf_get_time_ms()
|
||||
local delta = currenttime - starttime
|
||||
|
||||
if minetest.setting_getbool("mobf_enable_socket_trace_statistics") then
|
||||
if facility == nil then
|
||||
facility = "generic"
|
||||
end
|
||||
|
||||
if callback_statistics[facility] == nil then
|
||||
callback_statistics[facility] = {
|
||||
upto_005ms = 0,
|
||||
upto_010ms = 0,
|
||||
upto_020ms = 0,
|
||||
upto_050ms = 0,
|
||||
upto_100ms = 0,
|
||||
upto_200ms = 0,
|
||||
more = 0,
|
||||
valcount = 0,
|
||||
sum = 0,
|
||||
last_time = 0,
|
||||
}
|
||||
end
|
||||
|
||||
callback_statistics[facility].valcount = callback_statistics[facility].valcount +1
|
||||
callback_statistics[facility].sum = callback_statistics[facility].sum + delta
|
||||
|
||||
if callback_statistics[facility].valcount == 1000 then
|
||||
callback_statistics[facility].valcount = 0
|
||||
local deltatime = currenttime - callback_statistics[facility].last_time
|
||||
callback_statistics[facility].last_time = currenttime
|
||||
|
||||
minetest.log(LOGLEVEL_ERROR,"Statistics for: " .. facility .. ": " ..
|
||||
callback_statistics[facility].upto_005ms .. "," ..
|
||||
callback_statistics[facility].upto_010ms .. "," ..
|
||||
callback_statistics[facility].upto_020ms .. "," ..
|
||||
callback_statistics[facility].upto_050ms .. "," ..
|
||||
callback_statistics[facility].upto_100ms .. "," ..
|
||||
callback_statistics[facility].upto_200ms .. "," ..
|
||||
callback_statistics[facility].more ..
|
||||
" (".. callback_statistics[facility].sum .. " / " .. deltatime .. ") " ..
|
||||
tostring(math.floor((callback_statistics[facility].sum/deltatime) * 100)) .. "%")
|
||||
|
||||
callback_statistics[facility].sum = 0
|
||||
end
|
||||
|
||||
if delta < 5 then
|
||||
callback_statistics[facility].upto_005ms = callback_statistics[facility].upto_005ms +1
|
||||
return
|
||||
end
|
||||
if delta < 10 then
|
||||
callback_statistics[facility].upto_010ms = callback_statistics[facility].upto_010ms +1
|
||||
return
|
||||
end
|
||||
if delta < 20 then
|
||||
callback_statistics[facility].upto_020ms = callback_statistics[facility].upto_020ms +1
|
||||
return
|
||||
end
|
||||
if delta < 50 then
|
||||
callback_statistics[facility].upto_050ms = callback_statistics[facility].upto_050ms +1
|
||||
return
|
||||
end
|
||||
if delta < 100 then
|
||||
callback_statistics[facility].upto_100ms = callback_statistics[facility].upto_100ms +1
|
||||
return
|
||||
end
|
||||
|
||||
if delta < 200 then
|
||||
callback_statistics[facility].upto_200ms = callback_statistics[facility].upto_200ms +1
|
||||
return
|
||||
end
|
||||
|
||||
callback_statistics[facility].more = callback_statistics[facility].more +1
|
||||
end
|
||||
|
||||
if delta >200 then
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF: function " .. fctname .. " took too long: " .. delta .. " ms")
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_round_pos(pos)
|
||||
--
|
||||
--! @brief calculate integer position
|
||||
--
|
||||
--! @param pos position to be rounded
|
||||
--! @return rounded position
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_round_pos(pos)
|
||||
if pos == nil then
|
||||
return pos
|
||||
end
|
||||
|
||||
return { x=math.floor(pos.x + 0.5),
|
||||
y=math.floor(pos.y + 0.5),
|
||||
z=math.floor(pos.z + 0.5)
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_calc_distance(pos1,pos2)
|
||||
--
|
||||
--! @brief calculate 3d distance between to points
|
||||
--
|
||||
--! @param pos1 first position
|
||||
--! @param pos2 second position
|
||||
--! @retval scalar value, distance
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_calc_distance(pos1,pos2)
|
||||
return math.sqrt( math.pow(pos1.x-pos2.x,2) +
|
||||
math.pow(pos1.y-pos2.y,2) +
|
||||
math.pow(pos1.z-pos2.z,2))
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_calc_distance_2d(pos1,pos2)
|
||||
--
|
||||
--! @brief calculate 2d distance between to points
|
||||
--
|
||||
--! @param pos1 first position
|
||||
--! @param pos2 second position
|
||||
--! @return scalar value, distance
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_calc_distance_2d(pos1,pos2)
|
||||
return math.sqrt( math.pow(pos1.x-pos2.x,2) +
|
||||
math.pow(pos1.z-pos2.z,2))
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_find_entity(newobject) DEPRECATED
|
||||
--
|
||||
--! @brief find entity by object reference
|
||||
--
|
||||
--! @param newobject r object reference
|
||||
--! @return entity object reference points at or nil on error
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_find_entity(newobject)
|
||||
return newobject:get_luaentity()
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_max_light_around(pos,range,daytime)
|
||||
--
|
||||
--! @brief get maximum light level around specified position
|
||||
--
|
||||
--! @param pos center of area to search
|
||||
--! @param distance radius of area
|
||||
--! @param daytime time of day to check
|
||||
--! @return highest detected light level
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_max_light_around(pos,distance,daytime)
|
||||
|
||||
local max_light = 0
|
||||
|
||||
for y_run=pos.y-distance,pos.y+distance,1 do
|
||||
for z_run=pos.z-distance,pos.z+distance,1 do
|
||||
for x_run=pos.x-distance,pos.x+distance,1 do
|
||||
local current_pos = {x=x_run,y=y_run,z=z_run }
|
||||
local node = minetest.env:get_node(current_pos)
|
||||
|
||||
if node.name == "air" then
|
||||
local current_light = minetest.env:get_node_light(current_pos,daytime)
|
||||
|
||||
if current_light > max_light then
|
||||
max_light = current_light
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return max_light
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_mob_around(mob_name,mob_transform_name,pos,range,)
|
||||
--
|
||||
--! @brief get number of mobs of specified type within range of pos
|
||||
--
|
||||
--! @param mob_name basic name of mob
|
||||
--! @param mob_transform secondary name of mob
|
||||
--! @param pos position to check
|
||||
--! @param range range to check
|
||||
--! @param ignore_playerspawned ignore mob spawned by players for check
|
||||
--! @return number of mob found
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_mob_around(mob_name,mob_transform,pos,range,ignore_playerspawned)
|
||||
local count = 0
|
||||
local objectcount = 0
|
||||
|
||||
local objectlist = minetest.env:get_objects_inside_radius(pos,range)
|
||||
|
||||
if mob_transform == nil then
|
||||
mob_transform = ""
|
||||
end
|
||||
|
||||
for index,value in pairs(objectlist) do
|
||||
|
||||
local entity = mobf_find_entity(value)
|
||||
|
||||
dbg_mobf.generic_lvl1("MOBF: entity at "..printpos(pos)..
|
||||
" looking for: "..mob_name ..
|
||||
" or " .. mob_transform )
|
||||
|
||||
--any mob is required to have a name so we may use this to decide
|
||||
--if an entity is an mob or not
|
||||
if entity ~= nil and
|
||||
entity.data ~= nil and
|
||||
entity.dynamic_data ~= nil and
|
||||
entity.dynamic_data.spawning ~= nil then
|
||||
|
||||
if entity.removed == false then
|
||||
|
||||
if entity.data.modname..":"..entity.data.name == mob_name or
|
||||
entity.data.modname..":"..entity.data.name == mob_transform then
|
||||
if (ignore_playerspawned and entity.dynamic_data.spawning.player_spawned) or
|
||||
ignore_playerspawned ~= false then
|
||||
dbg_mobf.generic_lvl1("MOBF: Found "..mob_name.. " or "
|
||||
..mob_transform .. " within specified range of "..range)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
objectcount = objectcount +1
|
||||
end
|
||||
|
||||
dbg_mobf.generic_lvl2("MOBF: found " .. objectcount .. " within range "
|
||||
.. count .. " of them are relevant mobs ")
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_spawner_around(mob_name,pos,range)
|
||||
--
|
||||
--! @brief get number of mobs of specified type within range of pos
|
||||
--
|
||||
--! @param mob_name basic name of mob
|
||||
--! @param pos position to check
|
||||
--! @param range range to check
|
||||
--! @return number of mob found
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_spawner_around(mob_name,pos,range)
|
||||
dbg_mobf.generic_lvl2("MOBF: mobf_spawner_around param: ".. dump(mob_name)
|
||||
.. " "..dump(pos).. " " .. dump(range))
|
||||
|
||||
local count = 0
|
||||
local objectcount = 0
|
||||
|
||||
local objectlist = minetest.env:get_objects_inside_radius(pos,range)
|
||||
|
||||
for index,value in pairs(objectlist) do
|
||||
|
||||
local entity = value:get_luaentity()
|
||||
|
||||
dbg_mobf.generic_lvl3("MOBF: entity at: "..dump(value:getpos())..
|
||||
" looking for: "..mob_name .. " " ..
|
||||
dump(value) .. " " ..
|
||||
dump(entity))
|
||||
|
||||
--any mob is required to have a name so we may use this to decide
|
||||
--if an entity is an mob or not
|
||||
if entity ~= nil and
|
||||
entity.spawner_mob_name ~= nil then
|
||||
|
||||
if entity.spawner_mob_name == mob_name then
|
||||
dbg_mobf.generic_lvl2("MOBF: Found "..mob_name
|
||||
.. " within specified range of "..range)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
objectcount = objectcount +1
|
||||
end
|
||||
|
||||
dbg_mobf.generic_lvl2("MOBF: found " .. objectcount .. " within range "
|
||||
.. count .. " of them are relevant spawners ")
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_line_of_sightX(pos1,pos2)
|
||||
--
|
||||
--! @brief is there a line of sight between two specified positions
|
||||
-- TODO add code to minetest to get this working!
|
||||
--
|
||||
--! @param pos1 start position of los check
|
||||
--! @param pos2 end position of los check
|
||||
--! @return: true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_line_of_sightX(pos1,pos2)
|
||||
return minetest.env:get_line_of_sight(pos1,pos2)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_line_of_sight(pos1,pos2)
|
||||
--
|
||||
--! @brief is there a line of sight between two specified positions
|
||||
--
|
||||
--! @param pos1 start position of los check
|
||||
--! @param pos2 end position of los check
|
||||
--! @return: true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_line_of_sight(pos1,pos2)
|
||||
|
||||
--print("Checking line of sight between "..printpos(pos1).." and "..printpos(pos2))
|
||||
local distance = mobf_calc_distance(pos1,pos2)
|
||||
|
||||
local normalized_vector = { x=(pos2.x-pos1.x)/distance,
|
||||
y=(pos2.y-pos1.y)/distance,
|
||||
z=(pos2.z-pos1.z)/distance}
|
||||
|
||||
|
||||
local line_of_sight = true
|
||||
|
||||
for i=1,distance, 1 do
|
||||
local tocheck = { x=pos1.x + (normalized_vector.x * i),
|
||||
y=pos1.y + (normalized_vector.y *i),
|
||||
z=pos1.z + (normalized_vector.z *i)}
|
||||
|
||||
local node = minetest.env:get_node(tocheck)
|
||||
|
||||
|
||||
if minetest.registered_nodes[node.name].sunlight_propagates ~= true then
|
||||
line_of_sight = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return line_of_sight
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_get_direction(pos1,pos2)
|
||||
--
|
||||
--! @brief get normalized direction from pos1 to pos2
|
||||
--
|
||||
--! @param pos1 source point
|
||||
--! @param pos2 destination point
|
||||
--! @return xyz direction
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_get_direction(pos1,pos2)
|
||||
|
||||
local x_raw = pos2.x -pos1.x
|
||||
local y_raw = pos2.y -pos1.y
|
||||
local z_raw = pos2.z -pos1.z
|
||||
|
||||
|
||||
local x_abs = math.abs(x_raw)
|
||||
local y_abs = math.abs(y_raw)
|
||||
local z_abs = math.abs(z_raw)
|
||||
|
||||
if x_abs >= y_abs and
|
||||
x_abs >= z_abs then
|
||||
|
||||
y_raw = y_raw * (1/x_abs)
|
||||
z_raw = z_raw * (1/x_abs)
|
||||
|
||||
x_raw = x_raw/x_abs
|
||||
|
||||
end
|
||||
|
||||
if y_abs >= x_abs and
|
||||
y_abs >= z_abs then
|
||||
|
||||
|
||||
x_raw = x_raw * (1/y_abs)
|
||||
z_raw = z_raw * (1/y_abs)
|
||||
|
||||
y_raw = y_raw/y_abs
|
||||
|
||||
end
|
||||
|
||||
if z_abs >= y_abs and
|
||||
z_abs >= x_abs then
|
||||
|
||||
x_raw = x_raw * (1/z_abs)
|
||||
y_raw = y_raw * (1/z_abs)
|
||||
|
||||
z_raw = z_raw/z_abs
|
||||
|
||||
end
|
||||
|
||||
return {x=x_raw,y=y_raw,z=z_raw}
|
||||
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_pos_is_zero(pos)
|
||||
--
|
||||
--! @brief check if position is (0,0,0)
|
||||
--
|
||||
--! @param pos position to check
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function mobf_pos_is_zero(pos)
|
||||
|
||||
if pos.x ~= 0 then return false end
|
||||
if pos.y ~= 0 then return false end
|
||||
if pos.z ~= 0 then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_air_above(pos,height)
|
||||
--
|
||||
--! @brief check if theres at least height air abov pos
|
||||
--
|
||||
--! @param pos position to check
|
||||
--! @param height min number of air to check
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_air_above(pos,height)
|
||||
|
||||
for i=0, height, 1 do
|
||||
local pos_above = {
|
||||
x = pos.x,
|
||||
y = pos.y + 1,
|
||||
z = pos.z
|
||||
}
|
||||
local node_above = minetest.env:get_node(pos_above)
|
||||
|
||||
if node_above.name ~= "air" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_ground_distance(pos,media)
|
||||
--
|
||||
--! @brief get number of blocks above solid ground
|
||||
--
|
||||
--! @param pos position to check
|
||||
--! @param media table of blocks not considered to be ground
|
||||
--! @return number of blocks to ground
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_ground_distance(pos,media)
|
||||
|
||||
local node_to_check = minetest.env:get_node(pos)
|
||||
|
||||
local count = 0
|
||||
|
||||
while node_to_check ~= nil and mobf_contains(media,node_to_check.name) and
|
||||
count < 32 do
|
||||
|
||||
count = count +1
|
||||
pos = {x=pos.x,y=pos.y-1,z=pos.z};
|
||||
node_to_check = minetest.env:get_node(pos)
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_surface_distance(pos)
|
||||
--
|
||||
--! @brief get number of blocks above surface (solid or fluid!)
|
||||
--
|
||||
--! @param pos position to check
|
||||
--! @return number of blocks to ground
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_surface_distance(pos)
|
||||
|
||||
local node_to_check = minetest.env:get_node(pos)
|
||||
|
||||
local count = 0
|
||||
|
||||
while node_to_check ~= nil and
|
||||
node_to_check.name == "air" and
|
||||
count < 32 do
|
||||
|
||||
count = count +1
|
||||
|
||||
pos = {x=pos.x,y=pos.y-1,z=pos.z};
|
||||
node_to_check = minetest.env:get_node(pos)
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_air_distance(pos)
|
||||
--
|
||||
--! @brief get number of blocks below waterline
|
||||
--
|
||||
--! @param pos position to check
|
||||
--! @return number of blocks to air
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_air_distance(pos)
|
||||
|
||||
local node_to_check = minetest.env:get_node(pos)
|
||||
|
||||
local count = 0
|
||||
|
||||
while node_to_check ~= nil and (
|
||||
node_to_check.name == "default:water_source" or
|
||||
node_to_check.name == "default:water_flowing") do
|
||||
|
||||
count = count +1
|
||||
pos = {x=pos.x,y=pos.y+1,z=pos.z};
|
||||
node_to_check = minetest.env:get_node(pos)
|
||||
end
|
||||
|
||||
if node_to_check.name == "air" then
|
||||
return count
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_above_water(pos)
|
||||
--
|
||||
--! @brief check if next non-air block below mob is a water block
|
||||
--
|
||||
--! @param pos position to check
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_above_water(pos)
|
||||
|
||||
local node_to_check = minetest.env:get_node(pos)
|
||||
|
||||
while node_to_check ~= nil and
|
||||
node_to_check.name == "air" do
|
||||
|
||||
pos = {x=pos.x,y=pos.y-1,z=pos.z};
|
||||
node_to_check = minetest.env:get_node(pos)
|
||||
end
|
||||
|
||||
if node_to_check.name == "default:water_source" or
|
||||
node_to_check.name == "default:water_flowing" then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_surface(x,z, min_y, max_y)
|
||||
--
|
||||
--! @brief get surface for x/z coordinates
|
||||
--
|
||||
--! @param x x-coordinate
|
||||
--! @param z z-coordinate
|
||||
--! @param min_y minimum y-coordinate to consider
|
||||
--! @param max_y maximum y-coordinate to consider
|
||||
--! @return y value of surface or nil
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_get_sunlight_surface(x,z, min_y, max_y)
|
||||
|
||||
for runy = min_y, max_y,1 do
|
||||
local pos = { x=x,y=runy, z=z }
|
||||
local node_to_check = minetest.env:get_node(pos)
|
||||
|
||||
if node_to_check.name == "default:dirt_with_grass" then
|
||||
return pos.y
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_surface(x,z, min_y, max_y)
|
||||
--
|
||||
--! @brief get surface for x/z coordinates
|
||||
--
|
||||
--! @param x x-coordinate
|
||||
--! @param z z-coordinate
|
||||
--! @param min_y minimum y-coordinate to consider
|
||||
--! @param max_y maximum y-coordinate to consider
|
||||
--! @return y value of surface or nil
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_get_surface(x,z, min_y, max_y)
|
||||
|
||||
local last_node = minetest.env:get_node({ x=x,y=min_y, z=z })
|
||||
|
||||
for runy = min_y+1, max_y,1 do
|
||||
local pos = { x=x,y=runy, z=z }
|
||||
local node_to_check = minetest.env:get_node(pos)
|
||||
|
||||
if node_to_check.name == "air" and
|
||||
last_node.name ~= "air" and
|
||||
last_node.mame ~= "ignore" then
|
||||
return pos.y
|
||||
end
|
||||
last_node = node_to_check
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: entity_at_loaded_pos(entity)
|
||||
--
|
||||
--! @brief check if entity is activated at already loaded pos
|
||||
--
|
||||
--! @param pos to check
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function entity_at_loaded_pos(pos)
|
||||
|
||||
local current_node = minetest.env:get_node(pos)
|
||||
|
||||
if current_node ~= nil then
|
||||
if current_node.name == "ignore" then
|
||||
minetest.log(LOGLEVEL_WARNING,"MOBF: spawned at unloaded pos! : "
|
||||
.. dump(pos))
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
minetest.log(LOGLEVEL_WARNING,"MOBF: spawned at invalid pos!")
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_random_direction()
|
||||
--
|
||||
--! @brief get a random (blocked) 3d direction
|
||||
--
|
||||
--! @return 3d dir value
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_random_direction()
|
||||
|
||||
local retval = {}
|
||||
|
||||
retval.x=math.random(-1,1)
|
||||
retval.y=math.random(-1,1)
|
||||
retval.z=math.random(-1,1)
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_calc_yaw(x,z)
|
||||
--
|
||||
--! @brief calculate radians value of a 2 dimendional vector
|
||||
--
|
||||
--! @param x vector component 1
|
||||
--! @param z vector component 2
|
||||
--
|
||||
--! @return radians value
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_calc_yaw(x,z)
|
||||
local direction = math.atan2(z,x)
|
||||
|
||||
while direction < 0 do
|
||||
direction = direction + (2* math.pi)
|
||||
end
|
||||
|
||||
while direction > (2*math.pi) do
|
||||
direction = direction - (2* math.pi)
|
||||
end
|
||||
|
||||
return direction
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_calc_vector_components(dir_radians,absolute_speed)
|
||||
--
|
||||
--! @brief calculate calculate x and z components of a directed speed
|
||||
--
|
||||
--! @param dir_radians direction of movement radians
|
||||
--! @param absolute_speed speed in direction
|
||||
--
|
||||
--! @return {x,z}
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_calc_vector_components(dir_radians,absolute_speed)
|
||||
|
||||
local retval = {x=0,z=0}
|
||||
|
||||
retval.x = absolute_speed * math.cos(dir_radians)
|
||||
retval.z = absolute_speed * math.sin(dir_radians)
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_pos_is_same(pos1,pos2)
|
||||
--
|
||||
--! @brief check if two positions are equal
|
||||
--
|
||||
--! @param pos1
|
||||
--! @param pos2
|
||||
--
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_pos_is_same(pos1,pos2)
|
||||
if pos1 == nil or
|
||||
pos2 == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
if pos1.x ~= pos2.x or
|
||||
pos1.y ~= pos2.y or
|
||||
pos1.z ~= pos2.z or
|
||||
pos1.x == nil or
|
||||
pos1.y == nil or
|
||||
pos1.z == nil or
|
||||
pos2.x == nil or
|
||||
pos2.y == nil or
|
||||
pos2.z == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: mobf_assert_backtrace(value)
|
||||
--
|
||||
--! @brief assert in case value is false
|
||||
--
|
||||
--! @param value to evaluate
|
||||
-------------------------------------------------------------------------------
|
||||
function mobf_assert_backtrace(value)
|
||||
if minetest.assert_backtrace ~= nil then
|
||||
minetest.assert_backtrace(value)
|
||||
else
|
||||
assert(value)
|
||||
end
|
||||
end
|
||||
--!@}
|
232
mods/mobf/graphics.lua
Normal file
@ -0,0 +1,232 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file graphics.lua
|
||||
--! @brief graphics related parts of mob
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @class graphics
|
||||
--! @brief graphic features
|
||||
graphics = {}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: update_orientation_simple(entity,velocity)
|
||||
--
|
||||
--! @brief calculate direction of mob to face
|
||||
--! @memberof graphics
|
||||
--
|
||||
--! @param entity mob to calculate direction
|
||||
--! @param current_velocity data to calculate direction from
|
||||
-------------------------------------------------------------------------------
|
||||
function graphics.update_orientation_simple(entity,current_velocity)
|
||||
local x_abs = math.abs(current_velocity.x)
|
||||
local z_abs = math.abs(current_velocity.z)
|
||||
if x_abs > z_abs then
|
||||
if current_velocity.x > 0 then
|
||||
entity.object:setyaw(0)
|
||||
else
|
||||
entity.object:setyaw(math.pi)
|
||||
end
|
||||
else
|
||||
if current_velocity.z >0 then
|
||||
entity.object:setyaw(math.pi/2)
|
||||
else
|
||||
entity.object:setyaw(math.pi * (3/2))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: update_orientation(entity)
|
||||
--
|
||||
--! @brief callback for calculating a mobs direction
|
||||
--! @memberof graphics
|
||||
--
|
||||
--! @param entity mob to calculate direction
|
||||
--! @param now current time
|
||||
--! @param dtime current dtime
|
||||
-------------------------------------------------------------------------------
|
||||
function graphics.update_orientation(entity,now,dtime)
|
||||
|
||||
if entity.dynamic_data == nil or
|
||||
entity.dynamic_data.movement == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: >" ..entity.data.name
|
||||
.. "< removed=" .. dump(entity.removed) .. " entity="
|
||||
.. tostring(entity) .. " graphics callback without dynamic data")
|
||||
return
|
||||
end
|
||||
|
||||
local new_orientation = 0
|
||||
|
||||
-- if entity.dynamic_data.movement.ts_orientation_upd + 1 < now and
|
||||
if entity.dynamic_data.movement.orientation_fix_needed then
|
||||
|
||||
dbg_mobf.graphics_lvl3("MOBF: Updating orientation")
|
||||
--entity.dynamic_data.movement.ts_orientation_upd = now
|
||||
|
||||
local current_velocity = entity.object:getvelocity()
|
||||
local acceleration = entity.object:getacceleration()
|
||||
local pos = entity.getbasepos(entity)
|
||||
|
||||
dbg_mobf.graphics_lvl3("MOBF: vel: (" .. current_velocity.x .. ",".. current_velocity.z .. ") " ..
|
||||
"accel: (" ..acceleration.x .. "," .. acceleration.z .. ")")
|
||||
|
||||
--predict position mob will be in 0.25 seconds
|
||||
--local predicted_pos = movement_generic.calc_new_pos(pos,acceleration,dtime,current_velocity)
|
||||
|
||||
--local delta_x = predicted_pos.x - pos.x
|
||||
--local delta_z = predicted_pos.z - pos.z
|
||||
local delta_x = current_velocity.x
|
||||
local delta_z = current_velocity.z
|
||||
|
||||
--legacy 2d mode
|
||||
if (entity.mode == "2d") then
|
||||
graphics.update_orientation_simple(entity,{x=delta_x, z=delta_z})
|
||||
-- 3d mode
|
||||
else
|
||||
|
||||
if (delta_x ~= 0 ) and
|
||||
(delta_z ~= 0) then
|
||||
|
||||
entity.object:setyaw(mobf_calc_yaw(delta_x,delta_z))
|
||||
|
||||
dbg_mobf.graphics_lvl3("MOBF: x-delta: " .. delta_x
|
||||
.. " z-delta: " .. delta_z)
|
||||
elseif (delta_x ~= 0) or
|
||||
(delta_z ~= 0) then
|
||||
dbg_mobf.graphics_lvl3("MOBF: at least speed for one direction is 0")
|
||||
graphics.update_orientation_simple(entity,{x=delta_x,z=delta_z})
|
||||
else
|
||||
dbg_mobf.movement_lvl3("MOBF: not moving")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: set_animation(entity,name)
|
||||
--
|
||||
--! @brief set the drawmode for an mob entity
|
||||
--! @memberof graphics
|
||||
--
|
||||
--! @param entity mob to set drawmode for
|
||||
--! @param name name of animation
|
||||
-------------------------------------------------------------------------------
|
||||
function graphics.set_animation(entity,name)
|
||||
|
||||
if name == nil then
|
||||
dbg_mobf.graphics_lvl2("MOBF: calling updating animation without name for " .. entity.data.name)
|
||||
return
|
||||
end
|
||||
|
||||
if entity.mode == "2d" then
|
||||
|
||||
if id == "stand" then
|
||||
entity.object:setsprite({x=0,y=0}, 1, 0, true)
|
||||
end
|
||||
|
||||
if name == "burning" then
|
||||
entity.object:setsprite({x=0,y=1}, 1, 0, true)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if entity.mode == "3d" then
|
||||
--TODO change frame rate due to movement speed
|
||||
dbg_mobf.graphics_lvl2("MOBF: " .. entity.data.name .. " updating animation: " .. name)
|
||||
if entity.data.animation ~= nil and
|
||||
name ~= nil and
|
||||
entity.data.animation[name] ~= nil and
|
||||
entity.dynamic_data.animation ~= name then
|
||||
|
||||
dbg_mobf.graphics_lvl2("MOBF:\tSetting animation to " .. name
|
||||
.. " start: " .. entity.data.animation[name].start_frame
|
||||
.. " end: " .. entity.data.animation[name].end_frame)
|
||||
entity.object:set_animation({
|
||||
x=entity.data.animation[name].start_frame,
|
||||
y=entity.data.animation[name].end_frame
|
||||
}, nil, nil)
|
||||
entity.dynamic_data.animation = name
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
mobf_bug_warning(LOGLEVEL_WARNING,"MOBF BUG!!: invalid graphics mode specified "
|
||||
.. dump(entity.mode))
|
||||
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- name: prepare_graphic_info(graphics2d,graphics3d)
|
||||
--
|
||||
--! @brief get graphics information
|
||||
--! @memberof graphics
|
||||
--
|
||||
--! @param graphics2d
|
||||
--! @param graphics3d
|
||||
--! @param modname
|
||||
--! @param name
|
||||
--! @param statename
|
||||
--! @return grahpic information
|
||||
-------------------------------------------------------------------------------
|
||||
function graphics.prepare_info(graphics2d,graphics3d,modname,name,statename)
|
||||
|
||||
local setgraphics = {}
|
||||
|
||||
|
||||
|
||||
if (graphics3d == nil) or
|
||||
minetest.setting_getbool("mobf_disable_3d_mode") then
|
||||
if (graphics2d == nil) then
|
||||
--this maybe correct if there's a state model requested!
|
||||
return nil
|
||||
end
|
||||
|
||||
local basename = modname .. name
|
||||
|
||||
if statename ~= nil and
|
||||
statename ~= "default" then
|
||||
basename = basename .. "__" .. statename
|
||||
end
|
||||
|
||||
setgraphics.collisionbox = {-0.5,
|
||||
-0.5 * graphics2d.visible_height,
|
||||
-0.5,
|
||||
0.5,
|
||||
0.5 * graphics2d.visible_height,
|
||||
0.5}
|
||||
if graphics2d.visual ~= nil then
|
||||
setgraphics.visual = graphics2d.visual
|
||||
else
|
||||
setgraphics.visual = "sprite"
|
||||
end
|
||||
setgraphics.textures = { basename..".png^[makealpha:128,0,0^[makealpha:128,128,0" }
|
||||
setgraphics.visual_size = graphics2d.sprite_scale
|
||||
setgraphics.spritediv = graphics2d.sprite_div
|
||||
setgraphics.mode = "2d"
|
||||
else
|
||||
if graphics3d.visual == "mesh" then
|
||||
setgraphics.mesh = graphics3d.mesh
|
||||
end
|
||||
|
||||
setgraphics.collisionbox = graphics3d.collisionbox --todo is this required for mesh?
|
||||
setgraphics.visual = graphics3d.visual
|
||||
setgraphics.visual_size = graphics3d.visual_size
|
||||
setgraphics.textures = graphics3d.textures
|
||||
setgraphics.mode = "3d"
|
||||
end
|
||||
|
||||
return setgraphics
|
||||
end
|
219
mods/mobf/harvesting.lua
Normal file
@ -0,0 +1,219 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file harvesting.lua
|
||||
--! @brief component for all harvesting related mob features
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @defgroup harvesting Harvesting subcomponent
|
||||
--! @brief Component handling harvesting
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @class harvesting
|
||||
--! @brief harvesting features
|
||||
harvesting = {}
|
||||
|
||||
--!@}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: init_dynamic_data(entity,now)
|
||||
--
|
||||
--! @brief initialize dynamic data required by harvesting
|
||||
--! @memberof harvesting
|
||||
--
|
||||
--! @param entity mob to initialize harvest dynamic data
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function harvesting.init_dynamic_data(entity,now)
|
||||
dbg_mobf.harvesting_lvl1("MOBF: " .. entity.data.name
|
||||
.. " initializing harvesting dynamic data")
|
||||
local data = {
|
||||
ts_last = now,
|
||||
}
|
||||
entity.dynamic_data.harvesting = data
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: callback(entity,player,now)
|
||||
--
|
||||
--! @brief callback handler for harvest by player
|
||||
--! @memberof harvesting
|
||||
--
|
||||
--! @param entity mob being harvested
|
||||
--! @param player player harvesting
|
||||
--! @param now the current time
|
||||
--! @return true/false if handled by harvesting or not
|
||||
-------------------------------------------------------------------------------
|
||||
function harvesting.callback(entity,player,now)
|
||||
|
||||
dbg_mobf.harvesting_lvl1("MOBF: harvest function called")
|
||||
|
||||
local now = mobf_get_current_time()
|
||||
|
||||
--handle catching of mob
|
||||
if entity.data.catching ~= nil and
|
||||
entity.data.catching.tool ~= "" then
|
||||
|
||||
-- what's wielded by player
|
||||
local tool = player:get_wielded_item()
|
||||
|
||||
if tool:get_name() == entity.data.catching.tool then
|
||||
dbg_mobf.harvesting_lvl1("MOBF: player wearing ".. entity.data.catching.tool)
|
||||
|
||||
--play catch sound
|
||||
if entity.data.sound ~= nil then
|
||||
sound.play(entity.object:getpos(),entity.data.sound.catch);
|
||||
end
|
||||
|
||||
if entity.data.catching.consumed == true then
|
||||
if player:get_inventory():contains_item("main",entity.data.catching.tool.." 1") then
|
||||
dbg_mobf.harvesting_lvl2("MOBF: removing: "
|
||||
.. entity.data.catching.tool.." 1")
|
||||
player:get_inventory():remove_item("main",
|
||||
entity.data.catching.tool.." 1")
|
||||
else
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF: BUG!!! player is"
|
||||
.. " wearing a item he doesn't have in inventory!!!")
|
||||
--handled but not ok so don't attack
|
||||
return true
|
||||
end
|
||||
end
|
||||
if entity.data.generic.addoncatch ~= nil then
|
||||
player:get_inventory():add_item("main",
|
||||
entity.data.generic.addoncatch.." 1")
|
||||
else
|
||||
player:get_inventory():add_item("main",
|
||||
entity.data.modname ..":"..entity.data.name.." 1")
|
||||
end
|
||||
spawning.remove(entity, "cought")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--handle harvestable mobs, check if player is wearing correct tool
|
||||
if entity.data.harvest ~= nil then
|
||||
|
||||
dbg_mobf.harvesting_lvl1("MOBF: trying to harvest harvestable mob")
|
||||
if (entity.data.harvest.tool ~= "") then
|
||||
local tool = player:get_wielded_item()
|
||||
if tool ~= nil then
|
||||
dbg_mobf.harvesting_lvl1("MOBF: Player is wearing >"
|
||||
.. tool:get_name() .. "< required is >".. entity.data.harvest.tool
|
||||
.. "< wear: " .. tool:get_wear())
|
||||
|
||||
if (tool:get_name() ~= entity.data.harvest.tool) then
|
||||
--player is wearing wrong tool do an attack
|
||||
return false
|
||||
else
|
||||
--tool is completely consumed
|
||||
if entity.data.harvest.tool_consumed == true then
|
||||
if player:get_inventory():contains_item("main",entity.data.harvest.tool.." 1") == false then
|
||||
dbg_mobf.harvesting_lvl1("MOBF: Player doesn't have"
|
||||
.. " at least 1 of ".. entity.data.harvest.tool)
|
||||
--handled but not ok so don't attack
|
||||
return true
|
||||
end
|
||||
else
|
||||
--damage tool
|
||||
local tool_wear = tool:get_wear()
|
||||
|
||||
dbg_mobf.harvesting_lvl1("MOBF: tool " .. tool:get_name()
|
||||
.. " wear: " .. tool_wear)
|
||||
-- damage used tool
|
||||
if tool_wear ~= nil and
|
||||
entity.data.harvest.max_tool_usage ~= nil then
|
||||
|
||||
local todamage = (65535/entity.data.harvest.max_tool_usage)
|
||||
dbg_mobf.harvesting_lvl1("MOBF: tool damage calculated: "
|
||||
.. todamage);
|
||||
if tool:add_wear(todamage) ~= true then
|
||||
dbg_mobf.harvesting_lvl3("MOBF: Tried to damage non tool item "
|
||||
.. tool:get_name() .. "!");
|
||||
end
|
||||
player:set_wielded_item(tool)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
--player isn't wearing a tool so this has to be an attack
|
||||
return false
|
||||
end
|
||||
else
|
||||
--no havest tool defined so this has to be an attack
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--transformation and harvest delay is exclusive
|
||||
|
||||
--harvest delay mode
|
||||
if entity.data.harvest.min_delay < 0 or
|
||||
entity.dynamic_data.harvesting.ts_last + entity.data.harvest.min_delay < now then
|
||||
|
||||
player:get_inventory():add_item("main", entity.data.harvest.result.." 1")
|
||||
|
||||
--check if tool is consumed by action
|
||||
if entity.data.harvest.tool_consumed then
|
||||
dbg_mobf.harvesting_lvl2("MOBF: removing "
|
||||
..entity.data.harvest.tool.." 1")
|
||||
player:get_inventory():remove_item("main",entity.data.harvest.tool.." 1")
|
||||
end
|
||||
else
|
||||
dbg_mobf.harvesting_lvl1("MOBF: " .. entity.data.name
|
||||
.. " not ready to be harvested")
|
||||
end
|
||||
|
||||
-- check if mob is transformed by harvest
|
||||
if entity.data.harvest.transforms_to ~= "" then
|
||||
local transformed = spawning.replace_entity(entity,
|
||||
entity.data.harvest.transforms_to)
|
||||
else
|
||||
entity.dynamic_data.harvesting.ts_last = mobf_get_current_time()
|
||||
end
|
||||
|
||||
|
||||
--play harvest sound
|
||||
if entity.data.sound ~= nil then
|
||||
sound.play(entity.object:getpos(),entity.data.sound.harvest);
|
||||
end
|
||||
|
||||
--harvest done
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: transform(entity)
|
||||
--
|
||||
--! @brief self transform callback for mob
|
||||
--! @ingroup harvesting
|
||||
--
|
||||
--! @param entity mob calling
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function transform(entity,now)
|
||||
|
||||
--check if it's a transformable mob
|
||||
if entity.data.auto_transform ~= nil then
|
||||
|
||||
if now - entity.dynamic_data.spawning.original_spawntime
|
||||
> entity.data.auto_transform.delay then
|
||||
spawning.replace_entity(entity,entity.data.auto_transform.result)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
350
mods/mobf/init.lua
Normal file
@ -0,0 +1,350 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file init.lua
|
||||
--! @brief main module file responsible for including all parts of mob framework mod
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @defgroup framework_int Internal framework subcomponent API
|
||||
--! @brief this functions are used to provide additional features to mob framework
|
||||
--! e.g. add additional spawn algorithms, movement generators, environments ...
|
||||
--
|
||||
--
|
||||
--! @defgroup framework_mob Mob Framework API
|
||||
--! @brief this functions are used to add a mob to mob framework
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
print("MOD: mobf loading ...")
|
||||
|
||||
--! @brief runtime data required to be setup once on start
|
||||
mobf_rtd = {
|
||||
--!is mob running with fire support
|
||||
fire_enabled = false,
|
||||
--!do we have luatrace
|
||||
luatrace_enabled = false,
|
||||
--!do we have inventory plus support
|
||||
inventory_plus_enabled = false,
|
||||
--!registry for movement patterns
|
||||
movement_patterns = {},
|
||||
--!registry of mobs
|
||||
registred_mob = {},
|
||||
--!registred mobs_data
|
||||
registred_mob_data = {},
|
||||
}
|
||||
|
||||
--!path of mod
|
||||
mobf_modpath = minetest.get_modpath("mobf")
|
||||
|
||||
LOGLEVEL_INFO = "verbose"
|
||||
LOGLEVEL_NOTICE = "info"
|
||||
LOGLEVEL_WARNING = "action"
|
||||
LOGLEVEL_ERROR = "error"
|
||||
LOGLEVEL_CRITICAL = "error"
|
||||
|
||||
--include debug trace functions
|
||||
dofile (mobf_modpath .. "/debug_trace.lua")
|
||||
|
||||
--include engine
|
||||
dofile (mobf_modpath .. "/generic_functions.lua")
|
||||
dofile (mobf_modpath .. "/environment.lua")
|
||||
dofile (mobf_modpath .. "/movement_generic.lua")
|
||||
dofile (mobf_modpath .. "/graphics.lua")
|
||||
dofile (mobf_modpath .. "/movement_gen_registry.lua")
|
||||
dofile (mobf_modpath .. "/harvesting.lua")
|
||||
dofile (mobf_modpath .. "/weapons.lua")
|
||||
dofile (mobf_modpath .. "/fighting.lua")
|
||||
dofile (mobf_modpath .. "/random_drop.lua")
|
||||
dofile (mobf_modpath .. "/sound.lua")
|
||||
dofile (mobf_modpath .. "/permanent_data.lua")
|
||||
dofile (mobf_modpath .. "/ride.lua")
|
||||
dofile (mobf_modpath .. "/mobf.lua")
|
||||
dofile (mobf_modpath .. "/api.lua")
|
||||
dofile (mobf_modpath .. "/debug.lua")
|
||||
dofile (mobf_modpath .. "/mob_state.lua")
|
||||
dofile (mobf_modpath .. "/inventory.lua")
|
||||
|
||||
--include spawning support
|
||||
dofile (mobf_modpath .. "/spawning.lua")
|
||||
|
||||
--include movement generators
|
||||
dofile (mobf_modpath .. "/mgen_probab/main_probab.lua")
|
||||
dofile (mobf_modpath .. "/mgen_follow/main_follow.lua")
|
||||
dofile (mobf_modpath .. "/mgen_rasterized/mgen_raster.lua")
|
||||
dofile (mobf_modpath .. "/mgen_jordan4ibanez/mgen_jordan4ibanez.lua")
|
||||
dofile (mobf_modpath .. "/mov_gen_none.lua")
|
||||
|
||||
mobf_version = "2.0.5"
|
||||
|
||||
--! @brief define tools used for more than one mob
|
||||
function mobf_init_basic_tools()
|
||||
minetest.register_craft({
|
||||
output = "animalmaterials:lasso 5",
|
||||
recipe = {
|
||||
{'', "wool:white",''},
|
||||
{"wool:white",'', "wool:white"},
|
||||
{'',"wool:white",''},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalmaterials:net 1",
|
||||
recipe = {
|
||||
{"wool:white",'',"wool:white"},
|
||||
{'', "wool:white",''},
|
||||
{"wool:white",'',"wool:white"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'animalmaterials:sword_deamondeath',
|
||||
recipe = {
|
||||
{'animalmaterials:bone'},
|
||||
{'animalmaterials:bone'},
|
||||
{'default:stick'},
|
||||
}
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
|
||||
--! @brief main initialization function
|
||||
function mobf_init_framework()
|
||||
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initializing mob framework")
|
||||
mobf_init_basic_tools()
|
||||
|
||||
minetest.log(LOGLEVEL_NOTICE,"MOBF: Reading mob blacklist")
|
||||
local mobf_mob_blacklist_string = minetest.setting_get("mobf_blacklist")
|
||||
|
||||
if mobf_mob_blacklist_string ~= nil then
|
||||
mobf_rtd.registred_mob = minetest.deserialize(mobf_mob_blacklist_string)
|
||||
|
||||
if mobf_rtd.registred_mob == nil then
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF: Error on serializing blacklist!")
|
||||
mobf_rtd.registred_mob = {}
|
||||
end
|
||||
end
|
||||
|
||||
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initialize external mod dependencys...")
|
||||
mobf_init_mod_deps()
|
||||
|
||||
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initializing probabilistic movement generator")
|
||||
movement_gen.initialize()
|
||||
|
||||
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initializing weaponry..")
|
||||
mobf_init_weapons()
|
||||
|
||||
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initializing debug hooks..")
|
||||
mobf_debug.init()
|
||||
|
||||
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initialize mobf supplied modules..")
|
||||
mobf_init_modules()
|
||||
|
||||
-- initialize luatrace if necessary
|
||||
if mobf_rtd.luatrace_enabled then
|
||||
luatrace = require("luatrace")
|
||||
end
|
||||
|
||||
-- register privilege to change mobf settings
|
||||
minetest.register_privilege("mobfw_admin",
|
||||
{
|
||||
description = "Player may change mobf settings",
|
||||
give_to_singleplayer = true
|
||||
})
|
||||
|
||||
print("MOD: mob framework mod "..mobf_version.." loaded")
|
||||
end
|
||||
|
||||
--! @brief initialize mod dependencys
|
||||
function mobf_init_mod_deps()
|
||||
local modlist = minetest.get_modnames()
|
||||
|
||||
for i=1,#modlist,1 do
|
||||
if modlist[i] == "fire" then
|
||||
mobf_rtd.fire_enabled = true
|
||||
end
|
||||
|
||||
if modlist[i] == "inventory_plus" then
|
||||
mobf_rtd.inventory_plus_enabled = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--! @brief initialize mobf submodules
|
||||
function mobf_init_modules()
|
||||
|
||||
--state change callback
|
||||
mobf.register_on_step_callback({
|
||||
name = "state_change",
|
||||
handler = mob_state.callback,
|
||||
init = mob_state.initialize,
|
||||
configcheck = function(entity)
|
||||
if entity.data.states ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
})
|
||||
|
||||
--auto transform hook
|
||||
mobf.register_on_step_callback({
|
||||
name = "transform",
|
||||
handler = transform,
|
||||
init = nil,
|
||||
configcheck = function(entity)
|
||||
if entity.data.auto_transform ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
})
|
||||
|
||||
--combat hook
|
||||
mobf.register_on_step_callback({
|
||||
name = "combat",
|
||||
handler = fighting.combat,
|
||||
init = fighting.init_dynamic_data,
|
||||
configcheck = function(entity)
|
||||
if entity.data.combat ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
})
|
||||
|
||||
--attack hook
|
||||
mobf.register_on_step_callback({
|
||||
name = "aggression",
|
||||
handler = fighting.aggression,
|
||||
init = nil, -- already done by fighting.combat
|
||||
configcheck = function(entity)
|
||||
if entity.data.combat ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
|
||||
--workaround for shortcomings in spawn algorithm
|
||||
mobf.register_on_step_callback({
|
||||
name = "check_pop_dense",
|
||||
handler = spawning.check_population_density,
|
||||
init = spawning.init_dynamic_data,
|
||||
configcheck = function(entity)
|
||||
return true
|
||||
end
|
||||
})
|
||||
|
||||
--random drop hook
|
||||
mobf.register_on_step_callback({
|
||||
name = "random_drop",
|
||||
handler = random_drop.callback,
|
||||
init = random_drop.init_dynamic_data,
|
||||
configcheck = function(entity)
|
||||
if entity.data.random_drop ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
})
|
||||
|
||||
--random sound hook
|
||||
mobf.register_on_step_callback({
|
||||
name = "sound",
|
||||
handler = sound.play_random,
|
||||
init = sound.init_dynamic_data,
|
||||
configcheck = function(entity)
|
||||
if entity.data.sound ~= nil and
|
||||
entity.data.sound.random ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
})
|
||||
|
||||
--visual change hook
|
||||
mobf.register_on_step_callback({
|
||||
name = "update_orientation",
|
||||
handler = graphics.update_orientation,
|
||||
init = nil,
|
||||
configcheck = function(entity)
|
||||
return true
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
--custom hook
|
||||
mobf.register_on_step_callback({
|
||||
name = "custom_hooks",
|
||||
handler = function(entity,now,dtime)
|
||||
if type(entity.data.generic.custom_on_step_handler) == "function" then
|
||||
entity.data.generic.custom_on_step_handler(entity,now,dtime)
|
||||
end
|
||||
end,
|
||||
configcheck = function(entity)
|
||||
return true
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
--on punch callbacks
|
||||
mobf.register_on_punch_callback({
|
||||
name = "harvesting",
|
||||
handler = harvesting.callback,
|
||||
init = harvesting.init_dynamic_data,
|
||||
configcheck = function(entity)
|
||||
if (entity.data.catching ~= nil and
|
||||
entity.data.catching.tool ~= "" ) or
|
||||
entity.data.harvest ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
})
|
||||
|
||||
mobf.register_on_punch_callback({
|
||||
name = "riding",
|
||||
handler = mobf_ride.on_punch_callback,
|
||||
configcheck = mobf_ride.is_enabled
|
||||
})
|
||||
|
||||
mobf.register_on_punch_callback({
|
||||
name = "punching",
|
||||
handler = fighting.hit,
|
||||
configcheck = function(entity)
|
||||
return true
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
--on rightclick callbacks
|
||||
--Note debug needs to be registred FIRST!
|
||||
mobf.register_on_rightclick_callback({
|
||||
name = "debugcallback",
|
||||
handler = mobf_debug.rightclick_callback,
|
||||
configcheck = function(entity)
|
||||
return true
|
||||
end
|
||||
})
|
||||
|
||||
mobf.register_on_rightclick_callback({
|
||||
name = "tradercallback",
|
||||
handler = mob_inventory.trader_callback,
|
||||
configcheck = mob_inventory.config_check
|
||||
})
|
||||
|
||||
|
||||
end
|
||||
|
||||
mobf_init_framework()
|
||||
|
||||
dofile (mobf_modpath .. "/compatibility.lua")
|
534
mods/mobf/inventory.lua
Normal file
@ -0,0 +1,534 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file inventory.lua
|
||||
--! @brief component containing mob inventory related functions
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2013-01-02
|
||||
--
|
||||
--! @defgroup Inventory inventory subcomponent
|
||||
--! @brief Component handling mob inventory
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
mob_inventory = {}
|
||||
mob_inventory.trader_inventories = {}
|
||||
mob_inventory.formspecs = {}
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: allow_move(inv, from_list, from_index, to_list, to_index, count, player)
|
||||
--
|
||||
--! @brief check if there is enough at payroll
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv inventory reference
|
||||
--! @param from_list name of list elements taken
|
||||
--! @param from_index index at list elements taken
|
||||
--! @param to_list list name of list elements being put
|
||||
--! @param to_index index at list elements being put
|
||||
--! @param count number of elements moved
|
||||
--! @param player doing changes
|
||||
--
|
||||
--! @return number of elements allowed to move
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.allow_move(inv, from_list, from_index, to_list, to_index, count, player)
|
||||
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: move inv: " .. tostring(inv) .. " from:"
|
||||
.. dump(from_list) .. " to: " .. dump(to_list))
|
||||
if to_list ~= "selection" or
|
||||
from_list == "price_1" or
|
||||
from_list == "price_2" or
|
||||
from_list == "pay" or
|
||||
from_list == "takeaway" or
|
||||
from_list == "identifier" then
|
||||
return 0
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: allow_put(inv, listname, index, stack, player)
|
||||
--
|
||||
--! @brief check if there is enough at payroll
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv inventory reference
|
||||
--! @param listname name of list changed
|
||||
--! @param index index in list changed
|
||||
--! @param stack moved
|
||||
--! @param player doing changes
|
||||
--
|
||||
--! @return number of elements allowed to put
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.allow_put(inv, listname, index, stack, player)
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: put inv: " .. tostring(inv) .. " to:"
|
||||
.. dump(listname))
|
||||
|
||||
if listname == "pay" then
|
||||
return 99
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: allow_take(inv, listname, index, stack, player)
|
||||
--
|
||||
--! @brief check if there is enough at payroll
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv inventory reference
|
||||
--! @param listname name of list changed
|
||||
--! @param index index in list changed
|
||||
--! @param stack moved
|
||||
--! @param player doing changes
|
||||
--
|
||||
--! @return number of elements allowed to take
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.allow_take(inv, listname, index, stack, player)
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: take inv: " .. tostring(inv) .. " to:"
|
||||
.. dump(listname))
|
||||
|
||||
if listname == "takeaway" or
|
||||
listname == "pay" then
|
||||
return 99
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: on_move(inv, from_list, from_index, to_list, to_index, count, player)
|
||||
--
|
||||
--! @brief check if there is enough at payroll
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv inventory reference
|
||||
--! @param from_list name of list elements taken
|
||||
--! @param from_index index at list elements taken
|
||||
--! @param to_list list name of list elements being put
|
||||
--! @param to_index index at list elements being put
|
||||
--! @param count number of elements moved
|
||||
--! @param player doing changes
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.on_move(inv, from_list, from_index, to_list, to_index, count, player)
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: inv\"" .. tostring(inv) .. "\" moving "
|
||||
.. count .. " items from: " .. from_list .. ":" .. from_index .. " to: "
|
||||
.. to_list .. ":" .. to_index)
|
||||
|
||||
if from_list == "goods" and
|
||||
to_list == "selection" then
|
||||
|
||||
local moved = inv.get_stack(inv,to_list, to_index)
|
||||
|
||||
local elements = moved.get_count(moved)
|
||||
|
||||
--if elements > 1 then
|
||||
-- moved = moved.take_item(moved,elements-1)
|
||||
-- inv.set_stack(inv,from_list, from_index, moved)
|
||||
-- inv.set_stack(inv,to_list, to_index, moved)
|
||||
--else
|
||||
-- inv.set_stack(inv,from_list, from_index, moved)
|
||||
--end
|
||||
|
||||
local entity = mob_inventory.get_entity(inv)
|
||||
|
||||
if entity == nil then
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: move unable to find linked entity")
|
||||
return
|
||||
end
|
||||
|
||||
local goodname = moved.get_name(moved)
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: good selected: " .. goodname)
|
||||
|
||||
--get element put to selection
|
||||
mob_inventory.fill_prices(entity,inv,goodname,moved.get_count(moved))
|
||||
mob_inventory.update_takeaway(inv)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: on_put(inv, listname, index, stack, player)
|
||||
--
|
||||
--! @brief check if there is enough at payroll
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv inventory reference
|
||||
--! @param listname name of list changed
|
||||
--! @param index index in list changed
|
||||
--! @param stack moved
|
||||
--! @param player doing changes
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.on_put(inv, listname, index, stack, player)
|
||||
if listname == "pay" then
|
||||
local now_at_pay = inv.get_stack(inv,"pay",1)
|
||||
local playername = player.get_player_name(player)
|
||||
local count = now_at_pay.get_count(now_at_pay)
|
||||
local name = now_at_pay.get_name(now_at_pay)
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: putpay player: " .. playername
|
||||
.. " pays now count=" .. count .. " of type=" ..name)
|
||||
|
||||
mob_inventory.update_takeaway(inv)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: on_take(inv, listname, index, stack, player)
|
||||
--
|
||||
--! @brief check if there is enough at payroll
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv inventory reference
|
||||
--! @param listname name of list changed
|
||||
--! @param index index in list changed
|
||||
--! @param stack moved
|
||||
--! @param player doing changes
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.on_take(inv, listname, index, stack, player)
|
||||
if listname == "takeaway" then
|
||||
local now_at_pay = inv.get_stack(inv,"pay",index)
|
||||
local playername = player.get_player_name(player)
|
||||
local count = now_at_pay.get_count(now_at_pay)
|
||||
local name = now_at_pay.get_name(now_at_pay)
|
||||
dbg_mobf.trader_inv_lvl2("MOBF: takeaway player: " .. playername
|
||||
.. " pays now count=" .. count .. " of type=" ..name)
|
||||
|
||||
if not mob_inventory.check_pay(inv,true) then
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: error player hasn't payed enough!")
|
||||
end
|
||||
|
||||
mob_inventory.update_takeaway(inv)
|
||||
end
|
||||
|
||||
if listname == "pay" then
|
||||
if mob_inventory.check_pay(inv,false) then
|
||||
local selection = inv.get_stack(inv,"selection", 1)
|
||||
|
||||
if selection ~= nil then
|
||||
inv.set_stack(inv,"takeaway",1,selection)
|
||||
else
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: nothing selected to buy")
|
||||
end
|
||||
else
|
||||
inv.set_stack(inv,"takeaway",1,nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: update_takeaway(inv)
|
||||
--
|
||||
--! @brief update content of takeaway
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv to update
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.update_takeaway(inv)
|
||||
if mob_inventory.check_pay(inv,false) then
|
||||
local selection = inv.get_stack(inv,"selection", 1)
|
||||
|
||||
if selection ~= nil then
|
||||
inv.set_stack(inv,"takeaway",1,selection)
|
||||
else
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: nothing selected to buy")
|
||||
end
|
||||
else
|
||||
inv.set_stack(inv,"takeaway",1,nil)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: check_pay(inv)
|
||||
--
|
||||
--! @brief check if there is enough at payroll
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv inventory to do check
|
||||
--! @param paynow true/false if it's called to pay or not
|
||||
--
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.check_pay(inv,paynow)
|
||||
local now_at_pay = inv.get_stack(inv,"pay",1)
|
||||
local count = now_at_pay.get_count(now_at_pay)
|
||||
local name = now_at_pay.get_name(now_at_pay)
|
||||
|
||||
local price1 = inv.get_stack(inv,"price_1", 1)
|
||||
local price2 = inv.get_stack(inv,"price_2", 1)
|
||||
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: p1 " .. dump(price1) .. " " .. dump(price1:get_name()))
|
||||
if price1:get_name() == name then
|
||||
local price = price1:get_count()
|
||||
if price > 0 and
|
||||
price <= count then
|
||||
if paynow then
|
||||
now_at_pay.take_item(now_at_pay,price)
|
||||
inv.set_stack(inv,"pay",1,now_at_pay)
|
||||
return true
|
||||
else
|
||||
return true
|
||||
end
|
||||
else
|
||||
if paynow then
|
||||
inv.set_stack(inv,"pay",1,nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: p2 " .. dump(price1) .. " " .. dump(price2:get_name()))
|
||||
if price2:get_name() == name then
|
||||
local price = price2:get_count()
|
||||
if price > 0 and
|
||||
price <= count then
|
||||
if paynow then
|
||||
now_at_pay.take_item(now_at_pay,price)
|
||||
inv.set_stack(inv,"pay",1,now_at_pay)
|
||||
return true
|
||||
else
|
||||
return true
|
||||
end
|
||||
else
|
||||
if paynow then
|
||||
inv.set_stack(inv,"pay",1,nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: init_detached_inventories(entity,now)
|
||||
--
|
||||
--! @brief initialize dynamic data required by harvesting
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param entity mob to initialize harvest dynamic data
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.init_trader_inventory(entity)
|
||||
--TODO find out why calling "tostring" is necessary?!
|
||||
local tradername = tostring(entity.data.trader_inventory.random_names[math.random(1,#entity.data.trader_inventory.random_names)])
|
||||
dbg_mobf.trader_inv_lvl3("MOBF: randomly selected \"" .. tradername .. "\" as name")
|
||||
local unique_entity_id = string.gsub(tostring(entity),"table: ","")
|
||||
--local unique_entity_id = "testinv"
|
||||
local trader_inventory = minetest.create_detached_inventory(unique_entity_id,
|
||||
{
|
||||
allow_move = mob_inventory.allow_move,
|
||||
allow_put = mob_inventory.allow_put,
|
||||
allow_take = mob_inventory.allow_take,
|
||||
|
||||
on_move = mob_inventory.on_move,
|
||||
on_put = mob_inventory.on_put,
|
||||
on_take = mob_inventory.on_take,
|
||||
})
|
||||
|
||||
trader_inventory.set_size(trader_inventory,"goods",16)
|
||||
trader_inventory.set_size(trader_inventory,"takeaway",1)
|
||||
trader_inventory.set_size(trader_inventory,"selection",1)
|
||||
trader_inventory.set_size(trader_inventory,"price_1",1)
|
||||
trader_inventory.set_size(trader_inventory,"price_2",1)
|
||||
trader_inventory.set_size(trader_inventory,"pay",1)
|
||||
|
||||
mob_inventory.add_goods(entity,trader_inventory)
|
||||
|
||||
--register to trader inventories
|
||||
table.insert(mob_inventory.trader_inventories, {
|
||||
identifier = unique_entity_id,
|
||||
inv_ref = trader_inventory,
|
||||
ent_ref = entity,
|
||||
})
|
||||
dbg_mobf.trader_inv_lvl3("MOBF: registering identifier: " .. unique_entity_id
|
||||
.. " invref \"" .. tostring(trader_inventory) .. "\" for entity \""
|
||||
.. tostring(entity) .. "\"" )
|
||||
|
||||
local trader_formspec = "size[8,10;]" ..
|
||||
"label[2,0;Trader " .. tradername .. " Inventory]" ..
|
||||
"label[0,1;Selling:]" ..
|
||||
"list[detached:" .. unique_entity_id .. ";goods;0,1.5;8,2;]" ..
|
||||
"label[0,4.0;Selection]" ..
|
||||
"list[detached:" .. unique_entity_id .. ";selection;0,4.5;1,1;]" ..
|
||||
"label[1.25,4.75;-->]" ..
|
||||
"label[2,4.0;Price]" ..
|
||||
"list[detached:" .. unique_entity_id .. ";price_1;2,4.5;1,1;]" ..
|
||||
"label[3,4.0;or]" ..
|
||||
"list[detached:" .. unique_entity_id .. ";price_2;3,4.5;1,1;]" ..
|
||||
"label[4.25,4.75;-->]" ..
|
||||
"label[5,4.0;Pay]" ..
|
||||
"list[detached:" .. unique_entity_id .. ";pay;5,4.5;1,1;]" ..
|
||||
"label[6.25,4.75;-->]" ..
|
||||
"label[6.75,4.0;Takeaway]" ..
|
||||
"list[detached:" .. unique_entity_id .. ";takeaway;7,4.5;1,1;]" ..
|
||||
"list[current_player;main;0,6;8,4;]"
|
||||
|
||||
if mob_inventory.register_formspec("formspec_" .. unique_entity_id,trader_formspec) == false then
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: unable to create trader formspec")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: config_check(entity)
|
||||
--
|
||||
--! @brief check if mob is configured as trader
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param entity mob being checked
|
||||
--! @return true/false if trader or not
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.config_check(entity)
|
||||
if entity.data.trader_inventory ~= nil then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: register_formspec(name,formspec)
|
||||
--
|
||||
--! @brief check if mob is configured as trader
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param name name of formspec to register
|
||||
--! @param formspec formspec definition
|
||||
--
|
||||
--! @return true/false if succesfull or not
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.register_formspec(name,formspec)
|
||||
|
||||
if mob_inventory.formspecs[name] == nil then
|
||||
mob_inventory.formspecs[name] = formspec
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: callback(entity,player,now)
|
||||
--
|
||||
--! @brief callback handler for harvest by player
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param entity mob being harvested
|
||||
--! @param player player harvesting
|
||||
--
|
||||
--! @return true/false if handled by harvesting or not
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.trader_callback(entity,player)
|
||||
local unique_entity_id = string.gsub(tostring(entity),"table: ","")
|
||||
--local unique_entity_id = "testinv"
|
||||
local playername = player.get_player_name(player)
|
||||
|
||||
if mob_inventory.formspecs["formspec_" .. unique_entity_id] ~= nil then
|
||||
--rotate mob to face player
|
||||
local direction = mobf_get_direction(entity.object:getpos(),
|
||||
player:getpos())
|
||||
|
||||
if entity.mode == "3d" then
|
||||
entity.object:setyaw(mobf_calc_yaw(direction.x,direction.z)-math.pi/2)
|
||||
else
|
||||
entity.object:setyaw(mobf_calc_yaw(direction.x,direction.z)+math.pi/2)
|
||||
end
|
||||
|
||||
if minetest.show_formspec(playername,
|
||||
"formspec_" .. unique_entity_id,
|
||||
mob_inventory.formspecs["formspec_" .. unique_entity_id]) == false then
|
||||
dbg_mobf.trader_inv_lvl1("MOBF: unable to show trader formspec")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_entity(inv)
|
||||
--
|
||||
--! @brief find entity linked to inventory
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param inv name of inventory
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.get_entity(inv)
|
||||
dbg_mobf.trader_inv_lvl3("MOBF: checking " .. #mob_inventory.trader_inventories
|
||||
.. " registred inventorys")
|
||||
|
||||
local location = inv.get_location(inv)
|
||||
|
||||
if location.type == "detached" then
|
||||
for i=1,#mob_inventory.trader_inventories,1 do
|
||||
dbg_mobf.trader_inv_lvl3("MOBF: comparing \"" .. location.name .. "\" to \""
|
||||
.. mob_inventory.trader_inventories[i].identifier .. "\"")
|
||||
if mob_inventory.trader_inventories[i].identifier == location.name then
|
||||
return mob_inventory.trader_inventories[i].ent_ref
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: fill_prices(entity,inventory,goodname)
|
||||
--
|
||||
--! @brief fill price fields
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param entity to look for prices
|
||||
--! @param inventory to set prices
|
||||
--! @param goodname name of good to set prices for
|
||||
--! @param count number of elements
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.fill_prices(entity,inventory,goodname,count)
|
||||
|
||||
--get price info from entity
|
||||
local good = nil
|
||||
|
||||
for i=1,#entity.data.trader_inventory.goods,1 do
|
||||
local stackstring = goodname .." " .. count
|
||||
dbg_mobf.trader_inv_lvl3("MOBF: comparing \"" .. stackstring .. "\" to \""
|
||||
.. entity.data.trader_inventory.goods[i][1] .. "\"")
|
||||
if entity.data.trader_inventory.goods[i][1] == stackstring then
|
||||
good = entity.data.trader_inventory.goods[i]
|
||||
end
|
||||
end
|
||||
|
||||
if good ~= nil then
|
||||
inventory.set_stack(inventory,"price_1", 1, good[2])
|
||||
inventory.set_stack(inventory,"price_2", 1, good[3])
|
||||
else
|
||||
inventory.set_stack(inventory,"price_1", 1, nil)
|
||||
inventory.set_stack(inventory,"price_2", 1, nil)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: add_goods(entity,trader_inventory)
|
||||
--
|
||||
--! @brief fill inventory with mobs goods
|
||||
--! @ingroup mob_inventory
|
||||
--
|
||||
--! @param entity to look for prices
|
||||
--! @param trader_inventory to put goods
|
||||
-------------------------------------------------------------------------------
|
||||
function mob_inventory.add_goods(entity,trader_inventory)
|
||||
dbg_mobf.trader_inv_lvl3("MOBF: adding " .. #entity.data.trader_inventory.goods
|
||||
.. " goods for trader")
|
||||
for i=1,#entity.data.trader_inventory.goods,1 do
|
||||
dbg_mobf.trader_inv_lvl3("MOBF:\tadding " .. entity.data.trader_inventory.goods[i][1])
|
||||
trader_inventory.add_item(trader_inventory,"goods",
|
||||
entity.data.trader_inventory.goods[i][1])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--!@}
|
406
mods/mobf/mgen_follow/main_follow.lua
Normal file
@ -0,0 +1,406 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file main_follow.lua
|
||||
--! @brief component containing a targeted movement generator
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @defgroup mgen_follow MGEN: follow movement generator
|
||||
--! @brief A movement generator creating movement that trys to follow a moving
|
||||
--! target or reach a given point on map
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @class mgen_follow
|
||||
--! @brief a movement generator trying to follow or reach a target
|
||||
mgen_follow = {}
|
||||
|
||||
--!@}
|
||||
|
||||
--! @brief movement generator identifier
|
||||
--! @memberof mgen_follow
|
||||
mgen_follow.name = "follow_mov_gen"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: identify_movement_state(ownpos,targetpos)
|
||||
--
|
||||
--! @brief check what situation we are
|
||||
--! @memberof mgen_follow
|
||||
--
|
||||
--! @param ownpos position of entity
|
||||
--! @param targetpos position of target
|
||||
--!
|
||||
--! @return "below_los"
|
||||
--! "below_no_los"
|
||||
--! "same_height_los"
|
||||
--! "same_height_no_los"
|
||||
--! "above_los"
|
||||
--! "above_no_los"
|
||||
--! "unknown"
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_follow.identify_movement_state(ownpos,targetpos)
|
||||
local same_height_delta = 0.1
|
||||
|
||||
local los = mobf_line_of_sight(ownpos,targetpos)
|
||||
|
||||
if ownpos.y > targetpos.y - same_height_delta and
|
||||
ownpos.y < targetpos.y + same_height_delta then
|
||||
|
||||
if los then
|
||||
return "same_height_los"
|
||||
else
|
||||
return "same_height_no_los"
|
||||
end
|
||||
end
|
||||
|
||||
if ownpos.y < targetpos.y then
|
||||
if los then
|
||||
return "below_los"
|
||||
else
|
||||
return "below_no_los"
|
||||
end
|
||||
end
|
||||
|
||||
if ownpos.y > targetpos.y then
|
||||
if los then
|
||||
return "above_los"
|
||||
else
|
||||
return "above_no_los"
|
||||
end
|
||||
end
|
||||
|
||||
return "unknown"
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: handleteleport(entity,now)
|
||||
--
|
||||
--! @brief handle teleportsupport
|
||||
--! @memberof mgen_follow
|
||||
--
|
||||
--! @param entity mob to check for teleport
|
||||
--! @param now current time
|
||||
--! @param targetpos position of target
|
||||
--!
|
||||
--! @return true/false finish processing
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_follow.handleteleport(entity,now,targetpos)
|
||||
|
||||
if (entity.dynamic_data.movement.last_next_to_target ~= nil ) then
|
||||
local time_since_next_to_target =
|
||||
now - entity.dynamic_data.movement.last_next_to_target
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: time since next to target: " .. time_since_next_to_target ..
|
||||
" delay: " .. dump(entity.data.movement.teleportdelay) ..
|
||||
" teleportsupport: " .. dump(entity.dynamic_data.movement.teleportsupport))
|
||||
|
||||
if (entity.dynamic_data.movement.teleportsupport) and
|
||||
time_since_next_to_target > entity.data.movement.teleportdelay then
|
||||
|
||||
entity.object:setvelocity({x=0,y=0,z=0})
|
||||
entity.object:setacceleration({x=0,y=0,z=0})
|
||||
entity.object:moveto(targetpos)
|
||||
entity.dynamic_data.movement.last_next_to_target = now
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: callback(entity,now)
|
||||
--
|
||||
--! @brief main callback to make a mob follow its target
|
||||
--! @memberof mgen_follow
|
||||
--
|
||||
--! @param entity mob to generate movement for
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_follow.callback(entity,now)
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: Follow mgen callback called")
|
||||
|
||||
|
||||
|
||||
if entity == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: called movement gen without entity!")
|
||||
return
|
||||
end
|
||||
|
||||
if entity.dynamic_data == nil or
|
||||
entity.dynamic_data.movement == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: >" ..entity.data.name .. "< removed=" .. dump(entity.removed) .. " entity=" .. tostring(entity) .. " probab movement callback")
|
||||
return
|
||||
end
|
||||
|
||||
local follow_speedup = 10
|
||||
|
||||
if entity.data.movement.follow_speedup ~= nil then
|
||||
follow_speedup = entity.data.movement.follow_speedup
|
||||
end
|
||||
|
||||
--check max speed limit
|
||||
mgen_follow.checkspeed(entity)
|
||||
|
||||
|
||||
--check environment
|
||||
local basepos = entity.getbasepos(entity)
|
||||
local state = environment.pos_is_ok(basepos,entity)
|
||||
|
||||
if state == "ok" then
|
||||
local toset = {
|
||||
x= basepos.x,
|
||||
y= basepos.y - 0.5 - entity.collisionbox[2],
|
||||
z= basepos.z }
|
||||
--save known good position
|
||||
entity.dynamic_data.movement.last_pos_in_env = toset
|
||||
end
|
||||
|
||||
if not environment.possible_pos(entity,basepos) or
|
||||
state == "in_water" or
|
||||
state == "above_water" or
|
||||
state == "in_air" or
|
||||
state == "drop_above_water" then
|
||||
dbg_mobf.fmovement_lvl1("MOBF: followed to wrong place " .. state)
|
||||
if entity.dynamic_data.movement.last_pos_in_env ~= nil then
|
||||
entity.object:moveto(entity.dynamic_data.movement.last_pos_in_env)
|
||||
basepos = entity.getbasepos(entity)
|
||||
else
|
||||
local newpos = environment.get_suitable_pos_same_level(basepos,1,entity,true)
|
||||
|
||||
if newpos == nil then
|
||||
spawning.remove(entity,"mgen_follow poscheck")
|
||||
else
|
||||
newpos.y = newpos.y - (entity.collisionbox[2] + 0.49)
|
||||
entity.object:moveto(newpos)
|
||||
basepos = entity.getbasepos(entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if entity.dynamic_data.movement.target ~= nil or
|
||||
entity.dynamic_data.movement.guardspawnpoint then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: Target available")
|
||||
--calculate distance to target
|
||||
local targetpos = entity.dynamic_data.spawning.spawnpoint
|
||||
|
||||
|
||||
if entity.dynamic_data.movement.guardspawnpoint ~= true then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: moving target selected")
|
||||
targetpos = entity.dynamic_data.movement.target:getpos()
|
||||
end
|
||||
|
||||
if targetpos == nil then
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF: " .. entity.data.name
|
||||
.. " don't have targetpos "
|
||||
.. "SP: " .. dump(entity.dynamic_data.spawning.spawnpoint)
|
||||
.. " TGT: " .. dump(entity.dynamic_data.movement.target))
|
||||
return
|
||||
end
|
||||
|
||||
local distance = mobf_calc_distance_2d(basepos,targetpos)
|
||||
|
||||
local yaccel = environment.get_default_gravity(basepos,
|
||||
entity.environment.media,
|
||||
entity.data.movement.canfly)
|
||||
dbg_mobf.fmovement_lvl3("MOBF: default gravity is " .. yaccel )
|
||||
|
||||
if mobf_line_of_sight({x=basepos.x,y=basepos.y+1,z=basepos.z},
|
||||
{x=targetpos.x,y=targetpos.y+1,z=targetpos.z}) == false then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: no line of sight")
|
||||
--TODO teleport support?
|
||||
--TODO other ways to handle this?
|
||||
--return
|
||||
end
|
||||
dbg_mobf.fmovement_lvl3("MOBF: line of sight")
|
||||
|
||||
local max_distance = entity.dynamic_data.movement.max_distance
|
||||
|
||||
if max_distance == nil then
|
||||
max_distance = 1
|
||||
end
|
||||
|
||||
--check if mob needs to move towards target
|
||||
dbg_mobf.fmovement_lvl3("MOBF: max distance is set to : " .. max_distance)
|
||||
if distance > max_distance then
|
||||
|
||||
if mgen_follow.handleteleport(entity,now,targetpos) then
|
||||
return
|
||||
end
|
||||
|
||||
dbg_mobf.fmovement_lvl3("MOBF: distance:" .. distance)
|
||||
|
||||
local current_state = mgen_follow.identify_movement_state(basepos,targetpos)
|
||||
local handled = false
|
||||
|
||||
if handled == false and
|
||||
(current_state == "same_height_los" or
|
||||
current_state == "above_los" or
|
||||
current_state == "above_no_los" ) then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: \t Case 1: " .. current_state)
|
||||
local accel_to_set = movement_generic.get_accel_to(targetpos,entity)
|
||||
accel_to_set.y = yaccel
|
||||
dbg_mobf.fmovement_lvl3("MOBF: setting acceleration to: " .. printpos(accel_to_set));
|
||||
mgen_follow.set_acceleration(entity,accel_to_set,follow_speedup)
|
||||
|
||||
handled = true
|
||||
end
|
||||
|
||||
if handled == false and
|
||||
(current_state == "below_los" or
|
||||
current_state == "below_no_los" or
|
||||
current_state == "same_height_no_los" ) then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: \t Case 2: " .. current_state)
|
||||
local accel_to_set = movement_generic.get_accel_to(targetpos,entity)
|
||||
accel_to_set.y = yaccel
|
||||
|
||||
local current_velocity = entity.object:getvelocity()
|
||||
local predicted_pos = movement_generic.predict_next_block(basepos,current_velocity,accel_to_set)
|
||||
local pos_state = environment.pos_is_ok(predicted_pos,entity)
|
||||
|
||||
if pos_state == "collision_jumpable" then
|
||||
local pos_to_set = entity.object:getpos()
|
||||
pos_to_set.y = pos_to_set.y + 1.1
|
||||
entity.object:moveto(pos_to_set)
|
||||
end
|
||||
dbg_mobf.fmovement_lvl3("MOBF: setting acceleration to: "
|
||||
.. printpos(accel_to_set) .. " predicted_state: "
|
||||
.. pos_state);
|
||||
mgen_follow.set_acceleration(entity,accel_to_set,follow_speedup)
|
||||
|
||||
handled = true
|
||||
end
|
||||
|
||||
if handled == false then
|
||||
dbg_mobf.fmovement_lvl1("MOBF: \t Unexpected movement state: " .. current_state)
|
||||
end
|
||||
--nothing to do
|
||||
else
|
||||
dbg_mobf.fmovement_lvl3("MOBF: next to target")
|
||||
entity.object:setvelocity({x=0,y=0,z=0})
|
||||
entity.object:setacceleration({x=0,y=0,z=0})
|
||||
entity.dynamic_data.movement.last_next_to_target = now
|
||||
|
||||
|
||||
local dir = mobf_get_direction(basepos,targetpos)
|
||||
--update mob orientation
|
||||
if entity.mode == "3d" then
|
||||
entity.object:setyaw(mobf_calc_yaw(dir.x,dir.z))
|
||||
else
|
||||
entity.object:setyaw(mobf_calc_yaw(dir.x,dir.z))
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
--TODO evaluate if this is an error case
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: initialize()
|
||||
--
|
||||
--! @brief initialize movement generator
|
||||
--! @memberof mgen_follow
|
||||
--! @public
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_follow.initialize(entity,now)
|
||||
--intentionally empty
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: init_dynamic_data(entity,now)
|
||||
--
|
||||
--! @brief initialize dynamic data required by movement generator
|
||||
--! @memberof mgen_follow
|
||||
--! @public
|
||||
--
|
||||
--! @param entity mob to initialize dynamic data
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_follow.init_dynamic_data(entity,now)
|
||||
|
||||
local pos = entity.object:getpos()
|
||||
|
||||
|
||||
local data = {
|
||||
target = nil,
|
||||
guardspawnpoint = false,
|
||||
max_distance = entity.data.movement.max_distance,
|
||||
orientation_fix_needed = true,
|
||||
}
|
||||
|
||||
if entity.data.movement.guardspawnpoint ~= nil and
|
||||
entity.data.movement.guardspawnpoint then
|
||||
dbg_mobf.fmovement_lvl3("MOBF: setting guard point to: " .. printpos(entity.dynamic_data.spawning.spawnpoint))
|
||||
data.guardspawnpoint = true
|
||||
end
|
||||
|
||||
if entity.data.movement.teleportdelay~= nil then
|
||||
data.last_next_to_target = now
|
||||
data.teleportsupport = true
|
||||
end
|
||||
|
||||
entity.dynamic_data.movement = data
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: checkspeed(entity)
|
||||
--
|
||||
--! @brief check if mobs speed is within it's limits and correct if necessary
|
||||
--! @memberof mgen_follow
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to initialize dynamic data
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_follow.checkspeed(entity)
|
||||
|
||||
local current_velocity = entity.object:getvelocity()
|
||||
|
||||
local xzspeed = math.sqrt(math.pow(current_velocity.x,2)+
|
||||
math.pow(current_velocity.z,2))
|
||||
|
||||
if (xzspeed > entity.data.movement.max_speed) then
|
||||
|
||||
--preserver orientation when correcting speed
|
||||
local dir = mobf_calc_yaw(current_velocity.x,current_velocity.z)
|
||||
local velocity_to_set = mobf_calc_vector_components(dir,entity.data.movement.max_speed * 0.25)
|
||||
|
||||
velocity_to_set.y=current_velocity.y
|
||||
|
||||
entity.object:setvelocity(velocity_to_set)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: set_acceleration(entity,accel,speedup)
|
||||
--
|
||||
--! @brief apply acceleration to entity
|
||||
--! @memberof mgen_follow
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to apply to
|
||||
--! @param accel acceleration to set
|
||||
--! @param speedup speedup factor
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_follow.set_acceleration(entity,accel,speedup)
|
||||
entity.object:setacceleration({x=accel.x*speedup,
|
||||
y=accel.y,
|
||||
z=accel.z*speedup})
|
||||
end
|
||||
|
||||
|
||||
--register this movement generator
|
||||
registerMovementGen(mgen_follow.name,mgen_follow)
|
139
mods/mobf/mgen_jordan4ibanez/mgen_jordan4ibanez.lua
Normal file
@ -0,0 +1,139 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file main_follow.lua
|
||||
--! @brief component containing a movement generator based uppon jordan4ibanez code
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @defgroup mgen_jordan4ibanez MGEN: a velocity based movement generator
|
||||
--! @brief A movement generator creating simple random movement
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @class mgen_jordan4ibanez
|
||||
--! @brief a movement generator trying to follow or reach a target
|
||||
mgen_jordan4ibanez = {}
|
||||
mgen_jordan4ibanez.chillaxin_speed = 0.1
|
||||
--!@}
|
||||
|
||||
--! @brief movement generator identifier
|
||||
--! @memberof mgen_jordan4ibanez
|
||||
mgen_jordan4ibanez.name = "jordan4ibanez_mov_gen"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: callback(entity,now)
|
||||
--
|
||||
--! @brief main callback to make a mob follow its target
|
||||
--! @memberof mgen_jordan4ibanez
|
||||
--
|
||||
--! @param entity mob to generate movement for
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_jordan4ibanez.callback(entity,now)
|
||||
|
||||
--update timers
|
||||
entity.dynamic_data.movement.timer = entity.dynamic_data.movement.timer + 0.01
|
||||
entity.dynamic_data.movement.turn_timer = entity.dynamic_data.movement.turn_timer + 0.01
|
||||
entity.dynamic_data.movement.jump_timer = entity.dynamic_data.movement.jump_timer + 0.01
|
||||
entity.dynamic_data.movement.door_timer = entity.dynamic_data.movement.door_timer + 0.01
|
||||
|
||||
|
||||
if entity.dynamic_data.movement.direction ~= nil then
|
||||
entity.object:setvelocity({x=entity.dynamic_data.movement.direction.x*mgen_jordan4ibanez.chillaxin_speed,
|
||||
y=entity.object:getvelocity().y,
|
||||
z=entity.dynamic_data.movement.direction.z*mgen_jordan4ibanez.chillaxin_speed})
|
||||
end
|
||||
|
||||
if entity.dynamic_data.movement.turn_timer > math.random(1,4) then
|
||||
entity.dynamic_data.movement.yaw = 360 * math.random()
|
||||
entity.object:setyaw(entity.dynamic_data.movement.yaw)
|
||||
entity.dynamic_data.movement.turn_timer = 0
|
||||
entity.dynamic_data.movement.direction = {x = math.sin(entity.dynamic_data.movement.yaw)*-1,
|
||||
y = -10,
|
||||
z = math.cos(entity.dynamic_data.movement.yaw)}
|
||||
--entity.object:setvelocity({x=entity.dynamic_data.movement.direction.x,y=entity.object:getvelocity().y,z=entity.dynamic_data.movement.direction.z})
|
||||
--entity.object:setacceleration(entity.dynamic_data.movement.direction)
|
||||
end
|
||||
|
||||
--TODO update animation
|
||||
|
||||
--open a door [alpha]
|
||||
if entity.dynamic_data.movement.direction ~= nil then
|
||||
if entity.dynamic_data.movement.door_timer > 2 then
|
||||
local is_a_door = minetest.env:get_node({x=entity.object:getpos().x + entity.dynamic_data.movement.direction.x,
|
||||
y=entity.object:getpos().y,z=entity.object:getpos().
|
||||
z + entity.dynamic_data.movement.direction.z}).name
|
||||
if is_a_door == "doors:door_wood_t_1" then
|
||||
minetest.env:punch_node({x=entity.object:getpos().x + entity.dynamic_data.movement.direction.x,
|
||||
y=entity.object:getpos().y-1,
|
||||
z=entity.object:getpos().z + entity.dynamic_data.movement.direction.z})
|
||||
entity.dynamic_data.movement.door_timer = 0
|
||||
end
|
||||
local is_in_door = minetest.env:get_node(entity.object:getpos()).name
|
||||
if is_in_door == "doors:door_wood_t_1" then
|
||||
minetest.env:punch_node(entity.object:getpos())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--jump
|
||||
if entity.dynamic_data.movement.direction ~= nil then
|
||||
if entity.dynamic_data.movement.jump_timer > 0.3 then
|
||||
if minetest.registered_nodes[minetest.env:get_node({x=entity.object:getpos().x + entity.dynamic_data.movement.direction.x,
|
||||
y=entity.object:getpos().y-1,
|
||||
z=entity.object:getpos().z + entity.dynamic_data.movement.direction.z}).name].walkable then
|
||||
entity.object:setvelocity({x=entity.object:getvelocity().x,y=5,z=entity.object:getvelocity().z})
|
||||
entity.dynamic_data.movement.jump_timer = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: initialize()
|
||||
--
|
||||
--! @brief initialize movement generator
|
||||
--! @memberof mgen_jordan4ibanez
|
||||
--! @public
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_jordan4ibanez.initialize(entity,now)
|
||||
--intentionaly doing nothing this function is for symmetry reasons only
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: init_dynamic_data(entity,now)
|
||||
--
|
||||
--! @brief initialize dynamic data required by movement generator
|
||||
--! @memberof mgen_jordan4ibanez
|
||||
--! @public
|
||||
--
|
||||
--! @param entity mob to initialize dynamic data
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function mgen_jordan4ibanez.init_dynamic_data(entity,now)
|
||||
|
||||
local data = {
|
||||
timer = 0,
|
||||
turn_timer = 0,
|
||||
jump_timer = 0,
|
||||
door_timer = 0,
|
||||
direction = nil,
|
||||
yaw = nil,
|
||||
orientation_fix_needed = false,
|
||||
}
|
||||
|
||||
entity.dynamic_data.movement = data
|
||||
end
|
||||
|
||||
|
||||
--register this movement generator
|
||||
registerMovementGen(mgen_jordan4ibanez.name,mgen_jordan4ibanez)
|
204
mods/mobf/mgen_pathbased/path_based_movement_gen.lua
Normal file
@ -0,0 +1,204 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file path_based_movement_gen.lua
|
||||
--! @brief component containing a path based movement generator (NOT COMPLETED)
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @defgroup mgen_path_based MGEN: Path based movement generator (NOT COMPLETED)
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @class p_mov_gen
|
||||
--! @brief a movement generator evaluating a path to a target and following it
|
||||
p_mov_gen = {}
|
||||
|
||||
--!@}
|
||||
|
||||
--! @brief movement generator identifier
|
||||
--! @memberof p_mov_gen
|
||||
p_mov_gen.name = "mgen_path"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: validate_position(current_pos,origin,destination)
|
||||
--
|
||||
--! @brief check if current position is on movement path to destination
|
||||
--! @memberof p_mov_gen
|
||||
--! @private
|
||||
--
|
||||
--! @param current_pos
|
||||
--! @param origin of movement
|
||||
--! @param destination of movement
|
||||
-------------------------------------------------------------------------------
|
||||
function p_mov_gen.validate_path_position(current_pos,origin,destination)
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: validate_position(current_pos,origin,destination)
|
||||
--
|
||||
--! @brief check if there's a direct path from pos1 to pos2 for this mob
|
||||
--! @memberof p_mov_gen
|
||||
--! @private
|
||||
--
|
||||
-- param1: mob to check
|
||||
-- param2: position1
|
||||
-- param3: position2
|
||||
-- retval: -
|
||||
-------------------------------------------------------------------------------
|
||||
function p_mov_gen.direct_path_available(entity,pos1,pos2)
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: find_destination(entity,current_pos)
|
||||
--
|
||||
--! @brief find a suitable destination for this mob
|
||||
--! @memberof p_mov_gen
|
||||
--! @private
|
||||
--
|
||||
-- param1: mob to get destination for
|
||||
-- param2: current position
|
||||
-- retval: -
|
||||
-------------------------------------------------------------------------------
|
||||
function p_mov_gen.find_destination(entity,current_pos)
|
||||
|
||||
--TODO
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: set_speed(entity,destination)
|
||||
--
|
||||
--! brief set speed to destination for an mob
|
||||
--! @memberof p_mov_gen
|
||||
--! @private
|
||||
--
|
||||
-- param1: mob to get destination for
|
||||
-- param2: destination of mob
|
||||
-- retval: -
|
||||
-------------------------------------------------------------------------------
|
||||
function p_mov_gen.set_speed(entity,destination)
|
||||
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: fix_position(entity,current_pos)
|
||||
--
|
||||
--! @brief check if mob is in a valid position and fix it if necessary
|
||||
--! @memberof p_mov_gen
|
||||
--! @private
|
||||
--
|
||||
-- param1: mob to get destination for
|
||||
-- param2: position of mob
|
||||
-- retval: -
|
||||
-------------------------------------------------------------------------------
|
||||
function p_mov_gen.fix_position(entity,current_pos)
|
||||
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: update_movement(entity,now)
|
||||
--
|
||||
--! @brief check and update current movement state
|
||||
--! @memberof p_mov_gen
|
||||
--! @private
|
||||
--
|
||||
-- param1: mob to move
|
||||
-- param2: current time
|
||||
-- retval: -
|
||||
-------------------------------------------------------------------------------
|
||||
function p_mov_gen.update_movement(entity,now)
|
||||
|
||||
--position of base block (different from center for ground based mobs)
|
||||
local pos = entity.getbasepos(entity)
|
||||
local centerpos = entity.object:getpos()
|
||||
|
||||
|
||||
--validate current position for mob
|
||||
p_mov_gen.fix_position(entity,pos)
|
||||
|
||||
--validate position is on path
|
||||
if p_mov_gen.validate_path_position(pos,
|
||||
entity.dynamic_data.p_movement.origin,
|
||||
entity.dynamic_data.p_movement.destination)
|
||||
== false then
|
||||
|
||||
--validate target is reachable
|
||||
if p_mov_gen.direct_path_available(entity,pos,entity.dynamic_data.p_movement.destination) then
|
||||
|
||||
--set new direction to target
|
||||
p_mov_gen.set_speed(entity,dynamic_data.p_movement.destination)
|
||||
else -- get new destination
|
||||
dynamic_data.p_movement.destination = p_mov_gen.find_destination(entity,pos)
|
||||
|
||||
if dynamic_data.p_movement.destination ~= nil then
|
||||
p_mov_gen.set_speed(entity,dynamic_data.p_movement.destination)
|
||||
else
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF: BUG !!! unable to find a destination for an mob!")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: callback(entity,now)
|
||||
--
|
||||
--! @brief path based movement generator callback
|
||||
--! @memberof p_mov_gen
|
||||
--
|
||||
-- param1: mob to do movement
|
||||
-- param2: current time
|
||||
-- retval: -
|
||||
-------------------------------------------------------------------------------
|
||||
function p_mov_gen.callback(entity,now)
|
||||
|
||||
-- mob is in movement do movement handling
|
||||
if entity.dynamic_data.p_movement.in_movement then
|
||||
p_mov_gen.update_movement(entity,now)
|
||||
|
||||
else
|
||||
-- calculate start movement chance
|
||||
--TODO
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: init_dynamic_data(entity,now)
|
||||
--
|
||||
-- @brief initialize dynamic data required by movement generator
|
||||
--! @memberof p_mov_gen
|
||||
--
|
||||
-- param1: entity to initialize
|
||||
-- param2: current time
|
||||
-- retval: -
|
||||
-------------------------------------------------------------------------------
|
||||
function p_mov_gen.init_dynamic_data(entity,now)
|
||||
|
||||
local pos = entity.object:getpos()
|
||||
|
||||
local data = {
|
||||
origin = pos,
|
||||
targetlist = nil,
|
||||
eta = nil,
|
||||
last_move_stop = now,
|
||||
in_movement = false
|
||||
}
|
||||
|
||||
entity.dynamic_data.p_movement = data
|
||||
end
|
359
mods/mobf/mgen_probab/direction_control.lua
Normal file
@ -0,0 +1,359 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file direction_control.lua
|
||||
--! @brief functions for direction control in probabilistic movement gen
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @ingroup mgen_probab
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @class direction_control
|
||||
--! @brief functions for direction control in probabilistic movement gen
|
||||
direction_control = {}
|
||||
--!@}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: changeaccel(pos,entity,velocity)
|
||||
--
|
||||
--! @brief find a suitable new acceleration for mob
|
||||
--! @memberof direction_control
|
||||
--! @private
|
||||
--
|
||||
--! @param pos current position
|
||||
--! @param entity mob to get acceleration for
|
||||
--! @param current_velocity current velocity
|
||||
--! @return {{ x/y/z accel} + jump flag really?
|
||||
-------------------------------------------------------------------------------
|
||||
function direction_control.changeaccel(pos,entity,current_velocity)
|
||||
|
||||
local new_accel = direction_control.get_random_acceleration(entity.data.movement.min_accel,
|
||||
entity.data.movement.max_accel,entity.object:getyaw(),0)
|
||||
|
||||
local pos_predicted = movement_generic.predict_next_block(pos,current_velocity,new_accel)
|
||||
|
||||
local maxtries = 5
|
||||
|
||||
local state = environment.pos_is_ok(pos_predicted,entity)
|
||||
|
||||
--below_limit and above_limit are ok too respective to movement handled by this component is xz only
|
||||
while state ~= "ok" and
|
||||
state == "above_limit" and
|
||||
state == "below_limit"do
|
||||
dbg_mobf.pmovement_lvl1("MOBF: predicted pos " .. printpos(pos_predicted) .. " isn't ok " .. maxtries .. " tries left, state: " .. state)
|
||||
local done = false
|
||||
|
||||
--don't loop forever get to save mode and try next time
|
||||
if maxtries <= 0 then
|
||||
dbg_mobf.pmovement_lvl1("MOBF: Aborting acceleration finding for this cycle due to max retries")
|
||||
if state == "collision_jumpable" then
|
||||
dbg_mobf.movement_lvl1("Returning "..printpos(new_accel).." as new accel as mob may jump")
|
||||
return new_accel
|
||||
end
|
||||
|
||||
dbg_mobf.pmovement_lvl1("MOBF: Didn't find a suitable acceleration stopping movement: " .. entity.data.name .. printpos(pos))
|
||||
entity.object:setvelocity({x=0,y=0,z=0})
|
||||
entity.dynamic_data.movement.started = false
|
||||
--don't slow down mob
|
||||
return { x=0,
|
||||
y=0,
|
||||
z=0 }
|
||||
end
|
||||
|
||||
--in case mob is already at non perfect surface it's not that bad to get on it again
|
||||
if not done and (state == "possible_surface") then
|
||||
local current_state = environment.pos_is_ok(pos,entity)
|
||||
local probab = math.random()
|
||||
|
||||
if current_state == "wrong_surface" or
|
||||
current_state == "possible_surface" then
|
||||
if probab < 0.3 then
|
||||
done = true
|
||||
end
|
||||
else
|
||||
if probab < 0.05 then
|
||||
done = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--first try to invert acceleration on collision
|
||||
-- if not done and (state == "collision" or
|
||||
-- state == "collision_jumpable") then
|
||||
-- new_accel = { x= new_accel.x * -1,
|
||||
-- y= new_accel.y,
|
||||
-- z= new_accel.z * -1}
|
||||
|
||||
-- pos_predicted = movement_generic.predict_next_block(pos,current_velocity,new_accel)
|
||||
-- if environment.pos_is_ok(pos_predicted,entity) == "ok" then
|
||||
-- done = true
|
||||
-- end
|
||||
|
||||
-- end
|
||||
|
||||
--generic way to find new acceleration
|
||||
if not done then
|
||||
new_accel = direction_control.get_random_acceleration(entity.data.movement.min_accel,
|
||||
entity.data.movement.max_accel,entity.object:getyaw(),1.57)
|
||||
|
||||
pos_predicted = movement_generic.predict_next_block(pos,current_velocity,new_accel)
|
||||
end
|
||||
|
||||
state = environment.pos_is_ok(pos_predicted,entity)
|
||||
maxtries = maxtries -1
|
||||
end
|
||||
|
||||
return new_accel
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: get_random_acceleration(minaccel,maxaccel,current_yaw, minrotation)
|
||||
--
|
||||
--! @brief get a random x/z acceleration within a specified acceleration range
|
||||
--! @memberof direction_control
|
||||
--! @private
|
||||
--
|
||||
--! @param minaccel minimum acceleration to use
|
||||
--! @param maxaccel maximum acceleration
|
||||
--! @param current_yaw current orientation of mob
|
||||
--! @param minrotation minimum rotation to perform
|
||||
--! @return x/y/z acceleration
|
||||
-------------------------------------------------------------------------------
|
||||
function direction_control.get_random_acceleration(minaccel,maxaccel,current_yaw, minrotation)
|
||||
|
||||
local direction = 1
|
||||
if math.random() < 0.5 then
|
||||
direction = -1
|
||||
end
|
||||
|
||||
--calc random absolute value
|
||||
local rand_accel = (math.random() * (maxaccel - minaccel)) + minaccel
|
||||
|
||||
local orientation_delta = 0
|
||||
|
||||
--randomize direction
|
||||
for i=0, 100 do
|
||||
|
||||
if math.random() < 0.2 then
|
||||
break
|
||||
end
|
||||
orientation_delta = orientation_delta +0.1
|
||||
end
|
||||
|
||||
--calculate new acceleration
|
||||
|
||||
|
||||
local new_direction = current_yaw + ((minrotation + orientation_delta) * direction)
|
||||
|
||||
local new_accel = {
|
||||
x = math.sin(new_direction) *rand_accel,
|
||||
y = nil,
|
||||
z = math.cos(new_direction) *rand_accel
|
||||
}
|
||||
|
||||
dbg_mobf.pmovement_lvl3(" new direction: " .. new_direction .. " old direction: " .. current_yaw .. " new accel: " .. printpos(new_accel))
|
||||
|
||||
return new_accel
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: precheck_movement(entity,movement_state)
|
||||
--
|
||||
--! @brief check if x/z movement results in invalid position and change
|
||||
-- movement if required
|
||||
--! @memberof direction_control
|
||||
--
|
||||
--! @param entity mob to generate movement
|
||||
--! @param movement_state current state of movement
|
||||
--! @param pos_predicted position mob will be next
|
||||
--! @param pos_predicted_state suitability state of predicted position
|
||||
--! @return movement_state is changed!
|
||||
-------------------------------------------------------------------------------
|
||||
function direction_control.precheck_movement(entity,movement_state,pos_predicted,pos_predicted_state)
|
||||
|
||||
--next block mob is to be isn't a place where it can be so we need to change something
|
||||
if pos_predicted_state ~= "ok" and
|
||||
pos_predicted_state ~= "above_limit" and
|
||||
pos_predicted_state ~= "below_limit" then
|
||||
|
||||
-- mob would walk onto water
|
||||
if movement_state.changed == false and
|
||||
( pos_predicted_state == "above_water" or
|
||||
pos_predicted_state == "drop" or
|
||||
pos_predicted_state == "drop_above_water")
|
||||
then
|
||||
dbg_mobf.pmovement_lvl1("MOBF: mob " .. entity.data.name .. " is going to walk on water or drop")
|
||||
local new_pos = environment.get_suitable_pos_same_level(movement_state.basepos,1,entity)
|
||||
|
||||
--try to find at least a possible position
|
||||
if new_pos == nil then
|
||||
dbg_mobf.pmovement_lvl1("MOBF: mob " .. entity.data.name .. " no prefect fitting position found")
|
||||
new_pos = environment.get_suitable_pos_same_level(movement_state.basepos,1,entity,true)
|
||||
end
|
||||
|
||||
if new_pos ~= nil then
|
||||
dbg_mobf.pmovement_lvl2("MOBF: redirecting to safe position .. " .. printpos(new_pos))
|
||||
movement_state.accel_to_set = movement_generic.get_accel_to(new_pos,entity)
|
||||
pos_predicted = movement_generic.predict_next_block( movement_state.basepos,
|
||||
movement_state.current_velocity,
|
||||
movement_state.accel_to_set)
|
||||
pos_predicted_state = environment.pos_is_ok({x=pos_predicted.x,y=pos_predicted.y+1,z=pos_predicted.z},entity)
|
||||
for i=0,10,1 do
|
||||
if pos_predicted_state == "ok" or
|
||||
pos_predicted_state == "possible_surface" then
|
||||
break
|
||||
end
|
||||
movement_state.accel_to_set = movement_generic.get_accel_to(new_pos,entity)
|
||||
pos_predicted = movement_generic.predict_next_block( movement_state.basepos,
|
||||
movement_state.current_velocity,
|
||||
movement_state.accel_to_set)
|
||||
pos_predicted_state = environment.pos_is_ok({x=pos_predicted.x,y=pos_predicted.y+1,z=pos_predicted.z},entity)
|
||||
end
|
||||
|
||||
if pos_predicted_state == "ok" or
|
||||
pos_predicted_state == "possible_surface" then
|
||||
dbg_mobf.pmovement_lvl1("MOBF: redirecting to safe position .. " .. printpos(new_pos) .. " failed!")
|
||||
end
|
||||
movement_state.changed = true
|
||||
else
|
||||
local current_state = environment.pos_is_ok(movement_state.basepos,entity)
|
||||
|
||||
--animal is safe atm stop it to avoid doing silly things
|
||||
if current_state == "ok" or
|
||||
current_state == "possible_surface" then
|
||||
entity.object:setvelocity({x=0,y=0,z=0})
|
||||
movement_state.accel_to_set = {x=0,y=nil,z=0}
|
||||
movement_state.changed = true
|
||||
dbg_mobf.pmovement_lvl2("MOBF: couldn't find acceleration but mob is safe where it is")
|
||||
else
|
||||
--apply random acceleration to avoid permanent stuck mobs maybe mobs should be deleted instead
|
||||
movement_state.accel_to_set = direction_control.get_random_acceleration(entity.data.movement.min_accel,
|
||||
entity.data.movement.max_accel,entity.object:getyaw(),0)
|
||||
movement_state.changed = true
|
||||
dbg_mobf.pmovement_lvl2("MOBF: couldn't find acceleration mob ain't safe either, just move on with random movement")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if movement_state.changed == false and pos_predicted_state == "collision_jumpable" then
|
||||
dbg_mobf.movement_lvl1("mob is about to collide")
|
||||
if environment.pos_is_ok({x=pos_predicted.x,y=pos_predicted.y+1,z=pos_predicted.z},entity) == "ok" then
|
||||
if math.random() < ( entity.dynamic_data.movement.mpattern.jump_up * PER_SECOND_CORRECTION_FACTOR) then
|
||||
local node_at_predicted_pos = minetest.env:get_node(pos_predicted)
|
||||
dbg_mobf.pmovement_lvl2("MOBF: velocity is:" .. printpos(movement_state.current_velocity) .. " position is: "..printpos(pos) )
|
||||
dbg_mobf.pmovement_lvl2("MOBF: estimated position was: "..printpos(pos_predicted))
|
||||
dbg_mobf.pmovement_lvl2("MOBF: predicted node state is: " .. environment.pos_is_ok(pos_predicted,entity))
|
||||
--if node_at_predicted_pos ~= nil then
|
||||
--dbg_mobf.movement_lvl1("MOBF: jumping onto: " .. node_at_predicted_pos.name)
|
||||
--end
|
||||
movement_state.accel_to_set = { x=0,y=nil,z=0 }
|
||||
movement_state.changed = true
|
||||
|
||||
--todo check if y pos is ok?!
|
||||
local jumppos = {x=pos_predicted.x,y=movement_state.centerpos.y+1,z=pos_predicted.z}
|
||||
|
||||
dbg_mobf.pmovement_lvl2("MOBF: mob " ..entity.data.name .. " is jumping, moving to:" .. printpos(jumppos))
|
||||
dbg_mobf.pmovement_lvl2("MOBF: target pos node state is: " .. environment.pos_is_ok(jumppos,entity))
|
||||
|
||||
entity.object:moveto(jumppos)
|
||||
--TODO set movement state positions
|
||||
--movement_state.basepos=
|
||||
--movement_state.centerpos=
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--redirect mob to block thats not above its current level
|
||||
--or jump if possible
|
||||
if movement_state.changed == false and pos_predicted_state == "collision" then
|
||||
dbg_mobf.pmovement_lvl1("MOBF: mob is about to collide")
|
||||
|
||||
local new_pos = environment.get_suitable_pos_same_level(movement_state.basepos,1,entity)
|
||||
|
||||
--there is at least one direction to go
|
||||
if new_pos ~= nil then
|
||||
movement_state.accel_to_set = movement_generic.get_accel_to(new_pos,entity)
|
||||
movement_state.changed = true
|
||||
|
||||
else
|
||||
local jumppos = nil
|
||||
--there ain't any acceptable pos at same level try to find one above current position
|
||||
new_pos = environment.get_suitable_pos_same_level({ x=movement_state.basepos.x,
|
||||
y=movement_state.basepos.y+1,
|
||||
z=movement_state.basepos.z},
|
||||
1,entity)
|
||||
|
||||
if new_pos ~= nil then
|
||||
jumppos = {x=new_pos.x,y=movement_state.centerpos.y+1,z=new_pos.z}
|
||||
end
|
||||
|
||||
--there ain't any acceptable pos at same level try to find one below current position
|
||||
new_pos = environment.get_suitable_pos_same_level({ x=movement_state.basepos.x,
|
||||
y=movement_state.basepos.y-1,
|
||||
z=movement_state.basepos.z},
|
||||
1,entity)
|
||||
|
||||
if new_pos ~= nil then
|
||||
jumppos = {x=new_pos.x,y=movement_state.centerpos.y-1,z=new_pos.z}
|
||||
end
|
||||
|
||||
|
||||
if jumppos ~= nil then
|
||||
dbg_mobf.pmovement_lvl2("MOBF: mob " ..entity.data.name .. " seems to be locked in, moving to:" .. printpos(jumppos))
|
||||
entity.object:moveto(jumppos)
|
||||
|
||||
movement_state.accel_to_set = { x=0,y=nil,z=0 }
|
||||
movement_state.changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--generic try to solve situation eg wrong surface
|
||||
if movement_state.changed == false then
|
||||
dbg_mobf.pmovement_lvl1("MOBF: generic try to resolve state " .. pos_predicted_state .. " for mob " .. entity.data.name .. " "..printpos(movement_state.basepos))
|
||||
movement_state.accel_to_set = direction_control.changeaccel(movement_state.basepos,
|
||||
entity,movement_state.current_velocity)
|
||||
if movement_state.accel_to_set ~= nil then
|
||||
movement_state.changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: random_movement_handler(entity,movement_state)
|
||||
--
|
||||
--! @brief generate a random y-movement
|
||||
--! @memberof direction_control
|
||||
--
|
||||
--! @param entity mob to apply random jump
|
||||
--! @param movement_state current movement state
|
||||
--! @return movement_state is modified!
|
||||
-------------------------------------------------------------------------------
|
||||
function direction_control.random_movement_handler(entity,movement_state)
|
||||
dbg_mobf.pmovement_lvl1("MOBF: random movement handler called")
|
||||
if movement_state.changed == false and
|
||||
(math.random() < (entity.dynamic_data.movement.mpattern.random_acceleration_change * PER_SECOND_CORRECTION_FACTOR) or
|
||||
movement_state.force_change) then
|
||||
|
||||
movement_state.accel_to_set = direction_control.changeaccel(movement_state.basepos,
|
||||
entity,movement_state.current_velocity)
|
||||
if movement_state.accel_to_set ~= nil then
|
||||
--retain current y acceleration
|
||||
movement_state.accel_to_set.y = movement_state.current_acceleration.y
|
||||
movement_state.changed = true
|
||||
end
|
||||
dbg_mobf.pmovement_lvl1("MOBF: randomly changing speed from "..printpos(movement_state.current_acceleration).." to "..printpos(movement_state.accel_to_set))
|
||||
end
|
||||
end
|
291
mods/mobf/mgen_probab/height_level_control.lua
Normal file
@ -0,0 +1,291 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file height_level_control.lua
|
||||
--! @brief component containing random drop features
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--! @ingroup mgen_probab
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--! @class height_level_control
|
||||
--! @brief class containing height level functionality
|
||||
height_level_control = {}
|
||||
|
||||
|
||||
--!@}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: calc_level_change_time(entity)
|
||||
--
|
||||
--! @brief calculate time required to change one height level
|
||||
--! @memberof height_level_control
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to calculate change time
|
||||
--! @param default_accel default accel for mob
|
||||
--! @return time in seconds
|
||||
-------------------------------------------------------------------------------
|
||||
function height_level_control.calc_level_change_time(entity,default_accel)
|
||||
local retval = 1 --default value
|
||||
|
||||
--calculate a reasonable value to stop level change
|
||||
if entity.data.movement.canfly == nil or
|
||||
entity.data.movement.canfly == false then --case mob can't fly
|
||||
return 0
|
||||
else
|
||||
-- if it's a flying mob and left it's normal medium
|
||||
if default_accel ~= 0 then
|
||||
retval = 0
|
||||
else
|
||||
retval = math.sqrt(2/entity.data.movement.min_accel)
|
||||
end
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: precheck_movement(entity,movement_state,pos_predicted,pos_predicted_state)
|
||||
--
|
||||
--! @brief check if there is a level change in progress that may
|
||||
-- need to be stopped
|
||||
--! @memberof height_level_control
|
||||
--
|
||||
--! @param entity mob to check for level change
|
||||
--! @param movement_state current state of movement
|
||||
--! @param pos_predicted position the mob will be next
|
||||
--! @param pos_predicted_state state of the next position
|
||||
-------------------------------------------------------------------------------
|
||||
function height_level_control.precheck_movement(entity,movement_state,pos_predicted,pos_predicted_state)
|
||||
|
||||
if entity.data.movement.canfly ~= nil and
|
||||
entity.data.movement.canfly == true and
|
||||
entity.dynamic_data.movement.changing_levels == true then
|
||||
|
||||
local level_change_time = height_level_control.calc_level_change_time(entity,movement_state.default_y_accel)
|
||||
|
||||
local time_completed = entity.dynamic_data.movement.ts_random_jump + level_change_time
|
||||
|
||||
dbg_mobf.pmovement_lvl1("MOBF: ".. movement_state.now .. " " .. entity.data.name ..
|
||||
" check complete level change " .. time_completed)
|
||||
|
||||
if entity.dynamic_data.movement.changing_levels and
|
||||
time_completed < movement_state.now then
|
||||
|
||||
dbg_mobf.pmovement_lvl2("MOBF: ".. movement_state.now .. " " .. entity.data.name ..
|
||||
" level change complete reestablishing default y acceleration " .. movement_state.default_y_accel)
|
||||
entity.dynamic_data.movement.changing_levels = false
|
||||
|
||||
movement_state.current_velocity.y = 0
|
||||
entity.object:setvelocity(movement_state.current_velocity)
|
||||
|
||||
movement_state.accel_to_set = movement_state.current_acceleration
|
||||
movement_state.accel_to_set.y = movement_state.default_y_accel
|
||||
movement_state.changed = true
|
||||
end
|
||||
end
|
||||
|
||||
--mob would fly/swim into height it shouldn't be
|
||||
if movement_state.changed == false then
|
||||
local invalid_pos_handled = false
|
||||
|
||||
--mob would fly/swim into height it shouldn't be
|
||||
if invalid_pos_handled == false and
|
||||
pos_predicted_state == "above_limit" then
|
||||
|
||||
local min_y,max_y = environment.get_absolute_min_max_pos(entity.environment,movement_state.basepos)
|
||||
|
||||
if (pos_predicted.y - max_y) > 10 then
|
||||
movement_state.override_height_change_chance = 1
|
||||
else
|
||||
movement_state.override_height_change_chance = (pos_predicted.y - max_y)/10
|
||||
end
|
||||
|
||||
invalid_pos_handled = true
|
||||
end
|
||||
|
||||
--mob would fly/swim into height it shouldn't be
|
||||
if invalid_pos_handled == false and
|
||||
pos_predicted_state == "below_limit" then
|
||||
|
||||
local min_y,max_y = environment.get_absolute_min_max_pos(entity.environment,movement_state.basepos)
|
||||
|
||||
if (min_y - pos_predicted.y) > 10 then
|
||||
movement_state.override_height_change_chance = 1
|
||||
else
|
||||
movement_state.override_height_change_chance = (min_y - pos_predicted.y)/10
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: random_jump_fly(entity,movement_state)
|
||||
--
|
||||
--! @brief apply random jump for flying mobs
|
||||
--! @memberof height_level_control
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to apply random jump
|
||||
--! @param movement_state current movement state
|
||||
--! @return movement_state is modified!
|
||||
-------------------------------------------------------------------------------
|
||||
function height_level_control.random_jump_fly(entity,movement_state)
|
||||
|
||||
--get some information
|
||||
local accel_to_set = movement_state.current_acceleration
|
||||
local current_state = environment.pos_is_ok(movement_state.basepos,entity)
|
||||
|
||||
--find direction
|
||||
local ydirection = 1
|
||||
|
||||
if current_state == "ok" then
|
||||
if math.random() <= 0.5 then
|
||||
ydirection = -1
|
||||
end
|
||||
end
|
||||
|
||||
if current_state == "above_limit" then
|
||||
ydirection = -1
|
||||
end
|
||||
|
||||
--state "below_limit" is already handled by initialization value
|
||||
|
||||
|
||||
--prepare basic information about what may be afterwards
|
||||
local targetpos = {x=movement_state.basepos.x,y=movement_state.basepos.y+ydirection,z=movement_state.basepos.z}
|
||||
local target_state = environment.pos_is_ok(targetpos,entity);
|
||||
|
||||
dbg_mobf.pmovement_lvl2("MOBF: " .. entity.data.name .." flying change y accel dir="..ydirection.." ypos="..movement_state.basepos.y..
|
||||
" min="..entity.environment.min_height_above_ground..
|
||||
" max="..entity.environment.max_height_above_ground..
|
||||
" below="..target_state)
|
||||
|
||||
--really do level change
|
||||
if (target_state == "ok") or
|
||||
target_state == current_state then
|
||||
|
||||
local min_y, max_y = environment.get_absolute_min_max_pos(entity.environment,movement_state.basepos)
|
||||
|
||||
dbg_mobf.pmovement_lvl2("MOBF: check level borders current=".. movement_state.basepos.y ..
|
||||
" min=" .. min_y ..
|
||||
" max=" .. max_y)
|
||||
|
||||
movement_state.accel_to_set.y = ydirection * entity.data.movement.min_accel
|
||||
entity.dynamic_data.movement.ts_random_jump = movement_state.now
|
||||
entity.dynamic_data.movement.changing_levels = true
|
||||
dbg_mobf.pmovement_lvl2("MOBF: " .. entity.data.name .. " " .. movement_state.now .. " " ..
|
||||
" changing level within borders: " .. movement_state.accel_to_set.y)
|
||||
movement_state.changed = true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: random_jump_ground(entity,movement_state)
|
||||
--
|
||||
--! @brief apply random jump for ground mobs
|
||||
--! @memberof height_level_control
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to apply random jump
|
||||
--! @param movement_state current movement state
|
||||
--! @return movement_state is a modification!
|
||||
-------------------------------------------------------------------------------
|
||||
function height_level_control.random_jump_ground(entity,movement_state)
|
||||
|
||||
if movement_state.default_y_accel == 0 then
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF BUG!!! ground mob can't have zero default acceleration!!!")
|
||||
end
|
||||
|
||||
local random_jump_time = 2 * (entity.dynamic_data.movement.mpattern.random_jump_initial_speed /
|
||||
math.abs(movement_state.default_y_accel))
|
||||
|
||||
local next_jump = entity.dynamic_data.movement.ts_random_jump +
|
||||
entity.dynamic_data.movement.mpattern.random_jump_delay +
|
||||
random_jump_time
|
||||
|
||||
dbg_mobf.movement_lvl2("MOBF: now=" .. movement_state.now .. " time of next jump=" .. next_jump ..
|
||||
" | " .. random_jump_time .. " " .. entity.dynamic_data.movement.mpattern.random_jump_delay .. " " ..
|
||||
entity.dynamic_data.movement.ts_random_jump .. " " .. movement_state.default_y_accel .. " " ..
|
||||
entity.dynamic_data.movement.mpattern.random_jump_initial_speed)
|
||||
|
||||
if movement_state.now > next_jump then
|
||||
|
||||
local ground_distance = mobf_ground_distance(movement_state.basepos)
|
||||
|
||||
|
||||
--we shouldn't be moving in y direction at that time so probably we are just dropping
|
||||
--we can only jump while on solid ground!
|
||||
if ground_distance <= 1 then
|
||||
|
||||
local current_speed = entity.object:getvelocity();
|
||||
|
||||
dbg_mobf.pmovement_lvl2("MOBF: " .. entity.data.name .." doing random jump "..
|
||||
"speed: " .. entity.dynamic_data.movement.mpattern.random_jump_initial_speed ..
|
||||
": ",entity)
|
||||
|
||||
current_speed.y = entity.dynamic_data.movement.mpattern.random_jump_initial_speed
|
||||
|
||||
entity.object:setvelocity(current_speed)
|
||||
|
||||
entity.dynamic_data.movement.ts_random_jump = movement_state.now
|
||||
else
|
||||
dbg_mobf.pmovement_lvl2("MOBF: " .. entity.data.name .. " Random jump but ground distance was:" .. ground_distance ..
|
||||
" " ..movement_state.current_acceleration.y ..
|
||||
" " ..movement_state.default_y_accel)
|
||||
|
||||
--this is a workaround for a bug
|
||||
--setting y acceleration to 0 for ground born mobs shouldn't be possible
|
||||
if movement_state.current_acceleration.y == 0 then
|
||||
movement_state.accel_to_set.x = movement_state.current_acceleration.x
|
||||
movement_state.accel_to_set.y = movement_state.default_y_accel
|
||||
movement_state.accel_to_set.z = movement_state.current_acceleration.z
|
||||
movement_state.changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: random_movement_handler(entity,movement_state)
|
||||
--
|
||||
--! @brief generate a random y-movement
|
||||
--! @memberof height_level_control
|
||||
--
|
||||
--! @param entity mob to apply random jump
|
||||
--! @param movement_state current movement state
|
||||
--! @return movement_state is a modified!
|
||||
-------------------------------------------------------------------------------
|
||||
function height_level_control.random_movement_handler(entity,movement_state)
|
||||
--generate random y movement changes
|
||||
if movement_state.changed == false and
|
||||
entity.dynamic_data.movement.changing_levels == false and
|
||||
(math.random() < entity.dynamic_data.movement.mpattern.random_jump_chance or
|
||||
math.random() < movement_state.override_height_change_chance) then
|
||||
|
||||
dbg_mobf.pmovement_lvl1("MOBF: Random jump chance for mob " .. entity.data.name .. " "..
|
||||
entity.dynamic_data.movement.ts_random_jump .. " "..
|
||||
entity.dynamic_data.movement.mpattern.random_jump_delay .. " " .. movement_state.now
|
||||
)
|
||||
|
||||
local to_set
|
||||
--flying/swiming mobs do level change on random jump chance
|
||||
if entity.data.movement.canfly then
|
||||
|
||||
height_level_control.random_jump_fly(entity,movement_state)
|
||||
--ground mobs
|
||||
else
|
||||
height_level_control.random_jump_ground(entity,movement_state)
|
||||
end
|
||||
end
|
||||
end
|
572
mods/mobf/mgen_probab/main_probab.lua
Normal file
@ -0,0 +1,572 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file main_probab.lua
|
||||
--! @brief component containing a probabilistic movement generator
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-09
|
||||
--
|
||||
--
|
||||
--! @defgroup mgen_probab MGEN: probabilistic movement generator
|
||||
--! @brief A movement generator trying to create a random movement
|
||||
--! @ingroup framework_int
|
||||
--! @{
|
||||
--
|
||||
--! @defgroup mpatterns Movement patterns
|
||||
--! @brief movement patterns used for probabilistic movement gen
|
||||
--
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--factor used to adjust chances defined as x/per second to on_step frequency
|
||||
PER_SECOND_CORRECTION_FACTOR = 0.25
|
||||
|
||||
--! @class movement_gen
|
||||
--! @brief a probabilistic movement generator
|
||||
movement_gen = {}
|
||||
|
||||
--! @brief movement patterns known to probabilistic movement gen
|
||||
mov_patterns_defined = {}
|
||||
|
||||
--!@}
|
||||
|
||||
dofile (mobf_modpath .. "/mgen_probab/movement_patterns/dont_move.lua")
|
||||
dofile (mobf_modpath .. "/mgen_probab/movement_patterns/run_and_jump_low.lua")
|
||||
dofile (mobf_modpath .. "/mgen_probab/movement_patterns/stop_and_go.lua")
|
||||
dofile (mobf_modpath .. "/mgen_probab/movement_patterns/swim_pattern1.lua")
|
||||
dofile (mobf_modpath .. "/mgen_probab/movement_patterns/swim_pattern2.lua")
|
||||
dofile (mobf_modpath .. "/mgen_probab/movement_patterns/flight_pattern1.lua")
|
||||
|
||||
dofile (mobf_modpath .. "/mgen_probab/height_level_control.lua")
|
||||
dofile (mobf_modpath .. "/mgen_probab/direction_control.lua")
|
||||
|
||||
--! @brief movement generator identifier
|
||||
--! @memberof movement_gen
|
||||
movement_gen.name = "probab_mov_gen"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: register_pattern(pattern)
|
||||
--
|
||||
--! @brief initialize movement generator
|
||||
--! @memberof movement_gen
|
||||
--
|
||||
--! @param pattern pattern to register
|
||||
--! @return true/false
|
||||
-------------------------------------------------------------------------------
|
||||
function movement_gen.register_pattern(pattern)
|
||||
print ("\tregistering pattern "..pattern.name)
|
||||
if mobf_rtd.movement_patterns[pattern.name] == nil then
|
||||
mobf_rtd.movement_patterns[pattern.name] = pattern
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: initialize(entity)
|
||||
--
|
||||
--! @brief initialize movement generator
|
||||
--! @memberof movement_gen
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function movement_gen.initialize()
|
||||
for index,value in ipairs(mov_patterns_defined) do
|
||||
movement_gen.register_pattern(value)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: callback(entity)
|
||||
--
|
||||
--! @brief main movement generation function
|
||||
--! @memberof movement_gen
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to generate movement for
|
||||
-------------------------------------------------------------------------------
|
||||
function movement_gen.callback(entity)
|
||||
|
||||
if entity == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: called movement gen without entity!")
|
||||
return
|
||||
end
|
||||
|
||||
if entity.dynamic_data == nil or
|
||||
entity.dynamic_data.movement == nil then
|
||||
mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: >" ..entity.data.name .. "< removed=" .. dump(entity.removed) .. " entity=" .. tostring(entity) .. " probab movement callback")
|
||||
return
|
||||
end
|
||||
|
||||
--initialize status datastructure
|
||||
local movement_state = {
|
||||
basepos = entity.getbasepos(entity),
|
||||
default_y_accel = nil,
|
||||
centerpos = entity.object:getpos(),
|
||||
current_acceleration = nil,
|
||||
current_velocity = entity.object:getvelocity(),
|
||||
now = nil,
|
||||
|
||||
override_height_change_chance = 0,
|
||||
accel_to_set = nil,
|
||||
force_change = false,
|
||||
changed = false,
|
||||
}
|
||||
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
-- --
|
||||
-- CHECK MOB POSITION --
|
||||
-- --
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
dbg_mobf.pmovement_lvl1("MOBF: position check for mob ".. entity.data.name .. " "..printpos(movement_state.basepos))
|
||||
movement_state.default_y_accel = environment.get_default_gravity(movement_state.basepos,
|
||||
entity.environment.media,
|
||||
entity.data.movement.canfly)
|
||||
mobf_assert_backtrace(movement_state.default_y_accel ~= nil)
|
||||
movement_state.now = mobf_get_current_time()
|
||||
|
||||
|
||||
--check current position
|
||||
--movement state is modified by this function
|
||||
local retval = movement_gen.fix_current_pos(entity, movement_state)
|
||||
|
||||
--mob has been removed due to unfixable problems
|
||||
if retval.abort_processing then
|
||||
return
|
||||
end
|
||||
|
||||
--read additional information required for further processing
|
||||
movement_state.current_acceleration = entity.object:getacceleration()
|
||||
|
||||
if movement_state.changed then
|
||||
minetest.log(LOGLEVEL_WARNING,"MOBF:position got fixed ".. entity.data.name)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
-- --
|
||||
-- CHECK MOB MOVEMENT ITSELF --
|
||||
-- --
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
dbg_mobf.pmovement_lvl1("MOBF: movement hard limits check for mob ".. entity.data.name .. " "..printpos(movement_state.basepos))
|
||||
|
||||
movement_gen.fix_runaway(entity,movement_state)
|
||||
movement_gen.fix_to_slow(entity,movement_state)
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
-- --
|
||||
-- DO / PREPARE CHANGES THAT NEED TO BE DONE BECAUSE OF MOB IS --
|
||||
-- PREDICTED TO BE SOMEWHERE WHERE IT SHOULDN'T BE --
|
||||
-- --
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
dbg_mobf.pmovement_lvl1("MOBF: movement check for mob ".. entity.data.name .. " "..printpos(movement_state.basepos))
|
||||
|
||||
--skip if movement already got changed
|
||||
if movement_state.changed == false then
|
||||
--predict next block mob will be
|
||||
local pos_predicted = movement_generic.predict_next_block( movement_state.basepos,
|
||||
movement_state.current_velocity,
|
||||
movement_state.current_acceleration)
|
||||
|
||||
local pos_predicted_state = environment.pos_is_ok(pos_predicted,entity)
|
||||
dbg_mobf.pmovement_lvl3("MOBF: Pos predicted state ".. entity.data.name .. ": " .. pos_predicted_state)
|
||||
-- Y-Movement
|
||||
if movement_state.changed == false then
|
||||
height_level_control.precheck_movement(entity,movement_state,pos_predicted,pos_predicted_state)
|
||||
end
|
||||
|
||||
-- X/Z-Movement
|
||||
if movement_state.changed == false then
|
||||
direction_control.precheck_movement(entity,movement_state,pos_predicted,pos_predicted_state)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
-- --
|
||||
-- DO RANDOM CHANGES TO MOB MOVEMENT --
|
||||
-- --
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
dbg_mobf.pmovement_lvl1("MOBF: randomized movement for mob ".. entity.data.name .. " "..printpos(movement_state.basepos))
|
||||
|
||||
--do randomized changes if not fighting
|
||||
height_level_control.random_movement_handler(entity,movement_state)
|
||||
direction_control.random_movement_handler(entity,movement_state)
|
||||
|
||||
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
-- --
|
||||
-- APPLY CHANGES CALCULATED BEFORE --
|
||||
-- --
|
||||
---------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
movement_gen.apply_movement_changes(entity,movement_state)
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: apply_movement_changes(entity,movement_state)
|
||||
--
|
||||
--! @brief check and apply the changes from movement_state
|
||||
--! @memberof movement_gen
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to apply changes
|
||||
--! @param movement_state changes to apply
|
||||
-------------------------------------------------------------------------------
|
||||
function movement_gen.apply_movement_changes(entity,movement_state)
|
||||
if movement_state.changed then
|
||||
|
||||
--check if there is a acceleration to set
|
||||
if movement_state.accel_to_set == nil then
|
||||
movement_state.accel_to_set = {x=0,
|
||||
y=movement_state.default_y_accel,
|
||||
z=0}
|
||||
entity.object:setvelocity({x=0,y=0,z=0})
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF BUG!!!! set accel requested but no accel given!")
|
||||
end
|
||||
|
||||
--check if gravity is set
|
||||
if movement_state.accel_to_set.y == nil then
|
||||
|
||||
--print("fixing y movement: ".. printpos(movement_state.accel_to_set))
|
||||
movement_state.accel_to_set.y = movement_state.current_acceleration.y
|
||||
end
|
||||
|
||||
-- make sure non flying mobs have default acceleration
|
||||
if entity.data.movement.canfly == false then
|
||||
movement_state.accel_to_set.y = movement_state.default_y_accel
|
||||
|
||||
if movement_state.default_y_accel == 0 then
|
||||
minetest.log(LOGLEVEL_ERROR,"MOBF BUG!!! " .. entity.data.name .. " mob that can't fly has acceleration 0!")
|
||||
end
|
||||
end
|
||||
|
||||
dbg_mobf.pmovement_lvl1("MOBF: setting acceleration to " ..printpos(movement_state.accel_to_set) )
|
||||
entity.dynamic_data.movement.acceleration = movement_state.accel_to_set
|
||||
entity.object:setacceleration(movement_state.accel_to_set)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: init_dynamic_data(entity,now)
|
||||
--
|
||||
--! @brief initialize dynamic data required by movement generator
|
||||
--! @memberof movement_gen
|
||||
--
|
||||
--! @param entity mob to initialize
|
||||
--! @param now current time
|
||||
-------------------------------------------------------------------------------
|
||||
function movement_gen.init_dynamic_data(entity,now)
|
||||
|
||||
local accel_to_set = {x=0,y=9.81,z=0}
|
||||
local pos = entity.object:getpos()
|
||||
|
||||
--initialize acceleration values
|
||||
accel_to_set.y = environment.get_default_gravity(pos,
|
||||
entity.environment.media,
|
||||
entity.data.movement.canfly)
|
||||
|
||||
mobf_assert_backtrace(accel_to_set.y ~= nil)
|
||||
|
||||
local data = {
|
||||
started = false,
|
||||
acceleration = accel_to_set,
|
||||
changing_levels = false,
|
||||
ts_random_jump = now,
|
||||
ts_orientation_upd = now,
|
||||
mpattern = mobf_rtd.movement_patterns[entity.data.movement.pattern],
|
||||
orientation_fix_needed = true,
|
||||
}
|
||||
|
||||
entity.dynamic_data.movement = data
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: fix_runaway(entity,movement_state)
|
||||
--
|
||||
--! @brief fix runaway speed mobs
|
||||
--! @memberof movement_gen
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to check speed limits
|
||||
--! @param movement_state current state of movement
|
||||
-------------------------------------------------------------------------------
|
||||
function movement_gen.fix_runaway(entity,movement_state)
|
||||
--avoid mobs racing away
|
||||
local xzspeed = math.sqrt(math.pow(movement_state.current_velocity.x,2)+
|
||||
math.pow(movement_state.current_velocity.z,2))
|
||||
dbg_mobf.pmovement_lvl3("MOBF: checkrunaway x=" .. movement_state.current_velocity.x ..
|
||||
" z=" ..movement_state.current_velocity.z ..
|
||||
" xz=" .. xzspeed ..
|
||||
" maximum=" .. entity.data.movement.max_speed)
|
||||
|
||||
if xzspeed > entity.data.movement.max_speed then
|
||||
dbg_mobf.pmovement_lvl3("MOBF: too fast! vxz=" .. xzspeed)
|
||||
dbg_mobf.pmovement_lvl3("MOBF: current acceleration:" .. printpos(movement_state.current_acceleration))
|
||||
local newaccel = {x=0,y=movement_state.current_acceleration.y,z=0}
|
||||
|
||||
--calculate sign of acceleration
|
||||
if movement_state.current_velocity.x > 0 and
|
||||
movement_state.current_acceleration.x >= 0 then
|
||||
newaccel.x = entity.data.movement.max_accel * -1
|
||||
else
|
||||
newaccel.x = entity.data.movement.max_accel
|
||||
end
|
||||
|
||||
if movement_state.current_velocity.z > 0 and
|
||||
movement_state.current_acceleration.z >= 0 then
|
||||
newaccel.z = entity.data.movement.max_accel * -1
|
||||
else
|
||||
newaccel.z = entity.data.movement.max_accel
|
||||
end
|
||||
|
||||
--calculate relative partition of acceleration based on velocity
|
||||
if movement_state.current_velocity.x > 0 and
|
||||
movement_state.current_velocity.z > 0 then
|
||||
newaccel.x = newaccel.x * movement_state.current_velocity.x /
|
||||
(movement_state.current_velocity.x+movement_state.current_velocity.z)
|
||||
newaccel.z = newaccel.z * movement_state.current_velocity.z /
|
||||
(movement_state.current_velocity.x+movement_state.current_velocity.z)
|
||||
end
|
||||
|
||||
dbg_mobf.pmovement_lvl3("MOBF: fixed acceleration:" .. printpos(newaccel))
|
||||
--set acceleration based on min acceleration
|
||||
movement_state.accel_to_set = newaccel
|
||||
movement_state.changed = true
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: fix_to_slow(entity,movement_state)
|
||||
--
|
||||
--! @brief check if mobs motion is below its minimal speed (e.g. flying birds)
|
||||
--! @memberof movement_gen
|
||||
--! @private
|
||||
--
|
||||
--! @param entity mob to check speed limits
|
||||
--! @param movement_state current state of movement
|
||||
-------------------------------------------------------------------------------
|
||||
function movement_gen.fix_to_slow(entity,movement_state)
|
||||
local xzspeed = math.sqrt(math.pow(movement_state.current_velocity.x,2) +
|
||||
math.pow(movement_state.current_velocity.z,2) )
|
||||
|
||||
dbg_mobf.pmovement_lvl3("MOBF: checktoslow x=" .. movement_state.current_velocity.x ..
|
||||
" z=" ..movement_state.current_velocity.z ..
|
||||
" xz=" .. xzspeed ..
|
||||
" minimum=" .. dump(entity.data.movement.min_speed))
|
||||
|
||||
--this ain't perfect to avoid flying mobs standing in air
|
||||
--but it's a quick solution to fix most of the problems
|
||||
if entity.data.movement.min_speed ~= nil and
|
||||
xzspeed < entity.data.movement.min_speed then
|
||||
|
||||
dbg_mobf.pmovement_lvl3("MOBF: too slow! vxz=" .. xzspeed)
|
||||
--use normal speed change handling
|
||||
movement_state.force_change = true
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- name: fix_current_pos(entity,movement_state)
|
||||
--
|
||||
--! @brief check current position for validity and try to fix
|
||||
--! @memberof movement_gen
|
||||
--! @private
|
||||
--
|
||||
--! @param entity to fix position
|
||||
--! @param movement_state movement state of mob
|
||||
--! @return { speed_to_set = {x,y,z}, speed_changed = true/false, force_speed_change = true/false }
|
||||
-------------------------------------------------------------------------------
|
||||
function movement_gen.fix_current_pos(entity,movement_state)
|
||||
|
||||
--check if current pos is ok
|
||||
local current_state = environment.pos_is_ok(movement_state.basepos,entity)
|
||||
local handled = false
|
||||
|
||||
dbg_mobf.pmovement_lvl3("MOBF: current state ".. entity.data.name .. ": " .. current_state)
|
||||
|
||||
movement_state.accel_to_set = { x=0,
|
||||
y=movement_state.default_y_accel,
|
||||
z=0 }
|
||||
|
||||
local abort_processing = false
|
||||
|
||||
if current_state == "ok" or
|
||||
current_state == "possible_surface" then
|
||||
entity.dynamic_data.movement.last_pos_in_env = movement_state.centerpos
|
||||
handled = true
|
||||
end
|
||||
|
||||
--states ok drop and wrong_surface don't require an imediate action
|
||||
if current_state ~= "ok" and
|
||||
current_state ~= "drop" and
|
||||
current_state ~= "wrong_surface" and
|
||||
current_state ~= "possible_surface" and
|
||||
current_state ~= "below_limit" and
|
||||
current_state ~= "above_limit" then
|
||||
dbg_mobf.movement_lvl1("MOBF: BUG !!! somehow your mob managed to get where it shouldn't be, trying to fix")
|
||||
|
||||
--stop mob from moving at all
|
||||
entity.object:setacceleration({x=0,y=movement_state.default_y_accel,z=0})
|
||||
movement_state.force_change = true
|
||||
|
||||
--mob is currently in whater try to find a suitable position 1 level above current level
|
||||
if current_state == "in_water" or
|
||||
current_state == "above_water" then
|
||||
|
||||
local targetpos = nil
|
||||
|
||||
--if we don't have an old pos or old pos is to far away try to finde another good pos around
|
||||
if entity.dynamic_data.movement.last_pos_in_env == nil or
|
||||
entity.dynamic_data.movement.last_pos_in_env.y > movement_state.centerpos.y + 2 then
|
||||
targetpos = environment.get_suitable_pos_same_level({x=movement_state.basepos.x,
|
||||
y=movement_state.basepos.y+1,
|
||||
z=movement_state.basepos.z},
|
||||
1,
|
||||
entity)
|
||||
if targetpos ~= nil then
|
||||
targetpos.y = targetpos.y - entity.collisionbox[2]
|
||||
end
|
||||
else
|
||||
targetpos = entity.dynamic_data.movement.last_pos_in_env
|
||||
end
|
||||
|
||||
if targetpos ~= nil then
|
||||
mobf_bug_warning(LOGLEVEL_INFO,"MOBF: BUG !!! didn't find a way out of water, for mob at: " .. printpos(movement_state.basepos) .. " using last known good position")
|
||||
|
||||
if targetpos == nil then
|
||||
targetpos = entity.dynamic_data.movement.last_pos_in_env
|
||||
else
|
||||
targetpos.y = targetpos.y+1 --TODO use collision box
|
||||
end
|
||||
|
||||
minetest.log(LOGLEVEL_WARNING,"MOBF: Your mob " .. tostring(entity) .. " dropt into water moving to "..
|
||||
printpos(targetpos).." state: "..
|
||||
environment.pos_is_ok(targetpos,entity))
|
||||
entity.object:moveto(targetpos)
|
||||
movement_state.current_velocity.x = movement_state.current_velocity.x/10
|
||||
movement_state.current_velocity.z = movement_state.current_velocity.z/10
|
||||
entity.object:setvelocity(movement_state.current_velocity)
|
||||
movement_state.centerpos = targetpos
|
||||
movement_state.basepos = entity.getbasepos(entity)
|
||||
movement_state.accel_to_set.y = environment.get_default_gravity(targetpos,
|
||||
entity.environment.media,
|
||||
entity.data.movement.canfly)
|
||||
mobf_assert_backtrace(movement_state.accel_to_set.y ~= nil)
|
||||
else
|
||||
mobf_bug_warning(LOGLEVEL_WARNING,"MOBF: BUG !!! didn't find a way out of water, for mob at: " .. printpos(movement_state.basepos) .. " drowning " .. dump(entity.dynamic_data.movement.last_pos_in_env))
|
||||
abort_processing = true
|
||||
spawning.remove(entity, "mgen probab watercheck")
|
||||
end
|
||||
|
||||
handled = true
|
||||
end
|
||||
|
||||
if current_state == "in_air" then
|
||||
--TODO die?
|
||||
handled = true
|
||||
end
|
||||
end
|
||||
|
||||
local damagetime = 60
|
||||
|
||||
if entity.data.generic.wrong_surface_damage_time ~= nil then
|
||||
damagetime = entity.data.generic.wrong_surface_damage_time
|
||||
end
|
||||
|
||||
if current_state == "wrong_surface" and
|
||||
entity.dynamic_data.good_surface ~= nil then
|
||||
if movement_state.now - entity.dynamic_data.good_surface > damagetime then
|
||||
|
||||
entity.object:set_hp(entity.object:get_hp() - (entity.data.generic.base_health/25))
|
||||
dbg_mobf.movement_lvl1("MOBF: mob is on wrong surface it will slowly take damage")
|
||||
|
||||
--reset timer for next damage interval
|
||||
entity.dynamic_data.good_surface = movement_state.now
|
||||
if entity.object:get_hp() <= 0 then
|
||||
abort_processing = true
|
||||
spawning.remove(entity, "mgen probab surfacecheck")
|
||||
end
|
||||
|
||||
movement_state.force_change = true
|
||||
end
|
||||
|
||||
handled = true
|
||||
else
|
||||
entity.dynamic_data.good_surface = movement_state.now
|
||||
end
|
||||
|
||||
if current_state == "collision" then
|
||||
local current_pos = mobf_round_pos(movement_state.basepos);
|
||||
local current_node = minetest.env:get_node( current_pos );
|
||||
|
||||
dbg_mobf.movement_lvl3( "MOBF: Mob collided with "..tostring( current_pos.x )..":"..
|
||||
tostring( current_pos.y )..":"..
|
||||
tostring( current_pos.z ).." Nodename:"..
|
||||
tostring( current_node.name ).." walkable:"..
|
||||
tostring( minetest.registered_nodes[current_node.name].walkable ))
|
||||
|
||||
if not mobf_is_walkable(current_node) then
|
||||
local targetpos = environment.get_suitable_pos_same_level({x=current_pos.x,
|
||||
y=current_pos.y,
|
||||
z=current_pos.z},
|
||||
1,
|
||||
entity)
|
||||
if targetpos == nil then
|
||||
local targetpos = environment.get_suitable_pos_same_level({x=current_pos.x,
|
||||
y=current_pos.y+1,
|
||||
z=current_pos.z},
|
||||
1,
|
||||
entity)
|
||||
end
|
||||
|
||||
if targetpos ~= nil then
|
||||
minetest.log(LOGLEVEL_WARNING,"MOBF: Your mob " ..entity.data.name .. " is within solid block moving to"..
|
||||
printpos(targetpos).." state: "..
|
||||
environment.pos_is_ok(targetpos,entity))
|
||||
|
||||
entity.object:moveto(targetpos)
|
||||
movement_state.accel_to_set.y = environment.get_default_gravity(targetpos,
|
||||
entity.environment.media,
|
||||
entity.data.movement.canfly)
|
||||
mobf_assert_backtrace(movement_state.default_y_accel ~= nil)
|
||||
else
|
||||
minetest.log(LOGLEVEL_WARNING,"MOBF: mob " .. entity.data.name .. " was within solid block, removed")
|
||||
abort_processing = true
|
||||
spawning.remove(entity, "mgen probab solidblockcheck")
|
||||
end
|
||||
end
|
||||
|
||||
handled = true
|
||||
end
|
||||
|
||||
if not handled then
|
||||
dbg_mobf.movement_lvl1("MOBF: ".. entity.data.name .. " state: ".. current_state .. " not handled!")
|
||||
end
|
||||
|
||||
return { abort_processing=abort_processing, }
|
||||
end
|
||||
|
||||
|
||||
--register this movement generator
|
||||
registerMovementGen(movement_gen.name,movement_gen)
|
39
mods/mobf/mgen_probab/movement_patterns/dont_move.lua
Normal file
@ -0,0 +1,39 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file dont_move.lua
|
||||
--! @brief movementpattern for immobile mob
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup mpatterns
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--! @struct dont_move_prototype
|
||||
--! @brief a movement pattern resulting in a mob not moving at all
|
||||
local dont_move_prototype = {
|
||||
name ="dont_move",
|
||||
jump_up =0,
|
||||
|
||||
random_jump_chance =0,
|
||||
random_jump_initial_speed =0,
|
||||
random_jump_delay =0,
|
||||
random_acceleration_change =0,
|
||||
--
|
||||
-- --run towards player or run away? 1 <-> -1
|
||||
-- player_attraction =0,
|
||||
-- --maximum distance a player has an effect
|
||||
-- player_attraction_range =-1,
|
||||
}
|
||||
|
||||
--!@}
|
||||
|
||||
table.insert(mov_patterns_defined,dont_move_prototype)
|
39
mods/mobf/mgen_probab/movement_patterns/flight_pattern1.lua
Normal file
@ -0,0 +1,39 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file flight_pattern1.lua
|
||||
--! @brief movementpattern flight 1
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup mpatterns
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--! @struct flight_pattern1_prototype
|
||||
--! @brief a movement pattern used for flying mobs
|
||||
local flight_pattern1_prototype = {
|
||||
name ="flight_pattern1",
|
||||
jump_up =0,
|
||||
|
||||
random_jump_chance =0.4,
|
||||
random_jump_initial_speed =0,
|
||||
random_jump_delay =10,
|
||||
random_acceleration_change =0.3,
|
||||
--
|
||||
-- --run towards player or run away? 1 <-> -1
|
||||
-- player_attraction =0,
|
||||
-- --maximum distance a player has an effect
|
||||
-- player_attraction_range =-1,
|
||||
}
|
||||
|
||||
--!@}
|
||||
|
||||
table.insert(mov_patterns_defined,flight_pattern1_prototype)
|
41
mods/mobf/mgen_probab/movement_patterns/run_and_jump_low.lua
Normal file
@ -0,0 +1,41 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Mob Framework Mod by Sapier
|
||||
--
|
||||
-- You may copy, use, modify or do nearly anything except removing this
|
||||
-- copyright notice.
|
||||
-- And of course you are NOT allow to pretend you have written it.
|
||||
--
|
||||
--! @file run_and_jump_low.lua
|
||||
--! @brief movementpattern running arround ad doing random low jumps
|
||||
--! @copyright Sapier
|
||||
--! @author Sapier
|
||||
--! @date 2012-08-10
|
||||
--
|
||||
--! @addtogroup mpatterns
|
||||
--! @{
|
||||
-- Contact sapier a t gmx net
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--! @struct run_and_jump_low_prototype
|
||||
--! @brief a movement pattern used for quick moving and direction changing mobs
|
||||
--! that jump every now and then
|
||||
local run_and_jump_low_prototype = {
|
||||
name ="run_and_jump_low",
|
||||
jump_up =0.2,
|
||||
|
||||
random_jump_chance =0.3,
|
||||
random_jump_initial_speed =3.5,
|
||||
random_jump_delay =2,
|
||||
random_acceleration_change =0.6,
|
||||
|
||||
--
|
||||
-- --run towards player or run away? 1 <-> -1
|
||||
-- player_attraction =0,
|
||||
-- --maximum distance a player has an effect
|
||||
-- player_attraction_range =-1,
|
||||
}
|
||||
|
||||
--!~@}
|
||||
|
||||
table.insert(mov_patterns_defined,run_and_jump_low_prototype)
|