Logo Search packages:      
Sourcecode: warzone2100 version File versions

intorder.c

/*
      This file is part of Warzone 2100.
      Copyright (C) 1999-2004  Eidos Interactive
      Copyright (C) 2005-2007  Warzone Resurrection Project

      Warzone 2100 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 of the License, or
      (at your option) any later version.

      Warzone 2100 is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with Warzone 2100; if not, write to the Free Software
      Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>

#include "lib/framework/frame.h"
#include "lib/framework/strres.h"
#include "lib/widget/widget.h"
#include "lib/ivis_common/textdraw.h"
#include "objects.h"
#include "loop.h"
#include "map.h"
#include "lib/ivis_common/bitimage.h"//bitmap routines

#include "display3d.h"
#include "hci.h"
#include "lib/sound/audio.h"
#include "lib/widget/widgint.h"
#include "lib/widget/bar.h"
#include "lib/widget/form.h"
#include "lib/widget/label.h"
#include "lib/widget/button.h"
#include "lib/widget/editbox.h"
#include "lib/widget/slider.h"
#include "order.h"
#include "intimage.h"
#include "intdisplay.h"
#include "intorder.h"

#include "scriptextern.h"



#define ORDER_X               23
#define ORDER_Y               45
#define ORDER_WIDTH           RET_FORMWIDTH
#define ORDER_HEIGHT    273
#define ORDER_BUTX            8
#define ORDER_BUTY            16
#define ORDER_BUTGAP    4
#define ORDER_BOTTOMY   318   + E_H


#define MAX_SELECTED_DROIDS   100   // Max size of selected droids list.

#define MAX_AVAILABLE_ORDERS 16     // Max available orders list.
#define MAX_DISPLAYABLE_ORDERS 11   // Max number of displayable orders.
#define MAX_ORDER_BUTS 5            // Max number of buttons for a given order.
#define NUM_ORDERS 12               // Number of orders in OrderButtons list.

#define IDORDER_ATTACK_RANGE                    8010
#define IDORDER_REPAIR_LEVEL                    8020
#define IDORDER_ATTACK_LEVEL                    8030
#define IDORDER_PATROL                                8040
#define IDORDER_HALT_TYPE                             8050
#define IDORDER_RETURN                                8060
#define IDORDER_RECYCLE                               8070
#define IDORDER_ASSIGN_PRODUCTION               8080
#define IDORDER_ASSIGN_CYBORG_PRODUCTION  8090
#define IDORDER_FIRE_DESIGNATOR                       8100
#define IDORDER_ASSIGN_VTOL_PRODUCTION          8110
#define IDORDER_CIRCLE                                8120

//#define IDORDER_RETURN_TO_BASE          8050
//#define IDORDER_DESTRUCT                      8060
//#define IDORDER_RETURN_TO_REPAIR        8080
//#define IDORDER_EMBARK                        8100

typedef enum {
      ORD_BTYPE_RADIO,              // Only one state allowed.
      ORD_BTYPE_BOOLEAN,                  // Clicking on a button toggles it's state.
      ORD_BTYPE_BOOLEAN_DEPEND,     // Clicking on a button toggles it's state, button
                                                // is only enabled if previous button is down.
      ORD_BTYPE_BOOLEAN_COMBINE,    // Clicking on a button toggles it's state, all
                                                // the buttons states are OR'ed together to get the order state
} ORDBUTTONTYPE;

typedef enum {
      ORDBUTCLASS_NORMAL,                 // A normal button, one order type per line.
//    ORDBUTCLASS_NORMALMIXED,      // A normal button but multiple order types on one line.
      ORDBUTCLASS_FACTORY,          // A factory assignment button.
      ORDBUTCLASS_CYBORGFACTORY,    // A cyborg factory assignment button.
      ORDBUTCLASS_VTOLFACTORY,      // A VTOL factory assignment button.
} ORDBUTTONCLASS;


/*
 NOTE:
      ORD_BTYPE_BOOLEAN_DEPEND only supports two buttons
      ie button 1 = enable destruct, button 2 = destruct
*/

typedef enum {
      ORD_JUSTIFY_LEFT,             // Pretty self explanatory really.
      ORD_JUSTIFY_RIGHT,
      ORD_JUSTIFY_CENTER,
      ORD_JUSTIFY_COMBINE,          // allow the button to be put on the same line
                                                // as other orders with the same justify type
      ORD_NUM_JUSTIFY_TYPES,
} ORDBUTTONJUSTIFY;

// maximum number of orders on one line
#define ORD_MAX_COMBINE_BUTS  3

#define ORD_JUSTIFY_MASK      0x0f
#define ORD_JUSTIFY_NEWLINE   0x10  // Or with ORDBUTTONJUSTIFY enum type to specify start on new line.

typedef struct {
      ORDBUTTONCLASS Class;                           // The class of button.
      SECONDARY_ORDER Order;                          // The droid order.
      UDWORD StateMask;                               // It's state mask.
      ORDBUTTONTYPE ButType;                          // The group type.
      ORDBUTTONJUSTIFY ButJustify;              // Button justification.
      UDWORD ButBaseID;                               // Starting widget ID for buttons
      UWORD NumButs;                                        // Number of buttons ( = number of states )
      UWORD AcNumButs;                                // Actual bumber of buttons enabled.
      UWORD ButImageID[MAX_ORDER_BUTS];         // Image ID's for each button ( normal ).
      UWORD ButGreyID[MAX_ORDER_BUTS];          // Image ID's for each button ( greyed ).
      UWORD ButHilightID[MAX_ORDER_BUTS];       // Image ID's for each button ( hilight overlay ).
      UWORD ButTips[MAX_ORDER_BUTS];                  // Tip string id for each button.
      SECONDARY_STATE States[MAX_ORDER_BUTS];   // Order state relating to each button.
} ORDERBUTTONS;


typedef struct {
      UWORD OrderIndex;       // Index into ORDERBUTTONS array of available orders.
      UWORD RefCount;               // Number of times this order is referenced.
} AVORDER;


enum
{
      STR_DORD_RANGE1,
      STR_DORD_RANGE2,
      STR_DORD_RANGE3,
      STR_DORD_REPAIR1,
      STR_DORD_REPAIR2,
      STR_DORD_REPAIR3,
      STR_DORD_FIRE1,
      STR_DORD_FIRE2,
      STR_DORD_FIRE3,
      STR_DORD_PATROL,
      STR_DORD_PERSUE,
      STR_DORD_GUARD,
      STR_DORD_HOLDPOS,
      STR_DORD_RETREPAIR,
      STR_DORD_RETBASE,
      STR_DORD_EMBARK,
      STR_DORD_ARMRECYCLE,
      STR_DORD_RECYCLE,
      STR_DORD_FACTORY,
      STR_DORD_CYBORG_FACTORY,
      STR_DORD_FIREDES,
      STR_DORD_VTOL_FACTORY,
      STR_DORD_CIRCLE,
};

