We just released a Feb. 5 '89 prototype of DuckTales for the NES!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!

Frontline (DOS)

From The Cutting Room Floor
Jump to navigation Jump to search

Title Screen

Frontline

Developer: Cases Computer Simulations
Publisher: Cases Computer Simulations
Platform: DOS
Released in EU: 1990


SourceIcon.png This game has uncompiled source code.


Uncompiled Source Code

A significant chunk of the game's C code is included on the disk. The .ima dump of the game has it at 0x74C00 (block 934 on an actual disk).

	ng  worth;
   int  f_per;
   char  file_name[40], buffer[150];

   if (player == (struct persona *) NULL) /* initialisation */
   {


      strncpy (file_name, FILE_PATH, 40);
      strncat (file_name, "person.d", 40);
      f_per = open (file_name, S_IREAD);
      if (f_per < 0)
      {
         write_log ("Unable to open person.d");
         return (FALSE);
      }
      lseek(f_per,0L,0);
      while(read(f_per,(char *)&per_rec,sizeof(struct persona)) > 0)
      {
         if(per_rec.id[0] == '\0') /* dead player */
            continue;

         if(per_rec.pl_flags[1] & PL_INTERNAL) /* exclude internals */
            continue;

         if((per_rec.rank < 1) || (per_rec.rank > 15))
            continue;

         if(per_rec.balance < 0L) /* look at this later */
            continue;

         worth = net_worth(&per_rec);

         for(count = 0;count < 6;count++)
         {
            if(conclave_net_worth[count] < worth)
            {
               for(index = 4;index >= count;index--)
               {
                  strncpy(conclave_array[index + 1],conclave_array[index],16);
                  conclave_net_worth[index + 1] = conclave_net_worth[index];
               }
               strncpy(conclave_array[count],per_rec.name,16);
               conclave_net_worth[count] = worth;
               break;
            }
         }
       }
      close(f_per);
      strcpy(buffer,"The Conclave are:\n ");
      for(count = 0;count < 6;count++)
      {
         strncat(buffer,conclave_array[count],16);
         strcat(buffer,"  ");
      }
      strcat(buffer,"\n");
      write_log(buffer);
      strcat(buffer,"\n");
      produce_review(buffer);
          return(TRUE);
   } /* end of initialisation routines... */

   concat("The Conclave are:\n",player);
   for(count = 0;count < 6;count++)
   {
      concat ("   ",player);
      concat (conclave_array[count],player);
      concat ("\n",player);
   }
   return(TRUE);
}

/********************************************************/
/*
   Function: display_info()
   Displays info contained in info.d file to the
   player.
   Returns:
      TRUE if info found
      FALSE if no info found
*/
/********************************************************/
int  display_info(item,player)
register struct persona  *player;
register int  item;
{
   struct computer  info_rec;
   int  f_info;
   char  file_name[40];

   strncpy (file_name, FILE_PATH, 40);
   strncat (file_name, "info.d", 40);
   if((f_info = open(file_name,S_IREAD)) < 0)
   {
      write_log("Unable to open info.d");
      return(FALSE);
   }
   while(read(f_info,&info_rec,sizeof(struct computer)) > 0)
   {
      if(info_rec.number == item)
      {
         concat("# ",player);
         concat(info_rec.text,player);
         concat("\n",player);
         close(f_info);
         return(TRUE);
      }
   }
   close(f_info);
   return(FALSE);
}

