File: | src/map.c |
Location: | line 350, column 3 |
Description: | Value stored to 'fp' is never read |
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 | |
49 | void GetThisLevelsDroids(char *section_pointer); |
50 | |
51 | /* |
52 | * Initialize a map tile with default values. |
53 | */ |
54 | void 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 | */ |
72 | static 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 | */ |
92 | void 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 | */ |
171 | gps 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__, "\ |
191 | Resolving map label \"%s\" failed on the entire world!\n\ |
192 | This 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 | */ |
202 | static 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 | |
223 | static 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; |
Value stored to 'fp' is never read | |
351 | } else { |
352 | loadlevel->drop_class = 0; |
353 | } |
354 | |
355 | if (loadlevel->ylen >= MAX_MAP_LINES100) { |
356 | error_message(__FUNCTION__, "\ |
357 | A map/level in FreedroidRPG which was supposed to load has more map lines than allowed\n\ |
358 | for a map/level as by the constant MAX_MAP_LINES in defs.h.\n\ |
359 | Sorry, but unless this constant is raised, FreedroidRPG will refuse to load this map.", PLEASE_INFORM | IS_FATAL); |
360 | } |
361 | } |
362 | |
363 | static 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 | |
410 | static 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 | */ |
433 | static 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 | */ |
506 | static 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 | |
548 | static 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 | |
585 | static 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 | |
616 | static 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 | |
632 | static 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 | |
638 | static 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 | |
689 | static 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 | |
738 | static 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 | |
795 | static 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 | */ |
884 | static 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 | */ |
984 | int 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 | */ |
1010 | Uint16 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 | */ |
1043 | static 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 | */ |
1077 | static 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 | */ |
1093 | int 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 | */ |
1230 | static 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 | |
1249 | static 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 | */ |
1272 | static 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 | |
1305 | static 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 | |
1324 | static 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 | |
1339 | static 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 | |
1346 | static 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 | |
1352 | static 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 | |
1381 | static 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 | */ |
1409 | static 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 | */ |
1429 | static 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\ |
1436 | xlen of this level: %d\n\ |
1437 | ylen of this level: %d\n\ |
1438 | floor layers: %d\n\ |
1439 | light radius bonus of this level: %d\n\ |
1440 | minimal light on this level: %d\n\ |
1441 | infinite_running_on_this_level: %d\n\ |
1442 | random dungeon: %d\n\ |
1443 | teleport pair: %d\n\ |
1444 | dungeon generated: %d\n\ |
1445 | environmental flags: %d\n\ |
1446 | item drop class: %d\n\ |
1447 | jump target north: %d\n\ |
1448 | jump target south: %d\n\ |
1449 | jump target east: %d\n\ |
1450 | jump 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 | */ |
1518 | int 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 | |
1563 | int 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 | |
1623 | out: 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 | */ |
1631 | void 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 | * ----------------------------------------------------------------- */ |
1651 | int 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)) { |
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)) { |
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 |
1688 | } |
1689 | |
1690 | free(MainDroidsFilePointer); |
1691 | return (OK0); |
1692 | |
1693 | }; // int GetCrew ( ... ) |
1694 | |
1695 | /** |
1696 | * |
1697 | * |
1698 | */ |
1699 | static 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 | */ |
1789 | void 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 | */ |
1844 | int 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 | */ |
1869 | inline 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 | */ |
1892 | float 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 | */ |
1909 | moderately_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 | */ |
1932 | void 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 |