naev 0.12.6
dev_mapedit.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "SDL.h"
11#include "physfs.h"
12#include <inttypes.h>
13
14#include "naev.h"
16
17#include "dev_mapedit.h"
18
19#include "array.h"
20#include "commodity.h"
21#include "conf.h"
22#include "dev_spob.h"
23#include "dev_sysedit.h"
24#include "dev_system.h"
25#include "dev_uniedit.h"
26#include "dialogue.h"
27#include "load.h"
28#include "map.h"
29#include "mapData.h"
30#include "ndata.h"
31#include "nfile.h"
32#include "nstring.h"
33#include "opengl.h"
34#include "outfit.h"
35#include "pause.h"
36#include "space.h"
37#include "tk/toolkit_priv.h"
38#include "toolkit.h"
39#include "unidiff.h"
40
41extern StarSystem *systems_stack;
42
43#define BUTTON_WIDTH 80
44#define BUTTON_HEIGHT 30
45
46#define MAPEDIT_EDIT_WIDTH 400
47#define MAPEDIT_EDIT_HEIGHT 450
48
49#define MAPEDIT_DRAG_THRESHOLD 300
50#define MAPEDIT_MOVE_THRESHOLD 10
51
52#define MAPEDIT_ZOOM_STEP 1.2
53#define MAPEDIT_ZOOM_MAX 5
54#define MAPEDIT_ZOOM_MIN -5
55
56#define MAPEDIT_OPEN_WIDTH 800
57#define MAPEDIT_OPEN_HEIGHT 500
58#define MAPEDIT_OPEN_TXT_WIDTH 300
59
60#define MAPEDIT_SAVE_WIDTH 800
61#define MAPEDIT_SAVE_HEIGHT 500
62#define MAPEDIT_SAVE_TXT_WIDTH 300
63
64typedef struct mapOutfitsList_s {
65 char *fileName;
66 char *mapName;
67 char *description;
68 char *gfx_store;
69 int numSystems;
70 credits_t price;
71 int rarity;
73
74static mapOutfitsList_t *mapList =
75 NULL; /* Array of map outfits for displaying in the Open window. */
76
77static unsigned int mapedit_wid = 0;
78static double mapedit_xpos = 0.;
79static double mapedit_ypos = 0.;
80static double mapedit_zoom = 1.;
81static int mapedit_moved = 0;
82static unsigned int mapedit_dragTime = 0;
83static int mapedit_drag = 0;
84static StarSystem **mapedit_sys = NULL;
86 0;
87static int mapedit_tadd = 0;
88static int mapedit_nsys = 0;
89static int mapedit_msys = 0;
90static double mapedit_mx = 0.;
91static double mapedit_my = 0.;
92static unsigned int mapedit_widLoad = 0;
93static char *mapedit_sLoadMapName = NULL;
94static int mapedit_nospob = 0;
95static int mapedit_hidden = 0;
96
97/*
98 * Universe editor Prototypes.
99 */
100/* Selection. */
101static void mapedit_deselect( void );
102static void mapedit_selectAdd( StarSystem *sys );
103static void mapedit_selectRm( StarSystem *sys );
104/* Custom system editor widget. */
105static void mapedit_buttonZoom( unsigned int wid, const char *str );
106static void mapedit_render( double bx, double by, double w, double h,
107 void *data );
108static void mapedit_focusLose( unsigned int wid, const char *wgtname );
109static int mapedit_mouse( unsigned int wid, const SDL_Event *event, double mx,
110 double my, double w, double h, double xr, double yr,
111 void *data );
112/* Button functions. */
113static void mapedit_close( unsigned int wid, const char *wgt );
114static void mapedit_btnOpen( unsigned int wid_unused, const char *unused );
115static void mapedit_btnSaveMapAs( unsigned int wid_unused, const char *unused );
116static void mapedit_clear( unsigned int wid_unused, const char *unused );
117static void mapedit_chkSpob( unsigned int wid, const char *wgtname );
118static void mapedit_chkHidden( unsigned int wid, const char *wgtname );
119/* Keybindings handling. */
120static int mapedit_keys( unsigned int wid, SDL_Keycode key, SDL_Keymod mod,
121 int isrepeat );
122/* Loading of Map files. */
123static void mapedit_loadMapMenu_open( void );
124static void mapedit_loadMapMenu_close( unsigned int wdw, const char *str );
125static void mapedit_loadMapMenu_update( unsigned int wdw, const char *str );
126static void mapedit_loadMapMenu_load( unsigned int wdw, const char *str );
127/* Saving of Map files. */
128static int mapedit_saveMap( StarSystem **uniedit_sys, mapOutfitsList_t *ns );
129/* Management of last loaded/saved Map file. */
131/* Management of Map files list. */
132static int mapedit_mapsList_refresh( void );
133static void mapsList_free( void );
134
138void mapedit_open( unsigned int wid_unused, const char *unused )
139{
140 (void)wid_unused;
141 (void)unused;
142 unsigned int wid;
143 int buttonHPos = 0;
144 int buttonVPos = 1;
145 int textPos = 0;
146 int linesPos = 0;
147 int curLines = 0;
148 int lineHeight = gl_smallFont.h + 5;
149 int parHeight = 10;
150
151 /* Pause. */
152 pause_game();
153
154 /* Must have no diffs applied. */
155 diff_clear();
156
157 /* Reset some variables. */
158 mapedit_drag = 0;
159 mapedit_tadd = 0;
160 mapedit_zoom = 1.;
161 mapedit_xpos = 0.;
162 mapedit_ypos = 0.;
163
164 /* Create the window. */
165 wid = window_create( "wdwMapOutfitEditor", _( "Map Outfit Editor" ), -1, -1,
166 -1, -1 );
168 mapedit_wid = wid;
169
170 /* Actual viewport. */
171 window_addCust( wid, 20, -40, SCREEN_W - 350, SCREEN_H - 100, "cstSysEdit",
173 NULL );
174
175 /* Button : reset the current map. */
176 buttonHPos = 2;
177 window_addButtonKey( wid, -20 - ( BUTTON_WIDTH + 20 ) * buttonHPos,
178 20 + ( BUTTON_HEIGHT + 20 ) * buttonVPos, BUTTON_WIDTH,
179 BUTTON_HEIGHT, "btnClear", _( "Reset" ), mapedit_clear,
180 SDLK_r );
181 buttonHPos--;
182
183 /* Button : open map file. */
184 window_addButtonKey( wid, -20 - ( BUTTON_WIDTH + 20 ) * buttonHPos,
185 20 + ( BUTTON_HEIGHT + 20 ) * buttonVPos, BUTTON_WIDTH,
186 BUTTON_HEIGHT, "btnOpen", _( "Open" ), mapedit_btnOpen,
187 SDLK_o );
188 buttonHPos--;
189
190 /* Button : save current map to file. */
191 window_addButtonKey( wid, -20 - ( BUTTON_WIDTH + 20 ) * buttonHPos,
192 20 + ( BUTTON_HEIGHT + 20 ) * buttonVPos, BUTTON_WIDTH,
193 BUTTON_HEIGHT, "btnSaveAs", _( "Save" ),
194 mapedit_btnSaveMapAs, SDLK_s );
195 buttonHPos = 0;
196 buttonVPos--;
197
198 /* Button : exit editor. */
199 window_addButtonKey( wid, -20 - ( BUTTON_WIDTH + 20 ) * buttonHPos,
200 20 + ( BUTTON_HEIGHT + 20 ) * buttonVPos, BUTTON_WIDTH,
201 BUTTON_HEIGHT, "btnClose", _( "Exit" ), mapedit_close,
202 SDLK_x );
203
204 /* Filename. */
205 window_addText( wid, -200, -40 - textPos * parHeight - linesPos * lineHeight,
206 100, lineHeight, 0, "txtSFileName", &gl_smallFont, NULL,
207 _( "File Name:" ) );
208 window_addInput( wid, -30, -40 - textPos * parHeight - linesPos * lineHeight,
209 170, lineHeight, "inpFileName", 1024, 1, &gl_smallFont );
210 textPos++;
211 linesPos++;
212
213 /* Map name. */
214 window_addText( wid, -200, -40 - textPos * parHeight - linesPos * lineHeight,
215 100, lineHeight, 0, "txtSMapName", &gl_smallFont, NULL,
216 _( "Map Name:" ) );
217 window_addInput( wid, -30, -40 - textPos * parHeight - linesPos * lineHeight,
218 170, lineHeight, "inpMapName", 1024, 1, &gl_smallFont );
219 textPos++;
220 linesPos++;
221
222 /* Map description. */
223 curLines = 7;
224 window_addText( wid, -20, -40 - textPos * parHeight - linesPos * lineHeight,
225 300 - 20, lineHeight, 0, "txtSDescription", &gl_smallFont,
226 NULL, _( "Description:" ) );
227 window_addInput( wid, -20,
228 -40 - textPos * parHeight - ( linesPos + 1 ) * lineHeight,
229 300 - 20, curLines * lineHeight, "inpDescription", 32768, 0,
230 &gl_smallFont );
231 textPos++;
232 linesPos += ( curLines + 1 );
233
234 /* Current Map # of systems. */
235 curLines = 1;
236 window_addText( wid, -20, -40 - textPos * parHeight - linesPos * lineHeight,
237 300 - 20, 20, 0, "txtSCurrentNumSystems", &gl_smallFont,
238 NULL, _( "Number of Systems (up to 100):" ) );
239 window_addText( wid, -20, -40 - textPos * parHeight - linesPos * lineHeight,
240 60, curLines * lineHeight, 0, "txtCurrentNumSystems",
241 &gl_smallFont, NULL, "N/A" );
242 textPos++;
243 linesPos++;
244
245 /* Presence. */
246 curLines = 5;
247 window_addText( wid, -20, -40 - textPos * parHeight - linesPos * lineHeight,
248 300 - 20, 20, 0, "txtSPresence", &gl_smallFont, NULL,
249 _( "Presence:" ) );
250 window_addText( wid, -20,
251 -40 - textPos * parHeight - ( linesPos + 1 ) * lineHeight,
252 300 - 20, curLines * lineHeight, 0, "txtPresence",
253 &gl_smallFont, NULL, _( "No selection" ) );
254 textPos++;
255 linesPos += curLines + 1;
256
257 /* Outift attributes. */
258 curLines = 1;
259 window_addText( wid, -200, -40 - textPos * parHeight - linesPos * lineHeight,
260 100, 20, 0, "txtSPrice", &gl_smallFont, NULL,
261 _( "Price:" ) );
262 window_addInput( wid, -30, -40 - textPos * parHeight - linesPos * lineHeight,
263 170, lineHeight, "inpPrice", 64, 1, &gl_smallFont );
264 window_setInputFilter( wid, "inpPrice", INPUT_FILTER_NUMBER );
265 textPos++;
266 linesPos += curLines;
267
268 curLines = 1;
269 window_addText( wid, -200, -40 - textPos * parHeight - linesPos * lineHeight,
270 100, 20, 0, "txtSGFX", &gl_smallFont, NULL,
271 _( "Graphics:" ) );
272 window_addInput( wid, -30, -40 - textPos * parHeight - linesPos * lineHeight,
273 170, lineHeight, "inpGFX", 64, 1, &gl_smallFont );
274 textPos++;
275 linesPos += curLines;
276
277 curLines = 1;
278 window_addText( wid, -200, -40 - textPos * parHeight - linesPos * lineHeight,
279 100, 20, 0, "txtSRarity", &gl_smallFont, NULL,
280 _( "Rarity:" ) );
281 window_addInput( wid, -30, -40 - textPos * parHeight - linesPos * lineHeight,
282 170, lineHeight, "inpRarity", 64, 1, &gl_smallFont );
283 window_setInputFilter( wid, "inpRarity", INPUT_FILTER_NUMBER );
284 textPos++;
285 linesPos += curLines + 1;
286
287 curLines = 1;
288 mapedit_nospob = 0;
289 window_addCheckbox( wid, -30,
290 -40 - textPos * parHeight - linesPos * lineHeight, 170,
291 lineHeight, "chkSpob", _( "Ignore Spobs" ),
292 mapedit_chkSpob, mapedit_nospob );
293 textPos++;
294 linesPos += curLines + 1;
295
296 curLines = 1;
297 mapedit_nospob = 0;
298 window_addCheckbox( wid, -30,
299 -40 - textPos * parHeight - linesPos * lineHeight, 170,
300 lineHeight, "chkHidden", _( "Set Hidden Jumps" ),
301 mapedit_chkHidden, mapedit_nospob );
302 textPos++;
303 linesPos += curLines + 1;
304
305 curLines = 4;
306 window_addText(
307 wid, -20, -40 - textPos * parHeight - linesPos * lineHeight, 300 - 20,
308 curLines * lineHeight, 0, "txtSWarning", &gl_smallFont, NULL,
309 _( "Warning: Editor can't (yet) manage which details are mapped within a "
310 "system. Review its changes before committing." ) );
311 textPos++;
312 linesPos += curLines + 1;
313
314 /* Zoom buttons */
315 window_addButtonKey( wid, 40, 20, 30, 30, "btnZoomIn", "+",
316 mapedit_buttonZoom, SDLK_EQUALS );
317 window_addButtonKey( wid, 80, 20, 30, 30, "btnZoomOut", "-",
318 mapedit_buttonZoom, SDLK_MINUS );
319
320 /* Selected text. */
321 window_addText( wid, 140, 10, SCREEN_W - 350 - 30 - 30 - BUTTON_WIDTH - 20,
322 30, 0, "txtSelected", &gl_smallFont, NULL, NULL );
323
324 /* Deselect everything. */
326}
327
331static int mapedit_keys( unsigned int wid, SDL_Keycode key, SDL_Keymod mod,
332 int isrepeat )
333{
334 (void)mod;
335 (void)isrepeat;
336
337 switch (key) {
338 /* Mode changes. */
339 case SDLK_ESCAPE:
340 mapedit_close( wid, "Close" );
341 return 1;
342
343 default:
344 return 0;
345 }
346}
347
351static void mapedit_close( unsigned int wid, const char *wgt )
352{
353 /* Frees some memory. */
356
357 /* Reconstruct jumps. */
359
360 /* Unpause. */
361 unpause_game();
362
363 /* Close the window. */
364 window_close( wid, wgt );
365}
366
370static void mapedit_clear( unsigned int wid, const char *unused )
371{
372 (void)wid;
373 (void)unused;
374
375 /* Clear the map. */
377}
378
379static void mapedit_chkSpob( unsigned int wid, const char *wgtname )
380{
381 mapedit_nospob = window_checkboxState( wid, wgtname );
382}
383
384static void mapedit_chkHidden( unsigned int wid, const char *wgtname )
385{
386 mapedit_hidden = window_checkboxState( wid, wgtname );
387}
388
392static void mapedit_btnOpen( unsigned int wid_unused, const char *unused )
393{
394 (void)wid_unused;
395 (void)unused;
396
398}
399
403static void mapedit_render( double bx, double by, double w, double h,
404 void *data )
405{
406 (void)data;
407 double x, y, r;
408
409 /* Parameters. */
410 map_renderParams( bx, by, mapedit_xpos, mapedit_ypos, w, h, mapedit_zoom, &x,
411 &y, &r );
412
413 uniedit_renderMap( bx, by, w, h, x, y, mapedit_zoom, r );
414
415 /* Render the selected system selections. */
416 for (int i = 0; i < mapedit_nsys; i++) {
417 StarSystem *sys = mapedit_sys[i];
418 gl_renderCircle( x + sys->pos.x * mapedit_zoom,
419 y + sys->pos.y * mapedit_zoom, 1.8 * r, &cRed, 0 );
420 gl_renderCircle( x + sys->pos.x * mapedit_zoom,
421 y + sys->pos.y * mapedit_zoom, 2.0 * r, &cRed, 0 );
422 }
423
424 /* Render last clicked system */
426 StarSystem *sys = system_getIndex( mapedit_iLastClickedSystem );
427 gl_renderCircle( x + sys->pos.x * mapedit_zoom,
428 y + sys->pos.y * mapedit_zoom, 2.4 * r, &cBlue, 0 );
429 gl_renderCircle( x + sys->pos.x * mapedit_zoom,
430 y + sys->pos.y * mapedit_zoom, 2.6 * r, &cBlue, 0 );
431 gl_renderCircle( x + sys->pos.x * mapedit_zoom,
432 y + sys->pos.y * mapedit_zoom, 2.8 * r, &cBlue, 0 );
433 }
434}
435
439static void mapedit_focusLose( unsigned int wid, const char *wgtname )
440{
441 (void)wid;
442 (void)wgtname;
443 mapedit_drag = 0;
444}
445
449static int mapedit_mouse( unsigned int wid, const SDL_Event *event, double mx,
450 double my, double w, double h, double xr, double yr,
451 void *data )
452{
453 (void)data;
454 const double t = 15. * 15.; /* threshold */
455
456 switch (event->type) {
457 case SDL_MOUSEWHEEL:
458 /* Must be in bounds. */
459 if (( mx < 0. ) || ( mx > w ) || ( my < 0. ) || ( my > h ))
460 return 0;
461 if (event->wheel.y > 0)
462 mapedit_buttonZoom( 0, "btnZoomIn" );
463 else if (event->wheel.y < 0)
464 mapedit_buttonZoom( 0, "btnZoomOut" );
465 return 1;
466
467 case SDL_MOUSEBUTTONDOWN:
468 /* Must be in bounds. */
469 if (( mx < 0. ) || ( mx > w ) || ( my < 0. ) || ( my > h ))
470 return 0;
471 window_setFocus( wid, "cstSysEdit" );
472
473 /* Zooming */
474 if (event->button.button == SDL_BUTTON_X1) {
475 mapedit_buttonZoom( 0, "btnZoomIn" );
476 return 1;
477 } else if (event->button.button == SDL_BUTTON_X2) {
478 mapedit_buttonZoom( 0, "btnZoomOut" );
479 return 1;
480 }
481
482 /* selecting star system */
483 else {
484 mx -= w / 2 - mapedit_xpos;
485 my -= h / 2 - mapedit_ypos;
486
487 for (int i = 0; i < array_size( systems_stack ); i++) {
488 double x, y;
489 StarSystem *sys = system_getIndex( i );
490
491 /* get position */
492 x = sys->pos.x * mapedit_zoom;
493 y = sys->pos.y * mapedit_zoom;
494
495 if (( pow2( mx - x ) + pow2( my - y ) ) < t) {
496 int found = 0;
497
498 /* Set last clicked system */
500
501 /* Try to find in selected systems. */
502 for (int j = 0; j < mapedit_nsys; j++) {
503 /* Must match. */
504 if (mapedit_sys[j] == sys) {
505 found = 1;
506 break;
507 } else
508 continue;
509 }
510
511 /* Toggle system selection. */
512 if (found)
513 mapedit_selectRm( sys );
514 else
515 mapedit_selectAdd( sys );
516 return 1;
517 }
518 }
519
520 /* Start dragging the viewport. */
521 mapedit_drag = 1;
522 mapedit_dragTime = SDL_GetTicks();
523 mapedit_moved = 0;
524 }
525 break;
526
527 case SDL_MOUSEBUTTONUP:
528 /* Handles dragging viewport around. */
529 mapedit_drag = 0;
530 break;
531
532 case SDL_MOUSEMOTION:
533 /* Update mouse positions. */
534 mapedit_mx = mx;
535 mapedit_my = my;
536
537 /* Handle dragging. */
538 if (mapedit_drag) {
539 /* axis is inverted */
540 mapedit_xpos -= xr;
541 mapedit_ypos += yr;
542
543 /* Update mouse movement. */
544 mapedit_moved += ABS( xr ) + ABS( yr );
545 }
546 break;
547 }
548
549 return 0;
550}
551
555static void mapedit_deselect( void )
556{
557 if (mapedit_nsys > 0)
558 free( mapedit_sys );
559 mapedit_sys = NULL;
560 mapedit_nsys = 0;
561 mapedit_msys = 0;
562
563 /* Change window stuff. */
564 window_modifyText( mapedit_wid, "txtSelected", _( "No selection" ) );
565 window_modifyText( mapedit_wid, "txtCurrentNumSystems", "0" );
566}
567
571static void mapedit_selectAdd( StarSystem *sys )
572{
573 /* Workaround for BUG found in memory allocation */
574 if (mapedit_nsys == 100)
575 return;
576
577 /* Allocate if needed. */
578 if (mapedit_msys < mapedit_nsys + 1) {
579 if (mapedit_msys == 0)
580 mapedit_msys = 1;
581 mapedit_msys *= 2;
583 realloc( mapedit_sys, sizeof( StarSystem * ) * mapedit_msys );
584 }
585
586 /* Add system. */
588 mapedit_nsys++;
589
590 /* Set text again. */
592}
593
597static void mapedit_selectRm( StarSystem *sys )
598{
599 for (int i = 0; i < mapedit_nsys; i++) {
600 if (mapedit_sys[i] == sys) {
601 mapedit_nsys--;
602 memmove( &mapedit_sys[i], &mapedit_sys[i + 1],
603 sizeof( StarSystem * ) * ( mapedit_nsys - i ) );
605 return;
606 }
607 }
608}
609
614{
615 int l;
616 char buf[STRMAX_SHORT];
617
618 /* Built list of all selected systems names */
619 l = 0;
620 for (int i = 0; i < mapedit_nsys; i++) {
621 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s%s", mapedit_sys[i]->name,
622 ( i == mapedit_nsys - 1 ) ? "" : ", " );
623 }
624
625 if (l == 0)
626 /* Change display to reflect that no system is selected */
628 else {
629 /* Display list of selected systems */
630 window_modifyText( mapedit_wid, "txtSelected", buf );
631
632 /* Display number of selected systems */
633 snprintf( &buf[0], 4, "%i", mapedit_nsys );
634 window_modifyText( mapedit_wid, "txtCurrentNumSystems", buf );
635
636 /* Compute and display presence text. */
638 StarSystem *sys = system_getIndex( mapedit_iLastClickedSystem );
639 map_updateFactionPresence( mapedit_wid, "txtPresence", sys, 1 );
640 snprintf( &buf[0], sizeof( buf ), _( "Presence (%s)" ), sys->name );
641 window_modifyText( mapedit_wid, "txtSPresence", buf );
642 } else {
643 window_modifyText( mapedit_wid, "txtSPresence", _( "Presence" ) );
644 window_modifyText( mapedit_wid, "txtPresence",
645 _( "No system yet clicked" ) );
646 }
647 }
648}
649
656static void mapedit_buttonZoom( unsigned int wid, const char *str )
657{
658 (void)wid;
659 /* Transform coords to normal. */
662
663 /* Apply zoom. */
664 if (strcmp( str, "btnZoomIn" ) == 0) {
668 } else if (strcmp( str, "btnZoomOut" ) == 0) {
672 }
673
674 /* Transform coords back. */
677}
678
683{
684 unsigned int wid;
685 char **names;
686 int n;
687
688 /* window */
689 wid = window_create( "wdwOpenMapOutfit", _( "Open Map Outfit" ), -1, -1,
691 mapedit_widLoad = wid;
692
693 /* Default actions */
696
697 /* Load list of map outfits */
699
700 /* Load the maps */
701 n = array_size( mapList );
702 if (n > 0) {
703 names = malloc( sizeof( char * ) * n );
704 for (int i = 0; i < n; i++) {
705 mapOutfitsList_t *ns = &mapList[i];
706 names[i] = strdup( ns->mapName );
707 }
708 }
709 /* case there are no files */
710 else {
711 names = malloc( sizeof( char * ) );
712 names[0] = strdup( "None" );
713 n = 1;
714 }
715
716 /* Map info text. */
717 window_addText( mapedit_widLoad, -20, -40, MAPEDIT_OPEN_TXT_WIDTH,
718 MAPEDIT_OPEN_HEIGHT - 40 - 20 - 2 * ( BUTTON_HEIGHT + 20 ),
719 0, "txtMapInfo", NULL, NULL, NULL );
720
721 window_addList( mapedit_widLoad, 20, -50,
723 MAPEDIT_OPEN_HEIGHT - 110, "lstMapOutfits", names, n, 0,
725
726 /* Buttons */
727 window_addButtonKey( mapedit_widLoad, -20, 20 + BUTTON_HEIGHT + 20,
728 BUTTON_WIDTH, BUTTON_HEIGHT, "btnLoad", _( "Load" ),
729 mapedit_loadMapMenu_load, SDLK_l );
730 window_addButton( mapedit_widLoad, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
731 "btnBack", _( "Back" ), mapedit_loadMapMenu_close );
732 window_addButton( mapedit_widLoad, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
733 "btnDelete", _( "Del" ), mapedit_loadMapMenu_close );
734}
735
741static void mapedit_loadMapMenu_update( unsigned int wdw, const char *str )
742{
743 (void)str;
744 int pos;
746 const char *save;
747 char buf[STRMAX_SHORT];
748
749 /* Make sure list is ok. */
750 save = toolkit_getList( wdw, "lstMapOutfits" );
751 if (strcmp( save, "None" ) == 0)
752 return;
753
754 /* Get position. */
755 pos = toolkit_getListPos( wdw, "lstMapOutfits" );
756 ns = &mapList[pos];
757
758 /* Display text. */
759 snprintf( buf, sizeof( buf ),
760 _( "File Name:\n"
761 " %s\n"
762 "Map name:\n"
763 " %s\n"
764 "Description:\n"
765 " %s\n"
766 "Systems:\n"
767 " %i" ),
768 ns->fileName, ns->mapName, ns->description, ns->numSystems );
769
770 window_modifyText( wdw, "txtMapInfo", buf );
771}
772
778static void mapedit_loadMapMenu_close( unsigned int wdw, const char *str )
779{
780 (void)str;
781 window_destroy( wdw );
782}
783
787static void mapedit_loadMapMenu_load( unsigned int wdw, const char *str )
788{
789 (void)str;
790 int pos, len, compareLimit, i, found;
792 const char *save;
793 char *file, *name, *systemName;
794 xmlNodePtr node;
795 xmlDocPtr doc;
796 StarSystem *sys;
797
798 /* Debug log */
799
800 /* Make sure list is ok. */
801 save = toolkit_getList( wdw, "lstMapOutfits" );
802 if (strcmp( save, "None" ) == 0)
803 return;
804
805 /* Reset defaults. */
806 mapedit_nospob = 0;
807 mapedit_hidden = 0;
808
809 /* Get position. */
810 pos = toolkit_getListPos( wdw, "lstMapOutfits" );
811 ns = &mapList[pos];
812
813 /* Display text. */
814 len = strlen( MAP_DATA_PATH ) + strlen( ns->fileName ) + 2;
815 file = malloc( len );
816 snprintf( file, len, "%s%s", MAP_DATA_PATH, ns->fileName );
817
818 doc = xml_parsePhysFS( file );
819
820 /* Get first node, normally "outfit" */
821 node = doc->xmlChildrenNode;
822 if (node == NULL) {
823 free( file );
824 xmlFreeDoc( doc );
825 return;
826 }
827
828 if (!xml_isNode( node, "outfit" )) {
829 free( file );
830 xmlFreeDoc( doc );
831 return;
832 }
833
834 /* Get "name" property from the "outfit" node */
835 xmlr_attr_strd( node, "name", name );
836 if (strcmp( ns->mapName, name ) != 0) {
837 free( name );
838 free( file );
839 xmlFreeDoc( doc );
840 return;
841 } else {
842 free( name );
843 name = NULL;
844 }
845
846 /* Loop on the nodes to find <specific> node */
847 node = node->xmlChildrenNode;
848 do {
849 xml_onlyNodes( node );
850
851 if (!xml_isNode( node, "specific" ))
852 continue;
853
854 /* Break out of the loop, either with a correct outfitType or not */
855 break;
856 } while (xml_nextNode( node ));
857
859
860 /* Loop on the nodes to find all <sys> node */
861 node = node->xmlChildrenNode;
862 do {
863 xml_onlyNodes( node );
864
865 if (!xml_isNode( node, "sys" ))
866 continue;
867
868 /* Display "name" property from "sys" node and increment number of systems
869 * found */
870 xmlr_attr_strd( node, "name", systemName );
871
872 /* Find system */
873 found = 0;
874 for (i = 0; i < array_size( systems_stack ); i++) {
875 sys = system_getIndex( i );
876 compareLimit = strlen( systemName );
877 if (strncmp( systemName, sys->name, compareLimit ) == 0) {
878 found = 1;
879 break;
880 }
881 }
882
883 /* If system exists, select it */
884 if (found)
885 mapedit_selectAdd( sys );
886 free( systemName );
887 systemName = NULL;
888 } while (xml_nextNode( node ));
889
891
892 free( file );
893 xmlFreeDoc( doc );
894
895 window_destroy( wdw );
896}
897
901static void mapedit_btnSaveMapAs( unsigned int wdw, const char *unused )
902{
903 (void)unused;
905
906 ns.fileName = strdup( window_getInput( wdw, "inpFileName" ) );
907 ns.mapName = strdup( window_getInput( wdw, "inpMapName" ) );
908 ns.description = strdup( window_getInput( wdw, "inpDescription" ) );
909 ns.gfx_store = strdup( window_getInput( wdw, "inpGFX" ) );
910 ns.numSystems = mapedit_nsys;
911 ns.price = atoll( window_getInput( wdw, "inpPrice" ) );
912 ns.rarity = atoi( window_getInput( wdw, "inpRarity" ) );
913
914 if (mapedit_saveMap( mapedit_sys, &ns ))
915 uniedit_saveError();
916
917 free( ns.fileName );
918 free( ns.mapName );
919 free( ns.description );
920 free( ns.gfx_store );
921}
922
927{
928 char buf[32];
929
930 /* Displaying info strings */
931 window_setInput( mapedit_wid, "inpFileName", ns->fileName );
932 window_setInput( mapedit_wid, "inpMapName", ns->mapName );
933 window_setInput( mapedit_wid, "inpDescription", ns->description );
934 window_setInput( mapedit_wid, "inpGFX", ns->gfx_store );
935 snprintf( buf, sizeof( buf ), "%i", ns->numSystems );
936 window_modifyText( mapedit_wid, "txtCurrentNumSystems", buf );
937 snprintf( buf, sizeof( buf ), "%" CREDITS_PRI, ns->price );
938 window_setInput( mapedit_wid, "inpPrice", buf );
939 snprintf( buf, sizeof( buf ), "%i", ns->rarity );
940 window_setInput( mapedit_wid, "inpRarity", buf );
941
942 /* Local information. */
943 free( mapedit_sLoadMapName );
944 mapedit_sLoadMapName = strdup( ns->mapName );
945}
946
952static int mapedit_mapsList_refresh( void )
953{
954 int is_map, nSystems;
955 xmlNodePtr node, cur;
956 xmlDocPtr doc;
957 char **map_files;
958 char *file, *name, *outfitType;
959 mapOutfitsList_t *newMapItem;
960
962 mapList = array_create( mapOutfitsList_t );
963
964 map_files = PHYSFS_enumerateFiles( MAP_DATA_PATH );
965 newMapItem = NULL;
966 for (size_t i = 0; map_files[i] != NULL; i++) {
967 char *description = NULL;
968 char *gfx_store = NULL;
969 credits_t price = 1000;
970 int rarity = 0;
971
972 SDL_asprintf( &file, "%s%s", MAP_DATA_PATH, map_files[i] );
973
974 doc = xml_parsePhysFS( file );
975 if (doc == NULL) {
976 free( file );
977 continue;
978 }
979
980 /* Get first node, normally "outfit" */
981 node = doc->xmlChildrenNode;
982 if (node == NULL) {
983 free( file );
984 xmlFreeDoc( doc );
985 return -1;
986 }
987
988 if (!xml_isNode( node, "outfit" )) {
989 free( file );
990 xmlFreeDoc( doc );
991 return -1;
992 }
993
994 /* Get "name" property from the "outfit" node */
995 xmlr_attr_strd( node, "name", name );
996
997 /* Loop on the nodes to find <specific> node */
998 node = node->xmlChildrenNode;
999 do {
1000 is_map = 0;
1001 xml_onlyNodes( node );
1002
1003 if (!xml_isNode( node, "specific" )) {
1004 if (xml_isNode( node, "general" )) {
1005 cur = node->children;
1006 do {
1007 xml_onlyNodes( cur );
1008 xmlr_str( cur, "description", description );
1009 xmlr_long( cur, "price", price );
1010 xmlr_int( cur, "rarity", rarity );
1011 xmlr_str( cur, "gfx_store", gfx_store );
1012 } while (xml_nextNode( cur ));
1013 }
1014 continue;
1015 }
1016
1017 /* Get the "type" property from "specific" node */
1018 xmlr_attr_strd( node, "type", outfitType );
1019 is_map = outfitType == NULL ? 0 : !strncmp( outfitType, "map", 3 );
1020 free( outfitType );
1021
1022 /* Break out of the loop, either with a map or not */
1023 break;
1024 } while (xml_nextNode( node ));
1025
1026 /* If it's not a map, we don't care. */
1027 if (!is_map) {
1028 free( name );
1029 free( file );
1030 xmlFreeDoc( doc );
1031 continue;
1032 }
1033
1034 /* Loop on the nodes to find all <sys> node */
1035 nSystems = 0;
1036 node = node->xmlChildrenNode;
1037 do {
1038 xml_onlyNodes( node );
1039 if (!xml_isNode( node, "sys" ))
1040 continue;
1041
1042 /* Display "name" property from "sys" node and increment number of
1043 * systems found */
1044 nSystems++;
1045 } while (xml_nextNode( node ));
1046
1047 /* If the map is a regular one, then load it into the list */
1048 if (nSystems > 0) {
1049 newMapItem = &array_grow( &mapList );
1050 newMapItem->numSystems = nSystems;
1051 newMapItem->fileName = strdup( map_files[i] );
1052 newMapItem->mapName = strdup( name );
1053 newMapItem->description =
1054 strdup( ( description != NULL ) ? description : "" );
1055 newMapItem->gfx_store =
1056 strdup( ( gfx_store != NULL ) ? gfx_store : "" );
1057 newMapItem->price = price;
1058 newMapItem->rarity = rarity;
1059 }
1060
1061 /* Clean up. */
1062 free( name );
1063 free( file );
1064 free( description );
1065 free( gfx_store );
1066 }
1067
1068 /* Clean up. */
1069 PHYSFS_freeList( map_files );
1070
1071 return 0;
1072}
1073
1077static void mapsList_free( void )
1078{
1079 unsigned int n = array_size( mapList );
1080 for (unsigned int i = 0; i < n; i++) {
1081 free( mapList[i].fileName );
1082 free( mapList[i].mapName );
1083 free( mapList[i].description );
1084 free( mapList[i].gfx_store );
1085 }
1086 array_free( mapList );
1087 mapList = NULL;
1088
1089 free( mapedit_sLoadMapName );
1090 mapedit_sLoadMapName = NULL;
1091}
1092
1098static int mapedit_saveMap( StarSystem **uniedit_sys, mapOutfitsList_t *ns )
1099{
1100 xmlDocPtr doc;
1101 xmlTextWriterPtr writer;
1102 char *file;
1103 int ret = 0;
1104
1105 if (conf.dev_data_dir == NULL) {
1106 WARN( _( "%s is not set!" ), "conf.dev_data_dir" );
1107 return -1;
1108 }
1109
1110 /* Create the writer. */
1111 writer = xmlNewTextWriterDoc( &doc, 0 );
1112 if (writer == NULL) {
1113 WARN( _( "testXmlwriterDoc: Error creating the xml writer" ) );
1114 return -1;
1115 }
1116
1117 /* Set the writer parameters. */
1118 xmlw_setParams( writer );
1119
1120 /* Start writer. */
1121 xmlw_start( writer );
1122 xmlw_startElem( writer, "outfit" );
1123
1124 /* Attributes. */
1125 xmlw_attr( writer, "name", "%s", ns->mapName );
1126
1127 /* General. */
1128 xmlw_startElem( writer, "general" );
1129 xmlw_elem( writer, "rarity", "%d", ns->rarity );
1130 xmlw_elem( writer, "mass", "%d", 0 );
1131 xmlw_elem( writer, "price", "%" CREDITS_PRI, ns->price );
1132 xmlw_elem( writer, "description", "%s", ns->description );
1133 xmlw_elem( writer, "gfx_store", "%s", ns->gfx_store );
1134 xmlw_endElem( writer ); /* "general" */
1135
1136 xmlw_startElem( writer, "specific" );
1137 xmlw_attr( writer, "type", "map" );
1138
1139 /* Iterate over all selected systems. Save said systems and any NORMAL jumps
1140 * they might share. */
1141 for (int i = 0; i < ns->numSystems; i++) {
1142 StarSystem *s = uniedit_sys[i];
1143 xmlw_startElem( writer, "sys" );
1144 xmlw_attr( writer, "name", "%s", s->name );
1145
1146 /* Iterate jumps and see if they lead to any other systems in our array.
1147 */
1148 for (int j = 0; j < array_size( s->jumps ); j++) {
1149 /* Ignore hidden and exit-only jumps. */
1150 if (jp_isFlag( &s->jumps[j], JP_EXITONLY ))
1151 continue;
1152 if (!mapedit_hidden && jp_isFlag( &s->jumps[j], JP_HIDDEN ))
1153 continue;
1154 /* This is a normal jump. */
1155 for (int k = 0; k < ns->numSystems; k++) {
1156 if (s->jumps[j].target == uniedit_sys[k]) {
1157 xmlw_elem( writer, "jump", "%s", uniedit_sys[k]->name );
1158 break;
1159 }
1160 }
1161 }
1162
1163 /* Iterate spobs and add them */
1164 if (!mapedit_nospob)
1165 for (int j = 0; j < array_size( s->spobs ); j++)
1166 xmlw_elem( writer, "spob", "%s", s->spobs[j]->name );
1167
1168 xmlw_endElem( writer ); /* "sys" */
1169 }
1170
1171 xmlw_endElem( writer ); /* "specific" */
1172 xmlw_endElem( writer ); /* "outfit" */
1173 xmlw_done( writer );
1174
1175 /* No need for writer anymore. */
1176 xmlFreeTextWriter( writer );
1177
1178 /* Actually write data */
1179 SDL_asprintf( &file, "%s/outfits/maps/%s", conf.dev_data_dir, ns->fileName );
1180 if (xmlSaveFileEnc( file, doc, "UTF-8" ) < 0) {
1181 WARN( _( "Failed writing '%s'!" ), file );
1182 ret = -1;
1183 }
1184 free( file );
1185
1186 /* Clean up. */
1187 xmlFreeDoc( doc );
1188
1189 return ret;
1190}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
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_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
#define BUTTON_HEIGHT
Definition board.c:28
#define BUTTON_WIDTH
Definition board.c:27
static int mapedit_mapsList_refresh(void)
Gets the list of all the maps names. from outfit_mapParse()
static void mapedit_focusLose(unsigned int wid, const char *wgtname)
Called when it's de-focused.
static int mapedit_msys
Definition dev_mapedit.c:89
static int mapedit_keys(unsigned int wid, SDL_Keycode key, SDL_Keymod mod, int isrepeat)
Handles keybindings.
static void mapedit_buttonZoom(unsigned int wid, const char *str)
Handles the button zoom clicks.
static void mapedit_selectRm(StarSystem *sys)
Removes a system from the selection.
static void mapedit_btnOpen(unsigned int wid_unused, const char *unused)
Opens up a map file.
void mapedit_open(unsigned int wid_unused, const char *unused)
Opens the system editor interface.
static unsigned int mapedit_wid
Definition dev_mapedit.c:77
static char * mapedit_sLoadMapName
Definition dev_mapedit.c:93
#define MAPEDIT_OPEN_WIDTH
Definition dev_mapedit.c:56
static StarSystem ** mapedit_sys
Definition dev_mapedit.c:84
static void mapedit_loadMapMenu_update(unsigned int wdw, const char *str)
Updates the load menu.
static int mapedit_tadd
Definition dev_mapedit.c:87
static int mapedit_nospob
Definition dev_mapedit.c:94
static int mapedit_moved
Definition dev_mapedit.c:81
#define MAPEDIT_ZOOM_MIN
Definition dev_mapedit.c:54
static void mapedit_loadMapMenu_load(unsigned int wdw, const char *str)
Load the selected Map.
static int mapedit_hidden
Definition dev_mapedit.c:95
static double mapedit_zoom
Definition dev_mapedit.c:80
static int mapedit_mouse(unsigned int wid, const SDL_Event *event, double mx, double my, double w, double h, double xr, double yr, void *data)
System editor custom widget mouse handling.
static int mapedit_saveMap(StarSystem **uniedit_sys, mapOutfitsList_t *ns)
Saves selected systems as a map outfit file.
static unsigned int mapedit_widLoad
Definition dev_mapedit.c:92
static void mapedit_btnSaveMapAs(unsigned int wid_unused, const char *unused)
Save the current Map to selected file.
#define MAPEDIT_OPEN_TXT_WIDTH
Definition dev_mapedit.c:58
void mapedit_selectText(void)
Sets the selected system text.
static double mapedit_xpos
Definition dev_mapedit.c:78
static double mapedit_my
Definition dev_mapedit.c:91
static void mapedit_loadMapMenu_close(unsigned int wdw, const char *str)
Closes the load map outfit menu.
StarSystem * systems_stack
Definition space.c:94
static void mapedit_selectAdd(StarSystem *sys)
Adds a system to the selection.
static void mapsList_free(void)
Frees the loaded map.
void mapedit_setGlobalLoadedInfos(mapOutfitsList_t *ns)
Set and display the global variables describing last loaded/saved file.
static void mapedit_loadMapMenu_open(void)
Opens the load map outfit menu.
static unsigned int mapedit_dragTime
Definition dev_mapedit.c:82
static int mapedit_iLastClickedSystem
Definition dev_mapedit.c:85
static void mapedit_clear(unsigned int wid_unused, const char *unused)
Closes the system editor widget.
#define MAPEDIT_ZOOM_MAX
Definition dev_mapedit.c:53
#define MAPEDIT_OPEN_HEIGHT
Definition dev_mapedit.c:57
static double mapedit_mx
Definition dev_mapedit.c:90
static void mapedit_deselect(void)
Deselects selected targets.
static double mapedit_ypos
Definition dev_mapedit.c:79
static int mapedit_nsys
Definition dev_mapedit.c:88
static void mapedit_render(double bx, double by, double w, double h, void *data)
System editor custom widget rendering.
#define MAPEDIT_ZOOM_STEP
Definition dev_mapedit.c:52
static int mapedit_drag
Definition dev_mapedit.c:83
static void mapedit_close(unsigned int wid, const char *wgt)
Closes the system editor widget.
static StarSystem ** uniedit_sys
glFont gl_smallFont
Definition font.c:159
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define ABS(x)
Definition naev.h:32
#define pow2(x)
Definition naev.h:53
#define MAX(x, y)
Definition naev.h:37
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:102
void xmlw_setParams(xmlTextWriterPtr writer)
Sets up the standard xml write parameters.
Definition nxml.c:59
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:70
void gl_renderCircle(double cx, double cy, double r, const glColour *c, int filled)
Draws a circle.
void pause_game(void)
Pauses the game.
Definition pause.c:25
void unpause_game(void)
Unpauses the game.
Definition pause.c:43
void systems_reconstructJumps(void)
Reconstructs the jumps.
Definition space.c:2990
StarSystem * system_getIndex(int id)
Get the system by its index.
Definition space.c:1038
unsigned int window_create(const char *name, const char *displayname, const int x, const int y, const int w, const int h)
Creates a window.
Definition toolkit.c:688
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition toolkit.c:2488
void window_setAccept(unsigned int wid, void(*accept)(unsigned int, const char *))
Sets the default accept function of the window.
Definition toolkit.c:846
void window_setCancel(unsigned int wid, void(*cancel)(unsigned int, const char *))
Sets the default cancel function of the window.
Definition toolkit.c:868
void window_handleKeys(unsigned int wid, int(*keyhandler)(unsigned int, SDL_Keycode, SDL_Keymod, int))
Sets the key handler for the window.
Definition toolkit.c:961
void window_close(unsigned int wid, const char *str)
Helper function to automatically close the window calling it.
Definition toolkit.c:1028
void window_destroy(unsigned int wid)
Kills the window.
Definition toolkit.c:1039
void diff_clear(void)
Removes all active diffs. (Call before economy_destroy().)
Definition unidiff.c:1858