/**************************************************************************r * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * ROM 2.4 is copyright 1993-1995 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@pacinfo.com) * * Gabrielle Taylor (gtaylor@pacinfo.com) * * Brian Moore (rom@rom.efn.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * ***************************************************************************/ /*************************************************************************** * ROT 1.4 is copyright 1996-1997 by Russ Walsh * * By using this code, you have agreed to follow the terms of the * * ROT license, in the file doc/rot.license * ***************************************************************************/ #if defined(macintosh) #include <types.h> #else #include <sys/types.h> #endif #include <ctype.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include "merc.h" #include "magic.h" #include "tables.h" #include "db.h" #include "lookup.h" /* * Locals. */ MOB_INDEX_DATA * mob_index; OBJ_INDEX_DATA * obj_index; ROOM_INDEX_DATA * room_index; DRM_INDEX_DATA * drm_index; char * string_hash [MAX_KEY_HASH]; AREA_DATA * area_first; AREA_DATA * area_last; char * string_space; char * top_string; char str_empty [1]; int addlev; bool changelev; extern int first_object; extern int first_mobile; extern int first_room; extern int last_object; extern int last_mobile; extern int last_room; extern int newmin; extern int newmax; extern int newvnum; extern bool changevnum; /* * Memory management. * Increase MAX_STRING if you have too. * Tune the others only if you understand what you're doing. */ #define MAX_STRING 300032 #define MAX_PERM_BLOCK 131072 #define MAX_MEM_LIST 12 void * rgFreeList [MAX_MEM_LIST]; int nAllocString; int sAllocString; int nAllocPerm; int sAllocPerm; /* * Semi-locals. */ bool fBootDb; FILE * fpArea; char strArea[MAX_INPUT_LENGTH]; /* returns material number */ int material_lookup (const char *name) { return 0; } bool is_number ( char *arg ) { if ( *arg == '\0' ) return FALSE; if ( *arg == '+' || *arg == '-' ) arg++; for ( ; *arg != '\0'; arg++ ) { if ( !isdigit( *arg ) ) return FALSE; } return TRUE; } int skill_lookup( const char *name ) { int sn; for ( sn = 0; sn < MAX_SKILL; sn++ ) { if ( skill_table[sn].name == NULL ) break; if ( LOWER(name[0]) == LOWER(skill_table[sn].name[0]) && !str_prefix( name, skill_table[sn].name ) ) return sn; } return -1; } int class_lookup (const char *name) { int class; for ( class = 0; class < MAX_CLASS; class++) { if (LOWER(name[0]) == LOWER(class_table[class].name[0]) && !str_prefix( name,class_table[class].name)) return class; } return -1; } /* returns race number */ int race_lookup (const char *name) { int race; for ( race = 0; race_table[race].name != NULL; race++) { if (LOWER(name[0]) == LOWER(race_table[race].name[0]) && !str_prefix( name,race_table[race].name)) return race; } return 0; } int liq_lookup (const char *name) { int liq; for ( liq = 0; liq_table[liq].liq_name != NULL; liq++) { if (LOWER(name[0]) == LOWER(liq_table[liq].liq_name[0]) && !str_prefix(name,liq_table[liq].liq_name)) return liq; } return -1; } int weapon_lookup (const char *name) { int type; for (type = 0; weapon_table[type].name != NULL; type++) { if (LOWER(name[0]) == LOWER(weapon_table[type].name[0]) && !str_prefix(name,weapon_table[type].name)) return type; } return -1; } int weapon_type (const char *name) { int type; for (type = 0; weapon_table[type].name != NULL; type++) { if (LOWER(name[0]) == LOWER(weapon_table[type].name[0]) && !str_prefix(name,weapon_table[type].name)) return weapon_table[type].type; } return WEAPON_EXOTIC; } int attack_lookup (const char *name) { int att; for ( att = 0; attack_table[att].name != NULL; att++) { if (LOWER(name[0]) == LOWER(attack_table[att].name[0]) && !str_prefix(name,attack_table[att].name)) return att; } return 0; } int item_lookup(const char *name) { int type; for (type = 0; item_table[type].name != NULL; type++) { if (LOWER(name[0]) == LOWER(item_table[type].name[0]) && !str_prefix(name,item_table[type].name)) return item_table[type].type; } return -1; } char *item_name(int item_type) { int type; for (type = 0; item_table[type].name != NULL; type++) if (item_type == item_table[type].type) return item_table[type].name; return "none"; } char *weapon_name( int weapon_type) { int type; for (type = 0; weapon_table[type].name != NULL; type++) if (weapon_type == weapon_table[type].type) return weapon_table[type].name; return "exotic"; } bool is_class_obj(OBJ_DATA *obj) { return obj->class; } void set_def( void ) { if (!changevnum) { newvnum = area_first->min_vnum; newmin = area_first->min_vnum; newmax = area_first->max_vnum; } else { newvnum -= area_first->min_vnum; newmin = area_first->min_vnum + newvnum; newmax = area_first->max_vnum + newvnum; } return; } void default_mobs( void ) { MOB_INDEX_DATA *pMobIndex; int vnum; printf("Converting MOBILES.\n"); for (vnum = first_mobile; vnum <= last_mobile; vnum++ ) { if ( ( pMobIndex = get_mob_index( vnum ) ) != NULL ) { int numa, numb, avg, level, value; if (changelev) { pMobIndex->level += addlev; if (pMobIndex->level < 0) pMobIndex->level = 0; if (pMobIndex->level > 110) pMobIndex->level = 110; } numa = number_range(pMobIndex->level, pMobIndex->level+8); numb = number_range(pMobIndex->level, pMobIndex->level+8); avg = (numa+numb)/2; pMobIndex->hit[DICE_NUMBER] = moblev_table[avg].hpdice; pMobIndex->hit[DICE_TYPE] = moblev_table[avg].hpsides; pMobIndex->hit[DICE_BONUS] = moblev_table[avg].hpbonus; numa = number_range(pMobIndex->level, pMobIndex->level+8); numb = number_range(pMobIndex->level, pMobIndex->level+8); avg = (numa+numb)/2; pMobIndex->mana[DICE_NUMBER] = moblev_table[avg].hpdice; pMobIndex->mana[DICE_TYPE] = moblev_table[avg].hpsides; pMobIndex->mana[DICE_BONUS] = moblev_table[avg].hpbonus; numa = number_range(pMobIndex->level, pMobIndex->level+8); numb = number_range(pMobIndex->level, pMobIndex->level+8); avg = (numa+numb)/2; pMobIndex->damage[DICE_NUMBER] = moblev_table[avg].damdice; pMobIndex->damage[DICE_TYPE] = moblev_table[avg].damsides; pMobIndex->damage[DICE_BONUS] = moblev_table[avg].dambonus; level = pMobIndex->level + 4; numa = number_range(0, 6); numb = number_range(0, 6); avg = (numa+numb)/2; value = ((moblev_table[level].mobac + 3) - avg) * 10; pMobIndex->ac[AC_PIERCE] = value; numa = number_range(0, 6); numb = number_range(0, 6); avg = (numa+numb)/2; value = ((moblev_table[level].mobac + 3) - avg) * 10; pMobIndex->ac[AC_BASH] = value; numa = number_range(0, 6); numb = number_range(0, 6); avg = (numa+numb)/2; value = ((moblev_table[level].mobac + 3) - avg) * 10; pMobIndex->ac[AC_SLASH] = value; numa = number_range(0, 6); numb = number_range(0, 6); avg = (numa+numb)/2; value = ((moblev_table[level].mobac + 7) - avg) * 10; pMobIndex->ac[AC_EXOTIC] = value; } } return; } void find_exits( void ) { ROOM_INDEX_DATA *pRoomIndex; int vnum; printf("Finding external exits.\n"); for (vnum = last_room; vnum >= first_room; vnum--) { if ( ( pRoomIndex = get_room_index( vnum ) ) != NULL ) { int door; for ( door = 11; door >= 0; door--) { EXIT_DATA *pexit; if ( ( pexit = pRoomIndex->exit[door] ) != NULL) { ROOM_INDEX_DATA *pRoom; if ( ( pRoom = get_room_index( pexit->u1.vnum ) ) == NULL ) { EXEX_DATA *pexex; pexex = alloc_perm( sizeof(*pexex) ); pexex->vnum = pRoomIndex->vnum; pexex->to_vnum = pexit->u1.vnum; pexex->direction = door; if (changevnum) { pexex->vnum += newvnum; if ((pexex->to_vnum >= area_first->min_vnum) && (pexex->to_vnum <= area_first->max_vnum)) { pexex->to_vnum += newvnum; } } if (exit_list != NULL) { pexex->next = exit_list; } exit_list = pexex; } } } } } return; } void show_exits( void ) { EXEX_DATA *pexex; printf("\nThe following external exits were found:\n"); for (pexex = exit_list; pexex != NULL; pexex = pexex->next) { int direct; printf("\tRoom vnum #%d ", pexex->vnum); direct = pexex->direction; if (direct > 5) { printf(" evil"); direct -= 6; } if (direct == 0) printf(" north (D%d)", pexex->direction); else if (direct == 1) printf(" east (D%d)", pexex->direction); else if (direct == 2) printf(" south (D%d)", pexex->direction); else if (direct == 3) printf(" west (D%d)", pexex->direction); else if (direct == 4) printf(" up (D%d)", pexex->direction); else if (direct == 5) printf(" down (D%d)", pexex->direction); printf(" to room vnum #%d\n", pexex->to_vnum); } printf("\n"); return; } void default_objs( void ) { OBJ_INDEX_DATA *pObjIndex; int vnum; printf("Converting OBJECTS.\n"); for (vnum = first_object; vnum <= last_object; vnum++ ) { if ( ( pObjIndex = get_obj_index( vnum ) ) != NULL ) { int numa, numb, avg, level, value; switch(pObjIndex->item_type) { case ITEM_EXIT: case ITEM_PIT: case ITEM_DRINK_CON: case ITEM_FOUNTAIN: case ITEM_TREASURE: case ITEM_FURNITURE: case ITEM_TRASH: case ITEM_KEY: case ITEM_FOOD: case ITEM_MONEY: case ITEM_CORPSE_NPC: case ITEM_CORPSE_PC: case ITEM_MAP: case ITEM_ROOM_KEY: case ITEM_GEM: case ITEM_JUKEBOX: case ITEM_PASSBOOK: break; case ITEM_SCROLL: case ITEM_WAND: case ITEM_STAFF: case ITEM_POTION: case ITEM_PILL: if (changelev) { pObjIndex->level += addlev; if (pObjIndex->level < 0) pObjIndex->level = 0; if (pObjIndex->level > 110) pObjIndex->level = 110; pObjIndex->value[0] += addlev; if (pObjIndex->value[0] < 0) pObjIndex->value[0] = 0; if (pObjIndex->value[0] > 110) pObjIndex->value[0] = 110; } break; case ITEM_WEAPON: if (changelev) { pObjIndex->level += addlev; if (pObjIndex->level < 0) pObjIndex->level = 0; if (pObjIndex->level > 110) pObjIndex->level = 110; } numa = number_range(pObjIndex->level, pObjIndex->level+6); numb = number_range(pObjIndex->level, pObjIndex->level+6); avg = (numa+numb)/2; pObjIndex->value[1] = objlev_table[avg].weapdice; pObjIndex->value[2] = objlev_table[avg].weapsides; break; case ITEM_ARMOR: if (changelev) { pObjIndex->level += addlev; if (pObjIndex->level < 0) pObjIndex->level = 0; if (pObjIndex->level > 110) pObjIndex->level = 110; } level = pObjIndex->level + 3; numa = number_range(0, 4); numb = number_range(0, 4); avg = (numa+numb)/2; value = ((objlev_table[level].armorac - 2) + avg); pObjIndex->value[0] = value; numa = number_range(0, 6); numb = number_range(0, 6); avg = (numa+numb)/2; value = ((objlev_table[level].armorac - 2) + avg); pObjIndex->value[1] = value; numa = number_range(0, 6); numb = number_range(0, 6); avg = (numa+numb)/2; value = ((objlev_table[level].armorac - 2) + avg); pObjIndex->value[2] = value; numa = number_range(0, 6); numb = number_range(0, 6); avg = (numa+numb)/2; value = ((objlev_table[level].armorac - 6) + avg); pObjIndex->value[3] = value; break; default: if (changelev) { pObjIndex->level += addlev; if (pObjIndex->level < 0) pObjIndex->level = 0; if (pObjIndex->level > 110) pObjIndex->level = 110; } break; } } } return; } /* checks mob format */ bool is_old_mob(CHAR_DATA *ch) { if (ch->pIndexData == NULL) return FALSE; else if (ch->pIndexData->new_format) return FALSE; return TRUE; } /* * See if a string is one of the names of an object. */ /* bool is_name( const char *str, char *namelist ) { char name[MAX_INPUT_LENGTH]; for ( ; ; ) { namelist = one_argument( namelist, name ); if ( name[0] == '\0' ) return FALSE; if ( !str_cmp( str, name ) ) return TRUE; } } */ bool is_name ( char *str, char *namelist ) { char name[MAX_INPUT_LENGTH], part[MAX_INPUT_LENGTH]; char *list, *string; string = str; /* we need ALL parts of string to match part of namelist */ for ( ; ; ) /* start parsing string */ { str = one_argument(str,part); if (part[0] == '\0' ) return TRUE; /* check to see if this is part of namelist */ list = namelist; for ( ; ; ) /* start parsing namelist */ { list = one_argument(list,name); if (name[0] == '\0') /* this name was not found */ return FALSE; if (!str_prefix(string,name)) return TRUE; /* full pattern match */ if (!str_prefix(part,name)) break; } } } bool is_exact_name ( char *str, char *namelist ) { char name[MAX_INPUT_LENGTH], part[MAX_INPUT_LENGTH]; char *list, *string; string = str; /* we need ALL parts of string to match part of namelist */ for ( ; ; ) /* start parsing string */ { str = one_argument(str,part); if (part[0] == '\0' ) return TRUE; /* check to see if this is part of namelist */ list = namelist; for ( ; ; ) /* start parsing namelist */ { list = one_argument(list,name); if (name[0] == '\0') /* this name was not found */ return FALSE; if (!str_cmp(string,name)) return TRUE; /* full pattern match */ if (!str_cmp(part,name)) break; } } } char *wear_bit_name(int wear_flags) { static char buf[512]; buf [0] = '\0'; if (wear_flags & ITEM_TAKE ) strcat(buf, " take"); if (wear_flags & ITEM_WEAR_FINGER ) strcat(buf, " finger"); if (wear_flags & ITEM_WEAR_NECK ) strcat(buf, " neck"); if (wear_flags & ITEM_WEAR_BODY ) strcat(buf, " torso"); if (wear_flags & ITEM_WEAR_HEAD ) strcat(buf, " head"); if (wear_flags & ITEM_WEAR_LEGS ) strcat(buf, " legs"); if (wear_flags & ITEM_WEAR_FEET ) strcat(buf, " feet"); if (wear_flags & ITEM_WEAR_HANDS ) strcat(buf, " hands"); if (wear_flags & ITEM_WEAR_ARMS ) strcat(buf, " arms"); if (wear_flags & ITEM_WEAR_SHIELD ) strcat(buf, " shield"); if (wear_flags & ITEM_WEAR_ABOUT ) strcat(buf, " body"); if (wear_flags & ITEM_WEAR_WAIST ) strcat(buf, " waist"); if (wear_flags & ITEM_WEAR_WRIST ) strcat(buf, " wrist"); if (wear_flags & ITEM_WIELD ) strcat(buf, " wield"); if (wear_flags & ITEM_HOLD ) strcat(buf, " hold"); if (wear_flags & ITEM_WEAR_FLOAT ) strcat(buf, " float"); if (wear_flags & ITEM_WEAR_FACE ) strcat(buf, " face"); if (wear_flags & ITEM_NO_SAC ) strcat(buf, " no_sac"); return ( buf[0] != '\0' ) ? buf+1 : "none"; } char *room_bit_name(int room_flags) { static char buf[512]; buf [0] = '\0'; if (room_flags & ROOM_DARK ) strcat(buf, " dark"); if (room_flags & ROOM_NO_MOB ) strcat(buf, " no_mob"); if (room_flags & ROOM_INDOORS ) strcat(buf, " indoors"); if (room_flags & ROOM_PRIVATE ) strcat(buf, " private"); if (room_flags & ROOM_SAFE ) strcat(buf, " safe"); if (room_flags & ROOM_SOLITARY ) strcat(buf, " solitary"); if (room_flags & ROOM_PET_SHOP ) strcat(buf, " pet_shop"); if (room_flags & ROOM_NO_RECALL ) strcat(buf, " no_recall"); if (room_flags & ROOM_IMP_ONLY ) strcat(buf, " imp"); if (room_flags & ROOM_GODS_ONLY ) strcat(buf, " gods"); if (room_flags & ROOM_HEROES_ONLY ) strcat(buf, " heroes"); if (room_flags & ROOM_NEWBIES_ONLY ) strcat(buf, " newbies"); if (room_flags & ROOM_LAW ) strcat(buf, " law"); if (room_flags & ROOM_CLAN_ENT ) strcat(buf, " clan_ent"); if (room_flags & ROOM_NOWHERE ) strcat(buf, " nowhere"); if (room_flags & ROOM_LOCKED ) strcat(buf, " locked"); return ( buf[0] != '\0' ) ? buf+1 : "none"; } char *form_bit_name(int form_flags) { static char buf[512]; buf[0] = '\0'; if (form_flags & FORM_POISON ) strcat(buf, " poison"); else if (form_flags & FORM_EDIBLE ) strcat(buf, " edible"); if (form_flags & FORM_MAGICAL ) strcat(buf, " magical"); if (form_flags & FORM_INSTANT_DECAY ) strcat(buf, " instant_rot"); if (form_flags & FORM_OTHER ) strcat(buf, " other"); if (form_flags & FORM_ANIMAL ) strcat(buf, " animal"); if (form_flags & FORM_SENTIENT ) strcat(buf, " sentient"); if (form_flags & FORM_UNDEAD ) strcat(buf, " undead"); if (form_flags & FORM_CONSTRUCT ) strcat(buf, " construct"); if (form_flags & FORM_MIST ) strcat(buf, " mist"); if (form_flags & FORM_INTANGIBLE ) strcat(buf, " intangible"); if (form_flags & FORM_BIPED ) strcat(buf, " biped"); if (form_flags & FORM_CENTAUR ) strcat(buf, " centaur"); if (form_flags & FORM_INSECT ) strcat(buf, " insect"); if (form_flags & FORM_SPIDER ) strcat(buf, " spider"); if (form_flags & FORM_CRUSTACEAN ) strcat(buf, " crustacean"); if (form_flags & FORM_WORM ) strcat(buf, " worm"); if (form_flags & FORM_BLOB ) strcat(buf, " blob"); if (form_flags & FORM_MAMMAL ) strcat(buf, " mammal"); if (form_flags & FORM_BIRD ) strcat(buf, " bird"); if (form_flags & FORM_REPTILE ) strcat(buf, " reptile"); if (form_flags & FORM_SNAKE ) strcat(buf, " snake"); if (form_flags & FORM_DRAGON ) strcat(buf, " dragon"); if (form_flags & FORM_AMPHIBIAN ) strcat(buf, " amphibian"); if (form_flags & FORM_FISH ) strcat(buf, " fish"); if (form_flags & FORM_COLD_BLOOD ) strcat(buf, " cold_blooded"); return ( buf[0] != '\0' ) ? buf+1 : "none"; } char *part_bit_name(int part_flags) { static char buf[512]; buf[0] = '\0'; if (part_flags & PART_HEAD ) strcat(buf, " head"); if (part_flags & PART_ARMS ) strcat(buf, " arms"); if (part_flags & PART_LEGS ) strcat(buf, " legs"); if (part_flags & PART_HEART ) strcat(buf, " heart"); if (part_flags & PART_BRAINS ) strcat(buf, " brains"); if (part_flags & PART_GUTS ) strcat(buf, " guts"); if (part_flags & PART_HANDS ) strcat(buf, " hands"); if (part_flags & PART_FEET ) strcat(buf, " feet"); if (part_flags & PART_FINGERS ) strcat(buf, " fingers"); if (part_flags & PART_EAR ) strcat(buf, " ears"); if (part_flags & PART_EYE ) strcat(buf, " eyes"); if (part_flags & PART_LONG_TONGUE ) strcat(buf, " long_tongue"); if (part_flags & PART_EYESTALKS ) strcat(buf, " eyestalks"); if (part_flags & PART_TENTACLES ) strcat(buf, " tentacles"); if (part_flags & PART_FINS ) strcat(buf, " fins"); if (part_flags & PART_WINGS ) strcat(buf, " wings"); if (part_flags & PART_TAIL ) strcat(buf, " tail"); if (part_flags & PART_CLAWS ) strcat(buf, " claws"); if (part_flags & PART_FANGS ) strcat(buf, " fangs"); if (part_flags & PART_HORNS ) strcat(buf, " horns"); if (part_flags & PART_SCALES ) strcat(buf, " scales"); return ( buf[0] != '\0' ) ? buf+1 : "none"; } char *weapon_bit_name(int weapon_flags) { static char buf[512]; buf[0] = '\0'; if (weapon_flags & WEAPON_FLAMING ) strcat(buf, " flaming"); if (weapon_flags & WEAPON_FROST ) strcat(buf, " frost"); if (weapon_flags & WEAPON_VAMPIRIC ) strcat(buf, " vampiric"); if (weapon_flags & WEAPON_SHARP ) strcat(buf, " sharp"); if (weapon_flags & WEAPON_VORPAL ) strcat(buf, " vorpal"); if (weapon_flags & WEAPON_TWO_HANDS ) strcat(buf, " two-handed"); if (weapon_flags & WEAPON_SHOCKING ) strcat(buf, " shocking"); if (weapon_flags & WEAPON_POISON ) strcat(buf, " poison"); return ( buf[0] != '\0' ) ? buf+1 : "none"; } char *cont_bit_name( int cont_flags) { static char buf[512]; buf[0] = '\0'; if (cont_flags & CONT_CLOSEABLE ) strcat(buf, " closable"); if (cont_flags & CONT_PICKPROOF ) strcat(buf, " pickproof"); if (cont_flags & CONT_CLOSED ) strcat(buf, " closed"); if (cont_flags & CONT_LOCKED ) strcat(buf, " locked"); return (buf[0] != '\0' ) ? buf+1 : "none"; } char *off_bit_name(int off_flags) { static char buf[512]; buf[0] = '\0'; if (off_flags & OFF_AREA_ATTACK ) strcat(buf, " area attack"); if (off_flags & OFF_BACKSTAB ) strcat(buf, " backstab"); if (off_flags & OFF_BASH ) strcat(buf, " bash"); if (off_flags & OFF_BERSERK ) strcat(buf, " berserk"); if (off_flags & OFF_DISARM ) strcat(buf, " disarm"); if (off_flags & OFF_DODGE ) strcat(buf, " dodge"); if (off_flags & OFF_FADE ) strcat(buf, " fade"); if (off_flags & OFF_FAST ) strcat(buf, " fast"); if (off_flags & OFF_FEED ) strcat(buf, " feed"); if (off_flags & OFF_KICK ) strcat(buf, " kick"); if (off_flags & OFF_KICK_DIRT ) strcat(buf, " kick_dirt"); if (off_flags & OFF_PARRY ) strcat(buf, " parry"); if (off_flags & OFF_RESCUE ) strcat(buf, " rescue"); if (off_flags & OFF_TAIL ) strcat(buf, " tail"); if (off_flags & OFF_TRIP ) strcat(buf, " trip"); if (off_flags & OFF_CRUSH ) strcat(buf, " crush"); if (off_flags & OFF_CLAN_GUARD ) strcat(buf, " clan_guard"); if (off_flags & ASSIST_ALL ) strcat(buf, " assist_all"); if (off_flags & ASSIST_ALIGN ) strcat(buf, " assist_align"); if (off_flags & ASSIST_RACE ) strcat(buf, " assist_race"); if (off_flags & ASSIST_PLAYERS ) strcat(buf, " assist_players"); if (off_flags & ASSIST_GUARD ) strcat(buf, " assist_guard"); if (off_flags & ASSIST_VNUM ) strcat(buf, " assist_vnum"); return ( buf[0] != '\0' ) ? buf+1 : "none"; } char *one_argument( char *argument, char *arg_first ) { char cEnd; while ( isspace(*argument) ) argument++; cEnd = ' '; if ( *argument == '\'' || *argument == '"' ) cEnd = *argument++; while ( *argument != '\0' ) { if ( *argument == cEnd ) { argument++; break; } *arg_first = LOWER(*argument); arg_first++; argument++; } *arg_first = '\0'; while ( isspace(*argument) ) argument++; return argument; } int slot_lookup( int slot ) { extern bool fBootDb; int sn; if ( slot <= 0 ) return -1; for ( sn = 0; sn < MAX_SKILL; sn++ ) { if ( slot == skill_table[sn].slot ) return sn; } if ( fBootDb ) { bug( "Slot_lookup: bad slot %d.", slot ); abort( ); } return -1; } /* * Translates mob virtual number to its mob index struct. * Hash table lookup. */ MOB_INDEX_DATA *get_mob_index( int vnum ) { MOB_INDEX_DATA *pMobIndex; for ( pMobIndex = mob_index; pMobIndex != NULL; pMobIndex = pMobIndex->next ) { if ( pMobIndex->vnum == vnum ) return pMobIndex; } return NULL; } /* * Translates obj virtual number to its obj index struct. * Hash table lookup. */ OBJ_INDEX_DATA *get_obj_index( int vnum ) { OBJ_INDEX_DATA *pObjIndex; for ( pObjIndex = obj_index; pObjIndex != NULL; pObjIndex = pObjIndex->next ) { if ( pObjIndex->vnum == vnum ) return pObjIndex; } return NULL; } /* * Translates dream virtual number to its dream index struct. * Hash table lookup. */ DRM_INDEX_DATA *get_drm_index( int vnum ) { DRM_INDEX_DATA *pDrmIndex; for ( pDrmIndex = drm_index; pDrmIndex != NULL; pDrmIndex = pDrmIndex->next ) { if ( pDrmIndex->vnum == vnum ) return pDrmIndex; } return NULL; } /* * Translates room virtual number to its room index struct. * Hash table lookup. */ ROOM_INDEX_DATA *get_room_index( int vnum ) { ROOM_INDEX_DATA *pRoomIndex; for ( pRoomIndex = room_index; pRoomIndex != NULL; pRoomIndex = pRoomIndex->next ) { if ( pRoomIndex->vnum == vnum ) return pRoomIndex; } return NULL; } /* * Read a letter from a file. */ char fread_letter( FILE *fp ) { char c; do { c = getc( fp ); } while ( isspace(c) ); return c; } /* * Read a number from a file. */ int fread_number( FILE *fp ) { int number; bool sign; char c; do { c = getc( fp ); } while ( isspace(c) ); number = 0; sign = FALSE; if ( c == '+' ) { c = getc( fp ); } else if ( c == '-' ) { sign = TRUE; c = getc( fp ); } if ( !isdigit(c) ) { bug( "Fread_number: bad format.", 0 ); exit( 1 ); } while ( isdigit(c) ) { number = number * 10 + c - '0'; c = getc( fp ); } if ( sign ) number = 0 - number; if ( c == '|' ) number += fread_number( fp ); else if ( c != ' ' ) ungetc( c, fp ); return number; } long fread_flag( FILE *fp) { int number; char c; bool negative = FALSE; do { c = getc(fp); } while ( isspace(c)); if (c == '-') { negative = TRUE; c = getc(fp); } number = 0; if (!isdigit(c)) { while (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) { number += flag_convert(c); c = getc(fp); } } while (isdigit(c)) { number = number * 10 + c - '0'; c = getc(fp); } if (c == '|') number += fread_flag(fp); else if ( c != ' ') ungetc(c,fp); if (negative) return -1 * number; return number; } long flag_convert(char letter ) { long bitsum = 0; char i; if ('A' <= letter && letter <= 'Z') { bitsum = 1; for (i = letter; i > 'A'; i--) bitsum *= 2; } else if ('a' <= letter && letter <= 'z') { bitsum = 67108864; /* 2^26 */ for (i = letter; i > 'a'; i --) bitsum *= 2; } return bitsum; } /* * Read and allocate space for a string from a file. * These strings are read-only and shared. * Strings are hashed: * each string prepended with hash pointer to prev string, * hash code is simply the string length. * this function takes 40% to 50% of boot-up time. */ char *fread_string( FILE *fp ) { char *plast; char c; plast = top_string + sizeof(char *); if ( plast > &string_space[MAX_STRING - MAX_STRING_LENGTH] ) { bug( "Fread_string: MAX_STRING %d exceeded.", MAX_STRING ); exit( 1 ); } /* * Skip blanks. * Read first char. */ do { c = getc( fp ); } while ( isspace(c) ); if ( ( *plast++ = c ) == '~' ) return &str_empty[0]; for ( ;; ) { /* * Back off the char type lookup, * it was too dirty for portability. * -- Furey */ switch ( *plast = getc(fp) ) { default: plast++; break; case EOF: /* temp fix */ bug( "Fread_string: EOF", 0 ); return NULL; /* exit( 1 ); */ break; case '\n': plast++; *plast++ = '\r'; break; case '\r': break; case '~': plast++; { union { char * pc; char rgc[sizeof(char *)]; } u1; int ic; int iHash; char *pHash; char *pHashPrev; char *pString; plast[-1] = '\0'; iHash = UMIN( MAX_KEY_HASH - 1, plast - 1 - top_string ); for ( pHash = string_hash[iHash]; pHash; pHash = pHashPrev ) { for ( ic = 0; ic < sizeof(char *); ic++ ) u1.rgc[ic] = pHash[ic]; pHashPrev = u1.pc; pHash += sizeof(char *); if ( top_string[sizeof(char *)] == pHash[0] && !strcmp( top_string+sizeof(char *)+1, pHash+1 ) ) return pHash; } if ( fBootDb ) { pString = top_string; top_string = plast; u1.pc = string_hash[iHash]; for ( ic = 0; ic < sizeof(char *); ic++ ) pString[ic] = u1.rgc[ic]; string_hash[iHash] = pString; nAllocString += 1; sAllocString += top_string - pString; return pString + sizeof(char *); } else { return str_dup( top_string + sizeof(char *) ); } } } } } char *fread_string_eol( FILE *fp ) { static bool char_special[256-EOF]; char *plast; char c; if ( char_special[EOF-EOF] != TRUE ) { char_special[EOF - EOF] = TRUE; char_special['\n' - EOF] = TRUE; char_special['\r' - EOF] = TRUE; } plast = top_string + sizeof(char *); if ( plast > &string_space[MAX_STRING - MAX_STRING_LENGTH] ) { bug( "Fread_string: MAX_STRING %d exceeded.", MAX_STRING ); exit( 1 ); } /* * Skip blanks. * Read first char. */ do { c = getc( fp ); } while ( isspace(c) ); if ( ( *plast++ = c ) == '\n') return &str_empty[0]; for ( ;; ) { if ( !char_special[ ( *plast++ = getc( fp ) ) - EOF ] ) continue; switch ( plast[-1] ) { default: break; case EOF: bug( "Fread_string_eol EOF", 0 ); exit( 1 ); break; case '\n': case '\r': { union { char * pc; char rgc[sizeof(char *)]; } u1; int ic; int iHash; char *pHash; char *pHashPrev; char *pString; plast[-1] = '\0'; iHash = UMIN( MAX_KEY_HASH - 1, plast - 1 - top_string ); for ( pHash = string_hash[iHash]; pHash; pHash = pHashPrev ) { for ( ic = 0; ic < sizeof(char *); ic++ ) u1.rgc[ic] = pHash[ic]; pHashPrev = u1.pc; pHash += sizeof(char *); if ( top_string[sizeof(char *)] == pHash[0] && !strcmp( top_string+sizeof(char *)+1, pHash+1 ) ) return pHash; } if ( fBootDb ) { pString = top_string; top_string = plast; u1.pc = string_hash[iHash]; for ( ic = 0; ic < sizeof(char *); ic++ ) pString[ic] = u1.rgc[ic]; string_hash[iHash] = pString; nAllocString += 1; sAllocString += top_string - pString; return pString + sizeof(char *); } else { return str_dup( top_string + sizeof(char *) ); } } } } } /* * Read to end of line (for comments). */ void fread_to_eol( FILE *fp ) { char c; do { c = getc( fp ); } while ( c != '\n' && c != '\r' ); do { c = getc( fp ); } while ( c == '\n' || c == '\r' ); ungetc( c, fp ); return; } /* * Read one word (into static buffer). */ char *fread_word( FILE *fp ) { static char word[MAX_INPUT_LENGTH]; char *pword; char cEnd; do { cEnd = getc( fp ); } while ( isspace( cEnd ) ); if ( cEnd == '\'' || cEnd == '"' ) { pword = word; } else { word[0] = cEnd; pword = word+1; cEnd = ' '; } for ( ; pword < word + MAX_INPUT_LENGTH; pword++ ) { *pword = getc( fp ); if ( cEnd == ' ' ? isspace(*pword) : *pword == cEnd ) { if ( cEnd == ' ' ) ungetc( *pword, fp ); *pword = '\0'; return word; } } bug( "Fread_word: word too long.", 0 ); exit( 1 ); return NULL; } /* * Allocate some ordinary memory, * with the expectation of freeing it someday. */ void *alloc_mem( int sMem ) { void *pMem; int *magic; int iList; sMem += sizeof(*magic); for ( iList = 0; iList < MAX_MEM_LIST; iList++ ) { if ( sMem <= rgSizeList[iList] ) break; } if ( iList == MAX_MEM_LIST ) { bug( "Alloc_mem: size %d too large.", sMem ); exit( 1 ); } if ( rgFreeList[iList] == NULL ) { pMem = alloc_perm( rgSizeList[iList] ); } else { pMem = rgFreeList[iList]; rgFreeList[iList] = * ((void **) rgFreeList[iList]); } magic = (int *) pMem; *magic = MAGIC_NUM; pMem += sizeof(*magic); return pMem; } /* * Free some memory. * Recycle it back onto the free list for blocks of that size. */ void free_mem( void *pMem, int sMem ) { int iList; int *magic; pMem -= sizeof(*magic); magic = (int *) pMem; if (*magic != MAGIC_NUM) { bug("Attempt to recyle invalid memory of size %d.",sMem); bug((char*) pMem + sizeof(*magic),0); return; } *magic = 0; sMem += sizeof(*magic); for ( iList = 0; iList < MAX_MEM_LIST; iList++ ) { if ( sMem <= rgSizeList[iList] ) break; } if ( iList == MAX_MEM_LIST ) { bug( "Free_mem: size %d too large.", sMem ); exit( 1 ); } * ((void **) pMem) = rgFreeList[iList]; rgFreeList[iList] = pMem; return; } /* * Allocate some permanent memory. * Permanent memory is never freed, * pointers into it may be copied safely. */ void *alloc_perm( int sMem ) { static char *pMemPerm; static int iMemPerm; void *pMem; while ( sMem % sizeof(long) != 0 ) sMem++; if ( sMem > MAX_PERM_BLOCK ) { bug( "Alloc_perm: %d too large.", sMem ); exit( 1 ); } if ( pMemPerm == NULL || iMemPerm + sMem > MAX_PERM_BLOCK ) { iMemPerm = 0; if ( ( pMemPerm = calloc( 1, MAX_PERM_BLOCK ) ) == NULL ) { perror( "Alloc_perm" ); exit( 1 ); } } pMem = pMemPerm + iMemPerm; iMemPerm += sMem; nAllocPerm += 1; sAllocPerm += sMem; return pMem; } /* * Duplicate a string into dynamic memory. * Fread_strings are read-only and shared. */ char *str_dup( const char *str ) { char *str_new; if ( str[0] == '\0' ) return &str_empty[0]; if ( str >= string_space && str < top_string ) return (char *) str; str_new = alloc_mem( strlen(str) + 1 ); strcpy( str_new, str ); return str_new; } /* * Free a string. * Null is legal here to simplify callers. * Read-only shared strings are not touched. */ void free_string( char *pstr ) { if ( pstr == NULL || pstr == &str_empty[0] || ( pstr >= string_space && pstr < top_string ) ) return; free_mem( pstr, strlen(pstr) + 1 ); return; } /* * Generate a random number. */ int number_range( int from, int to ) { int power; int number; if (from == 0 && to == 0) return 0; if ( ( to = to - from + 1 ) <= 1 ) return from; for ( power = 2; power < to; power <<= 1 ) ; while ( ( number = number_mm() & (power -1 ) ) >= to ) ; return from + number; } /* * Generate a percentile roll. */ int number_percent( void ) { int percent; while ( (percent = number_mm() & (128-1) ) > 99 ) ; return 1 + percent; } /* * Generate a random door. */ int number_door( void ) { int door; while ( ( door = number_mm() & (8-1) ) > 11) ; return door; } int number_bits( int width ) { return number_mm( ) & ( ( 1 << width ) - 1 ); } /* * I've gotten too many bad reports on OS-supplied random number generators. * This is the Mitchell-Moore algorithm from Knuth Volume II. * Best to leave the constants alone unless you've read Knuth. * -- Furey */ /* I noticed streaking with this random number generator, so I switched back to the system srandom call. If this doesn't work for you, define OLD_RAND to use the old system -- Alander */ #if defined (OLD_RAND) static int rgiState[2+55]; #endif long number_mm( void ) { #if defined (OLD_RAND) int *piState; int iState1; int iState2; int iRand; piState = &rgiState[2]; iState1 = piState[-2]; iState2 = piState[-1]; iRand = (piState[iState1] + piState[iState2]) & ((1 << 30) - 1); piState[iState1] = iRand; if ( ++iState1 == 55 ) iState1 = 0; if ( ++iState2 == 55 ) iState2 = 0; piState[-2] = iState1; piState[-1] = iState2; return iRand >> 6; #else return random() >> 6; #endif } /* * Roll some dice. */ int dice( int number, int size ) { int idice; int sum; switch ( size ) { case 0: return 0; case 1: return number; } for ( idice = 0, sum = 0; idice < number; idice++ ) sum += number_range( 1, size ); return sum; } /* * Simple linear interpolation. */ int interpolate( int level, int value_00, int value_32 ) { return value_00 + level * (value_32 - value_00) / 32; } /* * Removes the tildes from a string. * Used for player-entered strings that go into disk files. */ void smash_tilde( char *str ) { for ( ; *str != '\0'; str++ ) { if ( *str == '~' ) *str = '-'; } return; } /* * Compare strings, case insensitive. * Return TRUE if different * (compatibility with historical functions). */ bool str_cmp( const char *astr, const char *bstr ) { if ( astr == NULL ) { bug( "Str_cmp: null astr.", 0 ); return TRUE; } if ( bstr == NULL ) { bug( "Str_cmp: null bstr.", 0 ); return TRUE; } for ( ; *astr || *bstr; astr++, bstr++ ) { if ( LOWER(*astr) != LOWER(*bstr) ) return TRUE; } return FALSE; } /* * Compare strings, case insensitive, for prefix matching. * Return TRUE if astr not a prefix of bstr * (compatibility with historical functions). */ bool str_prefix( const char *astr, const char *bstr ) { if ( astr == NULL ) { bug( "Strn_cmp: null astr.", 0 ); return TRUE; } if ( bstr == NULL ) { bug( "Strn_cmp: null bstr.", 0 ); return TRUE; } for ( ; *astr; astr++, bstr++ ) { if ( LOWER(*astr) != LOWER(*bstr) ) return TRUE; } return FALSE; } /* * Compare strings, case sensitive, for prefix matching. * Return TRUE if astr not a prefix of bstr * (compatibility with historical functions). */ bool str_prefix_c( const char *astr, const char *bstr ) { if ( astr == NULL ) { bug( "Strn_cmp: null astr.", 0 ); return TRUE; } if ( bstr == NULL ) { bug( "Strn_cmp: null bstr.", 0 ); return TRUE; } for ( ; *astr; astr++, bstr++ ) { if ( *astr != *bstr ) return TRUE; } return FALSE; } /* * Compare strings, case insensitive, for match anywhere. * Returns TRUE is astr not part of bstr. * (compatibility with historical functions). */ bool str_infix( const char *astr, const char *bstr ) { int sstr1; int sstr2; int ichar; char c0; if ( ( c0 = LOWER(astr[0]) ) == '\0' ) return FALSE; sstr1 = strlen(astr); sstr2 = strlen(bstr); for ( ichar = 0; ichar <= sstr2 - sstr1; ichar++ ) { if ( c0 == LOWER(bstr[ichar]) && !str_prefix( astr, bstr + ichar ) ) return FALSE; } return TRUE; } /* * Compare strings, case sensitive, for match anywhere. * Returns TRUE is astr not part of bstr. * (compatibility with historical functions). */ bool str_infix_c( const char *astr, const char *bstr ) { int sstr1; int sstr2; int ichar; char c0; if ( ( c0 = astr[0] ) == '\0' ) return FALSE; sstr1 = strlen(astr); sstr2 = strlen(bstr); for ( ichar = 0; ichar <= sstr2 - sstr1; ichar++ ) { if ( c0 == bstr[ichar] && !str_prefix_c( astr, bstr + ichar ) ) return FALSE; } return TRUE; } /* * Replace a substring in a string, case insensitive...Russ Walsh * looks for bstr within astr and replaces it with cstr. */ char *str_replace( char *astr, char *bstr, char *cstr ) { char newstr[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; bool found = FALSE; int sstr1, sstr2; int ichar, jchar; char c0, c1, c2; if ( ( ( c0 = LOWER(astr[0]) ) == '\0' ) || ( ( c1 = LOWER(bstr[0]) ) == '\0' ) || ( ( c2 = LOWER(cstr[0]) ) == '\0' ) ) return astr; if (str_infix(bstr, astr) ) return astr; /* make sure we don't start an infinite loop */ if (!str_infix(bstr, cstr) ) return astr; sstr1 = strlen(astr); sstr2 = strlen(bstr); jchar = 0; if (sstr1 < sstr2) return astr; for ( ichar = 0; ichar <= sstr1 - sstr2; ichar++ ) { if ( c1 == LOWER(astr[ichar]) && !str_prefix( bstr, astr + ichar ) ) { found = TRUE; jchar = ichar; ichar = sstr1; } } if (found) { buf[0] = '\0'; for ( ichar = 0; ichar < jchar; ichar++ ) { sprintf(newstr, "%c", astr[ichar]); strcat(buf, newstr); } strcat(buf, cstr); for ( ichar = jchar + sstr2; ichar < sstr1; ichar++ ) { sprintf(newstr, "%c", astr[ichar]); strcat(buf, newstr); } sprintf(astr, "%s", str_replace(buf, bstr, cstr) ); return astr; } return astr; } /* * Replace a substring in a string, case sensitive...Russ Walsh * looks for bstr within astr and replaces it with cstr. */ char *str_replace_c( char *astr, char *bstr, char *cstr ) { char newstr[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; bool found = FALSE; int sstr1, sstr2; int ichar, jchar; char c0, c1, c2; if ( ( ( c0 = astr[0] ) == '\0' ) || ( ( c1 = bstr[0] ) == '\0' ) || ( ( c2 = cstr[0] ) == '\0' ) ) return astr; if (str_infix_c(bstr, astr) ) return astr; /* make sure we don't start an infinite loop */ if (!str_infix_c(bstr, cstr) ) return astr; sstr1 = strlen(astr); sstr2 = strlen(bstr); jchar = 0; if (sstr1 < sstr2) return astr; for ( ichar = 0; ichar <= sstr1 - sstr2; ichar++ ) { if ( c1 == astr[ichar] && !str_prefix_c( bstr, astr + ichar ) ) { found = TRUE; jchar = ichar; ichar = sstr1; } } if (found) { buf[0] = '\0'; for ( ichar = 0; ichar < jchar; ichar++ ) { sprintf(newstr, "%c", astr[ichar]); strcat(buf, newstr); } strcat(buf, cstr); for ( ichar = jchar + sstr2; ichar < sstr1; ichar++ ) { sprintf(newstr, "%c", astr[ichar]); strcat(buf, newstr); } sprintf(astr, "%s", str_replace_c(buf, bstr, cstr) ); return astr; } return astr; } /* * Compare strings, case insensitive, for suffix matching. * Return TRUE if astr not a suffix of bstr * (compatibility with historical functions). */ bool str_suffix( const char *astr, const char *bstr ) { int sstr1; int sstr2; sstr1 = strlen(astr); sstr2 = strlen(bstr); if ( sstr1 <= sstr2 && !str_cmp( astr, bstr + sstr2 - sstr1 ) ) return FALSE; else return TRUE; } /* * Returns an initial-capped string. */ char *capitalize( const char *str ) { static char strcap[MAX_STRING_LENGTH]; int i; for ( i = 0; str[i] != '\0'; i++ ) strcap[i] = LOWER(str[i]); strcap[i] = '\0'; strcap[0] = UPPER(strcap[0]); return strcap; } /* * Reports a bug. */ void bug( const char *str, int param ) { char buf[MAX_STRING_LENGTH]; if ( fpArea != NULL ) { int iLine; int iChar; if ( fpArea == stdin ) { iLine = 0; } else { iChar = ftell( fpArea ); fseek( fpArea, 0, 0 ); for ( iLine = 0; ftell( fpArea ) < iChar; iLine++ ) { while ( getc( fpArea ) != '\n' ) ; } fseek( fpArea, iChar, 0 ); } sprintf( buf, "[*****] FILE: %s LINE: %d", strArea, iLine ); log_string( buf ); /* RT removed because we don't want bugs shutting the mud if ( ( fp = fopen( "shutdown.txt", "a" ) ) != NULL ) { fprintf( fp, "[*****] %s\n", buf ); fclose( fp ); } */ } strcpy( buf, "[*****] BUG: " ); sprintf( buf + strlen(buf), str, param ); log_string( buf ); /* RT removed due to bug-file spamming fclose( fpReserve ); if ( ( fp = fopen( BUG_FILE, "a" ) ) != NULL ) { fprintf( fp, "%s\n", buf ); fclose( fp ); } fpReserve = fopen( NULL_FILE, "r" ); */ return; } /* * Writes a string to the log. */ void log_string( const char *str ) { fprintf( stderr, "%s\n", str ); return; } /* * This function is here to aid in debugging. * If the last expression in a function is another function call, * gcc likes to generate a JMP instead of a CALL. * This is called "tail chaining." * It hoses the debugger call stack for that call. * So I make this the last call in certain critical functions, * where I really need the call stack to be right for debugging! * * If you don't understand this, then LEAVE IT ALONE. * Don't remove any calls to tail_chain anywhere. * * -- Furey */ void tail_chain( void ) { return; }