// return translated text
static const char *getDORDDescription(int id)
{
            switch ( id )
            {
                  case STR_DORD_RANGE1         : return _("Short Range");
                  case STR_DORD_RANGE2         : return _("Long Range");
                  case STR_DORD_RANGE3         : return _("Optimum Range");
                  case STR_DORD_REPAIR1        : return _("Retreat at Medium Damage");
                  case STR_DORD_REPAIR2        : return _("Retreat at Heavy Damage");
                  case STR_DORD_REPAIR3        : return _("Do or Die!");
                  case STR_DORD_FIRE1          : return _("Fire-At-Will");
                  case STR_DORD_FIRE2          : return _("Return Fire");
                  case STR_DORD_FIRE3          : return _("Hold Fire");
                  case STR_DORD_PATROL         : return _("Patrol");
                  case STR_DORD_PERSUE         : return _("Pursue");
                  case STR_DORD_GUARD          : return _("Guard Position");
                  case STR_DORD_HOLDPOS        : return _("Hold Position");
                  case STR_DORD_RETREPAIR      : return _("Return For Repair");
                  case STR_DORD_RETBASE        : return _("Return To HQ");
                  case STR_DORD_EMBARK         : return _("Go to Transport");
                  case STR_DORD_ARMRECYCLE     : return _("Return for Recycling");
                  case STR_DORD_RECYCLE        : return _("Recycle");
                  case STR_DORD_FACTORY        : return _("Assign Factory Production");
                  case STR_DORD_CYBORG_FACTORY : return _("Assign Cyborg Factory Production");
                  case STR_DORD_FIREDES        : return _("Assign Fire Support");
                  case STR_DORD_VTOL_FACTORY   : return _("Assign VTOL Factory Production");
                  case STR_DORD_CIRCLE         : return _("Circle");

                  default : return "";  // make compiler shut up
            }
};

