Remove magic.

master
Beha 2017-02-09 22:23:12 -05:00
parent 168c4957f0
commit 575ae75855
37 changed files with 35 additions and 1803 deletions

View File

@ -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.

View File

@ -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, ""}
}
})

View File

@ -1,5 +1,5 @@
default
kingdoms_meta
magic
magic?
ancient_world?
3d_armor?

View File

@ -6,4 +6,3 @@ if kingdoms.config.mapgen then
kingdoms.log("action", "Applied mapgen settings.")
end
magic.register_mapgen()

View File

@ -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"},
},
})

View File

@ -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

View File

@ -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

View File

@ -1,4 +0,0 @@
default
kingdoms_meta
ancient_world?
tnt?

View File

@ -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")

View File

@ -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)

View File

@ -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

View File

@ -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"},
})

Binary file not shown.

Binary file not shown.

View File

@ -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

View File

@ -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"},
},
})

View File

@ -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"},
},
})

View File

@ -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"},
},
})

View File

@ -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

View File

@ -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,
},
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -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

View File

@ -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,
})

View File

@ -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

View File

@ -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.

View File

@ -1,3 +1,3 @@
default
fire
magic?

View File

@ -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