view src/conquer.c @ 5:054275999194

Initial revision
author darius
date Sat, 06 Dec 1997 04:37:03 +0000
parents 2719a89505ba
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
--------------------------------------------------------------------------*/


#include "config.h"
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <setjmp.h>
#include <time.h>

#include "defs.h"
#include "struct.h"
#include "data.h"
#include "daemonII.h"
#include "misc.h"
#include "shmem.h"
#include "path.h"



/*----------------------------NUMBER DEFINES-------------------------------*/
#define SURRSTART  4		/* # planets where surrender starts */
#define SURREND	  7		/* # planets where surrender stops */
#define SURRLENGTH 25		/* give them 30 minutes to sustain empire */
/*-------------------------------------------------------------------------*/






/*----------------------------MODULE VARIABLES-----------------------------*/

/* used to store players found with the displayBest function */
typedef struct playerlist
{
  char name[16];		/* player's name */
  char mapchars[2];		/* player's map window image */
  int planets, armies;		/* planets taken and armies bombed */
  int resources, dooshes;	/* resources bombed and armies dooshed */
}   Players;

/*-------------------------------------------------------------------------*/






extern int enemy_admiral();
extern void perror();
extern void cause_kaboom();
extern void gen_planets();
extern void endtourn();
extern void stoptimer();
extern char *twoletters();
void checkwin();
void displayBest();

static void
swap(a, b)
  int *a, *b;
{
  int t = *a;
  *a = *b;
  *b = t;
}


/*----------------------------INTERNAL FUNCTIONS---------------------------*/

/*-----------------------------------GENOCIDE------------------------------*/
/*
 * This function checks for a genocide.  It also returns the two teams with
 * the most players.  It first goes through the four teams and finds the two
 * teams with the greatest number of players.  These two teams are returned
 * in the parameters team1 and team2.  If one of the teams does not have at
 * least one planet then a 1 is returned.  Otherwise a zero is returned.
 */

int
genocide(team1, team2)
  int *team1;			/* where to put first team */
  int *team2;			/* where to put second team */
{
  int t1, t2;			/* to hold two teams */
  int n1, n2;			/* to hold number of ships on teams */
  int t;			/* temp var */
  int i;			/* looping var */

  t1 = FED;			/* set first team */
  n1 = realNumShips(FED);	/* get players on it */
  t2 = ROM;			/* set second team */
  n2 = realNumShips(ROM);	/* get players on it */
  if (n1 < n2)
  {				/* place team with least players in t2 */
    swap(&n1, &n2);
    swap(&t1, &t2);
  }
  if (realNumShips(KLI) > n2)
  {				/* check the klingons */
    t2 = KLI;
    n2 = realNumShips(KLI);
  }
  if (n1 < n2)
  {				/* place team with least players in t2 */
    swap(&n1, &n2);
    swap(&t1, &t2);
  }
  if (realNumShips(ORI) > n2)
  {				/* check the orions */
    t2 = ORI;
    n2 = realNumShips(ORI);
  }
  /* no longer necessarily in order */
  *team1 = t1;			/* pass back team 1 */
  *team2 = t2;			/* pass back team 2 */
  t = 0;			/* no genocide detected yet */
  for (i = 0; i < NUMPLANETS; i++)
  {				/* see if team 1 has a planet */
    if (planets[i].pl_owner == t1)
    {				/* do they own this */
      t++;			/* inc t andd then get out of loop */
      break;
    }
  }
  for (i = 0; i < NUMPLANETS; i++)
  {				/* see if team 2 has a planet */
    if (planets[i].pl_owner == t2)
    {				/* do they own this */
      t++;			/* inc t andd then get out of loop */
      break;
    }
  }
  if (t != 2)			/* if both teams do not have planets then */
    return (1);			/* return that genocide has occured */
  else				/* else genocide has not occured */
    return (0);
}




/*------------------------------CHECKSURRENDER-----------------------------*/
/*
 * This function is called when a teams surrender status may have changed. It
 * takes a team and uses the s_plcount in the teams structure to check
 * whether a team has prevented surrender or the surrender process should
 * begin.
 */

