3 * Summary: data handlers for player-available spell list *
4 * Written by: don brodale <dbrodale@bigfootinteractive.com> *
37 #include "spl-damage.h"
41 #include "transform.h"
48 unsigned int disciplines
; // bitfield
49 unsigned int flags
; // bitfield
52 // Usually in the range 0..200 (0 means uncapped).
53 // Note that some spells are also capped through zap_type.
54 // See spell_power_cap below.
57 // At power 0, you get min_range. At power power_cap, you get max_range.
61 // Modify spell level for spell noise purposes.
64 const char *target_prompt
;
66 // If a monster is casting this, does it need a tracer?
69 // The spell can be used no matter what the monster's foe is.
73 static struct spell_desc spelldata
[] =
78 static int spell_list
[NUM_SPELLS
];
80 #define SPELLDATASIZE (sizeof(spelldata)/sizeof(struct spell_desc))
82 static struct spell_desc
*_seekspell(spell_type spellid
);
83 static bool _cloud_helper(cloud_func func
, const coord_def
& where
,
84 int pow
, int spread_rate
,
85 cloud_type ctype
, const actor
*agent
, int colour
,
86 std::string name
, std::string tile
);
89 // BEGIN PUBLIC FUNCTIONS
92 // All this does is merely refresh the internal spell list {dlb}:
93 void init_spell_descs(void)
95 for (int i
= 0; i
< NUM_SPELLS
; i
++)
98 for (unsigned int i
= 0; i
< SPELLDATASIZE
; i
++)
100 spell_desc
&data
= spelldata
[i
];
103 if (data
.id
< SPELL_NO_SPELL
|| data
.id
>= NUM_SPELLS
)
104 end(1, false, "spell #%d has invalid id %d", i
, data
.id
);
106 if (data
.title
== NULL
|| strlen(data
.title
) == 0)
107 end(1, false, "spell #%d, id %d has no name", i
, data
.id
);
109 if (data
.level
< 1 || data
.level
> 9)
111 end(1, false, "spell '%s' has invalid level %d",
112 data
.title
, data
.level
);
115 if (data
.min_range
> data
.max_range
)
117 end(1, false, "spell '%s' has min_range larger than max_range",
121 if (data
.flags
& SPFLAG_TARGETING_MASK
)
123 if (data
.min_range
<= -1 || data
.max_range
<= 0)
125 end(1, false, "targeted/directed spell '%s' has invalid range",
131 spell_list
[data
.id
] = i
;
135 typedef std::map
<std::string
, spell_type
> spell_name_map
;
136 static spell_name_map spell_name_cache
;
138 void init_spell_name_cache()
140 for (int i
= 0; i
< NUM_SPELLS
; i
++)
142 spell_type type
= static_cast<spell_type
>(i
);
144 if (!is_valid_spell(type
))
147 const char *sptitle
= spell_title(type
);
149 const std::string spell_name
= lowercase_string(sptitle
);
150 spell_name_cache
[spell_name
] = type
;
154 spell_type
spell_by_name(std::string name
, bool partial_match
)
157 return (SPELL_NO_SPELL
);
163 spell_name_map::iterator i
= spell_name_cache
.find(name
);
165 if (i
!= spell_name_cache
.end())
168 return (SPELL_NO_SPELL
);
172 for (int i
= 0; i
< NUM_SPELLS
; i
++)
174 spell_type type
= static_cast<spell_type
>(i
);
175 if (!is_valid_spell(type
))
178 const char *sptitle
= spell_title(type
);
179 const std::string spell_name
= lowercase_string(sptitle
);
181 if (spell_name
.find(name
) != std::string::npos
)
183 if (spell_name
== name
)
184 return static_cast<spell_type
>(i
);
190 return (spellmatch
!= -1 ? static_cast<spell_type
>(spellmatch
)
194 spschool_flag_type
school_by_name(std::string name
)
196 spschool_flag_type short_match
, long_match
;
197 int short_matches
, long_matches
;
199 short_match
= long_match
= SPTYP_NONE
;
200 short_matches
= long_matches
= 0;
204 for (int i
= 0; i
<= SPTYP_RANDOM
; i
++)
206 spschool_flag_type type
= (spschool_flag_type
) (1 << i
);
208 std::string short_name
= spelltype_short_name(type
);
209 std::string long_name
= spelltype_long_name(type
);
211 lowercase(short_name
);
212 lowercase(long_name
);
214 if (name
== short_name
)
216 if (name
== long_name
)
219 if (short_name
.find(name
) != std::string::npos
)
224 if (long_name
.find(name
) != std::string::npos
)
231 if (short_matches
!= 1 && long_matches
!= 1)
234 if (short_matches
== 1 && long_matches
!= 1)
236 if (short_matches
!= 1 && long_matches
== 1)
239 if (short_match
== long_match
)
245 int get_spell_slot_by_letter(char letter
)
247 ASSERT(isaalpha(letter
));
249 const int index
= letter_to_index(letter
);
251 if (you
.spell_letter_table
[ index
] == -1)
254 return (you
.spell_letter_table
[index
]);
257 int get_spell_slot(spell_type spell
)
259 for (int i
= 0; i
< MAX_KNOWN_SPELLS
; i
++)
260 if (you
.spells
[i
] == spell
)
266 spell_type
get_spell_by_letter(char letter
)
268 ASSERT(isaalpha(letter
));
270 const int slot
= get_spell_slot_by_letter(letter
);
272 return ((slot
== -1) ? SPELL_NO_SPELL
: you
.spells
[slot
]);
275 bool add_spell_to_memory(spell_type spell
)
279 // first we find a slot in our head:
280 for (i
= 0; i
< MAX_KNOWN_SPELLS
; i
++)
282 if (you
.spells
[i
] == SPELL_NO_SPELL
)
286 you
.spells
[i
] = spell
;
288 // now we find an available label:
289 for (j
= 0; j
< 52; j
++)
291 if (you
.spell_letter_table
[j
] == -1)
295 you
.spell_letter_table
[j
] = i
;
299 take_note(Note(NOTE_LEARN_SPELL
, spell
));
302 tiles
.layout_statcol();
309 bool del_spell_from_memory_by_slot(int slot
)
313 if (you
.last_cast_spell
== you
.spells
[slot
])
314 you
.last_cast_spell
= SPELL_NO_SPELL
;
316 you
.spells
[ slot
] = SPELL_NO_SPELL
;
318 for (j
= 0; j
< 52; j
++)
320 if (you
.spell_letter_table
[j
] == slot
)
321 you
.spell_letter_table
[j
] = -1;
328 tiles
.layout_statcol();
335 bool del_spell_from_memory(spell_type spell
)
337 int i
= get_spell_slot(spell
);
341 return del_spell_from_memory_by_slot(i
);
344 int spell_hunger(spell_type which_spell
, bool rod
)
346 const int level
= spell_difficulty(which_spell
);
348 const int basehunger
[] = {
349 50, 95, 160, 250, 350, 550, 700, 850, 1000
354 if (level
< 10 && level
> 0)
355 hunger
= basehunger
[level
-1];
357 hunger
= (basehunger
[0] * level
* level
) / 4;
361 hunger
-= 10 * you
.skills
[SK_EVOCATIONS
];
362 hunger
= std::max(hunger
, level
* 5);
365 hunger
-= you
.intel() * you
.skills
[SK_SPELLCASTING
];
373 // Used to determine whether or not a monster should always fire this spell
374 // if selected. If not, we should use a tracer.
376 // Note - this function assumes that the monster is "nearby" its target!
377 bool spell_needs_tracer(spell_type spell
)
379 return (_seekspell(spell
)->ms_needs_tracer
);
382 // Checks if the spell is an explosion that can be placed anywhere even without
383 // an unobstructed beam path, such as fire storm.
384 bool spell_is_direct_explosion(spell_type spell
)
386 return (spell
== SPELL_FIRE_STORM
|| spell
== SPELL_HELLFIRE_BURST
);
389 bool spell_needs_foe(spell_type spell
)
391 return (!_seekspell(spell
)->ms_utility
);
394 bool spell_harms_target(spell_type spell
)
396 const unsigned int flags
= _seekspell(spell
)->flags
;
398 if (flags
& (SPFLAG_HELPFUL
| SPFLAG_NEUTRAL
))
401 if (flags
& SPFLAG_TARGETING_MASK
)
407 bool spell_harms_area(spell_type spell
)
409 const unsigned int flags
= _seekspell(spell
)->flags
;
411 if (flags
& (SPFLAG_HELPFUL
| SPFLAG_NEUTRAL
))
414 if (flags
& SPFLAG_AREA
)
420 bool spell_sanctuary_castable(spell_type spell
)
425 // applied to spell misfires (more power = worse) and triggers
426 // for Xom acting (more power = more likely to grab his attention) {dlb}
427 int spell_mana(spell_type which_spell
)
429 if (vehumet_supports_spell(which_spell
)
430 && you
.religion
== GOD_VEHUMET
431 && !player_under_penance()
432 && you
.piety
>= piety_breakpoint(3)
433 && _seekspell(which_spell
)->level
>= 5)
435 return (_seekspell(which_spell
)->level
- 1);
438 return (_seekspell(which_spell
)->level
);
441 // applied in naughties (more difficult = higher level knowledge = worse)
442 // and triggers for Sif acting (same reasoning as above, just good) {dlb}
443 int spell_difficulty(spell_type which_spell
)
445 return (_seekspell(which_spell
)->level
);
448 int spell_levels_required(spell_type which_spell
)
450 int levels
= spell_difficulty(which_spell
);
452 if (which_spell
== SPELL_DELAYED_FIREBALL
453 && you
.has_spell(SPELL_FIREBALL
))
455 levels
-= spell_difficulty(SPELL_FIREBALL
);
457 else if (which_spell
== SPELL_FIREBALL
458 && you
.has_spell(SPELL_DELAYED_FIREBALL
))
466 unsigned int get_spell_flags(spell_type which_spell
)
468 return (_seekspell(which_spell
)->flags
);
471 const char *get_spell_target_prompt(spell_type which_spell
)
473 return (_seekspell(which_spell
)->target_prompt
);
476 bool spell_typematch(spell_type which_spell
, unsigned int which_discipline
)
478 return (get_spell_disciplines(which_spell
) & which_discipline
);
481 //jmf: next two for simple bit handling
482 unsigned int get_spell_disciplines(spell_type spell
)
484 unsigned int dis
= _seekspell(spell
)->disciplines
;
485 if (spell
== SPELL_DRAGON_FORM
&& player_genus(GENPC_DRACONIAN
))
486 dis
&= (~SPTYP_FIRE
);
491 int count_bits(unsigned int bits
)
496 for (n
= 1; n
< INT_MAX
; n
<<= 1)
503 // NOTE: Assumes that any single spell won't belong to conflicting
505 bool disciplines_conflict(unsigned int disc1
, unsigned int disc2
)
507 const unsigned int combined
= disc1
| disc2
;
509 return ((combined
& SPTYP_EARTH
) && (combined
& SPTYP_AIR
)
510 || (combined
& SPTYP_FIRE
) && (combined
& SPTYP_ICE
)
511 || (combined
& SPTYP_HOLY
) && (combined
& SPTYP_NECROMANCY
));
514 const char *spell_title(spell_type spell
)
516 return (_seekspell(spell
)->title
);
520 // FUNCTION APPLICATORS: Idea from Juho Snellman <jsnell@lyseo.edu.ouka.fi>
521 // on the Roguelike News pages, Development section.
522 // <URL:http://www.skoardy.demon.co.uk/rlnews/>
523 // Here are some function applicators: sort of like brain-dead,
524 // home-grown iterators for the container "dungeon".
526 // Apply a function-pointer to all visible squares
527 // Returns summation of return values from passed in function.
528 int apply_area_visible(cell_func cf
, int power
,
529 bool pass_through_trans
, actor
*agent
)
533 for (radius_iterator
ri(you
.pos(), LOS_RADIUS
); ri
; ++ri
)
534 if (pass_through_trans
|| you
.see_cell_no_trans(*ri
))
535 rv
+= cf(*ri
, power
, 0, agent
);
540 // Applies the effect to all nine squares around/including the target.
541 // Returns summation of return values from passed in function.
542 int apply_area_square(cell_func cf
, const coord_def
& where
, int power
,
547 for (adjacent_iterator
ai(where
, false); ai
; ++ai
)
548 rv
+= cf(*ai
, power
, 0, agent
);
554 // Applies the effect to the eight squares beside the target.
555 // Returns summation of return values from passed in function.
556 int apply_area_around_square(cell_func cf
, const coord_def
& where
, int power
,
561 for (adjacent_iterator
ai(where
, true); ai
; ++ai
)
562 rv
+= cf(*ai
, power
, 0, agent
);
567 // Like apply_area_around_square, but for monsters in those squares,
568 // and takes care not to affect monsters twice that change position.
569 int apply_monsters_around_square(monster_func mf
, const coord_def
& where
,
573 std::set
<const monster
*> affected
;
574 for (adjacent_iterator
ai(where
, true); ai
; ++ai
)
576 monster
* mon
= monster_at(*ai
);
577 if (mon
&& affected
.find(mon
) == affected
.end())
579 rv
+= mf(mon
, power
);
580 affected
.insert(mon
);
587 // Affect up to max_targs monsters around a point, chosen randomly.
588 // Return varies with the function called; return values will be added up.
589 int apply_random_around_square(cell_func cf
, const coord_def
& where
,
590 bool exclude_center
, int power
, int max_targs
,
598 if (max_targs
>= 9 && !exclude_center
)
599 return (apply_area_square(cf
, where
, power
, agent
));
601 if (max_targs
>= 8 && exclude_center
)
602 return (apply_area_around_square(cf
, where
, power
, agent
));
608 for (adjacent_iterator
ai(where
, exclude_center
); ai
; ++ai
)
610 if (monster_at(*ai
) == NULL
&& *ai
!= you
.pos())
616 // Slight difference here over the basic algorithm...
618 // For cases where the number of choices <= max_targs it's
619 // obvious (all available choices will be selected).
621 // For choices > max_targs, here's a brief proof:
623 // Let m = max_targs, k = choices - max_targs, k > 0.
625 // Proof, by induction (over k):
627 // 1) Show n = m + 1 (k = 1) gives uniform distribution,
628 // P(new one not chosen) = 1 / (m + 1).
630 // P(specific previous one replaced) = --- * --- = ---
633 // So the probablity is uniform (ie. any element has
634 // a 1/(m+1) chance of being in the unchosen slot).
636 // 2) Assume the distribution is uniform at n = m+k.
637 // (ie. the probablity that any of the found elements
638 // was chosen = m / (m+k) (the slots are symetric,
639 // so it's the sum of the probabilities of being in
642 // 3) Show n = m + k + 1 gives a uniform distribution.
643 // P(new one chosen) = m / (m + k + 1)
644 // P(any specific previous choice remaining chosen)
645 // = [1 - P(swaped into m+k+1 position)] * P(prev. chosen)
647 // = [ 1 - ----- * --- ] * ---
651 // = ----- * --- = -----
654 // Therefore, it's uniform for n = m + k + 1. QED
656 // The important thing to note in calculating the last
657 // probability is that the chosen elements have already
658 // passed tests which verify that they *don't* belong
659 // in slots m+1...m+k, so the only positions an already
660 // chosen element can end up in are its original
661 // position (in one of the chosen slots), or in the
664 // The new item can, of course, be placed in any slot,
665 // swapping the value there into the new slot... we
666 // just don't care about the non-chosen slots enough
667 // to store them, so it might look like the item
668 // automatically takes the new slot when not chosen
669 // (although, by symetry all the non-chosen slots are
670 // the same... and similarly, by symetry, all chosen
671 // slots are the same).
673 // Yes, that's a long comment for a short piece of
674 // code, but I want people to have an understanding
675 // of why this works (or at least make them wary about
676 // changing it without proof and breaking this code). -- bwr
678 // Accept the first max_targs choices, then when
679 // new choices come up, replace one of the choices
680 // at random, max_targs/count of the time (the rest
681 // of the time it replaces an element in an unchosen
682 // slot -- but we don't care about them).
683 if (count
<= max_targs
)
685 targs
[count
- 1] = *ai
;
687 else if (x_chance_in_y(max_targs
, count
))
689 const int pick
= random2(max_targs
);
694 const int targs_found
= std::min(count
, max_targs
);
698 // Used to divide the power up among the targets here, but
699 // it's probably better to allow the full power through and
700 // balance the called function. -- bwr
701 for (int i
= 0; i
< targs_found
; i
++)
703 ASSERT(!targs
[i
].origin());
704 rv
+= cf(targs
[i
], power
, 0, agent
);
711 // Apply func to one square of player's choice beside the player.
712 int apply_one_neighbouring_square(cell_func cf
, int power
, actor
*agent
)
715 direction_chooser_args args
;
716 args
.restricts
= DIR_DIR
;
717 args
.mode
= TARG_ANY
;
719 mpr("Which direction? [ESC to cancel]", MSGCH_PROMPT
);
720 direction(bmove
, args
);
728 return cf(you
.pos() + bmove
.delta
, power
, 1, agent
);
731 int apply_area_within_radius(cell_func cf
, const coord_def
& where
,
732 int pow
, int radius
, int ctype
,
738 for (radius_iterator
ri(where
, radius
, false, false); ri
; ++ri
)
739 rv
+= cf(*ri
, pow
, ctype
, agent
);
745 // Try to make a realistic cloud by expanding from a point, filling empty
746 // floor tiles until we run out of material (passed in as number).
747 // We really need some sort of a queue structure, since ideally I'd like
748 // to do a (shallow) breadth-first-search of the dungeon floor.
749 // This ought to work okay for small clouds.
750 void apply_area_cloud(cloud_func func
, const coord_def
& where
,
751 int pow
, int number
, cloud_type ctype
,
753 int spread_rate
, int colour
, std::string name
,
756 if (!in_bounds(where
))
759 int good_squares
= 0;
760 int neighbours
[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
762 if (number
&& _cloud_helper(func
, where
, pow
, spread_rate
, ctype
, agent
,
769 // These indices depend on the order in Compass (see main.cc)
770 int compass_order_orth
[4] = { 2, 6, 4, 0 };
771 int compass_order_diag
[4] = { 1, 3, 5, 7 };
773 int* const arrs
[2] = { compass_order_orth
, compass_order_diag
};
775 for (int m
= 0; m
< 2; ++m
)
777 // Randomise, but do orthogonals first and diagonals later.
778 std::random_shuffle(arrs
[m
], arrs
[m
] + 4);
779 for (int i
= 0; i
< 4 && number
; ++i
)
781 const int aux
= arrs
[m
][i
];
782 if (_cloud_helper(func
, where
+ Compass
[aux
],
783 pow
, spread_rate
, ctype
, agent
, colour
,
793 // Get a random permutation.
795 for (int i
= 0; i
< 8; ++i
)
797 std::random_shuffle(perm
, perm
+8);
798 for (int i
= 0; i
< 8 && number
; i
++)
800 // Spread (in random order.)
801 const int j
= perm
[i
];
803 if (neighbours
[j
] == 0)
806 int spread
= number
/ good_squares
;
809 apply_area_cloud(func
, where
+ Compass
[j
], pow
, spread
, ctype
, agent
,
810 spread_rate
, colour
, name
, tile
);
814 // Select a spell direction and fill dist and pbolt appropriately.
815 // Return false if the user canceled, true otherwise.
816 // FIXME: this should accept a direction_chooser_args directly rather
817 // than move the arguments into one.
818 bool spell_direction(dist
&spelld
, bolt
&pbolt
,
819 targeting_type restrict
, targ_mode_type mode
,
821 bool needs_path
, bool may_target_monster
,
822 bool may_target_self
, const char *target_prefix
,
823 const char* top_prompt
, bool cancel_at_self
)
826 range
= (pbolt
.range
< 1) ? LOS_RADIUS
: pbolt
.range
;
828 direction_chooser_args args
;
829 args
.restricts
= restrict
;
832 args
.just_looking
= false;
833 args
.needs_path
= needs_path
;
834 args
.may_target_monster
= may_target_monster
;
835 args
.may_target_self
= may_target_self
;
836 args
.target_prefix
= target_prefix
;
838 args
.top_prompt
= top_prompt
;
839 args
.behaviour
= NULL
;
840 args
.cancel_at_self
= cancel_at_self
;
842 direction(spelld
, args
);
846 // Check for user cancel.
851 pbolt
.set_target(spelld
);
852 pbolt
.source
= you
.pos();
857 const char* spelltype_short_name(int which_spelltype
)
859 switch (which_spelltype
)
861 case SPTYP_CONJURATION
:
871 case SPTYP_TRANSMUTATION
:
873 case SPTYP_NECROMANCY
:
877 case SPTYP_SUMMONING
:
879 case SPTYP_DIVINATION
:
881 case SPTYP_TRANSLOCATION
:
896 const char* spelltype_long_name(int which_spelltype
)
898 switch (which_spelltype
)
900 case SPTYP_CONJURATION
:
901 return ("Conjuration");
910 case SPTYP_TRANSMUTATION
:
911 return ("Transmutation");
912 case SPTYP_NECROMANCY
:
913 return ("Necromancy");
916 case SPTYP_SUMMONING
:
917 return ("Summoning");
918 case SPTYP_DIVINATION
:
919 return ("Divination");
920 case SPTYP_TRANSLOCATION
:
921 return ("Translocation");
935 skill_type
spell_type2skill(unsigned int spelltype
)
939 case SPTYP_CONJURATION
: return (SK_CONJURATIONS
);
940 case SPTYP_HEXES
: return (SK_HEXES
);
941 case SPTYP_CHARMS
: return (SK_CHARMS
);
942 case SPTYP_FIRE
: return (SK_FIRE_MAGIC
);
943 case SPTYP_ICE
: return (SK_ICE_MAGIC
);
944 case SPTYP_TRANSMUTATION
: return (SK_TRANSMUTATIONS
);
945 case SPTYP_NECROMANCY
: return (SK_NECROMANCY
);
946 case SPTYP_SUMMONING
: return (SK_SUMMONINGS
);
947 case SPTYP_TRANSLOCATION
: return (SK_TRANSLOCATIONS
);
948 case SPTYP_POISON
: return (SK_POISON_MAGIC
);
949 case SPTYP_EARTH
: return (SK_EARTH_MAGIC
);
950 case SPTYP_AIR
: return (SK_AIR_MAGIC
);
954 case SPTYP_DIVINATION
:
955 #ifdef DEBUG_DIAGNOSTICS
956 mprf(MSGCH_DIAGNOSTICS
, "spell_type2skill: called with spelltype %u",
961 } // end spell_type2skill()
964 **************************************************
966 * END PUBLIC FUNCTIONS *
968 **************************************************
971 //jmf: Simplified; moved init code to top function, init_spell_descs().
972 static spell_desc
*_seekspell(spell_type spell
)
974 ASSERT(spell
>= 0 && spell
< NUM_SPELLS
);
975 const int index
= spell_list
[spell
];
978 return (&spelldata
[index
]);
981 bool is_valid_spell(spell_type spell
)
983 return (spell
> SPELL_NO_SPELL
&& spell
< NUM_SPELLS
984 && spell_list
[spell
] != -1);
987 static bool _cloud_helper(cloud_func func
, const coord_def
& where
,
988 int pow
, int spread_rate
,
989 cloud_type ctype
, const actor
* agent
, int colour
,
990 std::string name
, std::string tile
)
993 && !feat_is_solid(grd(where
))
994 && env
.cgrid(where
) == EMPTY_CLOUD
)
996 func(where
, pow
, spread_rate
, ctype
, agent
, colour
, name
, tile
);
1003 static bool _spell_range_varies(spell_type spell
)
1005 int minrange
= _seekspell(spell
)->min_range
;
1006 int maxrange
= _seekspell(spell
)->max_range
;
1008 return (minrange
< maxrange
);
1011 int spell_power_cap(spell_type spell
)
1013 const int scap
= _seekspell(spell
)->power_cap
;
1014 const int zcap
= spell_zap_power_cap(spell
);
1022 // Two separate power caps; pre-zapping spell power
1024 if (scap
<= zcap
|| _spell_range_varies(spell
))
1031 int spell_range(spell_type spell
, int pow
, bool real_cast
, bool player_spell
)
1033 int minrange
= _seekspell(spell
)->min_range
;
1034 int maxrange
= _seekspell(spell
)->max_range
;
1035 ASSERT(maxrange
>= minrange
);
1037 // spells with no range have maxrange == minrange == -1
1041 // Sandblast is a special case.
1042 if (spell
== SPELL_SANDBLAST
&& wielding_rocks())
1049 && vehumet_supports_spell(spell
)
1050 && you
.religion
== GOD_VEHUMET
1051 && spell
!= SPELL_STICKY_FLAME
1052 && spell
!= SPELL_FREEZE
1053 && !player_under_penance()
1054 && you
.piety
>= piety_breakpoint(2))
1056 if (maxrange
< LOS_RADIUS
)
1059 if (minrange
< LOS_RADIUS
)
1063 if (minrange
== maxrange
)
1066 const int powercap
= spell_power_cap(spell
);
1068 if (powercap
<= pow
)
1071 // Round appropriately.
1072 return ((pow
* (maxrange
- minrange
) + powercap
/ 2) / powercap
+ minrange
);
1076 * Spell casting noise.
1078 * Returns the noise generated by the casting of a spell. The noise depends on
1079 * the spell schools and level. A modifier (noise_mod) can be applied to the
1083 * \param spell The spell being casted.
1084 * \return The amount of noise generated.
1086 int spell_noise(spell_type spell
)
1088 const spell_desc
*desc
= _seekspell(spell
);
1090 return spell_noise(desc
->disciplines
, desc
->level
+ desc
->noise_mod
);
1094 * Spell default noise.
1096 * Default value for spell noise given a level and a set of schools.
1097 * Formula (use first match):
1098 * - Conjuration (noisy) = \f$ level \f$
1099 * - Air and poison (quiet) = \f$ \frac{level}{2} \f$
1100 * - Other (normal) = \f$ \frac{3 \times level}{4} \f$
1102 * \param disciplines An integer which contain the school flags.
1103 * \param level The level of the spell.
1104 * \return The amount of noise generated.
1106 int spell_noise(unsigned int disciplines
, int level
)
1108 if (disciplines
== SPTYP_NONE
)
1110 else if (disciplines
& SPTYP_CONJURATION
)
1112 else if (disciplines
&& !(disciplines
& (SPTYP_POISON
| SPTYP_AIR
)))
1113 return div_round_up(level
* 3, 4);
1115 return div_round_up(level
, 2);
1118 spell_type
zap_type_to_spell(zap_type zap
)
1123 return SPELL_THROW_FLAME
;
1125 return SPELL_THROW_FROST
;
1130 case ZAP_MAGIC_DARTS
:
1131 return SPELL_MAGIC_DART
;
1133 return SPELL_MAJOR_HEALING
;
1135 return SPELL_PARALYSE
;
1137 return SPELL_BOLT_OF_FIRE
;
1139 return SPELL_BOLT_OF_COLD
;
1140 case ZAP_PRIMAL_WAVE
:
1141 return SPELL_PRIMAL_WAVE
;
1143 return SPELL_CONFUSE
;
1144 case ZAP_INVISIBILITY
:
1145 return SPELL_INVISIBILITY
;
1149 return SPELL_FIREBALL
;
1150 case ZAP_TELEPORTATION
:
1151 return SPELL_TELEPORT_OTHER
;
1153 return SPELL_LIGHTNING_BOLT
;
1154 case ZAP_POLYMORPH_OTHER
:
1155 return SPELL_POLYMORPH_OTHER
;
1156 case ZAP_NEGATIVE_ENERGY
:
1157 return SPELL_BOLT_OF_DRAINING
;
1158 case ZAP_ENSLAVEMENT
:
1159 return SPELL_ENSLAVEMENT
;
1160 case ZAP_DISINTEGRATION
:
1161 return SPELL_DISINTEGRATE
;
1163 die("zap_type_to_spell() only handles wand zaps for now");
1165 return SPELL_NO_SPELL
;
1168 bool spell_is_empowered(spell_type spell
)
1170 if ((you
.religion
== GOD_VEHUMET
)
1171 && vehumet_supports_spell(spell
)
1172 && piety_rank() > 2)
1179 case SPELL_SWIFTNESS
:
1180 // looking at player_movement_speed, this should be correct ~DMB
1181 if (player_movement_speed() > 6
1182 && you
.duration
[DUR_CONTROLLED_FLIGHT
] > 0
1183 && you
.duration
[DUR_SWIFTNESS
] < 1)
1188 case SPELL_STONESKIN
:
1189 if (you
.duration
[DUR_TRANSFORMATION
] > 0
1190 && you
.form
== TRAN_STATUE
1191 && you
.duration
[DUR_STONESKIN
] < 1)
1196 case SPELL_OZOCUBUS_ARMOUR
:
1197 if (you
.duration
[DUR_TRANSFORMATION
] > 0
1198 && you
.form
== TRAN_ICE_BEAST
1199 && you
.duration
[DUR_ICY_ARMOUR
] < 1)
1211 // This function attempts to determine if 'spell' is useless to
1212 // the player. if 'transient' is true, then it will include checks
1213 // for volatile or temporary states (such as status effects, mana, etc.)
1215 // its notably used by 'spell_highlight_by_utility'
1216 bool spell_is_useless(spell_type spell
, bool transient
)
1218 if (you_cannot_memorise(spell
))
1223 if (you
.duration
[DUR_CONF
] > 0
1224 || spell_mana(spell
) > you
.magic_points
1225 || spell_no_hostile_in_range(spell
, get_dist_to_nearest_monster()))
1234 case SPELL_CONTROLLED_BLINK
:
1235 case SPELL_TELEPORT_SELF
:
1236 if (item_blocks_teleport(false, false))
1239 case SPELL_SWIFTNESS
:
1240 // looking at player_movement_speed, this should be correct ~DMB
1241 if (player_movement_speed() <= 6)
1244 case SPELL_LEVITATION
:
1246 if (you
.species
== SP_KENKU
&& you
.experience_level
>= 15)
1248 if (transient
&& you
.is_levitating())
1251 case SPELL_REGENERATION
:
1252 if (you
.species
== SP_DEEP_DWARF
)
1255 case SPELL_INVISIBILITY
:
1256 if (transient
&& (you
.duration
[DUR_INVIS
] > 0 || you
.backlit()))
1259 case SPELL_CONTROL_TELEPORT
:
1260 if (transient
&& you
.duration
[DUR_CONTROL_TELEPORT
] > 0)
1263 case SPELL_SEE_INVISIBLE
:
1264 if (you
.can_see_invisible(false, false))
1267 // weapon branding is useless
1268 case SPELL_FIRE_BRAND
:
1269 case SPELL_FREEZING_AURA
:
1270 case SPELL_LETHAL_INFUSION
:
1271 case SPELL_WARP_BRAND
:
1272 case SPELL_EXCRUCIATING_WOUNDS
:
1273 case SPELL_POISON_WEAPON
:
1274 // could be useful if it didn't require wielding
1275 case SPELL_TUKIMAS_DANCE
:
1276 if (you
.species
== SP_CAT
)
1280 break; // quash unhandled constants warnings
1286 // This function takes a spell, and determines what color it should be
1287 // highlighted with. You shouldn't have to touch this unless you want
1288 // to add new highlighting options.
1290 // as you can see, the functions it uses to determine highlights are:
1291 // god_hates_spell(spell, god)
1292 // god_likes_spell(spell, god)
1293 // spell_is_empowered(spell)
1294 // spell_is_useless(spell, transient)
1295 int spell_highlight_by_utility(spell_type spell
, int default_color
,
1296 bool transient
, bool rod_spell
)
1298 // If your god hates the spell, that
1299 // overrides all other concerns
1300 if (god_hates_spell(spell
, you
.religion
))
1301 return (COL_FORBIDDEN
);
1303 if (spell_is_empowered(spell
) && !rod_spell
)
1304 default_color
= COL_EMPOWERED
;
1306 if (spell_is_useless(spell
, transient
))
1307 default_color
= COL_USELESS
;
1309 return (default_color
);
1312 bool spell_no_hostile_in_range(spell_type spell
, int minRange
)
1320 // These don't target monsters.
1321 case SPELL_APPORTATION
:
1322 case SPELL_PROJECTED_NOISE
:
1323 case SPELL_CONJURE_FLAME
:
1325 case SPELL_PASSWALL
:
1326 case SPELL_GOLUBRIAS_PASSAGE
:
1328 // Airstrike has LOS_RANGE and can go through glass walls.
1329 case SPELL_AIRSTRIKE
:
1331 // These bounce and may be aimed elsewhere to bounce at monsters
1332 // outside range (I guess).
1334 case SPELL_LIGHTNING_BOLT
:
1336 case SPELL_FIRE_STORM
:
1339 case SPELL_EVAPORATE
:
1340 case SPELL_MEPHITIC_CLOUD
:
1341 case SPELL_FIREBALL
:
1342 case SPELL_FREEZING_CLOUD
:
1343 case SPELL_NOXIOUS_CLOUD
:
1344 case SPELL_POISONOUS_CLOUD
:
1345 // Increase range by one due to cloud radius.
1353 // The healing spells.
1354 if (testbits(get_spell_flags(spell
), SPFLAG_HELPFUL
))
1357 const int range
= calc_spell_range(spell
);
1361 const int rsq
= (range
+ bonus
) * (range
+ bonus
) + 1;