
#import "XoxWars.h"
#import "BackView.h"
#import "Ship.h"
#import "ActorMgr.h"
#import "SoundMgr.h"
#import "XWBullet.h"
#import "XWShip.h"
#import "XWSpaceGen.h"
#import "XWSun.h"
#ifdef METEORS
#import "XWMeteor.h"
#endif
#import "GOLetter.h"
#import "Explosion.h"
#import "Thinker.h"

int xx_xwbullet, xx_xwship, xx_xwspace;
float xw_gravity;
int xw_bulletSpeed, xw_bounce, xw_meteors, xw_nastyShots;
int xw_bulletMass;
float xx_difficulty;

#import "CrazyMander.h"
#import "TrackMander.h"

@implementation XoxWars

- newGame
{
  dartKills = clawKills = 0;
  [[clawKillsText setIntValue:clawKills] display];
  [[dartKillsText setIntValue:dartKills] display];
  return self;
}

// invoked only by the actor manager
- _createLevel:(int)lev
{
  NXRect r;
  char title[40];

  goToNextLevel = explosionCount = goodBullets = badBullets = 0;

  goodShip = [actorMgr newActor:xx_xwship for:self tag:GOOD];
  badShip = [actorMgr newActor:xx_xwship for:self tag:EVIL];

  space = [actorMgr newActor:xx_xwspace  for:self tag:0];
  if (sun) sun = [actorMgr newActor:(int)[XWSun class] for:self tag:0];
#ifdef METEORS
  int i;
  for (i=0; i<xw_meteors; i++)
    [actorMgr newActor:(int)[XWMeteor class] for:self tag:0];
#endif
  [mainView getBounds:&r];
  [space newSize:&r.size];

  sprintf(title,"Xox Wars");
  [[mainView window] setTitle:title];

  if (!commanders) {
    commanders = [[List alloc] init];
    playerClasses = [[List alloc] init];
    [commanders addObject:[[[
      [Commander alloc] init] addShip:goodShip] addTarget:badShip]];
    [commanders addObject:[[[
      [Commander alloc] init] addShip:badShip] addTarget:goodShip]];
    [self initPlayers];
  }
  return self;
}

-free 
{
  [[commanders freeObjects] free];
  [playerClasses free];
  return [super free];
}

- initPlayers
{
  id buttons = [[playerBox contentView] subviews];
  int n = [buttons count];

  [self loadPlayers];

  while (n--) {
    static char title[20];
    PopUpList* popup = [[buttons objectAt:n] target];
    sprintf(title, "Player %d", n);
    [popup setTitle:title];
    [self changePlayer:[popup itemList]];
  }
  return self;
}

- loadPlayers
{
  [playerClasses addObject:[Commander class]];
  [playerClasses addObject:[CrazyMander class]];
  [playerClasses addObject:[TrackMander class]];
  return [self setPlayers];
}

- setPlayers
{
  List* buttons = [[playerBox contentView] subviews];
  int count = [playerClasses count];
  int i;

  int n = [buttons count];
  while (n--) {
    PopUpList* popup = [[buttons objectAt:n] target];
    for (i=0; i<count; ++i) {
      Class pc = [playerClasses objectAt:i];
      Cell* newCell = [popup addItem:[pc name]];
      [newCell setTag:i];
      [[newCell setTarget:self] setAction:@selector(changePlayer:)];
    }
  }
  return self;
}

- changePlayer:sender
{
  const char* title = [[sender window] title];
  const char* ptr = strchr(title, ' ');
  int np = atoi(++ptr);
  Class nc = [playerClasses objectAt:[[sender selectedCell] tag]];
  id newComm = [[nc alloc] init] ;
  id oldComm = [commanders replaceObjectAt:np with:newComm];
  [[oldComm transferTo:newComm] free];
  return self;
}

- infoView
{
  return infoView;
}

- didActivate:(Actor *)theActor
{
  if(theActor->actorType == xx_explosion)
    explosionCount++;
  else if(theActor->actorType == xx_xwbullet)
  {
    (theActor->theta == 0.) ? goodBullets++ : badBullets++;
  }
  else
  {
  }
  return self;
}

- didRetire:(Actor *)theActor
{
  if(theActor->actorType == xx_xwship)
  {
    if (theActor->alliance == GOOD)
    {
      [[clawKillsText setIntValue:++clawKills] display];
    }
    else
    {
      [[dartKillsText setIntValue:++dartKills] display];
    }

    if (dartKills >= 10 || clawKills >= 10)
    {
      if ([actorMgr gameStatus] != GAME_DYING)
        [GOLetter gameOver:self];
      [actorMgr setGameStatus: GAME_DYING];
      goToNextLevel = 0;
    }
    else goToNextLevel = 1;
  }
  else if(theActor->actorType == xx_explosion)
  {
    if ((--explosionCount <= 0) && goToNextLevel)
    {
      [actorMgr requestLevel: 1];
    }
  }
  else if(theActor->actorType == xx_xwbullet)
  {
    (theActor->theta == 0.) ? goodBullets-- : badBullets--;
  }
  else
  {
  }

  return self;
}



