#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#ifdef USE_X11
# include <unistd.h>
#else
# ifdef MS_WIN
int sleep(int n)
{
  return 0;
}
# endif
#endif

#include "defs.h"
#include "world.h"
#include "player.h"
#include "trans.h"
#include "move.h"
#include "units.h"
#include "graph.h"
#include "keyboard.h"
#include "MsgQ.h"
#include "city.h"
#include "mapdisplay.h"
#include "citydisplay.h"
#include "misc.h"
#include "rules.h"
#include "savefile.h"

// colors for players
static char *color_tbl[] = {
  "#e8e8e8e8e8e8", "#0c0ce0e0e8e8",
  "#ad00ff002f00", "#e8e8e8e8e8e8",
  "NavyBlue", "#e8e8e8e8e8e8",
  "DarkGray", "#e8e8e0e0e8e8" };

void NetFail(char *str)
{
  printf("Network failure %s\n", str);
  exit(1);
}

void HandleSelect(char *choice, Player *player)
{
  player->SelectEvent(choice);
}

void ShowMesg(List<charp>& m) {
  char *c = m.RemoveHead();
  screen->DispMessageBox(c, NULL, NULL);
  delete c;
}

Player::Player(char *Name, int Id)
{
  name = Name;
  sprintf(color1Str, "x c %s", color_tbl[Id*2]);
  sprintf(color2Str, "x c %s", color_tbl[Id*2+1]);
  id = Id;
  cityPic = 0;
  currUnit = NULL;
  doneMoving = 0;
  govt = DESPOT;
  capital = NULL;
  tax = 50;
  luxuries = 0;
  money = 0;
  initiatedSave = 0;

  treaties = new TreatyStatus[numPlayers];

  moveQ = new MsgQ; // FIXME: should be somewhere else

  if (!savedGame) {
    InitialScience(this);
    for (int i = 0; i < numPlayers;i++) treaties[i] = NEUTRAL;
    embassies = 0;
  }

  researching = NOSCIENCE;
  diplomacyId = 0;

  scienceAcc = 0;
  needScience = 10;
}

Player::~Player()
{
  delete name;
  delete treaties;
}

char *Player::title()
{
  switch (govt) {
  case ANARCHY:
    return "Mr.";
  case DESPOT:
    return "Chief";
  case MONARCH:
    return "King";
  case REPUBLIC:
    return "President";
  case DEMOCRACY:
    return "Prime Minister";
  }
  return "Generic Ruler"; // should never be used
}

// create the first settler for the player
void Player::Setup()
{
  // find a nice random place on the map which has at least a
  // 5x5 block of land around it
  Debug('i', "Trying to setup\n");
  MapCoord coord;
  while (1) {
    while (1) {
      coord.x = random() % world->MaxX();
      coord.y = random() % world->MaxY();
      int goodspot = 1;
      for (int x1 = -2; x1 <= 2; ++x1)
	for (int y1 = -2; y1 <= 2; ++y1)
	  if (world->Terrain(MapCoord(coord.x+x1, coord.y+y1)) == WATER)
	    { goodspot = 0; break; }
      if (goodspot) break;
    }
    if (!world->NextToOpponent(id, coord)) break;
  }
  // Unit constructor automatically adds it to the world and to the
  // list of units for the player
  Debug('i', "found spot %d %d\n", coord.x, coord.y);
  Unit *settler = NewUnit(SETTLER, id, trans->New(), 0, 0, coord);

  if (moveQ == NULL) {
    Debug('m', "New failed in Player::Setup");
    abort();
  }
  *moveQ << PieceMove(settler->id, PIECE_CREATE, coord, SETTLER,
		      0, 0);
}

// send all the moves across
void Player::SendMoves(MsgQ *q)
{
  *q << "moves";
  Debug('p', "sending moves\n");
  *q << *moveQ;
}