// Define the order button groups.
ORDERBUTTONS OrderButtons[NUM_ORDERS]=
{
      {
            ORDBUTCLASS_NORMAL,
            DSO_ATTACK_RANGE,
            DSS_ARANGE_MASK,
            ORD_BTYPE_RADIO,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_ATTACK_RANGE,
            3,0,
            {IMAGE_ORD_RANGE3UP,    IMAGE_ORD_RANGE1UP,     IMAGE_ORD_RANGE2UP},
            {IMAGE_ORD_RANGE3UP,    IMAGE_ORD_RANGE1UP,     IMAGE_ORD_RANGE2UP},
            {IMAGE_DES_HILIGHT,           IMAGE_DES_HILIGHT,      IMAGE_DES_HILIGHT},
            {STR_DORD_RANGE3, STR_DORD_RANGE1,  STR_DORD_RANGE2},
            {DSS_ARANGE_DEFAULT,    DSS_ARANGE_SHORT, DSS_ARANGE_LONG}
      },
      {
            ORDBUTCLASS_NORMAL,
            DSO_REPAIR_LEVEL,
            DSS_REPLEV_MASK,
            ORD_BTYPE_RADIO,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_REPAIR_LEVEL,
            3,0,
            {IMAGE_ORD_REPAIR3UP,   IMAGE_ORD_REPAIR2UP,    IMAGE_ORD_REPAIR1UP},
            {IMAGE_ORD_REPAIR3UP,   IMAGE_ORD_REPAIR2UP,    IMAGE_ORD_REPAIR1UP},
            {IMAGE_DES_HILIGHT,           IMAGE_DES_HILIGHT,      IMAGE_DES_HILIGHT},
            {STR_DORD_REPAIR3,      STR_DORD_REPAIR2, STR_DORD_REPAIR1},
            {DSS_REPLEV_NEVER,      DSS_REPLEV_HIGH,  DSS_REPLEV_LOW}
      },
      {
            ORDBUTCLASS_NORMAL,
            DSO_ATTACK_LEVEL,
            DSS_ALEV_MASK,
            ORD_BTYPE_RADIO,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_ATTACK_LEVEL,
            3,0,
            {IMAGE_ORD_FATWILLUP,   IMAGE_ORD_RETFIREUP,    IMAGE_ORD_HOLDFIREUP},
            {IMAGE_ORD_FATWILLUP,   IMAGE_ORD_RETFIREUP,    IMAGE_ORD_HOLDFIREUP},
            {IMAGE_DES_HILIGHT,           IMAGE_DES_HILIGHT,      IMAGE_DES_HILIGHT},
            {STR_DORD_FIRE1,  STR_DORD_FIRE2,   STR_DORD_FIRE3},
            {DSS_ALEV_ALWAYS, DSS_ALEV_ATTACKED,      DSS_ALEV_NEVER}
      },
      {
            ORDBUTCLASS_NORMAL,
            DSO_FIRE_DESIGNATOR,
            DSS_FIREDES_MASK,
            ORD_BTYPE_BOOLEAN,
            ORD_JUSTIFY_COMBINE,
            IDORDER_FIRE_DESIGNATOR,
            1,0,
            {IMAGE_ORD_FIREDES_UP,  0,    0},
            {IMAGE_ORD_FIREDES_UP,  0,    0},
            {IMAGE_DES_HILIGHT,     0,    0},
            {STR_DORD_FIREDES,      0,    0},
            {DSS_FIREDES_SET, 0,    0}
      },

      {
            ORDBUTCLASS_NORMAL,
            DSO_PATROL,
            DSS_PATROL_MASK,
            ORD_BTYPE_BOOLEAN,
            ORD_JUSTIFY_COMBINE,
            IDORDER_PATROL,
            1,0,
            {IMAGE_ORD_PATROLUP,    0,    0},
            {IMAGE_ORD_PATROLUP,    0,    0},
            {IMAGE_DES_HILIGHT,     0,    0},
            {STR_DORD_PATROL, 0,    0},
            {DSS_PATROL_SET,  0,    0}
      },

      {
            ORDBUTCLASS_NORMAL,
            DSO_CIRCLE,
            DSS_CIRCLE_MASK,
            ORD_BTYPE_BOOLEAN,
            ORD_JUSTIFY_COMBINE,
            IDORDER_CIRCLE,
            1,0,
            {IMAGE_ORD_PATROLUP,    0,    0},
            {IMAGE_ORD_PATROLUP,    0,    0},
            {IMAGE_DES_HILIGHT,     0,    0},
            {STR_DORD_CIRCLE, 0,    0},
            {DSS_CIRCLE_SET,  0,    0}
      },

      {
            ORDBUTCLASS_NORMAL,
            DSO_HALTTYPE,
            DSS_HALT_MASK,
            ORD_BTYPE_RADIO,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_HALT_TYPE,
            3,0,
            {IMAGE_ORD_PERSUEUP,    IMAGE_ORD_GUARDUP,      IMAGE_ORD_HALTUP},
            {IMAGE_ORD_PERSUEUP,    IMAGE_ORD_GUARDUP,      IMAGE_ORD_HALTUP},
            {IMAGE_DES_HILIGHT,           IMAGE_DES_HILIGHT,      IMAGE_DES_HILIGHT},
            {STR_DORD_PERSUE, STR_DORD_GUARD,   STR_DORD_HOLDPOS},
            {DSS_HALT_PERSUE, DSS_HALT_GUARD,   DSS_HALT_HOLD}
      },
      {
            ORDBUTCLASS_NORMAL,
            DSO_RETURN_TO_LOC,
            DSS_RTL_MASK,
            ORD_BTYPE_RADIO,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_RETURN,
            3,0,

            {IMAGE_ORD_RTRUP, IMAGE_ORD_GOTOHQUP,     IMAGE_ORD_EMBARKUP},
            {IMAGE_ORD_RTRUP, IMAGE_ORD_GOTOHQUP,     IMAGE_ORD_EMBARKUP},

            {IMAGE_DES_HILIGHT,           IMAGE_DES_HILIGHT,      IMAGE_DES_HILIGHT},
            {STR_DORD_RETREPAIR,    STR_DORD_RETBASE, STR_DORD_EMBARK},
            {DSS_RTL_REPAIR,  DSS_RTL_BASE,     DSS_RTL_TRANSPORT},
      },
/*    {
            ORDBUTCLASS_NORMAL,
            DSO_HOLD,
            DSS_HOLD_MASK,
            ORD_BTYPE_BOOLEAN,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_HOLD,
            1,0,
            {IMAGE_ORD_HALTUP,      0,    0},
            {IMAGE_ORD_HALTUP,      0,    0},
            {IMAGE_DES_HILIGHT,     0,    0},
            {STR_DORD_HOLDPOS,      0,    0},
            {DSS_HOLD_SET,    0,    0}
      },
//    {
//          ORDBUTCLASS_NORMALMIXED,
//          DSO_RETURN_TO_BASE, DSO_EMBARK,            DSO_RETURN_TO_REPAIR,
//          DSS_RTB_MASK,           DSS_EMBARK_MASK, DSS_RTR_MASK,
//          ORD_BTYPE_BOOLEAN,
//          ORD_JUSTIFY_CENTER,
//          IDORDER_RETURN_TO_BASE,IDORDER_EMBARK,IDORDER_RETURN_TO_REPAIR,
//          3,0,
//          {IMAGE_ORD_GOTOHQUP,    IMAGE_ORD_GOTOHQUP,     IMAGE_ORD_GOTOHQUP},
//          {IMAGE_ORD_GOTOHQUP,    IMAGE_ORD_GOTOHQUP,     IMAGE_ORD_GOTOHQUP},
//          {IMAGE_DES_HILIGHT,     IMAGE_DES_HILIGHT,      IMAGE_DES_HILIGHT},
//          {STR_DORD_RETBASE,      STR_DORD_RETBASE, STR_DORD_RETREPAIR},
//          {DSS_RTB_SET,     DSS_EMBARK_SET,   DSS_RTR_SET}
//    },
      {
            ORDBUTCLASS_NORMAL,
            DSO_RETURN_TO_BASE,
            DSS_RTB_MASK,
            ORD_BTYPE_BOOLEAN,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_RETURN_TO_BASE,
            1,0,
            {IMAGE_ORD_GOTOHQUP,    0,    0},
            {IMAGE_ORD_GOTOHQUP,    0,    0},
            {IMAGE_DES_HILIGHT,     0,    0},
            {STR_DORD_RETBASE,      0,    0},
            {DSS_RTB_SET,     0,    0}
      },
      {
            ORDBUTCLASS_NORMAL,
            DSO_EMBARK,
            DSS_EMBARK_MASK,
            ORD_BTYPE_BOOLEAN,
            ORD_JUSTIFY_CENTER,
            IDORDER_EMBARK,
            1,0,
            {IMAGE_ORD_GOTOHQUP,    0,    0},
            {IMAGE_ORD_GOTOHQUP,    0,    0},
            {IMAGE_DES_HILIGHT,     0,    0},
            {STR_DORD_EMBARK, 0,    0},
            {DSS_EMBARK_SET,  0,    0}
      },
      {
            ORDBUTCLASS_NORMAL,
            DSO_RETURN_TO_REPAIR,
            DSS_RTR_MASK,
            ORD_BTYPE_BOOLEAN,
            ORD_JUSTIFY_CENTER,
            IDORDER_RETURN_TO_REPAIR,
            1,0,
            {IMAGE_ORD_GOTOHQUP,    0,    0},
            {IMAGE_ORD_GOTOHQUP,    0,    0},
            {IMAGE_DES_HILIGHT,     0,    0},
            {STR_DORD_RETREPAIR,    0,    0},
            {DSS_RTR_SET,     0,    0}
      },
//    {
//          ORDBUTCLASS_NORMAL,
//          DSO_DESTRUCT,
//          DSS_DESTRUCT_MASK,
//          ORD_BTYPE_BOOLEAN_DEPEND,
//          ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
//          IDORDER_DESTRUCT,
//          2,0,
//          {IMAGE_ORD_DESTRUCT1UP, IMAGE_ORD_DESTRUCT2UP,  0},
//          {IMAGE_ORD_DESTRUCT1UP, IMAGE_ORD_DESTRUCT2GREY,      0},
//          {IMAGE_DES_HILIGHT,     IMAGE_DES_HILIGHT,      0},
//          {STR_DORD_ARMDESTRUCT,  STR_DORD_DESTRUCT,      0},
//          {DSS_DESTRUCT_SET,      DSS_DESTRUCT_SET, 0}
//    },*/
      {
            ORDBUTCLASS_NORMAL,
            DSO_RECYCLE,
            DSS_RECYCLE_MASK,
            ORD_BTYPE_BOOLEAN_DEPEND,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_RECYCLE,
            2,0,
            {IMAGE_ORD_DESTRUCT1UP, IMAGE_ORD_DESTRUCT2UP,  0},
            {IMAGE_ORD_DESTRUCT1UP, IMAGE_ORD_DESTRUCT2GREY,      0},
            {IMAGE_DES_HILIGHT,     IMAGE_DES_HILIGHT,      0},
            {STR_DORD_ARMRECYCLE,   STR_DORD_RECYCLE, 0},
            {DSS_RECYCLE_SET, DSS_RECYCLE_SET,  0}
      },
      {
            ORDBUTCLASS_FACTORY,
            DSO_ASSIGN_PRODUCTION,
            DSS_ASSPROD_MASK,
            ORD_BTYPE_BOOLEAN_COMBINE,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_ASSIGN_PRODUCTION,
            5,0,
            {IMAGE_ORD_FAC1UP,            IMAGE_ORD_FAC2UP, IMAGE_ORD_FAC3UP, IMAGE_ORD_FAC4UP, IMAGE_ORD_FAC5UP  },
            {IMAGE_ORD_FAC1UP,            IMAGE_ORD_FAC2UP, IMAGE_ORD_FAC3UP, IMAGE_ORD_FAC4UP, IMAGE_ORD_FAC5UP  },
            {IMAGE_ORD_FACHILITE,   IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE     },
            {STR_DORD_FACTORY,      STR_DORD_FACTORY, STR_DORD_FACTORY, STR_DORD_FACTORY, STR_DORD_FACTORY},
            { 0x01 << DSS_ASSPROD_SHIFT, 0x02 << DSS_ASSPROD_SHIFT, 0x04 << DSS_ASSPROD_SHIFT,
              0x08 << DSS_ASSPROD_SHIFT, 0x10 << DSS_ASSPROD_SHIFT }
      },
      {
            ORDBUTCLASS_CYBORGFACTORY,
            DSO_ASSIGN_CYBORG_PRODUCTION,
            DSS_ASSPROD_MASK,
            ORD_BTYPE_BOOLEAN_COMBINE,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_ASSIGN_CYBORG_PRODUCTION,
            5,0,
            {IMAGE_ORD_FAC1UP,            IMAGE_ORD_FAC2UP, IMAGE_ORD_FAC3UP, IMAGE_ORD_FAC4UP, IMAGE_ORD_FAC5UP  },
            {IMAGE_ORD_FAC1UP,            IMAGE_ORD_FAC2UP, IMAGE_ORD_FAC3UP, IMAGE_ORD_FAC4UP, IMAGE_ORD_FAC5UP  },
            {IMAGE_ORD_FACHILITE,   IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE     },
            {STR_DORD_CYBORG_FACTORY,     STR_DORD_CYBORG_FACTORY,      STR_DORD_CYBORG_FACTORY,      STR_DORD_CYBORG_FACTORY,      STR_DORD_CYBORG_FACTORY},
            { 0x01 << DSS_ASSPROD_CYBORG_SHIFT, 0x02 << DSS_ASSPROD_CYBORG_SHIFT, 0x04 << DSS_ASSPROD_CYBORG_SHIFT,
              0x08 << DSS_ASSPROD_CYBORG_SHIFT, 0x10 << DSS_ASSPROD_CYBORG_SHIFT }
      },
      {
            ORDBUTCLASS_VTOLFACTORY,
            DSO_ASSIGN_VTOL_PRODUCTION,
            DSS_ASSPROD_MASK,
            ORD_BTYPE_BOOLEAN_COMBINE,
            ORD_JUSTIFY_CENTER | ORD_JUSTIFY_NEWLINE,
            IDORDER_ASSIGN_VTOL_PRODUCTION,
            5,0,
            {IMAGE_ORD_FAC1UP,            IMAGE_ORD_FAC2UP, IMAGE_ORD_FAC3UP, IMAGE_ORD_FAC4UP, IMAGE_ORD_FAC5UP  },
            {IMAGE_ORD_FAC1UP,            IMAGE_ORD_FAC2UP, IMAGE_ORD_FAC3UP, IMAGE_ORD_FAC4UP, IMAGE_ORD_FAC5UP  },
            {IMAGE_ORD_FACHILITE,   IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE,IMAGE_ORD_FACHILITE     },
            {STR_DORD_VTOL_FACTORY, STR_DORD_VTOL_FACTORY,  STR_DORD_VTOL_FACTORY,  STR_DORD_VTOL_FACTORY,  STR_DORD_VTOL_FACTORY},
            { 0x01 << DSS_ASSPROD_VTOL_SHIFT, 0x02 << DSS_ASSPROD_VTOL_SHIFT, 0x04 << DSS_ASSPROD_VTOL_SHIFT,
              0x08 << DSS_ASSPROD_VTOL_SHIFT, 0x10 << DSS_ASSPROD_VTOL_SHIFT }
      },
};

