/* Definitions relating to units in Xconq.
   Copyright (C) 1987-1989, 1991-2000 Stanley T. Shebs.

Xconq is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.  See the file COPYING.  */

/* Advanced unit support. */
extern short default_size; 
extern short default_usedcells; 
extern short default_maxcells; 
extern long default_population; 

/* The unit structure should be small, because there may be many of them.
   Unit semantics go in this structure, while unit brains go into the
   act/plan.  Test: a unit that is like a rock and can't do anything at all
   just needs basic slots, plan needn't be allocated.  Another test:
   unit should still function correctly after its current plan has been
   destroyed and replaced with another. */

typedef struct a_unit {
    short type;			/* type */
    int id;		  	/* truly unique id number */
    char *name;			/* the name, if given */
    int number;			/* semi-unique number */
    short x, y, z;	     	/* position of unit in world */
    /* NOTE: unit->side and unit->origside must always point to
       valid side objects; dereferences are not checked! */
    struct a_side *side;	/* whose side this unit is on */
    struct a_side *origside;	/* the first side this unit was on */
    short hp;			/* how much more damage each part can take */
    short hp2;		 	/* buffer for next value of hp */
    short cp;		  	/* state of construction */
    short cxp;		 	/* combat experience */
    short morale;		/* morale */
    struct a_unit *transport;	/* pointer to transporting unit if any */
    SideMask tracking;		/* which sides always see us (bit vector) */
    short *supply;		/* how much supply we're carrying */
    short s_flow;		/* how much supply we received this turn */
    short s_conn;		/* how well connected we are to supply zones */
    short *tooling;	    	/* level of preparation for construction */
    short *opinions;		/* opinion of each side, both own side and others */
    struct a_actorstate *act;	/* the unit's current actor state */
    struct a_plan *plan;	/* the unit's current plan */
    struct a_unit_extras *extras;  /* pointer to optional stuff */
    char *aihook;		/* used by AI to keep info about this unit */
    /* Following slots are never saved. */
    struct a_unit *occupant;	/* pointer to first unit being carried */
    struct a_unit *nexthere;	/* pointer to fellow occupant */
    struct a_unit *prev;	/* previous unit in list of side's units */
    struct a_unit *next;	/* next unit in list of side's units */
    struct a_unit *unext;	/* next unit in list of all units */
    short prevx, prevy;		/* where were we last */
    Obj *transport_id;		/* read-in id of transport (should be tmp array instead) */
    short flags;		/* assorted flags */
    /* (should make optional in UnitExtras?) */
    short size;			/* Abstract size of the unit */
    short reach;		/* Size of the unit's zone of influence */
    short usedcells;		/* Number of cells actually used by unit */
    short maxcells;		/* Max number of cells that unit can use */
    short curadvance;		/* Advance currently being researched. */ 
    long population;		/* Size of units population */
    short *production;		/* Cache of units last production. */
    short autobuild;		/* True if building on automatic. */
    short autoresearch;		/* True if research on automatic. */
    short autoplan;		/* True if planning on automatic. */
    short cp_stash;		/* Stash of cps recovered from incomplete build tasks. */
    short buildingdone;		/* We are done with construction for this turn. */
    short researchdone;		/* We are done with research for this turn. */
   
} Unit;

/* The unit extras structure stores properties that are (usually)
   uncommon or special-purpose.  It is allocated as needed, access is
   through macros, and this does not appear as a separate structure
   when saving/restoring.  If a value is likely to be filled in for
   most or all units in several different game designs, then it should
   be in the main structure (even at the cost of extra space), rather
   than here. */

typedef struct a_unit_extras {
    short point_value;		/* individual point value for this unit */
    short appear;		/* turn of appearance in game */
    short appear_var_x, appear_var_y;	/* variation around appearance location */
    short disappear;		/* turn of disappearance from game */
    short priority;		/* individual priority */
    Obj *sym;			/* symbol for xrefs */
    Obj *sides;			/* list of possible sides */
} UnitExtras;

/* The unit view is a partial mirror of an actual unit, including only
   the data that might be known to another side seeing the unit from a
   distance. */

typedef struct a_unit_view {
    short type;			/* type */
    short side_id;		/* id of view's side */
    short size;			/* abstract size */
    short x, y;			/* location of view */
    short date;			/* turn on which last updated */
    int id;			/* id of actual unit if known */
    struct a_unit *unit;	/* pointer to actual unit, if id valid */
    struct a_unit_view *nexthere; /* pointer to next unit view */
} UnitView;