// show the moves made
void Player::ShowMoves(MsgQ *q, MsgQ *outQ, int MoverId)
{
  City *city;
  Unit *unit;
  char *name;
  BuildObject build;
  Science sci;

  int fortStat;
  while (q->Count() > 0) {
    Msg m;
    *q >> m;
    PieceMove *move = (PieceMove*)m.buf;
    move->HostOrder();
    MapCoord coord(move->x, move->y);
    switch (move->oper) {
    case PIECE_CREATE:
      unit = NewUnit(BuildObject(move->type), MoverId, move->id, move->veteran,
		     move->city, coord);
      Debug('u', "Created new unit type %d, id %ld, at %d %d\n", move->type,
	    unit->id, coord.x, coord.y);
      break;
    case PIECE_MOVE:
      // moving into a city automatically captures it
      // if a city is captured and it is the city for the player whose
      // civ this is, MoveUnit will tell the city to send its info across
      // it must tell the server to send the message to the owner of the
      // piece only
      MoveUnit(trans->TransUnit(move->id), coord, 0.0, outQ);
      sleep(1);
      break;
    case PIECE_DIE:
      delete trans->TransUnit(move->id);
      break;
    case CITY_CREATE:
      *q >> name;
      city = new City(name, move->id, coord, MoverId);
      break;
    case CITY_DIE:
      delete trans->TransCity(move->id);
      break;
    case CITY_SIZE:
      city = trans->TransCity(move->id);
      city->size = move->x;
      city->DrawIfVisible();
      break;
    case CITY_WALL:
      city = trans->TransCity(move->id);
      if (move->x) {
        if (!city->HasBuilding(CITYWALLS))
          city->AddBuilding(CITYWALLS);
      } else
	city->DeleteBuilding(CITYWALLS);

      city->DrawIfVisible();
      break;
    case SDI_DEFENSE:
      city = trans->TransCity(move->id);
      if (move->x) {
        if (!city->HasBuilding(SDIDEFENSE))
          city->AddBuilding(SDIDEFENSE);
      } else
	city->DeleteBuilding(SDIDEFENSE);

    case CITY_WORK_MAP:
      city = trans->TransCity(move->id);
      city->TransWorkMap(q);
      break;
    case UNIT_UPDATE:
      unit = trans->TransUnit(move->id);
      fortStat = unit->Fortified();
      if (move->x)
	unit->Fortify();
      else
	unit->UnFortify();
      if (move->y) unit->MakeVeteran();
      if (fortStat != unit->Fortified())
	unit->DrawIfVisible();
      break;
    case DISCOVERY: // some player has discovered something
	*q >> sci;
	players[move->id]->Discover(sci);
	break;
    case BUILDWONDER: // someone else has built a wonder
      {
	*q >> build;
	Player *p = players[move->id];
	ObjectData *obj = &(Objects[build]);
	obj->built = 1;
	p->InsertWonder(build);
	AddMessage(messages, "%s builds %s\n",p->name, obj->name);
	break;
      }
    case DESTROY_WONDER:
      break;
    case CAPTURE_WONDER:
      break;
    case DECLARE_WAR:
	players[move->x]->treaties[move->id] = AT_WAR;
	players[move->id]->treaties[move->x] = AT_WAR;
	if (move->x == id)
	  AddMessage(messages, "%s declares war!\n",players[move->id]->name);
	break;
    case OFFER_TREATY:
	if (move->x == playerId) {
	  if ((govt >= REPUBLIC) || players[move->x]->HasWonder(UNITEDNATIONS) || (players[move->x]->HasWonder(GREATWALL) && !Objects[GREATWALL].isObsolete))
	    { // automatic acception
	      *moveQ << PieceMove(id,ACCEPT_TREATY,move->id,0);
	      if (govt >= REPUBLIC)
		AddMessage(messages,"Senate signs peace treaty with %s",players[move->id]->name);
	      else
		AddMessage(messages,"Peace Treaty signed with %s",players[move->id]->name);
	      players[move->id]->treaties[move->x] = TREATY;
	      players[move->x]->treaties[move->id] = TREATY;
	    } else {
	      List<charp> options;
	      options.Insert("Accept");
	      options.Insert("Refuse");
	      char title[40];
	      sprintf(title,"%s offers peace treaty",players[move->id]->name);
	      selecting = TREATY_OFFER;
	      screen->CreateChoiceFrame(title,options, HandleSelect, this);
	      options.Delete();
	    }
	}
	break;
    case ACCEPT_TREATY:
	players[move->id]->treaties[move->x]= TREATY;
	players[move->x]->treaties[move->id] = TREATY;
	if (id == move->x)
	  AddMessage(messages, "%s accepts treaty offer from %s\n",players[move->id]->name,players[move->x]->name);
	break;
    case REFUSE_TREATY:
	if (playerId == move->x)
	  AddMessage(messages, "%s refuses treaty offer from %s\n",players[move->id]->name,players[move->x]->name);
	break;
    case TERRAIN_CHANGE:
      world->Set(coord, move->type);
      if (world->Visible(coord) && MainMap->Visible(coord))
	world->Draw(MainMap, coord, 1, 1);
      break;
    }
    delete move;
  }
  while (messages)
    ShowMesg(messages);
}

