Remove magic.
15
README.md
|
@ -1,14 +1,11 @@
|
|||
# Kingdoms and Magic by Beha
|
||||
# Kingdoms by Beha
|
||||
|
||||
The Kingdoms + Magic modpack is designed to allow kingdom vs kingdom PvP in Minetest, along with a wide variety of spells and nodes to attack and defend kingdoms.
|
||||
The Kingdoms modpack is designed to allow kingdom vs kingdom PvP in Minetest.
|
||||
|
||||
Interesting features include:
|
||||
|
||||
* A fully formspec-based kingdom manager.
|
||||
* Chat channels for the area, your kingdom, and everywhere.
|
||||
* Many magic crystals and essences which combine to form powerful devices and spells.
|
||||
* Several damage types and defenses.
|
||||
* The ability to hunt mobs via missile bombs.
|
||||
|
||||
# Modifications
|
||||
|
||||
|
@ -16,7 +13,7 @@ This modpack contains some alternative versions of mods with modifications to wo
|
|||
|
||||
* bones: drop items upon explosion, respect kingdom heavy_chests level.
|
||||
* doors: respect kingdom levels, add heavy doors.
|
||||
* tnt: respect explosion blockers/absorbers, work better with objects and mobs, deal damage through magic.damage_obj.
|
||||
* tnt: respect explosion blockers/absorbers, work better with objects and mobs, support magic.
|
||||
|
||||
Kingdoms also overrides a few default items.
|
||||
* chests: respect kingdom levels, add heavy chests.
|
||||
|
@ -32,9 +29,7 @@ Kingdoms also overrides a few default items.
|
|||
# Recommended/Tested Mods
|
||||
|
||||
* [ancient_world](https://github.com/shacknetisp/ancient_world) has been hooked into for generating magic crystals and silver blocks as hidden rewards.
|
||||
* [magic](https://github.com/shacknetisp/magic) is recommended.
|
||||
|
||||
* 3d_armor is fully compatible with kingdoms + magic and provides a variety of protections against all forms of "fleshy" damage. Kingdoms will disable the healing feature automatically.
|
||||
* 3d_armor is fully compatible with kingdoms and provides a variety of protections against all forms of "fleshy" damage. Kingdoms will disable the healing feature automatically.
|
||||
* unified_inventory is hooked into with a kingdoms button.
|
||||
|
||||
* Most hunger mods will work, the mana bar from magic is placed above the usual hunger bar location.
|
||||
* Most mob mods will be compatible with magic's damage system. Mobs such as Dungeon Masters should not deal direct damage to nodes (especially protected nodes), but should channel their destruction through the included tnt mod.
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
local has_magic = rawget(_G, 'magic') ~= nil
|
||||
local essences = {
|
||||
concentrated_area = has_magic and "magic:concentrated_area_essence" or "group:major_spellbinding",
|
||||
control = has_magic and "magic:control_essence" or "group:spellbinding",
|
||||
concentrated_control = has_magic and "magic:concentrated_control_essence" or "group:major_spellbinding",
|
||||
solidity = has_magic and "magic:solidity_essence" or "group:spellbinding",
|
||||
concentrated_solidity = has_magic and "magic:concentrated_solidity_essence" or "group:major_spellbinding",
|
||||
rage = has_magic and "magic:rage_essence" or "group:spellbinding",
|
||||
vitality = has_magic and "magic:vitality_essence" or "group:spellbinding",
|
||||
concentrated_vitality = has_magic and "magic:concentrated_vitality_essence" or "group:major_spellbinding",
|
||||
}
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'default:chest_locked_heavy',
|
||||
recipe = {
|
||||
|
@ -8,24 +20,24 @@ minetest.register_craft({
|
|||
minetest.register_craft({
|
||||
output = "kingdoms:corestone",
|
||||
recipe = {
|
||||
{"magic:concentrated_area_essence", "magic:control_essence"},
|
||||
{essences.concentrated_area, essences.control},
|
||||
{"default:steelblock", "group:spellbinding"},
|
||||
{"magic:solidity_essence", "group:major_spellbinding"}
|
||||
{essences.solidity, "group:major_spellbinding"}
|
||||
}
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "kingdoms:claimward",
|
||||
recipe = {
|
||||
{"magic:area_essence", ""},
|
||||
{"default:steelblock", "magic:control_essence"},
|
||||
{essences.area, ""},
|
||||
{"default:steelblock", essences.control},
|
||||
{"group:spellbinding", ""}
|
||||
}
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "kingdoms:core_disruptor",
|
||||
recipe = {
|
||||
{"magic:concentrated_area_essence", "magic:rage_essence"},
|
||||
{"default:steelblock", "magic:concentrated_control_essence"},
|
||||
{essences.concentrated_area, essences.rage},
|
||||
{"default:steelblock", essences.concentrated_control},
|
||||
{"group:major_spellbinding", ""}
|
||||
}
|
||||
})
|
||||
|
@ -34,16 +46,16 @@ minetest.register_craft({
|
|||
minetest.register_craft({
|
||||
output = "kingdoms:materialized_wall_1 9",
|
||||
recipe = {
|
||||
{"magic:vitality_essence", "", ""},
|
||||
{essences.vitality, "", ""},
|
||||
{"group:stone", "group:stone", "group:stone"},
|
||||
{"magic:concentrated_solidity_essence", "", ""}
|
||||
{essences.concentrated_solidity, "", ""}
|
||||
}
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "kingdoms:materializer",
|
||||
recipe = {
|
||||
{"magic:concentrated_vitality_essence", "magic:area_essence"},
|
||||
{essences.concentrated_vitality, essences.area},
|
||||
{"group:stone", "group:major_spellbinding"},
|
||||
{"magic:concentrated_solidity_essence", ""}
|
||||
{essences.concentrated_solidity, ""}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
default
|
||||
kingdoms_meta
|
||||
magic
|
||||
magic?
|
||||
ancient_world?
|
||||
3d_armor?
|
||||
|
|
|
@ -6,4 +6,3 @@ if kingdoms.config.mapgen then
|
|||
|
||||
kingdoms.log("action", "Applied mapgen settings.")
|
||||
end
|
||||
magic.register_mapgen()
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
function magic.register_crystal_craft(def)
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = "magic:"..def.name.."_essence",
|
||||
recipe = "magic:crystal_"..def.name,
|
||||
cooktime = 6,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "magic:crystal_"..def.name,
|
||||
recipe = {"magic:"..def.name.."_essence", "group:spellbinding", "group:stone"}
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "magic:"..def.name.."_essence 3",
|
||||
recipe = {"magic:concentrated_"..def.name.."_essence"}
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "magic:concentrated_"..def.name.."_essence",
|
||||
recipe = {"magic:"..def.name.."_essence", "magic:"..def.name.."_essence", "magic:"..def.name.."_essence"}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "magic:crystal_"..def.name.." 9",
|
||||
recipe = {"magic:concentrated_crystal_"..def.name}
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:concentrated_crystal_"..def.name,
|
||||
recipe = {
|
||||
{"magic:crystal_"..def.name, "magic:crystal_"..def.name, "magic:crystal_"..def.name},
|
||||
{"magic:crystal_"..def.name, "magic:crystal_"..def.name, "magic:crystal_"..def.name},
|
||||
{"magic:crystal_"..def.name, "magic:crystal_"..def.name, "magic:crystal_"..def.name},
|
||||
},
|
||||
})
|
||||
|
||||
if def.fuel then
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "magic:crystal_"..def.name,
|
||||
burntime = def.fuel,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "magic:null_essence 4",
|
||||
recipe = {"group:minor_essence", "default:gold_ingot", "group:minor_essence"},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "magic:nightcall",
|
||||
recipe = {
|
||||
{"magic:area_essence", "group:spellbinding", ""},
|
||||
{"default:bronzeblock", "magic:calm_essence", "magic:control_essence"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "magic:daypull",
|
||||
recipe = {
|
||||
{"magic:area_essence", "group:spellbinding", ""},
|
||||
{"default:bronzeblock", "magic:rage_essence", "magic:control_essence"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "magic:turret",
|
||||
recipe = {
|
||||
{"magic:rage_essence", "magic:control_essence"},
|
||||
{"default:steelblock", "group:spellbinding"},
|
||||
},
|
||||
})
|
|
@ -1,259 +0,0 @@
|
|||
magic.crystals = {
|
||||
{
|
||||
name = "rage",
|
||||
desc = "Rage",
|
||||
color = "#A00",
|
||||
light = 10,
|
||||
fuel = 500,
|
||||
ores = {
|
||||
{
|
||||
rarity = 4 * 4 * 4,
|
||||
clust_num_ores = 1,
|
||||
clust_size = 1,
|
||||
wherein = "default:lava_source",
|
||||
y_max = -64,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name = "solidity",
|
||||
desc = "Solidity",
|
||||
color = "#AA0",
|
||||
light = 4,
|
||||
},
|
||||
{
|
||||
name = "area",
|
||||
desc = "Area",
|
||||
color = "#033",
|
||||
light = 8,
|
||||
},
|
||||
{
|
||||
name = "warp",
|
||||
desc = "Warp",
|
||||
color = "#0CC",
|
||||
light = 13,
|
||||
rarity = 0.5,
|
||||
},
|
||||
{
|
||||
name = "control",
|
||||
desc = "Control",
|
||||
color = "#707",
|
||||
light = 7,
|
||||
},
|
||||
{
|
||||
name = "vitality",
|
||||
desc = "Vitality",
|
||||
color = "#0F0",
|
||||
light = 12,
|
||||
ores = {
|
||||
{
|
||||
rarity = 18 * 18 * 18,
|
||||
clust_num_ores = 1,
|
||||
clust_size = 1,
|
||||
wherein = "default:dirt",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name = "calm",
|
||||
desc = "Calm",
|
||||
color = "#00F",
|
||||
light = 5,
|
||||
ores = {
|
||||
{
|
||||
rarity = 4 * 4 * 4,
|
||||
clust_num_ores = 1,
|
||||
clust_size = 1,
|
||||
wherein = "default:water_source",
|
||||
y_max = -128,
|
||||
},
|
||||
{
|
||||
rarity = 16 * 16 * 16,
|
||||
clust_num_ores = 1,
|
||||
clust_size = 1,
|
||||
wherein = "default:water_source",
|
||||
y_min = -128,
|
||||
y_max = -8,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name = "day",
|
||||
desc = "Day",
|
||||
color = "#FFF",
|
||||
light = 14,
|
||||
fuel = 350,
|
||||
nodefgen = true,
|
||||
ores = {
|
||||
{
|
||||
rarity = 15 * 15 * 15,
|
||||
clust_num_ores = 3,
|
||||
clust_size = 2,
|
||||
y_min = 400,
|
||||
wherein = "air"
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name = "night",
|
||||
desc = "Night",
|
||||
color = "#000",
|
||||
light = 0,
|
||||
nodefgen = true,
|
||||
ores = {
|
||||
{
|
||||
rarity = 15 * 15 * 15,
|
||||
clust_num_ores = 3,
|
||||
clust_size = 2,
|
||||
y_min = 400,
|
||||
wherein = "air"
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
minetest.register_craftitem("magic:null_essence", {
|
||||
description = "Null Essence",
|
||||
inventory_image = "magic_essence.png",
|
||||
})
|
||||
|
||||
function magic.register_crystal(def, nocraft)
|
||||
minetest.register_node("magic:crystal_"..def.name, {
|
||||
description = def.desc.." Crystal",
|
||||
drawtype = "glasslike",
|
||||
tiles = {"magic_crystal.png^[colorize:"..def.color..":"..tostring(0xCC)},
|
||||
groups = {cracky = 2, not_in_creative_inventory = (def.hidecrystal and 1 or 0)},
|
||||
light_source = def.light or 7,
|
||||
sunlight_propagates = true,
|
||||
use_texture_alpha = true,
|
||||
paramtype = "light",
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("magic:concentrated_crystal_"..def.name, {
|
||||
description = "Compressed "..def.desc.." Crystal",
|
||||
tiles = {"magic_concentrated_crystal.png^[colorize:"..def.color..":"..tostring(0xCC)},
|
||||
is_ground_content = false,
|
||||
drawtype = "glasslike",
|
||||
light_source = def.light or 7,
|
||||
sunlight_propagates = true,
|
||||
use_texture_alpha = true,
|
||||
paramtype = "light",
|
||||
groups = {cracky = 2, not_in_creative_inventory = (def.hidecrystal and 1 or 0)},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
if rawget(_G, 'ancient_world') then
|
||||
ancient_world.register_item("magic:concentrated_crystal_"..def.name, (4 / #magic.crystals) * (def.rarity or 1))
|
||||
end
|
||||
|
||||
minetest.register_craftitem("magic:"..def.name.."_essence", {
|
||||
description = def.desc.." Essence",
|
||||
inventory_image = "magic_essence.png^[colorize:"..def.color..":"..tostring(0xCC),
|
||||
groups = {minor_essence = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("magic:concentrated_"..def.name.."_essence", {
|
||||
description = "Concentrated "..def.desc.." Essence",
|
||||
inventory_image = "magic_concentrated_essence.png^[colorize:"..def.color..":"..tostring(0xCC),
|
||||
})
|
||||
|
||||
local ndefd = {
|
||||
ore_type = "scatter",
|
||||
ore = "magic:crystal_"..def.name,
|
||||
wherein = "default:stone",
|
||||
clust_num_ores = 1,
|
||||
clust_size = 1,
|
||||
y_min = -31000,
|
||||
y_max = 31000,
|
||||
}
|
||||
|
||||
if def.ores then
|
||||
for _,oredef in ipairs(def.ores) do
|
||||
local ndef = table.copy(ndefd)
|
||||
ndef.clust_scarcity = oredef.rarity * #magic.crystals * (def.rarity or 1)
|
||||
for k,v in pairs(oredef) do
|
||||
ndef[k] = v
|
||||
end
|
||||
minetest.register_ore(ndef)
|
||||
end
|
||||
end
|
||||
|
||||
if not def.nodefgen then
|
||||
local ores = {
|
||||
-- 30k belt.
|
||||
{
|
||||
rarity = 8 * 8 * 8,
|
||||
clust_num_ores = 4,
|
||||
clust_size = 3,
|
||||
y_max = -30000,
|
||||
y_min = -30008,
|
||||
},
|
||||
-- 20k belt.
|
||||
{
|
||||
rarity = 9 * 9 * 9,
|
||||
clust_num_ores = 4,
|
||||
clust_size = 3,
|
||||
y_max = -20000,
|
||||
y_min = -20016,
|
||||
},
|
||||
-- 10k belt.
|
||||
{
|
||||
rarity = 10 * 10 * 10,
|
||||
clust_num_ores = 4,
|
||||
clust_size = 3,
|
||||
y_max = -10000,
|
||||
y_min = -10025,
|
||||
},
|
||||
{
|
||||
rarity = 12 * 12 * 12,
|
||||
clust_num_ores = 4,
|
||||
clust_size = 2,
|
||||
y_max = -2048,
|
||||
},
|
||||
{
|
||||
rarity = 13 * 13 * 13,
|
||||
clust_num_ores = 3,
|
||||
clust_size = 2,
|
||||
y_max = -1024,
|
||||
y_min = -2048,
|
||||
},
|
||||
{
|
||||
rarity = 14 * 14 * 14,
|
||||
clust_num_ores = 3,
|
||||
clust_size = 2,
|
||||
y_max = -512,
|
||||
y_min = -1024,
|
||||
},
|
||||
{
|
||||
rarity = 16 * 16 * 16,
|
||||
clust_num_ores = 3,
|
||||
clust_size = 2,
|
||||
y_max = -64,
|
||||
y_min = -512,
|
||||
},
|
||||
{
|
||||
rarity = 14 * 14 * 14,
|
||||
clust_num_ores = 3,
|
||||
clust_size = 2,
|
||||
y_min = 50,
|
||||
},
|
||||
}
|
||||
for _,oredef in ipairs(ores) do
|
||||
local ndef = table.copy(ndefd)
|
||||
ndef.clust_scarcity = oredef.rarity * #magic.crystals * (def.rarity or 1)
|
||||
for k,v in pairs(oredef) do
|
||||
ndef[k] = v
|
||||
end
|
||||
minetest.register_ore(ndef)
|
||||
end
|
||||
end
|
||||
|
||||
if not nocraft then
|
||||
magic.register_crystal_craft(def)
|
||||
end
|
||||
end
|
||||
|
||||
for _,def in ipairs(magic.crystals) do
|
||||
magic.register_crystal(def)
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
-- Maximum mana.
|
||||
magic.config.max_mana = 20
|
||||
|
||||
-- Seconds to regnerate one mana point. (Faster if mana_fast_regen_threshold applies.)
|
||||
magic.config.mana_regen = 6
|
||||
-- If player HP is >= this, mana will regenerate faster.
|
||||
magic.config.mana_fast_regen_threshold = 18
|
||||
-- Fast regeneration multiplier.
|
||||
magic.config.mana_fast_regen = 2
|
||||
|
||||
-- Search radius of a missile turret.
|
||||
magic.config.turret_missile_radius = 24
|
||||
-- Block radius of a defense turret.
|
||||
magic.config.turret_shield_radius = 5
|
||||
|
||||
-- Delay before actually teleporting.
|
||||
magic.config.teleportation_delay = 5
|
||||
|
||||
-- Enable short teleports.
|
||||
magic.config.enable_short_teleports = true
|
|
@ -1,4 +0,0 @@
|
|||
default
|
||||
kingdoms_meta
|
||||
ancient_world?
|
||||
tnt?
|
|
@ -1,40 +0,0 @@
|
|||
-- Function to execute more files.
|
||||
local modpath = minetest.get_modpath("magic")
|
||||
local function domodfile(f)
|
||||
dofile(modpath .. '/' .. f)
|
||||
end
|
||||
|
||||
-- Mod namespace.
|
||||
magic = {}
|
||||
|
||||
magic.config = kingdoms.config_table("magic")
|
||||
magic.log = kingdoms.log_function("magic")
|
||||
domodfile("defaults.lua")
|
||||
|
||||
minetest.override_item("default:mese", {
|
||||
groups = {cracky = 1, level = 2, major_spellbinding = 1}
|
||||
})
|
||||
|
||||
domodfile("mana.lua")
|
||||
domodfile("throwing.lua")
|
||||
domodfile("mapgen.lua")
|
||||
|
||||
domodfile("crafts.lua")
|
||||
|
||||
domodfile("timegens.lua")
|
||||
domodfile("crystals.lua")
|
||||
domodfile("spells.lua")
|
||||
domodfile("potions.lua")
|
||||
domodfile("turrets.lua")
|
||||
|
||||
domodfile("spells/action.lua")
|
||||
domodfile("spells/attack.lua")
|
||||
domodfile("spells/defense.lua")
|
||||
domodfile("spells/teleportation.lua")
|
||||
|
||||
if rawget(_G, "ancient_world") then
|
||||
domodfile("structures.lua")
|
||||
end
|
||||
|
||||
magic.log("action", "Loaded.")
|
||||
kingdoms.mod_ready("magic")
|
|
@ -1,79 +0,0 @@
|
|||
magic.manadb = {}
|
||||
local huds = {}
|
||||
local timer = 0
|
||||
|
||||
kingdoms.at_mod_load("kingdoms", function()
|
||||
kingdoms.db.magic = kingdoms.db.magic or {}
|
||||
kingdoms.db.magic.mana = kingdoms.db.magic.mana or {}
|
||||
magic.manadb = kingdoms.db.magic.mana
|
||||
end)
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer < 0.1 then return end
|
||||
timer = 0
|
||||
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local name = player:get_player_name()
|
||||
local p = magic.manadb[name]
|
||||
p.mana = math.min(p.max_mana, p.mana + (dtime / magic.config.mana_regen) * (player:get_hp() >= magic.config.mana_fast_regen_threshold and magic.config.mana_fast_regen or 1 ))
|
||||
local hud = huds[name]
|
||||
if not hud then
|
||||
hud = {}
|
||||
huds[name] = hud
|
||||
hud.id = player:hud_add({
|
||||
name = "mana",
|
||||
hud_elem_type = "statbar",
|
||||
position = {x = 0.5, y = 1},
|
||||
size = {x = 24, y = 24},
|
||||
text = "magic_essence.png^[colorize:#00A:200",
|
||||
number = p.mana,
|
||||
alignment = {x = -1, y = -1},
|
||||
offset = {x = -266, y = -110 - 24},
|
||||
max = 0,
|
||||
})
|
||||
hud.oldvalue = p.mana
|
||||
return
|
||||
elseif hud.oldvalue ~= p.mana then
|
||||
player:hud_change(hud.id, "number", p.mana)
|
||||
hud.oldvalue = p.mana
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function magic.require_mana(player, cost, message)
|
||||
local p = magic.manadb[player:get_player_name()]
|
||||
if not p then return false end
|
||||
if p.mana < cost then
|
||||
if message then minetest.chat_send_player(player:get_player_name(), "You do not have enough mana.") end
|
||||
return false
|
||||
end
|
||||
p.mana = math.max(0, p.mana - cost)
|
||||
return true
|
||||
end
|
||||
|
||||
function magic.require_energy(player, cost, message)
|
||||
local p = magic.manadb[player:get_player_name()]
|
||||
if not p then return false end
|
||||
if magic.require_mana(player, cost) then
|
||||
return true
|
||||
end
|
||||
local newcost = cost - p.mana
|
||||
p.mana = 0
|
||||
if player:get_hp() <= newcost then
|
||||
if message then minetest.chat_send_player(player:get_player_name(), "You do not have enough health.") end
|
||||
return false
|
||||
end
|
||||
player:set_hp(player:get_hp() - newcost)
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
magic.manadb[player:get_player_name()] = magic.manadb[player:get_player_name()] or {
|
||||
mana = magic.config.max_mana,
|
||||
}
|
||||
magic.manadb[player:get_player_name()].max_mana = magic.config.max_mana
|
||||
end)
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
huds[player:get_player_name()] = nil
|
||||
end)
|
|
@ -1,13 +0,0 @@
|
|||
function magic.register_mapgen()
|
||||
-- Vitality crystals form in warm forests.
|
||||
minetest.register_decoration({
|
||||
deco_type = "simple",
|
||||
place_on = {"default:dirt_with_grass"},
|
||||
sidelen = 80,
|
||||
fill_ratio = 0.00025,
|
||||
biomes = {"rainforest", "deciduous_forest", "coniferous_forest"},
|
||||
y_min = 1,
|
||||
y_max = 31000,
|
||||
decoration = "magic:crystal_vitality",
|
||||
})
|
||||
end
|
|
@ -1,81 +0,0 @@
|
|||
function magic.register_potion(name, def)
|
||||
local item_def = {
|
||||
description = def.description,
|
||||
drawtype = "plantlike",
|
||||
tiles = {"vessels_glass_bottle.png^[colorize:"..def.color..":200"},
|
||||
inventory_image = "vessels_glass_bottle.png^[colorize:"..def.color..":200",
|
||||
wield_image = "vessels_glass_bottle.png^[colorize:"..def.color..":200",
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.25, -0.5, -0.25, 0.25, 0.3, 0.25}
|
||||
},
|
||||
groups = {vessel = 1, dig_immediate = 3, attached_node = 1},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
}
|
||||
local function docost(player)
|
||||
if def.harmful then
|
||||
return magic.require_energy(player, def.cost, true)
|
||||
else
|
||||
return magic.require_mana(player, def.cost, true)
|
||||
end
|
||||
end
|
||||
if def.on_use then
|
||||
function item_def.on_use(itemstack, player)
|
||||
if def.cost then
|
||||
if not docost(player) then return end
|
||||
end
|
||||
if def.on_use(itemstack, player) then
|
||||
if player:get_inventory():room_for_item("main", "vessels:glass_bottle") then
|
||||
player:get_inventory():add_item("main", "vessels:glass_bottle")
|
||||
else
|
||||
minetest.add_item(pos, "vessels:glass_bottle")
|
||||
end
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
minetest.register_node(name, item_def)
|
||||
end
|
||||
|
||||
magic.register_potion("magic:water_bottle", {
|
||||
description = "Bottle of Water",
|
||||
color = "#02A",
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "magic:water_bottle",
|
||||
type = "shapeless",
|
||||
recipe = {"vessels:glass_bottle", "bucket:bucket_water"},
|
||||
replacements = {{"bucket:bucket_water", "bucket:bucket_empty"}},
|
||||
})
|
||||
|
||||
magic.register_potion("magic:purified_water_bottle", {
|
||||
description = "Purified Bottle of Water",
|
||||
color = "#23B",
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = "magic:purified_water_bottle",
|
||||
recipe = "magic:water_bottle",
|
||||
cooktime = 5,
|
||||
})
|
||||
|
||||
magic.register_potion("magic:minor_mana_potion", {
|
||||
description = "Minor Mana Restoration Potion",
|
||||
color = "#00F",
|
||||
on_use = function(itemstack, player)
|
||||
magic.require_mana(player, -2)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "magic:minor_mana_potion",
|
||||
type = "shapeless",
|
||||
recipe = {"magic:water_bottle", "flowers:geranium"},
|
||||
})
|
|
@ -1,84 +0,0 @@
|
|||
function magic.register_spell(name, def)
|
||||
local item_def = {
|
||||
description = def.description..(" (%d)"):format(def.cost),
|
||||
inventory_image = "magic_essence.png^[colorize:"..def.color..":"..tostring(0xCC).."^magic_emblem_"..def.emblem..".png",
|
||||
groups = def.groups or {spell = 1},
|
||||
original = def,
|
||||
}
|
||||
local function docost(player)
|
||||
-- If the spell is harmful, it will dip into player health when mana runs out.
|
||||
if def.harmful then
|
||||
return magic.require_energy(player, def.cost, true)
|
||||
else
|
||||
return magic.require_mana(player, def.cost, true)
|
||||
end
|
||||
end
|
||||
if def.type == "missile" then
|
||||
local f = magic.register_missile(name.."_missile", item_def.inventory_image, def, item_def)
|
||||
function item_def.on_use(itemstack, player, pointed_thing)
|
||||
if not docost(player) then return end
|
||||
return f(itemstack, player, pointed_thing)
|
||||
end
|
||||
elseif def.type == "action" then
|
||||
function item_def.on_use(itemstack, player, pointed_thing)
|
||||
if not docost(player) then return end
|
||||
if def.on_use(itemstack, player, pointed_thing) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
elseif def.type == "shield" then
|
||||
-- magic.damage_obj handles shields.
|
||||
else
|
||||
error("Unknown spell type: "..def.type)
|
||||
end
|
||||
minetest.register_craftitem(name, item_def)
|
||||
end
|
||||
|
||||
-- Convert all damage to fleshy.
|
||||
function magic.damage_obj(obj, g)
|
||||
local groups = table.copy(g)
|
||||
-- If the target is a player, apply shields.
|
||||
if obj:is_player() then
|
||||
local heldstack = obj:get_wielded_item()
|
||||
local def = minetest.registered_items[heldstack:get_name()]
|
||||
local remove = false
|
||||
if (def.groups.spell or 0) > 0 and def.original.protects then
|
||||
for k,protect in pairs(def.original.protects) do
|
||||
if not groups[k] then
|
||||
break
|
||||
end
|
||||
if def.original.harmful then
|
||||
if not magic.require_energy(obj, def.original.cost) then
|
||||
break
|
||||
end
|
||||
else
|
||||
if not magic.require_mana(obj, def.original.cost) then
|
||||
break
|
||||
end
|
||||
end
|
||||
remove = true
|
||||
groups[k] = math.max(0, math.min(protect.max, groups[k] * protect.factor))
|
||||
end
|
||||
end
|
||||
if remove then
|
||||
heldstack:take_item()
|
||||
obj:set_wielded_item(heldstack)
|
||||
end
|
||||
end
|
||||
local x = 0
|
||||
local armor = obj:get_armor_groups()
|
||||
for k,v in pairs(groups) do
|
||||
local factor = 1
|
||||
if k ~= 'fleshy' then
|
||||
factor = (armor.fleshy or 100) / 100
|
||||
end
|
||||
local delta = (v / factor)
|
||||
x = x + delta
|
||||
end
|
||||
obj:punch(obj, 1.0, {full_punch_interval=1.0, damage_groups={fleshy=x}, nil})
|
||||
-- Magic damage has a chance to drain mana (or deal extra damage if the target doesn't have enough mana).
|
||||
if obj:is_player() and groups.magic and groups.magic > 0 then
|
||||
magic.require_energy(obj, math.random(0, math.max(1, math.ceil(groups.magic / 3))))
|
||||
end
|
||||
end
|
|
@ -1,71 +0,0 @@
|
|||
-- Create a small explosion of flowing water.
|
||||
local function drop_water(self, pos)
|
||||
local water = "default:water_flowing"
|
||||
local limit = 5
|
||||
-- Put out fires first.
|
||||
local positions = kingdoms.utils.shuffled(kingdoms.utils.find_nodes_by_area(pos, 3, {"fire:basic_flame"}))
|
||||
for _,p in ipairs(positions) do
|
||||
limit = limit - 1
|
||||
minetest.set_node(p, {name=water})
|
||||
if limit <= 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
limit = math.max(limit, 3)
|
||||
-- A smaller air radius, avoiding travel through thick walls.
|
||||
positions = kingdoms.utils.shuffled(kingdoms.utils.find_nodes_by_area(pos, 1, {"air"}))
|
||||
for _,p in ipairs(positions) do
|
||||
limit = limit - 1
|
||||
minetest.set_node(p, {name=water})
|
||||
if limit <= 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
magic.register_spell("magic:spell_water", {
|
||||
description = "Water Spell",
|
||||
type = "missile",
|
||||
color = "#00F",
|
||||
emblem = "action",
|
||||
speed = 20,
|
||||
cost = 4,
|
||||
gravity = 0.25,
|
||||
hit_node = drop_water,
|
||||
hit_object = drop_water,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_water 2",
|
||||
recipe = {
|
||||
{"magic:calm_essence", "group:minor_spellbinding", "magic:area_essence"},
|
||||
},
|
||||
})
|
||||
|
||||
magic.register_spell("magic:spell_heal_minor", {
|
||||
description = "Minor Healing Spell",
|
||||
type = "missile",
|
||||
color = "#CCF",
|
||||
emblem = "action",
|
||||
speed = 30,
|
||||
cost = 4,
|
||||
allow_turret = true,
|
||||
friendly_turret = true,
|
||||
check_object = function(obj, ok)
|
||||
if obj:get_hp() >= 20 then
|
||||
return false
|
||||
end
|
||||
return ok
|
||||
end,
|
||||
hit_object = function(self, pos, obj)
|
||||
magic.damage_obj(obj, {
|
||||
healing = (self.was_near_turret > 0 and -1 or -2),
|
||||
})
|
||||
end,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_heal_minor 3",
|
||||
recipe = {
|
||||
{"magic:calm_essence", "group:minor_spellbinding", "magic:day_essence"},
|
||||
},
|
||||
})
|
|
@ -1,176 +0,0 @@
|
|||
-- The fireball, ignites flames and deals fire damage.
|
||||
magic.register_spell("magic:spell_fire", {
|
||||
description = "Fire Spell",
|
||||
type = "missile",
|
||||
color = "#F00",
|
||||
emblem = "attack",
|
||||
speed = 30,
|
||||
cost = 2,
|
||||
allow_turret = true,
|
||||
element = "fire",
|
||||
hit_node = function(self, pos, last_empty_pos)
|
||||
local flammable = minetest.get_item_group(minetest.get_node(pos).name, "flammable")
|
||||
local puts_out = minetest.get_item_group(minetest.get_node(pos).name, "puts_out_fire")
|
||||
if puts_out > 0 then
|
||||
-- No chance of a fire starting here.
|
||||
return true
|
||||
end
|
||||
if flammable > 0 then
|
||||
minetest.set_node(pos, {name = "fire:basic_flame"})
|
||||
return true
|
||||
elseif magic.missile_passable(pos) then
|
||||
return false
|
||||
elseif last_empty_pos then
|
||||
minetest.set_node(last_empty_pos, {name = "fire:basic_flame"})
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
hit_object = function(self, pos, obj)
|
||||
magic.damage_obj(obj, {fire = (self.was_near_turret > 0 and 2 or 4)})
|
||||
return true
|
||||
end,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_fire",
|
||||
recipe = {
|
||||
{"magic:rage_essence", "group:minor_spellbinding"},
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "magic:spell_fire",
|
||||
burntime = 550,
|
||||
})
|
||||
|
||||
-- The bomb, creates a TNT-style explosion at the contact point.
|
||||
if rawget(_G, 'tnt') and tnt.boom then
|
||||
local hit_node = function(self, pos, last_empty_pos)
|
||||
local puts_out = minetest.get_item_group(minetest.get_node(pos).name, "puts_out_fire")
|
||||
if puts_out > 0 then
|
||||
-- This spell can travel through water.
|
||||
return false
|
||||
end
|
||||
if magic.missile_passable(pos) then
|
||||
return false
|
||||
end
|
||||
tnt.boom(pos, {
|
||||
radius = 3,
|
||||
damage_radius = 5,
|
||||
})
|
||||
return true
|
||||
end
|
||||
magic.register_spell("magic:spell_bomb", {
|
||||
description = "Bomb Spell",
|
||||
type = "missile",
|
||||
color = "#FA0",
|
||||
emblem = "attack",
|
||||
speed = 15,
|
||||
cost = 6,
|
||||
gravity = 0.5,
|
||||
element = "fire",
|
||||
hit_node = hit_node,
|
||||
hit_object = function(self, pos, obj)
|
||||
return hit_node(self, pos)
|
||||
end,
|
||||
near_turret = function(self, pos, spell)
|
||||
if spell.protects and spell.protects.fire and magic.use_turrent_spell(pos) then
|
||||
return true
|
||||
end
|
||||
end,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_bomb",
|
||||
recipe = {
|
||||
{"magic:spell_fire", "group:minor_spellbinding", "magic:area_essence"},
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
-- A weak but cheap dart.
|
||||
magic.register_spell("magic:spell_dart", {
|
||||
description = "Dart Spell",
|
||||
type = "missile",
|
||||
color = "#333",
|
||||
emblem = "attack",
|
||||
speed = 60,
|
||||
cost = 1,
|
||||
element = "fleshy",
|
||||
allow_turret = true,
|
||||
hit_object = function(self, pos, obj)
|
||||
magic.damage_obj(obj, {fleshy = (self.was_near_turret > 0 and 1 or 2)})
|
||||
return true
|
||||
end,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_dart 6",
|
||||
recipe = {
|
||||
{"magic:area_essence", "magic:solidity_essence"},
|
||||
{"group:minor_spellbinding", "group:stone"},
|
||||
},
|
||||
})
|
||||
|
||||
-- A weak dart that deals armor-bypassing magic and fire damage.
|
||||
magic.register_spell("magic:spell_missile", {
|
||||
description = "Missile Spell",
|
||||
type = "missile",
|
||||
color = "#04F",
|
||||
emblem = "attack",
|
||||
speed = 50,
|
||||
cost = 1,
|
||||
element = "magic",
|
||||
allow_turret = true,
|
||||
hit_object = function(self, pos, obj)
|
||||
magic.damage_obj(obj, {magic = (self.was_near_turret > 0 and 0.5 or 1), fire = (self.was_near_turret > 0 and 0.5 or 1)})
|
||||
return true
|
||||
end,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_missile 2",
|
||||
recipe = {
|
||||
{"magic:rage_essence", "magic:day_essence", "group:minor_spellbinding"},
|
||||
},
|
||||
})
|
||||
|
||||
local function drop_ice(self, pos)
|
||||
self.firsthit = self.firsthit or pos
|
||||
if minetest.get_node(pos).name ~= "default:water_source" and minetest.get_node(pos).name ~= "default:water_flowing" then
|
||||
return true
|
||||
else
|
||||
if vector.distance(self.firsthit, pos) >= 16 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
local limit = 6
|
||||
local positions = kingdoms.utils.shuffled(kingdoms.utils.find_nodes_by_area_under_air(pos, 4, {"default:water_source"}))
|
||||
for _,p in ipairs(positions) do
|
||||
limit = limit - 1
|
||||
minetest.set_node(p, {name="default:ice"})
|
||||
if limit <= 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Convert water sources to ice.
|
||||
magic.register_spell("magic:spell_ice", {
|
||||
description = "Ice Spell",
|
||||
type = "missile",
|
||||
color = "#08B",
|
||||
emblem = "attack",
|
||||
speed = 20,
|
||||
cost = 8,
|
||||
element = "cold",
|
||||
hit_node = drop_ice,
|
||||
hit_object = function(self, pos, obj)
|
||||
magic.damage_obj(obj, {cold = (self.was_near_turret > 0 and 2 or 4)})
|
||||
return true
|
||||
end,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_ice 2",
|
||||
recipe = {
|
||||
{"magic:concentrated_night_essence", "magic:calm_essence", ""},
|
||||
{"group:minor_spellbinding", "magic:area_essence", "magic:solidity_essence"},
|
||||
},
|
||||
})
|
|
@ -1,66 +0,0 @@
|
|||
-- Absorb rage damage.
|
||||
magic.register_spell("magic:spell_dark_shield", {
|
||||
description = "Dark Shield Spell",
|
||||
type = "shield",
|
||||
color = "#222",
|
||||
emblem = "defense",
|
||||
cost = 1,
|
||||
allow_turret = true,
|
||||
protects = {
|
||||
fire = {
|
||||
max = 4,
|
||||
factor = 0.5,
|
||||
},
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_dark_shield 9",
|
||||
recipe = {
|
||||
{"group:minor_spellbinding", "magic:night_essence"},
|
||||
},
|
||||
})
|
||||
|
||||
-- Refract magic damage.
|
||||
magic.register_spell("magic:spell_white_shield", {
|
||||
description = "White Shield Spell",
|
||||
type = "shield",
|
||||
color = "#DDD",
|
||||
emblem = "defense",
|
||||
cost = 1,
|
||||
allow_turret = true,
|
||||
protects = {
|
||||
magic = {
|
||||
max = 4,
|
||||
factor = 0.5,
|
||||
},
|
||||
},
|
||||
harmful = true,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_white_shield 9",
|
||||
recipe = {
|
||||
{"group:minor_spellbinding", "magic:day_essence"},
|
||||
},
|
||||
})
|
||||
|
||||
-- Block fleshy damage.
|
||||
magic.register_spell("magic:spell_solid_shield", {
|
||||
description = "Solid Shield Spell",
|
||||
type = "shield",
|
||||
color = "#AA0",
|
||||
emblem = "defense",
|
||||
cost = 2,
|
||||
allow_turret = true,
|
||||
protects = {
|
||||
fleshy = {
|
||||
max = 4,
|
||||
factor = 0.5,
|
||||
},
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_solid_shield 9",
|
||||
recipe = {
|
||||
{"group:minor_spellbinding", "magic:solidity_essence"},
|
||||
},
|
||||
})
|
|
@ -1,130 +0,0 @@
|
|||
local teleporting = {}
|
||||
minetest.register_globalstep(function(dtime)
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local name = player:get_player_name()
|
||||
local tp = teleporting[name]
|
||||
if tp then
|
||||
tp.timer = tp.timer + dtime
|
||||
if vector.distance(player:getpos(), tp.start) > 0.1 then
|
||||
magic.cancel_teleportation(name)
|
||||
elseif tp.timer >= tp.delay then
|
||||
minetest.registered_items[tp.item].original.go(player)
|
||||
teleporting[name] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function magic.start_teleportation(player, item, delay)
|
||||
local name = player:get_player_name()
|
||||
if teleporting[name] then
|
||||
magic.cancel_teleportation(name)
|
||||
end
|
||||
teleporting[name] = {
|
||||
timer = 0,
|
||||
delay = delay,
|
||||
item = item,
|
||||
start = player:getpos(),
|
||||
}
|
||||
minetest.chat_send_player(name, "Teleportation will occur in "..tostring(delay).." seconds. Remain still.")
|
||||
end
|
||||
|
||||
function magic.cancel_teleportation(name)
|
||||
minetest.chat_send_player(name, "Teleportation has been canceled.")
|
||||
teleporting[name] = nil
|
||||
end
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
magic.cancel_teleportation(player:get_player_name())
|
||||
end)
|
||||
|
||||
magic.register_spell("magic:spell_teleport_spawn", {
|
||||
description = "Spawn Teleportation Spell",
|
||||
type = "action",
|
||||
color = "#0A0",
|
||||
emblem = "action",
|
||||
cost = 15,
|
||||
on_use = function(itemstack, player)
|
||||
magic.start_teleportation(player, itemstack:get_name(), magic.config.teleportation_delay)
|
||||
return true
|
||||
end,
|
||||
go = function(player)
|
||||
if not kingdoms.db.servercorestone then
|
||||
minetest.chat_send_player(player:get_player_name(), "There is no destination.")
|
||||
return
|
||||
end
|
||||
player:setpos(vector.add(kingdoms.db.servercorestone, {x=0, y=1, z=0}))
|
||||
end,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_teleport_spawn",
|
||||
recipe = {
|
||||
{"magic:concentrated_warp_essence", "magic:control_essence"},
|
||||
{"group:minor_spellbinding", "default:sapling"},
|
||||
},
|
||||
})
|
||||
|
||||
magic.register_spell("magic:spell_teleport_kingdom", {
|
||||
description = "Kingdom Teleportation Spell",
|
||||
type = "action",
|
||||
color = "#FA0",
|
||||
emblem = "action",
|
||||
cost = 15,
|
||||
on_use = function(itemstack, player)
|
||||
magic.start_teleportation(player, itemstack:get_name(), magic.config.teleportation_delay)
|
||||
return true
|
||||
end,
|
||||
go = function(player)
|
||||
local kingdom = kingdoms.player.kingdom(player:get_player_name())
|
||||
if not kingdom or not kingdom.corestone.pos then
|
||||
minetest.chat_send_player(player:get_player_name(), "There is no destination.")
|
||||
return
|
||||
end
|
||||
player:setpos(vector.add(kingdom.corestone.pos, {x=0, y=1, z=0}))
|
||||
end,
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_teleport_kingdom",
|
||||
recipe = {
|
||||
{"magic:concentrated_warp_essence", "magic:control_essence"},
|
||||
{"group:minor_spellbinding", "default:junglesapling"},
|
||||
},
|
||||
})
|
||||
|
||||
if magic.config.enable_short_teleports then
|
||||
magic.register_spell("magic:spell_short_teleport", {
|
||||
description = "Short Teleportation Spell",
|
||||
type = "missile",
|
||||
color = "#F0F",
|
||||
emblem = "action",
|
||||
speed = 10,
|
||||
cost = 7,
|
||||
gravity = 0.35,
|
||||
forceload = true,
|
||||
near_turret = function(self, pos, spell)
|
||||
if spell.protects and spell.protects.magic and magic.use_turrent_spell(pos) then
|
||||
return true
|
||||
end
|
||||
end,
|
||||
hit_node = function(self, pos, last_empty_pos)
|
||||
local akingdom = kingdoms.bypos(last_empty_pos)
|
||||
if self.player then
|
||||
local pkingdom = kingdoms.player.kingdom(self.player:get_player_name())
|
||||
if akingdom and (not pkingdom or pkingdom.id ~= akingdom.id) then
|
||||
minetest.chat_send_player(self.player:get_player_name(), "You cannot teleport there.")
|
||||
return true
|
||||
end
|
||||
self.player:setpos(last_empty_pos)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
hit_object = function() return false end
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "magic:spell_short_teleport",
|
||||
recipe = {
|
||||
{"magic:concentrated_warp_essence", "magic:control_essence"},
|
||||
{"group:minor_spellbinding", ""},
|
||||
},
|
||||
})
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
ancient_world.register("magic:magic_hovel_1", {
|
||||
schematic = minetest.get_modpath("magic") .. "/schematics/magic_hovel_1.mts",
|
||||
type = "decoration",
|
||||
limit_y = {
|
||||
max = -1024,
|
||||
min = -31000,
|
||||
},
|
||||
on = {"default:stone"},
|
||||
random_replacements = {
|
||||
["ancient_world:placeholder_1"] = {"magic:nightcall", "magic:daypull"},
|
||||
},
|
||||
})
|
||||
|
||||
ancient_world.register("magic:magic_hovel_2", {
|
||||
schematic = minetest.get_modpath("magic") .. "/schematics/magic_hovel_2.mts",
|
||||
type = "decoration",
|
||||
on = {"default:dirt_with_grass"},
|
||||
offset = {
|
||||
x = 0,
|
||||
y = -3,
|
||||
z = 0,
|
||||
},
|
||||
random_replacements = {
|
||||
["ancient_world:placeholder_1"] = true,
|
||||
},
|
||||
})
|
||||
|
||||
ancient_world.register("magic:underground_lab_1", {
|
||||
schematic = minetest.get_modpath("magic") .. "/schematics/underground_lab_1.mts",
|
||||
type = "decoration",
|
||||
limit_y = {
|
||||
max = -512,
|
||||
min = -31000,
|
||||
},
|
||||
offset = {
|
||||
x = 0,
|
||||
y = -16,
|
||||
z = 0,
|
||||
},
|
||||
on = {"default:stone"},
|
||||
replacements = {
|
||||
["ancient_world:placeholder_2"] = "air",
|
||||
},
|
||||
random_replacements = {
|
||||
["ancient_world:placeholder_1"] = true,
|
||||
},
|
||||
})
|
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.4 KiB |
|
@ -1,313 +0,0 @@
|
|||
-- Throwing movement physics.
|
||||
|
||||
NO_HIT_ENTS = {
|
||||
["__builtin:item"] = true,
|
||||
["itemframes:item"] = true,
|
||||
["xdecor:f_item"] = true,
|
||||
}
|
||||
|
||||
local TIMEOUT = 300
|
||||
|
||||
-- ORIGINALLY COPIED FROM technic, under LGPL v2
|
||||
-- BEGIN COPIED
|
||||
local scalar = vector.scalar or vector.dot or function(v1, v2)
|
||||
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
|
||||
end
|
||||
|
||||
local function biggest_of_vec(vec)
|
||||
if vec.x < vec.y then
|
||||
if vec.y < vec.z then
|
||||
return "z"
|
||||
end
|
||||
return "y"
|
||||
end
|
||||
if vec.x < vec.z then
|
||||
return "z"
|
||||
end
|
||||
return "x"
|
||||
end
|
||||
|
||||
local function rayIter(pos, dir, range)
|
||||
-- make a table of possible movements
|
||||
local step = {}
|
||||
for i in pairs(pos) do
|
||||
local v = math.sign(dir[i])
|
||||
if v ~= 0 then
|
||||
step[i] = v
|
||||
end
|
||||
end
|
||||
|
||||
local p
|
||||
return function()
|
||||
if not p then
|
||||
-- avoid skipping the first position
|
||||
p = vector.round(pos)
|
||||
return vector.new(p)
|
||||
end
|
||||
|
||||
-- find the position which has the smallest distance to the line
|
||||
local choose = {}
|
||||
local choosefit = vector.new()
|
||||
for i in pairs(step) do
|
||||
choose[i] = vector.new(p)
|
||||
choose[i][i] = choose[i][i] + step[i]
|
||||
choosefit[i] = scalar(vector.normalize(vector.subtract(choose[i], pos)), dir)
|
||||
end
|
||||
p = choose[biggest_of_vec(choosefit)]
|
||||
|
||||
if vector.distance(pos, p) <= range then
|
||||
return vector.new(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- END COPIED
|
||||
|
||||
function magic.missile_passable(pos)
|
||||
local def = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||
if not def.walkable and def.buildable_to then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function magic.register_missile(name, texture, def, item_def)
|
||||
|
||||
def.hit_object = def.hit_object or function(self, pos, obj)
|
||||
return true
|
||||
end
|
||||
|
||||
def.hit_player = def.hit_player or function(self, pos, obj)
|
||||
return def.hit_object(self, pos, obj)
|
||||
end
|
||||
|
||||
def.hit_node = def.hit_node or function(self, pos, last_empty_pos)
|
||||
if magic.missile_passable(pos) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def.near_turret = def.near_turret or function(self, pos, spell)
|
||||
return false
|
||||
end
|
||||
|
||||
def.is_passthrough_node = def.is_passthrough_node or function(self, pos, node)
|
||||
return node.name == "air"
|
||||
end
|
||||
|
||||
local ent_def = {
|
||||
physical = false,
|
||||
hp_max = math.ceil(def.cost / 2),
|
||||
timer=0,
|
||||
particletimer = 0,
|
||||
visual = "sprite",
|
||||
visual_size = {x=0.4, y=0.4},
|
||||
textures = {texture},
|
||||
lastpos={},
|
||||
lastair = nil,
|
||||
was_near_turret = 0,
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
}
|
||||
|
||||
ent_def.on_step = function(self, dtime)
|
||||
self.timer=self.timer+dtime
|
||||
self.particletimer = self.particletimer + dtime
|
||||
local pos = self.object:getpos()
|
||||
if self.lastpos.x == nil then
|
||||
self.lastpos = pos
|
||||
if def.is_passthrough_node(self, pos, minetest.get_node(pos).name) then
|
||||
self.lastair = pos
|
||||
elseif def.is_passthrough_node(self, vector.add(pos, {x=0, y=1, z=0}), minetest.get_node(vector.add(pos, {x=0, y=1, z=0}))) then
|
||||
self.lastair = vector.add(pos, {x=0, y=1, z=0})
|
||||
elseif def.is_passthrough_node(self, vector.add(pos, {x=0, y=2, z=0}), minetest.get_node(vector.add(pos, {x=0, y=2, z=0}))) then
|
||||
self.lastair = vector.add(pos, {x=0, y=2, z=0})
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if self.timer > TIMEOUT then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
local line = {
|
||||
start = self.lastpos,
|
||||
finish = pos,
|
||||
}
|
||||
|
||||
line.middle = {
|
||||
x = (line.start.x + line.finish.x) / 2,
|
||||
y = (line.start.y + line.finish.y) / 2,
|
||||
z = (line.start.z + line.finish.z) / 2,
|
||||
}
|
||||
|
||||
local Hit = {x=0, y=0, z=0};
|
||||
|
||||
local function GetIntersection(fDst1, fDst2, P1, P2)
|
||||
if ( (fDst1 * fDst2) >= 0.0) then return nil end
|
||||
if ( fDst1 == fDst2) then return nil end
|
||||
Hit = vector.multiply(vector.add(P1, vector.subtract(P2, P1)), ( -fDst1/(fDst2-fDst1) ));
|
||||
return true
|
||||
end
|
||||
|
||||
local function InBox(H, B1, B2, Axis)
|
||||
if ( Axis==1 and H.z > B1.z and H.z < B2.z and H.y > B1.y and H.y < B2.y) then return true; end
|
||||
if ( Axis==2 and H.z > B1.z and H.z < B2.z and H.x > B1.x and H.x < B2.x) then return true; end
|
||||
if ( Axis==3 and H.x > B1.x and H.x < B2.x and H.y > B1.y and H.y < B2.y) then return true; end
|
||||
return false;
|
||||
end
|
||||
|
||||
local function CheckLineBox( B1, B2, L1, L2)
|
||||
if (L2.x < B1.x and L1.x < B1.x) then return false end
|
||||
if (L2.x > B2.x and L1.x > B2.x) then return false end
|
||||
if (L2.y < B1.y and L1.y < B1.y) then return false end
|
||||
if (L2.y > B2.y and L1.y > B2.y) then return false end
|
||||
if (L2.z < B1.z and L1.z < B1.z) then return false end
|
||||
if (L2.z > B2.z and L1.z > B2.z) then return false end
|
||||
if (L1.x > B1.x and L1.x < B2.x and
|
||||
L1.y > B1.y and L1.y < B2.y and
|
||||
L1.z > B1.z and L1.z < B2.z)
|
||||
then
|
||||
Hit = L1;
|
||||
return true
|
||||
end
|
||||
if ( (GetIntersection( L1.x-B1.x, L2.x-B1.x, L1, L2) and InBox( Hit, B1, B2, 1 ))
|
||||
or (GetIntersection( L1.y-B1.y, L2.y-B1.y, L1, L2) and InBox( Hit, B1, B2, 2 ))
|
||||
or (GetIntersection( L1.z-B1.z, L2.z-B1.z, L1, L2) and InBox( Hit, B1, B2, 3 ))
|
||||
or (GetIntersection( L1.x-B2.x, L2.x-B2.x, L1, L2) and InBox( Hit, B1, B2, 1 ))
|
||||
or (GetIntersection( L1.y-B2.y, L2.y-B2.y, L1, L2) and InBox( Hit, B1, B2, 2 ))
|
||||
or (GetIntersection( L1.z-B2.z, L2.z-B2.z, L1, L2) and InBox( Hit, B1, B2, 3 )))
|
||||
then
|
||||
return true
|
||||
end
|
||||
|
||||
return false;
|
||||
end
|
||||
|
||||
local function CheckLineNear(line, pos, distance)
|
||||
local nx = 0.5
|
||||
if line.finish.x < line.start.x then nx = -nx end
|
||||
local ny = 0.5
|
||||
if line.finish.y < line.start.y then ny = -ny end
|
||||
local nz = 0.5
|
||||
if line.finish.z < line.start.z then nz = -nz end
|
||||
|
||||
for x=line.start.x,line.finish.x,nx do
|
||||
for y=line.start.y,line.finish.y,ny do
|
||||
for z=line.start.z,line.finish.z,nz do
|
||||
if vector.distance({x=x, y=y, z=z}, pos) <= distance then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if def.forceload then
|
||||
for pos in rayIter(line.start, vector.normalize(self.object:getvelocity()), math.max(64, vector.distance(line.start, line.finish) * 2)) do
|
||||
kingdoms.utils.load_pos(pos)
|
||||
end
|
||||
end
|
||||
|
||||
for _,pos in ipairs(kingdoms.utils.find_nodes_by_area(pos, magic.config.turret_shield_radius, {"magic:turret"})) do
|
||||
if self.kingdom ~= minetest.get_meta(pos):get_string("kingdom.id") then
|
||||
local turret_spell = magic.get_turret_spell(pos)
|
||||
if turret_spell.protects and turret_spell.protects[def.element] and (self.was_near_turret > 1 or magic.use_turrent_spell(pos)) then
|
||||
self.was_near_turret = self.was_near_turret + 1
|
||||
end
|
||||
if def.near_turret(self, pos, turret_spell) then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local hitnode = nil
|
||||
local willremove = false
|
||||
|
||||
for pos in rayIter(line.start, self.object:getvelocity(), vector.distance(line.start, line.finish)) do
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
elseif def.is_passthrough_node(self, pos, node) then
|
||||
self.lastair = pos
|
||||
else
|
||||
hitnode = pos
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if hitnode then
|
||||
if def.hit_node(self, hitnode, self.lastair) then
|
||||
self.object:remove()
|
||||
willremove = true
|
||||
end
|
||||
end
|
||||
|
||||
local objs = minetest.get_objects_inside_radius(line.middle, (math.ceil(vector.distance(line.middle, line.start)) + math.ceil(vector.distance(line.middle, line.finish)) * 2) + 6)
|
||||
for k, obj in pairs(objs) do
|
||||
local bb = obj:get_properties().collisionbox
|
||||
local pp = vector.add(obj:getpos(), {x=0, y=0.5, z=0})
|
||||
-- If bb collides with line...
|
||||
local b1 = vector.add(pp, vector.multiply({x=bb[1], y=bb[2], z=bb[3]}, 1.5))
|
||||
local b2 = vector.add(pp, vector.multiply({x=bb[4], y=bb[5], z=bb[6]}, 1.5))
|
||||
if willremove and vector.distance(obj:getpos(), line.start) > vector.distance(hitnode, line.start) then
|
||||
break
|
||||
end
|
||||
if CheckLineBox(b1, b2, line.start, line.finish) or CheckLineNear(line, pp, 1) then
|
||||
if obj:get_luaentity() ~= nil then
|
||||
if obj:get_luaentity().name ~= name and not NO_HIT_ENTS[obj:get_luaentity().name] then
|
||||
if def.hit_object(self, obj:getpos(), obj) then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
end
|
||||
elseif obj:is_player() then
|
||||
local can = true
|
||||
if self.timer > 0.5 or not self.player or obj:get_player_name() ~= self.player:get_player_name() then
|
||||
if def.hit_player(self, obj:getpos(), obj) then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if willremove then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
if self.particletimer > 0.05 then
|
||||
minetest.add_particle({
|
||||
pos = pos,
|
||||
velocity = {x=math.random()-0.5, y=math.random()-0.5, z=math.random()-0.5},
|
||||
acceleration = {x=0, y=-1, z=0},
|
||||
expirationtime = 1.5,
|
||||
size = math.random() * 4,
|
||||
texture = "smoke_puff.png^[transform" .. math.random(0, 7),
|
||||
})
|
||||
self.particletimer = 0
|
||||
end
|
||||
|
||||
self.lastpos={x=pos.x, y=pos.y, z=pos.z}
|
||||
end
|
||||
|
||||
minetest.register_entity(name, ent_def)
|
||||
|
||||
return function(itemstack, player, pointed_thing)
|
||||
local playerpos = player:getpos()
|
||||
local obj = minetest.add_entity({x=playerpos.x,y=playerpos.y+1.4,z=playerpos.z}, name)
|
||||
local dir = player:get_look_dir()
|
||||
obj:setvelocity({x=dir.x*def.speed, y=dir.y*def.speed, z=dir.z*def.speed})
|
||||
obj:setacceleration({x=0, y=-8.5*(def.gravity or 0), z=0})
|
||||
obj:setyaw(player:get_look_horizontal()+math.pi)
|
||||
obj:get_luaentity().player = player
|
||||
obj:get_luaentity().kingdom = kingdoms.player.kingdom(player:get_player_name()) and kingdoms.player.kingdom(player:get_player_name()).id or nil
|
||||
itemstack:take_item()
|
||||
return itemstack
|
||||
end
|
||||
end
|
|
@ -1,106 +0,0 @@
|
|||
minetest.register_node("magic:nightcall", {
|
||||
description = "Nightcall",
|
||||
tiles = {"magic_nightcall.png"},
|
||||
groups = {cracky = 1},
|
||||
after_place_node = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:get_inventory():set_size("input", 1)
|
||||
meta:get_inventory():set_size("output", 6)
|
||||
meta:set_string("formspec", [[
|
||||
size[8,7]
|
||||
label[0,0.1;Input null essences during the night to produce night essences. Requires mana.]
|
||||
list[context;input;0,1;1,1;]
|
||||
list[context;output;2,1;6,1;]
|
||||
list[current_player;main;0,3;8,4;]
|
||||
]])
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:get_inventory():set_list("input", {})
|
||||
local leftover = meta:get_inventory():add_item("output", "magic:night_essence "..tostring(stack:get_count()))
|
||||
minetest.add_item(vector.add(pos, {x=0, y=1, z=0}), leftover)
|
||||
end,
|
||||
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
return 0
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local tod = minetest.get_timeofday()
|
||||
if listname ~= "input" then return 0 end
|
||||
if stack:get_name() ~= "magic:null_essence" then
|
||||
return 0
|
||||
end
|
||||
if not kingdoms.player.canpos(pos, player:get_player_name(), "devices") then
|
||||
minetest.chat_send_player(player:get_player_name(), "You cannot use this device.")
|
||||
return 0
|
||||
end
|
||||
if not (tod < 0.2 or tod > 0.805) then
|
||||
minetest.chat_send_player(player:get_player_name(), "It is not night.")
|
||||
return 0
|
||||
end
|
||||
if not magic.require_mana(player, stack:get_count() / 10, true) then
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
if not kingdoms.player.canpos(pos, player:get_player_name(), "devices") then
|
||||
minetest.chat_send_player(player:get_player_name(), "You cannot use this device.")
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("magic:daypull", {
|
||||
description = "Daypull",
|
||||
tiles = {"magic_daypull.png"},
|
||||
groups = {cracky = 1},
|
||||
after_place_node = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:get_inventory():set_size("input", 1)
|
||||
meta:get_inventory():set_size("output", 6)
|
||||
meta:set_string("formspec", [[
|
||||
size[8,7]
|
||||
label[0,0.1;Input null essences during the day to produce day essences. Requires mana.]
|
||||
list[context;input;0,1;1,1;]
|
||||
list[context;output;2,1;6,1;]
|
||||
list[current_player;main;0,3;8,4;]
|
||||
]])
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:get_inventory():set_list("input", {})
|
||||
local leftover = meta:get_inventory():add_item("output", "magic:day_essence "..tostring(stack:get_count()))
|
||||
minetest.add_item(vector.add(pos, {x=0, y=1, z=0}), leftover)
|
||||
end,
|
||||
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
return 0
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local tod = minetest.get_timeofday()
|
||||
if listname ~= "input" then return 0 end
|
||||
if stack:get_name() ~= "magic:null_essence" then
|
||||
return 0
|
||||
end
|
||||
if not kingdoms.player.canpos(pos, player:get_player_name(), "devices") then
|
||||
minetest.chat_send_player(player:get_player_name(), "You cannot use this device.")
|
||||
return 0
|
||||
end
|
||||
if tod < 0.2 or tod > 0.805 then
|
||||
minetest.chat_send_player(player:get_player_name(), "It is not day.")
|
||||
return 0
|
||||
end
|
||||
if not magic.require_mana(player, stack:get_count() / 10, true) then
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
if not kingdoms.player.canpos(pos, player:get_player_name(), "devices") then
|
||||
minetest.chat_send_player(player:get_player_name(), "You cannot use this device.")
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
})
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
local function update_formspec(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local name = meta:get_string("spell_name")
|
||||
name = (name ~= "") and name or "N/A"
|
||||
local count = meta:get_int("spell_count")
|
||||
meta:set_string("formspec", ([[
|
||||
size[8,6]
|
||||
label[0,0.1;Input spells. Current: ]]..tostring(name).." qty "..tostring(count)..[[]
|
||||
button[0,1;8,1;setp_%d;Only target players (current: %s)]
|
||||
list[context;input;7,0;1,1;]
|
||||
list[current_player;main;0,2;8,4;]
|
||||
]]):format(meta:get_int("onlyplayers"), (meta:get_int("onlyplayers") == 1) and "yes" or "no"))
|
||||
end
|
||||
|
||||
minetest.register_node("magic:turret", {
|
||||
description = "Turret",
|
||||
tiles = {"magic_turret.png"},
|
||||
groups = {cracky = 1, kingdom_infotext = 1},
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if not placer or pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local kingdom = kingdoms.player.kingdom(placer:get_player_name())
|
||||
if not kingdom then
|
||||
minetest.chat_send_player(placer:get_player_name(), "You cannot place a turret if you are not a member of a kingdom.")
|
||||
return itemstack
|
||||
end
|
||||
|
||||
return minetest.item_place(itemstack, placer, pointed_thing)
|
||||
end,
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local kingdom = kingdoms.player.kingdom(placer:get_player_name())
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("kingdom.id", kingdom.id)
|
||||
meta:set_string("spell_name", "")
|
||||
meta:set_int("spell_count", 0)
|
||||
|
||||
meta:get_inventory():set_size("input", 8)
|
||||
update_formspec(pos)
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:get_inventory():set_list("input", {})
|
||||
meta:set_string("spell_name", stack:get_name())
|
||||
meta:set_int("spell_count", meta:get_int("spell_count") + stack:get_count())
|
||||
meta:set_int("spell_max", stack:get_stack_max())
|
||||
meta:set_int("onlyplayers", 0)
|
||||
update_formspec(pos)
|
||||
end,
|
||||
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
return 0
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if listname ~= "input" then return 0 end
|
||||
if not minetest.registered_items[stack:get_name()].original or not minetest.registered_items[stack:get_name()].original.allow_turret then
|
||||
minetest.chat_send_player(player:get_player_name(), "You must place turret-enabled spells in this device.")
|
||||
return 0
|
||||
end
|
||||
if stack:get_name() ~= meta:get_string("spell_name") and meta:get_int("spell_count") > 0 then
|
||||
minetest.chat_send_player(player:get_player_name(), "This turret still is holding "..meta:get_string("spell_name"))
|
||||
return 0
|
||||
end
|
||||
if not kingdoms.player.canpos(pos, player:get_player_name(), "devices") then
|
||||
minetest.chat_send_player(player:get_player_name(), "You cannot use this device.")
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
return 0
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if meta:get_string("spell_name") ~= "" then
|
||||
local count = meta:get_int("spell_count")
|
||||
local needed = math.ceil(count / meta:get_int("spell_max"))
|
||||
for i=1,needed do
|
||||
minetest.add_item(pos, meta:get_string("spell_name").." "..tostring(math.min(meta:get_int("spell_max"), count)))
|
||||
count = count - meta:get_int("spell_max")
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
if not kingdoms.player.canpos(pos, player:get_player_name(), "devices") then
|
||||
minetest.chat_send_player(player:get_player_name(), "You cannot use this device.")
|
||||
return 0
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
if fields.setp_0 then
|
||||
meta:set_int("onlyplayers", 1)
|
||||
elseif fields.setp_1 then
|
||||
meta:set_int("onlyplayers", 0)
|
||||
end
|
||||
update_formspec(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"magic:turret"},
|
||||
interval = 3,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if not kingdoms.db.kingdoms[meta:get_string("kingdom.id")] then
|
||||
return
|
||||
end
|
||||
local name = meta:get_string("spell_name")
|
||||
local count = meta:get_int("spell_count")
|
||||
if count <= 0 then return end
|
||||
local def = minetest.registered_items[name].original
|
||||
if def.type == "missile" then
|
||||
local closest = nil
|
||||
local objs = minetest.get_objects_inside_radius(pos, magic.config.turret_missile_radius)
|
||||
for _,obj in pairs(objs) do
|
||||
local ok = true
|
||||
if def.friendly_turret then
|
||||
if not obj:is_player() or not kingdoms.player.is_friendly(meta:get_string("kingdom.id"), obj:get_player_name()) then
|
||||
ok = false
|
||||
end
|
||||
else
|
||||
if obj:get_luaentity() ~= nil and meta:get_int("onlyplayers") == 0 then
|
||||
if NO_HIT_ENTS[obj:get_luaentity().name] then
|
||||
ok = false
|
||||
end
|
||||
elseif obj:is_player() then
|
||||
if kingdoms.player.kingdom(obj:get_player_name()) and kingdoms.player.is_friendly(meta:get_string("kingdom.id"), obj:get_player_name()) then
|
||||
ok = false
|
||||
end
|
||||
end
|
||||
end
|
||||
if def.check_object then
|
||||
ok = def.check_object(obj, ok)
|
||||
end
|
||||
if ok and (not closest or vector.distance(obj:getpos(), pos) < vector.distance(closest:getpos(), pos)) then
|
||||
closest = obj
|
||||
end
|
||||
end
|
||||
if closest then
|
||||
local dir = vector.normalize{x=closest:getpos().x - pos.x, y=(closest:getpos().y + closest:get_properties().collisionbox[5]) - pos.y, z=closest:getpos().z - pos.z}
|
||||
local mobj = minetest.add_entity(pos, name.."_missile")
|
||||
mobj:setvelocity({x=dir.x*def.speed, y=dir.y*def.speed, z=dir.z*def.speed})
|
||||
mobj:setacceleration({x=0, y=-8.5*(def.gravity or 0), z=0})
|
||||
mobj:get_luaentity().kingdom = meta:get_string("kingdom.id")
|
||||
meta:set_int("spell_count", count - 1)
|
||||
update_formspec(pos)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
function magic.get_turret_spell(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local name = meta:get_string("spell_name")
|
||||
local count = meta:get_int("spell_count")
|
||||
if count <= 0 then return end
|
||||
return minetest.registered_items[name].original
|
||||
end
|
||||
|
||||
function magic.use_turret_spell(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local name = meta:get_string("spell_name")
|
||||
local count = meta:get_int("spell_count")
|
||||
if count <= 0 then return false end
|
||||
meta:set_int("spell_count", count - 1)
|
||||
update_formspec(pos)
|
||||
return true
|
||||
end
|
||||
|
41
manual.md
|
@ -14,9 +14,8 @@ These claims cannot overlap with other claims, and must be spaced with at least
|
|||
|
||||
## Defending Land
|
||||
|
||||
Defending a neutral area, or even preventing enemies from entering your clamied area, is enhanced beyond personal battle by the addition of several nodes:
|
||||
Defending a neutral area, or even preventing enemies from entering your clamied area, is enhanced beyond personal battle by the addition of materializers.
|
||||
|
||||
* Turrets, which, after a missile or shield spell is inserted, will ward off enemies by blasting spells at them and cancel or subdue enemy spells.
|
||||
* Materializers and Materialized Walls. The Walls act like hard stone, but when a Materializer is placed by them they will level from 1 to 4 over time. A level 4 node, when dug, will revert to a level 3 instead of vanishing, and so on down to a level 1. They will also absorb explosions, preventing damage inside them.
|
||||
|
||||
## Destroying a Corestone
|
||||
|
@ -26,41 +25,3 @@ The ability to take over another kingdom's claim is a large part of the game, an
|
|||
### Defense
|
||||
|
||||
In order to protect your corestone score and allow it to naturally regenerate, you must destroy any attacking disruptors. Any expensive disruptors gained in battle can then be turned against your enemies, so a successful defense will help you and harm your enemies greatly.
|
||||
You can place traps, turrets, wards, and fight personally to drive the attackers away from their disruptors.
|
||||
|
||||
# Magic
|
||||
|
||||
Closely integrated with the kingdoms mod is the magic mod, which provides many attacking and defending options.
|
||||
|
||||
## Crystals
|
||||
|
||||
Use of magic begins with Magic Crystals, of which most are found underground:
|
||||
|
||||
* Rage (Red)
|
||||
* Calm (Blue)
|
||||
* Solidity (Yellow)
|
||||
* Vitality (Green)
|
||||
* Area (Teal)
|
||||
* Control (Purple)
|
||||
|
||||
Some crystals must be produced through machiney:
|
||||
|
||||
* Night (Grey), produced through *Nightcalls*
|
||||
* Day (White), produced through *Daypulls*
|
||||
|
||||
## Essences
|
||||
|
||||
Crystals can be melted into essences, which are the basic form of magic. When combined with spellbinding materials such as silver, essences can be merged into larger magical devices, or converted into spells.
|
||||
|
||||
## Spells
|
||||
|
||||
Spells are the most active form of magic. They are items which you can hold, and their use will drain upon your mana.
|
||||
There are three kinds of spells:
|
||||
|
||||
* Attack: These include Fireballs, Bombs, and Missiles, each of which deal different kinds of damage and are thrown by left-clicking with them.
|
||||
* Defense: This includes spells such as shields, which can be held in the hand and will be consumed to counter damage thrown at you from spells or explosions.
|
||||
* Action: Other spells are in this category, such as a spell to drop flowing water over a small area or a spell to change water sources into ice (which also deals cold damage).
|
||||
|
||||
## Mana
|
||||
|
||||
Each player has a mana count, which regenerates slowly, speeding up if the player is nearly or at full health.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
default
|
||||
fire
|
||||
|
||||
magic?
|
||||
|
|
|
@ -143,7 +143,11 @@ local function entity_physics(pos, radius)
|
|||
|
||||
local damage = (4 / dist) * radius
|
||||
if not obj:get_luaentity() or not NO_HIT_ENTS[obj:get_luaentity().name] then
|
||||
magic.damage_obj(obj, {fleshy=damage/2, fire=damage/2})
|
||||
if rawget(_G, 'magic') then
|
||||
magic.damage_obj(obj, {fleshy=damage/2, fire=damage/2})
|
||||
else
|
||||
obj:punch(obj, 1.0, {full_punch_interval=1.0, damage_groups={fleshy=damage}, nil})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|