#ifndef _UNITS_H
#define _UNITS_H

enum { ARMOR = 0, ARTILLERY, BATTLESHIP, BOMBER, CANNON, CARAVAN, CARRIER,
       CATAPULT, CAVALRY, CHARIOT, CRUISER, DIPLOMAT, FIGHTER, FRIGATE,
       IRONCLAD, KNIGHTS, LEGION, MECH_INF, MILITIA, MUSKETEERS,
       NUCLEAR, PHALANX, RIFLEMEN, SAIL, SETTLER, SUBMARINE, TRANSPORT,
       TRIREME };

#include "defs.h"
#include "mytypes.h"
#include "world.h"

class MsgQ;

const int MaxUnits = 255;

int UnitVisibility(int type);
int UnitAttack(int);
int UnitDefense(int);
int UnitMoves(int);

class Unit
{
public:
  Unit(uchar OwnerId, ulong Id, int Veteran, ulong CityId, int X, int Y,
       uchar unitType);
  Unit(); // read from save file
  ~Unit();

  ulong id, cityId;
  ulong carriedBy; // 0 if not carried
  uchar flags;
  uchar ownerId;
  int x, y;
  uchar type; // unit type
  double numMoves; // at each turn we fill this in with the movement points

  // these are used if the unit is ordered to do something
  // like irrigation or building a road, etc
  char currOrder;
  int orderProgress;

  List<ulong> carrying;

  enum { FORTIFIED = 0x01, VETERAN = 0x02, SLEEPING = 0x04 };

  int Fortified() { return flags & FORTIFIED; }
  int Veteran() { return flags & VETERAN; }
  int Sleeping() { return flags & SLEEPING; }
  
  void Fortify() { flags |= FORTIFIED; }
  void Sleep() { flags |= SLEEPING; }
  void MakeVeteran() { flags |= VETERAN; }

  void UnFortify() { flags &= ~FORTIFIED; }
  void Wake() { flags &= ~SLEEPING; }

  uchar Type() { return type; }

  int Attack() {
    return int(UnitAttack(type)*(Veteran() ? 1.5 : 1)+0.5);
  }
  int Defense(int against) {
    return int(UnitDefense(type)*(Veteran() ? 1.5 : 1)*
      (Fortified() ? 1.5 : 1)*world->SquareDefense(x, y, against)+0.5);
  }
  int Moves() { return UnitMoves(type); }
  int Visibility() { return UnitVisibility(type); }

  // true if the unit can carry us, checks if owners match too
  int CanCarry(Unit *);

  void SetCoord(int, int);

  List<ulong> &Carrying() { return carrying; }

  // if this fails that means the unit died
  int Order(int key);

  // after you fill in the moves call this function
  // if the unit is processing an order this will make it
  // do the work
  void CompleteOrder();

  // true if we can attack the given unit type
  int CanAttack(int type);

  // true if it can move on the given terrain type
  int CanMoveOn(int terrainType, int dx, int dy);

  // true if it can attack on the given terrain type
  int CanAttackOn(int terrainType);

  // returns the movement cost, if it is -ve then the piece loses all
  // its movement points and doesn't get to move
  double MoveCost(int terrainType, double movesRem, int sx, int sy,
		  int dx, int dy);

  void Draw(int atx, int aty);
  void ShowMoveTo(int x1, int y1, int x2, int y2, int newx, int newy);

  char **Picture();

  long *CompiledPics() { return compiledPicsArray[type]; }
  void SetCompiledPics(long *ptr) { compiledPicsArray[type] = ptr; }

  long CompiledPic(); // use ownerId for the player color

  friend int MoveUnit(Unit *, int newx, int newy, MsgQ *outQ);

  void DrawIfVisible();

  void Save();

private:
  static long *compiledPicsArray[MaxUnits];
};

Unit *NewUnit(int type, int owner, ulong id, int vet, ulong city,
	      int x, int y);

#endif
