/*************************************************************************** * 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. * * * * Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen * * * * 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. * ***************************************************************************/ /*************************************************************************** * _/ _/ * * _/_/_/ _/_/ _/_/_/ _/ _/_/ _/ _/ _/_/_/ * * _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ * * _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ * * _/ _/ _/ _/_/_/ _/ _/_/ _/_/_/ _/_/_/ * *************************************************************************** * Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius), * * Additional credits are in the help file CODECREDITS * * All Rights Reserved. * ***************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h> #include "merc.h" #include "interp.h" AREA_AFFECT *area_affect_free = NULL; bool gFound; #define RID ROOM_INDEX_DATA bool examine_room args((RID * pRoom, RID * tRoom, AREA_DATA * pArea, int steps)); void examine_steps args((RID * pRoom, RID * tRoom, AREA_DATA * pArea, int steps)); void dijkstra args((RID * chRoom, RID * victRoom)); RID *heap_getMinElement args((HEAP * heap)); HEAP *init_heap args((RID * root)); /* * Is astr contained within bstr ? * */ bool is_contained(const char *astr, const char *bstr) { int i, alen, blen, count; alen = strlen(astr); blen = strlen(bstr); if (alen > blen) return FALSE; for (i = 0; i <= (blen - alen); i++) { count = 0; while (count < alen && UPPER(astr[count]) == UPPER(bstr[i + count])) count++; if (count == alen) return TRUE; } return FALSE; } /* * A case sensitive version */ bool is_contained2(const char *astr, const char *bstr) { int i, alen, blen, count; alen = strlen(astr); blen = strlen(bstr); if (alen > blen) return FALSE; for (i = 0; i <= (blen - alen); i++) { count = 0; while (count < alen && astr[count] == bstr[i + count]) count++; if (count == alen) return TRUE; } return FALSE; } int strlen2(const char *s) { int i, b, count = 0; if (s[0] == '\0') return 0; b = strlen(s); for (i = 0; i < b; i++) { if (s[i] == '#') count++; } return (b + 7 * count); } void win_prize(CHAR_DATA * ch) { int i, vnum; OBJ_DATA *obj; OBJ_INDEX_DATA *pIndex; if (IS_NPC(ch)) return; i = number_range(1, 100); if (i < 50) vnum = OBJ_VNUM_PROTOPLASM; else if (i < 65) vnum = 33851; else if (i < 75) vnum = 33852; else if (i < 80) vnum = 33853; else if (i < 85) vnum = 33854; else if (i < 90) vnum = 33855; else if (i < 95) vnum = 33856; else vnum = 33857; if ((pIndex = get_obj_index(vnum)) == NULL) { bug("BAD PRIZE!!", 0); return; } obj = create_object(pIndex, 50); if (vnum == OBJ_VNUM_PROTOPLASM) { obj->level = 1; free_string(obj->short_descr); free_string(obj->name); free_string(obj->description); obj->short_descr = str_dup("A prize token"); obj->description = str_dup("A token lies on the floor"); obj->name = str_dup("prize token"); obj->value[0] = number_range(100, 300); obj->item_type = ITEM_QUEST; } obj_to_char(obj, ch); return; } void do_clearstats2(CHAR_DATA * ch, char *argument) { OBJ_DATA *obj; OBJ_DATA *obj_next; if (IS_NPC(ch)) return; powerdown(ch); /* remove class shit */ for (obj = ch->carrying; obj != NULL; obj = obj_next) { obj_next = obj->next_content; if (obj->wear_loc != WEAR_NONE) { obj_from_char(obj); obj_to_char(obj, ch); } } while (ch->affected) affect_remove(ch, ch->affected); if (IS_SET(ch->affected_by, AFF_POLYMORPH)) REMOVE_BIT(ch->affected_by, AFF_POLYMORPH); if (IS_SET(ch->affected_by, AFF_ETHEREAL)) REMOVE_BIT(ch->affected_by, AFF_ETHEREAL); if (IS_EXTRA(ch, EXTRA_DRAGON)) REMOVE_BIT(ch->extra, EXTRA_DRAGON); ch->affected_by = 0; ch->armor = 100; ch->hit = UMAX(1, ch->hit); ch->mana = UMAX(1, ch->mana); ch->move = UMAX(1, ch->move); ch->hitroll = 0; ch->damroll = 0; ch->saving_throw = 0; ch->pcdata->mod_str = 0; ch->pcdata->mod_int = 0; ch->pcdata->mod_wis = 0; ch->pcdata->mod_dex = 0; ch->pcdata->mod_con = 0; if (IS_SET(ch->newbits, NEW_DFORM)) REMOVE_BIT(ch->newbits, NEW_DFORM); if (IS_POLYAFF(ch, POLY_ZULOFORM)) REMOVE_BIT(ch->polyaff, POLY_ZULOFORM); if (IS_SET(ch->newbits, NEW_CUBEFORM)) REMOVE_BIT(ch->newbits, NEW_CUBEFORM); if (IS_SET(ch->newbits2, NEW2_EAGLES)) REMOVE_BIT(ch->newbits2, NEW2_EAGLES); if (IS_SET(ch->newbits2, NEW2_VVIGOR)) REMOVE_BIT(ch->newbits2, NEW2_VVIGOR); if (IS_SET(ch->newbits, NEW_CLOUDBLESS)) REMOVE_BIT(ch->newbits, NEW_CLOUDBLESS); if (IS_SET(ch->newbits2, NEW2_HAWKEYES)) REMOVE_BIT(ch->newbits2, NEW2_HAWKEYES); save_char_obj(ch); send_to_char ("Your stats have been cleared. Please rewear your equipment.\n\r", ch); return; } /* * If an item have a bad char in it's short/long/name desc, the mud * will freeze when the char with that item tries to log on, so use * this check on any renaming of items (glamour/reshape/etc). */ bool has_bad_chars(CHAR_DATA * ch, char *argument) { int i; if (argument[0] == '\0') return FALSE; for (i = 0; argument[i] != '\0'; i++) { if (argument[i] == '~') return TRUE; } return FALSE; } bool is_webbed(CHAR_DATA * ch) { if (IS_AFFECTED(ch, AFF_WEBBED)) { send_to_char("Not while webbed.\n\r", ch); return TRUE; } if (IS_AFFECTED2(ch, AFF2_THORNS)) { send_to_char("Not while rooted by brambles.\n\r", ch); return TRUE; } return FALSE; } void ragnarok_stop() { DESCRIPTOR_DATA *d; ragnarok = FALSE; do_info(NULL, "#CPeace has been restored in the realms, the time of ragnarok is no more#n"); for (d = descriptor_list; d != NULL; d = d->next) { if (d->character && d->connected == CON_PLAYING) { d->character->fight_timer = 0; d->character->pcdata->safe_counter = 5; do_call(d->character, "all"); do_restore(d->character, "self"); } } return; } void powerdown(CHAR_DATA * ch) { if (IS_NPC(ch)) return; if (IS_CLASS(ch, CLASS_DEMON)) { if (IS_POLYAFF(ch, POLY_ZULOFORM)) /* demonform */ { REMOVE_BIT(ch->polyaff, POLY_ZULOFORM); REMOVE_BIT(ch->affected_by, AFF_POLYMORPH); free_string(ch->morph); ch->morph = str_dup(""); } } else if (IS_CLASS(ch, CLASS_MONK)) /* spiritpower and monkflame */ { if (IS_SET(ch->newbits, NEW_MONKFLAME)) REMOVE_BIT(ch->newbits, NEW_MONKFLAME); if (IS_SET(ch->newbits, NEW_POWER)) REMOVE_BIT(ch->newbits, NEW_POWER); } else if (IS_CLASS(ch, CLASS_WEREWOLF)) { if (IS_SET(ch->special, SPC_WOLFMAN)) do_unwerewolf(ch, ""); } else if (IS_CLASS(ch, CLASS_DROW)) { if (IS_SET(ch->newbits, NEW_DFORM)) /* spiderform */ { free_string(ch->morph); ch->morph = str_dup(""); REMOVE_BIT(ch->newbits, NEW_DFORM); REMOVE_BIT(ch->newbits, THIRD_HAND); REMOVE_BIT(ch->newbits, FOURTH_HAND); } } else if (IS_CLASS(ch, CLASS_VAMPIRE)) { if (IS_EXTRA(ch, EXTRA_DRAGON)) /* dragonform */ { REMOVE_BIT(ch->extra, EXTRA_DRAGON); free_string(ch->morph); ch->morph = str_dup(""); } if (IS_POLYAFF(ch, POLY_ZULOFORM)) /* zuloform */ { REMOVE_BIT(ch->polyaff, POLY_ZULOFORM); REMOVE_BIT(ch->affected_by, AFF_POLYMORPH); free_string(ch->morph); ch->morph = str_dup(""); } } else if (IS_CLASS(ch, CLASS_GIANT)) { if (IS_SET(ch->newbits, NEW_CUBEFORM)) /* dawnstrength */ { REMOVE_BIT(ch->newbits, NEW_CUBEFORM); REMOVE_BIT(ch->affected_by, AFF_POLYMORPH); free_string(ch->morph); ch->morph = str_dup(""); } } else if (IS_CLASS(ch, CLASS_TANARRI)) { if (ch->pcdata->powers[TANARRI_FURY_ON] == 1) /* fury */ ch->pcdata->powers[TANARRI_FURY_ON] = 0; } else if (IS_CLASS(ch, CLASS_DRONE)) /* nightmare aura */ { if (ch->pcdata->powers[DRONE_NIGHTMARE] == 1) ch->pcdata->powers[DRONE_NIGHTMARE] = 0; } else if (IS_CLASS(ch, CLASS_SHAPESHIFTER)) { if (IS_SET(ch->affected_by, AFF_POLYMORPH)) /* reset form */ { ch->pcdata->powers[SHAPE_FORM] = 0; REMOVE_BIT(ch->affected_by, AFF_POLYMORPH); free_string(ch->morph); ch->morph = str_dup(""); } } else if (IS_CLASS(ch, CLASS_CYBORG)) { if (IS_SET(ch->newbits, NEW_CUBEFORM)) /* avatar of Lloth */ { REMOVE_BIT(ch->newbits, NEW_CUBEFORM); REMOVE_BIT(ch->affected_by, AFF_POLYMORPH); free_string(ch->morph); ch->morph = str_dup(""); } } else if (IS_CLASS(ch, CLASS_UNDEAD_KNIGHT)) { if (IS_SET(ch->pcdata->powers[AURAS], MIGHT_AURA)) /* aura of might */ REMOVE_BIT(ch->pcdata->powers[AURAS], MIGHT_AURA); } else if (IS_CLASS(ch, CLASS_ANGEL)) { if (IS_SET(ch->newbits, NEW_CUBEFORM)) /* godly favor */ { REMOVE_BIT(ch->newbits, NEW_CUBEFORM); REMOVE_BIT(ch->affected_by, AFF_POLYMORPH); free_string(ch->morph); ch->morph = str_dup(""); } } else if (IS_CLASS(ch, CLASS_FAE)) { if (IS_SET(ch->newbits, NEW_CUBEFORM)) /* elemental form */ { REMOVE_BIT(ch->newbits, NEW_CUBEFORM); REMOVE_BIT(ch->affected_by, AFF_POLYMORPH); if (IS_SET(ch->affected_by, AFF_PASS_DOOR)) REMOVE_BIT(ch->affected_by, AFF_PASS_DOOR); free_string(ch->morph); ch->morph = str_dup(""); } } /* * and a little bit of everything */ REMOVE_BIT(ch->pcdata->jflags, JFLAG_DRONE_HORRID); return; } int get_ratio(CHAR_DATA * ch) { long ratio; if (IS_NPC(ch)) return 0; if ((ch->pkill + ch->pdeath) == 0) ratio = 0; // to avoid divide by zero. else if (ch->pkill > ch->pdeath) ratio = ch->pkill * 100 * ((ch->pkill * ch->pkill) - (ch->pdeath * ch->pdeath)) / ((ch->pkill + ch->pdeath) * (ch->pkill + ch->pdeath)); else if (ch->pkill > 0) ratio = (-100) * (ch->pdeath - ch->pkill) / ch->pkill; else ratio = (-100) * ch->pdeath; return (int) ratio; } bool multicheck(CHAR_DATA * ch) { CHAR_DATA *gch; char buf[MAX_STRING_LENGTH]; if (ch->level > 6) return FALSE; for (gch = char_list; gch; gch = gch->next) { if (IS_NPC(gch)) continue; if (gch == ch) continue; if (gch->level > 6) continue; if (strlen(gch->lasthost) > 2) { if (gch->desc) { if (!str_cmp(gch->desc->host, ch->desc->host)) { xprintf(buf, "%s has connected from the same IP as %s", ch->name, gch->name); log_string(LOG_SECURITY, buf); //do_info(ch, buf); return TRUE; } } else if (!str_cmp(gch->lasthost, ch->desc->host)) { xprintf(buf, "%s has connected from the same IP as %s", ch->name, gch->name); log_string(LOG_SECURITY, buf); return TRUE; } } } return FALSE; } void death_info(char *str) { DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; if (str[0] == '\0') return; xprintf(buf, "#0/\\/\\ #RDe#Ya#Rth #0/\\/\\#n %s\n\r", str); for (d = descriptor_list; d != NULL; d = d->next) { if (d->connected == CON_PLAYING && d->character != NULL) send_to_char(buf, d->character); } return; } void avatar_info(char *str) { DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; if (str[0] == '\0') return; xprintf(buf, "#p-=#P[ #WAvatar #P]#p=-#n %s\n\r", str); for (d = descriptor_list; d != NULL; d = d->next) { if (d->connected == CON_PLAYING && d->character != NULL) send_to_char(buf, d->character); } return; } void leave_info(char *str) { DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; if (str[0] == '\0') return; xprintf(buf, "#G+#g-#G+ #0Leaves #G+#g-#G+#n %s\n\r", str); for (d = descriptor_list; d != NULL; d = d->next) { if (d->connected == CON_PLAYING && d->character != NULL) send_to_char(buf, d->character); } return; } void enter_info(char *str) { DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; if (str[0] == '\0') return; xprintf(buf, "#0=#w-#0= #WEnters #0=#w-#0= %s\n\r", str); for (d = descriptor_list; d != NULL; d = d->next) { if (d->connected == CON_PLAYING && d->character != NULL) send_to_char(buf, d->character); } return; } void forge_affect(OBJ_DATA * obj, int value) { AFFECT_DATA paf; paf.type = 0; paf.duration = -1; paf.location = APPLY_HITROLL; paf.modifier = value; paf.bitvector = 0; affect_to_obj(obj, &paf); paf.type = 0; paf.duration = -1; paf.location = APPLY_DAMROLL; paf.modifier = value; paf.bitvector = 0; affect_to_obj(obj, &paf); } void dump_last_command() { FILE *fp; char buf[MAX_STRING_LENGTH]; fp = fopen("../txt/crash.txt", "a"); if (cmd_done) fprintf(fp, "Last command typed : %s (thread count : %d) (command executed without flaws)\n", last_command, thread_count); else fprintf(fp, "Last command typed : %s (thread count : %d) (crash happended during this command)\n", last_command, thread_count); fflush(fp); fclose(fp); /* * creates a note to the immortals */ xprintf(buf, "It seems we have crashed, the last command typed was\n\r\n\r"); strcat(buf, last_command); strcat(buf, "\n\r\n\rPlease remember that this doesn't mean that this caused the crash.\n\r\n\rRegards,\n\r\n\rThe Crash Code"); make_note("Immortal", "Crash Code", "imm", "We Crashed", 7, buf); } void update_revision(CHAR_DATA * ch) { if (IS_NPC(ch)) return; if (ch->pcdata->revision == CURRENT_REVISION) return; /* * We don't end cases with break, since we want the player to be fully updated. */ switch (ch->pcdata->revision) { case 1: ch->pcdata->damreduct = 100; ch->pcdata->damreductdec = 0; ch->pcdata->revision++; default: break; } return; } bool in_fortress(CHAR_DATA * ch) { if (!ch->in_room) return FALSE; if (ch->in_room->vnum >= 151 && ch->in_room->vnum <= 170) return TRUE; return FALSE; } bool in_arena(CHAR_DATA * ch) { if (!ch->in_room) return FALSE; if (ch->in_room->vnum >= 50 && ch->in_room->vnum <= 67) return TRUE; return FALSE; } void increase_total_output(int clenght) { total_output += clenght; } void logout_message(CHAR_DATA * ch) { static char *const he_she[] = { "XX", "he", "she" }; static char *const him_her[] = { "XX", "him", "her" }; static char *const his_her[] = { "XX", "his", "her" }; DESCRIPTOR_DATA *d; char buf[400]; // that should be plenty. const char *dmess; const char *i; char *ptr2; char *ptr; int size; size = strlen2(ch->pcdata->logoutmessage); if (size > 380) { bug("Bad logoutmessage.", 0); return; } ptr2 = "#C<- #RLeaves #C->#n "; ptr = buf; dmess = ch->pcdata->logoutmessage; while ((*ptr = *ptr2) != '\0') ++ptr, ++ptr2; while (*dmess != '\0') { if (*dmess != '$') { *ptr++ = *dmess++; continue; } ++dmess; switch (*dmess) { default: i = ""; break; case 'n': i = ch->name; break; case 'e': i = he_she[URANGE(1, ch->sex, 2)]; break; case 'm': i = him_her[URANGE(1, ch->sex, 2)]; break; case 's': i = his_her[URANGE(1, ch->sex, 2)]; break; } ++dmess; /* * copying the data into the pointer */ while ((*ptr = *i) != '\0') ++ptr, ++i; } *ptr++ = '\n'; *ptr++ = '\r'; for (d = descriptor_list; d; d = d->next) { if (d->lookup_status != STATUS_DONE) continue; if (d->connected != CON_PLAYING) continue; write_to_buffer(d, buf, ptr - buf); } return; } void update_mudinfo() { DESCRIPTOR_DATA *d; int i, pcount = 0; /* * Each week, the data is stored to a file, and * the variable cleared. */ if (mudinfo[MUDINFO_UPDATED] > 20160) { write_mudinfo_database(); for (i = 0; i < (MUDINFO_MAX - 2); i++) { mudinfo[i] = 0; } log_string(LOG_GAME, "Mudinfo database updated."); } /* * Increase update count */ mudinfo[MUDINFO_UPDATED]++; /* * Outdate the output data */ if (total_output > mudinfo[MUDINFO_DATA_PEAK]) mudinfo[MUDINFO_DATA_PEAK] = total_output; /* * The stored data */ if (mudinfo[MUDINFO_BYTE] > 1048576) // 1 megabyte { mudinfo[MUDINFO_MBYTE]++; mudinfo[MUDINFO_BYTE] -= 1048576; } mudinfo[MUDINFO_BYTE] += total_output; /* * The temp data */ if (mudinfo[MUDINFO_BYTE_S] > 1048576) // 1 megabyte { mudinfo[MUDINFO_MBYTE_S]++; mudinfo[MUDINFO_BYTE_S] -= 1048576; } mudinfo[MUDINFO_BYTE_S] += total_output; /* * We clear the counter */ total_output = 0; for (d = descriptor_list; d; d = d->next) { if (d->connected == CON_PLAYING && d->lookup_status == STATUS_DONE) { if (d->character) { if (d->character->level < 13) { pcount++; if (d->out_compress) mudinfo[MUDINFO_MCCP_USERS]++; else mudinfo[MUDINFO_OTHER_USERS]++; if (IS_SET (d->character->act, PLR_SOUND)) mudinfo[MUDINFO_MSP_USERS]++; } } } } if (pcount > mudinfo[MUDINFO_PEAK_USERS]) mudinfo[MUDINFO_PEAK_USERS] = pcount; save_mudinfo(); } void recycle_descriptors() { DESCRIPTOR_DATA *dclose; DESCRIPTOR_DATA *dclose_next; for (dclose = descriptor_list; dclose; dclose = dclose_next) { dclose_next = dclose->next; if (dclose->lookup_status != STATUS_CLOSED) continue; /* * First let's get it out of the descriptor list. */ if (dclose == descriptor_list) { descriptor_list = descriptor_list->next; } else { DESCRIPTOR_DATA *d; for (d = descriptor_list; d && d->next != dclose; d = d->next) ; if (d != NULL) d->next = dclose->next; else { bug("Recycle_descriptors: dclose not found.", 0); continue; } } /* * Clear out that memory */ free_string(dclose->host); free_mem(dclose->outbuf, dclose->outsize); /* * Mccp */ if (dclose->out_compress) { deflateEnd(dclose->out_compress); free_mem(dclose->out_compress_buf, COMPRESS_BUF_SIZE); free_mem(dclose->out_compress, sizeof(z_stream)); } /* * Bye bye mr. Descriptor. */ close(dclose->descriptor); /* * And then we recycle */ dclose->next = descriptor_free; descriptor_free = dclose; } } void affect_to_area(AREA_DATA * pArea, AREA_AFFECT * paf) { AREA_AFFECT *paf_new; if (area_affect_free == NULL) { paf_new = alloc_perm(sizeof(*paf_new)); } else { paf_new = area_affect_free; area_affect_free = area_affect_free->next; } *paf_new = *paf; paf_new->next = pArea->affects; pArea->affects = paf_new; return; } void area_affect_remove(AREA_DATA * pArea, AREA_AFFECT * paf) { if (pArea->affects == NULL) { bug("Area_affect_remove: no affect.", 0); return; } if (paf == pArea->affects) { pArea->affects = paf->next; } else { AREA_AFFECT *prev; for (prev = pArea->affects; prev; prev = prev->next) { if (prev->next == paf) { prev->next = paf->next; break; } } if (!prev) { bug("Area_affect_remove: cannot find paf.", 0); return; } } paf->next = area_affect_free; area_affect_free = paf; return; } /* * A religion of 0 will result in any religion is true, * but a religion != 0 will only result in true if the spell * has that given religion. */ bool has_area_affect(AREA_DATA * pArea, int affect, int religion) { AREA_AFFECT *paf; for (paf = pArea->affects; paf; paf = paf->next) { if (paf->type == affect) { if (religion != 0 && paf->religion != religion) continue; else return TRUE; } } return FALSE; } int get_next_playerid() { top_playerid++; save_coreinfo(); return top_playerid; } void tie_message(CHAR_DATA * ch, CHAR_DATA * victim) { static char *const he_she[] = { "XX", "he", "she" }; static char *const him_her[] = { "XX", "him", "her" }; static char *const his_her[] = { "XX", "his", "her" }; DESCRIPTOR_DATA *d; char buf[400]; // that should be plenty. const char *dmess; const char *i; char *ptr2; char *ptr; int size; size = strlen2(ch->pcdata->tiemessage); if (size > 380) { bug("Bad tiemessage.", 0); return; } ptr2 = "#C<- #RTie #C->#n "; ptr = buf; dmess = ch->pcdata->tiemessage; while ((*ptr = *ptr2) != '\0') ++ptr, ++ptr2; while (*dmess != '\0') { if (*dmess != '$') { *ptr++ = *dmess++; continue; } ++dmess; switch (*dmess) { default: i = ""; break; case 'n': i = ch->name; break; case 'e': i = he_she[URANGE(1, ch->sex, 2)]; break; case 'm': i = him_her[URANGE(1, ch->sex, 2)]; break; case 's': i = his_her[URANGE(1, ch->sex, 2)]; break; case 'N': i = victim->name; break; case 'S': i = his_her[URANGE(1, victim->sex, 2)]; break; case 'M': i = him_her[URANGE(1, victim->sex, 2)]; break; case 'E': i = he_she[URANGE(1, victim->sex, 2)]; break; } ++dmess; /* * copying the data into the pointer */ while ((*ptr = *i) != '\0') ++ptr, ++i; } *ptr++ = '\n'; *ptr++ = '\r'; for (d = descriptor_list; d; d = d->next) { if (d->lookup_status != STATUS_DONE) continue; if (d->connected != CON_PLAYING) continue; write_to_buffer(d, buf, ptr - buf); } return; } void login_message(CHAR_DATA * ch) { static char *const he_she[] = { "XX", "he", "she" }; static char *const him_her[] = { "XX", "him", "her" }; static char *const his_her[] = { "XX", "his", "her" }; DESCRIPTOR_DATA *d; char buf[400]; // that should be plenty. const char *dmess; const char *i; char *ptr2; char *ptr; int size; size = strlen2(ch->pcdata->loginmessage); if (size > 380) { bug("Bad loginmessage.", 0); return; } ptr2 = "#C<- #REnters #C->#n "; ptr = buf; dmess = ch->pcdata->loginmessage; while ((*ptr = *ptr2) != '\0') ++ptr, ++ptr2; while (*dmess != '\0') { if (*dmess != '$') { *ptr++ = *dmess++; continue; } ++dmess; switch (*dmess) { default: i = ""; break; case 'n': i = ch->name; break; case 'e': i = he_she[URANGE(1, ch->sex, 2)]; break; case 'm': i = him_her[URANGE(1, ch->sex, 2)]; break; case 's': i = his_her[URANGE(1, ch->sex, 2)]; break; } ++dmess; /* * copying the data into the pointer */ while ((*ptr = *i) != '\0') ++ptr, ++i; } *ptr++ = '\n'; *ptr++ = '\r'; for (d = descriptor_list; d; d = d->next) { if (d->lookup_status != STATUS_DONE) continue; if (d->connected != CON_PLAYING) continue; write_to_buffer(d, buf, ptr - buf); } return; } void check_help_soundex(char *argument, CHAR_DATA * ch) { HELP_DATA *pHelp; char buf[MAX_STRING_LENGTH]; char tbuf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; char keyword[MAX_INPUT_LENGTH]; char *str; bool found = FALSE; one_argument(argument, arg); if (arg[0] == '\0') return; xprintf(buf, "\n\r[Perhaps:"); for (pHelp = first_help; pHelp; pHelp = pHelp->next) { if (pHelp->level > ch->level) continue; str = pHelp->keyword; str = one_argument(str, keyword); while (keyword[0] != '\0') { if (SoundexMatch (GetSoundexKey(arg), GetSoundexKey(keyword)) > 75) { found = TRUE; xprintf(tbuf, " %s", keyword); strcat(buf, tbuf); } str = one_argument(str, keyword); } } strcat(buf, "]\n\r"); if (found) send_to_char(buf, ch); } /* * New system to replace status, called fair fight, it measures the * difference between two players, giving them points for their * stances, powers, and stats. If they are within each others range, * the call will return TRUE, if not FALSE. Call for fair_fight when * you need to see if a fight is fair (ie. decapping). */ bool fair_fight(CHAR_DATA * ch, CHAR_DATA * victim) { return TRUE; } void special_decap_message(CHAR_DATA * ch, CHAR_DATA * victim) { static char *const he_she[] = { "XX", "he", "she" }; static char *const him_her[] = { "XX", "him", "her" }; static char *const his_her[] = { "XX", "his", "her" }; DESCRIPTOR_DATA *d; char buf[400]; // that should be plenty. const char *dmess; const char *i; char *ptr2; char *ptr; int size; size = strlen2(ch->pcdata->decapmessage); if (size > 380) { bug("Bad decapmessage.", 0); return; } ptr2 = "#C<- #RDeath #C->#n "; ptr = buf; dmess = ch->pcdata->decapmessage; while ((*ptr = *ptr2) != '\0') ++ptr, ++ptr2; while (*dmess != '\0') { if (*dmess != '$') { *ptr++ = *dmess++; continue; } ++dmess; switch (*dmess) { default: i = ""; break; case 'n': i = ch->name; break; case 'e': i = he_she[URANGE(1, ch->sex, 2)]; break; case 'm': i = him_her[URANGE(1, ch->sex, 2)]; break; case 's': i = his_her[URANGE(1, ch->sex, 2)]; break; case 'N': i = victim->name; break; case 'S': i = his_her[URANGE(1, victim->sex, 2)]; break; case 'M': i = him_her[URANGE(1, victim->sex, 2)]; break; case 'E': i = he_she[URANGE(1, victim->sex, 2)]; break; } ++dmess; /* * copying the data into the pointer */ while ((*ptr = *i) != '\0') ++ptr, ++i; } *ptr++ = '\n'; *ptr++ = '\r'; for (d = descriptor_list; d; d = d->next) { if (d->lookup_status != STATUS_DONE) continue; if (d->connected != CON_PLAYING) continue; write_to_buffer(d, buf, ptr - buf); } return; } /* * This function have always been broken, perhaps * one day in the future I'll make a functionel * piece of code, but untill then, it's more * guessing the right size than anything else. */ char *get_dystopia_banner(char *title, int size) { int tSize = strlen(title); int patternsize, bufferspaces = 0, blockcount, i; static char buf[200]; /* * just so we can use strcat */ buf[0] = '\0'; /* * calculating the amount of patterns on each side of the title */ patternsize = (size - tSize) / 2; if (!(patternsize % 4)) patternsize -= 4; else while (patternsize % 4) patternsize--; patternsize /= 4; /* * calculating buffer spaces */ while ((tSize + bufferspaces) % 4) bufferspaces++; blockcount = bufferspaces / 2; if (patternsize < 1) { strcat(buf, "#0<>== #G"); strcat(buf, title); strcat(buf, " #0==<>#n"); } else { /* * first add patterns */ strcat(buf, "#0<>=="); for (i = 1; i < patternsize; i++) strcat(buf, "<>=="); /* * add the title */ if (tSize) { strcat(buf, "#G "); while (bufferspaces > blockcount) { bufferspaces--; strcat(buf, " "); } } else strcat(buf, "<>"); strcat(buf, title); if (tSize) { strcat(buf, "#0 "); while (bufferspaces > 0) { bufferspaces--; strcat(buf, " "); } } /* * add secondary patterns */ for (i = 0; i < patternsize; i++) strcat(buf, "==<>"); strcat(buf, "#n"); } return buf; } int calc_ratio(int a, int b) { int ratio; if (b == 0 && a > 0) ratio = 100; else if ((a + b) != 0) ratio = (100 * a) / (a + b); else ratio = 0; return ratio; } void avatar_message(CHAR_DATA * ch) { static char *const he_she[] = { "XX", "he", "she" }; static char *const him_her[] = { "XX", "him", "her" }; static char *const his_her[] = { "XX", "his", "her" }; DESCRIPTOR_DATA *d; char buf[400]; // that should be plenty. const char *dmess; const char *i; char *ptr2; char *ptr; int size; size = strlen2(ch->pcdata->avatarmessage); if (size > 380) { bug("Bad avatarmessage.", 0); return; } ptr2 = "#C<- #RAvatar #C->#n "; ptr = buf; dmess = ch->pcdata->avatarmessage; while ((*ptr = *ptr2) != '\0') ++ptr, ++ptr2; while (*dmess != '\0') { if (*dmess != '$') { *ptr++ = *dmess++; continue; } ++dmess; switch (*dmess) { default: i = ""; break; case 'n': i = ch->name; break; case 'e': i = he_she[URANGE(0, ch->sex, 1)]; break; case 'm': i = him_her[URANGE(0, ch->sex, 1)]; break; case 's': i = his_her[URANGE(0, ch->sex, 1)]; break; } ++dmess; /* * copying the data into the pointer */ while ((*ptr = *i) != '\0') ++ptr, ++i; } *ptr++ = '\n'; *ptr++ = '\r'; for (d = descriptor_list; d; d = d->next) { if (d->lookup_status != STATUS_DONE) continue; if (d->connected != CON_PLAYING) continue; write_to_buffer(d, buf, ptr - buf); } return; } char *strip_ansi(char *str) { static char buf[MAX_STRING_LENGTH]; char *ptr; buf[0] = '\0'; ptr = buf; while (*str != '\0') { if (*str != '#') *ptr++ = *str++; else if (*(++str) != '\0') str++; } *ptr = '\0'; return buf; } char *line_indent(char *text, int wBegin, int wMax) { static char buf[MAX_STRING_LENGTH]; char *ptr; char *ptr2; int count = 0; bool stop = FALSE; int wEnd = 0; buf[0] = '\0'; ptr = text; ptr2 = buf; while (!stop) { if (count == 0) { if (*ptr == '\0') wEnd = wMax - wBegin; else if (strlen(ptr) < (wMax - wBegin)) wEnd = wMax - wBegin; else { int x = 0; while (*(ptr + (wMax - wBegin - x)) != ' ') x++; wEnd = wMax - wBegin - (x - 1); if (wEnd < 1) wEnd = wMax - wBegin; } } if (count == 0 && *ptr == ' ') ptr++; else if (++count != wEnd) { if ((*ptr2++ = *ptr++) == '\0') stop = TRUE; } else if (*ptr == '\0') { stop = TRUE; *ptr2 = '\0'; } else { int k; count = 0; *ptr2++ = '\n'; *ptr2++ = '\r'; for (k = 0; k < wBegin; k++) *ptr2++ = ' '; } } return buf; } char *get_exits(CHAR_DATA * ch) { //extern char *const dir_name[]; static char buf[MAX_STRING_LENGTH]; EXIT_DATA *pexit; bool found; int door; buf[0] = '\0'; if (!check_blind(ch)) return ""; xprintf(buf, "#0[#GExits#w:#C"); found = FALSE; for (door = 0; door <= 5; door++) { if ((pexit = ch->in_room->exit[door]) != NULL && pexit->to_room != NULL) { found = TRUE; if (IS_SET(pexit->exit_info, EX_CLOSED)) { strcat(buf, " #0(#C"); strcat(buf, dir_name[door]); strcat(buf, "#0)#C"); } else { strcat(buf, " "); strcat(buf, dir_name[door]); } } } if (!found) strcat(buf, " none"); strcat(buf, "#0]#n\n\r"); return buf; } void init_vt100(DESCRIPTOR_DATA * d, char *xbuf) { CHAR_DATA *ch; char buf[MAX_STRING_LENGTH]; int i; if ((ch = d->character) == NULL) { bug("Init_vt100: No character", 0); return; } if ((i = atoi(xbuf)) < 10) { send_to_char("VT100 Failed.\n\r", ch); return; } ch->pcdata->vt100_size = i; SET_BIT(ch->pcdata->tempflag, TEMP_VT100); xprintf(buf, "\e[%d;1H%s%s\e[1;1H%s%s\e[1;%dr", i, VT_CLEAR_LINE, VT_SAVECURSOR, VT_SETWIN_CLEAR, VT_CLEAR_SCREEN, i - 2); send_to_char(buf, ch); send_to_char("VT100 Initialized.\n\r", ch); return; } void recycle_dummys() { DUMMY_ARG *dummy; DUMMY_ARG *dummy_next; for (dummy = dummy_list; dummy; dummy = dummy_next) { dummy_next = dummy->next; if (dummy->status == 1) continue; // being used if (dummy == dummy_list) { dummy_list = dummy_list->next; } else { DUMMY_ARG *prev; /* * we find the prev dummy arg */ for (prev = dummy_list; prev && prev->next != dummy; prev = prev->next) ; if (prev != NULL) prev->next = dummy->next; else { bug("Recycle_dymmys: dummy not found.", 0); continue; } /* * recycle */ dummy->next = dummy_free; dummy_free = dummy; } } } HEAP *init_heap(RID * root) { AREA_DATA *pArea; RID *pRoom; HEAP *heap; int i, size, vnum; if ((pArea = root->area) == NULL) return NULL; size = pArea->uvnum - pArea->lvnum; if (size >= MAX_KNUDE) { bug("Init_heap: Size %d exceeds MAX_KNUDE", size); return NULL; } heap = calloc(1, sizeof(*heap)); /* * we want the root at the beginning */ heap->knude[1] = root; heap->knude[1]->steps = 0; heap->knude[1]->heap_index = 1; /* * initializing the rest of the heap */ for (i = 2, vnum = pArea->lvnum; vnum < pArea->uvnum; vnum++) { if ((pRoom = get_room_index(vnum))) { if (pRoom == root) continue; heap->knude[i] = pRoom; heap->knude[i]->steps = 2 * MAX_KNUDE; heap->knude[i]->heap_index = i; i++; } } heap->iVertice = i - 1; /* * setting the rest to NULL */ for (; i < MAX_KNUDE; i++) heap->knude[i] = NULL; return heap; } /* * Finds the smallest element and returns it after * making sure the heap is in perfect order after * the removal of the vertice with the smallest * element. */ RID *heap_getMinElement(HEAP * heap) { RID *tRoom; RID *pRoom; bool done = FALSE; int i = 1; /* * this is the element we wish to return */ pRoom = heap->knude[1]; if (pRoom->steps == 2 * MAX_KNUDE) bug("Removing room with max steps : %d", pRoom->vnum); /* * We move the last vertice to the front */ heap->knude[1] = heap->knude[heap->iVertice]; heap->knude[1]->heap_index = 1; /* * Decrease the size of the heap and remove the last entry */ heap->knude[heap->iVertice] = NULL; heap->iVertice--; /* * Swap places till it fits */ while (!done) { if (heap->knude[i] == NULL) done = TRUE; else if (heap->knude[2 * i] == NULL) done = TRUE; else if (heap->knude[2 * i + 1] == NULL) { if (heap->knude[i]->steps > heap->knude[2 * i]->steps) { tRoom = heap->knude[i]; heap->knude[i] = heap->knude[2 * i]; heap->knude[i]->heap_index = i; heap->knude[2 * i] = tRoom; heap->knude[2 * i]->heap_index = 2 * i; i = 2 * i; } done = TRUE; } else if (heap->knude[i]->steps <= heap->knude[2 * i]->steps && heap->knude[i]->steps <= heap->knude[2 * i + 1]->steps) done = TRUE; else if (heap->knude[2 * i]->steps <= heap->knude[2 * i + 1]->steps) { tRoom = heap->knude[i]; heap->knude[i] = heap->knude[2 * i]; heap->knude[i]->heap_index = i; heap->knude[2 * i] = tRoom; heap->knude[2 * i]->heap_index = 2 * i; i = 2 * i; } else { tRoom = heap->knude[i]; heap->knude[i] = heap->knude[2 * i + 1]; heap->knude[i]->heap_index = i; heap->knude[2 * i + 1] = tRoom; heap->knude[2 * i + 1]->heap_index = 2 * i + 1; i = 2 * i + 1; } } /* * return the element */ return pRoom; } void dijkstra(RID * chRoom, RID * victRoom) { RID *pRoom; RID *tRoom; RID *xRoom; HEAP *heap; int door, x; bool stop; /* * allocate a new heap */ heap = init_heap(chRoom); /* * find shortest amounts of steps to each room */ while (heap->iVertice) { if ((pRoom = heap_getMinElement(heap)) == NULL) { bug("Dijstra: Getting NULL room", 0); return; } if (pRoom == victRoom) gFound = TRUE; /* * update all exits */ for (door = 0; door < 6; door++) { if (pRoom->exit[door] == NULL) continue; if (pRoom->exit[door]->to_room == NULL) continue; /* * update step count, and swap in the heap */ if (pRoom->exit[door]->to_room->steps > pRoom->steps + 1) { xRoom = pRoom->exit[door]->to_room; xRoom->steps = pRoom->steps + 1; stop = FALSE; while ((x = xRoom->heap_index) != 1 && !stop) { if (heap->knude[x / 2]->steps > xRoom->steps) { tRoom = heap->knude[x / 2]; heap->knude[x / 2] = xRoom; xRoom->heap_index = xRoom->heap_index / 2; heap->knude[x] = tRoom; heap->knude[x]->heap_index = x; } else stop = TRUE; } } } } /* * free the heap */ free(heap); } /* * The mobs vnum is included for bug-reports. */ bool will_trigger(char *say, char *trigger, int vnum) { char buf[50]; char *ptr; bool found; buf[0] = '\0'; ptr = buf; while (*trigger != '\0') { switch (*trigger) { default: bug("Will_trigger: Bad keyword on mob %d.", vnum); return FALSE; case '&': // all keywords must be included trigger++; while (*trigger != '\0' && *trigger != '&' && *trigger != '!' && *trigger != '|') { if (*trigger != '*') *ptr++ = *trigger; else { *ptr = '\0'; if (!is_contained(buf, say)) return FALSE; else { buf[0] = '\0'; ptr = buf; } } trigger++; } break; case '|': // at least one must be included trigger++; found = FALSE; while (*trigger != '\0' && *trigger != '&' && *trigger != '!' && *trigger != '|') { if (*trigger != '*') *ptr++ = *trigger; else { *ptr = '\0'; if (is_contained(buf, say)) found = TRUE; buf[0] = '\0'; ptr = buf; } trigger++; } if (!found) return FALSE; break; case '!': // none of these may be included trigger++; while (*trigger != '\0' && *trigger != '&' && *trigger != '!' && *trigger != '|') { if (*trigger != '*') *ptr++ = *trigger; else { *ptr = '\0'; if (is_contained(buf, say)) return FALSE; else { buf[0] = '\0'; ptr = buf; } } trigger++; } break; } } return TRUE; } void mob_text(CHAR_DATA * ch, char *argument) { CHAR_DATA *vch; CHAR_DATA *vch_next; CHAR_DATA *victim; MOB_TRIGGER *mProg; char *arg; char buf[MAX_STRING_LENGTH]; if (IS_NPC(ch)) return; for (vch = ch->in_room->people; vch; vch = vch_next) { int runs = 0; vch_next = vch->next_in_room; if (!IS_NPC(vch)) continue; while (runs < 2) { if (runs == 0) mProg = vch->pIndexData->triggers; else mProg = vch->triggers; for (; mProg; mProg = mProg->next) { if (will_trigger (argument, mProg->keywords, vch->pIndexData->vnum)) { switch (mProg->type) { default: bug("Mob_text: Bad type on mob %d.", vch->pIndexData->vnum); break; case MTRIG_SAY: do_say(vch, mProg->roomOutput); break; case MTRIG_LOCATE: if ((arg = cut_after_locate (argument)) == NULL) { do_say(vch, mProg-> chOutput); return; } else if ((victim = get_char_area(ch, arg)) == NULL) { do_say(vch, mProg-> chOutput); return; } else { if ((arg = pathfind(ch, victim)) == NULL) { do_say(vch, mProg-> chOutput); return; } else { xprintf(buf, mProg-> roomOutput, arg); do_say(vch, buf); return; } } break; case MTRIG_HUNTER: if ((arg = cut_after_tracking (argument)) == NULL) { do_say(vch, mProg-> chOutput); return; } else if ((victim = get_char_area(ch, arg)) == NULL) { do_say(vch, mProg-> chOutput); return; } if (IS_NPC(victim)) { do_say(vch, mProg-> chOutput); return; } else { if ((arg = pathfind(ch, victim)) == NULL) { do_say(vch, mProg-> chOutput); return; } else { free_string (vch-> hunting); vch->hunting = str_dup (arg); vch->tracking = TRUE; vch->hunt_pointer = 0; vch->hunt_playerid = victim->pcdata->playerid; do_say(vch, mProg-> roomOutput); return; } } break; case MTRIG_SCRY: break; } return; } } runs++; } } } void trigger_remove(CHAR_DATA * ch, MOB_TRIGGER * mProg) { if (ch->triggers == NULL) { bug("Trigger_remove: no trigger.", 0); return; } if (mProg == ch->triggers) { ch->triggers = ch->triggers->next; } else { MOB_TRIGGER *prev; for (prev = ch->triggers; prev; prev = prev->next) { if (prev->next == mProg) { prev->next = mProg->next; break; } } if (!prev) { bug("Trigger_remove: cannot find mProg.", 0); return; } } mProg->next = trigger_free; trigger_free = mProg; return; } void update_aggressive_flags(CHAR_DATA * ch, CHAR_DATA * victim) { int iDef, iAggr; /* * first we check if we even care */ if (IS_NPC(ch) || IS_NPC(victim)) return; if (ch->level > 6) return; if (victim->pcdata->aggress_towards == ch->pcdata->playerid) return; if (ch->pcdata->aggress_from == victim->pcdata->playerid) return; if (!str_cmp(victim->name, ch->pcdata->retaliation)) return; if (in_arena(ch) || in_fortress(ch)) return; if (IS_SET(ch->pcdata->tempflag, TEMP_AGGRESSIVE)) return; if (ch->class == victim->class && ch->generation >= victim->generation) return; if (ragnarok) return; iDef = victim->race; iAggr = ch->race; /* * If the player aggresses someone other than * * the person who attacked them, they don't deserve * * the gang protection, since they are asking for it. */ ch->pcdata->aggress_from = 0; /* * This will take care of bully players * if (iDef < iAggr + 5) * { * victim->pcdata->aggress_from = ch->pcdata->playerid; * ch->pcdata->bully_points += 50; * if (ch->pcdata->bully_points > 400) * { * SET_BIT(ch->pcdata->jflags, JFLAG_BULLY); * ch->pcdata->bully_counter += 240; // roughly 2 hours * ch->pcdata->bully_points = 0; * send_to_char("#PTake that, bully!#n\n\r", ch); * } * } */ /* * this will take care of really small players attacking large players */ if (iAggr < iDef + 5) ch->pcdata->aggress_towards = victim->pcdata->playerid; /* * aggro counter up a little, untill I can fix it */ ch->pcdata->agg_counter = UMAX(2, ch->pcdata->agg_counter); victim->pcdata->agg_counter = UMAX(2, victim->pcdata->agg_counter); } void strip_aggression(CHAR_DATA * ch) { if (IS_NPC(ch)) return; ch->pcdata->agg_counter = 0; ch->pcdata->aggress_towards = 0; ch->pcdata->aggress_from = 0; } char *pathfind(CHAR_DATA * ch, CHAR_DATA * victim) { int const exit_names[] = { 'n', 'e', 's', 'w', 'u', 'd' }; RID *pRoom; AREA_DATA *pArea; static char path[MAX_STRING_LENGTH]; // should be plenty. int iPath = 0, vnum, door; bool found; if (!ch->in_room || !victim->in_room) return NULL; if (ch->in_room == victim->in_room) return NULL; if ((pArea = ch->in_room->area) != victim->in_room->area) return NULL; /* * initialize all rooms in the area */ for (vnum = pArea->lvnum; vnum < pArea->uvnum; vnum++) { if ((pRoom = get_room_index(vnum))) { pRoom->visited = FALSE; pRoom->steps = 999; for (door = 0; door < 6; door++) { if (pRoom->exit[door] == NULL) continue; pRoom->exit[door]->color = FALSE; } } } /* * initialize variables */ pRoom = ch->in_room; gFound = FALSE; /* * In the first run, we only count steps, no coloring is done */ examine_steps(pRoom, victim->in_room, pArea, 0); /* * If the target room was never found, we return NULL */ if (!gFound) return NULL; /* * in the second run, we color the shortest path using the step counts */ if (!examine_room(pRoom, victim->in_room, pArea, 0)) return NULL; /* * then we follow the trace */ while (pRoom != victim->in_room) { found = FALSE; for (door = 0; door < 6 && !found; door++) { if (pRoom->exit[door] == NULL) continue; if (pRoom->exit[door]->to_room == NULL) continue; if (!pRoom->exit[door]->color) continue; pRoom->exit[door]->color = FALSE; found = TRUE; path[iPath] = exit_names[door]; iPath++; pRoom = pRoom->exit[door]->to_room; } if (!found) { bug("Pathfind: Fatal Error in %d.", pRoom->vnum); return NULL; } } path[iPath] = '\0'; return path; } bool examine_room(ROOM_INDEX_DATA * pRoom, ROOM_INDEX_DATA * tRoom, AREA_DATA * pArea, int steps) { int door; /* * been here before, out of the area or can we get here faster */ if (pRoom->area != pArea) return FALSE; if (pRoom->visited) return FALSE; if (pRoom->steps < steps) return FALSE; /* * Have we found the room we are searching for */ if (pRoom == tRoom) return TRUE; /* * mark the room so we know we have been here */ pRoom->visited = TRUE; /* * Depth first traversel of all exits */ for (door = 0; door < 6; door++) { if (pRoom->exit[door] == NULL) continue; if (pRoom->exit[door]->to_room == NULL) continue; /* * assume we are walking the right way */ pRoom->exit[door]->color = TRUE; /* * recursive return */ if (examine_room (pRoom->exit[door]->to_room, tRoom, pArea, steps + 1)) return TRUE; /* * it seems we did not walk the right way */ pRoom->exit[door]->color = FALSE; } return FALSE; } void examine_steps(ROOM_INDEX_DATA * pRoom, ROOM_INDEX_DATA * tRoom, AREA_DATA * pArea, int steps) { int door; /* * Have we found the room we are searching for */ if (pRoom == tRoom) { if (pRoom->steps > steps) pRoom->steps = steps; gFound = TRUE; return; } /* * been here before, or out of the area */ if (pRoom->area != pArea) return; if (pRoom->steps != 999) { if (pRoom->steps > steps) pRoom->steps = steps; return; } /* * update the rooms step count */ pRoom->steps = steps; /* * Depth first traversel of all exits */ for (door = 0; door < 6; door++) { if (pRoom->exit[door] == NULL) continue; if (pRoom->exit[door]->to_room == NULL) continue; examine_steps(pRoom->exit[door]->to_room, tRoom, pArea, steps + 1); } return; }