/************************************************************************ Realms of Aurealis James Rhone aka Vall of RoA RoA MobProc code version 1.0 Beta mobproc.c Realms of Aurealis MobProc code, specifically written for RoA with OLCable MobProcs in mind... note this is completely ORIGINAL code, as you can tell by its crude form :P, this is NOT an adaptation from any other type of MobProc form out there, specifically Merc, which I happen to loathe, and which in itself is not amenable to Online Creation... For use with RoAOLCv2.0 or any other similar OLC and only with the consent of myself, JRhone... See wizhelp files for fairly complete info on how to create and use these mobprocs and what commands are available. ******** 100% completely original code ******** *** BE AWARE OF ALL RIGHTS AND RESERVATIONS *** ******** 100% completely original code ******** All rights reserved henceforth. Please note that no guarantees are associated with any code from Realms of Aurealis. All code which has been released to the general public has been done so with an 'as is' pretense. RoA is based on both Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well as the RoA license. *** Read, Learn, Understand, Improve *** *************************************************************************/ #include "conf.h" #include "sysdep.h" #include "structures.h" #include "utils.h" #include "db.h" #include "comm.h" #include "interpreter.h" #include "handler.h" #include "magic.h" #include "mobproc.h" #include "acmd.h" #include "quest.h" #include "lists.h" #include "htown.h" #include "clicomm.h" #include "global.h" /* external vars */ extern char *genders[]; extern struct htown_data htowns[]; // external functions extern struct mtrig_type *free_mtriggers(struct mtrig_type *head); #define MAX_MOB_REACTIONS 10 #define MAX_MOB_REACTION_LENGTH 1024 /* simple structure for corresponding mobproc calls... */ const struct mproc_type mproc_calls[] = { {"mtarget", do_mtarget}, {"mtargetroom", do_mtarget}, {"mtargetzone", do_mtarget_zone}, {"mtargetset", do_mtarget_set}, {"mreset", do_mreset}, {"mstart", do_mstart}, {"mend", do_mend}, {"mgoto", do_mgoto}, {"mif", do_mif}, {"mpause", do_mpause}, {"mrandom", do_mrandom}, {"mtelezone", do_mtele_zone}, {"mhunt", do_mhunt}, {"mtrigwait", do_mtrig_wait}, {"mtrigoff", do_mtrig_off}, {"mtrigon", do_mtrig_on}, {"mtrigwax", do_mtrig_wax}, {"mtrigadd", do_mtrig_add}, {"mtrigdelete", do_mtrig_delete}, {"msoundsendchar", do_msoundsendchar}, {"msoundsendroom", do_msoundsendroom}, {"mtag", do_mtag}, {"", NULL} /* last one used for check of end of defines */ }; // what MIF checks are available? char *mif_BOOLs[] = { "tarcharset", "!tarcharset", "tarobjset", "!tarobjset", "tarcharroom", "!tarcharroom", "tarobjroom", "!tarobjroom", "tarcharzone", "!tarcharzone", "tarobjzone", "!tarobjzone", "tarcharpc", "!tarcharpc", "tarcharcompquest", "!tarcharcompquest", "tarcharlevel", "inroom", "!inroom", "npcinroom", "!npcinroom", "objinroom", "!objinroom", "objinv", "!objinv", "objeq", "!objeq", "mfighting", "!mfighting", "transpresent", "!transpresent", "tarcharonquest", "!tarcharonquest", "tarcharrace", "!tarcharrace", "tarcharclass", "!tarcharclass", "tarchargender", "!tarchargender", "\n" }; // let immortal see all mobproc commands available ACMD(do_mobproc_show) { int i,j; one_argument(argument, arg); if (is_abbrev(arg, "mcommands")) { strcpy(buf, "%B%6MobProc Mob Commands%0:\n\r"); for (i=j=0; *mproc_calls[i].arg; i++) { sprintf(buf+strlen(buf), "%%5%%B%-19.19s%%0", mproc_calls[i].arg); if (!(++j % 4)) strcat(buf, "\n\r"); } if ((j%4)) strcat(buf, "\n\r"); page_string(ch->desc, buf, 1); } else if (is_abbrev(arg, "mifs")) { strcpy(buf, "%B%6MobProc Mob MIF Args%0:\n\r"); for (i=j=0; *mif_BOOLs[i] != '\n'; i++) { sprintf(buf+strlen(buf), "%%5%%B%-19.19s%%0", mif_BOOLs[i]); if (!(++j % 4)) strcat(buf, "\n\r"); } if ((j%4)) strcat(buf, "\n\r"); page_string(ch->desc, buf, 1); } else send_to_char("Usage: mprocshow < mcommands | mifs >.\n\r",ch); } // count number of objects in the mobs room int num_obj_room(chdata *mob) { int i; obdata *obj = world[mob->in_room].contents; for (i=0; obj; obj=obj->next_content, i++) ; return i; } // return ptr to the numTH item in mob's room obdata *get_obj_room(chdata *mob, int num) { int i; obdata *obj = world[mob->in_room].contents; for (i = 0; i < num && obj; obj=obj->next_content, i++) if (i == num) break; return obj; } // return ptr to the numTH object in mob's zone obdata* get_obj_zone(chdata *mob, int num) { int i; obdata *obj = object_list; for (i=0; obj && i < num; obj=obj->next) { if (INVALID_ROOM(obj->in_room)) continue; if (world[obj->in_room].zone == world[mob->in_room].zone) i++; if (i == num) return obj; } return NULL; } // return how many objects are in ROOMS in mob's zone int num_obj_zone(chdata *mob) { int i; obdata *obj = object_list; for (i=0; obj; obj=obj->next) { if (INVALID_ROOM(obj->in_room)) continue; if (world[obj->in_room].zone == world[mob->in_room].zone) i++; } return i; } // target counters for ROOMS int num_pc_room(chdata *mob) { int i; chdata *vict = world[mob->in_room].people; for (i=0; vict; vict = vict->next_in_room) if (IS_PC(vict) && vict != mob) i++; return i; } int num_npc_room(chdata *mob) { int i; chdata *vict = world[mob->in_room].people; for (i=0; vict; vict = vict->next_in_room) if (IS_NPC(vict) && vict != mob) i++; return i; } int num_any_room(chdata *mob) { int i; chdata *vict = world[mob->in_room].people; for (i=0; vict; vict = vict->next_in_room) if (vict != mob) i++; return i; } // target counters for ZONE int num_any_zone(chdata *mob) { int i; chdata *vict; int zone = world[mob->in_room].zone; for (i=0, vict = character_list; vict; vict = vict->next) if (world[vict->in_room].zone == zone && vict != mob) i++; return i; } int num_npc_zone(chdata *mob) { int i; chdata *vict; int zone = world[mob->in_room].zone; for (i=0, vict = character_list; vict; vict = vict->next) if (IS_NPC(vict) && world[vict->in_room].zone == zone && vict != mob) i++; return i; } int num_pc_zone(chdata *mob) { int i; chdata *vict; int zone = world[mob->in_room].zone; for (i=0, vict = character_list; vict; vict = vict->next) if (IS_PC(vict) && world[vict->in_room].zone == zone && vict != mob) i++; return i; } // targetting functions for ROOM chdata *get_any_room(chdata *mob, int num) { int i; chdata *vict = world[mob->in_room].people; for (i = 0; i < num && vict; vict = vict->next_in_room) { if (vict != mob) i++; if (i == num) break; } return vict; } chdata *get_pc_room(chdata *mob, int num) { int i; chdata *vict = world[mob->in_room].people; for (i = 0; i < num && vict; vict = vict->next_in_room) { if (IS_PC(vict) && vict != mob) i++; if (i == num) break; } return vict; } chdata *get_npc_room(chdata *mob, int num) { int i; chdata *vict = world[mob->in_room].people; for (i = 0; i < num && vict; vict = vict->next_in_room) { if (IS_NPC(vict) && vict != mob) i++; if (i == num) break; } return vict; } // targetting functions for ZONE chdata *get_any_zone(chdata *mob, int num) { int i; chdata *vict; for (i = 0, vict = character_list; vict && i < num; vict = vict->next) { if (INVALID_ROOM(vict->in_room)) continue; if (world[vict->in_room].zone == world[mob->in_room].zone && mob != vict) i++; if (i == num) return vict; } return NULL; } chdata *get_pc_zone(chdata *mob, int num) { int i; chdata *vict; for (i = 0, vict = character_list; vict && i < num; vict = vict->next) { if (INVALID_ROOM(vict->in_room)) continue; if (world[vict->in_room].zone == world[mob->in_room].zone && mob != vict && IS_PC(vict)) i++; if (i == num) return vict; } return NULL; } chdata *get_npc_zone(chdata *mob, int num) { int i; chdata *vict; for (i = 0, vict = character_list; vict && i < num; vict = vict->next) { if (INVALID_ROOM(vict->in_room)) continue; if (world[vict->in_room].zone == world[mob->in_room].zone && mob != vict && IS_NPC(vict)) i++; if (i == num) return vict; } return NULL; } // actual mobproc functions begin // msoundsendchar <char name> <soundfile name> // char must be in same room and have client connection int do_msoundsendchar(chdata *mob, char *comm) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; chdata *vict; half_chop(comm, arg1, arg2); if (!*arg1 || !*arg2) { sprintf(buf, "SYSERR: Invalid arguments sent to msoundsendchar (%s).", GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); send_to_char("Invalid argument to msoundsendchar...\n\r",mob); return MP_NORMAL; } if (!(vict = get_char_room_vis(mob, arg1))) { send_to_char("Target not found...\n\r",mob); return MP_NORMAL; } if (IS_PC(vict) && vict->desc && HAS_CLIENT(vict->desc)) { send_soundfile_to_client(vict->desc, arg2); send_to_char("Ok, soundfile sent...\n\r",mob); } else send_to_char("Target doesn't have client connection...\n\r",mob); return MP_NORMAL; } // msoundsendroom <soundfile name> // chars must be in same room and have client connection int do_msoundsendroom(chdata *mob, char *comm) { char arg1[MAX_INPUT_LENGTH]; chdata *vict; one_argument(comm, arg1); if (!*arg1) { sprintf(buf, "SYSERR: Invalid argument sent to msoundsendroom (%s).", GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); send_to_char("Invalid argument to msoundsendroom...\n\r",mob); return MP_NORMAL; } for (vict = world[mob->in_room].people; vict; vict=vict->next_in_room) if (IS_PC(vict) && vict->desc && HAS_CLIENT(vict->desc)) send_soundfile_to_client(vict->desc, arg1); return MP_NORMAL; } /* set a mobile's target character/object (in zone) */ int do_mtarget_zone(chdata *mob, char *comm) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int num, pick; chdata *vict = NULL; obdata *obj = NULL; BOOL pc, npc; pc = FALSE; npc = FALSE; half_chop(comm, arg1, arg2); if (!str_cmp(arg1, "char")) { if(TARGET_CHAR(mob)) free_log(TARGET_CHAR(mob), "do_mtarget_zone"); TARGET_CHAR(mob) = NULL; half_chop(arg2, arg1, arg2); if (!*arg1) { sprintf(buf, "SYSERR: Undefined char type (pc | npc | any) to mtargetzone (%s).", GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } else if (!str_cmp(arg1, "pc")) pc = TRUE; else if (!str_cmp(arg1, "npc")) npc = TRUE; else if (!str_cmp(arg1, "any")) { npc = TRUE; pc = TRUE; } else { sprintf(buf, "SYSERR: Undefined char type (pc | npc | any) to mtargetzone (%s).", GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } half_chop(arg2, arg1, arg2); if (!*arg1 || !is_number(arg1)) { sprintf(buf, "SYSERR: Undefined character number to mtargetzone (%s).",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if ((num = atoi(arg1))) /* if a number besides 0 is wanted */ { if ((!pc && (vict = get_npc_zone(mob, num))) || (!npc && (vict = get_pc_zone(mob, num))) || (pc && npc && (vict = get_any_zone(mob, num))) ) { if (MOB2_FLAGGED(vict, MOB2_NO_MTARGET)) return MP_MTARGET; TARGET_CHAR(mob) = str_dup(fname(vict->player.name)); sprintf(buf, "SYSUPD: %s setting char target to %s", GET_NAME(mob),fname(vict->player.name)); mudlog(buf, BUG, LEV_IMM, FALSE); } } else if (!num) /* this means pick a random character in the zone */ { pick = 0; if (!pc && num_npc_zone(mob)) pick = number(1, num_npc_zone(mob)); else if (!npc && num_pc_zone(mob)) pick = number(1, num_pc_zone(mob)); else if (pc && npc && num_any_zone(mob)) pick = number(1, num_any_zone(mob)); if (pick) { if ((!pc && (vict = get_npc_zone(mob, pick))) || (!npc && (vict = get_pc_zone(mob, pick))) || (pc && npc && (vict = get_any_zone(mob, pick))) ) { if (MOB2_FLAGGED(vict, MOB2_NO_MTARGET)) return MP_MTARGET; TARGET_CHAR(mob) = str_dup(fname(vict->player.name)); sprintf(buf, "SYSUPD: %s setting char target to %s", GET_NAME(mob), fname(vict->player.name)); mudlog(buf, BUG, LEV_IMM, FALSE); } } } } else if (!str_cmp(arg1, "obj")) { if(TARGET_OBJ(mob)) free_log(TARGET_OBJ(mob), "do_mtarget_zone 2"); TARGET_OBJ(mob) = NULL; half_chop(arg2, arg1, arg2); if (!*arg1 || !is_number(arg1)) { sprintf(buf, "SYSERR: Undefined object number to mtargetzone (%s).",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if ((num = atoi(arg1))) /* if a number besides 0 is wanted */ { num--; if ((obj = get_obj_zone(mob, num))) { sprintf(buf, "SYSUPD: %s setting obj target to %s", GET_NAME(mob), fname(obj->name)); mudlog(buf, BUG, LEV_IMM, FALSE); TARGET_OBJ(mob) = str_dup(fname(obj->name)); } } else if (!num && num_obj_zone(mob) && (obj = get_obj_zone(mob, number(0, (num_obj_zone(mob)-1))))) { sprintf(buf, "SYSUPD: %s setting obj target to %s", GET_NAME(mob), fname(obj->name)); mudlog(buf, BUG, LEV_IMM, FALSE); TARGET_OBJ(mob) = str_dup(fname(obj->name)); } } else { sprintf(buf, "SYSERR: Undefined arg (%s) to mtargetzone (%s).", arg1, GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } return MP_MTARGET; } /* set a mobile's target character/object (in room) */ int do_mtarget(chdata *mob, char *comm) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int num, pick; chdata *vict = NULL; obdata *obj = NULL; BOOL pc, npc; pc = FALSE; npc = FALSE; half_chop(comm, arg1, arg2); if (!str_cmp(arg1, "char")) { if(TARGET_CHAR(mob)) free_log(TARGET_CHAR(mob), "do_mtarget"); TARGET_CHAR(mob) = NULL; half_chop(arg2, arg1, arg2); if (!*arg1) { sprintf(buf, "SYSERR: Undefined char type (pc | npc | any) to mtarget (%s).",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } else if (!str_cmp(arg1, "pc")) pc = TRUE; else if (!str_cmp(arg1, "npc")) npc = TRUE; else if (!str_cmp(arg1, "any")) { npc = TRUE; pc = TRUE; } else { sprintf(buf, "SYSERR: Undefined char type (pc | npc | any) to mtarget (%s).",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } half_chop(arg2, arg1, arg2); if (!*arg1 || !is_number(arg1)) { sprintf(buf, "SYSERR: Undefined character number to mtarget (%s).",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if ((num = atoi(arg1))) /* if a number besides 0 is wanted */ { if ((!pc && (vict = get_npc_room(mob, num))) || (!npc && (vict = get_pc_room(mob, num))) || (pc && npc && (vict = get_any_room(mob, num))) ) { TARGET_CHAR(mob) = str_dup(fname(vict->player.name)); sprintf(buf, "SYSUPD: %s setting char target to %s", GET_NAME(mob), fname(vict->player.name)); mudlog(buf, BUG, LEV_IMM, FALSE); } } else if (!num) /* this means pick a random character in the room */ { pick = 0; if (!pc && num_npc_room(mob)) pick = number(1, num_npc_room(mob)); else if (!npc && num_pc_room(mob)) pick = number(1, num_pc_room(mob)); else if (pc && npc && num_any_room(mob)) pick = number(1, num_any_room(mob)); if (pick) { if ((!pc && (vict = get_npc_room(mob, pick))) || (!npc && (vict = get_pc_room(mob, pick))) || (pc && npc && (vict = get_any_room(mob, pick))) ) { TARGET_CHAR(mob) = str_dup(fname(vict->player.name)); sprintf(buf, "SYSUPD: %s setting char target to %s", GET_NAME(mob), fname(vict->player.name)); mudlog(buf, BUG, LEV_IMM, FALSE); } } } } else if (!str_cmp(arg1, "obj")) { if(TARGET_OBJ(mob)) free_log(TARGET_OBJ(mob), "do_mtarget 2"); TARGET_OBJ(mob) = NULL; half_chop(arg2, arg1, arg2); if (!*arg1 || !is_number(arg1)) { sprintf(buf, "SYSERR: Undefined object number to mtarget (%s).",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if ((num = atoi(arg1))) /* if a number besides 0 is wanted */ { num--; if ((obj = get_obj_room(mob, num))) { sprintf(buf, "SYSUPD: %s setting obj target to %s", GET_NAME(mob), fname(obj->name)); mudlog(buf, BUG, LEV_IMM, FALSE); TARGET_OBJ(mob) = str_dup(fname(obj->name)); } } else if (!num && num_obj_room(mob) && (obj = get_obj_room(mob, number(0, (num_obj_room(mob)-1))))) { sprintf(buf, "SYSUPD: %s setting obj target to %s", GET_NAME(mob), fname(obj->name)); mudlog(buf, BUG, LEV_IMM, FALSE); TARGET_OBJ(mob) = str_dup(fname(obj->name)); } } else { sprintf(buf, "SYSERR: Undefined arg (%s) to mtarget (%s).", arg1, GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } return MP_MTARGET; } // perform the mobproc subs // if ch, use ch for subs, else use TARGET_CHAR // if ob, use ob for subs, else use TARGET_OBJ BOOL do_mobproc_subs(chdata *mob, char *comm, chdata *ch, obdata *ob) { char newcomm[MAX_INPUT_LENGTH]; int i, j; if (!strchr(comm, '+')) return FALSE; // if ch wasnt passed, try to get a chdata ptr from target char if (!ch) if (TARGET_CHAR(mob)) if (!(ch = get_char_room_vis(mob, TARGET_CHAR(mob)))) if (!(ch = get_char_zone_vis(mob, TARGET_CHAR(mob)))) if (!(ch = get_char_vis(mob, TARGET_CHAR(mob)))) ; for (i=0, j=0; comm[i]; i++) { newcomm[j] = '\0'; if (comm[i] != '+') { newcomm[j] = comm[i]; j++; continue; } else if (comm[i+1]) { i++; switch (comm[i]) { case '+': /* double (++) means sub in one + */ newcomm[j] = comm[i]; j++; i++; break; case 'C': /* sub SHORT (NPC alias, PC normal) name of char target */ if (ch) { if (IS_PC(ch)) strcat(newcomm + j, GET_NAME(ch)); else strcat(newcomm + j, fname(ch->player.name)); j = strlen(newcomm); } else if (TARGET_CHAR(mob)) { strcat(newcomm + j, TARGET_CHAR(mob)); j = strlen(newcomm); } break; case 'N': case 'n': // normal name for pc, short desc for npc if (ch) { strcat(newcomm + j, GET_NAME(ch)); j = strlen(newcomm); } else if (TARGET_CHAR(mob)) { strcat(newcomm + j, TARGET_CHAR(mob)); j = strlen(newcomm); } /* if no sub there, ok, its as if we processed */ break; case 'R': case 'r': if (ch) { strcat(newcomm + j, rcarray[GET_RACE(ch)].race_name); j = strlen(newcomm); } break; case 'L': case 'l': if (ch) { strcat(newcomm + j, gskill_names[SPEAKING(ch)]); j = strlen(newcomm); } break; case 'H': case 'h': if (ch && htowns[GET_HTOWN(ch)].name) { strcat(newcomm + j, htowns[GET_HTOWN(ch)].name); j = strlen(newcomm); } break; case 'c': /* class, if incog sub race instead */ if (ch) { if (PRF_FLAGGED(ch, PRF_INCOGNITO)) strcat(newcomm + j, rcarray[GET_RACE(ch)].race_name); else strcat(newcomm + j, clarray[(int)GET_CLASS(ch)].class_name); j = strlen(newcomm); } break; case 'O': case 'o': /* sub name of obj target */ if (ob) { strcat(newcomm + j, ob->shdesc); j = strlen(newcomm); } else if (TARGET_OBJ(mob)) { strcat(newcomm + j, TARGET_OBJ(mob)); j = strlen(newcomm); } /* if no sub there, ok, its as if we processed */ break; default: sprintf(buf, "SYSERR: Undefined +(%c) to mobproc (%s)",comm[i+1], GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return FALSE; break; } } else { sprintf(buf, "SYSERR: Undefined +sub to mobproc (%s)",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return FALSE; } } newcomm[j] = '\0'; strncpy(comm, newcomm, MAX_INPUT_LENGTH - 1); send_to_char(comm, mob); send_to_char("\n\r",mob); return TRUE; } // if mobproc subs, sub them and send to command interpreter BOOL sub_and_execute(chdata *mob, char *comm, chdata *ch, obdata *ob) { char newcomm[MAX_INPUT_LENGTH]; strncpy(newcomm, comm, MAX_INPUT_LENGTH - 1); if (do_mobproc_subs(mob, newcomm, ch, ob)) { send_to_char(newcomm, mob); send_to_char("\n\r",mob); command_interpreter(mob, newcomm); return TRUE; } return FALSE; } // mrandom is the first mobproc command which utilizes blocks of commands // i.e. mrandom { blah blah blah } // mrandom followed by a block of randoms, chooses one and does command int do_mrandom(chdata *ch, char *argument) { char *pt; // our placeholder in the mproc list char *tmp, *tmp2; int count = 0, pick, i; char comm[MAX_INPUT_LENGTH]; // must be a start block! pt = MPROC_CUR(ch); skip_spaces(&pt); if (!pt || !*pt || *pt != '{') { sprintf(buf, "SYSERR: Mob #%d fatal mobproc error. No block after mrandom.",GET_MOB_VNUM(ch)); mudlog(buf, BUG, LEV_IMM, FALSE); send_to_char(strcat(buf, "\n\r"), ch); do_mend(ch, argument); // end mobproc } // now count commands in the block for (tmp = pt, count = 0; *tmp && *tmp != '}'; tmp++) { tmp = scan_past_eol(tmp); skip_spaces(&tmp); if (!tmp || !*tmp || *tmp == '}') break; else count++; } if (!tmp || !*tmp) { sprintf(buf, "SYSERR: Mob #%d fatal mobproc error. Mrandom block never ended.",GET_MOB_VNUM(ch)); mudlog(buf, BUG, LEV_IMM, FALSE); send_to_char(strcat(buf, "\n\r"), ch); do_mend(ch, argument); // end mobproc } // skip past closing bracket tmp = scan_past_eol(tmp); // this is where we wanna point after we done if (!count) { sprintf(buf, "SYSERR: Mob #%d fatal mobproc error. No randoms in mrandom block.",GET_MOB_VNUM(ch)); mudlog(buf, BUG, LEV_IMM, FALSE); send_to_char(strcat(buf, "\n\r"), ch); do_mend(ch, argument); // end mobproc } if (count > 1) pick = number(1, count); else pick = 1; // now go thru block and pick the pickth one pt = scan_past_eol(pt); for (count = 1, *comm = '\0'; count < pick; count++) pt = scan_past_eol(pt); skip_spaces(&pt); /* get length of next command */ for (i=0, tmp2 = pt; *tmp2 && !ISNEWL(*tmp2) && (i < MAX_INPUT_LENGTH); tmp2++, i++) ; /* copy this command line into comm */ strncpy(comm, pt, i); comm[i] = '\0'; /* show the mob what they typing */ send_to_char(comm, ch); send_to_char("\n\r",ch); if (*comm != '&') // process only if not our ignore character if (!sub_and_execute(ch, comm, NULL, NULL)) command_interpreter(ch, comm); MPROC_CUR(ch) = tmp; return MP_MRANDOM; } // pause a mobproc, 1 per 5 seconds for DTIME mobs // 1 per 10 seconds for normal mobproc mobs int do_mpause(chdata *ch, char *argument) { int num = 0; one_argument(argument, arg); if (!is_number(arg)) return MP_NORMAL; num = atoi(arg); num = MAX(0, MIN(num, 99)); ch->npc_specials.mob_wait = num; if (SPC_FLAGGED(ch, SPC_DOUBLETIME)) num *= 5; else num *= 10; sprintf(buf, "Ok. Mob Proc waiting %d seconds (roughly).\n\r",num); S2C(); return MP_NORMAL; } /* simply start from where th proc last ended */ /* only if actually MENDED that is */ /* if no mproc_cur, then restart */ int do_mstart(chdata *ch, char *argument) { if (ch->npc_specials.mob_wait >= 0) return MP_NORMAL; ch->npc_specials.mob_wait = 0; /* ok, begin processing of commands with this mob */ if (!MPROC_CUR(ch)) /* only jump to start if not pting to a comm */ MPROC_CUR(ch) = MPROC_BEG(ch); send_to_char("Ok. Mob Proc started from last endpoint.\n\r",ch); return MP_NORMAL; } /* wipes out all waits, sets cur back to beginning */ /* does it regardless if in a proc or not */ int do_mreset(chdata *ch, char *argument) { ch->npc_specials.mob_wait = 0; MPROC_CUR(ch) = MPROC_BEG(ch); TRIG_WAITING(ch) = FALSE; send_to_char("Ok. MobProc reset.\n\r",ch); return MP_NORMAL; } /* ends the processing of a mobproc, sets mobwait to -1 */ int do_mend(chdata *ch, char *argument) { if (ch->npc_specials.mob_wait < 0) return MP_NORMAL; /* already ended */ ch->npc_specials.mob_wait = -1; send_to_char("Ok. MobProc ended.\n\r",ch); return MP_NORMAL; } // sets mob waiting for a trigger to go off -jtr int do_mtrig_wait(chdata *ch, char *argument) { if (TRIG_WAITING(ch)) // already awaiting trigger return MP_NORMAL; if (!TRIGS(ch)) // no trigs? aint gonna wait { send_to_char("No triggers found... not waiting.\n\r",ch); return MP_NORMAL; } TRIG_WAITING(ch) = TRUE; send_to_char("Ok. Awaiting trigger.\n\r",ch); return MP_NORMAL; } // mob will ignore triggers after this call int do_mtrig_off(chdata *ch, char *argument) { if (TRIG_IGNORE(ch)) // already ignoring triggers return MP_MTRIG; if (!TRIGS(ch)) // no trigs? aint gonna ignore { send_to_char("No triggers found... no need to ignore.\n\r",ch); return MP_MTRIG; } TRIG_IGNORE(ch) = TRUE; send_to_char("Ok. Ignoring triggers.\n\r",ch); return MP_MTRIG; } // mob will NOT ignore triggers after this call int do_mtrig_on(chdata *ch, char *argument) { if (!TRIG_IGNORE(ch)) // already listening to triggers return MP_MTRIG; if (!TRIGS(ch)) // no trigs? why bother { send_to_char("No triggers found... nothing to listen for.\n\r",ch); return MP_MTRIG; } TRIG_IGNORE(ch) = FALSE; send_to_char("Ok. No longer ignoring triggers.\n\r",ch); return MP_MTRIG; } // add an mtrigger to chars list of trigs -jtr int add_mtrigger(chdata *mob, char *trigger, char *reaction) { struct mtrig_type *mt = NULL; if (!trigger || !reaction) { sprintf(buf, "SYSERR: Missing trig or react to %s (#%d).",GET_NAME(mob), GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_MTRIG; } // if adding existing trigger, replace reaction and return for (mt = TRIGS(mob); mt; mt=mt->next) if (!str_cmp(mt->trigger, trigger)) { FREENULL(mt->reaction); mt->reaction = STR_DUP(reaction); send_to_char("Trigger found and updated.\n\r",mob); return MP_MTRIG; } // ok new one, create and insert to front CREATE(mt, struct mtrig_type, 1); mt->trigger = STR_DUP(trigger); mt->reaction = STR_DUP(reaction); mt->next = TRIGS(mob); TRIGS(mob) = mt; send_to_char("Added trigger:\n\r",mob); send_to_char(trigger, mob); send_to_char("\n\rWith reaction:\n\r",mob); send_to_char(reaction, mob); return MP_MTRIG; } // mtrigadd utilizes blocks of commands // mtrigadd <trigger> {block of reactions} adds mtrig_type to mobs trigs list int do_mtrig_add(chdata *ch, char *trigger) { char *pt; // our placeholder in the mproc list int i; char reaction[MAX_MOB_REACTION_LENGTH]; if (!trigger) { sprintf(buf, "SYSERR: %s (#%d) fatal mobproc error. No trig to mtrigadd.", GET_NAME(ch), GET_MOB_VNUM(ch)); mudlog(buf, BUG, LEV_IMM, FALSE); send_to_char(strcat(buf, "\n\r"), ch); do_mend(ch, trigger); // end mobproc return MP_MTRIG; } // must be a start block! pt = MPROC_CUR(ch); skip_spaces(&pt); if (!pt || !*pt || *pt != '{') { sprintf(buf, "SYSERR: %s (#%d) fatal mobproc error. No block after mtrigadd.", GET_NAME(ch), GET_MOB_VNUM(ch)); mudlog(buf, BUG, LEV_IMM, FALSE); send_to_char(strcat(buf, "\n\r"), ch); do_mend(ch, trigger); // end mobproc return MP_MTRIG; } // yep, all the chars minus the two brackets i = chars_in_block(pt); if (i <= 0) { sprintf(buf, "SYSERR: %s (#%d) fatal mobproc error. Reaction block empty.", GET_NAME(ch), GET_MOB_VNUM(ch)); mudlog(buf, BUG, LEV_IMM, FALSE); send_to_char(strcat(buf, "\n\r"), ch); do_mend(ch, trigger); // end mobproc return MP_MTRIG; } if (i >= MAX_MOB_REACTION_LENGTH - 2) { sprintf(buf, "SYSERR: %s (#%d) fatal mobproc error. Reaction block too long.", GET_NAME(ch), GET_MOB_VNUM(ch)); mudlog(buf, BUG, LEV_IMM, FALSE); send_to_char(strcat(buf, "\n\r"), ch); do_mend(ch, trigger); // end mobproc return MP_MTRIG; } strncpy(reaction, pt+1, i+1); // add one for newline... reaction[i] = '\0'; add_mtrigger(ch, trigger, reaction); // OOOOkkk just skip the block... MPROC_CUR(ch) = skip_block(pt); if (!MPROC_CUR(ch) || !*MPROC_CUR(ch)) MPROC_CUR(ch) = MPROC_BEG(ch); return MP_MTRIG; } // remove an mtrigger from chars list of trigs -jtr int do_mtrig_delete(chdata *mob, char *trigger) { struct mtrig_type *mt = NULL; struct mtrig_type *next_mt, *temp; BOOL found; if (!trigger) { sprintf(buf, "SYSERR: Missing trig to %s (#%d) (remove_mtrig).",GET_NAME(mob), GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_MTRIG; } if (!TRIGS(mob)) return MP_MTRIG; for (mt = TRIGS(mob), found = FALSE; mt; mt=next_mt) { next_mt = mt->next; if (!str_cmp(mt->trigger, trigger)) { REMOVE_FROM_LIST(mt, TRIGS(mob), next); if (mt->trigger) free_log(mt->trigger, "do_mtrig_delete 1"); if (mt->reaction) free_log(mt->reaction, "do_mtrig_delete 2"); free_log(mt, "do_mtrig_delete 3"); found = TRUE; send_to_char("Trigger found and removed from list.\n\r",mob); } } if (!found) send_to_char("No matching trigger found, list unchanged.\n\r",mob); return MP_MTRIG; } // wax entire trigger list by mobproc command int do_mtrig_wax(chdata *mob, char *argument) { if (!TRIGS(mob)) { send_to_char("No triggers found.\n\r",mob); return MP_MTRIG; } TRIGS(mob) = free_mtriggers(TRIGS(mob)); TRIG_WAITING(mob) = FALSE; // cant be waiting if no list eh? -jtr send_to_char("Entire trigger list removed.\n\r",mob); return MP_MTRIG; } /* return the number of commands in a mobs mobproc (for gotos) */ int mproc_length(chdata *mob) { char *tmp; int count; if (!SPC_FLAGGED(mob, SPC_MOBPROC) || !*MPROC_BEG(mob)) return 0; for (count = 0, tmp = MPROC_BEG(mob); *tmp; tmp++) if (*tmp == '\n') count++; return count; } // scan a rproc for mtag <tname> char *get_mtag(char *proc, char *tname) { char *str = proc; char arg1[MAX_STRING_LENGTH]; char arg2[MAX_STRING_LENGTH]; skip_spaces(&str); while (*str) { half_chop(str, arg1, arg2); if (!str_cmp(arg1, "mtag") && is_abbrev(tname, arg2)) return str; str = scan_past_eol(str); skip_spaces(&str); if (!str || !*str) break; } return NULL; } // do nothing but set tag placeholder for mgotos // 6/14/98 -jtrhone int do_mtag(chdata *mob, char *argument) { if (!*argument) { sprintf(buf, "SYSERR: Undefined mtag tag (#%d).",GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_MTAG; } return MP_MTAG; } // goto a particular line of the mob proc // updated for use with mtags 6/14/98 -jtrhone int do_mgoto(chdata *mob, char *argument) { int line, ctr; char *tmp; char arg1[MAX_INPUT_LENGTH]; one_argument(argument, arg1); if (!*arg1) { sprintf(buf, "SYSERR: Undefined arg to mgoto (%s)",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // lookin for mtag... if (!is_number(arg1)) { tmp = get_mtag(MPROC_BEG(mob), arg1); if (!tmp) { sprintf(buf, "SYSERR: Unable to locate mtag (%s) in mgoto (#%d).",arg1,GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // juuuust to make sure if (tmp < MPROC_BEG(mob)) { sprintf(buf, "SYSERR: Lower bounds failure in mgoto (#%d).",GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } MPROC_CUR(mob) = tmp; sprintf(buf, "Mproc jumped to tag %s.\n\r",arg1); send_to_char(buf, mob); return MP_NORMAL; } line = atoi(arg1); if (line > mproc_length(mob) || line < 1) { sprintf(buf, "SYSERR: invalid line number to mgoto (%s)",GET_NAME(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if (line == 1) { MPROC_CUR(mob) = MPROC_BEG(mob); send_to_char("Ok. Jumped to line 1.\n\r",mob); return MP_NORMAL; } tmp = MPROC_BEG(mob); ctr = 1; while (ctr != line) { tmp = scan_past_eol(tmp); ctr++; } MPROC_CUR(mob) = tmp; sprintf(buf, "Ok. Jumped to line %d(target %d).\n\r",ctr, line); send_to_char(buf, mob); return MP_NORMAL; } // skip a command goto next or jump to beginning if none left // must add ability to skip mcommand blocks!, if the command structure // uses them, such as mrandom... mrandom uses a block structure // if we are pointing at a block, skip it! (mifs mostly) // mtrigadd is also a block structure now -jtr 3/21/97 void goto_next_mcom(chdata *mob) { char *tmp = MPROC_CUR(mob); char arg1[MAX_INPUT_LENGTH]; one_argument(tmp, arg1); // jump to the top... if (!*tmp) { MPROC_CUR(mob) = MPROC_BEG(mob); return; } // lets check the command we're skippin to see if it is a block command if (*arg1 == '{') { tmp = skip_block(tmp); if (!*tmp) tmp = MPROC_BEG(mob); MPROC_CUR(mob) = tmp; return; } else if (is_abbrev(arg1, "mrandom") || is_abbrev(arg1, "mtrigadd")) { tmp = scan_past_eol(tmp); tmp = skip_block(tmp); if (!*tmp) tmp = MPROC_BEG(mob); MPROC_CUR(mob) = tmp; return; } // else do the normal one line skip tmp = scan_past_eol(tmp); if (!*tmp) tmp = MPROC_BEG(mob); MPROC_CUR(mob) = tmp; } /* RoA Mobprocs -jtrhone aka Vall */ /* mif tests things based on arg */ // argument containes the mif comparisons, while MPROC_CUR pts to the block to be // executed or skipped based on the comparisons // added tarcharrace, tarcharclass, tarchargender 6/8/98 -jtrhone int do_mif(chdata *mob, char *argument) { static char mif_comp[MAX_INPUT_LENGTH]; static char comp_args[MAX_INPUT_LENGTH]; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int vroom, rroom; chdata *ch; obdata *obj; BOOL found; int i, cmd; int get_race_by_name(char *arg); // races.c, 8/22/98 -jtrhone half_chop(argument, mif_comp, comp_args); if ((cmd = search_block(mif_comp, mif_BOOLs, FALSE)) < 0) { send_to_char("Undefined MIF arg. FALSE by default.\n\r",mob); sprintf(buf, "SYSUPD: Undefined mobproc MIF argument. #%d",GET_MOB_VNUM(mob)); mudlog(buf, BUG, LEV_IMM, FALSE); sprintf(buf, "SYSUPD: Undefined MIF arg: %s",mif_comp); mudlog(buf, BUG, LEV_IMM, FALSE); goto_next_mcom(mob); } // add a little flexibility to these... 1/22/98 -jtrhone while (*MPROC_CUR(mob) && *MPROC_CUR(mob) != '{') MPROC_CUR(mob)++; if (*MPROC_CUR(mob) != '{') { send_to_char("No block following MIF.\n\r",mob); sprintf(buf, "SYSUPD: MIF with no following block. #%d",GET_MOB_VNUM(mob)); mudlog(buf, BUG, LEV_IMM, FALSE); do_mend(mob, " "); } // no more string compares, lets use the #s 1/18/98 -jtrhone switch (cmd) { case 0: //tarcharset if (!TARGET_CHAR(mob)) goto_next_mcom(mob); break; case 1: //!tarcharset if (TARGET_CHAR(mob)) goto_next_mcom(mob); break; case 2: //tarobjset if (!TARGET_OBJ(mob)) goto_next_mcom(mob); break; case 3: //!tarobjset if (TARGET_OBJ(mob)) goto_next_mcom(mob); break; case 4: //tarcharroom if (!TARGET_CHAR(mob) || !get_char_room_vis(mob, TARGET_CHAR(mob))) goto_next_mcom(mob); break; case 5: //!tarcharroom if (TARGET_CHAR(mob) && get_char_room_vis(mob, TARGET_CHAR(mob))) goto_next_mcom(mob); break; case 6: //tarobjroom if (!TARGET_OBJ(mob) || !get_obj_in_list_vis(mob, TARGET_OBJ(mob), world[mob->in_room].contents)) goto_next_mcom(mob); break; case 7: //!tarobjroom if (TARGET_OBJ(mob) && get_obj_in_list_vis(mob, TARGET_OBJ(mob), world[mob->in_room].contents)) goto_next_mcom(mob); break; case 8: //tarcharzone if (!TARGET_CHAR(mob) || !get_char_zone_vis(mob, TARGET_CHAR(mob))) goto_next_mcom(mob); break; case 9: //!tarcharzone if (TARGET_CHAR(mob) && get_char_zone_vis(mob, TARGET_CHAR(mob))) goto_next_mcom(mob); break; case 10: //tarobjzone if (!TARGET_OBJ(mob) || !get_obj_zone_vis(mob, TARGET_OBJ(mob))) goto_next_mcom(mob); break; case 11: //!tarobjzone if (TARGET_OBJ(mob) && get_obj_zone_vis(mob, TARGET_OBJ(mob))) goto_next_mcom(mob); break; case 12: //tarcharpc if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); break; case 13: //!tarcharpc if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || IS_PC(ch)) goto_next_mcom(mob); break; case 14: //tarcharcompquest half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || !VALID_QUEST(vroom)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid quest# check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or hasnt completed quest, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (!COMPLETED_QUEST(ch, vroom)) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 15: //!tarcharcompquest half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || !VALID_QUEST(vroom)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid quest# check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or has completed quest, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (COMPLETED_QUEST(ch, vroom)) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 16: //tarcharlevel ch = NULL; if (TARGET_CHAR(mob)) { if (!(ch = get_char_room_vis(mob, TARGET_CHAR(mob)))) if (!(ch = get_char_zone_vis(mob, TARGET_CHAR(mob)))) if (!(ch = get_char_vis(mob, TARGET_CHAR(mob)))) { goto_next_mcom(mob); return MP_MIF; } } else { goto_next_mcom(mob); return MP_MIF; } half_chop(comp_args, arg1, arg2); if (!*arg1 || !*arg2) { sprintf(buf, "SYSERR: mobproc mob #%d unknown tarcharlevel args.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if (!is_number(arg2) || (i = atoi(arg2)) > LEV_IMPL || i <= 0) { sprintf(buf, "SYSERR: mproc tarcharlevel invalid level arg, mob #%d.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } found = FALSE; switch (*arg1) { case '=': // is equal to found = (GET_LEVEL(ch) == i); break; case '!': // is != to found = (GET_LEVEL(ch) != i); break; case '<': // is less than equal to, or is less than if (*(arg1+1) == '=') found = (GET_LEVEL(ch) <= i); else found = (GET_LEVEL(ch) < i); break; case '>': // is greater than equal to, or is greater than if (*(arg1+1) == '=') found = (GET_LEVEL(ch) > i); else found = (GET_LEVEL(ch) >= i); break; default: sprintf(buf, "SYSERR: Unknown mobproc comparison, mob #%d.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if (!found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 17: //inroom half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_room(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid inroom arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if (mob->in_room != rroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 18: //!inroom half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_room(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid inroom arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } if (mob->in_room == rroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 19: //npcinroom half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_mobile(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid npcinroom arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } for (found = FALSE, ch = world[mob->in_room].people; ch && !found; ch = ch->next_in_room) if (IS_NPC(ch) && GET_MOB_VNUM(ch) == vroom) found = TRUE; if (!found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 20: //!npcinroom half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_mobile(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid npcinroom arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } for (found = FALSE, ch = world[mob->in_room].people; ch && !found; ch = ch->next_in_room) if (IS_NPC(ch) && GET_MOB_VNUM(ch) == vroom) found = TRUE; if (found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 21: //objinroom half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_object(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid objinroom arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } for (found = FALSE, obj = world[mob->in_room].contents; obj && !found; obj = obj->next_content) if (GET_OBJ_VNUM(obj) == vroom) found = TRUE; if (!found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 22: //!objinroom half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_object(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid objinroom arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } for (found = FALSE, obj = world[mob->in_room].contents; obj && !found; obj = obj->next_content) if (GET_OBJ_VNUM(obj) == vroom) found = TRUE; if (found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 23: //objinv half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_object(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid objinv arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); goto_next_mcom(mob); return MP_NORMAL; } for (found = FALSE, obj = mob->carrying; obj && !found; obj = obj->next_content) if (GET_OBJ_VNUM(obj) == vroom) found = TRUE; if (!found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 24: //!objinv half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_object(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid objinv arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); goto_next_mcom(mob); return MP_NORMAL; } for (found = FALSE, obj = mob->carrying; obj && !found; obj = obj->next_content) if (GET_OBJ_VNUM(obj) == vroom) found = TRUE; if (found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 25: //objeq half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_object(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid objeq arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); goto_next_mcom(mob); return MP_NORMAL; } for (found = FALSE, i = 0; i < MAX_WEAR && !found; i++) if (EQ(mob, i) && GET_OBJ_VNUM(EQ(mob, i)) == vroom) found = TRUE; if (!found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 26: //!objeq half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_object(vroom)) <= 0)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid objeq arg.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); goto_next_mcom(mob); return MP_NORMAL; } for (found = FALSE, i = 0; i < MAX_WEAR && !found; i++) if (EQ(mob, i) && GET_OBJ_VNUM(EQ(mob, i)) == vroom) found = TRUE; if (found) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 27: //mfighting if (!FIGHTING(mob)) goto_next_mcom(mob); break; case 28: //!mfighting if (FIGHTING(mob)) goto_next_mcom(mob); break; case 29: //transpresent half_chop(comp_args, arg1, arg2); if (!is_number(arg1)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid trans arg (%s).", GET_MOB_VNUM(mob), arg1); mudlog(buf, BRF, LEV_IMM, FALSE); goto_next_mcom(mob); return MP_NORMAL; } if (world[mob->in_room].trans_present != atoi(arg1)) goto_next_mcom(mob); break; case 30: //!transpresent half_chop(comp_args, arg1, arg2); if (!is_number(arg1)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid trans arg (%s).", GET_MOB_VNUM(mob), arg1); mudlog(buf, BRF, LEV_IMM, FALSE); goto_next_mcom(mob); return MP_NORMAL; } if (world[mob->in_room].trans_present == atoi(arg1)) goto_next_mcom(mob); break; case 31: //tarcharonquest half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || !VALID_QUEST(vroom)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid quest# check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or isnt doing quest, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (ONQUEST(ch) != vroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 32: //!tarcharonquest half_chop(comp_args, arg1, arg2); if (!is_number(arg1) || (!(vroom = atoi(arg1))) || !VALID_QUEST(vroom)) { sprintf(buf, "SYSERR: mobproc mob #%d invalid quest# check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or doing quest, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (ONQUEST(ch) == vroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 33: //tarcharrace <> half_chop(comp_args, arg1, arg2); if (!*arg1 || (vroom = get_race_by_name(arg1)) <= 0) { sprintf(buf, "SYSERR: mobproc mob #%d invalid race check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or not race, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (GET_RACE(ch) != vroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 34: //!tarcharrace <> half_chop(comp_args, arg1, arg2); if (!*arg1 || (vroom = get_race_by_name(arg1)) <= 0) { sprintf(buf, "SYSERR: mobproc mob #%d invalid race check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or not race, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (GET_RACE(ch) == vroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 35: //tarcharclass <> half_chop(comp_args, arg1, arg2); if (!*arg1 || (vroom = get_class_num(arg1)) <= 0) { sprintf(buf, "SYSERR: mobproc mob #%d invalid class check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or not class, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (GET_CLASS(ch) != vroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 36: //!tarcharclass <> half_chop(comp_args, arg1, arg2); if (!*arg1 || (vroom = get_class_num(arg1)) <= 0) { sprintf(buf, "SYSERR: mobproc mob #%d invalid class check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or not class, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (GET_CLASS(ch) == vroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 37: //tarchargender <> half_chop(comp_args, arg1, arg2); if (!*arg1 || (vroom = search_block(arg1, genders, FALSE)) <= 0) { sprintf(buf, "SYSERR: mobproc mob #%d invalid gender check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or not class, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (GET_SEX(ch) != vroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; case 38: //!tarchargender <> half_chop(comp_args, arg1, arg2); if (!*arg1 || (vroom = search_block(arg1, genders, FALSE)) <= 0) { sprintf(buf, "SYSERR: mobproc mob #%d invalid gender check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } // if is no target, or isnt visible, or isnt pc, or not class, skip block if (!TARGET_CHAR(mob) || !(ch = get_char_room_vis(mob, TARGET_CHAR(mob))) || !IS_PC(ch)) goto_next_mcom(mob); else if (GET_SEX(ch) == vroom) goto_next_mcom(mob); else MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; default: MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); break; } return MP_MIF; } /* manually set the mobs target strings */ int do_mtarget_set(chdata *mob, char *comm) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; half_chop(comm, arg1, arg2); if (is_abbrev(arg1, "char") && *arg2) { if(TARGET_CHAR(mob)) free_log(TARGET_CHAR(mob), "do_mtargetset 1"); TARGET_CHAR(mob) = str_dup(arg2); } else if (is_abbrev(arg1, "obj") && *arg2) { if(TARGET_OBJ(mob)) free_log(TARGET_OBJ(mob), "do_mtargetset 2"); TARGET_OBJ(mob) = str_dup(arg2); } else { sprintf(buf, "SYSERR: mobproc (mob #%d) invalid mtargetset command.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return MP_NORMAL; } return MP_MTARGET; } // mob teleports much like a immortal goto int do_mtele_zone(chdata *mob, char *comm) { char arg1[MAX_INPUT_LENGTH]; int location; extern int find_target_room(chdata *ch, char *arg); one_argument(comm, arg1); if ((location = find_target_room(mob, arg1)) < 0) return MP_NORMAL; /* roa jtrhone */ if (location == mob->in_room) { send_to_char("You're already where you want to go.\n\r",mob); return MP_NORMAL; } act("$n is engulfed by a swirling cloud.",TRUE,mob,0,0,TO_ROOM); char_from_room(mob); char_to_room(mob, location); act("$n arrives amidst a swirling cloud.",TRUE,mob,0,0,TO_ROOM); do_look_at_room(mob, 0, 0); return MP_NORMAL; } // similar to track and move, hunt tracks target and moves in its direction int do_mhunt(chdata *mob, char *comm) { char arg1[MAX_INPUT_LENGTH]; chdata *vict; int dir; extern int find_first_step(int src, int trg); one_argument(comm, arg1); if (!(vict = get_char_zone_vis(mob, arg1))) { send_to_char("Mhunt target not found in zone, ignoring hunt.\n\r",mob); return MP_NORMAL; } dir = find_first_step(mob->in_room, vict->in_room); if (dir < 0) { send_to_char("Mhunt cancelled. No path or already there.\n\r",mob); return MP_NORMAL; } if (!EXIT(mob, dir)) { send_to_char("Mhunt fatal error, exit doesnt exist.\n\r",mob); return MP_NORMAL; } if (ROOM_FLAGGED(EXIT(mob, dir)->to_room, DEATH) || ROOM_FLAGGED(EXIT(mob, dir)->to_room, FLY_DEATH)) { send_to_char("Mhunt would lead to DT. Hunt ignored.\n\r",mob); return MP_NORMAL; } do_move(mob, "", dir+1, 0); return MP_NORMAL; } // execute and return true if comm is a mobproc command int mobproc_interpreter(chdata *mob, char *comm, chdata *ch, obdata *ob) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int i; if (!SPC_FLAGGED(mob, SPC_MOBPROC)) { if (!sub_and_execute(mob, comm, ch, ob)) command_interpreter(mob, comm); return MP_NORMAL; } half_chop(comm, arg1, arg2); for (i = 0; *mproc_calls[i].arg; i++) if (is_abbrev(arg1, mproc_calls[i].arg)) { do_mobproc_subs(mob, arg2, ch, ob); // ok, call appropriate function with this command return ((*mproc_calls[i].mproc_fn) (mob, arg2)); } if (!sub_and_execute(mob, comm, ch, ob)) command_interpreter(mob, comm); return MP_NORMAL; } // lets do some bounds checking just to make sure -jtrhone BOOL check_mproc_bounds(chdata *mob) { if (MPROC_CUR(mob) < MPROC_BEG(mob)) { sprintf(buf, "SYSERR: mobproc #%d %%B%%1FAILED%%0 lower bounds check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return FALSE; } if (MPROC_CUR(mob) > (MPROC_BEG(mob) + strlen(MPROC_BEG(mob)))) { sprintf(buf, "SYSERR: mobproc #%d %%B%%1FAILED%%0 upper bounds check.", GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return FALSE; } return TRUE; } /* do a preset builder mob special procedure, step thru the string5 portion of mob->npc_specials -RoA jtrhone */ /* With specific mobproc commands such as mrandom, mtarget */ // Main mobproc interface begins here // this is called from mobact.c in mobile_activity() void do_mob_mobproc(chdata *mob) { int i; int current_command, command_count; char *tmp; char comm[MAX_INPUT_LENGTH+2]; if (IS_PC(mob)) return; if (!MPROC_BEG(mob) || !*MPROC_BEG(mob)) { sprintf(buf, "SYSERR: mobproc #%d missing instruction set.",GET_MOB_VNUM(mob)); mudlog(buf, BRF, LEV_IMM, FALSE); return; } /* check wait states, to see if loop or waiting or finished */ if (mob->npc_specials.mob_wait <= -1) return; /* finished */ else if (mob->npc_specials.mob_wait > 0) { mob->npc_specials.mob_wait--; return; /* waiting for now, see ya */ } else if (TRIGS(mob) && TRIG_WAITING(mob)) // waiting for trigger return; current_command = MP_MIF; command_count = 1; while ((current_command == MP_MIF || current_command == MP_MTARGET || current_command == MP_MTAG || current_command == MP_MTRIG) && command_count < 5) { if (!check_mproc_bounds(mob)) return; // skip leading white space, allow for nifty look mobproc code skip_spaces(&MPROC_CUR(mob)); // if we're pointing at close brackets, just skip em while ( *MPROC_CUR(mob) && *MPROC_CUR(mob) == '}' ) MPROC_CUR(mob) = scan_past_eol(MPROC_CUR(mob)); // if null, reset to beginning if (!MPROC_CUR(mob) || !*MPROC_CUR(mob)) MPROC_CUR(mob) = MPROC_BEG(mob); // get length of next command for (i=0, tmp = MPROC_CUR(mob); *tmp && !ISNEWL(*tmp) && (i < MAX_INPUT_LENGTH); tmp++, i++) ; /* copy this command line into comm */ strncpy(comm, MPROC_CUR(mob), i); comm[i] = '\0'; while (*tmp && ISNEWL(*tmp)) tmp++; // reset back to beginning to mproc command list if (!*tmp) tmp = MPROC_BEG(mob); MPROC_CUR(mob) = tmp; // show the mob what they typing send_to_char(comm, mob); send_to_char("\n\r",mob); // send it onto mobproc processing current_command = mobproc_interpreter(mob, comm, NULL, NULL); // prevent infinity -roa command_count++; } } /* following is for REACTOR mobs, react to certain triggers typed by players.... -RoA 10/8/96 -jtr streamlined this code, now recognizes newlines as a command terminator as well as the old * terminator */ void perform_reaction(chdata *mob, char *str, chdata *ch, obdata *ob, BOOL mobproc) { int num=1, i; char comm[MAX_MOB_REACTION_LENGTH]; char *tmp; if (ch && IS_NPC(ch)) return; if (!str || !*str) return; if (!mobproc) for (tmp = str, *comm = '\0'; tmp && *tmp; tmp++) if (*tmp == '\n' || *tmp == '*') num++; /* count the subcommands in string */ if ((num > MAX_MOB_REACTIONS) || (strlen(str) > MAX_MOB_REACTION_LENGTH)) { sprintf(buf, "SYSUPD: mreaction failed - %d reacs, length %d", num, strlen(str)); mudlog(buf, BUG, LEV_IMM, TRUE); return; } /* parse the string using * as pseudo EOL along with ISNEWL */ for (tmp = str, i=0; tmp && *tmp; tmp++) if (*tmp && !ISNEWL(*tmp) && *tmp != '*') comm[i++] = *tmp; else { comm[i] = '\0'; if (*comm) mobproc_interpreter(mob, comm, ch, ob); *comm = '\0'; i = 0; } comm[i] = '\0'; if (*comm) mobproc_interpreter(mob, comm, ch, ob); } /* this checks to see if trigger is one of a possible 5 triggers chosen by builder and seperated by * character, or newline (10/6/96) 11/9/96 -roa added substring comparison, if the # is first character in trigger */ int in_trigger(char *trigger, char *string) { char *trig; int num, i; char comm[MAX_MOB_REACTION_LENGTH]; extern int match(char *str, char *str2); if (!string || !trigger || !*trigger || !*string ) return FALSE; else num = 1; for (trig = trigger; *trig; trig++) if (*trig == '\n' || *trig == '*') num++; /* count the subcommands in string */ if ((num > MAX_MOB_REACTIONS) || (strlen(trig) > MAX_MOB_REACTION_LENGTH)) { sprintf(buf, "SYSUPD: mtrigger failed - %d trigs, length %d", num, strlen(trig)); mudlog(buf, BUG, LEV_IMM, TRUE); return FALSE; } /* parse the trigger using * as pseudo EOL character */ for (trig = trigger, i = 0; *trig; trig++) if (*trig && !ISNEWL(*trig) && *trig != '*') { comm[i] = *trig; i++; } else { comm[i] = '\0'; if (*comm && *comm != '\n') { if (*comm == '#') // the pound indicates a SUBSTRING match(strstr) { if (*(comm + 1) && match((comm + 1), string)) return TRUE; } else if (!str_cmp(comm, string)) return TRUE; } *comm = '\0'; i = 0; } /* now last subtrigger check */ comm[i] = '\0'; if (*comm && *comm != '\n') { if (*comm == '#') // the pound indicates a SUBSTRING match (strstr) { if (*(comm + 1) && match((comm + 1), string)) return TRUE; } else if (!str_cmp(comm, string)) return TRUE; } return FALSE; /* we didnt find any matches */ } /* does character's command trigger a mobile command? if so do it */ int check_reaction(chdata *ch, char *str) { static chdata *mob; char tmp[MAX_INPUT_LENGTH]; char *ptr; struct mtrig_type *mt; if (INVALID_ROOM(ch->in_room)) return FALSE; for(mob = world[ch->in_room].people; mob ; mob = mob->next_in_room) if (SPC_FLAGGED(mob, SPC_REACTOR) || (SPC_FLAGGED(mob, SPC_MOBPROC) && TRIGS(mob))) break; /* ding ding ding, we got a winner */ if (!mob || !str || !*str) return FALSE; /* sorry pal, try again next time */ // lower case entire string arg, cpy to temp buf first strcpy(tmp, str); for (ptr = tmp; *ptr; ptr++) if (isalpha(*ptr)) *ptr = LOWER(*ptr); if (SPC_FLAGGED(mob, SPC_REACTOR)) { if (MSTR1(mob) && in_trigger(MSTR1(mob), tmp)) { perform_reaction(mob, MSTR2(mob), ch, NULL, FALSE); return TRUE; } else if (MSTR3(mob) && in_trigger(MSTR3(mob), tmp)) { perform_reaction(mob, MSTR4(mob), ch, NULL, FALSE); return TRUE; } } // added mobproc trigger list capabilities 3/22/97 -jtr if (!TRIG_IGNORE(mob)) for (mt = TRIGS(mob); mt; mt = mt->next) if (in_trigger(mt->trigger, tmp)) { perform_reaction(mob, mt->reaction, ch, NULL, TRUE); // set new char target to the one who triggered us FREENULL(TARGET_CHAR(mob)); TARGET_CHAR(mob) = STR_DUP(GET_NAME(ch)); TRIG_WAITING(mob) = FALSE; send_to_char("Reaction triggered. Trigwait removed.\n\r",mob); return TRUE; } return FALSE; } // The following is for RAND mobs, random messages semi emoted by mobs. // NOTE: This type of mob is obsolete as a result of mrandom mobproc... // Keep function around for legacy mobs. -roa void do_mob_random(chdata *mob) { int room = mob->in_room; if (room == NOWHERE) return; switch (number(1,5)) { case 1: if (MSTR1(mob) && *MSTR1(mob) != '&' && number(0,1)) perform_reaction(mob, MSTR1(mob), NULL, NULL, FALSE); break; case 2: if (MSTR2(mob) && *MSTR2(mob) != '&' && number(0,1)) perform_reaction(mob, MSTR2(mob), NULL, NULL, FALSE); break; case 3: if (MSTR3(mob) && *MSTR3(mob) != '&' && number(0,1)) perform_reaction(mob, MSTR3(mob), NULL, NULL, FALSE); break; case 4: if (MSTR4(mob) && *MSTR4(mob) != '&' && number(0,1)) perform_reaction(mob, MSTR4(mob), NULL, NULL, FALSE); break; case 5: if (MSTR5(mob) && *MSTR5(mob) != '&' && number(0,1)) perform_reaction(mob, MSTR5(mob), NULL, NULL, FALSE); break; default: break; } }