Bug Summary

File:src/map.c
Location:line 337, column 3
Description:Value stored to 'fp' is never read

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