/***************************************************/
/* Function: get_persona_record()                  */
/* Searches the the persona file for a persona     */
/* record that matches either the user ID or the   */
/* player/ship name (depending on flag setting)    */
/* Returns:                                        */
/*    Pointer to record if found                   */
/*    Zero if no match found                       */
/***************************************************/
struct persona  *get_persona_record (match, flag)
register char  *match;
int  flag;
{
   int  f_per;
   register struct persona  *player;
   char  file_name[40];
#ifdef DEBUG
#ifdef GENIE
   char   buffer[80];
#endif
#endif

   strncpy (file_name, FILE_PATH, 40);
   strncat (file_name, "person.d", 40);
   f_per = open(file_name, S_IREAD);
   if(f_per < 0)
   {
      write_log ("GET_PER_REC: Unable to open persona file");
      exit (1);
   }
   
   if ((player = (struct persona *) malloc (sizeof (struct persona))) == NULL)
   {
      write_log ("GET_PER_REC: Unable to get space for persona rec");
      exit (1);
   }

#ifdef DEBUG
#ifdef GENIE
   if (flag == ID_SEARCH)
      sprintf (buffer, "GET_PER_REC: Searching for '%s' mode: ID_SEARCH",
         match);
   else
      sprintf (buffer, "GET_PER_REC: Searching for '%s' mode: NAME_SEARCH",
         match);
   write_log (buffer);
#endif
#endif

   lseek (f_per, 0L, 0);
   while ((read (f_per, (char *) player, sizeof (struct persona))) != 0)
   {
      if (flag == ID_SEARCH) /* match on ID */
      {
         if (strncmp (match, player->id, 9) == 0)
         {
            close (f_per);
            return (player);
         }
      }
      else /* match on name */
      {
         if ((strncmp (match, player->name, 16) == 0) | 
             (strncmp (match, player->ship_name, 16) == 0))
         {
            close (f_per);
            return (player);
         }
      }
   }

#ifdef DEBUG
#ifdef GENIE
   write_log("Persona search failed");
#endif
#endif

   free ((char *) player);
   close (f_per);
   return (0);
}

/******************************************************/
/* Function: get_this_per_rec()                       */
/* Searches the persona file for a persona rec at the */
/* specified offset.                                  */
/******************************************************/
struct persona  *get_this_per_rec(offset)
long  offset;
{
   int  f_per;
   register struct persona  *player;
   char  file_name[40];

   if (offset == -1L)
      return ((struct persona *)NULL);
   strncpy(file_name,FILE_PATH,40);
   strncat(file_name,"person.d",40);
   f_per = open(file_name,S_IREAD);
   if(f_per < 0)
   {
      write_log("GET_THIS_PER_REC: unable to open persona file...");
      exit(1);
   }
   if ((player = (struct persona *) malloc (sizeof (struct persona))) == NULL)
   {
      write_log ("GET_PER_REC: Unable to get space for persona rec");
      exit (1);
   }
   lseek(f_per,offset,0);
   if(read(f_per,(char *)player,sizeof(struct persona)) == 0)
   {
      free((char *)player);
      player = (struct persona *)NULL;
   }
   close(f_per);
   return(player);
}

/*------------------------------------------------------*/
/*
   Function: get_warehouse()
   Gets the warehouse structure which is stored at
   value 'offset' in the whouse.d file.
   Returns:
      Pointer to structure if all is OK
      NULL if there are any problems
*/
/*------------------------------------------------------*/
struct warehouse  *get_warehouse(offset)
long  offset;
{
   static struct warehouse  depot;

   if(lseek(f_warehouse,offset,0) != offset)
   {
      write_log("Unable to get result from lseek() in get_warehouse");
      return(NULL);
   }
   if(read(f_warehouse,(char *)&depot,sizeof(depot)) < sizeof(depot))
   {
      write_log("Error reading whouse.d in get_warehouse");
      return(NULL);
   }
   return(&depot);
}

/*----------------------------------------------------------*/
/*
   Function: levels()
   Gives the players a list of the top scorers at each
   level. The first time it is called it goes thru the
   persona file and compiles the list of names. Subsequent
   calls pass the list of names to the calling players.
   Returns:
      TRUE
*/
/*----------------------------------------------------------*/
int  levels(player)
register struct persona *player;
{
   struct level_block  level[16];
   static char  level_array[450];
   register int count;
   long  worth;
   int  f_per;
   char  file_name[40], buffer[50];

   if (player == (struct persona *) NULL) /* initialisation */
   {
      struct persona  per_rec;

      level_array[0] = '\0';
      strncpy(file_name,FILE_PATH,40);
      strncat(file_name,"person.d",40);
      f_per = open(file_name, S_IREAD);
      if(f_per < 0)
      {
         write_log("Unable to open person.d");
         return(FALSE);
      }
      lseek(f_per,0L,0);
      for(count = 0;count < 16;count++)
      {
         level[count].name[0] = '\0';
         level[count].worth = -300000L;
      }
      while(read(f_per,(char *)&per_rec,sizeof(struct persona)) > 0)
      {
         if(per_rec.id[0] == '\0') /* dead player */
            continue;

         if(per_rec.pl_flags[1] & PL_INTERNAL) /* exclude internals */
            continue;

         if((per_rec.rank > 15) || (per_rec.rank < 0))
         {
            printf("%s has a rank of %d!\n",per_rec.name,per_rec.rank);
            continue;
         }

         if((per_rec.rank == 0) || (per_rec.rank == 16))
            continue;

         if(per_rec.balance < 0L) /* must look at this odd one later! */
            continue;

         worth = net_worth(&per_rec);
         if(worth > level[per_rec.rank].worth)
         {
            strcpy(level[per_rec.rank].name,per_rec.name);
            level[per_rec.rank].worth = worth;
         }
      }
      close(f_per);
      sprintf(level_array,"The top scorers at each level are:");
      for(count = 1;count < 16;count++)
      {
         sprintf(buffer,"\n  [%2d] ",count + 1);
         strcat(level_array,buffer);
         if(strlen(level[count].name) == 0)
            strcat(level_array,"-----");
         else
            strcat(level_array,level[count].name);
      }
      strcat(level_array,"\n");
      return(TRUE);
   } /* end of initialisation */

   concat(level_array,player);
   return(TRUE);
}