extern BOOL ClosingOrder;
extern W_SCREEN *psWScreen;
extern void intDisplayPlainForm(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours);

static BOOL BuildSelectedDroidList(void);
//static BOOL factorySelected(void);
static BOOL SetSecondaryState(SECONDARY_ORDER sec, SECONDARY_STATE State);
static BOOL BuildDroidOrderList(void);
static BOOL BuildStructureOrderList(STRUCTURE *psStructure);
static SDWORD GetSecondaryStates(SECONDARY_ORDER sec);

static UDWORD GetImageWidth(IMAGEFILE *ImageFile,UDWORD ImageID);
static UDWORD GetImageHeight(IMAGEFILE *ImageFile,UDWORD ImageID);

static UWORD NumSelectedDroids;
static DROID *SelectedDroids[MAX_SELECTED_DROIDS];
static STRUCTURE *psSelectedFactory;
static UWORD NumAvailableOrders;
static AVORDER AvailableOrders[MAX_AVAILABLE_ORDERS];
//works on factories now as well - AB 21/04/99
//static BOOL CheckDroidOrderList(void);
static BOOL CheckObjectOrderList(void);
static BOOL intRefreshOrderButtons(void);




BOOL OrderUp = false;

// update the order interface only if it is already open.
BOOL intUpdateOrder(DROID *psDroid)
{
      if(widgGetFromID(psWScreen,IDORDER_FORM) != NULL && OrderUp)
      {
            widgDelete(psWScreen, IDORDER_CLOSE);
        //changed to a BASE_OBJECT to accomodate the factories - AB 21/04/99
            //intAddOrder(psDroid);
        intAddOrder((BASE_OBJECT *)psDroid);
      }

      return true;
}