void Player::InitMoveTurn()
{
  Debug('p', "initmoveturn for %d\n", id);
  if (initiatedSave) {
    MsgQ *q = new MsgQ;
    *q << "save_game";
    SendQ(q);
    CreateSaveFile();
    acks_left = numPlayers-1;
    accepts_left = 0;
    MainMap->DisplayMessage("Waiting for save", 0);
  }
  else {
    MsgQ *q = new MsgQ;
    *q << "myturn";
    *q << id;
    SendQ(q);
    if (moveQ == NULL) {
      Debug('m', "New failed in Player::InitMoveTurn");
      abort();
    }
    acks_left = numPlayers-1;
    accepts_left = 0;
    MainMap->DisplayMessage("Your Turn", 0);
    doneMoving = 0;
  }
}

void Player::MoveTurnMesg(MsgQ *q)
{
  char *mesg;
  *q >> mesg;
  if (initiatedSave && playerId == 0 && strcmp(mesg, "done_save") == 0) {
    if (--acks_left <= 0) {
      MsgQ *q1 = new MsgQ;
      *q1 << "commit_suicide"; // tell clients their job's done...
      SendQ(q1);
      exit(0);
    }
  }
  if (strcmp(mesg, "yourturn_ack") == 0) {
    if (--acks_left <= 0) {
      // startup moveturn

      UpdateCities();
      if (researching == NOSCIENCE)
	ChooseScience();
      MainMap->ShowPlayerInfo();

      currUnit = NULL;
      Lister<ulong> unitl = units;
      while (unitl) {
	Unit *ptr = trans->TransUnit(unitl.Elem());
	ptr->numMoves = ptr->Moves(players[playerId]->SeaMoveBonus());
	ptr->CompleteOrder();
	if (currUnit == NULL && ptr->numMoves > 0) currUnit = ptr;
	unitl.Next();
      }
      if (currUnit == NULL)
	MainMap->DisplayMessage("End of Turn, press Enter", 0);
      else /*if (state != IN_SELECT) */ {
	MainMap->ShowPiece(currUnit->coord, currUnit->id);
	MainMap->EnableCursor(currUnit->coord, currUnit->id);
      }
    }
  }
  else if (strcmp(mesg, "got_moves") == 0) {
    // if we took over any cities of this guy there will be more messages
    if (q->Count() > 0)
      GetCapturedCity(q, this);
    if (--acks_left <= 0) {
      currTurn = (currTurn+1) % numPlayers;
      doneMoving = 0;
      InitCityTurn();
    }
  }
  delete mesg;
  delete q;
  return;
}

void Player::Discover(Science sci)
{
  discovered.Insert(sci);
  ::Discover(this,sci); // update obsoleteness rules

  if (sci != SURVIVAL)
    {
      if (id == playerId) {
	// we discovered it!
	
	*moveQ << PieceMove(id, DISCOVERY, 0, 0);
	*moveQ << sci;
	if (sci == researching)
	  researching = NOSCIENCE;
      }
      else {
	// someone else's discovery
    
	if (players[playerId]->HasEmbassy(id))
	  AddMessage(players[playerId]->messages,"%s discovers %s", name,Sciences[sci].name);
	
	if (players[playerId]->HasWonder(GREATLIBRARY) && !Objects[GREATLIBRARY].isObsolete)
	  if (!players[playerId]->HasDiscovered(sci))
	    for (int i = 0;i < numPlayers;i++)
	      if ((i != id) && players[i]->HasDiscovered(sci)) {
		players[playerId]->Discover(sci);
		AddMessage(messages,"%s discovered through the Great Library",Sciences[sci].name);
		if (sci == researching)
		  researching = NOSCIENCE;
		break;
	      }
      }
    }
}