/*********************************************************/
/* Function: load_factory()                              */
/* Loads in the specified factory, and links it into the */
/* list of active factories.                             */
/* NOTE: The calling routine is responsible for updating */
/* the player record to show that it is in memory!       */
/* Returns:                                              */
/*    Pointer to the factory if successful               */
/*    NULL if unsuccessful                               */
/*********************************************************/
struct factory  *load_factory(player,offset)
register struct persona  *player;
long  offset;
{
   struct factory  *this_factory, *cur_factory;
   struct warehouse  *depot;
   struct planet_data  *planet;
   register int  count;
   long  w_offset;
   int  f_handle;
   char  buffer[80];
   strcpy(buffer,FILE_PATH);
   strcat(buffer,"factry.d");
   if((f_handle = open(buffer,S_IREAD)) < 0)
   {
      write_log("LOAD_FACTORY unable to open file!");
      return(NULL);
   }
   this_factory = (struct factory *)malloc(sizeof(struct factory));
   if(this_factory == (struct factory *)NULL)
   {
      write_log("LOAD_FACTORY - insufficient memory to load factory");
      close(f_handle);
      return(NULL);
   }
   lseek(f_handle,offset,0);
   if(read(f_handle,(char *)this_factory,sizeof(struct factory)) < 
       sizeof(struct factory))
   {
      sprintf(buffer,"LOAD_FACTORY unable to read from offset %ld.",offset);
      write_log(buffer);
      free(this_factory);
      close(f_handle);
      return(NULL);
   }
   close(f_handle);
   this_factory->remove += 4;
   this_factory->workers[1] = 0;

   /* link factory into processing list */
   this_factory->ptr_next = (struct factory *)NULL;
   if(first_factory == (struct factory *)NULL)
   {
      first_factory = this_factory;
      first_factory->ptr_last = (struct factory *)NULL;
   }
   else
   {
      cur_factory = first_factory;
      while(cur_factory->ptr_next != (struct factory *)NULL)
         cur_factory = cur_factory->ptr_next;
      cur_factory->ptr_next = this_factory;
      this_factory->ptr_last = cur_factory;
   }

   /* Note: calling routine is responsible to updating player record! */

   /* set up warehouse link if necessary */
   this_factory->offset_store = -1;
   if(player->w_house >= 0L)
   {
      w_offset = player->w_house;
      depot = get_warehouse(player->w_house);
      while(depot != (struct warehouse *)NULL)
      {
         for(count = 0;count < max_planets;count++)
         {
            if(((planetii + count)->vocab == this_factory->planet) &&
                ((planetii + count)->exchange == depot->exchange))
            {
               this_factory->offset_store = w_offset;
               break;
            }
         }
         if(this_factory->offset_store != -1L)
            break;
         w_offset = depot->offset;
         if(w_offset <= 0)
            break;
         depot = get_warehouse(w_offset);
      }
   }

   /* suppress native production & set stock to stockpile */
   for(count = 0;count < max_planets;count++)
      if((planetii + count)->vocab == this_factory->planet)
         break;
   planet = planetii + count;
   for(count = 0; count < MAX_EXCH;count++)
      if(planet->exchange == exch_array[count].loc)
         break;
   exch_array[count].goods[this_factory->product][1] = 0;
   exch_array[count].goods[this_factory->product][2] = 
       exch_array[count].goods[this_factory->product][3];
   return(this_factory);
}