// Add the droid order screen.
// Returns true if the form was displayed ok.
//
//changed to a BASE_OBJECT to accomodate the factories - AB 21/04/99
//BOOL _intAddOrder(DROID *Droid)
BOOL intAddOrder(BASE_OBJECT *psObj)
{
      W_FORMINIT              sFormInit;
      W_BUTINIT               sButInit;
      BOOL Animate = true;
      SECONDARY_STATE State;
      UWORD i,j;//,k;
      UWORD OrdIndex;
      W_FORM *Form;
      UWORD Height, NumDisplayedOrders;
      UWORD NumButs;
      UWORD NumJustifyButs, NumCombineButs, NumCombineBefore;
      BOOL  bLastCombine, bHidden;

    //added to accomodate the factories - AB 21/04/99
    DROID       *Droid;
    STRUCTURE   *psStructure;


      if(bInTutorial)
      {
            // No RMB orders in tutorial!!
            return(false);
      }

      // Is the form already up?
      if(widgGetFromID(psWScreen,IDORDER_FORM) != NULL) {
            intRemoveOrderNoAnim();
            Animate = false;
      }
      // Is the stats window up?
      if(widgGetFromID(psWScreen,IDSTAT_FORM) != NULL) {
            intRemoveStatsNoAnim();
            Animate = false;
      }

    if (psObj)
    {
        if (psObj->type == OBJ_DROID)
        {
            Droid = (DROID *)psObj;
            psStructure =  NULL;
        }
        else if (psObj->type == OBJ_STRUCTURE)
        {
            Droid = NULL;
            psStructure = (STRUCTURE *)psObj;
            psSelectedFactory = psStructure;
        }
        else
        {
            ASSERT( false, "_intAddOrder: Invalid object type" );
            Droid = NULL;
            psStructure =  NULL;
        }
    }
    else
    {
        Droid = NULL;
        psStructure =  NULL;
    }



  //  intResetScreen(true);
      setWidgetsStatus(true);

      NumAvailableOrders = 0;
      NumSelectedDroids = 0;

      // Selected droid is a command droid?
      if ((Droid != NULL) && (Droid->droidType == DROID_COMMAND))
      {
            // displaying for a command droid - ignore any other droids
            SelectedDroids[0] = Droid;
            NumSelectedDroids = 1;
      }
    //added to accomodate the factories - AB 21/04/99
    else if (psStructure != NULL)
    {
        if (!BuildStructureOrderList(psStructure))
        {
            return false;
        }
    }
      // Otherwise build a list of selected droids.
      else if(!BuildSelectedDroidList()) {
            // If no droids selected then see if we were given a specific droid.
            if(Droid != NULL) {
                  // and put it in the list.
                  SelectedDroids[0] = Droid;
                  NumSelectedDroids = 1;
            }
      }

      // Build a list of orders available for the list of selected droids. - if a factory has not been selected
    if (psStructure == NULL)
    {
          if(!BuildDroidOrderList())
        {
                // If no orders then return;
                return false;
        }
      }

      widgEndScreen(psWScreen);

      /* Create the basic form */

      memset(&sFormInit, 0, sizeof(W_FORMINIT));
      sFormInit.formID = 0;
      sFormInit.id = IDORDER_FORM;
      sFormInit.style = WFORM_PLAIN;
      sFormInit.x = ORDER_X;
      sFormInit.y = ORDER_Y;
      sFormInit.width = ORDER_WIDTH;
      sFormInit.height =      ORDER_HEIGHT;
      // If the window was closed then do open animation.
      if(Animate) {
            sFormInit.pDisplay = intOpenPlainForm;
            sFormInit.disableChildren = true;
      } else {
      // otherwise just recreate it.
            sFormInit.pDisplay = intDisplayPlainForm;
      }
      if (!widgAddForm(psWScreen, &sFormInit))
      {
            return false;
      }



      // Add the close button.
      memset(&sButInit, 0, sizeof(W_BUTINIT));
      sButInit.formID = IDORDER_FORM;
      sButInit.id = IDORDER_CLOSE;
      sButInit.style = WBUT_PLAIN;
      sButInit.x = ORDER_WIDTH - CLOSE_WIDTH;
      sButInit.y = 0;
      sButInit.width = CLOSE_WIDTH;
      sButInit.height = CLOSE_HEIGHT;
      sButInit.pTip = _("Close");
      sButInit.FontID = font_regular;
      sButInit.pDisplay = intDisplayImageHilight;
      sButInit.UserData = PACKDWORD_TRI(0,IMAGE_CLOSEHILIGHT , IMAGE_CLOSE);
      if (!widgAddButton(psWScreen, &sButInit))
      {
            return false;
      }


      memset(&sButInit, 0, sizeof(W_BUTINIT));
      sButInit.formID = IDORDER_FORM;
      sButInit.id = IDORDER_CLOSE+1;
      sButInit.style = WBUT_PLAIN;
      sButInit.pDisplay = intDisplayButtonHilight;
      sButInit.FontID = font_regular;
      sButInit.y = ORDER_BUTY;

      Height = 0;
      NumDisplayedOrders = 0;

      for(j=0; ((j<NumAvailableOrders) && (NumDisplayedOrders < MAX_DISPLAYABLE_ORDERS)); j++) {
            OrdIndex = AvailableOrders[j].OrderIndex;

            // Get current order state.
            //secondaryGetState(SelectedDroids[0], OrderButtons[OrdIndex].Order, &State);
            State = GetSecondaryStates(OrderButtons[OrdIndex].Order);

            // Get number of buttons.
            NumButs = OrderButtons[OrdIndex].NumButs;
            // Set actual number of buttons.
            OrderButtons[OrdIndex].AcNumButs = NumButs;

            // Handle special case for factory -> command droid assignment buttons.
            switch (OrderButtons[OrdIndex].Class) {
                  case ORDBUTCLASS_FACTORY:
                        NumButs = countAssignableFactories((UBYTE)selectedPlayer,FACTORY_FLAG);
                        break;
                  case ORDBUTCLASS_CYBORGFACTORY:
                        NumButs = countAssignableFactories((UBYTE)selectedPlayer,CYBORG_FLAG);
                        break;
                  case ORDBUTCLASS_VTOLFACTORY:
                        NumButs = countAssignableFactories((UBYTE)selectedPlayer,VTOL_FLAG);
                        break;
                  default:
                        break;
            }

            sButInit.id = OrderButtons[OrdIndex].ButBaseID;

            NumJustifyButs = NumButs;
//          for(k=j; k<NumAvailableOrders; k++) {
//                UWORD Index = AvailableOrders[j].OrderIndex;
//                if(OrderButtons[OrdIndex].ButJustify & ORD_JUSTIFY_NEWLINE) {
//                      DBPRINTF(("NewLine %d \n",k);
//                      break;
//                } else {
//                      DBPRINTF(("SameLine %d \n",k);
//                }
//          }

            bLastCombine = false;

            switch (OrderButtons[OrdIndex].ButJustify & ORD_JUSTIFY_MASK) {
                  case ORD_JUSTIFY_LEFT:
                        sButInit.x = ORDER_BUTX;
                        break;

                  case ORD_JUSTIFY_RIGHT:
                        sButInit.x = (SWORD)(sFormInit.width - ORDER_BUTX -
                                    ( ((NumJustifyButs * GetImageWidth(IntImages,OrderButtons[OrdIndex].ButImageID[0])) +
                                    ((NumJustifyButs-1) * ORDER_BUTGAP ) ) ));
                        break;

                  case ORD_JUSTIFY_CENTER:
//                      sButInit.x = (SWORD)((sFormInit.width / 2) -
//                                  ( ((NumJustifyButs * GetImageWidth(IntImages,OrderButtons[OrdIndex].ButImageID[0])) +
//                                  ((NumJustifyButs-1) * ORDER_BUTGAP ) ) / 2 ));
                        sButInit.x = ((SWORD)((sFormInit.width ) -
                                    ( ((NumJustifyButs * GetImageWidth(IntImages,OrderButtons[OrdIndex].ButImageID[0])) +
                                    ((NumJustifyButs-1) * ORDER_BUTGAP ) ))))/2;
                        break;

                  case ORD_JUSTIFY_COMBINE:
                        // see how many are on this line before the button
                        NumCombineBefore = 0;
                        for(i=0; i<j; i++)
                        {
                              if ((OrderButtons[AvailableOrders[i].OrderIndex].ButJustify & ORD_JUSTIFY_MASK)
                                                == ORD_JUSTIFY_COMBINE)
                              {
                                    NumCombineBefore += 1;
                              }
                        }
                        NumCombineButs = (UWORD)(NumCombineBefore + 1);

                        // now see how many in total
                        for(i=(UWORD)(j+1); i<NumAvailableOrders; i++)
                        {
                              if ((OrderButtons[AvailableOrders[i].OrderIndex].ButJustify & ORD_JUSTIFY_MASK)
                                                == ORD_JUSTIFY_COMBINE)
                              {
                                    NumCombineButs += 1;
                              }
                        }

                        // get position on line
                        NumCombineButs = (UWORD)(NumCombineButs - (NumCombineBefore - (NumCombineBefore % ORD_MAX_COMBINE_BUTS)));

                        if (NumCombineButs >= ORD_MAX_COMBINE_BUTS)
                        {
                              // the buttons will fill the line
                              sButInit.x = (SWORD)(ORDER_BUTX +
                                          (GetImageWidth(IntImages,OrderButtons[OrdIndex].ButImageID[0]) + ORDER_BUTGAP ) * NumCombineBefore);
                        }
                        else
                        {
                              // center the buttons
                              sButInit.x = (SWORD)((sFormInit.width / 2) -
                                          ( ((NumCombineButs * GetImageWidth(IntImages,OrderButtons[OrdIndex].ButImageID[0])) +
                                          ((NumCombineButs-1) * ORDER_BUTGAP ) ) / 2 ));
                              sButInit.x = (SWORD)(sButInit.x +
                                    (GetImageWidth(IntImages,OrderButtons[OrdIndex].ButImageID[0]) + ORDER_BUTGAP ) * NumCombineBefore);
                        }

                        // see if need to start a new line of buttons
                        if ((NumCombineBefore + 1) == (NumCombineButs % ORD_MAX_COMBINE_BUTS))
                        {
                              bLastCombine = true;
                        }

                        break;
            }

            for(i=0; i<OrderButtons[OrdIndex].AcNumButs; i++) {
                  sButInit.pTip = getDORDDescription(OrderButtons[OrdIndex].ButTips[i]);
                  sButInit.width = (UWORD)GetImageWidth(IntImages,OrderButtons[OrdIndex].ButImageID[i]);
                  sButInit.height = (UWORD)GetImageHeight(IntImages,OrderButtons[OrdIndex].ButImageID[i]);
                  sButInit.UserData = PACKDWORD_TRI(
                                                            OrderButtons[OrdIndex].ButGreyID[i],
                                                            OrderButtons[OrdIndex].ButHilightID[i],
                                                            OrderButtons[OrdIndex].ButImageID[i]
                                                                   );
                  if(!widgAddButton(psWScreen, &sButInit))
                  {
                        return false;
                  }

                  // Set the default state for the button.
                  switch(OrderButtons[OrdIndex].ButType) {
                        case ORD_BTYPE_RADIO:
                        case ORD_BTYPE_BOOLEAN:
                              if((State & OrderButtons[OrdIndex].StateMask) == (UDWORD)OrderButtons[OrdIndex].States[i]) {
                                    widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK);
                              } else {
                                    widgSetButtonState(psWScreen, sButInit.id, 0);
                              }
                              break;

                        case ORD_BTYPE_BOOLEAN_DEPEND:
                              if((State & OrderButtons[OrdIndex].StateMask) == (UDWORD)OrderButtons[OrdIndex].States[i]) {
                                    widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK);
                              } else {
                                    if(i == 0) {
                                          widgSetButtonState(psWScreen, sButInit.id, 0);
                                    } else {
                                          widgSetButtonState(psWScreen, sButInit.id, WBUT_DISABLE);
                                    }
                              }
                              break;
                        case ORD_BTYPE_BOOLEAN_COMBINE:
                              if( State & (UDWORD)OrderButtons[OrdIndex].States[i] )
                              {
                                    widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK);
                              }
                              break;
                  }

                  // may not add a button if the factory doesn't exist
                  bHidden = false;
                  switch (OrderButtons[OrdIndex].Class)
                  {
                  case ORDBUTCLASS_FACTORY:
                        if (!checkFactoryExists(selectedPlayer, FACTORY_FLAG, i))
                        {
                              widgHide(psWScreen, sButInit.id);
                              bHidden = true;
                        }
                        break;
                  case ORDBUTCLASS_CYBORGFACTORY:
                        if (!checkFactoryExists(selectedPlayer, CYBORG_FLAG, i))
                        {
                              widgHide(psWScreen, sButInit.id);
                              bHidden = true;
                        }
                        break;
                  case ORDBUTCLASS_VTOLFACTORY:
                        if (!checkFactoryExists(selectedPlayer, VTOL_FLAG, i))
                        {
                              widgHide(psWScreen, sButInit.id);
                              bHidden = true;
                        }
                        break;
                  default:
                        break;
                  }

                  if (!bHidden)
                  {

                        sButInit.x = (SWORD)(sButInit.x + sButInit.width + ORDER_BUTGAP);
                  }
                  sButInit.id++;
            }

            if (((OrderButtons[OrdIndex].ButJustify & ORD_JUSTIFY_MASK) != ORD_JUSTIFY_COMBINE) ||
                  bLastCombine)
            {
                  sButInit.y = (SWORD)(sButInit.y + sButInit.height + ORDER_BUTGAP);
                  Height = (UWORD)(Height + sButInit.height + ORDER_BUTGAP);
            }
            NumDisplayedOrders ++;
      }

      // Now we know how many orders there are we can resize the form accordingly.
      Form = (W_FORM*)widgGetFromID(psWScreen,IDORDER_FORM);
      Form->height = (UWORD)(Height + CLOSE_HEIGHT + ORDER_BUTGAP);
      Form->y = (SWORD)(ORDER_BOTTOMY-Form->height);



      OrderUp = true;

      return true;
}


