1 #ifndef CMDLINE_ONLY
2 # include <gtk/gtk.h>
3 #endif
4 #include <stdlib.h>
5 #include <string.h>
6 #ifndef CMDLINE_ONLY
7 # include "support.h"
8 #endif
9 #include "parser.h"
10 #include "misc.h"
11
12 #ifdef CMDLINE_ONLY
13
14 extern const char *unitdb;
15 extern const char *reinfrc;
16 extern const char *reinf_output;
17
18 #else /* !CMDLINE_ONLY */
19
20 extern GtkWidget *window;
21 const char unitdb[] = "../../src/units/pg.udb";
22 const char reinfrc[] = "reinf.rc";
23 const char reinf_output[] = "../../lgc-pg/convdata/reinf";
24
25 #endif /* !CMDLINE_ONLY */
26
27 const char *unit_classes[] = {
28 "inf", "Infantry",
29 "tank", "Tank",
30 "recon", "Recon",
31 "antitank", "Anti-Tank",
32 "art", "Artillery",
33 "antiair", "Anti-Aircraft",
34 "airdef", "Air-Defense",
35 #ifdef CMDLINE_ONLY
36 "fort", "Fortification",
37 #endif
38 "fighter", "Fighter",
39 "tacbomb", "Tactical Bomber",
40 "levbomb", "Level Bomber",
41 "sub", "Submarine",
42 "dest", "Destroyer",
43 "cap", "Capital Ship",
44 "carrier", "Aircraft Carrier",
45 #ifdef CMDLINE_ONLY
46 "landtrp", "Land Transport",
47 "airtrp", "Air Transport",
48 "seatrp", "Sea Transport",
49 #else
50 /* landtrp is supportive to classes
51 listed above */
52 #endif
53 };
54 #define NUM_UNIT_CLASSES (sizeof unit_classes/sizeof unit_classes[0])
55 const int num_unit_classes = NUM_UNIT_CLASSES;
56
57 const char *target_types[] = {
58 "soft", "Soft Target",
59 "hard", "Hard Target",
60 "air", "Air Target",
61 "naval", "Naval Target",
62 };
63 #define NUM_TARGET_TYPES (sizeof target_types/sizeof target_types[0])
64 const int num_target_types = NUM_TARGET_TYPES;
65
66 const char *sides[] = {
67 "axis", "Axis Forces",
68 "allied", "Allied Forces",
69 };
70 #define NUM_SIDES (sizeof sides/sizeof sides[0])
71 const int num_sides = NUM_SIDES;
72
73 const char *nation_table[] = {
74 "aus", "Austria",
75 "bel", "Belgia",
76 "bul", "Bulgaria",
77 "lux", "Luxemburg",
78 "den", "Denmark",
79 "fin", "Finnland",
80 "fra", "France",
81 "ger", "Germany",
82 "gre", "Greece",
83 "usa", "USA",
84 "hun", "Hungary",
85 "tur", "Turkey",
86 "it", "Italy",
87 "net", "Netherlands",
88 "nor", "Norway",
89 "pol", "Poland",
90 "por", "Portugal",
91 "rum", "Rumania",
92 "esp", "Spain",
93 "so", "Sovjetunion",
94 "swe", "Sweden",
95 "swi", "Switzerland",
96 "eng", "Great Britain",
97 "yug", "Yugoslavia",
98 };
99 #define NUM_NATION_TABLE (sizeof nation_table/sizeof nation_table[0])
100 const int num_nation_table = NUM_NATION_TABLE;
101
102 const char *scenarios[] = {
103 "Poland", "Warsaw", "Norway", "LowCountries", "France",
104 "Sealion40", "NorthAfrica", "MiddleEast", "ElAlamein",
105 "Caucasus", "Sealion43", "Torch", "Husky", "Anzio",
106 "D-Day", "Anvil", "Ardennes", "Cobra", "MarketGarden",
107 "BerlinWest", "Balkans", "Crete", "Barbarossa", "Kiev",
108 "Moscow41", "Sevastapol", "Moscow42", "Stalingrad",
109 "Kharkov", "Kursk", "Moscow43", "Byelorussia",
110 "Budapest", "BerlinEast", "Berlin", "Washington",
111 "EarlyMoscow", "SealionPlus"
112 };
113
114 /* while axis reinforcements are always
115 supplied to Germany the Allied side
116 depends on the scenario */
117 const char *nations[] = {
118 "pol", "pol", "eng", "eng", "fra", "eng", "eng", "eng",
119 "eng", "so", "eng", "usa", "usa", "usa", "usa", "usa",
120 "usa", "usa", "usa", "usa", "eng", "eng", "so", "so",
121 "so", "so", "so", "so", "so", "so", "so", "so", "so",
122 "so", "usa", "usa", "so", "eng"
123 };
124
125 /*
126 ====================================================================
127 Icon indices that must be mirrored terminated by -1
128 ====================================================================
129 */
130 int mirror_ids[] = {
131 83, 84, 85, 86, 87, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
132 102, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
133 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
134 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
135 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
136 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162,
137 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
138 175, 176, 177, 178, 179, 180, 181 ,182, 183, 184, 185, 186,
139 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
140 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 221,
141 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243,
142 244, 250, -1
143 };
144
145 /*
146 ====================================================================
147 UnitLib entries separated to their classes (axis/allies)
148 ====================================================================
149 */
150 List *unitlib[2][CLASS_COUNT];
151 List *trplib[2]; /* transporters */
152 /*
153 ====================================================================
154 Reinforcements for each scenario (axis/allies)
155 ====================================================================
156 */
157 List *reinf[2][SCEN_COUNT];
158 /*
159 ====================================================================
160 Current selections
161 ====================================================================
162 */
163 int cur_scen = 0, cur_player = AXIS, cur_class = 0;
164 int cur_unit = -1, cur_trp = -1, cur_pin = 1;
165 int cur_reinf = -1; /* row selection id */
166
167 /*
168 ====================================================================
169 Load/save reinforcement resources
170 ====================================================================
171 */
load_reinf()172 int load_reinf()
173 {
174 char *line;
175 Unit *unit;
176 int i, j, k, count;
177 FILE *file = fopen( reinfrc, "rb" );
178 List *list, *args;
179 if ( file )
180 list = file_read_lines( file );
181 else
182 return 0;
183 fclose( file );
184 cur_pin = 1;
185 for ( i = 0; i < SCEN_COUNT; i++ )
186 {
187 line = list_next( list );
188 for ( j = 0; j < 2; j++ ) {
189 list_clear( reinf[j][i] );
190 count = atoi( list_next( list ) );
191 for ( k = 0; k < count; k++ ) {
192 line = list_next( list );
193 if ( ( args = parser_explode_string( line, ',' ) ) ) {
194 if ( ( unit = calloc( 1, sizeof( Unit ) ) ) ) {
195 const char *arg;
196 unit->pin = cur_pin++;
197 unit->delay = atoi( list_next( args ) );
198 strcpy_lt( unit->id, list_next( args ), 7 );
199 unit->uid = atoi( unit->id );
200 strcpy_lt( unit->trp, list_next( args ), 7 );
201 unit->tid = strcmp( unit->trp, "none" ) == 0 ? -1 : atoi( unit->trp );
202 unit->str = atoi( list_next( args ) );
203 unit->exp = atoi( list_next( args ) );
204 unit->class_id = atoi( list_next( args ) );
205 unit->unit_id = atoi( list_next( args ) );
206 unit->trp_id = atoi( list_next( args ) );
207 if ( (arg = list_next( args )) )
208 unit->nation = atoi( arg );
209 else
210 unit->nation = -1;
211 build_unit_info( unit, j );
212 list_add( reinf[j][i], unit );
213 }
214 list_delete( args );
215 }
216 }
217 }
218 }
219 list_delete( list );
220 #ifndef CMDLINE_ONLY
221 /* update */
222 update_reinf_list( cur_scen, cur_player );
223 #endif
224 return 1;
225 }
save_reinf()226 int save_reinf()
227 {
228 Unit *unit;
229 int i, j;
230 FILE *file = fopen( reinfrc, "wb" );
231 if ( file == 0 ) return 0;
232 for ( i = 0; i < SCEN_COUNT; i++ )
233 {
234 fprintf( file, "%s\n", scenarios[i] );
235 for ( j = 0; j < 2; j++ ) {
236 fprintf( file, "%i\n", reinf[j][i]->count );
237 list_reset( reinf[j][i] );
238 while ( ( unit = list_next( reinf[j][i] ) ) )
239 fprintf( file, "%i,%s,%s,%i,%i,%i,%i,%i,%i\n", unit->delay,
240 unit->id, unit->trp, unit->str,
241 unit->exp,
242 unit->class_id, unit->unit_id, unit->trp_id,
243 unit->nation );
244 }
245 }
246 fclose( file );
247 printf( "Reinforcements saved to %s\n", reinfrc );
248 return 1;
249 }
250
get_nation_id_by_table_id(int id)251 char *get_nation_id_by_table_id( int id )
252 {
253 static char nat[4];
254 strcpy(nat,"---");
255 if (id<0||id>=num_nation_table/2)
256 return nat;
257 else
258 {
259 snprintf(nat,4,"%s",nation_table[id*2]);
260 return nat;
261 }
262 }
263 int determine_nation_for_unit(const UnitLib_Entry *entry);
264
265 /*
266 ====================================================================
267 Build LGC-PG reinforcements file in ../../src/convdata
268 ====================================================================
269 */
build_reinf()270 void build_reinf()
271 {
272 Unit *unit;
273 int i, j, nat;
274 FILE *file = fopen( reinf_output, "wb" );
275 if ( file ) {
276 for ( i = 0; i < SCEN_COUNT; i++ ) {
277 if ( reinf[AXIS][i]->count == 0 )
278 if ( reinf[ALLIES][i]->count == 0 )
279 continue;
280 fprintf( file, "%s {\n", scenarios[i] );
281 for ( j = 0; j < 2; j++ ) {
282 if ( reinf[j][i]->count == 0 )
283 continue;
284 list_reset( reinf[j][i] );
285 while ( ( unit = list_next( reinf[j][i] ) ) ) {
286 nat = unit->nation;
287 if (nat==-1)
288 {
289 UnitLib_Entry *entry = find_unit_by_id( unit->uid );
290 nat = determine_nation_for_unit(entry);
291 }
292 fprintf( file, " unit { nation = %s id = %s trsp = %s "
293 "delay = %i str = %i "
294 "exp = %i }\n",
295 get_nation_id_by_table_id(nat),
296 unit->id, unit->trp, unit->delay,
297 unit->str, unit->exp );
298 }
299 }
300 fprintf( file, "}\n\n" );
301 }
302 fclose( file );
303 printf( "Reinforcements built to %s\n", reinf_output );
304 }
305 else
306 printf( "%s not found!\n", reinf_output );
307 }
308
309 /*
310 ====================================================================
311 Convert string to scenario id. Returns -1 if invalid.
312 ====================================================================
313 */
to_scenario(const char * str)314 int to_scenario(const char *str) {
315 int i = SCEN_COUNT;
316 for (; i > 0; ) {
317 i--;
318 if (strcasecmp(str, scenarios[i]) == 0) return i;
319 }
320 return -1;
321 }
322
323 /*
324 ====================================================================
325 Convert string to side id. Returns -1 if invalid.
326 ====================================================================
327 */
to_side(const char * str)328 int to_side(const char *str) {
329 int i = NUM_SIDES;
330 for (; i > 0; ) {
331 i -= 2;
332 if (strcasecmp(str, sides[i]) == 0) return i >> 1;
333 }
334 return -1;
335 }
336
337 /*
338 ====================================================================
339 Convert string to nation id. Returns -1 if invalid.
340 ====================================================================
341 */
to_nation(const char * str)342 int to_nation(const char *str) {
343 int i = NUM_NATION_TABLE;
344 for (; i > 0; ) {
345 i -= 2;
346 if (strcasecmp(str, nation_table[i]) == 0) return i >> 1;
347 }
348 return -1;
349 }
350
351 /*
352 ====================================================================
353 Convert string to target type id. Returns -1 if invalid.
354 ====================================================================
355 */
to_target_type(const char * str)356 int to_target_type(const char *str) {
357 int i = NUM_TARGET_TYPES;
358 for (; i > 0; ) {
359 i -= 2;
360 if (strcasecmp(str, target_types[i]) == 0) return i >> 1;
361 }
362 return -1;
363 }
364
365 /*
366 ====================================================================
367 Convert string to unit class id. Returns -1 if invalid.
368 ====================================================================
369 */
to_unit_class(const char * str)370 int to_unit_class(const char *str) {
371 int i = NUM_UNIT_CLASSES;
372 for (; i > 0; ) {
373 i -= 2;
374 if (strcasecmp(str, unit_classes[i]) == 0) return i >> 1;
375 }
376 return -1;
377 }
378
379 /*
380 ====================================================================
381 Returns the side this nation typically belongs to.
382 0 is axis, 1 is allied.
383 ====================================================================
384 */
nation_to_side(int nation)385 int nation_to_side(int nation) {
386 switch (nation) {
387 case 0: case 2: case 4: case 5: case 7: case 10: case 11: case 12: case 20: case 21:
388 return 0;
389 default:
390 return 1;
391 }
392 }
393
394 /*
395 ====================================================================
396 Returns the total count of units.
397 ====================================================================
398 */
unit_count()399 int unit_count() {
400
401 int cnt = 0;
402 int side, cls;
403 for (side = 0; side < 2; side++) {
404 for (cls = 0; cls < CLASS_COUNT; cls++) {
405 cnt += unitlib[side][cls]->count;
406 }
407 cnt += trplib[side]->count;
408 }
409 return cnt;
410 }
411
412 /*
413 ====================================================================
414 Determines the nation the given unit belongs to. Returns -1 if
415 no nation could be determined.
416 ====================================================================
417 */
determine_nation_for_unit(const UnitLib_Entry * entry)418 int determine_nation_for_unit(const UnitLib_Entry *entry) {
419 static const struct {
420 const char * const prefix;
421 const char nat[4];
422 } prefix_xlate[] = {
423 { "ST ", "so" },
424 { "US ", "usa" },
425 { "GB ", "eng" },
426 { "FR ", "fra" },
427 { "FFR ", "fra" },
428 { "FPO ", "pol" },
429 { "IT ", "it" },
430 { "PO ", "pol" },
431 { "NOR ", "nor" },
432 { "LC ", "?" },
433 { "AF ", "?" },
434 { "AD ", "?" },
435 { "Rumanian ", "rum" },
436 { "Bulgarian ", "bul" },
437 { "Hungarian ", "hun" },
438 { "Greek ", "gre" },
439 { "Yugoslav ", "yug" },
440 };
441 int i;
442 const char *nat = 0;
443
444 for (i = 0; i < sizeof prefix_xlate/sizeof prefix_xlate[0]; i++) {
445 int prefix_len = strlen(prefix_xlate[i].prefix);
446 if (strncmp(entry->name, prefix_xlate[i].prefix, prefix_len) == 0) {
447 nat = prefix_xlate[i].nat;
448 break;
449 }
450 }
451
452 /* the Stalinorgeln miss their ST prefix */
453 if (entry->nid == 422 || entry->nid == 423) nat = "so";
454 else if (!nat) nat = "ger"; /* everything else is German */
455
456 return to_nation(nat);
457
458 }
459
460 /*
461 ====================================================================
462 Returns the unit with the given id or 0 if not found.
463 Don't call this while iterating all units by iterate_units_next()
464 ====================================================================
465 */
find_unit_by_id(int id)466 UnitLib_Entry *find_unit_by_id(int id) {
467 UnitLib_Entry *entry;
468 iterate_units_begin();
469 while ((entry = iterate_units_next())) {
470 if (entry->nid == id) return entry;
471 }
472 return 0;
473 }
474
475 /** opaque data structure for maintaining iterator state */
476 struct UdbIteratorState {
477 enum { AxisSide, AlliedSide, SidesTraversed } side;
478 enum { UnitArray, TransportArray, ArraysTraversed } ary;
479 int cls;
480 struct UnitLib_Entry *cur;
481 } udb_it;
482
483 /*
484 ====================================================================
485 Starts iterating the unit database.
486 ====================================================================
487 */
iterate_units_begin(void)488 void iterate_units_begin(void) {
489 udb_it.side = AxisSide;
490 udb_it.ary = UnitArray;
491 udb_it.cls = 0;
492 list_reset(unitlib[udb_it.side][udb_it.cls]);
493 }
494
495 /*
496 ====================================================================
497 Returns the next unit or 0 if end reached.
498 ====================================================================
499 */
iterate_units_next(void)500 UnitLib_Entry *iterate_units_next(void) {
501 List *lst = udb_it.ary == UnitArray ? unitlib[udb_it.side][udb_it.cls] : trplib[udb_it.side];
502 UnitLib_Entry *item = list_next(lst);
503 if (item) return item;
504
505 switch (udb_it.ary) {
506 case UnitArray:
507
508 udb_it.cls++;
509
510 if (udb_it.cls == CLASS_COUNT) {
511 udb_it.ary++;
512 list_reset(trplib[udb_it.side]);
513 } else
514 list_reset(unitlib[udb_it.side][udb_it.cls]);
515 item = iterate_units_next();
516 break;
517
518 case TransportArray:
519
520 udb_it.ary++;
521 /* fall through */
522
523 case ArraysTraversed:
524
525 udb_it.side++;
526
527 if (udb_it.side < SidesTraversed) {
528 udb_it.ary = UnitArray;
529 udb_it.cls = 0;
530 list_reset(unitlib[udb_it.side][udb_it.cls]);
531 item = iterate_units_next();
532 }
533 }
534
535 return item;
536 }
537
538 /*
539 ====================================================================
540 Inititate application and load resources.
541 ====================================================================
542 */
init()543 void init()
544 {
545 #ifndef CMDLINE_ONLY
546 gchar *row[1];
547 GtkWidget *clist = 0;
548 #endif
549 UnitLib_Entry *entry = 0;
550 PData *pd = 0, *units = 0, *unit = 0;
551 int i, j;
552 char *str;
553 /* create lists */
554 for ( j = 0; j < 2; j++ ) {
555 for ( i = 0; i < CLASS_COUNT; i++ )
556 unitlib[j][i] = list_create( LIST_AUTO_DELETE,
557 LIST_NO_CALLBACK );
558 trplib[j] = list_create( LIST_AUTO_DELETE,
559 LIST_NO_CALLBACK );
560 if ( ( entry = calloc( 1, sizeof( UnitLib_Entry ) ) ) ) {
561 strcpy( entry->name, "NONE" );
562 list_add( trplib[j], entry );
563 }
564 for ( i = 0; i < SCEN_COUNT; i++ )
565 reinf[j][i] = list_create( LIST_AUTO_DELETE,
566 LIST_NO_CALLBACK );
567 }
568 /* load unit lib */
569 if ( ( pd = parser_read_file( "unitlib", unitdb ) ) == 0 )
570 goto failure;
571 if ( !parser_get_pdata( pd, "unit_lib", &units ) )
572 goto failure;
573 /* load and categorize unit entries */
574 list_reset( units->entries );
575 while ( ( unit = list_next( units->entries ) ) ) {
576 /* id, name and side */
577 if ( ( entry = calloc( 1, sizeof( UnitLib_Entry ) ) ) == 0 )
578 goto failure;
579 strcpy_lt( entry->id, unit->name, 7 );
580 entry->nid = atoi(entry->id);
581 if ( parser_get_value( unit, "name", &str, 0 ) )
582 strcpy_lt( entry->name, str, 23 );
583 if ( parser_get_value( unit, "icon_id", &str, 0 ) )
584 j = atoi( str );
585 i = 0; entry->side = 0;
586 while ( 1 ) {
587 if ( mirror_ids[i++] == j ) {
588 entry->side = 1;
589 break;
590 }
591 if ( mirror_ids[i] == -1 )
592 break;
593 }
594 /* get class and add to list */
595 if ( parser_get_value( unit, "class", &str, 0 ) ) {
596 int class_id = to_unit_class(str);
597 #ifdef CMDLINE_ONLY
598 entry->class = class_id;
599 #endif
600 if ( STRCMP( "landtrp", str ) )
601 /* ground transporters are special */
602 list_add( trplib[entry->side], entry );
603 else if (class_id >= 0)
604 list_add( unitlib[entry->side][class_id], entry );
605 }
606 #ifdef CMDLINE_ONLY
607 if ( parser_get_value( unit, "target_type", &str, 0 ) )
608 entry->tgttype = to_target_type( str );
609 if ( parser_get_value( unit, "start_year", &str, 0 ) )
610 entry->start_year = atoi( str );
611 if ( parser_get_value( unit, "start_month", &str, 0 ) )
612 entry->start_month = atoi( str );
613 if ( parser_get_value( unit, "last_year", &str, 0 ) )
614 entry->last_year = atoi( str );
615 entry->nation = determine_nation_for_unit(entry);
616 #endif
617 }
618 /* load reinforcements */
619 load_reinf();
620 #ifndef CMDLINE_ONLY
621 /* add scenarios to list l_scenarios */
622 if ( ( clist = lookup_widget( window, "scenarios" ) ) ) {
623 for ( i = 0; i < SCEN_COUNT; i++ ) {
624 row[0] = (char *)scenarios[i];
625 gtk_clist_append( GTK_CLIST (clist), row );
626 }
627 }
628 /* show unit list */
629 update_unit_list( cur_player, cur_class );
630 update_trp_list( cur_player );
631 #endif
632 /* we're done */
633 parser_free( &pd );
634 return;
635 failure:
636 parser_free( &pd );
637 finalize();
638 fprintf( stderr, "Aborted: %s\n", parser_get_error() );
639 exit( 1 );
640 }
641
642 /*
643 ====================================================================
644 Cleanup
645 ====================================================================
646 */
finalize()647 void finalize()
648 {
649 int i, j;
650 for ( j = 0; j < 2; j++ ) {
651 for ( i = 0; i < CLASS_COUNT; i++ )
652 if ( unitlib[j][i] )
653 list_delete( unitlib[j][i] );
654 if ( trplib[j] )
655 list_delete( trplib[j] );
656 for ( i = 0; i < SCEN_COUNT; i++ )
657 if ( reinf[j][i] )
658 list_delete( reinf[j][i] );
659 }
660 }
661
662 /*
663 ====================================================================
664 Copy source to dest and at maximum limit chars. Terminate with 0.
665 ====================================================================
666 */
strcpy_lt(char * dest,char * src,int limit)667 void strcpy_lt( char *dest, char *src, int limit )
668 {
669 int len = strlen( src );
670 if ( len > limit ) {
671 strncpy( dest, src, limit );
672 dest[limit] = 0;
673 }
674 else
675 strcpy( dest, src );
676 }
677
678 #ifndef CMDLINE_ONLY
679 /*
680 ====================================================================
681 Update unit/transporters list
682 ====================================================================
683 */
update_unit_list(int player,int unit_class)684 void update_unit_list( int player, int unit_class )
685 {
686 UnitLib_Entry *entry;
687 gchar *row[1];
688 GtkWidget *clist;
689 if ( ( clist = lookup_widget( window, "units" ) ) ) {
690 gtk_clist_clear( GTK_CLIST(clist) );
691 list_reset( unitlib[player][unit_class] );
692 while ( ( entry = list_next( unitlib[player][unit_class] ) ) ) {
693 row[0] = entry->name;
694 gtk_clist_append( GTK_CLIST(clist), row );
695 }
696 }
697 }
update_trp_list(int player)698 void update_trp_list( int player )
699 {
700 UnitLib_Entry *entry;
701 gchar *row[1];
702 GtkWidget *clist;
703 if ( ( clist = lookup_widget( window, "transporters" ) ) ) {
704 gtk_clist_clear( GTK_CLIST(clist) );
705 list_reset( trplib[player] );
706 while ( ( entry = list_next( trplib[player] ) ) ) {
707 row[0] = entry->name;
708 gtk_clist_append( GTK_CLIST(clist), row );
709 }
710 }
711 }
update_reinf_list(int scen,int player)712 void update_reinf_list( int scen, int player )
713 {
714 Unit *entry;
715 gchar *row[1];
716 GtkWidget *clist;
717 if ( ( clist = lookup_widget( window, "reinforcements" ) ) ) {
718 gtk_clist_clear( GTK_CLIST(clist) );
719 list_reset( reinf[player][scen] );
720 while ( ( entry = list_next( reinf[player][scen] ) ) ) {
721 row[0] = entry->info;
722 gtk_clist_append( GTK_CLIST(clist), row );
723 }
724 gtk_clist_sort( GTK_CLIST(clist) );
725 }
726 }
727 #endif
728
729 /*
730 ====================================================================
731 Read all lines from file.
732 ====================================================================
733 */
file_read_lines(FILE * file)734 List* file_read_lines( FILE *file )
735 {
736 List *list;
737 char buffer[1024];
738
739 if ( !file ) return 0;
740
741 list = list_create( LIST_AUTO_DELETE, LIST_NO_CALLBACK );
742
743 /* read lines */
744 while( !feof( file ) ) {
745 if ( !fgets( buffer, 1023, file ) ) break;
746 if ( buffer[0] == 10 ) continue; /* empty line */
747 buffer[strlen( buffer ) - 1] = 0; /* cancel newline */
748 list_add( list, strdup( buffer ) );
749 }
750 return list;
751 }
752
753 /*
754 ====================================================================
755 Build unit's info string.
756 ====================================================================
757 */
build_unit_info(Unit * unit,int player)758 void build_unit_info( Unit *unit, int player )
759 {
760 UnitLib_Entry *entry = find_unit_by_id( unit->uid );
761 UnitLib_Entry *trp_entry = find_unit_by_id( unit->tid );
762
763 #ifndef CMDLINE_ONLY
764 if ( trp_entry ) {
765 snprintf( unit->info, sizeof unit->info,
766 "T %02i: '%s' (Strength: %i, Exp: %i, Nation: %s) [%s] #%i",
767 unit->delay + 1, entry ? entry->name : "<invalid>",
768 unit->str, unit->exp,
769 (unit->nation==-1)?"auto":get_nation_id_by_table_id(unit->nation),
770 trp_entry->name, unit->pin );
771 }
772 else
773 snprintf( unit->info, sizeof unit->info,
774 "T %02i: '%s' (Strength: %i, Exp: %i, Nation: %s) #%i",
775 unit->delay + 1, entry ? entry->name : "<invalid>",
776 unit->str, unit->exp,
777 (unit->nation==-1)?"auto":get_nation_id_by_table_id(unit->nation),
778 unit->pin );
779 #endif
780 unit->entry = entry;
781 unit->trp_entry = trp_entry;
782 }
783
784 /*
785 ====================================================================
786 Insert a new reinforcement unit into the reinforcements array.
787 ====================================================================
788 */
insert_reinf_unit(Unit * unit,int player,int scenario)789 void insert_reinf_unit( Unit *unit, int player, int scenario ) {
790 /* insert into list, but grouped by nation */
791 {
792 Unit *item;
793 int i = 0;
794 list_reset( reinf[player][scenario] );
795 for (i = 0; (item = list_next( reinf[player][scenario] )); i++) {
796 if ( unit->nation == item->nation ) break;
797 }
798
799 list_insert( reinf[player][scenario], unit, i );
800 }
801 }
802
803 #ifdef CMDLINE_ONLY
804
805 #include "util/paths.h"
806
807 /*
808 ====================================================================
809 Return the directory the game data is installed under.
810 ====================================================================
811 */
get_gamedir(void)812 const char *get_gamedir(void)
813 {
814 #ifdef DISABLE_INSTALL
815 return ".";
816 #else
817 const char *prefix;
818 static char *gamedir;
819 static const char suffix[] = "/share/games/lgeneral";
820 unsigned len;
821 if (gamedir) return gamedir;
822 prefix = paths_prefix();
823 len = strlen(prefix);
824 gamedir = malloc(len + sizeof suffix);
825 strcpy(gamedir, prefix);
826 strcpy(gamedir + len, suffix);
827 return gamedir;
828 #endif
829 }
830 #endif
831