/* Some convenient macros. */

/* Since it is possible for a unit to change sides and therefore
   prev/next pointers while iterating using the macros below, one
   must be very careful either that unit sides can't change during
   the loop, or else to maintain a temp var that can be used to
   repair the iteration.  This also applies to units dying. */

/* Iteration over all units. */

#define for_all_units(v)  \
    for (v = unitlist; v != NULL; v = v->unext)

/* Iteration over all units on a given side. */

#define for_all_side_units(s,v) \
    for (v = (s)->unithead->next; v != (s)->unithead; v = v->next)

/* Iteration over all occupants of a unit (but not sub-occupants). */

#define for_all_occupants(u1,v) \
  for (v = (u1)->occupant; v != NULL; v = v->nexthere)

/* Iterate through all occupants including occs within occs within
   occs within (u). */

/* This nifty little macro will climb the occupant : nexthere tree and
   follow all branches three levels below (u) to find all the occs
   within occs within occs within (u).  The test for (var) !=
   (u)->nexthere is to stop the macro from climbing up above (u). */

#define for_all_occs_with_occs(u,var)  \
  for ((var) = (u)->occupant; \
       (var) != NULL && (var) != (u)->nexthere; \
  	 (var) = ((var)->occupant != NULL ? \
  	 	        (var)->occupant : \
  	 	      ((var)->nexthere != NULL ? \
  	 	        (var)->nexthere : \
  		      ((var)->transport != NULL && \
  		        (var)->transport->nexthere != NULL ? \
  		        (var)->transport->nexthere : \
  		      ((var)->transport != NULL && \
  		        (var)->transport->transport != NULL && \
  		        (var)->transport->transport->nexthere != NULL ? \
  		        (var)->transport->transport->nexthere : NULL)))))

#define is_unit(unit) ((unit) != NULL && is_unit_type((unit)->type))

#define alive(unit) ((unit)->hp > 0)

#define indep(unit) ((unit)->side == indepside)

#define completed(unit) \
  ((unit)->cp >= completenesses[(unit)->type])
/*  ((unit)->cp >= (u_cp((unit)->type) / u_parts((unit)->type))) */

#define fullsized(unit) \
  ((unit)->cp >= u_cp((unit)->type))

/* Extractor for the actual altitude of an airborne unit. */

#define unit_alt(unit) (((unit)->z & 1) == 0 ? ((unit)->z >> 1) : 0)

/* Extractor for the connection a unit is on. */

#define unit_conn(unit) (((unit)->z & 1) == 1 ? ((unit)->z >> 1) : NONTTYPE)

/* This is true if the unit is on the board somewhere. */

#define in_play(unit) \
  (is_unit(unit) && alive(unit) && inside_area((unit)->x, (unit)->y))

#define is_active(unit) (in_play(unit) && completed(unit))

#define side_tracking_unit(side,unit) (side_in_set((side), (unit)->tracking))

/* Unit opinion, if defined, is an array of 2-byte values, one per side,
   indexed by side number.  Each value consists of a low byte, which is the
   for/against strength (positive is "for", negative is "against", neutral is 0),
   and a high byte, which is the level of courage/fear (positive is courage,
   negative is fear). */

#define unit_opinion(unit,side)  \
  ((unit)->opinions != NULL ? x_opinion((unit)->opinions[side_number(side)]) : 0)

#define unit_courage(unit,side)  \
  ((unit)->opinions != NULL ? x_courage((unit)->opinions[side_number(side)]) : 0)

#define x_opinion(val) (((val) & 0xff) - 128)

#define x_courage(val) (((val) >> 8) & 0xff)

#define s_opinion(val,val2) (((val) & ~0xff) | (val2 + 128))

#define s_courage(val,val2) (((val) & ~0xff00) | (val2 << 8))

/* These return a percentage value. */

#define supply_inflow(unit) ((unit)->s_flow / 163)

#define supply_connectedness(unit) ((unit)->s_conn / 254)

/* (could use bit fields in struct I suppose...) */

#define DETONATE_FLAG_BIT 0

#define was_detonated(unit) ((unit)->flags & (1 << DETONATE_FLAG_BIT))