/******************************************************/
/* Function: load_planets()                           */
/* Loads in the planets data file.                    */
/* Returns:                                           */
/*    TRUE if successful                              */
/*    FALSE if unable to load file                    */
/******************************************************/
int  load_planets()
{
   long  size;
   register int  count;
   int  f_planets;
   char  buffer[45], *fedloc;

   strcpy(buffer,FILE_PATH);
   strcat(buffer,"planet.d");
   if((f_planets = open(buffer,S_IREAD)) < 0)
      return(FALSE);
   size = lseek(f_planets,0L,2);
   lseek(f_planets,0L,0);
   max_planets = (int)(size/(long)sizeof(struct planet_data));
   if((planetii = (struct planet_data *)malloc(size)) == (struct planet_data *)NULL)
      return(FALSE);
   read(f_planets,(char *)planetii,size);
   close(f_planets);
   if((fedloc = build_loc_db()) == NULL)
      return(FALSE);
   for(count = 0;count < max_planets;count++)
      (planetii + count)->ptr_loc = fedloc;
   return(TRUE);
}

/*-------------------------------------------------------*/
/*
   Function: load_ship_locs()
   Loads the player's ship locations into RAM.
   Returns:
      Pointer to the locations if successful
      NULL if unable to load locations
*/
/*-------------------------------------------------------*/
struct location  *load_ship_locs()
{
   static struct location  *ship_locs = (struct location *)NULL;
   struct dblocation db;
   int  f_ship,i,j,slen;
   char  file_name[40];

   if(ship_locs != (struct location *)NULL)
      return(ship_locs);

   if((ship_locs = (struct location *)malloc(8 * sizeof(struct location)))
       == (struct location *)NULL)
   {
      write_log ("Not enough memory for ship locs.");
      return(NULL);
   }
   strncpy(file_name,FILE_PATH,40);
   strncat(file_name,"templt.d",40);
   if((f_ship = open(file_name,S_IREAD)) < 0)
   {
      free(ship_locs);
      return(NULL);
   }
   lseek(f_ship,0L,0);
   for(i=0;i<8;i++)
   {
      read(f_ship,&db,sizeof(struct dblocation));
      slen=strlen(db.desc)+1;
      ship_locs[i].desc = malloc(slen);
      if(ship_locs[i].desc == (char *)NULL)
      {
         write_log("Failed malloc for location description (ship)");
         close(f_ship);
         return(NULL);
      }
      strncpy(ship_locs[i].desc,db.desc,slen);
      ship_locs[i].desc[slen-1]='\0';
      ship_locs[i].list_top = (struct object *) NULL;
      for(j=0;j<EVENT_SIZE;j++)
         ship_locs[i].events[j]=db.events[j];
      ship_locs[i].map_flag = db.map_flag;
      for(j=0;j<13;j++)
         ship_locs[i].mov_tab[j] = db.mov_tab[j];
      ship_locs[i].sys_loc = db.sys_loc;
   }
   close(f_ship);
   return(ship_locs);
}

/******* player has chosen new persona ******/
int  new_persona(msg)
struct message  *msg;
{
   struct new_pers  this_persona;
   struct persona  *per_rec;
   long  lseek();
   register int  count, size;
   int  f_per, fed_time, date, tick;
   short  day;
   register char  *record;
   char buffer[100], file_name[40];