// Do any housekeeping for the droid order screen.
// Any droids that die now get set to NULL - John.
// No droids being selected no longer removes the screen,
// this lets the screen work with command droids - John.
void intRunOrder(void)
{
      UWORD i;
      UDWORD NumDead = 0;
      UDWORD NumSelected = 0;

      // Check to see if there all dead or unselected.
      for(i=0; i<NumSelectedDroids; i++) {
            if (SelectedDroids[i])
            {
//                if(SelectedDroids[i]->selected) {
                        NumSelected++;
//                }
                  if(SelectedDroids[i]->died) {
                        NumDead++;
                        SelectedDroids[i]=NULL;
                  }
            }
      }

      // If all dead then remove the screen.
      if(NumDead == NumSelectedDroids)
    {
        //might have a factory selected
        if (psSelectedFactory == NULL)
        {
            intRemoveOrder();
            return;
        }
      }

      // If droids no longer selected then remove screen.
      if(NumSelected == 0)
    {
        //might have a factory selected
        if (psSelectedFactory == NULL)
        {
            intRemoveOrder();
            return;
        }
      }
}


// Process the droid order screen.
//
void intProcessOrder(UDWORD id)
{
      UWORD i;
      UWORD OrdIndex;
      UDWORD BaseID;
      UDWORD StateIndex;
      UDWORD CombineState;

      if(id == IDORDER_CLOSE) {
            intRemoveOrder();
            if (intMode == INT_ORDER)
            {
                  intMode = INT_NORMAL;
            }
            else
            {
                  /* Unlock the stats button */
                  widgSetButtonState(psWScreen, objStatID, 0);
                  intMode = INT_OBJECT;
            }
            return;
      }

      for(OrdIndex = 0; OrdIndex < NUM_ORDERS; OrdIndex++) {
            BaseID = OrderButtons[OrdIndex].ButBaseID;

            switch(OrderButtons[OrdIndex].ButType) {
                  case ORD_BTYPE_RADIO:
                        if( (id >= BaseID) && (id < BaseID + OrderButtons[OrdIndex].AcNumButs) ) {
                              StateIndex = id - BaseID;

                              for(i=0; i<OrderButtons[OrdIndex].AcNumButs; i++) {
                                    widgSetButtonState(psWScreen, BaseID+i, 0);
                              }
                              if (SetSecondaryState(OrderButtons[OrdIndex].Order,
                                          OrderButtons[OrdIndex].States[StateIndex] & OrderButtons[OrdIndex].StateMask))
                              {
                                    widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK);
                              }
                        }
                        break;

                  case ORD_BTYPE_BOOLEAN:
                        if( (id >= BaseID) && (id < BaseID + OrderButtons[OrdIndex].AcNumButs) ) {
                              StateIndex = id - BaseID;

                              if(widgGetButtonState(psWScreen, id) & WBUT_CLICKLOCK) {
                                    widgSetButtonState(psWScreen, id, 0);
                                    SetSecondaryState(OrderButtons[OrdIndex].Order,0);
                              } else {
                                    widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK);
                                    SetSecondaryState(OrderButtons[OrdIndex].Order,
                                                OrderButtons[OrdIndex].States[StateIndex] & OrderButtons[OrdIndex].StateMask);
                              }

                        }
                        break;

                  case ORD_BTYPE_BOOLEAN_DEPEND:
                        // Toggle the state of this button.
                        if(id == BaseID) {
                              if(widgGetButtonState(psWScreen, id) & WBUT_CLICKLOCK) {
                                    widgSetButtonState(psWScreen, id, 0);
                                    // Disable the dependant button.
                                    widgSetButtonState(psWScreen, id+1, WBUT_DISABLE);
                              } else {
                                    widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK);
                                    // Enable the dependant button.
                                    widgSetButtonState(psWScreen, id+1, 0);
                              }
                        } if( (id > BaseID) && (id < BaseID + OrderButtons[OrdIndex].AcNumButs) ) {
                              // If the previous button is down ( armed )..
                              if(widgGetButtonState(psWScreen,id-1) & WBUT_CLICKLOCK) {
                                    // Toggle the state of this button.
                                    if(widgGetButtonState(psWScreen, id) & WBUT_CLICKLOCK) {
                                          widgSetButtonState(psWScreen, id, 0);
                                          SetSecondaryState(OrderButtons[OrdIndex].Order,0);
                                    } else {
                                          StateIndex = id - BaseID;

                                          widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK);
                                          SetSecondaryState(OrderButtons[OrdIndex].Order,
                                                      OrderButtons[OrdIndex].States[StateIndex] & OrderButtons[OrdIndex].StateMask);
                                    }
                              }
                        }
                        break;
                  case ORD_BTYPE_BOOLEAN_COMBINE:
                        if( (id >= BaseID) && (id < BaseID + OrderButtons[OrdIndex].AcNumButs) ) {
                              // Toggle the state of this button.
                              if(widgGetButtonState(psWScreen, id) & WBUT_CLICKLOCK) {
                                    widgSetButtonState(psWScreen, id, 0);
                              } else {
                                    widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK);
                              }

                              // read the state of all the buttons to get the final state
                              CombineState = 0;
                              for (StateIndex = 0; StateIndex < OrderButtons[OrdIndex].AcNumButs; StateIndex++)
                              {
                                    if ( widgGetButtonState(psWScreen, BaseID + StateIndex) & WBUT_CLICKLOCK )
                                    {
                                          CombineState |= OrderButtons[OrdIndex].States[StateIndex];
                                    }
                              }

                              // set the final state
                              SetSecondaryState(OrderButtons[OrdIndex].Order,
                                                CombineState & OrderButtons[OrdIndex].StateMask);
                        }
                        break;
            }
      }
}


