view src/robotII.c @ 6:8c6d5731234d

First entry of Paradise Server 2.9 patch 10 Beta
author darius
date Sat, 06 Dec 1997 04:37:04 +0000
parents
children
line wrap: on
line source

/*--------------------------------------------------------------------------
NETREK II -- Paradise

Permission to use, copy, modify, and distribute this software and its
documentation, or any derivative works thereof, for any NON-COMMERCIAL
purpose and without fee is hereby granted, provided that this copyright
notice appear in all copies.  No representations are made about the
suitability of this software for any purpose.  This software is provided
"as is" without express or implied warranty.

    Xtrek Copyright 1986                            Chris Guthrie
    Netrek (Xtrek II) Copyright 1989                Kevin P. Smith
                                                    Scott Silvey
    Paradise II (Netrek II) Copyright 1993          Larry Denys
                                                    Kurt Olsen
                                                    Brandon Gillespie
--------------------------------------------------------------------------*/

char binary[] = "@(#)robotII";

#include "config.h"

#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/file.h>
#ifndef ULTRIX
#include <sys/fcntl.h>
#endif
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "shmem.h"

extern void (*r_signal()) ();

void config();

struct itimerval udt;
extern int redrawall;		/* maint: missing "extern" 6/22/92 TC */
extern int lastm;		/* maint: missing "extern" 6/22/92 TC */

/* This lets you specify which ships a robot is allowed to choose */
int robotships[NUM_TYPES] = {
  1,				/* SCOUT */
  1,				/* DESTROYER */
  1,				/* CRUISER */
  1,				/* BATTLESHIP */
  1,				/* ASSAULT */
  0,				/* STARBASE */
  0,				/* ATT */
  0,				/* JUMPSHIP */
  1,				/* FRIGATE */
  0,				/* WARBASE */
  1,				/* LIGHTCRUISER */
  0,				/* CARRIER */
  0,				/* UTILITY */
  1				/* PATROL */
};

/* lots of neat flags */
int hostile;
int debug;
int level;
int fleet;
int sticky;
int berserk;
int practice;
int nofuel;

int polymorphic;		/* match opponent's ship class 8/15/91 TC */
int target;			/* Terminator's target 7/27/91 TC */
int phrange;			/* phaser range 7/31/91 TC */
int trrange;			/* tractor range 8/2/91 TC */

int startplanet = -1;		/* CRD feature - MAK,  2-Jun-93 */

/* velocities 8/9/91 TC */

int dogslow;			/* dodge speed (hard turn) */
int dogfast;			/* dodge speed (soft turn) */
int runslow;			/* run speed (flat etemp) */
int runfast;			/* run speed (gain etemp) */
int closeslow;			/* approach speed (hard turn) */
int closefast;			/* approach speed (soft turn) */

char *rnames[6] = {"M5", "Colossus", "Guardian", "HAL", "DreadPirate Bob",
"TERMINATOR"};

#ifdef ROBOTSTATS
void
do_robot_login()
{
  int plfd, position, entries, i;
  char *path;
  struct statentry player;
  struct stat buf;

  path = build_path(PLAYERFILE);
  plfd = open(path, O_RDONLY, 0);
  if (plfd < 0)
  {
    fprintf(stderr, "%s: I cannot open the player file! (errno: %d)\n",
	    argv0, errno);
    me->p_pos = -1;
    return;
  }
  position = 0;
  while (read(plfd, (char *) &player, sizeof(struct statentry)) ==
	 sizeof(struct statentry))
  {
    if (!strcmp(pseudo, player.name))
    {
      close(plfd);
      me->p_pos = position;
      memcpy(&(me->p_stats), &player.stats, sizeof(struct stats));
      return;
    }
    position++;
  }
  /* Not in there, so create it */
  strcpy(player.name, pseudo);
  strcpy(player.password, "*");	/* an invalid password to prevent logins */
  memset(&player.stats, 0, sizeof(struct stats));
  player.stats.st_tticks = 1;
  player.stats.st_flags = ST_INITIAL;

  plfd = open(path, O_RDWR | O_CREAT, 0644);
  if (plfd < 0)
  {
    fprintf(stderr, "%s: I cannot open the player file! (errno: %d)\n",
	    argv0, errno);
    me->p_pos = -1;
    return;
  }
  else
  {
    fstat(plfd, &buf);
    entries = buf.st_size / sizeof(struct statentry);
    lseek(plfd, entries * sizeof(struct statentry), 0);
    write(plfd, (char *) &player, sizeof(struct statentry));
    close(plfd);
    me->p_pos = entries;
    memcpy(&(me->p_stats), &player.stats, sizeof(struct stats));
  }
}