#define set_was_detonated(unit, v) \
  ((v) ? ((unit)->flags |= 1 << DETONATE_FLAG_BIT) \
   : ((unit)->flags &= ~(1 << DETONATE_FLAG_BIT)))

#define unit_point_value(unit) ((unit)->extras ? (unit)->extras->point_value : -1)

#define unit_appear_turn(unit) ((unit)->extras ? (unit)->extras->appear : -1)

#define unit_appear_var_x(unit) ((unit)->extras ? (unit)->extras->appear_var_x : -1)

#define unit_appear_var_y(unit) ((unit)->extras ? (unit)->extras->appear_var_y : -1)

#define unit_disappear_turn(unit) ((unit)->extras ? (unit)->extras->disappear : -1)

#define unit_extra_priority(unit) ((unit)->extras ? (unit)->extras->priority : -1)

#define unit_symbol(unit) ((unit)->extras ? (unit)->extras->sym : lispnil)

#define unit_sides(unit) ((unit)->extras ? (unit)->extras->sides : lispnil)

#define unit_doctrine(unit)  \
  (unit->side->udoctrine[unit->type])

#define construction_run_doctrine(unit,u2) \
  (unit_doctrine(unit)->construction_run[u2])

/* A sortable vector of units, generally useful. */

/* The kinds of sort keys available for list windows. */

enum sortkeys {
    bynothing,
    bytype,
    byname,
    byactorder,
    bylocation,
    byside,
    numsortkeytypes
};

/* Can sort on as many as five keys. */

#define MAXSORTKEYS 5

typedef struct a_unitvectorentry {
    Unit *unit;
    int flag;
} UnitVectorEntry;

typedef struct a_unitvector {
    int size;
    int numunits;
    enum sortkeys sortkeys[MAXSORTKEYS];
    UnitVectorEntry units[1];
} UnitVector;

/* Given an index into a unit vector, return the unit. */
/* (should check args?) */

#define unit_in_vector(uvec,ix) ((uvec)->units[ix].unit)

/* Types of primitive unit actions. */

typedef enum actiontype {

#undef  DEF_ACTION
#define DEF_ACTION(name,CODE,args,prepfn,netprepfn,dofn,checkfn,argdecl,doc) CODE,

#include "action.def"

    NUMACTIONTYPES

} ActionType;

typedef struct a_actiondefn {
    ActionType typecode;
    char *name;
    char *argtypes;
} ActionDefn;

#define MAXACTIONARGS 4

typedef struct a_action {
    ActionType type;		/* the type of the action */
    int args[MAXACTIONARGS];	/* assorted parameters */
    int actee;		/* the unit being affected by action */
    struct a_action *next;	/* chain to next action */
} Action;

typedef struct a_actorstate {
    short initacp;		/* how much we can still do */
    short acp;			/* how much we can still do */
    short actualmoves;		/* cells actually covered this turn */
    Action nextaction;
} ActorState;

#define valid(x) ((x) == A_ANY_OK)

#define has_pending_action(unit)  \
  ((unit)->act && (unit)->act->nextaction.type != ACTION_NONE)

#define acp_indep(unit) u_acp_independent((unit)->type)

/* This is true if the unit still has acp left to act with.  This used
   to test acp > acp-min, but that allows units to move around with
   negative acp, and doesn't work as well in game designs. */

/* Now returns TRUE if an acp-independent unit that can build is either 
waiting for tasks or not yet done with construction for this turn. */

#define has_acp_left(unit) \
  ((unit)->act \
  && ((unit)->act->acp > 0 \
        || (acp_indep((unit)) \
            && can_build((unit)) \
        	   && ((unit)->buildingdone != TRUE \
        	   	|| ((unit)->plan \
        	   	    && (unit)->plan->waitingfortasks)))))

/* All the definitions that govern planning. */

/* A goal is a predicate object that can be tested to see whether it has
   been achieved.  As such, it is a relatively static object and may be
   shared. */

/* The different types of goals. */

typedef enum goaltype {

#undef  DEF_GOAL
#define DEF_GOAL(name,dname,GOALTYPE,args) GOALTYPE,

#include "goal.def"

    g_t_dummy
} GoalType;

typedef struct a_goaldefn {
    char *name;
    char *display_name;
    char *argtypes;
} GoalDefn;

/* The goal structure proper. */

#define MAXGOALARGS 5