static BOOL _intRefreshOrder(void)
{
      // Is the Order screen up?
      if ((intMode == INT_ORDER) &&
            (widgGetFromID(psWScreen,IDORDER_FORM) != NULL))
      {
            BOOL Ret;

            NumSelectedDroids = 0;
        //check for factory selected first
        if (!psSelectedFactory)
        {
            if (!BuildSelectedDroidList())
            {
                  // no units selected - quit
                      intRemoveOrder();
                      return true;
            }
            }

            // if the orders havn't changed, just reset the state
            //if (CheckDroidOrderList())
        if (CheckObjectOrderList())
            {
                  Ret = intRefreshOrderButtons();
            }
            else
            {
                  // Refresh it by re-adding it.
                  Ret = intAddOrder(NULL);
                  if(Ret == false) {
                        intMode = INT_NORMAL;
                  }
            }
            return Ret;
      }

      return true;
}


// Call to refresh the Order screen, ie when a droids boards it.
//
BOOL intRefreshOrder(void)
{
//    DBPRINTF(("intRefreshOrder\n"));

      return _intRefreshOrder();
}


// Remove the droids order screen with animation.
//
void intRemoveOrder(void)
{

      W_TABFORM *Form;

      widgDelete(psWScreen, IDORDER_CLOSE);

      // Start the window close animation.
      Form = (W_TABFORM*)widgGetFromID(psWScreen,IDORDER_FORM);
      if(Form) {
            Form->display = intClosePlainForm;
            Form->pUserData = NULL; // Used to signal when the close anim has finished.
            Form->disableChildren = true;
            ClosingOrder = true;
            OrderUp = false;
            NumSelectedDroids = 0;
        psSelectedFactory = NULL;
    }

}


// Remove the droids order screen without animation.
//
void intRemoveOrderNoAnim(void)
{
      widgDelete(psWScreen, IDORDER_CLOSE);
      widgDelete(psWScreen, IDORDER_FORM);
      OrderUp = false;
      NumSelectedDroids = 0;
    psSelectedFactory = NULL;
}


// Build a list of currently selected droids.
// Returns true if droids were selected.
//
static BOOL BuildSelectedDroidList(void)
{
      DROID *psDroid;

      for(psDroid = apsDroidLists[selectedPlayer]; psDroid; psDroid = psDroid->psNext) {
            if(psDroid->selected) {
                  if(NumSelectedDroids < MAX_SELECTED_DROIDS) {
                        SelectedDroids[NumSelectedDroids] = psDroid;
                        NumSelectedDroids++;
                  }
            }
      }

      if(NumSelectedDroids) {
            return true;
      }

      return false;
}

//looks thru' the players' list of Structures to see if one is a factory and it is selected
/*static BOOL factorySelected(void)
{
    STRUCTURE *psStruct;

    for (psStruct = apsStructLists[selectedPlayer]; psStruct; psStruct = psStruct->psNext)
    {
        if (psStruct->selected && StructIsFactory(psStruct))
        {
            //found one - set as one to use for the interface
            psSelectedFactory = psStruct;
            return true;
        }
    }
    //obviously never found a factory
    return false;
}*/


// Set the secondary order state for all currently selected droids. And Factory (if one selected)
// Returns true if succesfull.
//
static BOOL SetSecondaryState(SECONDARY_ORDER sec, SECONDARY_STATE State)
{
      UWORD i;

      for(i=0; i<NumSelectedDroids; i++) {
            if (SelectedDroids[i])
            {
                  //Only set the state if it's not a transporter.
                  if(SelectedDroids[i]->droidType != DROID_TRANSPORTER) {
                        if(!secondarySetState(SelectedDroids[i], sec, State)) {
                              return false;
                        }
                  }
            }
      }
    //set the Factory settings
    if (psSelectedFactory)
    {
        if (!setFactoryState(psSelectedFactory, sec, State))
        {
            return false;
        }
    }

      return true;
}


// Build a list of orders available for the selected group of droids.
//
static BOOL BuildDroidOrderList(void)
{
      UWORD OrdIndex;
      UWORD i,j;
      BOOL Found;
      BOOL Sorted;
      AVORDER Tmp;

      NumAvailableOrders = 0;

      for(j=0; j<NumSelectedDroids; j++) {

            for(OrdIndex = 0; OrdIndex < NUM_ORDERS; OrdIndex++) {

                  // Is the order available?
                  if(secondarySupported(SelectedDroids[j], OrderButtons[OrdIndex].Order)) {
                        if(NumAvailableOrders < MAX_AVAILABLE_ORDERS) {
                              // Have we already got this order?
                              Found = false;
                              for(i=0; i<NumAvailableOrders; i++) {
                                    if(AvailableOrders[i].OrderIndex == OrdIndex) {
                                          // Yes! Then increment it's reference count.
                                          AvailableOrders[i].RefCount++;
                                          Found = true;
                                    }
                              }

                              if(!Found) {
                                    // Not already got it so add it to the list of available orders.
                                    AvailableOrders[NumAvailableOrders].OrderIndex = OrdIndex;
                                    AvailableOrders[NumAvailableOrders].RefCount = 1;
                                    NumAvailableOrders++;
                              }
                        }
                  }
            }
      }

      if(NumAvailableOrders == 0) {
            return false;
      }

      if(NumAvailableOrders > 1) {
            // Sort by Order index, A bubble sort? I know but it's only
            // a small list so what the hell.
            do {
                  Sorted = true;
                  for(i=0; i<NumAvailableOrders-1; i++) {
                        if(AvailableOrders[i].OrderIndex > AvailableOrders[i+1].OrderIndex) {
                              Tmp = AvailableOrders[i];
                              AvailableOrders[i] = AvailableOrders[i+1];
                              AvailableOrders[i+1] = Tmp;
                              Sorted = false;
                        }
                  }
            } while(!Sorted);
      }

      return true;
}

// Build a list of orders available for the selected structure.
static BOOL BuildStructureOrderList(STRUCTURE *psStructure)
{
    //only valid for Factories (at the moment)
    if (!StructIsFactory(psStructure))
    {
        ASSERT( false, "BuildStructureOrderList: structure is not a factory" );
        return false;
    }

    //this can be hard-coded!
    AvailableOrders[0].OrderIndex = 0;//DSO_ATTACK_RANGE;
    AvailableOrders[0].RefCount = 1;
    AvailableOrders[1].OrderIndex = 1;//DSO_REPAIR_LEVEL;
    AvailableOrders[1].RefCount = 1;
    AvailableOrders[2].OrderIndex = 2;//DSO_ATTACK_LEVEL;
    AvailableOrders[2].RefCount = 1;
    AvailableOrders[3].OrderIndex = 5;//DSO_HALTTYPE;
    AvailableOrders[3].RefCount = 1;

    NumAvailableOrders = 4;

    return true;
}