int Player::UnhappyPerUnitAway()
{
  switch(govt) {
  case DEMOCRACY:
    return HasWonder(WOMENSSUFFRAGE) ? 1 : 2;
  case REPUBLIC:
    return HasWonder(WOMENSSUFFRAGE) ? 0 : 1;
  default:
    return 0;
  }
}

void Player::SelectEvent(char *data)
{
  if (state != IN_SELECT) {
    Debug('p', "Warning: Player::SelectEvent called while not IN_SELECT\n");
    return;
  }
  
  if (selecting == SCIENCE) { // selecting science
    Debug('p', "Selected science %s\n", data);
    researching = *sciences.Find(StrKey(data));
    needScience = DiscoverCost(this,researching);
    MainMap->ShowPlayerInfo();
    if (scienceAcc >= needScience && researching != NOSCIENCE) { // should only occur for Darwin's voyage
      scienceAcc -= needScience;
      Discover(researching);
      researching = NOSCIENCE;
      ChooseScience();
    }
  }
  // MarkM added government type:
  else if (selecting == GOVERNMENT_TYPE) {
    if (strcmp(data,"Despotism") == 0) govt = DESPOT;
    else if (strcmp(data,"Monarchy") == 0) govt = MONARCH;
    else if (strcmp(data,"The Republic") == 0) govt = REPUBLIC;
    else if (strcmp(data,"Democracy") == 0) govt = DEMOCRACY;
  }
  else if (selecting == TAX_RATE) {
    sscanf(data, "Tax %d\n", &tax);
    for (Lister<ulong> l = citys; l; l.Next())
      trans->TransCity(l.Elem())->ComputeEcon();
    MainMap->ShowPlayerInfo();
  } 
  // MarkM added luxuries rate:
  else if (selecting == LUXURY_RATE) {
    sscanf(data, "Luxuries %d\n", &luxuries);
    for (Lister<ulong> l = citys; l; l.Next())
        trans->TransCity(l.Elem())->ComputeEcon();
    MainMap->ShowPlayerInfo();
  }
  // MarkM added revolution choice:
  else if (selecting == REVOLUTION) {
    if (strncmp(data,"Yes",3) == 0) govt = ANARCHY;
  }
  else if (selecting == CARAVAN_MOVE) {
    if (!strcmp(data,"Continue")) {
      ; // do nothing
    }
    else {
      if (!strcmp(data,"Build Wonder"))
	trans->TransCity(world->WhichCity(currUnit->coord))->accProd += 50;
      else if (!strcmp(data,"Establish Trade Route"))
	; // FIXME unimplemented
      *moveQ << PieceMove(currUnit->id,PIECE_DIE,0,0);
      delete currUnit;
      currUnit = NULL;
    }
  } else if (selecting == DIPLOMAT_MOVE) {
    if (!strcmp(data,"Say Hi"))
      ; // send a message?
    else if (!strcmp(data, "Establish Embassy"))
      MakeEmbassy(trans->TransCity(world->WhichCity(currUnit->coord))->ownerId);
    else if (!strcmp(data,"Demand tribute"))
      ; // FIXME unimplemented
    else if (!strcmp(data,"Offer Peace Treaty"))
      *moveQ << PieceMove(currUnit->ownerId,OFFER_TREATY,trans->TransCity(world->WhichCity(currUnit->coord))->ownerId,0);
    *moveQ << PieceMove(currUnit->id,PIECE_DIE,0,0);
    delete currUnit;
    currUnit = NULL;
  }
  else if (selecting == TREATY_OFFER) {
    if (!strcmp(data,"Refuse"))
      *moveQ << PieceMove(id,REFUSE_TREATY,diplomacyId,0);
    else if (!strcmp(data,"Accept")) {
      *moveQ << PieceMove(id,ACCEPT_TREATY,diplomacyId,0);
      treaties[diplomacyId] = TREATY;
      players[diplomacyId]->treaties[id] = TREATY;
    }
  }
  else if (selecting == WAR_DECL) {
    if (!strcmp(data,"Declare War"))
      {
	treaties[diplomacyId] = AT_WAR;
	players[diplomacyId]->treaties[id] = AT_WAR;
	*moveQ << PieceMove(id,DECLARE_WAR,diplomacyId,0);
      }
  }
}

