/************************************************************************** * file: db.c , Database module. Part of DIKUMUD * * Usage: Loading/Saving chars, booting world, resetting etc. * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ***************************************************************************/ #include CONFIG #if HAVE_STRINGS_H #include <strings.h> #endif #if HAVE_STRING_H #include <string.h> #endif #include <ctype.h> #include <time.h> #include <errno.h> #include "structs.h" #include "mob.h" #include "utils.h" #include "db.h" #include "org.h" #include "bio.h" #include "comm.h" #include "player.h" #include "skills.h" #include "time.h" #include "proto.h" /************************************************************************** * declarations of most of the 'global' variables * ************************************************************************ */ struct room_data *world; /* dyn alloc'ed array of rooms */ int top_of_world = 0; /* ref to the top element of world */ struct obj_data *object_list = 0; /* the global linked list of obj's */ struct char_data *character_list = 0; /* global l-list of chars */ struct ban_t *ban_list=0; /* list of banned site--sigh */ int log_all=0; /* If 1, log all commands to syslog*/ struct zone_data *zone_table; /* table of reset data */ int top_of_zone_table = 0; int top_of_bio_table = 0; char credits[MAX_STRING_LENGTH]; /* the Credits List */ char news[MAX_STRING_LENGTH]; /* the news */ char motd[MAX_STRING_LENGTH]; /* the messages of today */ char help[MAX_STRING_LENGTH]; /* the main help page */ char info[MAX_STRING_LENGTH]; /* the info text */ FILE *mob_f, /* file containing mob prototypes */ *obj_f, /* obj prototypes */ *help_fl; /* file for help texts (HELP <kwd>)*/ struct mob_index_data *mob_index; /* index table for mobile file */ struct bio_index_data *bio_index; /* index table for bio file */ struct obj_index_data *obj_index; /* index table for object file */ struct help_index_element *help_index = 0; int top_of_mobt = 0; /* top of mobile index table */ int top_of_objt = 0; /* top of object index table */ int top_of_helpt; /* top of help index table */ struct time_info_data time_info; /* the infomation about the time */ int dont_save_ids=TRUE; /* We won't save until we're done loading */ /* local procedures */ void setup_dir(FILE *fl, int room, int dir); void setup_current(FILE *fl, int room, int dir); void boot_world(void); void boot_zones(void); void boot_id(void); void boot_bio(void); struct mob_index_data *generate_mob_indices(FILE *fl, int *top); struct obj_index_data *generate_obj_indices(FILE *fl, int *top); int is_empty(int zone_nr); void reset_zone(int zone); int file_to_string(char *name, char *buf); void renum_world(void); void renum_zone_table(void); void reset_time(void); void weather_setup(void); void update_id(void); /* For the identification system */ #define ID_MOB 0 #define ID_PLAYER 1 #define ID_OBJ 2 int next_id(int kind); #define nextmob() next_id(ID_MOB) #define nextplayer() next_id(ID_PLAYER) #define nextobj() next_id(ID_OBJ) /* external refs */ void boot_cron(void); void boot_orgs(void); void boot_plot(void); void boot_syllables(void); extern struct descriptor_data *descriptor_list; void load_messages(void); void initialize_boards(void); void weather_and_time ( int mode ); void log(char *str); int dice(int number, int size); int number(int from, int to); void boot_social_messages(void); struct help_index_element *build_help_index(FILE *fl, int *num); void calc_light_zone(struct zone_data *zone); char get_season(struct zone_data *zone); extern int make_admin; extern char log_buf[]; extern struct bio_info bio_attrs[]; extern size_t obj_info_size[]; char *strdup(); /************************************************************************* * routines for booting the system * *********************************************************************** */ #if !HAVE_MEMSET void memset(char *s, char c, int n) { int i; for (i = 0; i < n; i++) { s[i] = c; } /* for */ } #endif int count_char(char c,FILE *fl) { char buf[100]; int count=0; rewind(fl); while(fgets(buf,99,fl)) { if(*buf==c) count++; } rewind(fl); return(count); } /* body of the booting system */ void boot_db(void) { int i; extern int no_specials; log("Boot db -- BEGIN."); log("Resetting the game time:"); reset_time(); log("Reading newsfile, credits, help-page, info and motd."); file_to_string(NEWS_FILE, news); file_to_string(CREDITS_FILE, credits); file_to_string(MOTD_FILE, motd); file_to_string(HELP_PAGE_FILE, help); file_to_string(INFO_FILE, info); log("Opening help file."); if (!(help_fl = fopen(HELP_KWRD_FILE, "r"))) log(" Could not open help file."); else help_index = build_help_index(help_fl, &top_of_helpt); log("Loading cron files."); boot_cron(); log("Loading online readers."); boot_readers(); log("Loading org files."); boot_orgs(); log("Loading zone table."); boot_zones(); log("Loading rooms."); boot_world(); log("Renumbering rooms."); renum_world(); log("Opening mobile, object files."); if (!(mob_f = fopen(MOB_FILE, "r"))) { perror("boot"); exit(0); } if (!(obj_f = fopen(OBJ_FILE, "r"))) { perror("boot"); exit(0); } log("Generating index tables for mobile and object files."); mob_index = generate_mob_indices(mob_f, &top_of_mobt); obj_index = generate_obj_indices(obj_f, &top_of_objt); log("Booting bios"); boot_bio(); log("Loading current identification limits."); boot_id(); log("Renumbering zone table."); renum_zone_table(); log("Loading fight messages."); load_messages(); log("Loading social messages."); boot_social_messages(); log("Initializing message boards."); initialize_boards(); log("Assigning function pointers:"); if (!no_specials) { log(" Mobiles."); assign_mobiles(); log(" Objects."); assign_objects(); log(" Room."); assign_rooms(); } log("Loading world objects"); load_world_obj(); log("Setting up weather"); weather_setup(); for (i = 0; i <= top_of_zone_table; i++) { fprintf(stderr, "Boot-time reset of %s, rooms %d-%d (%d-%d).\n", zone_table[i].name, (i ? (zone_table[i - 1].top + 1) : 0), zone_table[i].top, zone_table[i].real_bottom, zone_table[i].real_top); reset_zone(i); } log("Booting syllables"); boot_syllables(); log("Booting plot system"); boot_plot(); reset_q.head = reset_q.tail = 0; dont_save_ids = FALSE; update_id(); log("Boot db -- DONE."); {void temp_cron_hack(); temp_cron_hack(); } } /* reset the time in the game from file */ void reset_time(void) { char buf[MAX_STRING_LENGTH]; long beginning_of_time = 650336715; struct time_info_data mud_time_passed(time_t t2, time_t t1); FILE *f1; long current_time; long last_time; long diff_time; time_info = mud_time_passed(time(0), beginning_of_time); if (!(f1 = fopen(TIME_FILE, "r"))) { perror("reset time"); exit(0); } fscanf(f1, "#\n"); fscanf(f1, "%d\n", &last_time); fscanf(f1, "%hd\n", &time_info.hours); fscanf(f1, "%hd\n", &time_info.day); fscanf(f1, "%hd\n", &time_info.month); fscanf(f1, "%hd\n", &time_info.year); fclose(f1); current_time = time(0); diff_time = current_time - last_time; sprintf(buf," Time since last shutdown: %d.", diff_time); log(buf); /* not sure of the purpose of this... diff_hours = diff_time/SECS_PER_MUD_HOUR; diff_time = diff_time % SEC_PR_HOUR; sprintf(buf," Real time lack : %d sec.", diff_time); log(buf); for(;diff_hours > 0; diff_hours--) weather_and_time(0); */ sprintf(buf," Current Gametime: %dH %dD %dM %dY.", time_info.hours, time_info.day, time_info.month, time_info.year); log(buf); } /* Smandoggi's new weather setup */ void weather_setup() { int zon,s; /* default conditions for season values */ char winds[6] = {2,12,30,40,50,80}; char precip[9] = {0,0,0,1,3,8,15,23,45}; char humid[9] = {4,10,20,30,40,50,60,75,100}; char temps[11] = {-20,-10,0,2,7,17,23,29,37,55,95}; for(zon=0;zon<=top_of_zone_table;zon++) { /* get the season */ s=get_season(&zone_table[zon]); /* These are pretty standard start values */ zone_table[zon].conditions.pressure=980; zone_table[zon].conditions.free_energy=10000; zone_table[zon].conditions.precip_depth=0; /* These use the default conditions above */ zone_table[zon].conditions.windspeed= winds[(int)zone_table[zon].climate.season_wind[s]]; zone_table[zon].conditions.wind_dir= zone_table[zon].climate.season_wind_dir[s]; zone_table[zon].conditions.precip_rate= precip[(int)zone_table[zon].climate.season_precip[s]]; zone_table[zon].conditions.temp= temps[(int)zone_table[zon].climate.season_temp[s]]; zone_table[zon].conditions.humidity= humid[(int)zone_table[zon].climate.season_precip[s]]; /* Set ambient light */ calc_light_zone(&zone_table[zon]); } } /* update the time file */ void update_time(void) { FILE *f1; extern struct time_info_data time_info; long current_time; if (!(f1 = fopen(TIME_FILE, "w"))) { perror("update time"); exit(0); } current_time = time(0); log("Time update."); fprintf(f1, "#\n"); fprintf(f1, "%d\n", current_time); fprintf(f1, "%d\n", time_info.hours); fprintf(f1, "%d\n", time_info.day); fprintf(f1, "%d\n", time_info.month); fprintf(f1, "%d\n", time_info.year); fclose(f1); } /* generate index table for monster file */ struct mob_index_data *generate_mob_indices(FILE *fl, int *top) { int i = 0; struct mob_index_data *index; char buf[82]; CREATE(index,struct mob_index_data,count_char('#',fl)); for (;;) { if (fgets(buf, 81, fl)) { if (*buf == '#') { sscanf(buf, "#%d", &index[i].virtual); index[i].pos = ftell(fl); index[i].number = 0; index[i].func = 0; /* location and frequency information to go here */ index[i].name = fread_string(fl); i++; } else if (*buf == '$') /* EOF */ break; } else { perror("generate mob indices"); exit(0); } } *top = i - 2; return(index); } /* generate index table for object file */ struct obj_index_data *generate_obj_indices(FILE *fl, int *top) { int i = 0; struct obj_index_data *index; char buf[82]; CREATE(index,struct obj_index_data,count_char('#',fl)); for (;;) { if (fgets(buf, 81, fl)) { if (*buf == '#') { sscanf(buf, "#%d", &index[i].virtual); index[i].pos = ftell(fl); index[i].number = 0; index[i].func = 0; index[i].name = fread_string(fl); i++; } else if (*buf == '$') /* EOF */ break; } else { perror("generate obj indices"); exit(0); } } *top = i - 2; return(index); } /* load the rooms */ void boot_world(void) { FILE *fl; int room_nr = 0, zone = 0, virtual_nr, flag, tmp; char *temp, chk[50]; struct extra_descr_data *new_descr; world = 0; character_list = 0; object_list = 0; if (!(fl = fopen(WORLD_FILE, "r"))) { perror("fopen"); log("boot_world: could not open world file."); exit(0); } CREATE(world,struct room_data,count_char('#',fl)); do { fscanf(fl, " #%d\n", &virtual_nr); temp = fread_string(fl); if((flag = (*temp != '$'))) /* a new record to be read */ { for(tmp=0;tmp<MAX_RDESC;tmp++) world[room_nr].description[tmp] = NULL; world[room_nr].number = virtual_nr; world[room_nr].name = temp; world[room_nr].description[0] = fread_string(fl); if (top_of_zone_table >= 0) { fscanf(fl, " %*d "); /* OBS: Assumes ordering of input rooms */ if (world[room_nr].number <= (zone ? zone_table[zone-1].top : -1)) { fprintf(stderr, "Room nr %d is below zone %d.\n", room_nr, zone); exit(0); } while (world[room_nr].number > zone_table[zone].top) if(++zone > top_of_zone_table) { fprintf(stderr, "Room %d is outside of any zone.\n", virtual_nr); exit(0); } world[room_nr].zone = zone; /* Update zone range of real rooms */ if(zone_table[zone].real_bottom==-1) zone_table[zone].real_bottom=room_nr; zone_table[zone].real_top=room_nr; } fscanf(fl, " %d ", &tmp); world[room_nr].room_flags = tmp; fscanf(fl, " %d ", &tmp); world[room_nr].sector_type = tmp; world[room_nr].funct = 0; world[room_nr].contents = 0; world[room_nr].people = 0; world[room_nr].light = 0; /* Zero light sources */ world[room_nr].ex_description = 0; /* Default values */ world[room_nr].chance_fall = 0; world[room_nr].mana_alignment = -1; world[room_nr].mana = 0; world[room_nr].trap = TRAP_NONE; for (;;) { fscanf(fl, " %s \n", chk); if (*chk == 'C') /* current field */ setup_current(fl,room_nr,atoi(chk + 1)); else if (*chk == 'D') /* direction field */ setup_dir(fl, room_nr, atoi(chk + 1)); else if (*chk == 'E') /* extra description field */ { CREATE(new_descr, struct extra_descr_data, 1); new_descr->keyword = fread_string(fl); new_descr->description = fread_string(fl); new_descr->next = world[room_nr].ex_description; world[room_nr].ex_description = new_descr; } else if (*chk == 'R') { fscanf(fl," %d ",&tmp); fscanf(fl," %d ",&tmp); } else if(*chk == 'F') { fscanf(fl," %d ",&tmp); world[room_nr].chance_fall = tmp; } else if(*chk == 'M') { fscanf(fl," %d ",&tmp); world[room_nr].mana_alignment = tmp; fscanf(fl," %d ",&tmp); world[room_nr].mana = tmp; } else if(*chk == 'S') /* end of current room */ break; } room_nr++; } } while (flag); free(temp); /* cleanup the area containing the terminal $ */ fclose(fl); top_of_world = --room_nr; } /* read current data */ void setup_current(FILE *fl, int room, int dir) { /* int tmp; CREATE(world[room].current[dir], struct current_data, 1); world[room].current[dir]->msg_char = fread_string(fl); world[room].current[dir]->msg_to_room = fread_string(fl); world[room].current[dir]->msg_from_room = fread_string(fl); world[room].current[dir]->msg_item_to_room = fread_string(fl); world[room].current[dir]->msg_item_from_room = fread_string(fl); fscanf(fl, " %d ", &tmp); world[room].current[dir]->strength = tmp; fscanf(fl, " %d ", &tmp); world[room].current[dir]->chance = tmp; fscanf(fl, " %d ", &tmp); world[room].current[dir]->flags = tmp; */ } /* read direction data */ void setup_dir(FILE *fl, int room, int dir) { int tmp; struct obj_data *exit_obj; struct obj_info_exit *exit_info; exit_obj = new_object(); exit_obj->obj_flags.extra_flags = ITEM_IGNORE; exit_info=(struct obj_info_exit *)new_obj_info(ITEM_EXIT,exit_obj); exit_info->dir = dir; exit_info->general_description = fread_string(fl); exit_obj->name = fread_string(fl); fscanf(fl, " %d ", &tmp); if (tmp == 1) exit_info->exit_info = EX_ISDOOR; else if (tmp == 2) exit_info->exit_info = EX_ISDOOR | EX_PICKPROOF; else exit_info->exit_info = 0; fscanf(fl, " %d ", &tmp); exit_info->key = tmp; fscanf(fl, " %d ", &tmp); exit_info->to_room = tmp; obj_to_room(exit_obj,room); } void renum_world(void) { register int room,res; struct obj_data *o; struct obj_info_exit *exit; for (room = 0; room <= top_of_world; room++) for (o=world[room].contents;o;o=o->next_content) if ((exit=(struct obj_info_exit *)get_obj_info(o,ITEM_EXIT))) { if(exit->to_room !=-1) { res = exit->to_room = real_room(exit->to_room); if(res==-1) fprintf(stderr,"from room %d dir %d\n", world[room].number,exit->dir); } } } void renum_zone_table(void) { int zone, comm; for (zone = 0; zone <= top_of_zone_table; zone++) for (comm = 0; zone_table[zone].cmd[comm].command != 'S'; comm++) switch(zone_table[zone].cmd[comm].command) { case 'M': zone_table[zone].cmd[comm].arg1 = real_mobile(zone_table[zone].cmd[comm].arg1); zone_table[zone].cmd[comm].arg3 = real_room(zone_table[zone].cmd[comm].arg3); break; case 'O': zone_table[zone].cmd[comm].arg1 = real_object(zone_table[zone].cmd[comm].arg1); if (zone_table[zone].cmd[comm].arg3 != NOWHERE) zone_table[zone].cmd[comm].arg3 = real_room(zone_table[zone].cmd[comm].arg3); break; case 'G': zone_table[zone].cmd[comm].arg1 = real_object(zone_table[zone].cmd[comm].arg1); break; case 'E': zone_table[zone].cmd[comm].arg1 = real_object(zone_table[zone].cmd[comm].arg1); break; case 'P': zone_table[zone].cmd[comm].arg1 = real_object(zone_table[zone].cmd[comm].arg1); zone_table[zone].cmd[comm].arg3 = real_object(zone_table[zone].cmd[comm].arg3); break; case 'D': zone_table[zone].cmd[comm].arg1 = real_room(zone_table[zone].cmd[comm].arg1); break; } } /* load the zone table and command tables */ void boot_zones(void) { FILE *fl; int zon = 0, cmd_no = 0, expand, tmp, i; char *check, buf[81]; if (!(fl = fopen(ZONE_FILE, "r"))) { perror("boot_zones"); exit(0); } CREATE(zone_table,struct zone_data,count_char('#',fl)); for (;;) { fscanf(fl, " #%d\n",&tmp); check = fread_string(fl); if (*check == '$') break; /* end of file */ zone_table[zon].number = tmp; zone_table[zon].name = check; zone_table[zon].author = fread_string(fl); fscanf(fl, " %d ", &zone_table[zon].top); fscanf(fl, " %d ", &zone_table[zon].lifespan); fscanf(fl, " %d ", &zone_table[zon].reset_mode); fscanf(fl, " %d ", &zone_table[zon].flags); zone_table[zon].desc_mode = RDESC_NORMAL; /* Start in default mode */ /* get weather info for the zone */ fscanf(fl, " %d ", &zone_table[zon].climate.season_pattern); fscanf(fl, " %d ", &zone_table[zon].climate.flags); fscanf(fl, " %d ", &zone_table[zon].climate.energy_add); for(i=0;i<MAX_SEASONS;i++) fscanf(fl," %d ",&zone_table[zon].climate.season_wind[i]); for(i=0;i<MAX_SEASONS;i++) fscanf(fl," %d ",&zone_table[zon].climate.season_wind_dir[i]); for(i=0;i<MAX_SEASONS;i++) fscanf(fl," %d ",&zone_table[zon].climate.season_wind_variance[i]); for(i=0;i<MAX_SEASONS;i++) fscanf(fl," %d ",&zone_table[zon].climate.season_precip[i]); for(i=0;i<MAX_SEASONS;i++) fscanf(fl," %d ",&zone_table[zon].climate.season_temp[i]); /* Set beginning values for zone real range */ zone_table[zon].real_bottom=zone_table[zon].real_top=-1; /* read the command table */ cmd_no = 0; for (expand = 1;;) { if (expand) if (!cmd_no) CREATE(zone_table[zon].cmd, struct reset_com, 1); else if (!(zone_table[zon].cmd = (struct reset_com *) realloc(zone_table[zon].cmd, (cmd_no + 1) * sizeof(struct reset_com)))) { perror("reset command load"); exit(0); } expand = 1; fscanf(fl, " "); /* skip blanks */ fscanf(fl, "%c", &zone_table[zon].cmd[cmd_no].command); if (zone_table[zon].cmd[cmd_no].command == 'S') break; if (zone_table[zon].cmd[cmd_no].command == '*') { expand = 0; fgets(buf, 80, fl); /* skip command */ continue; } fscanf(fl, " %d %d %d", &tmp, &zone_table[zon].cmd[cmd_no].arg1, &zone_table[zon].cmd[cmd_no].arg2); zone_table[zon].cmd[cmd_no].if_flag = tmp; if (zone_table[zon].cmd[cmd_no].command == 'M' || zone_table[zon].cmd[cmd_no].command == 'O' || zone_table[zon].cmd[cmd_no].command == 'E' || zone_table[zon].cmd[cmd_no].command == 'P' || zone_table[zon].cmd[cmd_no].command == 'D') fscanf(fl, " %d", &zone_table[zon].cmd[cmd_no].arg3); fgets(buf, 80, fl); /* read comment */ cmd_no++; } zon++; } top_of_zone_table = --zon; free(check); fclose(fl); } /************************************************************************* * procedures for resetting, both play-time and boot-time * *********************************************************************** */ void boot_bio() { FILE *fl; char buf[MAX_INPUT_LENGTH],ch,atname[MAX_INPUT_LENGTH], atval1[MAX_INPUT_LENGTH], atval2[MAX_INPUT_LENGTH]; struct bio_attr *new_attr; int tmp,attrib; if(!(fl=fopen(BIO_FILE,"r"))) { log("Cannot open bio file!"); exit(1); } CREATE(bio_index,struct bio_index_data, count_char('#',fl)); top_of_bio_table=0; for(;;) { fscanf(fl, "#%d\n", &tmp); if(feof(fl)) break; bio_index[top_of_bio_table].virtual=tmp; /* What we keep track of internally */ bio_index[top_of_bio_table].count=0; /* location */ fgets(buf,80,fl); tmp=0; bio_index[top_of_bio_table].loc = 0; while(buf[tmp] && buf[tmp]!='\n') { switch(buf[tmp]) { case 'C': bio_index[top_of_bio_table].loc |= TER_CITY; break; case 'V': bio_index[top_of_bio_table].loc |= TER_VILLAGE; break; case 'c': bio_index[top_of_bio_table].loc |= TER_CAVES; break; case 'D': bio_index[top_of_bio_table].loc |= TER_DUNGEON; break; case 'F': bio_index[top_of_bio_table].loc |= TER_FOREST; break; case 'P': bio_index[top_of_bio_table].loc |= TER_PLAIN; break; case 'H': bio_index[top_of_bio_table].loc |= TER_HILLS; break; case 'M': bio_index[top_of_bio_table].loc |= TER_MOUNTAIN; break; case 'L': bio_index[top_of_bio_table].loc |= TER_LAKE; break; case 'm': bio_index[top_of_bio_table].loc |= TER_MARSH; break; case 'S': bio_index[top_of_bio_table].loc |= TER_SWAMP; break; case 'R': bio_index[top_of_bio_table].loc |= TER_RIVER; break; case 'h': bio_index[top_of_bio_table].loc |= TER_SHALLOW; break; case 'd': bio_index[top_of_bio_table].loc |= TER_DEEPWATER; break; case 'A': bio_index[top_of_bio_table].loc |= TER_ASTRAL; break; case 'E': bio_index[top_of_bio_table].loc |= TER_ETHER; break; case 'U': bio_index[top_of_bio_table].loc |= TER_UNDERWORLD; break; case 'O': bio_index[top_of_bio_table].loc |= TER_OTHERPLANE; break; case '-': bio_index[top_of_bio_table].loc = 0; break; default: fprintf(stderr,"BUG: Bad bio location %c.\n",buf[tmp]); break; } tmp++; } /* frequency */ fscanf(fl,"%c\n",&ch); switch(ch) { case 'C': bio_index[top_of_bio_table].freq = FREQ_COMMON; break; case 'U': bio_index[top_of_bio_table].freq = FREQ_UNCOMMON; break; case 'R': bio_index[top_of_bio_table].freq = FREQ_RARE; break; case 'V': bio_index[top_of_bio_table].freq = FREQ_VERYRARE; break; case 'S': bio_index[top_of_bio_table].freq = FREQ_SPECIAL; break; case '1': bio_index[top_of_bio_table].freq = FREQ_UNIQUE; break; case '-': bio_index[top_of_bio_table].freq = FREQ_NEVER; break; default: fprintf(stderr,"BUG: Bad bio frequency %c.\n",ch); bio_index[top_of_bio_table].freq = FREQ_NEVER; break; } /* inherits */ fgets(buf,80,fl); sscanf(buf,"%d",&tmp); bio_index[top_of_bio_table].inherits = find_bio(tmp); bio_index[top_of_bio_table].name = fread_string(fl); /* descriptions */ bio_index[top_of_bio_table].sdesc = fread_string(fl); bio_index[top_of_bio_table].ldesc = fread_string(fl); /* Loop on reading attributes */ for(;;) { fgets(buf,80,fl); if(buf[0]=='S') break; sscanf(buf,"%s %s %s",atname, atval1,atval2); attrib=search_block_offset(atname,(char **)bio_attrs,1,sizeof(struct bio_info),0); if(attrib==-1) { sprintf(buf,"BUG: Bad bio attribute %s in %s.",atname, bio_index[top_of_bio_table].name); log(buf); } else { /* Make attribute and add it */ CREATE(new_attr,struct bio_attr,1); new_attr->next = bio_index[top_of_bio_table].attribs; bio_index[top_of_bio_table].attribs = new_attr; /*** new_attr->value = mung_somehow(atval);****/ new_attr->type = attrib; new_attr->value1 = atoi(atval1); if(new_attr->value1<bio_attrs[attrib].low || new_attr->value1>bio_attrs[attrib].high) { sprintf(log_buf,"BUG: Bio %s value %s out of range [%d,%d]", atname,atval1,bio_attrs[attrib].low,bio_attrs[attrib].high); log(log_buf); } if(bio_attrs[attrib].flags & BI_RANGE) { new_attr->value2 = atoi(atval2); if(new_attr->value2<bio_attrs[attrib].low || new_attr->value2>bio_attrs[attrib].high) { sprintf(log_buf,"Bio %s value %s out of range [%d,%d]", atname,atval2,bio_attrs[attrib].low,bio_attrs[attrib].high); log(log_buf); } } else if(bio_attrs[attrib].flags & BI_DICE) { new_attr->value2 = atoi(atval2); if(new_attr->value1<bio_attrs[attrib].low || new_attr->value1 * new_attr->value2 > bio_attrs[attrib].high) { sprintf(log_buf, "Bio dice %s value %sd%s out of range [%d,%d]", atname,atval1,atval2,bio_attrs[attrib].low, bio_attrs[attrib].high); log(log_buf); } } } } top_of_bio_table++; } fclose(fl); } int find_bio(int number) { int top,bot,mid; top=top_of_bio_table-1; bot=0; if(top==-1) /* This *is* quite possible */ return -1; if(top==0) /* This too... */ return (bio_index[0].virtual==number) ? 0 : -1; while(top >= bot) { mid=(top+bot)/2; if(bio_index[mid].virtual==number) return mid; else if(bio_index[mid].virtual<number) bot=mid+1; else top=mid-1; } return -1; } struct bio_attr *find_bio_attr(int bio_type,int attr) { int i; struct bio_attr *ba; if((i = find_bio(bio_type)) == -1) { sprintf(log_buf,"BUG: Can't find bio %d in find_bio_attr",bio_type); log(log_buf); return NULL; } while(i!=-1) { for(ba = bio_index[i].attribs;ba;ba = ba->next) if(ba->type == attr) return ba; i = bio_index[i].inherits; /* inherits is real, not virtual */ } log("BUG: Hit root bio node without finding attr."); return NULL; } int get_bio_attr(struct char_data *ch, int attr) { int ret=NULL; struct bio_attr *ba; switch(attr) { case BIO_STR : ret = GET_STR(ch); break; case BIO_INT : ret = GET_INT(ch); break; case BIO_WIS : ret = GET_WIS(ch); break; case BIO_DEX : ret = GET_DEX(ch); break; case BIO_CON : ret = GET_CON(ch); break; case BIO_CHR : ret = GET_CHR(ch); break; case BIO_HITPOINTS : ret = GET_HIT(ch); break; case BIO_MANA : ret = GET_MANA(ch); break; case BIO_MOVES : ret = GET_MOVE(ch); break; case BIO_HITDICE : case BIO_LIMBS : case BIO_LIMBS_PROPEL : case BIO_LIMBS_GRASP : case BIO_TAILS : case BIO_SIGHTED : case BIO_HEARING : case BIO_SMELLING : case BIO_ODOR_TYPE : case BIO_ODOR_STRENGTH : case BIO_SIZE : case BIO_RESERVED1 : case BIO_RESERVED2 : case BIO_RESERVED3 : case BIO_RESERVED4 : case BIO_RESERVED5 : case BIO_POS_SLEEP : case BIO_POS_REST : case BIO_POS_SIT : case BIO_POS_SWIM : case BIO_POS_STAND : case BIO_POS_LEVITATE : case BIO_POS_FLY : case BIO_MOBILE : case BIO_GESTATION : case BIO_LITTER_SIZE : case BIO_SEXES : case BIO_SEX_RATIO : case BIO_DIET : case BIO_PREF_TEMP : case BIO_PREF_HUMIDITY : case BIO_TEMP_TOLERATE : case BIO_HUMID_TOLERATE : case BIO_DAILY_CALS : default: /* This should *ALWAYS* be a value, not a range!! */ ba=find_bio_attr(ch->physical->species,attr); if(ba) ret = ba->value1; } return ret; } /* to probably take over as read_mobile... */ /* There needs to be routine(s) to call this which does * mob- or player- specific data, struct creation */ struct char_data *read_bio(int nr,int type) { struct char_data *ch; int i; if (type == VIRTUAL) { if ((nr = find_bio(nr)) < 0){ return(0); } } ch = bare_char(); init_char(ch); ch->desc = 0; ch->in_room = NOWHERE; ch->physical->species = bio_index[nr].virtual; ch->player.name = strdup(bio_index[nr].name); ch->player.short_descr = strdup(bio_index[nr].sdesc); ch->player.long_descr = strdup(bio_index[nr].ldesc); /* Loop on the various attributes, assigning them */ for(i=0;*bio_attrs[i].name!='\n';i++) if(bio_attrs[i].flags & BI_INTRINSIC) roll_bio_attr(ch,i); /* Handle those bios which have no hitdice */ if(GET_HIT(ch)<1) roll_bio_attr(ch,BIO_HITPOINTS); /* NEED TO MAKE ch->physical FIRST!!! */ ch->tmpabilities = ch->physical->abilities; CREATE(ch->mobinfo,struct char_mob_data,1); return(ch); } struct char_data *load_bio_to(int nr,int type,int where) { struct char_data *ch; if(!(ch = read_bio(nr,type))) return NULL; SET_BIT(ch->specials.act,ACT_ISNPC); ch->id=nextmob(); /* insert in list */ ch->next = character_list; character_list = ch; char_to_room(ch,where,0); return ch; } void roll_bio_attr(struct char_data *ch,int attr) { int val; struct bio_attr *ba; struct char_phys_data *phys; phys=ch->physical; if(!(ba = find_bio_attr(phys->species,attr))) { sprintf(log_buf,"Cannot roll bio attr '%s'.",bio_attrs[attr].name); log(log_buf); return; /* What can we do? */ } if(bio_attrs[attr].flags & BI_RANGE) val = number(ba->value1,ba->value2); else if(bio_attrs[attr].flags & BI_DICE) val = dice(ba->value1,ba->value2); else val = ba->value1; switch(attr) { case BIO_STR: phys->abilities.str = val; break; case BIO_INT: phys->abilities.intel = val; break; case BIO_WIS: phys->abilities.wis = val; break; case BIO_DEX: phys->abilities.dex = val; break; case BIO_CON: phys->abilities.con = val; break; case BIO_CHR: phys->abilities.chr = val; break; case BIO_HITPOINTS: phys->max_hit = val; break; case BIO_HITDICE: phys->max_hit = dice(val,8); break; case BIO_MANA: phys->max_mana = val; break; case BIO_MOVES: phys->max_move = val; break; default: sprintf(log_buf,"Cannot set bio attr %d.",attr); log(log_buf); break; } if(val < bio_attrs[attr].low) { } else if(val > bio_attrs[attr].high) { } } /* read a mobile from MOB_FILE */ struct char_data *read_mobile(int nr, int type) { int i; long tmp, tmp2, tmp3; struct char_data *mob; char letter; i = nr; if (type == VIRTUAL) { if ((nr = real_mobile(nr)) < 0){ return(0); } } fseek(mob_f, mob_index[nr].pos, 0); mob = bare_char(); /***** String data *** */ mob->player.name = fread_string(mob_f); mob->player.short_descr = fread_string(mob_f); mob->player.long_descr = fread_string(mob_f); mob->player.description = fread_string(mob_f); mob->player.title = 0; /* *** Numeric data *** */ fscanf(mob_f, "%d ", &tmp); mob->specials.act = tmp & (ACT_NICE_THIEF|ACT_NOSAVE); SET_BIT(mob->specials.act, ACT_ISNPC); fscanf(mob_f, " %d ", &tmp); fscanf(mob_f, " %d ", &tmp); mob->specials.alignment = tmp; fscanf(mob_f, " %c \n", &letter); if (letter == 'S') { /* New line of information */ fscanf(mob_f, " %c ",&letter); /*switch(letter) { case 'A': GET_CLASS(mob)=CLASS_ANIMAL; break; case 'B': GET_CLASS(mob)=CLASS_BIRD; break; case 'D': GET_CLASS(mob)=CLASS_DRAGON; break; case 'G': GET_CLASS(mob)=CLASS_GIANT; break; case 'H': GET_CLASS(mob)=CLASS_HUMANOID; break; case 'I': GET_CLASS(mob)=CLASS_INSECT; break; case 'O': default: GET_CLASS(mob)=CLASS_OTHER; break; case 'U': GET_CLASS(mob)=CLASS_UNDEAD; break; case 'X': GET_CLASS(mob)=CLASS_DEMON; break; }*/ fscanf(mob_f, " %d ",&tmp); GET_HOME(mob)=tmp; fscanf(mob_f, " %d \n",&tmp); /* don't do anything with this one yet */ /* The new easy monsters */ mob->physical->abilities.str = 11; mob->physical->abilities.intel = 11; mob->physical->abilities.wis = 11; mob->physical->abilities.dex = 11; mob->physical->abilities.con = 11; mob->physical->hunger = 24; mob->physical->thirst = 24; mob->physical->exhaustion = 24; mob->physical->impairment = 0; fscanf(mob_f, " %d ", &tmp); /*GET_LEVEL(mob) = tmp;*/ fscanf(mob_f, " %d ", &tmp); mob->points.hitroll = 20-tmp; fscanf(mob_f, " %d ", &tmp); mob->physical->armor = 10*tmp; fscanf(mob_f, " %dd%d+%d ", &tmp, &tmp2, &tmp3); mob->physical->max_hit = dice(tmp, tmp2)+tmp3; mob->physical->hit = mob->physical->max_hit; fscanf(mob_f, " %dd%d+%d \n", &tmp, &tmp2, &tmp3); mob->points.damroll = tmp3; mob->specials.damnodice = tmp; mob->specials.damsizedice = tmp2; mob->physical->mana = 10; mob->physical->max_mana = 10; mob->physical->move = 50; mob->physical->max_move = 50; fscanf(mob_f, " %d ", &tmp); /* mob->points.gold = tmp;*/ fscanf(mob_f, " %d \n", &tmp); GET_EXP(mob) = tmp; fscanf(mob_f, " %d ", &tmp); mob->specials.position = tmp; fscanf(mob_f, " %d ", &tmp); fscanf(mob_f, " %d \n", &tmp); GET_SEX(mob) = tmp; mob->player.time.birth = time(0); mob->player.time.played = 0; mob->player.time.logon = time(0); GET_WEIGHT(mob) = 200; GET_HEIGHT(mob) = 198; for (i = 0; i < 5; i++) mob->specials.apply_saving_throw[i] = MAX(20, 2); } mob->tmpabilities = mob->physical->abilities; mob->nr = nr; mob->desc = 0; mob->in_room = NOWHERE; CREATE(mob->mobinfo,struct char_mob_data,1); /* insert in list */ mob->next = character_list; character_list = mob; mob_index[nr].number++; mob->id = nextmob(); return(mob); } struct obj_data *new_object() { struct obj_data *obj; CREATE(obj, struct obj_data, 1); clear_object(obj); obj->in_room = NOWHERE; obj->next_content = 0; obj->carried_by = 0; obj->in_obj = 0; obj->contains = 0; obj->info = NULL; obj->material = NULL; obj->affected = NULL; obj->next = object_list; object_list = obj; return(obj); } struct obj_info *new_obj_info(sh_int type,struct obj_data *obj) { struct obj_info *new; /* CREATE(new,obj_info_size[type],1); silly macro, trix are for kids */ /* This is what the macro looks like in real life...huh? */ do { if(!(new=(struct obj_info *)malloc(obj_info_size[type]))) { abort(); } } while(0); /* I can understand the occasional while(1), but 0? */ new->next = obj->info; obj->info = new; new->obj_type = type; return new; } /* read an object from OBJ_FILE */ struct obj_data *read_object(int nr, int type) { struct obj_data *obj; int tmp, i; char chk[50]; struct extra_descr_data *new_descr; i = nr; if (type == VIRTUAL) { if ((nr = real_object(nr)) < 0) { sprintf(log_buf, "BUG: Object %d does not exist in database.",i); log(log_buf); return(0); } } fseek(obj_f, obj_index[nr].pos, 0); obj = new_object(); /* *** string data *** */ obj->name = fread_string(obj_f); obj->short_description = fread_string(obj_f); obj->description = fread_string(obj_f); obj->action_description = fread_string(obj_f); /* *** numeric data *** */ fscanf(obj_f, " %d ", &tmp); /** obj->obj_flags.type_flag = tmp; **/ fscanf(obj_f, " %d ", &tmp); obj->obj_flags.extra_flags = tmp; fscanf(obj_f, " %d ", &tmp); /** obj->obj_flags.wear_flags = tmp; **/ fscanf(obj_f, " %d ", &tmp); /** obj->obj_flags.value[0] = tmp; **/ fscanf(obj_f, " %d ", &tmp); /** obj->obj_flags.value[1] = tmp; **/ fscanf(obj_f, " %d ", &tmp); /** obj->obj_flags.value[2] = tmp; **/ fscanf(obj_f, " %d ", &tmp); /** obj->obj_flags.value[3] = tmp; **/ fscanf(obj_f, " %d ", &tmp); obj->obj_flags.weight = tmp; fscanf(obj_f, " %d \n", &tmp); obj->obj_flags.cost = tmp; fscanf(obj_f, " %d \n", &tmp); /* was cost per day */ /* *** extra descriptions *** */ obj->ex_description = 0; while (fscanf(obj_f, " %s \n", chk), *chk == 'E') { CREATE(new_descr, struct extra_descr_data, 1); new_descr->keyword = fread_string(obj_f); new_descr->description = fread_string(obj_f); new_descr->next = obj->ex_description; obj->ex_description = new_descr; } /* for( i = 0 ; (i < MAX_OBJ_AFFECT) && (*chk == 'A') ; i++) { fscanf(obj_f, " %d ", &tmp); obj->affected[i].location = tmp; fscanf(obj_f, " %d \n", &tmp); obj->affected[i].modifier = tmp; fscanf(obj_f, " %s \n", chk); } for (;(i < MAX_OBJ_AFFECT);i++) { obj->affected[i].location = APPLY_NONE; obj->affected[i].modifier = 0; }*/ obj->item_number = nr; obj_index[nr].number++; return (obj); } struct obj_info *get_obj_info(struct obj_data *o,int type) { struct obj_info *i; for(i=o->info;i;i=i->next) if(i->obj_type==type) return i; return NULL; } #define ZO_DEAD 999 #define MAX_ZONES_PER_PASS 3 /* update zone ages, queue for reset if necessary, and dequeue when possible */ void zone_update(void) { int i; struct reset_q_element *update_u, *temp; /* enqueue zones */ for (i = 0; i <= top_of_zone_table; i++) { if (zone_table[i].age < zone_table[i].lifespan && zone_table[i].reset_mode) (zone_table[i].age)++; else if (zone_table[i].age < ZO_DEAD && zone_table[i].reset_mode) { /* enqueue zone */ CREATE(update_u, struct reset_q_element, 1); update_u->zone_to_reset = i; update_u->next = 0; if (!reset_q.head) reset_q.head = reset_q.tail = update_u; else { reset_q.tail->next = update_u; reset_q.tail = update_u; } zone_table[i].age = ZO_DEAD; } } /* dequeue zones (if possible) and reset */ for(i=0, update_u = reset_q.head; update_u; update_u = update_u->next) if (zone_table[update_u->zone_to_reset].reset_mode == 2 || is_empty(update_u->zone_to_reset)) { reset_zone(update_u->zone_to_reset); /* dequeue */ if (update_u == reset_q.head) reset_q.head = reset_q.head->next; else { for (temp = reset_q.head; temp->next != update_u; temp = temp->next); if (!update_u->next) reset_q.tail = temp; temp->next = update_u->next; } free(update_u); /* Thanks to Brian aka Benedict of Mudde Pathetique for this */ /* We used to just "break;" here. But with so many zones, */ /* things started to bunch up. So now we try to dequeue more */ /* than one. */ if(i++ >= MAX_ZONES_PER_PASS) break; } } #define ZCMD zone_table[zone].cmd[cmd_no] /* execute the reset command table of a given zone */ void reset_zone(int zone) { int cmd_no =0, last_cmd = 1; char buf[256]; struct char_data *mob; struct obj_data *obj, *obj_to; return; for (cmd_no = 0;;cmd_no++) { if (ZCMD.command == 'S') break; if (last_cmd || !ZCMD.if_flag) switch(ZCMD.command) { case 'M': /* read a mobile */ if (mob_index[ZCMD.arg1].number < ZCMD.arg2) { mob = read_mobile(ZCMD.arg1, REAL); if(!mob) { log("BUG: mob not loaded!!"); last_cmd = 0; } else { char_to_room(mob, ZCMD.arg3,0); last_cmd = 1; } } else last_cmd = 0; break; case 'O': /* read an object */ if (obj_index[ZCMD.arg1].number < ZCMD.arg2) if (ZCMD.arg3 >= 0) { if (!get_obj_in_list_num(ZCMD.arg1,world[ZCMD.arg3].contents)) { obj = read_object(ZCMD.arg1, REAL); obj_to_room(obj, ZCMD.arg3); last_cmd = 1; } else last_cmd = 0; } else { obj = read_object(ZCMD.arg1, REAL); obj->in_room = NOWHERE; last_cmd = 1; } else last_cmd = 0; break; case 'P': /* object to object */ if (obj_index[ZCMD.arg1].number < ZCMD.arg2) { if((obj_to = get_obj_num(ZCMD.arg3))) { obj=read_object(ZCMD.arg1,REAL); obj_to_obj(obj, obj_to); last_cmd=1; } else last_cmd=0; } else last_cmd=0; break; case 'G': /* obj_to_char */ if (obj_index[ZCMD.arg1].number < ZCMD.arg2) { obj = read_object(ZCMD.arg1, REAL); obj_to_char(obj, mob); last_cmd = 1; } else last_cmd = 0; break; case 'E': /* object to equipment list */ if (obj_index[ZCMD.arg1].number < ZCMD.arg2) { obj = read_object(ZCMD.arg1, REAL); equip_char(mob, obj, ZCMD.arg3); last_cmd = 1; } else last_cmd = 0; break; case 'T': world[ZCMD.arg1].trap=ZCMD.arg2; break; default: sprintf(buf,"BUG: Undefd cmd in reset table; zone %d cmd %d.", zone, cmd_no); log(buf); exit(0); break; } else last_cmd = 0; } zone_table[zone].age = 0; } /* for use in reset_zone; return TRUE if zone 'nr' is free of PC's */ int is_empty(int zone_nr) { struct descriptor_data *i; for (i = descriptor_list; i; i = i->next) if (!i->connected) if (world[i->character->in_room].zone == zone_nr) return(0); return(1); } /************************************************************************ * procs of a (more or less) general utility nature * ********************************************************************** */ /* New version supplied by MERC */ /* read and allocate space for a '~'-terminated string from a given file */ char *fread_string(FILE *fl) { char buf[MAX_STRING_LENGTH]; char * pAlloc; char * pBufLast; for ( pBufLast = buf; pBufLast < &buf[sizeof(buf)-2]; ) { switch( *pBufLast = getc( fl ) ) { default: pBufLast++; break; case EOF: perror( "fread_string: EOF" ); exit( 0 ); break; /** Let's see if I like it with this commented out.. case '\n': while ( pBufLast > buf && isspace(pBufLast[-1]) ) pBufLast--; *pBufLast++ = '\n'; *pBufLast++ = '\r'; break; ***/ case '~': getc( fl ); if ( pBufLast == buf ) pAlloc = ""; else { *pBufLast++ = '\0'; CREATE( pAlloc, char, pBufLast-buf ); memcpy( pAlloc, buf, pBufLast-buf ); } return pAlloc; } } perror( "fread_string: string too long" ); exit( 0 ); return( NULL ); } /* release memory allocated for a char struct */ void free_char(struct char_data *ch) { struct affected_type *af; free(GET_NAME(ch)); if (ch->player.title) free(ch->player.title); if (ch->player.short_descr) free(ch->player.short_descr); if (ch->player.long_descr) free(ch->player.long_descr); if(ch->player.description) free(ch->player.description); for (af = ch->affected; af; af = af->next) affect_remove(ch, af); free(ch); } /* release memory allocated for an obj struct */ void free_obj(struct obj_data *obj) { struct extra_descr_data *this, *next_one; free(obj->name); if(obj->description) free(obj->description); if(obj->short_description) free(obj->short_description); if(obj->action_description) free(obj->action_description); for( this = obj->ex_description ; (this != 0);this = next_one ) { next_one = this->next; if(this->keyword) free(this->keyword); if(this->description) free(this->description); free(this); } free(obj); } /* read contents of a text file, and place in buf */ int file_to_string(char *name, char *buf) { FILE *fl; char tmp[100]; *buf = '\0'; if (!(fl = fopen(name, "r"))) { sprintf(log_buf,"BUG: file_to_string (%s): %s",name,strerror(errno)); log(log_buf); *buf = '\0'; return(-1); } do { fgets(tmp, 99, fl); if (!feof(fl)) { if (strlen(buf) + strlen(tmp) + 2 > MAX_STRING_LENGTH) { log("BUGL fl->strng - string too big (file_to_string)"); *buf = '\0'; return(-1); } strcat(buf, tmp); *(buf + strlen(buf) + 1) = '\0'; *(buf + strlen(buf)) = '\r'; } } while (!feof(fl)); fclose(fl); return(0); } /* clear some of the the working variables of a char */ void reset_char(struct char_data *ch) { ch->followers = 0; ch->master = 0; ch->in_room = NOWHERE; ch->next = 0; ch->next_fighting = 0; ch->next_in_room = 0; ch->specials.fighting = 0; ch->specials.position = POS_STAND; if (GET_HIT(ch) <= 0) GET_HIT(ch) = 1; if (GET_MOVE(ch) <= 0) GET_MOVE(ch) = 1; if (GET_MANA(ch) <= 0) GET_MANA(ch) = 1; } /* clear ALL the working variables of a char and do NOT free any space alloc'ed*/ struct char_data *bare_char() { struct char_data *ch; CREATE(ch,struct char_data,1); memset((char *)ch, (char)'\0', (int)sizeof(struct char_data)); CREATE(ch->physical,struct char_phys_data,1); memset((char *)ch->physical,(char)'\0',(int)sizeof(struct char_phys_data)); ch->in_room = NOWHERE; ch->specials.was_in_room = NOWHERE; ch->specials.position = POS_STAND; ch->specials.dispflags = NULL; ch->specials.spec[0]=0; ch->specials.spec[1]=0; ch->specials.spec[2]=0; ch->specials.spec[3]=0; ch->specials.ovl_timer=0; ch->specials.ovl_count=0; ch->specials.lights_carried=0; GET_AC(ch) = 100; if (affected_by_spell(ch, SKILL_ARMOR)) GET_AC(ch) -= 20; if (affected_by_spell(ch, SKILL_BLINDNESS)) GET_AC(ch) += 40; if (ch->physical->max_mana < 100) { ch->physical->max_mana = 100; } /* if */ return ch; } void clear_object(struct obj_data *obj) { memset((char *)obj, (char)'\0', (int)sizeof(struct obj_data)); obj->item_number = -1; obj->in_room = NOWHERE; } /* initialize a new guest character */ void init_char(struct char_data *ch) { int i; GET_EXP(ch) = 0; ch->player.short_descr = 0; ch->player.long_descr = 0; ch->player.description = 0; ch->player.time.birth = time(0); ch->player.time.played = 0; ch->player.time.logon = time(0); for (i = 0; i < MAX_TOUNGE; i++) ch->player.talks[i] = 0; ch->orgs = NULL; ch->skills = NULL; for (i = 0; i < 5; i++) ch->specials.apply_saving_throw[i] = 0; for (i = 0; i < 4; i++) ch->specials.spec[i] = 0; ch->specials.ovl_timer=0; ch->specials.ovl_count=0; ch->physical->hunger = 24; ch->physical->thirst = 24; ch->physical->exhaustion = 24; ch->physical->impairment = 0; /* SET_BIT(ch->specials.act,ACT_NOSAVE);*/ } /* player-related stuff... */ void start_player(struct char_data *ch) { int i; struct obj_data *obj; void advance_level(struct char_data *ch); REMOVE_BIT(ch->specials.act,ACT_NOSAVE); set_title(ch); /*shouldn't need now ch->points.max_hit = 10; / * These are BASE numbers */ advance_level(ch); GET_HIT(ch) = hit_limit(ch); GET_MANA(ch) = mana_limit(ch); GET_MOVE(ch) = move_limit(ch); ch->player.time.played = 0; ch->player.time.logon = time(0); ch->id = nextplayer(); CREATE(ch->prefs,struct player_prefs,1); ch->prefs->flags=PLR_SECURE; /* force secure until the player changes it */ ch->prefs->pwd[0]='\0'; for(i=0;i<MAX_DISCON_CMDS;i++) ch->prefs->discon[0][i]='\0'; save_char(ch); /* Give the player some minimal stuff --Sman */ obj=read_object(3010,VIRTUAL); /* A loaf of bread */ obj_to_char(obj,ch); obj=read_object(3102,VIRTUAL); /* A cup of water */ obj_to_char(obj,ch); obj=read_object(90,VIRTUAL); /* Jacket */ equip_char(ch,obj,WEAR_BODY); obj=read_object(91,VIRTUAL); /* Tights */ equip_char(ch,obj,WEAR_LEGS); obj=read_object(3021,VIRTUAL); /* Short sword */ equip_char(ch,obj,HOLD_HAND1); send_to_char("Welcome. This is now your character in Copper DikuMud,\n\rYou can now earn XP, and lots more...\n\r\n\r", ch); send_to_char("A disembodied voice tells you 'Take these meager " \ "items. I wish you\n\rgood fortune in this life. Please be " \ "courteous to your fellow mudders'\n\r\n\rYou find a map " \ "and other objects in your hands, and you are clothed\n\r" \ "in simple garb.\n\r\n\r",ch); /* enc = create_challenge(..ch...,DIFF_FAIR); char_to_room(ch,enc->???); execute_challenge(enc...);*/ } /* returns the real number of the room with given virtual number */ int real_room(int virtual) { int bot, top, mid; bot = 0; top = top_of_world; /* perform binary search on world-table */ for (;;) { mid = (bot + top) / 2; if ((world + mid)->number == virtual) return(mid); if (bot >= top) { fprintf(stderr, "Room %d does not exist in database\n", virtual); return(-1); } if ((world + mid)->number > virtual) top = mid - 1; else bot = mid + 1; } } /* returns the real number of the monster with given virtual number */ int real_mobile(int virtual) { int bot, top, mid; bot = 0; top = top_of_mobt; /* perform binary search on mob-table */ for (;;) { mid = (bot + top) / 2; if ((mob_index + mid)->virtual == virtual) return(mid); if (bot >= top) return(-1); if ((mob_index + mid)->virtual > virtual) top = mid - 1; else bot = mid + 1; } } /* returns the real number of the object with given virtual number */ int real_object(int virtual) { int bot, top, mid; bot = 0; top = top_of_objt; /* perform binary search on obj-table */ for (;;) { mid = (bot + top) / 2; if ((obj_index + mid)->virtual == virtual) return(mid); if (bot >= top) return(-1); if ((obj_index + mid)->virtual > virtual) top = mid - 1; else bot = mid + 1; } } int last[3] = {0,0,0}; void boot_id() { FILE *fl; char buf[82],directive[82]; int num; if(!(fl=fopen(ID_FILE,"r"))) { fprintf(stderr,"Cannot open id file.\n"); exit(1); } while(fgets(buf,81,fl)) { sscanf(buf,"%s %d",directive,&num); if(!strcmp(directive,"mob:")) last[ID_MOB]=num; else if(!strcmp(directive,"player:")) last[ID_PLAYER]=num; else if(!strcmp(directive,"obj:")) last[ID_OBJ]=num; } if(!last[ID_MOB] || !last[ID_PLAYER] || !last[ID_OBJ]) { fprintf(stderr,"Missing proper match in id file.\n"); exit(1); } fclose(fl); } void update_id() { FILE *fl; if(dont_save_ids) /* So we don't waste time during boot */ return; if(!(fl=fopen(ID_FILE,"w"))) { fprintf(stderr,"Cannot open id file.\n"); exit(1); } fprintf(fl,"mob: %d\nplayer: %d\nobj: %d\n",last[ID_MOB],last[ID_PLAYER],last[ID_OBJ]); fclose(fl); } int next_id(int kind) { if(kind==ID_MOB) last[kind]--; else last[kind]++; update_id(); return last[kind]; }