void
checksurrender(team, otherplanets)
  int team;			/* the team to check */
  int otherplanets;
{
  char buf[80];			/* to sprintf into */

  if ((teams[team].s_surrender > 0) &&	/* surrender timer running? */
      ((teams[team].s_plcount >= SURREND) ||
       (teams[team].s_plcount * 2 > otherplanets)))
  {				/* and enough planets */
    pmessage("", 0, MALL, "");
    sprintf(buf, "The %s %s prevented collapse of the empire.",
	    teams[team].name, teamVerbage[team]);
    pmessage(buf, 0, MALL, MSERVA);	/* message to all */
    pmessage("", 0, MALL, "");
    teams[team].s_surrender = 0;/* stop surrender clock */
  }
  else if ((teams[team].s_surrender == 0) &&	/* start surrender  ? */
	   (teams[team].s_plcount <= SURRSTART) &&
	   (teams[team].s_plcount * 2 <= otherplanets) &&
	   (realNumShips(team) >= configvals->tournplayers) &&
	   (teams[team].s_plcount < teams[team].s_plcountold))
  {
    teams[team].s_surrender = SURRLENGTH;
    sprintf(buf, "The %s %s %d minutes before the empire collapses.",
	    teams[team].name, teamVerbage[team], SURRLENGTH);
    pmessage("", 0, MALL, "");
    pmessage(buf, 0, MALL, MSERVA);
    sprintf(buf, "%d planets are needed to sustain the empire.",
	    SURREND);
    pmessage(buf, 0, MALL, MSERVA);
    pmessage("", 0, MALL, "");
  }
}

/*-------------------------------------------------------------------------*/







/*------------------------------VISIBLE PROCEDURES-------------------------*/

/*---------------------------------UDSURRENDER-----------------------------*/
/*
 * This function updates the surender stuff.  There is also stuff for
 * updating the ship construction timers here.
 */

void
udsurrend()
{
  register int i, t;		/* looping vars */
  char buf[80];
  struct planet *l;
  struct player *j;

  /* TC's termination of players not on a t-mode team */
  for (i = 0, j = &players[0]; i < MAXPLAYER; i++, j++)
  {
    if ((j->p_status == PALIVE) &&
	!(j->p_flags & PFROBOT) && (j->p_team != NOBODY) &&
	(realNumShips(j->p_team) < configvals->tournplayers) &&
	(lrand48() % 5 == 0))
      rescue(TERMINATOR, j->p_no, -1);
  }
  for (t = 0; t <= MAXTEAM; t++)
  {				/* go through all teams */
    if ((teams[t].s_surrender == 0) ||
	(realNumShips(t) < configvals->tournplayers))
      continue;			/* suspend if no t-mode */
    if (teams[t].s_plcount > SURRSTART)	/* suspend timer if they have */
      continue;			/* enough planets */
    teams[t].s_surrender--;	/* dec the surrender timer */
    if (teams[t].s_surrender <= 0)
    {				/* if timer ran out then */
      teams[t].s_surrender = -1;/* set it so it isnt 0 (otherwise it
				 * announces surrender again) (BG) */
      sprintf(buf, "The %s %s surrendered.", teams[t].name,
	      teamVerbage[t]);	/* print surrender message */
      pmessage("", 0, MALL, "");
      pmessage(buf, 0, MALL, MSERVA);
      pmessage("", 0, MALL, "");
      for (i = 0, l = &planets[i]; i < NUMPLANETS; i++, l++)
      {
	if (l->pl_owner == t)
	{			/* neutralize and zero the */
	  l->pl_owner = NOBODY;	/* armies on all loser's planets */
	  l->pl_armies = 0;
	}
      }
      checkwin(enemy_admiral(t));	/* go check the win */
    }
    else if ((teams[t].s_surrender % 5) == 0 ||
	     (teams[t].s_surrender < 4))
    {
      sprintf(buf, "The %s %s %d minutes remaining.",
	      teams[t].name, teamVerbage[t], teams[t].s_surrender);
      pmessage("", 0, MALL, "");/* blank line */
      pmessage(buf, 0, MALL, MSERVA);	/* printf counting down */
      sprintf(buf, "%d planets will sustain the empire.  ", SURREND);
      pmessage(buf, 0, MALL, MSERVA);
      sprintf(buf, "%d or half enemy suspends countdown.", SURRSTART + 1);
      pmessage(buf, 0, MALL, MSERVA);
      pmessage("", 0, MALL, "");/* blank line */
    }
  }				/* end for team */
}


/*------------------------------CONQUERMESSAGE-----------------------------*/
/*
 * This function is called after a race is genocided.  It lists the players
 * on the winning and losing teams.  The reason should be either GENOCIDE or
 * SURRENDER.  The list is written to the conquer file.
 */

void
conquerMessage(winners, losers, pno)
  int winners;
  int losers;
  int pno;