// check whether the order list has changed
//works on factories now as well - AB 21/04/99
//static BOOL CheckDroidOrderList(void)
static BOOL CheckObjectOrderList(void)
{
      UWORD OrdIndex;
      UWORD i,j;
      BOOL Found;
      BOOL Sorted;
      AVORDER Tmp;
      UWORD NumNewOrders;
      AVORDER NewAvailableOrders[MAX_AVAILABLE_ORDERS];

      NumNewOrders = 0;

    //added for factories - AB 21/04/99
    if (psSelectedFactory != NULL)
    {
        //only valid for Factories (at the moment)
        if (!StructIsFactory(psSelectedFactory))
        {
            ASSERT( false, "CheckObjectOrderList: structure is not a factory" );
            return false;
        }

        //this can be hard-coded!
        NewAvailableOrders[0].OrderIndex = 0;//DSO_ATTACK_RANGE;
        NewAvailableOrders[0].RefCount = 1;
        NewAvailableOrders[1].OrderIndex = 1;//DSO_REPAIR_LEVEL;
        NewAvailableOrders[1].RefCount = 1;
        NewAvailableOrders[2].OrderIndex = 2;//DSO_ATTACK_LEVEL;
        NewAvailableOrders[2].RefCount = 1;
        NewAvailableOrders[3].OrderIndex = 5;//DSO_HALTTYPE;
        NewAvailableOrders[3].RefCount = 1;

        NumNewOrders = 4;

          if (NumNewOrders != NumAvailableOrders)
          {
                return false;
          }
    }
    else
    {
          for(j=0; j<NumSelectedDroids; j++) {

                for(OrdIndex = 0; OrdIndex < NUM_ORDERS; OrdIndex++) {

                      // Is the order available?
                      if(secondarySupported(SelectedDroids[j], OrderButtons[OrdIndex].Order)) {
                            if(NumNewOrders < MAX_AVAILABLE_ORDERS) {
                                  // Have we already got this order?
                                  Found = false;
                                  for(i=0; i<NumNewOrders; i++) {
                                        if(NewAvailableOrders[i].OrderIndex == OrdIndex) {
                                              // Yes! Then increment it's reference count.
                                              NewAvailableOrders[i].RefCount++;
                                              Found = true;
                                        }
                                  }

                                  if(!Found) {
                                        // Not already got it so add it to the list of available orders.
                                        NewAvailableOrders[NumNewOrders].OrderIndex = OrdIndex;
                                        NewAvailableOrders[NumNewOrders].RefCount = 1;
                                        NumNewOrders++;
                                  }
                            }
                      }
                }
          }

          if (NumNewOrders != NumAvailableOrders)
          {
                return false;
          }

          if(NumNewOrders > 1) {
                // Sort by Order index, A bubble sort? I know but it's only
                // a small list so what the hell.
                do {
                      Sorted = true;
                      for(i=0; i<NumNewOrders-1; i++) {
                            if(NewAvailableOrders[i].OrderIndex > NewAvailableOrders[i+1].OrderIndex) {
                                  Tmp = NewAvailableOrders[i];
                                  NewAvailableOrders[i] = NewAvailableOrders[i+1];
                                  NewAvailableOrders[i+1] = Tmp;
                                  Sorted = false;
                            }
                      }
                } while(!Sorted);
          }
    }

      // now check that all the orders are the same
      for (i=0; i< NumNewOrders; i++)
      {
            if (NewAvailableOrders[i].OrderIndex != AvailableOrders[i].OrderIndex)
            {
                  return false;
            }
      }

      return true;
}

static BOOL intRefreshOrderButtons(void)
{
      SECONDARY_STATE State;
      UWORD i,j;//,k;
      UWORD OrdIndex;
      UWORD NumButs;
      UDWORD      id;

      for(j=0; ((j<NumAvailableOrders) && (j < MAX_DISPLAYABLE_ORDERS)); j++) {
            OrdIndex = AvailableOrders[j].OrderIndex;

            // Get current order state.
            //secondaryGetState(SelectedDroids[0], OrderButtons[OrdIndex].Order, &State);
            State = GetSecondaryStates(OrderButtons[OrdIndex].Order);

            // Get number of buttons.
            NumButs = OrderButtons[OrdIndex].NumButs;
            // Set actual number of buttons.
            OrderButtons[OrdIndex].AcNumButs = NumButs;

            // Handle special case for factory -> command droid assignment buttons.
            switch (OrderButtons[OrdIndex].Class) {
                  case ORDBUTCLASS_FACTORY:
                        NumButs = countAssignableFactories((UBYTE)selectedPlayer,FACTORY_FLAG);
                        break;
                  case ORDBUTCLASS_CYBORGFACTORY:
                        NumButs = countAssignableFactories((UBYTE)selectedPlayer,CYBORG_FLAG);
                        break;
                  case ORDBUTCLASS_VTOLFACTORY:
                        NumButs = countAssignableFactories((UBYTE)selectedPlayer,VTOL_FLAG);
                        break;
                  default:
                        break;
            }

            id = OrderButtons[OrdIndex].ButBaseID;
            for(i=0; i<OrderButtons[OrdIndex].AcNumButs; i++) {

                  // Set the state for the button.
                  switch(OrderButtons[OrdIndex].ButType) {
                        case ORD_BTYPE_RADIO:
                        case ORD_BTYPE_BOOLEAN:
                              if((State & OrderButtons[OrdIndex].StateMask) == (UDWORD)OrderButtons[OrdIndex].States[i]) {
                                    widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK);
                              } else {
                                    widgSetButtonState(psWScreen, id, 0);
                              }
                              break;

                        case ORD_BTYPE_BOOLEAN_DEPEND:
                              if((State & OrderButtons[OrdIndex].StateMask) == (UDWORD)OrderButtons[OrdIndex].States[i]) {
                                    widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK);
                              } else {
                                    if(i == 0) {
                                          widgSetButtonState(psWScreen, id, 0);
                                    } else {
                                          widgSetButtonState(psWScreen, id, WBUT_DISABLE);
                                    }
                              }
                              break;
                        case ORD_BTYPE_BOOLEAN_COMBINE:
                              if( State & (UDWORD)OrderButtons[OrdIndex].States[i] )
                              {
                                    widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK);
                              }
                              break;
                  }

                  id ++;
            }
      }

      return true;
}


// return the state for an order for all the units selected
// if there are multiple states then don't return a state
static SDWORD GetSecondaryStates(SECONDARY_ORDER sec)
{
      SDWORD      i;
      SECONDARY_STATE state, currState;
      BOOL  bFirst;

      state = 0;
      bFirst = true;
    //handle a factory being selected - AB 22/04/99
    if (psSelectedFactory)
    {
        if (getFactoryState(psSelectedFactory, sec, &currState))
        {
            state = currState;
        }
    }
    else //droids
    {
          for(i=0; i<NumSelectedDroids; i++)
          {
                if (secondaryGetState(SelectedDroids[i], sec, &currState))
                {
                      if (bFirst)
                      {
                            state = currState;
                            bFirst = false;
                      }
                      else if (state != currState)
                      {
                            state = 0;
                      }
                }
          }
    }

      return state;
}


static UDWORD GetImageWidth(IMAGEFILE *ImageFile,UDWORD ImageID)
{
      return iV_GetImageWidth(ImageFile,(UWORD)ImageID);
}


static UDWORD GetImageHeight(IMAGEFILE *ImageFile,UDWORD ImageID)
{
      return iV_GetImageHeight(ImageFile,(UWORD)ImageID);
}

//new function added to bring up the RMB order form for Factories as well as droids
void intAddFactoryOrder(STRUCTURE *psStructure)
{
      if(!OrderUp)
      {
            intResetScreen(false);
            intAddOrder((BASE_OBJECT *)psStructure);
            intMode = INT_ORDER;
      }
      else
      {
            intAddOrder((BASE_OBJECT *)psStructure);
      }
}

Generated by  Doxygen 1.6.0   Back to index