/* 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 #include #include "lib/framework/frame.h" #include "lib/widget/widget.h" #include "objects.h" #include "loop.h" #include "edit2d.h" #include "map.h" #include "lib/ivis_common/bitimage.h"//bitmap routines #include "display3d.h" #include "hci.h" #include "lib/sound/audio.h" #include "audio_id.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 "text.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 11 // 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_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; // 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_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, #ifdef PSX {IMAGE_ORD_EMBARK, 0, 0}, {IMAGE_ORD_EMBARK, 0, 0}, #else {IMAGE_ORD_GOTOHQUP, 0, 0}, {IMAGE_ORD_GOTOHQUP, 0, 0}, #endif {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, #ifdef PSX {IMAGE_ORD_GOTOREPAIR, 0, 0}, {IMAGE_ORD_GOTOREPAIR, 0, 0}, #else {IMAGE_ORD_GOTOHQUP, 0, 0}, {IMAGE_ORD_GOTOHQUP, 0, 0}, #endif {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 int WFont; extern UDWORD currentGameFrame; extern void intDisplayPlainForm(struct _widget *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *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 = strresGetString(psStringRes, STR_MISC_CLOSE); sButInit.FontID = WFont; sButInit.pDisplay = intDisplayImageHilight; sButInit.pUserData = (void*)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 = intDisplayAltButtonHilight; sButInit.FontID = WFont; sButInit.y = ORDER_BUTY; Height = 0; NumDisplayedOrders = 0; for(j=0; ((j 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= 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; iheight = (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; iselected) { 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= 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(); } //changed to a BASE_OBJECT to accomodate the factories - AB 21/04/99 //BOOL intAddOrder(DROID *Droid) BOOL intAddOrder(BASE_OBJECT *psObj) { //changed to a BASE_OBJECT to accomodate the factories - AB 21/04/99 //return _intAddOrder(Droid); return _intAddOrder(psObj); } void intProcessOrder(UDWORD id) { _intProcessOrder(id); } // 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 = (void*)0; // 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 AND psDroid->sDisplay.frameNumber == currentGameFrame) { if(psDroid->selected) { if(NumSelectedDroids < MAX_SELECTED_DROIDS) { SelectedDroids[NumSelectedDroids] = psDroid; NumSelectedDroids++; } } } // DBPRINTF(("%d droids selected\n",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 AND 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; idroidType != 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 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 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 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 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 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