forked from Warzone2100/warzone2100
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhci.cpp
6423 lines (5605 loc) · 165 KB
/
hci.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2012 Warzone 2100 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
*/
/**
* @file hci.c
*
* Functions for the in game interface.
* (Human Computer Interface - thanks to Alex for the file name).
*
* Obviously HCI should mean "Hellish Code Incoming" -- Toksyuryel.
*
*/
#include <string.h>
#include <algorithm>
#include "lib/framework/frame.h"
#include "lib/framework/strres.h"
#include "lib/framework/stdio_ext.h"
#include "lib/gamelib/gtime.h"
#include "lib/ivis_opengl/bitimage.h"
#include "lib/ivis_opengl/pieblitfunc.h"
#include "lib/ivis_opengl/piepalette.h"
#include "lib/ivis_opengl/piestate.h"
// FIXME Direct iVis implementation include!
#include "lib/ivis_opengl/screen.h"
#include "lib/script/script.h"
#include "lib/netplay/netplay.h"
#include "action.h"
#include "lib/sound/audio_id.h"
#include "lib/sound/audio.h"
#include "console.h"
#include "design.h"
#include "display.h"
#include "display3d.h"
#include "drive.h"
#include "edit3d.h"
#include "effects.h"
#include "game.h"
#include "hci.h"
#include "ingameop.h"
#include "intdisplay.h"
#include "intelmap.h"
#include "intorder.h"
#include "keymap.h"
#include "loadsave.h"
#include "loop.h"
#include "mapdisplay.h"
#include "mission.h"
#include "multimenu.h"
#include "multiplay.h"
#include "multigifts.h"
#include "radar.h"
#include "research.h"
#include "scriptcb.h"
#include "scriptextern.h"
#include "scripttabs.h"
#include "transporter.h"
#include "warcam.h"
#include "main.h"
#include "template.h"
#include "wrappers.h"
#include "keybind.h"
#include "qtscript.h"
//#define DEBUG_SCROLLTABS //enable to see tab scroll button info for buttons
// Empty edit window
//#define EDIT_OPTIONS
bool SecondaryWindowUp = false;
static UDWORD newMapWidth, newMapHeight;
#define RETXOFFSET (0)// Reticule button offset
#define RETYOFFSET (0)
#define NUMRETBUTS 7 // Number of reticule buttons.
enum { // Reticule button indecies.
RETBUT_CANCEL,
RETBUT_FACTORY,
RETBUT_RESEARCH,
RETBUT_BUILD,
RETBUT_DESIGN,
RETBUT_INTELMAP,
RETBUT_COMMAND,
};
struct BUTSTATE
{
UDWORD id;
bool Enabled;
bool Hidden;
};
struct BUTOFFSET
{
SWORD x;
SWORD y;
};
BUTOFFSET ReticuleOffsets[NUMRETBUTS] = { // Reticule button form relative positions.
{48,47}, // RETBUT_CANCEL,
{53,15}, // RETBUT_FACTORY,
{87,33}, // RETBUT_RESEARCH,
{87,68}, // RETBUT_BUILD,
{53,86}, // RETBUT_DESIGN,
{19,68}, // RETBUT_INTELMAP,
{19,33}, // RETBUT_COMMAND,
};
BUTSTATE ReticuleEnabled[NUMRETBUTS] = { // Reticule button enable states.
{IDRET_CANCEL,false,false},
{IDRET_MANUFACTURE,false,false},
{IDRET_RESEARCH,false,false},
{IDRET_BUILD,false,false},
{IDRET_DESIGN,false,false},
{IDRET_INTEL_MAP,false,false},
{IDRET_COMMAND,false,false},
};
// Set the x,y members of a button widget initialiser given a reticule button index.
//
static void SetReticuleButPos(UWORD ButId, W_BUTINIT *sButInit)
{
ASSERT( ButId < NUMRETBUTS,"SetReticuleButPos : Bad button index" );
sButInit->x = (SWORD)(ReticuleOffsets[ButId].x + RETXOFFSET);
sButInit->y = (SWORD)(ReticuleOffsets[ButId].y + RETYOFFSET);
}
static bool ClosingObject = false;
static bool ClosingStats = false;
static UDWORD keyButtonMapping = 0;
bool ClosingMessageView = false;
bool ClosingIntelMap = false;
bool ClosingOrder = false;
bool ClosingTrans = false;
bool ClosingTransCont = false;
bool ClosingTransDroids = false;
bool ReticuleUp = false;
bool Refreshing = false;
/***************************************************************************************/
/* Widget ID numbers */
#define IDPOW_FORM 100 // power bar form
/* Option screen IDs */
#define IDOPT_FORM 1000 // The option form
#define IDOPT_MAPFORM 1001
#define IDOPT_MAPLOAD 1002 // The load map button
#define IDOPT_MAPSAVE 1003 // The save map button
#define IDOPT_MAPLABEL 1004 // The map label
#define IDOPT_EDIT 1005 // The edit mode toggle
#define IDOPT_CLOSE 1006 // The close button
#define IDOPT_LABEL 1007 // The Option screen label
#define IDOPT_PLAYERFORM 1008 // The player button form
#define IDOPT_PLAYERLABEL 1009 // The player form label
#define IDOPT_PLAYERSTART 1010 // The first player button
#define IDOPT_PLAYEREND 1030 // The last possible player button
#define IDOPT_QUIT 1031 // Quit the game
#define IDOPT_MAPNEW 1032 // The new map button
#define IDOPT_MAPWIDTH 1033 // The edit box for the map width
#define IDOPT_MAPHEIGHT 1034 // The edit box for the map height
#define IDOPT_DROID 1037 // The place droid button
#define IDOPT_STRUCT 1038 // The place struct button
#define IDOPT_FEATURE 1039 // The place feature button
#define IDOPT_TILE 1040 // The place tile button
#define IDOPT_PAUSE 1041 // The edit pause button
#define IDOPT_ZALIGN 1042 // The z-align button
#define IDOPT_IVISFORM 1043 // iViS engine form
#define IDOPT_IVISLABEL 1044 // iViS form label
/* Edit screen IDs */
#define IDED_FORM 2000 // The edit form
#define IDED_LABEL 2001 // The edit screen label
#define IDED_CLOSE 2002 // The edit screen close box
#define IDED_STATFORM 2003 // The edit screen stats form (for droids/structs/features)
//Design Screen uses 5000
//Intelligence Map uses 6000
//Droid order screen uses 8000
//Transporter screen uses 9000
//CD span screen uses 9800
//MultiPlayer Frontend uses 10100/10200/10300/10400
//Ingame Options use 10500
//Ingame MultiMenu uses 10600
//Mission Timer uses 11000
//Frontend uses 20000
//LOADSAVE uses 21000
//MULTILIMITS uses 22000
#define IDPROX_START 120000 // The first proximity button
#define IDPROX_END 129999 // The last proximity button
#define PROX_BUTWIDTH 9
#define PROX_BUTHEIGHT 9
/***************************************************************************************/
/* Widget Positions */
/* Reticule positions */
#define RET_BUTWIDTH 25
#define RET_BUTHEIGHT 28
#define RET_BUTGAPX 6
#define RET_BUTGAPY 6
/* Option positions */
#define OPT_X (640-300)
#define OPT_Y 20
#define OPT_WIDTH 275
#define OPT_HEIGHT 350
#define OPT_BUTWIDTH 60
#define OPT_BUTHEIGHT 20
#define OPT_MAPY 25
#define OPT_EDITY 100
#define OPT_PLAYERY 150
#define OPT_LOADY 260
/* Edit positions */
#define ED_X 32
#define ED_Y 200
#define ED_WIDTH 80
#define ED_HEIGHT 105
#define ED_GAP 5
#define ED_BUTWIDTH 60
#define ED_BUTHEIGHT 20
#define STAT_TABOFFSET 2
#define STAT_BUTX 4
#define STAT_BUTY 2
/* Structure type screen positions */
#define STAT_BASEWIDTH 134 // Size of the main form.
#define STAT_BASEHEIGHT 254
#define STAT_GAP 2
#define STAT_BUTWIDTH 60
#define STAT_BUTHEIGHT 46
/* Close strings */
static char pCloseText[] = "X";
/* Player button strings */
static const char *apPlayerText[] =
{
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "11", "12", "13", "14", "15",
};
static const char *apPlayerTip[] =
{
"Select Player 0",
"Select Player 1",
"Select Player 2",
"Select Player 3",
"Select Player 4",
"Select Player 5",
"Select Player 6",
"Select Player 7",
"Select Player 8",
"Select Player 9",
"Select Player 10",
"Select Player 11",
"Select Player 12",
"Select Player 13",
"Select Player 14",
"Select Player 15",
};
/* The widget screen */
W_SCREEN *psWScreen;
// The last widget ID from widgRunScreen
UDWORD intLastWidget;
INTMODE intMode;
/* Status of the positioning for the object placement */
enum _edit_pos_mode
{
IED_NOPOS,
IED_POS,
} editPosMode;
/* Which type of object screen is being displayed. Starting value is where the intMode left off*/
enum _obj_mode
{
IOBJ_NONE = INT_MAXMODE, // Nothing doing.
IOBJ_BUILD, // The build screen
IOBJ_BUILDSEL, // Selecting a position for a new structure
IOBJ_DEMOLISHSEL, // Selecting a structure to demolish
IOBJ_MANUFACTURE, // The manufacture screen
IOBJ_RESEARCH, // The research screen
IOBJ_COMMAND, // the command droid screen
IOBJ_MAX, // maximum object mode
} objMode;
/* Function type for selecting a base object while building the object screen */
typedef bool (* OBJ_SELECT)(BASE_OBJECT *psObj);
/* Function type for getting the appropriate stats for an object */
typedef BASE_STATS *(* OBJ_GETSTATS)(BASE_OBJECT *psObj);
/* Function type for setting the appropriate stats for an object */
typedef bool (* OBJ_SETSTATS)(BASE_OBJECT *psObj, BASE_STATS *psStats);
/* functions to select and get stats from the current object list */
static OBJ_SELECT objSelectFunc;
OBJ_GETSTATS objGetStatsFunc;
static OBJ_SETSTATS objSetStatsFunc;
/* Whether the objects that are on the object screen have changed this frame */
static bool objectsChanged;
/* The current stats list being used by the stats screen */
static BASE_STATS **ppsStatsList;
static UDWORD numStatsListEntries;
/* The selected object on the object screen when the stats screen is displayed */
static BASE_OBJECT *psObjSelected;
/* The button ID of the objects stat when the stat screen is displayed */
UDWORD objStatID;
/* The button ID of an objects stat on the stat screen if it is locked down */
static UDWORD statID;
/* The stats for the current getStructPos */
static BASE_STATS *psPositionStats;
/* The number of tabs on the object form (used by intObjDestroyed to tell whether */
/* the number of tabs has changed). */
static UWORD objNumTabs;
/* The tab positions of the object form when the structure form is displayed */
static UWORD objMajor, objMinor;
/* Store a list of stats pointers from the main structure stats */
static STRUCTURE_STATS **apsStructStatsList;
/* Store a list of research pointers for topics that can be performed*/
static RESEARCH **ppResearchList;
/* Store a list of Template pointers for Droids that can be built */
std::vector<DROID_TEMPLATE *> apsTemplateList;
std::list<DROID_TEMPLATE> localTemplates;
/* Store a list of Feature pointers for features to be placed on the map */
static FEATURE_STATS **apsFeatureList;
/*Store a list of research indices which can be performed*/
static UWORD *pList;
static UWORD *pSList;
/* Store a list of component stats pointers for the design screen */
UDWORD numComponent;
COMPONENT_STATS **apsComponentList;
UDWORD numExtraSys;
COMPONENT_STATS **apsExtraSysList;
// store the objects that are being used for the object bar
std::vector<BASE_OBJECT *> apsObjectList;
/* The current design being edited on the design screen */
extern DROID_TEMPLATE sCurrDesign;
/* Flags to check whether the power bars are currently on the screen */
static bool powerBarUp = false;
static bool StatsUp = false;
static BASE_OBJECT *psStatsScreenOwner = NULL;
/* The previous object for each object bar */
static BASE_OBJECT *apsPreviousObj[IOBJ_MAX];
/* The jump position for each object on the base bar */
static std::vector<Vector2i> asJumpPos;
/***************************************************************************************/
/* Function Prototypes */
static bool intUpdateObject(BASE_OBJECT *psObjects, BASE_OBJECT *psSelected,bool bForceStats);
/* Remove the object widgets from the widget screen */
void intRemoveObject(void);
static void intRemoveObjectNoAnim(void);
/* Process the object widgets */
static void intProcessObject(UDWORD id);
/* Get the object refered to by a button ID on the object screen.
* This works for droid or structure buttons
*/
static BASE_OBJECT *intGetObject(UDWORD id);
/* Reset the stats button for an object */
static void intSetStats(UDWORD id, BASE_STATS *psStats);
/* Add the stats widgets to the widget screen */
/* If psSelected != NULL it specifies which stat should be hilited */
static bool intAddStats(BASE_STATS **ppsStatsList, UDWORD numStats,
BASE_STATS *psSelected, BASE_OBJECT *psOwner);
/* Process return codes from the stats screen */
static void intProcessStats(UDWORD id);
// clean up when an object dies
static void intObjectDied(UDWORD objID);
/* Add the build widgets to the widget screen */
/* If psSelected != NULL it specifies which droid should be hilited */
static bool intAddBuild(DROID *psSelected);
/* Add the manufacture widgets to the widget screen */
/* If psSelected != NULL it specifies which factory should be hilited */
static bool intAddManufacture(STRUCTURE *psSelected);
/* Add the research widgets to the widget screen */
/* If psSelected != NULL it specifies which droid should be hilited */
static bool intAddResearch(STRUCTURE *psSelected);
/* Add the command droid widgets to the widget screen */
/* If psSelected != NULL it specifies which droid should be hilited */
static bool intAddCommand(DROID *psSelected);
/* Start looking for a structure location */
static void intStartStructPosition(BASE_STATS *psStats);
/* Stop looking for a structure location */
static void intStopStructPosition(void);
static STRUCTURE *CurrentStruct = NULL;
static SWORD CurrentStructType = 0;
static DROID *CurrentDroid = NULL;
static SWORD CurrentDroidType = 0;
/******************Power Bar Stuff!**************/
/* Add the power bars */
static bool intAddPower(void);
/* Set the shadow for the PowerBar */
static void intRunPower(void);
static void intRunStats(void);
/*Deals with the RMB click for the stats screen */
static void intStatsRMBPressed(UDWORD id);
/*Deals with the RMB click for the object screen */
static void intObjectRMBPressed(UDWORD id);
/*Deals with the RMB click for the Object Stats buttons */
static void intObjStatRMBPressed(UDWORD id);
//proximity display stuff
static void processProximityButtons(UDWORD id);
static void intInitialiseReticule(void);
static DROID* intCheckForDroid(UDWORD droidType);
static STRUCTURE* intCheckForStructure(UDWORD structType);
static void intCheckReticuleButtons(void);
// count the number of selected droids of a type
static SDWORD intNumSelectedDroids(UDWORD droidType);
/***************************GAME CODE ****************************/
/* Initialise the in game interface */
bool intInitialise(void)
{
UDWORD comp, inc;
intInitialiseReticule();
widgSetTipColour(WZCOL_TOOLTIP_TEXT);
if(GetGameMode() == GS_NORMAL) {
WidgSetAudio(WidgetAudioCallback,-1,ID_SOUND_SELECT);
} else {
WidgSetAudio(WidgetAudioCallback,-1,ID_SOUND_SELECT);
}
/* Create storage for Structures that can be built */
apsStructStatsList = (STRUCTURE_STATS **)malloc(sizeof(STRUCTURE_STATS *) *
MAXSTRUCTURES);
if (!apsStructStatsList)
{
debug( LOG_FATAL, "Out of memory" );
abort();
return false;
}
//create the storage for Research topics - max possible size
ppResearchList = (RESEARCH **) malloc(sizeof(RESEARCH *) * MAXRESEARCH);
if (ppResearchList == NULL)
{
debug( LOG_FATAL, "Unable to allocate memory for research list" );
abort();
return false;
}
//create the list for the selected player
//needs to be UWORD sized for Patches
pList = (UWORD *) malloc(sizeof (UWORD) * MAXRESEARCH);
pSList = (UWORD *) malloc(sizeof (UWORD) * MAXRESEARCH);
if (pList == NULL)
{
debug( LOG_FATAL, "Unable to allocate memory for research list" );
abort();
return false;
}
if (pSList == NULL)
{
debug( LOG_FATAL, "Unable to allocate memory for sorted research list" );
abort();
return false;
}
/* Create storage for Templates that can be built */
apsTemplateList.clear();
/* Create storage for the feature list */
apsFeatureList = (FEATURE_STATS **)malloc(sizeof(FEATURE_STATS *) *
MAXFEATURES);
if (apsFeatureList == NULL)
{
debug( LOG_FATAL, "Unable to allocate memory for feature list" );
abort();
return false;
}
/* Create storage for the component list */
apsComponentList = (COMPONENT_STATS **)malloc(sizeof(COMPONENT_STATS *) *
MAXCOMPONENT);
if (apsComponentList == NULL)
{
debug( LOG_FATAL, "Unable to allocate memory for component list" );
abort();
return false;
}
/* Create storage for the extra systems list */
apsExtraSysList = (COMPONENT_STATS **)malloc(sizeof(COMPONENT_STATS *) *
MAXEXTRASYS);
if (apsExtraSysList == NULL)
{
debug( LOG_FATAL, "Unable to allocate memory for extra systems list" );
abort();
return false;
}
// allocate the object list
apsObjectList.clear();
intInitialiseGraphics();
psWScreen = widgCreateScreen();
if (psWScreen == NULL)
{
debug(LOG_ERROR, "intInitialise: Couldn't create widget screen");
return false;
}
widgSetTipFont(psWScreen, font_regular);
if(GetGameMode() == GS_NORMAL) {
if (!intAddReticule())
{
debug( LOG_ERROR, "intInitialise: Couldn't create reticule widgets (Out of memory ?)" );
return false;
}
if (!intAddPower())
{
debug( LOG_ERROR, "intInitialise: Couldn't create power Bar widget(Out of memory ?)" );
return false;
}
}
/* Initialise the screen to be run */
widgStartScreen(psWScreen);
/* Note the current screen state */
intMode = INT_NORMAL;
objectsChanged = false;
// reset the previous objects
intResetPreviousObj();
// reset the jump positions
asJumpPos.clear();
/* make demolish stat always available */
if(!bInTutorial)
{
for (comp=0; comp < numStructureStats; comp++)
{
//if (!strcmp(asStructureStats[comp].pName, "Demolish Structure"))
if (asStructureStats[comp].type == REF_DEMOLISH)
{
for (inc = 0; inc < MAX_PLAYERS; inc++)
{
apStructTypeLists[inc][comp] = AVAILABLE;
}
}
}
}
return true;
}
//initialise all the previous obj - particularly useful for when go Off world!
void intResetPreviousObj(void)
{
//make sure stats screen doesn't think it should be up
StatsUp = false;
// reset the previous objects
memset(apsPreviousObj, 0, sizeof(apsPreviousObj));
}
/* Shut down the in game interface */
void interfaceShutDown(void)
{
widgReleaseScreen(psWScreen);
free(apsStructStatsList);
free(ppResearchList);
free(pList);
free(pSList);
apsTemplateList.clear();
free(apsFeatureList);
free(apsComponentList);
free(apsExtraSysList);
apsObjectList.clear();
psWScreen = NULL;
apsStructStatsList = NULL;
ppResearchList = NULL;
pList = NULL;
pSList = NULL;
apsFeatureList = NULL;
apsComponentList = NULL;
apsExtraSysList = NULL;
interfaceDeleteGraphics();
//obviously!
ReticuleUp = false;
}
static bool IntRefreshPending = false;
// Set widget refresh pending flag.
//
void intRefreshScreen(void)
{
IntRefreshPending = true;
}
bool intIsRefreshing(void)
{
return Refreshing;
}
// see if a delivery point is selected
static FLAG_POSITION *intFindSelectedDelivPoint(void)
{
FLAG_POSITION *psFlagPos;
for (psFlagPos = apsFlagPosLists[selectedPlayer]; psFlagPos;
psFlagPos = psFlagPos->psNext)
{
if (psFlagPos->selected && (psFlagPos->type == POS_DELIVERY))
{
return psFlagPos;
}
}
return NULL;
}
// Refresh widgets once per game cycle if pending flag is set.
//
static void intDoScreenRefresh(void)
{
UWORD objMajor=0, objMinor=0, statMajor=0, statMinor=0;
FLAG_POSITION *psFlag;
if(IntRefreshPending) {
Refreshing = true;
if (( (intMode == INT_OBJECT) ||
(intMode == INT_STAT) ||
(intMode == INT_CMDORDER) ||
(intMode == INT_ORDER) ||
(intMode == INT_TRANSPORTER) ) &&
(widgGetFromID(psWScreen,IDOBJ_FORM) != NULL) &&
!(widgGetFromID(psWScreen,IDOBJ_FORM)->style & WIDG_HIDDEN) )
{
bool StatsWasUp = false;
bool OrderWasUp = false;
// If the stats form is up then remove it, but remember that it was up.
if ((intMode == INT_STAT) && widgGetFromID(psWScreen,IDSTAT_FORM) != NULL)
{
StatsWasUp = true;
}
// store the current tab position
if (widgGetFromID(psWScreen, IDOBJ_TABFORM) != NULL)
{
widgGetTabs(psWScreen, IDOBJ_TABFORM, &objMajor, &objMinor);
}
if (StatsWasUp)
{
widgGetTabs(psWScreen, IDSTAT_TABFORM, &statMajor, &statMinor);
}
// now make sure the stats screen isn't up
if (widgGetFromID(psWScreen,IDSTAT_FORM) != NULL )
{
intRemoveStatsNoAnim();
}
if (psObjSelected &&
psObjSelected->died)
{
// refresh when unit dies
psObjSelected = NULL;
objMajor = objMinor = 0;
statMajor = statMinor = 0;
}
// see if there was a delivery point being positioned
psFlag = intFindSelectedDelivPoint();
// see if the commander order screen is up
if ( (intMode == INT_CMDORDER) &&
(widgGetFromID(psWScreen,IDORDER_FORM) != NULL) )
{
OrderWasUp = true;
}
switch(objMode)
{
case IOBJ_MANUFACTURE: // The manufacture screen (factorys on bottom bar)
case IOBJ_RESEARCH: // The research screen
//pass in the currently selected object
intUpdateObject((BASE_OBJECT *)interfaceStructList(), psObjSelected, StatsWasUp);
break;
case IOBJ_BUILD:
case IOBJ_COMMAND: // the command droid screen
case IOBJ_BUILDSEL: // Selecting a position for a new structure
case IOBJ_DEMOLISHSEL: // Selecting a structure to demolish
//pass in the currently selected object
intUpdateObject((BASE_OBJECT *)apsDroidLists[selectedPlayer], psObjSelected, StatsWasUp);
break;
default:
// generic refresh (trouble at the moment, cant just always pass in a null to addobject
// if object screen is up, refresh it if stats screen is up, refresh that.
break;
}
// set the tabs again
if (widgGetFromID(psWScreen, IDOBJ_TABFORM) != NULL)
{
if (objMajor >= widgGetNumTabMajor(psWScreen, IDOBJ_TABFORM))
{
objMajor = 0; // reset
objMinor = 0;
debug(LOG_ERROR, "Reset tabs since objMajor is too big");
}
else if (objMinor >= widgGetNumTabMinor(psWScreen, IDOBJ_TABFORM, objMajor))
{
objMinor = 0; // reset minor only
debug(LOG_ERROR, "Reset minor tabs since objMinor is too big");
}
widgSetTabs(psWScreen, IDOBJ_TABFORM, objMajor, objMinor);
}
if (widgGetFromID(psWScreen,IDSTAT_TABFORM) != NULL )
{
if (statMajor >= widgGetNumTabMajor(psWScreen, IDSTAT_TABFORM))
{
statMajor = 0; // reset
statMinor = 0;
debug(LOG_ERROR, "Reset tabs since statMajor is too big");
}
else if (statMinor >= widgGetNumTabMinor(psWScreen, IDSTAT_TABFORM, statMajor))
{
statMinor = 0; // reset minor only
debug(LOG_ERROR, "Reset minor tabs since statMinor is too big");
}
widgSetTabs(psWScreen, IDSTAT_TABFORM, statMajor, statMinor);
}
if (psFlag != NULL)
{
// need to restart the delivery point position
startDeliveryPosition(psFlag);
}
// make sure the commander order screen is in the right state
if ( (intMode == INT_CMDORDER) &&
!OrderWasUp &&
(widgGetFromID(psWScreen,IDORDER_FORM) != NULL) )
{
intRemoveOrderNoAnim();
if (statID)
{
widgSetButtonState(psWScreen, statID, 0);
}
}
}
// Refresh the transporter interface.
intRefreshTransporter();
// Refresh the order interface.
intRefreshOrder();
Refreshing = false;
}
IntRefreshPending = false;
}
//hides the power bar from the display
static void intHidePowerBar(void)
{
//only hides the power bar if the player has requested no power bar
if (!powerBarUp)
{
if (widgGetFromID(psWScreen, IDPOW_POWERBAR_T))
{
widgHide(psWScreen, IDPOW_POWERBAR_T);
}
}
}
/* Remove the options widgets from the widget screen */
static void intRemoveOptions(void)
{
widgDelete(psWScreen, IDOPT_FORM);
}
#ifdef EDIT_OPTIONS
/* Add the edit widgets to the widget screen */
static bool intAddEdit(void)
{
W_FORMINIT sFormInit;
W_LABINIT sLabInit;
W_BUTINIT sButInit;
/* Add the edit form */
sFormInit.formID = 0;
sFormInit.id = IDED_FORM;
sFormInit.style = WFORM_PLAIN;
sFormInit.x = ED_X;
sFormInit.y = ED_Y;
sFormInit.width = ED_WIDTH;
sFormInit.height = ED_HEIGHT;
if (!widgAddForm(psWScreen, &sFormInit))
{
return false;
}
/* Add the Option screen label */
sLabInit.formID = IDED_FORM;
sLabInit.id = IDED_LABEL;
sLabInit.x = ED_GAP;
sLabInit.y = ED_GAP;
sLabInit.width = ED_WIDTH;
sLabInit.height = ED_BUTHEIGHT;
sLabInit.pText = "Edit";
if (!widgAddLabel(psWScreen, &sLabInit))
{
return false;
}
/* Add the close box */
sButInit.formID = IDED_FORM;
sButInit.id = IDED_CLOSE;
sButInit.x = ED_WIDTH - ED_GAP - CLOSE_SIZE;
sButInit.y = ED_GAP;
sButInit.width = CLOSE_SIZE;
sButInit.height = CLOSE_SIZE;
sButInit.pText = pCloseText;
sButInit.pTip = _("Close");
if (!widgAddButton(psWScreen, &sButInit))
{
return false;
}
return true;
}
/* Remove the edit widgets from the widget screen */
static void intRemoveEdit(void)
{
widgDelete(psWScreen, IDED_FORM);
}
#endif
/* Get and validate the new map size from the options screen */
static void intGetMapSize(void)
{
SDWORD editWidth, editHeight;
char aText[WIDG_MAXSTR];
UDWORD i, tmp, bitCount;
bool widthChanged = false, heightChanged = false;
const char *pStr = widgGetString(psWScreen, IDOPT_MAPWIDTH);
if (isdigit(*pStr))
{
// There is a number in the string
sscanf(pStr, "%d", &editWidth);
}
else
{
// No number in the string, restore the old value
editWidth = newMapWidth;
widthChanged = true;
}
// Get the new height
pStr = widgGetString(psWScreen, IDOPT_MAPHEIGHT);
if (isdigit(*pStr))
{
// There is a number in the string
sscanf(pStr, "%d", &editHeight);
}
else
{
// No number in the string, restore the old value
editHeight = newMapHeight;
heightChanged = true;
}
// now validate the sizes
if (editWidth <= 0 || editWidth > MAP_MAXWIDTH)
{
editWidth = newMapWidth;
widthChanged = true;
}
else
{
// Check it is a power of 2
bitCount = 0;
tmp = editWidth;
for (i = 0; i < 32; i++)
{
if (tmp & 1)
{
bitCount ++;
}
tmp = tmp >> 1;
}
if (bitCount != 1)
{
editWidth = newMapWidth;
widthChanged = true;
}
}
if (editHeight <= 0 || editHeight > MAP_MAXHEIGHT)
{
editHeight = newMapHeight;
heightChanged = true;
}
else
{
// Check it is a power of 2
bitCount = 0;