Bug Summary

File:src/blocks.c
Location:line 206, column 19
Description:Access to field 'w' results in a dereference of a null pointer (loaded from variable 'original_img')

Annotated Source Code

1/*
2 *
3 * Copyright (c) 2004-2010 Arthur Huillet
4 * Copyright (c) 1994, 2002, 2003 Johannes Prix
5 * Copyright (c) 1994, 2002 Reinhard Prix
6 *
7 *
8 * This file is part of Freedroid
9 *
10 * Freedroid is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * Freedroid is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Freedroid; see the file COPYING. If not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 * MA 02111-1307 USA
24 *
25 */
26
27#define _blocks_c
28
29#include "system.h"
30
31#include "defs.h"
32#include "struct.h"
33#include "global.h"
34#include "proto.h"
35
36#include "lvledit/lvledit_display.h"
37
38static int current_enemy_nr;
39
40static int __enemy_animation(const char *filename, int *rotation, int *phase, int *first_image, int **last_image)
41{
42 int i;
43 int rotation_index = 0;
44 int phase_index = 0;
45 int first_animation_image = 0;
46 int* last_animation_image = NULL((void*)0);
47
48 struct {
49 const char *format_string;
50 int first_image;
51 int *last_image;
52 } animations[] = {
53 { "enemy_rot_%02d_walk-%02d.png", first_walk_animation_image[current_enemy_nr], &last_walk_animation_image[current_enemy_nr] },
54 { "enemy_rot_%02d_attack-%02d.png", first_attack_animation_image[current_enemy_nr], &last_attack_animation_image[current_enemy_nr] },
55 { "enemy_rot_%02d_gethit-%02d.png", first_gethit_animation_image[current_enemy_nr], &last_gethit_animation_image[current_enemy_nr] },
56 { "enemy_rot_%02d_death-%02d.png", first_death_animation_image[current_enemy_nr], &last_death_animation_image[current_enemy_nr] },
57 { "enemy_rot_%02d_stand-%02d.png", first_stand_animation_image[current_enemy_nr], &last_stand_animation_image[current_enemy_nr] }
58 };
59
60 for (i = 0; i < sizeof(animations) / sizeof(animations[0]); i++) {
61 if (sscanf(filename, animations[i].format_string, &rotation_index, &phase_index) == 2) {
62 first_animation_image = animations[i].first_image;
63 last_animation_image = animations[i].last_image;
64 break;
65 }
66 }
67
68 if (i == sizeof(animations) / sizeof(animations[0])) {
69 error_message(__FUNCTION__, "Unexpected image filename '%s' for enemy '%s'.", PLEASE_INFORM,
70 filename, PrefixToFilename[current_enemy_nr]);
71 return -1;
72 }
73
74 if (rotation)
75 *rotation = rotation_index;
76 if (phase)
77 *phase = phase_index;
78 if (first_image)
79 *first_image = first_animation_image;
80 if (last_image)
81 *last_image = last_animation_image;
82
83 return 0;
84}
85
86static struct image *get_storage_for_enemy_image(const char *filename)
87{
88 int rotation_index;
89 int phase_index;
90 int first_animation_image;
91
92 if (__enemy_animation(filename, &rotation_index, &phase_index, &first_animation_image, NULL((void*)0)))
93 return NULL((void*)0);
94
95 return &enemy_images[current_enemy_nr][rotation_index][first_animation_image + phase_index - 1];
96}
97
98static struct image *compute_number_of_phases_for_enemy(const char *filename)
99{
100 int phase_index;
101 int *last_animation_image;
102
103 if (!__enemy_animation(filename, NULL((void*)0), &phase_index, NULL((void*)0), &last_animation_image)) {
104 if (*last_animation_image < phase_index + 1)
105 *last_animation_image = phase_index + 1;
106 }
107
108 return NULL((void*)0);
109}
110
111/**
112 * Enemy animation images are stored in texture atlases. This functions loads all
113 * the images for the given enemy model.
114 * It's typically called once whenever the enemy type is first encountered
115 * in one run of the engine.
116 */
117static void load_enemy_graphics(int enemy_model_nr)
118{
119 char atlas_filename[4096];
120 char atlas_directory[4096];
121
122 sprintf(atlas_filename, "droids/%s/atlas.txt", PrefixToFilename[enemy_model_nr]);
123 sprintf(atlas_directory, "droids/%s/", PrefixToFilename[enemy_model_nr]);
124
125 // The information about cycle length needs to be entered into the
126 // corresponding arrays (usually initialized in blocks.c, for those
127 // series, that don't have an image archive yet...)
128 //
129 last_walk_animation_image[enemy_model_nr] = 0;
130 last_attack_animation_image[enemy_model_nr] = 0;
131 last_gethit_animation_image[enemy_model_nr] = 0;
132 last_death_animation_image[enemy_model_nr] = 0;
133 last_stand_animation_image[enemy_model_nr] = 0;
134
135 current_enemy_nr = enemy_model_nr;
136 if (load_texture_atlas(atlas_filename, atlas_directory, compute_number_of_phases_for_enemy)) {
137 error_message(__FUNCTION__, "Unable to access the texture atlas for enemy '%s' at '%s'.",
138 PLEASE_INFORM | IS_FATAL, PrefixToFilename[enemy_model_nr], atlas_filename);
139 }
140
141 first_walk_animation_image[enemy_model_nr] = 1;
142 first_attack_animation_image[enemy_model_nr] = last_walk_animation_image[enemy_model_nr] + 1;
143 last_attack_animation_image[enemy_model_nr] += last_walk_animation_image[enemy_model_nr];
144 first_gethit_animation_image[enemy_model_nr] = last_attack_animation_image[enemy_model_nr] + 1;
145 last_gethit_animation_image[enemy_model_nr] += last_attack_animation_image[enemy_model_nr];
146 first_death_animation_image[enemy_model_nr] = last_gethit_animation_image[enemy_model_nr] + 1;
147 last_death_animation_image[enemy_model_nr] += last_gethit_animation_image[enemy_model_nr];
148 first_stand_animation_image[enemy_model_nr] = last_death_animation_image[enemy_model_nr] + 1;
149 last_stand_animation_image[enemy_model_nr] += last_death_animation_image[enemy_model_nr];
150
151 // Now some error checking against more phases in this enemy animation than
152 // currently allowed from the array size...
153 //
154 if (last_stand_animation_image[enemy_model_nr] >= MAX_ENEMY_MOVEMENT_PHASES999) {
155 error_message(__FUNCTION__,
156 "The number of images found in the image collection for enemy model %d is bigger than currently allowed (found %d images, max. %d).",
157 PLEASE_INFORM | IS_FATAL, enemy_model_nr, last_stand_animation_image[enemy_model_nr], MAX_ENEMY_MOVEMENT_PHASES999);
158 }
159
160 if (load_texture_atlas(atlas_filename, atlas_directory, get_storage_for_enemy_image)) {
161 error_message(__FUNCTION__, "Unable to load texture atlas for enemy '%s' at %s.",
162 PLEASE_INFORM | IS_FATAL, PrefixToFilename[enemy_model_nr], atlas_filename);
163 }
164}
165
166
167/**
168 * This function loads the Blast image and decodes it into the multiple
169 * small Blast surfaces.
170 */
171void Load_Blast_Surfaces(void)
172{
173 int i, j;
174 char fpath[2048];
175
176 for (i = 0; i < sizeof(Blastmap) / sizeof(Blastmap[0]); i++) {
177 for (j = 0; j < Blastmap[i].phases; j++) {
178 sprintf(fpath, "blasts/%s_%04d.png", Blastmap[i].name, j + 1);
179 load_image(&Blastmap[i].images[j], fpath, TRUE(1));
180 }
181 }
182}
183
184static void load_item_graphics(int item_type)
185{
186 SDL_Surface *original_img;
187 SDL_Surface *tmp_surf2 = NULL((void*)0);
188 char fpath[PATH_MAX4096];
189 char our_filename[PATH_MAX4096];
190 itemspec *spec = &ItemMap[item_type];
191
192 sprintf(our_filename, "items/%s", spec->item_inv_file_name);
193
194 // Load the inventory image
195 find_file(our_filename, GRAPHICS_DIR, fpath, PLEASE_INFORM | IS_FATAL);
196
197 original_img = IMG_Load(fpath);
1
Value assigned to 'original_img'
198 if (original_img == NULL((void*)0)) {
2
Assuming 'original_img' is equal to null
3
Taking true branch
199 error_message(__FUNCTION__, "Inventory image for item type %d, at path %s was not found",
200 PLEASE_INFORM | IS_FATAL, item_type, fpath);
201 }
202
203 int target_x = spec->inv_size.x * 32;
204 int target_y = spec->inv_size.y * 32;
205 float factor_x, factor_y;
206 if ((target_x != original_img->w) || (target_y != original_img->h)) {
4
Access to field 'w' results in a dereference of a null pointer (loaded from variable 'original_img')
207 factor_x = (float)target_x / (float)original_img->w;
208 factor_y = (float)target_y / (float)original_img->h;
209 tmp_surf2 = zoomSurface(original_img, factor_x, factor_y, FALSE(0));
210 spec->inventory_image.surface = SDL_DisplayFormatAlpha(tmp_surf2);
211 SDL_FreeSurface(tmp_surf2);
212 } else
213 spec->inventory_image.surface = SDL_DisplayFormatAlpha(original_img);
214
215 if (use_open_gl) {
216 make_texture_out_of_surface(&spec->inventory_image);
217 } else {
218 spec->inventory_image.w = spec->inventory_image.surface->w;
219 spec->inventory_image.h = spec->inventory_image.surface->h;
220 }
221
222 // For the shop, we need versions of each image, where the image is scaled so
223 // that it takes up a whole 64x64 shop display square. So we prepare scaled
224 // versions here and now...
225
226 // Scale shop image
227 if (original_img->w >= original_img->h) {
228 target_x = 64;
229 target_y = original_img->h * 64.0 / (float)original_img->w; //keep the scaling ratio !
230 }
231
232 if (original_img->h > original_img->w) {
233 target_y = 64;
234 target_x = original_img->w * 64.0 / (float)original_img->h;
235 }
236
237 factor_x = ((float)GameConfig.screen_width / 640.0) * ((float)target_x / (float)original_img->w);
238 factor_y = ((float)GameConfig.screen_height / 480.0) * ((float)target_y / (float)original_img->h);
239 tmp_surf2 = zoomSurface(original_img, factor_x, factor_y, FALSE(0));
240 spec->shop_image.surface = SDL_DisplayFormatAlpha(tmp_surf2);
241 SDL_FreeSurface(original_img);
242 SDL_FreeSurface(tmp_surf2);
243
244 if (use_open_gl) {
245 make_texture_out_of_surface(&spec->shop_image);
246 } else {
247 spec->shop_image.w = spec->shop_image.surface->w;
248 spec->shop_image.h = spec->shop_image.surface->h;
249 }
250
251 // Load ingame image
252 if (strcmp(spec->item_rotation_series_prefix, "NONE_AVAILABLE_YET")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(spec->item_rotation_series_prefix) && __builtin_constant_p
("NONE_AVAILABLE_YET") && (__s1_len = strlen (spec->
item_rotation_series_prefix), __s2_len = strlen ("NONE_AVAILABLE_YET"
), (!((size_t)(const void *)((spec->item_rotation_series_prefix
) + 1) - (size_t)(const void *)(spec->item_rotation_series_prefix
) == 1) || __s1_len >= 4) && (!((size_t)(const void
*)(("NONE_AVAILABLE_YET") + 1) - (size_t)(const void *)("NONE_AVAILABLE_YET"
) == 1) || __s2_len >= 4)) ? __builtin_strcmp (spec->item_rotation_series_prefix
, "NONE_AVAILABLE_YET") : (__builtin_constant_p (spec->item_rotation_series_prefix
) && ((size_t)(const void *)((spec->item_rotation_series_prefix
) + 1) - (size_t)(const void *)(spec->item_rotation_series_prefix
) == 1) && (__s1_len = strlen (spec->item_rotation_series_prefix
), __s1_len < 4) ? (__builtin_constant_p ("NONE_AVAILABLE_YET"
) && ((size_t)(const void *)(("NONE_AVAILABLE_YET") +
1) - (size_t)(const void *)("NONE_AVAILABLE_YET") == 1) ? __builtin_strcmp
(spec->item_rotation_series_prefix, "NONE_AVAILABLE_YET")
: (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) ("NONE_AVAILABLE_YET"); int __result =
(((const unsigned char *) (const char *) (spec->item_rotation_series_prefix
))[0] - __s2[0]); if (__s1_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (spec
->item_rotation_series_prefix))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (spec->item_rotation_series_prefix
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (spec->
item_rotation_series_prefix))[3] - __s2[3]); } } __result; })
)) : (__builtin_constant_p ("NONE_AVAILABLE_YET") && (
(size_t)(const void *)(("NONE_AVAILABLE_YET") + 1) - (size_t)
(const void *)("NONE_AVAILABLE_YET") == 1) && (__s2_len
= strlen ("NONE_AVAILABLE_YET"), __s2_len < 4) ? (__builtin_constant_p
(spec->item_rotation_series_prefix) && ((size_t)(
const void *)((spec->item_rotation_series_prefix) + 1) - (
size_t)(const void *)(spec->item_rotation_series_prefix) ==
1) ? __builtin_strcmp (spec->item_rotation_series_prefix,
"NONE_AVAILABLE_YET") : (- (__extension__ ({ const unsigned char
*__s2 = (const unsigned char *) (const char *) (spec->item_rotation_series_prefix
); int __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET"
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET"
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (spec
->item_rotation_series_prefix, "NONE_AVAILABLE_YET")))); }
)
) {
253 sprintf(our_filename, "items/%s/ingame.png", spec->item_rotation_series_prefix);
254 load_image(&spec->ingame_image, our_filename, TRUE(1));
255 } else {
256 memcpy(&spec->ingame_image, &spec->inventory_image, sizeof(struct image));
257 }
258}
259
260static void load_if_needed(int type)
261{
262 itemspec *spec = &ItemMap[type];
263
264 if (!image_loaded(&spec->inventory_image)) {
265 load_item_graphics(type);
266 }
267}
268
269struct image *get_item_inventory_image(int type)
270{
271 load_if_needed(type);
272 return &ItemMap[type].inventory_image;
273}
274
275struct image *get_item_shop_image(int type)
276{
277 load_if_needed(type);
278 return &ItemMap[type].shop_image;
279}
280
281struct image *get_item_ingame_image(int type)
282{
283 load_if_needed(type);
284 return &ItemMap[type].ingame_image;
285}
286
287void load_all_items(void)
288{
289 int i;
290
291 for (i = 0; i < Number_Of_Item_Types; i++) {
292 load_item_graphics(i);
293 }
294}
295
296/**
297 * Free all images associated with items.
298 */
299void free_item_graphics(void)
300{
301 int i;
302 struct image empty_image = EMPTY_IMAGE{ .surface = ((void*)0) , .offset_x = 0 , .offset_y = 0 , .texture_has_been_created
= 0 , .cached_transformation = { ((void*)0), 0.0, 0.0, { 0.0
, 0.0, 0.0, 0.0}, 0 } }
;
303
304 for (i = 0; i < Number_Of_Item_Types; i++) {
305 if (image_loaded(&ItemMap[i].inventory_image)) {
306 delete_image(&ItemMap[i].inventory_image);
307
308 // If the ingame image is not available for an item, then it is just a copy
309 // of the inventory image. In this case, the ingame image should not be
310 // deleted. The resources associated with this image will be freed when
311 // the inventory image is deleted.
312 if (strcmp(ItemMap[i].item_rotation_series_prefix, "NONE_AVAILABLE_YET")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(ItemMap[i].item_rotation_series_prefix) && __builtin_constant_p
("NONE_AVAILABLE_YET") && (__s1_len = strlen (ItemMap
[i].item_rotation_series_prefix), __s2_len = strlen ("NONE_AVAILABLE_YET"
), (!((size_t)(const void *)((ItemMap[i].item_rotation_series_prefix
) + 1) - (size_t)(const void *)(ItemMap[i].item_rotation_series_prefix
) == 1) || __s1_len >= 4) && (!((size_t)(const void
*)(("NONE_AVAILABLE_YET") + 1) - (size_t)(const void *)("NONE_AVAILABLE_YET"
) == 1) || __s2_len >= 4)) ? __builtin_strcmp (ItemMap[i].
item_rotation_series_prefix, "NONE_AVAILABLE_YET") : (__builtin_constant_p
(ItemMap[i].item_rotation_series_prefix) && ((size_t
)(const void *)((ItemMap[i].item_rotation_series_prefix) + 1)
- (size_t)(const void *)(ItemMap[i].item_rotation_series_prefix
) == 1) && (__s1_len = strlen (ItemMap[i].item_rotation_series_prefix
), __s1_len < 4) ? (__builtin_constant_p ("NONE_AVAILABLE_YET"
) && ((size_t)(const void *)(("NONE_AVAILABLE_YET") +
1) - (size_t)(const void *)("NONE_AVAILABLE_YET") == 1) ? __builtin_strcmp
(ItemMap[i].item_rotation_series_prefix, "NONE_AVAILABLE_YET"
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) ("NONE_AVAILABLE_YET"); int __result =
(((const unsigned char *) (const char *) (ItemMap[i].item_rotation_series_prefix
))[0] - __s2[0]); if (__s1_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (ItemMap
[i].item_rotation_series_prefix))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (ItemMap[i].item_rotation_series_prefix
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (ItemMap
[i].item_rotation_series_prefix))[3] - __s2[3]); } } __result
; }))) : (__builtin_constant_p ("NONE_AVAILABLE_YET") &&
((size_t)(const void *)(("NONE_AVAILABLE_YET") + 1) - (size_t
)(const void *)("NONE_AVAILABLE_YET") == 1) && (__s2_len
= strlen ("NONE_AVAILABLE_YET"), __s2_len < 4) ? (__builtin_constant_p
(ItemMap[i].item_rotation_series_prefix) && ((size_t
)(const void *)((ItemMap[i].item_rotation_series_prefix) + 1)
- (size_t)(const void *)(ItemMap[i].item_rotation_series_prefix
) == 1) ? __builtin_strcmp (ItemMap[i].item_rotation_series_prefix
, "NONE_AVAILABLE_YET") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (ItemMap
[i].item_rotation_series_prefix); int __result = (((const unsigned
char *) (const char *) ("NONE_AVAILABLE_YET"))[0] - __s2[0])
; if (__s2_len > 0 && __result == 0) { __result = (
((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET"
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("NONE_AVAILABLE_YET"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (ItemMap
[i].item_rotation_series_prefix, "NONE_AVAILABLE_YET")))); })
)
313 delete_image(&ItemMap[i].ingame_image);
314 else
315 memcpy(&ItemMap[i].ingame_image, &empty_image, sizeof(struct image));
316
317 delete_image(&ItemMap[i].shop_image);
318 }
319 }
320}
321
322/**
323 * This function loads the items image and decodes it into the multiple
324 * small item surfaces.
325 */
326void Load_Mouse_Move_Cursor_Surfaces(void)
327{
328 int j;
329 char our_filename[2000] = "";
330
331 for (j = 0; j < NUMBER_OF_MOUSE_CURSOR_PICTURES2; j++) {
332 sprintf(our_filename, "cursors/mouse_move_cursor_%d.png", j);
333 load_image(&MouseCursorImageList[j], our_filename, FALSE(0));
334 }
335
336}; // void Load_Mouse_Move_Cursor_Surfaces( void )
337
338/**
339 * This function loads all the bullet images into memory.
340 *
341 */
342void iso_load_bullet_surfaces(void)
343{
344 int i, j, k;
345 char constructed_filename[5000];
346
347 for (i = 0; i < bullet_specs.size; i++) {
348 struct bulletspec *bullet_spec = dynarray_member(&bullet_specs, i, sizeof(struct bulletspec));
349
350 if (strlen(bullet_spec->name) && strstr(bullet_spec->name, "NO BULLET IMAGE"))
351 continue;
352
353 for (j = 0; j < bullet_spec->phases; j++) {
354 for (k = 0; k < BULLET_DIRECTIONS16; k++) {
355 sprintf(constructed_filename, "bullets/iso_bullet_%s_%02d_%04d.png", bullet_spec->name, k, j + 1);
356
357 load_image(&bullet_spec->image[k][j], constructed_filename, TRUE(1));
358 }
359 }
360 }
361
362}; // void iso_load_bullet_surfaces ( void )
363
364/**
365 *
366 *
367 */
368void get_offset_for_iso_image_from_file_and_path(char *fpath, struct image * our_iso_image)
369{
370 char offset_file_name[10000];
371 FILE *OffsetFile;
372 char *offset_data;
373 // Now we try to load the associated offset file, that we'll be needing
374 // in order to properly fine-position the image later when blitting is to
375 // a map location.
376 //
377 strcpy(offset_file_name, fpath);
378 offset_file_name[strlen(offset_file_name) - 4] = 0;
379 strcat(offset_file_name, ".offset");
380
381 // Let's see if we can find an offset file...
382 //
383 if ((OffsetFile = fopen(offset_file_name, "rb")) == NULL((void*)0)) {
384 error_message(__FUNCTION__, "\
385FreedroidRPG was unable to open offset file %s for an isometric image.\n\
386Since the offset could not be obtained from the offset file, 0 will be used instead.\n\
387This can lead to minor positioning perturbations\n\
388in graphics displayed, but FreedroidRPG will continue to work.", NO_REPORT, offset_file_name);
389 our_iso_image->offset_x = 0;
390 our_iso_image->offset_y = 0;
391 return;
392 } else {
393 fclose(OffsetFile);
394 }
395
396 // So at this point we can be certain, that the offset file is there.
397 // That means, that we can now use the (otherwise terminating) read-and-malloc-...
398 // functions.
399 //
400 offset_data = ReadAndMallocAndTerminateFile(offset_file_name, END_OF_OFFSET_FILE_STRING"** End of iso_image offset file **");
401
402 ReadValueFromString(offset_data, OFFSET_FILE_OFFSETX_STRING"OffsetX=", "%hd", &(our_iso_image->offset_x), offset_data + strlen(offset_data));
403
404 ReadValueFromString(offset_data, OFFSET_FILE_OFFSETY_STRING"OffsetY=", "%hd", &(our_iso_image->offset_y), offset_data + strlen(offset_data));
405 free(offset_data);
406
407}; // void get_offset_for_iso_image_from_file_and_path ( fpath , our_iso_image )
408
409static int EnemyFullyPrepared[ENEMY_ROTATION_MODELS_AVAILABLE43];
410
411/**
412 *
413 *
414 */
415void LoadAndPrepareEnemyRotationModelNr(int ModelNr)
416{
417 // Now a sanity check against using rotation types, that don't exist
418 // in FreedroidRPG at all!
419 //
420 if ((ModelNr < 0) || (ModelNr >= ENEMY_ROTATION_MODELS_AVAILABLE43)) {
421 error_message(__FUNCTION__, "\
422FreedroidRPG received a rotation model number that does not exist: %d", PLEASE_INFORM | IS_FATAL, ModelNr);
423 }
424 // Now we can check if the given rotation model type was perhaps already
425 // allocated and loaded and fully prepared. Then of course we need not
426 // do anything here... Otherwise we can have trust and mark it as loaded
427 // already...
428 //
429 if (EnemyFullyPrepared[ModelNr])
430 return;
431 EnemyFullyPrepared[ModelNr] = TRUE(1);
432 Activate_Conservative_Frame_Computation();
433
434 load_enemy_graphics(ModelNr);
435}
436
437void free_enemy_graphics(void)
438{
439 int i;
440 int rotation_index, phase_index;
441
442 for (i = 0; i < ENEMY_ROTATION_MODELS_AVAILABLE43; i++) {
443 if (!EnemyFullyPrepared[i])
444 continue;
445
446 for (rotation_index = 0; rotation_index < ROTATION_ANGLES_PER_ROTATION_MODEL8; rotation_index++) {
447 for (phase_index = 0; phase_index < MAX_ENEMY_MOVEMENT_PHASES999; phase_index++)
448 delete_image(&enemy_images[i][rotation_index][phase_index]);
449 }
450 EnemyFullyPrepared[i] = FALSE(0);
451 }
452}
453
454/**
455 * Read the Enemy Surfaces details from the data stream.
456 */
457void get_enemy_surfaces_data(char *DataPointer)
458{
459 char *SurfacePointer;
460 char *EndOfSurfaceData;
461 int SurfaceIndex = 0;
462
463#define ENEMY_SURFACES_SECTION_BEGIN_STRING"*** Start of Enemy Surfaces Section: ***" "*** Start of Enemy Surfaces Section: ***"
464#define ENEMY_SURFACES_SECTION_END_STRING"*** End of Enemy Surfaces Section: ***" "*** End of Enemy Surfaces Section: ***"
465#define NEW_SURFACE_BEGIN_STRING"** Start of new surface specification subsection **" "** Start of new surface specification subsection **"
466
467#define SURFACES_FILE_NAME_BEGIN_STRING"PrefixToFilename=\"" "PrefixToFilename=\""
468#define SURFACES_WALK_ANI_SPEED_BEGIN_STRING"droid_walk_animation_speed_factor=" "droid_walk_animation_speed_factor="
469#define SURFACES_ATTACK_ANI_SPEED_BEGIN_STRING"droid_attack_animation_speed_factor=" "droid_attack_animation_speed_factor="
470#define SURFACES_GETHIT_ANI_SPEED_BEGIN_STRING"droid_gethit_animation_speed_factor=" "droid_gethit_animation_speed_factor="
471#define SURFACES_DEATH_ANI_SPEED_BEGIN_STRING"droid_death_animation_speed_factor=" "droid_death_animation_speed_factor="
472#define SURFACES_STAND_ANI_SPEED_BEGIN_STRING"droid_stand_animation_speed_factor=" "droid_stand_animation_speed_factor="
473
474
475 EndOfSurfaceData = LocateStringInData(DataPointer, ENEMY_SURFACES_SECTION_END_STRING"*** End of Enemy Surfaces Section: ***");
476
477 DebugPrintf(1, "\n\nStarting to read surfaces data...\n\n");
478
479 SurfacePointer = DataPointer;
480
481 while ((SurfacePointer = strstr(SurfacePointer, NEW_SURFACE_BEGIN_STRING"** Start of new surface specification subsection **")) != NULL((void*)0)) {
482 if (SurfaceIndex >= ENEMY_ROTATION_MODELS_AVAILABLE43) {
483 error_message(__FUNCTION__, "enemy_surfaces.dat specifies more surfaces than ENEMY_ROTATION_MODELS_AVAILABLE (%d) allows.", PLEASE_INFORM | IS_FATAL, ENEMY_ROTATION_MODELS_AVAILABLE43);
484 }
485
486 DebugPrintf(1, "\n\nFound another surface specification entry! Lets add that to the others!");
487 SurfacePointer++;
488
489 PrefixToFilename[SurfaceIndex] = ReadAndMallocStringFromData(SurfacePointer, SURFACES_FILE_NAME_BEGIN_STRING"PrefixToFilename=\"", "\"");
490
491 ReadValueFromStringWithDefault(SurfacePointer, SURFACES_WALK_ANI_SPEED_BEGIN_STRING"droid_walk_animation_speed_factor=",
492 "%d", "0", &(droid_walk_animation_speed_factor[SurfaceIndex]), EndOfSurfaceData);
493 ReadValueFromStringWithDefault(SurfacePointer, SURFACES_ATTACK_ANI_SPEED_BEGIN_STRING"droid_attack_animation_speed_factor=",
494 "%d", "0", &(droid_attack_animation_speed_factor[SurfaceIndex]), EndOfSurfaceData);
495 ReadValueFromStringWithDefault(SurfacePointer, SURFACES_GETHIT_ANI_SPEED_BEGIN_STRING"droid_gethit_animation_speed_factor=",
496 "%d", "0", &(droid_gethit_animation_speed_factor[SurfaceIndex]), EndOfSurfaceData);
497 ReadValueFromStringWithDefault(SurfacePointer, SURFACES_DEATH_ANI_SPEED_BEGIN_STRING"droid_death_animation_speed_factor=",
498 "%d", "0", &(droid_death_animation_speed_factor[SurfaceIndex]), EndOfSurfaceData);
499 ReadValueFromStringWithDefault(SurfacePointer, SURFACES_STAND_ANI_SPEED_BEGIN_STRING"droid_stand_animation_speed_factor=",
500 "%d", "0", &(droid_stand_animation_speed_factor[SurfaceIndex]), EndOfSurfaceData);
501
502 SurfaceIndex++;
503 }
504
505 DebugPrintf(1, "\nEnd of get_enemy_surfaces_data ( char* DataPointer ) reached.");
506}
507
508/**
509 * This function creates all the surfaces, that are necessary to blit the
510 * 'head' and 'shoes' of an enemy. The numbers are not dealt with here.
511 */
512void Load_Enemy_Surfaces(void)
513{
514 int i;
515
516 for (i = 0; i < ENEMY_ROTATION_MODELS_AVAILABLE43; i++) {
517 struct image empty = EMPTY_IMAGE{ .surface = ((void*)0) , .offset_x = 0 , .offset_y = 0 , .texture_has_been_created
= 0 , .cached_transformation = { ((void*)0), 0.0, 0.0, { 0.0
, 0.0, 0.0, 0.0}, 0 } }
;
518 chat_portrait_of_droid[i] = empty;
519 }
520
521 // When using the new tux image collection files, the animation cycle
522 // lengths for droids will be taken from the image collection file itself.
523 // That is good, because it's so dynamic. However, it also means, that
524 // the real animation phase lengths and that will in general not be known
525 // until the graphics for that bot has been loaded. But on the other hand
526 // it might happen that some phase computation is done before the first
527 // blit already. In that case, uninitialized data structs might cause
528 // severe harm. Therefore we initialize some sane default values, that should
529 // protect against certain cases of wrong phase counts.
530 //
531 for (i = 0; i < ENEMY_ROTATION_MODELS_AVAILABLE43; i++) {
532 first_walk_animation_image[i] = 1;
533 last_walk_animation_image[i] = 1;
534 first_attack_animation_image[i] = 1;
535 last_attack_animation_image[i] = 1;
536 first_gethit_animation_image[i] = 1;
537 last_gethit_animation_image[i] = 1;
538 first_death_animation_image[i] = 1;
539 last_death_animation_image[i] = 1;
540 first_stand_animation_image[i] = 1;
541 last_stand_animation_image[i] = 1;
542 }
543
544
545 char fpath[PATH_MAX4096];
546 char *Data;
547
548 find_file("enemy_surfaces.dat", MAP_DIR, fpath, PLEASE_INFORM | IS_FATAL);
549 Data = ReadAndMallocAndTerminateFile(fpath, "*** End of this Freedroid data File ***");
550 get_enemy_surfaces_data(Data);
551 free(Data);
552}
553
554static void load_droid_portrait(int type)
555{
556 char fpath[1024];
557
558 strcpy(fpath, "droids/");
559 strcat(fpath, PrefixToFilename[Droidmap[type].individual_shape_nr]);
560 strcat(fpath, "/portrait.png");
561
562 load_image(&chat_portrait_of_droid[type], fpath, FALSE(0));
563}
564
565struct image *get_droid_portrait_image(int type)
566{
567 if (type >= ENEMY_ROTATION_MODELS_AVAILABLE43) {
568 error_message(__FUNCTION__, "Tried to load a portrait image of a bot those type is #%d, but the maximum configured value is %d."
569 "ENEMY_ROTATION_MODELS_AVAILABLE should be raised.",
570 PLEASE_INFORM | IS_FATAL,
571 type, ENEMY_ROTATION_MODELS_AVAILABLE43 - 1);
572 return NULL((void*)0);
573 }
574
575 if (!image_loaded(&chat_portrait_of_droid[type])) {
576 load_droid_portrait(type);
577 }
578
579 return &chat_portrait_of_droid[type];
580}
581
582/**
583 * Return a pointer towards the struct image
584 * associated to the given obstacle type.
585 */
586struct image *get_obstacle_image(int type, int frame_index)
587{
588 struct obstacle_graphics *obs_graphics = &((struct obstacle_graphics *)obstacle_images.arr)[type];
589 return &obs_graphics->images[frame_index % obs_graphics->count];
590}
591
592/**
593 * Return a pointer towards the shadow image
594 * associated to the given obstacle type.
595 */
596struct image *get_obstacle_shadow_image(int type, int frame_index)
597{
598 struct obstacle_graphics *obs_graphics= &((struct obstacle_graphics *)obstacle_images.arr)[type];
599 return &obs_graphics->shadows[frame_index % obs_graphics->count];
600}
601
602/**
603 * Return a pointer towards the map label image.
604 */
605struct image *get_map_label_image()
606{
607 static struct image img = EMPTY_IMAGE{ .surface = ((void*)0) , .offset_x = 0 , .offset_y = 0 , .texture_has_been_created
= 0 , .cached_transformation = { ((void*)0), 0.0, 0.0, { 0.0
, 0.0, 0.0, 0.0}, 0 } }
;
608
609 if (!image_loaded(&img))
610 load_image(&img, "level_editor_map_label_indicator.png", TRUE(1));
611
612 return &img;
613}
614
615/**
616 * Free all images associated with obstacles.
617 */
618void free_obstacle_graphics(void)
619{
620 int i, j;
621 for (i = 0; i < obstacle_map.size; i++) {
622 struct obstacle_graphics *graphics = &((struct obstacle_graphics *)obstacle_images.arr)[i];
623 for (j = 0; j < graphics->count; j++) {
624 delete_image(&graphics->images[j]);
625 delete_image(&graphics->shadows[j]);
626 }
627 }
628}
629
630/**
631 * Check if all images for obstacles were loaded correctly. Issue warnings for
632 * missing images.
633 */
634static void validate_obstacle_graphics(void)
635{
636 int i, j;
637 for (i = 0; i < obstacle_map.size; i++) {
638 struct obstacle_graphics *graphics = &((struct obstacle_graphics *)obstacle_images.arr)[i];
639 for (j = 0; j < graphics->count; j++) {
640 const char *filename = ((char **)get_obstacle_spec(i)->filenames.arr)[j];
641 if (!image_loaded(&graphics->images[j])) {
642 if (strcmp(filename, "DUMMY OBSTACLE")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(filename) && __builtin_constant_p ("DUMMY OBSTACLE"
) && (__s1_len = strlen (filename), __s2_len = strlen
("DUMMY OBSTACLE"), (!((size_t)(const void *)((filename) + 1
) - (size_t)(const void *)(filename) == 1) || __s1_len >= 4
) && (!((size_t)(const void *)(("DUMMY OBSTACLE") + 1
) - (size_t)(const void *)("DUMMY OBSTACLE") == 1) || __s2_len
>= 4)) ? __builtin_strcmp (filename, "DUMMY OBSTACLE") : (
__builtin_constant_p (filename) && ((size_t)(const void
*)((filename) + 1) - (size_t)(const void *)(filename) == 1) &&
(__s1_len = strlen (filename), __s1_len < 4) ? (__builtin_constant_p
("DUMMY OBSTACLE") && ((size_t)(const void *)(("DUMMY OBSTACLE"
) + 1) - (size_t)(const void *)("DUMMY OBSTACLE") == 1) ? __builtin_strcmp
(filename, "DUMMY OBSTACLE") : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) ("DUMMY OBSTACLE"
); int __result = (((const unsigned char *) (const char *) (filename
))[0] - __s2[0]); if (__s1_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (filename
))[1] - __s2[1]); if (__s1_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (filename
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (filename
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
"DUMMY OBSTACLE") && ((size_t)(const void *)(("DUMMY OBSTACLE"
) + 1) - (size_t)(const void *)("DUMMY OBSTACLE") == 1) &&
(__s2_len = strlen ("DUMMY OBSTACLE"), __s2_len < 4) ? (__builtin_constant_p
(filename) && ((size_t)(const void *)((filename) + 1
) - (size_t)(const void *)(filename) == 1) ? __builtin_strcmp
(filename, "DUMMY OBSTACLE") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (filename
); int __result = (((const unsigned char *) (const char *) ("DUMMY OBSTACLE"
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("DUMMY OBSTACLE"
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("DUMMY OBSTACLE"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("DUMMY OBSTACLE"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (filename
, "DUMMY OBSTACLE")))); })
) {
643 error_message(__FUNCTION__, "Could not load the image '%s' for obstacle %d.",
644 PLEASE_INFORM, filename, i);
645 }
646 }
647 }
648 }
649}
650
651static struct image *get_storage_for_obstacle_image(const char *filename)
652{
653 int i, j;
654
655 for (i = 0; i < obstacle_map.size; i++) {
656 obstacle_spec *spec = get_obstacle_spec(i);
657 struct obstacle_graphics *graphics = &((struct obstacle_graphics *)obstacle_images.arr)[i];
658 for (j = 0; j < spec->filenames.size; j++) {
659 const char *fname = ((char **)spec->filenames.arr)[j];
660 if (!strcmp(fname, filename)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(fname) && __builtin_constant_p (filename) &&
(__s1_len = strlen (fname), __s2_len = strlen (filename), (!
((size_t)(const void *)((fname) + 1) - (size_t)(const void *)
(fname) == 1) || __s1_len >= 4) && (!((size_t)(const
void *)((filename) + 1) - (size_t)(const void *)(filename) ==
1) || __s2_len >= 4)) ? __builtin_strcmp (fname, filename
) : (__builtin_constant_p (fname) && ((size_t)(const void
*)((fname) + 1) - (size_t)(const void *)(fname) == 1) &&
(__s1_len = strlen (fname), __s1_len < 4) ? (__builtin_constant_p
(filename) && ((size_t)(const void *)((filename) + 1
) - (size_t)(const void *)(filename) == 1) ? __builtin_strcmp
(fname, filename) : (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) (filename); int __result
= (((const unsigned char *) (const char *) (fname))[0] - __s2
[0]); if (__s1_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (fname))[1] - __s2
[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (fname))[2] - __s2
[2]); if (__s1_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (fname))[3] - __s2[
3]); } } __result; }))) : (__builtin_constant_p (filename) &&
((size_t)(const void *)((filename) + 1) - (size_t)(const void
*)(filename) == 1) && (__s2_len = strlen (filename),
__s2_len < 4) ? (__builtin_constant_p (fname) && (
(size_t)(const void *)((fname) + 1) - (size_t)(const void *)(
fname) == 1) ? __builtin_strcmp (fname, filename) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (fname); int __result = (((const unsigned char *) (const
char *) (filename))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (filename))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (filename))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (filename))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(fname, filename)))); })
)
661 return &graphics->images[j];
662 }
663 }
664
665 error_message(__FUNCTION__, "Obstacles texture atlas specifies element %s which is not expected.",
666 PLEASE_INFORM, filename);
667 return NULL((void*)0);
668}
669
670static struct image *get_storage_for_obstacle_shadow_image(const char *filename)
671{
672 int i, j;
673 const char *obstacle_filename = filename + strlen("shadow_");
674
675 for (i = 0; i < obstacle_map.size; i++) {
676 obstacle_spec *spec = get_obstacle_spec(i);
677 struct obstacle_graphics *graphics = &((struct obstacle_graphics *)obstacle_images.arr)[i];
678 for (j = 0; j < spec->filenames.size; j++) {
679 const char *fname = ((char **)spec->filenames.arr)[j];
680 if (!strcmp(fname, obstacle_filename)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(fname) && __builtin_constant_p (obstacle_filename) &&
(__s1_len = strlen (fname), __s2_len = strlen (obstacle_filename
), (!((size_t)(const void *)((fname) + 1) - (size_t)(const void
*)(fname) == 1) || __s1_len >= 4) && (!((size_t)(
const void *)((obstacle_filename) + 1) - (size_t)(const void *
)(obstacle_filename) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(fname, obstacle_filename) : (__builtin_constant_p (fname) &&
((size_t)(const void *)((fname) + 1) - (size_t)(const void *
)(fname) == 1) && (__s1_len = strlen (fname), __s1_len
< 4) ? (__builtin_constant_p (obstacle_filename) &&
((size_t)(const void *)((obstacle_filename) + 1) - (size_t)(
const void *)(obstacle_filename) == 1) ? __builtin_strcmp (fname
, obstacle_filename) : (__extension__ ({ const unsigned char *
__s2 = (const unsigned char *) (const char *) (obstacle_filename
); int __result = (((const unsigned char *) (const char *) (fname
))[0] - __s2[0]); if (__s1_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (fname
))[1] - __s2[1]); if (__s1_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (fname
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (fname)
)[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
obstacle_filename) && ((size_t)(const void *)((obstacle_filename
) + 1) - (size_t)(const void *)(obstacle_filename) == 1) &&
(__s2_len = strlen (obstacle_filename), __s2_len < 4) ? (
__builtin_constant_p (fname) && ((size_t)(const void *
)((fname) + 1) - (size_t)(const void *)(fname) == 1) ? __builtin_strcmp
(fname, obstacle_filename) : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (fname);
int __result = (((const unsigned char *) (const char *) (obstacle_filename
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (obstacle_filename
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (obstacle_filename
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (obstacle_filename
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (fname
, obstacle_filename)))); })
)
681 return &graphics->shadows[j];
682 }
683 }
684
685 error_message(__FUNCTION__, "Obstacle shadows texture atlas specifies element %s which is not expected.",
686 PLEASE_INFORM, filename);
687 return NULL((void*)0);
688}
689
690void load_all_obstacles(int with_startup_bar)
691{
692 int i, j;
693 struct image empty_image = EMPTY_IMAGE{ .surface = ((void*)0) , .offset_x = 0 , .offset_y = 0 , .texture_has_been_created
= 0 , .cached_transformation = { ((void*)0), 0.0, 0.0, { 0.0
, 0.0, 0.0, 0.0}, 0 } }
;
694
695 if (load_texture_atlas("obstacles/atlas.txt", "obstacles/", get_storage_for_obstacle_image)) {
696 error_message(__FUNCTION__, "Unable to load texture atlas for obstacles at obstacles/atlas.txt.", PLEASE_INFORM | IS_FATAL);
697 }
698
699 if (with_startup_bar)
700 next_startup_percentage(62);
701
702 // Clear obstacle shadow images
703 // It's required because only subset of obstacles has got shadow
704 for (i = 0; i < obstacle_map.size; i++) {
705 obstacle_spec *spec = get_obstacle_spec(i);
706 struct obstacle_graphics *graphics = &((struct obstacle_graphics *)obstacle_images.arr)[i];
707 for (j = 0; j < spec->filenames.size; j++)
708 memcpy(&graphics->shadows[j], &empty_image, sizeof(empty_image));
709 }
710
711 if (load_texture_atlas("obstacles/shadow_atlas.txt", "obstacles/", get_storage_for_obstacle_shadow_image))
712 error_message(__FUNCTION__, "Unable to load texture atlas for obstacle shadows at obstacle/shadow_atlas.txt.", PLEASE_INFORM | IS_FATAL);
713
714 if (with_startup_bar)
715 next_startup_percentage(8);
716
717 validate_obstacle_graphics();
718}
719
720static struct image *get_storage_for_floor_tile(const char *filename)
721{
722 int i, j;
723
724 for (i = 0; i < underlay_floor_tiles.size; i++) {
725 struct floor_tile_spec *floor_tile = dynarray_member(&underlay_floor_tiles, i, sizeof(struct floor_tile_spec));
726 for (j = 0; j < floor_tile->frames; j++) {
727 if (!strcmp(((char **)floor_tile->filenames.arr)[j], filename)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(((char **)floor_tile->filenames.arr)[j]) && __builtin_constant_p
(filename) && (__s1_len = strlen (((char **)floor_tile
->filenames.arr)[j]), __s2_len = strlen (filename), (!((size_t
)(const void *)((((char **)floor_tile->filenames.arr)[j]) +
1) - (size_t)(const void *)(((char **)floor_tile->filenames
.arr)[j]) == 1) || __s1_len >= 4) && (!((size_t)(const
void *)((filename) + 1) - (size_t)(const void *)(filename) ==
1) || __s2_len >= 4)) ? __builtin_strcmp (((char **)floor_tile
->filenames.arr)[j], filename) : (__builtin_constant_p (((
char **)floor_tile->filenames.arr)[j]) && ((size_t
)(const void *)((((char **)floor_tile->filenames.arr)[j]) +
1) - (size_t)(const void *)(((char **)floor_tile->filenames
.arr)[j]) == 1) && (__s1_len = strlen (((char **)floor_tile
->filenames.arr)[j]), __s1_len < 4) ? (__builtin_constant_p
(filename) && ((size_t)(const void *)((filename) + 1
) - (size_t)(const void *)(filename) == 1) ? __builtin_strcmp
(((char **)floor_tile->filenames.arr)[j], filename) : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (filename); int __result = (((const unsigned char *)
(const char *) (((char **)floor_tile->filenames.arr)[j]))
[0] - __s2[0]); if (__s1_len > 0 && __result == 0)
{ __result = (((const unsigned char *) (const char *) (((char
**)floor_tile->filenames.arr)[j]))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (((char **)floor_tile->filenames.arr
)[j]))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) ((
(char **)floor_tile->filenames.arr)[j]))[3] - __s2[3]); } }
__result; }))) : (__builtin_constant_p (filename) &&
((size_t)(const void *)((filename) + 1) - (size_t)(const void
*)(filename) == 1) && (__s2_len = strlen (filename),
__s2_len < 4) ? (__builtin_constant_p (((char **)floor_tile
->filenames.arr)[j]) && ((size_t)(const void *)(((
(char **)floor_tile->filenames.arr)[j]) + 1) - (size_t)(const
void *)(((char **)floor_tile->filenames.arr)[j]) == 1) ? __builtin_strcmp
(((char **)floor_tile->filenames.arr)[j], filename) : (- (
__extension__ ({ const unsigned char *__s2 = (const unsigned char
*) (const char *) (((char **)floor_tile->filenames.arr)[j
]); int __result = (((const unsigned char *) (const char *) (
filename))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
filename))[1] - __s2[1]); if (__s2_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
filename))[2] - __s2[2]); if (__s2_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (filename
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (((char
**)floor_tile->filenames.arr)[j], filename)))); })
)
728 return &floor_tile->images[j];
729 }
730 }
731
732 for (i = 0; i < overlay_floor_tiles.size; i++) {
733 struct floor_tile_spec *floor_tile = dynarray_member(&overlay_floor_tiles, i, sizeof(struct floor_tile_spec));
734 for (j = 0; j < floor_tile->frames; j++) {
735 if (!strcmp(((char **)floor_tile->filenames.arr)[j], filename)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(((char **)floor_tile->filenames.arr)[j]) && __builtin_constant_p
(filename) && (__s1_len = strlen (((char **)floor_tile
->filenames.arr)[j]), __s2_len = strlen (filename), (!((size_t
)(const void *)((((char **)floor_tile->filenames.arr)[j]) +
1) - (size_t)(const void *)(((char **)floor_tile->filenames
.arr)[j]) == 1) || __s1_len >= 4) && (!((size_t)(const
void *)((filename) + 1) - (size_t)(const void *)(filename) ==
1) || __s2_len >= 4)) ? __builtin_strcmp (((char **)floor_tile
->filenames.arr)[j], filename) : (__builtin_constant_p (((
char **)floor_tile->filenames.arr)[j]) && ((size_t
)(const void *)((((char **)floor_tile->filenames.arr)[j]) +
1) - (size_t)(const void *)(((char **)floor_tile->filenames
.arr)[j]) == 1) && (__s1_len = strlen (((char **)floor_tile
->filenames.arr)[j]), __s1_len < 4) ? (__builtin_constant_p
(filename) && ((size_t)(const void *)((filename) + 1
) - (size_t)(const void *)(filename) == 1) ? __builtin_strcmp
(((char **)floor_tile->filenames.arr)[j], filename) : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (filename); int __result = (((const unsigned char *)
(const char *) (((char **)floor_tile->filenames.arr)[j]))
[0] - __s2[0]); if (__s1_len > 0 && __result == 0)
{ __result = (((const unsigned char *) (const char *) (((char
**)floor_tile->filenames.arr)[j]))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (((char **)floor_tile->filenames.arr
)[j]))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) ((
(char **)floor_tile->filenames.arr)[j]))[3] - __s2[3]); } }
__result; }))) : (__builtin_constant_p (filename) &&
((size_t)(const void *)((filename) + 1) - (size_t)(const void
*)(filename) == 1) && (__s2_len = strlen (filename),
__s2_len < 4) ? (__builtin_constant_p (((char **)floor_tile
->filenames.arr)[j]) && ((size_t)(const void *)(((
(char **)floor_tile->filenames.arr)[j]) + 1) - (size_t)(const
void *)(((char **)floor_tile->filenames.arr)[j]) == 1) ? __builtin_strcmp
(((char **)floor_tile->filenames.arr)[j], filename) : (- (
__extension__ ({ const unsigned char *__s2 = (const unsigned char
*) (const char *) (((char **)floor_tile->filenames.arr)[j
]); int __result = (((const unsigned char *) (const char *) (
filename))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
filename))[1] - __s2[1]); if (__s2_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
filename))[2] - __s2[2]); if (__s2_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (filename
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (((char
**)floor_tile->filenames.arr)[j], filename)))); })
)
736 return &floor_tile->images[j];
737 }
738 }
739
740 error_message(__FUNCTION__, "Floor tiles texture atlas specifies element %s which is not expected.",
741 PLEASE_INFORM, filename);
742 return NULL((void*)0);
743}
744
745/**
746 * This function loads isometric floor tiles, and in OpenGL mode, generates
747 * a texture atlas.
748 *
749 */
750void load_floor_tiles(void)
751{
752 // Try to load the atlas
753 if (load_texture_atlas("floor_tiles/atlas.txt", "floor_tiles/", get_storage_for_floor_tile)) {
754 error_message(__FUNCTION__, "Unable to load floor tiles atlas at floor_tiles/atlas.txt.", PLEASE_INFORM | IS_FATAL);
755 }
756}
757
758void free_floor_tiles(void)
759{
760 int i, j;
761
762 for (i = 0; i < underlay_floor_tiles.size; i++) {
763 struct floor_tile_spec *floor_tile = dynarray_member(&underlay_floor_tiles, i, sizeof(struct floor_tile_spec));
764 for (j = 0; j < floor_tile->frames; j++) {
765 delete_image(&floor_tile->images[j]);
766 }
767 }
768
769 for (i = 0; i < overlay_floor_tiles.size; i++) {
770 struct floor_tile_spec *floor_tile = dynarray_member(&overlay_floor_tiles, i, sizeof(struct floor_tile_spec));
771 for (j = 0; j < floor_tile->frames; j++) {
772 delete_image(&floor_tile->images[j]);
773 }
774 }
775}
776
777static int current_tux_motion_class;
778static int current_tux_part_group;
779
780static struct image *get_storage_for_tux_image(const char *filename)
781{
782 int rotation;
783 int phase;
784
785 if (sscanf(filename, "tux_rot_%02d_phase_%02d.png", &rotation, &phase) != 2) {
786 error_message(__FUNCTION__, "Invalid filename '%s' in tux texture atlas.",
787 PLEASE_INFORM, filename);
788 return NULL((void*)0);
789 }
790
791 if (rotation >= MAX_TUX_DIRECTIONS16) {
792 error_message(__FUNCTION__, "Invalid rotation index %d in tux texture atlas.\n"
793 "Maximum allowed value for the rotation index is %d.", PLEASE_INFORM,
794 rotation, MAX_TUX_DIRECTIONS16 - 1);
795 return NULL((void*)0);
796 }
797
798 if (phase >= TUX_TOTAL_PHASES35) {
799 error_message(__FUNCTION__, "Invalid phase index %d in tux texture atlas.\n"
800 "Maximum allowed value for the phase index is %d.", PLEASE_INFORM,
801 phase, TUX_TOTAL_PHASES35 - 1);
802 return NULL((void*)0);
803 }
804
805 return &tux_images[current_tux_motion_class].part_images[current_tux_part_group][phase][rotation];
806}
807
808/**
809 * Load the tux image part group for the given motion class.
810 */
811void load_tux_graphics(int motion_class, int tux_part_group, const char *part_string)
812{
813 char atlas_filename[4096];
814 char atlas_directory[4096];
815 static char *part_group_strings[ALL_PART_GROUPS] = {
816 "head/",
817 "shield/",
818 "torso/",
819 "feet/",
820 "weapon/",
821 "weaponarm/"
822 };
823
824 sprintf(atlas_directory, "tux_motion_parts/%s/%s%s/",
825 get_motion_class_name_by_id(motion_class), part_group_strings[tux_part_group], part_string);
826 sprintf(atlas_filename, "%s/atlas.txt", atlas_directory);
827
828 current_tux_motion_class = motion_class;
829 current_tux_part_group = tux_part_group;
830 if (load_texture_atlas(atlas_filename, atlas_directory, get_storage_for_tux_image)) {
831 error_message(__FUNCTION__, "Unable to load tux texture atlas at %s.",
832 PLEASE_INFORM | IS_FATAL, atlas_filename);
833 }
834}
835
836/**
837 * Force tux graphics to reload.
838 */
839void reload_tux_graphics(void)
840{
841 int i, j;
842
843 // Clear tux part strings. It will force tux graphics to reload.
844 for (i = 0; i < tux_rendering.motion_class_names.size; i++) {
845 struct tux_motion_class_images *motion_class = &tux_images[i];
846 for (j = 0; j < ALL_PART_GROUPS; j++)
847 motion_class->part_names[j][0] = '\0';
848 }
849}
850
851#undef _blocks_c