/* the losing and winning teams */
/* the person who won it */
{
  char buf[80];			/* to sprintf into */
  FILE *conqfile;		/* to open conquer file */
  time_t curtime;		/* to get current time */
  char *paths;			/* to hold path to directory */

  paths = build_path(CONQFILE);
  conqfile = fopen(paths, "a");	/* open the conquer file */
  if (!conqfile)
  {
    perror("");
    fprintf(stderr, "failed to open file %s\n", paths);
  }
#ifdef LEAGUE_SUPPORT
#define OUT pmessage(buf, 0, MALL | MGENO, " "); \
	if (conqfile) fprintf(conqfile, "  %s\n", buf); \
	tlog_conquerline(buf);
#else
#define OUT pmessage(buf, 0, MALL | MGENO, " "); \
	if (conqfile) fprintf(conqfile, "  %s\n", buf);
#endif

  time(&curtime);		/* get current time */
  strcpy(buf, "\nConquer! ");	/* this is a genocide */
  strcat(buf, ctime(&curtime));	/* cat on current time */
  if (conqfile)
    fprintf(conqfile, "  %s\n", buf);	/* write it to conquer file */
  pmessage("***********************************************************",
	   0, MALL | MGENO, " ");	/* print enclosure to messages */

  if (pno >= 0)
  {
    sprintf(buf, "The galaxy has been conquered by %s and the %s!!!!",
	    players[pno].p_name, teams[winners].name);
  }
  else
  {
    sprintf(buf, "Stalemate.");
  }
  OUT;

  sprintf(buf,
#ifdef LEAGUE_SUPPORT
	  status2->league ? "The %s(%s):" :
#endif
	  "The %s:",
	  teams[winners].name
#ifdef LEAGUE_SUPPORT
	  ,((winners == (1 << status2->home.index)) ?
	    (&status2->home) :
	    (&status2->away))->name
#endif
    );
  OUT;
  displayBest(conqfile, winners);	/* go display team 1 */
  sprintf(buf,
#ifdef LEAGUE_SUPPORT
	  status2->league ? "The %s(%s):" :
#endif
	  "The %s:",
	  teams[losers].name
#ifdef LEAGUE_SUPPORT
	  ,((losers == (1 << status2->home.index)) ?
	    (&status2->home) :
	    (&status2->away))->name
#endif
    );
  OUT;
  displayBest(conqfile, losers);/* go display team 2 */
  pmessage("***********************************************************",
	   0, MALL | MGENO, " ");	/* printf the enclosure */
  if (conqfile)
  {
    fprintf(conqfile, "\n");	/* space between conquering */
    fclose(conqfile);		/* close conquer file */
  }
}


void
refresh_team_planetcounts()
{
  int i;
  register struct planet *l;	/* to point to planets */

  for (i = 0; i <= MAXTEAM; i++)
  {				/* zero out each teams planet count */
    teams[i].s_plcountold = teams[i].s_plcount;	/* save last planet count */
    teams[i].s_plcount = 0;
  }
  for (i = 0, l = &planets[i]; i < NUMPLANETS; i++, l++)	/* recompute */
    teams[l->pl_owner].s_plcount++;	/* planet counts for teams */
}

/* blow everyone up, print the conquer assessments, figure out who won. */
void
endgame_effects(t1, t2, pno)
  int t1;
  int t2;
  int pno;
{
  int i;
  struct player *j;

  refresh_team_planetcounts();

  if (teams[t1].s_plcount < teams[t2].s_plcount)
  {
    int i;
    i = t1;
    t1 = t2;
    t2 = i;			/* t1 is the winners */
  }
  if (pno >= 0 && players[pno].p_team != t1)
    pno = -1;			/* he can't win the game! */

  if (pno < 0)
    pno = enemy_admiral(t2);

  if (teams[t1].s_plcount == teams[t2].s_plcount)
  {
    /* tie, nobody wins */
    pno = -1;
  }
  status->genocides++;		/* inc number of genocides */
  conquerMessage(t1, t2, pno);	/* print conquer message */

  for (i = 0, j = &players[0]; i < MAXPLAYER; i++, j++)
  {
    if (j->p_status == PFREE)	/* if player not in game */
      continue;			/* ignore him */
    if (status->tourn)		/* only inc genos if t-mode */
      j->p_stats.st_genocides++;/* inc player's genocides */
    j->p_whydead = KWINNER;	/* because someone won */
    j->p_whodead = pno;		/* set who won the game */
    j->p_status = POUTFIT;	/* send them immediately to outfit screen */
    /*
     * cause_kaboom (j);
     */
    j->p_ntorp = 0;		/* no torps shot */
    j->p_nplasmatorp = 0;	/* no plasmas shot */
  }
}