   if ((per_rec = (struct persona *) malloc (sizeof (struct persona))) == NULL)
   {
      write_log ("NEW_PERSONA: Unable to malloc space for persona record.");
      exit (1);
   }
   memcpy((char *)&this_persona,msg->text,sizeof(this_persona));
   if(!check_name(this_persona.name))
   {
      msg->head.type = NAME_IN_USE;
      talk(msg);
      return(TRUE);
   }
   record = (char *)per_rec;
   size = sizeof(struct persona);
   for(count = 0; count < size; count++,*(record++) = '\0')
      ;
   sprintf(buffer,"Setting up new persona for %s [%s]",this_persona.name,this_persona.id);
   write_log(buffer);
   strncpy(per_rec->name,this_persona.name,16);
   strncpy(per_rec->id,this_persona.id,9);
   sprintf(buffer,"Federation welcomes %s to the game!\n",per_rec->name);
   produce_review(buffer);
   per_rec->race = 'h'; /* humans */
   per_rec->rank = 0;
   per_rec->sex = this_persona.sex;
   strncpy(per_rec->per_desc,"You see an ordinary person of average ",50);
   strncat(per_rec->per_desc,"height, wearing nondescript clothes.\n",50);
   per_rec->balance = 13000;
   per_rec->reward = per_rec->games = per_rec->status = 0;
   per_rec->title = 0;
   per_rec->loan = 0L;
   per_rec->ship_loc = per_rec->spying = per_rec->last_mayday = 0;
   for(count = 0;count < 4;per_rec->frame[count++] = 0)
      ;
   per_rec->max_str = per_rec->cur_str = this_persona.max_str;
   per_rec->max_sta = per_rec->cur_sta = this_persona.max_sta;
   per_rec->max_int = per_rec->cur_int = this_persona.max_int;
   per_rec->max_dex = per_rec->cur_dex = this_persona.max_dex;
   per_rec->last_loc = per_rec->loc_no = START;
   per_rec->ptr_loc = get_loc_addr(START);
   per_rec->games = per_rec->objects = 0;
   per_rec->max_objects = per_rec->max_str/5;
   per_rec->list_top = (struct object *)NULL;
   per_rec->it = 0;
   per_rec->last_name[0] = '\0';
   per_rec->next_commodity = 0;
   per_rec->w_house = -1;
   for (count = 0; count < MAX_LOAD; per_rec->load[count++].goods = -1)
      ;
   for (count = 0; count < 17; per_rec->ship_name[count++] = '\0')
      ;
   for (count = 0; count < 7; per_rec->pl_flags[count++] = 0)
      ;
   for (count = 0; count < 6; per_rec->g_count[count++] = 0)
      ;
   for (count = 0; count < 20; count++)
   {
      per_rec->plant_array[count].offset = -1L;
      per_rec->plant_array[count].ptr_plant = (struct factory *)NULL;
   }
   per_rec->pl_flags[0] |= PL_C_UNT;
   per_rec->pl_flags[0] |= PL_VAC;
   per_rec->pl_flags[0] |= PL_JOB;
   per_rec->number = per_rec->verb = 0;
   per_rec->msg_in = per_rec->msg_out = (struct message *)NULL;
   per_rec->last_on = 0;
   per_rec->term_width = 0;
   per_rec->pl_job.flag = 0;
   _sysdate(1,&fed_time,&date,&day,&tick);
   per_rec->time_on = fed_time;
   strncpy(file_name,FILE_PATH,40);
   strncat(file_name,"person.d",40);
   f_per = open(file_name, O_RDWR);
   if(f_per < 0)
   {
      write_log("NEW_PERSONA: Unable to open persona file");
      exit(1);
   }
   per_rec->abs_pl_set = lseek(f_per,0L,2);
   write(f_per,per_rec,sizeof(struct persona));
   close(f_per);
   for(count = 1;count < MAX_PLAYER;count++)
   {
      if(per_array[count] == 0)
      {
         per_array[count] = per_rec;
         msg->head.key = count;
         msg->head.type = MESSG;
         strncpy(msg->text,sys_mess[4],200);
         strncat(msg->text,sys_mess[5],150);
         talk(msg);
         msg = get_fed_module();
         msg->head.key = count;
         msg->head.type = FED_MESSG;
         strncpy(msg->head.id,per_array[count]->id,9);
         strcpy(msg->text,per_array[count]->ptr_loc->desc);
         talk(msg);
         per_array[count]->thread = count;
         sprintf(buffer,"%s [%s] has logged on",per_array[count]->name,
             per_array[count]->id);
         write_log(buffer);
         notify_players(per_array[count],LOG_ON);
         return(TRUE);
      }
   }
   /* No free threads - game is full */
   msg->head.key = 0;
   msg->head.type = NO_THRED;
   talk(msg);
   return(TRUE);
}

/****** player has bought a new ship ******/
int  new_space_ship(msg)
struct message  *msg;
{
   struct new_ship  ship;
   struct persona  *player;
   char  buffer[100];

