/************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefiting. We hope that you share your changes too. What goes * * around, comes around. * *************************************************************************** * ROM 2.4 is copyright 1993-1998 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@hypercube.org) * * Gabrielle Taylor (gtaylor@hypercube.org) * * Brian Moore (zump@rom.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * *************************************************************************** * 1stMud ROM Derivative (c) 2001-2004 by Markanth * * http://www.firstmud.com/ <markanth@firstmud.com> * * By using this code you have agreed to follow the term of * * the 1stMud license in ../doc/1stMud/LICENSE * ***************************************************************************/ #include "merc.h" #include "recycle.h" void acid_effect (void *vo, int level, int dam, int target) { if (target == TARGET_ROOM) { RoomIndex *room = (RoomIndex *) vo; ObjData *obj, *obj_next; for (obj = room->content_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; acid_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_CHAR) { CharData *victim = (CharData *) vo; ObjData *obj, *obj_next; for (obj = victim->carrying_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; acid_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_OBJ) { ObjData *obj = (ObjData *) vo; ObjData *t_obj, *n_obj; int chance; char *msg; if (IsObjStat (obj, ITEM_BURN_PROOF) || IsObjStat (obj, ITEM_NOPURGE) || number_range (0, 4) == 0) return; chance = level / 4 + dam / 10; if (chance > 25) chance = (chance - 25) / 2 + 25; if (chance > 50) chance = (chance - 50) / 2 + 50; if (IsObjStat (obj, ITEM_BLESS)) chance -= 5; chance -= obj->level * 2; switch (obj->item_type) { default: return; case ITEM_CONTAINER: case ITEM_CORPSE_PC: case ITEM_CORPSE_NPC: msg = "$p fumes and dissolves."; break; case ITEM_ARMOR: msg = "$p is pitted and etched."; break; case ITEM_CLOTHING: msg = "$p is corroded into scrap."; break; case ITEM_STAFF: case ITEM_WAND: chance -= 10; msg = "$p corrodes and breaks."; break; case ITEM_SCROLL: chance += 10; msg = "$p is burned into waste."; break; } chance = Range (5, chance, 95); if (number_percent () > chance) return; if (obj->carried_by != NULL) act (msg, obj->carried_by, obj, NULL, TO_ALL); else if (obj->in_room != NULL && obj->in_room->person_first != NULL) act (msg, obj->in_room->person_first, obj, NULL, TO_ALL); if (obj->item_type == ITEM_ARMOR) { AffectData *paf; bool af_found = false; int i; affect_enchant (obj); for (paf = obj->affect_first; paf != NULL; paf = paf->next) { if (paf->location == APPLY_AC) { af_found = true; paf->type = -1; paf->modifier += 1; paf->level = Max (paf->level, level); break; } } if (!af_found) { paf = new_affect (); paf->type = -1; paf->level = level; paf->duration = -1; paf->location = APPLY_AC; paf->modifier = 1; paf->bitvector = 0; Link (paf, obj->affect, next, prev); } if (obj->carried_by != NULL && obj->wear_loc != WEAR_NONE) for (i = 0; i < MAX_AC; i++) obj->carried_by->armor[i] += 1; return; } if (obj->content_first) { for (t_obj = obj->content_first; t_obj != NULL; t_obj = n_obj) { n_obj = t_obj->next_content; obj_from_obj (t_obj); if (obj->in_room != NULL) obj_to_room (t_obj, obj->in_room); else if (obj->carried_by != NULL) obj_to_room (t_obj, obj->carried_by->in_room); else { extract_obj (t_obj); continue; } acid_effect (t_obj, level / 2, dam / 2, TARGET_OBJ); } } extract_obj (obj); return; } } void cold_effect (void *vo, int level, int dam, int target) { if (target == TARGET_ROOM) { RoomIndex *room = (RoomIndex *) vo; ObjData *obj, *obj_next; for (obj = room->content_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; cold_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_CHAR) { CharData *victim = (CharData *) vo; ObjData *obj, *obj_next; if (!saves_spell (level / 4 + dam / 20, victim, DAM_COLD)) { AffectData af; act ("$n turns blue and shivers.", victim, NULL, NULL, TO_ROOM); act ("A chill sinks deep into your bones.", victim, NULL, NULL, TO_CHAR); af.where = TO_AFFECTS; af.type = skill_lookup ("chill touch"); af.level = level; af.duration = 6; af.location = APPLY_STR; af.modifier = -1; af.bitvector = 0; affect_join (victim, &af); } if (!IsNPC (victim)) gain_condition (victim, COND_HUNGER, dam / 20); for (obj = victim->carrying_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; cold_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_OBJ) { ObjData *obj = (ObjData *) vo; int chance; char *msg; if (IsObjStat (obj, ITEM_BURN_PROOF) || IsObjStat (obj, ITEM_NOPURGE) || number_range (0, 4) == 0) return; chance = level / 4 + dam / 10; if (chance > 25) chance = (chance - 25) / 2 + 25; if (chance > 50) chance = (chance - 50) / 2 + 50; if (IsObjStat (obj, ITEM_BLESS)) chance -= 5; chance -= obj->level * 2; switch (obj->item_type) { default: return; case ITEM_POTION: msg = "$p freezes and shatters!"; chance += 25; break; case ITEM_DRINK_CON: msg = "$p freezes and shatters!"; chance += 5; break; } chance = Range (5, chance, 95); if (number_percent () > chance) return; if (obj->carried_by != NULL) act (msg, obj->carried_by, obj, NULL, TO_ALL); else if (obj->in_room != NULL && obj->in_room->person_first != NULL) act (msg, obj->in_room->person_first, obj, NULL, TO_ALL); extract_obj (obj); return; } } void fire_effect (void *vo, int level, int dam, int target) { if (target == TARGET_ROOM) { RoomIndex *room = (RoomIndex *) vo; ObjData *obj, *obj_next; for (obj = room->content_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; fire_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_CHAR) { CharData *victim = (CharData *) vo; ObjData *obj, *obj_next; if (!IsAffected (victim, AFF_BLIND) && !saves_spell (level / 4 + dam / 20, victim, DAM_FIRE)) { AffectData af; act ("$n is blinded by smoke!", victim, NULL, NULL, TO_ROOM); act ("Your eyes tear up from smoke...you can't see a thing!", victim, NULL, NULL, TO_CHAR); af.where = TO_AFFECTS; af.type = skill_lookup ("fire breath"); af.level = level; af.duration = number_range (0, level / 10); af.location = APPLY_HITROLL; af.modifier = -4; af.bitvector = AFF_BLIND; affect_to_char (victim, &af); } if (!IsNPC (victim)) gain_condition (victim, COND_THIRST, dam / 20); for (obj = victim->carrying_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; fire_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_OBJ) { ObjData *obj = (ObjData *) vo; ObjData *t_obj, *n_obj; int chance; char *msg; if (IsObjStat (obj, ITEM_BURN_PROOF) || IsObjStat (obj, ITEM_NOPURGE) || number_range (0, 4) == 0) return; chance = level / 4 + dam / 10; if (chance > 25) chance = (chance - 25) / 2 + 25; if (chance > 50) chance = (chance - 50) / 2 + 50; if (IsObjStat (obj, ITEM_BLESS)) chance -= 5; chance -= obj->level * 2; switch (obj->item_type) { default: return; case ITEM_CONTAINER: msg = "$p ignites and burns!"; break; case ITEM_POTION: chance += 25; msg = "$p bubbles and boils!"; break; case ITEM_SCROLL: chance += 50; msg = "$p crackles and burns!"; break; case ITEM_STAFF: chance += 10; msg = "$p smokes and chars!"; break; case ITEM_WAND: msg = "$p sparks and sputters!"; break; case ITEM_FOOD: msg = "$p blackens and crisps!"; break; case ITEM_PILL: msg = "$p melts and drips!"; break; } chance = Range (5, chance, 95); if (number_percent () > chance) return; if (obj->carried_by != NULL) act (msg, obj->carried_by, obj, NULL, TO_ALL); else if (obj->in_room != NULL && obj->in_room->person_first != NULL) act (msg, obj->in_room->person_first, obj, NULL, TO_ALL); if (obj->content_first) { for (t_obj = obj->content_first; t_obj != NULL; t_obj = n_obj) { n_obj = t_obj->next_content; obj_from_obj (t_obj); if (obj->in_room != NULL) obj_to_room (t_obj, obj->in_room); else if (obj->carried_by != NULL) obj_to_room (t_obj, obj->carried_by->in_room); else { extract_obj (t_obj); continue; } fire_effect (t_obj, level / 2, dam / 2, TARGET_OBJ); } } extract_obj (obj); return; } } void poison_effect (void *vo, int level, int dam, int target) { if (target == TARGET_ROOM) { RoomIndex *room = (RoomIndex *) vo; ObjData *obj, *obj_next; for (obj = room->content_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; poison_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_CHAR) { CharData *victim = (CharData *) vo; ObjData *obj, *obj_next; if (!saves_spell (level / 4 + dam / 20, victim, DAM_POISON)) { AffectData af; chprintln (victim, "You feel poison coursing through your veins."); act ("$n looks very ill.", victim, NULL, NULL, TO_ROOM); af.where = TO_AFFECTS; af.type = gsn_poison; af.level = level; af.duration = level / 2; af.location = APPLY_STR; af.modifier = -1; af.bitvector = AFF_POISON; affect_join (victim, &af); } for (obj = victim->carrying_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; poison_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_OBJ) { ObjData *obj = (ObjData *) vo; int chance; if (IsObjStat (obj, ITEM_BURN_PROOF) || IsObjStat (obj, ITEM_BLESS) || number_range (0, 4) == 0) return; chance = level / 4 + dam / 10; if (chance > 25) chance = (chance - 25) / 2 + 25; if (chance > 50) chance = (chance - 50) / 2 + 50; chance -= obj->level * 2; switch (obj->item_type) { default: return; case ITEM_FOOD: break; case ITEM_DRINK_CON: if (obj->value[0] == obj->value[1]) return; break; } chance = Range (5, chance, 95); if (number_percent () > chance) return; obj->value[3] = 1; return; } } void shock_effect (void *vo, int level, int dam, int target) { if (target == TARGET_ROOM) { RoomIndex *room = (RoomIndex *) vo; ObjData *obj, *obj_next; for (obj = room->content_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; shock_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_CHAR) { CharData *victim = (CharData *) vo; ObjData *obj, *obj_next; if (!saves_spell (level / 4 + dam / 20, victim, DAM_LIGHTNING)) { chprintln (victim, "Your muscles stop responding."); DazeState (victim, Max (12, level / 4 + dam / 20)); } for (obj = victim->carrying_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; shock_effect (obj, level, dam, TARGET_OBJ); } return; } if (target == TARGET_OBJ) { ObjData *obj = (ObjData *) vo; int chance; char *msg; if (IsObjStat (obj, ITEM_BURN_PROOF) || IsObjStat (obj, ITEM_NOPURGE) || number_range (0, 4) == 0) return; chance = level / 4 + dam / 10; if (chance > 25) chance = (chance - 25) / 2 + 25; if (chance > 50) chance = (chance - 50) / 2 + 50; if (IsObjStat (obj, ITEM_BLESS)) chance -= 5; chance -= obj->level * 2; switch (obj->item_type) { default: return; case ITEM_WAND: case ITEM_STAFF: chance += 10; msg = "$p overloads and explodes!"; break; case ITEM_JEWELRY: chance -= 10; msg = "$p is fused into a worthless lump."; } chance = Range (5, chance, 95); if (number_percent () > chance) return; if (obj->carried_by != NULL) act (msg, obj->carried_by, obj, NULL, TO_ALL); else if (obj->in_room != NULL && obj->in_room->person_first != NULL) act (msg, obj->in_room->person_first, obj, NULL, TO_ALL); extract_obj (obj); return; } }