/*-------------------------------CHECKWIN---------------------------------*/
/*
 * This function is called when a planet is taken or beamed to zero. It
 * recalculates s_plcount for each team.  It then finds the two teams that
 * are in t-mode.  If either of them has just sustained the empire from
 * collapse or should start the surrender procedure then that is done.  If a
 * team has been genocided then the genocide message is printed and the game
 * is reset.
 */

void
checkwin(pno)
  int pno;
{
  int g;			/* to hold whether genocide occured */
  int t1, t2;			/* to hold the t-mode teams */

  refresh_team_planetcounts();
  g = genocide(&t1, &t2);	/* check genocide */
  if (teams[t1].s_plcount < teams[t2].s_plcount)
  {
    int i;
    i = t1;
    t1 = t2;
    t2 = i;			/* t1 is the winners */
  }
  checksurrender(t1, teams[t2].s_plcount);	/* check for change in */
  checksurrender(t2, teams[t1].s_plcount);	/* surrender status */
  if (!g)			/* if genocide did not occur */
    return;			/* then return from func */
  teams[t1].s_surrender = 0;	/* stop the surrender clock */
  teams[t2].s_surrender = 0;

  stoptimer();

#ifdef LEAGUE_SUPPORT
  if (status2->league)
  {
    endtourn();			/* calls endgame_effects */
  }
  else
#endif
    endgame_effects(t1, t2, pno);
#if 0
  gen_planets();		/* generate new galaxy */

  longjmp(env, 0);		/* restart */
#else
  status->gameup = 0;		/* exit the daemon */
  status->count = 0;
  save_planets();
  sleep(2);
  blast_shmem();
  exit(0);
#endif
}







/*-------------------------------DISPLAYBEST-------------------------------*/
/*
 * This function is used to get a list of players on a team after a genocide.
 * It goes through the players and selects the ones that have inflicted the
 * most damage.  They are then printed to the message window and to the
 * conquer file.  They are arranged according to how much damage the players
 * have inflicted on the enemy, with one planet taken counting as thirty
 * armies bombed.  A resource counts as 8 armies bombed and a army dooshed
 * counts as five armies bombed.
 */

void
displayBest(conqfile, team)
  FILE *conqfile;		/* the opened conquer file */
  int team;			/* the winning team */
{
  register int i, k, l;		/* looping vars */
  register struct player *j;	/* to point to players */
  int planets, armies;		/* # planets and armies for player */
  int resources, dooshes;	/* resources bombed, armies dooshed */
  Players winners[MAXPLAYER + 1];	/* to hold player's stats */
  char buf[100];		/* to sprintf into */
  int number;			/* to hold # players found */

  number = 0;			/* number of players found */
  for (i = 0, j = &players[0]; i < MAXPLAYER; i++, j++)
  {
    if ((j->p_team != team) || (j->p_status == PFREE))	/* player wrong race */
      continue;			/* or not here, then forget him */
    planets = j->p_planets;	/* get all planets and armies for */
    armies = j->p_armsbomb;	/* entire game */
    resources = j->p_resbomb;	/* get resources and armies dooshed */
    dooshes = j->p_dooshes;
    for (k = 0; k < number; k++)
    {				/* go find postion in current list */
      if (30 * winners[k].planets + winners[k].armies + 8 * winners[k].resources
	  + 5 * winners[k].dooshes <
	  30 * planets + armies + 8 * resources + 5 * dooshes)
      {
	break;			/* break when position found */
      }
    }
    for (l = number; l >= k; l--)	/* move other players to make room */
      winners[l + 1] = winners[l];	/* for new player */
    number++;			/* we have found one more player */
    winners[k].planets = planets;	/* record his planets and armies */
    winners[k].armies = armies;
    winners[k].resources = resources;
    winners[k].dooshes = dooshes;
    strncpy(winners[k].mapchars, twoletters(j), 2);
    strncpy(winners[k].name, j->p_name, 16);	/* get his name */
    winners[k].name[15] = 0;	/* `Just in case' paranoia */
  }
  for (k = 0; k < number; k++)
  {				/* go through all players found */
    if (winners[k].planets != 0 || winners[k].armies != 0)
    {				/* damage done? */
      sprintf(buf, " %16s (%2.2s)  %d planets %d armies %d resources %d dooshes",
	      winners[k].name, winners[k].mapchars, winners[k].planets,
	      winners[k].armies, winners[k].resources, winners[k].dooshes);
      OUT;
    }
  }
}

/*-------------------------------------------------------------------------*/






/*-----------END OF FILE-----*/