/*___________________________________________________________________________* )()( DalekenMUD 1.12 (C) 2000 )()( `][' by Martin Thomson, Lee Brooks, `][' || Ken Herbert and David Jacques || || ----------------------------------------------------------------- || || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, || || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse. || || Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael || || Chastain, Michael Quan, and Mitchell Tse. || || Original Diku Mud copyright (C) 1990, 1991 || || by Sebastian Hammer, Michael Seifert, Hans Henrik St{rfeldt, || || Tom Madsen, and Katja Nyboe. || || ----------------------------------------------------------------- || || Any use of this software must follow the licenses of the || || creators. 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. || || ----------------------------------------------------------------- || || mob_commands.c || || Special commands for use in MUDPrograms. Based on N'Atas-ha's || || MOBPrograms and SMAUG's MUDPrograms. || *_/<>\_________________________________________________________________/<>\_*/ #include "mud.h" #include "event.h" /* * Local functions. */ void mp_force_sub args( ( CHAR_DATA *ch, const char *argument, bool quiet ) ); /* * Display the MudPrograms and variables present. */ void append_progs( BUFFER *buf, MPROG_DATA *mprg, const char *argument, MPROG_VAR *var ) { int num = 0; int argnum = -1; bool sh = FALSE; if( argument[0] != '\0' ) { if( is_number( argument ) ) argnum = atoi( argument ); else if( !str_cmp( argument, "short" ) ) sh = TRUE; else sh = TRUE; } for( ; mprg; mprg = mprg->next, num++ ) { if( argnum >= 0 && num != argnum ) continue; bprintf( buf, "[%3d] %-20s", num, flag_string( mud_prog_flags, &mprg->type ) ); bprintf( buf, "arg-[%s]\n\r", mprg->arglist ); if( sh ) continue; bprintf( buf, "%s\n\r", mprg->comlist ); if( argnum >= 0 ) break; } num = 0; for( ; argnum < 0 && var; var = var->next ) { if( num++ == 0 ) buffer_strcat( buf, "Variables:\n\r" ); bprintf( buf, "%s = %s\n\r", var->name, var->value ); } if( argnum >= 0 && !mprg ) { buffer_clear( buf ); buffer_strcat( buf, "No such Program found.\n\r" ); } } void do_mpstat( CHAR_DATA *ch, const char *argument ) { BUFFER *buf; char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; argument = one_argument( argument, arg ); if( arg[0] == '\0' ) { send_to_char( "MobProg stat whom?\n\r", ch ); return; } if( ( victim = get_char_world( ch, arg ) ) == NULL ) { send_to_char( "They aren't here.\n\r", ch ); return; } if( !IS_NPC( victim ) ) { send_to_char( "Only Mobiles can have Programs!\n\r", ch ); return; } if( !( victim->pIndexData->mudprogs ) ) { send_to_char( "That Mobile has no Programs set.\n\r", ch ); return; } buf = buffer_new( MAX_STRING_LENGTH ); bprintf( buf, "Name: %s. Vnum: %d.\n\r", victim->name, victim->pIndexData->vnum ); bprintf( buf, "Short description: %s.\n\rLong description: %s", victim->short_descr, victim->long_descr[0] != '\0' ? victim->long_descr : "(none).\n\r" ); bprintf( buf, "Hp: %d/%d. Mana: %d/%d. Move: %d/%d. \n\r", victim->hit, victim->max_hit, total_mana( victim->mana ), total_mana( victim->max_mana ), victim->move, victim->max_move ); bprintf( buf, "Lv: %d. Class: %d. Align: %d. Gold: %d.\n\r", victim->level, victim->class, victim->alignment, victim->gold ); append_progs( buf, victim->pIndexData->mudprogs, argument, victim->variables ); send_to_char( buf->data, ch ); buffer_free( buf ); return; } void do_opstat( CHAR_DATA *ch, const char *argument ) { BUFFER *buf; char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; argument = one_argument( argument, arg ); if( arg[0] == '\0' ) { send_to_char( "ObjProg stat which?\n\r", ch ); return; } if( ( obj = get_obj_here( ch, arg ) ) == NULL ) { send_to_char( "That isn't here.\n\r", ch ); return; } if( !( obj->pIndexData->mudprogs ) ) { send_to_char( "That Object has no Programs set.\n\r", ch ); return; } buf = buffer_new( MAX_STRING_LENGTH ); bprintf( buf, "Name: %s. Vnum: %d. Level: %d.\n\r", obj->name, obj->pIndexData->vnum, obj->level ); bprintf( buf, "Short description: %s.\n\r", obj->short_descr ); append_progs( buf, obj->pIndexData->mudprogs, argument, obj->variables ); send_to_char( buf->data, ch ); buffer_free( buf ); return; } void do_rpstat( CHAR_DATA *ch, const char *argument ) { BUFFER *buf; ROOM_INDEX_DATA *room; room = ch->in_room; if( !( room->mudprogs ) ) { send_to_char( "This room has no Programs set.\n\r", ch ); return; } buf = buffer_new( MAX_STRING_LENGTH ); bprintf( buf, "Name: %s. Vnum: %d.\n\r", room->name, room->vnum ); append_progs( buf, room->mudprogs, argument, room->variables ); send_to_char( buf->data, ch ); buffer_free( buf ); return; } /* * This command allows access to all the funky commands in this file * through the mudprog interpreter. It is important to note that the * check against players using this is on descriptor. This has the * benefit of allowing mobprograms, through mp_qforce, make players run * these commands, huge flexibility advantages, no loopholes forseen, yet! * * However, * Utmost care at all times please. --Symposium */ void do_mpcomm( CHAR_DATA *ch, const char *argument ) { if( ch->desc ) { send_to_char( "You commune with the mobiles, how boring.\n\r", ch ); return; } if( !prog_only_cmnd( ch, argument ) ) progbug( ch, "bad mpcommand" ); return; } /* prints the message to the room at large */ void mp_aecho( CHAR_DATA *ch, const char *argument ) { DESCRIPTOR_DATA *d; if( argument[0] == '\0' ) { progbug( ch, "aecho - called w/o argument." ); return; } for( d = descriptor_list; d; d = d->next ) { if( !IS_SET( d->interpreter->flags, INTERPRETER_NOMESSAGE ) && ch->in_room->area == d->character->in_room->area && IS_AWAKE( d->character ) ) act( argument, ch, NULL, d->character, TO_VICT ); } return; } /* prints the argument to all the rooms aroud the mobile */ void mp_asound( CHAR_DATA *ch, const char *argument ) { ROOM_INDEX_DATA *was_in_room; int door; if( argument[0] == '\0' ) { progbug( ch, "Mpasound - No argument." ); return; } was_in_room = ch->in_room; for( door = 0; door <= 5; door++ ) { EXIT_DATA *pexit; if( ( pexit = was_in_room->exit[door] ) != NULL && pexit->to_room != NULL && pexit->to_room != was_in_room ) { ch->in_room = pexit->to_room; REMOVE_BIT( SysInfo->flags, SYSINFO_ACT_TRIGGER ); act( argument, ch, NULL, NULL, TO_ROOM ); } } ch->in_room = was_in_room; return; } /* Lets the mobile do a command at another location. Very useful */ void mp_at( CHAR_DATA *ch, const char *argument ) { char arg[MAX_INPUT_LENGTH]; ROOM_INDEX_DATA *location; ROOM_INDEX_DATA *original; OBJ_DATA *orig_on; CHAR_DATA *wch; argument = one_argument( argument, arg ); if( arg[0] == '\0' || argument[0] == '\0' ) { progbug( ch, "Mpat - Bad argument: %s %s.", arg, argument ); return; } if( ( location = find_location( ch, arg ) ) == NULL ) { progbug( ch, "Mpat - No such location: %s.", arg ); return; } original = ch->in_room; orig_on = ch->on; char_from_room( ch ); char_to_room( ch, location ); if( !prog_only_cmnd( ch, argument ) ) interpret( ch, argument ); /* * See if 'ch' still exists before continuing! * Handles 'at XXXX quit' case. */ for( wch = char_list; wch != NULL; wch = wch->next ) { if( wch == ch && !wch->deleted ) { char_from_room( ch ); char_to_room( ch, original ); ch->on = orig_on; break; } } return; } /* Hides the mobile quite effectively, mobile only */ void mp_burrow( CHAR_DATA *ch, const char *argument ) { if( IS_NPC( ch ) ) xSET_BIT( ch->act, ACT_BURIED ); } void mp_damage( CHAR_DATA *ch, const char *argument ) { char buf[MAX_INPUT_LENGTH]; char arg1[MAX_INPUT_LENGTH]; CHAR_DATA *victim; CHAR_DATA *nextinroom; int dam; int already_fighting = FALSE; argument = one_argument( argument, arg1 ); if ( !str_cmp( arg1, "all" ) ) { for( victim = ch->in_room->people; victim; victim = nextinroom ) { nextinroom = victim->next_in_room; if( victim != ch && can_see( ch, victim ) ) { sprintf( buf, "'%s' %s", name_expand( arg1, victim ), argument ); mp_damage( ch, buf ); } } return; } if( argument[0] == '\0' ) { progbug( ch, "Mpdamage: no damage amount given." ); return; } if( ( victim = get_char_room( ch, arg1 ) ) == NULL ) { progbug( ch, "Mpdamage: victim not in room." ); return; } if( victim == ch ) { progbug( ch, "Mpdamage: trying to damage self." ); return; } dam = atoi( argument ); if( ( dam < 0) || ( dam > 32000 ) ) { progbug( ch, "Mpdamage: invalid (nonexistent?) argument: %s" ); return; } if( ch->fighting ) already_fighting = TRUE; damage( ch, victim, dam, TYPE_MPDAMAGE, WEAR_NONE ); if( already_fighting ) stop_fighting( ch, TRUE ); return; } /* * Either lag PC characters (not all that useful). * or delay an NPC that will allow it to trigger a delay_prog. */ void mp_delay( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *victim; char arg[MAX_INPUT_LENGTH]; int val; EVENT *e; argument = one_argument( argument, arg ); if( !*arg ) victim = ch; else if( !( victim = get_char_world( ch, arg ) ) ) return; val = atoi( argument ); if( val < 0 ) { progbug( ch, "Bad mp_delay argument: %s %s.", arg, argument ); return; } if( IS_NPC( victim ) ) { if( victim->pIndexData->vnum == MOB_VNUM_SUPERMOB ) { progbug( ch, "Trying to delay supermob.", arg, argument ); return; } if( xIS_SET( victim->pIndexData->progtypes, DELAY_PROG ) ) { e = create_char_event( victim, evn_prog_trigger, val ); e->data[0] = DELAY_PROG; } } victim->wait = val; return; } /* * Deposit some gold into the current area's economy -Thoric */ void mp_deposit( CHAR_DATA *ch, const char *argument ) { int gold; if( argument[0] == '\0' ) { progbug( ch, "deposit - bad syntax" ); return; } gold = atoi( argument ); if( gold <= ch->gold && ch->in_room ) { ch->gold -= gold; ch->in_room->area->economy += gold; } } /* * Withdraw some gold from the current area's economy -Thoric */ void mp_withdraw( CHAR_DATA *ch, const char *argument ) { int gold; if( argument[0] == '\0' ) { progbug( ch, "withdraw - bad syntax" ); return; } gold = atoi( argument ); if( ch->gold < 1000000000 && gold < 1000000000 && ch->in_room && ch->in_room->area->economy >= gold ) { ch->gold += gold; ch->in_room->area -= gold; } } void mp_dream( CHAR_DATA *ch, const char *argument ) { char arg1[MAX_STRING_LENGTH]; CHAR_DATA *vict; argument = one_argument( argument, arg1 ); if( ( vict = get_char_world( ch, arg1 ) ) == NULL ) { progbug( ch, "Mpdream: No such character" ); return; } if( vict->position <= POS_SLEEPING ) { send_to_char( argument, vict ); send_to_char( "\n\r", vict ); } return; } /* prints the message to the room at large */ void mp_echo( CHAR_DATA *ch, const char *argument ) { if( argument[0] == '\0' ) { progbug( ch, "echo - called w/o argument." ); return; } act( argument, ch, NULL, NULL, TO_ROOM ); return; } /* prints the message to everyone in the room other than the mob and victim */ void mp_echoaround( CHAR_DATA *ch, const char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; argument = one_argument( argument, arg ); if( arg[0] == '\0' ) { progbug( ch, "echoaround - No argument." ); return; } if( !( victim = get_char_room( ch, arg ) ) ) { progbug( ch, "echoaround - victim does not exist: %s.", arg ); return; } act( argument, ch, NULL, victim, TO_NOTVICT ); return; } /* prints the message to only the victim */ void mp_echoat( CHAR_DATA *ch, const char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; argument = one_argument( argument, arg ); if( arg[0] == '\0' || argument[0] == '\0' ) { progbug( ch, "echoat - No argument." ); return; } if( !( victim = get_char_room( ch, arg ) ) ) { progbug( ch, "echoat - victim does not exist: %s.", arg ); return; } act( argument, ch, NULL, victim, TO_VICT ); return; } void mp_force_sub( CHAR_DATA *ch, const char *argument, bool quiet ) { char arg[MAX_INPUT_LENGTH]; DESCRIPTOR_DATA *d; argument = one_argument( argument, arg ); if( arg[0] == '\0' || argument[0] == '\0' ) { progbug( ch, "Mp[q]force - Bad syntax: %s %s.",arg, argument ); return; } if( !str_cmp( arg, "all" ) ) { CHAR_DATA *vch; CHAR_DATA *vch_next; for( vch = char_list; vch != NULL; vch = vch_next ) { vch_next = vch->next; if( vch->in_room == ch->in_room && get_trust( vch ) < get_trust( ch ) && can_see( ch, vch ) ) { d = vch->desc; if( quiet ) vch->desc = NULL; if( !quiet || !prog_only_cmnd( vch, argument ) ) interpret( vch, argument ); vch->desc = d; } } } else { CHAR_DATA *victim; if( ( victim = get_char_room( ch, arg ) ) == NULL ) { progbug( ch, "Mp[q]force - No such victim." ); return; } if( victim == ch ) { progbug( ch, "Mp[q]force - Forcing oneself." ); return; } d = victim->desc; if( quiet ) victim->desc = NULL; if( !quiet || !prog_only_cmnd( victim, argument ) ) interpret( victim, argument ); victim->desc = d; } return; } /* * Lets the mobile force someone to do something. Must be mortal level * and the all argument only affects those in the room with the mobile. * * Note: additionally this force command allows the character access to * the extra commands commands in this file, either through mp_comm or * directly. * --Symposium */ void mp_qforce( CHAR_DATA *ch, const char *argument ) { mp_force_sub( ch, argument, TRUE ); } /* Standard force, no tricks allowed */ void mp_force( CHAR_DATA *ch, const char *argument ) { mp_force_sub( ch, argument, FALSE ); } /* Lets the mobile goto any location it wishes that is not private */ void mp_goto( CHAR_DATA *ch, const char *argument ) { char arg[MAX_INPUT_LENGTH]; ROOM_INDEX_DATA *location; one_argument( argument, arg ); if( arg[0] == '\0' ) { progbug( ch, "Mpgoto - No argument." ); return; } if( ( location = find_location( ch, arg ) ) == NULL ) { progbug( ch, "Mpgoto - No such location: %s.", arg ); return; } if( ch->fighting != NULL ) stop_fighting( ch, TRUE ); char_from_room( ch ); char_to_room( ch, location ); return; } void mp_grant( CHAR_DATA *ch, const char *argument ) { char arg1[MAX_INPUT_LENGTH]; CHAR_DATA *victim; int num; argument = one_argument( argument, arg1 ); if( argument[0] == '\0' || !is_number( argument ) ) { progbug( ch, "grant: called with no arguments" ); return; } if( !( victim = get_char_world( ch, arg1 ) ) ) { progbug( ch, "grant: can't find player to grant." ); return; } num = atoi_special( argument ) * 100; sprintf( arg1, "%s has granted you %d experience!\n\r", ch->name, num / 100 ); wiznetf( ch, WIZ_LEVELS, get_trust( ch ), "%s has just granted %s %d experience (mp_grant).", ch->name, victim->name, num / 100 ); send_to_char( arg1, victim ); gain_exp( victim, num ); return; } /* lets the mobile destroy an object in its inventory it can also destroy a worn object and it can destroy items using all.xxxxx or just plain all of them */ void mp_junk( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; OBJ_DATA *obj_next; if( argument[0] == '\0' ) { progbug( ch, "Mpjunk - No argument." ); return; } if( str_cmp( argument, "all" ) && str_prefix( "all.", argument ) ) { if( ( obj = get_obj_wear( ch, argument ) ) != NULL ) { unequip_char( ch, obj ); extract_obj( obj ); return; } if( ( obj = get_obj_carry( ch, argument ) ) == NULL ) return; extract_obj( obj ); } else for( obj = ch->carrying; obj != NULL; obj = obj_next ) { obj_next = obj->next_content; if( argument[3] == '\0' || is_obj_name( obj, &argument[4] ) ) { if( obj->wear_loc != WEAR_NONE ) unequip_char( ch, obj ); extract_obj( obj ); } } return; } /* lets the mobile kill any player or mobile without murder */ void mp_kill( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *victim; if( argument[0] == '\0' ) { progbug( ch, "MpKill - no argument." ); return; } if( ( victim = get_char_room( ch, argument ) ) == NULL ) { progbug( ch, "MpKill - Victim not in room: %s.", argument ); return; } if( victim == ch ) { progbug( ch, "MpKill - Bad victim to attack, self." ); return; } if( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim ) { progbug( ch, "MpKill - Charmed mob attacking master: %s.", ch->master->name ); return; } if( ch->position == POS_FIGHTING ) { progbug( ch, "MpKill - Already fighting." ); return; } multi_hit( ch, victim, TYPE_UNDEFINED ); return; } /* lets the mobile load an item or mobile. All items are loaded into inventory. you can specify a level with the load object portion as well. */ void mp_mload( CHAR_DATA *ch, const char *argument ) { char arg[MAX_INPUT_LENGTH]; MOB_INDEX_DATA *pMobIndex; CHAR_DATA *victim; one_argument( argument, arg ); if( arg[0] == '\0' || !is_number( arg ) ) { progbug( ch, "Mpmload - Bad vnum as arg: %s.", arg ); return; } if( ( pMobIndex = get_mob_index( atoi( arg ) ) ) == NULL ) { progbug( ch, "Mpmload - Bad mob vnum: %s.", arg ); return; } victim = create_mobile( pMobIndex ); char_to_room( victim, ch->in_room ); return; } /* * Trimmed down version of mset. */ void mp_mset( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *vict; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; char arg3[MAX_INPUT_LENGTH]; int value; int *ival = NULL; char **sval = NULL; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); strcpy( arg3, argument ); if( !( vict = get_char_world( ch, arg1 ) ) ) { progbug( ch, "mset: non-existant character %s.", arg1 ); return; } value = atoi_functions( arg3 ); if( !str_cmp( arg2, "short" ) ) sval = &vict->short_descr; else if( !str_cmp( arg2, "long" ) ) { strcat( arg3, "\n\r" ); sval = &vict->long_descr; } else if( !str_cmp( arg2, "title" ) ) { set_title( vict, arg3 ); return; } else if( !str_cmp( arg2, "class" ) ) { if( value < 0 || value >= MAX_CLASS ) { for( value = 0; value < MAX_CLASS; value++ ) { if( !str_cmp( arg3, class_table[value].who_name ) || !str_cmp( arg3, class_table[value].name ) ) break; } if( value >= MAX_CLASS ) { progbug( ch, "mset: invalid class." ); return; } vict->class = value; return; } if( value == -1 && !IS_NPC( ch ) ) { progbug( ch, "mset: invalid class 'none' on a PC." ); return; } vict->class = value; return; } else if( !str_cmp( arg2, "sex" ) ) { if( IS_AFFECTED( vict, AFF_POLYMORPH ) ) return; if( value < 0 || value > 2 ) { if( !str_cmp( arg3, "male" ) ) vict->sex = SEX_MALE; else if( !str_cmp( arg3, "female" ) ) vict->sex = SEX_FEMALE; else if( !str_cmp( arg3, "neuter" ) ) vict->sex = SEX_NEUTRAL; else progbug( ch, "mset: invalid sex." ); return; } vict->sex = value; return; } else if( !str_cmp( arg2, "race" ) ) { if( IS_AFFECTED( vict, AFF_POLYMORPH ) ) return; value = race_lookup( arg3 ); if( value < 0 ) { progbug( ch, "mset: invalid race." ); return; } vict->race = value; return; } else if( !str_cmp( arg2, "sublevel" ) ) { if( value < 0 || value > vict->level ) { progbug( ch, "mset: sublevel out of range." ); return; } vict->sublevel = value; return; } else if( !str_cmp( arg2, "gold" ) ) ival = &vict->gold; else if( !str_cmp( arg2, "hp" ) ) ival = &vict->hit; else if( !str_cmp( arg2, "maxhp" ) ) ival = &vict->max_hit; else if( !str_prefix( "mana", arg2 ) || !str_prefix( "maxmana", arg2 ) ) { int which; argument = &arg2[4]; if( !str_prefix( "max", arg2 ) ) argument += 3; while( isspace( *argument ) ) argument++; if( !str_cmp( argument, "air" ) ) which = MAGIC_AIR; else if( !str_cmp( argument, "earth" ) ) which = MAGIC_EARTH; else if( !str_cmp( argument, "fire" ) ) which = MAGIC_FIRE; else if( !str_cmp( argument, "spirit" ) ) which = MAGIC_SPIRIT; else if( !str_cmp( argument, "water" ) ) which = MAGIC_WATER; else { progbug( ch, "mset: bad magic sphere." ); return; } if( !str_prefix( "max", arg2 ) ) ival = &vict->max_mana[which]; else ival = &vict->mana[which]; } else if( !str_cmp( arg2, "move" ) ) ival = &vict->move; else if( !str_cmp( arg2, "maxmove" ) ) ival = &vict->max_move; else if( !str_cmp( arg2, "practice" ) ) ival = &vict->practice; else if( !str_cmp( arg2, "align" ) ) { if( value < -1000 || value > 1000 ) return; ival = &vict->alignment; } if( !IS_NPC( vict ) ) { if( !str_cmp( arg2, "name" ) ) sval = &vict->name; else if( !str_cmp( arg2, "str" ) ) ival = &vict->pcdata->perm_str; else if( !str_cmp( arg2, "int" ) ) ival = &vict->pcdata->perm_int; else if( !str_cmp( arg2, "wis" ) ) ival = &vict->pcdata->perm_wis; else if( !str_cmp( arg2, "dex" ) ) ival = &vict->pcdata->perm_dex; else if( !str_cmp( arg2, "con" ) ) ival = &vict->pcdata->perm_con; else if( !str_cmp( arg2, "multi" ) ) { char classbuf[ MAX_INPUT_LENGTH ]; if( !str_cmp( argument, "all clear" ) ) { vict->class = get_first_class( vict ); for( value = 0; value < AVAIL_CLASS; value++ ) vict->pcdata->multi_class[value] = CLASS_UNKNOWN; return; } argument = one_argument( argument, classbuf ); for( value = 0; value < AVAIL_CLASS; value++ ) if( !str_cmp( classbuf, class_table[value].who_name ) || !str_cmp( classbuf, class_table[value].name ) ) break; if( value >= AVAIL_CLASS ) { progbug( ch, "mset multi: bad class name %s", classbuf ); return; } if( !str_cmp( argument, "clear" ) ) { if( vict->pcdata->multi_class[value] > CLASS_ADEPT ) { progbug( ch, "mset multi clear: bad args" ); return; } vict->pcdata->multi_class[value] = CLASS_UNKNOWN; if( vict->sublevel ) vict->sublevel = 0; return; } if( !str_cmp( argument, "aspire" ) ) { if( get_aspire_class( vict ) >= 0 ) { progbug( ch, "mset multi aspire: bad args" ); return; } vict->pcdata->multi_class[value] = CLASS_ASPIRING; return; } if( !str_cmp( argument, "adept" ) ) { if( vict->pcdata->multi_class[value] > CLASS_ADEPT ) { progbug( ch, "mset multi adept: bad args" ); return; } vict->pcdata->multi_class[value] = CLASS_ADEPT; return; } progbug( ch, "mset multi: bad args" ); return; } else if( !str_cmp( arg2, "qscore" ) ) ival = &vict->pcdata->quest->score; else if( !str_cmp( arg2, "qtime" ) ) ival = &vict->pcdata->quest->time; else if( !str_prefix( "magic", arg2 ) ) { int which; argument = &arg2[4]; while( isspace( *argument ) ) argument++; if( !str_cmp( argument, "air" ) ) which = MAGIC_AIR; else if( !str_cmp( argument, "earth" ) ) which = MAGIC_EARTH; else if( !str_cmp( argument, "fire" ) ) which = MAGIC_FIRE; else if( !str_cmp( argument, "spirit" ) ) which = MAGIC_SPIRIT; else if( !str_cmp( argument, "water" ) ) which = MAGIC_WATER; else { progbug( ch, "mset magic: bad magic sphere." ); return; } ival = &vict->pcdata->perm_magic[which]; } else if( !str_cmp( arg2, "thirst" ) ) { strcat( arg3, "0" ); ival = &vict->pcdata->condition[COND_THIRST]; } else if( !str_cmp( arg2, "full" ) ) { strcat( arg3, "0" ); ival = &vict->pcdata->condition[COND_FULL]; } else if( !str_cmp( arg2, "drunk" ) ) { strcat( arg3, "0" ); ival = &vict->pcdata->condition[COND_DRUNK]; } else if( !str_cmp( arg2, "clan" ) ) { CLAN_DATA *clan; if( !str_cmp( arg3, "none" ) ) { if( is_clan( vict ) ) remove_from_clan( vict ); return; } if( !( clan = clan_lookup( arg3 ) ) ) { progbug( ch, "mset clan: non-existant clan." ); return; } if( vict->pcdata->clan == clan ) return; if( is_clan( vict ) ) remove_from_clan( vict ); add_to_clan( vict, clan, RANK_CLANSMAN ); return; } else if( !str_cmp( arg2, "religion" ) ) { RELIGION_DATA *religion; if ( !( religion = religion_lookup( arg3 ) ) ) { progbug( ch, "mset religion: invalid religion." ); return; } vict->pcdata->religion = religion; return; } else if( !str_cmp( arg2, "clanrank" ) ) { CLAN_DATA *clan; if( !( clan = vict->pcdata->clan ) ) { progbug( ch, "mset clanrank: vict not in clan." ); return; } if( value < RANK_EXILED ) { remove_from_clan( vict ); return; } if( value > RANK_OVERLORD ) { progbug( ch, "mset clanrank: bad clan rank %d.", value ); return; } if( vict->pcdata->clan_rank == value ) return; switch( value ) { default: break; case RANK_CLANHERO: if( clan->clanheros >= clan->members / 3 ) { progbug( ch, "mset clanrank: too many heroes." ); return; } break; case RANK_CHIEFTAIN: if( clan->members < 10 ) { progbug( ch, "mset clanrank: too many cheiftans." ); return; } break; case RANK_OVERLORD: if( clan->overlord != NULL && clan->overlord[0] != '\0' ) { progbug( ch, "mest clanrank: already an overlord." ); return; } break; } remove_from_clan( vict ); add_to_clan( vict, clan, value ); return; } } else /* IS_NPC(vict) */ { if( !str_cmp( arg2, "name" ) ) sval = &vict->name; else if( !str_cmp( arg2, "level" ) ) ival = &vict->level; else if( !str_cmp( arg2, "spec" ) ) { if( ( value = spec_lookup( arg3 ) ) <= 0 ) { progbug( ch, "mset spec: invalid spec_fun name" ); return; } ival = &vict->spec_fun; } } if( ival ) *ival = atoi_functions( arg3 ); else if( sval ) { free_string( *sval ); *sval = str_dup( arg3 ); } else { progbug( ch, "mset: unknown field %s.", arg2 ); return; } return; } void mp_oload( CHAR_DATA *ch, const char *argument ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; OBJ_INDEX_DATA *pObjIndex; OBJ_DATA *obj; int level; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); if( arg1[0] == '\0' || !is_number( arg1 ) ) { progbug( ch, "Mpoload - Bad syntax: %s %s %s.", arg1, arg2, argument ); return; } if( arg2[0] == '\0' ) { level = 0; } else { /* * New feature from Alander. */ if( !is_number( arg2 ) ) { progbug( ch, "Mpoload - Bad syntax: arg2: %s.", arg2 ); return; } level = atoi( arg2 ); if( level < 0 || level > get_trust( ch ) ) { progbug( ch, "Mpoload - Bad level: %s.", arg2 ); return; } } if( ( pObjIndex = get_obj_index( atoi( arg1 ) ) ) == NULL ) { progbug( ch, "Mpoload - Bad vnum arg: %s.", arg1 ); return; } obj = create_object( pObjIndex, level ); if( CAN_WEAR( obj, ITEM_TAKE ) ) { obj_to_char( obj, ch ); } else { obj_to_room( obj, ch->in_room ); } return; } /* * Trimmed down version of oset. */ void mp_oset( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; char arg3[MAX_INPUT_LENGTH]; int value; int *ival = NULL; char **sval = NULL; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); strcpy( arg3, argument ); if( !( obj = get_obj_here( ch, arg1 ) ) ) { progbug( ch, "oset: non-existant object %s.", arg1 ); return; } value = atoi_functions( arg3 ); if( !str_cmp( arg2, "name" ) ) sval = &obj->name; else if( !str_cmp( arg2, "short" ) ) sval = &obj->short_descr; else if( !str_cmp( arg2, "long" ) ) { strcat( arg3, "\n\r" ); sval = &obj->description; } else if( !str_cmp( arg2, "action" ) ) { strcat( arg3, "\n\r" ); sval = &obj->action; } else if( !str_cmp( arg2, "value0" ) || !str_cmp( arg2, "v0" ) ) ival = &obj->value[0]; else if( !str_cmp( arg2, "value1" ) || !str_cmp( arg2, "v1" ) ) ival = &obj->value[2]; else if( !str_cmp( arg2, "value2" ) || !str_cmp( arg2, "v2" ) ) ival = &obj->value[2]; else if( !str_cmp( arg2, "value3" ) || !str_cmp( arg2, "v3" ) ) ival = &obj->value[3]; else if( !str_cmp( arg2, "extra" ) ) ival = &obj->extra_flags; else if( !str_cmp( arg2, "wear" ) ) ival = &obj->wear_flags; else if( !str_cmp( arg2, "level" ) ) ival = &obj->level; else if( !str_cmp( arg2, "weight" ) ) ival = &obj->weight; /* be careful! no checks! */ else if( !str_cmp( arg2, "cost" ) ) ival = &obj->cost; else if( !str_cmp( arg2, "timer" ) ) { set_timer_tick( obj, value ); return; } else if( !str_cmp( arg2, "imptimer" ) ) { create_obj_event( obj, evn_imp_grab, value * PULSE_TICK ); return; } else if( !str_cmp( arg2, "required" ) ) { obj->required_skill = skill_lookup( arg3 ); return; } else if( !str_cmp( arg2, "condition" ) ) { value *= 10; ival = &obj->condition; } if( ival ) *ival = value; else if( sval ) { free_string( *sval ); *sval = str_dup( arg3 ); } else { progbug( ch, "oset: unknown field %s.", arg2 ); return; } return; } /* * openpassage <#fromvnum> <#tovnum> <dir> * only a one directional passage, <dir> can be number/n/s/e... * * Potential Problem: these might not be able to be removed by progs * in rooms which have exit randomisations. --Symposium */ void mp_openpassage( CHAR_DATA *ch, const char *argument ) { char arg1[ MAX_INPUT_LENGTH ]; char arg2[ MAX_INPUT_LENGTH ]; ROOM_INDEX_DATA *targetRoom, *fromRoom; int targetRoomVnum, fromRoomVnum, exit_num; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); if( arg1[0] == '\0' || arg2[0] == '\0' || argument[0] == '\0' ) { progbug( ch, "Mpopenpassage - Bad syntax '%s' '%s' %s", arg1, arg2, argument ); return; } if( !is_number( arg1 ) || !is_number( arg2 ) ) { progbug( ch, "MpOpenPassage - Bad syntax: %s %s ...", arg1, arg2 ); return; } fromRoomVnum = atoi( arg1 ); targetRoomVnum = atoi( arg2 ); if( ( fromRoom = get_room_index( fromRoomVnum ) ) == NULL || ( targetRoom = get_room_index( targetRoomVnum ) ) == NULL ) { progbug( ch, "MpOpenPassage - Bad room vnums: %d - %d", fromRoomVnum, targetRoomVnum ); return; } if( isdigit( argument[0] ) ) { exit_num = argument[0] - '0'; } else switch( argument[0] ) { case 'n': case 'N': exit_num = 0; break; case 'e': case 'E': exit_num = 1; break; case 's': case 'S': exit_num = 2; break; case 'w': case 'W': exit_num = 3; break; case 'u': case 'U': exit_num = 4; break; case 'd': case 'D': exit_num = 5; break; default: progbug( ch, "mpopenpassage: Bad direction." ); return; } if( exit_num < 0 || exit_num >= MAX_DIR ) { progbug( ch, "mpopenpassage: invalid exit number %d.", exit_num ); return; } if( fromRoom->exit[exit_num] != NULL ) { if( !IS_SET( fromRoom->exit[exit_num]->exit_info, EX_TEMPORARY ) ) progbug( ch, "MpOpenPassage - Exit exists" ); return; } fromRoom->exit[exit_num] = new_exit( ); fromRoom->exit[exit_num]->in_room = fromRoom; fromRoom->exit[exit_num]->to_room = targetRoom; fromRoom->exit[exit_num]->key = -1; SET_BIT( fromRoom->exit[exit_num]->exit_info, EX_TEMPORARY ); SET_BIT( fromRoom->exit[exit_num]->rs_flags, EX_TEMPORARY ); } /* * closepassage <#room> <dir> * as above (SEE NOTE) */ void mp_closepassage( CHAR_DATA *ch, const char *argument ) { char arg[MAX_INPUT_LENGTH]; ROOM_INDEX_DATA *room; int exit_num; argument = one_argument( argument, arg ); if( arg[0] == '\0' || argument[0] == '\0' ) { progbug( ch, "mp_close_passage: illegal arguments: %s %s", arg, argument ); return; } if( ( room = get_room_index( atoi( arg ) ) ) == NULL ) { progbug( ch, "mp_close_passage: couldn't find room '%s'!", arg ); return; } if( isdigit( argument[0] ) ) { exit_num = argument[0] - '0'; } else switch( argument[0] ) { case 'n': case 'N': exit_num = 0; break; case 'e': case 'E': exit_num = 1; break; case 's': case 'S': exit_num = 2; break; case 'w': case 'W': exit_num = 3; break; case 'u': case 'U': exit_num = 4; break; case 'd': case 'D': exit_num = 5; break; default: progbug( ch, "mpclosepassage: Bad direction." ); return; } if( exit_num < 0 || exit_num > MAX_DIR || !room->exit[exit_num] || !IS_SET( room->exit[exit_num]->rs_flags | room->exit[exit_num]->exit_info, EX_TEMPORARY ) ) { progbug( ch, "mpclosepassage: exit %d from %d isn't temporary.", exit_num, room->vnum ); return; } free_exit( room->exit[exit_num] ); room->exit[exit_num] = NULL; return; } /* * Stop fights in the room. */ void mp_peace( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *rch; for( rch = ch->in_room->people; rch; rch = rch->next_in_room ) { if( rch->fighting ) stop_fighting( rch, TRUE ); } send_to_char( "Ok.\n\r", ch ); return; } /* Lets the mobile purge all objects and other npcs in the room, or purge a specified object or mob in the room. It can purge itself, but this had best be the last command in the MOBprogram otherwise ugly stuff will happen */ void mp_purge( CHAR_DATA *ch, const char *argument ) { purge_room( ch, argument ); return; } /* * Set a 'prog variable. */ void mp_set( CHAR_DATA *ch, const char *argument ) { char var[MAX_INPUT_LENGTH]; argument = first_arg( argument, var, FALSE ); set_mob_var( ch, var, argument ); } /* * Delete/remove a 'prog variable. */ void mp_delete( CHAR_DATA *ch, const char *argument ) { delete_mob_var( ch, argument ); } /* Lets the mobile transfer people. The all argument transfers everyone in the current room to the specified location. */ void mp_transfer( CHAR_DATA *ch, const char *argument ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; ROOM_INDEX_DATA *location; DESCRIPTOR_DATA *d; CHAR_DATA *victim; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); if( arg1[0] == '\0' ) { progbug( ch, "Mptransfer - Bad syntax: %s %s %s.", arg1, arg2, argument ); return; } if( !str_cmp( arg1, "all" ) ) { for( d = descriptor_list; d != NULL; d = d->next ) { if( !IS_SET( d->interpreter->flags, INTERPRETER_SAFE ) && d->character != ch && d->character->in_room != NULL && can_see( ch, d->character ) ) { char buf[MAX_STRING_LENGTH]; sprintf( buf, "%s %s", d->character->name, arg2 ); do_transfer( ch, buf ); } } return; } /* * Thanks to Grodyn for the optional location parameter. */ if( arg2[0] == '\0' ) { location = ch->in_room; } else { if( ( location = find_location( ch, arg2 ) ) == NULL ) { progbug( ch, "Mptransfer - No such location: %s.", arg2 ); return; } if( room_is_private( location ) ) { progbug( ch, "Mptransfer - Private room: vnum %d.", location->vnum ); return; } } if( ( victim = get_char_world( ch, arg1 ) ) == NULL ) { progbug( ch, "Mptransfer - No such person %s.", arg1 ); return; } if( victim->in_room == NULL ) { progbug( ch, "Mptransfer - Victim in Limbo." ); return; } if( victim->fighting != NULL ) stop_fighting( victim, TRUE ); char_from_room( victim ); char_to_room( victim, location ); return; } /* Lets the mobile transfer objects. * Use otransfer <object> character <character> * otransfer <object> object <object> * otransfer <object> [room] <room> */ void mp_otransfer( CHAR_DATA *ch, const char *argument ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; ROOM_INDEX_DATA *location = NULL; CHAR_DATA *vict = NULL; OBJ_DATA *obj; OBJ_DATA *objto = NULL; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); if( arg1[0] == '\0' || arg2[0] == '\0' ) { progbug( ch, "Otransfer - Bad syntax: %s %s %s.", arg1, arg2, argument ); return; } if( ( obj = get_obj_here( ch, arg1 ) ) == NULL ) { progbug( ch, "Otransfer - No such object %s.", arg1 ); return; } if( !str_prefix( arg2, "character" ) ) { if( ( vict = get_char_world( ch, argument ) ) == NULL ) { progbug( ch, "Otransfer - No such character: %s.", argument ); return; } } else if( !str_prefix( arg2, "object" ) ) { if( ( objto = get_obj_here( ch, argument ) ) == NULL ) { progbug( ch, "Otransfer - No such object: %s.", argument ); return; } } else if( !str_prefix( arg2, "room" ) ) strcpy( arg2, argument ); if( !vict && !objto && ( location = find_location( ch, arg2 ) ) == NULL ) { progbug( ch, "Otransfer - No such location: %s.", arg2 ); return; } if( obj->in_room ) obj_from_room( obj ); else if( obj->in_obj ) obj_from_obj( obj ); else if( obj->carried_by ) obj_from_char( obj ); else progbug( ch, "Otransfer - Obj [%s] not anywhere.", obj->name ); if( vict ) obj_to_char( obj, vict ); else if( objto ) obj_to_obj( obj, objto ); else if( location ) { obj_to_room( obj, location ); strip_events( &obj->events, evn_imp_grab ); } return; } /* * Trigger a sub_prog on another mobile. * Usage: trigger <mob> <trigger> * The mobile need not be visible to the triggerer if * it is in the same room. */ void mp_trigger( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *mob; char arg[MAX_INPUT_LENGTH]; char name[MAX_INPUT_LENGTH]; int count; argument = one_argument( argument, arg ); count = number_argument( arg, name ); for( mob = ch->in_room->people; mob; mob = mob->next_in_room ) { if( !mob->deleted && is_char_name( mob, name ) && --count <= 0 ) break; } if( !mob ) mob = get_char_world( ch, arg ); if( arg[0] == '\0' || argument[0] == '\0' || !mob || mob == ch || !IS_NPC( mob ) ) { progbug( ch, "Bad arguments to mptrigger mob." ); return; } mprog_sub_trigger( mob, ch, argument ); return; } /* Trimmed down and silent version of do_open with no triggers or traps */ void mp_open( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; int door; if( argument[0] == '\0' ) { progbug( ch, "Trying to open nothingness." ); return; } if( ( door = find_door( ch, argument ) ) >= 0 ) { /* 'open door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; REMOVE_BIT( pexit->exit_info, EX_CLOSED ); /* * open the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) REMOVE_BIT( pexit_rev->exit_info, EX_CLOSED ); return; } if( ( obj = get_obj_here( ch, argument ) ) ) { /* 'open object' */ if( obj->item_type != ITEM_CONTAINER ) { progbug( ch, "Trying to open a non-container '%s'.", argument ); return; } if( !IS_SET( obj->value[1], CONT_CLOSEABLE ) ) { progbug( ch, "Trying to open a non-closable '%s'.", argument ); return; } REMOVE_BIT( obj->value[1], CONT_CLOSED ); return; } progbug( ch, "Couldn't open a '%s'.", argument ); return; } /* Trimmed down and silent version of do_close with no triggers or traps */ void mp_close( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; int door; if( argument[0] == '\0' ) { progbug( ch, "Trying to close nothingness." ); return; } if( ( door = find_door( ch, argument ) ) >= 0 ) { /* 'close door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; SET_BIT( pexit->exit_info, EX_CLOSED ); /* close the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) SET_BIT( pexit_rev->exit_info, EX_CLOSED ); return; } if( ( obj = get_obj_here( ch, argument ) ) ) { if( obj->item_type != ITEM_CONTAINER ) { progbug( ch, "Trying to open a non-container '%s'.", argument ); return; } if( !IS_SET( obj->value[1], CONT_CLOSEABLE ) ) { progbug( ch, "Trying to open a non-closable '%s'.", argument ); return; } SET_BIT( obj->value[1], CONT_CLOSED ); return; } progbug( ch, "Couldn't close a '%s'.", argument ); return; } /* Trimmed down and silent version of do_lock. */ void mp_lock( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; int door; if( argument[0] == '\0' ) { progbug( ch, "Trying to lock nothingness." ); return; } if( ( door = find_door( ch, argument ) ) >= 0 ) { /* 'lock door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; if( !IS_SET( pexit->exit_info, EX_CLOSED ) ) { progbug( ch, "Trying to lock an open door." ); return; } /* Let's just see if this causes problems, it should be ok as the resets still take care of these. if( pexit->key < 0 ) { progbug( ch, "Trying to lock an unlockable door." ); return; } */ if( IS_SET( pexit->exit_info, EX_LOCKED ) ) return; SET_BIT( pexit->exit_info, EX_LOCKED ); /* lock the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) SET_BIT( pexit_rev->exit_info, EX_LOCKED ); return; } if( ( obj = get_obj_here( ch, argument ) ) ) { /* 'lock object' */ if( obj->item_type != ITEM_CONTAINER ) { progbug( ch, "Trying to lock a non-container '%s'.", argument ); return; } if( !IS_SET( obj->value[1], CONT_CLOSED ) ) { progbug( ch, "Trying to lock an open container '%s'.", argument ); return; } if( obj->value[2] < 0 ) { progbug( ch, "Trying to lock an unlockable container '%s'.", argument ); return; } if( IS_SET( obj->value[1], CONT_LOCKED ) ) return; SET_BIT( obj->value[1], CONT_LOCKED ); return; } progbug( ch, "Trying to lock non-existant '%s'", argument ); return; } /* Trimmed down, safe and silent version of do_unlock */ void mp_unlock( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; int door; if( argument[0] == '\0' ) { progbug( ch, "Trying to unlock nothingness." ); return; } if( ( door = find_door( ch, argument ) ) >= 0 ) { /* 'unlock door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; if( !IS_SET( pexit->exit_info, EX_CLOSED ) ) return; if( !IS_SET( pexit->exit_info, EX_LOCKED ) ) return; REMOVE_BIT( pexit->exit_info, EX_LOCKED ); /* unlock the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED ); return; } if( ( obj = get_obj_here( ch, argument ) ) ) { /* 'unlock object' */ if( obj->item_type != ITEM_CONTAINER ) { progbug( ch, "Trying to unlock a non-container '%s'.", argument ); return; } if( !IS_SET( obj->value[1], CONT_CLOSED ) ) return; if( !IS_SET( obj->value[1], CONT_LOCKED ) ) return; REMOVE_BIT( obj->value[1], CONT_LOCKED ); return; } progbug( ch, "Trying to unlock non-existant '%s'.", argument ); return; }