void
Player::WakeUnit(Unit *ptr)
{
  if (ptr->currOrder == 's') {
    ptr->currOrder = ' ';
    ptr->numMoves = ptr->Moves(players[playerId]->SeaMoveBonus());
  }
  else if (ptr->currOrder == 'f') {
    ptr->currOrder = ' ';
    ptr->UnFortify();
    ptr->numMoves = ptr->Moves(players[playerId]->SeaMoveBonus());
    // tell other players
    *moveQ << PieceMove(ptr->id, UNIT_UPDATE, 0,
			ptr->Veteran() != 0 ? 1 : 0);
  }
}

void
Player::WakeUnits(MapCoord c)
{
  Unit *found = NULL;
  for (Lister<ulong> l = world->Units(c); l; l.Next()) {
    Unit *ptr = trans->TransUnit(l.Elem());
    if ((ptr->currOrder == 's') || (ptr->currOrder == 'f')) {
      WakeUnit(ptr);
      found = ptr;
    }
    if (ptr->carrying) {
      for (Lister<ulong> l2 = ptr->carrying;l2;l2.Next()) {
	Unit* ptr2 = trans->TransUnit(l2.Elem());
	if ((ptr2->currOrder == 's') || (ptr2->currOrder == 'f')) {
	  WakeUnit(ptr2);
	  found = ptr2;
	}
      }
    }
  }
  if ((currUnit == NULL || currUnit->numMoves <= 0) && found != NULL)
    currUnit = found;
}

void Player::MoveCurrUnit(int key)
{
  MapCoord newCoord = currUnit->coord;
  if (newCoord.move(key)) {
    int terrain = world->Terrain(newCoord);
    
    if (currUnit->CanMoveOn(terrain, newCoord)) {
      City *destCity = trans->TransCity(world->WhichCity(newCoord));
      if (world->OpponentPresent(playerId,newCoord) ||
	  (destCity == NULL ?  0 : destCity->ownerId != id))
	// this is an attack move
	AttackMove(destCity,newCoord);
      else // non-attacking move
	NonAttackMove(destCity,newCoord);
      sleep(1);
    }
    if (currUnit != NULL && currUnit->numMoves <= 0) {
      currUnit->EndTurn();
      NextUnit();
    }
  }
}

void
Player::UnitOrders(int key)
{
  if (currUnit != NULL && !currUnit->Order(key)) {
    Debug('p', "Killing unit %d\n", currUnit->id);
    delete currUnit;
    currUnit = NULL;
  }
}

void
Player::CheckCurrUnit() 
{
  // need to work with cursor
  if (currUnit == NULL || currUnit->numMoves <= 0) {
    if (currUnit != NULL)
      currUnit->EndTurn();
    Lister<ulong> unitl = units;
    
    while (unitl &&
	   (currUnit = trans->TransUnit(unitl.Elem()))->numMoves <= 0)
      unitl.Next();
  }
  if (currUnit == NULL || currUnit->numMoves <= 0) {
    // move turn is done
    currUnit = NULL;
    MainMap->DisplayMessage("Waiting for Acknowledgement", 0);
    MsgQ *q = new MsgQ;
    *q << "turn_done";
    *q << id;
    SendMoves(q);
    SendQ(q);
    acks_left = numPlayers-1;
    accepts_left = 0;
    doneMoving = 1;
  }
}

void
Player::NextUnit()
{
  Lister<ulong> unitl = units;
  while (unitl && unitl.Elem() != currUnit->id) unitl.Next();
  if (unitl) unitl.Next();
  currUnit = NULL;
  while (unitl &&
	 (currUnit = trans->TransUnit(unitl.Elem()))->numMoves <= 0)
    unitl.Next();
}

