1 /*
2  * Search for a DinkC script usage in the world map
3 
4  * Copyright (C) 1997, 1998, 1999, 2002, 2003  Seth A. Robinson
5  * Copyright (C) 2010  Sylvain Beucler
6 
7  * This file is part of GNU FreeDink
8 
9  * GNU FreeDink is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 3 of the
12  * License, or (at your option) any later version.
13 
14  * GNU FreeDink is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18 
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see
21  * <http://www.gnu.org/licenses/>.
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #define log_info printf
29 #define log_error printf
30 
31 #define BOOL_1BYTE char /* Boolean value on 1 byte exactly, used to
32 			   replace the C++ bool type during the C++=>C
33 			   conversion. Do not change to int, else
34 			   player_info (among others) will have a
35 			   different size and savegame format will
36 			   change! */
37 
38 typedef struct rect {
39   int left, top, right, bottom;
40 } rect;
41 
42 /* Background square in a screen */
43 struct tile
44 {
45   short square_full_idx0; /* tile index */
46   short althard; /* alternate hardness index, 0 = default tile hardness */
47 };
48 
49 struct sprite_placement
50 {
51   int x, y, seq, frame, type, size;
52   BOOL_1BYTE active;
53   int rotation, special, brain;
54 
55   char script[13+1]; /* attached DinkC script */
56   int speed, base_walk, base_idle, base_attack, base_hit, timer, que;
57   int hard;
58   rect alt; /* trim left/top/right/bottom */
59   int prop;
60   int warp_map;
61   int warp_x;
62   int warp_y;
63   int parm_seq;
64 
65   int base_die, gold, hitpoints, strength, defense, exp, sound, vision, nohit, touch_damage;
66   int buff[5];
67 };
68 
69 /* one screen from map.dat */
70 struct small_map
71 {
72   struct tile t[12*8+1]; // 97 background tiles
73   struct sprite_placement sprite[100+1];
74   char script[20+1]; /* script to run when entering the script */
75 };
76 
77 /* dink.dat */
78 struct map_info
79 {
80   int loc[769];
81   int music[769];
82   int indoor[769];
83 };
84 extern struct map_info map;
85 
86 
87 /**
88  * Read integer portably (same result with MSB and LSB
89  * endianness). Source data is a file with little-endian data.
90  */
read_lsb_int(FILE * f)91 int read_lsb_int(FILE *f)
92 {
93   unsigned char buf[4];
94   fread(buf, 4, 1, f);
95   return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | (buf[0]);
96 }
97 
98 
99 /**
100  * Write integer portably (same result with MSB and LSB
101  * endianness). Will write little-endian data to file.
102  */
write_lsb_int(int n,FILE * f)103 void write_lsb_int(int n, FILE *f)
104 {
105   unsigned char buf[4];
106   buf[0] = n & 0xFF;
107   buf[1] = (n >> (1*8)) & 0xFF;
108   buf[2] = (n >> (2*8)) & 0xFF;
109   buf[3] = (n >> (3*8)) & 0xFF;
110   fwrite(buf, 4, 1, f);
111 }
112 
113 /**
114  * Read short portably (same result with MSB and LSB
115  * endianness). Source data is a file with little-endian data.
116  */
read_lsb_short(FILE * f)117 short read_lsb_short(FILE *f)
118 {
119   unsigned char buf[2];
120   fread(buf, 2, 1, f);
121   return (buf[1] << 8) | (buf[0]);
122 }
123 
124 
125 /**
126  * Write short portably (same result with MSB and LSB
127  * endianness). Will write little-endian data to file.
128  */
write_lsb_short(short n,FILE * f)129 void write_lsb_short(short n, FILE *f)
130 {
131   unsigned char buf[2];
132   buf[0] = n & 0xFF;
133   buf[1] = (n >> (1*8)) & 0xFF;
134   fwrite(buf, 2, 1, f);
135 }
136 
137 
138 
139 /**
140  * Load dink.dat to specified memory buffer
141  */
load_info_to(char * path,struct map_info * mymap)142 int load_info_to(char* path, struct map_info *mymap)
143 {
144   FILE *f = NULL;
145 
146   f = fopen(path, "rb");
147   if (!f)
148     return -1;
149 
150   //log_info("World data loaded.");
151 
152   /* Portably load struct map_info from disk */
153   int i = 0;
154   fseek(f, 20, SEEK_CUR); // unused 'name' field
155   for (i = 0; i < 769; i++)
156     mymap->loc[i]    = read_lsb_int(f);
157   for (i = 0; i < 769; i++)
158     mymap->music[i]  = read_lsb_int(f);
159   for (i = 0; i < 769; i++)
160     mymap->indoor[i] = read_lsb_int(f);
161   fseek(f, 2240, SEEK_CUR); // unused space
162 
163   fclose(f);
164 
165   return 0;
166 }
167 
168 /**
169  * Load 1 screen from specified map.dat in specified memory buffer
170  */
load_map_to(char * path,const int num,struct small_map * screen)171 int load_map_to(char* path, const int num, struct small_map* screen)
172 {
173   /* Instead of using 'fseek(...)' when we want to skip a little bit
174      of data, we read it to this buffer - this is much faster on PSP
175      (1000ms -> 60ms), probably related to cache validation. No
176      noticeable change on PC (<1ms). */
177   char skipbuf[10000]; // more than any fseek we do
178 
179   FILE *f = NULL;
180   long holdme,lsize;
181   f = fopen(path, "rb");
182   if (!f)
183     {
184       log_error("Cannot find %s file!!!", path);
185       return -1;
186     }
187   lsize = 31280; // sizeof(struct small_map); // under ia32, not portable
188   holdme = (lsize * (num-1));
189   fseek(f, holdme, SEEK_SET);
190   //Msg("Trying to read %d bytes with offset of %d",lsize,holdme);
191 
192   /* Portably load map structure from disk */
193   int i = 0;
194   fread(skipbuf, 20, 1, f); // unused 'name' field
195   for (i = 0; i < 97; i++)
196     {
197       screen->t[i].square_full_idx0 = read_lsb_int(f);
198       fread(skipbuf, 4, 1, f); // unused 'property' field
199       screen->t[i].althard = read_lsb_int(f);
200       fread(skipbuf, 6, 1, f); // unused 'more2', 'more3', 'more4' fields
201       fread(skipbuf, 2, 1, f); // reproduce memory alignment
202       fread(skipbuf, 60, 1, f); // unused 'buff' field
203     }
204   // offset 7780
205 
206   fread(skipbuf, 160, 1, f); // unused 'v' field
207   fread(skipbuf, 80, 1, f);  // unused 's' field
208   // offset 8020
209 
210   /* struct sprite_placement sprite[101]; */
211   /* size = 220 */
212   for (i = 0; i < 101; i++)
213     {
214       screen->sprite[i].x = read_lsb_int(f);
215       screen->sprite[i].y = read_lsb_int(f);
216       screen->sprite[i].seq = read_lsb_int(f);
217       screen->sprite[i].frame = read_lsb_int(f);
218       screen->sprite[i].type = read_lsb_int(f);
219       screen->sprite[i].size = read_lsb_int(f);
220 
221       screen->sprite[i].active = fgetc(f);
222       fread(skipbuf, 3, 1, f); // reproduce memory alignment
223       // offset 28
224 
225       screen->sprite[i].rotation = read_lsb_int(f);
226       screen->sprite[i].special = read_lsb_int(f);
227       screen->sprite[i].brain = read_lsb_int(f);
228 
229       fread(screen->sprite[i].script, 14, 1, f);
230       screen->sprite[i].script[14-1] = '\0'; // safety
231       fread(skipbuf, 38, 1, f); // unused hit/die/talk fields
232       // offset 92
233 
234       screen->sprite[i].speed = read_lsb_int(f);
235       screen->sprite[i].base_walk = read_lsb_int(f);
236       screen->sprite[i].base_idle = read_lsb_int(f);
237       screen->sprite[i].base_attack = read_lsb_int(f);
238       screen->sprite[i].base_hit = read_lsb_int(f);
239       screen->sprite[i].timer = read_lsb_int(f);
240       screen->sprite[i].que = read_lsb_int(f);
241       screen->sprite[i].hard = read_lsb_int(f);
242       // offset 124
243 
244       screen->sprite[i].alt.left = read_lsb_int(f);
245       screen->sprite[i].alt.top = read_lsb_int(f);
246       screen->sprite[i].alt.right = read_lsb_int(f);
247       screen->sprite[i].alt.bottom = read_lsb_int(f);
248       // offset 140
249 
250       screen->sprite[i].prop = read_lsb_int(f);
251       screen->sprite[i].warp_map = read_lsb_int(f);
252       screen->sprite[i].warp_x = read_lsb_int(f);
253       screen->sprite[i].warp_y = read_lsb_int(f);
254       screen->sprite[i].parm_seq = read_lsb_int(f);
255       // offset 160
256 
257       screen->sprite[i].base_die = read_lsb_int(f);
258       screen->sprite[i].gold = read_lsb_int(f);
259       screen->sprite[i].hitpoints = read_lsb_int(f);
260       screen->sprite[i].strength = read_lsb_int(f);
261       screen->sprite[i].defense = read_lsb_int(f);
262       screen->sprite[i].exp = read_lsb_int(f);
263       screen->sprite[i].sound = read_lsb_int(f);
264       screen->sprite[i].vision = read_lsb_int(f);
265       screen->sprite[i].nohit = read_lsb_int(f);
266       screen->sprite[i].touch_damage = read_lsb_int(f);
267       // offset 200
268 
269       int j = 0;
270       for (j = 0; j < 5; j++)
271 	screen->sprite[i].buff[j] = read_lsb_int(f);
272     }
273   // offset 30204
274 
275   fread(screen->script, 21, 1, f);
276   screen->script[21-1] = '\0'; // safety
277   fread(skipbuf, 1018, 1, f); // unused hit/die/talk fields
278   fread(skipbuf, 1, 1, f); // reproduce memory alignment
279   // offset 31280
280 
281   fclose(f);
282   return 0;
283 }
284 
main(int argc,char * argv[])285 int main(int argc, char* argv[])
286 {
287   struct map_info dinkdat;
288   if (load_info_to("DINK.DAT", &dinkdat) < 0)
289     {
290       fprintf(stderr, "Cannot open DINK.DAT\n");
291       exit(1);
292     }
293   int r = 0;
294   for (r = 0; r < 769; r++)
295     {
296       // printf("%d: %d\n", r, dinkdat.loc[r]);
297       if (dinkdat.music[r] != 0)
298 	{
299 	  printf("#%d: %d\n", r, dinkdat.music[r]);
300 	}
301     }
302 }
303 
304 /**
305  * Local Variables:
306  * compile-command: "gcc -Wall -std=c99 -pedantic -g search_music.c -o search_music"
307  * End:
308  */
309