/* Definitions relating to units in Xconq.
   Copyright (C) 1987-1989, 1991-1999 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 */
    short 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 */
    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 */
    char *uihook;		/* used by interfaces for their own purposes */
    /* 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. */
} 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 *hook;		 	/* placeholder for more optional stuff */
} UnitExtras;

/* 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 == NULL || (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)

/* We test the hook for NULL, because lispnil is not NULL and we can't
   count on the hook being initialized when extras are allocated. */

#define unit_hook(unit)  \
  (((unit)->extras && (unit)->extras->hook) ? (unit)->extras->hook : lispnil)

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

/* 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;

/* 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 */
    short args[MAXACTIONARGS];	/* assorted parameters */
    short 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)

/* 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,GOALTYPE,args) GOALTYPE,

#include "goal.def"

    g_t_dummy
} GoalType;

typedef struct a_goaldefn {
    char *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;

extern Goal *create_goal(GoalType type, Side *side, int tf);
extern int cell_unknown(int x, int y);
extern int enemies_present(int x, int y);
extern int goal_truth(Side *side, Goal *goal);
extern char *goal_desig(Goal *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. */

typedef enum a_tasktype {

#undef  DEF_TASK
#define DEF_TASK(name,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 */
    short 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;
    char *argtypes;
    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)

/* 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. */

extern void init_units(void);
extern Unit *create_bare_unit(int type);
extern Unit *create_unit(int type, int makebrains);
extern void init_unit_actorstate(Unit *unit, int flagacp);
extern void init_unit_plan(Unit *unit);
extern void init_unit_tooling(Unit *unit);
extern void init_unit_opinions(Unit *unit, int nsides);
extern void init_unit_extras(Unit *unit);
extern void change_unit_type(Unit *unit, int newtype, int reason);
extern int max_builds(int u);
extern int enter_cell(Unit *unit, int x, int y);
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 void enter_cell_aux(Unit *unit, 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 void enter_transport(Unit *unit, Unit *transport);
extern void leave_cell(Unit *unit);
extern void leave_transport(Unit *unit);
extern void eject_excess_occupants(Unit *unit);
extern void eject_occupant(Unit *unit, Unit *occ);
extern int new_unit_allowed_on_side(int u, Side *side);
extern int unit_allowed_on_side(Unit *unit, Side *side);
extern int test_class_membership(Obj *leaf);
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 void dispose_of_plan(Unit *unit);
extern void flush_dead_units(void);
extern void sort_units(int byidonly);
extern int moves_till_low_supplies(Unit *unit);
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);
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);
extern int find_unit_name(char *str);
extern void insert_unit(Unit *unithead, Unit *unit);
extern void delete_unit(Unit *unit);
extern int num_occupants(Unit *unit);
extern int num_units_at(int x, int y);
extern void check_all_units(void);
extern void check_unit(Unit *unit);
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);
extern Obj *get_x_property(Unit *unit, int subkey);
extern Obj *get_x_property_by_name(Unit *unit, char *str);

extern int disband_unit_directly(Side *side, Unit *unit);

extern void add_unit_to_stack(Unit *unit, int x, int y);
extern void remove_unit_from_stack(Unit *unit);
extern void glimpse_adjacent_terrain(Unit *unit);
extern void add_to_unit_hp(Unit *unit, int hp);
extern void wreck_unit(Unit *unit);

/* Declarations of plan-related functions. */

extern int move_into_formation(Unit *unit);
extern int victim_here(int x, int y);
extern int worth_capturing(Side *side, int u2, Side *oside, int x, int y);
extern int target_here(int x, int y);
extern int supplies_here(Unit *unit, int x, int y, int m);
extern int indep_captureable_here(int x, int y);
extern int useful_captureable_here(int x, int y);
extern int useful_type(Side *side, int u);
extern int could_capture_any(int u);
extern void make_plausible_random_args(char *argtypestr, int i, short *args, Unit *unit);
extern int range_left(Unit *unit);
extern int find_worths(int range);
extern int attack_worth(Unit *unit, int e);
extern int threat(Side *side, int u, int x0, int y0);
extern int react_to_enemies(Unit *unit);
extern int move_patrol(Unit *unit);
extern int build_time(Unit *unit, int prod);
extern Plan *create_plan(void);
extern void free_plan(Plan *plan);
extern char *plan_desig(Plan *plan);
extern int might_be_captured(Unit *unit);
extern int occupant_could_capture(Unit *unit, int etype);
extern int can_capture_neighbor(Unit *unit);
extern int occupant_can_capture_neighbor(Unit *unit);
extern int find_closest_unit(Side *side, int x0, int y0, int maxdist, int (*pred)(int x, int y), int *rxp, int *ryp);
extern int fullness(Unit *unit);
extern int can_build(Unit *unit);
extern int can_move(Unit *unit);
extern int out_of_ammo(Unit *unit);
extern int survival_time(Unit *unit);
extern int usable_cell(Unit *unit, int x, int y);
extern int explorable_cell(int x, int y);
extern int reachable_unknown(int x, int y);
extern int adj_known_ok_terrain(int x, int y, Side *side, int u);
extern int should_capture_maker(Unit *unit);
extern int no_possible_moves(Unit *unit);
extern int normal_completion_time(int u, int u2);
extern int adj_unit(int x, int y);
extern int past_halfway_point(Unit *unit);

extern int self_build_base_for_self(Unit *unit);

extern int operating_range_worst(int u);
extern int operating_range_best(int u);

extern int terrain_always_impassable(int u, int t);

extern int execute_standing_order(Unit *unit, int addtask);
extern int can_build_or_help(Unit *unit);
extern int can_produce(Unit *unit);
extern int low_on_supplies_one(Unit *unit);
extern int low_on_ammo_one(Unit *unit);

extern void set_waiting_for_tasks(Unit *unit, int flag);

extern int execute_standing_order(Unit *unit, int addtask);

/* Declarations of task-related functions. */

extern void init_tasks(void);
extern void allocate_task_block(void);
extern Task *create_task(TaskType type);
extern Task *clone_task(Task *oldtask);
extern int fire_can_damage(Unit *unit, Unit *unit2);
extern Unit *repair_here(int x, int y);
extern Unit *aux_resupply_here(Unit *unit);
extern Unit *resupply_here(int x, int y);
extern int can_auto_resupply_self(Unit *unit, int *materials, int numtypes);
extern int choose_move_dirs(Unit *unit, int tx, int ty, int shortest, int (*dirtest)(Unit *, int), void (*dirsort)(Unit *, int *, int), int *dirs);
extern int plausible_move_dir(Unit *unit, int dir);
extern void sort_directions(Unit *unit, int *dirs, int numdirs);
extern void free_task(Task *task);
extern char *parse_task(Side *side, char *str, Task **taskp);
extern char *task_desig(Task *task);
extern Unit *find_unit_to_complete(Unit *unit, Task *task);

extern int real_capture_chance(Unit *unit, Unit *unit2);
extern int attack_can_damage_or_capture(Unit *unit, Unit *unit2);
extern int fire_can_damage_or_capture(Unit *unit, Unit *unit2);

#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,code,argtypes,dofn,CREATEFN,setfn,netsetfn,pushfn,netpushfn,ARGDECL)  \
  extern Task *CREATEFN ARGDECL;

#include "task.def"

