/*************************************************************************** * MOBProgram ported for CircleMUD 3.0 by Mattias Larsson * * Traveller@AnotherWorld (ml@eniac.campus.luth.se 4000) * **************************************************************************/ /*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * 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. * ***************************************************************************/ /*************************************************************************** * The MOBprograms have been contributed by N'Atas-ha. Any support for * * these routines should not be expected from Merc Industries. However, * * under no circumstances should the blame for bugs, etc be placed on * * Merc Industries. They are not guaranteed to work on all systems due * * to their frequent use of strxxx functions. They are also not the most * * efficient way to perform their tasks, but hopefully should be in the * * easiest possible way to install and begin using. Documentation for * * such installation can be found in INSTALL. Enjoy........ N'Atas-Ha * ***************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include "structs.h" #include "db.h" #include "utils.h" #include "handler.h" #include "interpreter.h" #include "comm.h" extern struct index_data *mob_index; extern struct room_data *world; extern struct index_data *obj_index; extern struct descriptor_data *descriptor_list; extern struct index_data *get_mob_index(int vnum); extern struct index_data *get_obj_index(int vnum); extern sh_int find_target_room(struct char_data * ch, char *rawroomstr); #define bug(x, y) { sprintf(buf2, (x), (y)); log(buf2); } /* * Local functions. */ char * mprog_type_to_name (int type); /* This routine transfers between alpha and numeric forms of the * mob_prog bitvector types. It allows the words to show up in mpstat to * make it just a hair bit easier to see what a mob should be doing. */ char *mprog_type_to_name(int type) { switch (type) { case IN_FILE_PROG: return "in_file_prog"; case ACT_PROG: return "act_prog"; case SPEECH_PROG: return "speech_prog"; case RAND_PROG: return "rand_prog"; case FIGHT_PROG: return "fight_prog"; case HITPRCNT_PROG: return "hitprcnt_prog"; case DEATH_PROG: return "death_prog"; case ENTRY_PROG: return "entry_prog"; case GREET_PROG: return "greet_prog"; case ALL_GREET_PROG: return "all_greet_prog"; case GIVE_PROG: return "give_prog"; case BRIBE_PROG: return "bribe_prog"; default: return "ERROR_PROG"; } } /* string prefix routine */ bool str_prefix(const char *astr, const char *bstr) { if (!astr) { log("Strn_cmp: null astr."); return TRUE; } if (!bstr) { log("Strn_cmp: null astr."); return TRUE; } for(; *astr; astr++, bstr++) { if(LOWER(*astr) != LOWER(*bstr)) return TRUE; } return FALSE; } /* prints the argument to all the rooms aroud the mobile */ ACMD(do_mpasound) { room_num was_in_room; int door; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } if (argument[0] == '\0') { bug("Mpasound - No argument: vnum %d.", mob_index[ch->nr].virtual); return; } one_argument(argument, arg); was_in_room = ch->in_room; for (door = 0; door <= 5; door++) { struct room_direction_data *pexit; if ((pexit = world[was_in_room].dir_option[door]) != NULL && pexit->to_room != NOWHERE && pexit->to_room != was_in_room) { ch->in_room = pexit->to_room; MOBTrigger = FALSE; act(arg, FALSE, ch, NULL, NULL, TO_ROOM); } } ch->in_room = was_in_room; return; } /* lets the mobile kill any player or mobile without murder*/ ACMD(do_mpkill) { char arg[ MAX_INPUT_LENGTH ]; struct char_data *victim; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } one_argument(argument, arg); if (arg[0] == '\0') { bug("MpKill - no argument: vnum %d.", mob_index[ch->nr].virtual); return; } if ((victim = get_char_room_vis(ch, arg)) == NULL) { bug("MpKill - Victim not in room: vnum %d.", mob_index[ch->nr].virtual); return; } if (victim == ch) { bug("MpKill - Bad victim to attack: vnum %d.", mob_index[ch->nr].virtual); return; } if (IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim) { bug("MpKill - Charmed mob attacking master: vnum %d.", mob_index[ch->nr].virtual); return; } if (ch->char_specials.position == POS_FIGHTING) { bug("MpKill - Already fighting: vnum %d", mob_index[ch->nr].virtual); return; } hit(ch, victim, -1); 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 */ ACMD(do_mpjunk) { char arg[ MAX_INPUT_LENGTH ]; int pos; struct obj_data *obj; struct obj_data *obj_next; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } one_argument(argument, arg); if (arg[0] == '\0') { bug("Mpjunk - No argument: vnum %d.", mob_index[ch->nr].virtual); return; } if (str_cmp(arg, "all") && str_prefix("all.", arg)) { if ((obj=get_object_in_equip_vis(ch,arg,ch->equipment,&pos))!= NULL) { unequip_char(ch, pos); extract_obj(obj); return; } if ((obj = get_obj_in_list_vis(ch, arg, ch->carrying)) != NULL) extract_obj(obj); return; } else { for (obj = ch->carrying; obj != NULL; obj = obj_next) { obj_next = obj->next_content; if (arg[3] == '\0' || isname(arg+4, obj->name)) { extract_obj(obj); } } while((obj=get_object_in_equip_vis(ch,arg,ch->equipment,&pos))!=NULL){ unequip_char(ch, pos); extract_obj(obj); } } return; } /* prints the message to everyone in the room other than the mob and victim */ ACMD(do_mpechoaround) { char arg[ MAX_INPUT_LENGTH ]; struct char_data *victim; char *p; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } p=one_argument(argument, arg); while(isspace(*p)) p++; /* skip over leading space */ if (arg[0] == '\0') { bug("Mpechoaround - No argument: vnum %d.", mob_index[ch->nr].virtual); return; } if (!(victim=get_char_room_vis(ch, arg))) { bug("Mpechoaround - victim does not exist: vnum %d.", mob_index[ch->nr].virtual); return; } act(p, FALSE, ch, NULL, victim, TO_NOTVICT); return; } /* prints the message to only the victim */ ACMD(do_mpechoat) { char arg[ MAX_INPUT_LENGTH ]; struct char_data *victim; char *p; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } p = one_argument(argument, arg); while(isspace(*p)) p++; /* skip over leading space */ if (arg[0] == '\0') { bug("Mpechoat - No argument: vnum %d.", mob_index[ch->nr].virtual); return; } if (!(victim = get_char_room_vis(ch, arg))) { bug("Mpechoat - victim does not exist: vnum %d.", mob_index[ch->nr].virtual); return; } act(p,FALSE, ch, NULL, victim, TO_VICT); return; } /* prints the message to the room at large */ ACMD(do_mpecho) { char *p; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } if (argument[0] == '\0') { bug("Mpecho - called w/o argument: vnum %d.", mob_index[ch->nr].virtual); return; } p = argument; while(isspace(*p)) p++; act(p,FALSE, ch, NULL, NULL, TO_ROOM); 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. */ ACMD(do_mpmload) { char arg[ MAX_INPUT_LENGTH ]; struct index_data *pMobIndex; struct char_data *victim; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } one_argument(argument, arg); if (arg[0] == '\0' || !is_number(arg)) { bug("Mpmload - Bad vnum as arg: vnum %d.", mob_index[ch->nr].virtual); return; } if ((pMobIndex = get_mob_index(atoi(arg))) == NULL) { bug("Mpmload - Bad mob vnum: vnum %d.", mob_index[ch->nr].virtual); return; } victim = read_mobile(atoi(arg), VIRTUAL); char_to_room(victim, ch->in_room); return; } ACMD(do_mpoload) { char arg1[ MAX_INPUT_LENGTH ]; struct index_data *pObjIndex; struct obj_data *obj; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } argument = one_argument(argument, arg1); if (arg1[0] == '\0' || !is_number(arg1)) { bug("Mpoload - Bad syntax: vnum %d.", mob_index[ch->nr].virtual); return; } if ((pObjIndex = get_obj_index(atoi(arg1))) == NULL) { bug("Mpoload - Bad vnum arg: vnum %d.", mob_index[ch->nr].virtual); return; } obj = read_object(atoi(arg1), VIRTUAL); if (obj == NULL) return; if (CAN_WEAR(obj, ITEM_WEAR_TAKE)) { obj_to_char(obj, ch); } else { obj_to_room(obj, ch->in_room); } 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 */ ACMD(do_mppurge) { struct char_data *victim; struct obj_data *obj; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } one_argument(argument, arg); if (arg[0] == '\0') { /* 'purge' */ struct char_data *vnext; struct obj_data *obj_next; for (victim = world[ch->in_room].people; victim != NULL; victim = vnext) { vnext = victim->next_in_room; if (IS_NPC(victim) && victim != ch) extract_char(victim); } for (obj = world[ch->in_room].contents; obj != NULL; obj = obj_next) { obj_next = obj->next_content; extract_obj(obj); } return; } if (!(victim = get_char_room_vis(ch, arg))) { if ((obj = get_obj_vis(ch, arg))) { extract_obj(obj); } else { bug("Mppurge - Bad argument: vnum %d.",mob_index[ch->nr].virtual); } return; } if (!IS_NPC(victim)) { bug("Mppurge - Purging a PC: vnum %d.", mob_index[ch->nr].virtual); return; } extract_char(victim); return; } /* lets the mobile goto any location it wishes that is not private */ ACMD(do_mpgoto) { char arg[ MAX_INPUT_LENGTH ]; sh_int location; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } one_argument(argument, arg); if (arg[0] == '\0') { bug("Mpgoto - No argument: vnum %d.", mob_index[ch->nr].virtual); return; } if ((location = find_target_room(ch, arg)) < 0) { bug("Mpgoto - No such location: vnum %d.", mob_index[ch->nr].virtual); return; } if (FIGHTING(ch) != NULL) stop_fighting(ch); char_from_room(ch); char_to_room(ch, location); return; } /* lets the mobile do a command at another location. Very useful */ ACMD(do_mpat) { char arg[ MAX_INPUT_LENGTH ]; sh_int location; sh_int original; /* struct char_data *wch; */ if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } argument = one_argument(argument, arg); if (arg[0] == '\0' || argument[0] == '\0') { bug("Mpat - Bad argument: vnum %d.", mob_index[ch->nr].virtual); return; } if ((location = find_target_room(ch, arg)) < 0) { bug("Mpat - No such location: vnum %d.", mob_index[ch->nr].virtual); return; } original = ch->in_room; char_from_room(ch); char_to_room(ch, location); command_interpreter(ch, argument); /* * See if 'ch' still exists before continuing! * Handles 'at XXXX quit' case. */ if(ch->in_room == location) { char_from_room(ch); char_to_room(ch, original); } return; } /* lets the mobile transfer people. the all argument transfers everyone in the current room to the specified location */ ACMD(do_mptransfer) { char arg1[ MAX_INPUT_LENGTH ]; char arg2[ MAX_INPUT_LENGTH ]; sh_int location; struct descriptor_data *d; struct char_data *victim; ACMD(do_trans); if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (arg1[0] == '\0') { bug("Mptransfer - Bad syntax: vnum %d.", mob_index[ch->nr].virtual); return; } if (!str_cmp(arg1, "all")) { for (d = descriptor_list; d != NULL; d = d->next) { if (d->connected == CON_PLAYING && d->character != ch && d->character->in_room != NOWHERE && CAN_SEE(ch, d->character)) { char buf[MAX_STRING_LENGTH]; sprintf(buf, "%s %s", d->character->player.name, arg2); do_trans(ch, buf, cmd, 0); } } return; } /* * Thanks to Grodyn for the optional location parameter. */ if (arg2[0] == '\0') { location = ch->in_room; } else { if ((location = find_target_room(ch, arg2)) < 0) { bug("Mptransfer - No such location: vnum %d.", mob_index[ch->nr].virtual); return; } if (IS_SET(world[location].room_flags, ROOM_PRIVATE)) { bug("Mptransfer - Private room: vnum %d.", mob_index[ch->nr].virtual); return; } } if ((victim = get_char_vis(ch, arg1)) == NULL) { bug("Mptransfer - No such person: vnum %d.", mob_index[ch->nr].virtual); return; } if (victim->in_room == 0) { bug("Mptransfer - Victim in Limbo: vnum %d.", mob_index[ch->nr].virtual); return; } if (FIGHTING(victim) != NULL) stop_fighting(victim); char_from_room(victim); char_to_room(victim, location); 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 */ ACMD(do_mpforce) { char arg[ MAX_INPUT_LENGTH ]; if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM) || ch->desc) { send_to_char("Huh?\n\r", ch); return; } argument = one_argument(argument, arg); if (arg[0] == '\0' || argument[0] == '\0') { bug("Mpforce - Bad syntax: vnum %d.", mob_index[ch->nr].virtual); return; } if (!str_cmp(arg, "all")) { struct descriptor_data *i; struct char_data *vch; for (i = descriptor_list; i ; i = i->next) { if(i->character != ch && !i->connected && i->character->in_room == ch->in_room) { vch = i->character; if(GET_LEVEL(vch) < GET_LEVEL(ch) && CAN_SEE(ch, vch)) { command_interpreter(vch, argument); } } } } else { struct char_data *victim; if ((victim = get_char_room_vis(ch, arg)) == NULL) { bug("Mpforce - No such victim: vnum %d.", mob_index[ch->nr].virtual); return; } if (victim == ch) { bug("Mpforce - Forcing oneself: vnum %d.", mob_index[ch->nr].virtual); return; } command_interpreter(victim, argument); } return; }