void
Player::AttackMove(City *destCity, MapCoord newCoord)
{

  // special options for caravans and diplomats
  if (destCity != NULL) {
    if (currUnit->type == DIPLOMAT) {
      List<charp> options;
      if (treaties[destCity->ownerId] == AT_WAR)
	options.Insert("Offer Peace Treaty");
      // else if (govt < REPUBLIC)
      //  options.Insert("Demand Tribute");
      if (!HasEmbassy(destCity->ownerId))
	options.Insert("Establish Embassy");
      options.Insert("Say Hi");
      selecting = DIPLOMAT_MOVE;
      screen->CreateChoiceFrame("Diplomat:",options, HandleSelect, this); 
      options.Delete();
      *moveQ << PieceMove(currUnit->id,PIECE_DIE,0,0);
      delete currUnit;
      return;
    }
    else if (currUnit->type == CARAVAN) {
      List<charp> options;
      options.Insert("Continue");
      // options.Insert("Establish Trade Route");
      if ((destCity->ownerId == currUnit->ownerId) && Objects[destCity->building].IsWonder())
	options.Insert("Build wonder");
      selecting = CARAVAN_MOVE;
      screen->CreateChoiceFrame("Caravan:",options, HandleSelect, this);
    }
  }

  Lister<ulong> unitsl = world->Units(newCoord);
  int ownerId = (destCity == NULL ? trans->TransUnit(unitsl.Elem())->ownerId : destCity->ownerId);
  if (CanAttack(ownerId)) {
    // see if the unit can attack an enemy unit
    int canAttack = 0;
    if (unitsl) {
      Unit *ptr;
      while (unitsl && !canAttack) {
	ptr = trans->TransUnit(unitsl.Elem());
	if (ptr->ownerId != playerId && currUnit->CanAttack(ptr->Type()))
	  canAttack = 1;
	unitsl.Next();
      }
    }
    else
      canAttack = !AirUnit(currUnit->type) && !SeaUnit(currUnit->type); // attacking empty city
    
    if (canAttack) {
      if (!MoveUnit(currUnit, newCoord, 1.0, NULL))
	currUnit = NULL;
    }
  }
}

void
Player::NonAttackMove(City */*destCity*/, MapCoord newCoord)
{
  // only diplomat and caravan can move in opponent zone of control
  if ((currUnit->type!=DIPLOMAT) && (currUnit->type!=CARAVAN)
      && (world->NextToOpponent(playerId,currUnit->coord)
	   && world->NextToOpponent(playerId,newCoord)))
    return;

  int terrain = world->Terrain(newCoord);
  double cost = currUnit->MoveCost(terrain, currUnit->numMoves, newCoord);
  if (cost < 0)
    currUnit->numMoves = 0;
  else {
    if (world->Working(newCoord)) {
      int ownerId = trans->TransCity(world->Working(newCoord))->ownerId;
      if ((ownerId != id) && (!CanAttack(ownerId)))
	return;
    }
    if (!MoveUnit(currUnit, newCoord, cost, NULL))
      currUnit = NULL;
  }
}

int
Player::CanAttack(int playerId)
{
  if (treaties[playerId] == AT_WAR)
    return 1;

  if (govt >= REPUBLIC) {
    screen->DispMessageBox("Overruled by Senate", NULL, NULL);
  }
  else {
    List<charp> options;
    options.Insert("Declare War");
    options.Insert("Cancel Action");
    selecting = WAR_DECL;
    screen->CreateChoiceFrame("This is a declaration of war",options, HandleSelect, this);
  }
  return 0;
}

City *Player::FindCityWithMsg()
{
  for (Lister<ulong> l = citys; l; l.Next()) {
    City *city = trans->TransCity(l.Elem());
    if (city->messages) return city;
  }
  return NULL;
}

void Player::InitCityTurn()
{
  Debug('p', "InitCityTurn for %d\n", id);
  MainMap->DisplayMessage(players[currTurn]->name, 0);
  City *city;

  while (messages)
    ShowMesg(messages);
  if ((city = FindCityWithMsg()) != NULL) {
    city->Show();
    while (city->messages)
      ShowMesg(city->messages);
  }
}

void Player::ChooseScience()
{
  List<Science> canDiscover;
  CanDiscover(this,&canDiscover);
  List<charp> disclist;
  for (Lister<Science> l = canDiscover;l;l.Next())
    disclist.Insert(Sciences[l.Elem()].name);

  selecting = SCIENCE;
  screen->CreateChoiceFrame("Choose Research", disclist, HandleSelect, this);
}

