/* timeouts.cc 1.12 95/12/28 23:24:14 */


// xspacewarp by Greg Walker (gow@math.orst.edu)

// This is free software. Non-profit redistribution and/or modification
// is allowed and welcome.


// all the Intrinsics timeouts are in this file.


#include "c_combatant.hh"
#include "c_sector.hh"
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <stdlib.h>		// rand()
#include <time.h>		// seed for rand()
#include "common.hh"
#include "params.hh"
#include "globals.hh"
#include "c_endever.hh"

extern void clear_echo(void);
extern void echo(const char *str, int len);


// flash "Federation base at (3,1) is under attack!" sort of thing

void flash_to(XtPointer client_data, XtIntervalId *id)
{
  static enum {OFF, ON} timerstate = OFF;
  int ur, uc;

  // if timer already in progress, ignore new requests for flashing messages.

  if (id == NULL && timerstate == ON)
     return;

  // if game paused then just refresh the timer

  if (gamestate.input == PAUSE)
  {
    (void) XtAppAddTimeOut(app_context, PAUSEINT,
			   (XtTimerCallbackProc) flash_to, client_data);
    return;
  }

  // stop flashing if base no longer under attack or endever is present

  ur = Sector::attack_loc.urow;
  uc = Sector::attack_loc.ucol;
  if (universe[ur-1][uc-1].getbasepop() != 0 &&	   // base still alive
      (universe[ur-1][uc-1].getjovpop() == 0 ||     // jovs have left
       universe[ur-1][uc-1].getendvpop() > 0))	   // endever arrived
  {
    timerstate = OFF;
    clear_echo();
    return;
  }
  else if (universe[ur-1][uc-1].getbasepop() == 0)   // base destroyed
  {
    timerstate = OFF;
    return;
  }

  if (gamestate.input != ACTION) // do not flash mesg if trying to input stuff
  {
    timerstate = OFF;
    return;
  }
  
  if (client_data)		// flash
  {
    clear_echo();
    echo(Sector::attack_msg, XtNumber(Sector::attack_msg)-1);
    (void) XtAppAddTimeOut(app_context, FLASHINT,
			   (XtTimerCallbackProc) flash_to, (XtPointer)0);
  }
  else				// unflash
  {
    clear_echo();
    (void) XtAppAddTimeOut(app_context, UNFLASHINT,
			   (XtTimerCallbackProc) flash_to, (XtPointer)1);
  }

  timerstate = ON;
}


// timeout for controlling rate of endever movement

void move_to(XtPointer client_data, XtIntervalId *id)
{
  endever.setnomove(false);
}
  

void faser_to(XtPointer client_data, XtIntervalId *id)
{
  Combatant *src = (Combatant *) client_data; // source of faser shot

  // if game paused then just refresh the timer

  if (gamestate.input == PAUSE)
  {
    (void) XtAppAddTimeOut(app_context, PAUSEINT,
			   (XtTimerCallbackProc) faser_to, client_data);
    return;
  }
    
  src->moveshot(FASERLEN, FASERMARGIN, FASERINT,
		faserGC, faserGC_rv, (XtTimerCallbackProc)faser_to);
}


void torpedo_to(XtPointer client_data, XtIntervalId *id)
{
  Combatant *src = (Combatant *) client_data; // source of torpedo shot

  // if game paused then just refresh the timer

  if (gamestate.input == PAUSE)
  {
    (void) XtAppAddTimeOut(app_context, PAUSEINT,
			   (XtTimerCallbackProc) torpedo_to, client_data);
    return;
  }

  src->moveshot(TORPLEN, TORPMARGIN, TORPINT,
		torpGC, torpGC_rv, (XtTimerCallbackProc)torpedo_to);
}


void explosion_to(XtPointer client_data, XtIntervalId *id)
{
  Ship *src = (Ship *) client_data; // source of explosion

  // if game paused then just refresh the timer

  if (gamestate.input == PAUSE)
  {
    (void) XtAppAddTimeOut(app_context, PAUSEINT,
			   (XtTimerCallbackProc) explosion_to, client_data);
    return;
  }

  src->expand();
}


// ship re-energizing timeout

void energize_to(XtPointer client_data, XtIntervalId *id)
{
  int i, j;

  if (gamestate.visual == WIN || gamestate.visual == LOSE)
     return;

  // if game paused then just refresh the timer

  if (gamestate.input == PAUSE)
  {
    (void) XtAppAddTimeOut(app_context, PAUSEINT,
			   (XtTimerCallbackProc) energize_to, client_data);
    return;
  }

  for (i = 0; i < UROWS; i++)
  {
     for (j = 0; j < UCOLS; j++)
     {
       universe[i][j].energize();
     }
   }

  (void) XtAppAddTimeOut(app_context, ERGINT,
			 (XtTimerCallbackProc) energize_to, NULL);
}


// timeout for making jovians fight back.

void jovian_to(XtPointer client_data, XtIntervalId *id)
{
  int i, j;

  if (gamestate.visual == WIN || gamestate.visual == LOSE)
     return;		// so jovs stop fighting when game over

  // if game paused then just refresh the timer

  if (gamestate.input == PAUSE)
  {
    (void) XtAppAddTimeOut(app_context, PAUSEINT,
			   (XtTimerCallbackProc) jovian_to, client_data);
    return;
  }

  Jovian::setleapflag(false);	// At most one jov leap per jovian_to() call.
  for (i = 0; i < UROWS; i++)
  {
     for (j = 0; j < UCOLS; j++)
     {
       universe[i][j].jovian();
     }
   }

  (void) XtAppAddTimeOut(app_context, JOVINT,
			 (XtTimerCallbackProc) jovian_to, NULL);
}


// timeout for changing the rand() seed at random intervals

void reseed_to(XtPointer client_data, XtIntervalId *id)
{
  long seedint;

  srand(time(0));

  seedint = SEEDINT + (rand() % (2*SEEDINTRANGE)) - SEEDINTRANGE;

  (void) XtAppAddTimeOut(app_context, seedint,
			 (XtTimerCallbackProc) reseed_to, NULL);
}


// end