   memcpy((char *)&ship,msg->text,sizeof(ship));
   if(!check_name(ship.ship_name))
   {
      strncpy(msg->text,"Registry reports that the name you chose ",60);
      strncat(msg->text,"is currently unavailable. Please try again ",60);
      strncat(msg->text,"next time you log on to Federation II.\n",60);
      msg->head.type = SHIP_REPLY; /* other variables already set up */
      talk(msg);
      return(TRUE);
   }
   player = get_persona_record(msg->head.id,ID_SEARCH);
   if(player == 0)
   {
      sprintf(buffer,"Unable to find persona rec for SHIP_CHECK - ");
      sprintf(buffer,"ID is %s",msg->head.id);
      write_log(buffer);
      strncpy(msg->text,"Error locating your persona - please report ",80);
      strncat(msg->text,"circumstances by mbx to ID: YETI. Thanx\n",80);
      msg->head.type = SHIP_REPLY;
      talk(msg);
      return(TRUE);
   }
   sprintf(buffer,"Setting up new ship for %s",player->name);
   write_log(buffer);
   strncpy(msg->text,"Name accepted, your ship has been registered.\n",65);
   strncat(msg->text,"Transfering funds from your account...\n",60);
   if(player->rank == 0)
   {
      player->loan = (ship.cost/10) * 9;
      sprintf(buffer,"\nLoan of %ld Imperial Groats agreed, ",player->loan);
      strncat(msg->text,buffer,80);
      change_balance(player,-(long)(ship.cost - player->loan),0L,43);
      player->loan *= 2;
      sprintf(buffer,"total repayable is %ld IG\n", player->loan);
      strncat(msg->text,buffer,80);
      sprintf(buffer,"10%% will be deducted from all income until the ");
      strncat(msg->text,buffer,80);
      sprintf(buffer,"loan is repaid.\n");
      strncat(msg->text,buffer,80);
      player->rank = 1;
   }
   else
      change_balance(player,-(long)ship.cost,0L,44);
   sprintf(buffer,"Your new account balance is %ld\n",player->balance);
   strncat(msg->text,buffer,80);
   strncat(msg->text,"\nYour new ship will be on the landing pad ",65);
   strncat(msg->text,"when you next log on -  have fun!\n",65);
   player->missiles = player->ammo = player->g_count[2] = 0;
   strncpy(player->ship_desc,"You see a nondesript looking ship painted",50);
   strncat(player->ship_desc," a manky shade of institutional grey\n",50);
   player->ship_loc = SHIP_START;
   memcpy((char *)&KIT,(char *)&ship.kit,sizeof(ship.kit));
   memcpy((char *)player->ship_guns,(char *)ship.guns,sizeof(ship.guns));
   strncpy(player->ship_name,ship.ship_name,16);
   write_persona(player);
   msg->head.type = SHIP_REPLY;
   talk(msg);
   free((char *)player);
   return(TRUE);
}

/************************************************************/
/* Function: open_files()                                   */
/* Checks that all the data files are there, and reads the  */
/* data into memory, where appropriate.                     */
/* Returns: TRUE                                            */
/************************************************************/
int  open_files()
{
   struct location  *loc_addr;
   int  f_per, f_tem, f_info, loc;
   long  lseek();
   char  file_name[40];

#ifdef UNIX
   setbuf(stdout,NULL);
#endif
#ifdef VMS
   setbuf(stdout,NULL);
#endif

   /* Check persona file is there */
   strncpy(file_name,FILE_PATH,40);
   strncat(file_name,"person.d",40);
   f_per = open(file_name, S_IREAD);
   if(f_per < 0)
   {
      write_log("Unable to open person.d");
      return(FALSE);
   }

#ifdef DEBUG
   temp = lseek(f_per,0L,2);
   fprintf(stderr,"persona file is %ld long!\n",temp);
#ifndef VMS
   if((temp % sizeof(persona_rec)) != 0)
   {
      write_log("Persona file corrupted!");
      close(f_per);
      return(FALSE);
   }
#endif
#endif 

   close(f_per);

   /* check for existence of ship template file */
   strncpy(file_name,FILE_PATH,40);
   strncat(file_name,"templt.d",40);
   if((f_tem = open(file_name,S_IREAD)) < 0)
   {
      write_log("Unable to open template.d");
      return(FALSE);
   }
   close(f_tem);

   /* open the warehouse file - leave it open for later use */
   strncpy(file_name,FILE_PATH,40);
   strncat(file_name,"whouse.d",40);
   if((f_warehouse = open(file_name,O_RDWR)) < 0)
   {
      write_log("Unable to open whouse.d");
      return(FALSE);
   }

   /* check for existence of computer info file */
   strncpy(file_name,FILE_PATH,40);
   strncat(file_name,"info.d",40);
   if((f_info = open(file_name,S_IREAD)) < 0)
   {
      write_log("Unable to open info.d");
      return(FALSE);
   }
   close(f_info);

   produce_review(NULL);

   if((!load_planets()) || (!build_dictionary()) || (!build_jobs_table()))
      return(FALSE);
   if((!build_goods_table()) || (!build_events_table()))
      return(FALSE);
   if((!build_object_list()) || (!build_exchange_table()))
      return(FALSE);

   if((!conclave(NULL)) || (!levels(NULL)))
      return(FALSE);

   /* set up event 13 (transition to trader status) */
   for(;;)
   {
      loc = 10 + random() % 750;
      if((loc == 217) || ((loc > 394) && (loc < 425)))
         continue;

      loc_addr = get_loc_addr(loc);
      if((loc_addr != (struct location *)NULL) && (loc_addr->map_flag == 0))
         break;
   }
   change_event(loc,0,13);

   return(TRUE);
}