// MarkM added government-type choice:
void Player::ChooseGovernment()
{
  List<charp> canGovern;
  CanGovern(this,&canGovern);

  selecting = GOVERNMENT_TYPE;
  screen->CreateChoiceFrame("Choose Government", canGovern, HandleSelect, this);
}

void Player::ChooseTaxRate()
{
  List<charp> taxl;
  // MarkM made max tax rate limited by luxuries rate (and vice-versa):
  for (int i = 10-luxuries/10; i >= 0; --i) {
    char *str = new char[20];
    sprintf(str, "Tax %d%%", i*10);
    taxl.Insert(str);
  }

  selecting = TAX_RATE;
  screen->CreateChoiceFrame("Set Tax Rate ...", taxl, HandleSelect, this);
  while(taxl) delete taxl.RemoveHead();
}

void Player::ChooseLuxRate()
{
  List<charp> luxl;
  for (int i = 10-tax/10; i >= 0; --i) {
    char *str = new char[20];
    sprintf(str, "Luxuries %d%%", i*10);
    luxl.Insert(str);
  }

  selecting = LUXURY_RATE;
  screen->CreateChoiceFrame("Set Luxuries Rate ...", luxl, HandleSelect, this);
  while (luxl) delete luxl.RemoveHead();
}

void Player::ChooseRevolution()
{
  List<charp> revl;
  char *str1 = new char[30];
  sprintf(str1,"No revolution thank you.");
  revl.Insert(str1);
  char *str2 = new char[30];
  sprintf(str2,"Yes, time for a revolution!");
  revl.Insert(str2);

  selecting = REVOLUTION;
  screen->CreateChoiceFrame("Revoltion?", revl, HandleSelect, this);
  while (revl) delete revl.RemoveHead();
}

void Player::AskForAccept()
{
  MainMap->DisplayMessage("Done: press Accept", 0);
}

void Player::AcceptMoves()
{
  if (!players[currTurn]->doneMoving)
    return;

  // accepted his moves, show them, if he captured our city
  // we will send the info for it across too
  Debug('p', "showing players moves\n");
  players[currTurn]->doneMoving = 0;
  MsgQ *q = new MsgQ;
  *q << "got_moves";
  players[playerId]->ShowMoves(players[currTurn]->unDispQ, q,currTurn);
  SendQ(q);
  // next player's turn
  currTurn = (currTurn+1) % numPlayers;
  Debug('p', "currTurn %d, my id %d\n", currTurn, id);
  if (currTurn == id) {
    InitMoveTurn();
  } else {
    MainMap->DisplayMessage(players[currTurn]->name, 0);
  }
}

void
Player::ShowMessages()
{
  City *city;

  while (messages)
    ShowMesg(messages);
  if ((city = FindCityWithMsg()) != NULL) {
    city->Show();
    while(city->messages)
      ShowMesg(city->messages);
  }
}
void
Player::InitiateSave()
{
  if (playerId == 0)
    initiatedSave = 1;
  else if (initiatedSave) {
    CreateSaveFile();
    MsgQ *q = new MsgQ;
    *q << "done_save";
    SendQ(q);
    MainMap->DisplayMessage("Waiting for save", 0);
  }
}

// message in city turn
void Player::CityTurnMesg(MsgQ *q)
{
  char *mesg;
  *q >> mesg;
  if (strcmp(mesg, "myturn") == 0) { // acknowledge a moveturn
    int player;
    *q >> player;
    if (player != currTurn) {
      Debug('n',"Myturn from %d; currTurn is %d!\n",player, currTurn);
      NetFail("CityTurn");
    }
    MsgQ *q1 = new MsgQ;
    *q1 << "yourturn_ack";
    SendQ(q1);
    delete q;
  }
  else if (strcmp(mesg, "turn_done") == 0) {
    int player;
    *q >> player;
    if (player != currTurn) {
      Debug('n',"Turndone from %d; currTurn is %d!\n",player, currTurn);
      NetFail("CityTurn");
    }
    char *str;
    *q >> str;
    delete str;
    players[currTurn]->unDispQ = q;
    Debug('p', "got turn done from %d\n", currTurn);
    if ((numPlayers > 2) && ((currTurn+1) % numPlayers) == id) {
      accepts_left = numPlayers-2;
      MainMap->DisplayMessage("Waiting for turn...", 0);
    }
    else {
      players[currTurn]->doneMoving = 1;
      AskForAccept();
    }
  }
  else if (accepts_left > 0 && strcmp(mesg,"got_moves") ==0) {
    if (--accepts_left <= 0) {
      players[currTurn]->doneMoving = 1;
      AskForAccept();
    }
  }
  else if (playerId != 0 && strcmp(mesg, "save_game") == 0) {
    MainMap->DisplayMessage("Got Save Request", 0);
    initiatedSave = 1;
  }
  else if (playerId != 0 && strcmp(mesg, "commit_suicide") == 0) {
    exit(0); // the server confirms everyone saved their games...
  }
  
  else
    delete q;
  delete mesg;
}

