/***************************************************************************
* 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 "class.h"
#include "objs.h"
#include "rooms.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, world[ch->in_room].zone);
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, world[ch->in_room].zone);
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;
}