/*
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 <types.h>
#include <time.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#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!