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