/* Treasure Chests and Lockpicks */ /* Here's a piece of code that may throw some confusion into your * MUD. Human mobiles may drop a treasure chest when they are struck * down, offering players the opportunity to pick them up and pick * them with a lockpick, gathering wealth and power beyond their * wildest imaginations... * * Ok, so it really just tosses a few coins and gems in a box and * lets players have something to do with their spare time. */ /* This is what I'd consider to be a moderately difficult snippet * to add. You have to edit a few different files, including the * Makefile, add a new item type, and set up a shop to sell the * new item type. * * AWW is a ROM based MUD, and this snippet is pulled from it. It * should work with any Diku style base with a bit of tweaking. * As usual, I cant garauntee it will work for you, but if you * have troubles with it, I will try to help. * * Dalsor, aka Eric * dalsor@cfl.rr.com */ /* Files to edit: */ /* * merc.h, mud.h, or whatever your main header is. * Add the following somewhere in the #defines for item types. */ #define ITEM_TREASURECHEST 45 /* for treasure code -Dal */ #define ITEM_LOCKPICK 46 /* used for picking locks */ /* Add these pretty much anywhere you like. */ #define stc send_to_char #define ptc printf_to_char #define TRAP_BOOMER (A) #define TRAP_GASSER (B) #define TRAP_BLADE (C) #define TRAP_NEEDLE (D) #define TRAP_MANA (E) #define TRAP_FIRE (F) #define TRAP_ACID (G) /* In act_info.c or where you have your do_look function, add * the following in the 'in' switch. Right before or right * after the CONTAINER case is a good spot. */ case ITEM_TREASURECHEST: if ( IS_SET(obj->value[1], CONT_CLOSED) ) { stc( "It is closed.\n\r", ch ); break; } act( "$p holds:", ch, obj, NULL, TO_CHAR ); show_list_to_char( obj->contains, ch, TRUE, TRUE ); break; /* In act_obj, or where you have your do_get function, add * the following mess of code. Feel free to remove the junk * for pits... I dont use em, but am too lazy to remove it. * Put this in the get all switch for container->item_type * somewhere near the CONTAINER case. */ case ITEM_TREASURECHEST: if ( IS_SET(container->value[1], CONT_CLOSED) ) { act( "{cThe $d is closed.", ch, NULL, container->name, TO_CHAR ); return; } if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) ) { /* 'get obj container' */ obj = get_obj_list( ch, arg1, container->contains ); if ( obj == NULL ) { act( "{cI see nothing like that in the $T.",ch, NULL, arg2, TO_CHAR ); return; } get_obj( ch, obj, container ); } else { /* 'get all container' or 'get all.obj container' */ found = FALSE; for ( obj = container->contains; obj != NULL; obj = obj_next ) { obj_next = obj->next_content; if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) ) && can_see_obj( ch, obj ) ) { found = TRUE; if (container->pIndexData->vnum == OBJ_VNUM_PIT && !IS_IMMORTAL(ch)) { stc( "{cDon't be so greedy!\n\r",ch); return; } get_obj( ch, obj, container ); } } if ( !found ) { if ( arg1[3] == '\0' ) act( "{cI see nothing in the $T.",ch, NULL, arg2, TO_CHAR ); else act( "{cI see nothing like that in the $T.",ch, NULL, arg2, TO_CHAR ); } return; } /* in do_put, add some redundancy to see if the character is putting * something in a valid container. Hackish, yes, I know... Put this * right before the check for CONT_CLOSED */ if ( container->item_type != ITEM_CONTAINER ) { if ( container->item_type != ITEM_TREASURECHEST ) { stc( "{cThat's not a container.\n\r", ch ); return; } } /* And after the check for can_drop_obj in the same function... */ if ( obj->item_type == ITEM_TREASURECHEST ) { stc( "{cCannot put a container in a treasure chest.\n\r",ch); return; } if ( obj->item_type == ITEM_TREASURECHEST && container->item_type == ITEM_TREASURECHEST ) { stc( "{cCannot put a treasure chest in a treasure chest.\n\r",ch); return; } /* Now in act_move, or where your do_open function is, add this before * where is checks for CONT_CLOSED */ if ( obj->item_type != ITEM_CONTAINER ) { if ( obj->item_type != ITEM_TREASURECHEST ) { stc( "{cThat's not a container.\n\r{c", ch ); return; } } /* Now add this right after the check for CONT_LOCKED, just a few * lines below. If you really want to get dirty, replace the BOOM * line with a damage function, inflict some poison, chop off a * limb, or some other good wholesome fun. This is in here in case * we ever get around to making characters disarm the boxes before * they pick them. */ if ( obj->item_type == ITEM_TREASURECHEST ) { if ( obj->value[3] > 0 ) stc("BOOM! hehehe.\n\r",ch); } /* In do_close, add the following code right before the check for * CONT_CLOSED */ if ( obj->item_type != ITEM_CONTAINER ) { if ( obj->item_type != ITEM_TREASURECHEST ) { stc( "{cThat's not a container.\n\r{c", ch ); return; } } /* In do_lock, add this before the check for CONT_CLOSED */ if ( obj->item_type != ITEM_CONTAINER ) { if ( obj->item_type != ITEM_TREASURECHEST ) { stc( "{cThat's not a container.\n\r{c", ch ); return; } } /* In do_unlock, add this before the check for ITEM_CONTAINER and CONT_CLOSED */ if ( obj->item_type == ITEM_TREASURECHEST ) { stc( "{cYou unlock the treasure chest.\n\r{c", ch ); stc( "{cWe now check to see if it's trapped, and if so, if it's disarmed.\n\r{c", ch ); stc( "{cIf not, make loud scary noises and go boom!\n\r{c", ch ); return; } /* In do_pick, add the following (look familiar?) before CONT_CLOSED */ if ( obj->item_type != ITEM_CONTAINER ) { if ( obj->item_type != ITEM_TREASURECHEST ) { stc( "{cThat's not a container.\n\r{c", ch ); return; } } /* And then right after CONT_PICKPROOF, add the following. If you decide not * to make lock picking a skill, remove the checks for it. If you do not have * a REFLEX stat, replace it with DEXTERITY or whatever. If you need to debug * it, remove the comments from ptc. You can add the lockpicking element to * your DEX struct if need be, or well, it's your code, do whatever you want * to with it. :) */ if ( obj->item_type == ITEM_TREASURECHEST ) { int lock_diff = obj->value[2]; int result = number_range(chance*8/12,chance)+ref_app[get_curr_stat(ch,STAT_REF)].lockpicking; result += pick->condition / 10; if ( result < lock_diff ) { ptc(ch,"You attempt to pick the lock on %s, but fail.\n\r",obj->short_descr); /*ptc(ch,"Result was %d chance, and you needed to go over %d lock_diff.\n\r", result, lock_diff);*/ obj->value[2] -= ref_app[get_curr_stat(ch,STAT_REF)].lockpicking / 10; if ( number_percent() > number_percent() + ref_app[get_curr_stat(ch,STAT_REF)].lockpicking ) { act("You wince as you feel your lockpick bend inside the lock.",ch,NULL,NULL,TO_CHAR); act("You hear a wince from $n as $e tests $s skill at lockpicking.",ch,NULL,NULL,TO_ROOM); pick->condition -= number_range(1,3); if ( pick->condition < 1 ) { act("With a *snap* your lockpick breaks off inside the lock.",ch,NULL,NULL,TO_CHAR); act("You hear a *snap* and a muttered curse from $n as $s lockpick breaks in two.",ch,NULL,NULL,TO_ROOM); extract_obj ( pick ); } } check_improve(ch,gsn_pick_lock,FALSE,9); return; } } /* If you use auction code, I would recomment placing a check in it when people * get info on an auctioned item so they will know if it's empty or not. Do this * to foil slackers who try to auction boxes that contain nada. */ case ITEM_TREASURECHEST: if ( obj->contains == NULL ) stc("The treasure chest is empty, unfortunately.\n\r",ch); break; /* In const.c add the following two lines to the item_type struct */ { ITEM_TREASURECHEST, "treasurechest"}, { ITEM_LOCKPICK, "lockpick" }, /* In db.c add these two lines under ITEM_FOUNTAIN in create_object */ case ITEM_TREASURECHEST: case ITEM_LOCKPICK: /* In fight.c somewhere near the top, but after the declarations, * add this function, but make sure to change it to reflect your * human race names. */ void make_treasure_chest args( ( CHAR_DATA *ch, CHAR_DATA *victim, int level ) ); bool is_human( CHAR_DATA *ch ) { if (!IS_NPC(ch)) return FALSE; if (ch->race == race_lookup("andor") || ch->race == race_lookup("amador") || ch->race == race_lookup("illian") || ch->race == race_lookup("shienar") || ch->race == race_lookup("domani") || ch->race == race_lookup("aiel") || ch->race == race_lookup("ogier") || ch->race == race_lookup("tairen") || ch->race == race_lookup("cairhien") || ch->race == race_lookup("seanchan") || ch->race == race_lookup("altara") || ch->race == race_lookup("trolloc") || ch->race == race_lookup("tarvalon") || ch->race == race_lookup("arafel") || ch->race == race_lookup("tarabon") || ch->race == race_lookup("kandor") || ch->race == race_lookup("mayene") || ch->race == race_lookup("tworiver") || ch->race == race_lookup("malkier")) return TRUE; else return FALSE; } /* Again in fight.c in damage, after the person is dead, let's check * to see if they drop a treasure chest. */ int chance = number_percent(); int chance_diff = number_range(1,victim->level) / 2; if ( chance < chance_diff ) { if (is_human(victim) && !IS_NPC(ch)) { make_treasure_chest(ch, victim, victim->level); } } /* In handler.c, in item_type_name, add these two lines. */ case ITEM_TREASURECHEST: return "treasure chest"; case ITEM_LOCKPICK: return "lockpick"; /* In olc_act.c in show_obj_values, add this. You dont have * to do this, since you really dont want your builders making * treasure chests, but it is here to give you an idea of what * the v#s look like for the chest objects. */ case ITEM_TREASURECHEST: ptc(ch, "{C[{cv0{C]{c Silver: {C[{c%d{C]{c\n\r" "{C[{cv1{C]{c Flags: {C[{c%s{C]{c\n\r" "{C[{cv2{C]{c Lock Diff: %s {C[{c%d{C]{c\n\r" "{C[{cv3{C]{c Trap Type {C[{c%d{C]{c\n\r" "{C[{cv4{C]{c Trap Dmg {C[{c%d{C]{c\n\r", obj->value[0], flag_string( container_flags, obj->value[1] ), obj->value[2], obj->value[3], obj->value[4] ); break; case ITEM_LOCKPICK: ptc(ch, "{C[{cv0{C]{c Strength: {C[{c%d{C] {c1-100\n\r", obj->value[0]); break; /* After this, you're gonna want to upload the two files random.c * and treasure2.c * Put the .o includes in your Makefile and make CLEAN! * Make a new shop somewhere in your MUD and let the shopkeep sell * lockpicks for a reasonable sum. * * I dont think I've left anything out, but chances are I did. If * you have troubles, remember the email address at the top. */