view src/dutil.c @ 3:cafa94d86546

Initial revision
author darius
date Sat, 06 Dec 1997 04:37:01 +0000
parents
children d28f3d01043c
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 <stdio.h>
#include <math.h>
#include <signal.h>
#include <string.h>

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

#define	friendly(fred, bart) \
	(!(fred->p_team & (bart->p_swar|bart->p_hostile)) && \
	 !(bart->p_team & (fred->p_swar|fred->p_hostile)))

/*--------------------------------KILLMESS--------------------------------*/

/*
 * This function prints to the messages who killed who.  This function now
 * adds the way of death onto the end of the kill message.
 */


extern void pmessage();
int get_explode_views();
#ifndef SYSV			/* this is barfing on HP/UX */
extern int fprintf();
#endif
extern void killerstats();
extern void checkmaxkills();
#ifdef LEAGUE_SUPPORT
extern void tlog_plkill();
#else
#define tlog_plkill(a,b,c)
#endif
extern void loserstats();

void
killmess(victim, killer)
  struct player *victim, *killer;	/* killee and killer */
{
  char buf[80];			/* to sprintf into */

  sprintf(buf, "%s (%s", victim->p_name, twoletters(victim));

  if (victim->p_armies)
  {
    if ((victim->p_ship.s_nflags & SFNHASFIGHTERS) && (victim->p_ship.s_type != STARBASE))
      sprintf(buf + strlen(buf), "+%d fighters",
	      victim->p_ship.s_missilestored);
    else
      sprintf(buf + strlen(buf), "+%d armies", victim->p_armies);
  }
  strcat(buf, ")");
  if (killer)
  {
    sprintf(buf + strlen(buf), " was kill %0.2f for %s (%s)",
	    killer->p_kills, killer->p_name,
	    twoletters(killer));

    if (friendly(victim, killer))
      strcat(buf, "[no credit]");

  }
  else
  {
    if (victim->p_whydead == KPLANET)
    {
      sprintf(buf + strlen(buf), " was %s by %s (%s)",
	      PL_TYPE(planets[victim->p_whodead]) == PLSTAR ?
	      "burned to a crisp" : "shot down",
	      planets[victim->p_whodead].pl_name,
	      teams[planets[victim->p_whodead].pl_owner].shortname);
    }
    else if (victim->p_whydead == KASTEROID)
      sprintf(buf + strlen(buf), " was crushed by an asteroid");
    else
    {
      strcat(buf, " was killed");
    }
  }
  switch (victim->p_whydead)
  {				/* determine why player died */
   case KTORP:
    strcat(buf, "[torp]");
    break;
   case KPHASER:
    strcat(buf, "[phaser]");
    break;
   case KSHIP:
    strcat(buf, "[explosion]");
    break;
   case KPLASMA:
    strcat(buf, "[plasma]");
    break;
   case KASTEROID:
    strcat(buf, "[asteroid]");
    break;
   case KPLANET:
    switch (PL_TYPE(planets[victim->p_whodead]))
    {
     case PLSTAR:
      strcat(buf, "[star]");
      break;
     case PLPLANET:
      strcat(buf, "[planet]");
      break;
     default:
      strcat(buf, "[space rock]");
      break;
    }
    break;
   default:
    strcat(buf, "[unknown]");
  }
  pmessage(buf, 0, MALL | MKILLA, "GOD->ALL");
}




/*-------------------------------VISIBLE FUNCTIONS------------------------*/

/*-------------------------------CAUSE_KABOOM------------------------------*/
/*
 * This function sets the victim to explode and sets the counter for the
 * explosion views.
 */

void
cause_kaboom(victim)
  struct player *victim;	/* which ship to blast to tiny fragments */
{
  victim->p_status = PEXPLODE;	/* set player as exploding */
  victim->p_explode = (short) get_explode_views(victim->p_ship.s_type);
}

/*------------------------------GET_EXPLODE_VIEWS--------------------------*/
/* returns the number of ship views for the given ship type */

int
get_explode_views(stype)
  short stype;
{
  switch (stype)
  {
   case STARBASE:
   case WARBASE:
   case JUMPSHIP:
    return 2 * SBEXPVIEWS / PLAYERFUSE;	/* big kablooey */
  }
  return 10 / PLAYERFUSE;	/* small kablooey */
}

/*------------------------------INFLICT_DAMAGE-----------------------------*/
/*
 * This function is used to inflict damage on a player.  If the player dies
 * as a result he will be made to explode.  The function returns a 1 if the
 * victim was killed and a 0 otherwise.  If the sp parameter is a zero then
 * the victim was damaged by something other than a ship.  It is the
 * responsibil- ity of the caller to set the whydead field of the victim.
 */