// update cities
// send the list of places where they are working to everyone too
void Player::UpdateCities()
{
  Lister<ulong> cityl = citys;
  while (cityl) {
    City *city = trans->TransCity(cityl.Elem());
    if (city->ownerId != id || !city->Update()) { // lost this city
      while (city->units) {
	Unit *unit = trans->TransUnit(city->units.RemoveHead());
	*moveQ << PieceMove(unit->id, PIECE_DIE, 0, 0);
	delete unit;
      }
      if (city->ownerId == id) { // city died
	*moveQ << PieceMove(city->id, CITY_DIE, 0, 0);
	cityl.Delete(); // MUST do this first
	delete city;
      }
      else
	cityl.Delete();
    }
    else {
      *moveQ << PieceMove(city->id, CITY_WORK_MAP, 0, 0);
      int len;
      char *cmap = city->MakeWorkMap(len);
      *moveQ << Msg(cmap, len);
      cityl.Next();
    }
  }
  if (scienceAcc >= needScience && researching != NOSCIENCE) {
    scienceAcc -= needScience;
    Discover(researching);
    researching = NOSCIENCE;
  }
  // MarkM added 40% chance if ANARCHY of getting to select govt type:
  if (govt == ANARCHY && random() %9 <= 3) ChooseGovernment();
}

void Player::Save()
{
  Debug('s', "Saving player %d\n", id);
  WriteUShort(govt);
  WriteUShort(tax);
  // MarkM added luxuries rate:
  WriteUShort(luxuries);
  WriteUShort(money);

  WriteUShort(scienceAcc);
  WriteUShort(needScience);
  WriteUShort(researching);

  discovered.Save();

  for (int i=0;i<numPlayers;i++)
    WriteUShort(treaties[i]);
  
  WriteULong(embassies);

  wonders.Save();

  WriteUShort(citys.Count());
  Lister<ulong> l1;
  for (l1 = citys; l1; l1.Next())
    trans->TransCity(l1.Elem())->Save();

  if (capital != NULL)
    WriteULong(capital->id);
  else
    WriteULong(0);

  WriteUShort(units.Count());
  for (l1 = units; l1; l1.Next())
    trans->TransUnit(l1.Elem())->Save();
}

void Player::Restore()
{
  Debug('s', "Restoring player %d\n", id);
  govt = ReadUShort();
  tax = ReadUShort();
  // MarkM added luxuries rate:
  luxuries = ReadUShort();
  money = ReadUShort();

  scienceAcc = ReadUShort();
  needScience = ReadUShort();
  researching = Science(ReadUShort());
  Debug('s', "Restored upto researching %s\n", researching);

  discovered.Restore();

  for(int i = 0; i <numPlayers;i++)
    treaties[i] = TreatyStatus(ReadUShort());

  embassies = ReadULong();

  wonders.Restore();

  int n = ReadUShort();
  Debug('s', "Restoring %d cities\n", n);
  // FIXME: `city' not used !!
  for (; n > 0; --n)
    City *city = new City; // default constructor reads from save file

  long c = ReadULong();
  if (c)
    capital = trans->TransCity(c);
  else
    capital = NULL;

  n = ReadUShort();
  Debug('s', "Restoring %d units\n", n);
  // FIXME: `unit' not used !!
  for (; n > 0; --n)
    Unit *unit = new Unit; // default constructor reads from save file

  // compute economies
  if (playerId == id)
    for (Lister<ulong> l = citys; l; l.Next())
      trans->TransCity(l.Elem())->ComputeEcon();
}