void
save_robot()
{
  int fd;
  char *path;

  if (me->p_pos < 0)
    return;
  path = build_path(PLAYERFILE);
  fd = open(path, O_WRONLY, 0644);
  if (fd >= 0)
  {
    me->p_stats.st_lastlogin = time(NULL);
    lseek(fd, 32 + me->p_pos * sizeof(struct statentry), 0);
    write(fd, (char *) &me->p_stats, sizeof(struct stats));
    close(fd);
  }
}
#endif

int 
main(argc, argv)
  int argc;
  char **argv;
{
  register int i;
  int rmove();
  int team = -1;
  int bteam;
  int pno;
  int class;			/* ship class 8/9/91 TC */

  argv0 = argv[0];
  srand48(time(NULL) + getpid());

  openmem(0, 0);

  for (;;)
  {
    class = lrand48() % NUM_TYPES;	/* pick a ship type */
    if (robotships[class] && shipsallowed[class])
      break;
  }

  target = -1;			/* no target 7/27/91 TC */
  for (; argc > 1 && argv[1][0] == '-'; argc--, argv++)
  {
    switch (argv[1][1])
    {
     case 'S':
      startplanet = atoi(&argv[1][2]);
      if (startplanet >= configvals->numplanets)
      {
	printf("startplanet insane: %d\n", startplanet);
	startplanet = -1;
      }
      break;
     case 'F':
      nofuel++;
      break;
     case 'P':
      polymorphic++;
      break;
     case 'f':
      fleet++;
      break;
     case 's':
      sticky++;
      break;
     case 'd':
      debug++;
      break;
     case 'h':
      hostile++;
      break;
     case 'p':
      practice++;
      break;
     case 'b':
      berserk++;
      break;
     case 'l':
      if (argv[1][2] != '\0')
	level = atoi(&argv[1][2]);
      else
	level = 100;
      break;
     case 'c':			/* ship class */
      {
	char cstr[NUM_TYPES + 1];

	for (class = 0; class <= NUM_TYPES; class++)
	{
	  if (class == NUM_TYPES)
	  {
	    cstr[NUM_TYPES] = 0;
	    fprintf(stderr, "Unknown ship class, must be one of [%s].\n", cstr);
	    exit(1);
	  }
	  if (argv[1][2] == shipvals[class].s_letter)
	    break;
	  cstr[class] = shipvals[class].s_letter;
	}
      }
      break;
     case 'T':			/* team */
      switch (argv[1][2])
      {
       case 'f':
	team = 0;
	bteam = FED;
	break;
       case 'r':
	team = 1;
	bteam = ROM;
	break;
       case 'k':
	team = 2;
	bteam = KLI;
	break;
       case 'o':
	team = 3;
	bteam = ORI;
	break;
       case 'n':		/* change 5/10/91 TC neutral */
       case 'i':
	team = 4;
	bteam = FED | ROM | KLI | ORI;	/* don't like anybody */
	break;
       case 't':
	{
	  char c;
	  c = argv[1][3];

	  team = 5;
	  bteam = FED | ROM | KLI | ORI;	/* don't like anybody */
	  target = -1;
	  if (c == '\0')
	  {
	    fprintf(stderr, "Must specify target.  e.g. -Tt3.\n");
	    exit(1);
	  }
	  if ((c >= '0') && (c <= '9'))
	    target = c - '0';
	  else if ((c >= 'a') && (c <= 'v'))
	    target = c - 'a' + 10;
	  else
	  {
	    fprintf(stderr, "Must specify target.  e.g. -Tt3.\n");
	    exit(1);
	  }
	}			/* end case 't' */
	break;
       default:
	fprintf(stderr, "Unknown team type.  Usage -Tx where x is [frko]\n");
	exit(1);
      }				/* end switch argv */
      break;
     default:
      fprintf(stderr, "Unknown option '%c' (must be one of: bcdfpsFPT)\n", argv[1][1]);
      exit(1);
    }				/* end switch argv[1][1] */


  }				/* end for */

  if (team < 0 || team >= 6)
  {				/* change 7/27/91 TC was 4 now 6 */
    if (debug)
      fprintf(stderr, "Choosing random team.\n");
    team = lrand48() % 4;
  }

  pno = findrslot();		/* Robots are entitled to tester's slots. */
  me = &players[pno];
  me->p_no = pno;
  myship = &me->p_ship;
  mystats = &me->p_stats;
  lastm = mctl->mc_current;

  /*
   * At this point we have memory set up.  If we aren't a fleet, we don't
   * want to replace any other robots on this team, so we'll check the other
   * players and get out if there are any on our team.
   */

  if (practice)
  {
    strcpy(pseudo, "Hozer");
  }
  else
  {
    strcpy(pseudo, rnames[team]);
  }
  strcpy(login, "Robot");

  (void) strncpy(me->p_login, login, sizeof(me->p_login));
  me->p_login[sizeof(me->p_login) - 1] = '\0';
  (void) strncpy(me->p_monitor, "Nowhere", sizeof(me->p_monitor));
  me->p_monitor[sizeof(me->p_monitor) - 1] = '\0';

  /* repeat "Nowhere" for completeness 4/13/92 TC */
  (void) strncpy(me->p_full_hostname, "Nowhere", sizeof(me->p_full_hostname));
  me->p_full_hostname[sizeof(me->p_full_hostname) - 1] = '\0';

  if (target >= 0)
  {				/* hack 7/27/91 TC */
    enter(team, target, pno, class, startplanet);
    startplanet = -1;		/* Termies should forget about startplanet */
  }
  else
    startplanet = enter(team, 0, pno, class, startplanet);

#ifdef ROBOTSTATS
  do_robot_login();
#else
  me->p_pos = -1;		/* So robot stats don't get saved */
#endif

  me->p_flags |= PFROBOT;	/* Mark as a robot */
  if ((berserk) || (team == 4))	/* indeps are hostile */
    me->p_hostile = (FED | ROM | KLI | ORI);	/* unless they are berserk */
  else if (team == 5)
    me->p_hostile = 0;		/* Termies declare war later */
  else if (practice)
    me->p_hostile = bteam;	/* or practice */
  else
    me->p_hostile = 0;		/* robots are peaceful */

  if (practice)
    me->p_flags |= PFPRACTR;	/* Mark as a practice robot */
  r_signal(SIGALRM, rmove);

  config();
  if (practice)
  {
    udt.it_interval.tv_sec = 1;	/* Robots get to move 1/sec */
    udt.it_interval.tv_usec = 000000;
  }
  else
  {
    udt.it_interval.tv_sec = 0;	/* Robots get to move 2/sec */
    udt.it_interval.tv_usec = 500000;
  }
  udt.it_value.tv_sec = 1;
  udt.it_value.tv_usec = 0;
  if (setitimer(ITIMER_REAL, &udt, 0) < 0)
  {
    perror("setitimer");
    me->p_status = PFREE;	/* Put robot in game */
    move_player(me->p_no, -1, -1, 1);
    exit(1);
  }
  /* allows robots to be forked by the daemon -- Evil ultrix bullshit */
#ifndef SVR4
  sigsetmask(0);
#endif				/* SVR4 */

  if (team == 4)
  {
    int count = 0;
    for (i = 0; i < MAXPLAYER; i++)
    {
      if (players[i].p_status == PALIVE)
	count++;
    }
    if (((count <= 1) && (!fleet)) ||
	((count < 1) && (fleet)))
    {				/* if one or less players, don't show */
      if (debug)
	fprintf(stderr, "No one to hoze.\n");
      players[pno].p_status = PFREE;
      move_player(me->p_no, -1, -1, 1);
      exit(1);
    }
  }
  if (!fleet)
  {
    for (i = 0; i < MAXPLAYER; i++)
    {
      if ((players[i].p_status == PALIVE) && (players[i].p_team == bteam))
      {
	if (debug)
	  fprintf(stderr, "Galaxy already defended\n");
	players[pno].p_status = PFREE;
	move_player(me->p_no, -1, -1, 1);
	exit(1);
      }
    }
  }
  me->p_status = PALIVE;	/* Put robot in game */
  while (1)
  {
    pause();
  }
  return 0;
}

