/* * RAM $Id: db.c 81 2009-01-14 06:16:31Z ghasatta $ */ /*************************************************************************** * 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-1998 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@hypercube.org) * * Gabrielle Taylor (gtaylor@hypercube.org) * * Brian Moore (zump@rom.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * ***************************************************************************/ /*************************************************************************** * * * This code was freely distributed with the The Isles 1.1 source code, * * and has been used here for OLC - OLC would not be what it is without * * all the previous coders who released their source code. * * * ***************************************************************************/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <sys/time.h> #include <sys/resource.h> #include <errno.h> #include <string> #include "merc.h" #include "strings.h" #include "random.h" #include "tables.h" #include "act.h" #include "db.h" #include "interp.h" #include "magic.h" #include "special.h" #include "olc.h" #include "ban.h" /* * Globals. */ HELP_DATA *help_first = NULL; HELP_DATA *help_last = NULL; HELP_AREA *had_list = NULL; SHOP_DATA *shop_first = NULL; SHOP_DATA *shop_last = NULL; AREA_DATA *area_first = NULL; AREA_DATA *area_last = NULL; AREA_DATA *current_area = NULL; MPROG_CODE *mprog_list = NULL; MPROG_CODE *mpcode_free = NULL; char bug_buf[2 * MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; char log_buf[2 * MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; CHAR_DATA *char_list = NULL; HELP_DATA *help_greeting = NULL; KILL_DATA kill_table[MAX_LEVEL]; OBJ_DATA *object_list = NULL; TIME_INFO_DATA time_info; WEATHER_DATA weather_info; bool MOBtrigger = true; /* act() switch */ /* * Locals. */ MOB_INDEX_DATA *mob_index_hash[MAX_KEY_HASH]; OBJ_INDEX_DATA *obj_index_hash[MAX_KEY_HASH]; ROOM_INDEX_DATA *room_index_hash[MAX_KEY_HASH]; char *string_hash[MAX_KEY_HASH]; int top_affect = 0; int top_area = 0; int top_ed = 0; int top_exit = 0; int top_help = 0; int top_mob_index = 0; int top_obj_index = 0; int top_reset = 0; int top_room = 0; int top_shop = 0; int top_vnum_room = 0; /* OLC */ int top_vnum_mob = 0; /* OLC */ int top_vnum_obj = 0; /* OLC */ int top_mprog_index = 0; /* OLC */ int mobile_count = 0; int newmobs = 0; int newobjs = 0; /* * Semi-locals. */ bool fBootDb = false; FILE *fpArea = NULL; char strArea[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; struct social_type social_table[MAX_SOCIALS]; int social_count = 0; /* stuff for recycling extended descs */ EXTRA_DESCR_DATA *extra_descr_free = NULL; EXTRA_DESCR_DATA *new_extra_descr( void ) { EXTRA_DESCR_DATA *ed = NULL; if ( extra_descr_free == NULL ) ed = ( EXTRA_DESCR_DATA * ) alloc_perm( sizeof( *ed ) ); else { ed = extra_descr_free; extra_descr_free = extra_descr_free->next; } ed->keyword = &str_empty[0]; ed->description = &str_empty[0]; VALIDATE( ed ); return ed; } void free_extra_descr( EXTRA_DESCR_DATA *ed ) { if ( !IS_VALID( ed ) ) return; free_string( ed->keyword ); free_string( ed->description ); INVALIDATE( ed ); ed->next = extra_descr_free; extra_descr_free = ed; } /* stuff for recycling objects */ OBJ_DATA *obj_free = NULL; OBJ_DATA *new_obj( void ) { static OBJ_DATA obj_zero; OBJ_DATA *obj = NULL; if ( obj_free == NULL ) obj = ( OBJ_DATA * ) alloc_perm( sizeof( *obj ) ); else { obj = obj_free; obj_free = obj_free->next; } *obj = obj_zero; VALIDATE( obj ); return obj; } void free_obj( OBJ_DATA *obj ) { AFFECT_DATA *paf = NULL; AFFECT_DATA *paf_next = NULL; EXTRA_DESCR_DATA *ed = NULL; EXTRA_DESCR_DATA *ed_next = NULL; if ( !IS_VALID( obj ) ) return; for ( paf = obj->affected; paf != NULL; paf = paf_next ) { paf_next = paf->next; free_affect( paf ); } obj->affected = NULL; for ( ed = obj->extra_descr; ed != NULL; ed = ed_next ) { ed_next = ed->next; free_extra_descr( ed ); } obj->extra_descr = NULL; free_string( obj->name ); free_string( obj->description ); free_string( obj->short_descr ); free_string( obj->owner ); INVALIDATE( obj ); obj->next = obj_free; obj_free = obj; } /* stuff for recyling characters */ CHAR_DATA *char_free = NULL; CHAR_DATA *new_char( void ) { static CHAR_DATA ch_zero; CHAR_DATA *ch = NULL; int i = 0; if ( char_free == NULL ) ch = ( CHAR_DATA * ) alloc_perm( sizeof( *ch ) ); else { ch = char_free; char_free = char_free->next; } *ch = ch_zero; VALIDATE( ch ); ch->name = &str_empty[0]; ch->short_descr = &str_empty[0]; ch->long_descr = &str_empty[0]; ch->description = &str_empty[0]; ch->prompt = &str_empty[0]; ch->prefix = &str_empty[0]; ch->logon = current_time; ch->lines = PAGELEN; for ( i = 0; i < 4; i++ ) ch->armor[i] = 100; ch->position = POS_STANDING; ch->hit = 20; ch->max_hit = 20; ch->mana = 100; ch->max_mana = 100; ch->move = 100; ch->max_move = 100; for ( i = 0; i < MAX_STATS; i++ ) { ch->perm_stat[i] = 13; ch->mod_stat[i] = 0; } return ch; } void free_char( CHAR_DATA *ch ) { OBJ_DATA *obj = NULL; OBJ_DATA *obj_next = NULL; AFFECT_DATA *paf = NULL; AFFECT_DATA *paf_next = NULL; if ( !IS_VALID( ch ) ) return; if ( IS_NPC( ch ) ) mobile_count--; for ( obj = ch->carrying; obj != NULL; obj = obj_next ) { obj_next = obj->next_content; extract_obj( obj ); } for ( paf = ch->affected; paf != NULL; paf = paf_next ) { paf_next = paf->next; affect_remove( ch, paf ); } free_string( ch->name ); free_string( ch->short_descr ); free_string( ch->long_descr ); free_string( ch->description ); free_string( ch->prompt ); free_string( ch->prefix ); free_note( ch->pnote ); free_pcdata( ch->pcdata ); ch->next = char_free; char_free = ch; INVALIDATE( ch ); return; } PC_DATA *pcdata_free = NULL; PC_DATA *new_pcdata( void ) { int alias = 0; static PC_DATA pcdata_zero; PC_DATA *pcdata = NULL; if ( pcdata_free == NULL ) pcdata = ( PC_DATA * ) alloc_perm( sizeof( *pcdata ) ); else { pcdata = pcdata_free; pcdata_free = pcdata_free->next; } *pcdata = pcdata_zero; for ( alias = 0; alias < MAX_ALIAS; alias++ ) { pcdata->alias[alias] = NULL; pcdata->alias_sub[alias] = NULL; } pcdata->buffer = new_buf( ); VALIDATE( pcdata ); return pcdata; } void free_pcdata( PC_DATA *pcdata ) { int alias = 0; if ( !IS_VALID( pcdata ) ) return; free_string( pcdata->pwd ); free_string( pcdata->bamfin ); free_string( pcdata->bamfout ); free_string( pcdata->title ); free_buf( pcdata->buffer ); for ( alias = 0; alias < MAX_ALIAS; alias++ ) { free_string( pcdata->alias[alias] ); free_string( pcdata->alias_sub[alias] ); } INVALIDATE( pcdata ); pcdata->next = pcdata_free; pcdata_free = pcdata; return; } /* stuff for setting ids */ int last_pc_id = 0; int last_mob_id = 0; int get_pc_id( void ) { int val = 0; val = ( current_time <= last_pc_id ) ? last_pc_id + 1 : current_time; last_pc_id = val; return val; } int get_mob_id( void ) { last_mob_id++; return last_mob_id; } MEM_DATA *mem_data_free = NULL; MEM_DATA *new_mem_data( void ) { MEM_DATA *memory = NULL; if ( mem_data_free == NULL ) memory = ( MEM_DATA * ) alloc_mem( sizeof( *memory ) ); else { memory = mem_data_free; mem_data_free = mem_data_free->next; } memory->next = NULL; memory->id = 0; memory->reaction = 0; memory->when = 0; VALIDATE( memory ); return memory; } void free_mem_data( MEM_DATA *memory ) { if ( !IS_VALID( memory ) ) return; memory->next = mem_data_free; mem_data_free = memory; INVALIDATE( memory ); } /* This was added for OLC */ RESET_DATA *reset_free = NULL; RESET_DATA *new_reset_data( void ) { RESET_DATA *pReset = NULL; if ( !reset_free ) { pReset = ( RESET_DATA * ) alloc_perm( sizeof( *pReset ) ); top_reset++; } else { pReset = reset_free; reset_free = reset_free->next; } pReset->next = NULL; pReset->command = 'X'; pReset->arg1 = 0; pReset->arg2 = 0; pReset->arg3 = 0; pReset->arg4 = 0; return pReset; } void free_reset_data( RESET_DATA *pReset ) { pReset->next = reset_free; reset_free = pReset; return; } AREA_DATA *area_free = NULL; AREA_DATA *new_area( void ) { AREA_DATA *pArea = NULL; char buf[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; if ( !area_free ) { pArea = ( AREA_DATA * ) alloc_perm( sizeof( *pArea ) ); top_area++; } else { pArea = area_free; area_free = area_free->next; } pArea->next = NULL; pArea->name = str_dup( "New area" ); /* pArea->recall = ROOM_VNUM_TEMPLE; ROM OLC */ pArea->area_flags = AREA_ADDED; pArea->security = 1; pArea->builders = str_dup( "None" ); pArea->min_vnum = 0; pArea->max_vnum = 0; pArea->age = 0; pArea->nplayer = 0; pArea->empty = true; /* ROM patch */ sprintf( buf, "area%d.are", pArea->vnum ); pArea->file_name = str_dup( buf ); pArea->vnum = top_area - 1; return pArea; } void free_area( AREA_DATA *pArea ) { free_string( pArea->name ); free_string( pArea->file_name ); free_string( pArea->builders ); free_string( pArea->credits ); pArea->next = area_free->next; area_free = pArea; return; } EXIT_DATA *exit_free = NULL; EXIT_DATA *new_exit( void ) { EXIT_DATA *pExit = NULL; if ( !exit_free ) { pExit = ( EXIT_DATA * ) alloc_perm( sizeof( *pExit ) ); top_exit++; } else { pExit = exit_free; exit_free = exit_free->next; } pExit->u1.to_room = NULL; /* ROM OLC */ pExit->next = NULL; /* pExit->vnum = 0; ROM OLC */ pExit->exit_info = 0; pExit->key = 0; pExit->keyword = &str_empty[0]; pExit->description = &str_empty[0]; pExit->rs_flags = 0; return pExit; } void free_exit( EXIT_DATA *pExit ) { free_string( pExit->keyword ); free_string( pExit->description ); pExit->next = exit_free; exit_free = pExit; return; } ROOM_INDEX_DATA *room_index_free = NULL; ROOM_INDEX_DATA *new_room_index( void ) { ROOM_INDEX_DATA *pRoom = NULL; int door = -1; if ( !room_index_free ) { pRoom = ( ROOM_INDEX_DATA * ) alloc_perm( sizeof( *pRoom ) ); top_room++; } else { pRoom = room_index_free; room_index_free = room_index_free->next; } pRoom->next = NULL; pRoom->people = NULL; pRoom->contents = NULL; pRoom->extra_descr = NULL; pRoom->area = NULL; for ( door = 0; door < MAX_DIR; door++ ) pRoom->exit[door] = NULL; pRoom->name = &str_empty[0]; pRoom->description = &str_empty[0]; pRoom->owner = &str_empty[0]; pRoom->vnum = 0; pRoom->room_flags = 0; pRoom->light = 0; pRoom->sector_type = 0; pRoom->clan = 0; pRoom->heal_rate = 100; pRoom->mana_rate = 100; return pRoom; } void free_room_index( ROOM_INDEX_DATA *pRoom ) { int door = -1; EXTRA_DESCR_DATA *pExtra = NULL; RESET_DATA *pReset = NULL; free_string( pRoom->name ); free_string( pRoom->description ); free_string( pRoom->owner ); for ( door = 0; door < MAX_DIR; door++ ) { if ( pRoom->exit[door] ) free_exit( pRoom->exit[door] ); } for ( pExtra = pRoom->extra_descr; pExtra; pExtra = pExtra->next ) { free_extra_descr( pExtra ); } for ( pReset = pRoom->reset_first; pReset; pReset = pReset->next ) { free_reset_data( pReset ); } pRoom->next = room_index_free; room_index_free = pRoom; return; } SHOP_DATA *shop_free = NULL; SHOP_DATA *new_shop( void ) { SHOP_DATA *pShop = NULL; int buy = 0; if ( !shop_free ) { pShop = ( SHOP_DATA * ) alloc_perm( sizeof( *pShop ) ); top_shop++; } else { pShop = shop_free; shop_free = shop_free->next; } pShop->next = NULL; pShop->keeper = 0; for ( buy = 0; buy < MAX_TRADE; buy++ ) pShop->buy_type[buy] = 0; pShop->profit_buy = 100; pShop->profit_sell = 100; pShop->open_hour = 0; pShop->close_hour = 23; return pShop; } void free_shop( SHOP_DATA *pShop ) { pShop->next = shop_free; shop_free = pShop; return; } OBJ_INDEX_DATA *obj_index_free = NULL; OBJ_INDEX_DATA *new_obj_index( void ) { OBJ_INDEX_DATA *pObj = NULL; int value = 0; if ( !obj_index_free ) { pObj = ( OBJ_INDEX_DATA * ) alloc_perm( sizeof( *pObj ) ); top_obj_index++; } else { pObj = obj_index_free; obj_index_free = obj_index_free->next; } pObj->next = NULL; pObj->extra_descr = NULL; pObj->affected = NULL; pObj->area = NULL; pObj->name = str_dup( "no name" ); pObj->short_descr = str_dup( "(no short description)" ); pObj->description = str_dup( "(no description)" ); pObj->vnum = 0; pObj->item_type = ITEM_TRASH; pObj->extra_flags = 0; pObj->wear_flags = 0; pObj->count = 0; pObj->weight = 0; pObj->cost = 0; pObj->material = str_dup( "unknown" ); /* ROM */ pObj->condition = 100; /* ROM */ for ( value = 0; value < 5; value++ ) /* 5 - ROM */ pObj->value[value] = 0; pObj->new_format = true; /* ROM */ return pObj; } void free_obj_index( OBJ_INDEX_DATA *pObj ) { EXTRA_DESCR_DATA *pExtra = NULL; AFFECT_DATA *pAf = NULL; free_string( pObj->name ); free_string( pObj->short_descr ); free_string( pObj->description ); for ( pAf = pObj->affected; pAf; pAf = pAf->next ) { free_affect( pAf ); } for ( pExtra = pObj->extra_descr; pExtra; pExtra = pExtra->next ) { free_extra_descr( pExtra ); } pObj->next = obj_index_free; obj_index_free = pObj; return; } MOB_INDEX_DATA *mob_index_free = NULL; MOB_INDEX_DATA *new_mob_index( void ) { MOB_INDEX_DATA *pMob = NULL; if ( !mob_index_free ) { pMob = ( MOB_INDEX_DATA * ) alloc_perm( sizeof( *pMob ) ); top_mob_index++; } else { pMob = mob_index_free; mob_index_free = mob_index_free->next; } pMob->next = NULL; pMob->spec_fun = NULL; pMob->pShop = NULL; pMob->area = NULL; pMob->player_name = str_dup( "no name" ); pMob->short_descr = str_dup( "(no short description)" ); pMob->long_descr = str_dup( "(no long description)\r\n" ); pMob->description = &str_empty[0]; pMob->vnum = 0; pMob->count = 0; pMob->killed = 0; pMob->sex = 0; pMob->level = 0; pMob->act = ACT_IS_NPC; pMob->affected_by = 0; pMob->alignment = 0; pMob->hitroll = 0; pMob->race = race_lookup( "human" ); /* - Hugin */ pMob->form = 0; /* ROM patch -- Hugin */ pMob->parts = 0; /* ROM patch -- Hugin */ pMob->imm_flags = 0; /* ROM patch -- Hugin */ pMob->res_flags = 0; /* ROM patch -- Hugin */ pMob->vuln_flags = 0; /* ROM patch -- Hugin */ pMob->material = str_dup( "unknown" ); /* -- Hugin */ pMob->off_flags = 0; /* ROM patch -- Hugin */ pMob->size = SIZE_MEDIUM; /* ROM patch -- Hugin */ pMob->ac[AC_PIERCE] = 0; /* ROM patch -- Hugin */ pMob->ac[AC_BASH] = 0; /* ROM patch -- Hugin */ pMob->ac[AC_SLASH] = 0; /* ROM patch -- Hugin */ pMob->ac[AC_EXOTIC] = 0; /* ROM patch -- Hugin */ pMob->hit[DICE_NUMBER] = 0; /* ROM patch -- Hugin */ pMob->hit[DICE_TYPE] = 0; /* ROM patch -- Hugin */ pMob->hit[DICE_BONUS] = 0; /* ROM patch -- Hugin */ pMob->mana[DICE_NUMBER] = 0; /* ROM patch -- Hugin */ pMob->mana[DICE_TYPE] = 0; /* ROM patch -- Hugin */ pMob->mana[DICE_BONUS] = 0; /* ROM patch -- Hugin */ pMob->damage[DICE_NUMBER] = 0; /* ROM patch -- Hugin */ pMob->damage[DICE_TYPE] = 0; /* ROM patch -- Hugin */ pMob->damage[DICE_NUMBER] = 0; /* ROM patch -- Hugin */ pMob->start_pos = POS_STANDING; /* -- Hugin */ pMob->default_pos = POS_STANDING; /* -- Hugin */ pMob->wealth = 0; pMob->new_format = true; /* ROM */ return pMob; } void free_mob_index( MOB_INDEX_DATA *pMob ) { free_string( pMob->player_name ); free_string( pMob->short_descr ); free_string( pMob->long_descr ); free_string( pMob->description ); free_mprog( pMob->mprogs ); free_shop( pMob->pShop ); pMob->next = mob_index_free; mob_index_free = pMob; return; } MPROG_CODE *new_mpcode( void ) { MPROG_CODE *NewCode = NULL; if ( !mpcode_free ) { NewCode = ( MPROG_CODE * ) alloc_perm( sizeof( *NewCode ) ); top_mprog_index++; } else { NewCode = mpcode_free; mpcode_free = mpcode_free->next; } NewCode->vnum = 0; NewCode->code = str_dup( "" ); NewCode->next = NULL; return NewCode; } void free_mpcode( MPROG_CODE *pMcode ) { free_string( pMcode->code ); pMcode->next = mpcode_free; mpcode_free = pMcode; return; } /* * Big mama top level function. */ void boot_db( void ) { /* * Init some data space stuff. */ { log_boot( "Allocating %d bytes of static string space", MAX_STRING ); if ( ( string_space = ( char * ) calloc( 1, MAX_STRING ) ) == NULL ) { proper_exit( MUD_HALT, "Boot_db: can't alloc %d string space.", MAX_STRING ); } top_string = string_space; fBootDb = true; } /* * Init random number generator. */ { log_boot( "Seeding random number generator" ); init_random( ); } /* * Set time and weather. */ { int lhour = 0; int lday = 0; int lmonth = 0; log_boot( "Updating game time and weather" ); lhour = ( current_time - 650336715 ) / ( PULSE_TICK / PULSE_PER_SECOND ); time_info.hour = lhour % 24; lday = lhour / 24; time_info.day = lday % 35; lmonth = lday / 35; time_info.month = lmonth % 17; time_info.year = lmonth / 17; if ( time_info.hour < 5 ) weather_info.sunlight = SUN_DARK; else if ( time_info.hour < 6 ) weather_info.sunlight = SUN_RISE; else if ( time_info.hour < 19 ) weather_info.sunlight = SUN_LIGHT; else if ( time_info.hour < 20 ) weather_info.sunlight = SUN_SET; else weather_info.sunlight = SUN_DARK; weather_info.change = 0; weather_info.mmhg = 960; if ( time_info.month >= 7 && time_info.month <= 12 ) weather_info.mmhg += number_range( 1, 50 ); else weather_info.mmhg += number_range( 1, 80 ); if ( weather_info.mmhg <= 980 ) weather_info.sky = SKY_LIGHTNING; else if ( weather_info.mmhg <= 1000 ) weather_info.sky = SKY_RAINING; else if ( weather_info.mmhg <= 1020 ) weather_info.sky = SKY_CLOUDY; else weather_info.sky = SKY_CLOUDLESS; } sort_skill_table( ); /* * Read in all the area files. */ { FILE *fpList = NULL; log_boot( "Loading areas..." ); if ( ( fpList = fopen( AREA_LIST, "r" ) ) == NULL ) { char *e = strerror( errno ); proper_exit( MUD_HALT, "%s: %s\n", AREA_LIST, e ); } for ( ;; ) { strcpy( strArea, fread_word( fpList ) ); if ( strArea[0] == '$' ) break; //log_boot( "Loading %s", strArea ); if ( strArea[0] == '-' ) { fpArea = stdin; } else { if ( ( fpArea = fopen( strArea, "r" ) ) == NULL ) { char *e = strerror( errno ); proper_exit( MUD_HALT, "%s: %s\n", strArea, e ); } } load_area_file( fpArea ); if ( fpArea != stdin ) fclose( fpArea ); fpArea = NULL; } fclose( fpList ); } /* * Fix up exits. * Declare db booting over. * Reset all areas once. * Load up the notes and ban files. */ { log_boot( "Fixing exits" ); fix_exits( ); fix_mobprogs( ); fBootDb = false; convert_objects( ); /* ROM OLC */ area_update( ); load_notes( ); ban_manager::Instance()->load_bans( ); load_player_list( ); } return; } /* * Figures out which area format is in use. */ void load_area_file( FILE * fp ) { char *word = NULL; int version = 0; if ( fp == stdin ) { /* * We can't fseek here, so assume it's OLD format! */ load_rom_area_file( fp ); return; } if ( fread_letter( fpArea ) != '#' ) { proper_exit( MUD_HALT, "Boot_db: # not found." ); } word = fread_word( fpArea ); if ( str_cmp( word, "VERSION" ) ) { /* * If the first line isn't #VERSION, this is an old format file. */ rewind( fp ); load_rom_area_file( fp ); return; } version = fread_number( fp ); load_ram_area_file( fp, version ); } /* * Loads an entire area file, RaM format. */ void load_ram_area_file( FILE * fp, int version ) { load_rom_area_file( fp ); } /* * Loads an entire area file, ROM format. */ void load_rom_area_file( FILE * fp ) { current_area = NULL; for ( ;; ) { char *word = NULL; if ( fread_letter( fp ) != '#' ) { proper_exit( MUD_HALT, "Boot_db: # not found." ); } word = fread_word( fp ); if ( word[0] == '$' ) break; else if ( !str_cmp( word, "AREA" ) ) load_area( fp ); else if ( !str_cmp( word, "AREADATA" ) ) new_load_area( fp ); else if ( !str_cmp( word, "HELPS" ) ) load_helps( fp, strArea ); else if ( !str_cmp( word, "MOBOLD" ) ) load_old_mob( fp ); else if ( !str_cmp( word, "MOBILES" ) ) load_mobiles( fp ); else if ( !str_cmp( word, "MOBPROGS" ) ) load_mobprogs( fp ); else if ( !str_cmp( word, "OBJOLD" ) ) load_old_obj( fp ); else if ( !str_cmp( word, "OBJECTS" ) ) load_objects( fp ); else if ( !str_cmp( word, "RESETS" ) ) load_resets( fp ); else if ( !str_cmp( word, "ROOMS" ) ) load_rooms( fp ); else if ( !str_cmp( word, "SHOPS" ) ) load_shops( fp ); else if ( !str_cmp( word, "SOCIALS" ) ) load_socials( fp ); else if ( !str_cmp( word, "SPECIALS" ) ) load_specials( fp ); else { proper_exit( MUD_HALT, "Boot_db: bad section name." ); } } } /* * Snarf an 'area' header line. */ void load_area( FILE * fp ) { AREA_DATA *pArea = NULL; pArea = ( AREA_DATA * ) alloc_perm( sizeof( *pArea ) ); pArea->reset_first = NULL; pArea->reset_last = NULL; pArea->file_name = fread_string( fp ); pArea->area_flags = AREA_LOADING; /* OLC */ pArea->security = 9; /* OLC - 9 -- Hugin */ pArea->builders = str_dup( "None" ); /* OLC */ pArea->vnum = top_area; /* OLC */ pArea->name = fread_string( fp ); pArea->credits = fread_string( fp ); pArea->min_vnum = fread_number( fp ); pArea->max_vnum = fread_number( fp ); pArea->age = 15; pArea->nplayer = 0; pArea->empty = false; if ( area_first == NULL ) area_first = pArea; if ( area_last != NULL ) { area_last->next = pArea; REMOVE_BIT( area_last->area_flags, AREA_LOADING ); /* OLC */ } area_last = pArea; pArea->next = NULL; current_area = pArea; top_area++; return; } /* OLC * Snarf an 'area' header line. Check this format. MUCH better. Add fields * too. * * #AREAFILE * Name { All } Locke Newbie School~ * Repop A teacher pops in the room and says, 'Repop coming!'~ * Recall 3001 * End */ void new_load_area( FILE * fp ) { AREA_DATA *pArea = NULL; const char *word = NULL; bool fMatch = false; pArea = ( AREA_DATA * ) alloc_perm( sizeof( *pArea ) ); pArea->age = 15; pArea->nplayer = 0; pArea->file_name = str_dup( strArea ); pArea->vnum = top_area; pArea->name = str_dup( "New Area" ); pArea->builders = str_dup( "" ); pArea->security = 9; /* 9 -- Hugin */ pArea->min_vnum = 0; pArea->max_vnum = 0; pArea->area_flags = 0; /* pArea->recall = ROOM_VNUM_TEMPLE; ROM OLC */ for ( ;; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = false; switch ( UPPER( word[0] ) ) { case 'N': KEYS( "Name", pArea->name, fread_string( fp ) ); break; case 'S': KEY( "Security", pArea->security, fread_number( fp ) ); break; case 'V': if ( !str_cmp( word, "VNUMs" ) ) { pArea->min_vnum = fread_number( fp ); pArea->max_vnum = fread_number( fp ); } break; case 'E': if ( !str_cmp( word, "End" ) ) { fMatch = true; if ( area_first == NULL ) area_first = pArea; if ( area_last != NULL ) area_last->next = pArea; area_last = pArea; pArea->next = NULL; current_area = pArea; top_area++; return; } break; case 'B': KEYS( "Builders", pArea->builders, fread_string( fp ) ); break; case 'C': KEYS( "Credits", pArea->credits, fread_string( fp ) ); break; } } } /* * Sets vnum range for area using OLC protection features. */ void assign_area_vnum( int vnum ) { if ( area_last->min_vnum == 0 || area_last->max_vnum == 0 ) area_last->min_vnum = area_last->max_vnum = vnum; if ( vnum != URANGE( area_last->min_vnum, vnum, area_last->max_vnum ) ) { if ( vnum < area_last->min_vnum ) area_last->min_vnum = vnum; else area_last->max_vnum = vnum; } return; } #if 0 /* * Snarf an old help section. */ void old_load_helps( FILE * fp ) { HELP_DATA *pHelp = NULL; for ( ;; ) { pHelp = ( HELP_DATA * ) alloc_perm( sizeof( *pHelp ) ); pHelp->level = fread_number( fp ); pHelp->keyword = fread_string( fp ); if ( pHelp->keyword[0] == '$' ) break; pHelp->text = fread_string( fp ); if ( !str_cmp( pHelp->keyword, "greeting" ) ) help_greeting = pHelp->text; if ( help_first == NULL ) help_first = pHelp; if ( help_last != NULL ) help_last->next = pHelp; help_last = pHelp; pHelp->next = NULL; top_help++; } return; } #endif /* * Snarf a help section. */ void load_helps( FILE * fp, const char *fname ) { HELP_DATA *pHelp = NULL; char *keyword = NULL; int level = 0; log_boot( "Loading helps..." ); for ( ;; ) { HELP_AREA *had = NULL; level = fread_number( fp ); keyword = fread_string( fp ); if ( keyword[0] == '$' ) break; if ( !had_list ) { had = new_had( ); had->filename = str_dup( fname ); had->area = current_area; if ( current_area ) current_area->helps = had; had_list = had; } else if ( str_cmp( fname, had_list->filename ) ) { had = new_had( ); had->filename = str_dup( fname ); had->area = current_area; if ( current_area ) current_area->helps = had; had->next = had_list; had_list = had; } else had = had_list; pHelp = new_help( ); pHelp->level = level; //debug fixme // log_boot( "loading help keyword: %s", keyword ); pHelp->keyword = keyword; char *txt = fread_string(fp); // log_boot( "loading help text: %s", txt ); //pHelp->text = fread_string( fp ); pHelp->text = txt; if ( !str_cmp( pHelp->keyword.c_str(), "greeting" ) ) help_greeting = pHelp; if ( help_first == NULL ) help_first = pHelp; if ( help_last != NULL ) help_last->next = pHelp; help_last = pHelp; pHelp->next = NULL; if ( !had->first ) had->first = pHelp; if ( !had->last ) had->last = pHelp; had->last->next_area = pHelp; had->last = pHelp; pHelp->next_area = NULL; top_help++; } return; } /* * Snarf a mob section. old style */ void load_old_mob( FILE * fp ) { MOB_INDEX_DATA *pMobIndex = NULL; /* * for race updating */ int race = 0; char name[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0"; if ( !area_last ) /* OLC */ { proper_exit( MUD_HALT, "OLD Load_mobiles: no #AREA seen yet." ); } for ( ;; ) { int vnum = 0; char letter = '\0'; int iHash = 0; letter = fread_letter( fp ); if ( letter != '#' ) { proper_exit( MUD_HALT, "Load_mobiles: # not found." ); } vnum = fread_number( fp ); if ( vnum == 0 ) break; fBootDb = false; if ( get_mob_index( vnum ) != NULL ) { proper_exit( MUD_HALT, "Load_mobiles: vnum %d duplicated.", vnum ); } fBootDb = true; pMobIndex = ( MOB_INDEX_DATA * ) alloc_perm( sizeof( *pMobIndex ) ); pMobIndex->vnum = vnum; pMobIndex->area = area_last; /* OLC */ pMobIndex->new_format = false; pMobIndex->player_name = fread_string( fp ); pMobIndex->short_descr = fread_string( fp ); pMobIndex->long_descr = fread_string( fp ); pMobIndex->description = fread_string( fp ); pMobIndex->long_descr[0] = UPPER( pMobIndex->long_descr[0] ); pMobIndex->description[0] = UPPER( pMobIndex->description[0] ); pMobIndex->act = fread_flag( fp ) | ACT_IS_NPC; pMobIndex->affected_by = fread_flag( fp ); pMobIndex->pShop = NULL; pMobIndex->alignment = fread_number( fp ); letter = fread_letter( fp ); pMobIndex->level = fread_number( fp ); /* * The unused stuff is for imps who want to use the old-style * stats-in-files method. */ fread_number( fp ); /* Unused */ fread_number( fp ); /* Unused */ fread_number( fp ); /* Unused */ fread_letter( fp ); /* 'd' */ fread_number( fp ); /* Unused */ fread_letter( fp ); /* '+' */ fread_number( fp ); /* Unused */ fread_number( fp ); /* Unused */ fread_letter( fp ); /* 'd' */ fread_number( fp ); /* Unused */ fread_letter( fp ); /* '+' */ fread_number( fp ); /* Unused */ pMobIndex->wealth = fread_number( fp ) / 20; fread_number( fp ); /* xp can't be used! */ pMobIndex->start_pos = fread_number( fp ); /* Unused */ pMobIndex->default_pos = fread_number( fp ); /* Unused */ if ( pMobIndex->start_pos < POS_SLEEPING ) pMobIndex->start_pos = POS_STANDING; if ( pMobIndex->default_pos < POS_SLEEPING ) pMobIndex->default_pos = POS_STANDING; /* * Back to meaningful values. */ pMobIndex->sex = fread_number( fp ); /* * compute the race BS */ one_argument( pMobIndex->player_name, name ); if ( name[0] == '\0' || ( race = race_lookup( name ) ) == 0 ) { /* * fill in with blanks */ pMobIndex->race = race_lookup( "human" ); pMobIndex->off_flags = OFF_DODGE | OFF_DISARM | OFF_TRIP | ASSIST_VNUM; pMobIndex->imm_flags = 0; pMobIndex->res_flags = 0; pMobIndex->vuln_flags = 0; pMobIndex->form = FORM_EDIBLE | FORM_SENTIENT | FORM_BIPED | FORM_MAMMAL; pMobIndex->parts = PART_HEAD | PART_ARMS | PART_LEGS | PART_HEART | PART_BRAINS | PART_GUTS; } else { pMobIndex->race = race; pMobIndex->off_flags = OFF_DODGE | OFF_DISARM | OFF_TRIP | ASSIST_RACE | race_table[race].off; pMobIndex->imm_flags = race_table[race].imm; pMobIndex->res_flags = race_table[race].res; pMobIndex->vuln_flags = race_table[race].vuln; pMobIndex->form = race_table[race].form; pMobIndex->parts = race_table[race].parts; } if ( letter != 'S' ) { proper_exit( MUD_HALT, "Load_mobiles: vnum %d non-S.", vnum ); } convert_mobile( pMobIndex ); /* ROM OLC */ iHash = vnum % MAX_KEY_HASH; pMobIndex->next = mob_index_hash[iHash]; mob_index_hash[iHash] = pMobIndex; top_mob_index++; top_vnum_mob = top_vnum_mob < vnum ? vnum : top_vnum_mob; /* OLC */ assign_area_vnum( vnum ); /* OLC */ kill_table[URANGE( 0, pMobIndex->level, MAX_LEVEL - 1 )].number++; } return; } /* * Snarf an obj section. old style */ void load_old_obj( FILE * fp ) { OBJ_INDEX_DATA *pObjIndex = NULL; if ( !area_last ) /* OLC */ { proper_exit( MUD_HALT, "OLD Load_objects: no #AREA seen yet." ); } for ( ;; ) { int vnum = 0; char letter = '\0'; int iHash = 0; letter = fread_letter( fp ); if ( letter != '#' ) { proper_exit( MUD_HALT, "Load_objects: # not found." ); } vnum = fread_number( fp ); if ( vnum == 0 ) break; fBootDb = false; if ( get_obj_index( vnum ) != NULL ) { proper_exit( MUD_HALT, "Load_objects: vnum %d duplicated.", vnum ); } fBootDb = true; pObjIndex = ( OBJ_INDEX_DATA * ) alloc_perm( sizeof( *pObjIndex ) ); pObjIndex->vnum = vnum; pObjIndex->area = area_last; /* OLC */ pObjIndex->new_format = false; pObjIndex->reset_num = 0; pObjIndex->name = fread_string( fp ); pObjIndex->short_descr = fread_string( fp ); pObjIndex->description = fread_string( fp ); /* * Action description */ fread_string( fp ); pObjIndex->short_descr[0] = LOWER( pObjIndex->short_descr[0] ); pObjIndex->description[0] = UPPER( pObjIndex->description[0] ); pObjIndex->material = str_dup( "" ); pObjIndex->item_type = fread_number( fp ); pObjIndex->extra_flags = fread_flag( fp ); pObjIndex->wear_flags = fread_flag( fp ); pObjIndex->value[0] = fread_number( fp ); pObjIndex->value[1] = fread_number( fp ); pObjIndex->value[2] = fread_number( fp ); pObjIndex->value[3] = fread_number( fp ); pObjIndex->value[4] = 0; pObjIndex->level = 0; pObjIndex->condition = 100; pObjIndex->weight = fread_number( fp ); pObjIndex->cost = fread_number( fp ); /* Unused */ /* * Cost per day */ fread_number( fp ); if ( pObjIndex->item_type == ITEM_WEAPON ) { if ( is_name( "two", pObjIndex->name ) || is_name( "two-handed", pObjIndex->name ) || is_name( "claymore", pObjIndex->name ) ) SET_BIT( pObjIndex->value[4], WEAPON_TWO_HANDS ); } for ( ;; ) { char another_letter = '\0'; another_letter = fread_letter( fp ); if ( another_letter == 'A' ) { AFFECT_DATA *paf; paf = ( AFFECT_DATA * ) alloc_perm( sizeof( *paf ) ); paf->where = TO_OBJECT; paf->type = -1; paf->level = 20; /* RT temp fix */ paf->duration = -1; paf->location = fread_number( fp ); paf->modifier = fread_number( fp ); paf->bitvector = 0; paf->next = pObjIndex->affected; pObjIndex->affected = paf; top_affect++; } else if ( another_letter == 'E' ) { EXTRA_DESCR_DATA *ed = NULL; ed = ( EXTRA_DESCR_DATA * ) alloc_perm( sizeof( *ed ) ); ed->keyword = fread_string( fp ); ed->description = fread_string( fp ); ed->next = pObjIndex->extra_descr; pObjIndex->extra_descr = ed; top_ed++; } else { ungetc( another_letter, fp ); break; } } /* * fix armors */ if ( pObjIndex->item_type == ITEM_ARMOR ) { pObjIndex->value[1] = pObjIndex->value[0]; pObjIndex->value[2] = pObjIndex->value[1]; } /* * Translate spell "slot numbers" to internal "skill numbers." */ switch ( pObjIndex->item_type ) { case ITEM_PILL: case ITEM_POTION: case ITEM_SCROLL: pObjIndex->value[1] = slot_lookup( pObjIndex->value[1] ); pObjIndex->value[2] = slot_lookup( pObjIndex->value[2] ); pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] ); pObjIndex->value[4] = slot_lookup( pObjIndex->value[4] ); break; case ITEM_STAFF: case ITEM_WAND: pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] ); break; } iHash = vnum % MAX_KEY_HASH; pObjIndex->next = obj_index_hash[iHash]; obj_index_hash[iHash] = pObjIndex; top_obj_index++; top_vnum_obj = top_vnum_obj < vnum ? vnum : top_vnum_obj; /* OLC */ assign_area_vnum( vnum ); /* OLC */ } return; } /* * Adds a reset to a room. OLC * Similar to add_reset in olc.c */ void new_reset( ROOM_INDEX_DATA *pR, RESET_DATA *pReset ) { RESET_DATA *pr = NULL; if ( !pR ) return; pr = pR->reset_last; if ( !pr ) { pR->reset_first = pReset; pR->reset_last = pReset; } else { pR->reset_last->next = pReset; pR->reset_last = pReset; pR->reset_last->next = NULL; } return; } #if 0 /* * Snarf a reset section. */ void old_load_resets( FILE * fp ) { RESET_DATA *pReset = NULL; if ( area_last == NULL ) { proper_exit( MUD_HALT, "Load_resets: no #AREA seen yet." ); } for ( ;; ) { ROOM_INDEX_DATA *pRoomIndex = NULL; EXIT_DATA *pexit = NULL; char letter = '\0'; OBJ_INDEX_DATA *temp_index = NULL; if ( ( letter = fread_letter( fp ) ) == 'S' ) break; if ( letter == '*' ) { fread_to_eol( fp ); continue; } pReset = ( RESET_DATA * ) alloc_perm( sizeof( *pReset ) ); pReset->command = letter; /* * if_flag */ fread_number( fp ); pReset->arg1 = fread_number( fp ); pReset->arg2 = fread_number( fp ); pReset->arg3 = ( letter == 'G' || letter == 'R' ) ? 0 : fread_number( fp ); pReset->arg4 = ( letter == 'P' || letter == 'M' ) ? fread_number( fp ) : 0; fread_to_eol( fp ); /* * Validate parameters. * We're calling the index functions for the side effect. */ switch ( letter ) { default: proper_exit( MUD_HALT, "Load_resets: bad command '%c'.", letter ); break; case 'M': get_mob_index( pReset->arg1 ); get_room_index( pReset->arg3 ); break; case 'O': temp_index = get_obj_index( pReset->arg1 ); temp_index->reset_num++; get_room_index( pReset->arg3 ); break; case 'P': temp_index = get_obj_index( pReset->arg1 ); temp_index->reset_num++; get_obj_index( pReset->arg3 ); break; case 'G': case 'E': temp_index = get_obj_index( pReset->arg1 ); temp_index->reset_num++; break; case 'D': pRoomIndex = get_room_index( pReset->arg1 ); if ( pReset->arg2 < 0 || pReset->arg2 > 5 || ( pexit = pRoomIndex->exit[pReset->arg2] ) == NULL || !IS_SET( pexit->exit_info, EX_ISDOOR ) ) { proper_exit( MUD_HALT, "Load_resets: 'D': exit %d not door.", pReset->arg2 ); } if ( pReset->arg3 < 0 || pReset->arg3 > 2 ) { proper_exit( MUD_HALT, "Load_resets: 'D': bad 'locks': %d.", pReset->arg3 ); } break; case 'R': pRoomIndex = get_room_index( pReset->arg1 ); if ( pReset->arg2 < 0 || pReset->arg2 > 6 ) { proper_exit( MUD_HALT, "Load_resets: 'R': bad exit %d.", pReset->arg2 ); } break; } if ( area_last->reset_first == NULL ) area_last->reset_first = pReset; if ( area_last->reset_last != NULL ) area_last->reset_last->next = pReset; area_last->reset_last = pReset; pReset->next = NULL; top_reset++; } return; } #endif /* * Snarf a reset section. */ void load_resets( FILE * fp ) { RESET_DATA *pReset = NULL; EXIT_DATA *pexit = NULL; ROOM_INDEX_DATA *pRoomIndex = NULL; int rVnum = -1; if ( area_last == NULL ) { proper_exit( MUD_HALT, "Load_resets: no #AREA seen yet." ); } for ( ;; ) { char letter = '\0'; if ( ( letter = fread_letter( fp ) ) == 'S' ) break; if ( letter == '*' ) { fread_to_eol( fp ); continue; } pReset = new_reset_data( ); pReset->command = letter; fread_number( fp ); /* if_flag */ pReset->arg1 = fread_number( fp ); pReset->arg2 = fread_number( fp ); pReset->arg3 = ( letter == 'G' || letter == 'R' ) ? 0 : fread_number( fp ); pReset->arg4 = ( letter == 'P' || letter == 'M' ) ? fread_number( fp ) : 0; fread_to_eol( fp ); /* * Validate parameters. * We're calling the index functions for the side effect. */ switch ( pReset->command ) { case 'M': case 'O': rVnum = pReset->arg3; break; case 'P': case 'G': case 'E': break; case 'D': pRoomIndex = get_room_index( ( rVnum = pReset->arg1 ) ); if ( pReset->arg2 < 0 || pReset->arg2 >= MAX_DIR || !pRoomIndex || !( pexit = pRoomIndex->exit[pReset->arg2] ) || !IS_SET( pexit->rs_flags, EX_ISDOOR ) ) { proper_exit( MUD_HALT, "Load_resets: 'D': exit %d, room %d not door.", pReset->arg2, pReset->arg1 ); } switch ( pReset->arg3 ) { default: log_error( "Load_resets: 'D': bad 'locks': %d.", pReset->arg3 ); break; case 0: break; case 1: SET_BIT( pexit->rs_flags, EX_CLOSED ); SET_BIT( pexit->exit_info, EX_CLOSED ); break; case 2: SET_BIT( pexit->rs_flags, EX_CLOSED | EX_LOCKED ); SET_BIT( pexit->exit_info, EX_CLOSED | EX_LOCKED ); break; } break; case 'R': rVnum = pReset->arg1; break; } if ( rVnum == -1 ) proper_exit( MUD_HALT, "load_resets : rVnum == -1" ); if ( pReset->command != 'D' ) new_reset( get_room_index( rVnum ), pReset ); else free_reset_data( pReset ); } return; } /* * Snarf a room section. */ void load_rooms( FILE * fp ) { ROOM_INDEX_DATA *pRoomIndex = NULL; if ( area_last == NULL ) { proper_exit( MUD_HALT, "Load_resets: no #AREA seen yet." ); } for ( ;; ) { int vnum = 0; char letter = '\0'; int door = 0; int iHash = 0; letter = fread_letter( fp ); if ( letter != '#' ) { proper_exit( MUD_HALT, "Load_rooms: # not found." ); } vnum = fread_number( fp ); if ( vnum == 0 ) break; fBootDb = false; if ( get_room_index( vnum ) != NULL ) { proper_exit( MUD_HALT, "Load_rooms: vnum %d duplicated.", vnum ); } fBootDb = true; pRoomIndex = ( ROOM_INDEX_DATA * ) alloc_perm( sizeof( *pRoomIndex ) ); pRoomIndex->owner = str_dup( "" ); pRoomIndex->people = NULL; pRoomIndex->contents = NULL; pRoomIndex->extra_descr = NULL; pRoomIndex->area = area_last; pRoomIndex->vnum = vnum; pRoomIndex->name = fread_string( fp ); pRoomIndex->description = fread_string( fp ); /* * Area number */ fread_number( fp ); pRoomIndex->room_flags = fread_flag( fp ); pRoomIndex->sector_type = fread_number( fp ); pRoomIndex->light = 0; for ( door = 0; door < MAX_EXIT; door++ ) pRoomIndex->exit[door] = NULL; /* * defaults */ pRoomIndex->heal_rate = 100; pRoomIndex->mana_rate = 100; for ( ;; ) { letter = fread_letter( fp ); if ( letter == 'S' ) break; if ( letter == 'H' ) /* healing room */ pRoomIndex->heal_rate = fread_number( fp ); else if ( letter == 'M' ) /* mana room */ pRoomIndex->mana_rate = fread_number( fp ); else if ( letter == 'C' ) /* clan */ { if ( pRoomIndex->clan ) { proper_exit( MUD_HALT, "Load_rooms: duplicate clan fields." ); } pRoomIndex->clan = clan_lookup( fread_string( fp ) ); } else if ( letter == 'D' ) { EXIT_DATA *pexit; int locks; door = fread_number( fp ); if ( door < 0 || door >= MAX_EXIT ) { proper_exit( MUD_HALT, "Fread_rooms: vnum %d has bad door number.", vnum ); } pexit = ( EXIT_DATA * ) alloc_perm( sizeof( *pexit ) ); pexit->description = fread_string( fp ); pexit->keyword = fread_string( fp ); pexit->exit_info = 0; pexit->rs_flags = 0; /* OLC */ locks = fread_number( fp ); pexit->key = fread_number( fp ); pexit->u1.vnum = fread_number( fp ); pexit->orig_door = door; /* OLC */ switch ( locks ) { case 1: pexit->exit_info = EX_ISDOOR; pexit->rs_flags = EX_ISDOOR; break; case 2: pexit->exit_info = EX_ISDOOR | EX_PICKPROOF; pexit->rs_flags = EX_ISDOOR | EX_PICKPROOF; break; case 3: pexit->exit_info = EX_ISDOOR | EX_NOPASS; pexit->rs_flags = EX_ISDOOR | EX_NOPASS; break; case 4: pexit->exit_info = EX_ISDOOR | EX_NOPASS | EX_PICKPROOF; pexit->rs_flags = EX_ISDOOR | EX_NOPASS | EX_PICKPROOF; break; } pRoomIndex->exit[door] = pexit; top_exit++; } else if ( letter == 'E' ) { EXTRA_DESCR_DATA *ed = NULL; ed = ( EXTRA_DESCR_DATA * ) alloc_perm( sizeof( *ed ) ); ed->keyword = fread_string( fp ); ed->description = fread_string( fp ); ed->next = pRoomIndex->extra_descr; pRoomIndex->extra_descr = ed; top_ed++; } else if ( letter == 'O' ) { if ( pRoomIndex->owner[0] != '\0' ) { proper_exit( MUD_HALT, "Load_rooms: duplicate owner." ); } pRoomIndex->owner = fread_string( fp ); } else { proper_exit( MUD_HALT, "Load_rooms: vnum %d has flag not 'DES'.", vnum ); } } iHash = vnum % MAX_KEY_HASH; pRoomIndex->next = room_index_hash[iHash]; room_index_hash[iHash] = pRoomIndex; top_room++; top_vnum_room = top_vnum_room < vnum ? vnum : top_vnum_room; /* OLC */ assign_area_vnum( vnum ); /* OLC */ } return; } /* * Snarf a shop section. */ void load_shops( FILE * fp ) { SHOP_DATA *pShop = NULL; for ( ;; ) { MOB_INDEX_DATA *pMobIndex = NULL; int iTrade = 0; pShop = ( SHOP_DATA * ) alloc_perm( sizeof( *pShop ) ); pShop->keeper = fread_number( fp ); if ( pShop->keeper == 0 ) break; for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ ) pShop->buy_type[iTrade] = fread_number( fp ); pShop->profit_buy = fread_number( fp ); pShop->profit_sell = fread_number( fp ); pShop->open_hour = fread_number( fp ); pShop->close_hour = fread_number( fp ); fread_to_eol( fp ); pMobIndex = get_mob_index( pShop->keeper ); pMobIndex->pShop = pShop; if ( shop_first == NULL ) shop_first = pShop; if ( shop_last != NULL ) shop_last->next = pShop; shop_last = pShop; pShop->next = NULL; top_shop++; } return; } /* * Snarf spec proc declarations. */ void load_specials( FILE * fp ) { for ( ;; ) { MOB_INDEX_DATA *pMobIndex = NULL; char letter = '\0'; switch ( letter = fread_letter( fp ) ) { default: proper_exit( MUD_HALT, "Load_specials: letter '%c' not *MS.", letter ); case 'S': return; case '*': break; case 'M': pMobIndex = get_mob_index( fread_number( fp ) ); pMobIndex->spec_fun = spec_lookup( fread_word( fp ) ); if ( pMobIndex->spec_fun == 0 ) { proper_exit( MUD_HALT, "Load_specials: 'M': vnum %d.", pMobIndex->vnum ); } break; } fread_to_eol( fp ); } } /* * Translate all room exits from virtual to real. * Has to be done after all rooms are read in. * Check for bad reverse exits. */ void fix_exits( void ) { ROOM_INDEX_DATA *pRoomIndex = NULL; ROOM_INDEX_DATA *to_room = NULL; EXIT_DATA *pexit = NULL; EXIT_DATA *pexit_rev = NULL; RESET_DATA *pReset = NULL; ROOM_INDEX_DATA *iLastRoom = NULL; ROOM_INDEX_DATA *iLastObj = NULL; int iHash = 0; int door = -1; for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ) { for ( pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL; pRoomIndex = pRoomIndex->next ) { bool fexit = false; iLastRoom = iLastObj = NULL; /* * OLC : new check of resets */ for ( pReset = pRoomIndex->reset_first; pReset; pReset = pReset->next ) { switch ( pReset->command ) { default: proper_exit( MUD_HALT, "fix_exits : room %d with reset cmd %c", pRoomIndex->vnum, pReset->command ); break; case 'M': get_mob_index( pReset->arg1 ); iLastRoom = get_room_index( pReset->arg3 ); break; case 'O': get_obj_index( pReset->arg1 ); iLastObj = get_room_index( pReset->arg3 ); break; case 'P': get_obj_index( pReset->arg1 ); if ( iLastObj == NULL ) { proper_exit( MUD_HALT, "fix_exits : reset in room %d with iLastObj NULL", pRoomIndex->vnum ); } break; case 'G': case 'E': get_obj_index( pReset->arg1 ); if ( iLastRoom == NULL ) { proper_exit( MUD_HALT, "fix_exits : reset in room %d with iLastRoom NULL", pRoomIndex->vnum ); } iLastObj = iLastRoom; break; case 'D': log_error( "???" ); break; case 'R': get_room_index( pReset->arg1 ); if ( pReset->arg2 < 0 || pReset->arg2 > MAX_DIR ) { proper_exit( MUD_HALT, "fix_exits : reset in room %d with arg2 %d >= MAX_DIR", pRoomIndex->vnum, pReset->arg2 ); } break; } /* switch */ } /* for */ for ( door = 0; door < MAX_EXIT; door++ ) { if ( ( pexit = pRoomIndex->exit[door] ) != NULL ) { if ( pexit->u1.vnum <= 0 || get_room_index( pexit->u1.vnum ) == NULL ) pexit->u1.to_room = NULL; else { fexit = true; pexit->u1.to_room = get_room_index( pexit->u1.vnum ); } } } if ( !fexit ) SET_BIT( pRoomIndex->room_flags, ROOM_NO_MOB ); } } for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ) { for ( pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL; pRoomIndex = pRoomIndex->next ) { for ( door = 0; door < MAX_EXIT; door++ ) { if ( ( pexit = pRoomIndex->exit[door] ) != NULL && ( to_room = pexit->u1.to_room ) != NULL && ( pexit_rev = to_room->exit[rev_dir[door]] ) != NULL && pexit_rev->u1.to_room != pRoomIndex ) { log_error( "Non-euclidean exit: %d:%d -> %d:%d but -> %d", pRoomIndex->vnum, door, to_room->vnum, rev_dir[door], ( pexit_rev->u1.to_room == NULL ) ? 0 : pexit_rev->u1.to_room->vnum ); } } } } return; } /* * Load mobprogs section */ void load_mobprogs( FILE * fp ) { MPROG_CODE *pMprog = NULL; if ( area_last == NULL ) { proper_exit( MUD_HALT, "Load_mobprogs: no #AREA seen yet." ); } for ( ;; ) { int vnum = 0; char letter = '\0'; letter = fread_letter( fp ); if ( letter != '#' ) { proper_exit( MUD_HALT, "Load_mobprogs: # not found." ); } vnum = fread_number( fp ); if ( vnum == 0 ) break; fBootDb = false; if ( get_mprog_index( vnum ) != NULL ) { proper_exit( MUD_HALT, "Load_mobprogs: vnum %d duplicated.", vnum ); } fBootDb = true; pMprog = ( MPROG_CODE * ) alloc_perm( sizeof( *pMprog ) ); pMprog->vnum = vnum; pMprog->code = fread_string( fp ); if ( mprog_list == NULL ) mprog_list = pMprog; else { pMprog->next = mprog_list; mprog_list = pMprog; } top_mprog_index++; } return; } /* * Translate mobprog vnums pointers to real code */ void fix_mobprogs( void ) { MOB_INDEX_DATA *pMobIndex; MPROG_LIST *list; MPROG_CODE *prog; int iHash; for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ) { for ( pMobIndex = mob_index_hash[iHash]; pMobIndex != NULL; pMobIndex = pMobIndex->next ) { for ( list = pMobIndex->mprogs; list != NULL; list = list->next ) { if ( ( prog = get_mprog_index( list->vnum ) ) != NULL ) list->code = prog->code; else { proper_exit( MUD_HALT, "Fix_mobprogs: code vnum %d not found.", list->vnum ); } } } } } /* * Repopulate areas periodically. */ void area_update( void ) { AREA_DATA *pArea = NULL; for ( pArea = area_first; pArea != NULL; pArea = pArea->next ) { if ( ++pArea->age < 3 ) continue; /* * Check age and reset. * Note: Mud School resets every 3 minutes (not 15). */ if ( ( !pArea->empty && ( pArea->nplayer == 0 || pArea->age >= 15 ) ) || pArea->age >= 31 ) { ROOM_INDEX_DATA *pRoomIndex = NULL; reset_area( pArea ); log_reset( "%s reset", pArea->name ); wiz_printf( NULL, NULL, WIZ_RESETS, 0, 0, "%s reset", pArea->name ); pArea->age = number_range( 0, 3 ); pRoomIndex = get_room_index( ROOM_VNUM_SCHOOL ); if ( pRoomIndex != NULL && pArea == pRoomIndex->area ) pArea->age = 15 - 2; else if ( pArea->nplayer == 0 ) pArea->empty = true; } } return; } #if 0 /* * Reset one area. */ void old_reset_area( AREA_DATA *pArea ) { RESET_DATA *pReset = NULL; CHAR_DATA *mob = NULL; bool last = true; int level = 0; for ( pReset = pArea->reset_first; pReset != NULL; pReset = pReset->next ) { ROOM_INDEX_DATA *pRoomIndex = NULL; MOB_INDEX_DATA *pMobIndex = NULL; OBJ_INDEX_DATA *pObjIndex = NULL; OBJ_INDEX_DATA *pObjToIndex = NULL; EXIT_DATA *pexit = NULL; OBJ_DATA *obj = NULL; OBJ_DATA *obj_to = NULL; int count = 0; int limit = 0; switch ( pReset->command ) { default: log_error( "Bad reset command %c", pReset->command ); break; case 'M': if ( ( pMobIndex = get_mob_index( pReset->arg1 ) ) == NULL ) { log_error( "'M': bad vnum %d", pReset->arg1 ); continue; } if ( ( pRoomIndex = get_room_index( pReset->arg3 ) ) == NULL ) { log_error( "'R': bad vnum %d", pReset->arg3 ); continue; } if ( pMobIndex->count >= pReset->arg2 ) { last = false; break; } count = 0; for ( mob = pRoomIndex->people; mob != NULL; mob = mob->next_in_room ) if ( mob->pIndexData == pMobIndex ) { count++; if ( count >= pReset->arg4 ) { last = false; break; } } if ( count >= pReset->arg4 ) break; mob = create_mobile( pMobIndex ); /* * Check for pet shop. */ { ROOM_INDEX_DATA *pRoomIndexPrev = NULL; pRoomIndexPrev = get_room_index( pRoomIndex->vnum - 1 ); if ( pRoomIndexPrev != NULL && IS_SET( pRoomIndexPrev->room_flags, ROOM_PET_SHOP ) ) SET_BIT( mob->act, ACT_PET ); } /* * set area */ mob->zone = pRoomIndex->area; char_to_room( mob, pRoomIndex ); level = URANGE( 0, mob->level - 2, LEVEL_HERO - 1 ); last = true; break; case 'O': if ( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL ) { log_error( "'O': bad vnum %d", pReset->arg1 ); continue; } if ( ( pRoomIndex = get_room_index( pReset->arg3 ) ) == NULL ) { log_error( "'R': bad vnum %d", pReset->arg3 ); continue; } if ( pArea->nplayer > 0 || count_obj_list( pObjIndex, pRoomIndex->contents ) > 0 ) { last = false; break; } obj = create_object( pObjIndex, UMIN( number_fuzzy( level ), LEVEL_HERO - 1 ) ); obj->cost = 0; obj_to_room( obj, pRoomIndex ); last = true; break; case 'P': if ( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL ) { log_error( "'P': bad vnum %d", pReset->arg1 ); continue; } if ( ( pObjToIndex = get_obj_index( pReset->arg3 ) ) == NULL ) { log_error( "'P': bad vnum %d", pReset->arg3 ); continue; } if ( pReset->arg2 > 50 ) /* old format */ limit = 6; else if ( pReset->arg2 == -1 ) /* no limit */ limit = 999; else limit = pReset->arg2; if ( pArea->nplayer > 0 || ( obj_to = get_obj_type( pObjToIndex ) ) == NULL || ( obj_to->in_room == NULL && !last ) || ( pObjIndex->count >= limit && number_range( 0, 4 ) != 0 ) || ( count = count_obj_list( pObjIndex, obj_to->contains ) ) > pReset->arg4 ) { last = false; break; } while ( count < pReset->arg4 ) { obj = create_object( pObjIndex, number_fuzzy( obj_to->level ) ); obj_to_obj( obj, obj_to ); count++; if ( pObjIndex->count >= limit ) break; } /* * fix object lock state! */ obj_to->value[1] = obj_to->pIndexData->value[1]; last = true; break; case 'G': case 'E': if ( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL ) { log_error( "'E' or 'G': bad vnum %d", pReset->arg1 ); continue; } if ( !last ) break; if ( mob == NULL ) { log_error( "'E' or 'G': NULL mob for vnum %d", pReset->arg1 ); last = false; break; } if ( mob->pIndexData->pShop != NULL ) { int olevel = 0; int i = 0; int j = 0; if ( !pObjIndex->new_format ) switch ( pObjIndex->item_type ) { case ITEM_PILL: case ITEM_POTION: case ITEM_SCROLL: olevel = 53; for ( i = 1; i < 5; i++ ) { if ( pObjIndex->value[i] > 0 ) { for ( j = 0; j < MAX_CLASS; j++ ) { olevel = UMIN( olevel, skill_table[pObjIndex-> value[i]]. skill_level[j] ); } } } olevel = UMAX( 0, ( olevel * 3 / 4 ) - 2 ); break; case ITEM_WAND: olevel = number_range( 10, 20 ); break; case ITEM_STAFF: olevel = number_range( 15, 25 ); break; case ITEM_ARMOR: olevel = number_range( 5, 15 ); break; case ITEM_WEAPON: olevel = number_range( 5, 15 ); break; case ITEM_TREASURE: olevel = number_range( 10, 20 ); break; } obj = create_object( pObjIndex, olevel ); SET_BIT( obj->extra_flags, ITEM_INVENTORY ); } else { if ( pReset->arg2 > 50 ) /* old format */ limit = 6; else if ( pReset->arg2 == -1 ) /* no limit */ limit = 999; else limit = pReset->arg2; if ( pObjIndex->count < limit || number_range( 0, 4 ) == 0 ) { obj = create_object( pObjIndex, UMIN( number_fuzzy( level ), LEVEL_HERO - 1 ) ); /* * error message if it is too high */ if ( obj->item_type != ITEM_WEAPON && obj->level > mob->level + 3 ) log_balance( mob, "Level %d object \"%s\"(#%d), owned by level %d mob \"%s\"(#%d)", obj->level, obj->short_descr, obj->pIndexData->vnum, mob->level, mob->short_descr, mob->pIndexData->vnum ); if ( obj->item_type == ITEM_WEAPON && pReset->command == 'E' && obj->level < mob->level - 5 && obj->level < 45 ) log_balance( mob, "Level %d weapon \"%s\"(#%d), wielded by level %d mob \"%s\"(#%d)", obj->level, obj->short_descr, obj->pIndexData->vnum, mob->level, mob->short_descr, mob->pIndexData->vnum ); } else break; } obj_to_char( obj, mob ); if ( pReset->command == 'E' ) equip_char( mob, obj, pReset->arg3 ); last = true; break; case 'D': if ( ( pRoomIndex = get_room_index( pReset->arg1 ) ) == NULL ) { log_error( "'D': bad vnum %d", pReset->arg1 ); continue; } if ( ( pexit = pRoomIndex->exit[pReset->arg2] ) == NULL ) break; switch ( pReset->arg3 ) { case 0: REMOVE_BIT( pexit->exit_info, EX_CLOSED ); REMOVE_BIT( pexit->exit_info, EX_LOCKED ); break; case 1: SET_BIT( pexit->exit_info, EX_CLOSED ); REMOVE_BIT( pexit->exit_info, EX_LOCKED ); break; case 2: SET_BIT( pexit->exit_info, EX_CLOSED ); SET_BIT( pexit->exit_info, EX_LOCKED ); break; } last = true; break; case 'R': if ( ( pRoomIndex = get_room_index( pReset->arg1 ) ) == NULL ) { log_error( "'R': bad vnum %d", pReset->arg1 ); continue; } { int d0 = 0; int d1 = 0; for ( d0 = 0; d0 < pReset->arg2 - 1; d0++ ) { d1 = number_range( d0, pReset->arg2 - 1 ); pexit = pRoomIndex->exit[d0]; pRoomIndex->exit[d0] = pRoomIndex->exit[d1]; pRoomIndex->exit[d1] = pexit; } } break; } } return; } #endif /* * OLC * Reset one room. Called by reset_area and olc. */ void reset_room( ROOM_INDEX_DATA *pRoom ) { RESET_DATA *pReset = NULL; CHAR_DATA *pMob = NULL; CHAR_DATA *mob = NULL; OBJ_DATA *pObj = NULL; CHAR_DATA *LastMob = NULL; OBJ_DATA *LastObj = NULL; int iExit; int level = 0; bool last = true; if ( !pRoom ) return; last = false; for ( iExit = 0; iExit < MAX_DIR; iExit++ ) { EXIT_DATA *pExit; if ( ( pExit = pRoom->exit[iExit] ) /* * && !IS_SET( pExit->exit_info, EX_BASHED ) ROM OLC */ ) { pExit->exit_info = pExit->rs_flags; if ( ( pExit->u1.to_room != NULL ) && ( ( pExit = pExit->u1.to_room->exit[rev_dir[iExit]] ) ) ) { /* * nail the other side */ pExit->exit_info = pExit->rs_flags; } } } for ( pReset = pRoom->reset_first; pReset != NULL; pReset = pReset->next ) { MOB_INDEX_DATA *pMobIndex; OBJ_INDEX_DATA *pObjIndex; OBJ_INDEX_DATA *pObjToIndex; ROOM_INDEX_DATA *pRoomIndex; int count, limit = 0; switch ( pReset->command ) { default: log_error( "Reset_room: bad command %c.", pReset->command ); break; case 'M': if ( !( pMobIndex = get_mob_index( pReset->arg1 ) ) ) { log_error( "Reset_room: 'M': bad vnum %d.", pReset->arg1 ); continue; } if ( ( pRoomIndex = get_room_index( pReset->arg3 ) ) == NULL ) { log_error( "'R': bad vnum %d", pReset->arg3 ); continue; } if ( pMobIndex->count >= pReset->arg2 ) { last = false; break; } count = 0; for ( mob = pRoomIndex->people; mob != NULL; mob = mob->next_in_room ) if ( mob->pIndexData == pMobIndex ) { count++; if ( count >= pReset->arg4 ) { last = false; break; } } if ( count >= pReset->arg4 ) break; pMob = create_mobile( pMobIndex ); /* * Some more hard coding. */ //if ( room_is_dark( pRoom ) ) //SET_BIT( pMob->affected_by, AFF_INFRARED ); /* * Pet shop mobiles get ACT_PET set. */ { ROOM_INDEX_DATA *pRoomIndexPrev = NULL; pRoomIndexPrev = get_room_index( pRoom->vnum - 1 ); if ( pRoomIndexPrev && IS_SET( pRoomIndexPrev->room_flags, ROOM_PET_SHOP ) ) SET_BIT( pMob->act, ACT_PET ); } char_to_room( pMob, pRoom ); LastMob = pMob; level = URANGE( 0, pMob->level - 2, LEVEL_HERO - 1 ); /* -1 ROM */ last = true; break; case 'O': if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) ) { log_error( "Reset_room: 'O' 1 : bad vnum %d", pReset->arg1 ); log_error( "%d %d %d %d", pReset->arg1, pReset->arg2, pReset->arg3, pReset->arg4 ); continue; } if ( !( pRoomIndex = get_room_index( pReset->arg3 ) ) ) { log_error( "Reset_room: 'O' 2 : bad vnum %d.", pReset->arg3 ); log_error( "%d %d %d %d", pReset->arg1, pReset->arg2, pReset->arg3, pReset->arg4 ); continue; } if ( pRoom->area->nplayer > 0 || count_obj_list( pObjIndex, pRoom->contents ) > 0 ) { last = false; break; } pObj = create_object( pObjIndex, /* UMIN - ROM OLC */ UMIN( number_fuzzy( level ), LEVEL_HERO - 1 ) ); pObj->cost = 0; obj_to_room( pObj, pRoom ); last = true; break; case 'P': if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) ) { log_error( "Reset_room: 'P': bad vnum %d.", pReset->arg1 ); continue; } if ( !( pObjToIndex = get_obj_index( pReset->arg3 ) ) ) { log_error( "Reset_room: 'P': bad vnum %d.", pReset->arg3 ); continue; } if ( pReset->arg2 > 50 ) /* old format */ limit = 6; else if ( pReset->arg2 == -1 ) /* no limit */ limit = 999; else limit = pReset->arg2; if ( pRoom->area->nplayer > 0 || ( LastObj = get_obj_type( pObjToIndex ) ) == NULL || ( LastObj->in_room == NULL && !last ) || ( pObjIndex->count >= limit /* && * number_range( * 0, * 4 * ) * != * 0 */ ) || ( count = count_obj_list( pObjIndex, LastObj->contains ) ) > pReset->arg4 ) { last = false; break; } while ( count < pReset->arg4 ) { pObj = create_object( pObjIndex, number_fuzzy( LastObj->level ) ); obj_to_obj( pObj, LastObj ); count++; if ( pObjIndex->count >= limit ) break; } /* * fix object lock state! */ LastObj->value[1] = LastObj->pIndexData->value[1]; last = true; break; case 'G': case 'E': if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) ) { log_error( "Reset_room: 'E' or 'G': bad vnum %d.", pReset->arg1 ); continue; } if ( !last ) break; if ( !LastMob ) { log_error( "Reset_room: 'E' or 'G': null mob for vnum %d.", pReset->arg1 ); last = false; break; } if ( LastMob->pIndexData->pShop ) /* Shop-keeper? */ { int olevel = 0; int i = 0; int j = 0; if ( !pObjIndex->new_format ) switch ( pObjIndex->item_type ) { default: olevel = 0; break; case ITEM_PILL: case ITEM_POTION: case ITEM_SCROLL: olevel = 53; for ( i = 1; i < 5; i++ ) { if ( pObjIndex->value[i] > 0 ) { for ( j = 0; j < MAX_CLASS; j++ ) { olevel = UMIN( olevel, skill_table[pObjIndex-> value[i]]. skill_level[j] ); } } } olevel = UMAX( 0, ( olevel * 3 / 4 ) - 2 ); break; case ITEM_WAND: olevel = number_range( 10, 20 ); break; case ITEM_STAFF: olevel = number_range( 15, 25 ); break; case ITEM_ARMOR: olevel = number_range( 5, 15 ); break; case ITEM_WEAPON: olevel = number_range( 5, 15 ); break; case ITEM_TREASURE: olevel = number_range( 10, 20 ); break; } pObj = create_object( pObjIndex, olevel ); SET_BIT( pObj->extra_flags, ITEM_INVENTORY ); /* ROM OLC */ } else /* ROM OLC else version */ { if ( pReset->arg2 > 50 ) /* old format */ limit = 6; else if ( pReset->arg2 == -1 || pReset->arg2 == 0 ) limit = 999; else limit = pReset->arg2; if ( pObjIndex->count < limit || number_range( 0, 4 ) == 0 ) { pObj = create_object( pObjIndex, UMIN( number_fuzzy( level ), LEVEL_HERO - 1 ) ); /* * error message if it is too high */ if ( pObj->item_type != ITEM_WEAPON && pObj->level > LastMob->level + 3 ) log_balance( LastMob, "Level %d object \"%s\"(#%d), owned by level %d mob \"%s\"(#%d)", pObj->level, pObj->short_descr, pObj->pIndexData->vnum, LastMob->level, LastMob->short_descr, LastMob->pIndexData->vnum ); if ( pObj->item_type == ITEM_WEAPON && pReset->command == 'E' && pObj->level < LastMob->level - 5 && pObj->level < 45 ) log_balance( LastMob, "Level %d weapon \"%s\"(#%d), wielded by level %d mob \"%s\"(#%d)", pObj->level, pObj->short_descr, pObj->pIndexData->vnum, LastMob->level, LastMob->short_descr, LastMob->pIndexData->vnum ); } else break; } obj_to_char( pObj, LastMob ); if ( pReset->command == 'E' ) equip_char( LastMob, pObj, pReset->arg3 ); last = true; break; case 'D': break; case 'R': if ( !( pRoomIndex = get_room_index( pReset->arg1 ) ) ) { log_error( "Reset_room: 'R': bad vnum %d.", pReset->arg1 ); continue; } { EXIT_DATA *pExit; int d0; int d1; for ( d0 = 0; d0 < pReset->arg2 - 1; d0++ ) { d1 = number_range( d0, pReset->arg2 - 1 ); pExit = pRoomIndex->exit[d0]; pRoomIndex->exit[d0] = pRoomIndex->exit[d1]; pRoomIndex->exit[d1] = pExit; } } break; } } return; } /* OLC * Reset one area. */ void reset_area( AREA_DATA *pArea ) { ROOM_INDEX_DATA *pRoom; int vnum; for ( vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++ ) { if ( ( pRoom = get_room_index( vnum ) ) ) reset_room( pRoom ); } return; } /* * Create an instance of a mobile. */ CHAR_DATA *create_mobile( MOB_INDEX_DATA *pMobIndex ) { CHAR_DATA *mob = NULL; int i = 0; AFFECT_DATA af; mobile_count++; if ( pMobIndex == NULL ) { proper_exit( MUD_HALT, "Create_mobile: NULL pMobIndex." ); } mob = new_char( ); mob->pIndexData = pMobIndex; mob->name = str_dup( pMobIndex->player_name ); /* OLC */ mob->short_descr = str_dup( pMobIndex->short_descr ); /* OLC */ mob->long_descr = str_dup( pMobIndex->long_descr ); /* OLC */ mob->description = str_dup( pMobIndex->description ); /* OLC */ mob->id = get_mob_id( ); mob->spec_fun = pMobIndex->spec_fun; mob->prompt = NULL; mob->mprog_target = NULL; if ( pMobIndex->wealth == 0 ) { mob->silver = 0; mob->gold = 0; } else { int wealth = 0; wealth = number_range( pMobIndex->wealth / 2, 3 * pMobIndex->wealth / 2 ); mob->gold = number_range( wealth / 200, wealth / 100 ); mob->silver = wealth - ( mob->gold * 100 ); } if ( pMobIndex->new_format ) /* * load in new style */ { /* * read from prototype */ mob->group = pMobIndex->group; mob->act = pMobIndex->act; mob->comm = COMM_NOCHANNELS | COMM_NOSHOUT | COMM_NOTELL; mob->affected_by = pMobIndex->affected_by; mob->alignment = pMobIndex->alignment; mob->level = pMobIndex->level; mob->hitroll = pMobIndex->hitroll; mob->damroll = pMobIndex->damage[DICE_BONUS]; mob->max_hit = dice( pMobIndex->hit[DICE_NUMBER], pMobIndex->hit[DICE_TYPE] ) + pMobIndex->hit[DICE_BONUS]; mob->hit = mob->max_hit; mob->max_mana = dice( pMobIndex->mana[DICE_NUMBER], pMobIndex->mana[DICE_TYPE] ) + pMobIndex->mana[DICE_BONUS]; mob->mana = mob->max_mana; mob->damage[DICE_NUMBER] = pMobIndex->damage[DICE_NUMBER]; mob->damage[DICE_TYPE] = pMobIndex->damage[DICE_TYPE]; mob->dam_type = pMobIndex->dam_type; if ( mob->dam_type == 0 ) switch ( number_range( 1, 3 ) ) { case ( 1 ): mob->dam_type = 3; break; /* slash */ case ( 2 ): mob->dam_type = 7; break; /* pound */ case ( 3 ): mob->dam_type = 11; break; /* pierce */ } for ( i = 0; i < 4; i++ ) mob->armor[i] = pMobIndex->ac[i]; mob->off_flags = pMobIndex->off_flags; mob->imm_flags = pMobIndex->imm_flags; mob->res_flags = pMobIndex->res_flags; mob->vuln_flags = pMobIndex->vuln_flags; mob->start_pos = pMobIndex->start_pos; mob->default_pos = pMobIndex->default_pos; mob->sex = pMobIndex->sex; if ( mob->sex == 3 ) /* random sex */ mob->sex = number_range( 1, 2 ); mob->race = pMobIndex->race; mob->form = pMobIndex->form; mob->parts = pMobIndex->parts; mob->size = pMobIndex->size; mob->material = str_dup( pMobIndex->material ); /* * computed on the spot */ for ( i = 0; i < MAX_STATS; i++ ) mob->perm_stat[i] = UMIN( 25, 11 + mob->level / 4 ); if ( IS_SET( mob->act, ACT_WARRIOR ) ) { mob->perm_stat[STAT_STR] += 3; mob->perm_stat[STAT_INT] -= 1; mob->perm_stat[STAT_CON] += 2; } if ( IS_SET( mob->act, ACT_THIEF ) ) { mob->perm_stat[STAT_DEX] += 3; mob->perm_stat[STAT_INT] += 1; mob->perm_stat[STAT_WIS] -= 1; } if ( IS_SET( mob->act, ACT_CLERIC ) ) { mob->perm_stat[STAT_WIS] += 3; mob->perm_stat[STAT_DEX] -= 1; mob->perm_stat[STAT_STR] += 1; } if ( IS_SET( mob->act, ACT_MAGE ) ) { mob->perm_stat[STAT_INT] += 3; mob->perm_stat[STAT_STR] -= 1; mob->perm_stat[STAT_DEX] += 1; } if ( IS_SET( mob->off_flags, OFF_FAST ) ) mob->perm_stat[STAT_DEX] += 2; mob->perm_stat[STAT_STR] += mob->size - SIZE_MEDIUM; mob->perm_stat[STAT_CON] += ( mob->size - SIZE_MEDIUM ) / 2; /* * let's get some spell action */ if ( IS_AFFECTED( mob, AFF_SANCTUARY ) ) { af.where = TO_AFFECTS; af.type = skill_lookup( "sanctuary" ); af.level = mob->level; af.duration = -1; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_SANCTUARY; affect_to_char( mob, &af ); } if ( IS_AFFECTED( mob, AFF_HASTE ) ) { af.where = TO_AFFECTS; af.type = skill_lookup( "haste" ); af.level = mob->level; af.duration = -1; af.location = APPLY_DEX; af.modifier = 1 + ( mob->level >= 18 ) + ( mob->level >= 25 ) + ( mob->level >= 32 ); af.bitvector = AFF_HASTE; affect_to_char( mob, &af ); } if ( IS_AFFECTED( mob, AFF_PROTECT_EVIL ) ) { af.where = TO_AFFECTS; af.type = skill_lookup( "protection evil" ); af.level = mob->level; af.duration = -1; af.location = APPLY_SAVES; af.modifier = -1; af.bitvector = AFF_PROTECT_EVIL; affect_to_char( mob, &af ); } if ( IS_AFFECTED( mob, AFF_PROTECT_GOOD ) ) { af.where = TO_AFFECTS; af.type = skill_lookup( "protection good" ); af.level = mob->level; af.duration = -1; af.location = APPLY_SAVES; af.modifier = -1; af.bitvector = AFF_PROTECT_GOOD; affect_to_char( mob, &af ); } } else { /* * read in old format and convert */ mob->act = pMobIndex->act; mob->affected_by = pMobIndex->affected_by; mob->alignment = pMobIndex->alignment; mob->level = pMobIndex->level; mob->hitroll = pMobIndex->hitroll; mob->damroll = 0; mob->max_hit = mob->level * 8 + number_range( mob->level * mob->level / 4, mob->level * mob->level ); mob->max_hit *= 10 / 9; mob->hit = mob->max_hit; mob->max_mana = 100 + dice( mob->level, 10 ); mob->mana = mob->max_mana; switch ( number_range( 1, 3 ) ) { case ( 1 ): mob->dam_type = 3; break; /* slash */ case ( 2 ): mob->dam_type = 7; break; /* pound */ case ( 3 ): mob->dam_type = 11; break; /* pierce */ } for ( i = 0; i < 3; i++ ) mob->armor[i] = interpolate( mob->level, 100, -100 ); mob->armor[3] = interpolate( mob->level, 100, 0 ); mob->race = pMobIndex->race; mob->off_flags = pMobIndex->off_flags; mob->imm_flags = pMobIndex->imm_flags; mob->res_flags = pMobIndex->res_flags; mob->vuln_flags = pMobIndex->vuln_flags; mob->start_pos = pMobIndex->start_pos; mob->default_pos = pMobIndex->default_pos; mob->sex = pMobIndex->sex; mob->form = pMobIndex->form; mob->parts = pMobIndex->parts; mob->size = SIZE_MEDIUM; mob->material = str_dup( "" ); /* This should be ok as a shared * string */ for ( i = 0; i < MAX_STATS; i++ ) mob->perm_stat[i] = 11 + mob->level / 4; } mob->position = mob->start_pos; /* * link the mob to the world list */ mob->next = char_list; char_list = mob; pMobIndex->count++; return mob; } /* duplicate a mobile exactly -- except inventory */ void clone_mobile( CHAR_DATA *parent, CHAR_DATA *clone ) { int i = 0; AFFECT_DATA *paf = NULL; if ( parent == NULL || clone == NULL || !IS_NPC( parent ) ) return; /* * start fixing values */ clone->name = str_dup( parent->name ); clone->version = parent->version; clone->short_descr = str_dup( parent->short_descr ); clone->long_descr = str_dup( parent->long_descr ); clone->description = str_dup( parent->description ); clone->group = parent->group; clone->sex = parent->sex; clone->iclass = parent->iclass; clone->race = parent->race; clone->level = parent->level; clone->trust = 0; clone->timer = parent->timer; clone->wait = parent->wait; clone->hit = parent->hit; clone->max_hit = parent->max_hit; clone->mana = parent->mana; clone->max_mana = parent->max_mana; clone->move = parent->move; clone->max_move = parent->max_move; clone->gold = parent->gold; clone->silver = parent->silver; clone->exp = parent->exp; clone->act = parent->act; clone->comm = parent->comm; clone->imm_flags = parent->imm_flags; clone->res_flags = parent->res_flags; clone->vuln_flags = parent->vuln_flags; clone->invis_level = parent->invis_level; clone->affected_by = parent->affected_by; clone->position = parent->position; clone->practice = parent->practice; clone->train = parent->train; clone->saving_throw = parent->saving_throw; clone->alignment = parent->alignment; clone->hitroll = parent->hitroll; clone->damroll = parent->damroll; clone->wimpy = parent->wimpy; clone->form = parent->form; clone->parts = parent->parts; clone->size = parent->size; clone->material = str_dup( parent->material ); clone->off_flags = parent->off_flags; clone->dam_type = parent->dam_type; clone->start_pos = parent->start_pos; clone->default_pos = parent->default_pos; clone->spec_fun = parent->spec_fun; for ( i = 0; i < 4; i++ ) clone->armor[i] = parent->armor[i]; for ( i = 0; i < MAX_STATS; i++ ) { clone->perm_stat[i] = parent->perm_stat[i]; clone->mod_stat[i] = parent->mod_stat[i]; } for ( i = 0; i < 3; i++ ) clone->damage[i] = parent->damage[i]; /* * now add the affects */ for ( paf = parent->affected; paf != NULL; paf = paf->next ) affect_to_char( clone, paf ); } /* * Create an instance of an object. */ OBJ_DATA *create_object( OBJ_INDEX_DATA *pObjIndex, int level ) { AFFECT_DATA *paf = NULL; OBJ_DATA *obj = NULL; if ( pObjIndex == NULL ) { proper_exit( MUD_HALT, "Create_object: NULL pObjIndex." ); } obj = new_obj( ); obj->pIndexData = pObjIndex; obj->in_room = NULL; obj->enchanted = false; if ( pObjIndex->new_format ) obj->level = pObjIndex->level; else obj->level = UMAX( 0, level ); obj->wear_loc = -1; obj->name = str_dup( pObjIndex->name ); /* OLC */ obj->short_descr = str_dup( pObjIndex->short_descr ); /* OLC */ obj->description = str_dup( pObjIndex->description ); /* OLC */ obj->material = str_dup( pObjIndex->material ); obj->item_type = pObjIndex->item_type; obj->extra_flags = pObjIndex->extra_flags; obj->wear_flags = pObjIndex->wear_flags; obj->value[0] = pObjIndex->value[0]; obj->value[1] = pObjIndex->value[1]; obj->value[2] = pObjIndex->value[2]; obj->value[3] = pObjIndex->value[3]; obj->value[4] = pObjIndex->value[4]; obj->weight = pObjIndex->weight; obj->condition = pObjIndex->condition; if ( level == -1 || pObjIndex->new_format ) obj->cost = pObjIndex->cost; else obj->cost = number_fuzzy( 10 ) * number_fuzzy( level ) * number_fuzzy( level ); /* * Mess with object properties. */ switch ( obj->item_type ) { default: log_error( "Object VNUM %d is of unknown type", pObjIndex->vnum ); break; case ITEM_LIGHT: if ( obj->value[2] == 999 ) obj->value[2] = -1; break; case ITEM_FURNITURE: case ITEM_TRASH: case ITEM_CONTAINER: case ITEM_DRINK_CON: case ITEM_KEY: case ITEM_FOOD: case ITEM_BOAT: case ITEM_CORPSE_NPC: case ITEM_CORPSE_PC: case ITEM_FOUNTAIN: case ITEM_MAP: case ITEM_CLOTHING: case ITEM_PORTAL: if ( !pObjIndex->new_format ) obj->cost /= 5; break; case ITEM_TREASURE: case ITEM_WARP_STONE: case ITEM_ROOM_KEY: case ITEM_GEM: case ITEM_JEWELRY: break; case ITEM_SCROLL: if ( level != -1 && !pObjIndex->new_format ) obj->value[0] = number_fuzzy( obj->value[0] ); break; case ITEM_WAND: case ITEM_STAFF: if ( level != -1 && !pObjIndex->new_format ) { obj->value[0] = number_fuzzy( obj->value[0] ); obj->value[1] = number_fuzzy( obj->value[1] ); obj->value[2] = obj->value[1]; } if ( !pObjIndex->new_format ) obj->cost *= 2; break; case ITEM_WEAPON: if ( level != -1 && !pObjIndex->new_format ) { obj->value[1] = number_fuzzy( number_fuzzy( 1 * level / 4 + 2 ) ); obj->value[2] = number_fuzzy( number_fuzzy( 3 * level / 4 + 6 ) ); } break; case ITEM_ARMOR: if ( level != -1 && !pObjIndex->new_format ) { obj->value[0] = number_fuzzy( level / 5 + 3 ); obj->value[1] = number_fuzzy( level / 5 + 3 ); obj->value[2] = number_fuzzy( level / 5 + 3 ); } break; case ITEM_POTION: case ITEM_PILL: if ( level != -1 && !pObjIndex->new_format ) obj->value[0] = number_fuzzy( number_fuzzy( obj->value[0] ) ); break; case ITEM_MONEY: if ( !pObjIndex->new_format ) obj->value[0] = obj->cost; break; } for ( paf = pObjIndex->affected; paf != NULL; paf = paf->next ) if ( paf->location == APPLY_SPELL_AFFECT ) affect_to_obj( obj, paf ); obj->next = object_list; object_list = obj; pObjIndex->count++; return obj; } /* duplicate an object exactly -- except contents */ void clone_object( OBJ_DATA *parent, OBJ_DATA *clone ) { int i = 0; AFFECT_DATA *paf = NULL; EXTRA_DESCR_DATA *ed = NULL; EXTRA_DESCR_DATA *ed_new = NULL; if ( parent == NULL || clone == NULL ) return; /* * start fixing the object */ clone->name = str_dup( parent->name ); clone->short_descr = str_dup( parent->short_descr ); clone->description = str_dup( parent->description ); clone->item_type = parent->item_type; clone->extra_flags = parent->extra_flags; clone->wear_flags = parent->wear_flags; clone->weight = parent->weight; clone->cost = parent->cost; clone->level = parent->level; clone->condition = parent->condition; clone->material = str_dup( parent->material ); clone->timer = parent->timer; for ( i = 0; i < 5; i++ ) clone->value[i] = parent->value[i]; /* * affects */ clone->enchanted = parent->enchanted; for ( paf = parent->affected; paf != NULL; paf = paf->next ) affect_to_obj( clone, paf ); /* * extended desc */ for ( ed = parent->extra_descr; ed != NULL; ed = ed->next ) { ed_new = new_extra_descr( ); ed_new->keyword = str_dup( ed->keyword ); ed_new->description = str_dup( ed->description ); ed_new->next = clone->extra_descr; clone->extra_descr = ed_new; } } /* * Clear a new character. */ void clear_char( CHAR_DATA *ch ) { static CHAR_DATA ch_zero; int i = 0; *ch = ch_zero; ch->name = &str_empty[0]; ch->short_descr = &str_empty[0]; ch->long_descr = &str_empty[0]; ch->description = &str_empty[0]; ch->prompt = &str_empty[0]; ch->logon = current_time; ch->lines = PAGELEN; for ( i = 0; i < 4; i++ ) ch->armor[i] = 100; ch->position = POS_STANDING; ch->hit = 20; ch->max_hit = 20; ch->mana = 100; ch->max_mana = 100; ch->move = 100; ch->max_move = 100; ch->on = NULL; for ( i = 0; i < MAX_STATS; i++ ) { ch->perm_stat[i] = 13; ch->mod_stat[i] = 0; } return; } /* * Get an extra description from a list. */ char *get_extra_descr( char *name, EXTRA_DESCR_DATA *ed ) { for ( ; ed != NULL; ed = ed->next ) { if ( is_name( name, ed->keyword ) ) return ed->description; } return NULL; } /* * Translates mob virtual number to its mob index struct. * Hash table lookup. */ MOB_INDEX_DATA *get_mob_index( int vnum ) { MOB_INDEX_DATA *pMobIndex = NULL; for ( pMobIndex = mob_index_hash[vnum % MAX_KEY_HASH]; pMobIndex != NULL; pMobIndex = pMobIndex->next ) { if ( pMobIndex->vnum == vnum ) return pMobIndex; } if ( fBootDb ) { proper_exit( MUD_HALT, "Get_mob_index: bad vnum %d.", vnum ); } return NULL; } /* * Translates mob virtual number to its obj index struct. * Hash table lookup. */ OBJ_INDEX_DATA *get_obj_index( int vnum ) { OBJ_INDEX_DATA *pObjIndex = NULL; for ( pObjIndex = obj_index_hash[vnum % MAX_KEY_HASH]; pObjIndex != NULL; pObjIndex = pObjIndex->next ) { if ( pObjIndex->vnum == vnum ) return pObjIndex; } if ( fBootDb ) { proper_exit( MUD_HALT, "Get_obj_index: bad vnum %d.", vnum ); } return NULL; } /* * Translates mob virtual number to its room index struct. * Hash table lookup. */ ROOM_INDEX_DATA *get_room_index( int vnum ) { ROOM_INDEX_DATA *pRoomIndex = NULL; for ( pRoomIndex = room_index_hash[vnum % MAX_KEY_HASH]; pRoomIndex != NULL; pRoomIndex = pRoomIndex->next ) { if ( pRoomIndex->vnum == vnum ) return pRoomIndex; } if ( fBootDb ) { proper_exit( MUD_HALT, "Get_room_index: bad vnum %d.", vnum ); } return NULL; } /* * Read a letter from a file. */ char fread_letter( FILE * fp ) { char c = '\0'; do { c = getc( fp ); } while ( isspace( c ) ); return c; } /* * Read a number from a file. */ int fread_number( FILE * fp ) { int number = 0; bool sign = false; char c = '\0'; 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 ) ) { proper_exit( MUD_HALT, "Fread_number: bad format." ); } 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; } int str_read_flag(const char *str) { bool neg = false; int number = 0; while( isspace(*str) ) ++str; if(*str == '=') { neg = true; ++str; } // we expect the order of characters to be any alpha chars, any numeric chars, and then any pipes for a bitset or. while(isalpha(*str)) { number += flag_convert(*str); ++str; } while(isdigit(*str)) { number = number * 10 + (*str) - '0'; ++str; } if(*str == '|') number += str_read_flag(++str); if(neg == true) number *= -1; return number; } int fread_flag( FILE * fp ) { const char *word = fread_word(fp); int flagval = str_read_flag(word); return flagval; } int flag_convert( char letter ) { int bitsum = 0; char i = '\0'; 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 = NULL; char c = '\0'; plast = top_string + sizeof( char * ); if ( plast > &string_space[MAX_STRING - MAX_STRING_LENGTH] ) { proper_exit( MUD_HALT, "Fread_string: MAX_STRING %d exceeded.", MAX_STRING ); } /* * 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 */ log_error( "%s", "EOF in fread_string" ); return NULL; /* * exit( 1 ); */ break; case '\n': plast++; *plast++ = '\r'; break; case '\r': break; case '~': plast++; { union { char *pc; char rgc[sizeof( char * )]; } u1; size_t ic = 0; int iHash = 0; char *pHash = NULL; char *pHashPrev = NULL; char *pString = NULL; 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 = NULL; char c = '\0'; 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] ) { proper_exit( MUD_HALT, "Fread_string: MAX_STRING %d exceeded.", MAX_STRING ); } /* * 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: /* * temp fix */ log_error( "%s", "EOF in fread_string_eol" ); return NULL; /* * exit( 1 ); */ break; case '\n': case '\r': { union { char *pc; char rgc[sizeof( char * )]; } u1; size_t ic = 0; int iHash = 0; char *pHash = NULL; char *pHashPrev = NULL; char *pString = NULL; 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 = '\0'; 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] = "\0\0\0\0\0\0\0"; char *pword = NULL; char cEnd = '\0'; 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; } } proper_exit( MUD_HALT, "Fread_word: word too long." ); return NULL; } void do_areas( CHAR_DATA *ch, const char *argument ) { AREA_DATA *pArea1 = NULL; AREA_DATA *pArea2 = NULL; int iArea = 0; int iAreaHalf = 0; if ( argument[0] != '\0' ) { ch_printf( ch, "No argument is used with this command.\r\n" ); return; } iAreaHalf = ( top_area + 1 ) / 2; pArea1 = area_first; pArea2 = area_first; for ( iArea = 0; iArea < iAreaHalf; iArea++ ) pArea2 = pArea2->next; for ( iArea = 0; iArea < iAreaHalf; iArea++ ) { ch_printf( ch, "%-39s%-39s\r\n", pArea1->credits, ( pArea2 != NULL ) ? pArea2->credits : "" ); pArea1 = pArea1->next; if ( pArea2 != NULL ) pArea2 = pArea2->next; } return; } void do_memory( CHAR_DATA *ch, const char *argument ) { ch_printf( ch, "Affects %5d\r\n", top_affect ); ch_printf( ch, "Areas %5d\r\n", top_area ); ch_printf( ch, "ExDes %5d\r\n", top_ed ); ch_printf( ch, "Exits %5d\r\n", top_exit ); ch_printf( ch, "Helps %5d\r\n", top_help ); ch_printf( ch, "Socials %5d\r\n", social_count ); ch_printf( ch, "Mobs %5d(%d new format)\r\n", top_mob_index, newmobs ); ch_printf( ch, "(in use)%5d\r\n", mobile_count ); ch_printf( ch, "Objs %5d(%d new format)\r\n", top_obj_index, newobjs ); ch_printf( ch, "Resets %5d\r\n", top_reset ); ch_printf( ch, "Rooms %5d\r\n", top_room ); ch_printf( ch, "Shops %5d\r\n", top_shop ); ch_printf( ch, "Strings %5d strings of %7zd bytes (max %d).\r\n", nAllocString, sAllocString, MAX_STRING ); ch_printf( ch, "Perms %5d blocks of %7zd bytes.\r\n", nAllocPerm, sAllocPerm ); return; } void do_dump( CHAR_DATA *ch, const char *argument ) { int count = 0; int count2 = 0; int num_pcs = 0; int aff_count = 0; CHAR_DATA *fch = NULL; MOB_INDEX_DATA *pMobIndex = NULL; PC_DATA *pc = NULL; OBJ_DATA *obj = NULL; OBJ_INDEX_DATA *pObjIndex = NULL; ROOM_INDEX_DATA *room = NULL; EXIT_DATA *pExit = NULL; DESCRIPTOR_DATA *d = NULL; AFFECT_DATA *af = NULL; FILE *fp = NULL; int vnum = 0; int nMatch = 0; /* * open file */ fp = fopen( "mem.dmp", "w" ); /* * report use of data structures */ num_pcs = 0; aff_count = 0; /* * mobile prototypes */ fprintf( fp, "MobProt %4d (%8zd bytes)\n", top_mob_index, top_mob_index * ( sizeof( *pMobIndex ) ) ); /* * mobs */ count = 0; count2 = 0; for ( fch = char_list; fch != NULL; fch = fch->next ) { count++; if ( fch->pcdata != NULL ) num_pcs++; for ( af = fch->affected; af != NULL; af = af->next ) aff_count++; } for ( fch = char_free; fch != NULL; fch = fch->next ) count2++; fprintf( fp, "Mobs %4d (%8zd bytes), %2d free (%zd bytes)\n", count, count * ( sizeof( *fch ) ), count2, count2 * ( sizeof( *fch ) ) ); /* * pcdata */ count = 0; for ( pc = pcdata_free; pc != NULL; pc = pc->next ) count++; fprintf( fp, "Pcdata %4d (%8zd bytes), %2d free (%zd bytes)\n", num_pcs, num_pcs * ( sizeof( *pc ) ), count, count * ( sizeof( *pc ) ) ); /* * descriptors */ count = 0; count2 = 0; for ( d = descriptor_list; d != NULL; d = d->next ) count++; for ( d = descriptor_free; d != NULL; d = d->next ) count2++; fprintf( fp, "Descs %4d (%8zd bytes), %2d free (%zd bytes)\n", count, count * ( sizeof( *d ) ), count2, count2 * ( sizeof( *d ) ) ); /* * object prototypes */ for ( vnum = 0; nMatch < top_obj_index; vnum++ ) if ( ( pObjIndex = get_obj_index( vnum ) ) != NULL ) { for ( af = pObjIndex->affected; af != NULL; af = af->next ) aff_count++; nMatch++; } fprintf( fp, "ObjProt %4d (%8zd bytes)\n", top_obj_index, top_obj_index * ( sizeof( *pObjIndex ) ) ); /* * objects */ count = 0; count2 = 0; for ( obj = object_list; obj != NULL; obj = obj->next ) { count++; for ( af = obj->affected; af != NULL; af = af->next ) aff_count++; } for ( obj = obj_free; obj != NULL; obj = obj->next ) count2++; fprintf( fp, "Objs %4d (%8zd bytes), %2d free (%zd bytes)\n", count, count * ( sizeof( *obj ) ), count2, count2 * ( sizeof( *obj ) ) ); /* * affects */ count = 0; for ( af = affect_free; af != NULL; af = af->next ) count++; fprintf( fp, "Affects %4d (%8zd bytes), %2d free (%zd bytes)\n", aff_count, aff_count * ( sizeof( *af ) ), count, count * ( sizeof( *af ) ) ); /* * rooms */ fprintf( fp, "Rooms %4d (%8zd bytes)\n", top_room, top_room * ( sizeof( *room ) ) ); /* * exits */ fprintf( fp, "Exits %4d (%8zd bytes)\n", top_exit, top_exit * ( sizeof( *pExit ) ) ); fclose( fp ); /* * start printing out mobile data */ fp = fopen( "mob.dmp", "w" ); fprintf( fp, "\nMobile Analysis\n" ); fprintf( fp, "---------------\n" ); nMatch = 0; for ( vnum = 0; nMatch < top_mob_index; vnum++ ) if ( ( pMobIndex = get_mob_index( vnum ) ) != NULL ) { nMatch++; fprintf( fp, "#%-4d %3d active %3d killed %s\n", pMobIndex->vnum, pMobIndex->count, pMobIndex->killed, pMobIndex->short_descr ); } fclose( fp ); /* * start printing out object data */ fp = fopen( "obj.dmp", "w" ); fprintf( fp, "\nObject Analysis\n" ); fprintf( fp, "---------------\n" ); nMatch = 0; for ( vnum = 0; nMatch < top_obj_index; vnum++ ) if ( ( pObjIndex = get_obj_index( vnum ) ) != NULL ) { nMatch++; fprintf( fp, "#%-4d %3d active %3d reset %s\n", pObjIndex->vnum, pObjIndex->count, pObjIndex->reset_num, pObjIndex->short_descr ); } /* * close file */ fclose( fp ); } /* * Simple linear interpolation. */ int interpolate( int level, int value_00, int value_32 ) { return value_00 + level * ( value_32 - value_00 ) / 32; } /* * Append a string to a file. */ void append_file( CHAR_DATA *ch, const char *file, const char *str ) { FILE *fp = NULL; if ( !str || !*str ) return; if ( ch && IS_NPC( ch ) ) return; if ( ( fp = fopen( file, "a" ) ) == NULL ) { char *e = strerror( errno ); log_error( "fopen: %s: %s", file, e ); if ( ch ) ch_printf( ch, "Could not open the file!\r\n" ); } else { if ( ch ) fprintf( fp, "[%5d] %s: %s\n", ch->in_room ? ch->in_room->vnum : 0, NAME( ch ), str ); else fprintf( fp, "[ 0] SYSTEM: %s\n", str ); fclose( fp ); } 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; } MPROG_CODE *get_mprog_index( int vnum ) { MPROG_CODE *prg = NULL; for ( prg = mprog_list; prg; prg = prg->next ) { if ( prg->vnum == vnum ) return ( prg ); } return NULL; } /* snarf a socials file */ void load_socials( FILE * fp ) { for ( ;; ) { struct social_type social; char *temp = NULL; /* * clear social */ social.char_no_arg = NULL; social.others_no_arg = NULL; social.char_found = NULL; social.others_found = NULL; social.vict_found = NULL; social.char_not_found = NULL; social.char_auto = NULL; social.others_auto = NULL; temp = fread_word( fp ); if ( !strcmp( temp, "#0" ) ) return; /* done */ #if defined(SOCIAL_DEBUG) else log_boot( "SOCIAL: %s", temp ); #endif strcpy( social.name, temp ); fread_to_eol( fp ); temp = fread_string_eol( fp ); if ( !strcmp( temp, "$" ) ) social.char_no_arg = NULL; else if ( !strcmp( temp, "#" ) ) { social_table[social_count] = social; social_count++; continue; } else social.char_no_arg = temp; temp = fread_string_eol( fp ); if ( !strcmp( temp, "$" ) ) social.others_no_arg = NULL; else if ( !strcmp( temp, "#" ) ) { social_table[social_count] = social; social_count++; continue; } else social.others_no_arg = temp; temp = fread_string_eol( fp ); if ( !strcmp( temp, "$" ) ) social.char_found = NULL; else if ( !strcmp( temp, "#" ) ) { social_table[social_count] = social; social_count++; continue; } else social.char_found = temp; temp = fread_string_eol( fp ); if ( !strcmp( temp, "$" ) ) social.others_found = NULL; else if ( !strcmp( temp, "#" ) ) { social_table[social_count] = social; social_count++; continue; } else social.others_found = temp; temp = fread_string_eol( fp ); if ( !strcmp( temp, "$" ) ) social.vict_found = NULL; else if ( !strcmp( temp, "#" ) ) { social_table[social_count] = social; social_count++; continue; } else social.vict_found = temp; temp = fread_string_eol( fp ); if ( !strcmp( temp, "$" ) ) social.char_not_found = NULL; else if ( !strcmp( temp, "#" ) ) { social_table[social_count] = social; social_count++; continue; } else social.char_not_found = temp; temp = fread_string_eol( fp ); if ( !strcmp( temp, "$" ) ) social.char_auto = NULL; else if ( !strcmp( temp, "#" ) ) { social_table[social_count] = social; social_count++; continue; } else social.char_auto = temp; temp = fread_string_eol( fp ); if ( !strcmp( temp, "$" ) ) social.others_auto = NULL; else if ( !strcmp( temp, "#" ) ) { social_table[social_count] = social; social_count++; continue; } else social.others_auto = temp; social_table[social_count] = social; social_count++; } return; } /* * Snarf a mob section. new style */ void load_mobiles( FILE * fp ) { MOB_INDEX_DATA *pMobIndex; if ( !area_last ) /* OLC */ { proper_exit( MUD_HALT, "Load_mobiles: no #AREA seen yet." ); } for ( ;; ) { int vnum = 0; char letter = '\0'; int iHash = 0; letter = fread_letter( fp ); if ( letter != '#' ) { proper_exit( MUD_HALT, "Load_mobiles: # not found." ); } vnum = fread_number( fp ); if ( vnum == 0 ) break; fBootDb = false; if ( get_mob_index( vnum ) != NULL ) { proper_exit( MUD_HALT, "Load_mobiles: vnum %d duplicated.", vnum ); } fBootDb = true; pMobIndex = ( MOB_INDEX_DATA * ) alloc_perm( sizeof( *pMobIndex ) ); pMobIndex->vnum = vnum; pMobIndex->area = area_last; /* OLC */ pMobIndex->new_format = true; newmobs++; pMobIndex->player_name = fread_string( fp ); pMobIndex->short_descr = fread_string( fp ); pMobIndex->long_descr = fread_string( fp ); pMobIndex->description = fread_string( fp ); pMobIndex->race = race_lookup( fread_string( fp ) ); pMobIndex->long_descr[0] = UPPER( pMobIndex->long_descr[0] ); pMobIndex->description[0] = UPPER( pMobIndex->description[0] ); pMobIndex->act = fread_flag( fp ) | ACT_IS_NPC | race_table[pMobIndex->race].act; pMobIndex->affected_by = fread_flag( fp ) | race_table[pMobIndex->race].aff; pMobIndex->pShop = NULL; pMobIndex->alignment = fread_number( fp ); pMobIndex->group = fread_number( fp ); pMobIndex->level = fread_number( fp ); pMobIndex->hitroll = fread_number( fp ); /* * read hit dice */ pMobIndex->hit[DICE_NUMBER] = fread_number( fp ); fread_letter( fp ); /* 'd' */ pMobIndex->hit[DICE_TYPE] = fread_number( fp ); fread_letter( fp ); /* '+' */ pMobIndex->hit[DICE_BONUS] = fread_number( fp ); /* * read mana dice */ pMobIndex->mana[DICE_NUMBER] = fread_number( fp ); fread_letter( fp ); pMobIndex->mana[DICE_TYPE] = fread_number( fp ); fread_letter( fp ); pMobIndex->mana[DICE_BONUS] = fread_number( fp ); /* * read damage dice */ pMobIndex->damage[DICE_NUMBER] = fread_number( fp ); fread_letter( fp ); pMobIndex->damage[DICE_TYPE] = fread_number( fp ); fread_letter( fp ); pMobIndex->damage[DICE_BONUS] = fread_number( fp ); pMobIndex->dam_type = attack_lookup( fread_word( fp ) ); /* * read armor class */ pMobIndex->ac[AC_PIERCE] = fread_number( fp ) * 10; pMobIndex->ac[AC_BASH] = fread_number( fp ) * 10; pMobIndex->ac[AC_SLASH] = fread_number( fp ) * 10; pMobIndex->ac[AC_EXOTIC] = fread_number( fp ) * 10; /* * read flags and add in data from the race table */ pMobIndex->off_flags = fread_flag( fp ) | race_table[pMobIndex->race].off; pMobIndex->imm_flags = fread_flag( fp ) | race_table[pMobIndex->race].imm; pMobIndex->res_flags = fread_flag( fp ) | race_table[pMobIndex->race].res; pMobIndex->vuln_flags = fread_flag( fp ) | race_table[pMobIndex->race].vuln; /* * vital statistics */ pMobIndex->start_pos = position_lookup( fread_word( fp ) ); pMobIndex->default_pos = position_lookup( fread_word( fp ) ); pMobIndex->sex = sex_lookup( fread_word( fp ) ); pMobIndex->wealth = fread_number( fp ); pMobIndex->form = fread_flag( fp ) | race_table[pMobIndex->race].form; pMobIndex->parts = fread_flag( fp ) | race_table[pMobIndex->race].parts; /* * size */ CHECK_POS( pMobIndex->size, size_lookup( fread_word( fp ) ), "size" ); pMobIndex->material = str_dup( fread_word( fp ) ); for ( ;; ) { letter = fread_letter( fp ); if ( letter == 'F' ) { char *word = NULL; int vector = 0; word = str_dup(fread_word( fp )); vector = fread_flag( fp ); /* * These really shouldn't be str_prefix() */ if ( !str_cmp( word, "act" ) ) REMOVE_BIT( pMobIndex->act, vector ); else if ( !str_cmp( word, "aff" ) ) REMOVE_BIT( pMobIndex->affected_by, vector ); else if ( !str_cmp( word, "off" ) ) REMOVE_BIT( pMobIndex->off_flags, vector ); else if ( !str_cmp( word, "imm" ) ) REMOVE_BIT( pMobIndex->imm_flags, vector ); else if ( !str_cmp( word, "res" ) ) REMOVE_BIT( pMobIndex->res_flags, vector ); else if ( !str_cmp( word, "vul" ) ) REMOVE_BIT( pMobIndex->vuln_flags, vector ); else if ( !str_cmp( word, "for" ) ) REMOVE_BIT( pMobIndex->form, vector ); else if ( !str_cmp( word, "par" ) ) REMOVE_BIT( pMobIndex->parts, vector ); else { proper_exit( MUD_HALT, "Flag remove: flag not found."); } free_string(word); } else if ( letter == 'M' ) { MPROG_LIST *pMprog = NULL; char *word = NULL; int trigger = 0; pMprog = ( MPROG_LIST * ) alloc_perm( sizeof( *pMprog ) ); word = fread_word( fp ); if ( ( trigger = flag_lookup( word, mprog_flags ) ) == NO_FLAG ) { proper_exit( MUD_HALT, "MOBprogs: invalid trigger." ); } SET_BIT( pMobIndex->mprog_flags, trigger ); pMprog->trig_type = trigger; pMprog->vnum = fread_number( fp ); pMprog->trig_phrase = fread_string( fp ); pMprog->next = pMobIndex->mprogs; pMobIndex->mprogs = pMprog; } else { ungetc( letter, fp ); break; } } iHash = vnum % MAX_KEY_HASH; pMobIndex->next = mob_index_hash[iHash]; mob_index_hash[iHash] = pMobIndex; top_mob_index++; top_vnum_mob = top_vnum_mob < vnum ? vnum : top_vnum_mob; /* OLC */ assign_area_vnum( vnum ); /* OLC */ kill_table[URANGE( 0, pMobIndex->level, MAX_LEVEL - 1 )].number++; } return; } /* * Snarf an obj section. new style */ void load_objects( FILE * fp ) { OBJ_INDEX_DATA *pObjIndex = NULL; if ( !area_last ) /* OLC */ { proper_exit( MUD_HALT, "Load_objects: no #AREA seen yet." ); } for ( ;; ) { int vnum = 0; char letter = '\0'; int iHash = 0; letter = fread_letter( fp ); if ( letter != '#' ) { proper_exit( MUD_HALT, "Load_objects: # not found." ); } vnum = fread_number( fp ); if ( vnum == 0 ) break; fBootDb = false; if ( get_obj_index( vnum ) != NULL ) { proper_exit( MUD_HALT, "Load_objects: vnum %d duplicated.", vnum ); } fBootDb = true; pObjIndex = ( OBJ_INDEX_DATA * ) alloc_perm( sizeof( *pObjIndex ) ); pObjIndex->vnum = vnum; pObjIndex->area = area_last; /* OLC */ pObjIndex->new_format = true; pObjIndex->reset_num = 0; newobjs++; pObjIndex->name = fread_string( fp ); pObjIndex->short_descr = fread_string( fp ); pObjIndex->description = fread_string( fp ); pObjIndex->material = fread_string( fp ); CHECK_POS( pObjIndex->item_type, item_lookup( fread_word( fp ) ), "item_type" ); pObjIndex->extra_flags = fread_flag( fp ); pObjIndex->wear_flags = fread_flag( fp ); switch ( pObjIndex->item_type ) { case ITEM_WEAPON: pObjIndex->value[0] = weapon_type_lookup( fread_word( fp ) ); pObjIndex->value[1] = fread_number( fp ); pObjIndex->value[2] = fread_number( fp ); pObjIndex->value[3] = attack_lookup( fread_word( fp ) ); pObjIndex->value[4] = fread_flag( fp ); break; case ITEM_CONTAINER: pObjIndex->value[0] = fread_number( fp ); pObjIndex->value[1] = fread_flag( fp ); pObjIndex->value[2] = fread_number( fp ); pObjIndex->value[3] = fread_number( fp ); pObjIndex->value[4] = fread_number( fp ); break; case ITEM_DRINK_CON: case ITEM_FOUNTAIN: pObjIndex->value[0] = fread_number( fp ); pObjIndex->value[1] = fread_number( fp ); CHECK_POS( pObjIndex->value[2], liq_lookup( fread_word( fp ) ), "liq_lookup" ); pObjIndex->value[3] = fread_number( fp ); pObjIndex->value[4] = fread_number( fp ); break; case ITEM_WAND: case ITEM_STAFF: pObjIndex->value[0] = fread_number( fp ); pObjIndex->value[1] = fread_number( fp ); pObjIndex->value[2] = fread_number( fp ); pObjIndex->value[3] = skill_lookup( fread_word( fp ) ); pObjIndex->value[4] = fread_number( fp ); break; case ITEM_POTION: case ITEM_PILL: case ITEM_SCROLL: pObjIndex->value[0] = fread_number( fp ); pObjIndex->value[1] = skill_lookup( fread_word( fp ) ); pObjIndex->value[2] = skill_lookup( fread_word( fp ) ); pObjIndex->value[3] = skill_lookup( fread_word( fp ) ); pObjIndex->value[4] = skill_lookup( fread_word( fp ) ); break; default: pObjIndex->value[0] = fread_flag( fp ); pObjIndex->value[1] = fread_flag( fp ); pObjIndex->value[2] = fread_flag( fp ); pObjIndex->value[3] = fread_flag( fp ); pObjIndex->value[4] = fread_flag( fp ); break; } pObjIndex->level = fread_number( fp ); pObjIndex->weight = fread_number( fp ); pObjIndex->cost = fread_number( fp ); /* * condition */ letter = fread_letter( fp ); switch ( letter ) { case ( 'P' ): pObjIndex->condition = 100; break; case ( 'G' ): pObjIndex->condition = 90; break; case ( 'A' ): pObjIndex->condition = 75; break; case ( 'W' ): pObjIndex->condition = 50; break; case ( 'D' ): pObjIndex->condition = 25; break; case ( 'B' ): pObjIndex->condition = 10; break; case ( 'R' ): pObjIndex->condition = 0; break; default: pObjIndex->condition = 100; break; } for ( ;; ) { char another_letter = '\0'; another_letter = fread_letter( fp ); if ( another_letter == 'A' ) { AFFECT_DATA *paf; paf = ( AFFECT_DATA * ) alloc_perm( sizeof( *paf ) ); paf->where = TO_OBJECT; paf->type = -1; paf->level = pObjIndex->level; paf->duration = -1; paf->location = fread_number( fp ); paf->modifier = fread_number( fp ); paf->bitvector = 0; paf->next = pObjIndex->affected; pObjIndex->affected = paf; top_affect++; } else if ( another_letter == 'F' ) { AFFECT_DATA *paf; paf = ( AFFECT_DATA * ) alloc_perm( sizeof( *paf ) ); another_letter = fread_letter( fp ); switch ( another_letter ) { case 'A': paf->where = TO_AFFECTS; break; case 'I': paf->where = TO_IMMUNE; break; case 'R': paf->where = TO_RESIST; break; case 'V': paf->where = TO_VULN; break; default: proper_exit( MUD_HALT, "Load_objects: Bad where on flag set." ); break; } paf->type = -1; paf->level = pObjIndex->level; paf->duration = -1; paf->location = fread_number( fp ); paf->modifier = fread_number( fp ); paf->bitvector = fread_flag( fp ); paf->next = pObjIndex->affected; pObjIndex->affected = paf; top_affect++; } else if ( another_letter == 'E' ) { EXTRA_DESCR_DATA *ed; ed = ( EXTRA_DESCR_DATA * ) alloc_perm( sizeof( *ed ) ); ed->keyword = fread_string( fp ); ed->description = fread_string( fp ); ed->next = pObjIndex->extra_descr; pObjIndex->extra_descr = ed; top_ed++; } else { ungetc( another_letter, fp ); break; } } iHash = vnum % MAX_KEY_HASH; pObjIndex->next = obj_index_hash[iHash]; obj_index_hash[iHash] = pObjIndex; top_obj_index++; top_vnum_obj = top_vnum_obj < vnum ? vnum : top_vnum_obj; /* OLC */ assign_area_vnum( vnum ); /* OLC */ } return; } /***************************************************************************** Name: convert_objects Purpose: Converts all old format objects to new format Called by: boot_db (db.c). Note: Loops over all resets to find the level of the mob loaded before the object to determine the level of the object. It might be better to update the levels in load_resets(). This function is not pretty.. Sorry about that :) Author: Hugin ****************************************************************************/ void convert_objects( void ) { int vnum = 0; AREA_DATA *pArea = NULL; RESET_DATA *pReset = NULL; MOB_INDEX_DATA *pMob = NULL; OBJ_INDEX_DATA *pObj = NULL; OBJ_INDEX_DATA *pObjTo = NULL; ROOM_INDEX_DATA *pRoom = NULL; if ( newobjs == top_obj_index ) return; /* all objects in new format */ for ( pArea = area_first; pArea; pArea = pArea->next ) { for ( vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++ ) { if ( !( pRoom = get_room_index( vnum ) ) ) continue; for ( pReset = pRoom->reset_first; pReset; pReset = pReset->next ) { switch ( pReset->command ) { case 'M': if ( !( pMob = get_mob_index( pReset->arg1 ) ) ) log_error( "Convert_objects: 'M': bad vnum %d.", pReset->arg1 ); break; case 'O': if ( !( pObj = get_obj_index( pReset->arg1 ) ) ) { log_error( "Convert_objects: 'O': bad vnum %d.", pReset->arg1 ); break; } if ( pObj->new_format ) continue; if ( !pMob ) { log_error( "Convert_objects: 'O': No mob reset yet." ); break; } pObj->level = pObj->level < 1 ? pMob->level - 2 : UMIN( pObj->level, pMob->level - 2 ); break; case 'P': { if ( !( pObj = get_obj_index( pReset->arg1 ) ) ) { log_error( "Convert_objects: 'P': bad vnum %d.", pReset->arg1 ); break; } if ( pObj->new_format ) continue; if ( !( pObjTo = get_obj_index( pReset->arg3 ) ) ) { log_error( "Convert_objects: 'P': bad vnum %d.", pReset->arg3 ); break; } pObj->level = pObj->level < 1 ? pObjTo->level : UMIN( pObj->level, pObjTo->level ); } break; case 'G': case 'E': if ( !( pObj = get_obj_index( pReset->arg1 ) ) ) { log_error( "Convert_objects: 'E' or 'G': bad vnum %d.", pReset->arg1 ); break; } if ( !pMob ) { log_error ( "Convert_objects: 'E' or 'G': null mob for vnum %d.", pReset->arg1 ); break; } if ( pObj->new_format ) continue; if ( pMob->pShop ) { switch ( pObj->item_type ) { default: pObj->level = UMAX( 0, pObj->level ); break; case ITEM_PILL: case ITEM_POTION: pObj->level = UMAX( 5, pObj->level ); break; case ITEM_SCROLL: case ITEM_ARMOR: case ITEM_WEAPON: pObj->level = UMAX( 10, pObj->level ); break; case ITEM_WAND: case ITEM_TREASURE: pObj->level = UMAX( 15, pObj->level ); break; case ITEM_STAFF: pObj->level = UMAX( 20, pObj->level ); break; } } else pObj->level = pObj->level < 1 ? pMob->level : UMIN( pObj->level, pMob->level ); break; } /* switch ( pReset->command ) */ } } } /* * do the conversion: */ for ( pArea = area_first; pArea; pArea = pArea->next ) for ( vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++ ) if ( ( pObj = get_obj_index( vnum ) ) ) if ( !pObj->new_format ) convert_object( pObj ); return; } /***************************************************************************** Name: convert_object Purpose: Converts an old_format obj to new_format Called by: convert_objects (db2.c). Note: Dug out of create_obj (db.c) Author: Hugin ****************************************************************************/ void convert_object( OBJ_INDEX_DATA *pObjIndex ) { int level = 0; int number = 0; int type = 0; /* for dice-conversion */ if ( !pObjIndex || pObjIndex->new_format ) return; level = pObjIndex->level; pObjIndex->level = UMAX( 0, pObjIndex->level ); /* just to be sure */ pObjIndex->cost = 10 * level; switch ( pObjIndex->item_type ) { default: log_error( "Obj_convert: vnum %d bad type.", pObjIndex->item_type ); break; case ITEM_LIGHT: case ITEM_TREASURE: case ITEM_FURNITURE: case ITEM_TRASH: case ITEM_CONTAINER: case ITEM_DRINK_CON: case ITEM_KEY: case ITEM_FOOD: case ITEM_BOAT: case ITEM_CORPSE_NPC: case ITEM_CORPSE_PC: case ITEM_FOUNTAIN: case ITEM_MAP: case ITEM_CLOTHING: case ITEM_SCROLL: break; case ITEM_WAND: case ITEM_STAFF: pObjIndex->value[2] = pObjIndex->value[1]; break; case ITEM_WEAPON: /* * The conversion below is based on the values generated * in one_hit() (fight.c). Since I don't want a lvl 50 * weapon to do 15d3 damage, the min value will be below * the one in one_hit, and to make up for it, I've made * the max value higher. * (I don't want 15d2 because this will hardly ever roll * 15 or 30, it will only roll damage close to 23. * I can't do 4d8+11, because one_hit there is no dice- * bounus value to set...) * * The conversion below gives: level: dice min max mean 1: 1d8 1( 2) 8( 7) 5( 5) 2: 2d5 2( 3) 10( 8) 6( 6) 3: 2d5 2( 3) 10( 8) 6( 6) 5: 2d6 2( 3) 12(10) 7( 7) 10: 4d5 4( 5) 20(14) 12(10) 20: 5d5 5( 7) 25(21) 15(14) 30: 5d7 5(10) 35(29) 20(20) 50: 5d11 5(15) 55(44) 30(30) */ number = UMIN( level / 4 + 1, 5 ); type = ( level + 7 ) / number; pObjIndex->value[1] = number; pObjIndex->value[2] = type; break; case ITEM_ARMOR: pObjIndex->value[0] = level / 5 + 3; pObjIndex->value[1] = pObjIndex->value[0]; pObjIndex->value[2] = pObjIndex->value[0]; break; case ITEM_POTION: case ITEM_PILL: break; case ITEM_MONEY: pObjIndex->value[0] = pObjIndex->cost; break; } pObjIndex->new_format = true; ++newobjs; return; } /***************************************************************************** Name: convert_mobile Purpose: Converts an old_format mob into new_format Called by: load_old_mob (db.c). Note: Dug out of create_mobile (db.c) Author: Hugin ****************************************************************************/ void convert_mobile( MOB_INDEX_DATA *pMobIndex ) { int i = 0; int type = 0; int number = 0; int bonus = 0; int level = 0; if ( !pMobIndex || pMobIndex->new_format ) return; level = pMobIndex->level; pMobIndex->act |= ACT_WARRIOR; /* * Calculate hit dice. Gives close to the hitpoints * of old format mobs created with create_mobile() (db.c) * A high number of dice makes for less variance in mobiles * hitpoints. * (might be a good idea to reduce the max number of dice) * * The conversion below gives: level: dice min max diff mean 1: 1d2+6 7( 7) 8( 8) 1( 1) 8( 8) 2: 1d3+15 16( 15) 18( 18) 2( 3) 17( 17) 3: 1d6+24 25( 24) 30( 30) 5( 6) 27( 27) 5: 1d17+42 43( 42) 59( 59) 16( 17) 51( 51) 10: 3d22+96 99( 95) 162( 162) 63( 67) 131( ) 15: 5d30+161 166(159) 311( 311) 145( 150) 239( ) 30: 10d61+416 426(419) 1026(1026) 600( 607) 726( ) 50: 10d169+920 930(923) 2610(2610) 1680(1688) 1770( ) The values in parenthesis give the values generated in create_mobile. Diff = max - min. Mean is the arithmetic mean. (hmm.. must be some roundoff error in my calculations.. smurfette got 1d6+23 hp at level 3 ? -- anyway.. the values above should be approximately right..) */ type = level * level * 27 / 40; number = UMIN( type / 40 + 1, 10 ); /* how do they get 11 ??? */ type = UMAX( 2, type / number ); /* bonus = UMAX( 0, level * ( 8 + level ) * .9 - number * type ); */ bonus = UMAX( 0, level * ( ( 8 + level ) * 9 / 10 ) - number * type ); pMobIndex->hit[DICE_NUMBER] = number; pMobIndex->hit[DICE_TYPE] = type; pMobIndex->hit[DICE_BONUS] = bonus; pMobIndex->mana[DICE_NUMBER] = level; pMobIndex->mana[DICE_TYPE] = 10; pMobIndex->mana[DICE_BONUS] = 100; /* * Calculate dam dice. Gives close to the damage * of old format mobs in damage() (fight.c) */ type = level * 7 / 4; number = UMIN( type / 8 + 1, 5 ); type = UMAX( 2, type / number ); bonus = UMAX( 0, level * 9 / 4 - number * type ); pMobIndex->damage[DICE_NUMBER] = number; pMobIndex->damage[DICE_TYPE] = type; pMobIndex->damage[DICE_BONUS] = bonus; switch ( number_range( 1, 3 ) ) { case ( 1 ): pMobIndex->dam_type = 3; break; /* slash */ case ( 2 ): pMobIndex->dam_type = 7; break; /* pound */ case ( 3 ): pMobIndex->dam_type = 11; break; /* pierce */ } for ( i = 0; i < 3; i++ ) pMobIndex->ac[i] = interpolate( level, 100, -100 ); pMobIndex->ac[3] = interpolate( level, 100, 0 ); /* exotic */ pMobIndex->wealth /= 100; pMobIndex->size = SIZE_MEDIUM; pMobIndex->material = str_dup( "none" ); pMobIndex->new_format = true; ++newmobs; return; } /* stuff for recycling mobprograms */ MPROG_LIST *mprog_free = NULL; MPROG_LIST *new_mprog( void ) { static MPROG_LIST mp_zero; MPROG_LIST *mp = NULL; if ( mprog_free == NULL ) mp = ( MPROG_LIST * ) alloc_perm( sizeof( *mp ) ); else { mp = mprog_free; mprog_free = mprog_free->next; } *mp = mp_zero; mp->vnum = 0; mp->trig_type = 0; mp->code = str_dup( "" ); VALIDATE( mp ); return mp; } void free_mprog( MPROG_LIST *mp ) { if ( !IS_VALID( mp ) ) return; INVALIDATE( mp ); mp->next = mprog_free; mprog_free = mp; } HELP_AREA *had_free = NULL; HELP_AREA *new_had( void ) { HELP_AREA *had = NULL; static HELP_AREA zHad; if ( had_free ) { had = had_free; had_free = had_free->next; } else had = ( HELP_AREA * ) alloc_perm( sizeof( *had ) ); *had = zHad; return had; } HELP_DATA *new_help( void ) { return new HELP_DATA; } void free_help( HELP_DATA *help ) { delete help; }