/*----------------------------------------------------*/
/*
   Function: produce_review()
   Sets up the module used to produce the SpyNet
   Review, and maintains the edition during the game.
   Initiallises and terminates when called with a
   NULL string.
   Returns: TRUE
*/
/*----------------------------------------------------*/
int  produce_review(story)
char  *story;
{
   long  size;
   int  f_news, fed_time, date, tick;
   short  day;
   char  buffer[80];

   if(story == NULL) /* initialise */
   {
      /* load in any news */
      strncpy(buffer,FILE_PATH,40);
      strncat(buffer,"spynet.r",40);
      if((f_news = open(buffer,S_IREAD)) < 0)
         spynet_news[0] = '\0';
      else
      {
         size = lseek(f_news,0L,2);
         lseek(f_news,0L,0);
         read(f_news,spynet_news,(unsigned int)size);
         close(f_news);
      }

      /* set up the spynet review */
      _sysdate(0,&fed_time,&date,&day,&tick);
      sprintf(spynet_review,
                  "The SpyNet Review\n**>> Earth date %d/%d %d:%02d <<**\n",
                  (date & 0xFF),((date >> 8) & 0xFF),(fed_time >> 16),
                  ((fed_time >> 8) & 0xFF));
      strcat(spynet_review,stardate());
      strcat(spynet_review,"\n");
      return(TRUE);
   }

   /* add the story to the review */
   if(strlen(spynet_review) > 1800) /* then start review again */
   {
      _sysdate(0,&fed_time,&date,&day,&tick);
      sprintf(spynet_review,
                  "The SpyNet Review\n**>> Earth date %d/%d %d:%02d <<**\n",
                  (date & 0xFF),((date >> 8) & 0xFF),(fed_time >> 16),
                  ((fed_time >> 8) & 0xFF));
      strcat(spynet_review,stardate());
      strcat(spynet_review,"\n");
   }
   sprintf(buffer,"%04d:",game_time);
   strncat(spynet_review,buffer,80);
   strncat(spynet_review,story,80);

   return(TRUE);
}

/*********************************************************/
/* Function: save_factory()                              */
/* Saves a factory record off to disk. -1 in the factory */
/* number indicates that it is a new factory.            */
/* Returns:                                              */
/*    offset if record successfully written              */
/*    ERROR if unable to write record                    */
/*********************************************************/
long  save_factory(facility)
register struct factory  *facility;
{
   long   size;
   int      f_handle;
   char   buffer[80];

   strcpy(buffer,FILE_PATH);
   strcat(buffer,"factry.d");
   if((f_handle = open(buffer,O_RDWR)) < 0)
   {
      write_log("SAVE_FACTORY unable to open file!");
      return(ERROR);
   }
   if(facility->number == -1) /* new factory */
   {
      size = lseek (f_handle, 0L, 2);
      facility->number = (int) size/(sizeof (struct factory));
      facility->offset_this = size;
   }
   lseek(f_handle,facility->offset_this,0);
   write(f_handle,facility,sizeof(struct factory