/* ************************************************************************ * File: magic.c Part of CircleMUD * * Usage: low-level functions for magic; spell template code * * * * All rights reserved. See license.doc for complete information. * * * * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * ************************************************************************ */ #include <stdio.h> #include <string.h> #include "structs.h" #include "utils.h" #include "comm.h" #include "spells.h" #include "handler.h" #include "db.h" extern struct room_data *world; extern struct obj_data *object_list; extern struct char_data *character_list; extern struct cha_app_type cha_app[]; extern struct int_app_type int_app[]; extern struct index_data *obj_index; extern struct weather_data weather_info; extern struct descriptor_data *descriptor_list; extern struct zone_data *zone_table; extern int mini_mud; extern int pk_allowed; extern struct default_mobile_stats *mob_defaults; extern char weapon_verbs[]; extern int *max_ac_applys; extern struct apply_mod_defaults *apmd; void clearMemory(struct char_data * ch); void act(char *str, int i, struct char_data * c, struct obj_data * o, void *vict_obj, int j); void damage(struct char_data * ch, struct char_data * victim, int damage, int weapontype); void weight_change_object(struct obj_data * obj, int weight); void add_follower(struct char_data * ch, struct char_data * leader); int dice(int number, int size); extern struct spell_info_type spell_info[]; bool CAN_MURDER(struct char_data * ch, struct char_data * victim); struct char_data *read_mobile(int, int); /* * Saving throws for: * MCTWBSDWN * PARA, ROD, PETRI, BREATH, SPELL * Levels 0-40 */ const byte saving_throws[NUM_CLASSES][5][41] = { { /* Mages */ {90, 70, 69, 68, 67, 66, 65, 63, 61, 60, 59, /* 0 - 10 */ /* PARA */ 57, 55, 54, 53, 53, 52, 51, 50, 48, 46, /* 11 - 20 */ 45, 44, 42, 40, 38, 36, 34, 32, 30, 28, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 55, 53, 51, 49, 47, 45, 43, 41, 40, 39, /* 0 - 10 */ /* ROD */ 37, 35, 33, 31, 30, 29, 27, 25, 23, 21, /* 11 - 20 */ 20, 19, 17, 15, 14, 13, 12, 11, 10, 9, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 63, 61, 59, 57, 55, 53, 51, 50, 49, /* 0 - 10 */ /* PETRI */ 47, 45, 43, 41, 40, 39, 37, 35, 33, 31, /* 11 - 20 */ 30, 29, 27, 25, 23, 21, 19, 17, 15, 13, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 73, 71, 69, 67, 65, 63, 61, 60, 59, /* 0 - 10 */ /* BREATH */ 57, 55, 53, 51, 50, 49, 47, 45, 43, 41, /* 11 - 20 */ 40, 39, 37, 35, 33, 31, 29, 27, 25, 23, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 60, 58, 56, 54, 52, 50, 48, 46, 45, 44, /* 0 - 10 */ /* SPELL */ 42, 40, 38, 36, 35, 34, 32, 30, 28, 26, /* 11 - 20 */ 25, 24, 22, 20, 18, 16, 14, 12, 10, 8, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ }, { /* Clerics */ {90, 50, 59, 48, 46, 45, 43, 40, 37, 35, 34, /* 0 - 10 */ /* PARA */ 33, 31, 30, 29, 27, 26, 25, 24, 23, 22, /* 11 - 20 */ 21, 20, 18, 15, 14, 12, 10, 9, 8, 7, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 69, 68, 66, 65, 63, 60, 57, 55, 54, /* 0 - 10 */ /* ROD */ 53, 51, 50, 49, 47, 46, 45, 44, 43, 42, /* 11 - 20 */ 41, 40, 38, 35, 34, 32, 30, 29, 28, 27, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 64, 63, 61, 60, 58, 55, 53, 50, 49, /* 0 - 10 */ /* PETRI */ 48, 46, 45, 44, 43, 41, 40, 39, 38, 37, /* 11 - 20 */ 36, 35, 33, 31, 29, 27, 25, 24, 23, 22, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 76, 75, 73, 70, 67, 65, 64, /* 0 - 10 */ /* BREATH */ 63, 61, 60, 59, 57, 56, 55, 54, 53, 52, /* 11 - 20 */ 51, 50, 48, 45, 44, 42, 40, 39, 38, 37, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 74, 73, 71, 70, 68, 65, 63, 60, 59, /* 0 - 10 */ /* SPELL */ 58, 56, 55, 54, 53, 51, 50, 49, 48, 47, /* 11 - 20 */ 46, 45, 43, 41, 39, 37, 35, 34, 33, 32, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ }, { /* Thieves */ {90, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, /* 0 - 10 */ /* PARA */ 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, /* 11 - 20 */ 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 68, 66, 64, 62, 60, 58, 56, 54, 52, /* 0 - 10 */ /* ROD */ 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, /* 11 - 20 */ 30, 28, 26, 24, 22, 20, 18, 16, 14, 13, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 60, 59, 58, 58, 56, 55, 54, 53, 52, 51, /* 0 - 10 */ /* PETRI */ 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, /* 11 - 20 */ 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, /* 0 - 10 */ /* BREATH */ 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, /* 11 - 20 */ 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 73, 71, 69, 67, 65, 63, 61, 59, 57, /* 0 - 10 */ /* SPELL */ 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, /* 11 - 20 */ 35, 33, 31, 29, 27, 25, 23, 21, 19, 17, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ }, { /* Warriors */ {90, 70, 68, 67, 65, 62, 58, 55, 53, 52, 50, /* 0 - 10 */ /* PARA */ 47, 43, 40, 38, 37, 35, 32, 28, 25, 24, /* 11 - 20 */ 23, 22, 20, 19, 17, 16, 15, 14, 13, 12, /* 21 - 30 */ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2}, /* 31 - 40 */ {90, 80, 78, 77, 75, 72, 68, 65, 63, 62, 60, /* 0 - 10 */ /* ROD */ 57, 53, 50, 48, 47, 45, 42, 38, 35, 34, /* 11 - 20 */ 33, 32, 30, 29, 27, 26, 25, 24, 23, 22, /* 21 - 30 */ 20, 18, 16, 14, 12, 10, 8, 6, 5, 4}, /* 31 - 40 */ {90, 75, 73, 72, 70, 67, 63, 60, 58, 57, 55, /* 0 - 10 */ /* PETRI */ 52, 48, 45, 43, 42, 40, 37, 33, 30, 29, /* 11 - 20 */ 28, 26, 25, 24, 23, 21, 20, 19, 18, 17, /* 21 - 30 */ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7}, /* 31 - 40 */ {90, 85, 83, 82, 80, 75, 70, 65, 63, 62, 60, /* 0 - 10 */ /* BREATH */ 55, 50, 45, 43, 42, 40, 37, 33, 30, 29, /* 11 - 20 */ 28, 26, 25, 24, 23, 21, 20, 19, 18, 17, /* 21 - 30 */ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7}, /* 31 - 40 */ {90, 85, 83, 82, 80, 77, 73, 70, 68, 67, 65, /* 0 - 10 */ /* SPELL */ 62, 58, 55, 53, 52, 50, 47, 43, 40, 39, /* 11 - 20 */ 38, 36, 35, 34, 33, 31, 30, 29, 28, 27, /* 21 - 30 */ 25, 23, 21, 19, 17, 15, 13, 11, 9, 7} /* 31 - 40 */ }, { /* Barbarians */ {90, 70, 68, 67, 65, 62, 58, 55, 53, 52, 50, /* 0 - 10 */ /* PARA */ 47, 43, 40, 38, 37, 35, 32, 28, 25, 24, /* 11 - 20 */ 23, 22, 20, 19, 17, 16, 15, 14, 13, 12, /* 21 - 30 */ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2}, /* 31 - 40 */ {90, 80, 78, 77, 75, 72, 68, 65, 63, 62, 60, /* 0 - 10 */ /* ROD */ 57, 53, 50, 48, 47, 45, 42, 38, 35, 34, /* 11 - 20 */ 33, 32, 30, 29, 27, 26, 25, 24, 23, 22, /* 21 - 30 */ 20, 18, 16, 14, 12, 10, 8, 6, 5, 4}, /* 31 - 40 */ {90, 75, 73, 72, 70, 67, 63, 60, 58, 57, 55, /* 0 - 10 */ /* PETRI */ 52, 48, 45, 43, 42, 40, 37, 33, 30, 29, /* 11 - 20 */ 28, 26, 25, 24, 23, 21, 20, 19, 18, 17, /* 21 - 30 */ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7}, /* 31 - 40 */ {90, 85, 83, 82, 80, 75, 70, 65, 63, 62, 60, /* 0 - 10 */ /* BREATH */ 55, 50, 45, 43, 42, 40, 37, 33, 30, 29, /* 11 - 20 */ 28, 26, 25, 24, 23, 21, 20, 19, 18, 17, /* 21 - 30 */ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7}, /* 31 - 40 */ {90, 85, 83, 82, 80, 77, 73, 70, 68, 67, 65, /* 0 - 10 */ /* SPELL */ 62, 58, 55, 53, 52, 50, 47, 43, 40, 39, /* 11 - 20 */ 38, 36, 35, 34, 33, 31, 30, 29, 28, 27, /* 21 - 30 */ 25, 23, 21, 19, 17, 15, 13, 11, 9, 7} /* 31 - 40 */ }, { /* Samurai */ {90, 50, 59, 48, 46, 45, 43, 40, 37, 35, 34, /* 0 - 10 */ /* PARA */ 33, 31, 30, 29, 27, 26, 25, 24, 23, 22, /* 11 - 20 */ 21, 20, 18, 15, 14, 12, 10, 9, 8, 7, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 69, 68, 66, 65, 63, 60, 57, 55, 54, /* 0 - 10 */ /* ROD */ 53, 51, 50, 49, 47, 46, 45, 44, 43, 42, /* 11 - 20 */ 41, 40, 38, 35, 34, 32, 30, 29, 28, 27, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 64, 63, 61, 60, 58, 55, 53, 50, 49, /* 0 - 10 */ /* PETRI */ 48, 46, 45, 44, 43, 41, 40, 39, 38, 37, /* 11 - 20 */ 36, 35, 33, 31, 29, 27, 25, 24, 23, 22, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 76, 75, 73, 70, 67, 65, 64, /* 0 - 10 */ /* BREATH */ 63, 61, 60, 59, 57, 56, 55, 54, 53, 52, /* 11 - 20 */ 51, 50, 48, 45, 44, 42, 40, 39, 38, 37, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 74, 73, 71, 70, 68, 65, 63, 60, 59, /* 0 - 10 */ /* SPELL */ 58, 56, 55, 54, 53, 51, 50, 49, 48, 47, /* 11 - 20 */ 46, 45, 43, 41, 39, 37, 35, 34, 33, 32, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ }, { /* Druid */ {90, 50, 59, 48, 46, 45, 43, 40, 37, 35, 34, /* 0 - 10 */ /* PARA */ 33, 31, 30, 29, 27, 26, 25, 24, 23, 22, /* 11 - 20 */ 21, 20, 18, 15, 14, 12, 10, 9, 8, 7, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 69, 68, 66, 65, 63, 60, 57, 55, 54, /* 0 - 10 */ /* ROD */ 53, 51, 50, 49, 47, 46, 45, 44, 43, 42, /* 11 - 20 */ 41, 40, 38, 35, 34, 32, 30, 29, 28, 27, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 64, 63, 61, 60, 58, 55, 53, 50, 49, /* 0 - 10 */ /* PETRI */ 48, 46, 45, 44, 43, 41, 40, 39, 38, 37, /* 11 - 20 */ 36, 35, 33, 31, 29, 27, 25, 24, 23, 22, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 76, 75, 73, 70, 67, 65, 64, /* 0 - 10 */ /* BREATH */ 63, 61, 60, 59, 57, 56, 55, 54, 53, 52, /* 11 - 20 */ 51, 50, 48, 45, 44, 42, 40, 39, 38, 37, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 74, 73, 71, 70, 68, 65, 63, 60, 59, /* 0 - 10 */ /* SPELL */ 58, 56, 55, 54, 53, 51, 50, 49, 48, 47, /* 11 - 20 */ 46, 45, 43, 41, 39, 37, 35, 34, 33, 32, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ }, { /* Wizards */ {90, 70, 69, 68, 67, 66, 65, 63, 61, 60, 59, /* 0 - 10 */ /* PARA */ 57, 55, 54, 53, 53, 52, 51, 50, 48, 46, /* 11 - 20 */ 45, 44, 42, 40, 38, 36, 34, 32, 30, 28, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 55, 53, 51, 49, 47, 45, 43, 41, 40, 39, /* 0 - 10 */ /* ROD */ 37, 35, 33, 31, 30, 29, 27, 25, 23, 21, /* 11 - 20 */ 20, 19, 17, 15, 14, 13, 12, 11, 10, 9, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 63, 61, 59, 57, 55, 53, 51, 50, 49, /* 0 - 10 */ /* PETRI */ 47, 45, 43, 41, 40, 39, 37, 35, 33, 31, /* 11 - 20 */ 30, 29, 27, 25, 23, 21, 19, 17, 15, 13, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 73, 71, 69, 67, 65, 63, 61, 60, 59, /* 0 - 10 */ /* BREATH */ 57, 55, 53, 51, 50, 49, 47, 45, 43, 41, /* 11 - 20 */ 40, 39, 37, 35, 33, 31, 29, 27, 25, 23, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 60, 58, 56, 54, 52, 50, 48, 46, 45, 44, /* 0 - 10 */ /* SPELL */ 42, 40, 38, 36, 35, 34, 32, 30, 28, 26, /* 11 - 20 */ 25, 24, 22, 20, 18, 16, 14, 12, 10, 8, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ }, { /* MONK */ {90, 50, 59, 48, 46, 45, 43, 40, 37, 35, 34, /* 0 - 10 */ /* PARA */ 33, 31, 30, 29, 27, 26, 25, 24, 23, 22, /* 11 - 20 */ 21, 20, 18, 15, 14, 12, 10, 9, 8, 7, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 69, 68, 66, 65, 63, 60, 57, 55, 54, /* 0 - 10 */ /* ROD */ 53, 51, 50, 49, 47, 46, 45, 44, 43, 42, /* 11 - 20 */ 41, 40, 38, 35, 34, 32, 30, 29, 28, 27, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 64, 63, 61, 60, 58, 55, 53, 50, 49, /* 0 - 10 */ /* PETRI */ 48, 46, 45, 44, 43, 41, 40, 39, 38, 37, /* 11 - 20 */ 36, 35, 33, 31, 29, 27, 25, 24, 23, 22, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 76, 75, 73, 70, 67, 65, 64, /* 0 - 10 */ /* BREATH */ 63, 61, 60, 59, 57, 56, 55, 54, 53, 52, /* 11 - 20 */ 51, 50, 48, 45, 44, 42, 40, 39, 38, 37, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 74, 73, 71, 70, 68, 65, 63, 60, 59, /* 0 - 10 */ /* SPELL */ 58, 56, 55, 54, 53, 51, 50, 49, 48, 47, /* 11 - 20 */ 46, 45, 43, 41, 39, 37, 35, 34, 33, 32, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ }, { /* Avatar */ {90, 50, 59, 48, 46, 45, 43, 40, 37, 35, 34, /* 0 - 10 */ /* PARA */ 33, 31, 30, 29, 27, 26, 25, 24, 23, 22, /* 11 - 20 */ 21, 20, 18, 15, 14, 12, 10, 9, 8, 7, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 69, 68, 66, 65, 63, 60, 57, 55, 54, /* 0 - 10 */ /* ROD */ 53, 51, 50, 49, 47, 46, 45, 44, 43, 42, /* 11 - 20 */ 41, 40, 38, 35, 34, 32, 30, 29, 28, 27, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 64, 63, 61, 60, 58, 55, 53, 50, 49, /* 0 - 10 */ /* PETRI */ 48, 46, 45, 44, 43, 41, 40, 39, 38, 37, /* 11 - 20 */ 36, 35, 33, 31, 29, 27, 25, 24, 23, 22, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 76, 75, 73, 70, 67, 65, 64, /* 0 - 10 */ /* BREATH */ 63, 61, 60, 59, 57, 56, 55, 54, 53, 52, /* 11 - 20 */ 51, 50, 48, 45, 44, 42, 40, 39, 38, 37, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 74, 73, 71, 70, 68, 65, 63, 60, 59, /* 0 - 10 */ /* SPELL */ 58, 56, 55, 54, 53, 51, 50, 49, 48, 47, /* 11 - 20 */ 46, 45, 43, 41, 39, 37, 35, 34, 33, 32, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ }, { /* Ninja */ {90, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, /* 0 - 10 */ /* PARA */ 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, /* 11 - 20 */ 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 68, 66, 64, 62, 60, 58, 56, 54, 52, /* 0 - 10 */ /* ROD */ 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, /* 11 - 20 */ 30, 28, 26, 24, 22, 20, 18, 16, 14, 13, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 60, 59, 58, 58, 56, 55, 54, 53, 52, 51, /* 0 - 10 */ /* PETRI */ 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, /* 11 - 20 */ 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, /* 0 - 10 */ /* BREATH */ 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, /* 11 - 20 */ 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 73, 71, 69, 67, 65, 63, 61, 59, 57, /* 0 - 10 */ /* SPELL */ 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, /* 11 - 20 */ 35, 33, 31, 29, 27, 25, 23, 21, 19, 17, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ }, { /* Dual Class */ {90, 50, 59, 48, 46, 45, 43, 40, 37, 35, 34, /* 0 - 10 */ /* PARA */ 33, 31, 30, 29, 27, 26, 25, 24, 23, 22, /* 11 - 20 */ 21, 20, 18, 15, 14, 12, 10, 9, 8, 7, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 69, 68, 66, 65, 63, 60, 57, 55, 54, /* 0 - 10 */ /* ROD */ 53, 51, 50, 49, 47, 46, 45, 44, 43, 42, /* 11 - 20 */ 41, 40, 38, 35, 34, 32, 30, 29, 28, 27, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 64, 63, 61, 60, 58, 55, 53, 50, 49, /* 0 - 10 */ /* PETRI */ 48, 46, 45, 44, 43, 41, 40, 39, 38, 37, /* 11 - 20 */ 36, 35, 33, 31, 29, 27, 25, 24, 23, 22, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 76, 75, 73, 70, 67, 65, 64, /* 0 - 10 */ /* BREATH */ 63, 61, 60, 59, 57, 56, 55, 54, 53, 52, /* 11 - 20 */ 51, 50, 48, 45, 44, 42, 40, 39, 38, 37, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 74, 73, 71, 70, 68, 65, 63, 60, 59, /* 0 - 10 */ /* SPELL */ 58, 56, 55, 54, 53, 51, 50, 49, 48, 47, /* 11 - 20 */ 46, 45, 43, 41, 39, 37, 35, 34, 33, 32, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ }, { /* Triple Class */ {90, 50, 59, 48, 46, 45, 43, 40, 37, 35, 34, /* 0 - 10 */ /* PARA */ 33, 31, 30, 29, 27, 26, 25, 24, 23, 22, /* 11 - 20 */ 21, 20, 18, 15, 14, 12, 10, 9, 8, 7, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 70, 69, 68, 66, 65, 63, 60, 57, 55, 54, /* 0 - 10 */ /* ROD */ 53, 51, 50, 49, 47, 46, 45, 44, 43, 42, /* 11 - 20 */ 41, 40, 38, 35, 34, 32, 30, 29, 28, 27, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 65, 64, 63, 61, 60, 58, 55, 53, 50, 49, /* 0 - 10 */ /* PETRI */ 48, 46, 45, 44, 43, 41, 40, 39, 38, 37, /* 11 - 20 */ 36, 35, 33, 31, 29, 27, 25, 24, 23, 22, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 80, 79, 78, 76, 75, 73, 70, 67, 65, 64, /* 0 - 10 */ /* BREATH */ 63, 61, 60, 59, 57, 56, 55, 54, 53, 52, /* 11 - 20 */ 51, 50, 48, 45, 44, 42, 40, 39, 38, 37, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 31 - 40 */ {90, 75, 74, 73, 71, 70, 68, 65, 63, 60, 59, /* 0 - 10 */ /* SPELL */ 58, 56, 55, 54, 53, 51, 50, 49, 48, 47, /* 11 - 20 */ 46, 45, 43, 41, 39, 37, 35, 34, 33, 32, /* 21 - 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 31 - 40 */ } }; int mag_savingthrow(struct char_data * ch, int type) { int save; /* negative apply_saving_throw values make saving throws better! */ if (IS_NPC(ch)) /* NPCs use warrior tables according to some book */ save = saving_throws[CLASS_WARRIOR][type][(int) GET_LEVEL(ch)]; else save = saving_throws[(int) GET_CLASS_NUM_FULL(ch)][type][(int) GET_LEVEL(ch)]; save += GET_SAVE(ch, type); /* throwing a 0 is always a failure */ if (MAX(1, save) < number(0, 99)) return TRUE; else return FALSE; } /* affect_update: called from comm.c (causes spells to wear off) */ void affect_update(void) { static struct affected_type *af, *next; static struct char_data *i; extern char *spell_wear_off_msg[]; for (i = character_list; i; i = i->next) for (af = i->affected; af; af = next) { next = af->next; if (af->duration >= 1) af->duration--; else if (af->duration == -1) /* No action */ af->duration = -1; /* GODs only! unlimited */ else { if ((af->type > 0) && (af->type <= MAX_SPELLS)) if (!af->next || (af->next->type != af->type) || (af->next->duration > 0)) if (*spell_wear_off_msg[af->type]) { send_to_char(spell_wear_off_msg[af->type], i); send_to_char("\r\n", i); } affect_remove(i, af); } } } /* * mag_materials: * Checks for up to 3 vnums (spell reagents) in the player's inventory. * * No spells implemented in Circle 3.0 use mag_materials, but you can use * it to implement your own spells which require ingredients (i.e., some * heal spell which requires a rare herb or some such.) */ int mag_materials(struct char_data * ch, int item0, int item1, int item2, int extract, int verbose) { struct obj_data *tobj; struct obj_data *obj0, *obj1, *obj2; for (tobj = ch->carrying; tobj; tobj = tobj->next) { if ((item0 > 0) && (GET_OBJ_VNUM(tobj) == item0)) { obj0 = tobj; item0 = -1; } else if ((item1 > 0) && (GET_OBJ_VNUM(tobj) == item1)) { obj1 = tobj; item1 = -1; } else if ((item2 > 0) && (GET_OBJ_VNUM(tobj) == item2)) { obj2 = tobj; item2 = -1; } } if ((item0 > 0) || (item1 > 0) || (item2 > 0)) { if (verbose) { switch (number(0, 2)) { case 0: send_to_char("A wart sprouts on your nose.\r\n", ch); break; case 1: send_to_char("Your hair falls out in clumps.\r\n", ch); break; case 2: send_to_char("A huge corn develops on your big toe.\r\n", ch); break; } } return (FALSE); } if (extract) { if (item0 < 0) { obj_from_char(obj0); extract_obj(obj0); } if (item1 < 0) { obj_from_char(obj1); extract_obj(obj1); } if (item2 < 0) { obj_from_char(obj2); extract_obj(obj2); } } if (verbose) { send_to_char("A puff of smoke rises from your pack.\r\n", ch); act("A puff of smoke rises from $n's pack.", TRUE, ch, NULL, NULL, TO_ROOM); } return (TRUE); } /* * Every spell that does damage comes through here. This calculates the * amount of damage, adds in any modifiers, determines what the saves are, * tests for save and calls damage(). */ void mag_damage(int level, struct char_data * ch, struct char_data * victim, int spellnum, int savetype) { int is_mage = 0, is_cleric = 0; int dam = 0; if (victim == NULL || ch == NULL) return; is_mage = (IS_MAGIC_USER(ch) || IS_WIZARD(ch)); is_cleric = (IS_CLERIC(ch) || IS_DRUID(ch)); switch (spellnum) { /* Mostly mages */ case SPELL_MAGIC_MISSILE: if (is_mage) dam = dice(MIN(5, lvD4(ch)) , 8) + lvD4(ch); else dam = dice(MIN(5, lvD4(ch)), 6) + lvD4(ch); if (AFF_FLAGGED(victim, AFF_SHIELD)) { send_to_char("Your shield absorbs the magic missile!\r\n", victim); send_to_char("Your magic missile disappears!!\r\n", ch); dam = 0; } break; case SPELL_CHILL_TOUCH: /* chill touch also has an affect */ if (is_mage) dam = dice(1, 8); else dam = dice(1, 6); break; case SPELL_BURNING_HANDS: if (is_mage) dam = dice(1, 6) + MIN(20, GET_LEVEL(ch)); else dam = dice(1, 4) + MIN(20, GET_LEVEL(ch)); break; case SPELL_SHOCKING_GRASP: if (is_mage) dam = dice(1, 8) + GET_LEVEL(ch); else dam = dice(1, 6) + GET_LEVEL(ch); break; case SPELL_LIGHTNING_BOLT: if (is_mage) dam = dice(MIN(10, lvD2(ch)), 8); else dam = dice(MIN(10, lvD2(ch)), 6); break; case SPELL_COLOR_SPRAY: if (is_mage) dam = dice(1, 8) + lvD8(ch); else dam = dice(1, 6) + lvD8(ch); break; case SPELL_FIREBALL: if (is_mage) dam = dice(MIN(12, lvD2(ch)), 8); else dam = dice(MIN(12, lvD2(ch)), 6); break; /* Mostly clerics */ case SPELL_DISPEL_EVIL: dam = dice(lvD4(ch), 8) + (int) (GET_HIT(victim) / 2); if (IS_EVIL(ch)) { victim = ch; dam = GET_HIT(ch) - 1; act("You lift high your unholy symbol against yourself.", FALSE, ch, 0, victim, TO_CHAR); } else if (IS_GOOD(victim)) { act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR); dam = 0; return; } break; case SPELL_DISPEL_GOOD: dam = dice(lvD4(ch), 8) + (int) (GET_HIT(victim) / 2); if (IS_GOOD(ch)) { victim = ch; dam = GET_HIT(ch) - 1; act("You lift high your holy symbol against yourself.", FALSE, ch, 0, victim, TO_CHAR); } else if (IS_EVIL(victim)) { act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR); dam = 0; return; } break; case SPELL_CALL_LIGHTNING: dam = dice((lvD2(ch) + 2), 8); break; case SPELL_HARM: if (GET_LEVEL(victim) < GET_LEVEL(ch)) dam = dice(lvD2(ch), lvD4(ch)); else dam = dice(lvD2(ch), lvD6(ch)); break; case SPELL_ENERGY_DRAIN: if (GET_LEVEL(victim) <= GET_LEVEL(ch)) dam = dice(lvD3(ch), lvD3(ch)); else dam = dice(lvD3(ch), lvD4(ch)); break; case SPELL_ACID_ARROW: dam = dice(lvD3(ch), 4); break; case SPELL_FLAME_ARROW: dam = dice(5*lvD5(ch), 4); break; /* Area spells */ case SPELL_MINUTE_METEOR: dam = dice(lvD5(ch), 6); break; case SPELL_CONE_OF_COLD: dam = dice(MIN(20, GET_LEVEL(ch)), 4); break; case SPELL_AREA_LIGHTNING: dam = dice(MIN(20, GET_LEVEL(ch)), 6); break; case SPELL_EARTHQUAKE: dam = dice(GET_LEVEL(ch), lvD2(ch)); break; case SPELL_FIRE_BREATH: dam = dice(MIN(12, lvD2(ch)), 8); break; case SPELL_GAS_BREATH: dam = dice(lvD2(ch), 12); break; case SPELL_FROST_BREATH: dam = dice(MIN(14, lvD2(ch)), 10); break; case SPELL_ACID_BREATH: dam = dice(MIN(GET_LEVEL(ch), 20), 12);; break; case SPELL_LIGHTNING_BREATH: dam = dice(MIN(10, lvD2(ch)), 8); break; case SPELL_BLADEBARRIER: dam = dice(8,lvD3(ch) + 1); break; } /* switch(spellnum) */ /* divide damage by two if victim makes his saving throw */ if (mag_savingthrow(victim, savetype)) dam >>= 1; /* and finally, inflict the damage */ if (!IS_NPC(ch) && !IS_NPC(victim) && !CAN_MURDER(ch, victim)) act("The Mark of Neutrality protects $N.", FALSE, ch, 0, victim, TO_CHAR); else damage(ch, victim, dam, spellnum); } /* * Every spell that does an affect comes through here. This determines * the effect, whether it is added or replacement, whether it is legal or * not, etc. * * affect_join(vict, aff, add_dur, avg_dur, add_mod, avg_mod) */ void mag_affects(int level, struct char_data * ch, struct char_data * victim, int spellnum, int savetype) { struct affected_type af, af2; int is_mage = FALSE; int is_cleric = FALSE; int accum_affect = FALSE; int accum_duration = FALSE; char *to_vict = NULL; char *to_room = NULL; if (victim == NULL || ch == NULL) return; is_mage = (IS_MAGIC_USER(ch) || IS_WIZARD(ch)); is_cleric = (IS_CLERIC(ch) || IS_DRUID(ch)); af.type = spellnum; af.bitvector = 0; af.bitvector2 = 0; af.bitvector3 = 0; af.modifier = 0; af.location = APPLY_NONE; af2.type = spellnum; af2.bitvector = 0; af2.bitvector2 = 0; af2.bitvector3 = 0; af2.modifier = 0; af2.location = APPLY_NONE; switch (spellnum) { case SPELL_CHILL_TOUCH: if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(victim) && !CAN_MURDER(ch, victim)) { return; } af.location = APPLY_STR; if (mag_savingthrow(victim, savetype)) af.duration = 1; else af.duration = 4; af.modifier = -1; accum_duration = TRUE; to_vict = "You feel your strength wither!"; break; case SPELL_ARMOR: af.location = APPLY_AC; af.modifier = -5 - ((ch == victim) * 15); af.duration = 24; accum_duration = TRUE; to_vict = "You feel someone protecting you."; break; case SPELL_AID: af.bitvector = AFF_PROT_FIRE; af.bitvector2 = AFF2_PROT_COLD; case SPELL_BLESS: af.location = APPLY_HITROLL; af.modifier = 2 + ((ch == victim) * 3); af.duration = 5 + lvD6(ch); af2.location = APPLY_SAVING_SPELL; af2.modifier = -1; af2.duration = 6; to_vict = "You feel righteous."; break; case SPELL_BLINDNESS: if (MOB_FLAGGED(victim,MOB_NOBLIND) || mag_savingthrow(victim, savetype)) { send_to_char("You fail.\r\n", ch); return; } if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(victim) && !CAN_MURDER(ch, victim)) { act("The Mark of Neutrality protects $N.", FALSE, ch, 0, victim, TO_CHAR); return; } af.location = APPLY_HITROLL; af.modifier = -4; af.duration = 2; af.bitvector = AFF_BLIND; af2.location = APPLY_AC; af2.modifier = 40; af2.duration = 2; af2.bitvector = AFF_BLIND; to_room = "$n seems to be blinded!"; to_vict = "You have been blinded!"; break; case SPELL_CURSE: if (mag_savingthrow(victim, savetype)) { send_to_char(NOEFFECT, ch); return; } if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(victim) && !CAN_MURDER(ch, victim)) { act("The Mark of Neutrality protects $N.", FALSE, ch, 0, victim, TO_CHAR); return; } af.location = APPLY_HITROLL; af.duration = 1 + (GET_LEVEL(ch) >> 1); af.modifier = 0 - lvD8(ch); af.bitvector = AFF_CURSE; af2.location = APPLY_DAMROLL; af2.duration = 1 + (GET_LEVEL(ch) >> 1); af2.modifier = 0 - lvD10(ch); af2.bitvector = AFF_CURSE; accum_duration = TRUE; to_room = "$n briefly glows red!"; to_vict = "You feel very uncomfortable."; break; case SPELL_DETECT_ALIGN: af.duration = 12 + level; af.bitvector = AFF_DETECT_ALIGN; accum_duration = TRUE; to_vict = "Your eyes tingle."; break; case SPELL_DETECT_INVIS: af.duration = 12 + level; af.bitvector = AFF_DETECT_INVIS; accum_duration = TRUE; to_vict = "Your eyes tingle."; break; case SPELL_DETECT_MAGIC: af.duration = 12 + level; af.bitvector = AFF_DETECT_MAGIC; accum_duration = TRUE; to_vict = "Your eyes tingle."; break; case SPELL_INFRAVISION: af.duration = 12 + level; af.bitvector = AFF_INFRAVISION; accum_duration = TRUE; to_vict = "Your eyes glow red."; to_room = "$n's eyes glow red."; break; case SPELL_INVISIBLE: if (!victim) victim = ch; af.duration = 12 + (GET_LEVEL(ch) >> 2); af.modifier = -40; af.location = APPLY_AC; af.bitvector = AFF_INVISIBLE; accum_duration = TRUE; to_vict = "You vanish."; to_room = "$n slowly fades out of existence."; break; case SPELL_POISON: if (mag_savingthrow(victim, savetype)) { send_to_char(NOEFFECT, ch); return; } if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(victim) && !CAN_MURDER(ch, victim)) { act("The Mark of Neutrality protects $N.", FALSE, ch, 0, victim, TO_CHAR); break; } af.location = APPLY_STR; af.duration = GET_LEVEL(ch); af.modifier = -2; af.bitvector = AFF_POISON; accum_affect = TRUE; to_vict = "You feel very sick."; to_room = "$n gets violently ill!"; break; case SPELL_PROT_FROM_EVIL: af.duration = 24; af.bitvector = AFF_PROTECT_EVIL; accum_duration = TRUE; to_vict = "You feel invulnerable!"; break; case SPELL_SANCTUARY: af.duration = 4 + (int) (GET_LEVEL(ch) / 5); af.bitvector = AFF_SANCTUARY; to_vict = "A white aura momentarily surrounds you."; to_room = "$n is surrounded by a white aura."; break; case SPELL_SLEEP: if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(victim) && !CAN_MURDER(ch, victim)) return; if (MOB_FLAGGED(victim, MOB_NOSLEEP)) return; if (mag_savingthrow(victim, savetype)) return; af.duration = 4 + (GET_LEVEL(ch) >> 2); af.bitvector = AFF_SLEEP; if (GET_POS(victim) > POS_SLEEPING) { act("You feel very sleepy... Zzzz......", FALSE, victim, 0, 0, TO_CHAR); act("$n goes to sleep.", TRUE, victim, 0, 0, TO_ROOM); GET_POS(victim) = POS_SLEEPING; } break; case SPELL_STRENGTH: af.location = APPLY_STR; af.duration = (GET_LEVEL(ch) >> 1) + 4; af.modifier = 1 + (int)(level / 10); accum_duration = TRUE; accum_affect = TRUE; to_vict = "You feel stronger!"; break; case SPELL_SENSE_LIFE: to_vict = "Your feel your awareness improve."; af.duration = GET_LEVEL(ch); af.bitvector = AFF_SENSE_LIFE; accum_duration = TRUE; break; case SPELL_WATERWALK: af.duration = 24; af.bitvector = AFF_WATERWALK; accum_duration = TRUE; to_vict = "You feel webbing between your toes."; break; case SPELL_FLY: af.duration = 2 + GET_LEVEL(ch); af.modifier = -10; af.location = APPLY_AC; af.bitvector = AFF_FLYING; accum_duration = FALSE; to_vict = "You take off into the air."; to_room = "$n takes off into the air."; break; case SPELL_LEVITATE: af.duration = 8 + GET_LEVEL(ch); af.bitvector = AFF_WATERWALK; af.modifier = -5; af.location = APPLY_AC; accum_duration = TRUE; to_vict = "You start to float off the ground."; to_room = "$n begins to float off the ground."; break; case SPELL_PROT_FIRE: af.duration = 10 + GET_LEVEL(ch); af.bitvector = AFF_PROT_FIRE; accum_duration = FALSE; to_vict = "You feel a shell of insulation form around your body."; break; case SPELL_PROT_COLD: af.duration = 10 + GET_LEVEL(ch); af.bitvector2 = AFF2_PROT_COLD; accum_duration = FALSE; to_vict = "You feel a shell of warmth form around your body."; break; case SPELL_WATERBREATH: af.duration = 24; af.bitvector = AFF_WATERBREATH; accum_duration = FALSE; to_vict = "It feels as if you just sprouted some gills."; break; case SPELL_CONE_OF_COLD: af.duration = 1; af.bitvector2 = AFF2_FREEZING; accum_duration = TRUE; to_vict = "You are consumed with coldness."; to_room = "$n starts shivering."; break; case SPELL_ACID_ARROW: af.duration = 1; af.bitvector2 = AFF2_ACIDED; accum_duration = TRUE; to_vict = "The acid arrow drenches you."; to_room = "$n is drenched by an acid arrow."; break; case SPELL_FLAME_ARROW: af.duration = 1; af.bitvector2 = AFF2_BURNING; accum_duration = TRUE; to_vict = "The flame arrow sets you on fire."; to_room = "$n starts burning."; break; case SPELL_BARKSKIN: af.location = APPLY_AC; af.modifier = -20 - (IS_CLERIC(ch) * 20); af.duration = lvD5(ch); to_vict = "You feel your skin hardening."; break; case SPELL_STONESKIN: af.location = APPLY_AC; af.modifier = -40; af.duration = lvD8(ch); af.bitvector = AFF_SILVER; af.bitvector2 = AFF2_STONESKIN; to_vict = "You feel your skin turn into granite."; break; case SPELL_MIRROR_IMAGE: af.duration = 6; af.bitvector2 = AFF2_MIRRORIMAGE; af.location = APPLY_AC; af.modifier = -15; to_vict = "Your image breaks up!"; to_room = "$n breaks up into many images!!!"; break; case SPELL_BLINK: af.duration = 6; af.bitvector2 = AFF2_BLINK; to_vict = "You don't feel any different."; to_room = "You see $n shift a few feet away."; break; case SPELL_SHIELD: af.duration = MAX(1, lvD4(ch)); af.bitvector = AFF_SHIELD; to_vict = "You create a force shield."; to_room = "A force shield surrounds $n."; af.location = APPLY_AC; af.modifier = -10; break; case SPELL_DEATHDANCE: af.duration = 24; af.bitvector = AFF_DEATHDANCE; to_vict = "You feel your life take on a whole new meaning...."; to_room = "A wave of death dances forth from $n."; break; case SPELL_WRAITHFORM: af.duration = 8; af.bitvector3 = AFF3_PASSDOOR; to_vict = "You turn translucent!"; to_room = "$n turns translucent!"; break; case SPELL_FIRE_BREATH: af.duration = 1; af.bitvector2 = AFF2_BURNING; accum_duration = TRUE; to_vict = "You are engulfed in flames."; to_room = "$n is engulfed in flames."; break; case SPELL_FROST_BREATH: af.duration = 1; af.bitvector2 = AFF2_FREEZING; accum_duration = TRUE; to_vict = "You are consumed with coldness."; to_room = "$n starts shivering."; break; case SPELL_ACID_BREATH: af.duration = 1; af.bitvector2 = AFF2_ACIDED; accum_duration = TRUE; to_vict = "You are drenched in acid."; to_room = "$n drops some acid."; break; case SPELL_BURN: af.duration = 1; af.bitvector2 = AFF2_BURNING; accum_duration = TRUE; to_vict = "You are engulfed in flames."; to_room = "$n is engulfed in flames."; break; case SPELL_FREEZE: af.duration = 1; af.bitvector2 = AFF2_FREEZING; accum_duration = TRUE; to_vict = "You are consumed with coldness."; to_room = "$n starts shivering."; break; case SPELL_ACID: af.duration = 1; af.bitvector2 = AFF2_ACIDED; accum_duration = TRUE; to_vict = "You are drenched in acid."; to_room = "$n drops some acid."; break; case SPELL_CRIT_HIT: af.duration = 2; af.bitvector2 = AFF2_CRIT_HIT; accum_duration = FALSE; to_vict = "You bleed from a fatal wound."; to_room = "$n bleeds from a fatal wound."; break; case SPELL_ENH_HEAL: af.duration = 24; af.bitvector2 = AFF2_ENH_HEAL; to_vict = "You feel much healthier."; break; case SPELL_ENH_MANA: af.duration = 24; af.bitvector2 = AFF2_ENH_MANA; to_vict = "You feel much more intuned to the flow of mana."; break; case SPELL_ENH_MOVE: af.duration = 24; af.bitvector2 = AFF2_ENH_MOVE; to_vict = "You feel much more restful."; break; /* end of spells */ } /* * If this is a mob that has this affect set in its mob file, do not * perform the affect. This prevents people from un-sancting mobs * by sancting them and waiting for it to fade, for example. */ if (IS_NPC(victim) && (IS_AFFECTED(victim, af.bitvector|af2.bitvector) || IS_SET(AFF2_FLAGS(victim), af.bitvector2|af2.bitvector2) || IS_SET(AFF3_FLAGS(victim), af.bitvector3|af2.bitvector3)) && !affected_by_spell(victim, spellnum)) { send_to_char(NOEFFECT, ch); return; } /* * If the victim is already affected by this spell, and the spell does * not have an accumulative effect, then fail the spell. */ if (affected_by_spell(victim,spellnum) && !(accum_duration||accum_affect)) { send_to_char(NOEFFECT, ch); return; } affect_join(victim, &af, accum_duration, FALSE, accum_affect, FALSE); if (af2.bitvector || af2.location) affect_join(victim, &af2, accum_duration, FALSE, accum_affect, FALSE); if (to_vict != NULL) act(to_vict, FALSE, victim, 0, ch, TO_CHAR); if (to_room != NULL) act(to_room, TRUE, victim, 0, ch, TO_ROOM); } /* * This function is used to provide services to mag_groups. This function * is the one you should change to add new group spells. */ void perform_mag_groups(int level, struct char_data * ch, struct char_data * tch, int spellnum, int savetype) { switch (spellnum) { case SPELL_GROUP_HEAL: mag_points(level, ch, tch, SPELL_HEAL, savetype); break; case SPELL_GROUP_ARMOR: mag_affects(level, ch, tch, SPELL_ARMOR, savetype); break; case SPELL_GROUP_RECALL: spell_recall(level, ch, tch, NULL); break; case SPELL_GROUP_FLY: mag_affects(level, ch, tch, SPELL_FLY, savetype); break; case SPELL_GROUP_INVIS: mag_affects(level, ch, tch, SPELL_INVISIBLE, savetype); break; case SPELL_GROUP_PROT_EVIL: mag_affects(level, ch, tch, SPELL_PROT_FROM_EVIL, savetype); break; case SPELL_GROUP_WATBREATH: mag_affects(level, ch, tch, SPELL_WATERBREATH, savetype); break; } } /* * Every spell that affects the group should run through here * perform_mag_groups contains the switch statement to send us to the right * magic. * * group spells affect everyone grouped with the caster who is in the room, * caster last. * * To add new group spells, you shouldn't have to change anything in * mag_groups -- just add a new case to perform_mag_groups. */ void mag_groups(int level, struct char_data * ch, int spellnum, int savetype) { struct char_data *tch, *k; struct follow_type *f, *f_next; if (ch == NULL) return; if (!IS_AFFECTED(ch, AFF_GROUP)) return; if (ch->master != NULL) k = ch->master; else k = ch; for (f = k->followers; f; f = f_next) { f_next = f->next; tch = f->follower; if (tch->in_room != ch->in_room) continue; if (!IS_AFFECTED(tch, AFF_GROUP)) continue; if (ch == tch) continue; perform_mag_groups(level, ch, tch, spellnum, savetype); } if ((k != ch) && IS_AFFECTED(k, AFF_GROUP)) perform_mag_groups(level, ch, k, spellnum, savetype); perform_mag_groups(level, ch, ch, spellnum, savetype); } /* * mass spells affect every creature in the room except the caster. * * No spells of this class currently implemented as of Circle 3.0. */ void mag_masses(int level, struct char_data * ch, int spellnum, int savetype) { struct char_data *tch, *tch_next; for (tch = world[ch->in_room].people; tch; tch = tch_next) { tch_next = tch->next_in_room; if (tch == ch) continue; switch (spellnum) { } } } /* * Every spell that affects an area (room) runs through here. These are * generally offensive spells. This calls mag_damage to do the actual * damage -- all spells listed here must also have a case in mag_damage() * in order for them to work. * * area spells have limited targets within the room. */ void mag_areas(byte level, struct char_data * ch, int spellnum, int savetype) { struct char_data *tch, *next_tch; char *to_char = NULL; char *to_room = NULL; if (ch == NULL) return; /* * to add spells to this fn, just add the message here plus an entry * in mag_damage for the damaging part of the spell. */ switch (spellnum) { case SPELL_EARTHQUAKE: to_char = "You gesture and the earth begins to shake all around you!"; to_room ="$n gracefully gestures and the earth begins to shake violently!"; break; case SPELL_FIRE_BREATH: to_room ="With a draconian roar, $n breaths fire into the room!"; to_char = "With a draconian roar, you toast everything in the room!"; break; case SPELL_GAS_BREATH: to_room ="With a roar, $n fills the room with deadly vapors!"; to_char ="You cast a deadly spell, filling the room with vapors from hell!"; break; case SPELL_FROST_BREATH: to_room ="With a mighty roar, $n freezes everyone with a breath of ice!"; to_char ="You roar, filling the room with a deadly stream of ice!"; break; case SPELL_ACID_BREATH: to_room ="Spittle stream forth from the mouth of $n, eroding everything!"; to_char ="You breath acid into the room!"; break; case SPELL_LIGHTNING_BREATH: to_room ="$n roars, spraying bolts of electricity everywhere!"; to_char ="You open your mouth and generate enough electricity to power Capitol for ten years!"; break; case SPELL_CONE_OF_COLD: to_room ="$n launches a deadly cone of super-cooled air!"; to_char ="You aim your cone of cold."; break; case SPELL_AREA_LIGHTNING: to_room ="With an almost fural scream, $n conjures a chain of lightning!"; to_char ="You carefully flip on the switch to your UPS and focus the extra energy toward your enemies!"; break; case SPELL_BLADEBARRIER: to_room ="$n laughs and attempts to put up a BLADE BARRIER!"; to_char ="You concentrate on swords. Swords. SWORDS!!!"; break; } if (to_char != NULL) act(to_char, FALSE, ch, 0, 0, TO_CHAR); if (to_room != NULL) act(to_room, FALSE, ch, 0, 0, TO_ROOM); for (tch = world[ch->in_room].people; tch; tch = next_tch) { next_tch = tch->next_in_room; /* * The skips: 1: the caster * 2: immortals * 3: if no pk on this mud, skips over all players * 4: pets (charmed NPCs) * players can only hit players in CRIMEOK rooms 4) players can only hit * charmed mobs in CRIMEOK rooms */ if (tch == ch) continue; if (ROOM_FLAGGED(ch->in_room, ROOM_PEACEFUL)) continue; if (!IS_NPC(tch) && GET_LEVEL(tch) >= LVL_IMMORT) continue; if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(tch) && !CAN_MURDER(ch, tch)) continue; if (!IS_NPC(ch) && IS_NPC(tch) && IS_AFFECTED(tch, AFF_CHARM)) continue; mag_damage(GET_LEVEL(ch), ch, tch, spellnum, 1); } } void mag_points(int level, struct char_data * ch, struct char_data * victim, int spellnum, int savetype) { int hit = 0; int move = 0; if (victim == NULL) return; switch (spellnum) { case SPELL_CURE_LIGHT: hit = dice(1, 8) + 1 + lvD2(ch); send_to_char("You feel better.\r\n", victim); break; case SPELL_CURE_SERIOUS: hit = dice(3, 8) + 3 + lvD2(ch); send_to_char("You feel much better!\r\n", victim); break; case SPELL_CURE_CRITIC: hit = dice(8, 8) + 3 + lvD2(ch); send_to_char("You feel a lot better!\r\n", victim); break; case SPELL_HEAL: hit = 100 + dice(3, 8) + lvD2(ch); send_to_char("A warm feeling floods your body.\r\n", victim); break; case SPELL_DEATHDANCE: hit = 0 - (GET_MAX_HIT(victim) / 2); move = 0 - (GET_MAX_MOVE(victim) / 4); break; } GET_HIT(victim) = MIN(GET_MAX_HIT(victim), GET_HIT(victim) + hit); GET_MOVE(victim) = MIN(GET_MAX_MOVE(victim), GET_MOVE(victim) + move); } void mag_unaffects(int level, struct char_data * ch, struct char_data * victim, int spellnum, int type) { int spell = 0; char *to_vict = NULL, *to_room = NULL; if (victim == NULL) return; switch (spellnum) { case SPELL_CURE_BLIND: case SPELL_HEAL: spell = SPELL_BLINDNESS; to_vict = "Your vision returns!"; to_room = "There's a momentary gleam in $n's eyes."; break; case SPELL_REMOVE_POISON: spell = SPELL_POISON; to_vict = "A warm feeling runs through your body!"; to_room = "$n looks better."; break; case SPELL_REMOVE_CURSE: spell = SPELL_CURSE; to_vict = "You don't feel so unlucky."; break; default: sprintf(buf, "SYSERR: unknown spellnum %d passed to mag_unaffects", spellnum); log(buf); return; break; } if (!affected_by_spell(victim, spell)) { send_to_char(NOEFFECT, ch); return; } affect_from_char(victim, spell); if (to_vict != NULL) act(to_vict, FALSE, victim, 0, ch, TO_CHAR); if (to_room != NULL) act(to_room, TRUE, victim, 0, ch, TO_ROOM); } void mag_alter_objs(int level, struct char_data * ch, struct obj_data * obj, int spellnum, int savetype) { char *to_char = NULL; char *to_room = NULL; if (obj == NULL) return; switch (spellnum) { case SPELL_BLESS: if (!IS_OBJ_STAT(obj, ITEM_BLESS) && (GET_OBJ_WEIGHT(obj) <= 5 * GET_LEVEL(ch))) { SET_BIT(GET_OBJ_EXTRA(obj), ITEM_BLESS); to_char = "$p glows briefly."; } break; case SPELL_CURSE: if (!IS_OBJ_STAT(obj, ITEM_NODROP)) { SET_BIT(GET_OBJ_EXTRA(obj), ITEM_NODROP); if (GET_OBJ_TYPE(obj) == ITEM_WEAPON) GET_OBJ_VAL(obj, 2)--; to_char = "$p briefly glows red."; } break; case SPELL_INVISIBLE: if (!IS_OBJ_STAT(obj, ITEM_NOINVIS | ITEM_INVISIBLE)) { SET_BIT(obj->obj_flags.extra_flags, ITEM_INVISIBLE); to_char = "$p vanishes."; } break; case SPELL_POISON: if (((GET_OBJ_TYPE(obj) == ITEM_DRINKCON) || (GET_OBJ_TYPE(obj) == ITEM_FOUNTAIN) || (GET_OBJ_TYPE(obj) == ITEM_FOOD)) && !GET_OBJ_VAL(obj, 3)) { GET_OBJ_VAL(obj, 3) = 1; to_char = "$p steams briefly."; } break; case SPELL_REMOVE_CURSE: if (IS_OBJ_STAT(obj, ITEM_NODROP)) { REMOVE_BIT(obj->obj_flags.extra_flags, ITEM_NODROP); if (GET_OBJ_TYPE(obj) == ITEM_WEAPON) GET_OBJ_VAL(obj, 2)++; to_char = "$p briefly glows blue."; } break; case SPELL_REMOVE_POISON: if (((GET_OBJ_TYPE(obj) == ITEM_DRINKCON) || (GET_OBJ_TYPE(obj) == ITEM_FOUNTAIN) || (GET_OBJ_TYPE(obj) == ITEM_FOOD)) && GET_OBJ_VAL(obj, 3)) { GET_OBJ_VAL(obj, 3) = 0; to_char = "$p steams briefly."; } break; } if (to_char == NULL) send_to_char(NOEFFECT, ch); else act(to_char, TRUE, ch, obj, 0, TO_CHAR); if (to_room != NULL) act(to_room, TRUE, ch, obj, 0, TO_ROOM); else if (to_char != NULL) act(to_char, TRUE, ch, obj, 0, TO_ROOM); } void mag_creations(int level, struct char_data * ch, int spellnum) { struct obj_data *tobj; int z; if (ch == NULL) return; level = MAX(MIN(level, LVL_IMPL), 1); switch (spellnum) { case SPELL_CREATE_FOOD: z = 10; break; default: send_to_char("Spell unimplemented, it would seem.\r\n", ch); return; break; } if (!(tobj = read_object(z, VIRTUAL))) { send_to_char("I seem to have goofed.\r\n", ch); sprintf(buf, "SYSERR: spell_creations, spell %d, obj %d: obj not found", spellnum, z); log(buf); return; } obj_to_char(tobj, ch); act("$n creates $p.", FALSE, ch, tobj, 0, TO_ROOM); act("You create $p.", FALSE, ch, tobj, 0, TO_CHAR); } /* Every spell which summons/gates/conjours a mob comes through here. None of these spells are currently implemented in Circle 3.0; these were taken as examples from the JediMUD code. Summons can be used for spells like clone, ariel servant, etc. */ static char *mag_summon_msgs[] = { "\r\n", "$n makes a strange magical gesture; you feel a strong breeze!\r\n", "$n animates a corpse!\r\n", "$N appears from a cloud of thick blue smoke!\r\n", "$N appears from a cloud of thick green smoke!\r\n", "$N appears from a cloud of thick red smoke!\r\n", "$N disappears in a thick black cloud!\r\n" "As $n makes a strange magical gesture, you feel a strong breeze.\r\n", "As $n makes a strange magical gesture, you feel a searing heat.\r\n", "As $n makes a strange magical gesture, you feel a sudden chill.\r\n", "As $n makes a strange magical gesture, you feel the dust swirl.\r\n", "$n magically divides!\r\n", "$n animates a corpse!\r\n" }; #define MOB_MONSUM_I 4020 /* lesser level */ #define MOB_MONSUM_II 4020 /* regular */ #define MOB_MONSUM_III 4020 /* greater */ #define MOB_MONSUM_IV 4020 /* dragon */ #define MOB_MONSUM_V 4020 /* ancient */ #define MOB_GATE_I 4020 #define MOB_GATE_II 4020 #define MOB_GATE_III 4020 #define MOB_ELEMENTAL_BASE 4020 #define MOB_CLONE 4020 #define MOB_ZOMBIE 1176 #define MOB_AERIALSERVANT 4020 static char *mag_summon_fail_msgs[] = { "\r\n", "There are no such creatures.\r\n", "Uh oh...\r\n", "Oh dear.\r\n", "Oh shit!\r\n", "The elements resist!\r\n", "You failed.\r\n", "There is no corpse!\r\n" }; void mag_summons(int level, struct char_data * ch, struct obj_data * obj, int spellnum, int savetype) { struct char_data *mob; struct obj_data *tobj, *next_obj; int pfail = 0; int msg = 0, fmsg = 0; int mob_num = 0; int change_mob = 0; int handle_corpse = 0; char mob_name[256]; char mob_sdes[256]; if (ch == NULL) return; switch (spellnum) { case SPELL_ANIMATE_DEAD: if ((obj == NULL) || (GET_OBJ_TYPE(obj) != ITEM_CONTAINER) || (!GET_OBJ_VAL(obj, 3))) { act(mag_summon_fail_msgs[7], FALSE, ch, 0, 0, TO_CHAR); return; } handle_corpse = 1; change_mob = 1; msg = 15; mob_num = MOB_ZOMBIE; pfail = 8; strcpy(mob_name, (obj)->short_description); strcpy(mob_sdes, (obj)->short_description); break; case SPELL_MONSUM_I: msg = 4; mob_num = MOB_MONSUM_I; pfail = 20; change_mob = 0; break; case SPELL_MONSUM_II: msg = 4; mob_num = MOB_MONSUM_II; pfail = 20; change_mob = 0; break; case SPELL_MONSUM_III: msg = 4; mob_num = MOB_MONSUM_III; pfail = 20; change_mob = 0; break; case SPELL_MONSUM_IV: msg = 4; mob_num = MOB_MONSUM_IV; pfail = 20; change_mob = 0; break; case SPELL_MONSUM_V: msg = 4; mob_num = MOB_MONSUM_V; pfail = 20; change_mob = 0; break; case SPELL_CONJ_ELEMENTAL: msg = 4; mob_num = MOB_ELEMENTAL_BASE; pfail = 20; change_mob = 0; break; case SPELL_CLONE: mob_num = MOB_CLONE; pfail = 20; strcpy(mob_name, GET_NAME(ch)); strcpy(mob_sdes, GET_NAME(ch)); change_mob = 1; break; default: return; } if (IS_AFFECTED(ch, AFF_CHARM)) { send_to_char("You are too giddy to have any followers!\r\n", ch); return; } if (number(0, 101) < pfail) { send_to_char(mag_summon_fail_msgs[fmsg], ch); return; } if (!(mob = read_mobile(real_mobile(mob_num), REAL))) { send_to_char("I seem to have goofed.\r\n", ch); sprintf(buf, "SYSERR: spell_summons, spell %d, mob %d: mob not found", spellnum, mob_num); log(buf); return; } char_to_room(mob, ch->in_room); IS_CARRYING_W(mob) = 0; IS_CARRYING_N(mob) = 0; SET_BIT(AFF_FLAGS(mob), AFF_CHARM); SET_BIT(MOB_FLAGS(mob), MOB_PET); add_follower(mob, ch); act(mag_summon_msgs[fmsg], FALSE, ch, 0, mob, TO_ROOM); if (change_mob) { mob->player.name = strdup(mob_name); mob->player.short_descr = strdup(mob_sdes); sprintf(mob_sdes, "%s is standing here.\r\n", mob_sdes); mob->player.long_descr = strdup(mob_sdes); } if (handle_corpse) { for (tobj = obj->contains; tobj; tobj = next_obj) { next_obj = tobj->next_content; obj_from_obj(tobj); obj_to_char(tobj, mob); } extract_obj(obj); } }