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( &region, 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