summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/ghost.cc
diff options
context:
space:
mode:
authorDracoOmega <draco_omega@live.com>2014-02-25 07:21:30 -0330
committerSteve Melenchuk <smelenchuk@gmail.com>2014-03-06 09:58:10 -0700
commit2a0814e80e4265e48f4a64bdc9eff03199f80c2f (patch)
treedb7dfb24b59ad76cc25edd9bd40aa2cee4e9b1f3 /crawl-ref/source/ghost.cc
parent5112a529f80abc0ff50deb9ed1cb59b1f15397f6 (diff)
downloadcrawl-ref-2a0814e80e4265e48f4a64bdc9eff03199f80c2f.tar.gz
crawl-ref-2a0814e80e4265e48f4a64bdc9eff03199f80c2f.zip
New spell: Spellforged Servitor
With the idea of introducing more summoning spells that a bit unique in some way, this is a level 7 Summoning/Conjurations spell which summons a single golem-like being that possesses a subset of the caster's own conjurations. The spell list is assembled deterministically, somewhat similar to player ghosts (though different in a number of regards). The first 3 spell slots draw from a 'primary' list containing direct conjurations like bolt of cold or poison arrow, while the next 2 are from a 'secondary' list which tends to contain AoE effects and cloud spells, as well as things like airstrike. Spells are selected roughly in order of level and power, with the player's higher spell skills having a small effect. In practice, I think the servitor will fairly transparently possess a selection of the player's better spells, without anyone needing to think much on how it arrived at this list. Many of the highest level spells (like fire storm and shatter) are excluded not only for power reasons, but also because a servitor using these could be downright dangerous to its caster. The main exception I made here was CBL, which is allowed (being both lower-level and often similarly dangerous when the player uses it, though I open to changing this).
Diffstat (limited to 'crawl-ref/source/ghost.cc')
-rw-r--r--crawl-ref/source/ghost.cc128
1 files changed, 128 insertions, 0 deletions
diff --git a/crawl-ref/source/ghost.cc b/crawl-ref/source/ghost.cc
index 5d56eacfb2..0418dff169 100644
--- a/crawl-ref/source/ghost.cc
+++ b/crawl-ref/source/ghost.cc
@@ -20,6 +20,7 @@
#include "random.h"
#include "skills2.h"
#include "spl-cast.h"
+#include "spl-util.h"
#include "mon-util.h"
#include "mon-transit.h"
#include "player.h"
@@ -1044,3 +1045,130 @@ int ghost_level_to_rank(const int xl)
if (xl < 27) return 6;
return 7;
}
+
+static spell_type servitor_spells_primary[] =
+{
+ SPELL_LEHUDIBS_CRYSTAL_SPEAR,
+ SPELL_IOOD,
+ SPELL_IRON_SHOT,
+ SPELL_BOLT_OF_FIRE,
+ SPELL_BOLT_OF_COLD,
+ SPELL_POISON_ARROW,
+ SPELL_LIGHTNING_BOLT,
+ SPELL_BOLT_OF_MAGMA,
+ SPELL_VENOM_BOLT,
+ SPELL_THROW_ICICLE,
+ SPELL_ISKENDERUNS_MYSTIC_BLAST,
+ SPELL_NO_SPELL, // end search
+};
+
+static spell_type servitor_spells_secondary[] =
+{
+ SPELL_CONJURE_BALL_LIGHTNING,
+ SPELL_FIREBALL,
+ SPELL_AIRSTRIKE,
+ SPELL_LRD,
+ SPELL_FREEZING_CLOUD,
+ SPELL_POISONOUS_CLOUD,
+ SPELL_FORCE_LANCE,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_NO_SPELL, // end search
+};
+
+static spell_type servitor_spells_fallback[] =
+{
+ SPELL_STONE_ARROW,
+ SPELL_STICKY_FLAME,
+ SPELL_THROW_FLAME,
+ SPELL_THROW_FROST,
+ SPELL_FREEZE,
+ SPELL_FLAME_TONGUE,
+ SPELL_STING,
+ SPELL_SANDBLAST,
+ SPELL_MAGIC_DART,
+ SPELL_NO_SPELL, // end search
+};
+
+static spell_type _best_aligned_spell(vector<spell_type> spells, skill_type skill)
+{
+ for (unsigned int i = 0; i < spells.size(); ++i)
+ {
+ if (spell_typematch(spells[i], skill))
+ return spells[i];
+ }
+
+ // If we couldn't find any that match, just pick the first one
+ return spells[0];
+}
+
+// Select servitor spells based on those known to the player
+// (Primary determines whether we are populating the first 3 or next 2 slots)
+bool ghost_demon::populate_servitor_spells(spell_type* spell_list, bool primary,
+ skill_type primary_skill)
+{
+ vector<spell_type> candidates;
+ const unsigned int num = (primary ? 3 : 2);
+ const unsigned int offset = (primary ? 0 : 3);
+
+ int i = 0;
+ spell_type spell = SPELL_NO_SPELL;
+ while ((spell = spell_list[i++]) != SPELL_NO_SPELL)
+ {
+ if (_know_spell(spell))
+ candidates.push_back(spell);
+ }
+
+ if (candidates.size() >= num)
+ {
+ for (unsigned int j = offset; j < offset + num; ++j)
+ spells[j] = candidates[j - offset];
+ }
+ else if (candidates.size() > 0)
+ {
+ // Choose the highest-level spell best aligned with our spell
+ // skills to duplicate
+ const spell_type copy_spell = _best_aligned_spell(candidates,
+ primary_skill);
+
+ for (unsigned int j = offset; j < offset + num; ++j)
+ {
+ if (candidates.size() > j - offset)
+ spells[j] = candidates[j - offset];
+ else
+ spells[j] = copy_spell;
+ }
+ }
+
+ return (candidates.size() > 0);
+}
+
+void ghost_demon::init_spellforged_servitor()
+{
+ // Determine highest magic skill (used for solving some tie-breakers)
+ skill_type best_magic_skill = NUM_SKILLS;
+ int skill_level = -1;
+ for (int i = SK_FIRE_MAGIC; i <= SK_POISON_MAGIC; ++i)
+ {
+ if (you.skill((skill_type)i) >= skill_level)
+ {
+ skill_level = you.skill((skill_type)i);
+ best_magic_skill = (skill_type)i;
+ }
+ }
+
+ int pow = calc_spell_power(SPELL_SPELLFORGED_SERVITOR, true);
+
+ speed = 10;
+ ev = 10;
+ ac = 10;
+ xl = 9 + (pow/16);
+ max_hp = 80;
+ spellcaster = true;
+ damage = 0;
+ att_type = AT_NONE;
+
+ // Give the servitor its spells
+ if (!populate_servitor_spells(servitor_spells_primary, true, best_magic_skill))
+ populate_servitor_spells(servitor_spells_fallback, true, best_magic_skill);
+ populate_servitor_spells(servitor_spells_secondary, false, best_magic_skill);
+}