naev 0.12.6
unidiff.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
14#include <stdlib.h>
16
17#include "unidiff.h"
18
19#include "array.h"
20#include "conf.h"
21#include "economy.h"
22#include "log.h"
23#include "map_overlay.h"
24#include "ndata.h"
25#include "nxml.h"
26#include "player.h"
27#include "safelanes.h"
28#include "space.h"
29
31
42
43/*
44 * Diff stack.
45 */
46static UniDiff_t *diff_stack = NULL;
47
48/* Useful variables. */
50 0;
51static int diff_universe_defer = 0;
52static const char *diff_nav_spob =
53 NULL;
54static const char *diff_nav_hyperspace =
55 NULL;
56
57typedef struct HunkProperties {
58 const char *name;
59 const char *tag;
60 UniHunkType_t reverse;
61 const char *const *attrs;
64const char *const hunk_attr_label[] = { "label", NULL };
65static const HunkProperties hunk_prop[HUNK_TYPE_SENTINAL + 1] = {
66 [HUNK_TYPE_NONE] =
67 {
68 .name = N_( "none" ),
69 .tag = "none",
70 .reverse = HUNK_TYPE_NONE,
71 },
72 /* HUNK_TARGET_SYSTEM. */
73 [HUNK_TYPE_SPOB_ADD] = { .name = N_( "spob add" ),
74 .tag = "spob_add",
75 .reverse = HUNK_TYPE_SPOB_REMOVE },
76 [HUNK_TYPE_SPOB_REMOVE] = { .name = N_( "spob remove" ),
77 .tag = "spob_remove",
78 .reverse = HUNK_TYPE_SPOB_ADD },
79 [HUNK_TYPE_VSPOB_ADD] = { .name = N_( "virtual spob add" ),
80 .tag = "spob_virtual_add",
81 .reverse = HUNK_TYPE_VSPOB_REMOVE },
82 [HUNK_TYPE_VSPOB_REMOVE] = { .name = N_( "virtual spob remove" ),
83 .tag = "spob_virtual_remove",
84 .reverse = HUNK_TYPE_VSPOB_ADD },
85 [HUNK_TYPE_JUMP_ADD] = { .name = N_( "jump add" ),
86 .tag = "jump_add",
87 .reverse = HUNK_TYPE_JUMP_REMOVE },
88 [HUNK_TYPE_JUMP_REMOVE] = { .name = N_( "jump remove" ),
89 .tag = "jump_remove",
90 .reverse = HUNK_TYPE_JUMP_ADD },
91 [HUNK_TYPE_SSYS_BACKGROUND] = { .name = N_( "ssys background" ),
92 .tag = "background",
93 .reverse =
94 HUNK_TYPE_SSYS_BACKGROUND_REVERT },
95 [HUNK_TYPE_SSYS_BACKGROUND_REVERT] =
96 {
97 .name = N_( "ssys background revert" ),
98 .tag = NULL,
99 .reverse = HUNK_TYPE_NONE,
100 },
101 [HUNK_TYPE_SSYS_FEATURES] = { .name = N_( "ssys features" ),
102 .tag = "features",
103 .reverse = HUNK_TYPE_SSYS_FEATURES_REVERT },
104 [HUNK_TYPE_SSYS_FEATURES_REVERT] = { .name = N_( "ssys features revert" ),
105 .tag = NULL,
106 .reverse = HUNK_TYPE_NONE },
107 [HUNK_TYPE_SSYS_POS_X] = { .name = N_( "ssys pos x" ),
108 .tag = "pos_x",
109 .reverse = HUNK_TYPE_SSYS_POS_X_REVERT },
110 [HUNK_TYPE_SSYS_POS_X_REVERT] = { .name = N_( "ssys pos x revert" ),
111 .tag = NULL,
112 .reverse = HUNK_TYPE_NONE },
113 [HUNK_TYPE_SSYS_POS_Y] = { .name = N_( "ssys pos y" ),
114 .tag = "pos_y",
115 .reverse = HUNK_TYPE_SSYS_POS_Y_REVERT },
116 [HUNK_TYPE_SSYS_POS_Y_REVERT] = { .name = N_( "ssys pos x revert" ),
117 .tag = NULL,
118 .reverse = HUNK_TYPE_NONE },
119 [HUNK_TYPE_SSYS_DISPLAYNAME] = { .name = N_( "ssys displayname" ),
120 .tag = "displayname",
121 .reverse =
122 HUNK_TYPE_SSYS_DISPLAYNAME_REVERT },
123 [HUNK_TYPE_SSYS_DISPLAYNAME_REVERT] = { .name =
124 N_( "ssys displayname revert" ),
125 .tag = NULL,
126 .reverse = HUNK_TYPE_NONE },
127 [HUNK_TYPE_SSYS_DUST] = { .name = N_( "ssys dust" ),
128 .tag = "dust",
129 .reverse = HUNK_TYPE_SSYS_DUST_REVERT },
130 [HUNK_TYPE_SSYS_DUST_REVERT] = { .name = N_( "ssys dust revert" ),
131 .tag = NULL,
132 .reverse = HUNK_TYPE_NONE },
133 [HUNK_TYPE_SSYS_INTERFERENCE] = { .name = N_( "ssys interference" ),
134 .tag = "interference",
135 .reverse =
136 HUNK_TYPE_SSYS_INTERFERENCE_REVERT },
137 [HUNK_TYPE_SSYS_INTERFERENCE_REVERT] = { .name =
138 N_( "ssys interference revert" ),
139 .tag = NULL,
140 .reverse = HUNK_TYPE_NONE },
141 [HUNK_TYPE_SSYS_NEBU_DENSITY] = { .name = N_( "ssys nebula density" ),
142 .tag = "nebu_density",
143 .reverse =
144 HUNK_TYPE_SSYS_NEBU_DENSITY_REVERT },
145 [HUNK_TYPE_SSYS_NEBU_DENSITY_REVERT] = { .name = N_(
146 "ssys nebula density revert" ),
147 .tag = NULL,
148 .reverse = HUNK_TYPE_NONE },
149 [HUNK_TYPE_SSYS_NEBU_VOLATILITY] =
150 { .name = N_( "ssys nebula volatility" ),
151 .tag = "nebu_volatility",
152 .reverse = HUNK_TYPE_SSYS_NEBU_VOLATILITY_REVERT },
153 [HUNK_TYPE_SSYS_NEBU_VOLATILITY_REVERT] =
154 {
155 .name = N_( "ssys nebula volatility revert" ),
156 .tag = NULL,
157 .reverse = HUNK_TYPE_NONE,
158 },
159 [HUNK_TYPE_SSYS_NEBU_HUE] = { .name = N_( "ssys nebula hue" ),
160 .tag = "nebu_hue",
161 .reverse = HUNK_TYPE_SSYS_NEBU_HUE_REVERT },
162 [HUNK_TYPE_SSYS_NEBU_HUE_REVERT] = { .name = N_( "ssys nebula hue revert" ),
163 .tag = NULL,
164 .reverse = HUNK_TYPE_NONE },
165 [HUNK_TYPE_SSYS_NOLANES_ADD] = { .name = N_( "ssys nolanes add" ),
166 .tag = "nolanes_add",
167 .reverse = HUNK_TYPE_SSYS_NOLANES_REMOVE },
168 [HUNK_TYPE_SSYS_NOLANES_REMOVE] = { .name = N_( "ssys nolanes remove" ),
169 .tag = "nolanes_remove",
170 .reverse = HUNK_TYPE_SSYS_NOLANES_ADD },
171 [HUNK_TYPE_SSYS_TAG_ADD] = { .name = N_( "ssys tag = NULL add" ),
172 .tag = "tag_add",
173 .reverse = HUNK_TYPE_SSYS_TAG_REMOVE },
174 [HUNK_TYPE_SSYS_TAG_REMOVE] = { .name = N_( "ssys tag = NULL remove" ),
175 .tag = "tag_remove",
176 .reverse = HUNK_TYPE_SSYS_TAG_ADD },
177 /* HUNK_TARGET_SYSTEM with label. */
178 [HUNK_TYPE_SSYS_ASTEROIDS_ADD] = { .name = N_( "ssys asteroids add" ),
179 .tag = "asteroids_add",
180 .reverse =
181 HUNK_TYPE_SSYS_ASTEROIDS_ADD_REVERT },
182 [HUNK_TYPE_SSYS_ASTEROIDS_ADD_REVERT] = { .name = N_(
183 "ssys asteroids add revert" ),
184 .tag = NULL,
185 .reverse = HUNK_TYPE_NONE },
186 [HUNK_TYPE_SSYS_ASTEROIDS_REMOVE] =
187 { .name = N_( "ssys asteroids remove" ),
188 .tag = "asteroids_remove",
189 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_REMOVE_REVERT },
190 [HUNK_TYPE_SSYS_ASTEROIDS_REMOVE_REVERT] =
191 { .name = N_( "ssys asteroids remove revert" ),
192 .tag = NULL,
193 .reverse = HUNK_TYPE_NONE },
194 [HUNK_TYPE_SSYS_ASTEROIDS_POS_X] =
195 { .name = N_( "ssys asteroids pos x" ),
196 .tag = "asteroids_pos_x",
197 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_POS_X_REVERT,
198 .attrs = hunk_attr_label },
199 [HUNK_TYPE_SSYS_ASTEROIDS_POS_X_REVERT] =
200 { .name = N_( "ssys asteroids pos x revert" ),
201 .tag = NULL,
202 .reverse = HUNK_TYPE_NONE },
203 [HUNK_TYPE_SSYS_ASTEROIDS_POS_Y] =
204 { .name = N_( "ssys asteroids pos y" ),
205 .tag = "asteroids_pos_y",
206 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_POS_Y_REVERT,
207 .attrs = hunk_attr_label },
208 [HUNK_TYPE_SSYS_ASTEROIDS_POS_Y_REVERT] =
209 { .name = N_( "ssys asteroids pos y revert" ),
210 .tag = NULL,
211 .reverse = HUNK_TYPE_NONE },
212 [HUNK_TYPE_SSYS_ASTEROIDS_DENSITY] =
213 { .name = N_( "ssys asteroids density" ),
214 .tag = "asteroids_density",
215 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_DENSITY_REVERT,
216 .attrs = hunk_attr_label },
217 [HUNK_TYPE_SSYS_ASTEROIDS_DENSITY_REVERT] =
218 { .name = N_( "ssys asteroids density revert" ),
219 .tag = NULL,
220 .reverse = HUNK_TYPE_NONE },
221 [HUNK_TYPE_SSYS_ASTEROIDS_RADIUS] =
222 { .name = N_( "ssys asteroids radius" ),
223 .tag = "asteroids_radius",
224 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_RADIUS_REVERT,
225 .attrs = hunk_attr_label },
226 [HUNK_TYPE_SSYS_ASTEROIDS_RADIUS_REVERT] =
227 { .name = N_( "ssys asteroids radius revert" ),
228 .tag = NULL,
229 .reverse = HUNK_TYPE_NONE },
230 [HUNK_TYPE_SSYS_ASTEROIDS_MAXSPEED] =
231 { .name = N_( "ssys asteroids maxspeed" ),
232 .tag = "asteroids_maxspeed",
233 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_MAXSPEED_REVERT,
234 .attrs = hunk_attr_label },
235 [HUNK_TYPE_SSYS_ASTEROIDS_MAXSPEED_REVERT] =
236 { .name = N_( "ssys asteroids maxspeed revert" ),
237 .tag = NULL,
238 .reverse = HUNK_TYPE_NONE },
239 [HUNK_TYPE_SSYS_ASTEROIDS_ACCEL] =
240 { .name = N_( "ssys asteroids accel" ),
241 .tag = "asteroids_accel",
242 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_ACCEL_REVERT,
243 .attrs = hunk_attr_label },
244 [HUNK_TYPE_SSYS_ASTEROIDS_ACCEL_REVERT] =
245 { .name = N_( "ssys asteroids accel revert" ),
246 .tag = NULL,
247 .reverse = HUNK_TYPE_NONE },
248 [HUNK_TYPE_SSYS_ASTEROIDS_ADD_TYPE] =
249 { .name = N_( "ssys asteroids add type" ),
250 .tag = "asteroids_add_type",
251 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_REMOVE_TYPE,
252 .attrs = hunk_attr_label },
253 [HUNK_TYPE_SSYS_ASTEROIDS_REMOVE_TYPE] =
254 { .name = N_( "ssys asteroids remove type" ),
255 .tag = "asteroids_remove_type",
256 .reverse = HUNK_TYPE_SSYS_ASTEROIDS_ADD_TYPE,
257 .attrs = hunk_attr_label },
258 /* HUNK_TARGET_TECH. */
259 [HUNK_TYPE_TECH_ADD] = { .name = N_( "tech add" ),
260 .tag = "item_add",
261 .reverse = HUNK_TYPE_TECH_REMOVE },
262 [HUNK_TYPE_TECH_REMOVE] = { .name = N_( "tech remove" ),
263 .tag = "item_remove",
264 .reverse = HUNK_TYPE_TECH_ADD },
265 /* HUNK_TARGET_SPOB. */
266 [HUNK_TYPE_SPOB_POS_X] = { .name = N_( "spob pos x" ),
267 .tag = "pos_x",
268 .reverse = HUNK_TYPE_SPOB_POS_X_REVERT },
269 [HUNK_TYPE_SPOB_POS_X_REVERT] = { .name = N_( "spob pos x revert" ),
270 .tag = NULL,
271 .reverse = HUNK_TYPE_NONE },
272 [HUNK_TYPE_SPOB_POS_Y] = { .name = N_( "spob pos y" ),
273 .tag = "pos_y",
274 .reverse = HUNK_TYPE_SPOB_POS_Y_REVERT },
275 [HUNK_TYPE_SPOB_POS_Y_REVERT] = { .name = N_( "spob pos y revert" ),
276 .tag = NULL,
277 .reverse = HUNK_TYPE_NONE },
278 [HUNK_TYPE_SPOB_CLASS] = { .name = N_( "spob class" ),
279 .tag = "class",
280 .reverse = HUNK_TYPE_SPOB_CLASS_REVERT },
281 [HUNK_TYPE_SPOB_CLASS_REVERT] = { .name = N_( "spob class revert" ),
282 .tag = NULL,
283 .reverse = HUNK_TYPE_NONE },
284 [HUNK_TYPE_SPOB_FACTION] = { .name = N_( "spob faction" ),
285 .tag = "faction",
286 .reverse = HUNK_TYPE_SPOB_FACTION_REVERT },
287 [HUNK_TYPE_SPOB_FACTION_REVERT] = { .name = N_( "spob faction revert" ),
288 .tag = NULL,
289 .reverse = HUNK_TYPE_NONE },
290 [HUNK_TYPE_SPOB_PRESENCE_BASE] = { .name = N_( "spob presence base" ),
291 .tag = "presence_base",
292 .reverse =
293 HUNK_TYPE_SPOB_PRESENCE_BASE_REVERT },
294 [HUNK_TYPE_SPOB_PRESENCE_BASE_REVERT] = { .name = N_(
295 "spob presence base revert" ),
296 .tag = NULL,
297 .reverse = HUNK_TYPE_NONE },
298 [HUNK_TYPE_SPOB_PRESENCE_BONUS] =
299 { .name = N_( "spob presence bonus" ),
300 .tag = "presence_bonus",
301 .reverse = HUNK_TYPE_SPOB_PRESENCE_BONUS_REVERT },
302 [HUNK_TYPE_SPOB_PRESENCE_BONUS_REVERT] = { .name = N_(
303 "spob presence bonus revert" ),
304 .tag = NULL,
305 .reverse = HUNK_TYPE_NONE },
306 [HUNK_TYPE_SPOB_PRESENCE_RANGE] =
307 { .name = N_( "spob presence range" ),
308 .tag = "presence_range",
309 .reverse = HUNK_TYPE_SPOB_PRESENCE_RANGE_REVERT },
310 [HUNK_TYPE_SPOB_PRESENCE_RANGE_REVERT] = { .name = N_(
311 "spob presence range revert" ),
312 .tag = NULL,
313 .reverse = HUNK_TYPE_NONE },
314 [HUNK_TYPE_SPOB_HIDE] = { .name = N_( "spob hide" ),
315 .tag = "hide",
316 .reverse = HUNK_TYPE_SPOB_HIDE_REVERT },
317 [HUNK_TYPE_SPOB_HIDE_REVERT] = { .name = N_( "spob hide revert" ),
318 .tag = NULL,
319 .reverse = HUNK_TYPE_NONE },
320 [HUNK_TYPE_SPOB_POPULATION] = { .name = N_( "spob population" ),
321 .tag = "population",
322 .reverse =
323 HUNK_TYPE_SPOB_POPULATION_REVERT },
324 [HUNK_TYPE_SPOB_POPULATION_REVERT] = { .name =
325 N_( "spob population revert" ),
326 .tag = NULL,
327 .reverse = HUNK_TYPE_NONE },
328 [HUNK_TYPE_SPOB_DISPLAYNAME] = { .name = N_( "spob displayname" ),
329 .tag = "displayname",
330 .reverse =
331 HUNK_TYPE_SPOB_DISPLAYNAME_REVERT },
332 [HUNK_TYPE_SPOB_DISPLAYNAME_REVERT] = { .name =
333 N_( "spob displayname revert" ),
334 .tag = NULL,
335 .reverse = HUNK_TYPE_NONE },
336 [HUNK_TYPE_SPOB_DESCRIPTION] = { .name = N_( "spob description" ),
337 .tag = "description",
338 .reverse =
339 HUNK_TYPE_SPOB_DESCRIPTION_REVERT },
340 [HUNK_TYPE_SPOB_DESCRIPTION_REVERT] = { .name =
341 N_( "spob description revert" ),
342 .tag = NULL,
343 .reverse = HUNK_TYPE_NONE },
344 [HUNK_TYPE_SPOB_BAR] = { .name = N_( "spob bar" ),
345 .tag = "bar",
346 .reverse = HUNK_TYPE_SPOB_BAR_REVERT },
347 [HUNK_TYPE_SPOB_BAR_REVERT] = { .name = N_( "spob bar revert" ),
348 .tag = NULL,
349 .reverse = HUNK_TYPE_NONE },
350 [HUNK_TYPE_SPOB_SPACE] = { .name = N_( "spob space" ),
351 .tag = "gfx_space",
352 .reverse = HUNK_TYPE_SPOB_SPACE_REVERT },
353 [HUNK_TYPE_SPOB_SPACE_REVERT] = { .name = N_( "spob space revert" ),
354 .tag = NULL,
355 .reverse = HUNK_TYPE_NONE },
356 [HUNK_TYPE_SPOB_EXTERIOR] = { .name = N_( "spob exterior" ),
357 .tag = "gfx_exterior",
358 .reverse = HUNK_TYPE_SPOB_EXTERIOR_REVERT },
359 [HUNK_TYPE_SPOB_EXTERIOR_REVERT] = { .name = N_( "spob exterior revert" ),
360 .tag = NULL,
361 .reverse = HUNK_TYPE_NONE },
362 [HUNK_TYPE_SPOB_LUA] = { .name = N_( "spob lua" ),
363 .tag = "lua",
364 .reverse = HUNK_TYPE_SPOB_LUA_REVERT },
365 [HUNK_TYPE_SPOB_LUA_REVERT] = { .name = N_( "spob lua revert" ),
366 .tag = NULL,
367 .reverse = HUNK_TYPE_NONE },
368 [HUNK_TYPE_SPOB_SERVICE_ADD] = { .name = N_( "spob service add" ),
369 .tag = "service_add",
370 .reverse = HUNK_TYPE_SPOB_SERVICE_REMOVE },
371 [HUNK_TYPE_SPOB_SERVICE_REMOVE] = { .name = N_( "spob service remove" ),
372 .tag = "service_remove",
373 .reverse = HUNK_TYPE_SPOB_SERVICE_ADD },
374 [HUNK_TYPE_SPOB_NOMISNSPAWN_ADD] = { .name = N_( "spob nomissionspawn add" ),
375 .tag = "nomissionspawn_add",
376 .reverse =
377 HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE },
378 [HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE] = { .name = N_(
379 "spob nomissionspawn remove" ),
380 .tag = "nomissionspawn_remove",
381 .reverse =
382 HUNK_TYPE_SPOB_NOMISNSPAWN_ADD },
383 [HUNK_TYPE_SPOB_TECH_ADD] = { .name = N_( "spob tech add" ),
384 .tag = "tech_add",
385 .reverse = HUNK_TYPE_SPOB_TECH_REMOVE },
386 [HUNK_TYPE_SPOB_TECH_REMOVE] = { .name = N_( "spob tech remove" ),
387 .tag = "tech_remove",
388 .reverse = HUNK_TYPE_SPOB_TECH_ADD },
389 [HUNK_TYPE_SPOB_TAG_ADD] = { .name = N_( "spob tag = NULL add" ),
390 .tag = "tag_add",
391 .reverse = HUNK_TYPE_SPOB_TAG_REMOVE },
392 [HUNK_TYPE_SPOB_TAG_REMOVE] = { .name = N_( "spob tag = NULL remove" ),
393 .tag = "tag_remove",
394 .reverse = HUNK_TYPE_SPOB_TAG_ADD },
395 /* HUNK_TARGET_FACTION. */
396 [HUNK_TYPE_FACTION_VISIBLE] = { .name = N_( "faction visible" ),
397 .tag = "visible",
398 .reverse = HUNK_TYPE_FACTION_INVISIBLE },
399 [HUNK_TYPE_FACTION_INVISIBLE] = { .name = N_( "faction invisible" ),
400 .tag = "invisible",
401 .reverse = HUNK_TYPE_FACTION_INVISIBLE },
402 [HUNK_TYPE_FACTION_ALLY] = { .name = N_( "faction set ally" ),
403 .tag = "ally",
404 .reverse = HUNK_TYPE_FACTION_REALIGN },
405 [HUNK_TYPE_FACTION_ENEMY] = { .name = N_( "faction set enemy" ),
406 .tag = "enemy",
407 .reverse = HUNK_TYPE_FACTION_REALIGN },
408 [HUNK_TYPE_FACTION_NEUTRAL] = { .name = N_( "faction set neutral" ),
409 .tag = "neutral",
410 .reverse = HUNK_TYPE_FACTION_REALIGN },
411 [HUNK_TYPE_FACTION_REALIGN] = { .name = N_( "faction alignment reset" ),
412 .tag = NULL,
413 .reverse = HUNK_TYPE_NONE },
414 [HUNK_TYPE_SENTINAL] = { .name = N_( "sentinal" ),
415 .tag = NULL,
416 .reverse = HUNK_TYPE_NONE },
417};
418
419#define HUNK_CUST( TYPE, DTYPE, FUNC ) \
420 /* should be possible to do the static_assert with C23's constexpr. */ \
421 /* static_assert( hunk_prop[TYPE].tag != NULL, "" ); */ \
422 if ( xml_isNode( cur, hunk_prop[TYPE].tag ) ) { \
423 memset( &hunk, 0, sizeof( hunk ) ); \
424 hunk.target.type = base.target.type; \
425 hunk.target.u.name = strdup( base.target.u.name ); \
426 hunk.type = TYPE; \
427 hunk.dtype = DTYPE; \
428 diff_parseAttr( &hunk, cur ); \
429 FUNC array_push_back( &diff->hunks, hunk ); \
430 continue; \
431 }
432#define HUNK_NONE( TYPE ) \
433 HUNK_CUST( TYPE, HUNK_DATA_NONE, hunk.u.name = NULL; );
434#define HUNK_STRD( TYPE ) \
435 HUNK_CUST( TYPE, HUNK_DATA_STRING, hunk.u.name = xml_getStrd( cur ); );
436#define HUNK_INT( TYPE ) \
437 HUNK_CUST( TYPE, HUNK_DATA_INT, hunk.u.data = xml_getUInt( cur ); );
438#define HUNK_FLOAT( TYPE ) \
439 HUNK_CUST( TYPE, HUNK_DATA_FLOAT, hunk.u.fdata = xml_getFloat( cur ); );
440
441/*
442 * Prototypes.
443 */
444static int diff_applyInternal( const char *name, int oneshot );
445NONNULL( 1 ) static UniDiff_t *diff_get( const char *name );
446static UniDiff_t *diff_newDiff( void );
447static int diff_removeDiff( UniDiff_t *diff );
448static const char *diff_getAttr( UniHunk_t *hunk, const char *name );
449static void diff_parseAttr( UniHunk_t *hunk, xmlNodePtr node );
450static int diff_parseDoc( UniDiffData_t *diff, xmlDocPtr doc );
451static int diff_parseSystem( UniDiffData_t *diff, xmlNodePtr node );
452static int diff_parseTech( UniDiffData_t *diff, xmlNodePtr node );
453static int diff_parseSpob( UniDiffData_t *diff, xmlNodePtr node );
454static int diff_parseFaction( UniDiffData_t *diff, xmlNodePtr node );
455static void diff_hunkFailed( UniDiff_t *diff, const UniHunk_t *hunk );
456static void diff_hunkSuccess( UniDiff_t *diff, const UniHunk_t *hunk );
457static void diff_cleanup( UniDiff_t *diff );
458/* Misc. */
459static int diff_checkUpdateUniverse( void );
460/* Externed. */
461int diff_save( xmlTextWriterPtr writer );
462int diff_load( xmlNodePtr parent );
463
467static int diff_cmp( const void *p1, const void *p2 )
468{
469 const UniDiffData_t *d1, *d2;
470 d1 = (const UniDiffData_t *)p1;
471 d2 = (const UniDiffData_t *)p2;
472 return strcmp( d1->name, d2->name );
473}
474
480int diff_init( void )
481{
482#if DEBUGGING
483 Uint32 time = SDL_GetTicks();
484
485 for ( int i = 0; i < HUNK_TYPE_SENTINAL; i++ ) {
486 if ( hunk_prop[i].name == NULL )
487 WARN( "HUNK_TYPE '%d' missing name!", i );
488 if ( hunk_prop[i].reverse == HUNK_TYPE_NONE ) {
489 /* It's possible that this is an internal usage only reverse one, so we
490 * have to see if something points to it instead. */
491 int found = 0;
492 for ( int j = 0; j < HUNK_TYPE_SENTINAL; j++ ) {
493 if ( hunk_prop[j].reverse == (UniHunkType_t)i ) {
494 found = 1;
495 break;
496 }
497 }
498 /* If not found, that means that the type is not referred to by anyone.
499 */
500 if ( !found ) {
501 if ( hunk_prop[i].name == NULL )
502 WARN( "HUNK_TYPE '%d' missing reverse!", i );
503 else
504 WARN( "HUNK_TYPE '%s' missing reverse!", hunk_prop[i].name );
505 }
506 }
507 }
508#endif /* DEBUGGING */
509
510 char **diff_files = ndata_listRecursive( UNIDIFF_DATA_PATH );
513 for ( int i = 0; i < array_size( diff_files ); i++ ) {
514 UniDiffData_t diff;
515
516 memset( &diff, 0, sizeof( diff ) );
517 if ( diff_parsePhysFS( &diff, diff_files[i] ) == 0 )
519 // xmlr_attr_strd( node, "name", diff.name );
520 }
521 array_free( diff_files );
523
524 /* Sort and warn about duplicates. */
526 diff_cmp );
527 for ( int i = 0; i < array_size( diff_available ) - 1; i++ ) {
529 const UniDiffData_t *dn = &diff_available[i + 1];
530 if ( strcmp( d->name, dn->name ) == 0 )
531 WARN( _( "Two unidiff have the same name '%s'!" ), d->name );
532 }
533
534#if DEBUGGING
535 if ( conf.devmode ) {
536 DEBUG( n_( "Loaded %d UniDiff in %.3f s", "Loaded %d UniDiffs in %.3f s",
538 array_size( diff_available ), ( SDL_GetTicks() - time ) / 1000. );
539 } else
540 DEBUG( n_( "Loaded %d UniDiff", "Loaded %d UniDiffs",
543#endif /* DEBUGGING */
544
545 return 0;
546}
547
548void diff_freeData( UniDiffData_t *diff )
549{
550 for ( int j = 0; j < array_size( diff->hunks ); j++ )
551 diff_cleanupHunk( &diff->hunks[j] );
552 array_free( diff->hunks );
553 free( diff->name );
554 free( diff->filename );
555}
556
560void diff_exit( void )
561{
562 diff_clear();
563 for ( int i = 0; i < array_size( diff_available ); i++ ) {
565 diff_freeData( d );
566 }
568 diff_available = NULL;
569}
570
571int diff_parse( UniDiffData_t *diff, char *filename )
572{
573 xmlDocPtr doc = xmlParseFile( filename );
574 memset( diff, 0, sizeof( UniDiffData_t ) );
575 diff->filename = filename;
576 if ( doc == NULL )
577 return -1;
578 return diff_parseDoc( diff, doc );
579}
580
581int diff_parsePhysFS( UniDiffData_t *diff, char *filename )
582{
583 xmlDocPtr doc = xml_parsePhysFS( filename );
584 memset( diff, 0, sizeof( UniDiffData_t ) );
585 diff->filename = filename;
586 if ( doc == NULL )
587 return -1;
588 return diff_parseDoc( diff, doc );
589}
590
591static int diff_parseDoc( UniDiffData_t *diff, xmlDocPtr doc )
592{
593 xmlNodePtr parent = doc->xmlChildrenNode;
594 xmlNodePtr node;
595 if ( strcmp( (char *)parent->name, "unidiff" ) ) {
596 WARN( _( "Malformed unidiff file: missing root element 'unidiff'" ) );
597 return -1;
598 }
599
600 xmlr_attr_strd( parent, "name", diff->name );
601 diff->hunks = array_create( UniHunk_t );
602
603 /* Start parsing. */
604 node = parent->xmlChildrenNode;
605 do {
606 xml_onlyNodes( node );
607
608 if ( xml_isNode( node, "system" ) )
609 diff_parseSystem( diff, node );
610 else if ( xml_isNode( node, "tech" ) )
611 diff_parseTech( diff, node );
612 else if ( xml_isNode( node, "spob" ) )
613 diff_parseSpob( diff, node );
614 else if ( xml_isNode( node, "faction" ) )
615 diff_parseFaction( diff, node );
616 else
617 WARN( _( "Unidiff '%s' has unknown node '%s'." ), diff->name,
618 node->name );
619 } while ( xml_nextNode( node ) );
620
621 xmlFreeDoc( doc );
622 return 0;
623}
624
631int diff_isApplied( const char *name )
632{
633 if ( diff_get( name ) != NULL )
634 return 1;
635 return 0;
636}
637
644static UniDiff_t *diff_get( const char *name )
645{
646 for ( int i = 0; i < array_size( diff_stack ); i++ )
647 if ( strcmp( diff_stack[i].data->name, name ) == 0 )
648 return &diff_stack[i];
649 return NULL;
650}
651
658int diff_apply( const char *name )
659{
660 diff_nav_hyperspace = NULL;
661 diff_nav_spob = NULL;
662 if ( player.p ) {
663 if ( player.p->nav_hyperspace >= 0 )
665 cur_system->jumps[player.p->nav_hyperspace].target->name;
666 if ( player.p->nav_spob >= 0 )
667 diff_nav_spob = cur_system->spobs[player.p->nav_spob]->name;
668 }
669 return diff_applyInternal( name, 1 );
670}
671
680static int diff_applyInternal( const char *name, int oneshot )
681{
683 UniDiff_t *diff;
684 int nfailed;
685
686 /* Check if already applied. */
687 if ( diff_isApplied( name ) )
688 return 0;
689
690 /* Reset change variable. */
691 if ( oneshot && !diff_universe_defer )
693
694 const UniDiffData_t q = { .name = (char *)name };
695 d = bsearch( &q, diff_available, array_size( diff_available ),
696 sizeof( UniDiffData_t ), diff_cmp );
697 if ( d == NULL ) {
698 WARN( _( "UniDiff '%s' not found in %s!" ), name, UNIDIFF_DATA_PATH );
699 return -1;
700 }
701
702 /* Prepare it. */
703 diff = diff_newDiff();
704 memset( diff, 0, sizeof( UniDiff_t ) );
705 diff->data = d;
706
707 /* Time to apply. */
708 for ( int i = 0; i < array_size( d->hunks ); i++ ) {
709 UniHunk_t *hi = &d->hunks[i];
710 UniHunk_t h = *hi;
711
712 /* Create a copy of the hunk. */
713 h.target.u.name = strdup( hi->target.u.name );
714 if ( hi->dtype == HUNK_DATA_STRING )
715 h.u.name = strdup( hi->u.name );
716 if ( h.attr != NULL ) {
718 for ( int j = 0; j < array_size( hi->attr ); j++ ) {
719 UniAttribute_t attr;
720 attr.name = strdup( hi->attr[j].name );
721 attr.value = strdup( hi->attr[j].value );
722 array_push_back( &h.attr, attr );
723 }
724 }
725
726 /* Patch. */
727 if ( diff_patchHunk( &h ) < 0 )
728 diff_hunkFailed( diff, &h );
729 else
730 diff_hunkSuccess( diff, &h );
731 }
732
733 /* Warn about failures. */
734 nfailed = array_size( diff->failed );
735 if ( nfailed > 0 ) {
736 WARN( n_( "Unidiff '%s' failed to apply %d hunk.",
737 "Unidiff '%s' failed to apply %d hunks.", nfailed ),
738 d->name, nfailed );
739 for ( int i = 0; i < nfailed; i++ ) {
740 UniHunk_t *fail = &diff->failed[i];
741 char *target = fail->target.u.name;
742 const char *hname;
743 if ( ( fail->type < 0 ) || ( fail->type >= HUNK_TYPE_SENTINAL ) ||
744 ( hunk_prop[fail->type].name == NULL ) ) {
745 WARN( _( "Unknown unidiff hunk '%d'!" ), fail->type );
746 hname = N_( "unknown hunk" );
747 } else
748 hname = hunk_prop[fail->type].name;
749
750 /* Have to handle all possible data cases. */
751 switch ( fail->dtype ) {
752 case HUNK_DATA_NONE:
753 WARN( p_( "unidiff", " [%s] %s" ), target, _( hname ) );
754 break;
755 case HUNK_DATA_STRING:
756 WARN( p_( "unidiff", " [%s] %s: %s" ), target, _( hname ),
757 fail->u.name );
758 break;
759 case HUNK_DATA_INT:
760 WARN( p_( "unidiff", " [%s] %s: %d" ), target, _( hname ),
761 fail->u.data );
762 break;
763 case HUNK_DATA_FLOAT:
764 WARN( p_( "unidiff", " [%s] %s: %f" ), target, _( hname ),
765 fail->u.fdata );
766 break;
767
768 default:
769 WARN( p_( "unidiff", " [%s] %s: UNKNOWN DATA" ), target,
770 _( hname ) );
771 }
772 }
773 }
774
775 /* Update overlay map just in case. */
776 ovr_refresh();
777
778 /* Update universe. */
779 if ( oneshot )
781
782 return 0;
783}
784
788void diff_start( void )
789{
791}
792
796void diff_end( void )
797{
799}
800
804static void diff_parseAttr( UniHunk_t *hunk, xmlNodePtr node )
805{
806 const char *const *attrs = hunk_prop[hunk->type].attrs;
807 xmlAttr *attribute = node->properties;
808 while ( attribute && attribute->name && attribute->children ) {
809 UniAttribute_t attr;
810 int found = 0;
811
812 /* Check if we are interested in the type. */
813 if ( attrs != NULL ) {
814 for ( int i = 0; attrs[i] != 0; i++ ) {
815 if ( strcmp( (const char *)attribute->name, attrs[i] ) == 0 ) {
816 found = 1;
817 break;
818 }
819 }
820 }
821 if ( !found ) {
822 WARN( _( "Unidiff hunk '%s' has unkown attribute '%s'" ),
823 hunk_prop[hunk->type].name, attribute->name );
824 attribute = attribute->next;
825 continue;
826 }
827
828 attr.name = strdup( (const char *)attribute->name );
829 attr.value =
830 (char *)xmlNodeListGetString( node->doc, attribute->children, 1 );
831 if ( hunk->attr == NULL )
833 array_push_back( &hunk->attr, attr );
834 attribute = attribute->next;
835 }
836}
837
838static const char *diff_getAttr( UniHunk_t *hunk, const char *name )
839{
840 for ( int i = 0; i < array_size( hunk->attr ); i++ )
841 if ( strcmp( hunk->attr[i].name, name ) == 0 )
842 return hunk->attr[i].value;
843 return NULL;
844}
845
846static AsteroidAnchor *diff_getAsteroidsLabel( StarSystem *ssys,
847 const char *label )
848{
849 for ( int i = 0; i < array_size( ssys->asteroids ); i++ ) {
850 AsteroidAnchor *ast = &ssys->asteroids[i];
851 if ( ast->label && strcmp( ast->label, label ) == 0 )
852 return ast;
853 }
854 return NULL;
855}
856
857static AsteroidAnchor *diff_getAsteroids( StarSystem *ssys, UniHunk_t *hunk )
858{
859 const char *label = diff_getAttr( hunk, "label" );
860 if ( label == NULL ) {
861 WARN( _( "Hunk '%s' does not have a label attribute!" ),
862 hunk_prop[hunk->type].name );
863 return NULL;
864 }
865 AsteroidAnchor *ast = diff_getAsteroidsLabel( ssys, label );
866 if ( ast != NULL )
867 return ast;
868 WARN( _( "Hunk '%s' can not find an asteroid field with label '%s' in "
869 "system '%s'!" ),
870 hunk_prop[hunk->type].name, label, ssys->name );
871 return NULL;
872}
873
881static int diff_parseSystem( UniDiffData_t *diff, xmlNodePtr node )
882{
883 UniHunk_t base, hunk;
884 xmlNodePtr cur;
885
886 /* Set the target. */
887 memset( &base, 0, sizeof( UniHunk_t ) );
888 base.target.type = HUNK_TARGET_SYSTEM;
889 xmlr_attr_strd( node, "name", base.target.u.name );
890 if ( base.target.u.name == NULL ) {
891 WARN( _( "Unidiff '%s' has a system node without a 'name' tag, not "
892 "applying." ),
893 diff->name );
894 return -1;
895 }
896
897 /* Now parse the possible changes. */
898 cur = node->xmlChildrenNode;
899 do {
900 xml_onlyNodes( cur );
901
902 HUNK_STRD( HUNK_TYPE_SPOB_ADD );
903 HUNK_STRD( HUNK_TYPE_SPOB_REMOVE );
904 HUNK_STRD( HUNK_TYPE_VSPOB_ADD );
905 HUNK_STRD( HUNK_TYPE_VSPOB_REMOVE );
906 HUNK_STRD( HUNK_TYPE_JUMP_ADD );
907 HUNK_STRD( HUNK_TYPE_JUMP_REMOVE );
908 HUNK_STRD( HUNK_TYPE_SSYS_BACKGROUND );
909 HUNK_STRD( HUNK_TYPE_SSYS_FEATURES );
910 HUNK_FLOAT( HUNK_TYPE_SSYS_POS_X );
911 HUNK_FLOAT( HUNK_TYPE_SSYS_POS_Y );
912 HUNK_STRD( HUNK_TYPE_SSYS_DISPLAYNAME );
913 HUNK_INT( HUNK_TYPE_SSYS_DUST );
914 HUNK_FLOAT( HUNK_TYPE_SSYS_INTERFERENCE );
915 HUNK_FLOAT( HUNK_TYPE_SSYS_NEBU_DENSITY );
916 HUNK_FLOAT( HUNK_TYPE_SSYS_NEBU_VOLATILITY );
917 HUNK_FLOAT( HUNK_TYPE_SSYS_NEBU_HUE );
918 HUNK_NONE( HUNK_TYPE_SSYS_NOLANES_ADD );
919 HUNK_NONE( HUNK_TYPE_SSYS_NOLANES_REMOVE );
920 HUNK_STRD( HUNK_TYPE_SSYS_TAG_ADD );
921 HUNK_STRD( HUNK_TYPE_SSYS_TAG_REMOVE );
922 /* These below use labels to indicate the asteroid field. */
923 HUNK_STRD( HUNK_TYPE_SSYS_ASTEROIDS_ADD );
924 HUNK_STRD( HUNK_TYPE_SSYS_ASTEROIDS_REMOVE );
925 HUNK_FLOAT( HUNK_TYPE_SSYS_ASTEROIDS_POS_X );
926 HUNK_FLOAT( HUNK_TYPE_SSYS_ASTEROIDS_POS_Y );
927 HUNK_FLOAT( HUNK_TYPE_SSYS_ASTEROIDS_DENSITY );
928 HUNK_FLOAT( HUNK_TYPE_SSYS_ASTEROIDS_RADIUS );
929 HUNK_FLOAT( HUNK_TYPE_SSYS_ASTEROIDS_MAXSPEED );
930 HUNK_FLOAT( HUNK_TYPE_SSYS_ASTEROIDS_ACCEL );
931 HUNK_STRD( HUNK_TYPE_SSYS_ASTEROIDS_ADD_TYPE );
932 HUNK_STRD( HUNK_TYPE_SSYS_ASTEROIDS_REMOVE_TYPE );
933
934 WARN( _( "Unidiff '%s' has unknown node '%s'." ), diff->name, cur->name );
935 } while ( xml_nextNode( cur ) );
936
937 /* Clean up some stuff. */
938 free( base.target.u.name );
939 base.target.u.name = NULL;
940
941 return 0;
942}
943
951static int diff_parseTech( UniDiffData_t *diff, xmlNodePtr node )
952{
953 UniHunk_t base, hunk;
954 xmlNodePtr cur;
955
956 /* Set the target. */
957 memset( &base, 0, sizeof( UniHunk_t ) );
958 base.target.type = HUNK_TARGET_TECH;
959 xmlr_attr_strd( node, "name", base.target.u.name );
960 if ( base.target.u.name == NULL ) {
961 WARN( _( "Unidiff '%s' has an target node without a 'name' tag" ),
962 diff->name );
963 return -1;
964 }
965
966 /* Now parse the possible changes. */
967 cur = node->xmlChildrenNode;
968 do {
969 xml_onlyNodes( cur );
970
971 HUNK_STRD( HUNK_TYPE_TECH_ADD );
972 HUNK_STRD( HUNK_TYPE_TECH_REMOVE );
973
974 WARN( _( "Unidiff '%s' has unknown node '%s'." ), diff->name, cur->name );
975 } while ( xml_nextNode( cur ) );
976
977 /* Clean up some stuff. */
978 free( base.target.u.name );
979 base.target.u.name = NULL;
980
981 return 0;
982}
983
991static int diff_parseSpob( UniDiffData_t *diff, xmlNodePtr node )
992{
993 UniHunk_t base, hunk;
994 xmlNodePtr cur;
995
996 /* Set the target. */
997 memset( &base, 0, sizeof( UniHunk_t ) );
998 base.target.type = HUNK_TARGET_SPOB;
999 xmlr_attr_strd( node, "name", base.target.u.name );
1000 if ( base.target.u.name == NULL ) {
1001 WARN( _( "Unidiff '%s' has an target node without a 'name' tag" ),
1002 diff->name );
1003 return -1;
1004 }
1005
1006 /* Now parse the possible changes. */
1007 cur = node->xmlChildrenNode;
1008 do {
1009 xml_onlyNodes( cur );
1010
1011 HUNK_FLOAT( HUNK_TYPE_SPOB_POS_X );
1012 HUNK_FLOAT( HUNK_TYPE_SPOB_POS_Y );
1013 HUNK_STRD( HUNK_TYPE_SPOB_CLASS );
1014 HUNK_STRD( HUNK_TYPE_SPOB_FACTION );
1015 HUNK_FLOAT( HUNK_TYPE_SPOB_PRESENCE_BASE );
1016 HUNK_FLOAT( HUNK_TYPE_SPOB_PRESENCE_BONUS );
1017 HUNK_INT( HUNK_TYPE_SPOB_PRESENCE_RANGE );
1018 HUNK_FLOAT( HUNK_TYPE_SPOB_HIDE );
1019 HUNK_INT( HUNK_TYPE_SPOB_POPULATION );
1020 HUNK_STRD( HUNK_TYPE_SPOB_DISPLAYNAME );
1021 HUNK_STRD( HUNK_TYPE_SPOB_DESCRIPTION );
1022 HUNK_STRD( HUNK_TYPE_SPOB_BAR );
1023 HUNK_STRD( HUNK_TYPE_SPOB_SERVICE_ADD );
1024 HUNK_STRD( HUNK_TYPE_SPOB_SERVICE_REMOVE );
1025 HUNK_NONE( HUNK_TYPE_SPOB_NOMISNSPAWN_ADD );
1026 HUNK_NONE( HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE );
1027 HUNK_STRD( HUNK_TYPE_SPOB_TECH_ADD );
1028 HUNK_STRD( HUNK_TYPE_SPOB_TECH_REMOVE );
1029 HUNK_STRD( HUNK_TYPE_SPOB_TAG_ADD );
1030 HUNK_STRD( HUNK_TYPE_SPOB_TAG_REMOVE );
1031 HUNK_CUST( HUNK_TYPE_SPOB_SPACE, HUNK_DATA_STRING, char str[PATH_MAX];
1032 snprintf( str, sizeof( str ), SPOB_GFX_SPACE_PATH "%s",
1033 xml_get( cur ) );
1034 hunk.u.name = strdup( str ); );
1035 HUNK_CUST( HUNK_TYPE_SPOB_EXTERIOR, HUNK_DATA_STRING, char str[PATH_MAX];
1036 snprintf( str, sizeof( str ), SPOB_GFX_EXTERIOR_PATH "%s",
1037 xml_get( cur ) );
1038 hunk.u.name = strdup( str ); );
1039 HUNK_STRD( HUNK_TYPE_SPOB_LUA );
1040
1041 // cppcheck-suppress nullPointerRedundantCheck
1042 WARN( _( "Unidiff '%s' has unknown node '%s'." ), diff->name, cur->name );
1043 } while ( xml_nextNode( cur ) );
1044
1045 /* Clean up some stuff. */
1046 free( base.target.u.name );
1047 base.target.u.name = NULL;
1048
1049 return 0;
1050}
1051
1059static int diff_parseFaction( UniDiffData_t *diff, xmlNodePtr node )
1060{
1061 UniHunk_t base, hunk;
1062 xmlNodePtr cur;
1063
1064 /* Set the target. */
1065 memset( &base, 0, sizeof( UniHunk_t ) );
1066 base.target.type = HUNK_TARGET_FACTION;
1067 xmlr_attr_strd( node, "name", base.target.u.name );
1068 if ( base.target.u.name == NULL ) {
1069 WARN( _( "Unidiff '%s' has an target node without a 'name' tag" ),
1070 diff->name );
1071 return -1;
1072 }
1073
1074 /* Now parse the possible changes. */
1075 cur = node->xmlChildrenNode;
1076 do {
1077 xml_onlyNodes( cur );
1078
1079 HUNK_NONE( HUNK_TYPE_FACTION_VISIBLE );
1080 HUNK_NONE( HUNK_TYPE_FACTION_INVISIBLE );
1081 HUNK_STRD( HUNK_TYPE_FACTION_ALLY );
1082 HUNK_STRD( HUNK_TYPE_FACTION_ENEMY );
1083 HUNK_STRD( HUNK_TYPE_FACTION_NEUTRAL );
1084
1085 WARN( _( "Unidiff '%s' has unknown node '%s'." ), diff->name, cur->name );
1086 } while ( xml_nextNode( cur ) );
1087
1088 /* Clean up some stuff. */
1089 free( base.target.u.name );
1090 base.target.u.name = NULL;
1091
1092 return 0;
1093}
1094
1101int diff_revertHunk( const UniHunk_t *hunk )
1102{
1103 UniHunk_t rhunk = *hunk;
1104 rhunk.type = hunk_prop[hunk->type].reverse;
1105 return diff_patchHunk( &rhunk );
1106}
1107
1115{
1116 Spob *p = NULL;
1117 StarSystem *ssys = NULL;
1118 StarSystem *ssys2 = NULL;
1119 int a, b;
1120 int f = -1;
1121
1122 /* Common loading target bit to simplify code below. */
1123 switch ( hunk->target.type ) {
1124 case HUNK_TARGET_SYSTEM:
1125 ssys = system_get( hunk->target.u.name );
1126 if ( ssys == NULL )
1127 return -1;
1128 break;
1129 case HUNK_TARGET_SPOB:
1130 p = spob_get( hunk->target.u.name );
1131 if ( p == NULL )
1132 return -1;
1133 break;
1134 case HUNK_TARGET_FACTION:
1135 f = faction_get( hunk->target.u.name );
1136 if ( f < 0 )
1137 return -1;
1138 break;
1139 case HUNK_TARGET_NONE:
1140 case HUNK_TARGET_TECH:
1141 break;
1142 }
1143
1144 switch ( hunk->type ) {
1145 /* Adding an spob. */
1146 case HUNK_TYPE_SPOB_ADD:
1147 p = spob_get( hunk->u.name );
1148 if ( p == NULL )
1149 return -1;
1150 spob_luaInit( p );
1152 return system_addSpob( ssys, hunk->u.name );
1153 /* Removing an spob. */
1154 case HUNK_TYPE_SPOB_REMOVE:
1156 return system_rmSpob( ssys, hunk->u.name );
1157
1158 /* Adding a virtual spob. */
1159 case HUNK_TYPE_VSPOB_ADD:
1161 return system_addVirtualSpob( ssys, hunk->u.name );
1162 /* Removing a virtual spob. */
1163 case HUNK_TYPE_VSPOB_REMOVE:
1165 return system_rmVirtualSpob( ssys, hunk->u.name );
1166
1167 /* Adding a jump. */
1168 case HUNK_TYPE_JUMP_ADD:
1169 ssys2 = system_get( hunk->u.name );
1170 if ( ssys2 == NULL )
1171 return -1;
1173 if ( system_addJump( ssys, ssys2 ) )
1174 return -1;
1175 if ( system_addJump( ssys2, ssys ) )
1176 return -1;
1177 return 0;
1178 /* Removing a jump. */
1179 case HUNK_TYPE_JUMP_REMOVE:
1180 ssys2 = system_get( hunk->u.name );
1181 if ( ssys2 == NULL )
1182 return -1;
1184 if ( system_rmJump( ssys, ssys2 ) )
1185 return -1;
1186 if ( system_rmJump( ssys2, ssys ) )
1187 return -1;
1188 return 0;
1189
1190 /* Changing system background. */
1191 case HUNK_TYPE_SSYS_BACKGROUND:
1192 hunk->o.name = ssys->background;
1193 ssys->background = hunk->u.name;
1194 return 0;
1195 case HUNK_TYPE_SSYS_BACKGROUND_REVERT:
1196 ssys->background = (char *)hunk->o.name;
1197 return 0;
1198
1199 /* Changing system features designation. */
1200 case HUNK_TYPE_SSYS_FEATURES:
1201 hunk->o.name = ssys->features;
1202 ssys->features = hunk->u.name;
1203 return 0;
1204 case HUNK_TYPE_SSYS_FEATURES_REVERT:
1205 ssys->features = (char *)hunk->o.name;
1206 return 0;
1207
1208 /* Position changes. */
1209 case HUNK_TYPE_SSYS_POS_X:
1210 hunk->o.fdata = ssys->pos.x;
1211 ssys->pos.x = hunk->u.fdata;
1212 return 0;
1213 case HUNK_TYPE_SSYS_POS_X_REVERT:
1214 ssys->pos.x = hunk->o.fdata;
1215 return 0;
1216 case HUNK_TYPE_SSYS_POS_Y:
1217 hunk->o.fdata = ssys->pos.y;
1218 ssys->pos.y = hunk->u.fdata;
1219 return 0;
1220 case HUNK_TYPE_SSYS_POS_Y_REVERT:
1221 ssys->pos.y = hunk->o.fdata;
1222 return 0;
1223
1224 /* Displayname. */
1225 case HUNK_TYPE_SSYS_DISPLAYNAME:
1226 hunk->o.name = ssys->display;
1227 ssys->display = hunk->u.name;
1228 return 0;
1229 case HUNK_TYPE_SSYS_DISPLAYNAME_REVERT:
1230 ssys->display = (char *)hunk->o.name;
1231 return 0;
1232
1233 /* Dust. */
1234 case HUNK_TYPE_SSYS_DUST:
1235 hunk->o.data = ssys->spacedust;
1236 ssys->spacedust = hunk->u.data;
1237 return 0;
1238 case HUNK_TYPE_SSYS_DUST_REVERT:
1239 ssys->spacedust = hunk->o.data;
1240 return 0;
1241
1242 /* Interefrence. */
1243 case HUNK_TYPE_SSYS_INTERFERENCE:
1244 hunk->o.data = ssys->interference;
1245 ssys->interference = hunk->u.fdata;
1246 return 0;
1247 case HUNK_TYPE_SSYS_INTERFERENCE_REVERT:
1248 ssys->interference = hunk->o.fdata;
1249 return 0;
1250
1251 /* Nebula density. */
1252 case HUNK_TYPE_SSYS_NEBU_DENSITY:
1253 hunk->o.data = ssys->nebu_density;
1254 ssys->nebu_density = hunk->u.fdata;
1255 return 0;
1256 case HUNK_TYPE_SSYS_NEBU_DENSITY_REVERT:
1257 ssys->nebu_density = hunk->o.fdata;
1258 return 0;
1259
1260 /* Nebula volatility. */
1261 case HUNK_TYPE_SSYS_NEBU_VOLATILITY:
1262 hunk->o.data = ssys->nebu_volatility;
1263 ssys->nebu_volatility = hunk->u.fdata;
1264 return 0;
1265 case HUNK_TYPE_SSYS_NEBU_VOLATILITY_REVERT:
1266 ssys->nebu_volatility = hunk->o.fdata;
1267 return 0;
1268
1269 /* Nebula hue. */
1270 case HUNK_TYPE_SSYS_NEBU_HUE:
1271 hunk->o.data = ssys->nebu_hue;
1272 ssys->nebu_hue = hunk->u.fdata;
1273 return 0;
1274 case HUNK_TYPE_SSYS_NEBU_HUE_REVERT:
1275 ssys->nebu_hue = hunk->o.fdata;
1276 return 0;
1277
1278 /* Toggle nolanes flag. */
1279 case HUNK_TYPE_SSYS_NOLANES_ADD:
1280 if ( sys_isFlag( ssys, SYSTEM_NOLANES ) )
1281 return -1;
1282 sys_setFlag( ssys, SYSTEM_NOLANES );
1283 return 0;
1284 case HUNK_TYPE_SSYS_NOLANES_REMOVE:
1285 if ( !sys_isFlag( ssys, SYSTEM_NOLANES ) )
1286 return -1;
1287 sys_rmFlag( ssys, SYSTEM_NOLANES );
1288 return 0;
1289
1290 /* Modifying tag stuff. */
1291 case HUNK_TYPE_SSYS_TAG_ADD:
1292 if ( ssys->tags == NULL )
1293 ssys->tags = array_create( char * );
1294 array_push_back( &ssys->tags, strdup( hunk->u.name ) );
1295 return 0;
1296 case HUNK_TYPE_SSYS_TAG_REMOVE:
1297 a = -1;
1298 for ( int i = 0; i < array_size( ssys->tags ); i++ ) {
1299 if ( strcmp( ssys->tags[i], hunk->u.name ) == 0 ) {
1300 a = i;
1301 break;
1302 }
1303 }
1304 if ( a < 0 )
1305 return -1; /* Didn't find tag! */
1306 free( ssys->tags[a] );
1307 array_erase( &ssys->tags, &ssys->tags[a], &ssys->tags[a + 1] );
1308 return 0;
1309
1310 /* Adding an asteroid field. */
1311 case HUNK_TYPE_SSYS_ASTEROIDS_ADD: {
1312 AsteroidAnchor ast;
1313 asteroid_initAnchor( &ast );
1314 ast.label = strdup( hunk->u.name );
1316 array_push_back( &ssys->asteroids, ast );
1317 }
1318 return 0;
1319 case HUNK_TYPE_SSYS_ASTEROIDS_ADD_REVERT: {
1320 AsteroidAnchor *ast = diff_getAsteroidsLabel( ssys, hunk->u.name );
1321 if ( ast != NULL ) {
1322 asteroid_freeAnchor( ast );
1323 array_erase( &ssys->asteroids, ast, ast + 1 );
1324 return 0;
1325 } else
1326 WARN( _( "Hunk '%s' can not find an asteroid field with label '%s' in "
1327 "system '%s'!" ),
1328 hunk->target.type, hunk->u.name, ssys->name );
1329 }
1330 return -1;
1331 /* Removing an asteroid field. */
1332 case HUNK_TYPE_SSYS_ASTEROIDS_REMOVE: {
1333 AsteroidAnchor *ast = diff_getAsteroidsLabel( ssys, hunk->u.name );
1334 if ( ast != NULL ) {
1335 hunk->o.ptr = ast;
1336 array_erase( &ssys->asteroids, ast, ast + 1 );
1337 return 0;
1338 } else
1339 WARN( _( "Hunk '%s' can not find an asteroid field with label '%s' in "
1340 "system '%s'!" ),
1341 hunk->target.type, hunk->u.name, ssys->name );
1342 }
1343 return -1;
1344 case HUNK_TYPE_SSYS_ASTEROIDS_REMOVE_REVERT:
1345 if ( hunk->o.ptr != NULL ) {
1346 AsteroidAnchor *ast = hunk->o.ptr;
1347 array_push_back( &ssys->asteroids, *ast );
1348 return 0;
1349 }
1350 return -1;
1351 /* Position for asteroid field. */
1352 case HUNK_TYPE_SSYS_ASTEROIDS_POS_X: {
1353 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1354 if ( ast != NULL ) {
1355 hunk->o.fdata = ast->pos.x;
1356 ast->pos.x = hunk->u.fdata;
1357 return 0;
1358 }
1359 }
1360 return -1;
1361 case HUNK_TYPE_SSYS_ASTEROIDS_POS_X_REVERT: {
1362 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1363 if ( ast != NULL ) {
1364 ast->pos.x = hunk->o.fdata;
1365 return 0;
1366 }
1367 }
1368 return -1;
1369 case HUNK_TYPE_SSYS_ASTEROIDS_POS_Y: {
1370 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1371 if ( ast != NULL ) {
1372 hunk->o.fdata = ast->pos.y;
1373 ast->pos.y = hunk->u.fdata;
1374 return 0;
1375 }
1376 }
1377 return -1;
1378 case HUNK_TYPE_SSYS_ASTEROIDS_POS_Y_REVERT: {
1379 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1380 if ( ast != NULL ) {
1381 ast->pos.y = hunk->o.fdata;
1382 return 0;
1383 }
1384 }
1385 return -1;
1386 /* Asteroid properties. */
1387 case HUNK_TYPE_SSYS_ASTEROIDS_DENSITY: {
1388 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1389 if ( ast != NULL ) {
1390 hunk->o.fdata = ast->density;
1391 ast->density = hunk->u.fdata;
1393 return 0;
1394 }
1395 }
1396 return -1;
1397 case HUNK_TYPE_SSYS_ASTEROIDS_DENSITY_REVERT: {
1398 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1399 if ( ast != NULL ) {
1400 ast->density = hunk->o.fdata;
1402 return 0;
1403 }
1404 }
1405 return -1;
1406 case HUNK_TYPE_SSYS_ASTEROIDS_RADIUS: {
1407 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1408 if ( ast != NULL ) {
1409 hunk->o.fdata = ast->radius;
1410 ast->radius = hunk->u.fdata;
1412 return 0;
1413 }
1414 }
1415 return -1;
1416 case HUNK_TYPE_SSYS_ASTEROIDS_RADIUS_REVERT: {
1417 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1418 if ( ast != NULL ) {
1419 ast->radius = hunk->o.fdata;
1421 return 0;
1422 }
1423 }
1424 return -1;
1425 case HUNK_TYPE_SSYS_ASTEROIDS_MAXSPEED: {
1426 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1427 if ( ast != NULL ) {
1428 hunk->o.fdata = ast->maxspeed;
1429 ast->maxspeed = hunk->u.fdata;
1431 return 0;
1432 }
1433 }
1434 return -1;
1435 case HUNK_TYPE_SSYS_ASTEROIDS_MAXSPEED_REVERT: {
1436 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1437 if ( ast != NULL ) {
1438 ast->maxspeed = hunk->o.fdata;
1440 return 0;
1441 }
1442 }
1443 return -1;
1444 case HUNK_TYPE_SSYS_ASTEROIDS_ACCEL: {
1445 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1446 if ( ast != NULL ) {
1447 hunk->o.fdata = ast->accel;
1448 ast->accel = hunk->u.fdata;
1450 return 0;
1451 }
1452 }
1453 return -1;
1454 case HUNK_TYPE_SSYS_ASTEROIDS_ACCEL_REVERT: {
1455 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1456 if ( ast != NULL ) {
1457 ast->accel = hunk->o.fdata;
1459 return 0;
1460 }
1461 }
1462 return -1;
1463 case HUNK_TYPE_SSYS_ASTEROIDS_ADD_TYPE: {
1464 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1465 if ( ast != NULL ) {
1466 AsteroidTypeGroup *grp = astgroup_getName( hunk->u.name );
1467 if ( grp == NULL )
1468 return -1;
1469 for ( int i = 0; i < array_size( ast->groups ); i++ ) {
1470 if ( strcmp( grp->name, ast->groups[i]->name ) == 0 ) {
1471 WARN( _( "Unidiff '%s' trying to add already existing asteroid "
1472 "type '%s'." ),
1473 diff_hunkName( hunk->type ), grp->name );
1474 return -1;
1475 }
1476 }
1477 array_push_back( &ast->groups, grp );
1478 return 0;
1479 }
1480 }
1481 return -1;
1482 case HUNK_TYPE_SSYS_ASTEROIDS_REMOVE_TYPE: {
1483 AsteroidAnchor *ast = diff_getAsteroids( ssys, hunk );
1484 if ( ast != NULL ) {
1485 AsteroidTypeGroup *grp = astgroup_getName( hunk->u.name );
1486 if ( grp == NULL )
1487 return -1;
1488 for ( int i = 0; i < array_size( ast->groups ); i++ ) {
1489 if ( strcmp( grp->name, ast->groups[i]->name ) == 0 ) {
1490 array_erase( &ast->groups, &ast->groups[i],
1491 &ast->groups[i + 1] );
1492 return 0;
1493 }
1494 }
1495 WARN(
1496 _( "Unidiff '%s' trying to remove inexistent asteroid type '%s'." ),
1497 diff_hunkName( hunk->type ), grp->name );
1498 }
1499 }
1500 return -1;
1501
1502 /* Adding a tech. */
1503 case HUNK_TYPE_TECH_ADD:
1504 return tech_addItem( hunk->target.u.name, hunk->u.name );
1505 /* Removing a tech. */
1506 case HUNK_TYPE_TECH_REMOVE:
1507 return tech_rmItem( hunk->target.u.name, hunk->u.name );
1508
1509 /* Position changes. */
1510 case HUNK_TYPE_SPOB_POS_X:
1511 hunk->o.fdata = p->pos.x;
1512 p->pos.x = hunk->u.fdata;
1513 return 0;
1514 case HUNK_TYPE_SPOB_POS_X_REVERT:
1515 p->pos.x = hunk->o.fdata;
1516 return 0;
1517 case HUNK_TYPE_SPOB_POS_Y:
1518 hunk->o.fdata = p->pos.y;
1519 p->pos.y = hunk->u.fdata;
1520 return 0;
1521 case HUNK_TYPE_SPOB_POS_Y_REVERT:
1522 p->pos.y = hunk->o.fdata;
1523 return 0;
1524
1525 /* Changing spob faction. */
1526 case HUNK_TYPE_SPOB_CLASS:
1527 hunk->o.name = p->class;
1528 p->class = hunk->u.name;
1529 return 0;
1530 case HUNK_TYPE_SPOB_CLASS_REVERT:
1531 p->class = (char *)hunk->o.name;
1532 return 0;
1533
1534 /* Changing spob faction. */
1535 case HUNK_TYPE_SPOB_FACTION:
1536 if ( p->presence.faction < 0 )
1537 hunk->o.name = NULL;
1538 else
1539 hunk->o.name = faction_name( p->presence.faction );
1541 /* Special case to clear the faction. */
1542 if ( strcasecmp( hunk->u.name, "None" ) == 0 )
1543 return spob_setFaction( p, -1 );
1544 else
1545 return spob_setFaction( p, faction_get( hunk->u.name ) );
1546 case HUNK_TYPE_SPOB_FACTION_REVERT:
1548 if ( hunk->o.name == NULL )
1549 return spob_setFaction( p, -1 );
1550 else
1551 return spob_setFaction( p, faction_get( hunk->o.name ) );
1552
1553 /* Presence stuff. */
1554 case HUNK_TYPE_SPOB_PRESENCE_BASE:
1556 hunk->o.fdata = p->presence.base;
1557 p->presence.base = hunk->u.fdata;
1558 return 0;
1559 case HUNK_TYPE_SPOB_PRESENCE_BASE_REVERT:
1561 p->presence.base = hunk->o.fdata;
1562 return 0;
1563 case HUNK_TYPE_SPOB_PRESENCE_BONUS:
1565 hunk->o.fdata = p->presence.bonus;
1566 p->presence.bonus = hunk->u.fdata;
1567 return 0;
1568 case HUNK_TYPE_SPOB_PRESENCE_BONUS_REVERT:
1570 p->presence.bonus = hunk->o.fdata;
1571 return 0;
1572 case HUNK_TYPE_SPOB_PRESENCE_RANGE:
1574 hunk->o.data = p->presence.range;
1575 p->presence.range = hunk->u.data;
1576 return 0;
1577 case HUNK_TYPE_SPOB_PRESENCE_RANGE_REVERT:
1579 p->presence.range = hunk->o.data;
1580 return 0;
1581
1582 /* Changing spob hide. */
1583 case HUNK_TYPE_SPOB_HIDE:
1584 hunk->o.fdata = p->hide;
1585 p->hide = hunk->u.fdata;
1586 return 0;
1587 case HUNK_TYPE_SPOB_HIDE_REVERT:
1588 p->hide = hunk->o.fdata;
1589 return 0;
1590
1591 /* Changing spob population. */
1592 case HUNK_TYPE_SPOB_POPULATION:
1593 hunk->o.fdata = p->population;
1594 p->population = hunk->u.data;
1595 return 0;
1596 case HUNK_TYPE_SPOB_POPULATION_REVERT:
1597 p->population = hunk->o.fdata;
1598 return 0;
1599
1600 /* Changing spob displayname. */
1601 case HUNK_TYPE_SPOB_DISPLAYNAME:
1602 hunk->o.name = p->display;
1603 p->display = hunk->u.name;
1604 return 0;
1605 case HUNK_TYPE_SPOB_DISPLAYNAME_REVERT:
1606 p->display = (char *)hunk->o.name;
1607 return 0;
1608
1609 /* Changing spob description. */
1610 case HUNK_TYPE_SPOB_DESCRIPTION:
1611 hunk->o.name = p->description;
1612 p->description = hunk->u.name;
1613 return 0;
1614 case HUNK_TYPE_SPOB_DESCRIPTION_REVERT:
1615 p->description = (char *)hunk->o.name;
1616 return 0;
1617
1618 /* Changing spob bar description. */
1619 case HUNK_TYPE_SPOB_BAR:
1620 hunk->o.name = p->bar_description;
1621 p->bar_description = hunk->u.name;
1622 return 0;
1623 case HUNK_TYPE_SPOB_BAR_REVERT:
1624 p->bar_description = (char *)hunk->o.name;
1625 return 0;
1626
1627 /* Modifying spob services. */
1628 case HUNK_TYPE_SPOB_SERVICE_ADD:
1629 a = spob_getService( hunk->u.name );
1630 if ( a < 0 )
1631 return -1;
1632 if ( spob_hasService( p, a ) )
1633 return -1;
1634 spob_addService( p, a );
1636 return 0;
1637 case HUNK_TYPE_SPOB_SERVICE_REMOVE:
1638 a = spob_getService( hunk->u.name );
1639 if ( a < 0 )
1640 return -1;
1641 if ( !spob_hasService( p, a ) )
1642 return -1;
1643 spob_rmService( p, a );
1645 return 0;
1646
1647 /* Modifying mission spawn. */
1648 case HUNK_TYPE_SPOB_NOMISNSPAWN_ADD:
1649 if ( spob_isFlag( p, SPOB_NOMISNSPAWN ) )
1650 return -1;
1651 spob_setFlag( p, SPOB_NOMISNSPAWN );
1652 return 0;
1653 case HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE:
1654 if ( !spob_isFlag( p, SPOB_NOMISNSPAWN ) )
1655 return -1;
1656 spob_rmFlag( p, SPOB_NOMISNSPAWN );
1657 return 0;
1658
1659 /* Modifying tech stuff. */
1660 case HUNK_TYPE_SPOB_TECH_ADD:
1661 if ( p->tech == NULL )
1662 p->tech = tech_groupCreate();
1663 tech_addItemTech( p->tech, hunk->u.name );
1664 return 0;
1665 case HUNK_TYPE_SPOB_TECH_REMOVE:
1666 tech_rmItemTech( p->tech, hunk->u.name );
1667 return 0;
1668
1669 /* Modifying tag stuff. */
1670 case HUNK_TYPE_SPOB_TAG_ADD:
1671 if ( p->tags == NULL )
1672 p->tags = array_create( char * );
1673 array_push_back( &p->tags, strdup( hunk->u.name ) );
1674 return 0;
1675 case HUNK_TYPE_SPOB_TAG_REMOVE:
1676 a = -1;
1677 for ( int i = 0; i < array_size( p->tags ); i++ ) {
1678 if ( strcmp( p->tags[i], hunk->u.name ) == 0 ) {
1679 a = i;
1680 break;
1681 }
1682 }
1683 if ( a < 0 )
1684 return -1; /* Didn't find tag! */
1685 free( p->tags[a] );
1686 array_erase( &p->tags, &p->tags[a], &p->tags[a + 1] );
1687 return 0;
1688
1689 /* Changing spob space graphics. */
1690 case HUNK_TYPE_SPOB_SPACE:
1691 hunk->o.name = p->gfx_spaceName;
1692 p->gfx_spaceName = hunk->u.name;
1694 return 0;
1695 case HUNK_TYPE_SPOB_SPACE_REVERT:
1696 p->gfx_spaceName = (char *)hunk->o.name;
1698 return 0;
1699
1700 /* Changing spob exterior graphics. */
1701 case HUNK_TYPE_SPOB_EXTERIOR:
1702 hunk->o.name = p->gfx_exterior;
1703 p->gfx_exterior = hunk->u.name;
1704 return 0;
1705 case HUNK_TYPE_SPOB_EXTERIOR_REVERT:
1706 p->gfx_exterior = (char *)hunk->o.name;
1707 return 0;
1708
1709 /* Change Lua stuff. */
1710 case HUNK_TYPE_SPOB_LUA:
1711 hunk->o.name = p->lua_file;
1712 p->lua_file = hunk->u.name;
1713 spob_luaInit( p );
1715 return 0;
1716 case HUNK_TYPE_SPOB_LUA_REVERT:
1717 p->lua_file = (char *)hunk->o.name;
1718 spob_luaInit( p );
1720 return 0;
1721
1722 /* Making a faction visible. */
1723 case HUNK_TYPE_FACTION_VISIBLE:
1724 return faction_setInvisible( f, 0 );
1725 /* Making a faction invisible. */
1726 case HUNK_TYPE_FACTION_INVISIBLE:
1727 return faction_setInvisible( f, 1 );
1728 /* Making two factions allies. */
1729 case HUNK_TYPE_FACTION_ALLY:
1730 a = f;
1731 b = faction_get( hunk->u.name );
1732 if ( areAllies( a, b ) )
1733 hunk->o.data = 'A';
1734 else if ( areEnemies( a, b ) )
1735 hunk->o.data = 'E';
1736 else
1737 hunk->o.data = 0;
1738 faction_addAlly( a, b );
1739 faction_addAlly( b, a );
1740 return 0;
1741 /* Making two factions enemies. */
1742 case HUNK_TYPE_FACTION_ENEMY:
1743 a = f;
1744 b = faction_get( hunk->u.name );
1745 if ( b < 0 )
1746 return -1;
1747 if ( areAllies( a, b ) )
1748 hunk->o.data = 'A';
1749 else if ( areEnemies( a, b ) )
1750 hunk->o.data = 'E';
1751 else
1752 hunk->o.data = 0;
1753 faction_addEnemy( a, b );
1754 faction_addEnemy( b, a );
1755 return 0;
1756 /* Making two factions neutral (removing enemy/ally statuses). */
1757 case HUNK_TYPE_FACTION_NEUTRAL:
1758 a = f;
1759 b = faction_get( hunk->u.name );
1760 if ( b < 0 )
1761 return -1;
1762 if ( areAllies( a, b ) )
1763 hunk->o.data = 'A';
1764 else if ( areEnemies( a, b ) )
1765 hunk->o.data = 'E';
1766 else
1767 hunk->o.data = 0;
1768 faction_rmAlly( a, b );
1769 faction_rmAlly( b, a );
1770 faction_rmEnemy( a, b );
1771 faction_rmEnemy( b, a );
1772 return 0;
1773 /* Resetting the alignment state of two factions. */
1774 case HUNK_TYPE_FACTION_REALIGN:
1775 a = f;
1776 b = faction_get( hunk->u.name );
1777 if ( b < 0 )
1778 return -1;
1779 if ( hunk->o.data == 'A' ) {
1780 faction_rmEnemy( a, b );
1781 faction_rmEnemy( b, a );
1782 faction_addAlly( a, b );
1783 faction_addAlly( b, a );
1784 } else if ( hunk->o.data == 'E' ) {
1785 faction_rmAlly( a, b );
1786 faction_rmAlly( b, a );
1787 faction_addEnemy( a, b );
1788 faction_addEnemy( b, a );
1789 } else {
1790 faction_rmAlly( a, b );
1791 faction_rmAlly( b, a );
1792 faction_rmEnemy( a, b );
1793 faction_rmEnemy( b, a );
1794 }
1795 return 0;
1796
1797 case HUNK_TYPE_NONE:
1798 case HUNK_TYPE_SENTINAL:
1799 break;
1800 }
1801 if ( diff_hunkName( hunk->type ) != NULL )
1802 WARN( _( "Unknown hunk type '%s'." ), diff_hunkName( hunk->type ) );
1803 else
1804 WARN( _( "Unknown hunk type '%d'." ), hunk->type );
1805 return -1;
1806}
1807
1814static void diff_hunkFailed( UniDiff_t *diff, const UniHunk_t *hunk )
1815{
1816 if ( diff == NULL )
1817 return;
1818 if ( diff->failed == NULL )
1819 diff->failed = array_create( UniHunk_t );
1820 array_grow( &diff->failed ) = *hunk;
1821}
1822
1829static void diff_hunkSuccess( UniDiff_t *diff, const UniHunk_t *hunk )
1830{
1831 if ( diff == NULL )
1832 return;
1833 if ( diff->applied == NULL )
1834 diff->applied = array_create( UniHunk_t );
1835 array_grow( &diff->applied ) = *hunk;
1836}
1837
1843void diff_remove( const char *name )
1844{
1845 /* Check if already applied. */
1846 UniDiff_t *diff = diff_get( name );
1847 if ( diff == NULL )
1848 return;
1849
1850 diff_removeDiff( diff );
1851
1853}
1854
1858void diff_clear( void )
1859{
1860 /* Remove in reverse order. */
1861 while ( array_size( diff_stack ) > 0 )
1864 diff_stack = NULL;
1865
1867}
1868
1875{
1876 /* Check if needs initialization. */
1877 if ( diff_stack == NULL )
1879 return &array_grow( &diff_stack );
1880}
1881
1888static int diff_removeDiff( UniDiff_t *diff )
1889{
1890 /* Remove hunks in reverse order. */
1891 for ( int i = array_size( diff->applied ) - 1; i >= 0; i-- ) {
1892 UniHunk_t hunk = diff->applied[i];
1893 if ( diff_revertHunk( &hunk ) )
1894 WARN( _( "Failed to remove hunk type '%s'." ),
1895 hunk_prop[hunk.type].name );
1896 }
1897
1898 diff_cleanup( diff );
1899 array_erase( &diff_stack, diff, &diff[1] );
1900 return 0;
1901}
1902
1908static void diff_cleanup( UniDiff_t *diff )
1909{
1910 for ( int i = 0; i < array_size( diff->applied ); i++ )
1911 diff_cleanupHunk( &diff->applied[i] );
1912 array_free( diff->applied );
1913 for ( int i = 0; i < array_size( diff->failed ); i++ )
1914 diff_cleanupHunk( &diff->failed[i] );
1915 array_free( diff->failed );
1916 memset( diff, 0, sizeof( UniDiff_t ) );
1917}
1918
1922const char *diff_hunkName( UniHunkType_t t )
1923{
1924 return hunk_prop[t].name;
1925}
1926
1930const char *diff_hunkTag( UniHunkType_t t )
1931{
1932 return hunk_prop[t].tag;
1933}
1934
1941{
1942 free( hunk->target.u.name );
1943 if ( hunk->dtype == HUNK_DATA_STRING )
1944 free( hunk->u.name );
1945 for ( int i = 0; i < array_size( hunk->attr ); i++ ) {
1946 UniAttribute_t *attr = &hunk->attr[i];
1947 free( attr->name );
1948 free( attr->value );
1949 }
1950 array_free( hunk->attr );
1951 memset( hunk, 0, sizeof( UniHunk_t ) );
1952}
1953
1960int diff_save( xmlTextWriterPtr writer )
1961{
1962 xmlw_startElem( writer, "diffs" );
1963 if ( diff_stack != NULL ) {
1964 for ( int i = 0; i < array_size( diff_stack ); i++ ) {
1965 const UniDiff_t *diff = &diff_stack[i];
1966 xmlw_elem( writer, "diff", "%s", diff->data->name );
1967 }
1968 }
1969 xmlw_endElem( writer ); /* "diffs" */
1970 return 0;
1971}
1972
1979int diff_load( xmlNodePtr parent )
1980{
1981 xmlNodePtr node;
1982 int defer = diff_universe_defer;
1983
1984 /* Don't update universe here. */
1987 diff_nav_spob = NULL;
1988 diff_nav_hyperspace = NULL;
1989 diff_clear();
1990 diff_universe_defer = defer;
1991
1992 node = parent->xmlChildrenNode;
1993 do {
1994 if ( xml_isNode( node, "diffs" ) ) {
1995 xmlNodePtr cur = node->xmlChildrenNode;
1996 do {
1997 if ( xml_isNode( cur, "diff" ) ) {
1998 const char *diffName = xml_get( cur );
1999 if ( diffName == NULL ) {
2000 WARN( _( "Expected node \"diff\" to contain the name of a "
2001 "unidiff. Was empty." ) );
2002 continue;
2003 }
2004 diff_applyInternal( diffName, 0 );
2005 continue;
2006 }
2007 } while ( xml_nextNode( cur ) );
2008 }
2009 } while ( xml_nextNode( node ) );
2010
2011 /* Update as necessary. */
2013
2014 return 0;
2015}
2016
2021{
2022 Pilot *const *pilots;
2023
2025 return 0;
2026
2027 /* Reconstruct jumps just in case. */
2029 /* Update presences, then safelanes. */
2032
2033 /* Re-compute the economy. */
2036
2037 /* Have to update planet graphics if necessary. */
2038 if ( cur_system != NULL ) {
2041 }
2042
2043 /* Have to pilot targetting just in case. */
2044 pilots = pilot_getAll();
2045 for ( int i = 0; i < array_size( pilots ); i++ ) {
2046 Pilot *p = pilots[i];
2047 p->nav_spob = -1;
2048 p->nav_hyperspace = -1;
2049
2050 /* Hack in case the pilot was actively jumping, this won't run the hook,
2051 * but I guess it's too much effort to properly fix for a situation that
2052 * will likely never happen. */
2053 if ( !pilot_isWithPlayer( p ) && pilot_isFlag( p, PILOT_HYPERSPACE ) )
2054 pilot_delete( p );
2055 else
2056 pilot_rmFlag(
2057 p, PILOT_HYPERSPACE ); /* Corner case player, just have it not crash
2058 and randomly stop the jump. */
2059
2060 /* Have to reset in the case of starting. */
2061 if ( pilot_isFlag( p, PILOT_HYP_BEGIN ) ||
2062 pilot_isFlag( p, PILOT_HYP_BRAKE ) ||
2063 pilot_isFlag( p, PILOT_HYP_PREP ) )
2065 }
2066
2067 /* Try to restore the targets if possible. */
2068 if ( diff_nav_spob != NULL ) {
2069 int found = 0;
2070 for ( int i = 0; i < array_size( cur_system->spobs ); i++ ) {
2071 if ( strcmp( cur_system->spobs[i]->name, diff_nav_spob ) == 0 ) {
2072 found = 1;
2073 player.p->nav_spob = i;
2075 break;
2076 }
2077 }
2078 if ( !found )
2080 } else
2082 if ( diff_nav_hyperspace != NULL ) {
2083 int found = 0;
2084 for ( int i = 0; i < array_size( cur_system->jumps ); i++ ) {
2085 if ( strcmp( cur_system->jumps[i].target->name,
2086 diff_nav_hyperspace ) == 0 ) {
2087 found = 1;
2088 player.p->nav_hyperspace = i;
2090 break;
2091 }
2092 }
2093 if ( !found )
2095 } else
2097
2099 return 1;
2100}
2101
2107void unidiff_universeDefer( int enable )
2108{
2109 int defer = diff_universe_defer;
2110 diff_universe_defer = enable;
2111 if ( defer && !enable )
2113}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:148
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition array.h:160
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void asteroids_computeInternals(AsteroidAnchor *a)
Updates internal alues of an asteroid field.
Definition asteroid.c:508
void asteroid_freeAnchor(AsteroidAnchor *ast)
Frees an asteroid anchor.
Definition asteroid.c:1036
AsteroidTypeGroup * astgroup_getName(const char *name)
Gets an asteroid type group by name.
Definition asteroid.c:1170
void asteroid_initAnchor(AsteroidAnchor *ast)
Initializes an asteroid anchor.
Definition asteroid.c:1019
void economy_initialiseCommodityPrices(void)
Initialises commodity prices for the sinusoidal economy model.
Definition economy.c:870
int economy_execQueued(void)
Calls economy_refresh if an economy update is queued.
Definition economy.c:473
void faction_rmAlly(int f, int o)
Removes an ally from the faction's allies list.
Definition faction.c:732
void faction_rmEnemy(int f, int o)
Removes an enemy from the faction's enemies list.
Definition faction.c:636
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1450
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:331
int faction_setInvisible(int id, int state)
Sets the faction's invisible state.
Definition faction.c:283
void faction_addAlly(int f, int o)
Adds an ally to the faction's allies list.
Definition faction.c:685
void faction_addEnemy(int f, int o)
Adds an enemy to the faction's enemies list.
Definition faction.c:589
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:209
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1476
int diff_load(xmlNodePtr parent)
Loads the diffs.
Definition unidiff.c:1979
#define PATH_MAX
Definition naev.h:57
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:286
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:70
void pilot_hyperspaceAbort(Pilot *p)
Stops the pilot from hyperspacing.
Definition pilot.c:3140
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition pilot.c:93
void pilot_delete(Pilot *p)
Deletes a pilot.
Definition pilot.c:2965
void player_targetHyperspaceSet(int id, int nomsg)
Sets the player's hyperspace target.
Definition player.c:1905
void player_targetSpobSet(int id)
Sets the player's target spob.
Definition player.c:1559
Player_t player
Definition player.c:77
static const double d[]
Definition rng.c:263
void safelanes_recalculate(void)
Update the safe lane locations in response to the universe changing (e.g., diff applied).
Definition safelanes.c:296
int diff_save(xmlTextWriterPtr writer)
Saves the active diffs.
Definition unidiff.c:1960
void space_reconstructPresences(void)
Reset the presence of all systems.
Definition space.c:4620
void space_gfxUnload(StarSystem *sys)
Unloads all the graphics for a star system.
Definition space.c:2281
int spob_luaInit(Spob *spob)
Updatse the spob's internal Lua stuff.
Definition space.c:2120
void systems_reconstructJumps(void)
Reconstructs the jumps.
Definition space.c:2990
int system_addJump(StarSystem *sys, StarSystem *target)
Adds a jump point between two star systems.
Definition space.c:2829
int spob_getService(const char *name)
Converts name to spob service flag.
Definition space.c:197
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1107
int system_addVirtualSpob(StarSystem *sys, const char *spobname)
Adds a virtual spob to a system.
Definition space.c:2765
int spob_setFaction(Spob *p, int faction)
Changes the spobs faction.
Definition space.c:372
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition space.c:1007
int spob_rmService(Spob *p, int service)
Removes a service from a spob.
Definition space.c:442
StarSystem * cur_system
Definition space.c:110
int system_addSpob(StarSystem *sys, const char *spobname)
Adds a spob to a star system.
Definition space.c:2668
int system_rmVirtualSpob(StarSystem *sys, const char *spobname)
Removes a virtual spob from a system.
Definition space.c:2789
int spob_addService(Spob *p, int service)
Removes a service from a spob.
Definition space.c:399
int system_rmJump(StarSystem *sys, StarSystem *target)
Removes a jump point from a star system.
Definition space.c:2868
void space_gfxLoad(StarSystem *sys)
Loads all the graphics for a star system.
Definition space.c:2266
int system_rmSpob(StarSystem *sys, const char *spobname)
Removes a spob from a star system.
Definition space.c:2709
Represents an asteroid field anchor.
Definition asteroid.h:111
double radius
Definition asteroid.h:118
double density
Definition asteroid.h:115
double maxspeed
Definition asteroid.h:123
Asteroid * asteroids
Definition asteroid.h:116
AsteroidTypeGroup ** groups
Definition asteroid.h:120
Represents a group of asteroids.
Definition asteroid.h:78
const char *const * attrs
Definition unidiff.c:61
UniHunkType_t reverse
Definition unidiff.c:60
const char * tag
Definition unidiff.c:59
const char * name
Definition unidiff.c:58
The representation of an in-game pilot.
Definition pilot.h:263
int nav_spob
Definition pilot.h:402
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:102
Universe diff filepath list.
Definition unidiff.h:183
char * name
Definition unidiff.h:184
char * filename
Definition unidiff.h:185
UniHunk_t * hunks
Definition unidiff.h:186
Represents each Universe Diff.
Definition unidiff.c:37
UniDiffData_t * data
Definition unidiff.c:38
UniHunk_t * failed
Definition unidiff.c:40
UniHunk_t * applied
Definition unidiff.c:39
union UniHunkTarget_t::@075106202173013221375222217331323374140174001165 u
UniHunkTargetType_t type
Definition unidiff.h:27
char * name
Definition unidiff.h:29
Represents a single hunk in the diff.
Definition unidiff.h:162
UniHunkDataType_t dtype
Definition unidiff.h:165
union UniHunk_t::@375235000240300110336260027115076046055102130370 u
UniHunkType_t type
Definition unidiff.h:164
UniAttribute_t * attr
Definition unidiff.h:177
UniHunkTarget_t target
Definition unidiff.h:163
double y
Definition vec2.h:47
double x
Definition vec2.h:46
int tech_rmItemTech(tech_group_t *tech, const char *value)
Removes an item from a tech.
Definition tech.c:506
tech_group_t * tech_groupCreate(void)
Creates a tech group.
Definition tech.c:196
int tech_rmItem(const char *name, const char *value)
Removes a tech item.
Definition tech.c:525
int tech_addItemTech(tech_group_t *tech, const char *value)
Adds an item to a tech.
Definition tech.c:480
int tech_addItem(const char *name, const char *value)
Adds an item to a tech.
Definition tech.c:443
static UniDiffData_t * diff_available
Definition unidiff.c:30
static const char * diff_nav_hyperspace
Definition unidiff.c:54
static int diff_checkUpdateUniverse(void)
Checks and updates the universe if necessary.
Definition unidiff.c:2020
static int diff_parseFaction(UniDiffData_t *diff, xmlNodePtr node)
Patches a faction.
Definition unidiff.c:1059
int diff_init(void)
Loads available universe diffs.
Definition unidiff.c:480
void diff_exit(void)
Clean up after diffs.
Definition unidiff.c:560
static UniDiff_t * diff_get(const char *name)
Gets a diff by name.
Definition unidiff.c:644
static UniDiff_t * diff_stack
Definition unidiff.c:46
static int diff_parseTech(UniDiffData_t *diff, xmlNodePtr node)
Patches a tech.
Definition unidiff.c:951
int diff_load(xmlNodePtr parent)
Loads the diffs.
Definition unidiff.c:1979
void unidiff_universeDefer(int enable)
Sets whether or not to defer universe change stuff.
Definition unidiff.c:2107
static UniDiff_t * diff_newDiff(void)
Creates a new UniDiff_t for usage.
Definition unidiff.c:1874
int diff_apply(const char *name)
Applies a diff to the universe.
Definition unidiff.c:658
static void diff_hunkSuccess(UniDiff_t *diff, const UniHunk_t *hunk)
Adds a hunk to the applied list.
Definition unidiff.c:1829
static void diff_hunkFailed(UniDiff_t *diff, const UniHunk_t *hunk)
Adds a hunk to the failed list.
Definition unidiff.c:1814
void diff_remove(const char *name)
Removes a diff from the universe.
Definition unidiff.c:1843
void diff_end(void)
Cleans up after applying a set of diffs.
Definition unidiff.c:796
static void diff_cleanup(UniDiff_t *diff)
Cleans up a diff.
Definition unidiff.c:1908
void diff_clear(void)
Removes all active diffs. (Call before economy_destroy().)
Definition unidiff.c:1858
static int diff_applyInternal(const char *name, int oneshot)
Applies a diff to the universe.
Definition unidiff.c:680
int diff_revertHunk(const UniHunk_t *hunk)
Reverts a hunk.
Definition unidiff.c:1101
void diff_cleanupHunk(UniHunk_t *hunk)
Cleans up a hunk.
Definition unidiff.c:1940
static int diff_universe_changed
Definition unidiff.c:49
static void diff_parseAttr(UniHunk_t *hunk, xmlNodePtr node)
Parsess the attributes.
Definition unidiff.c:804
const char * diff_hunkTag(UniHunkType_t t)
Gets the XML tag of a hunk.
Definition unidiff.c:1930
int diff_patchHunk(UniHunk_t *hunk)
Applies a hunk.
Definition unidiff.c:1114
static int diff_universe_defer
Definition unidiff.c:51
static int diff_removeDiff(UniDiff_t *diff)
Removes a diff.
Definition unidiff.c:1888
static int diff_parseSpob(UniDiffData_t *diff, xmlNodePtr node)
Patches a spob.
Definition unidiff.c:991
void diff_start(void)
Starts applying a set of diffs.
Definition unidiff.c:788
int diff_save(xmlTextWriterPtr writer)
Saves the active diffs.
Definition unidiff.c:1960
int diff_isApplied(const char *name)
Checks if a diff is currently applied.
Definition unidiff.c:631
static int diff_parseSystem(UniDiffData_t *diff, xmlNodePtr node)
Patches a system.
Definition unidiff.c:881
const char * diff_hunkName(UniHunkType_t t)
Gets the human readable name of a hunk.
Definition unidiff.c:1922
static const char * diff_nav_spob
Definition unidiff.c:52