typedef struct a_goal {
    GoalType type;
    short tf;
    Side *side;
    short args[MAXGOALARGS];
} Goal;

/* A task is a single executable element of a unit's plan.  Each task
   type is something that has been found useful or convenient to
   encapsulate as a step in a plan.  Tasks are also useful for human
   interfaces to use instead of actions, since they have retry
   capabilities that are not part of action execution. */

/* Note that a task's arguments are not the same as the arguments
   passed to the functions that create and push tasks.  For instance,
   the 'c' task argument is actually a state variable recording a
   direction choice; this is important for coherent routefinding, but
   is not needed in order to create a movement task. */

typedef enum a_tasktype {

#undef  DEF_TASK
#define DEF_TASK(name,dname,CODE,argtypes,dofn,createfn,setfn,netsetfn,pushfn,netpushfn,argdecl) CODE,

#include "task.def"

    NUMTASKTYPES
} TaskType;

typedef enum a_taskoutcome {
  TASK_UNKNOWN,
  TASK_FAILED,
  TASK_IS_INCOMPLETE,
  TASK_PREPPED_ACTION,
  TASK_IS_COMPLETE
} TaskOutcome;

#define MAXTASKARGS 6

typedef struct a_task {
    TaskType type;		/* the kind of task we want to do */
    int args[MAXTASKARGS];	/* arguments */
    short execnum;		/* how many times this has been done */
    short retrynum;		/* number of immed failures so far */
    struct a_task *next;	/* the next task to undertake */
} Task;

typedef struct a_taskdefn {
    char *name;			/* name of the task type */
    char *display_name;		/* name to display in interfaces */
    char *argtypes;		/* string giving types of task's args */
    TaskOutcome (*exec)(Unit *unit, Task *task);
} TaskDefn;

#define is_task_type(x) (between(0, (x), NUMTASKTYPES - 1))

/* A plan is what a single unit uses to make decisions, both for itself and
   for any other units it commands.  Any unit that can act at all has a
   plan object.  A plan collects lots of unit behavior, but its most
   important structure is the task queue, which contains a list of what
   to do next, in order. */

/* Plan types distinguish several kinds of usages. */

typedef enum plantype {

#undef  DEF_PLAN
#define DEF_PLAN(name,CODE) CODE,

#include "plan.def"

    NUMPLANTYPES
} PlanType;

typedef struct a_plan {
    PlanType type;		/* general type of plan that we've got here */
    short creation_turn;	/* turn at which this plan was created */
    short initial_turn;		/* turn at which this plan is to be done */
    short final_turn;		/* turn to deactivate this plan */
    short asleep;		/* true if the unit is doing nothing */
    short reserve;		/* true if unit waiting until next turn */
    short delayed;
    short waitingfortasks;	/* true if waiting to be given a task */
    short aicontrol;		/* true if an AI can operate on the unit */
    short supply_alarm;
    short supply_is_low;
    short waitingfortransport;
    struct a_goal *maingoal;	/* the main goal of this plan */
    struct a_goal *formation;	/* goal to keep in a formation */
    struct a_task *tasks;	/* pointer to chain of sequential tasks */
    /* Not saved/restored. (little value, some trouble to do) */
    struct a_unit *funit;	/* pointer to unit keeping formation */
    Action lastaction;	 	/* a copy of the last action attempted */
    short lastresult;		/* that action's outcome */
    Task last_task;		/* a copy of the last task executed */
    TaskOutcome last_task_outcome; /* that task's outcome */
    short execs_this_turn;
} Plan;

#define for_all_tasks(plan,task)  \
  for (task = (plan)->tasks; task != NULL; task = task->next)

#define ai_controlled(unit)  \
  ((unit)->plan && (unit)->plan->aicontrol && side_has_ai(unit->side))

/* Global unit variables. */

extern Unit *unitlist;
extern Unit *tmpunit;

extern int numunits;
extern int numliveunits;

extern short *completenesses;

extern enum sortkeys tmpsortkeys[];

extern ActionDefn actiondefns[];

extern GoalDefn goaldefns[];

extern TaskDefn taskdefns[];

extern char *plantypenames[];

/* Declarations of unit-related functions that do not change the kernel state. 
Those that actually do something have been moved to kernel.h. */

/* Testable conditions etc. */