- keyDown:(NXEvent *)theEvent
{
  if (theEvent->data.key.repeat > 0) return self;

  switch(theEvent->data.key.charCode)
  {
    case 'z':    // rotate left
      [goodShip setTurning:LEFT down:YES time:theEvent->time];
      break;
    case 'x':    // rotate right
      [goodShip setTurning:RIGHT down:YES time:theEvent->time];
      break;
    case '.':    // fire
      [goodShip fire];
      break;
    case ',':    // thrust
      [goodShip setThrusting:YES time:theEvent->time];
      break;
    case ' ':    // shields
      [goodShip setShields:1];
      break;

    case '1':    // rotate left
      [badShip setTurning:LEFT down:YES time:theEvent->time];
      break;
    case '2':    // rotate right
      [badShip setTurning:RIGHT down:YES time:theEvent->time];
      break;
    case '9':    // fire
      [badShip fire];
      break;
    case '6':    // thrust
      [badShip setThrusting:YES time:theEvent->time];
      break;
    case '\003':    // shields
      [badShip setShields:1];
      break;
  }
  return self;
}

- keyUp:(NXEvent *)theEvent
{
  switch(theEvent->data.key.charCode)
  {
    case 'z':    // rotate left
      [goodShip setTurning:LEFT down:NO time:theEvent->time];
      break;
    case 'x':    // rotate right
      [goodShip setTurning:RIGHT down:NO time:theEvent->time];
      break;
    case ',':    // thrust
      [goodShip setThrusting:NO time:theEvent->time];
      break;
    case ' ':    // shields
      [goodShip setShields:0];
      break;

    case '1':    // rotate left
      [badShip setTurning:LEFT down:NO time:theEvent->time];
      break;
    case '2':    // rotate right
      [badShip setTurning:RIGHT down:NO time:theEvent->time];
      break;
    case '6':    // thrust
      [badShip setThrusting:NO time:theEvent->time];
      break;
    case '\003':    // shields
      [badShip setShields:0];
      break;
  }
  return self;
}

- scenarioSelected
{
  goodShip = [actorMgr newActor:xx_xwship for:self tag:GOOD];
  badShip = [actorMgr newActor:xx_xwship for:self tag:EVIL];
  [goodShip scenarioSelected];
  [badShip scenarioSelected];
  return self; 
}

- scenarioDeselected
{  return self; }

- newSize:(NXSize *)s
{
  [space newSize:s];
  return self;
}

- (COLLISION_PARADIGM)collisionParadigm
{
  return GOOD_V_EVIL;
}

- init
{
  char path[256];
  id cv, subviews;

  [super init];

  if ([[NXBundle bundleForClass:[self class]]
    getPath:path
    forResource:"xoxwars"
    ofType:"nib"])
  {
    [NXApp loadNibFile:path
      owner:self
      withNames:NO
      fromZone:[self zone]];

    cv = [uselessBox contentView];
    subviews = [cv subviews];
    while ([subviews count] > 0)
      [scoreView addSubview:[subviews objectAt:0]];
    
  }

  xx_xwbullet = (int)[XWBullet class];
  xx_xwship = (int)[XWShip class];
  xx_xwspace = (int)[XWSpaceGen class];

  [self adjustSettings:self];

  [[NXApp delegate] addImageResource:"explosionM" for: [Explosion class]];
  [[NXApp delegate] addImageResource:"explosionS" for: [Explosion class]];
  [[NXApp delegate] addSoundResource:  SHIPSND];

  return self;
}

- tile
{
  NXRect r;
  float f;

  [gcontentView getBounds:&r];
  r.size.width -= 60;
  f = r.size.width;
  [abackView setFrame:&r];
  [gcontentView getBounds:&r];
  r.size.width = 60;
  r.origin.x = f;
  [scoreView setFrame:&r];
  [gcontentView addSubview:abackView];
  [gcontentView addSubview:scoreView];
  return abackView;
}

//
// Scenario-specific actions

- (int) bullets : (int) type
{
  return (type == GOOD) ? goodBullets : badBullets;
}

- (BOOL) hasBullets : (int) type
{
  return ([self bullets:type] < 5);
}

- adjustSettings:sender
{
  switch([gravityMatrix selectedRow])
  {
    case 0: xw_gravity = 30000; break;
    case 1: xw_gravity = 0; break;
    case 2: xw_gravity = -30000; break;
    case 3: xw_gravity = -66000; break;
  }
  switch([bulletMatrix selectedRow])
  {
    case 0: xw_bulletSpeed = 13; break;
    case 1: xw_bulletSpeed = 22; break;
    case 2: xw_bulletSpeed = 34; break;
  }

  if ([[settingsMatrix cellAt:0:0] state])
  {  // sun enabled
    if (!sun) sun = [actorMgr newActor:(int)[XWSun class] for:self tag:0]; 
  }
  else
  {
    if (sun) [actorMgr destroyActor:sun];
    sun = nil;
  }

  xw_bounce = ([[settingsMatrix cellAt:1:0] state]);
  xw_nastyShots = ([[settingsMatrix cellAt:2:0] state]);
  xw_bulletMass = ([[settingsMatrix cellAt:3:0] state]);

#ifdef METEORS
  xw_meteors = ([meteorsSlider intValue]);
#endif
  xx_difficulty = [difficultySlider floatValue];

  return self;
}

- oneStep
{
  static int phase = 0;
  int STEP = 20.0 * (1.0-xx_difficulty) + 1.0;
  [commanders makeObjectsPerform:@selector(reset)];
  if ((phase++ % STEP) == 0)
    [commanders makeObjectsPerform:@selector(oneStep:) with:self];
  return self;
}

@end


@implementation ActorMgr(XoxWarsAdditions)
- listFor:(ALLIANCE)alliance
{
    switch((int)alliance)
    {
      case GOOD:
        return goodList;
      case EVIL:
        return badList;
      case DESTROYALL:
        return destroyAllList;
      // these will be collided twice against destroyall actors
      case GOODNBAD:
        return nil;
    }
  return nil;
}

@end



