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