extern int side_owns_occupant(Side *side, Unit *unit);
extern int can_occupy_cell(Unit *unit, int x, int y);
extern int type_can_occupy_cell(int u, int x, int y);
extern int can_occupy_cell_without(Unit *unit, int x, int y, Unit *unit3);
extern int type_can_occupy_cell_without(int u, int x, int y, Unit *unit3);
extern int type_can_sit_on_conn(int u, int x, int y);
extern int can_occupy(Unit *unit, Unit *transport);
extern int can_carry(Unit *transport, Unit *unit);
extern int type_can_occupy(int u, Unit *transport);
extern int can_occupy_type(Unit *unit, int u2);
extern int can_carry_type(Unit *transport, int u);
extern int new_unit_allowed_on_side(int u, Side *side);
extern int unit_allowed_on_side(Unit *unit, Side *side);
extern int num_sides_allowed(int u);
extern int type_allowed_on_side(int u, Side *side);
extern int type_ever_available(int u, Side *side);
extern int unit_trusts_unit(Unit *unit1, Unit *unit2);
extern int can_occupy_conn(Unit *unit, int nx, int ny, int nz);
extern int can_build(Unit *unit);
extern int can_move(Unit *unit);
extern int can_extract_at(Unit *unit, int x, int y, int *mp);
extern int can_load_at(Unit *unit, int x, int y, int *mp);
extern int can_develop(Unit *unit);
extern int type_can_develop(int u);
extern int can_toolup(Unit *unit);
extern int type_can_toolup(int u);
extern int can_create(Unit *unit);
extern int type_can_create(int u);
extern int can_complete(Unit *unit);
extern int type_can_complete(int u);
extern int can_repair(Unit *unit);
extern int type_can_repair(int u);
extern int can_change_type(Unit *unit);
extern int type_can_change_type(int u);
extern int can_disband(Unit *unit);
extern int type_can_disband(int u);
extern int side_can_disband(Side *side, Unit *unit);
extern int can_add_terrain(Unit *unit);
extern int type_can_add_terrain(int u);
extern int can_remove_terrain(Unit *unit);
extern int type_can_remove_terrain(int u);
extern int can_build_attackers(Side *side, int u);
extern int can_build_defenders(Side *side, int u);
extern int can_build_explorers(Side *side, int u);
extern int can_build_colonizers(Side *side, int u);
extern int can_build_facilities(Side *side, int u);
extern int can_build_or_help(Unit *unit);
extern int can_research(Unit *unit);
extern int can_produce(Unit *unit);
extern int operating_range_best(int u);
extern int operating_range_worst(int u);

#if 0
extern int moves_till_low_supplies(Unit *unit);
extern int num_occupants(Unit *unit);
extern int num_units_at(int x, int y);
#endif

/* Unit names and designations. */

extern char *unit_desig(Unit *unit);
extern char *unit_desig_no_loc(Unit *unit);
extern char *utype_name_n(int u, int n);
extern char *shortest_unique_name(int u);
extern char *shortest_generic_name(int u);
extern char *actorstate_desig(struct a_actorstate *as);

/* Unit locators. */

extern Unit *find_unit(int n);
extern Unit *find_unit_dead_or_alive(int n);
extern Unit *find_unit_by_name(char *nm);
extern Unit *find_unit_by_number(int nb);
extern Unit *find_unit_by_symbol(Obj *sym);

/* Unit vector manipulating functions. Declared here rather than in kernel.h 
since they also are used in the interfaces. */

extern UnitVector *make_unit_vector(int initsize);
extern void clear_unit_vector(UnitVector *vec);
extern UnitVector *add_unit_to_vector(UnitVector *vec, Unit *unit, int flag);
extern void remove_unit_from_vector(UnitVector *vec, Unit *unit, int pos);
extern void sort_unit_vector(UnitVector *vec);

/* Turn init code - does not really belong here. */

extern void check_all_units(void);

#undef  DEF_ACTION
#define DEF_ACTION(name,code,args,prepfn,netprepfn,dofn,CHECKFN,ARGDECL,doc)  \
  extern int CHECKFN ARGDECL;

#include "action.def"

#undef  DEF_TASK
#define DEF_TASK(name,dname,code,argtypes,dofn,CREATEFN,setfn,netsetfn,pushfn,netpushfn,ARGDECL)  \
  extern Task *CREATEFN ARGDECL;

#include "task.def"
