File: | src/map.c |
Location: | line 1666, column 32 |
Description: | Null pointer passed as an argument to a 'nonnull' parameter |
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; | |||
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 |