/* This is the third release of my take on traps. It is updated and a bit more thorough than the first couple attempts. If you have any questions or comments please direct them to drew.haley@gmail.com. I know this will work on a basic QuickMUD / Rom 2.4 base, should also go pretty easily in envy, smaug and other close relatives. This release includes the code for additional spells/skills (Detect Traps (mage), Remove Trap (thief), Find Traps (a passive thief skill), and Lay Trap (thief)). */ ____________________________________________________________________________________ /* Merc.h */ //Ok First off I added a new item type for this, which is ITEM_THIEVES_TOOLS, which is required to //lay/remove traps. In order to do this, add this line to merc.h: #define ITEM_THIEVES_TOOLS 39 //used for lock picking, trap setting/disarming, etc.. //Of course it may not be item type 39 in your mud, keep that in mind. Also remember to edit tables.c/db.c //with the new item type. //In merc.h, under these lines: #define ITEM_BURN_PROOF (Y) #define ITEM_NOUNCURSE (Z) //Add these: #define ITEM_FIRE_TRAP (aa) #define ITEM_GAS_TRAP (bb) #define ITEM_POISON_TRAP (cc) #define ITEM_DART_TRAP (dd) //Increase MAX_SKILLS by four. //Also, I use a macro for send_to_char, you might do the same: #define SEND send_to_char //Put these with the rest of your gsns: extern sh_int gsn_find_trap; extern sh_int gsn_detect_trap; __________________________________________________________________________________ /* Const.c */ //You will need to add entries for detect trap, find trap, remove trap, and lay trap. __________________________________________________________________________________ /* Act_info.c */ //In local functions, add this: bool is_trapped args((OBJ_DATA *obj)); //Then, in format_obj_to_char, add these lines: if (get_skill(ch, gsn_find_trap) > 0 && !is_affected(ch, gsn_detect_traps)) { if (number_percent() < get_skill(ch, gsn_find_trap)) { if (is_trapped(obj)) { strcat (buf, "({CTrapped{x) "); check_improve (ch, gsn_find_trap, TRUE, 4); } } } if (is_affected(ch, gsn_detect_traps) && is_trapped(obj)) strcat (buf, "({CTrapped{x) "); _____________________________________________________________________________________ /* Act_obj.c */ //Add these to your local functions: void remove_trap args((OBJ_DATA *obj)); void spring_trap args((CHAR_DATA *ch, OBJ_DATA *obj)); bool is_trapped args((OBJ_DATA *obj)); void lay_trap args((OBJ_DATA *obj, int type)); //Then at the bottom of the file add this: bool has_thieves_tools(CHAR_DATA *ch) { OBJ_DATA *obj; bool found = FALSE; for (obj = ch->carrying; obj != NULL; obj = obj->next_content) { if (obj->item_type == ITEM_THIEVES_TOOLS && can_see_obj (ch, obj)) { found = TRUE; break; } } return found; } //This just sets a dart trap by default but you can always expand it to do others. void do_set_trap(CHAR_DATA *ch, char *argument) { OBJ_DATA *obj; int chance = 0; char arg1[MSL]; int trap_type = -1; one_argument(argument, arg1); if (arg1[0] == '\0') { SEND("Lay trap in/on what?\r\n", ch); return; } if ((obj = get_obj_here (ch, arg1)) == NULL || !can_see_obj(ch,obj)) { SEND("You don't see that object here.\r\n",ch); return; } else { if(get_skill(ch,gsn_lay_trap) < 1) { SEND ("You don't know how to lay traps.\r\n",ch); return; } if (!has_thieves_tools(ch)) { SEND ("You need some sort of tool to do that!\r\n",ch); return; } if (obj->item_type != ITEM_CONTAINER) { SEND ("That's not a container.\r\n", ch); return; } if (is_trapped(obj)) { SEND ("That item already has a trap on it.\r\n",ch); return; } trap_type = DART_TRAP; chance = number_percent(); if (obj->level > ch->level) chance += (obj->level - ch->level) * 2; if (get_curr_stat(ch, STAT_DEX) > 15) chance -= 25 - get_curr_stat(ch, STAT_DEX); if (chance < get_skill(ch,gsn_lay_trap)) { lay_trap(obj, trap_type); act( "$n successfully places a trap on $p.\r\n", ch, obj, NULL, TO_ROOM ); act( "You successfully place a trap on $p.\r\n", ch, obj, NULL, TO_CHAR ); check_improve(ch,gsn_lay_trap,TRUE,3); return; } else { act( "$n failed to place a trap on $p.\r\n", ch, obj, NULL, TO_ROOM ); act( "You failed to place a trap on $p.\r\n", ch, obj, NULL, TO_CHAR ); return; } } return; } //Also, in wear_obj, after these lines: if (ch->level < obj->level) { sprintf (buf, "You must be level %d to use this object.\n\r", obj->level); send_to_char (buf, ch); act ("$n tries to use $p, but is too inexperienced.", ch, obj, NULL, TO_ROOM); return; } //Add this to prevent people seeing weirdness in their eq command: //We obviously don't want people wearing trapped objects. if (is_trapped(obj)) spring_trap(ch,obj); _________________________________________________________________________________________________ /* Magic.c */ // Add this: void spell_detect_traps (int sn, int level, CHAR_DATA *ch, void *vo, int target) { CHAR_DATA *victim = (CHAR_DATA *) vo; AFFECT_DATA af; if (victim != ch) { SEND("You can only cast that on yourself.\n\r",ch); return; } if (is_affected(ch, gsn_detect_traps)) { SEND("You already sense traps.\n\r",ch); return; } af.where = TO_AFFECTS; af.type = sn; af.level = level; af.duration = level; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = gsn_detect_traps; affect_to_char (victim, &af); send_to_char ("You feel an inner sense of traps.\r\n", victim); return; } __________________________________________________________________________________________________ /* Magic.h */ DECLARE_SPELL_FUN( spell_detect_traps ); __________________________________________________________________________________________________ /* Act_move.c */ //At the top, add these: //Trap functions bool is_trapped args((OBJ_DATA *obj)); int get_trap_type args((OBJ_DATA *obj)); void remove_trap args((OBJ_DATA *obj)); void spring_trap args((CHAR_DATA *victim, OBJ_DATA *obj)); bool save_vs_trap args((CHAR_DATA *ch, OBJ_DATA *obj)); //Then under these lines: REMOVE_BIT (obj->value[1], CONT_CLOSED); act ("You open $p.", ch, obj, NULL, TO_CHAR); act ("$n opens $p.", ch, obj, NULL, TO_ROOM); //Add these lines: //This is the code that fires the traps themselves. You can always add this to other places, //but I only put it for containers (treasure boxes and whatnot). if (is_trapped(obj)) { if (!save_vs_trap(ch, obj)) { spring_trap(ch, obj); remove_trap(obj); return; } else { SEND ("You got lucky... the trap failed to spring.\r\n", ch); remove_trap(obj); return; } } __________________________________________________________________________________________ /* Tables.c */ //Underneath these lines: {"burnproof", ITEM_BURN_PROOF, TRUE}, {"nouncurse", ITEM_NOUNCURSE, TRUE}, //Add these lines: {"fire_trap", ITEM_FIRE_TRAP, TRUE}, {"poison_trap", ITEM_POISON_TRAP, TRUE}, {"gas_trap", ITEM_GAS_TRAP, TRUE}, {"dart_trap", ITEM_DART_TRAP, TRUE}, __________________________________________________________________________________________ /* Traps.c */ //Then make a new file called traps.c, and add all of the following to it: /*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik Strfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments 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. * * * * Thanks to abaddon for proof-reading our comm.c and pointing out bugs. * * Any remaining bugs are, of course, our work, not his. :) * * * * Much time and thought has gone into this software and you are * * benefitting. 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 * ****************************************************************************/ #if defined(macintosh) #include #include #else #include #include #endif #include #include #include #include "merc.h" #include "interp.h" void raw_kill args ((CHAR_DATA * victim)); int get_trap_type(OBJ_DATA *obj) { int type = 0; if (IS_SET(obj->extra_flags, ITEM_FIRE_TRAP)) type = FIRE_TRAP; if (IS_SET(obj->extra_flags, ITEM_POISON_TRAP)) type = POISON_TRAP; if (IS_SET(obj->extra_flags, ITEM_GAS_TRAP)) type = GAS_TRAP; if (IS_SET(obj->extra_flags, ITEM_DART_TRAP)) type = DART_TRAP; return type; } void lay_trap(OBJ_DATA *obj, int type) { switch (type) { default: return; case FIRE_TRAP: SET_BIT (obj->extra_flags, ITEM_FIRE_TRAP); case POISON_TRAP: SET_BIT (obj->extra_flags, ITEM_POISON_TRAP); case GAS_TRAP: SET_BIT (obj->extra_flags, ITEM_GAS_TRAP); case DART_TRAP: SET_BIT (obj->extra_flags, ITEM_DART_TRAP); } return; } void remove_trap(OBJ_DATA *obj) { int type; type = get_trap_type(obj); switch (type) { default: return; case FIRE_TRAP: REMOVE_BIT (obj->extra_flags, ITEM_FIRE_TRAP); case POISON_TRAP: REMOVE_BIT (obj->extra_flags, ITEM_POISON_TRAP); case GAS_TRAP: REMOVE_BIT (obj->extra_flags, ITEM_GAS_TRAP); case DART_TRAP: REMOVE_BIT (obj->extra_flags, ITEM_DART_TRAP); } return; } bool save_vs_trap(CHAR_DATA *ch, OBJ_DATA *obj) { int trap_type = 0; int reaction = 0, difficulty = 15; trap_type = get_trap_type(obj); switch (trap_type) { case FIRE_TRAP: difficulty += 5; case POISON_TRAP: difficulty += 3; case GAS_TRAP: difficulty += 8; case DART_TRAP: difficulty += 2; default: difficulty = 15; } difficulty += number_range(1,4); //add a little randomness to it. reaction = number_range(1,20); //roll a reaction. if (trap_type == POISON_TRAP || trap_type == DART_TRAP) { if (get_curr_stat(ch, STAT_DEX) < 15) reaction -= ((get_curr_stat(ch, STAT_DEX) - 25) / 2); //max neg. of 12 w/ a Dex of 1. if (get_curr_stat(ch, STAT_DEX) > 15) reaction += ((get_curr_stat(ch, STAT_DEX)) / 5); //max bonus of 5 at Dex 25. } if (trap_type == FIRE_TRAP) { if (get_curr_stat(ch, STAT_INT) > 15) reaction += ((get_curr_stat(ch, STAT_INT)) / 5); //max bonus of 5 at Int 25. } if (reaction >= difficulty) return TRUE; else return FALSE; } bool is_trapped(OBJ_DATA *obj) { if (IS_SET(obj->extra_flags, ITEM_FIRE_TRAP) || IS_SET(obj->extra_flags, ITEM_POISON_TRAP) || IS_SET(obj->extra_flags, ITEM_GAS_TRAP) || IS_SET(obj->extra_flags, ITEM_DART_TRAP)) return TRUE; else return FALSE; } void spring_trap(CHAR_DATA *victim, OBJ_DATA *obj) { int trap_type = 0; int dam = 0; char buf[MAX_STRING_LENGTH]; AFFECT_DATA af; trap_type = get_trap_type(obj); switch (trap_type) { default: SEND ("You got lucky... the trap failed to spring.\n\r", victim); return; case FIRE_TRAP: dam = dice(6,8) + 5; act ("A gout of flames shoots forth, searing $n!", victim, NULL, NULL, TO_ROOM); sprintf( buf, "A gout of flames shoots forth, searing you! {r[{x%d{r]{x\r\n", dam ); remove_trap(obj); SEND(buf, victim); victim->hit -= dam; if (victim->hit <= 0) raw_kill(victim); return; case POISON_TRAP: dam = dice(4,8) + 5; act ("A poison dart springs forth, striking $n!", victim, NULL, NULL, TO_ROOM); sprintf( buf, "A poison dart springs forth, striking you! {r[{x%d{r]{x\r\n", dam ); remove_trap(obj); SEND(buf, victim); af.where = TO_AFFECTS; af.type = gsn_poison; af.level = number_range(25,40); af.duration = number_range(25,40); af.location = APPLY_STR; af.modifier = -2; af.bitvector = AFF_POISON; affect_join (victim, &af); SEND ("You feel very sick.\n\r", victim); act ("$n looks very ill.", victim, NULL, NULL, TO_ROOM); victim->hit -= dam; if (victim->hit <= 0) raw_kill(victim); return; case GAS_TRAP: dam = dice(3,8) + 5; act ("A cloud of gas seeps out, choking $n!", victim, NULL, NULL, TO_ROOM); sprintf( buf, "A cloud of gas seeps out, choking you! {r[{x%d{r]{x\r\n", dam ); remove_trap(obj); SEND(buf, victim); victim->hit -= dam; if (victim->hit <= 0) raw_kill(victim); return; case DART_TRAP: dam = dice(3,8) + 5; act ("A spring loaded dart leaps out, stabbing $n!", victim, NULL, NULL, TO_ROOM); sprintf( buf, "A spring loaded dart leaps out, stabbing you! {r[{x%d{r]{x\r\n", dam ); remove_trap(obj); SEND(buf, victim); victim->hit -= dam; if (victim->hit <= 0) raw_kill(victim); return; } return; } ___________________________________________________________________________________________________ //Ok that's it! You should now be able to do a clean compile and start trapping things all over your mud! //Things I might add in the future are a spell to trap an object (think explosive runes), and trap difficulty //(for disarming them and such). Email me if you have any issues with this code and I'll try to help you finger //it out. Thanks for checking it out!