1 
2 #include "extractstages.h"
3 
4 #include "../maprecord.h"
5 #include "../stagedata.h"
6 
7 #include <cstdint>
8 #include <cstdio>
9 #include <cstdlib>
10 #include <cstring>
11 #include <sys/stat.h>
12 
13 #define NMAPS 95
14 #define DATA_OFFSET 0x937B0
15 
16 #if defined(_WIN32)
17 #define strcasecmp _stricmp
18 #endif
19 
20 struct EXEMapRecord
21 {
22   char tileset[32];
23   char filename[32];
24   int scroll_type;
25   char background[32];
26   char NPCset1[32];
27   char NPCset2[32];
28   uint8_t bossNo;
29   char caption[35];
30 };
31 
32 EXEMapRecord exemapdata[NMAPS];
33 MapRecord mapdata[NMAPS];
34 
35 // the NPC set system isn't used by NXEngine, but the information
36 // is used in a few places to figure out which sprite to be drawn.
37 // for example Balrog when he appears in the Gum Room is supposed to be green.
38 const char *npcsetnames[]
39     = {"guest", "0",      "eggs1", "ravil", "weed",  "maze", "sand",  "omg",    "cemet",  "bllg",   "plant", "frog",
40        "curly", "stream", "ironh", "toro",  "x",     "dark", "almo1", "eggs2",  "twind",  "moon",   "cent",  "heri",
41        "red",   "miza",   "dr",    "almo2", "kings", "hell", "press", "priest", "ballos", "island", NULL};
42 
find_index(const char * fname,const char * list[])43 int find_index(const char *fname, const char *list[])
44 {
45   for (int i = 0; list[i]; i++)
46   {
47     if (!strcasecmp(list[i], fname))
48     {
49       return i;
50     }
51   }
52 
53   return 0xff;
54 }
55 
extract_stages(FILE * exefp)56 bool extract_stages(FILE *exefp)
57 {
58   int i;
59 
60   printf("[ data/stage.dat ]\n");
61 
62   // load raw data into struct
63   fseek(exefp, DATA_OFFSET, SEEK_SET);
64   fread(exemapdata, sizeof(EXEMapRecord), NMAPS, exefp);
65 
66   // convert the data
67   memset(mapdata, 0, sizeof(mapdata));
68   const char *error = NULL;
69 
70   for (i = 0; i < NMAPS; i++)
71   {
72     strcpy(mapdata[i].filename, exemapdata[i].filename);
73     strcpy(mapdata[i].stagename, exemapdata[i].caption);
74 
75     mapdata[i].scroll_type = exemapdata[i].scroll_type;
76     mapdata[i].bossNo      = exemapdata[i].bossNo;
77 
78     mapdata[i].tileset = find_index(exemapdata[i].tileset, tileset_names);
79     if (mapdata[i].tileset == 0xff)
80     {
81       error = "tileset";
82       break;
83     }
84 
85     mapdata[i].bg_no = find_index(exemapdata[i].background, backdrop_names);
86     if (mapdata[i].bg_no == 0xff)
87     {
88       error = "backdrop";
89       break;
90     }
91 
92     mapdata[i].NPCset1 = find_index(exemapdata[i].NPCset1, npcsetnames);
93     if (mapdata[i].NPCset1 == 0xff)
94     {
95       error = "NPCset1";
96       break;
97     }
98 
99     mapdata[i].NPCset2 = find_index(exemapdata[i].NPCset2, npcsetnames);
100     if (mapdata[i].NPCset2 == 0xff)
101     {
102       error = "NPCset2";
103       break;
104     }
105   }
106 
107   if (error)
108   {
109     printf("didn't recognize map %s name\n", error);
110     printf("on stage %d\n", i);
111 
112     return 1;
113   }
114 
115   // write out
116   FILE *fpo = fopen("data/stage.dat", "wb");
117   if (!fpo)
118   {
119     printf("failed to open stage.dat for writing\n");
120     return 1;
121   }
122 
123   fputc(NMAPS, fpo);
124   for (i = 0; i < NMAPS; i++)
125     fwrite(&mapdata[i], sizeof(MapRecord), 1, fpo);
126 
127   fclose(fpo);
128   return 0;
129 }
130