Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

mob_cmds.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
00003  *  Michael Seifert, Hans Henrik Strfeldt, Tom Madsen, and Katja Nyboe.    *
00004  *                                                                         *
00005  *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
00006  *  Chastain, Michael Quan, and Mitchell Tse.                              *
00007  *                                                                         *
00008  *  In order to use any part of this Merc Diku Mud, you must comply with   *
00009  *  both the original Diku license in 'license.doc' as well the Merc       *
00010  *  license in 'license.txt'.  In particular, you may not remove either of *
00011  *  these copyright notices.                                               *
00012  *                                                                         *
00013  *  Much time and thought has gone into this software and you are          *
00014  *  benefitting.  We hope that you share your changes too.  What goes      *
00015  *  around, comes around.                                                  *
00016  ***************************************************************************/
00017 
00018 /***************************************************************************
00019  *  ROM 2.4 is copyright 1993-1998 Russ Taylor                             *
00020  *  ROM has been brought to you by the ROM consortium                      *
00021  *      Russ Taylor (rtaylor@hypercube.org)                                *
00022  *      Gabrielle Taylor (gtaylor@hypercube.org)                           *
00023  *      Brian Moore (zump@rom.org)                                         *
00024  *  By using this code, you have agreed to follow the terms of the         *
00025  *  ROM license, in the file Rom24/doc/rom.license                         *
00026  ***************************************************************************/
00027 
00028 /***************************************************************************
00029  *                                                                         *
00030  *  Based on MERC 2.2 MOBprograms by N'Atas-ha.                            *
00031  *  Written and adapted to ROM 2.4 by                                      *
00032  *          Markku Nylander (markku.nylander@uta.fi)                       *
00033  *                                                                         *
00034  ***************************************************************************/
00035 
00036 #include <sys/types.h>
00037 #include <stdio.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include "merc.h"
00041 #include "mob_cmds.h"
00042 
00043 DECLARE_DO_FUN (do_look);
00044 extern ROOM_INDEX_DATA *find_location (CHAR_DATA *, char *);
00045 
00046 /*
00047  * Command table.
00048  */
00049 const struct mob_cmd_type mob_cmd_table[] = {
00050     {"asound", do_mpasound},
00051     {"gecho", do_mpgecho},
00052     {"zecho", do_mpzecho},
00053     {"kill", do_mpkill},
00054     {"assist", do_mpassist},
00055     {"junk", do_mpjunk},
00056     {"echo", do_mpecho},
00057     {"echoaround", do_mpechoaround},
00058     {"echoat", do_mpechoat},
00059     {"mload", do_mpmload},
00060     {"oload", do_mpoload},
00061     {"purge", do_mppurge},
00062     {"goto", do_mpgoto},
00063     {"at", do_mpat},
00064     {"transfer", do_mptransfer},
00065     {"gtransfer", do_mpgtransfer},
00066     {"otransfer", do_mpotransfer},
00067     {"force", do_mpforce},
00068     {"gforce", do_mpgforce},
00069     {"vforce", do_mpvforce},
00070     {"cast", do_mpcast},
00071     {"damage", do_mpdamage},
00072     {"remember", do_mpremember},
00073     {"forget", do_mpforget},
00074     {"delay", do_mpdelay},
00075     {"cancel", do_mpcancel},
00076     {"call", do_mpcall},
00077     {"flee", do_mpflee},
00078     {"remove", do_mpremove},
00079     {"", 0}
00080 };
00081 
00082 void do_mob (CHAR_DATA * ch, char *argument)
00083 {
00084     /*
00085      * Security check!
00086      */
00087     if (ch->desc != NULL && get_trust (ch) < MAX_LEVEL)
00088         return;
00089     mob_interpret (ch, argument);
00090 }
00091 
00092 /*
00093  * Mob command interpreter. Implemented separately for security and speed
00094  * reasons. A trivial hack of interpret()
00095  */
00096 void mob_interpret (CHAR_DATA * ch, char *argument)
00097 {
00098     char buf[MAX_STRING_LENGTH], command[MAX_INPUT_LENGTH];
00099     int cmd;
00100 
00101     argument = one_argument (argument, command);
00102 
00103     /*
00104      * Look for command in command table.
00105      */
00106     for (cmd = 0; mob_cmd_table[cmd].name[0] != '\0'; cmd++)
00107     {
00108         if (command[0] == mob_cmd_table[cmd].name[0]
00109             && !str_prefix (command, mob_cmd_table[cmd].name))
00110         {
00111             (*mob_cmd_table[cmd].do_fun) (ch, argument);
00112             tail_chain ();
00113             return;
00114         }
00115     }
00116     sprintf (buf, "Mob_interpret: invalid cmd from mob %d: '%s'",
00117              IS_NPC (ch) ? ch->pIndexData->vnum : 0, command);
00118     bug (buf, 0);
00119 }
00120 
00121 char *mprog_type_to_name (int type)
00122 {
00123     switch (type)
00124     {
00125         case TRIG_ACT:
00126             return "ACT";
00127         case TRIG_SPEECH:
00128             return "SPEECH";
00129         case TRIG_RANDOM:
00130             return "RANDOM";
00131         case TRIG_FIGHT:
00132             return "FIGHT";
00133         case TRIG_HPCNT:
00134             return "HPCNT";
00135         case TRIG_DEATH:
00136             return "DEATH";
00137         case TRIG_ENTRY:
00138             return "ENTRY";
00139         case TRIG_GREET:
00140             return "GREET";
00141         case TRIG_GRALL:
00142             return "GRALL";
00143         case TRIG_GIVE:
00144             return "GIVE";
00145         case TRIG_BRIBE:
00146             return "BRIBE";
00147         case TRIG_KILL:
00148             return "KILL";
00149         case TRIG_DELAY:
00150             return "DELAY";
00151         case TRIG_SURR:
00152             return "SURRENDER";
00153         case TRIG_EXIT:
00154             return "EXIT";
00155         case TRIG_EXALL:
00156             return "EXALL";
00157         default:
00158             return "ERROR";
00159     }
00160 }
00161 
00162 /* 
00163  * Displays MOBprogram triggers of a mobile
00164  *
00165  * Syntax: mpstat [name]
00166  */
00167 void do_mpstat (CHAR_DATA * ch, char *argument)
00168 {
00169     char arg[MAX_STRING_LENGTH];
00170     MPROG_LIST *mprg;
00171     CHAR_DATA *victim;
00172     int i;
00173 
00174     one_argument (argument, arg);
00175 
00176     if (arg[0] == '\0')
00177     {
00178         send_to_char ("Mpstat whom?\n\r", ch);
00179         return;
00180     }
00181 
00182     if ((victim = get_char_world (ch, arg)) == NULL)
00183     {
00184         send_to_char ("No such creature.\n\r", ch);
00185         return;
00186     }
00187 
00188     if (!IS_NPC (victim))
00189     {
00190         send_to_char ("That is not a mobile.\n\r", ch);
00191         return;
00192     }
00193 
00194     if ((victim = get_char_world (ch, arg)) == NULL)
00195     {
00196         send_to_char ("No such creature visible.\n\r", ch);
00197         return;
00198     }
00199 
00200     sprintf (arg, "Mobile #%-6d [%s]\n\r",
00201              victim->pIndexData->vnum, victim->short_descr);
00202     send_to_char (arg, ch);
00203 
00204     sprintf (arg, "Delay   %-6d [%s]\n\r",
00205              victim->mprog_delay,
00206              victim->mprog_target == NULL
00207              ? "No target" : victim->mprog_target->name);
00208     send_to_char (arg, ch);
00209 
00210     if (!victim->pIndexData->mprog_flags)
00211     {
00212         send_to_char ("[No programs set]\n\r", ch);
00213         return;
00214     }
00215 
00216     for (i = 0, mprg = victim->pIndexData->mprogs; mprg != NULL;
00217          mprg = mprg->next)
00218     {
00219         sprintf (arg, "[%2d] Trigger [%-8s] Program [%4d] Phrase [%s]\n\r",
00220                  ++i,
00221                  mprog_type_to_name (mprg->trig_type),
00222                  mprg->vnum, mprg->trig_phrase);
00223         send_to_char (arg, ch);
00224     }
00225 
00226     return;
00227 
00228 }
00229 
00230 /*
00231  * Displays the source code of a given MOBprogram
00232  *
00233  * Syntax: mpdump [vnum]
00234  */
00235 void do_mpdump (CHAR_DATA * ch, char *argument)
00236 {
00237     char buf[MAX_INPUT_LENGTH];
00238     MPROG_CODE *mprg;
00239 
00240     one_argument (argument, buf);
00241     if ((mprg = get_mprog_index (atoi (buf))) == NULL)
00242     {
00243         send_to_char ("No such MOBprogram.\n\r", ch);
00244         return;
00245     }
00246     page_to_char (mprg->code, ch);
00247 }
00248 
00249 /*
00250  * Prints the argument to all active players in the game
00251  *
00252  * Syntax: mob gecho [string]
00253  */
00254 void do_mpgecho (CHAR_DATA * ch, char *argument)
00255 {
00256     DESCRIPTOR_DATA *d;
00257 
00258     if (argument[0] == '\0')
00259     {
00260         bug ("MpGEcho: missing argument from vnum %d",
00261              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00262         return;
00263     }
00264 
00265     for (d = descriptor_list; d; d = d->next)
00266     {
00267         if (d->connected == CON_PLAYING)
00268         {
00269             if (IS_IMMORTAL (d->character))
00270                 send_to_char ("Mob echo> ", d->character);
00271             send_to_char (argument, d->character);
00272             send_to_char ("\n\r", d->character);
00273         }
00274     }
00275 }
00276 
00277 /*
00278  * Prints the argument to all players in the same area as the mob
00279  *
00280  * Syntax: mob zecho [string]
00281  */
00282 void do_mpzecho (CHAR_DATA * ch, char *argument)
00283 {
00284     DESCRIPTOR_DATA *d;
00285 
00286     if (argument[0] == '\0')
00287     {
00288         bug ("MpZEcho: missing argument from vnum %d",
00289              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00290         return;
00291     }
00292 
00293     if (ch->in_room == NULL)
00294         return;
00295 
00296     for (d = descriptor_list; d; d = d->next)
00297     {
00298         if (d->connected == CON_PLAYING
00299             && d->character->in_room != NULL
00300             && d->character->in_room->area == ch->in_room->area)
00301         {
00302             if (IS_IMMORTAL (d->character))
00303                 send_to_char ("Mob echo> ", d->character);
00304             send_to_char (argument, d->character);
00305             send_to_char ("\n\r", d->character);
00306         }
00307     }
00308 }
00309 
00310 /*
00311  * Prints the argument to all the rooms aroud the mobile
00312  *
00313  * Syntax: mob asound [string]
00314  */
00315 void do_mpasound (CHAR_DATA * ch, char *argument)
00316 {
00317 
00318     ROOM_INDEX_DATA *was_in_room;
00319     int door;
00320 
00321     if (argument[0] == '\0')
00322         return;
00323 
00324     was_in_room = ch->in_room;
00325     for (door = 0; door < 10; door++)
00326     {
00327         EXIT_DATA *pexit;
00328 
00329         if ((pexit = was_in_room->exit[door]) != NULL
00330             && pexit->u1.to_room != NULL && pexit->u1.to_room != was_in_room)
00331         {
00332             ch->in_room = pexit->u1.to_room;
00333             MOBtrigger = FALSE;
00334             act (argument, ch, NULL, NULL, TO_ROOM);
00335             MOBtrigger = TRUE;
00336         }
00337     }
00338     ch->in_room = was_in_room;
00339     return;
00340 
00341 }
00342 
00343 /*
00344  * Lets the mobile kill any player or mobile without murder
00345  *
00346  * Syntax: mob kill [victim]
00347  */
00348 void do_mpkill (CHAR_DATA * ch, char *argument)
00349 {
00350     char arg[MAX_INPUT_LENGTH];
00351     CHAR_DATA *victim;
00352 
00353     one_argument (argument, arg);
00354 
00355     if (arg[0] == '\0')
00356         return;
00357 
00358     if ((victim = get_char_room (ch, arg)) == NULL)
00359         return;
00360 
00361     if (victim == ch || IS_NPC (victim) || ch->position == POS_FIGHTING)
00362         return;
00363 
00364     if (IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)
00365     {
00366         bug ("MpKill - Charmed mob attacking master from vnum %d.",
00367              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00368         return;
00369     }
00370 
00371     multi_hit (ch, victim, TYPE_UNDEFINED);
00372     return;
00373 }
00374 
00375 /*
00376  * Lets the mobile assist another mob or player
00377  *
00378  * Syntax: mob assist [character]
00379  */
00380 void do_mpassist (CHAR_DATA * ch, char *argument)
00381 {
00382     char arg[MAX_INPUT_LENGTH];
00383     CHAR_DATA *victim;
00384 
00385     one_argument (argument, arg);
00386 
00387     if (arg[0] == '\0')
00388         return;
00389 
00390     if ((victim = get_char_room (ch, arg)) == NULL)
00391         return;
00392 
00393     if (victim == ch || ch->fighting != NULL || victim->fighting == NULL)
00394         return;
00395 
00396     multi_hit (ch, victim->fighting, TYPE_UNDEFINED);
00397     return;
00398 }
00399 
00400 
00401 /*
00402  * Lets the mobile destroy an object in its inventory
00403  * it can also destroy a worn object and it can destroy 
00404  * items using all.xxxxx or just plain all of them 
00405  *
00406  * Syntax: mob junk [item]
00407  */
00408 
00409 void do_mpjunk (CHAR_DATA * ch, char *argument)
00410 {
00411     char arg[MAX_INPUT_LENGTH];
00412     OBJ_DATA *obj;
00413     OBJ_DATA *obj_next;
00414 
00415     one_argument (argument, arg);
00416 
00417     if (arg[0] == '\0')
00418         return;
00419 
00420     if (str_cmp (arg, "all") && str_prefix ("all.", arg))
00421     {
00422         if ((obj = get_obj_wear (ch, arg)) != NULL)
00423         {
00424             unequip_char (ch, obj);
00425             extract_obj (obj);
00426             return;
00427         }
00428         if ((obj = get_obj_carry (ch, arg, ch)) == NULL)
00429             return;
00430         extract_obj (obj);
00431     }
00432     else
00433         for (obj = ch->carrying; obj != NULL; obj = obj_next)
00434         {
00435             obj_next = obj->next_content;
00436             if (arg[3] == '\0' || is_name (&arg[4], obj->name))
00437             {
00438                 if (obj->wear_loc != WEAR_NONE)
00439                     unequip_char (ch, obj);
00440                 extract_obj (obj);
00441             }
00442         }
00443 
00444     return;
00445 
00446 }
00447 
00448 /*
00449  * Prints the message to everyone in the room other than the mob and victim
00450  *
00451  * Syntax: mob echoaround [victim] [string]
00452  */
00453 
00454 void do_mpechoaround (CHAR_DATA * ch, char *argument)
00455 {
00456     char arg[MAX_INPUT_LENGTH];
00457     CHAR_DATA *victim;
00458 
00459     argument = one_argument (argument, arg);
00460 
00461     if (arg[0] == '\0')
00462         return;
00463 
00464     if ((victim = get_char_room (ch, arg)) == NULL)
00465         return;
00466 
00467     act (argument, ch, NULL, victim, TO_NOTVICT);
00468 }
00469 
00470 /*
00471  * Prints the message to only the victim
00472  *
00473  * Syntax: mob echoat [victim] [string]
00474  */
00475 void do_mpechoat (CHAR_DATA * ch, char *argument)
00476 {
00477     char arg[MAX_INPUT_LENGTH];
00478     CHAR_DATA *victim;
00479 
00480     argument = one_argument (argument, arg);
00481 
00482     if (arg[0] == '\0' || argument[0] == '\0')
00483         return;
00484 
00485     if ((victim = get_char_room (ch, arg)) == NULL)
00486         return;
00487 
00488     act (argument, ch, NULL, victim, TO_VICT);
00489 }
00490 
00491 /*
00492  * Prints the message to the room at large
00493  *
00494  * Syntax: mpecho [string]
00495  */
00496 void do_mpecho (CHAR_DATA * ch, char *argument)
00497 {
00498     if (argument[0] == '\0')
00499         return;
00500     act (argument, ch, NULL, NULL, TO_ROOM);
00501 }
00502 
00503 /*
00504  * Lets the mobile load another mobile.
00505  *
00506  * Syntax: mob mload [vnum]
00507  */
00508 void do_mpmload (CHAR_DATA * ch, char *argument)
00509 {
00510     char arg[MAX_INPUT_LENGTH];
00511     MOB_INDEX_DATA *pMobIndex;
00512     CHAR_DATA *victim;
00513     int vnum;
00514 
00515     one_argument (argument, arg);
00516 
00517     if (ch->in_room == NULL || arg[0] == '\0' || !is_number (arg))
00518         return;
00519 
00520     vnum = atoi (arg);
00521     if ((pMobIndex = get_mob_index (vnum)) == NULL)
00522     {
00523         sprintf (arg, "Mpmload: bad mob index (%d) from mob %d",
00524                  vnum, IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00525         bug (arg, 0);
00526         return;
00527     }
00528     victim = create_mobile (pMobIndex);
00529     char_to_room (victim, ch->in_room);
00530     return;
00531 }
00532 
00533 /*
00534  * Lets the mobile load an object
00535  *
00536  * Syntax: mob oload [vnum] [level] {R}
00537  */
00538 void do_mpoload (CHAR_DATA * ch, char *argument)
00539 {
00540     char arg1[MAX_INPUT_LENGTH];
00541     char arg2[MAX_INPUT_LENGTH];
00542     char arg3[MAX_INPUT_LENGTH];
00543     OBJ_INDEX_DATA *pObjIndex;
00544     OBJ_DATA *obj;
00545     int level;
00546     bool fToroom = FALSE, fWear = FALSE;
00547 
00548     argument = one_argument (argument, arg1);
00549     argument = one_argument (argument, arg2);
00550     one_argument (argument, arg3);
00551 
00552     if (arg1[0] == '\0' || !is_number (arg1))
00553     {
00554         bug ("Mpoload - Bad syntax from vnum %d.",
00555              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00556         return;
00557     }
00558 
00559     if (arg2[0] == '\0')
00560     {
00561         level = get_trust (ch);
00562     }
00563     else
00564     {
00565         /*
00566          * New feature from Alander.
00567          */
00568         if (!is_number (arg2))
00569         {
00570             bug ("Mpoload - Bad syntax from vnum %d.",
00571                  IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00572             return;
00573         }
00574         level = atoi (arg2);
00575         if (level < 0 || level > get_trust (ch))
00576         {
00577             bug ("Mpoload - Bad level from vnum %d.",
00578                  IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00579             return;
00580         }
00581     }
00582 
00583     /*
00584      * Added 3rd argument
00585      * omitted - load to mobile's inventory
00586      * 'R'     - load to room
00587      * 'W'     - load to mobile and force wear
00588      */
00589     if (arg3[0] == 'R' || arg3[0] == 'r')
00590         fToroom = TRUE;
00591     else if (arg3[0] == 'W' || arg3[0] == 'w')
00592         fWear = TRUE;
00593 
00594     if ((pObjIndex = get_obj_index (atoi (arg1))) == NULL)
00595     {
00596         bug ("Mpoload - Bad vnum arg from vnum %d.",
00597              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00598         return;
00599     }
00600 
00601     obj = create_object (pObjIndex, level);
00602     if ((fWear || !fToroom) && CAN_WEAR (obj, ITEM_TAKE))
00603     {
00604         obj_to_char (obj, ch);
00605         if (fWear)
00606             wear_obj (ch, obj, TRUE);
00607     }
00608     else
00609     {
00610         obj_to_room (obj, ch->in_room);
00611     }
00612 
00613     return;
00614 }
00615 
00616 /*
00617  * Lets the mobile purge all objects and other npcs in the room,
00618  * or purge a specified object or mob in the room. The mobile cannot
00619  * purge itself for safety reasons.
00620  *
00621  * syntax mob purge {target}
00622  */
00623 void do_mppurge (CHAR_DATA * ch, char *argument)
00624 {
00625     char arg[MAX_INPUT_LENGTH];
00626     CHAR_DATA *victim;
00627     OBJ_DATA *obj;
00628 
00629     one_argument (argument, arg);
00630 
00631     if (arg[0] == '\0')
00632     {
00633         /* 'purge' */
00634         CHAR_DATA *vnext;
00635         OBJ_DATA *obj_next;
00636 
00637         for (victim = ch->in_room->people; victim != NULL; victim = vnext)
00638         {
00639             vnext = victim->next_in_room;
00640             if (IS_NPC (victim) && victim != ch
00641                 && !IS_SET (victim->act, ACT_NOPURGE))
00642                 extract_char (victim, TRUE);
00643         }
00644 
00645         for (obj = ch->in_room->contents; obj != NULL; obj = obj_next)
00646         {
00647             obj_next = obj->next_content;
00648             if (!IS_SET (obj->extra_flags, ITEM_NOPURGE))
00649                 extract_obj (obj);
00650         }
00651 
00652         return;
00653     }
00654 
00655     if ((victim = get_char_room (ch, arg)) == NULL)
00656     {
00657         if ((obj = get_obj_here (ch, arg)))
00658         {
00659             extract_obj (obj);
00660         }
00661         else
00662         {
00663             bug ("Mppurge - Bad argument from vnum %d.",
00664                  IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00665         }
00666         return;
00667     }
00668 
00669     if (!IS_NPC (victim))
00670     {
00671         bug ("Mppurge - Purging a PC from vnum %d.",
00672              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00673         return;
00674     }
00675     extract_char (victim, TRUE);
00676     return;
00677 }
00678 
00679 
00680 /*
00681  * Lets the mobile goto any location it wishes that is not private.
00682  *
00683  * Syntax: mob goto [location]
00684  */
00685 void do_mpgoto (CHAR_DATA * ch, char *argument)
00686 {
00687     char arg[MAX_INPUT_LENGTH];
00688     ROOM_INDEX_DATA *location;
00689 
00690     one_argument (argument, arg);
00691     if (arg[0] == '\0')
00692     {
00693         bug ("Mpgoto - No argument from vnum %d.",
00694              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00695         return;
00696     }
00697 
00698     if ((location = find_location (ch, arg)) == NULL)
00699     {
00700         bug ("Mpgoto - No such location from vnum %d.",
00701              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00702         return;
00703     }
00704 
00705     if (ch->fighting != NULL)
00706         stop_fighting (ch, TRUE);
00707 
00708     char_from_room (ch);
00709     char_to_room (ch, location);
00710 
00711     return;
00712 }
00713 
00714 /* 
00715  * Lets the mobile do a command at another location.
00716  *
00717  * Syntax: mob at [location] [commands]
00718  */
00719 void do_mpat (CHAR_DATA * ch, char *argument)
00720 {
00721     char arg[MAX_INPUT_LENGTH];
00722     ROOM_INDEX_DATA *location;
00723     ROOM_INDEX_DATA *original;
00724     CHAR_DATA *wch;
00725     OBJ_DATA *on;
00726 
00727     argument = one_argument (argument, arg);
00728 
00729     if (arg[0] == '\0' || argument[0] == '\0')
00730     {
00731         bug ("Mpat - Bad argument from vnum %d.",
00732              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00733         return;
00734     }
00735 
00736     if ((location = find_location (ch, arg)) == NULL)
00737     {
00738         bug ("Mpat - No such location from vnum %d.",
00739              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00740         return;
00741     }
00742 
00743     original = ch->in_room;
00744     on = ch->on;
00745     char_from_room (ch);
00746     char_to_room (ch, location);
00747     interpret (ch, argument);
00748 
00749     /*
00750      * See if 'ch' still exists before continuing!
00751      * Handles 'at XXXX quit' case.
00752      */
00753     for (wch = char_list; wch != NULL; wch = wch->next)
00754     {
00755         if (wch == ch)
00756         {
00757             char_from_room (ch);
00758             char_to_room (ch, original);
00759             ch->on = on;
00760             break;
00761         }
00762     }
00763 
00764     return;
00765 }
00766 
00767 /*
00768  * Lets the mobile transfer people.  The 'all' argument transfers
00769  *  everyone in the current room to the specified location
00770  *
00771  * Syntax: mob transfer [target|'all'] [location]
00772  */
00773 void do_mptransfer (CHAR_DATA * ch, char *argument)
00774 {
00775     char arg1[MAX_INPUT_LENGTH];
00776     char arg2[MAX_INPUT_LENGTH];
00777     char buf[MAX_STRING_LENGTH];
00778     ROOM_INDEX_DATA *location;
00779     CHAR_DATA *victim;
00780 
00781     argument = one_argument (argument, arg1);
00782     argument = one_argument (argument, arg2);
00783 
00784     if (arg1[0] == '\0')
00785     {
00786         bug ("Mptransfer - Bad syntax from vnum %d.",
00787              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00788         return;
00789     }
00790 
00791     if (!str_cmp (arg1, "all"))
00792     {
00793         CHAR_DATA *victim_next;
00794 
00795         for (victim = ch->in_room->people; victim != NULL;
00796              victim = victim_next)
00797         {
00798             victim_next = victim->next_in_room;
00799             if (!IS_NPC (victim))
00800             {
00801                 sprintf (buf, "%s %s", victim->name, arg2);
00802                 do_mptransfer (ch, buf);
00803             }
00804         }
00805         return;
00806     }
00807 
00808     /*
00809      * Thanks to Grodyn for the optional location parameter.
00810      */
00811     if (arg2[0] == '\0')
00812     {
00813         location = ch->in_room;
00814     }
00815     else
00816     {
00817         if ((location = find_location (ch, arg2)) == NULL)
00818         {
00819             bug ("Mptransfer - No such location from vnum %d.",
00820                  IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00821             return;
00822         }
00823 
00824         if (room_is_private (location))
00825             return;
00826     }
00827 
00828     if ((victim = get_char_world (ch, arg1)) == NULL)
00829         return;
00830 
00831     if (victim->in_room == NULL)
00832         return;
00833 
00834     if (victim->fighting != NULL)
00835         stop_fighting (victim, TRUE);
00836     char_from_room (victim);
00837     char_to_room (victim, location);
00838     do_look (victim, "auto");
00839 
00840     return;
00841 }
00842 
00843 /*
00844  * Lets the mobile transfer all chars in same group as the victim.
00845  *
00846  * Syntax: mob gtransfer [victim] [location]
00847  */
00848 void do_mpgtransfer (CHAR_DATA * ch, char *argument)
00849 {
00850     char arg1[MAX_INPUT_LENGTH];
00851     char arg2[MAX_INPUT_LENGTH];
00852     char buf[MAX_STRING_LENGTH];
00853     CHAR_DATA *who, *victim, *victim_next;
00854 
00855     argument = one_argument (argument, arg1);
00856     argument = one_argument (argument, arg2);
00857 
00858     if (arg1[0] == '\0')
00859     {
00860         bug ("Mpgtransfer - Bad syntax from vnum %d.",
00861              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00862         return;
00863     }
00864 
00865     if ((who = get_char_room (ch, arg1)) == NULL)
00866         return;
00867 
00868     for (victim = ch->in_room->people; victim; victim = victim_next)
00869     {
00870         victim_next = victim->next_in_room;
00871         if (is_same_group (who, victim))
00872         {
00873             sprintf (buf, "%s %s", victim->name, arg2);
00874             do_mptransfer (ch, buf);
00875         }
00876     }
00877     return;
00878 }
00879 
00880 /*
00881  * Lets the mobile force someone to do something. Must be mortal level
00882  * and the all argument only affects those in the room with the mobile.
00883  *
00884  * Syntax: mob force [victim] [commands]
00885  */
00886 void do_mpforce (CHAR_DATA * ch, char *argument)
00887 {
00888     char arg[MAX_INPUT_LENGTH];
00889 
00890     argument = one_argument (argument, arg);
00891 
00892     if (arg[0] == '\0' || argument[0] == '\0')
00893     {
00894         bug ("Mpforce - Bad syntax from vnum %d.",
00895              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00896         return;
00897     }
00898 
00899     if (!str_cmp (arg, "all"))
00900     {
00901         CHAR_DATA *vch;
00902         CHAR_DATA *vch_next;
00903 
00904         for (vch = char_list; vch != NULL; vch = vch_next)
00905         {
00906             vch_next = vch->next;
00907 
00908             if (vch->in_room == ch->in_room
00909                 && get_trust (vch) < get_trust (ch) && can_see (ch, vch))
00910             {
00911                 interpret (vch, argument);
00912             }
00913         }
00914     }
00915     else
00916     {
00917         CHAR_DATA *victim;
00918 
00919         if ((victim = get_char_room (ch, arg)) == NULL)
00920             return;
00921 
00922         if (victim == ch)
00923             return;
00924 
00925         interpret (victim, argument);
00926     }
00927 
00928     return;
00929 }
00930 
00931 /*
00932  * Lets the mobile force a group something. Must be mortal level.
00933  *
00934  * Syntax: mob gforce [victim] [commands]
00935  */
00936 void do_mpgforce (CHAR_DATA * ch, char *argument)
00937 {
00938     char arg[MAX_INPUT_LENGTH];
00939     CHAR_DATA *victim, *vch, *vch_next;
00940 
00941     argument = one_argument (argument, arg);
00942 
00943     if (arg[0] == '\0' || argument[0] == '\0')
00944     {
00945         bug ("MpGforce - Bad syntax from vnum %d.",
00946              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00947         return;
00948     }
00949 
00950     if ((victim = get_char_room (ch, arg)) == NULL)
00951         return;
00952 
00953     if (victim == ch)
00954         return;
00955 
00956     for (vch = victim->in_room->people; vch != NULL; vch = vch_next)
00957     {
00958         vch_next = vch->next_in_room;
00959 
00960         if (is_same_group (victim, vch))
00961         {
00962             interpret (vch, argument);
00963         }
00964     }
00965     return;
00966 }
00967 
00968 /*
00969  * Forces all mobiles of certain vnum to do something (except ch)
00970  *
00971  * Syntax: mob vforce [vnum] [commands]
00972  */
00973 void do_mpvforce (CHAR_DATA * ch, char *argument)
00974 {
00975     CHAR_DATA *victim, *victim_next;
00976     char arg[MAX_INPUT_LENGTH];
00977     int vnum;
00978 
00979     argument = one_argument (argument, arg);
00980 
00981     if (arg[0] == '\0' || argument[0] == '\0')
00982     {
00983         bug ("MpVforce - Bad syntax from vnum %d.",
00984              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00985         return;
00986     }
00987 
00988     if (!is_number (arg))
00989     {
00990         bug ("MpVforce - Non-number argument vnum %d.",
00991              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
00992         return;
00993     }
00994 
00995     vnum = atoi (arg);
00996 
00997     for (victim = char_list; victim; victim = victim_next)
00998     {
00999         victim_next = victim->next;
01000         if (IS_NPC (victim) && victim->pIndexData->vnum == vnum
01001             && ch != victim && victim->fighting == NULL)
01002             interpret (victim, argument);
01003     }
01004     return;
01005 }
01006 
01007 
01008 /*
01009  * Lets the mobile cast spells --
01010  * Beware: this does only crude checking on the target validity
01011  * and does not account for mana etc., so you should do all the
01012  * necessary checking in your mob program before issuing this cmd!
01013  *
01014  * Syntax: mob cast [spell] {target}
01015  */
01016 
01017 void do_mpcast (CHAR_DATA * ch, char *argument)
01018 {
01019     CHAR_DATA *vch;
01020     OBJ_DATA *obj;
01021     void *victim = NULL;
01022     char spell[MAX_INPUT_LENGTH], target[MAX_INPUT_LENGTH];
01023     int sn;
01024 
01025     argument = one_argument (argument, spell);
01026     one_argument (argument, target);
01027 
01028     if (spell[0] == '\0')
01029     {
01030         bug ("MpCast - Bad syntax from vnum %d.",
01031              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01032         return;
01033     }
01034 
01035     if ((sn = skill_lookup (spell)) < 0)
01036     {
01037         bug ("MpCast - No such spell from vnum %d.",
01038              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01039         return;
01040     }
01041     vch = get_char_room (ch, target);
01042     obj = get_obj_here (ch, target);
01043     switch (skill_table[sn].target)
01044     {
01045         default:
01046             return;
01047         case TAR_IGNORE:
01048             break;
01049         case TAR_CHAR_OFFENSIVE:
01050             if (vch == NULL || vch == ch)
01051                 return;
01052             victim = (void *) vch;
01053             break;
01054         case TAR_CHAR_DEFENSIVE:
01055             victim = vch == NULL ? (void *) ch : (void *) vch;
01056             break;
01057         case TAR_CHAR_SELF:
01058             victim = (void *) ch;
01059             break;
01060         case TAR_OBJ_CHAR_DEF:
01061         case TAR_OBJ_CHAR_OFF:
01062         case TAR_OBJ_INV:
01063             if (obj == NULL)
01064                 return;
01065             victim = (void *) obj;
01066     }
01067     (*skill_table[sn].spell_fun) (sn, ch->level, ch, victim,
01068                                   skill_table[sn].target);
01069     return;
01070 }
01071 
01072 /*
01073  * Lets mob cause unconditional damage to someone. Nasty, use with caution.
01074  * Also, this is silent, you must show your own damage message...
01075  *
01076  * Syntax: mob damage [victim] [min] [max] {kill}
01077  */
01078 void do_mpdamage (CHAR_DATA * ch, char *argument)
01079 {
01080     CHAR_DATA *victim = NULL, *victim_next;
01081     char target[MAX_INPUT_LENGTH],
01082         min[MAX_INPUT_LENGTH], max[MAX_INPUT_LENGTH];
01083     int low, high;
01084     bool fAll = FALSE, fKill = FALSE;
01085 
01086     argument = one_argument (argument, target);
01087     argument = one_argument (argument, min);
01088     argument = one_argument (argument, max);
01089 
01090     if (target[0] == '\0')
01091     {
01092         bug ("MpDamage - Bad syntax from vnum %d.",
01093              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01094         return;
01095     }
01096     if (!str_cmp (target, "all"))
01097         fAll = TRUE;
01098     else if ((victim = get_char_room (ch, target)) == NULL)
01099         return;
01100 
01101     if (is_number (min))
01102         low = atoi (min);
01103     else
01104     {
01105         bug ("MpDamage - Bad damage min vnum %d.",
01106              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01107         return;
01108     }
01109     if (is_number (max))
01110         high = atoi (max);
01111     else
01112     {
01113         bug ("MpDamage - Bad damage max vnum %d.",
01114              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01115         return;
01116     }
01117     one_argument (argument, target);
01118 
01119     /*
01120      * If kill parameter is omitted, this command is "safe" and will not
01121      * kill the victim.
01122      */
01123 
01124     if (target[0] != '\0')
01125         fKill = TRUE;
01126     if (fAll)
01127     {
01128         for (victim = ch->in_room->people; victim; victim = victim_next)
01129         {
01130             victim_next = victim->next_in_room;
01131             if (victim != ch)
01132                 damage (victim, victim,
01133                         fKill ?
01134                         number_range (low, high) : UMIN (victim->hit,
01135                                                          number_range (low,
01136                                                                        high)),
01137                         TYPE_UNDEFINED, DAM_NONE, FALSE);
01138         }
01139     }
01140     else
01141         damage (victim, victim,
01142                 fKill ?
01143                 number_range (low, high) : UMIN (victim->hit,
01144                                                  number_range (low, high)),
01145                 TYPE_UNDEFINED, DAM_NONE, FALSE);
01146     return;
01147 }
01148 
01149 /*
01150  * Lets the mobile to remember a target. The target can be referred to
01151  * with $q and $Q codes in MOBprograms. See also "mob forget".
01152  *
01153  * Syntax: mob remember [victim]
01154  */
01155 void do_mpremember (CHAR_DATA * ch, char *argument)
01156 {
01157     char arg[MAX_INPUT_LENGTH];
01158     one_argument (argument, arg);
01159     if (arg[0] != '\0')
01160         ch->mprog_target = get_char_world (ch, arg);
01161     else
01162         bug ("MpRemember: missing argument from vnum %d.",
01163              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01164 }
01165 
01166 /*
01167  * Reverse of "mob remember".
01168  *
01169  * Syntax: mob forget
01170  */
01171 void do_mpforget (CHAR_DATA * ch, char *argument)
01172 {
01173     ch->mprog_target = NULL;
01174 }
01175 
01176 /*
01177  * Sets a delay for MOBprogram execution. When the delay time expires,
01178  * the mobile is checked for a MObprogram with DELAY trigger, and if
01179  * one is found, it is executed. Delay is counted in PULSE_MOBILE
01180  *
01181  * Syntax: mob delay [pulses]
01182  */
01183 void do_mpdelay (CHAR_DATA * ch, char *argument)
01184 {
01185     char arg[MAX_INPUT_LENGTH];
01186 
01187     one_argument (argument, arg);
01188     if (!is_number (arg))
01189     {
01190         bug ("MpDelay: invalid arg from vnum %d.",
01191              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01192         return;
01193     }
01194     ch->mprog_delay = atoi (arg);
01195 }
01196 
01197 /*
01198  * Reverse of "mob delay", deactivates the timer.
01199  *
01200  * Syntax: mob cancel
01201  */
01202 void do_mpcancel (CHAR_DATA * ch, char *argument)
01203 {
01204     ch->mprog_delay = -1;
01205 }
01206 
01207 /*
01208  * Lets the mobile to call another MOBprogram withing a MOBprogram.
01209  * This is a crude way to implement subroutines/functions. Beware of
01210  * nested loops and unwanted triggerings... Stack usage might be a problem.
01211  * Characters and objects referred to must be in the same room with the
01212  * mobile.
01213  *
01214  * Syntax: mob call [vnum] [victim|'null'] [object1|'null'] [object2|'null']
01215  *
01216  */
01217 void do_mpcall (CHAR_DATA * ch, char *argument)
01218 {
01219     char arg[MAX_INPUT_LENGTH];
01220     CHAR_DATA *vch;
01221     OBJ_DATA *obj1, *obj2;
01222     MPROG_CODE *prg;
01223     extern void program_flow ( int vnum, char *, CHAR_DATA *, CHAR_DATA *,
01224                               const void *, const void *);
01225 
01226     argument = one_argument (argument, arg);
01227     if (arg[0] == '\0')
01228     {
01229         bug ("MpCall: missing arguments from vnum %d.",
01230              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01231         return;
01232     }
01233     if ((prg = get_mprog_index (atoi (arg))) == NULL)
01234     {
01235         bug ("MpCall: invalid prog from vnum %d.",
01236              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01237         return;
01238     }
01239     vch = NULL;
01240     obj1 = obj2 = NULL;
01241     argument = one_argument (argument, arg);
01242     if (arg[0] != '\0')
01243         vch = get_char_room (ch, arg);
01244     argument = one_argument (argument, arg);
01245     if (arg[0] != '\0')
01246         obj1 = get_obj_here (ch, arg);
01247     argument = one_argument (argument, arg);
01248     if (arg[0] != '\0')
01249         obj2 = get_obj_here (ch, arg);
01250     program_flow (prg->vnum, prg->code, ch, vch, (void *) obj1,
01251                   (void *) obj2);
01252 }
01253 
01254 /*
01255  * Forces the mobile to flee.
01256  *
01257  * Syntax: mob flee
01258  *
01259  */
01260 void do_mpflee (CHAR_DATA * ch, char *argument)
01261 {
01262     ROOM_INDEX_DATA *was_in;
01263     EXIT_DATA *pexit;
01264     int door, attempt;
01265 
01266     if (ch->fighting != NULL)
01267         return;
01268 
01269     if ((was_in = ch->in_room) == NULL)
01270         return;
01271 
01272     for (attempt = 0; attempt < 9; attempt++)
01273     {
01274         door = number_door ();
01275         if ((pexit = was_in->exit[door]) == 0
01276             || pexit->u1.to_room == NULL
01277             || IS_SET (pexit->exit_info, EX_CLOSED) || (IS_NPC (ch)
01278                                                         && IS_SET (pexit->
01279                                                                    u1.to_room->room_flags,
01280                                                                    ROOM_NO_MOB)))
01281             continue;
01282 
01283         move_char (ch, door, FALSE);
01284         if (ch->in_room != was_in)
01285             return;
01286     }
01287 }
01288 
01289 /*
01290  * Lets the mobile to transfer an object. The object must be in the same
01291  * room with the mobile.
01292  *
01293  * Syntax: mob otransfer [item name] [location]
01294  */
01295 void do_mpotransfer (CHAR_DATA * ch, char *argument)
01296 {
01297     OBJ_DATA *obj;
01298     ROOM_INDEX_DATA *location;
01299     char arg[MAX_INPUT_LENGTH];
01300     char buf[MAX_INPUT_LENGTH];
01301 
01302     argument = one_argument (argument, arg);
01303     if (arg[0] == '\0')
01304     {
01305         bug ("MpOTransfer - Missing argument from vnum %d.",
01306              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01307         return;
01308     }
01309     one_argument (argument, buf);
01310     if ((location = find_location (ch, buf)) == NULL)
01311     {
01312         bug ("MpOTransfer - No such location from vnum %d.",
01313              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01314         return;
01315     }
01316     if ((obj = get_obj_here (ch, arg)) == NULL)
01317         return;
01318     if (obj->carried_by == NULL)
01319         obj_from_room (obj);
01320     else
01321     {
01322         if (obj->wear_loc != WEAR_NONE)
01323             unequip_char (ch, obj);
01324         obj_from_char (obj);
01325     }
01326     obj_to_room (obj, location);
01327 }
01328 
01329 /*
01330  * Lets the mobile to strip an object or all objects from the victim.
01331  * Useful for removing e.g. quest objects from a character.
01332  *
01333  * Syntax: mob remove [victim] [object vnum|'all']
01334  */
01335 void do_mpremove (CHAR_DATA * ch, char *argument)
01336 {
01337     CHAR_DATA *victim;
01338     OBJ_DATA *obj, *obj_next;
01339     int vnum = 0;
01340     bool fAll = FALSE;
01341     char arg[MAX_INPUT_LENGTH];
01342 
01343     argument = one_argument (argument, arg);
01344     if ((victim = get_char_room (ch, arg)) == NULL)
01345         return;
01346 
01347     one_argument (argument, arg);
01348     if (!str_cmp (arg, "all"))
01349         fAll = TRUE;
01350     else if (!is_number (arg))
01351     {
01352         bug ("MpRemove: Invalid object from vnum %d.",
01353              IS_NPC (ch) ? ch->pIndexData->vnum : 0);
01354         return;
01355     }
01356     else
01357         vnum = atoi (arg);
01358 
01359     for (obj = victim->carrying; obj; obj = obj_next)
01360     {
01361         obj_next = obj->next_content;
01362         if (fAll || obj->pIndexData->vnum == vnum)
01363         {
01364             unequip_char (ch, obj);
01365             obj_from_char (obj);
01366             extract_obj (obj);
01367         }
01368     }
01369 }

Generated on Thu Jan 13 21:48:12 2005 for Beyond the Shadows by  doxygen 1.4.0