Bug Summary

File:src/map.c
Location:line 1678, column 32
Description:Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

1/*
2 *
3 * Copyright (c) 1994, 2002, 2003 Johannes Prix
4 * Copyright (c) 1994, 2002 Reinhard Prix
5 * Copyright (c) 2004-2010 Arthur Huillet
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/**
28 * This file contains (all?) map-related functions, which also includes
29 * loading of decks and whole ships, starting the lifts and consoles if
30 * close to the paradroid, refreshes as well as determining the map brick
31 * that contains specified coordinates are done in this file.
32 */
33
34#define _map_c
35
36#include "system.h"
37
38#include "defs.h"
39#include "struct.h"
40#include "proto.h"
41#include "global.h"
42
43#include "lvledit/lvledit_actions.h"
44#include "lvledit/lvledit_display.h"
45#include "map.h"
46
47#define TELEPORT_PAIR_STRING"teleport pair:" "teleport pair:"
48
49void GetThisLevelsDroids(char *section_pointer);
50
51/*
52 * Initialize a map tile with default values.
53 */
54void init_map_tile(struct map_tile* tile)
55{
56 int i;
57 tile->floor_values[0] = ISO_FLOOR_SAND;
58 for (i = 1; i < MAX_FLOOR_LAYERS2; i++)
59 tile->floor_values[i] = ISO_FLOOR_EMPTY;
60 dynarray_init(&tile->glued_obstacles, 0, sizeof(int));
61 tile->timestamp = 0;
62}
63
64/**
65 * This function removes all volatile obstacles from a given level.
66 * An example of a volatile obstacle is the blood.
67 * If the blood doesn't vanish, then there will be more and more blood,
68 * especially after the bots on the level have respawned a few times.
69 * Therefore we need this function, which will remove all traces of blood
70 * from a given level.
71 */
72static void remove_volatile_obstacles(int level_num)
73{
74 int i;
75
76 // We pass through all the obstacles, deleting those
77 // that are 'blood'.
78 //
79 for (i = 0; i < MAX_OBSTACLES_ON_MAP4000; i++) {
80 int obstacle_type = curShip.AllLevels[level_num]->obstacle_list[i].type;
81 if (obstacle_type == -1)
82 continue;
83 if (get_obstacle_spec(obstacle_type)->flags & IS_VOLATILE)
84 del_obstacle(&curShip.AllLevels[level_num]->obstacle_list[i]);
85 }
86}
87
88/**
89 * This function will make all blood obstacles vanish, all dead bots come
90 * back to life, and get all bots return to a wandering state.
91 */
92void respawn_level(int level_num)
93{
94 enemy *erot, *nerot;
95
96 int wp_num = curShip.AllLevels[level_num]->waypoints.size;
97 char wp_used[wp_num]; // is a waypoint already used ?
98 memset(wp_used, 0, wp_num);
99
100 // First we remove all the volatile obstacles...
101 //
102 remove_volatile_obstacles(level_num);
103
104 // Now we can give new life to dead bots...
105 //
106 BROWSE_DEAD_BOTS_SAFE(erot, nerot)for (erot = ({ const typeof( ((typeof(*erot) *)0)->global_list
) *__mptr = ((&dead_bots_head)->next); (typeof(*erot)
*)( (char *)__mptr - __builtin_offsetof(typeof(*erot), global_list
) );}), nerot = ({ const typeof( ((typeof(*erot) *)0)->global_list
) *__mptr = (erot->global_list.next); (typeof(*erot) *)( (
char *)__mptr - __builtin_offsetof(typeof(*erot), global_list
) );}); &erot->global_list != (&dead_bots_head); erot
= nerot, nerot = ({ const typeof( ((typeof(*nerot) *)0)->
global_list ) *__mptr = (nerot->global_list.next); (typeof
(*nerot) *)( (char *)__mptr - __builtin_offsetof(typeof(*nerot
), global_list) );}))
{
107 if (erot->pos.z != level_num || Droidmap[erot->type].is_human || !erot->will_respawn)
108 continue;
109 /* Move the bot to the alive list */
110 list_move(&(erot->global_list), &alive_bots_head);
111 /* Reinsert it into the current level list */
112 list_add(&(erot->level_list), &level_bots_head[level_num]);
113 }
114
115 // Finally, we reset the runtime attributes of the bots, place them
116 // on a waypoint, and ask them to start wandering...
117 //
118 BROWSE_LEVEL_BOTS(erot, level_num)for (erot = ({ const typeof( ((typeof(*erot) *)0)->level_list
) *__mptr = ((&level_bots_head[(level_num)])->next); (
typeof(*erot) *)( (char *)__mptr - __builtin_offsetof(typeof(
*erot), level_list) );}); &erot->level_list != (&level_bots_head
[(level_num)]); erot = ({ const typeof( ((typeof(*erot) *)0)->
level_list ) *__mptr = (erot->level_list.next); (typeof(*erot
) *)( (char *)__mptr - __builtin_offsetof(typeof(*erot), level_list
) );}))
{
119
120 // Unconditional reset of the 'transient state' attributes
121 enemy_reset(erot);
122
123 // Conditional reset of some 'global state' attributes
124 if (erot->has_been_taken_over) {
125 erot->faction = FACTION_BOTS;
126 erot->has_been_taken_over = FALSE(0);
127 erot->CompletelyFixed = FALSE(0);
128 erot->follow_tux = FALSE(0);
129 }
130
131 erot->has_greeted_influencer = FALSE(0);
132
133 if (wp_num) {
134 // Re-place the bots onto the waypoint system
135 if (!erot->SpecialForce) {
136 // Standard bots are randomly placed on one waypoint
137 int wp = teleport_to_random_waypoint(erot, curShip.AllLevels[level_num], wp_used);
138 wp_used[wp] = 1;
139 erot->homewaypoint = erot->lastwaypoint;
140 erot->combat_state = SELECT_NEW_WAYPOINT;
141 erot->state_timeout = 0.0;
142 } else {
143 if (erot->homewaypoint == -1) {
144 // If a special force droid has not yet been integrated onto
145 // the waypoint system, place it near its current position.
146 int wp = teleport_to_closest_waypoint(erot);
147 wp_used[wp] = 1;
148 erot->homewaypoint = erot->lastwaypoint;
149 erot->combat_state = SELECT_NEW_WAYPOINT;
150 erot->state_timeout = 0.0;
151 } else {
152 // Consider that the nextwaypoint of a special force droid
153 // is occupied, so that a standard bot will not be placed here
154 if (erot->nextwaypoint != -1)
155 wp_used[erot->nextwaypoint] = 1;
156 }
157 }
158 } else {
159 error_message(__FUNCTION__, "There is no waypoint on level %d - unable to place random bots.",
160 PLEASE_INFORM, level_num);
161 }
162 }
163}
164
165/**
166 * \brief Get the center coordinates of a given map label.
167 * In case of fail, a fatal error is thrown.
168 * \param map_label The name of map label to resolve.
169 * \return The gps center of the map label.
170 */
171gps get_map_label_center(const char *map_label)
172{
173 struct map_label *m;
174 gps position = {0., 0., -1};
175 int i;
176
177 for (i = 0; i < curShip.num_levels; i++) {
178 if (!level_exists(i))
179 continue;
180
181 m = get_map_label(curShip.AllLevels[i], map_label);
182 if (m) {
183 position.x = m->pos.x + 0.5;
184 position.y = m->pos.y + 0.5;
185 position.z = i;
186 return position;
187 }
188 }
189
190 error_message(__FUNCTION__, "\
191Resolving map label \"%s\" failed on the entire world!\n\
192This is a severe error in the game data of FreedroidRPG.", PLEASE_INFORM, map_label);
193
194 return position;
195};
196
197/**
198 * Next we extract the level interface data from the human-readable data
199 * into the level struct, but WITHOUT destroying or damaging the
200 * human-readable data in the process!
201 */
202static void decode_interfaces(level *loadlevel, char *DataPointer)
203{
204 char *TempSectionPointer;
205 char PreservedLetter;
206
207 // We look for the beginning and end of the map statement section
208 TempSectionPointer = LocateStringInData(DataPointer, MAP_BEGIN_STRING"beginning_of_map");
209
210 // We add a terminator at the end, but ONLY TEMPORARY. The damage will be restored later!
211 PreservedLetter = TempSectionPointer[0];
212 TempSectionPointer[0] = 0;
213
214 ReadValueFromString(DataPointer, "jump target north: ", "%d", &(loadlevel->jump_target_north), TempSectionPointer);
215 ReadValueFromString(DataPointer, "jump target south: ", "%d", &(loadlevel->jump_target_south), TempSectionPointer);
216 ReadValueFromString(DataPointer, "jump target east: ", "%d", &(loadlevel->jump_target_east), TempSectionPointer);
217 ReadValueFromString(DataPointer, "jump target west: ", "%d", &(loadlevel->jump_target_west), TempSectionPointer);
218
219 TempSectionPointer[0] = PreservedLetter;
220
221}
222
223static void decode_dimensions(level *loadlevel, char *DataPointer)
224{
225
226 int off = 0;
227
228 /* Read levelnumber */
229 char *fp = DataPointer;
230 fp += strlen(LEVEL_HEADER_LEVELNUMBER"Levelnumber:");
231 while (*(fp + off) != '\n')
232 off++;
233 fp[off] = 0;
234 loadlevel->levelnum = atoi(fp);
235 fp[off] = '\n';
236 fp += off + 1;
237 off = 0;
238
239 /* Read xlen */
240 fp += strlen("xlen of this level:");
241 while (*(fp + off) != '\n')
242 off++;
243 fp[off] = 0;
244 loadlevel->xlen = atoi(fp);
245 fp[off] = '\n';
246 fp += off + 1;
247 off = 0;
248
249 /* Read ylen */
250 fp += strlen("ylen of this level:");
251 while (*(fp + off) != '\n')
252 off++;
253 fp[off] = 0;
254 loadlevel->ylen = atoi(fp);
255 fp[off] = '\n';
256 fp += off + 1;
257 off = 0;
258
259 /* Read floor_layers */
260 fp += strlen("floor layers:");
261 while (*(fp + off) != '\n')
262 off++;
263 fp[off] = 0;
264 loadlevel->floor_layers = atoi(fp);
265 fp[off] = '\n';
266 fp += off + 1;
267 off = 0;
268
269 /* Read lrb */
270 fp += strlen("light radius bonus of this level:");
271 while (*(fp + off) != '\n')
272 off++;
273 fp[off] = 0;
274 loadlevel->light_bonus = atoi(fp);
275 fp[off] = '\n';
276 fp += off + 1;
277 off = 0;
278
279 fp += strlen("minimal light on this level:");
280 while (*(fp + off) != '\n')
281 off++;
282 fp[off] = 0;
283 loadlevel->minimum_light_value = atoi(fp);
284 fp[off] = '\n';
285 fp += off + 1;
286 off = 0;
287
288 fp += strlen("infinite_running_on_this_level:");
289 while (*(fp + off) != '\n')
290 off++;
291 fp[off] = 0;
292 loadlevel->infinite_running_on_this_level = atoi(fp);
293 fp[off] = '\n';
294 fp += off + 1;
295 off = 0;
296
297 fp += strlen("random dungeon:");
298 while (*(fp + off) != '\n')
299 off++;
300 fp[off] = 0;
301 loadlevel->random_dungeon = atoi(fp);
302 fp[off] = '\n';
303 fp += off + 1;
304 off = 0;
305
306 if (!strncmp(fp, TELEPORT_PAIR_STRING, strlen(TELEPORT_PAIR_STRING))(__extension__ (__builtin_constant_p (strlen("teleport pair:"
)) && ((__builtin_constant_p (fp) && strlen (
fp) < ((size_t) (strlen("teleport pair:")))) || (__builtin_constant_p
("teleport pair:") && strlen ("teleport pair:") <
((size_t) (strlen("teleport pair:"))))) ? __extension__ ({ size_t
__s1_len, __s2_len; (__builtin_constant_p (fp) && __builtin_constant_p
("teleport pair:") && (__s1_len = strlen (fp), __s2_len
= strlen ("teleport pair:"), (!((size_t)(const void *)((fp) +
1) - (size_t)(const void *)(fp) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("teleport pair:") + 1) - (size_t)
(const void *)("teleport pair:") == 1) || __s2_len >= 4)) ?
__builtin_strcmp (fp, "teleport pair:") : (__builtin_constant_p
(fp) && ((size_t)(const void *)((fp) + 1) - (size_t)
(const void *)(fp) == 1) && (__s1_len = strlen (fp), __s1_len
< 4) ? (__builtin_constant_p ("teleport pair:") &&
((size_t)(const void *)(("teleport pair:") + 1) - (size_t)(const
void *)("teleport pair:") == 1) ? __builtin_strcmp (fp, "teleport pair:"
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) ("teleport pair:"); int __result = ((
(const unsigned char *) (const char *) (fp))[0] - __s2[0]); if
(__s1_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (fp))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (fp))[2] - __s2[2]); if (__s1_len >
2 && __result == 0) __result = (((const unsigned char
*) (const char *) (fp))[3] - __s2[3]); } } __result; }))) : (
__builtin_constant_p ("teleport pair:") && ((size_t)(
const void *)(("teleport pair:") + 1) - (size_t)(const void *
)("teleport pair:") == 1) && (__s2_len = strlen ("teleport pair:"
), __s2_len < 4) ? (__builtin_constant_p (fp) && (
(size_t)(const void *)((fp) + 1) - (size_t)(const void *)(fp)
== 1) ? __builtin_strcmp (fp, "teleport pair:") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (fp); int __result = (((const unsigned char *) (const
char *) ("teleport pair:"))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) ("teleport pair:"))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("teleport pair:"))[2] - __s2[2]); if
(__s2_len > 2 && __result == 0) __result = (((const
unsigned char *) (const char *) ("teleport pair:"))[3] - __s2
[3]); } } __result; })))) : __builtin_strcmp (fp, "teleport pair:"
)))); }) : strncmp (fp, "teleport pair:", strlen("teleport pair:"
))))
) {
307 fp += strlen(TELEPORT_PAIR_STRING"teleport pair:");
308 while (*(fp + off) != '\n')
309 off++;
310 fp[off] = 0;
311 loadlevel->teleport_pair = atoi(fp);
312 fp[off] = '\n';
313 fp += off + 1;
314 off = 0;
315 } else {
316 loadlevel->teleport_pair = 0;
317 }
318
319 if (!strncmp(fp, "dungeon generated:", 18)(__extension__ (__builtin_constant_p (18) && ((__builtin_constant_p
(fp) && strlen (fp) < ((size_t) (18))) || (__builtin_constant_p
("dungeon generated:") && strlen ("dungeon generated:"
) < ((size_t) (18)))) ? __extension__ ({ size_t __s1_len, __s2_len
; (__builtin_constant_p (fp) && __builtin_constant_p (
"dungeon generated:") && (__s1_len = strlen (fp), __s2_len
= strlen ("dungeon generated:"), (!((size_t)(const void *)((
fp) + 1) - (size_t)(const void *)(fp) == 1) || __s1_len >=
4) && (!((size_t)(const void *)(("dungeon generated:"
) + 1) - (size_t)(const void *)("dungeon generated:") == 1) ||
__s2_len >= 4)) ? __builtin_strcmp (fp, "dungeon generated:"
) : (__builtin_constant_p (fp) && ((size_t)(const void
*)((fp) + 1) - (size_t)(const void *)(fp) == 1) && (
__s1_len = strlen (fp), __s1_len < 4) ? (__builtin_constant_p
("dungeon generated:") && ((size_t)(const void *)(("dungeon generated:"
) + 1) - (size_t)(const void *)("dungeon generated:") == 1) ?
__builtin_strcmp (fp, "dungeon generated:") : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) ("dungeon generated:"); int __result = (((const unsigned
char *) (const char *) (fp))[0] - __s2[0]); if (__s1_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (fp))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (fp))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (fp
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
"dungeon generated:") && ((size_t)(const void *)(("dungeon generated:"
) + 1) - (size_t)(const void *)("dungeon generated:") == 1) &&
(__s2_len = strlen ("dungeon generated:"), __s2_len < 4) ?
(__builtin_constant_p (fp) && ((size_t)(const void *
)((fp) + 1) - (size_t)(const void *)(fp) == 1) ? __builtin_strcmp
(fp, "dungeon generated:") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (fp); int
__result = (((const unsigned char *) (const char *) ("dungeon generated:"
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("dungeon generated:"
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("dungeon generated:"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("dungeon generated:"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (fp,
"dungeon generated:")))); }) : strncmp (fp, "dungeon generated:"
, 18)))
) {
320 fp += strlen("dungeon generated:");
321 while (*(fp + off) != '\n')
322 off++;
323 fp[off] = 0;
324 loadlevel->dungeon_generated = atoi(fp);
325 fp[off] = '\n';
326 fp += off + 1;
327 } else {
328 loadlevel->dungeon_generated = 0;
329 }
330
331 if (!strncmp(fp, "environmental flags:", 20)(__extension__ (__builtin_constant_p (20) && ((__builtin_constant_p
(fp) && strlen (fp) < ((size_t) (20))) || (__builtin_constant_p
("environmental flags:") && strlen ("environmental flags:"
) < ((size_t) (20)))) ? __extension__ ({ size_t __s1_len, __s2_len
; (__builtin_constant_p (fp) && __builtin_constant_p (
"environmental flags:") && (__s1_len = strlen (fp), __s2_len
= strlen ("environmental flags:"), (!((size_t)(const void *)
((fp) + 1) - (size_t)(const void *)(fp) == 1) || __s1_len >=
4) && (!((size_t)(const void *)(("environmental flags:"
) + 1) - (size_t)(const void *)("environmental flags:") == 1)
|| __s2_len >= 4)) ? __builtin_strcmp (fp, "environmental flags:"
) : (__builtin_constant_p (fp) && ((size_t)(const void
*)((fp) + 1) - (size_t)(const void *)(fp) == 1) && (
__s1_len = strlen (fp), __s1_len < 4) ? (__builtin_constant_p
("environmental flags:") && ((size_t)(const void *)(
("environmental flags:") + 1) - (size_t)(const void *)("environmental flags:"
) == 1) ? __builtin_strcmp (fp, "environmental flags:") : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) ("environmental flags:"); int __result = (((const unsigned
char *) (const char *) (fp))[0] - __s2[0]); if (__s1_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (fp))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (fp))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (fp
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
"environmental flags:") && ((size_t)(const void *)(("environmental flags:"
) + 1) - (size_t)(const void *)("environmental flags:") == 1)
&& (__s2_len = strlen ("environmental flags:"), __s2_len
< 4) ? (__builtin_constant_p (fp) && ((size_t)(const
void *)((fp) + 1) - (size_t)(const void *)(fp) == 1) ? __builtin_strcmp
(fp, "environmental flags:") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (fp); int
__result = (((const unsigned char *) (const char *) ("environmental flags:"
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("environmental flags:"
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("environmental flags:"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("environmental flags:"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (fp,
"environmental flags:")))); }) : strncmp (fp, "environmental flags:"
, 20)))
) {
332 fp += strlen("environmental flags:");
333 while (*(fp + off) != '\n')
334 off++;
335 fp[off] = 0;
336 loadlevel->flags = atoi(fp);
337 fp[off] = '\n';
338 fp += off + 1;
339 } else {
340 loadlevel->flags = 0;
341 }
342
343 if (!strncmp(fp, "item drop class:", 16)(__extension__ (__builtin_constant_p (16) && ((__builtin_constant_p
(fp) && strlen (fp) < ((size_t) (16))) || (__builtin_constant_p
("item drop class:") && strlen ("item drop class:") <
((size_t) (16)))) ? __extension__ ({ size_t __s1_len, __s2_len
; (__builtin_constant_p (fp) && __builtin_constant_p (
"item drop class:") && (__s1_len = strlen (fp), __s2_len
= strlen ("item drop class:"), (!((size_t)(const void *)((fp
) + 1) - (size_t)(const void *)(fp) == 1) || __s1_len >= 4
) && (!((size_t)(const void *)(("item drop class:") +
1) - (size_t)(const void *)("item drop class:") == 1) || __s2_len
>= 4)) ? __builtin_strcmp (fp, "item drop class:") : (__builtin_constant_p
(fp) && ((size_t)(const void *)((fp) + 1) - (size_t)
(const void *)(fp) == 1) && (__s1_len = strlen (fp), __s1_len
< 4) ? (__builtin_constant_p ("item drop class:") &&
((size_t)(const void *)(("item drop class:") + 1) - (size_t)
(const void *)("item drop class:") == 1) ? __builtin_strcmp (
fp, "item drop class:") : (__extension__ ({ const unsigned char
*__s2 = (const unsigned char *) (const char *) ("item drop class:"
); int __result = (((const unsigned char *) (const char *) (fp
))[0] - __s2[0]); if (__s1_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (fp))
[1] - __s2[1]); if (__s1_len > 1 && __result == 0)
{ __result = (((const unsigned char *) (const char *) (fp))[
2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result
= (((const unsigned char *) (const char *) (fp))[3] - __s2[3
]); } } __result; }))) : (__builtin_constant_p ("item drop class:"
) && ((size_t)(const void *)(("item drop class:") + 1
) - (size_t)(const void *)("item drop class:") == 1) &&
(__s2_len = strlen ("item drop class:"), __s2_len < 4) ? (
__builtin_constant_p (fp) && ((size_t)(const void *)(
(fp) + 1) - (size_t)(const void *)(fp) == 1) ? __builtin_strcmp
(fp, "item drop class:") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (fp); int
__result = (((const unsigned char *) (const char *) ("item drop class:"
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("item drop class:"
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("item drop class:"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("item drop class:"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (fp,
"item drop class:")))); }) : strncmp (fp, "item drop class:"
, 16)))
) {
344 fp += strlen("item drop class:");
345 while (*(fp + off) != '\n')
346 off++;
347 fp[off] = 0;
348 loadlevel->drop_class = atoi(fp);
349 fp[off] = '\n';
350 fp += off + 1;
351 } else {
352 loadlevel->drop_class = 0;
353 }
354
355 if (loadlevel->ylen >= MAX_MAP_LINES100) {
356 error_message(__FUNCTION__, "\
357A map/level in FreedroidRPG which was supposed to load has more map lines than allowed\n\
358for a map/level as by the constant MAX_MAP_LINES in defs.h.\n\
359Sorry, but unless this constant is raised, FreedroidRPG will refuse to load this map.", PLEASE_INFORM | IS_FATAL);
360 }
361}
362
363static void decode_random_droids(level *loadlevel, char *data)
364{
365 char *search_ptr;
366 char *end_ptr;
367
368#define DROIDS_NUMBER_INDICATION_STRING"number of random droids: " "number of random droids: "
369#define ALLOWED_TYPE_INDICATION_STRING"random droid types: " "random droid types: "
370
371 // Read the number of random droids for this level
372 end_ptr = strstr(data, ALLOWED_TYPE_INDICATION_STRING"random droid types: ");
373 ReadValueFromString(data, DROIDS_NUMBER_INDICATION_STRING"number of random droids: ", "%d", &loadlevel->random_droids.nr, end_ptr);
374
375 data = strstr(data, ALLOWED_TYPE_INDICATION_STRING"random droid types: ");
376
377 // Now we read in the type(s) of random droids for this level
378 search_ptr = ReadAndMallocStringFromDataOptional(data, ALLOWED_TYPE_INDICATION_STRING"random droid types: ", "\n");
379 if (search_ptr && (loadlevel->random_droids.nr > 0)) {
380 char *droid_type_ptr = search_ptr;
381 while (*droid_type_ptr) {
382 while (*droid_type_ptr && isspace(*droid_type_ptr)((*__ctype_b_loc ())[(int) ((*droid_type_ptr))] & (unsigned
short int) _ISspace)
) {
383 droid_type_ptr++;
384 }
385 int droid_type_length = 0;
386 char *ptr = droid_type_ptr;
387 while (isalnum(*ptr)((*__ctype_b_loc ())[(int) ((*ptr))] & (unsigned short int
) _ISalnum)
) {
388 ptr++;
389 droid_type_length++;
390 }
391 if (!droid_type_length)
392 break;
393
394 char type_indication_string[droid_type_length + 1];
395 strncpy(type_indication_string, droid_type_ptr, droid_type_length)__builtin_strncpy (type_indication_string, droid_type_ptr, droid_type_length
)
;
396 type_indication_string[droid_type_length] = 0;
397
398 int droid_type = get_droid_type(type_indication_string);
399
400 loadlevel->random_droids.types[loadlevel->random_droids.types_size++] = droid_type;
401
402 droid_type_ptr += droid_type_length;
403 if (*droid_type_ptr)
404 droid_type_ptr++; //skip the comma
405 }
406 free(search_ptr);
407 }
408}
409
410static int decode_header(level *loadlevel, char *data)
411{
412 data = strstr(data, LEVEL_HEADER_LEVELNUMBER"Levelnumber:");
413 if (!data)
414 return 1;
415
416 decode_interfaces(loadlevel, data);
417 decode_dimensions(loadlevel, data);
418 decode_random_droids(loadlevel, data);
419
420 // Read the levelname.
421 loadlevel->Levelname = ReadAndMallocStringFromData(data, LEVEL_NAME_STRING"Name of this level=_\"", "\"");
422
423 loadlevel->Background_Song_Name = ReadAndMallocStringFromData(data, BACKGROUND_SONG_NAME_STRING"BgSong=", "\n");
424
425 return 0;
426}
427
428/**
429 * Next we extract the human readable obstacle data into the level struct
430 * WITHOUT destroying or damaging the human-readable data in the process!
431 * This is an improved parser that is not quite readable but very performant.
432 */
433static char *decode_obstacles(level *loadlevel, char *DataPointer)
434{
435 int i;
436 char *curfield = NULL((void*)0);
437 char *curfieldend = NULL((void*)0);
438 char *obstacle_SectionBegin;
439 float x, y;
440 int type;
441
442 // First we initialize the obstacles with 'empty' information
443 //
444 for (i = 0; i < MAX_OBSTACLES_ON_MAP4000; i++) {
445 loadlevel->obstacle_list[i].type = -1;
446 loadlevel->obstacle_list[i].pos.x = -1;
447 loadlevel->obstacle_list[i].pos.y = -1;
448 loadlevel->obstacle_list[i].pos.z = loadlevel->levelnum;
449 loadlevel->obstacle_list[i].timestamp = 0;
450 loadlevel->obstacle_list[i].frame_index = 0;
451 }
452
453 if (loadlevel->random_dungeon && !loadlevel->dungeon_generated)
454 return DataPointer;
455
456 // Now we look for the beginning and end of the obstacle section
457 //
458 obstacle_SectionBegin = LocateStringInData(DataPointer, OBSTACLE_DATA_BEGIN_STRING"obsdata") + strlen(OBSTACLE_DATA_BEGIN_STRING"obsdata") + 1;
459
460 // Now we decode all the obstacle information
461 //
462 curfield = obstacle_SectionBegin;
463 while (*curfield != '/') {
464 //structure of obstacle entry is : // t59 x2.50 y63.50 l-1 d-1
465 //we read the type
466 curfield++;
467 curfieldend = curfield;
468 while ((*curfieldend) != ' ')
469 curfieldend++;
470 (*curfieldend) = 0;
471 type = atoi(curfield);
472 (*curfieldend) = ' ';
473
474 //we read the X position
475 curfield = curfieldend + 2;
476 curfieldend += 2;
477 while ((*curfieldend) != ' ')
478 curfieldend++;
479 (*curfieldend) = 0;
480 x = atof(curfield);
481 (*curfieldend) = ' ';
482
483 //Y position
484 curfield = curfieldend + 2;
485 curfieldend += 2;
486 while ((*curfieldend) != ' ')
487 curfieldend++;
488 (*curfieldend) = 0;
489 y = atof(curfield);
490 (*curfieldend) = ' ';
491
492 while ((*curfield) != '\n')
493 curfield++;
494 curfield++;
495
496 add_obstacle(loadlevel, x, y, type);
497 }
498
499 return curfield;
500}
501
502/**
503 * Next we extract the map labels of this level WITHOUT destroying
504 * or damaging the data in the process!
505 */
506static char *decode_map_labels(level *loadlevel, char *data)
507{
508 char *label_name;
509 int i, x, y;
510
511 // Initialize map labels
512 dynarray_init(&loadlevel->map_labels, 10, sizeof(struct map_label));
513
514 if (loadlevel->random_dungeon && !loadlevel->dungeon_generated)
515 return data;
516
517 // Now we look for the beginning and end of the map labels section
518 char *map_label_begin = LocateStringInData(data, MAP_LABEL_BEGIN_STRING"plabelinfolvl") + strlen(MAP_LABEL_BEGIN_STRING"plabelinfolvl") + 1;
519 char *map_label_end = LocateStringInData(map_label_begin, MAP_LABEL_END_STRING"/plabelinfolvl");
520 *map_label_end = '\0';
521
522 // Get the number of map labels in this level
523 int nb_map_labels_in_level = CountStringOccurences(map_label_begin, LABEL_ITSELF_ANNOUNCE_STRING"name=\"");
524 DebugPrintf(1, "\nNumber of map labels found in this level : %d.", nb_map_labels_in_level);
525
526 // Now we decode all the map label information
527 for (i = 0; i < nb_map_labels_in_level ; i++) {
528 if (i)
529 map_label_begin = strstr(map_label_begin + 1, X_POSITION_OF_LABEL_STRING"x=");
530
531 // Get the position of the map label
532 ReadValueFromString(map_label_begin, X_POSITION_OF_LABEL_STRING"x=", "%d", &x, map_label_end);
533 ReadValueFromString(map_label_begin, Y_POSITION_OF_LABEL_STRING"y=", "%d", &y, map_label_end);
534
535 // Get the name of the map label
536 label_name = ReadAndMallocStringFromData(map_label_begin, LABEL_ITSELF_ANNOUNCE_STRING"name=\"", "\"");
537
538 // Add the map label on the level
539 add_map_label(loadlevel, x, y, label_name);
540
541 DebugPrintf(1, "\npos.x=%d pos.y=%d label_name=\"%s\"", x, y, label_name);
542 }
543
544 *map_label_end = MAP_LABEL_END_STRING"/plabelinfolvl"[0];
545 return map_label_end;
546}
547
548static void ReadInOneItem(char *ItemPointer, char *ItemsSectionEnd, item *TargetItem)
549{
550 init_item(TargetItem);
551
552 char *item_id = ReadAndMallocStringFromData(ItemPointer, ITEM_ID_STRING"it: id=\"", "\"");
553 TargetItem->type = get_item_type_by_id(item_id);
554 free(item_id);
555
556 ReadValueFromString(ItemPointer, ITEM_POS_X_STRING" X=", "%f", &(TargetItem->pos.x), ItemsSectionEnd);
557 ReadValueFromString(ItemPointer, ITEM_POS_Y_STRING" Y=", "%f", &(TargetItem->pos.y), ItemsSectionEnd);
558 ReadValueFromStringWithDefault(ItemPointer, ITEM_ARMOR_CLASS_BASE_STRING" AC=", "%d", "0", &(TargetItem->armor_class), ItemsSectionEnd);
559 ReadValueFromString(ItemPointer, ITEM_MAX_DURABILITY_STRING" MDur=", "%d", &(TargetItem->max_durability), ItemsSectionEnd);
560 ReadValueFromString(ItemPointer, ITEM_CUR_DURABILITY_STRING" CDur=", "%f", &(TargetItem->current_durability), ItemsSectionEnd);
561 ReadValueFromString(ItemPointer, ITEM_AMMO_CLIP_STRING" AClip=", "%d", &(TargetItem->ammo_clip), ItemsSectionEnd);
562 ReadValueFromString(ItemPointer, ITEM_MULTIPLICITY_STRING" Multi=", "%d", &(TargetItem->multiplicity), ItemsSectionEnd);
563
564 // Read the socket data of the item and calculate bonuses using it.
565 int i;
566 int socket_count;
567 ReadValueFromStringWithDefault(ItemPointer, ITEM_SOCKETS_SIZE_STRING" Sockets=", "%d", "0", &socket_count, ItemsSectionEnd);
568 for (i = 0; i < socket_count; i++) {
569 char type_string[32];
570 char addon_string[32];
571 struct upgrade_socket socket;
572 sprintf(type_string, "%s%d=", ITEM_SOCKET_TYPE_STRING"SocketType", i);
573 sprintf(addon_string, "%s%d=", ITEM_SOCKET_ADDON_STRING"SocketAddon", i);
574 ReadValueFromString(ItemPointer, type_string, "%d", &socket.type, ItemsSectionEnd);
575 socket.addon = ReadAndMallocStringFromDataOptional(ItemPointer, addon_string, "\"");
576 create_upgrade_socket(TargetItem, socket.type, socket.addon);
577 free(socket.addon);
578 }
579 calculate_item_bonuses(TargetItem);
580
581 DebugPrintf(1, "\nPosX=%f PosY=%f Item=%d", TargetItem->pos.x, TargetItem->pos.y, TargetItem->type);
582
583}
584
585static char *decode_extension_chest(char *ext, void **data)
586{
587 struct dynarray *chest = dynarray_alloc(1, sizeof(item));
588 char *item_str, *item_end;
589
590 item_str = ext;
591
592 while (*item_str != '}') {
593 // Find end of this item (beginning of next item)
594 item_end = item_str;
595 while (*item_end != '\n')
596 item_end++;
597 while (isspace(*item_end)((*__ctype_b_loc ())[(int) ((*item_end))] & (unsigned short
int) _ISspace)
)
598 item_end++;
599
600 // Read the item on this line
601 item new_item;
602 ReadInOneItem(item_str, item_end, &new_item);
603
604 // Add the item to the dynarray
605 dynarray_add(chest, &new_item, sizeof(item));
606
607 // Move to the next item definition
608 item_str = item_end;
609 }
610
611
612 *data = chest;
613 return item_str;
614}
615
616static char *decode_extension_label(char *ext, void **data)
617{
618 char *end = ext;
619 while (*end != '\n')
620 end++;
621
622 *end = '\0';
623 *data = strdup(ext)(__extension__ (__builtin_constant_p (ext) && ((size_t
)(const void *)((ext) + 1) - (size_t)(const void *)(ext) == 1
) ? (((const char *) (ext))[0] == '\0' ? (char *) calloc ((size_t
) 1, (size_t) 1) : ({ size_t __len = strlen (ext) + 1; char *
__retval = (char *) malloc (__len); if (__retval != ((void*)0
)) __retval = (char *) memcpy (__retval, ext, __len); __retval
; })) : __strdup (ext)))
;
624 *end = '\n';
625
626 while (*end != '}')
627 end++;
628
629 return end;
630}
631
632static char *decode_extension_dialog(char *ext, void **data)
633{
634 // dialog and label extensions are both a string
635 return decode_extension_label(ext, data);
636}
637
638static char *decode_obstacle_extensions(level *loadlevel, char *data)
639{
640 dynarray_init(&loadlevel->obstacle_extensions, 10, sizeof(struct obstacle_extension));
641
642 if (loadlevel->random_dungeon && !loadlevel->dungeon_generated)
643 return data;
644
645 char *ext_begin = LocateStringInData(data, OBSTACLE_EXTENSIONS_BEGIN_STRING"obstacleextensions");
646 char *ext_end = LocateStringInData(ext_begin, OBSTACLE_EXTENSIONS_END_STRING"/obstacleextensions");
647 *ext_end = '\0';
648
649 while (1) {
650 // Look for the next extension
651 ext_begin = strstr(ext_begin, "idx=");
652 if (!ext_begin)
653 break;
654
655 // Read extension information
656 int index;
657 int type;
658 void *ext_data = NULL((void*)0);
659 sscanf(ext_begin, "idx=%d type=%d", &index, &type);
660
661 // Move to the extension data definition
662 ext_begin = strstr(ext_begin, "data={\n");
663 while (*ext_begin != '\n')
664 ext_begin++;
665 while (isspace(*ext_begin)((*__ctype_b_loc ())[(int) ((*ext_begin))] & (unsigned short
int) _ISspace)
)
666 ext_begin++;
667
668 // Read the extension data
669 switch (type) {
670 case OBSTACLE_EXTENSION_CHEST_ITEMS:
671 ext_begin = decode_extension_chest(ext_begin, &ext_data);
672 break;
673 case OBSTACLE_EXTENSION_LABEL:
674 ext_begin = decode_extension_label(ext_begin, &ext_data);
675 break;
676 case OBSTACLE_EXTENSION_DIALOGFILE:
677 ext_begin = decode_extension_dialog(ext_begin, &ext_data);
678 break;
679 }
680
681 // Add the obstacle extension on the level
682 add_obstacle_extension(loadlevel, &(loadlevel->obstacle_list[index]), type, ext_data);
683 }
684
685 *ext_end = OBSTACLE_EXTENSIONS_END_STRING"/obstacleextensions"[0];
686 return ext_end;
687}
688
689static char *decode_item_section(level *loadlevel, char *data)
690{
691 int i;
692 char Preserved_Letter;
693 int NumberOfItemsInThisLevel;
694 char *ItemPointer;
695 char *ItemsSectionBegin;
696 char *ItemsSectionEnd;
697
698 // First we initialize the items arrays with 'empty' information
699 //
700 for (i = 0; i < MAX_ITEMS_PER_LEVEL300; i++) {
701 init_item(&loadlevel->ItemList[i]);
702 }
703
704 if (loadlevel->random_dungeon && !loadlevel->dungeon_generated)
705 return data;
706
707 // We look for the beginning and end of the items section
708 ItemsSectionBegin = LocateStringInData(data, ITEMS_SECTION_BEGIN_STRING"piteminfolvl");
709 ItemsSectionEnd = LocateStringInData(ItemsSectionBegin, ITEMS_SECTION_END_STRING"/piteminfolvl");
710
711 // We add a terminator at the end of the items section, but ONLY TEMPORARY.
712 // The damage will be restored later!
713 Preserved_Letter = ItemsSectionEnd[0];
714 ItemsSectionEnd[0] = 0;
715 NumberOfItemsInThisLevel = CountStringOccurences(ItemsSectionBegin, ITEM_ID_STRING"it: id=\"");
716 DebugPrintf(1, "\nNumber of items found in this level : %d.", NumberOfItemsInThisLevel);
717
718 // Now we decode all the item information
719 ItemPointer = ItemsSectionBegin;
720 char *NextItemPointer;
721 for (i = 0; i < NumberOfItemsInThisLevel; i++) {
722 if ((ItemPointer = strstr(ItemPointer + 1, ITEM_ID_STRING"it: id=\""))) {
723 NextItemPointer = strstr(ItemPointer + 1, ITEM_ID_STRING"it: id=\"");
724 if (NextItemPointer)
725 NextItemPointer[0] = 0;
726 ReadInOneItem(ItemPointer, ItemsSectionEnd, &(loadlevel->ItemList[i]));
727 loadlevel->ItemList[i].pos.z = loadlevel->levelnum;
728 if (NextItemPointer)
729 NextItemPointer[0] = ITEM_ID_STRING"it: id=\""[0];
730 }
731 }
732
733 // Now we repair the damage done to the loaded level data
734 ItemsSectionEnd[0] = Preserved_Letter;
735 return ItemsSectionEnd;
736}
737
738static char *decode_map(level *loadlevel, char *data)
739{
740 char *map_begin, *map_end;
741 char *this_line;
742 int i;
743
744 if ((map_begin = strstr(data, MAP_BEGIN_STRING"beginning_of_map")) == NULL((void*)0))
745 return NULL((void*)0);
746 map_begin += strlen(MAP_BEGIN_STRING"beginning_of_map") + 1;
747
748 if ((map_end = strstr(data, MAP_END_STRING"/pmapinfolvl")) == NULL((void*)0))
749 return NULL((void*)0);
750
751 /* now scan the map */
752 unsigned int curlinepos = 0;
753 this_line = (char *)MyMalloc(4096);
754
755 /* read MapData */
756 for (i = 0; i < loadlevel->ylen; i++) {
757 int col;
758 int layer;
759 map_tile *Buffer;
760 int tmp;
761
762 /* Select the next line */
763 unsigned int nlpos = 0;
764 memset(this_line, 0, 4096);
765 while (map_begin[curlinepos + nlpos] != '\n')
766 nlpos++;
767 memcpy(this_line, map_begin + curlinepos, nlpos);
768 this_line[nlpos] = '\0';
769 nlpos++;
770
771 /* Decode it */
772 Buffer = MyMalloc((loadlevel->xlen + 10) * sizeof(map_tile));
773 for (col = 0; col < loadlevel->xlen; col++) {
774 // Make sure that all floor layers are always initialized properly.
775 init_map_tile(&Buffer[col]);
776
777 for (layer = 0; layer < loadlevel->floor_layers; layer++) {
778 tmp = strtol(this_line + 4 * (loadlevel->floor_layers * col + layer), NULL((void*)0), 10);
779 Buffer[col].floor_values[layer] = (Uint16) tmp;
780 }
781 }
782
783 // Now the old text pointer can be replaced with a pointer to the
784 // correctly assembled struct...
785 //
786 loadlevel->map[i] = Buffer;
787
788 curlinepos += nlpos;
789 }
790
791 free(this_line);
792 return map_end;
793}
794
795static char *decode_waypoints(level *loadlevel, char *data)
796{
797 char *wp_begin, *wp_end;
798 char *this_line;
799 int nr, x, y, wp_rnd;
800 char *pos;
801
802 // Initialize waypoints
803 dynarray_init(&loadlevel->waypoints, 2, sizeof(struct waypoint));
804
805 if (loadlevel->random_dungeon && !loadlevel->dungeon_generated)
806 return data;
807
808 // Find the beginning and end of the waypoint list
809 if ((wp_begin = strstr(data, WP_BEGIN_STRING"wp")) == NULL((void*)0))
810 return NULL((void*)0);
811 wp_begin += strlen(WP_BEGIN_STRING"wp") + 1;
812
813 if ((wp_end = strstr(data, WP_END_STRING"end_of_level")) == NULL((void*)0))
814 return NULL((void*)0);
815
816 int curlinepos = 0;
817 this_line = (char *)MyMalloc(4096);
818
819 while (1) {
820 /* Select the next line */
821 short int nlpos = 0;
822 memset(this_line, 0, 4096);
823 while (wp_begin[curlinepos + nlpos] != '\n')
824 nlpos++;
825 memcpy(this_line, wp_begin + curlinepos, nlpos);
826 this_line[nlpos] = '\0';
827 nlpos++;
828
829 curlinepos += nlpos;
830
831 if (!strncmp(this_line, wp_end, strlen(WP_END_STRING))(__extension__ (__builtin_constant_p (strlen("end_of_level"))
&& ((__builtin_constant_p (this_line) && strlen
(this_line) < ((size_t) (strlen("end_of_level")))) || (__builtin_constant_p
(wp_end) && strlen (wp_end) < ((size_t) (strlen("end_of_level"
))))) ? __extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(this_line) && __builtin_constant_p (wp_end) &&
(__s1_len = strlen (this_line), __s2_len = strlen (wp_end), (
!((size_t)(const void *)((this_line) + 1) - (size_t)(const void
*)(this_line) == 1) || __s1_len >= 4) && (!((size_t
)(const void *)((wp_end) + 1) - (size_t)(const void *)(wp_end
) == 1) || __s2_len >= 4)) ? __builtin_strcmp (this_line, wp_end
) : (__builtin_constant_p (this_line) && ((size_t)(const
void *)((this_line) + 1) - (size_t)(const void *)(this_line)
== 1) && (__s1_len = strlen (this_line), __s1_len <
4) ? (__builtin_constant_p (wp_end) && ((size_t)(const
void *)((wp_end) + 1) - (size_t)(const void *)(wp_end) == 1)
? __builtin_strcmp (this_line, wp_end) : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(wp_end); int __result = (((const unsigned char *) (const char
*) (this_line))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (this_line))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (this_line))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (this_line))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
(wp_end) && ((size_t)(const void *)((wp_end) + 1) - (
size_t)(const void *)(wp_end) == 1) && (__s2_len = strlen
(wp_end), __s2_len < 4) ? (__builtin_constant_p (this_line
) && ((size_t)(const void *)((this_line) + 1) - (size_t
)(const void *)(this_line) == 1) ? __builtin_strcmp (this_line
, wp_end) : (- (__extension__ ({ const unsigned char *__s2 = (
const unsigned char *) (const char *) (this_line); int __result
= (((const unsigned char *) (const char *) (wp_end))[0] - __s2
[0]); if (__s2_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (wp_end))[1] - __s2
[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (wp_end))[2] - __s2
[2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (wp_end))[3] - __s2
[3]); } } __result; })))) : __builtin_strcmp (this_line, wp_end
)))); }) : strncmp (this_line, wp_end, strlen("end_of_level")
)))
) {
832 break;
833 }
834 wp_rnd = 0;
835 sscanf(this_line, "Nr.=%d \t x=%d \t y=%d rnd=%d", &nr, &x, &y, &wp_rnd);
836
837 // Create a new waypoint
838 waypoint new_wp;
839 new_wp.x = x;
840 new_wp.y = y;
841 new_wp.suppress_random_spawn = wp_rnd;
842
843 // Initalize the connections of the new waypoint
844 dynarray_init(&new_wp.connections, 2, sizeof(int));
845
846 pos = strstr(this_line, CONNECTION_STRING"c: ");
847 if (pos == NULL((void*)0)) {
848 fprintf(stderrstderr, "Unable to find connection string. line is %s, level %i\n", this_line,
849 loadlevel->levelnum);
850 }
851 pos += strlen(CONNECTION_STRING"c: "); // skip connection-string
852 pos += strspn(pos, WHITE_SPACE)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" \t") && ((size_t)(const void *)((" \t") + 1) - (size_t
)(const void *)(" \t") == 1) ? ((__builtin_constant_p (pos) &&
((size_t)(const void *)((pos) + 1) - (size_t)(const void *)(
pos) == 1)) ? __builtin_strspn (pos, " \t") : ((__a0 = ((const
char *) (" \t"))[0], __a0 == '\0') ? ((void) (pos), (size_t)
0) : ((__a1 = ((const char *) (" \t"))[1], __a1 == '\0') ? __strspn_c1
(pos, __a0) : ((__a2 = ((const char *) (" \t"))[2], __a2 == '\0'
) ? __strspn_c2 (pos, __a0, __a1) : (((const char *) (" \t"))
[3] == '\0' ? __strspn_c3 (pos, __a0, __a1, __a2) : __builtin_strspn
(pos, " \t")))))) : __builtin_strspn (pos, " \t")); })
; // skip initial whitespace
853
854 while (1) {
855 if (*pos == '\0')
856 break;
857 int connection;
858 int res = sscanf(pos, "%d", &connection);
859 if ((connection == -1) || (res == 0) || (res == EOF(-1)))
860 break;
861
862 // Add the connection on this waypoint
863 dynarray_add(&new_wp.connections, &connection, sizeof(int));
864
865 pos += strcspn(pos, WHITE_SPACE)__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
(" \t") && ((size_t)(const void *)((" \t") + 1) - (size_t
)(const void *)(" \t") == 1) ? ((__builtin_constant_p (pos) &&
((size_t)(const void *)((pos) + 1) - (size_t)(const void *)(
pos) == 1)) ? __builtin_strcspn (pos, " \t") : ((__r0 = ((const
char *) (" \t"))[0], __r0 == '\0') ? strlen (pos) : ((__r1 =
((const char *) (" \t"))[1], __r1 == '\0') ? __strcspn_c1 (pos
, __r0) : ((__r2 = ((const char *) (" \t"))[2], __r2 == '\0')
? __strcspn_c2 (pos, __r0, __r1) : (((const char *) (" \t"))
[3] == '\0' ? __strcspn_c3 (pos, __r0, __r1, __r2) : __builtin_strcspn
(pos, " \t")))))) : __builtin_strcspn (pos, " \t")); })
; // skip last token
866 pos += strspn(pos, WHITE_SPACE)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" \t") && ((size_t)(const void *)((" \t") + 1) - (size_t
)(const void *)(" \t") == 1) ? ((__builtin_constant_p (pos) &&
((size_t)(const void *)((pos) + 1) - (size_t)(const void *)(
pos) == 1)) ? __builtin_strspn (pos, " \t") : ((__a0 = ((const
char *) (" \t"))[0], __a0 == '\0') ? ((void) (pos), (size_t)
0) : ((__a1 = ((const char *) (" \t"))[1], __a1 == '\0') ? __strspn_c1
(pos, __a0) : ((__a2 = ((const char *) (" \t"))[2], __a2 == '\0'
) ? __strspn_c2 (pos, __a0, __a1) : (((const char *) (" \t"))
[3] == '\0' ? __strspn_c3 (pos, __a0, __a1, __a2) : __builtin_strspn
(pos, " \t")))))) : __builtin_strspn (pos, " \t")); })
; // skip initial whitespace for next one
867 }
868
869 // Add the waypoint on the level
870 dynarray_add(&loadlevel->waypoints, &new_wp, sizeof(struct waypoint));
871 }
872
873 free(this_line);
874 return wp_end;
875}
876
877/**
878 * The smash_obstacle function uses this function as a subfunction to
879 * check for exploding obstacles glued to one specific map square. Of
880 * course also the player number (or -1 in case of no check/bullet hit)
881 * must be supplied so as to be able to suppress hits through walls or
882 * the like.
883 */
884static int smash_obstacles_only_on_tile(float x, float y, int level, int map_x, int map_y)
885{
886 Level BoxLevel = curShip.AllLevels[level];
887 int i;
888 int target_idx;
889 obstacle *target_obstacle;
890 int smashed_something = FALSE(0);
891 moderately_finepoint blast_start_pos;
892
893 // First some security checks against touching the outsides of the map...
894 //
895 if (!pos_inside_level(map_x, map_y, BoxLevel))
896 return (FALSE(0));
897
898 // We check all the obstacles on this square if they are maybe destructible
899 // and if they are, we destruct them, haha
900 //
901 for (i = 0; i < BoxLevel->map[map_y][map_x].glued_obstacles.size; i++) {
902 // First we see if there is something glued to this map tile at all.
903 //
904 target_idx = ((int *)(BoxLevel->map[map_y][map_x].glued_obstacles.arr))[i];
905
906 target_obstacle = &(BoxLevel->obstacle_list[target_idx]);
907
908 obstacle_spec *obstacle_spec = get_obstacle_spec(target_obstacle->type);
909 if (!(obstacle_spec->flags & IS_SMASHABLE))
910 continue;
911
912 // Now we check if the item really was close enough to the strike target.
913 // A range of 0.5 should do.
914 //
915 if (fabsf(x - target_obstacle->pos.x) > 0.4)
916 continue;
917 if (fabsf(y - target_obstacle->pos.y) > 0.4)
918 continue;
919
920 colldet_filter filter = FlyableExceptIdPassFilter;
921 filter.data = &target_idx;
922 gps smash_pos = { x, y, level };
923 gps vsmash_pos;
924 update_virtual_position(&vsmash_pos, &smash_pos, Me.pos.z);
925 if (vsmash_pos.x == -1)
926 continue;
927 if (!DirectLineColldet(vsmash_pos.x, vsmash_pos.y, Me.pos.x, Me.pos.y, Me.pos.z, &filter)) {
928 continue;
929 }
930
931 DebugPrintf(1, "\nObject smashed at: (%f/%f) by hit/explosion at (%f/%f).",
932 target_obstacle->pos.x, target_obstacle->pos.y, x, y);
933
934 smashed_something = TRUE(1);
935
936 // Since the obstacle is destroyed, we start a blast at it's position.
937 // But here a WARNING WARNING WARNING! is due! We must not start the
938 // blast before the obstacle is removed, because the blast will again
939 // cause this very obstacle removal function, so we need to be careful
940 // so as not to incite endless recursion. We memorize the position for
941 // later, then delete the obstacle, then we start the blast.
942 //
943 blast_start_pos.x = target_obstacle->pos.x;
944 blast_start_pos.y = target_obstacle->pos.y;
945
946 int obstacle_drops_treasure
947 = obstacle_spec->flags & DROPS_RANDOM_TREASURE;
948
949 // Let the automap know that we've updated things
950 update_obstacle_automap(level, target_obstacle);
951
952 // Now we really smash the obstacle, i.e. we can set it's type to the debris that has
953 // been configured for this obstacle type. In if there is nothing configured (i.e. -1 set)
954 // then we'll just delete the obstacle in question entirely. For this we got a standard function to
955 // safely do it and not make some errors into the glue structure or obstacles lists...
956 //
957 if (obstacle_spec->result_type_after_smashing_once == (-1)) {
958 del_obstacle(target_obstacle);
959 } else {
960 target_obstacle->type = obstacle_spec->result_type_after_smashing_once;
961 }
962
963 // Drop items after destroying the obstacle, in order to avoid collisions
964 if (obstacle_drops_treasure)
965 DropRandomItem(level, target_obstacle->pos.x, target_obstacle->pos.y, BoxLevel->drop_class, FALSE(0));
966
967 // Now that the obstacle is removed AND ONLY NOW that the obstacle is
968 // removed, we may start a blast at this position. Otherwise we would
969 // run into trouble, see the warning further above.
970 StartBlast(blast_start_pos.x, blast_start_pos.y,
971 level, obstacle_spec->blast_type, 0.0, FACTION_SELF, obstacle_spec->smashed_sound);
972 }
973
974 return smashed_something;
975}
976
977/**
978 * When a destructible type of obstacle gets hit, e.g. by a blast
979 * exploding on the tile or a melee hit on the same floor tile, then some
980 * of the obstacles (like barrel or crates) might explode, sometimes
981 * leaving some treasure behind.
982 *
983 */
984int smash_obstacle(float x, float y, int level)
985{
986 int map_x, map_y;
987 int smash_x, smash_y;
988 int smashed_something = FALSE(0);
989
990 map_x = (int)rintf(x);
991 map_y = (int)rintf(y);
992
993 for (smash_y = map_y - 1; smash_y < map_y + 2; smash_y++) {
994 for (smash_x = map_x - 1; smash_x < map_x + 2; smash_x++) {
995 if (smash_obstacles_only_on_tile(x, y, level, smash_x, smash_y))
996 smashed_something = TRUE(1);
997 }
998 }
999
1000 return (smashed_something);
1001
1002} // int smash_obstacle ( float x , float y );
1003
1004/**
1005 * This function returns the map brick code of the tile that occupies the
1006 * given position in the given layer.
1007 * Floor layers are indexed from 0 to lvl->floor_layers - 1. The lowest
1008 * floor layer is #0. Every map has at least one layer.
1009 */
1010Uint16 get_map_brick(level *lvl, float x, float y, int layer)
1011{
1012 Uint16 BrickWanted;
1013 int RoundX, RoundY;
1014
1015 gps vpos = { x, y, lvl->levelnum };
1016 gps rpos;
1017 if (!resolve_virtual_position(&rpos, &vpos)) {
1018 return ISO_FLOOR_EMPTY;
1019 }
1020 RoundX = (int)rintf(rpos.x);
1021 RoundY = (int)rintf(rpos.y);
1022
1023 BrickWanted = curShip.AllLevels[rpos.z]->map[RoundY][RoundX].floor_values[layer];
1024
1025 if (BrickWanted >= underlay_floor_tiles.size) {
1026 if (BrickWanted < MAX_UNDERLAY_FLOOR_TILES500 || (BrickWanted - MAX_UNDERLAY_FLOOR_TILES500) >= overlay_floor_tiles.size) {
1027 error_message(__FUNCTION__, "Level %d at %d %d in %d layer uses an unknown floor tile: %d.", PLEASE_INFORM,
1028 lvl->levelnum, RoundX, RoundY, layer, BrickWanted);
1029 return ISO_FLOOR_EMPTY;
1030 }
1031 }
1032
1033 return BrickWanted;
1034}
1035
1036/**
1037 * This functions reads the specification for a level
1038 * taken from the ship file.
1039 *
1040 * @return pointer to the level
1041 * @param text buffer containing level description
1042 */
1043static level *decode_level(char **buffer)
1044{
1045 level *loadlevel;
1046 char *data = *buffer;
1047
1048 loadlevel = (level *)MyMalloc(sizeof(level));
1049
1050 if (decode_header(loadlevel, data)) {
1051 error_message(__FUNCTION__, "Unable to decode level header!", PLEASE_INFORM | IS_FATAL);
1052 }
1053
1054 // The order of sections in the file has to match this.
1055 data = decode_map(loadlevel, data);
1056 if (!data) {
1057 error_message(__FUNCTION__, "Unable to decode the map for level %d", PLEASE_INFORM | IS_FATAL, loadlevel->levelnum);
1058 }
1059 data = decode_obstacles(loadlevel, data);
1060 data = decode_map_labels(loadlevel, data);
1061 data = decode_item_section(loadlevel, data);
1062 data = decode_obstacle_extensions(loadlevel, data);
1063 data = decode_waypoints(loadlevel, data);
1064
1065 // Point the buffer to the end of this level, so the next level can be read
1066 *buffer = data;
1067 return loadlevel;
1068}
1069
1070
1071/**
1072 * Call the random dungeon generator on this level if this level is marked
1073 * as being randomly generated and if we are not in the "leveleditor" mode
1074 * in which case random dungeons must not be considered as generated (so that
1075 * they will be exported as being non-generated random levels).
1076 */
1077static void generate_dungeon_if_needed(level *l)
1078{
1079 if (!l->random_dungeon || l->dungeon_generated) {
1080 return;
1081 }
1082
1083 // Generate random dungeon now
1084 set_dungeon_output(l);
1085 generate_dungeon(l->xlen, l->ylen, l->random_dungeon, l->teleport_pair);
1086 l->dungeon_generated = 1;
1087}
1088
1089/**
1090 * This function loads the data for a whole ship
1091 * Possible return values are : OK and ERR
1092 */
1093int LoadShip(char *filename, int compressed)
1094{
1095 char *ShipData = NULL((void*)0);
1096 FILE *ShipFile;
1097 int i;
1098
1099#define END_OF_SHIP_DATA_STRING"*** End of Ship Data ***" "*** End of Ship Data ***"
1100
1101 // Free existing level data
1102 for (i = 0; i < MAX_LEVELS100; i++) {
1103 if (level_exists(i)) {
1104 level *lvl = curShip.AllLevels[i];
1105 int row = 0;
1106 int col = 0;
1107
1108 // Map tiles
1109 for (row = 0; row < lvl->ylen; row++) {
1110 if (lvl->map[row]) {
1111 for (col = 0; col < lvl->xlen; col++) {
1112 dynarray_free(&lvl->map[row][col].glued_obstacles);
1113 }
1114
1115 free(curShip.AllLevels[i]->map[row]);
1116 curShip.AllLevels[i]->map[row] = NULL((void*)0);
1117 }
1118 }
1119
1120 // Level strings
1121 if (lvl->Levelname) {
1122 free(lvl->Levelname);
1123 lvl->Levelname = NULL((void*)0);
1124 }
1125
1126 if (lvl->Background_Song_Name) {
1127 free(lvl->Background_Song_Name);
1128 lvl->Background_Song_Name = NULL((void*)0);
1129 }
1130
1131 // Waypoints
1132 int w;
1133 for (w = 0; w < lvl->waypoints.size; w++) {
1134 struct waypoint *wpts = lvl->waypoints.arr;
1135 dynarray_free(&wpts[w].connections);
1136 }
1137
1138 dynarray_free(&lvl->waypoints);
1139
1140 // Obstacle extensions
1141 free_obstacle_extensions(lvl);
1142
1143 // Map labels
1144 free_map_labels(lvl);
1145
1146 // Random droids
1147 lvl->random_droids.types_size = 0;
1148
1149 free(lvl);
1150 curShip.AllLevels[i] = NULL((void*)0);
1151
1152 }
1153 }
1154
1155 // Read the whole ship-data to memory
1156 //
1157 ShipFile = fopen(filename, "rb");
1158 if (!ShipFile) {
1159 error_message(__FUNCTION__, "Unable to open ship file %s: %s.", PLEASE_INFORM | IS_FATAL, filename, strerror(errno(*__errno_location ())));
1160 }
1161
1162 if (compressed) {
1163 if (inflate_stream(ShipFile, (unsigned char **)&ShipData, NULL((void*)0))) {
1164 error_message(__FUNCTION__, "Unable to decompress ship file %s.", PLEASE_INFORM | IS_FATAL, filename);
1165 }
1166 } else {
1167 int length = FS_filelength(ShipFile);
1168 ShipData = malloc(length + 1);
1169 if (!fread(ShipData, length, 1, ShipFile))
1170 error_message(__FUNCTION__, "Reading ship file %s failed with fread().", PLEASE_INFORM | IS_FATAL, filename);
1171 ShipData[length] = 0;
1172 }
1173
1174 fclose(ShipFile);
1175
1176 // Read each level
1177 int done = 0;
1178 char *pos = ShipData;
1179 while (!done) {
1180 level *this_level = decode_level(&pos);
1181 int this_levelnum = this_level->levelnum;
1182
1183 if (this_levelnum >= MAX_LEVELS100)
1184 error_message(__FUNCTION__, "One levelnumber in savegame (%d) is bigger than the maximum allowed (%d).",
1185 PLEASE_INFORM | IS_FATAL, this_levelnum, MAX_LEVELS100 - 1);
1186 if (level_exists(this_levelnum))
1187 error_message(__FUNCTION__, "Two levels with same levelnumber (%d) found in the savegame.",
1188 PLEASE_INFORM | IS_FATAL, this_levelnum);
1189
1190 curShip.AllLevels[this_levelnum] = this_level;
1191 curShip.num_levels = this_levelnum + 1;
1192
1193 generate_dungeon_if_needed(this_level);
1194
1195 // Move to the level termination marker
1196 pos = strstr(pos, LEVEL_END_STRING"end_of_level");
1197 pos += strlen(LEVEL_END_STRING"end_of_level") + 1;
1198
1199 // Check if there is another level
1200 if (!strstr(pos, LEVEL_HEADER_LEVELNUMBER"Levelnumber:")) {
1201 done = 1;
1202 }
1203 }
1204
1205 // Check for consistency of levels
1206 int check_level = curShip.num_levels;
1207 while (check_level--) {
1208 if (!level_exists(check_level)) {
1209 error_message(__FUNCTION__, "Level number %d should exist but is NULL.", PLEASE_INFORM | IS_FATAL, check_level);
1210 }
1211 }
1212
1213 // Now that all the information has been copied, we can free the loaded data
1214 // again.
1215 //
1216 free(ShipData);
1217
1218 // Compute the gps transform acceleration data
1219 gps_transform_map_dirty_flag = TRUE(1);
1220 gps_transform_map_init();
1221
1222 return OK0;
1223
1224}; // int LoadShip ( ... )
1225
1226/**
1227 * This should write the obstacle information in human-readable form into
1228 * a buffer.
1229 */
1230static void encode_obstacles_of_this_level(struct auto_string *shipstr, level *Lev)
1231{
1232 int i;
1233 autostr_append(shipstr, "%s\n", OBSTACLE_DATA_BEGIN_STRING"obsdata");
1234
1235 defrag_obstacle_array(Lev);
1236
1237 for (i = 0; i < MAX_OBSTACLES_ON_MAP4000; i++) {
1238 if (Lev->obstacle_list[i].type == (-1))
1239 continue;
1240
1241 autostr_append(shipstr, "%s%d %s%3.2f %s%3.2f\n", OBSTACLE_TYPE_STRING"t", Lev->obstacle_list[i].type,
1242 OBSTACLE_X_POSITION_STRING"x", Lev->obstacle_list[i].pos.x, OBSTACLE_Y_POSITION_STRING"y",
1243 Lev->obstacle_list[i].pos.y);
1244 }
1245
1246 autostr_append(shipstr, "%s\n", OBSTACLE_DATA_END_STRING"/obsdata");
1247}
1248
1249static void encode_map_labels(struct auto_string *shipstr, level *lvl)
1250{
1251 int i;
1252 struct map_label *map_label;
1253
1254 autostr_append(shipstr, "%s\n", MAP_LABEL_BEGIN_STRING"plabelinfolvl");
1255
1256 for (i = 0; i < lvl->map_labels.size; i++) {
1257 // Get the map label
1258 map_label = &ACCESS_MAP_LABEL(lvl->map_labels, i)((struct map_label *)(lvl->map_labels.arr))[i];
1259
1260 // Encode map label
1261 autostr_append(shipstr, "%s%d %s%d %s%s\"\n", X_POSITION_OF_LABEL_STRING"x=", map_label->pos.x, Y_POSITION_OF_LABEL_STRING"y=",
1262 map_label->pos.y, LABEL_ITSELF_ANNOUNCE_STRING"name=\"", map_label->label_name);
1263 }
1264
1265 autostr_append(shipstr, "%s\n", MAP_LABEL_END_STRING"/plabelinfolvl");
1266}
1267
1268/**
1269 *
1270 *
1271 */
1272static void WriteOutOneItem(struct auto_string *shipstr, item *ItemToWriteOut)
1273{
1274
1275 autostr_append(shipstr, "%s%s\" %s%f %s%f ", ITEM_ID_STRING"it: id=\"", ItemMap[ItemToWriteOut->type].id,
1276 ITEM_POS_X_STRING" X=", ItemToWriteOut->pos.x, ITEM_POS_Y_STRING" Y=", ItemToWriteOut->pos.y);
1277
1278 if (ItemToWriteOut->armor_class) {
1279 autostr_append(shipstr, "%s%d ", ITEM_ARMOR_CLASS_BASE_STRING" AC=", ItemToWriteOut->armor_class);
1280 }
1281
1282 autostr_append(shipstr, "%s%d %s%f %s%d %s%d",
1283 ITEM_MAX_DURABILITY_STRING" MDur=", ItemToWriteOut->max_durability,
1284 ITEM_CUR_DURABILITY_STRING" CDur=", ItemToWriteOut->current_durability,
1285 ITEM_AMMO_CLIP_STRING" AClip=", ItemToWriteOut->ammo_clip,
1286 ITEM_MULTIPLICITY_STRING" Multi=", ItemToWriteOut->multiplicity);
1287
1288 // Write the sockets of the item. The bonuses can be reconstructed from
1289 // these easily so we don't need to write them at all.
1290 if (ItemToWriteOut->upgrade_sockets.size) {
1291 int i;
1292 autostr_append(shipstr, "%s%d ", ITEM_SOCKETS_SIZE_STRING" Sockets=", ItemToWriteOut->upgrade_sockets.size);
1293 for (i = 0; i < ItemToWriteOut->upgrade_sockets.size; i++) {
1294 struct upgrade_socket *socket = &ItemToWriteOut->upgrade_sockets.arr[i];
1295 autostr_append(shipstr, "%s%d=%d ", ITEM_SOCKET_TYPE_STRING"SocketType", i, socket->type);
1296 if (socket->addon) {
1297 autostr_append(shipstr, "%s%d=%s\" ", ITEM_SOCKET_ADDON_STRING"SocketAddon", i, socket->addon);
1298 }
1299 }
1300 }
1301
1302 autostr_append(shipstr, "\n");
1303}
1304
1305static void EncodeItemSectionOfThisLevel(struct auto_string *shipstr, level *Lev)
1306{
1307 int i;
1308
1309 autostr_append(shipstr, "%s\n", ITEMS_SECTION_BEGIN_STRING"piteminfolvl");
1310
1311 // Now we write out the bulk of items infos
1312 //
1313 for (i = 0; i < MAX_ITEMS_PER_LEVEL300; i++) {
1314 if (Lev->ItemList[i].type == (-1))
1315 continue;
1316
1317 WriteOutOneItem(shipstr, &(Lev->ItemList[i]));
1318
1319 }
1320
1321 autostr_append(shipstr, "%s\n", ITEMS_SECTION_END_STRING"/piteminfolvl");
1322}
1323
1324static void encode_extension_chest(struct auto_string *shipstr, struct obstacle_extension *ext)
1325{
1326 int i;
1327 struct dynarray *da = ext->data;
1328
1329 for (i = 0; i < da->size; i++) {
1330 item *it = &((item *)da->arr)[i];
1331 if (it->type == -1)
1332 continue;
1333
1334 autostr_append(shipstr, "\t");
1335 WriteOutOneItem(shipstr, it);
1336 }
1337}
1338
1339static void encode_extension_label(struct auto_string *shipstr, struct obstacle_extension *ext)
1340{
1341 const char *label = ext->data;
1342
1343 autostr_append(shipstr, "\t%s\n", label);
1344}
1345
1346static void encode_extension_dialog(struct auto_string *shipstr, struct obstacle_extension *ext)
1347{
1348 // dialog and label extensions are both a string
1349 encode_extension_label(shipstr, ext);
1350}
1351
1352static void encode_obstacle_extensions(struct auto_string *shipstr, level *l)
1353{
1354 int i;
1355 autostr_append(shipstr, "%s\n", OBSTACLE_EXTENSIONS_BEGIN_STRING"obstacleextensions");
1356 for (i = 0; i < l->obstacle_extensions.size; i++) {
1357 struct obstacle_extension *ext = &ACCESS_OBSTACLE_EXTENSION(l->obstacle_extensions, i)((struct obstacle_extension *)(l->obstacle_extensions.arr)
)[i]
;
1358
1359 if (ext->type == 0)
1360 continue;
1361
1362 autostr_append(shipstr, "idx=%d type=%d data={\n", get_obstacle_index(l, ext->obs), ext->type);
1363
1364 switch ((enum obstacle_extension_type)(ext->type)) {
1365 case OBSTACLE_EXTENSION_CHEST_ITEMS:
1366 encode_extension_chest(shipstr, ext);
1367 break;
1368 case OBSTACLE_EXTENSION_LABEL:
1369 encode_extension_label(shipstr, ext);
1370 break;
1371 case OBSTACLE_EXTENSION_DIALOGFILE:
1372 encode_extension_dialog(shipstr, ext);
1373 break;
1374 }
1375
1376 autostr_append(shipstr, "}\n");
1377 }
1378 autostr_append(shipstr, "%s\n", OBSTACLE_EXTENSIONS_END_STRING"/obstacleextensions");
1379}
1380
1381static void encode_waypoints(struct auto_string *shipstr, level *lvl)
1382{
1383 waypoint *wpts = lvl->waypoints.arr;
1384 int *connections;
1385 int i, j;
1386
1387 autostr_append(shipstr, "%s\n", WP_BEGIN_STRING"wp");
1388
1389 for (i = 0; i < lvl->waypoints.size; i++) {
1390 // Encode the waypoint
1391 autostr_append(shipstr, "Nr.=%3d x=%4d y=%4d rnd=%1d\t %s", i, wpts[i].x, wpts[i].y, wpts[i].suppress_random_spawn, CONNECTION_STRING"c: ");
1392
1393 // Get the connections of the waypoint
1394 connections = wpts[i].connections.arr;
1395
1396 for (j = 0; j < wpts[i].connections.size; j++) {
1397 // Encode the connection of the waypoint
1398 autostr_append(shipstr, " %3d", connections[j]);
1399 }
1400
1401 autostr_append(shipstr, "\n");
1402 }
1403}
1404
1405/**
1406 * This function translates map data into human readable map code, that
1407 * can later be written to the map file on disk.
1408 */
1409static void TranslateToHumanReadable(struct auto_string *str, map_tile * MapInfo, int LineLength, int layers)
1410{
1411 int col;
1412 int layer;
1413
1414 for (col = 0; col < LineLength; col++) {
1415 for (layer = 0; layer < layers; layer++)
1416 autostr_append(str, "%3d ", MapInfo[col].floor_values[layer]);
1417 }
1418
1419 autostr_append(str, "\n");
1420}
1421
1422/**
1423 * This function generates savable text out of the current level data
1424 *
1425 * If reset_random_levels is TRUE, then the random levels are saved
1426 * "un-generated" (typical usage: levels.dat).
1427 *
1428 */
1429static void encode_level_for_saving(struct auto_string *shipstr, level *lvl, int reset_random_levels)
1430{
1431 int i;
1432 int xlen = lvl->xlen, ylen = lvl->ylen;
1433
1434 // Write level header
1435 autostr_append(shipstr, "%s %d\n\
1436xlen of this level: %d\n\
1437ylen of this level: %d\n\
1438floor layers: %d\n\
1439light radius bonus of this level: %d\n\
1440minimal light on this level: %d\n\
1441infinite_running_on_this_level: %d\n\
1442random dungeon: %d\n\
1443teleport pair: %d\n\
1444dungeon generated: %d\n\
1445environmental flags: %d\n\
1446item drop class: %d\n\
1447jump target north: %d\n\
1448jump target south: %d\n\
1449jump target east: %d\n\
1450jump target west: %d\n", LEVEL_HEADER_LEVELNUMBER"Levelnumber:", lvl->levelnum,
1451 lvl->xlen, lvl->ylen, lvl->floor_layers,
1452 lvl->light_bonus, lvl->minimum_light_value,
1453 lvl->infinite_running_on_this_level,
1454 lvl->random_dungeon,
1455 lvl->teleport_pair,
1456 (reset_random_levels && lvl->random_dungeon) ? 0 : lvl->dungeon_generated,
1457 lvl->flags,
1458 lvl->drop_class,
1459 lvl->jump_target_north,
1460 lvl->jump_target_south,
1461 lvl->jump_target_east,
1462 lvl->jump_target_west);
1463
1464 autostr_append(shipstr, "number of random droids: %d\n", lvl->random_droids.nr);
1465 autostr_append(shipstr, "random droid types: ");
1466
1467 for (i = 0; i < lvl->random_droids.types_size; i++) {
1468 if (i)
1469 autostr_append(shipstr, ", ");
1470 autostr_append(shipstr, "%s", Droidmap[lvl->random_droids.types[i]].droidname);
1471 }
1472
1473 autostr_append(shipstr, "\n%s%s\"\n%s%s\n", LEVEL_NAME_STRING"Name of this level=_\"", lvl->Levelname,
1474 BACKGROUND_SONG_NAME_STRING"BgSong=", lvl->Background_Song_Name);
1475
1476 autostr_append(shipstr, "%s\n", MAP_BEGIN_STRING"beginning_of_map");
1477
1478 // Now in the loop each line of map data should be saved as a whole
1479 for (i = 0; i < ylen; i++) {
1480 if (!(reset_random_levels && lvl->random_dungeon)) {
1481 TranslateToHumanReadable(shipstr, lvl->map[i], xlen, lvl->floor_layers);
1482 } else {
1483 int j = xlen;
1484 while (j--) {
1485 autostr_append(shipstr, " 0 ");
1486 }
1487 autostr_append(shipstr, "\n");
1488 }
1489 }
1490
1491 autostr_append(shipstr, "%s\n", MAP_END_STRING"/pmapinfolvl");
1492
1493 if (!(reset_random_levels && lvl->random_dungeon)) {
1494 encode_obstacles_of_this_level(shipstr, lvl);
1495
1496 encode_map_labels(shipstr, lvl);
1497
1498 EncodeItemSectionOfThisLevel(shipstr, lvl);
1499
1500 encode_obstacle_extensions(shipstr, lvl);
1501
1502 encode_waypoints(shipstr, lvl);
1503 }
1504
1505 autostr_append(shipstr, "%s\n----------------------------------------------------------------------\n",
1506 LEVEL_END_STRING"end_of_level");
1507}
1508
1509/**
1510 * This function should save a whole ship to disk to the given filename.
1511 * It is not only used by the level editor, but also by the function that
1512 * saves whole games.
1513 *
1514 * If reset_random_levels is TRUE, then the random levels are saved
1515 * "un-generated" (typical usage: levels.dat).
1516 * @return 0 if OK, 1 on error
1517 */
1518int SaveShip(const char *filename, int reset_random_levels, int compress)
1519{
1520 int i;
1521 FILE *ShipFile = NULL((void*)0);
1522 struct auto_string *shipstr;
1523
1524 // Open the ship file
1525 if ((ShipFile = fopen(filename, "wb")) == NULL((void*)0)) {
1526 error_message(__FUNCTION__, "Error opening ship file %s for writing.", NO_REPORT, filename);
1527 return ERR-1;
1528 }
1529
1530 shipstr = alloc_autostr(1048576);
1531 autostr_printf(shipstr, "\n");
1532
1533 // Save all the levels
1534 for (i = 0; i < curShip.num_levels; i++) {
1535 if (level_exists(i)) {
1536 encode_level_for_saving(shipstr, curShip.AllLevels[i], reset_random_levels);
1537 }
1538 }
1539
1540 autostr_append(shipstr, "%s\n\n", END_OF_SHIP_DATA_STRING"*** End of Ship Data ***");
1541
1542 if (compress) {
1543 deflate_to_stream((unsigned char *)shipstr->value, shipstr->length, ShipFile);
1544 } else {
1545 if (fwrite((unsigned char *)shipstr->value, shipstr->length, 1, ShipFile) != 1) {
1546 error_message(__FUNCTION__, "Error writing ship file %s.", PLEASE_INFORM, filename);
1547 fclose(ShipFile);
1548 free_autostr(shipstr);
1549 return ERR-1;
1550 }
1551 }
1552
1553 if (fclose(ShipFile) == EOF(-1)) {
1554 error_message(__FUNCTION__, "Closing of ship file failed!", PLEASE_INFORM);
1555 free_autostr(shipstr);
1556 return ERR-1;
1557 }
1558
1559 free_autostr(shipstr);
1560 return OK0;
1561}
1562
1563int save_special_forces(const char *filename)
1564{
1565 FILE *s_forces_file = NULL((void*)0);
1566 struct auto_string *s_forces_str;
1567 level *lvl;
1568 int i;
1569
1570 if ((s_forces_file = fopen(filename, "wb")) == NULL((void*)0)) {
1571 error_message(__FUNCTION__, "Error opening Special Forces file %s for writing.", NO_REPORT, filename);
1572 return ERR-1;
1573 }
1574
1575 s_forces_str = alloc_autostr(64);
1576
1577 for (i = 0; i < curShip.num_levels; i++) {
1578 if (!level_exists(i))
1579 continue;
1580
1581 lvl = curShip.AllLevels[i];
1582 autostr_append(s_forces_str, "** Beginning of new Level **\n");
1583 autostr_append(s_forces_str, "Level=%d\n\n", lvl->levelnum);
1584
1585 enemy *en;
1586
1587 list_for_each_entry_reverse(en, &level_bots_head[lvl->levelnum], level_list)for (en = ({ const typeof( ((typeof(*en) *)0)->level_list )
*__mptr = ((&level_bots_head[lvl->levelnum])->prev
); (typeof(*en) *)( (char *)__mptr - __builtin_offsetof(typeof
(*en), level_list) );}); &en->level_list != (&level_bots_head
[lvl->levelnum]); en = ({ const typeof( ((typeof(*en) *)0)
->level_list ) *__mptr = (en->level_list.prev); (typeof
(*en) *)( (char *)__mptr - __builtin_offsetof(typeof(*en), level_list
) );}))
{
1588 if (!en->SpecialForce)
1589 continue;
1590
1591 autostr_append(s_forces_str, "T=%s: ", Droidmap[en->type].droidname);
1592 autostr_append(s_forces_str, "PosX=%d PosY=%d ", (int)en->pos.x, (int)en->pos.y);
1593 autostr_append(s_forces_str, "Faction=\"%s\" ", get_faction_from_id(en->faction));
1594 autostr_append(s_forces_str, "UseDialog=\"%s\" ", en->dialog_section_name);
1595
1596 autostr_append(s_forces_str, "ShortLabel=_\"%s\" ", en->short_description_text);
1597 autostr_append(s_forces_str, "Marker=%d ", en->marker);
1598 autostr_append(s_forces_str, "RushTux=%d ", en->will_rush_tux);
1599
1600 autostr_append(s_forces_str, "Fixed=%hi ", en->CompletelyFixed);
1601 autostr_append(s_forces_str, "DropItemId=\"%s\" ",
1602 (en->on_death_drop_item_code == -1) ? "none" : ItemMap[en->on_death_drop_item_code].id);
1603 autostr_append(s_forces_str, "MaxDistanceToHome=%hd\n", en->max_distance_to_home);
1604 }
1605
1606 autostr_append(s_forces_str, "** End of this levels Special Forces data **\n");
1607 autostr_append(s_forces_str, "---------------------------------------------------------\n");
1608 }
1609
1610 autostr_append(s_forces_str, "*** End of Droid Data ***");
1611
1612 if (fwrite((unsigned char *)s_forces_str->value, s_forces_str->length, 1, s_forces_file) != 1) {
1613 error_message(__FUNCTION__, "Error writing SpecialForces file %s.", PLEASE_INFORM, filename);
1614 fclose(s_forces_file);
1615 goto out;
1616 }
1617
1618 if (fclose(s_forces_file) == EOF(-1)) {
1619 error_message(__FUNCTION__, "Closing of Special Forces file failed!", PLEASE_INFORM);
1620 goto out;
1621 }
1622
1623out: free_autostr(s_forces_str);
1624 return OK0;
1625}
1626
1627/**
1628 * This function is used to calculate the number of the droids on the
1629 * ship, which is a global variable.
1630 */
1631void CountNumberOfDroidsOnShip(void)
1632{
1633 Number_Of_Droids_On_Ship = 0;
1634
1635 enemy *erot;
1636 BROWSE_ALIVE_BOTS(erot)for (erot = ({ const typeof( ((typeof(*erot) *)0)->global_list
) *__mptr = ((&alive_bots_head)->next); (typeof(*erot
) *)( (char *)__mptr - __builtin_offsetof(typeof(*erot), global_list
) );}); &erot->global_list != (&alive_bots_head); erot
= ({ const typeof( ((typeof(*erot) *)0)->global_list ) *__mptr
= (erot->global_list.next); (typeof(*erot) *)( (char *)__mptr
- __builtin_offsetof(typeof(*erot), global_list) );}))
{
1637 Number_Of_Droids_On_Ship++;
1638 }
1639
1640 BROWSE_DEAD_BOTS(erot)for (erot = ({ const typeof( ((typeof(*erot) *)0)->global_list
) *__mptr = ((&dead_bots_head)->next); (typeof(*erot)
*)( (char *)__mptr - __builtin_offsetof(typeof(*erot), global_list
) );}); &erot->global_list != (&dead_bots_head); erot
= ({ const typeof( ((typeof(*erot) *)0)->global_list ) *__mptr
= (erot->global_list.next); (typeof(*erot) *)( (char *)__mptr
- __builtin_offsetof(typeof(*erot), global_list) );}))
{
1641 Number_Of_Droids_On_Ship++;
1642 }
1643
1644}; // void CountNumberOfDroidsOnShip ( void )
1645
1646/* -----------------------------------------------------------------
1647 * This function initializes all enemies, which means that enemies are
1648 * filled in into the enemy list according to the enemies types that
1649 * are to be found on each deck.
1650 * ----------------------------------------------------------------- */
1651int GetCrew(char *filename)
1652{
1653 char fpath[PATH_MAX4096];
1654 char *MainDroidsFilePointer;
1655 char *DroidSectionPointer;
1656 char *EndOfThisDroidSectionPointer;
1657
1658#define START_OF_DROID_DATA_STRING"*** Beginning of Droid Data ***" "*** Beginning of Droid Data ***"
1659#define END_OF_DROID_DATA_STRING"*** End of Droid Data ***" "*** End of Droid Data ***"
1660#define DROIDS_LEVEL_DESCRIPTION_START_STRING"** Beginning of new Level **" "** Beginning of new Level **"
1661#define DROIDS_LEVEL_DESCRIPTION_END_STRING"** End of this levels Special Forces data **" "** End of this levels Special Forces data **"
1662
1663 //Now its time to start decoding the droids file.
1664 //For that, we must get it into memory first.
1665 //The procedure is the same as with LoadShip
1666 //
1667 find_file(filename, MAP_DIR, fpath, PLEASE_INFORM | IS_FATAL);
1668
1669 MainDroidsFilePointer = ReadAndMallocAndTerminateFile(fpath, END_OF_DROID_DATA_STRING"*** End of Droid Data ***");
1670
1671 // The Droid crew file for this map is now completely read into memory
1672 // It's now time to decode the file and to fill the array of enemys with
1673 // new droids of the given types.
1674 //
1675 enemy_reset_fabric();
1676
1677 DroidSectionPointer = MainDroidsFilePointer;
1678 while ((DroidSectionPointer = strstr(DroidSectionPointer, DROIDS_LEVEL_DESCRIPTION_START_STRING"** Beginning of new Level **")) != NULL((void*)0)) {
1
Loop condition is true. Entering loop body
5
Null pointer passed as an argument to a 'nonnull' parameter
1679 DroidSectionPointer += strlen(DROIDS_LEVEL_DESCRIPTION_START_STRING"** Beginning of new Level **");
1680 DebugPrintf(1, "\nFound another levels droids description starting point entry!");
1681 EndOfThisDroidSectionPointer = strstr(DroidSectionPointer, DROIDS_LEVEL_DESCRIPTION_END_STRING"** End of this levels Special Forces data **");
1682 if (EndOfThisDroidSectionPointer == NULL((void*)0)) {
2
Assuming 'EndOfThisDroidSectionPointer' is equal to null
3
Taking true branch
1683 error_message(__FUNCTION__, "Unterminated droid section encountered!", PLEASE_INFORM | IS_FATAL);
1684 }
1685 // EndOfThisDroidSectionPointer[0]=0;
1686 GetThisLevelsDroids(DroidSectionPointer);
1687 DroidSectionPointer = EndOfThisDroidSectionPointer + 2; // Move past the inserted String terminator
4
Null pointer value stored to 'DroidSectionPointer'
1688 }
1689
1690 free(MainDroidsFilePointer);
1691 return (OK0);
1692
1693}; // int GetCrew ( ... )
1694
1695/**
1696 *
1697 *
1698 */
1699static void GetThisLevelsSpecialForces(char *search_pointer, int our_level_number, char *lvl_end_location)
1700{
1701 int droid_type;
1702#define SPECIAL_FORCE_INDICATION_STRING"T=" "T="
1703
1704 while ((search_pointer = strstr(search_pointer, SPECIAL_FORCE_INDICATION_STRING"T=")) != NULL((void*)0)) {
1705 char *special_droid = ReadAndMallocStringFromData(search_pointer, SPECIAL_FORCE_INDICATION_STRING"T=", "\n");
1706 char *special_droid_end = special_droid + strlen(special_droid);
1707 search_pointer += strlen(SPECIAL_FORCE_INDICATION_STRING"T=");
1708 //identify what model of droid to display:
1709 char *ptr = special_droid;
1710 int droid_type_length = 0;
1711 while (isalnum(*ptr)((*__ctype_b_loc ())[(int) ((*ptr))] & (unsigned short int
) _ISalnum)
) {
1712 ptr++;
1713 droid_type_length++;
1714 }
1715 char type_indication_string[droid_type_length + 1];
1716 strncpy(type_indication_string, special_droid, droid_type_length)__builtin_strncpy (type_indication_string, special_droid, droid_type_length
)
;
1717 type_indication_string[droid_type_length] = 0;
1718
1719 droid_type = get_droid_type(type_indication_string);
1720
1721 // Create a new enemy, and initialize its 'identity' and 'global state'
1722 // (the enemy will be fully initialized by respawn_level())
1723
1724
1725 enemy *newen = enemy_new(droid_type);
1726
1727
1728 newen->SpecialForce = TRUE(1);
1729
1730
1731 char *tmp_sensor_ID = ReadAndMallocStringFromDataOptional(special_droid, "UseSensor=\"","\"");
1732
1733 if (!tmp_sensor_ID)
1734 newen->sensor_id=Droidmap[newen->type].sensor_id; //Not declared? In this case, use default.
1735 else
1736 newen->sensor_id=get_sensor_id_by_name(tmp_sensor_ID); // Otherwise, use the specified sensor!
1737
1738 free(tmp_sensor_ID);
1739
1740 ReadValueFromStringWithDefault(special_droid, "Fixed=", "%hd", "0", &(newen->CompletelyFixed), special_droid_end);
1741 ReadValueFromStringWithDefault(special_droid, "Marker=", "%d", "0000", &(newen->marker), special_droid_end);
1742 ReadValueFromStringWithDefault(special_droid, "MaxDistanceToHome=", "%hd", "0", &(newen->max_distance_to_home),
1743 special_droid_end);
1744
1745 char *faction = ReadAndMallocStringFromData(special_droid, "Faction=\"", "\"");
1746 newen->faction = get_faction_id(faction);
1747 free(faction);
1748
1749 char *x, *y;
1750 x = ReadAndMallocStringFromData(special_droid, "PosX=", " ");
1751 y = ReadAndMallocStringFromData(special_droid, "PosY=", " ");
1752
1753 newen->pos.x = strtof(x, NULL((void*)0));
1754 newen->pos.y = strtof(y, NULL((void*)0));
1755 newen->pos.z = our_level_number;
1756 free(x);
1757 free(y);
1758
1759 ReadValueFromStringWithDefault(special_droid, "RushTux=", "%hu", "0", &(newen->will_rush_tux), special_droid_end);
1760
1761 newen->dialog_section_name = ReadAndMallocStringFromData(special_droid, "UseDialog=\"", "\"");
1762 npc_get(newen->dialog_section_name); // Check that we have a valid dialog.
1763
1764 if (newen->short_description_text)
1765 free(newen->short_description_text);
1766
1767 newen->short_description_text = ReadAndMallocStringFromData(special_droid, "ShortLabel=_\"", "\"");;
1768
1769 char *death_drop;
1770 death_drop = ReadAndMallocStringFromData(special_droid, "DropItemId=\"", "\"");
1771 if (strcmp(death_drop, "none")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(death_drop) && __builtin_constant_p ("none") &&
(__s1_len = strlen (death_drop), __s2_len = strlen ("none"),
(!((size_t)(const void *)((death_drop) + 1) - (size_t)(const
void *)(death_drop) == 1) || __s1_len >= 4) && (!
((size_t)(const void *)(("none") + 1) - (size_t)(const void *
)("none") == 1) || __s2_len >= 4)) ? __builtin_strcmp (death_drop
, "none") : (__builtin_constant_p (death_drop) && ((size_t
)(const void *)((death_drop) + 1) - (size_t)(const void *)(death_drop
) == 1) && (__s1_len = strlen (death_drop), __s1_len <
4) ? (__builtin_constant_p ("none") && ((size_t)(const
void *)(("none") + 1) - (size_t)(const void *)("none") == 1)
? __builtin_strcmp (death_drop, "none") : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
("none"); int __result = (((const unsigned char *) (const char
*) (death_drop))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (death_drop))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (death_drop))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (death_drop))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("none") && ((size_t)(const void *)(("none") + 1) - (
size_t)(const void *)("none") == 1) && (__s2_len = strlen
("none"), __s2_len < 4) ? (__builtin_constant_p (death_drop
) && ((size_t)(const void *)((death_drop) + 1) - (size_t
)(const void *)(death_drop) == 1) ? __builtin_strcmp (death_drop
, "none") : (- (__extension__ ({ const unsigned char *__s2 = (
const unsigned char *) (const char *) (death_drop); int __result
= (((const unsigned char *) (const char *) ("none"))[0] - __s2
[0]); if (__s2_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) ("none"))[1] - __s2
[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) ("none"))[2] - __s2
[2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) ("none"))[3] - __s2
[3]); } } __result; })))) : __builtin_strcmp (death_drop, "none"
)))); })
) {
1772 newen->on_death_drop_item_code = get_item_type_by_id(death_drop);
1773 } else {
1774 newen->on_death_drop_item_code = -1;
1775 }
1776 free(death_drop);
1777 free(special_droid);
1778 enemy_insert_into_lists(newen, TRUE(1));
1779 }
1780
1781};
1782
1783/**
1784 * This function receives a pointer to the already read in crew section
1785 * in a already read in droids file and decodes all the contents of that
1786 * droid section to fill the AllEnemys array with droid types according
1787 * to the specifications made in the file.
1788 */
1789void GetThisLevelsDroids(char *section_pointer)
1790{
1791 int our_level_number;
1792 char *search_ptr;
1793 char *lvl_end_location;
1794 int random_droids;
1795 int *allowed_type_list;
1796 level *lvl;
1797
1798#define DROIDS_LEVEL_INDICATION_STRING"Level=" "Level="
1799#define DROIDS_LEVEL_END_INDICATION_STRING"** End of this levels Special Forces data **" "** End of this levels Special Forces data **"
1800
1801 lvl_end_location = LocateStringInData(section_pointer, DROIDS_LEVEL_END_INDICATION_STRING"** End of this levels Special Forces data **");
1802 lvl_end_location[0] = 0;
1803
1804 // Now we read in the level number for this level
1805 ReadValueFromString(section_pointer, DROIDS_LEVEL_INDICATION_STRING"Level=", "%d", &our_level_number, lvl_end_location);
1806
1807 lvl = curShip.AllLevels[our_level_number];
1808
1809 // At this point, the List "allowed_type_list" has been filled with the NUMBERS of
1810 // the allowed types. The number of different allowed types found is also available.
1811 // That means that now we can add the appropriate droid types into the list of existing
1812 // droids in that mission.
1813
1814 random_droids = lvl->random_droids.nr;
1815 allowed_type_list = lvl->random_droids.types;
1816
1817 while (random_droids--) {
1818 // Create a new enemy, and initialize its 'identity' and 'global state'
1819 // (the enemy will be fully initialized by respawn_level())
1820 enemy *newen = enemy_new(allowed_type_list[MyRandom(lvl->random_droids.types_size - 1)]);
1821 newen->pos.x = newen->pos.y = -1;
1822 newen->pos.z = our_level_number;
1823 newen->on_death_drop_item_code = -1;
1824 newen->dialog_section_name = strdup("AfterTakeover")(__extension__ (__builtin_constant_p ("AfterTakeover") &&
((size_t)(const void *)(("AfterTakeover") + 1) - (size_t)(const
void *)("AfterTakeover") == 1) ? (((const char *) ("AfterTakeover"
))[0] == '\0' ? (char *) calloc ((size_t) 1, (size_t) 1) : ({
size_t __len = strlen ("AfterTakeover") + 1; char *__retval =
(char *) malloc (__len); if (__retval != ((void*)0)) __retval
= (char *) memcpy (__retval, "AfterTakeover", __len); __retval
; })) : __strdup ("AfterTakeover")))
;
1825 newen->faction = FACTION_BOTS;
1826
1827 enemy_insert_into_lists(newen, TRUE(1));
1828 } // while (enemy-limit of this level not reached)
1829
1830 search_ptr = section_pointer;
1831 GetThisLevelsSpecialForces(search_ptr, our_level_number, lvl_end_location);
1832
1833 // End bot's initialization, and put them onto a waypoint.
1834 respawn_level(our_level_number);
1835};
1836
1837/**
1838 * This function determines whether a given object on x/y is visible to
1839 * the 001 or not (due to some walls or something in between
1840 *
1841 * Return values are TRUE or FALSE accordingly
1842 *
1843 */
1844int IsVisible(gps *objpos)
1845{
1846
1847 // For the purpose of visibility checking, we might as well exclude objects
1848 // that are too far away to ever be visible and thereby save some checks of
1849 // longer lines on the map, that wouldn't be necessary or helpful anyway.
1850 //
1851 if ((fabsf(Me.pos.x - objpos->x) > FLOOR_TILES_VISIBLE_AROUND_TUX((GameConfig . screen_width >= 1024 ? 13 : GameConfig . screen_width
>= 800 ? 9 : 7))
) ||
1852 (fabsf(Me.pos.y - objpos->y) > FLOOR_TILES_VISIBLE_AROUND_TUX((GameConfig . screen_width >= 1024 ? 13 : GameConfig . screen_width
>= 800 ? 9 : 7))
))
1853 return (FALSE(0));
1854
1855 // So if the object in question is close enough to be visible, we'll do the
1856 // actual check and see if the line of sight is free or blocked, a rather
1857 // time-consuming and often re-iterated process. (Maybe some do-it-every-
1858 // -10th-frame-only code could be added here later... and in the meantime
1859 // old values could be used from a stored flag?!
1860 //
1861 return (DirectLineColldet(objpos->x, objpos->y, Me.pos.x, Me.pos.y, objpos->z, &VisiblePassFilter));
1862
1863}; // int IsVisible( Point objpos )
1864
1865/**
1866 *
1867 *
1868 */
1869inline float translate_pixel_to_map_location(float axis_x, float axis_y, int give_x)
1870{
1871
1872 // NOTE: This function does not expect absolute screen coordinates but rather coordinates relative
1873 // to the center of the screen.
1874 //
1875 // That's also why it's 'axis' rather than 'pos' or 'point'.
1876 //
1877 // That is because mouse clicks can best be analyzed this way.
1878 //
1879
1880 if (give_x) {
1881 return (Me.pos.x + (axis_x / ((float)iso_floor_tile_width)) + (axis_y / ((float)iso_floor_tile_height)));
1882 } else {
1883 return (Me.pos.y - (axis_x / ((float)iso_floor_tile_width)) + (axis_y / ((float)iso_floor_tile_height)));
1884 }
1885
1886}; // int translate_pixel_to_map_location ( int axis_x , int axis_y , int give_x )
1887
1888/**
1889 *
1890 *
1891 */
1892float translate_pixel_to_zoomed_map_location(float axis_x, float axis_y, int give_x)
1893{
1894 float zf = lvledit_zoomfact();
1895 if (give_x) {
1896 return (Me.pos.x + (zf * axis_x / ((float)iso_floor_tile_width)) + (zf * axis_y / ((float)iso_floor_tile_height)));
1897 // return ( ( axis_x / ISO_WIDTH ) + ( axis_y / ISO_HEIGHT ) ) ;
1898 } else {
1899 return (Me.pos.y - (zf * axis_x / ((float)iso_floor_tile_width)) + (zf * axis_y / ((float)iso_floor_tile_height)));
1900 // return ( - ( axis_x / ISO_WIDTH ) + ( axis_y / ISO_HEIGHT ) ) ;
1901 }
1902
1903}; // int translate_pixel_to_zoomed_map_location ( int axis_x , int axis_y , int give_x )
1904
1905/**
1906 *
1907 *
1908 */
1909moderately_finepoint translate_point_to_map_location(float axis_x, float axis_y, int zoom_is_on)
1910{
1911 moderately_finepoint position;
1912 if (zoom_is_on) {
1913 position.x = translate_pixel_to_zoomed_map_location(axis_x, axis_y, TRUE(1));
1914 position.y = translate_pixel_to_zoomed_map_location(axis_x, axis_y, FALSE(0));
1915 } else {
1916 position.x = translate_pixel_to_map_location(axis_x, axis_y, TRUE(1));
1917 position.y = translate_pixel_to_map_location(axis_x, axis_y, FALSE(0));
1918 }
1919 return position;
1920}
1921
1922/**
1923 * This function translates a given map point to screen coordinates.
1924 *
1925 * @param x_map_pos X position on map
1926 * @param y_map_pos Y position on map
1927 * @param x_res pointer to the int that will hold the x position on screen
1928 * @param y_res pointer to the y position on screen
1929 * @param zoom_factor zoom factor in use
1930 *
1931 */
1932void translate_map_point_to_screen_pixel_func(float x_map_pos, float y_map_pos, int *x_res, int *y_res)
1933{
1934 float zoom_factor = 1.0;
1935
1936 /* XXX should not check for leveleditor here! */
1937 if (game_status == INSIDE_LVLEDITOR && GameConfig.zoom_is_on) {
1938 zoom_factor = lvledit_zoomfact_inv();
1939 }
1940#define R ceilf
1941#define factX iso_floor_tile_width*0.5*zoom_factor
1942#define factY iso_floor_tile_height*0.5*zoom_factor
1943 if (x_res != NULL((void*)0)) {
1944 //obstacles oscillent *x_res = UserCenter_x + R( (x_map_pos - Me.pos.x) * factX) + R((Me . pos . y - y_map_pos) * factX);
1945 //murs tilent pas -- en fait si
1946 *x_res = UserCenter_x(User_Rect.x+User_Rect.w/2) + R(x_map_pos * factX) - R(y_map_pos * factX) + R(Me.pos.y * factX) - R(factX * Me.pos.x);
1947 //murs tilent pas ET tux oscille *x_res = UserCenter_x + R( x_map_pos * factX) - R(y_map_pos * factX) + R((Me.pos.y - Me.pos.x) * factX);
1948 //original "devtrack" - murs tilent pas *x_res = ( UserCenter_x + R ( ( x_map_pos - y_map_pos ) * factX ) + R ( ( Me . pos . y - Me . pos . x ) * factX ) );
1949
1950 }
1951 if (y_res != NULL((void*)0)) {
1952 //*y_res = UserCenter_y + R( (x_map_pos - Me.pos.x)* factY ) + R((y_map_pos - Me . pos . y)* factY);
1953 *y_res = UserCenter_y(User_Rect.y+User_Rect.h/2) + R(x_map_pos * factY) + R(y_map_pos * factY) - R(Me.pos.x * factY) - R(factY * Me.pos.y);
1954 //*y_res = UserCenter_y + R( x_map_pos * factY ) + R(y_map_pos * factY) - R((Me.pos.x + Me.pos.y) * factY);
1955 //*y_res=( UserCenter_y + R ( ( x_map_pos + y_map_pos ) * factY ) - R( ( Me . pos . x + Me . pos . y ) * factY ));
1956 }
1957#undef R
1958#undef factX
1959#undef factY
1960}
1961
1962#undef _map_c