int
inflict_damage(sp, op, victim, damage, why)
  struct player *sp;		/* player that inflicted the damage */
  struct player *op;		/* other player that could be responsible */
  struct player *victim;	/* which ship to victimize */
  int damage;			/* how much damage, should be positive */
  int why;			/* the source of the damage */
{
  if (damage < 0)
  {				/* should not be called with - damage */
    fprintf(stderr, "Attempt to inflict negative damage\n");
    return 0;
  }

  if (victim->p_flags & PFSHIELD)
  {				/* shields up? */
    int penetrated;
    /*
     * if the server is configured for damage penetration then the shields
     * will not absorb all the damage
     */
    penetrated = damage * configvals->penetration
      * (victim->p_ship.s_maxshield - victim->p_shield)
      / (victim->p_ship.s_maxshield);
    damage -= penetrated;

    victim->p_shield -= damage;	/* damage shields */
    if (victim->p_shield < 0)
    {				/* we punched through the shield */
      damage = -victim->p_shield;	/* excess damage will apply to hull */
      victim->p_shield = 0;	/* and zero the shields */
    }
    else
      damage = 0;
    damage += penetrated;	/* some of the damage got through the shields */
  }
  if (damage > 0)
  {
    victim->p_damage += damage;	/* all damage to hull */
    if (configvals->erosion > 0)
    {
      float chance = damage * configvals->erosion;
      while (chance >= 0.5)
      {				/* no matter how much you suffer there's a
				 * chance you can avoid permanent damage */
	if (lrand48() & 0x40)
	{
	  victim->p_ship.s_maxdamage--;	/* apply damage to maximum */
	  victim->p_damage--;	/* instead of current */
	}
	chance -= 0.5;
      }
      if (drand48() < chance)
      {
	victim->p_ship.s_maxdamage--;	/* apply damage to maximum */
	victim->p_damage--;	/* instead of current */
      }
    }
  }

  if (victim->p_damage >= victim->p_ship.s_maxdamage)
  {				/* victim dead? */
    cause_kaboom(victim);	/* make him explode */
    if (sp)
    {
      victim->p_whydead = why;
      if (!friendly(sp, victim)
	  && sp != victim	/* hozers were getting credit for killing
				 * themselves because they were at war with
	      their own race */ )
      {
	/* if a hostile player was responsible */
	tlog_plkill(victim, sp, op);
	if (victim->p_ship.s_type == PATROL)
	  sp->p_kills += .5 + ((float) victim->p_armies + victim->p_kills) / 10.0;
	else
	  sp->p_kills += 1.0 + ((float) victim->p_armies + victim->p_kills) / 10.0;
	killerstats(sp->p_no, victim);	/* adjust everyones stats */
	checkmaxkills(sp->p_no);
	killmess(victim, sp);
	victim->p_whodead = sp->p_no;
      }
      else if (op && !friendly(op, victim) && op != victim)
      {
	/* the primary assassin was friendly, check auxiliary killer */
	tlog_plkill(victim, op, sp);

	if (victim->p_ship.s_type == PATROL)
	  op->p_kills += .5 + ((float) victim->p_armies + victim->p_kills) / 10.0;
	else
	  op->p_kills += 1.0 + ((float) victim->p_armies + victim->p_kills) / 10.0;
	killerstats(op->p_no, victim);	/* adjust everyones stats */
	checkmaxkills(op->p_no);
	killmess(victim, op);
	victim->p_whodead = op->p_no;
      }
      else
      {
	/*
	 * give no credit since it was friendly and the auxiliary murderer
	 * was friendly too
	 */
	tlog_plkill(victim, sp, (struct player *) 0);
	killmess(victim, sp);
	victim->p_whodead = sp->p_no;
      }
    }
    loserstats(victim->p_no);
    return 1;			/* victim died */
  }
  else
    return 0;			/* victim lived */
}

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


struct ranksorter
{
  int pno;
  int rank;
  float di;
  int teammates;
};

static struct ranksorter admirals[MAXTEAM];

int
enemy_admiral(tno)
  int tno;
{
  int teammates;
  int pno;
  int i;

  for (i = 0; i < MAXTEAM; i++)
  {
    admirals[i].teammates = 0;
    admirals[i].rank = -1;
  }

  for (i = 0; i < MAXPLAYER; i++)
  {
    int team;
    struct player *pl;
    pl = &players[i];

    if (pl->p_status == PFREE ||
	pl->p_team == tno)
      continue;

    team = pl->p_team;
    admirals[team].teammates++;

    if (pl->p_stats.st_rank < admirals[team].rank)
      continue;
    if (pl->p_stats.st_rank > admirals[team].rank ||
	pl->p_stats.st_di > admirals[team].di)
    {
      admirals[team].pno = i;
      admirals[team].rank = pl->p_stats.st_rank;
      admirals[team].di = pl->p_stats.st_di;
    }
  }

  teammates = -1;
  pno = 0;
  for (i = 0; i < MAXTEAM; i++)
  {
    if (admirals[i].teammates > teammates)
    {
      pno = admirals[i].pno;
      teammates = admirals[i].teammates;
    }
  }
  return pno;
}


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