ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
(Generate patch)

Comparing deliantra/server/server/spell_effect.C (file contents):
Revision 1.83 by root, Tue May 6 16:55:26 2008 UTC vs.
Revision 1.111 by root, Mon Oct 12 21:27:55 2009 UTC

3 * 3 *
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen 6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 * 7 *
8 * Deliantra is free software: you can redistribute it and/or modify 8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * it under the terms of the GNU General Public License as published by 9 * the terms of the Affero GNU General Public License as published by the
10 * the Free Software Foundation, either version 3 of the License, or 10 * Free Software Foundation, either version 3 of the License, or (at your
11 * (at your option) any later version. 11 * option) any later version.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 16 * GNU General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the Affero GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
20 * 21 *
21 * The authors can be reached via e-mail to <support@deliantra.net> 22 * The authors can be reached via e-mail to <support@deliantra.net>
22 */ 23 */
23 24
24#include <global.h> 25#include <global.h>
61{ 62{
62 object *wand, *tmp; 63 object *wand, *tmp;
63 int ncharges; 64 int ncharges;
64 65
65 wand = find_marked_object (op); 66 wand = find_marked_object (op);
66 if (wand == NULL || wand->type != WAND) 67 if (!wand || wand->type != WAND)
67 { 68 {
68 new_draw_info (NDI_UNIQUE, 0, op, "You need to mark the wand you want to recharge."); 69 new_draw_info (NDI_UNIQUE, 0, op, "You need to mark the wand you want to recharge.");
69 return 0; 70 return 0;
70 } 71 }
71 if (!(random_roll (0, 3, op, PREFER_HIGH))) 72 if (!(random_roll (0, 3, op, PREFER_HIGH)))
122 * The # of arrows created also goes up with level, so if a 30th level mage 123 * The # of arrows created also goes up with level, so if a 30th level mage
123 * wants LOTS of arrows, and doesn't care what the plus is he could 124 * wants LOTS of arrows, and doesn't care what the plus is he could
124 * create nonnmagic arrows, or even -1, etc... 125 * create nonnmagic arrows, or even -1, etc...
125 */ 126 */
126int 127int
127cast_create_missile (object *op, object *caster, object *spell, int dir, const char *stringarg) 128cast_create_missile (object *op, object *caster, object *spell, int dir, const char *spellparam)
128{ 129{
129 int bonus_plus = 0; 130 int bonus_plus = 0;
130 const char *missile_name = "arrow"; 131 const char *missile_name = "arrow";
131 132
132 for (object *tmp = op->inv; tmp; tmp = tmp->below) 133 for (object *tmp = op->inv; tmp; tmp = tmp->below)
143 return 0; 144 return 0;
144 } 145 }
145 146
146 object *missile = missile_arch->instance (); 147 object *missile = missile_arch->instance ();
147 148
148 if (stringarg) 149 if (spellparam)
149 { 150 {
150 /* If it starts with a letter, presume it is a description */ 151 /* If it starts with a letter, presume it is a description */
151 if (isalpha (*stringarg)) 152 if (isalpha (*spellparam))
152 { 153 {
153 artifact *al = find_artifactlist (missile->type)->items; 154 artifact *al = find_artifactlist (missile->type)->items;
154 155
155 for (; al; al = al->next) 156 for (; al; al = al->next)
156 if (!strcasecmp (al->item->name, stringarg)) 157 if (!strcasecmp (al->item->name, spellparam))
157 break; 158 break;
158 159
159 if (!al) 160 if (!al)
160 { 161 {
161 missile->destroy (); 162 missile->destroy ();
162 new_draw_info_format (NDI_UNIQUE, 0, op, "No such object %ss of %s", missile_name, stringarg); 163 new_draw_info_format (NDI_UNIQUE, 0, op, "No such object %ss of %s", missile_name, spellparam);
163 return 0; 164 return 0;
164 } 165 }
165 166
166 if (al->item->slaying) 167 if (al->item->slaying)
167 { 168 {
168 missile->destroy (); 169 missile->destroy ();
169 new_draw_info_format (NDI_UNIQUE, 0, op, "You are not allowed to create %ss of %s", missile_name, stringarg); 170 new_draw_info_format (NDI_UNIQUE, 0, op, "You are not allowed to create %ss of %s", missile_name, spellparam);
170 return 0; 171 return 0;
171 } 172 }
172 173
173 give_artifact_abilities (missile, al->item); 174 give_artifact_abilities (missile, al->item);
174 /* These special arrows cost something extra. Don't have them also be magical - 175 /* These special arrows cost something extra. Don't have them also be magical -
176 * the parsing of having to do both plus and type. 177 * the parsing of having to do both plus and type.
177 */ 178 */
178 bonus_plus = 1 + (al->item->value / 5); 179 bonus_plus = 1 + (al->item->value / 5);
179 missile_plus = 0; 180 missile_plus = 0;
180 } 181 }
181 else if (atoi (stringarg) < missile_plus) 182 else if (atoi (spellparam) < missile_plus)
182 missile_plus = atoi (stringarg); 183 missile_plus = atoi (spellparam);
183 } 184 }
184 185
185 missile_plus = clamp (missile_plus, -4, 4); 186 missile_plus = clamp (missile_plus, -4, 4);
186 187
187 missile->nrof = spell->duration + SP_level_duration_adjust (caster, spell); 188 missile->nrof = spell->duration + SP_level_duration_adjust (caster, spell);
202 return 1; 203 return 1;
203} 204}
204 205
205 206
206/* allows the choice of what sort of food object to make. 207/* allows the choice of what sort of food object to make.
207 * If stringarg is NULL, it will create food dependent on level --PeterM*/ 208 * If spellparam is NULL, it will create food dependent on level --PeterM*/
208int 209int
209cast_create_food (object *op, object *caster, object *spell_ob, int dir, const char *stringarg) 210cast_create_food (object *op, object *caster, object *spell_ob, int dir, const char *spellparam)
210{ 211{
211 int food_value; 212 int food_value;
212 archetype *at = NULL; 213 archetype *at = NULL;
213 object *new_op; 214 object *new_op;
214 215
215 food_value = spell_ob->stats.food + 50 * SP_level_duration_adjust (caster, spell_ob); 216 food_value = spell_ob->stats.food + 50 * SP_level_duration_adjust (caster, spell_ob);
216 217
217 if (stringarg) 218 if (spellparam)
218 { 219 {
219 at = find_archetype_by_object_type_name (FOOD, stringarg); 220 at = find_archetype_by_object_type_name (FOOD, spellparam);
220 if (at == NULL) 221 if (at == NULL)
221 at = find_archetype_by_object_type_name (DRINK, stringarg); 222 at = find_archetype_by_object_type_name (DRINK, spellparam);
222 if (at == NULL || at->stats.food > food_value) 223 if (at == NULL || at->stats.food > food_value)
223 stringarg = NULL; 224 spellparam = NULL;
224 } 225 }
225 226
226 if (!stringarg) 227 if (!spellparam)
227 { 228 {
228 archetype *at_tmp; 229 archetype *at_tmp;
229 230
230 /* We try to find the archetype with the maximum food value. 231 /* We try to find the archetype with the maximum food value.
231 * This removes the dependancy of hard coded food values in this 232 * This removes the dependancy of hard coded food values in this
301 if (!QUERY_FLAG (op, FLAG_WIZCAST) && (mflags & P_NO_MAGIC)) 302 if (!QUERY_FLAG (op, FLAG_WIZCAST) && (mflags & P_NO_MAGIC))
302 { 303 {
303 new_draw_info (NDI_UNIQUE, 0, op, "Something blocks your magic."); 304 new_draw_info (NDI_UNIQUE, 0, op, "Something blocks your magic.");
304 return 0; 305 return 0;
305 } 306 }
307
306 if (mflags & P_IS_ALIVE) 308 if (mflags & P_IS_ALIVE)
307 { 309 {
308 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above) 310 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
309 if (QUERY_FLAG (tmp, FLAG_ALIVE) && (tmp->type == PLAYER || QUERY_FLAG (tmp, FLAG_MONSTER))) 311 if (QUERY_FLAG (tmp, FLAG_ALIVE) && (tmp->type == PLAYER || QUERY_FLAG (tmp, FLAG_MONSTER)))
310 { 312 {
311 new_draw_info (NDI_UNIQUE, 0, op, "You detect something."); 313 new_draw_info (NDI_UNIQUE, 0, op, "You detect something.");
312 if (tmp->head != NULL) 314 if (tmp->head != NULL)
313 tmp = tmp->head; 315 tmp = tmp->head;
344 346
345 return 1; 347 return 1;
346 } 348 }
347 349
348 /* invis_race is set if we get here */ 350 /* invis_race is set if we get here */
349 if (!strcmp (pl->contr->invis_race, "undead") && is_true_undead (mon)) 351 if (pl->contr->invis_race == shstr_undead && is_true_undead (mon))
350 return 1; 352 return 1;
351 353
352 /* No race, can't be invisible to it */ 354 /* No race, can't be invisible to it */
353 if (!mon->race) 355 if (!mon->race)
354 return 0; 356 return 0;
355 357
356 if (strstr (mon->race, pl->contr->invis_race)) 358 if (mon->race.contains (pl->contr->invis_race))
357 return 1; 359 return 1;
358 360
359 /* Nothing matched above, return 0 */ 361 /* Nothing matched above, return 0 */
360 return 0; 362 return 0;
361 } 363 }
424/* earth to dust spell. Basically destroys earthwalls in the area. 426/* earth to dust spell. Basically destroys earthwalls in the area.
425 */ 427 */
426int 428int
427cast_earth_to_dust (object *op, object *caster, object *spell_ob) 429cast_earth_to_dust (object *op, object *caster, object *spell_ob)
428{ 430{
429 object *tmp, *next;
430 int range, i, j, mflags; 431 int range, i, j, mflags;
431 sint16 sx, sy; 432 sint16 sx, sy;
432 maptile *m; 433 maptile *m;
433
434 if (op->type != PLAYER)
435 return 0;
436 434
437 range = spell_ob->range + SP_level_range_adjust (caster, spell_ob); 435 range = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
438 436
439 for (i = -range; i <= range; i++) 437 for (i = -range; i <= range; i++)
440 for (j = -range; j <= range; j++) 438 for (j = -range; j <= range; j++)
445 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy); 443 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
446 444
447 if (mflags & P_OUT_OF_MAP) 445 if (mflags & P_OUT_OF_MAP)
448 continue; 446 continue;
449 447
450 // earth to dust tears down everything that can be teared down 448 // earth to dust tears down everything that can be torn down
451 for (tmp = GET_MAP_OB (m, sx, sy); tmp != NULL; tmp = next) 449 for (object *next, *tmp = m->at (sx, sy).bot; tmp; tmp = next)
452 { 450 {
453 next = tmp->above; 451 next = tmp->above;
452
454 if (QUERY_FLAG (tmp, FLAG_TEAR_DOWN)) 453 if (QUERY_FLAG (tmp, FLAG_TEAR_DOWN))
455 hit_player (tmp, 9998, op, AT_PHYSICAL, 0); 454 hit_player (tmp, 9998, op, AT_PHYSICAL, 0);
456 } 455 }
457 } 456 }
458 457
491 new_draw_info (NDI_UNIQUE, 0, op, "You feel a force starting to build up inside you."); 490 new_draw_info (NDI_UNIQUE, 0, op, "You feel a force starting to build up inside you.");
492 return 1; 491 return 1;
493 } 492 }
494 493
495 dummy = get_archetype (FORCE_NAME); 494 dummy = get_archetype (FORCE_NAME);
496 if (dummy == NULL) 495
496 if (!dummy)
497 { 497 {
498 new_draw_info (NDI_UNIQUE, 0, op, "Oops, program error!"); 498 new_draw_info (NDI_UNIQUE, 0, op, "Oops, program error!");
499 LOG (llevError, "cast_word_of_recall: get_archetype(force) failed!\n"); 499 LOG (llevError, "cast_word_of_recall: get_archetype(force) failed!\n");
500 return 0; 500 return 0;
501 } 501 }
567perceive_self (object *op) 567perceive_self (object *op)
568{ 568{
569 const char *cp = describe_item (op, op); 569 const char *cp = describe_item (op, op);
570 archetype *at = archetype::find (ARCH_DEPLETION); 570 archetype *at = archetype::find (ARCH_DEPLETION);
571 571
572 dynbuf_text buf; 572 dynbuf_text &buf = msg_dynbuf; buf.clear ();
573 573
574 if (player *pl = op->contr) 574 if (!op->is_player ())
575 return 0;
576
575 if (object *race = archetype::find (op->race)) 577 if (object *race = archetype::find (op->race))
576 buf << "You are a " << (pl->gender ? "female" : "male") << " " << &race->name << ".\n"; 578 buf << " - You are a G<male|female> " << &race->name << ".\n";
577 579
578 if (object *god = find_god (determine_god (op))) 580 if (object *god = find_god (determine_god (op)))
579 buf << "You worship " << &god->name << ".\n"; 581 buf << " - You worship " << &god->name << ".\n";
580 else 582 else
581 buf << "You worship no god.\n"; 583 buf << " - You worship no god.\n";
582 584
583 object *tmp = present_arch_in_ob (at, op); 585 object *tmp = present_arch_in_ob (at, op);
584 586
585 if (*cp == '\0' && tmp == NULL) 587 if (*cp == '\0' && !tmp)
586 buf << "You feel very mundane. "; 588 buf << " - You feel very mundane. ";
587 else 589 else
588 { 590 {
589 buf << "You have: " << cp << ".\n"; 591 buf << " - You have: " << cp << ".\n";
590 592
591 if (tmp) 593 if (tmp)
592 for (int i = 0; i < NUM_STATS; i++) 594 for (int i = 0; i < NUM_STATS; i++)
593 if (tmp->stats.stat (i) < 0) 595 if (tmp->stats.stat (i) < 0)
594 buf.printf ("Your %s is depleted by %d.\n", statname[i], -tmp->stats.stat (i)); 596 buf.printf (" - Your %s is depleted by %d.\n", statname[i], -tmp->stats.stat (i));
595 } 597 }
596 598
597 if (is_dragon_pl (op)) 599 if (is_dragon_pl (op))
598 /* now grab the 'dragon_ability'-force from the player's inventory */ 600 /* now grab the 'dragon_ability'-force from the player's inventory */
599 for (tmp = op->inv; tmp; tmp = tmp->below) 601 for (tmp = op->inv; tmp; tmp = tmp->below)
600 { 602 {
601 if (tmp->type == FORCE && tmp->arch->archname == shstr_dragon_ability_force) 603 if (tmp->type == FORCE && tmp->arch->archname == shstr_dragon_ability_force)
602 { 604 {
603 if (tmp->stats.exp == 0) 605 if (tmp->stats.exp == 0)
604 buf << "Your metabolism isn't focused on anything.\n"; 606 buf << " - Your metabolism isn't focused on anything.\n";
605 else 607 else
606 buf << "Your metabolism is focused on " << change_resist_msg[tmp->stats.exp] << ".\n"; 608 buf << " - Your metabolism is focused on " << change_resist_msg[tmp->stats.exp] << ".\n";
607 609
608 break; 610 break;
609 } 611 }
610 } 612 }
611 613
612 buf << '\0'; // zero-terminate 614 op->contr->infobox (MSG_CHANNEL ("perceiveself"), buf);
613
614 new_draw_info (NDI_UNIQUE, 0, op, buf.linearise ());
615 615
616 return 1; 616 return 1;
617} 617}
618 618
619/* This creates magic walls. Really, it can create most any object, 619/* This creates magic walls. Really, it can create most any object,
707 */ 707 */
708 if (tmp->type != EARTHWALL) //TODO 708 if (tmp->type != EARTHWALL) //TODO
709 tmp->set_owner (op); 709 tmp->set_owner (op);
710 710
711 set_spell_skill (op, caster, spell_ob, tmp); 711 set_spell_skill (op, caster, spell_ob, tmp);
712 tmp->level = caster_level (caster, spell_ob) / 2; 712 tmp->level = casting_level (caster, spell_ob) / 2;
713 713
714 name = tmp->name; 714 name = tmp->name;
715 if (!(tmp = m->insert (tmp, x, y, op))) 715 if (!(tmp = m->insert (tmp, x, y, op)))
716 { 716 {
717 new_draw_info_format (NDI_UNIQUE, 0, op, "Something destroys your %s", name); 717 new_draw_info_format (NDI_UNIQUE, 0, op, "Something destroys your %s", name);
778 778
779 return 1; 779 return 1;
780} 780}
781 781
782int 782int
783dimension_door (object *op, object *caster, object *spob, int dir) 783dimension_door (object *op, object *caster, object *spob, int dir, const char *spellparam)
784{ 784{
785 uint32 dist, maxdist; 785 uint32 dist, maxdist;
786 int mflags; 786 int mflags;
787 maptile *m; 787 maptile *m;
788 sint16 sx, sy; 788 sint16 sx, sy;
799 /* Given the new outdoor maps, can't let players dimension door for 799 /* Given the new outdoor maps, can't let players dimension door for
800 * ever, so put limits in. 800 * ever, so put limits in.
801 */ 801 */
802 maxdist = spob->range + SP_level_range_adjust (caster, spob); 802 maxdist = spob->range + SP_level_range_adjust (caster, spob);
803 803
804 if (op->contr->count) 804 if (spellparam)
805 { 805 {
806 int count = atoi (spellparam);
807
806 if (op->contr->count > maxdist) 808 if (count > maxdist)
807 { 809 {
808 new_draw_info (NDI_UNIQUE, 0, op, "You can't dimension door that far!"); 810 new_draw_info (NDI_UNIQUE, 0, op, "You can't dimension door that far!");
809 return 0; 811 return 0;
810 } 812 }
811 813
812 for (dist = 0; dist < op->contr->count; dist++) 814 for (dist = 0; dist < count; dist++)
813 { 815 {
814 mflags = get_map_flags (op->map, &m, op->x + freearr_x[dir] * (dist + 1), op->y + freearr_y[dir] * (dist + 1), &sx, &sy); 816 mflags = get_map_flags (op->map, &m, op->x + freearr_x[dir] * (dist + 1), op->y + freearr_y[dir] * (dist + 1), &sx, &sy);
815 817
816 if (mflags & (P_NO_MAGIC | P_OUT_OF_MAP)) 818 if (mflags & (P_NO_MAGIC | P_OUT_OF_MAP))
817 break; 819 break;
818 820
819 if ((mflags & P_BLOCKSVIEW) && OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy))) 821 if ((mflags & P_BLOCKSVIEW) && OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy)))
820 break; 822 break;
821 } 823 }
822 824
823 if (dist < op->contr->count) 825 if (dist < count)
824 { 826 {
825 new_draw_info (NDI_UNIQUE, 0, op, "Something blocks the magic of the spell.\n"); 827 new_draw_info (NDI_UNIQUE, 0, op, "Something blocks the magic of the spell.\n");
826 op->contr->count = 0;
827 return 0; 828 return 0;
828 } 829 }
829
830 op->contr->count = 0;
831 830
832 /* Remove code that puts player on random space on maps. IMO, 831 /* Remove code that puts player on random space on maps. IMO,
833 * a lot of maps probably have areas the player should not get to, 832 * a lot of maps probably have areas the player should not get to,
834 * but may not be marked as NO_MAGIC (as they may be bounded 833 * but may not be marked as NO_MAGIC (as they may be bounded
835 * by such squares). Also, there are probably treasure rooms and 834 * by such squares). Also, there are probably treasure rooms and
1032 "You don't feel any more powerful." 1031 "You don't feel any more powerful."
1033 "You are no easier to look at.", 1032 "You are no easier to look at.",
1034}; 1033};
1035 1034
1036int 1035int
1036change_ability_duration (object *spell, object *caster)
1037{
1038 return spell->duration + SP_level_duration_adjust (caster, spell) * 50;
1039}
1040
1041int
1037cast_change_ability (object *op, object *caster, object *spell_ob, int dir, int silent) 1042cast_change_ability (object *op, object *caster, object *spell_ob, int dir, int silent)
1038{ 1043{
1039 object *force = NULL; 1044 object *force = 0;
1040 int i; 1045 int i;
1041 1046
1042 /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */ 1047 /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
1043 object *tmp = dir 1048 object *tmp = dir
1044 ? find_target_for_friendly_spell (op, dir) 1049 ? find_target_for_friendly_spell (op, dir)
1045 : op; 1050 : op;
1046 1051
1047 if (!tmp) 1052 if (!tmp)
1048 return 0; 1053 return 0;
1049 1054
1050 /* If we've already got a force of this type, don't add a new one. */ 1055 /* If we've already got a force of this type, don't add a new one. */
1058 break; 1063 break;
1059 } 1064 }
1060 else if (spell_ob->race && spell_ob->race == tmp2->name) 1065 else if (spell_ob->race && spell_ob->race == tmp2->name)
1061 { 1066 {
1062 if (!silent) 1067 if (!silent)
1063 new_draw_info_format (NDI_UNIQUE, 0, op, "You can not cast %s while %s is in effect", &spell_ob->name, &tmp2->name_pl); 1068 new_draw_info_format (NDI_UNIQUE, 0, op,
1069 "You can not cast %s while %s is in effect",
1070 &spell_ob->name, &tmp2->name_pl);
1071
1064 return 0; 1072 return 0;
1065 } 1073 }
1066 } 1074 }
1067 } 1075 }
1076
1077 int duration = change_ability_duration (spell_ob, caster);
1078
1068 if (force == NULL) 1079 if (force)
1069 {
1070 force = get_archetype (FORCE_NAME);
1071 force->subtype = FORCE_CHANGE_ABILITY;
1072 if (spell_ob->race)
1073 force->name = spell_ob->race;
1074 else
1075 force->name = spell_ob->name;
1076 force->name_pl = spell_ob->name;
1077 new_draw_info (NDI_UNIQUE, 0, op, "You create an aura of magical force.");
1078
1079 } 1080 {
1080 else
1081 {
1082 int duration;
1083
1084 duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1085 if (duration > force->duration) 1081 if (duration > force->duration)
1086 { 1082 {
1087 force->duration = duration; 1083 force->duration = duration;
1088 new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect."); 1084 new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
1089 } 1085 }
1090 else 1086 else
1091 {
1092 new_draw_info (NDI_UNIQUE, 0, op, "Recasting the spell had no effect."); 1087 new_draw_info (NDI_UNIQUE, 0, op, "Recasting the spell had no effect.");
1093 }
1094 1088
1095 return 1; 1089 return 1;
1096 } 1090 }
1097 1091
1098 force->duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50; 1092 new_draw_info_format (NDI_UNIQUE, 0, op,
1093 "You create an aura of magical force. H<The effect will last for about %.10g seconds.>",
1094 TICK2TIME (duration));
1095
1096 force = get_archetype (FORCE_NAME);
1097 force->subtype = FORCE_CHANGE_ABILITY;
1098 force->duration = duration;
1099
1100 if (spell_ob->race)
1101 force->name = spell_ob->race;
1102 else
1103 force->name = spell_ob->name;
1104
1105 force->name_pl = spell_ob->name;
1106
1099 force->speed = 1.0; 1107 force->speed = 1.0;
1100 force->speed_left = -1.0; 1108 force->speed_left = -1.0;
1101 SET_FLAG (force, FLAG_APPLIED); 1109 SET_FLAG (force, FLAG_APPLIED);
1102 1110
1103 /* Now start processing the effects. First, protections */ 1111 /* Now start processing the effects. First, protections */
1170 */ 1178 */
1171int 1179int
1172cast_bless (object *op, object *caster, object *spell_ob, int dir) 1180cast_bless (object *op, object *caster, object *spell_ob, int dir)
1173{ 1181{
1174 int i; 1182 int i;
1175 object *god = find_god (determine_god (op)), *tmp2, *force = NULL, *tmp; 1183 object *god = find_god (determine_god (op)), *force = NULL, *tmp;
1176 1184
1177 /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */ 1185 /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
1178 if (dir != 0) 1186 if (dir != 0)
1179 { 1187 {
1180 tmp = find_target_for_friendly_spell (op, dir); 1188 tmp = find_target_for_friendly_spell (op, dir);
1189
1190 if (!tmp)
1191 return 0;
1181 } 1192 }
1182 else 1193 else
1183 {
1184 tmp = op; 1194 tmp = op;
1185 }
1186 1195
1187 /* If we've already got a force of this type, don't add a new one. */ 1196 /* If we've already got a force of this type, don't add a new one. */
1188 for (tmp2 = tmp->inv; tmp2 != NULL; tmp2 = tmp2->below) 1197 for (object *tmp2 = tmp->inv; tmp2; tmp2 = tmp2->below)
1189 { 1198 {
1190 if (tmp2->type == FORCE && tmp2->subtype == FORCE_CHANGE_ABILITY) 1199 if (tmp2->type == FORCE && tmp2->subtype == FORCE_CHANGE_ABILITY)
1191 { 1200 {
1192 if (tmp2->name == spell_ob->name) 1201 if (tmp2->name == spell_ob->name)
1193 { 1202 {
1199 new_draw_info_format (NDI_UNIQUE, 0, op, "You can not cast %s while %s is in effect", &spell_ob->name, &tmp2->name_pl); 1208 new_draw_info_format (NDI_UNIQUE, 0, op, "You can not cast %s while %s is in effect", &spell_ob->name, &tmp2->name_pl);
1200 return 0; 1209 return 0;
1201 } 1210 }
1202 } 1211 }
1203 } 1212 }
1213
1204 if (force == NULL) 1214 if (force == NULL)
1205 { 1215 {
1206 force = get_archetype (FORCE_NAME); 1216 force = get_archetype (FORCE_NAME);
1207 force->subtype = FORCE_CHANGE_ABILITY; 1217 force->subtype = FORCE_CHANGE_ABILITY;
1208 if (spell_ob->race) 1218 if (spell_ob->race)
1412 * items. 1422 * items.
1413 */ 1423 */
1414int 1424int
1415remove_curse (object *op, object *caster, object *spell) 1425remove_curse (object *op, object *caster, object *spell)
1416{ 1426{
1417 object *tmp;
1418 int success = 0, was_one = 0; 1427 int success = 0, was_one = 0;
1419 1428
1420 for (tmp = op->inv; tmp; tmp = tmp->below) 1429 for (object *tmp = op->inv; tmp; tmp = tmp->below)
1421 if (QUERY_FLAG (tmp, FLAG_APPLIED) && 1430 if (QUERY_FLAG (tmp, FLAG_APPLIED) &&
1422 ((QUERY_FLAG (tmp, FLAG_CURSED) && QUERY_FLAG (spell, FLAG_CURSED)) || 1431 ((QUERY_FLAG (tmp, FLAG_CURSED) && QUERY_FLAG (spell, FLAG_CURSED)) ||
1423 (QUERY_FLAG (tmp, FLAG_DAMNED) && QUERY_FLAG (spell, FLAG_DAMNED)))) 1432 (QUERY_FLAG (tmp, FLAG_DAMNED) && QUERY_FLAG (spell, FLAG_DAMNED))))
1424 { 1433 {
1425 was_one++; 1434 was_one++;
1426 1435
1427 if (tmp->level <= caster_level (caster, spell)) 1436 if (tmp->level <= casting_level (caster, spell))
1428 { 1437 {
1429 success++; 1438 success++;
1430 if (QUERY_FLAG (spell, FLAG_DAMNED)) 1439 if (QUERY_FLAG (spell, FLAG_DAMNED))
1431 CLEAR_FLAG (tmp, FLAG_DAMNED); 1440 CLEAR_FLAG (tmp, FLAG_DAMNED);
1432 1441
1457 1466
1458/* Identifies objects in the players inventory/on the ground */ 1467/* Identifies objects in the players inventory/on the ground */
1459int 1468int
1460cast_identify (object *op, object *caster, object *spell) 1469cast_identify (object *op, object *caster, object *spell)
1461{ 1470{
1462 dynbuf_text buf;
1463 object *tmp; 1471 object *tmp;
1472 dynbuf_text &buf = msg_dynbuf; buf.clear ();
1464 1473
1465 int num_ident = spell->stats.dam + SP_level_dam_adjust (caster, spell); 1474 int num_ident = max (1, spell->stats.dam + SP_level_dam_adjust (caster, spell));
1466
1467 if (num_ident < 1)
1468 num_ident = 1;
1469 1475
1470 for (tmp = op->inv; tmp; tmp = tmp->below) 1476 for (tmp = op->inv; tmp; tmp = tmp->below)
1471 { 1477 {
1472 if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !tmp->invisible && need_identify (tmp)) 1478 if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !tmp->invisible && need_identify (tmp))
1473 { 1479 {
1474 identify (tmp); 1480 identify (tmp);
1475 1481
1476 if (op->type == PLAYER) 1482 if (op->type == PLAYER)
1477 { 1483 {
1478 buf.printf ("You identified: %s.\n\n", long_desc (tmp, op)); 1484 buf.printf ("You identified: %s.\r", long_desc (tmp, op));
1479 1485
1480 if (tmp->msg) 1486 if (tmp->msg)
1481 buf << "The item has a story:\n\n" << tmp->msg << "\n\n"; 1487 buf << "The item has a story:\r" << tmp->msg << "\n\n";
1482 } 1488 }
1483 1489
1484 num_ident--;
1485 if (!num_ident) 1490 if (!--num_ident)
1486 break; 1491 break;
1487 } 1492 }
1488 } 1493 }
1489 1494
1490 /* If all the power of the spell has been used up, don't go and identify 1495 /* If all the power of the spell has been used up, don't go and identify
1498 { 1503 {
1499 identify (tmp); 1504 identify (tmp);
1500 1505
1501 if (object *pl = tmp->visible_to ()) 1506 if (object *pl = tmp->visible_to ())
1502 { 1507 {
1503 buf.printf ("On the ground you identified: %s.\n\n", long_desc (tmp, op)); 1508 buf.printf ("On the ground you identified: %s.\r", long_desc (tmp, op));
1504 1509
1505 if (tmp->msg) 1510 if (tmp->msg)
1506 buf << "The item has a story:\n\n" << tmp->msg << "\n\n"; 1511 buf << "The item has a story:\r" << tmp->msg << "\n\n";
1507 } 1512 }
1508 1513
1509 num_ident--;
1510 if (!num_ident) 1514 if (!--num_ident)
1511 break; 1515 break;
1512 } 1516 }
1513 } 1517 }
1514 1518
1515 if (buf.empty ()) 1519 if (buf.empty ())
1537 1541
1538 /* We precompute some values here so that we don't have to keep 1542 /* We precompute some values here so that we don't have to keep
1539 * doing it over and over again. 1543 * doing it over and over again.
1540 */ 1544 */
1541 god = find_god (determine_god (op)); 1545 god = find_god (determine_god (op));
1542 level = caster_level (caster, spell); 1546 level = casting_level (caster, spell);
1543 range = spell->range + SP_level_range_adjust (caster, spell); 1547 range = spell->range + SP_level_range_adjust (caster, spell);
1544 1548
1545 if (!skill) 1549 if (!skill)
1546 skill = caster; 1550 skill = caster;
1547 1551
1548 for (x = op->x - range; x <= op->x + range; x++) 1552 unordered_mapwalk (op, -range, -range, range, range)
1549 for (y = op->y - range; y <= op->y + range; y++)
1550 { 1553 {
1551 m = op->map;
1552 mflags = get_map_flags (m, &m, x, y, &nx, &ny);
1553 if (mflags & P_OUT_OF_MAP)
1554 continue;
1555
1556 /* For most of the detections, we only detect objects above the 1554 /* For most of the detections, we only detect objects above the
1557 * floor. But this is not true for show invisible. 1555 * floor. But this is not true for show invisible.
1558 * Basically, we just go and find the top object and work 1556 * Basically, we just go and find the top object and work
1559 * down - that is easier than working up. 1557 * down - that is easier than working up.
1560 */ 1558 */
1561 1559
1562 for (last = NULL, tmp = GET_MAP_OB (m, nx, ny); tmp; tmp = tmp->above) 1560 for (last = NULL, tmp = m->at (nx, ny).bot; tmp; tmp = tmp->above)
1563 last = tmp; 1561 last = tmp;
1564 1562
1565 /* Shouldn't happen, but if there are no objects on a space, this 1563 /* Shouldn't happen, but if there are no objects on a space, this
1566 * would happen. 1564 * would happen.
1567 */ 1565 */
1568 if (!last) 1566 if (!last)
1569 continue; 1567 continue;
1570 1568
1571 done_one = 0; 1569 done_one = 0;
1572 floor = 0; 1570 floor = 0;
1573 detect = NULL; 1571 detect = NULL;
1574 for (tmp = last; tmp; tmp = tmp->below) 1572 for (tmp = last; tmp; tmp = tmp->below)
1575 { 1573 {
1576 /* show invisible */ 1574 /* show invisible */
1577 if (QUERY_FLAG (spell, FLAG_MAKE_INVIS) && 1575 if (QUERY_FLAG (spell, FLAG_MAKE_INVIS) &&
1578 /* Might there be other objects that we can make visible? */ 1576 /* Might there be other objects that we can make visible? */
1579 (tmp->invisible && (QUERY_FLAG (tmp, FLAG_MONSTER) || 1577 (tmp->invisible && (QUERY_FLAG (tmp, FLAG_MONSTER)
1580 (tmp->type == PLAYER && !QUERY_FLAG (tmp, FLAG_WIZ)) || 1578 || (tmp->type == PLAYER && !QUERY_FLAG (tmp, FLAG_WIZ))
1581 tmp->type == CF_HANDLE || 1579 || tmp->type == T_HANDLE
1582 tmp->type == TRAPDOOR || tmp->type == EXIT || tmp->type == HOLE || 1580 || tmp->type == TRAPDOOR
1581 || tmp->type == EXIT
1582 || tmp->type == HOLE
1583 || tmp->type == BUTTON
1583 tmp->type == BUTTON || tmp->type == TELEPORTER || 1584 || tmp->type == TELEPORTER
1585 || tmp->type == GATE
1584 tmp->type == GATE || tmp->type == LOCKED_DOOR || 1586 || tmp->type == LOCKED_DOOR
1585 tmp->type == WEAPON || tmp->type == ALTAR || tmp->type == SIGN || 1587 || tmp->type == WEAPON
1588 || tmp->type == ALTAR
1589 || tmp->type == SIGN
1586 tmp->type == TRIGGER_PEDESTAL || tmp->type == SPECIAL_KEY || 1590 || tmp->type == TRIGGER_PEDESTAL
1587 tmp->type == TREASURE || tmp->type == BOOK || tmp->type == HOLY_ALTAR))) 1591 || tmp->type == SPECIAL_KEY
1592 || tmp->type == TREASURE
1593 || tmp->type == BOOK
1594 || tmp->type == HOLY_ALTAR
1595 || tmp->type == CONTAINER)))
1588 { 1596 {
1589 if (random_roll (0, skill->level - 1, op, PREFER_HIGH) > level / 4) 1597 if (random_roll (0, skill->level - 1, op, PREFER_HIGH) > level / 4)
1590 { 1598 {
1591 tmp->invisible = 0; 1599 tmp->invisible = 0;
1592 done_one = 1; 1600 done_one = 1;
1593 } 1601 }
1594 } 1602 }
1595 1603
1596 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR)) 1604 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1597 floor = 1; 1605 floor = 1;
1598 1606
1599 /* All detections below this point don't descend beneath the floor, 1607 /* All detections below this point don't descend beneath the floor,
1600 * so just continue on. We could be clever and look at the type of 1608 * so just continue on. We could be clever and look at the type of
1601 * detection to completely break out if we don't care about objects beneath 1609 * detection to completely break out if we don't care about objects beneath
1602 * the floor, but once we get to the floor, not likely a very big issue anyways. 1610 * the floor, but once we get to the floor, not likely a very big issue anyways.
1603 */ 1611 */
1604 if (floor) 1612 if (floor)
1605 continue; 1613 continue;
1606 1614
1607 /* I had thought about making detect magic and detect curse 1615 /* I had thought about making detect magic and detect curse
1608 * show the flash the magic item like it does for detect monster. 1616 * show the flash the magic item like it does for detect monster.
1609 * however, if the object is within sight, this would then make it 1617 * however, if the object is within sight, this would then make it
1610 * difficult to see what object is magical/cursed, so the 1618 * difficult to see what object is magical/cursed, so the
1611 * effect wouldn't be as apparant. 1619 * effect wouldn't be as apparent.
1612 */ 1620 */
1613 1621
1614 /* detect magic */ 1622 /* detect magic */
1615 if (QUERY_FLAG (spell, FLAG_KNOWN_MAGICAL) && 1623 if (QUERY_FLAG (spell, FLAG_KNOWN_MAGICAL) &&
1616 !QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) && !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && is_magical (tmp)) 1624 !QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) && !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && is_magical (tmp))
1617 { 1625 {
1618 SET_FLAG (tmp, FLAG_KNOWN_MAGICAL); 1626 SET_FLAG (tmp, FLAG_KNOWN_MAGICAL);
1619 /* make runes more visibile */ 1627 /* make runes more visibile */
1620 if (tmp->type == RUNE && tmp->attacktype & AT_MAGIC) 1628 if (tmp->type == RUNE && tmp->attacktype & AT_MAGIC)
1621 tmp->stats.Cha /= 4; 1629 tmp->stats.Cha /= 4;
1630
1622 done_one = 1; 1631 done_one = 1;
1623 } 1632 }
1633
1624 /* detect monster */ 1634 /* detect monster */
1625 if (QUERY_FLAG (spell, FLAG_MONSTER) && (QUERY_FLAG (tmp, FLAG_MONSTER) || tmp->type == PLAYER)) 1635 if (QUERY_FLAG (spell, FLAG_MONSTER) && (QUERY_FLAG (tmp, FLAG_MONSTER) || tmp->type == PLAYER))
1626 { 1636 {
1627 done_one = 2; 1637 done_one = 2;
1638
1628 if (!detect) 1639 if (!detect)
1629 detect = tmp; 1640 detect = tmp;
1630 } 1641 }
1642
1631 /* Basically, if race is set in the spell, then the creatures race must 1643 /* Basically, if race is set in the spell, then the creatures race must
1632 * match that. if the spell race is set to GOD, then the gods opposing 1644 * match that. if the spell race is set to GOD, then the gods opposing
1633 * race must match. 1645 * race must match.
1634 */ 1646 */
1635 if (spell->race && QUERY_FLAG (tmp, FLAG_MONSTER) && tmp->race && 1647 if (spell->race && QUERY_FLAG (tmp, FLAG_MONSTER) && tmp->race &&
1636 ((!strcmp (spell->race, "GOD") && god && god->slaying && strstr (god->slaying, tmp->race)) || 1648 ((spell->race == shstr_GOD && god && god->slaying.contains (tmp->race)) ||
1637 (strstr (spell->race, tmp->race)))) 1649 spell->race.contains (tmp->race)))
1638 { 1650 {
1639 done_one = 2; 1651 done_one = 2;
1652
1640 if (!detect) 1653 if (!detect)
1641 detect = tmp; 1654 detect = tmp;
1642 } 1655 }
1656
1643 if (QUERY_FLAG (spell, FLAG_KNOWN_CURSED) && !QUERY_FLAG (tmp, FLAG_KNOWN_CURSED) && 1657 if (QUERY_FLAG (spell, FLAG_KNOWN_CURSED) && !QUERY_FLAG (tmp, FLAG_KNOWN_CURSED) &&
1644 (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))) 1658 (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)))
1645 { 1659 {
1646 SET_FLAG (tmp, FLAG_KNOWN_CURSED); 1660 SET_FLAG (tmp, FLAG_KNOWN_CURSED);
1647 done_one = 1; 1661 done_one = 1;
1648 } 1662 }
1649 } /* for stack of objects on this space */ 1663 } /* for stack of objects on this space */
1650 1664
1651 /* Code here puts an effect of the spell on the space, so you can see 1665 /* Code here puts an effect of the spell on the space, so you can see
1652 * where the magic is. 1666 * where the magic is.
1653 */ 1667 */
1654 if (done_one) 1668 if (done_one)
1655 { 1669 {
1656 object *detect_ob = arch_to_object (spell->other_arch); 1670 object *detect_ob = arch_to_object (spell->other_arch);
1657 1671
1658 /* if this is set, we want to copy the face */ 1672 /* if this is set, we want to copy the face */
1659 if (done_one == 2 && detect) 1673 if (done_one == 2 && detect)
1660 { 1674 {
1661 detect_ob->face = detect->face; 1675 detect_ob->face = detect->face;
1662 detect_ob->animation_id = detect->animation_id; 1676 detect_ob->animation_id = detect->animation_id;
1663 detect_ob->anim_speed = detect->anim_speed; 1677 detect_ob->anim_speed = detect->anim_speed;
1664 detect_ob->last_anim = 0; 1678 detect_ob->last_anim = 0;
1665 /* by default, the detect_ob is already animated */ 1679 /* by default, the detect_ob is already animated */
1666 if (!QUERY_FLAG (detect, FLAG_ANIMATE)) 1680 if (!QUERY_FLAG (detect, FLAG_ANIMATE))
1667 CLEAR_FLAG (detect_ob, FLAG_ANIMATE); 1681 CLEAR_FLAG (detect_ob, FLAG_ANIMATE);
1668 } 1682 }
1669 1683
1670 m->insert (detect_ob, nx, ny, op); 1684 m->insert (detect_ob, nx, ny, op);
1671 } 1685 }
1672 } /* for processing the surrounding spaces */ 1686 } /* for processing the surrounding spaces */
1673 1687
1674 1688
1675 /* Now process objects in the players inventory if detect curse or magic */ 1689 /* Now process objects in the players inventory if detect curse or magic */
1676 if (QUERY_FLAG (spell, FLAG_KNOWN_CURSED) || QUERY_FLAG (spell, FLAG_KNOWN_MAGICAL)) 1690 if (QUERY_FLAG (spell, FLAG_KNOWN_CURSED) || QUERY_FLAG (spell, FLAG_KNOWN_MAGICAL))
1677 { 1691 {
1721 1735
1722 new_draw_info (NDI_UNIQUE, 0, victim, "You feel energy course through you."); 1736 new_draw_info (NDI_UNIQUE, 0, victim, "You feel energy course through you.");
1723 1737
1724 if (victim->stats.sp >= victim->stats.maxsp * 2) 1738 if (victim->stats.sp >= victim->stats.maxsp * 2)
1725 { 1739 {
1726 object *tmp;
1727
1728 new_draw_info (NDI_UNIQUE, 0, victim, "Your head explodes!"); 1740 new_draw_info (NDI_UNIQUE, 0, victim, "Your head explodes!");
1729
1730 /* Explodes a fireball centered at player */
1731 tmp = get_archetype (EXPLODING_FIREBALL);
1732 tmp->dam_modifier = random_roll (1, caster_level, victim, PREFER_LOW) / 5 + 1;
1733 tmp->stats.maxhp = random_roll (1, caster_level, victim, PREFER_LOW) / 10 + 2;
1734
1735 tmp->insert_at (victim);
1736 victim->stats.sp = 2 * victim->stats.maxsp; 1741 victim->stats.sp = 2 * victim->stats.maxsp;
1742 create_exploding_ball_at (victim, caster_level);
1737 } 1743 }
1738 else if (victim->stats.sp >= victim->stats.maxsp * 1.88) 1744 else if (victim->stats.sp >= victim->stats.maxsp * 1.88)
1739 new_draw_info (NDI_UNIQUE, NDI_ORANGE, victim, "You feel like your head is going to explode."); 1745 new_draw_info (NDI_UNIQUE | NDI_ORANGE, 0, victim, "You feel like your head is going to explode.");
1740 else if (victim->stats.sp >= victim->stats.maxsp * 1.66) 1746 else if (victim->stats.sp >= victim->stats.maxsp * 1.66)
1741 new_draw_info (NDI_UNIQUE, 0, victim, "You get a splitting headache!"); 1747 new_draw_info (NDI_UNIQUE, 0, victim, "You get a splitting headache!");
1742 else if (victim->stats.sp >= victim->stats.maxsp * 1.5) 1748 else if (victim->stats.sp >= victim->stats.maxsp * 1.5)
1743 { 1749 {
1744 new_draw_info (NDI_UNIQUE, 0, victim, "Chaos fills your world."); 1750 new_draw_info (NDI_UNIQUE, 0, victim, "Chaos fills your world.");
1790 } 1796 }
1791 /* give sp */ 1797 /* give sp */
1792 if (spell->stats.dam > 0) 1798 if (spell->stats.dam > 0)
1793 { 1799 {
1794 plyr->stats.sp += spell->stats.dam + SP_level_dam_adjust (caster, spell); 1800 plyr->stats.sp += spell->stats.dam + SP_level_dam_adjust (caster, spell);
1795 charge_mana_effect (plyr, caster_level (caster, spell)); 1801 charge_mana_effect (plyr, casting_level (caster, spell));
1796 return 1; 1802 return 1;
1797 } 1803 }
1798 /* suck sp away. Can't suck sp from yourself */ 1804 /* suck sp away. Can't suck sp from yourself */
1799 else if (op != plyr) 1805 else if (op != plyr)
1800 { 1806 {
1812 /* Player doesn't get full credit */ 1818 /* Player doesn't get full credit */
1813 sucked = (sucked * rate) / 100; 1819 sucked = (sucked * rate) / 100;
1814 op->stats.sp += sucked; 1820 op->stats.sp += sucked;
1815 if (sucked > 0) 1821 if (sucked > 0)
1816 { 1822 {
1817 charge_mana_effect (op, caster_level (caster, spell)); 1823 charge_mana_effect (op, casting_level (caster, spell));
1818 } 1824 }
1819 } 1825 }
1820 return 1; 1826 return 1;
1821 } 1827 }
1822 return 0; 1828 return 0;
1919 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR)) 1925 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1920 break; 1926 break;
1921 if (tmp->type == HOLY_ALTAR) 1927 if (tmp->type == HOLY_ALTAR)
1922 { 1928 {
1923 1929
1924 if (tmp->level > caster_level (caster, spell)) 1930 if (tmp->level > casting_level (caster, spell))
1925 { 1931 {
1926 new_draw_info_format (NDI_UNIQUE, 0, op, "You are not powerful enough to reconsecrate the %s", &tmp->name); 1932 new_draw_info_format (NDI_UNIQUE, 0, op, "You are not powerful enough to reconsecrate the %s", &tmp->name);
1927 return 0; 1933 return 0;
1928 } 1934 }
1929 else 1935 else
1930 { 1936 {
1931 /* If we got here, we are consecrating an altar */ 1937 /* If we got here, we are consecrating an altar */
1932 sprintf (buf, "Altar of %s", &god->name); 1938 sprintf (buf, "Altar of %s", &god->name);
1933 tmp->name = buf; 1939 tmp->name = buf;
1934 tmp->level = caster_level (caster, spell); 1940 tmp->level = casting_level (caster, spell);
1935 tmp->other_arch = god->arch; 1941 tmp->other_arch = god->arch;
1936 1942
1937 if (op->type == PLAYER) 1943 if (op->type == PLAYER)
1938 esrv_update_item (UPD_NAME, op, tmp); 1944 esrv_update_item (UPD_NAME, op, tmp);
1939 1945
1982 return 0; 1988 return 0;
1983 } 1989 }
1984 1990
1985 /* if no direction specified, pick one */ 1991 /* if no direction specified, pick one */
1986 if (!dir) 1992 if (!dir)
1987 dir = find_free_spot (NULL, op->map, op->x, op->y, 1, 9); 1993 dir = find_free_spot (spell->other_arch, op->map, op->x, op->y, 1, 9);
1988 1994
1989 m = op->map; 1995 m = op->map;
1990 x = op->x + freearr_x[dir]; 1996 x = op->x + freearr_x[dir];
1991 y = op->y + freearr_y[dir]; 1997 y = op->y + freearr_y[dir];
1992 1998
1993 /* if there's no place to put the golem, abort */ 1999 /* if there's no place to put the golem, abort */
1994 if ((dir == -1) || (get_map_flags (m, &m, x, y, &x, &y) & P_OUT_OF_MAP) || 2000 if (dir < 0 || (get_map_flags (m, &m, x, y, &x, &y) & P_OUT_OF_MAP)
1995 ((spell->other_arch->move_type & GET_MAP_MOVE_BLOCK (m, x, y)) == spell->other_arch->move_type)) 2001 || ((spell->other_arch->move_type & GET_MAP_MOVE_BLOCK (m, x, y)) == spell->other_arch->move_type))
1996 { 2002 {
1997 new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way."); 2003 new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way.");
1998 return 0; 2004 return 0;
1999 } 2005 }
2000 2006
2004 if (!weapon) 2010 if (!weapon)
2005 { 2011 {
2006 new_draw_info (NDI_BLACK, 0, op, "You must mark a weapon to use with this spell!"); 2012 new_draw_info (NDI_BLACK, 0, op, "You must mark a weapon to use with this spell!");
2007 return 0; 2013 return 0;
2008 } 2014 }
2015
2009 if (spell->race && strcmp (weapon->arch->archname, spell->race)) 2016 if (spell->race && weapon->arch->archname != spell->race)
2010 { 2017 {
2011 new_draw_info (NDI_UNIQUE, 0, op, "The spell fails to transform your weapon."); 2018 new_draw_info (NDI_UNIQUE, 0, op, "The spell fails to transform your weapon.");
2012 return 0; 2019 return 0;
2013 } 2020 }
2021
2014 if (weapon->type != WEAPON) 2022 if (weapon->type != WEAPON)
2015 { 2023 {
2016 new_draw_info (NDI_UNIQUE, 0, op, "You need to wield a weapon to animate it."); 2024 new_draw_info (NDI_UNIQUE, 0, op, "You need to wield a weapon to animate it.");
2017 return 0; 2025 return 0;
2018 } 2026 }
2027
2019 if (QUERY_FLAG (weapon, FLAG_APPLIED)) 2028 if (QUERY_FLAG (weapon, FLAG_APPLIED))
2020 { 2029 {
2021 new_draw_info_format (NDI_BLACK, 0, op, "You need to unequip %s before using it in this spell", query_name (weapon)); 2030 new_draw_info_format (NDI_BLACK, 0, op, "You need to unequip %s before using it in this spell", query_name (weapon));
2022 return 0; 2031 return 0;
2023 } 2032 }
2126 tmp->state = weapon->state; 2135 tmp->state = weapon->state;
2127 tmp->flag [FLAG_ANIMATE] = weapon->flag [FLAG_ANIMATE]; 2136 tmp->flag [FLAG_ANIMATE] = weapon->flag [FLAG_ANIMATE];
2128 } 2137 }
2129 2138
2130 /* make experience increase in proportion to the strength of the summoned creature. */ 2139 /* make experience increase in proportion to the strength of the summoned creature. */
2131 tmp->stats.exp *= 1 + (MAX (spell->stats.maxgrace, spell->stats.sp) / caster_level (caster, spell)); 2140 tmp->stats.exp *= 1 + (MAX (spell->stats.maxgrace, spell->stats.sp) / casting_level (caster, spell));
2132 2141
2133 tmp->speed_left = -1; 2142 tmp->speed_left = -1;
2134 tmp->direction = dir; 2143 tmp->direction = dir;
2135 2144
2136 m->insert (tmp, x, y, op); 2145 m->insert (tmp, x, y, op);
2140/* cast_daylight() - changes the map darkness level *lower* */ 2149/* cast_daylight() - changes the map darkness level *lower* */
2141 2150
2142/* cast_change_map_lightlevel: Was cast_daylight/nightfall. 2151/* cast_change_map_lightlevel: Was cast_daylight/nightfall.
2143 * This changes the light level for the entire map. 2152 * This changes the light level for the entire map.
2144 */ 2153 */
2145
2146int 2154int
2147cast_change_map_lightlevel (object *op, object *caster, object *spell) 2155cast_change_map_lightlevel (object *op, object *caster, object *spell)
2148{ 2156{
2149 int success; 2157 int success;
2150 2158
2158 if (spell->stats.dam < 0) 2166 if (spell->stats.dam < 0)
2159 new_draw_info (NDI_UNIQUE, 0, op, "It can be no brighter here."); 2167 new_draw_info (NDI_UNIQUE, 0, op, "It can be no brighter here.");
2160 else 2168 else
2161 new_draw_info (NDI_UNIQUE, 0, op, "It can be no darker here."); 2169 new_draw_info (NDI_UNIQUE, 0, op, "It can be no darker here.");
2162 } 2170 }
2171
2163 return success; 2172 return success;
2164} 2173}
2165 2174
2166/* create an aura spell object and put it in the player's inventory. 2175/* create an aura spell object and put it in the player's inventory.
2167 * as usual, op is player, caster is the object casting the spell, 2176 * as usual, op is player, caster is the object casting the spell,
2184 new_aura->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell); 2193 new_aura->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
2185 2194
2186 set_spell_skill (op, caster, spell, new_aura); 2195 set_spell_skill (op, caster, spell, new_aura);
2187 new_aura->attacktype = spell->attacktype; 2196 new_aura->attacktype = spell->attacktype;
2188 2197
2189 new_aura->level = caster_level (caster, spell); 2198 new_aura->level = casting_level (caster, spell);
2190 2199
2191 if (refresh) 2200 if (refresh)
2192 new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect."); 2201 new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
2193 else 2202 else
2194 new_draw_info (NDI_UNIQUE, 0, op, "You create an aura of magical force."); 2203 new_draw_info (NDI_UNIQUE, 0, op, "You create an aura of magical force.");
2265 * op is the piece object. 2274 * op is the piece object.
2266 */ 2275 */
2267void 2276void
2268move_peacemaker (object *op) 2277move_peacemaker (object *op)
2269{ 2278{
2270 object *tmp; 2279 for (object *tmp = op->ms ().bot; tmp; tmp = tmp->above)
2271
2272 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above)
2273 { 2280 {
2274 int atk_lev, def_lev; 2281 int atk_lev, def_lev;
2275 object *victim = tmp->head_ (); 2282 object *victim = tmp->head_ ();
2276 2283
2277 if (!QUERY_FLAG (victim, FLAG_MONSTER)) 2284 if (!QUERY_FLAG (victim, FLAG_MONSTER))
2312 new_draw_info_format (NDI_UNIQUE, 0, op->owner, "%s no longer feels like fighting.", &victim->name); 2319 new_draw_info_format (NDI_UNIQUE, 0, op->owner, "%s no longer feels like fighting.", &victim->name);
2313 } 2320 }
2314 } 2321 }
2315} 2322}
2316 2323
2317
2318/* This writes a rune that contains the appropriate message. 2324/* This writes a rune that contains the appropriate message.
2319 * There really isn't any adjustments we make. 2325 * There really isn't any adjustments we make.
2320 */ 2326 */
2321
2322int 2327int
2323write_mark (object *op, object *spell, const char *msg) 2328write_mark (object *op, object *spell, const char *msg)
2324{ 2329{
2325 char rune[HUGE_BUF];
2326 object *tmp;
2327
2328 if (!msg || msg[0] == 0) 2330 if (!msg || msg[0] == 0)
2329 { 2331 {
2330 new_draw_info (NDI_UNIQUE, 0, op, "Write what?"); 2332 new_draw_info (NDI_UNIQUE, 0, op, "Write what?");
2331 return 0; 2333 return 0;
2332 } 2334 }
2333 2335
2334 if (strcasestr_local (msg, "endmsg")) 2336 if (!msg_is_safe (msg))
2335 { 2337 {
2336 new_draw_info (NDI_UNIQUE, 0, op, "Trying to cheat are we?"); 2338 new_draw_info (NDI_UNIQUE, 0, op, "Trying to cheat are we?");
2337 LOG (llevInfo, "write_rune: player %s tried to write bogus rune %s\n", &op->name, msg); 2339 LOG (llevInfo, "write_mark: player %s tried to write bogus rune %s\n", &op->name, msg);
2338 return 0; 2340 return 0;
2339 } 2341 }
2342
2340 if (!spell->other_arch) 2343 if (!spell->other_arch)
2341 return 0; 2344 return 0;
2345
2342 tmp = arch_to_object (spell->other_arch); 2346 object *tmp = arch_to_object (spell->other_arch);
2343
2344 snprintf (rune, sizeof (rune), "%s\n", msg);
2345 2347
2346 tmp->race = op->name; /*Save the owner of the rune */ 2348 tmp->race = op->name; /*Save the owner of the rune */
2347 tmp->msg = rune; 2349 tmp->msg = msg;
2348 2350
2349 tmp->insert_at (op, op, INS_BELOW_ORIGINATOR); 2351 tmp->insert_at (op, op, INS_BELOW_ORIGINATOR);
2352
2350 return 1; 2353 return 1;
2351} 2354}
2355

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines