1 /***************************************************************************
2 scenarios.c - description
3 -------------------
4 begin : Tue Mar 12 2002
5 copyright : (C) 2001 by Michael Speck
6 email : kulkanie@gmx.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <SDL_endian.h>
24 #include "units.h"
25 #include "misc.h"
26 #include "scenarios.h"
27 #include "parser.h"
28
29 /*
30 ====================================================================
31 Externals
32 ====================================================================
33 */
34 extern char *source_path;
35 extern char *dest_path;
36 extern char target_name[128];
37 extern int map_or_scen_files_missing;
38 extern int nation_count;
39 extern char *nations[];
40 /* unofficial options */
41 extern const char *axis_name, *allies_name;
42 extern const char *axis_nations, *allies_nations;
43
44 int unit_entry_used[UDB_LIMIT];
45
46 /*
47 ====================================================================
48 The scenario result is determined by a list of conditions.
49 If any of the conditions turn out to be true the scenario ends,
50 the message is displayed and result is returned (for campaign).
51 If there is no result after the LAST turn result and message
52 of the else struct are used.
53 A condition has two test fields: one is linked with an
54 logical AND the other is linkes with an logical OR. Both
55 fields must return True if the condition is supposed to be
56 fullfilled. An empty field does always return True.
57 Struct:
58 result {
59 check = every_turn | last_turn
60 cond {
61 and { test .. testX }
62 or { test .. testY }
63 result = ...
64 message = ... }
65 cond { ... }
66 else { result = ... message = ... }
67 }
68 Tests:
69 control_hex { player x = ... y = ... }
70 :: control a special victory hex
71 control_any_hex { player count = ... }
72 :: control this number of victory
73 hexes
74 control_all_hexes { player }
75 :: conquer everything important
76 on the map
77 turns_left { count = ... }
78 :: at least so many turns are left
79 ====================================================================
80 */
81 /*
82 ====================================================================
83 Scenario file names
84 ====================================================================
85 */
86 char *fnames[] = {
87 "Poland",
88 "Warsaw",
89 "Norway",
90 "LowCountries",
91 "France",
92 "Sealion40",
93 "NorthAfrica",
94 "MiddleEast",
95 "ElAlamein",
96 "Caucasus",
97 "Sealion43",
98 "Torch",
99 "Husky",
100 "Anzio",
101 "D-Day",
102 "Anvil",
103 "Ardennes",
104 "Cobra",
105 "MarketGarden",
106 "BerlinWest",
107 "Balkans",
108 "Crete",
109 "Barbarossa",
110 "Kiev",
111 "Moscow41",
112 "Sevastapol",
113 "Moscow42",
114 "Stalingrad",
115 "Kharkov",
116 "Kursk",
117 "Moscow43",
118 "Byelorussia",
119 "Budapest",
120 "BerlinEast",
121 "Berlin",
122 "Washington",
123 "EarlyMoscow",
124 "SealionPlus"
125 };
126
127 /*
128 ====================================================================
129 AI modules names
130 ====================================================================
131 */
132 char *ai_modules[] = {
133 /* axis, allied -- scenarios as listed above */
134 "default", "default",
135 "default", "default",
136 "default", "default",
137 "default", "default",
138 "default", "default",
139 "default", "default",
140 "default", "default",
141 "default", "default",
142 "default", "default",
143 "default", "default",
144 "default", "default",
145 "default", "default",
146 "default", "default",
147 "default", "default",
148 "default", "default",
149 "default", "default",
150 "default", "default",
151 "default", "default",
152 "default", "default",
153 "default", "default",
154 "default", "default",
155 "default", "default",
156 "default", "default",
157 "default", "default",
158 "default", "default",
159 "default", "default",
160 "default", "default",
161 "default", "default",
162 "default", "default",
163 "default", "default",
164 "default", "default",
165 "default", "default",
166 "default", "default",
167 "default", "default",
168 "default", "default",
169 "default", "default",
170 "default", "default",
171 "default", "default",
172 "default", "default"
173 };
174 /*
175 ====================================================================
176 Per-turn prestige
177 ====================================================================
178 */
179 int prestige_per_turn[] = {
180 /* axis, allied -- scenarios as listed above */
181 0, 20,
182 0, 20,
183 0, 40,
184 0, 48,
185 0, 45,
186 0, 84,
187 0, 45,
188 0, 70,
189 0, 63,
190 0, 85,
191 0, 103,
192 0, 0,
193 71, 0,
194 47, 0,
195 70, 0,
196 48, 0,
197 0, 75,
198 48, 0,
199 61, 0,
200 70, 0,
201 0, 101,
202 0, 45,
203 0, 60,
204 0, 80,
205 0, 115,
206 0, 63,
207 0, 105,
208 0, 95,
209 0, 55,
210 0, 115,
211 0, 122,
212 47, 0,
213 0, 0,
214 70, 0,
215 82, 0,
216 0, 115,
217 0, 135,
218 0, 85
219 };
220
221 /*
222 ====================================================================
223 Locals
224 ====================================================================
225 */
226
227 /*
228 ====================================================================
229 Random generator
230 ====================================================================
231 */
232 int seed;
random_seed(int _seed)233 void random_seed( int _seed )
234 {
235 seed = _seed;
236 }
random_get(int low,int high)237 int random_get( int low, int high )
238 {
239 int p1 = 1103515245;
240 int p2 = 12345;
241 seed = ( seed * p1 + p2 ) % 2147483647;
242 return ( ( abs( seed ) / 3 ) % ( high - low + 1 ) ) + low;
243 }
244
245 /*
246 ====================================================================
247 Read all flags from MAP%i.SET and add them to dest_file.
248 We need the scenario file as well as the victory hex positions
249 are saved there.
250 ====================================================================
251 */
scen_add_flags(FILE * dest_file,FILE * scen_file,int id)252 int scen_add_flags( FILE *dest_file, FILE *scen_file, int id )
253 {
254 FILE *map_file;
255 char path[MAXPATHLEN];
256 int width, height, ibuf;
257 int x, y, i, obj;
258 int vic_hexes[40]; /* maximum if 20 hexes in PG - terminated with -1 */
259 int obj_count = 0;
260 /* read victory hexes from scen_file */
261 memset( vic_hexes, 0, sizeof(int) * 40 );
262 fseek( scen_file, 37, SEEK_SET );
263 for ( i = 0; i < 20; i++ ) {
264 _fread( &vic_hexes[i * 2], 2, 1, scen_file );
265 vic_hexes[i * 2] = SDL_SwapLE16(vic_hexes[i * 2]);
266 _fread( &vic_hexes[i * 2 + 1], 2, 1, scen_file );
267 vic_hexes[i * 2 + 1] = SDL_SwapLE16(vic_hexes[i * 2 + 1]);
268 if ( vic_hexes[i * 2] >= 1000 || vic_hexes[i * 2] < 0 )
269 break;
270 obj_count++;
271 }
272 /* open set file */
273 snprintf( path, MAXPATHLEN, "%s/map%02i.set", source_path, id );
274 if ( ( map_file = fopen_ic( path, "rb" ) ) == 0 ) {
275 fprintf( stderr, "%s: file not found\n", path );
276 return 0;
277 }
278 /* read/write map size */
279 width = height = 0;
280 fseek( map_file, 101, SEEK_SET );
281 _fread( &width, 2, 1, map_file );
282 width = SDL_SwapLE16(width);
283 fseek( map_file, 103, SEEK_SET );
284 _fread( &height, 2, 1, map_file );
285 height = SDL_SwapLE16(height);
286 width++; height++;
287 /* owner info */
288 fseek( map_file, 123 + 3 * width * height, SEEK_SET );
289 for ( y = 0; y < height; y++ ) {
290 for ( x = 0; x < width; x++ ) {
291 ibuf = 0; _fread( &ibuf, 1, 1, map_file );
292 if ( ibuf > 0 ) {
293 obj = 0;
294 for ( i = 0; i < obj_count; i++ )
295 if ( vic_hexes[i * 2] == x && vic_hexes[i * 2 + 1] == y ) {
296 obj = 1; break;
297 }
298 fprintf( dest_file, "<flag\nx�%i\ny�%i\nnation�%s\nobj�%i\n>\n", x, y, nations[(ibuf - 1) * 3], obj );
299 }
300 }
301 }
302 return 1;
303 }
304
305 /*
306 ====================================================================
307 Panzer General offers two values: weather condition and weather
308 region which are used to determine the weather throughout the
309 scenario. As the historical battle did only occur once the weather
310 may not change from game to game so we compute the weather of a
311 scenario depending on three values:
312 inital condition, weather region, month
313 Initial Condition:
314 1 clear
315 0 rain/snow
316 Regions:
317 0 Desert
318 1 Mediterranean
319 2 Northern Europe
320 3 Eastern Europe
321 This routine does only use Fair(Dry), Overcast(Dry), Rain(Mud) and
322 Snow(Ice), so there is no delay between ground and air conditions.
323 ====================================================================
324 */
scen_create_random_weather(FILE * dest_file,FILE * scen_file,int month,int turns)325 void scen_create_random_weather( FILE *dest_file, FILE *scen_file, int month, int turns )
326 {
327 float month_mod[13] = { 0, 1.7, 1.6, 1.0, 2.0, 1.2, 0.7, 0.5, 0.6, 1.4, 1.7, 2.2, 1.7 };
328 int med_weather[4] = { 0, 16, 24, 36 };
329 int bad_weather[4] = { 0, 8, 12, 18 };
330 int i, result;
331 int init_cond = 0, region = 0;
332 int weather[turns];
333 memset( weather, 0, sizeof( int ) * turns );
334 /* get condition and region */
335 fseek( scen_file, 16, SEEK_SET );
336 _fread( &init_cond, 1, 1, scen_file );
337 _fread( ®ion, 1, 1, scen_file );
338
339 /* compute the weather */
340 random_seed( month * turns + ( region + 1 ) * ( init_cond + 1 ) );
341 for ( i = 0; i < turns; i++ ) {
342 result = random_get( 1, 100 );
343 if ( result <= (int)( month_mod[month] * bad_weather[region] ) )
344 weather[i] = 2;
345 else
346 if ( result <= (int)( month_mod[month] * med_weather[region] ) )
347 weather[i] = 1;
348 }
349
350 /* initial condition */
351 weather[0] = (init_cond==1)?0:2;
352 /* from december to february turn 2 (rain) into 3 (snow) */
353 if ( month < 3 || month == 12 ) {
354 for ( i = 0; i < turns; i++ )
355 if ( weather[i] == 2 )
356 weather[i]++;
357 }
358
359 /* write weather */
360 fprintf( dest_file, "weather�" );
361 i = 0;
362 while ( i < turns ) {
363 fprintf( dest_file, "%s", weather[i]==0?"fair":weather[i]==1?"clouds":weather[i]==2?"rain":"snow" );
364 if ( i < turns - 1 )
365 fprintf( dest_file, "�" );
366 i++;
367 }
368 fprintf( dest_file, "\n" );
369 }
370
371 /*
372 ====================================================================
373 Use fixed weather obtained from a run of PG for scen_id!=-1. If -1
374 use old algorithm for random weather.
375 ====================================================================
376 */
scen_create_pg_weather(FILE * dest_file,int scen_id,FILE * scen_file,int turns)377 void scen_create_pg_weather( FILE *dest_file, int scen_id, FILE *scen_file, int turns )
378 {
379 /* HACK: use weather type id's directly with shortcut f=fair,o=clouds,R=rain,S=snow */
380 char *weathers[] = {
381 "fffffroRff",
382 "ffffffffffffrooorRff",
383 "fffforRRRmfffforRROffffff",
384 "fffffffrROooffffffffffooroffff",
385 "ffffffffffffoorfffffffffff",
386 "ffffffooorfffff",
387 "",
388 "",
389 "",
390 "ffffffffffffffrooooofffsoSISSi",
391 "fffffffffffffoo",
392 "",
393 "ffffffffooorRffffffff",
394 "fffforofffffff",
395 "",
396 "ooofffffffforRoffffffff",
397 "SISSSSSSSIISISSiffsSSSSISSSISSII",
398 "ffffffffffffffrooffffffff",
399 "fffffroRooffffff",
400 "ffroorfffffff",
401 "ffffffffffforooffffffffoo",
402 "fffffffffroRR",
403 "ffffffffoorofffffffffff",
404 "fffffffffoorofffffffffffrooo",
405 "fffffsooSSSiffffsSffff",
406 "ffffffffffforofff",
407 "fffooooosSfffsoSIffffoo",
408 "ffffffffffffforoooffffffffffffo",
409 "ffsoSSiffroooroRffffsS",
410 "fffffffffffffoorofff",
411 "ffffooosfffffosSSSIif",
412 "ffffffffffffffrooffffff",
413 "fffffoorRRRmffffosSf",
414 "ffffoosofffoo",
415 "fffroRofffrRM",
416 "fffffffffffffrffffffff",
417 "ffffffffffsooofffffoosos",
418 "ffffffroforofff"
419 };
420 int i;
421 char w[32];
422 if (strlen(weathers[scen_id])>0&&strlen(weathers[scen_id])!=turns)
423 fprintf(stderr,"ERROR: scen %d: mismatch in length of weather (%d) and turn number (%d)\n",
424 scen_id,strlen(weathers[scen_id]),turns);
425 /* write weather */
426 fprintf( dest_file, "weather�" );
427 i = 0;
428 while ( i < turns ) {
429 if (weathers[0]==0)
430 strcpy(w,"fair");
431 else
432 {
433 w[0] = weathers[scen_id][i]; w[1] = 0;
434 if (w[0]=='f') strcpy(w,"fair");
435 else if (w[0]=='o') strcpy(w,"clouds");
436 else if (w[0]=='R') strcpy(w,"rain");
437 else if (w[0]=='S') strcpy(w,"snow");
438 }
439 fprintf( dest_file, "%s", w );
440 if ( i < turns - 1 )
441 fprintf( dest_file, "�" );
442 i++;
443 }
444 fprintf( dest_file, "\n" );
445 }
446
447 /*
448 ====================================================================
449 Read unit data from scen_file, convert and write it to dest_file.
450 ====================================================================
451 */
scen_create_unit(int scen_id,FILE * dest_file,FILE * scen_file,int is_core_unit)452 void scen_create_unit( int scen_id, FILE *dest_file, FILE *scen_file, int is_core_unit )
453 {
454 int id = 0, nation = 0, x = 0, y = 0, str = 0, entr = 0, exp = 0, trsp_id = 0, org_trsp_id = 0;
455 /* read unit -- 14 bytes */
456 /* icon id */
457 _fread( &id, 2, 1, scen_file ); /* icon id */
458 id = SDL_SwapLE16(id);
459 _fread( &org_trsp_id, 2, 1, scen_file ); /* transporter of organic unit */
460 org_trsp_id = SDL_SwapLE16(org_trsp_id);
461 _fread( &nation, 1, 1, scen_file ); nation--; /* nation + 1 */
462 _fread( &trsp_id, 2, 1, scen_file ); /* sea/air transport */
463 trsp_id = SDL_SwapLE16(trsp_id);
464 _fread( &x, 2, 1, scen_file ); /* x */
465 x = SDL_SwapLE16(x);
466 _fread( &y, 2, 1, scen_file ); /* y */
467 y = SDL_SwapLE16(y);
468 _fread( &str, 1, 1, scen_file ); /* strength */
469 _fread( &entr, 1, 1, scen_file ); /* entrenchment */
470 _fread( &exp, 1, 1, scen_file ); /* experience */
471 /* FIX: give transporters to artillery in Kiev */
472 if (scen_id==23)
473 {
474 if (x==7&&y==14) trsp_id = 86;
475 if (x==8&&y==23) trsp_id = 86;
476 }
477 /* mark id */
478 unit_entry_used[id - 1] = 1;
479 if ( trsp_id )
480 unit_entry_used[trsp_id - 1] = 1;
481 else
482 if ( org_trsp_id )
483 unit_entry_used[org_trsp_id - 1] = 1;
484 /* write unit */
485 fprintf( dest_file, "<unit\n" );
486 fprintf( dest_file, "id�%i\nnation�%s\n",
487 id - 1, nations[nation * 3]);
488 if (is_core_unit)
489 fprintf( dest_file, "core�1\n");
490 fprintf( dest_file, "x�%i\ny�%i\n", x, y );
491 fprintf( dest_file, "str�%i\nentr�%i\nexp�%i\n", str, entr, exp );
492 if ( trsp_id == 0 && org_trsp_id == 0 )
493 fprintf( dest_file, "trsp�none\n" );
494 else {
495 if ( trsp_id )
496 fprintf( dest_file, "trsp�%i\n", trsp_id - 1 );
497 else
498 fprintf( dest_file, "trsp�%i\n", org_trsp_id - 1 );
499 }
500 fprintf( dest_file, ">\n" );
501 }
502
503 /*
504 ====================================================================
505 Add the victory conditions
506 ====================================================================
507 */
508 int major_limits[] = {
509 /* if an entry is not -1 it's a default axis offensive
510 and this is the turn number that must remain for a major
511 victory when all flags where captured */
512 -1, /* UNUSED */
513 3, /* POLAND */
514 7, /* WARSAW */
515 5, /* NORWAY */
516 6, /* LOWCOUNRTIES */
517 13, /* FRANCE */
518 3, /* SEALION 40 */
519 4, /* NORTH AFRICA */
520 5, /* MIDDLE EAST */
521 3, /* EL ALAMEIN */
522 12, /* CAUCASUS */
523 3, /* SEALION 43 */
524 -1, /* TORCH */
525 -1, /* HUSKY */
526 -1, /* ANZIO */
527 -1, /* D-DAY */
528 -1, /* ANVIL */
529 -1, /* ARDENNES */
530 -1, /* COBRA */
531 -1, /* MARKETGARDEN */
532 -1, /* BERLIN WEST */
533 3, /* BALKANS */
534 2, /* CRETE */
535 10, /* BARBAROSSA */
536 8, /* KIEV */
537 4, /* MOSCOW 41 */
538 3, /* SEVASTAPOL */
539 6, /* MOSCOW 42 */
540 13, /*STALINGRAD */
541 4, /* KHARKOV */
542 -1, /*KURSK */
543 5, /* MOSCOW 43*/
544 -1, /* BYELORUSSIA */
545 5, /* BUDAPEST */
546 -1, /* BERLIN EAST */
547 -1, /* BERLIN */
548 7, /* WASHINGTON */
549 5, /* EARLY MOSCOW */
550 3, /* SEALION PLUS */
551 };
552 #define COND_BEGIN fprintf( file, "<cond\n" )
553 #define COND_END fprintf( file, ">\n" )
554 #define COND_RESULT( str ) fprintf( file, "result�%s\n", str )
555 #define COND_MESSAGE( str ) fprintf( file, "message�%s\n", str )
scen_add_vic_conds(FILE * file,int id)556 void scen_add_vic_conds( FILE *file, int id )
557 {
558 /* for panzer general the check is usually run every turn.
559 * exceptions:
560 * ardennes: major/minor victory depends on whether bruessel
561 * can be taken
562 * d-day: axis must hold its initial three objectives until
563 * the end
564 * anvil: axis must hold its initial five objectives until
565 * the end
566 */
567 if ( id == 15 || id == 16 || id == 17 )
568 fprintf( file, "<result\ncheck�last_turn\n" );
569 else
570 fprintf( file, "<result\ncheck�every_turn\n" );
571 /* add conditions */
572 if ( major_limits[id] != -1 ) {
573 COND_BEGIN;
574 fprintf( file, "<and\n<control_all_hexes\nplayer�axis\n>\n<turns_left\ncount�%i\n>\n>\n", major_limits[id] );
575 COND_RESULT( "major" );
576 COND_MESSAGE( "Axis Major Victory" );
577 COND_END;
578 COND_BEGIN;
579 fprintf( file, "<and\n<control_all_hexes\nplayer�axis\n>\n>\n" );
580 COND_RESULT( "minor" );
581 COND_MESSAGE( "Axis Minor Victory" );
582 COND_END;
583 fprintf( file, "<else\n" );
584 COND_RESULT( "defeat" );
585 COND_MESSAGE( "Axis Defeat" );
586 COND_END;
587 }
588 else
589 if ( id == 17 ) {
590 /* ardennes is a special axis offensive */
591 COND_BEGIN;
592 fprintf( file, "<and\n"\
593 "<control_hex\nplayer�axis\nx�16\ny�16\n>\n"\
594 "<control_hex\nplayer�axis\nx�26\ny�4\n>\n"\
595 "<control_hex\nplayer�axis\nx�27\ny�21\n>\n"\
596 "<control_hex\nplayer�axis\nx�39\ny�21\n>\n"\
597 "<control_hex\nplayer�axis\nx�48\ny�8\n>\n"\
598 "<control_hex\nplayer�axis\nx�54\ny�14\n>\n"\
599 "<control_hex\nplayer�axis\nx�59\ny�18\n>\n"\
600 ">\n" );
601 COND_RESULT( "minor" );
602 COND_MESSAGE( "Axis Minor Victory" );
603 COND_END;
604 /* major victory */
605 COND_BEGIN;
606 fprintf( file, "<or\n<control_all_hexes\nplayer�axis\n>\n>\n" );
607 COND_RESULT( "major" );
608 COND_MESSAGE( "Axis Major Victory" );
609 COND_END;
610 /* defeat otherwise */
611 fprintf( file, "<else\n" );
612 COND_RESULT( "defeat" );
613 COND_MESSAGE( "Axis Defeat" );
614 COND_END;
615 }
616 else {
617 /* allied offensives */
618 COND_BEGIN;
619 switch ( id ) {
620 case 12: /* TORCH */
621 fprintf( file, "<or\n<control_hex\nplayer�allies\nx�27\ny�5\n>\n<control_hex_num\nplayer�allies\ncount�6\n>\n>\n" );
622 break;
623 case 13: /* HUSKY */
624 fprintf( file, "<or\n<control_hex_num\nplayer�allies\ncount�14\n>\n>\n" );
625 break;
626 case 14: /* ANZIO */
627 fprintf( file, "<or\n<control_hex\nplayer�allies\nx�13\ny�17\n>\n<control_hex_num\nplayer�allies\ncount�5\n>\n>\n" );
628 break;
629 case 15: /* D-DAY */
630 fprintf( file, "<or\n<control_hex_num\nplayer�allies\ncount�4\n>\n>\n" );
631 break;
632 case 16: /* ANVIL */
633 fprintf( file, "<or\n<control_hex_num\nplayer�allies\ncount�5\n>\n>\n" );
634 break;
635 case 18: /* COBRA */
636 fprintf( file, "<or\n<control_hex_num\nplayer�allies\ncount�5\n>\n>\n" );
637 break;
638 case 19: /* MARKET-GARDEN */
639 fprintf( file, "<and\n<control_hex\nplayer�allies\nx�37\ny�10\n>\n>\n" );
640 break;
641 case 20: /* BERLIN WEST */
642 fprintf( file, "<or\n<control_hex\nplayer�allies\nx�36\ny�14\n>\n<control_hex_num\nplayer�allies\ncount�5\n>\n>\n" );
643 break;
644 case 30: /* KURSK */
645 fprintf( file, "<or\n<control_all_hexes\nplayer�allies\n>\n>\n" );
646 break;
647 case 32: /* BYELORUSSIA */
648 fprintf( file, "<or\n<control_hex\nplayer�allies\nx�3\ny�12\n>\n>\n" );
649 break;
650 case 34: /* BERLIN EAST */
651 fprintf( file, "<or\n<control_hex\nplayer�allies\nx�36\ny�14\n>\n<control_hex_num\nplayer�allies\ncount�8\n>\n>\n" );
652 break;
653 case 35: /* BERLIN */
654 fprintf( file, "<or\n<control_hex\nplayer�allies\nx�36\ny�14\n>\n>\n" );
655 break;
656 }
657 COND_RESULT( "defeat" );
658 COND_MESSAGE( "Axis Defeat" );
659 COND_END;
660 /* axis major victory condition */
661 COND_BEGIN;
662 if ( id == 15 )
663 {
664 /* D-DAY */
665 fprintf( file, "<and\n"\
666 "<control_hex\nplayer�axis\nx�11\ny�7\n>\n"\
667 "<control_hex\nplayer�axis\nx�22\ny�28\n>\n"\
668 "<control_hex\nplayer�axis\nx�43\ny�27\n>\n"\
669 ">\n" );
670 }
671 else if ( id == 16 )
672 {
673 /* ANVIL */
674 fprintf( file, "<and\n"\
675 "<control_hex\nplayer�axis\nx�7\ny�3\n>\n"\
676 "<control_hex\nplayer�axis\nx�15\ny�4\n>\n"\
677 "<control_hex\nplayer�axis\nx�5\ny�22\n>\n"\
678 "<control_hex\nplayer�axis\nx�12\ny�27\n>\n"\
679 "<control_hex\nplayer�axis\nx�31\ny�21\n>\n"\
680 ">\n" );
681 }
682 else
683 {
684 /* capture all */
685 fprintf( file, "<or\n<control_all_hexes\nplayer�axis\n>\n>\n" );
686 }
687 COND_RESULT( "major" );
688 COND_MESSAGE( "Axis Major Victory" );
689 COND_END;
690 fprintf( file, "<else\n" );
691 COND_RESULT( "minor" );
692 COND_MESSAGE( "Axis Minor Victory" );
693 COND_END;
694 }
695 /* end result struct */
696 fprintf( file, ">\n" );
697 }
698
699 /** Read @num bytes into @buf from @file at position @offset. Return
700 * number of bytes read or -1 on error.
701 * Note: File position indicator is not reset. */
freadat(FILE * file,int offset,unsigned char * buf,int num)702 int freadat( FILE *file, int offset, unsigned char *buf, int num)
703 {
704 if (fseek( file, offset, SEEK_SET ) < 0)
705 return -1;
706 return fread( buf, 1, num, file );
707 }
708
709 /** Read prestige info from open file handle @file and store it to @pi_axis
710 * and @pi_allies respectively.
711 * Return -1 on error (prestige info may be incomplete), 0 on success. */
712 struct prestige_info {
713 int start;
714 int bucket;
715 int interval;
716 };
read_prestige_info(FILE * file,struct prestige_info * pi_axis,struct prestige_info * pi_allies)717 int read_prestige_info( FILE *file, struct prestige_info *pi_axis,
718 struct prestige_info *pi_allies )
719 {
720 /* Offsets in scenario buffer as taken from FPGE:
721 * axis start prestige: scnbuf[0x75]*4+0x77
722 * allies start prestige: scnbuf[0x75]*4+0x77 + 2
723 * axis prestige bucket: 27
724 * allies prestige bucket: 29
725 * axis prestige interval: 31
726 * allies prestige interval: 32
727 */
728 unsigned char c, buf[6];
729 int idx;
730
731 memset(pi_axis,0,sizeof(struct prestige_info));
732 memset(pi_allies,0,sizeof(struct prestige_info));
733
734 if (freadat(file, 0x75, &c, 1) < 1)
735 return -1;
736 idx = ((int)c) * 4 + 0x77;
737
738 /* start prestige */
739 if (freadat(file, idx, buf, 4) < 4)
740 return -1;
741 pi_axis->start = buf[0] + 256 * buf[1];
742 pi_allies->start = buf[2] + 256 * buf[3];
743
744 /* bucket + interval */
745 if (freadat(file, 27, buf, 6) < 6)
746 return -1;
747 pi_axis->bucket = buf[0] + 256 * buf[1];
748 pi_allies->bucket = buf[2] + 256 * buf[3];
749 pi_axis->interval = buf[4];
750 pi_allies->interval = buf[5];
751
752 return 0;
753 }
754
755 /** Convert PG prestige info into fixed prestige per turn values.
756 * @sid: PG scenario id (starting at 0, or -1 if custom)
757 * @pid: player id (0=axis, 1=allies)
758 * @pi: PG prestige info (start prestige, bucket and interval)
759 * @strat: player strategy
760 * @nturns: number of scenario turns
761 * @ppt: pointer to prestige per turn output array
762 */
convert_prestige_info(int sid,int pid,const struct prestige_info * pi,int strat,int nturns,int * ppt)763 void convert_prestige_info(int sid, int pid, const struct prestige_info *pi,
764 int strat, int nturns, int *ppt)
765 {
766 int i, val;
767
768 /* PG seems to behave as follows:
769 * Attacker gets start prestige and that's it. No per turn prestige
770 * is added. Defender gets constant prestige per turn and in first
771 * turn also a bonus of two times the turn prestige added to start
772 * prestige.
773 * Loosing/capturing victory objectives does not change the amount
774 * of per turn prestige for defender/attacker (on capturing fixed
775 * amount of prestige is given to player once, no loss for other
776 * player).
777 *
778 * FIXME: Per turn value seems to be related to number of turns and
779 * bucket value, while interval does not seem to be used at all. But
780 * since I could not figure out the formula use hardcoded per turn
781 * values (as observed in PG). Try bucket/nturns as formula for
782 * custom scenarios. */
783
784 if (sid == -1)
785 val = pi->bucket / nturns;
786 else
787 val = prestige_per_turn[sid*2 + pid];
788
789 /* Clear output array */
790 memset(ppt, 0, sizeof(int) * nturns);
791
792 /* Set start prestige */
793 ppt[0] = pi->start;
794 /* Add bonus if strategy is defensive */
795 if (strat < 0)
796 ppt[0] += 2 * val;
797
798 /* Set remaining per turn prestige */
799 if (strat <= 0) /* if both are even in strength both get prestige */
800 for (i = 1; i < nturns; i++)
801 ppt[i] = val;
802 }
803
804 /** Write prestige per turn list to @file. */
write_prestige_info(FILE * file,int turns,int * ppt)805 int write_prestige_info( FILE *file, int turns, int *ppt )
806 {
807 int i;
808
809 fprintf( file, "prestige�" );
810 for (i = 0; i < turns; i++)
811 fprintf( file, "%d%c", ppt[i],
812 (i < turns - 1) ? '�' : '\n');
813 return 0;
814 }
815
816 /** Read axis/allies max unit count from file handle @file.
817 * Return -1 on error (values incomplete then) or 0 on success. */
read_unit_limit(FILE * file,int * axis_ulimit,int * axis_core_ulimit,int * allies_ulimit)818 int read_unit_limit( FILE *file, int *axis_ulimit, int *axis_core_ulimit, int *allies_ulimit )
819 {
820 unsigned char buf[3];
821
822 *axis_ulimit = *axis_core_ulimit = *allies_ulimit = 0;
823
824 if (freadat(file, 18, buf, 3) < 3)
825 return -1;
826 *axis_ulimit = buf[0] + buf[1]; /* core + aux */
827 *axis_core_ulimit = buf[0];
828 *allies_ulimit = buf[2];
829 return 0;
830 }
831
832 /** Get a decent file name from scenario title: Change to lower case,
833 * remove blanks and special characters. Return as pointer to static
834 * string. */
scentitle_to_filename(const char * title)835 static char *scentitle_to_filename( const char *title )
836 {
837 static char fname[32];
838 int i, j;
839
840 snprintf(fname, 32, "%s", title);
841 for (i = 0; i < strlen(fname); i++) {
842 /* adjust case (first character of word is upper case) */
843 if (i == 0 || fname[i - 1] == ' ')
844 fname[i] = toupper(fname[i]);
845 else
846 fname[i] = tolower(fname[i]);
847 /* only allow alphanumerical chars */
848 if ((fname[i] >= 'A' && fname[i] <= 'Z') ||
849 (fname[i] >= 'a' && fname[i] <= 'z') ||
850 (fname[i] >= '0' && fname[i] <= '9') ||
851 fname[i] == '-' || fname[i] == '_')
852 ; /* is okay, do nothing */
853 else
854 fname[i] = ' ';
855 }
856
857 /* remove all blanks */
858 for (i = 0; fname[i] != 0; i++) {
859 if (fname[i] != ' ')
860 continue;
861 for (j = i; fname[j] != 0; j++)
862 fname[j] = fname[j + 1];
863 i--; /* re-check if we just shifted a blank */
864 }
865
866 return fname;
867 }
868
869
870
871
872 /*
873 ====================================================================
874 Publics
875 ====================================================================
876 */
877
878 /*
879 ====================================================================
880 If scen_id == -1 convert all scenarios found in 'source_path'.
881 If scen_id >= 0 convert single scenario from current working
882 directory.
883 ====================================================================
884 */
scenarios_convert(int scen_id)885 int scenarios_convert( int scen_id )
886 {
887 int i, j, start, end;
888 char dummy[256];
889 int day, month, year, turns, turns_per_day, days_per_turn, ibuf;
890 int unit_offset, unit_count;
891 int axis_orient, axis_strat, allied_strat;
892 int deploy_fields_count;
893 struct prestige_info pi_axis, pi_allies;
894 char path[MAXPATHLEN];
895 FILE *dest_file = 0, *scen_file = 0, *aux_file = 0, *scenstat_file = 0;
896 PData *pd = 0, *reinf, *unit;
897 int def_str, def_exp;
898 char *str;
899 int axis_ulimit = 0, axis_core_ulimit = 0, allies_ulimit = 0;
900 char scen_title[16], scen_desc[160], scen_author[32];
901 int core_unit_count = 0;
902
903 printf( "Scenarios...\n" );
904
905 if ( scen_id == -1 ) {
906 snprintf( path, MAXPATHLEN, "%s/scenarios/%s", dest_path, target_name );
907 mkdir( path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH );
908
909 if (strcmp(target_name, "pg") == 0) {
910 /* write out order of preferred listing */
911 snprintf( path, MAXPATHLEN, "%s/scenarios/pg/.order", dest_path );
912 aux_file = fopen( path, "wb" );
913 if ( aux_file ) {
914 for (i = 0; i < sizeof fnames/sizeof fnames[0]; i++)
915 fprintf( aux_file, "%s\n", fnames[i] );
916 fclose( aux_file );
917 } else
918 fprintf( stderr, "Could not write sort order to %s\n", path );
919 }
920
921 /* get the reinforcements which are used later */
922 snprintf( path, MAXPATHLEN, "%s/convdata/reinf", get_gamedir() );
923 if ( ( pd = parser_read_file( "reinforcements", path ) ) == 0 ) {
924 fprintf( stderr, "%s\n", parser_get_error() );
925 goto failure;
926 }
927
928 }
929
930 /* set loop range */
931 if ( scen_id == -1 ) {
932 start = 1;
933 end = 38;
934 } else {
935 start = end = scen_id;
936 }
937
938 /* open scen stat file containing scenario names and descriptions */
939 if ( scen_id == -1 ) {
940 snprintf( path, MAXPATHLEN, "%s/scenstat.bin", source_path );
941 if ((scenstat_file = fopen_ic(path, "rb")) == NULL)
942 goto failure;
943 }
944
945 /* go */
946 for ( i = start; i <=end; i++ ) {
947 /* open scenario file */
948 snprintf( path, MAXPATHLEN, "%s/game%03d.scn", source_path, i );
949 if ((scen_file = fopen_ic(path, "rb")) == NULL) {
950 fprintf( stderr, "%s: file not found\n", path );
951 if (scen_id == -1 && strcmp(target_name,"pg")) {
952 map_or_scen_files_missing = 1;
953 continue;
954 } else
955 goto failure;
956 }
957
958 /* read title and description from scenstat file for campaign */
959 if ( scen_id == -1 ) {
960 fseek( scenstat_file, 40 + (i - 1) * 14, SEEK_SET );
961 _fread( dummy, 14, 1, scenstat_file );
962 snprintf( scen_title, sizeof(scen_title), "%s", dummy);
963 fseek( scenstat_file, 600 + (i - 1) * 160 , SEEK_SET );
964 _fread( dummy, 160, 1, scenstat_file );
965 snprintf( scen_desc, sizeof(scen_desc), "%s", dummy);
966 if (strcmp(target_name,"pg") == 0)
967 snprintf( scen_author, sizeof(scen_author), "SSI" );
968 else
969 snprintf( scen_author, sizeof(scen_author), "unknown" );
970 } else {
971 snprintf( scen_title, sizeof(scen_title), "%s", target_name );
972 snprintf( scen_desc, sizeof(scen_desc), "none" );
973 snprintf( scen_author, sizeof(scen_author), "unknown" );
974 }
975
976 /* open dest file */
977 if ( scen_id == -1 ) {
978 if (strcmp(target_name,"pg") == 0)
979 snprintf( path, MAXPATHLEN, "%s/scenarios/pg/%s",
980 dest_path, fnames[i - 1] );
981 else {
982 char fname[32];
983 snprintf(fname, 32, "%s", scentitle_to_filename(scen_title));
984 if (fname[0] == 0) {
985 /* bad scenario name so use a default name */
986 snprintf(fname, 32, "scn%02d", i);
987 fprintf(stderr, "Using %s as filename for scenario %d as "
988 "title '%s' is not suitable\n", fname, i,
989 scen_title);
990 }
991 snprintf( path, MAXPATHLEN, "%s/scenarios/%s/%s",
992 dest_path, target_name, fname);
993 }
994 } else
995 snprintf( path, MAXPATHLEN, "%s/scenarios/%s",
996 dest_path, target_name );
997 if ( ( dest_file = fopen( path, "wb" ) ) == 0 ) {
998 fprintf( stderr, "%s: access denied\n", path );
999 goto failure;
1000 }
1001
1002 /* file magic */
1003 fprintf( dest_file, "@\n" );
1004
1005 /* scenario name and description */
1006 fprintf( dest_file, "name�%s\n", scen_title );
1007 fprintf( dest_file, "desc�%s\n", scen_desc );
1008 fprintf( dest_file, "authors�%s\n", scen_author );
1009
1010 /* date */
1011 fseek( scen_file, 22, SEEK_SET );
1012 day = 0; _fread( &day, 1, 1, scen_file );
1013 month = 0; _fread( &month, 1, 1, scen_file );
1014 year = 0; _fread( &year, 1, 1, scen_file );
1015 fprintf( dest_file, "date�%02i.%02i.19%i\n", day, month, year );
1016
1017 /* turn limit */
1018 fseek( scen_file, 21, SEEK_SET );
1019 turns = 0; _fread( &turns, 1, 1, scen_file );
1020 fprintf( dest_file, "turns�%i\n", turns );
1021 fseek( scen_file, 25, SEEK_SET );
1022 turns_per_day = 0; _fread( &turns_per_day, 1, 1, scen_file );
1023 fprintf( dest_file, "turns_per_day�%i\n", turns_per_day );
1024 days_per_turn = 0; _fread( &days_per_turn, 1, 1, scen_file );
1025 if ( turns_per_day == 0 && days_per_turn == 0 )
1026 days_per_turn = 1;
1027 fprintf( dest_file, "days_per_turn�%i\n", days_per_turn );
1028
1029 /* domain */
1030 fprintf( dest_file, "domain�pg\n" );
1031 /* nations */
1032 if ( scen_id == -1 )
1033 fprintf( dest_file, "nation_db�%s.ndb\n", target_name );
1034 else
1035 fprintf( dest_file, "nation_db�pg.ndb\n" );
1036 /* units */
1037 if ( scen_id == -1 )
1038 fprintf( dest_file, "<unit_db\nmain�%s.udb\n>\n", target_name );
1039 else if (!units_find_panzequp())
1040 fprintf( dest_file, "<unit_db\nmain�pg.udb\n>\n");
1041 /* if there modified units they are added to the
1042 scenario file. lgeneral loads from the scenario file
1043 if no unit_db was specified. */
1044 /* map:
1045 a custom scenario will have the map added to the same file which
1046 will be checked when no map was specified.
1047 */
1048 if ( scen_id == -1 )
1049 fprintf( dest_file, "map�%s/map%02d\n", target_name, i );
1050 /* weather */
1051 if (scen_id == -1 && strcmp(target_name,"pg") == 0)
1052 scen_create_pg_weather( dest_file, i-1, scen_file, turns );
1053 else
1054 scen_create_random_weather( dest_file, scen_file, month, turns );
1055 /* flags */
1056 fprintf( dest_file, "<flags\n" );
1057 if ( !scen_add_flags( dest_file, scen_file, i ) ) goto failure;
1058 fprintf( dest_file, ">\n" );
1059 /* get unit offset */
1060 fseek( scen_file, 117, SEEK_SET );
1061 ibuf = 0; _fread( &ibuf, 1, 1, scen_file );
1062 unit_offset = ibuf * 4 + 135;
1063 /* get prestige data for axis and allies */
1064 read_prestige_info(scen_file, &pi_axis, &pi_allies );
1065 /* get unit limits for axis and allies */
1066 read_unit_limit( scen_file, &axis_ulimit, &axis_core_ulimit, &allies_ulimit );
1067 /* players */
1068 fprintf( dest_file, "<players\n" );
1069 /* axis */
1070 fseek( scen_file, 12, SEEK_SET );
1071 /* orientation */
1072 axis_orient = 0; _fread( &axis_orient, 1, 1, scen_file );
1073 if ( axis_orient == 1 )
1074 sprintf( dummy, "right" );
1075 else
1076 sprintf( dummy, "left" );
1077 /* strategy: -2 (very defensive) to 2 (very aggressive) */
1078 fseek( scen_file, 15, SEEK_SET );
1079 axis_strat = 0; _fread( &axis_strat, 1, 1, scen_file );
1080 if ( axis_strat == 0 )
1081 axis_strat = 1;
1082 else
1083 axis_strat = -1;
1084 /* definition */
1085 if (axis_name)
1086 fprintf( dest_file, "<axis\nname�%s\n", axis_name );
1087 else
1088 fprintf( dest_file, "<axis\nname�Axis\n" );
1089 if (axis_nations) {
1090 char *ptr, auxstr[256]; /* commata need conversion */
1091 snprintf(auxstr,256,"%s",axis_nations);
1092 for (ptr = auxstr; *ptr != 0; ptr++)
1093 if (ptr[0] == ',')
1094 ptr[0] = '�';
1095 fprintf( dest_file, "nations�%s\n", auxstr );
1096 } else
1097 fprintf( dest_file, "nations�ger�aus�it�hun�bul�rum�fin�esp\n" );
1098 fprintf( dest_file, "allied_players�\n" );
1099 fprintf( dest_file, "unit_limit�%d\n", axis_ulimit );
1100 fprintf( dest_file, "core_unit_limit�%d\n", axis_core_ulimit );
1101 fprintf( dest_file, "orientation�%s\ncontrol�human\nstrategy�%i\n", dummy, axis_strat );
1102 {
1103 int ppt[turns]; /* prestige per turn with dynamic size */
1104 convert_prestige_info((scen_id==-1)?(i-1):-1, 0, &pi_axis,
1105 axis_strat, turns, ppt);
1106 write_prestige_info( dest_file, turns, ppt );
1107 }
1108 if ( scen_id == -1 && strcmp(target_name,"pg") == 0 )
1109 fprintf( dest_file, "ai_module�%s\n", ai_modules[i*2] );
1110 else
1111 fprintf( dest_file, "ai_module�default\n" );
1112 /* transporter */
1113 fprintf( dest_file, "<transporters\n" );
1114 /* air */
1115 fseek( scen_file, unit_offset - 8, SEEK_SET );
1116 ibuf = 0; _fread( &ibuf, 2, 1, scen_file );
1117 ibuf = SDL_SwapLE16(ibuf);
1118 if ( ibuf )
1119 fprintf( dest_file, "<air\nunit�%i\ncount�50\n>\n", ibuf - 1 );
1120 /* sea */
1121 fseek( scen_file, unit_offset - 4, SEEK_SET );
1122 ibuf = 0; _fread( &ibuf, 2, 1, scen_file );
1123 ibuf = SDL_SwapLE16(ibuf);
1124 if ( ibuf )
1125 fprintf( dest_file, "<sea\nunit�%i\ncount�50\n>\n", ibuf - 1 );
1126 fprintf( dest_file, ">\n" );
1127 fprintf( dest_file, ">\n" );
1128 /* allies */
1129 if ( axis_orient == 1 )
1130 sprintf( dummy, "left" );
1131 else
1132 sprintf( dummy, "right" );
1133 if ( axis_strat == 1 )
1134 allied_strat = -1;
1135 else
1136 allied_strat = 1;
1137 if (allies_name)
1138 fprintf( dest_file, "<allies\nname�%s\n", allies_name );
1139 else
1140 fprintf( dest_file, "<allies\nname�Allies\n" );
1141 if (allies_nations) {
1142 char *ptr, auxstr[256]; /* commata need conversion */
1143 snprintf(auxstr,256,"%s",allies_nations);
1144 for (ptr = auxstr; *ptr != 0; ptr++)
1145 if (ptr[0] == ',')
1146 ptr[0] = '�';
1147 fprintf( dest_file, "nations�%s\n", auxstr );
1148 } else
1149 fprintf( dest_file, "nations�bel�lux�den�fra�gre�usa�tur�net�nor�pol�por�so�swe�swi�eng�yug\n" );
1150 fprintf( dest_file, "allied_players�\n" );
1151 fprintf( dest_file, "unit_limit�%d\n", allies_ulimit );
1152 fprintf( dest_file, "core_unit_limit�0\n" );
1153 fprintf( dest_file, "orientation�%s\ncontrol�cpu\nstrategy�%i\n", dummy, allied_strat );
1154 {
1155 int ppt[turns]; /* prestige per turn with dynamic size */
1156 convert_prestige_info((scen_id==-1)?(i-1):-1, 1, &pi_allies,
1157 allied_strat, turns, ppt);
1158 write_prestige_info( dest_file, turns, ppt );
1159 }
1160 if ( scen_id == -1 && strcmp(target_name,"pg") == 0 )
1161 fprintf( dest_file, "ai_module�%s\n", ai_modules[i*2 + 1] );
1162 else
1163 fprintf( dest_file, "ai_module�default\n" );
1164 /* transporter */
1165 fprintf( dest_file, "<transporters\n" );
1166 /* air */
1167 fseek( scen_file, unit_offset - 6, SEEK_SET );
1168 ibuf = 0; _fread( &ibuf, 2, 1, scen_file );
1169 ibuf = SDL_SwapLE16(ibuf);
1170 if ( ibuf )
1171 fprintf( dest_file, "<air\nunit�%i\ncount�50\n>\n", ibuf - 1 );
1172 /* sea */
1173 fseek( scen_file, unit_offset - 2, SEEK_SET );
1174 ibuf = 0; _fread( &ibuf, 2, 1, scen_file );
1175 ibuf = SDL_SwapLE16(ibuf);
1176 if ( ibuf )
1177 fprintf( dest_file, "<sea\nunit�%i\ncount�50\n>\n", ibuf - 1 );
1178 fprintf( dest_file, ">\n" );
1179 fprintf( dest_file, ">\n" );
1180 fprintf( dest_file, ">\n" );
1181 /* victory conditions */
1182 if ( scen_id == -1 && strcmp(target_name,"pg") == 0 )
1183 scen_add_vic_conds( dest_file, i );
1184 else {
1185 /* and the default is that the attacker must capture
1186 all targets */
1187 fprintf( dest_file, "<result\ncheck�every_turn\n" );
1188 fprintf( dest_file, "<cond\n" );
1189 fprintf( dest_file, "<and\n<control_all_hexes\nplayer�%s\n>\n>\n",
1190 (axis_strat > 0) ? "axis" : "allies" );
1191 fprintf( dest_file, "result�victory\n" );
1192 fprintf( dest_file, "message�%s\n",
1193 (axis_strat > 0) ? "Axis Victory" : "Allied Victory" );
1194 fprintf( dest_file, ">\n" );
1195 fprintf( dest_file, "<else\n" );
1196 fprintf( dest_file, "result�defeat\n" );
1197 fprintf( dest_file, "message�%s\n",
1198 (axis_strat > 0) ? "Axis Defeat" : "Allied Defeat" );
1199 fprintf( dest_file, ">\n" );
1200 fprintf( dest_file, ">\n" );
1201 }
1202 /* deployment fields */
1203 fseek( scen_file, 117, SEEK_SET );
1204 ibuf = 0; _fread( &ibuf, 2, 1, scen_file );
1205 deploy_fields_count = SDL_SwapLE16(ibuf);
1206 fprintf( dest_file, "<deployfields\n<player\nid�axis\ncoordinates�default�" );
1207 /* last coordinate is always (-1, -1) */
1208 for (j = 0; j < deploy_fields_count - 1; j++) {
1209 int x, y;
1210 ibuf = 0; _fread( &ibuf, 2, 1, scen_file );
1211 x = SDL_SwapLE16(ibuf);
1212 ibuf = 0; _fread( &ibuf, 2, 1, scen_file );
1213 y = SDL_SwapLE16(ibuf);
1214 fprintf( dest_file, "%s%d,%d", j ? "�" : "", x, y );
1215 }
1216 fprintf( dest_file, "\n>\n" );
1217 if (scen_id == -1 && strcmp(target_name,"pg") == 0 && i == 19)
1218 /* MarketGarden's Allies may not deploy freely */
1219 fprintf( dest_file, "<player\nid�allies\ncoordinates�none\n>\n" );
1220 else
1221 fprintf( dest_file, "<player\nid�allies\ncoordinates�default\n>\n" );
1222 fprintf( dest_file, ">\n" );
1223 /* units */
1224 /* mark all id's that will be used from PANZEQUP.EQP
1225 for modified unit database */
1226 memset( unit_entry_used, 0, sizeof( unit_entry_used ) );
1227 /* count them */
1228 fseek( scen_file, 33, SEEK_SET );
1229 ibuf = 0; _fread( &ibuf, 1, 1, scen_file );
1230 unit_count = ibuf; /* core */
1231 core_unit_count = unit_count; /* needed for core flag */
1232 ibuf = 0; _fread( &ibuf, 1, 1, scen_file );
1233 unit_count += ibuf; /* allies */
1234 ibuf = 0; _fread( &ibuf, 1, 1, scen_file );
1235 unit_count += ibuf; /* auxiliary */
1236 /* build them */
1237 fseek( scen_file, unit_offset, SEEK_SET );
1238 fprintf( dest_file, "<units\n" );
1239 for ( j = 0; j < unit_count; j++ )
1240 scen_create_unit( (scen_id!=-1)?(-1):(i-1), dest_file, scen_file, j < core_unit_count );
1241 /* reinforcements -- only for original PG scenarios */
1242 if ( scen_id == -1 && strcmp(target_name,"pg") == 0 ) {
1243 if ( parser_get_pdata( pd, fnames[i - 1], &reinf ) ) {
1244 /* units come unsorted with the proper nation stored for each
1245 unit */
1246 def_str = 10; def_exp = 0;
1247 list_reset( reinf->entries );
1248 while ( ( unit = list_next( reinf->entries ) ) )
1249 if ( !strcmp( "unit", unit->name ) ) {
1250 /* add unit */
1251 fprintf( dest_file, "<unit\n" );
1252 if ( !parser_get_value( unit, "nation", &str, 0 ) )
1253 goto failure;
1254 fprintf( dest_file, "nation�%s\n", str );
1255 if ( !parser_get_int( unit, "id", &ibuf ) )
1256 goto failure;
1257 fprintf( dest_file, "id�%i\n", ibuf );
1258 ibuf = def_str; parser_get_int( unit, "str", &ibuf );
1259 fprintf( dest_file, "str�%i\n", ibuf );
1260 ibuf = def_exp; parser_get_int( unit, "exp", &ibuf );
1261 fprintf( dest_file, "exp�%i\n", ibuf );
1262 fprintf( dest_file, "entr�0\n" );
1263 if ( parser_get_value( unit, "trsp", &str, 0 ) )
1264 fprintf( dest_file, "trsp�%s\n", str );
1265 if ( !parser_get_int( unit, "delay", &ibuf ) )
1266 goto failure;
1267 fprintf( dest_file, "delay�%i\n", ibuf );
1268 fprintf( dest_file, ">\n" );
1269 }
1270 }
1271 }
1272 fprintf( dest_file, ">\n" );
1273 fclose( scen_file );
1274 fclose( dest_file );
1275 }
1276 if ( scenstat_file )
1277 fclose( scenstat_file );
1278 parser_free( &pd );
1279 return 1;
1280 failure:
1281 parser_free( &pd );
1282 if ( scenstat_file ) fclose( scenstat_file );
1283 if ( aux_file ) fclose( aux_file );
1284 if ( scen_file ) fclose( scen_file );
1285 if ( dest_file ) fclose( dest_file );
1286 return 0;
1287 }
1288