Forked from
tome / Tales of MajEyal
1458 commits behind the upstream repository.
-
Otowa Kotori authoredOtowa Kotori authored
living-weapons.lua 12.32 KiB
-- ToME - Tales of Maj'Eyal
-- Copyright (C) 2009 - 2019 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
startx = 12
starty = 10
setStatusAll{no_teleport=true}
rotates = {"default", "90", "180", "270", "flipx", "flipy"}
local Talents = require("engine.interface.ActorTalents")
--make other requirement equipment from Cursed Sentry
local make_req = function(el, o, subtype, slot)
local o2 = nil
if o.subtype == subtype then
o2 = o:clone()
o2.no_drop = true
else
local level = o.material_level or 1
-- Code from cursed aura
local egos = o.egos_number or (o.ego_list and #o.ego_list) or (o.egoed and 1) or 0
local greater = o.greater_ego or 0
local double_greater = (o.unique and egos == 0) or greater > 1 -- artifact or purple
local greater_normal = (o.unique and egos > 2) or greater == 1 and egos > 1 -- randart or blue
local greater = (o.unique and egos > 0) or greater == 1 and egos == 1 -- rare or blue
local double_ego = not o.unique and greater == 0 and egos > 1
local ego = not o.unique and greater == 0 and egos == 1
local filter = {subtype=subtype, ignore_material_restriction=true, tome={double_greater=double_greater and 1, greater_normal=greater_normal and 1,
greater = greater and 1, double_ego = double_ego and 1, ego = ego and 1}, special = function(e) return not e.unique and e.material_level == level end}
o2 = game.zone:makeEntity(game.level, "object", filter, nil, true)
o2.no_drop = true
if slot == "QUIVER" then o2.infinite = true end
end
el[#el+1] = {o2, slot or "OFFHAND"}
end
local imbueEgo = function(gem, object)
if not gem then return end
if not object then return end
local Entity = require("engine.Entity")
local ego = Entity.new{
name = "imbue "..gem.name,
keywords = {[gem.name] = true},
wielder = table.clone(gem.imbue_powers),
talent_on_spell = gem.talent_on_spell,
fake_ego = true, unvault_ego = true,
}
game.zone:applyEgo(object, ego, "object", true)
end
-- A lot of elseif
local make_poltergeist = function(type)
local o = nil
local filter = nil
local x_level = nil
if type == "greater" then
filter = {no_tome_drops=true, unique=true, special=function(o) return (o.slot == "MAINHAND") end}
x_level = math.max(15, resolvers.current_level + 10)
elseif type == "normal" then
filter = {id=true, type="weapon", add_levels=5, force_tome_drops=true, tome_drops="store", tome_mod="gvault", special=function(o) return true end}
x_level = math.max(10, resolvers.current_level + 5)
else
filter = {id=true, type="weapon", add_levels=0, force_tome_drops=true, tome_drops="store", tome_mod="vault", special=function(o) return true end}
x_level = math.max(5, resolvers.current_level)
end
o = game.zone:makeEntity(game.level, "object", filter, nil, true)
o.no_drop = false
local e = mod.class.NPC.new{
type = "construct", subtype = "weapon",
display = o.display, color=o.color, image = o.image, blood_color = colors.GREY,
faction = "enemies",
body = { INVEN = 10, MAINHAND=1, OFFHAND=1, QUIVER=1,PSIONIC_FOCUS=1},
level_range = {x_level, nil},
size_category = 1,
ai = "tactical", ai_state = { talent_in=2, ai_move="move_astar", },
ai_tactic = resolvers.tactic"melee",
max_life = resolvers.rngavg(100,120),
stats = {wil= 20, cun = 20, mag = 20, con = 20},
resolvers.sustains_at_birth(),
resolvers.talents{
[Talents.T_WEAPON_COMBAT]={base=1, every=10, max=5},
}
}
local class = nil
local req = nil
local el = {}
if o.subtype == "staff" then
class = "Archmage"
e.autolevel = "caster"
e.max_mana = e.max_mana + 250 -- protect staffs from being dumb and having 0 mana left over after sustains
e.ai_tactic = resolvers.tactic"ranged"
e[#e+1] = resolvers.talents{
[Talents.T_MANATHRUST]={base=1, every=10, max=5},
[Talents.T_FLAME]={base=1, every=10, max=5},
}
elseif o.subtype == "dagger" then
class = "Rogue"
e.autolevel = "rogue"
e[#e+1] = resolvers.talents{
[Talents.T_KNIFE_MASTERY]={base=1, every=10, max=5},
}
make_req(el, o, "dagger")
elseif o.subtype == "longbow" then
class = "Archer"
e.autolevel = "warrior"
e.ai_tactic = resolvers.tactic"ranged"
e[#e+1] = resolvers.talents{
[Talents.T_MASTER_MARKSMAN] = {base=1, every=10, max=5},
}
make_req(el, o, "arrow", "QUIVER")
elseif o.subtype == "sling" then
class = "Skirmisher"
e.autolevel = "rogue"
e.ai_tactic = resolvers.tactic"ranged"
e[#e+1] = resolvers.talents{
[Talents.T_SKIRMISHER_SLING_SUPREMACY] = {base=1, every=10, max=5},
[Talents.T_SKIRMISHER_KNEECAPPER] = {base=1, every=10, max=5},
[Talents.T_SHOOT] = 1
}
make_req(el, o, "shield")
make_req(el, o, "shot", "QUIVER")
elseif o.subtype == "mindstar" then
class = "Mindslayer"
e.autolevel = "wildcaster"
e[#e+1] = resolvers.talents{
[Talents.T_PSIBLADES] = {base=1, every=10, max=5},
[Talents.T_TELEKINETIC_SMASH] = 1,
}
e[#e+1] = resolvers.equip{
{type="weapon", subtype="greatsword", autoreq=true, force_inven = "PSIONIC_FOCUS", no_drops=true},
}
make_req(el, o, "mindstar")
elseif o.subtype == "steamgun" then --For Orcs DLC!
class = "Gunslinger"
e.autolevel = "slinger"
e.ai_tactic = resolvers.tactic"ranged"
e[#e+1] = resolvers.talents{
[Talents.T_STEAMGUN_MASTERY] = {base=1, every=10, max=5},
[Talents.T_STRAFE] = {base=1, every=10, max=5},
[Talents.T_SHOOT] = 1
}
e[#e+1] = resolvers.inscription("IMPLANT:_STEAM_GENERATOR", {cooldown=32, power=10}),
make_req(el, o, "steamgun")
make_req(el, o, "shot", "QUIVER")
elseif o.subtype == "steamsaw" then
class = "Sawbutcher"
e.autolevel = "warrior"
e[#e+1] = resolvers.talents{
[Talents.T_STEAMSAW_MASTERY]={base=1, every=10, max=5},
[Talents.T_TO_THE_ARMS] = {base=1, every=10, max=5},
}
e[#e+1] = resolvers.inscription("IMPLANT:_STEAM_GENERATOR", {cooldown=32, power=10}),
make_req(el, o, "steamsaw")
elseif o.subtype == "whip" then
class = "Corruptor"
e.autolevel = "caster"
e.ai_tactic = resolvers.tactic"ranged"
e[#e+1] = resolvers.talents{
[Talents.T_CORRUPTED_NEGATION]={base=3, every=12, max=6},
[Talents.T_DRAIN]={base=5, every=10, max=7},
[Talents.T_BLOOD_GRASP]={base=4, every=5, max=7},
}
elseif o.type == "weapon" and o.slot_forbid == "OFFHAND" then
class = "Berserker"
e.autolevel = "warrior"
e[#e+1] = resolvers.talents{
[Talents.T_WEAPONS_MASTERY]={base=1, every=10, max=5},
}
elseif o.type == "weapon" and o.offslot == nil then
class = "Bulwark"
e.autolevel = "warrior"
e[#e+1] = resolvers.talents{
[Talents.T_WEAPONS_MASTERY]={base=1, every=10, max=5},
[Talents.T_ARMOUR_TRAINING]=2
}
make_req(el, o, "shield")
else -- failsafe for if no other category fits so we don't break generation
class = "Doomed"
e.autolevel = "wildcaster"
e[#e+1] = resolvers.talents{
[Talents.T_CALL_SHADOWS]={base=1, every=8, max=6},
[Talents.T_SHADOW_WARRIORS]={base=1, every=8, max=6},
[Talents.T_REPROACH]={base=5, every=10, max=5},
}
end
e[#e+1] = resolvers.auto_equip_filters(class)
if type == "greater" then
e.name = ("Poltergeist %s"):tformat(_t(o.name))
e.rank = 3.5
e.max_life = resolvers.rngavg(100,120)
e.life_rating = 20
e.resist = {all=20}
e.auto_classes={
{class=class, start_level=10, level_rate=80},
{class=(rng.percent(65) and "Cursed" or "Doomed"), start_level=20, level_rate=40}
}
elseif type == "normal" then
e.name = ("Animated %s"):tformat(_t(o.name))
e.rank = 3
e.max_life = resolvers.rngavg(80,100)
e.life_rating = 15
e.auto_classes={
{class=class, start_level=10, level_rate=50}
}
else
e.name = ("Moving %s"):tformat(_t(o.name))
e.rank = 2
e.max_life = resolvers.rngavg(60,80)
e.life_rating = 12
e.auto_classes={
{class=class, start_level=10, level_rate=30}
}
end
if type == "greater" then
local filter = {type="gem", ignore_material_restriction=true,special=function(ee) return ee.material_level == o.material_level end}
gem = game.zone:makeEntity(game.level, "object", filter, nil, true)
imbueEgo(gem, o)
o.name = ("Poltergeist's %s"):tformat(_t(o.name))
end
local qo = nil
--if class ==
e:resolve()
e:resolve(nil, true)
game.zone:addEntity(game.level, o, "object")
e:wearObject(o, true, false, "MAINHAND")
for _, v in ipairs(el) do
e:wearObject(v[1], true, false, v[2])
end
return e
end
specialList("actor", {
"/data/general/npcs/wight.lua",
"/data/general/npcs/skeleton.lua",
"/data/general/npcs/horror.lua",
})
local p_char = '0'
local used_char = {}
local function check_def(def)
for x = 1, #(def[1]) do
for y = 1, #def do
used_char[used_char[y]:sub(x,x)] = true
end
end
end
local function get_next(p_char)
while used_char[p_char] == true do
p_char = string.char(string.byte(p_char) + 1)
end
used_char[p_char] = true
return p_char
end
function make_poltergeist_room(def)
for x = 1, #(def[1]) do
for y = 1, #def do
if def[y]:sub(x, x) == "P" then
p_char = get_next(p_char)
defineTile(p_char, "FLOOR", nil, make_poltergeist("greater"))
def[y] = def[y]:sub(1, x-1)..p_char..def[y]:sub(x+1, #def[y])
elseif def[y]:sub(x, x) == "p" then
p_char = get_next(p_char)
defineTile(p_char, "FLOOR", nil, make_poltergeist("normal"))
def[y] = def[y]:sub(1, x-1)..p_char..def[y]:sub(x+1, #def[y])
elseif def[y]:sub(x, x) == "a" then
p_char = get_next(p_char)
defineTile(p_char, "FLOOR", nil, make_poltergeist("smaller"))
def[y] = def[y]:sub(1, x-1)..p_char..def[y]:sub(x+1, #def[y])
end
end
end
return def
end
-- It had been updated to detect unused characters on alphabet to be replaced with moving weapons.
-- Just use make_poltergeist_room(def)
defineTile('#', "WALL")
defineTile('+', "DOOR")
defineTile('.', "FLOOR")
defineTile('X', "HARDWALL")
defineTile('!', "DOOR_VAULT")
defineTile('A', "FLOOR", {random_filter={type="armor", add_levels=5, tome_mod="gvault"}}, nil)
defineTile('W', "FLOOR", {random_filter={type="weapon", add_levels=5, tome_mod="gvault"}}, {random_filter={subtype='wight', add_levels=5}})
defineTile('Z', "FLOOR", {random_filter={add_levels=10, tome_mod="gvault"}}, nil)
defineTile('b', "FLOOR", nil, {random_filter={name='blade horror', add_levels=10}})
defineTile('h', "FLOOR", {random_filter={add_levels=10, tome_mod="gvault"}}, {random_filter={subtype='eldritch', add_levels=10}})
defineTile('s', "FLOOR", nil, {random_filter={subtype='skeleton', add_levels=5}})
startx = 12
starty = 10
local def = {
[[XXXXXXXXXXXXXXX]],
[[XA#pA.a#...aZZX]],
[[XP+....+....hpX]],
[[XW#.W.a##.....X]],
[[X##+######....X]],
[[Xp..#..P.##a..X]],
[[X..a#p...p##+#X]],
[[XA..#.....#.a.X]],
[[X...###+###s.sX]],
[[XWpA+..b###...X]],
[[XXXXXXXXXXXX!XX]],
}
return make_poltergeist_room(def)