… | |
… | |
122 | * The # of arrows created also goes up with level, so if a 30th level mage |
122 | * 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 |
123 | * wants LOTS of arrows, and doesn't care what the plus is he could |
124 | * create nonnmagic arrows, or even -1, etc... |
124 | * create nonnmagic arrows, or even -1, etc... |
125 | */ |
125 | */ |
126 | int |
126 | int |
127 | cast_create_missile (object *op, object *caster, object *spell, int dir, const char *stringarg) |
127 | cast_create_missile (object *op, object *caster, object *spell, int dir, const char *spellparam) |
128 | { |
128 | { |
129 | int bonus_plus = 0; |
129 | int bonus_plus = 0; |
130 | const char *missile_name = "arrow"; |
130 | const char *missile_name = "arrow"; |
131 | |
131 | |
132 | for (object *tmp = op->inv; tmp; tmp = tmp->below) |
132 | for (object *tmp = op->inv; tmp; tmp = tmp->below) |
… | |
… | |
143 | return 0; |
143 | return 0; |
144 | } |
144 | } |
145 | |
145 | |
146 | object *missile = missile_arch->instance (); |
146 | object *missile = missile_arch->instance (); |
147 | |
147 | |
148 | if (stringarg) |
148 | if (spellparam) |
149 | { |
149 | { |
150 | /* If it starts with a letter, presume it is a description */ |
150 | /* If it starts with a letter, presume it is a description */ |
151 | if (isalpha (*stringarg)) |
151 | if (isalpha (*spellparam)) |
152 | { |
152 | { |
153 | artifact *al = find_artifactlist (missile->type)->items; |
153 | artifact *al = find_artifactlist (missile->type)->items; |
154 | |
154 | |
155 | for (; al; al = al->next) |
155 | for (; al; al = al->next) |
156 | if (!strcasecmp (al->item->name, stringarg)) |
156 | if (!strcasecmp (al->item->name, spellparam)) |
157 | break; |
157 | break; |
158 | |
158 | |
159 | if (!al) |
159 | if (!al) |
160 | { |
160 | { |
161 | missile->destroy (); |
161 | missile->destroy (); |
162 | new_draw_info_format (NDI_UNIQUE, 0, op, "No such object %ss of %s", missile_name, stringarg); |
162 | new_draw_info_format (NDI_UNIQUE, 0, op, "No such object %ss of %s", missile_name, spellparam); |
163 | return 0; |
163 | return 0; |
164 | } |
164 | } |
165 | |
165 | |
166 | if (al->item->slaying) |
166 | if (al->item->slaying) |
167 | { |
167 | { |
168 | missile->destroy (); |
168 | missile->destroy (); |
169 | new_draw_info_format (NDI_UNIQUE, 0, op, "You are not allowed to create %ss of %s", missile_name, stringarg); |
169 | new_draw_info_format (NDI_UNIQUE, 0, op, "You are not allowed to create %ss of %s", missile_name, spellparam); |
170 | return 0; |
170 | return 0; |
171 | } |
171 | } |
172 | |
172 | |
173 | give_artifact_abilities (missile, al->item); |
173 | give_artifact_abilities (missile, al->item); |
174 | /* These special arrows cost something extra. Don't have them also be magical - |
174 | /* These special arrows cost something extra. Don't have them also be magical - |
… | |
… | |
176 | * the parsing of having to do both plus and type. |
176 | * the parsing of having to do both plus and type. |
177 | */ |
177 | */ |
178 | bonus_plus = 1 + (al->item->value / 5); |
178 | bonus_plus = 1 + (al->item->value / 5); |
179 | missile_plus = 0; |
179 | missile_plus = 0; |
180 | } |
180 | } |
181 | else if (atoi (stringarg) < missile_plus) |
181 | else if (atoi (spellparam) < missile_plus) |
182 | missile_plus = atoi (stringarg); |
182 | missile_plus = atoi (spellparam); |
183 | } |
183 | } |
184 | |
184 | |
185 | missile_plus = clamp (missile_plus, -4, 4); |
185 | missile_plus = clamp (missile_plus, -4, 4); |
186 | |
186 | |
187 | missile->nrof = spell->duration + SP_level_duration_adjust (caster, spell); |
187 | missile->nrof = spell->duration + SP_level_duration_adjust (caster, spell); |
… | |
… | |
202 | return 1; |
202 | return 1; |
203 | } |
203 | } |
204 | |
204 | |
205 | |
205 | |
206 | /* allows the choice of what sort of food object to make. |
206 | /* allows the choice of what sort of food object to make. |
207 | * If stringarg is NULL, it will create food dependent on level --PeterM*/ |
207 | * If spellparam is NULL, it will create food dependent on level --PeterM*/ |
208 | int |
208 | int |
209 | cast_create_food (object *op, object *caster, object *spell_ob, int dir, const char *stringarg) |
209 | cast_create_food (object *op, object *caster, object *spell_ob, int dir, const char *spellparam) |
210 | { |
210 | { |
211 | int food_value; |
211 | int food_value; |
212 | archetype *at = NULL; |
212 | archetype *at = NULL; |
213 | object *new_op; |
213 | object *new_op; |
214 | |
214 | |
215 | food_value = spell_ob->stats.food + 50 * SP_level_duration_adjust (caster, spell_ob); |
215 | food_value = spell_ob->stats.food + 50 * SP_level_duration_adjust (caster, spell_ob); |
216 | |
216 | |
217 | if (stringarg) |
217 | if (spellparam) |
218 | { |
218 | { |
219 | at = find_archetype_by_object_type_name (FOOD, stringarg); |
219 | at = find_archetype_by_object_type_name (FOOD, spellparam); |
220 | if (at == NULL) |
220 | if (at == NULL) |
221 | at = find_archetype_by_object_type_name (DRINK, stringarg); |
221 | at = find_archetype_by_object_type_name (DRINK, spellparam); |
222 | if (at == NULL || at->stats.food > food_value) |
222 | if (at == NULL || at->stats.food > food_value) |
223 | stringarg = NULL; |
223 | spellparam = NULL; |
224 | } |
224 | } |
225 | |
225 | |
226 | if (!stringarg) |
226 | if (!spellparam) |
227 | { |
227 | { |
228 | archetype *at_tmp; |
228 | archetype *at_tmp; |
229 | |
229 | |
230 | /* We try to find the archetype with the maximum food value. |
230 | /* We try to find the archetype with the maximum food value. |
231 | * This removes the dependancy of hard coded food values in this |
231 | * This removes the dependancy of hard coded food values in this |
… | |
… | |
425 | /* earth to dust spell. Basically destroys earthwalls in the area. |
425 | /* earth to dust spell. Basically destroys earthwalls in the area. |
426 | */ |
426 | */ |
427 | int |
427 | int |
428 | cast_earth_to_dust (object *op, object *caster, object *spell_ob) |
428 | cast_earth_to_dust (object *op, object *caster, object *spell_ob) |
429 | { |
429 | { |
430 | object *tmp, *next; |
|
|
431 | int range, i, j, mflags; |
430 | int range, i, j, mflags; |
432 | sint16 sx, sy; |
431 | sint16 sx, sy; |
433 | maptile *m; |
432 | maptile *m; |
434 | |
|
|
435 | if (op->type != PLAYER) |
|
|
436 | return 0; |
|
|
437 | |
433 | |
438 | range = spell_ob->range + SP_level_range_adjust (caster, spell_ob); |
434 | range = spell_ob->range + SP_level_range_adjust (caster, spell_ob); |
439 | |
435 | |
440 | for (i = -range; i <= range; i++) |
436 | for (i = -range; i <= range; i++) |
441 | for (j = -range; j <= range; j++) |
437 | for (j = -range; j <= range; j++) |
… | |
… | |
446 | mflags = get_map_flags (m, &m, sx, sy, &sx, &sy); |
442 | mflags = get_map_flags (m, &m, sx, sy, &sx, &sy); |
447 | |
443 | |
448 | if (mflags & P_OUT_OF_MAP) |
444 | if (mflags & P_OUT_OF_MAP) |
449 | continue; |
445 | continue; |
450 | |
446 | |
451 | // earth to dust tears down everything that can be teared down |
447 | // earth to dust tears down everything that can be torn down |
452 | for (tmp = GET_MAP_OB (m, sx, sy); tmp != NULL; tmp = next) |
448 | for (object *next, *tmp = m->at (sx, sy).bot; tmp; tmp = next) |
453 | { |
449 | { |
454 | next = tmp->above; |
450 | next = tmp->above; |
|
|
451 | |
455 | if (QUERY_FLAG (tmp, FLAG_TEAR_DOWN)) |
452 | if (QUERY_FLAG (tmp, FLAG_TEAR_DOWN)) |
456 | hit_player (tmp, 9998, op, AT_PHYSICAL, 0); |
453 | hit_player (tmp, 9998, op, AT_PHYSICAL, 0); |
457 | } |
454 | } |
458 | } |
455 | } |
459 | |
456 | |
… | |
… | |
569 | perceive_self (object *op) |
566 | perceive_self (object *op) |
570 | { |
567 | { |
571 | const char *cp = describe_item (op, op); |
568 | const char *cp = describe_item (op, op); |
572 | archetype *at = archetype::find (ARCH_DEPLETION); |
569 | archetype *at = archetype::find (ARCH_DEPLETION); |
573 | |
570 | |
574 | dynbuf_text buf; |
571 | dynbuf_text &buf = msg_dynbuf; buf.clear (); |
575 | |
572 | |
576 | if (player *pl = op->contr) |
573 | if (!op->is_player ()) |
|
|
574 | return 0; |
|
|
575 | |
577 | if (object *race = archetype::find (op->race)) |
576 | if (object *race = archetype::find (op->race)) |
578 | buf << " - You are a G<male|female> " << &race->name << ".\n"; |
577 | buf << " - You are a G<male|female> " << &race->name << ".\n"; |
579 | |
578 | |
580 | if (object *god = find_god (determine_god (op))) |
579 | if (object *god = find_god (determine_god (op))) |
581 | buf << " - You worship " << &god->name << ".\n"; |
580 | buf << " - You worship " << &god->name << ".\n"; |
582 | else |
581 | else |
583 | buf << " - You worship no god.\n"; |
582 | buf << " - You worship no god.\n"; |
… | |
… | |
609 | |
608 | |
610 | break; |
609 | break; |
611 | } |
610 | } |
612 | } |
611 | } |
613 | |
612 | |
614 | buf << '\0'; // zero-terminate |
613 | op->contr->infobox (MSG_CHANNEL ("perceiveself"), buf); |
615 | |
|
|
616 | new_draw_info (NDI_UNIQUE, 0, op, buf.linearise ()); |
|
|
617 | |
614 | |
618 | return 1; |
615 | return 1; |
619 | } |
616 | } |
620 | |
617 | |
621 | /* This creates magic walls. Really, it can create most any object, |
618 | /* This creates magic walls. Really, it can create most any object, |
… | |
… | |
780 | |
777 | |
781 | return 1; |
778 | return 1; |
782 | } |
779 | } |
783 | |
780 | |
784 | int |
781 | int |
785 | dimension_door (object *op, object *caster, object *spob, int dir) |
782 | dimension_door (object *op, object *caster, object *spob, int dir, const char *spellparam) |
786 | { |
783 | { |
787 | uint32 dist, maxdist; |
784 | uint32 dist, maxdist; |
788 | int mflags; |
785 | int mflags; |
789 | maptile *m; |
786 | maptile *m; |
790 | sint16 sx, sy; |
787 | sint16 sx, sy; |
… | |
… | |
801 | /* Given the new outdoor maps, can't let players dimension door for |
798 | /* Given the new outdoor maps, can't let players dimension door for |
802 | * ever, so put limits in. |
799 | * ever, so put limits in. |
803 | */ |
800 | */ |
804 | maxdist = spob->range + SP_level_range_adjust (caster, spob); |
801 | maxdist = spob->range + SP_level_range_adjust (caster, spob); |
805 | |
802 | |
806 | if (op->contr->count) |
803 | if (spellparam) |
807 | { |
804 | { |
|
|
805 | int count = atoi (spellparam); |
|
|
806 | |
808 | if (op->contr->count > maxdist) |
807 | if (count > maxdist) |
809 | { |
808 | { |
810 | new_draw_info (NDI_UNIQUE, 0, op, "You can't dimension door that far!"); |
809 | new_draw_info (NDI_UNIQUE, 0, op, "You can't dimension door that far!"); |
811 | return 0; |
810 | return 0; |
812 | } |
811 | } |
813 | |
812 | |
814 | for (dist = 0; dist < op->contr->count; dist++) |
813 | for (dist = 0; dist < count; dist++) |
815 | { |
814 | { |
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 | mflags = get_map_flags (op->map, &m, op->x + freearr_x[dir] * (dist + 1), op->y + freearr_y[dir] * (dist + 1), &sx, &sy); |
817 | |
816 | |
818 | if (mflags & (P_NO_MAGIC | P_OUT_OF_MAP)) |
817 | if (mflags & (P_NO_MAGIC | P_OUT_OF_MAP)) |
819 | break; |
818 | break; |
820 | |
819 | |
821 | if ((mflags & P_BLOCKSVIEW) && OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy))) |
820 | if ((mflags & P_BLOCKSVIEW) && OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy))) |
822 | break; |
821 | break; |
823 | } |
822 | } |
824 | |
823 | |
825 | if (dist < op->contr->count) |
824 | if (dist < count) |
826 | { |
825 | { |
827 | new_draw_info (NDI_UNIQUE, 0, op, "Something blocks the magic of the spell.\n"); |
826 | new_draw_info (NDI_UNIQUE, 0, op, "Something blocks the magic of the spell.\n"); |
828 | op->contr->count = 0; |
|
|
829 | return 0; |
827 | return 0; |
830 | } |
828 | } |
831 | |
|
|
832 | op->contr->count = 0; |
|
|
833 | |
829 | |
834 | /* Remove code that puts player on random space on maps. IMO, |
830 | /* Remove code that puts player on random space on maps. IMO, |
835 | * a lot of maps probably have areas the player should not get to, |
831 | * a lot of maps probably have areas the player should not get to, |
836 | * but may not be marked as NO_MAGIC (as they may be bounded |
832 | * but may not be marked as NO_MAGIC (as they may be bounded |
837 | * by such squares). Also, there are probably treasure rooms and |
833 | * by such squares). Also, there are probably treasure rooms and |
… | |
… | |
1034 | "You don't feel any more powerful." |
1030 | "You don't feel any more powerful." |
1035 | "You are no easier to look at.", |
1031 | "You are no easier to look at.", |
1036 | }; |
1032 | }; |
1037 | |
1033 | |
1038 | int |
1034 | int |
|
|
1035 | change_ability_duration (object *spell, object *caster) |
|
|
1036 | { |
|
|
1037 | return spell->duration + SP_level_duration_adjust (caster, spell) * 50; |
|
|
1038 | } |
|
|
1039 | |
|
|
1040 | int |
1039 | cast_change_ability (object *op, object *caster, object *spell_ob, int dir, int silent) |
1041 | cast_change_ability (object *op, object *caster, object *spell_ob, int dir, int silent) |
1040 | { |
1042 | { |
1041 | object *force = 0; |
1043 | object *force = 0; |
1042 | int i; |
1044 | int i; |
1043 | |
1045 | |
… | |
… | |
1083 | new_draw_info (NDI_UNIQUE, 0, op, "You create an aura of magical force."); |
1085 | new_draw_info (NDI_UNIQUE, 0, op, "You create an aura of magical force."); |
1084 | |
1086 | |
1085 | } |
1087 | } |
1086 | else |
1088 | else |
1087 | { |
1089 | { |
1088 | int duration; |
1090 | int duration = change_ability_duration (spell_ob, caster); |
1089 | |
1091 | |
1090 | duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50; |
|
|
1091 | if (duration > force->duration) |
1092 | if (duration > force->duration) |
1092 | { |
1093 | { |
1093 | force->duration = duration; |
1094 | force->duration = duration; |
1094 | new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect."); |
1095 | new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect."); |
1095 | } |
1096 | } |
… | |
… | |
1418 | * items. |
1419 | * items. |
1419 | */ |
1420 | */ |
1420 | int |
1421 | int |
1421 | remove_curse (object *op, object *caster, object *spell) |
1422 | remove_curse (object *op, object *caster, object *spell) |
1422 | { |
1423 | { |
1423 | object *tmp; |
|
|
1424 | int success = 0, was_one = 0; |
1424 | int success = 0, was_one = 0; |
1425 | |
1425 | |
1426 | for (tmp = op->inv; tmp; tmp = tmp->below) |
1426 | for (object *tmp = op->inv; tmp; tmp = tmp->below) |
1427 | if (QUERY_FLAG (tmp, FLAG_APPLIED) && |
1427 | if (QUERY_FLAG (tmp, FLAG_APPLIED) && |
1428 | ((QUERY_FLAG (tmp, FLAG_CURSED) && QUERY_FLAG (spell, FLAG_CURSED)) || |
1428 | ((QUERY_FLAG (tmp, FLAG_CURSED) && QUERY_FLAG (spell, FLAG_CURSED)) || |
1429 | (QUERY_FLAG (tmp, FLAG_DAMNED) && QUERY_FLAG (spell, FLAG_DAMNED)))) |
1429 | (QUERY_FLAG (tmp, FLAG_DAMNED) && QUERY_FLAG (spell, FLAG_DAMNED)))) |
1430 | { |
1430 | { |
1431 | was_one++; |
1431 | was_one++; |
… | |
… | |
1463 | |
1463 | |
1464 | /* Identifies objects in the players inventory/on the ground */ |
1464 | /* Identifies objects in the players inventory/on the ground */ |
1465 | int |
1465 | int |
1466 | cast_identify (object *op, object *caster, object *spell) |
1466 | cast_identify (object *op, object *caster, object *spell) |
1467 | { |
1467 | { |
1468 | dynbuf_text buf; |
|
|
1469 | object *tmp; |
1468 | object *tmp; |
|
|
1469 | dynbuf_text &buf = msg_dynbuf; buf.clear (); |
1470 | |
1470 | |
1471 | int num_ident = spell->stats.dam + SP_level_dam_adjust (caster, spell); |
1471 | int num_ident = max (1, spell->stats.dam + SP_level_dam_adjust (caster, spell)); |
1472 | |
|
|
1473 | if (num_ident < 1) |
|
|
1474 | num_ident = 1; |
|
|
1475 | |
1472 | |
1476 | for (tmp = op->inv; tmp; tmp = tmp->below) |
1473 | for (tmp = op->inv; tmp; tmp = tmp->below) |
1477 | { |
1474 | { |
1478 | if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !tmp->invisible && need_identify (tmp)) |
1475 | if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !tmp->invisible && need_identify (tmp)) |
1479 | { |
1476 | { |
… | |
… | |
1485 | |
1482 | |
1486 | if (tmp->msg) |
1483 | if (tmp->msg) |
1487 | buf << "The item has a story:\r" << tmp->msg << "\n\n"; |
1484 | buf << "The item has a story:\r" << tmp->msg << "\n\n"; |
1488 | } |
1485 | } |
1489 | |
1486 | |
1490 | num_ident--; |
|
|
1491 | if (!num_ident) |
1487 | if (!--num_ident) |
1492 | break; |
1488 | break; |
1493 | } |
1489 | } |
1494 | } |
1490 | } |
1495 | |
1491 | |
1496 | /* If all the power of the spell has been used up, don't go and identify |
1492 | /* If all the power of the spell has been used up, don't go and identify |
… | |
… | |
1510 | |
1506 | |
1511 | if (tmp->msg) |
1507 | if (tmp->msg) |
1512 | buf << "The item has a story:\r" << tmp->msg << "\n\n"; |
1508 | buf << "The item has a story:\r" << tmp->msg << "\n\n"; |
1513 | } |
1509 | } |
1514 | |
1510 | |
1515 | num_ident--; |
|
|
1516 | if (!num_ident) |
1511 | if (!--num_ident) |
1517 | break; |
1512 | break; |
1518 | } |
1513 | } |
1519 | } |
1514 | } |
1520 | |
1515 | |
1521 | if (buf.empty ()) |
1516 | if (buf.empty ()) |
… | |
… | |
1574 | for (tmp = last; tmp; tmp = tmp->below) |
1569 | for (tmp = last; tmp; tmp = tmp->below) |
1575 | { |
1570 | { |
1576 | /* show invisible */ |
1571 | /* show invisible */ |
1577 | if (QUERY_FLAG (spell, FLAG_MAKE_INVIS) && |
1572 | if (QUERY_FLAG (spell, FLAG_MAKE_INVIS) && |
1578 | /* Might there be other objects that we can make visible? */ |
1573 | /* Might there be other objects that we can make visible? */ |
1579 | (tmp->invisible && (QUERY_FLAG (tmp, FLAG_MONSTER) || |
1574 | (tmp->invisible && (QUERY_FLAG (tmp, FLAG_MONSTER) |
1580 | (tmp->type == PLAYER && !QUERY_FLAG (tmp, FLAG_WIZ)) |
1575 | || (tmp->type == PLAYER && !QUERY_FLAG (tmp, FLAG_WIZ)) |
1581 | || tmp->type == CF_HANDLE |
1576 | || tmp->type == CF_HANDLE |
1582 | || tmp->type == TRAPDOOR || tmp->type == EXIT || tmp->type == HOLE |
1577 | || tmp->type == TRAPDOOR |
|
|
1578 | || tmp->type == EXIT |
|
|
1579 | || tmp->type == HOLE |
|
|
1580 | || tmp->type == BUTTON |
1583 | || tmp->type == BUTTON || tmp->type == TELEPORTER |
1581 | || tmp->type == TELEPORTER |
|
|
1582 | || tmp->type == GATE |
1584 | || tmp->type == GATE || tmp->type == LOCKED_DOOR |
1583 | || tmp->type == LOCKED_DOOR |
1585 | || tmp->type == WEAPON || tmp->type == ALTAR || tmp->type == SIGN |
1584 | || tmp->type == WEAPON |
|
|
1585 | || tmp->type == ALTAR |
|
|
1586 | || tmp->type == SIGN |
1586 | || tmp->type == TRIGGER_PEDESTAL || tmp->type == SPECIAL_KEY |
1587 | || tmp->type == TRIGGER_PEDESTAL |
1587 | || tmp->type == TREASURE || tmp->type == BOOK || tmp->type == HOLY_ALTAR))) |
1588 | || tmp->type == SPECIAL_KEY |
|
|
1589 | || tmp->type == TREASURE |
|
|
1590 | || tmp->type == BOOK |
|
|
1591 | || tmp->type == HOLY_ALTAR |
|
|
1592 | || tmp->type == CONTAINER))) |
1588 | { |
1593 | { |
1589 | if (random_roll (0, skill->level - 1, op, PREFER_HIGH) > level / 4) |
1594 | if (random_roll (0, skill->level - 1, op, PREFER_HIGH) > level / 4) |
1590 | { |
1595 | { |
1591 | tmp->invisible = 0; |
1596 | tmp->invisible = 0; |
1592 | done_one = 1; |
1597 | done_one = 1; |