int 
findrslot()
{
  register int i;

#if 0
  for (i = 0; i < MAXPLAYER; i++)
#else
  for (i = MAXPLAYER - 1; i >= 0; i--)
#endif
  {
    /* reverse entry..let's be trendy 4/6/92 TC */
    if (players[i].p_status == PFREE)
    {				/* We have a free slot */
      players[i].p_status = POUTFIT;	/* possible race code */
      break;
    }
  }
  if ((i == MAXPLAYER) || (i == -1))
  {
    if (debug)
    {
      fprintf(stderr, "No more room in game\n");
    }
    exit(0);
  }
  memset(&players[i].p_stats, 0, sizeof(struct stats));
  players[i].p_stats.st_tticks = 1;
  return (i);
}

void
warning(mess)
  char *mess;
{
  if (debug)
    fprintf(stderr, "warning: %s\n", mess);
}

void
config()
{
  /* calc class-specific stuff */

  phrange = PHASEDIST * me->p_ship.s_phaser.damage / 100;
  trrange = TRACTDIST * me->p_ship.s_tractrng;

  switch (myship->s_type)
  {
   case SCOUT:
    dogslow = 5;
    dogfast = 7;
    runslow = 8;
    runfast = 9;
    closeslow = 5;
    closefast = 7;
    break;
   case DESTROYER:
    dogslow = 4;
    dogfast = 6;
    runslow = 6;
    runfast = 8;
    closeslow = 4;
    closefast = 6;
    break;
   case CRUISER:
    dogslow = 4;
    dogfast = 6;
    runslow = 6;
    runfast = 7;
    closeslow = 4;
    closefast = 6;
    break;
   case BATTLESHIP:
    dogslow = 3;
    dogfast = 5;
    runslow = 5;
    runfast = 6;
    closeslow = 3;
    closefast = 4;
    break;
   case FRIGATE:
    dogslow = 3;
    dogfast = 5;
    runslow = 5;
    runfast = 6;
    closeslow = 3;
    closefast = 4;
    break;
   case ASSAULT:
    dogslow = 3;
    dogfast = 5;
    runslow = 6;
    runfast = 7;
    closeslow = 3;
    closefast = 4;
    break;
   case JUMPSHIP:
    dogslow = 2;
    dogfast = 3;
    runslow = 2;
    runfast = 3;
    closeslow = 2;
    closefast = 3;
    break;
   case STARBASE:
    dogslow = 2;
    dogfast = 2;
    runslow = 2;
    runfast = 2;
    closeslow = 2;
    closefast = 2;
    break;
   case WARBASE:
    dogslow = 2;
    dogfast = 2;
    runslow = 2;
    runfast = 2;
    closeslow = 2;
    closefast = 2;
    break;
   case LIGHTCRUISER:
    dogslow = 5;
    dogfast = 6;
    runslow = 6;
    runfast = 7;
    closeslow = 5;
    closefast = 7;
    break;
   case CARRIER:
    dogslow = 3;
    dogfast = 4;
    runslow = 5;
    runfast = 6;
    closeslow = 4;
    closefast = 6;
    break;
   case UTILITY:
    dogslow = 3;
    dogfast = 4;
    runslow = 5;
    runfast = 6;
    closeslow = 4;
    closefast = 5;
    break;
   case PATROL:
    dogslow = 7;
    dogfast = 8;
    runslow = 9;
    runfast = 10;
    closeslow = 8;
    closefast = 9;
    break;
  }

  if (debug)
    printf("My phaser range: %d.\n", phrange);
  if (debug)
    printf("My tractor range: %d.\n", trrange);

  if (!nofuel)
  {
    myship->s_phaser.cost = 0;
    myship->s_torp.cost = 0;
    myship->s_cloakcost = 0;
  }
  if (target >= 0)
  {				/* 7/27/91 TC */
    myship->s_imp.maxspeed = 20;/* was 10, so you can't run */
    myship->s_imp.cost = 1;
    myship->s_egncoolrate = 100;
  }
}