Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | /* |
2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
3 | * described in COPYING.txt. |
||
4 | * Portions of this file are copyright Parallax Software and licensed |
||
5 | * according to the Parallax license below. |
||
6 | * See COPYING.txt for license details. |
||
7 | |||
8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
17 | COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
18 | */ |
||
19 | |||
20 | /* |
||
21 | * |
||
22 | * Editor loop for Inferno |
||
23 | * |
||
24 | */ |
||
25 | |||
26 | //#define DEMO 1 |
||
27 | |||
28 | #define DIAGNOSTIC_MESSAGE_MAX 90 |
||
29 | #define EDITOR_STATUS_MESSAGE_DURATION 4 // Shows for 3+..4 seconds |
||
30 | |||
31 | #include <stdio.h> |
||
32 | #include <stdlib.h> |
||
33 | #include <stdarg.h> |
||
34 | #include <string.h> |
||
35 | #include <time.h> |
||
36 | |||
37 | #include "inferno.h" |
||
38 | #include "args.h" |
||
39 | #include "segment.h" |
||
40 | #include "gr.h" |
||
41 | #include "palette.h" |
||
42 | #include "physfsx.h" |
||
43 | #include "event.h" |
||
44 | #include "window.h" |
||
45 | #include "game.h" |
||
46 | #include "messagebox.h" |
||
47 | #include "ui.h" |
||
48 | #include "editor.h" |
||
49 | #include "editor/esegment.h" |
||
50 | #include "state.h" |
||
51 | #include "gamesave.h" |
||
52 | #include "gameseg.h" |
||
53 | #include "key.h" |
||
54 | #include "kconfig.h" |
||
55 | #include "mouse.h" |
||
56 | #include "dxxerror.h" |
||
57 | #include "kfuncs.h" |
||
58 | #include "macro.h" |
||
59 | #ifdef INCLUDE_XLISP |
||
60 | #include "medlisp.h" |
||
61 | #endif |
||
62 | #include "u_mem.h" |
||
63 | #include "render.h" |
||
64 | #include "game.h" |
||
65 | #include "gamefont.h" |
||
66 | #include "menu.h" |
||
67 | #include "slew.h" |
||
68 | #include "player.h" |
||
69 | #include "kdefs.h" |
||
70 | #include "func.h" |
||
71 | #include "textures.h" |
||
72 | #include "screens.h" |
||
73 | #include "texmap.h" |
||
74 | #include "object.h" |
||
75 | #include "effects.h" |
||
76 | #include "info.h" |
||
77 | #include "ai.h" |
||
78 | #include "console.h" |
||
79 | #include "texpage.h" // Textue selection paging stuff |
||
80 | #include "objpage.h" // Object selection paging stuff |
||
81 | #include "d_enumerate.h" |
||
82 | |||
83 | #include "medmisc.h" |
||
84 | #include "meddraw.h" |
||
85 | #include "medsel.h" |
||
86 | #include "medrobot.h" |
||
87 | #include "medwall.h" |
||
88 | #include "eswitch.h" |
||
89 | #include "ehostage.h" |
||
90 | #include "centers.h" |
||
91 | |||
92 | #include "fuelcen.h" |
||
93 | #include "gameseq.h" |
||
94 | #include "mission.h" |
||
95 | #include "newmenu.h" |
||
96 | |||
97 | #if defined(DXX_BUILD_DESCENT_II) |
||
98 | #include "gamepal.h" |
||
99 | #endif |
||
100 | |||
101 | #include "dxxsconf.h" |
||
102 | #include "compiler-range_for.h" |
||
103 | |||
104 | //#define _MARK_ON 1 |
||
105 | //#include <wsample.h> //should come after inferno.h to get mark setting //Not included here. |
||
106 | |||
107 | #define COMPRESS_INTERVAL 5 // seconds |
||
108 | |||
109 | static void med_show_warning(const char *s); |
||
110 | |||
111 | //char *undo_status[128]; |
||
112 | |||
113 | int initializing; |
||
114 | |||
115 | //these are instances of canvases, pointed to by variables below |
||
116 | grs_canvas _canv_editor_game, _canv_editor; //the game on the editor screen, the canvas that the editor writes to |
||
117 | |||
118 | //these are pointers to our canvases |
||
119 | grs_canvas *Canv_editor; //the editor screen |
||
120 | grs_canvas *const Canv_editor_game = &_canv_editor_game; //the game on the editor screen |
||
121 | |||
122 | window *Pad_info; // Keypad text |
||
123 | |||
124 | grs_font_ptr editor_font; |
||
125 | |||
126 | //where the editor is looking |
||
127 | vms_vector Ed_view_target; |
||
128 | |||
129 | editor_gamestate gamestate = editor_gamestate::none; |
||
130 | |||
131 | UI_DIALOG * EditorWindow = NULL; |
||
132 | |||
133 | int Large_view_index = -1; |
||
134 | |||
135 | std::unique_ptr<UI_GADGET_USERBOX> GameViewBox, LargeViewBox, GroupViewBox; |
||
136 | |||
137 | #if ORTHO_VIEWS |
||
138 | UI_GADGET_USERBOX * TopViewBox; |
||
139 | UI_GADGET_USERBOX * FrontViewBox; |
||
140 | UI_GADGET_USERBOX * RightViewBox; |
||
141 | #endif |
||
142 | |||
143 | static std::unique_ptr<UI_GADGET_ICON> |
||
144 | ViewIcon, |
||
145 | AllIcon, |
||
146 | AxesIcon, |
||
147 | ChaseIcon, |
||
148 | OutlineIcon, |
||
149 | LockIcon; |
||
150 | |||
151 | //grs_canvas * BigCanvas[2]; |
||
152 | //int CurrentBigCanvas = 0; |
||
153 | //int BigCanvasFirstTime = 1; |
||
154 | |||
155 | int Found_seg_index=0; // Index in Found_segs corresponding to Cursegp |
||
156 | |||
157 | namespace { |
||
158 | |||
159 | class editor_dialog |
||
160 | { |
||
161 | public: |
||
162 | std::array<std::unique_ptr<UI_GADGET_BUTTON>, 9> pad_goto; |
||
163 | std::unique_ptr<UI_GADGET_BUTTON> |
||
164 | pad_prev, |
||
165 | pad_next; |
||
166 | }; |
||
167 | |||
168 | } |
||
169 | |||
170 | static editor_dialog editor_window; |
||
171 | |||
172 | static void print_status_bar(const std::array<char, DIAGNOSTIC_MESSAGE_MAX> &message) |
||
173 | { |
||
174 | gr_set_default_canvas(); |
||
175 | auto &canvas = *grd_curcanv; |
||
176 | const auto &editor_font = *::editor_font; |
||
177 | gr_set_fontcolor(canvas, CBLACK, CGREY); |
||
178 | int w,h; |
||
179 | gr_get_string_size(editor_font, message.data(), &w, &h, nullptr); |
||
180 | gr_string(canvas, editor_font, 4, 583, message.data(), w, h); |
||
181 | gr_set_fontcolor(canvas, CBLACK, CWHITE); |
||
182 | gr_rect(canvas, 4+w, 583, 799, 599, CGREY); |
||
183 | } |
||
184 | |||
185 | static std::array<char, DIAGNOSTIC_MESSAGE_MAX> status_line; |
||
186 | |||
187 | struct tm Editor_status_last_time; |
||
188 | |||
189 | void (editor_status_fmt)( const char *format, ... ) |
||
190 | { |
||
191 | va_list ap; |
||
192 | |||
193 | va_start(ap, format); |
||
194 | vsnprintf(status_line.data(), status_line.size(), format, ap); |
||
195 | va_end(ap); |
||
196 | |||
197 | Editor_status_last_time = Editor_time_of_day; |
||
198 | } |
||
199 | |||
200 | void editor_status( const char *text) |
||
201 | { |
||
202 | Editor_status_last_time = Editor_time_of_day; |
||
203 | strcpy(status_line.data(), text); |
||
204 | } |
||
205 | |||
206 | // int tm_sec; /* seconds after the minute -- [0,61] */ |
||
207 | // int tm_min; /* minutes after the hour -- [0,59] */ |
||
208 | // int tm_hour; /* hours after midnight -- [0,23] */ |
||
209 | // int tm_mday; /* day of the month -- [1,31] */ |
||
210 | // int tm_mon; /* months since January -- [0,11] */ |
||
211 | // int tm_year; /* years since 1900 */ |
||
212 | // int tm_wday; /* days since Sunday -- [0,6] */ |
||
213 | // int tm_yday; /* days since January 1 -- [0,365]*/ |
||
214 | // int tm_isdst; /* Daylight Savings Time flag */ |
||
215 | |||
216 | static void clear_editor_status(void) |
||
217 | { |
||
218 | int cur_time = Editor_time_of_day.tm_hour * 3600 + Editor_time_of_day.tm_min*60 + Editor_time_of_day.tm_sec; |
||
219 | int erase_time = Editor_status_last_time.tm_hour * 3600 + Editor_status_last_time.tm_min*60 + Editor_status_last_time.tm_sec + EDITOR_STATUS_MESSAGE_DURATION; |
||
220 | |||
221 | if (cur_time > erase_time) { |
||
222 | std::fill(status_line.begin(), std::prev(status_line.end()), ' '); |
||
223 | status_line.back() = 0; |
||
224 | Editor_status_last_time.tm_hour = 99; |
||
225 | } |
||
226 | } |
||
227 | |||
228 | static inline void editor_slew_init() |
||
229 | { |
||
230 | auto &Objects = LevelUniqueObjectState.Objects; |
||
231 | auto &vmobjptr = Objects.vmptr; |
||
232 | Viewer = ConsoleObject; |
||
233 | slew_init(vmobjptr(ConsoleObject)); |
||
234 | init_player_object(); |
||
235 | } |
||
236 | |||
237 | int DropIntoDebugger() |
||
238 | { |
||
239 | Int3(); |
||
240 | return 1; |
||
241 | } |
||
242 | |||
243 | |||
244 | #ifdef INCLUDE_XLISP |
||
245 | int CallLisp() |
||
246 | { |
||
247 | medlisp_go(); |
||
248 | return 1; |
||
249 | } |
||
250 | #endif |
||
251 | |||
252 | |||
253 | int ExitEditor() |
||
254 | { |
||
255 | if (SafetyCheck()) { |
||
256 | ModeFlag = 1; |
||
257 | } |
||
258 | return 1; |
||
259 | } |
||
260 | |||
261 | int GotoGameScreen() |
||
262 | { |
||
263 | auto &Objects = LevelUniqueObjectState.Objects; |
||
264 | auto &vmobjptr = Objects.vmptr; |
||
265 | pause_game_world_time p; |
||
266 | |||
267 | //@@ init_player_stats(); |
||
268 | //@@ |
||
269 | //@@ Player_init.pos = Player->pos; |
||
270 | //@@ Player_init.orient = Player->orient; |
||
271 | //@@ Player_init.segnum = Player->segnum; |
||
272 | |||
273 | |||
274 | // -- must always save gamesave.sge/lvl because the restore-objects code relies on it |
||
275 | // -- that code could be made smarter and use the original file, if appropriate. |
||
276 | // if (mine_changed) |
||
277 | switch (gamestate) |
||
278 | { |
||
279 | case editor_gamestate::none: |
||
280 | // Always use the simple mission when playing level (for now at least) |
||
281 | create_new_mission(); |
||
282 | Current_level_num = 1; |
||
283 | if (save_level( |
||
284 | #if defined(DXX_BUILD_DESCENT_II) |
||
285 | LevelSharedSegmentState.DestructibleLights, |
||
286 | #endif |
||
287 | "GAMESAVE.LVL")) |
||
288 | return 0; |
||
289 | editor_status("Level saved.\n"); |
||
290 | break; |
||
291 | |||
292 | case editor_gamestate::unsaved: |
||
293 | case editor_gamestate::saved: |
||
294 | if (!SafetyCheck()) // if mine edited but not saved, warn the user! |
||
295 | return 0; |
||
296 | |||
297 | const auto &&console = vmobjptr(get_local_player().objnum); |
||
298 | Viewer = ConsoleObject = console; |
||
299 | set_player_id(console, Player_num); |
||
300 | fly_init(*ConsoleObject); |
||
301 | |||
302 | if (!state_save_all_sub(PLAYER_DIRECTORY_STRING("gamesave.sge"), "Editor generated")) |
||
303 | { |
||
304 | editor_slew_init(); |
||
305 | |||
306 | return 0; |
||
307 | } |
||
308 | gamestate = editor_gamestate::saved; |
||
309 | editor_status("Game saved.\n"); |
||
310 | break; |
||
311 | } |
||
312 | |||
313 | ModeFlag = 3; |
||
314 | return 1; |
||
315 | } |
||
316 | |||
317 | int GotoMainMenu() |
||
318 | { |
||
319 | ModeFlag = 2; |
||
320 | return 1; |
||
321 | } |
||
322 | |||
323 | static std::array<int (*)(), 2048> KeyFunction; |
||
324 | |||
325 | static void medkey_init() |
||
326 | { |
||
327 | char keypress[100]; |
||
328 | int key; |
||
329 | int np; |
||
330 | char LispCommand[DIAGNOSTIC_MESSAGE_MAX]; |
||
331 | |||
332 | KeyFunction = {}; |
||
333 | |||
334 | if (auto keyfile = PHYSFSX_openReadBuffered("GLOBAL.KEY")) |
||
335 | { |
||
336 | PHYSFSX_gets_line_t<200> line_buffer; |
||
337 | while (PHYSFSX_fgets(line_buffer, keyfile)) |
||
338 | { |
||
339 | sscanf(line_buffer, " %s %s ", keypress, LispCommand); |
||
340 | //ReadLispMacro( keyfile, LispCommand ); |
||
341 | |||
342 | if ( (key=DecodeKeyText( keypress ))!= -1 ) |
||
343 | { |
||
344 | Assert( key < 2048); |
||
345 | KeyFunction[key] = func_get( LispCommand, &np ); |
||
346 | } else { |
||
347 | UserError( "Bad key %s in GLOBAL.KEY!", keypress ); |
||
348 | } |
||
349 | } |
||
350 | } |
||
351 | } |
||
352 | |||
353 | static int padnum=0; |
||
354 | //@@short camera_objnum; //a camera for viewing. Who knows, might become handy |
||
355 | |||
356 | static void init_editor_screen(grs_canvas &canvas); |
||
357 | static void gamestate_restore_check(); |
||
358 | static window_event_result editor_handler(UI_DIALOG *dlg,const d_event &event, unused_ui_userdata_t *data); |
||
359 | static void close_editor(); |
||
360 | |||
361 | namespace dsx { |
||
362 | void init_editor() |
||
363 | { |
||
364 | static const char pads[][13] = { |
||
365 | "segmove.pad", |
||
366 | "segsize.pad", |
||
367 | "curve.pad", |
||
368 | "texture.pad", |
||
369 | "object.pad", |
||
370 | "objmov.pad", |
||
371 | "group.pad", |
||
372 | "lighting.pad", |
||
373 | "test.pad" |
||
374 | }; |
||
375 | ModeFlag = Game_wind ? 3 : 2; // go back to where we were unless we loaded everything properly |
||
376 | |||
377 | // first, make sure we can find the files we need |
||
378 | PHYSFSX_addRelToSearchPath("editor/data", 1); // look in source directory first (for work in progress) |
||
379 | PHYSFSX_addRelToSearchPath("editor", 1); // then in editor directory |
||
380 | PHYSFSX_addRelToSearchPath("editor.zip", 1); // then in a zip file |
||
381 | PHYSFSX_addRelToSearchPath("editor.dxa", 1); // or addon pack |
||
382 | |||
383 | if (!ui_init()) |
||
384 | { |
||
385 | close_editor(); |
||
386 | return; |
||
387 | } |
||
388 | |||
389 | init_med_functions(); // Must be called before medlisp_init |
||
390 | |||
391 | range_for (auto &&e, enumerate(pads)) |
||
392 | if (!ui_pad_read(e.idx, e.value)) |
||
393 | { |
||
394 | close_editor(); |
||
395 | return; |
||
396 | } |
||
397 | |||
398 | medkey_init(); |
||
399 | |||
400 | game_flush_inputs(); |
||
401 | |||
402 | editor_font = gr_init_font(*grd_curcanv, "pc8x16.fnt"); |
||
403 | if (!editor_font) |
||
404 | { |
||
405 | Warning("Could not find pc8x16.fnt"); |
||
406 | close_editor(); |
||
407 | return; |
||
408 | } |
||
409 | |||
410 | if (!menubar_init(*grd_curcanv, "MED.MNU")) |
||
411 | { |
||
412 | close_editor(); |
||
413 | return; |
||
414 | } |
||
415 | |||
416 | Draw_all_segments = 1; // Say draw all segments, not just connected ones |
||
417 | |||
418 | if (!Cursegp) |
||
419 | Cursegp = imsegptridx(segment_first); |
||
420 | |||
421 | init_autosave(); |
||
422 | |||
423 | Clear_window = 1; // do full window clear. |
||
424 | |||
425 | InitCurve(); |
||
426 | |||
427 | restore_effect_bitmap_icons(); |
||
428 | |||
429 | if (!set_screen_mode(SCREEN_EDITOR)) |
||
430 | { |
||
431 | close_editor(); |
||
432 | return; |
||
433 | } |
||
434 | #if defined(DXX_BUILD_DESCENT_I) |
||
435 | gr_use_palette_table( "palette.256" ); |
||
436 | gr_palette_load( gr_palette ); |
||
437 | #elif defined(DXX_BUILD_DESCENT_II) |
||
438 | load_palette(Current_level_palette,1,0); |
||
439 | #endif |
||
440 | |||
441 | //Editor renders into full (320x200) game screen |
||
442 | |||
443 | game_init_render_buffers(320, 200); |
||
444 | gr_init_sub_canvas(_canv_editor, grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT); |
||
445 | Canv_editor = &_canv_editor; |
||
446 | gr_set_current_canvas(*Canv_editor); |
||
447 | init_editor_screen(*grd_curcanv); // load the main editor dialog |
||
448 | gr_set_default_canvas(); |
||
449 | set_warn_func(med_show_warning); |
||
450 | |||
451 | // _MARK_("start of editor");//Nuked to compile -KRB |
||
452 | |||
453 | //@@ //create a camera for viewing in the editor. copy position from ConsoleObject |
||
454 | //@@ camera_objnum = obj_create(OBJ_CAMERA,0,ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0); |
||
455 | //@@ Viewer = &Objects[camera_objnum]; |
||
456 | //@@ slew_init(Viewer); //camera is slewing |
||
457 | |||
458 | editor_slew_init(); |
||
459 | |||
460 | Update_flags = UF_ALL; |
||
461 | |||
462 | //set the wire-frame window to be the current view |
||
463 | current_view = &LargeView; |
||
464 | |||
465 | gr_set_current_canvas( GameViewBox->canvas ); |
||
466 | gr_set_curfont(*grd_curcanv, editor_font); |
||
467 | // No font scaling! |
||
468 | FNTScaleX.reset(1); |
||
469 | FNTScaleY.reset(1); |
||
470 | ui_pad_goto(padnum); |
||
471 | |||
472 | ModeFlag = 0; // success! |
||
473 | |||
474 | gamestate_restore_check(); |
||
475 | } |
||
476 | } |
||
477 | |||
478 | int ShowAbout() |
||
479 | { |
||
480 | ui_messagebox( -2, -2, 1, "INFERNO Mine Editor\n\n" \ |
||
481 | "Copyright (c) 1993 Parallax Software Corp.", |
||
482 | "OK"); |
||
483 | return 0; |
||
484 | } |
||
485 | |||
486 | int SetPlayerFromCurseg() |
||
487 | { |
||
488 | move_player_2_segment(Cursegp,Curside); |
||
489 | Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED; |
||
490 | return 1; |
||
491 | } |
||
492 | |||
493 | int fuelcen_create_from_curseg() |
||
494 | { |
||
495 | Cursegp->special = SEGMENT_IS_FUELCEN; |
||
496 | fuelcen_activate(Cursegp); |
||
497 | return 1; |
||
498 | } |
||
499 | |||
500 | int repaircen_create_from_curseg() |
||
501 | { |
||
502 | Int3(); // -- no longer supported! |
||
503 | // Cursegp->special = SEGMENT_IS_REPAIRCEN; |
||
504 | // fuelcen_activate(Cursegp, Cursegp->special); |
||
505 | return 1; |
||
506 | } |
||
507 | |||
508 | int controlcen_create_from_curseg() |
||
509 | { |
||
510 | Cursegp->special = SEGMENT_IS_CONTROLCEN; |
||
511 | fuelcen_activate(Cursegp); |
||
512 | return 1; |
||
513 | } |
||
514 | |||
515 | int robotmaker_create_from_curseg() |
||
516 | { |
||
517 | Cursegp->special = SEGMENT_IS_ROBOTMAKER; |
||
518 | fuelcen_activate(Cursegp); |
||
519 | return 1; |
||
520 | } |
||
521 | |||
522 | int fuelcen_reset_all() { |
||
523 | fuelcen_reset(); |
||
524 | return 1; |
||
525 | } |
||
526 | |||
527 | int fuelcen_delete_from_curseg() { |
||
528 | fuelcen_delete( Cursegp ); |
||
529 | return 1; |
||
530 | } |
||
531 | |||
532 | |||
533 | //@@//this routine places the viewer in the center of the side opposite to curside, |
||
534 | //@@//with the view toward the center of curside |
||
535 | //@@int SetPlayerFromCursegMinusOne() |
||
536 | //@@{ |
||
537 | //@@ vms_vector vp; |
||
538 | //@@ |
||
539 | //@@// int newseg,newside; |
||
540 | //@@// get_previous_segment(SEG_PTR_2_NUM(Cursegp),Curside,&newseg,&newside); |
||
541 | //@@// move_player_2_segment(&Segments[newseg],newside); |
||
542 | //@@ |
||
543 | //@@ med_compute_center_point_on_side(&Player->obj_position,Cursegp,Side_opposite[Curside]); |
||
544 | //@@ med_compute_center_point_on_side(&vp,Cursegp,Curside); |
||
545 | //@@ vm_vec_sub2(&vp,&Player->position); |
||
546 | //@@ vm_vector_2_matrix(&Player->orient,&vp,NULL,NULL); |
||
547 | //@@ |
||
548 | //@@ Player->seg = SEG_PTR_2_NUM(Cursegp); |
||
549 | //@@ |
||
550 | //@@ Update_flags |= UF_GAME_VIEW_CHANGED; |
||
551 | //@@ return 1; |
||
552 | //@@} |
||
553 | |||
554 | //this constant determines how much of the window will be occupied by the |
||
555 | //viewed side when SetPlayerFromCursegMinusOne() is called. It actually |
||
556 | //determine how from from the center of the window the farthest point will be |
||
557 | #define SIDE_VIEW_FRAC (f1_0*8/10) //80% |
||
558 | |||
559 | |||
560 | static void move_player_2_segment_and_rotate(const vmsegptridx_t seg, const unsigned side) |
||
561 | { |
||
562 | auto &Objects = LevelUniqueObjectState.Objects; |
||
563 | auto &vmobjptr = Objects.vmptr; |
||
564 | auto &vmobjptridx = Objects.vmptridx; |
||
565 | static int edgenum=0; |
||
566 | |||
567 | auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state(); |
||
568 | auto &Vertices = LevelSharedVertexState.get_vertices(); |
||
569 | auto &vcvertptr = Vertices.vcptr; |
||
570 | compute_segment_center(vcvertptr, ConsoleObject->pos,seg); |
||
571 | auto vp = compute_center_point_on_side(vcvertptr, seg, side); |
||
572 | vm_vec_sub2(vp,ConsoleObject->pos); |
||
573 | |||
574 | auto &sv = Side_to_verts[Curside]; |
||
575 | auto &verts = Cursegp->verts; |
||
576 | const auto upvec = vm_vec_sub(vcvertptr(verts[sv[edgenum % 4]]), vcvertptr(verts[sv[(edgenum + 3) % 4]])); |
||
577 | edgenum++; |
||
578 | |||
579 | vm_vector_2_matrix(ConsoleObject->orient,vp,&upvec,nullptr); |
||
580 | // vm_vector_2_matrix(&ConsoleObject->orient,&vp,NULL,NULL); |
||
581 | |||
582 | obj_relink(vmobjptr, vmsegptr, vmobjptridx(ConsoleObject), seg); |
||
583 | } |
||
584 | |||
585 | int SetPlayerFromCursegAndRotate() |
||
586 | { |
||
587 | move_player_2_segment_and_rotate(Cursegp,Curside); |
||
588 | Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED; |
||
589 | return 1; |
||
590 | } |
||
591 | |||
592 | |||
593 | //sets the player facing curseg/curside, normal to face0 of curside, and |
||
594 | //far enough away to see all of curside |
||
595 | int SetPlayerFromCursegMinusOne() |
||
596 | { |
||
597 | auto &Objects = LevelUniqueObjectState.Objects; |
||
598 | auto &vmobjptr = Objects.vmptr; |
||
599 | auto &vmobjptridx = Objects.vmptridx; |
||
600 | std::array<g3s_point, 4> corner_p; |
||
601 | fix max,view_dist=f1_0*10; |
||
602 | static int edgenum=0; |
||
603 | const auto view_vec = vm_vec_negated(Cursegp->shared_segment::sides[Curside].normals[0]); |
||
604 | |||
605 | auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state(); |
||
606 | auto &Vertices = LevelSharedVertexState.get_vertices(); |
||
607 | auto &vcvertptr = Vertices.vcptr; |
||
608 | const auto &&side_center = compute_center_point_on_side(vcvertptr, Cursegp, Curside); |
||
609 | const auto view_vec2 = vm_vec_copy_scale(view_vec,view_dist); |
||
610 | vm_vec_sub(ConsoleObject->pos,side_center,view_vec2); |
||
611 | |||
612 | auto &sv = Side_to_verts[Curside]; |
||
613 | auto &verts = Cursegp->verts; |
||
614 | const auto upvec = vm_vec_sub(vcvertptr(verts[sv[edgenum % 4]]), vcvertptr(verts[sv[(edgenum + 3) % 4]])); |
||
615 | edgenum++; |
||
616 | |||
617 | vm_vector_2_matrix(ConsoleObject->orient,view_vec,&upvec,nullptr); |
||
618 | |||
619 | gr_set_current_canvas(*Canv_editor_game); |
||
620 | g3_start_frame(*grd_curcanv); |
||
621 | g3_set_view_matrix(ConsoleObject->pos,ConsoleObject->orient,Render_zoom); |
||
622 | |||
623 | for (unsigned i = max = 0; i < 4; ++i) |
||
624 | { |
||
625 | g3_rotate_point(corner_p[i], vcvertptr(verts[sv[i]])); |
||
626 | if (labs(corner_p[i].p3_x) > max) max = labs(corner_p[i].p3_x); |
||
627 | if (labs(corner_p[i].p3_y) > max) max = labs(corner_p[i].p3_y); |
||
628 | } |
||
629 | |||
630 | view_dist = fixmul(view_dist,fixdiv(fixdiv(max,SIDE_VIEW_FRAC),corner_p[0].p3_z)); |
||
631 | const auto view_vec3 = vm_vec_copy_scale(view_vec,view_dist); |
||
632 | vm_vec_sub(ConsoleObject->pos,side_center,view_vec3); |
||
633 | |||
634 | //obj_relink(ConsoleObject-Objects, SEG_PTR_2_NUM(Cursegp) ); |
||
635 | //update_object_seg(ConsoleObject); //might have backed right out of curseg |
||
636 | |||
637 | const auto &&newseg = find_point_seg(LevelSharedSegmentState, LevelUniqueSegmentState, ConsoleObject->pos, Cursegp); |
||
638 | if (newseg != segment_none) |
||
639 | obj_relink(vmobjptr, vmsegptr, vmobjptridx(ConsoleObject), newseg); |
||
640 | |||
641 | Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED; |
||
642 | return 1; |
||
643 | } |
||
644 | |||
645 | #if !DXX_USE_OGL |
||
646 | static int ToggleLighting(void) |
||
647 | { |
||
648 | Lighting_on++; |
||
649 | if (Lighting_on >= 2) |
||
650 | Lighting_on = 0; |
||
651 | |||
652 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
653 | |||
654 | switch (Lighting_on) { |
||
655 | case 0: |
||
656 | diagnostic_message("Lighting off."); |
||
657 | break; |
||
658 | case 1: |
||
659 | diagnostic_message("Static lighting."); |
||
660 | break; |
||
661 | case 2: |
||
662 | diagnostic_message("Ship lighting."); |
||
663 | break; |
||
664 | case 3: |
||
665 | diagnostic_message("Ship and static lighting."); |
||
666 | break; |
||
667 | } |
||
668 | |||
669 | return Lighting_on; |
||
670 | } |
||
671 | #endif |
||
672 | |||
673 | int FindConcaveSegs() |
||
674 | { |
||
675 | find_concave_segs(); |
||
676 | |||
677 | Update_flags |= UF_ED_STATE_CHANGED; //list may have changed |
||
678 | |||
679 | return 1; |
||
680 | } |
||
681 | |||
682 | static int ToggleOutlineMode() |
||
683 | { |
||
684 | #ifndef NDEBUG |
||
685 | int mode; |
||
686 | |||
687 | mode=toggle_outline_mode(); |
||
688 | |||
689 | if (mode) |
||
690 | { |
||
691 | //if (keypress != KEY_O) |
||
692 | diagnostic_message("[Ctrl-O] Outline Mode ON."); |
||
693 | //else |
||
694 | // diagnostic_message("Outline Mode ON."); |
||
695 | } |
||
696 | else |
||
697 | { |
||
698 | //if (keypress != KEY_O) |
||
699 | diagnostic_message("[Ctrl-O] Outline Mode OFF."); |
||
700 | //else |
||
701 | // diagnostic_message("Outline Mode OFF."); |
||
702 | } |
||
703 | |||
704 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
705 | return mode; |
||
706 | #else |
||
707 | return 1; |
||
708 | #endif |
||
709 | } |
||
710 | |||
711 | //@@int do_reset_orient() |
||
712 | //@@{ |
||
713 | //@@ slew_reset_orient(SlewObj); |
||
714 | //@@ |
||
715 | //@@ Update_flags |= UF_GAME_VIEW_CHANGED; |
||
716 | //@@ |
||
717 | //@@ * reinterpret_cast<uint8_t *>(0x417) &= ~0x20; |
||
718 | //@@ |
||
719 | //@@ return 1; |
||
720 | //@@} |
||
721 | |||
722 | int GameZoomOut() |
||
723 | { |
||
724 | Render_zoom = fixmul(Render_zoom,68985); |
||
725 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
726 | return 1; |
||
727 | } |
||
728 | |||
729 | int GameZoomIn() |
||
730 | { |
||
731 | Render_zoom = fixmul(Render_zoom,62259); |
||
732 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
733 | return 1; |
||
734 | } |
||
735 | |||
736 | |||
737 | static int med_keypad_goto_0() { ui_pad_goto(0); return 0; } |
||
738 | static int med_keypad_goto_1() { ui_pad_goto(1); return 0; } |
||
739 | static int med_keypad_goto_2() { ui_pad_goto(2); return 0; } |
||
740 | static int med_keypad_goto_3() { ui_pad_goto(3); return 0; } |
||
741 | static int med_keypad_goto_4() { ui_pad_goto(4); return 0; } |
||
742 | static int med_keypad_goto_5() { ui_pad_goto(5); return 0; } |
||
743 | static int med_keypad_goto_6() { ui_pad_goto(6); return 0; } |
||
744 | static int med_keypad_goto_7() { ui_pad_goto(7); return 0; } |
||
745 | static int med_keypad_goto_8() { ui_pad_goto(8); return 0; } |
||
746 | |||
747 | #define PAD_WIDTH 30 |
||
748 | #define PAD_WIDTH1 (PAD_WIDTH + 7) |
||
749 | |||
750 | int editor_screen_open = 0; |
||
751 | |||
752 | //setup the editors windows, canvases, gadgets, etc. |
||
753 | static void init_editor_screen(grs_canvas &canvas) |
||
754 | { |
||
755 | // grs_bitmap * bmp; |
||
756 | |||
757 | if (editor_screen_open) return; |
||
758 | |||
759 | grd_curscreen->sc_canvas.cv_font = editor_font.get(); |
||
760 | |||
761 | //create canvas for game on the editor screen |
||
762 | initializing = 1; |
||
763 | gr_set_current_canvas(*Canv_editor); |
||
764 | Canv_editor->cv_font = editor_font.get(); |
||
765 | gr_init_sub_canvas(*Canv_editor_game, *Canv_editor, GAMEVIEW_X, GAMEVIEW_Y, GAMEVIEW_W, GAMEVIEW_H); |
||
766 | |||
767 | //Editor renders into full (320x200) game screen |
||
768 | |||
769 | init_info = 1; |
||
770 | |||
771 | //do other editor screen setup |
||
772 | |||
773 | // Since the palette might have changed, find some good colors... |
||
774 | CBLACK = gr_find_closest_color( 1, 1, 1 ); |
||
775 | CGREY = gr_find_closest_color( 28, 28, 28 ); |
||
776 | CWHITE = gr_find_closest_color( 38, 38, 38 ); |
||
777 | CBRIGHT = gr_find_closest_color( 60, 60, 60 ); |
||
778 | CRED = gr_find_closest_color( 63, 0, 0 ); |
||
779 | |||
780 | gr_set_curfont(canvas, editor_font); |
||
781 | gr_set_fontcolor(canvas, CBLACK, CWHITE); |
||
782 | |||
783 | EditorWindow = ui_create_dialog( 0 , 0, ED_SCREEN_W, ED_SCREEN_H, DF_FILLED, editor_handler, unused_ui_userdata ); |
||
784 | |||
785 | LargeViewBox = ui_add_gadget_userbox( EditorWindow,LVIEW_X,LVIEW_Y,LVIEW_W,LVIEW_H); |
||
786 | #if ORTHO_VIEWS |
||
787 | TopViewBox = ui_add_gadget_userbox( EditorWindow,TVIEW_X,TVIEW_Y,TVIEW_W,TVIEW_H); |
||
788 | FrontViewBox = ui_add_gadget_userbox( EditorWindow,FVIEW_X,FVIEW_Y,FVIEW_W,FVIEW_H); |
||
789 | RightViewBox = ui_add_gadget_userbox( EditorWindow,RVIEW_X,RVIEW_Y,RVIEW_W,RVIEW_H); |
||
790 | #endif |
||
791 | ui_gadget_calc_keys(EditorWindow); //make tab work for all windows |
||
792 | |||
793 | GameViewBox = ui_add_gadget_userbox( EditorWindow, GAMEVIEW_X, GAMEVIEW_Y, GAMEVIEW_W, GAMEVIEW_H ); |
||
794 | // GroupViewBox = ui_add_gadget_userbox( EditorWindow,GVIEW_X,GVIEW_Y,GVIEW_W,GVIEW_H); |
||
795 | |||
796 | // GameViewBox->when_tab = GameViewBox->when_btab = LargeViewBox; |
||
797 | // LargeViewBox->when_tab = LargeViewBox->when_btab = GameViewBox; |
||
798 | |||
799 | // ui_gadget_calc_keys(EditorWindow); //make tab work for all windows |
||
800 | |||
801 | ViewIcon = ui_add_gadget_icon( EditorWindow, "Lock\nview", 455,25+530, 40, 22, KEY_V+KEY_CTRLED, ToggleLockViewToCursegp ); |
||
802 | AllIcon = ui_add_gadget_icon( EditorWindow, "Draw\nall", 500,25+530, 40, 22, -1, ToggleDrawAllSegments ); |
||
803 | AxesIcon = ui_add_gadget_icon( EditorWindow, "Coord\naxes",545,25+530, 40, 22, KEY_D+KEY_CTRLED, ToggleCoordAxes ); |
||
804 | ChaseIcon = ui_add_gadget_icon( EditorWindow, "Chase\nmode",635,25+530, 40, 22, -1, ToggleChaseMode ); |
||
805 | OutlineIcon = ui_add_gadget_icon( EditorWindow, "Out\nline", 680,25+530, 40, 22, KEY_O+KEY_CTRLED, ToggleOutlineMode ); |
||
806 | LockIcon = ui_add_gadget_icon( EditorWindow, "Lock\nstep", 725,25+530, 40, 22, KEY_L+KEY_CTRLED, ToggleLockstep ); |
||
807 | |||
808 | meddraw_init_views(LargeViewBox->canvas.get()); |
||
809 | |||
810 | //ui_add_gadget_button( EditorWindow, 460, 510, 50, 25, "Quit", ExitEditor ); |
||
811 | //ui_add_gadget_button( EditorWindow, 520, 510, 50, 25, "Lisp", CallLisp ); |
||
812 | //ui_add_gadget_button( EditorWindow, 580, 510, 50, 25, "Mine", MineMenu ); |
||
813 | //ui_add_gadget_button( EditorWindow, 640, 510, 50, 25, "Help", DoHelp ); |
||
814 | //ui_add_gadget_button( EditorWindow, 460, 540, 50, 25, "Macro", MacroMenu ); |
||
815 | //ui_add_gadget_button( EditorWindow, 520, 540, 50, 25, "About", ShowAbout ); |
||
816 | //ui_add_gadget_button( EditorWindow, 640, 540, 50, 25, "Shell", DosShell ); |
||
817 | |||
818 | auto &e = editor_window; |
||
819 | |||
820 | ui_pad_activate(*EditorWindow, PAD_X, PAD_Y); |
||
821 | Pad_info = info_window_create(); |
||
822 | e.pad_prev = ui_add_gadget_button( EditorWindow, PAD_X+6, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "<<", med_keypad_goto_prev ); |
||
823 | e.pad_next = ui_add_gadget_button( EditorWindow, PAD_X+PAD_WIDTH1+6, PAD_Y+(30*5)+22, PAD_WIDTH, 20, ">>", med_keypad_goto_next ); |
||
824 | |||
825 | { int i; |
||
826 | i = 0; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "SR", med_keypad_goto_0 ); |
||
827 | i++; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "SS", med_keypad_goto_1 ); |
||
828 | i++; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "CF", med_keypad_goto_2 ); |
||
829 | i++; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "TM", med_keypad_goto_3 ); |
||
830 | i++; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "OP", med_keypad_goto_4 ); |
||
831 | i++; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "OR", med_keypad_goto_5 ); |
||
832 | i++; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "GE", med_keypad_goto_6 ); |
||
833 | i++; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "LI", med_keypad_goto_7 ); |
||
834 | i++; e.pad_goto[i] = ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "TT", med_keypad_goto_8 ); |
||
835 | } |
||
836 | |||
837 | menubar_show(); |
||
838 | |||
839 | // INIT TEXTURE STUFF |
||
840 | texpage_init( EditorWindow ); |
||
841 | objpage_init( EditorWindow ); |
||
842 | |||
843 | EditorWindow->keyboard_focus_gadget = LargeViewBox.get(); |
||
844 | |||
845 | // BigCanvas[0]->cv_font = grd_curscreen->sc_canvas.cv_font; |
||
846 | // BigCanvas[1]->cv_font = grd_curscreen->sc_canvas.cv_font; |
||
847 | // BigCanvasFirstTime = 1; |
||
848 | |||
849 | Update_flags = UF_ALL; |
||
850 | initializing = 0; |
||
851 | editor_screen_open = 1; |
||
852 | } |
||
853 | |||
854 | //shutdown ui on the editor screen |
||
855 | void close_editor_screen() |
||
856 | { |
||
857 | if (!editor_screen_open) return; |
||
858 | |||
859 | editor_screen_open = 0; |
||
860 | ui_pad_deactivate(); |
||
861 | if (Pad_info) |
||
862 | window_close(Pad_info); |
||
863 | |||
864 | //ui_close_dialog(EditorWindow); // moved into handler, so we can handle the quit request |
||
865 | //EditorWindow = NULL; |
||
866 | |||
867 | close_all_windows(); |
||
868 | |||
869 | // CLOSE TEXTURE STUFF |
||
870 | texpage_close(); |
||
871 | objpage_close(); |
||
872 | |||
873 | menubar_hide(); |
||
874 | |||
875 | } |
||
876 | |||
877 | static void med_show_warning(const char *s) |
||
878 | { |
||
879 | grs_canvas &save_canv = *grd_curcanv; |
||
880 | |||
881 | //gr_pal_fade_in(grd_curscreen->pal); //in case palette is blacked |
||
882 | |||
883 | ui_messagebox(-2,-2,1,s,"OK"); |
||
884 | |||
885 | gr_set_current_canvas(save_canv); |
||
886 | } |
||
887 | |||
888 | // Returns 1 if OK to trash current mine. |
||
889 | int SafetyCheck() |
||
890 | { |
||
891 | int x; |
||
892 | |||
893 | if (mine_changed) { |
||
894 | x = nm_messagebox( "Warning!", 2, "Cancel", "OK", "You are about to lose work." ); |
||
895 | if (x<1) { |
||
896 | return 0; |
||
897 | } |
||
898 | } |
||
899 | return 1; |
||
900 | } |
||
901 | |||
902 | //called at the end of the program |
||
903 | |||
904 | static void close_editor() |
||
905 | { |
||
906 | // _MARK_("end of editor");//Nuked to compile -KRB |
||
907 | |||
908 | #if defined(WIN32) || defined(__APPLE__) || defined(__MACH__) |
||
909 | set_warn_func(msgbox_warning); |
||
910 | #else |
||
911 | clear_warn_func(); |
||
912 | #endif |
||
913 | |||
914 | close_editor_screen(); |
||
915 | |||
916 | //kill our camera object |
||
917 | |||
918 | Viewer = ConsoleObject; //reset viewer |
||
919 | //@@obj_delete(camera_objnum); |
||
920 | |||
921 | padnum = ui_pad_get_current(); |
||
922 | |||
923 | close_autosave(); |
||
924 | |||
925 | ui_close(); |
||
926 | |||
927 | editor_font.reset(); |
||
928 | |||
929 | PHYSFSX_removeRelFromSearchPath("editor/data"); |
||
930 | PHYSFSX_removeRelFromSearchPath("editor"); |
||
931 | PHYSFSX_removeRelFromSearchPath("editor.zip"); |
||
932 | PHYSFSX_removeRelFromSearchPath("editor.dxa"); |
||
933 | |||
934 | switch (ModeFlag) |
||
935 | { |
||
936 | case 1: |
||
937 | break; |
||
938 | |||
939 | case 2: |
||
940 | set_screen_mode(SCREEN_MENU); //put up menu screen |
||
941 | show_menus(); |
||
942 | break; |
||
943 | |||
944 | case 3: |
||
945 | if (Game_wind) |
||
946 | return; // if we're already playing a game, don't touch! |
||
947 | |||
948 | switch (gamestate) |
||
949 | { |
||
950 | case editor_gamestate::none: |
||
951 | StartNewGame(Current_level_num); |
||
952 | break; |
||
953 | |||
954 | case editor_gamestate::saved: |
||
955 | state_restore_all_sub( |
||
956 | #if defined(DXX_BUILD_DESCENT_II) |
||
957 | LevelSharedSegmentState.DestructibleLights, secret_restore::none, |
||
958 | #endif |
||
959 | PLAYER_DIRECTORY_STRING("gamesave.sge") |
||
960 | ); |
||
961 | break; |
||
962 | |||
963 | default: |
||
964 | Int3(); // shouldn't happen |
||
965 | break; |
||
966 | } |
||
967 | break; |
||
968 | } |
||
969 | |||
970 | return; |
||
971 | } |
||
972 | |||
973 | //variables for find segments process |
||
974 | |||
975 | // --------------------------------------------------------------------------------------------------- |
||
976 | // Subtract all elements in Found_segs from selected list. |
||
977 | static void subtract_found_segments_from_selected_list(void) |
||
978 | { |
||
979 | range_for (const auto &foundnum, Found_segs) |
||
980 | { |
||
981 | selected_segment_array_t::iterator i = Selected_segs.find(foundnum), e = Selected_segs.end(); |
||
982 | if (i != e) |
||
983 | { |
||
984 | *i = *-- e; |
||
985 | Selected_segs.erase(e); |
||
986 | } |
||
987 | } |
||
988 | } |
||
989 | |||
990 | // --------------------------------------------------------------------------------------------------- |
||
991 | // Add all elements in Found_segs to selected list. |
||
992 | static void add_found_segments_to_selected_list(void) { |
||
993 | range_for (const auto &foundnum, Found_segs) |
||
994 | { |
||
995 | selected_segment_array_t::iterator i = Selected_segs.find(foundnum), e = Selected_segs.end(); |
||
996 | if (i == e) |
||
997 | Selected_segs.emplace_back(foundnum); |
||
998 | } |
||
999 | } |
||
1000 | |||
1001 | void gamestate_restore_check() |
||
1002 | { |
||
1003 | auto &Objects = LevelUniqueObjectState.Objects; |
||
1004 | auto &vmobjptr = Objects.vmptr; |
||
1005 | auto &vmobjptridx = Objects.vmptridx; |
||
1006 | obj_position Save_position; |
||
1007 | |||
1008 | if (gamestate == editor_gamestate::saved) |
||
1009 | { |
||
1010 | if (ui_messagebox(-2, -2, 2, "Do you wish to restore game state?\n", "Yes", "No") == 1) |
||
1011 | { |
||
1012 | |||
1013 | // Save current position |
||
1014 | Save_position.pos = ConsoleObject->pos; |
||
1015 | Save_position.orient = ConsoleObject->orient; |
||
1016 | Save_position.segnum = ConsoleObject->segnum; |
||
1017 | |||
1018 | if (!state_restore_all_sub( |
||
1019 | #if defined(DXX_BUILD_DESCENT_II) |
||
1020 | LevelSharedSegmentState.DestructibleLights, secret_restore::none, |
||
1021 | #endif |
||
1022 | PLAYER_DIRECTORY_STRING("gamesave.sge") |
||
1023 | )) |
||
1024 | return; |
||
1025 | |||
1026 | // Switch back to slew mode - loading saved game made ConsoleObject flying |
||
1027 | editor_slew_init(); |
||
1028 | |||
1029 | // Restore current position |
||
1030 | if (Save_position.segnum <= Highest_segment_index) { |
||
1031 | ConsoleObject->pos = Save_position.pos; |
||
1032 | ConsoleObject->orient = Save_position.orient; |
||
1033 | obj_relink(vmobjptr, vmsegptr, vmobjptridx(ConsoleObject), vmsegptridx(Save_position.segnum)); |
||
1034 | } |
||
1035 | |||
1036 | Update_flags |= UF_WORLD_CHANGED; |
||
1037 | } |
||
1038 | else |
||
1039 | gamestate = editor_gamestate::none; |
||
1040 | } |
||
1041 | } |
||
1042 | |||
1043 | int RestoreGameState() |
||
1044 | { |
||
1045 | if (!SafetyCheck()) |
||
1046 | return 0; |
||
1047 | |||
1048 | if (!state_restore_all_sub( |
||
1049 | #if defined(DXX_BUILD_DESCENT_II) |
||
1050 | LevelSharedSegmentState.DestructibleLights, secret_restore::none, |
||
1051 | #endif |
||
1052 | PLAYER_DIRECTORY_STRING("gamesave.sge") |
||
1053 | )) |
||
1054 | return 0; |
||
1055 | |||
1056 | // Switch back to slew mode - loading saved game made ConsoleObject flying |
||
1057 | editor_slew_init(); |
||
1058 | |||
1059 | gamestate = editor_gamestate::saved; |
||
1060 | |||
1061 | editor_status("Gamestate restored.\n"); |
||
1062 | |||
1063 | Update_flags |= UF_WORLD_CHANGED; |
||
1064 | return 1; |
||
1065 | } |
||
1066 | |||
1067 | // Handler for the main editor dialog |
||
1068 | window_event_result editor_handler(UI_DIALOG *, const d_event &event, unused_ui_userdata_t *) |
||
1069 | { |
||
1070 | auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state(); |
||
1071 | auto &Vertices = LevelSharedVertexState.get_vertices(); |
||
1072 | editor_view *new_cv; |
||
1073 | int keypress = 0; |
||
1074 | window_event_result rval = window_event_result::ignored; |
||
1075 | |||
1076 | if (event.type == EVENT_WINDOW_CREATED) |
||
1077 | return window_event_result::ignored; |
||
1078 | |||
1079 | if (event.type == EVENT_KEY_COMMAND) |
||
1080 | keypress = event_key_get(event); |
||
1081 | else if (event.type == EVENT_WINDOW_CLOSE) |
||
1082 | { |
||
1083 | EditorWindow = NULL; |
||
1084 | close_editor(); |
||
1085 | return window_event_result::ignored; |
||
1086 | } |
||
1087 | |||
1088 | // Update the windows |
||
1089 | |||
1090 | if (event.type == EVENT_UI_DIALOG_DRAW) |
||
1091 | { |
||
1092 | // Draw status box |
||
1093 | gr_set_default_canvas(); |
||
1094 | gr_rect(*grd_curcanv, STATUS_X,STATUS_Y,STATUS_X+STATUS_W-1,STATUS_Y+STATUS_H-1, CGREY); |
||
1095 | |||
1096 | medlisp_update_screen(); |
||
1097 | calc_frame_time(); |
||
1098 | texpage_do(event); |
||
1099 | objpage_do(event); |
||
1100 | ui_pad_draw(EditorWindow, PAD_X, PAD_Y); |
||
1101 | |||
1102 | print_status_bar(status_line); |
||
1103 | TimedAutosave(mine_filename); // shows the time, hence here |
||
1104 | set_editor_time_of_day(); |
||
1105 | return window_event_result::handled; |
||
1106 | } |
||
1107 | |||
1108 | if ((selected_gadget == GameViewBox.get() && !render_3d_in_big_window) || |
||
1109 | (selected_gadget == LargeViewBox.get() && render_3d_in_big_window)) |
||
1110 | switch (event.type) |
||
1111 | { |
||
1112 | case EVENT_MOUSE_BUTTON_UP: |
||
1113 | case EVENT_MOUSE_BUTTON_DOWN: |
||
1114 | break; |
||
1115 | case EVENT_MOUSE_MOVED: |
||
1116 | if (!keyd_pressed[ KEY_LCTRL ] && !keyd_pressed[ KEY_RCTRL ]) |
||
1117 | break; |
||
1118 | DXX_BOOST_FALLTHROUGH; |
||
1119 | case EVENT_JOYSTICK_BUTTON_UP: |
||
1120 | case EVENT_JOYSTICK_BUTTON_DOWN: |
||
1121 | case EVENT_JOYSTICK_MOVED: |
||
1122 | case EVENT_KEY_COMMAND: |
||
1123 | case EVENT_KEY_RELEASE: |
||
1124 | case EVENT_IDLE: |
||
1125 | kconfig_read_controls(Controls, event, 1); |
||
1126 | |||
1127 | if (slew_frame(0)) |
||
1128 | { //do movement and check keys |
||
1129 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
1130 | if (Gameview_lockstep) |
||
1131 | { |
||
1132 | Cursegp = imsegptridx(ConsoleObject->segnum); |
||
1133 | med_create_new_segment_from_cursegp(); |
||
1134 | Update_flags |= UF_ED_STATE_CHANGED; |
||
1135 | } |
||
1136 | |||
1137 | rval = window_event_result::handled; |
||
1138 | } |
||
1139 | break; |
||
1140 | case EVENT_LOOP_BEGIN_LOOP: |
||
1141 | kconfig_begin_loop(Controls); |
||
1142 | break; |
||
1143 | |||
1144 | default: |
||
1145 | break; |
||
1146 | } |
||
1147 | |||
1148 | //do non-essential stuff in idle event |
||
1149 | if (event.type == EVENT_IDLE) |
||
1150 | { |
||
1151 | check_wall_validity(); |
||
1152 | |||
1153 | if (Gameview_lockstep) { |
||
1154 | static segment *old_cursegp=NULL; |
||
1155 | static int old_curside=-1; |
||
1156 | |||
1157 | if (old_cursegp!=Cursegp || old_curside!=Curside) { |
||
1158 | SetPlayerFromCursegMinusOne(); |
||
1159 | old_cursegp = Cursegp; |
||
1160 | old_curside = Curside; |
||
1161 | } |
||
1162 | } |
||
1163 | |||
1164 | if ( event_get_idle_seconds() > COMPRESS_INTERVAL ) |
||
1165 | { |
||
1166 | med_compress_mine(); |
||
1167 | event_reset_idle_seconds(); |
||
1168 | } |
||
1169 | |||
1170 | // Commented out because it occupies about 25% of time in twirling the mine. |
||
1171 | // Removes some Asserts.... |
||
1172 | // med_check_all_vertices(); |
||
1173 | clear_editor_status(); // if enough time elapsed, clear editor status message |
||
1174 | } |
||
1175 | |||
1176 | gr_set_current_canvas( GameViewBox->canvas ); |
||
1177 | |||
1178 | // Remove keys used for slew |
||
1179 | switch(keypress) |
||
1180 | { |
||
1181 | case KEY_PAD9: |
||
1182 | case KEY_PAD7: |
||
1183 | case KEY_PADPLUS: |
||
1184 | case KEY_PADMINUS: |
||
1185 | case KEY_PAD8: |
||
1186 | case KEY_PAD2: |
||
1187 | case KEY_LBRACKET: |
||
1188 | case KEY_RBRACKET: |
||
1189 | case KEY_PAD1: |
||
1190 | case KEY_PAD3: |
||
1191 | case KEY_PAD6: |
||
1192 | case KEY_PAD4: |
||
1193 | keypress = 0; |
||
1194 | } |
||
1195 | if ((keypress&0xff)==KEY_LSHIFT) keypress=0; |
||
1196 | if ((keypress&0xff)==KEY_RSHIFT) keypress=0; |
||
1197 | if ((keypress&0xff)==KEY_LCTRL) keypress=0; |
||
1198 | if ((keypress&0xff)==KEY_RCTRL) keypress=0; |
||
1199 | if ((keypress&0xff)==KEY_LMETA) keypress=0; |
||
1200 | if ((keypress&0xff)==KEY_RMETA) keypress=0; |
||
1201 | // if ((keypress&0xff)==KEY_LALT) keypress=0; |
||
1202 | // if ((keypress&0xff)==KEY_RALT) keypress=0; |
||
1203 | |||
1204 | //=================== DO FUNCTIONS ==================== |
||
1205 | |||
1206 | if ( KeyFunction[ keypress ] != NULL ) |
||
1207 | { |
||
1208 | KeyFunction[keypress](); |
||
1209 | keypress = 0; |
||
1210 | rval = window_event_result::handled; |
||
1211 | } |
||
1212 | |||
1213 | switch (keypress) |
||
1214 | { |
||
1215 | case 0: |
||
1216 | case KEY_Z: |
||
1217 | case KEY_G: |
||
1218 | case KEY_LALT: |
||
1219 | case KEY_RALT: |
||
1220 | case KEY_LCTRL: |
||
1221 | case KEY_RCTRL: |
||
1222 | case KEY_LSHIFT: |
||
1223 | case KEY_RSHIFT: |
||
1224 | case KEY_LAPOSTRO: |
||
1225 | break; |
||
1226 | case KEY_SHIFTED + KEY_L: |
||
1227 | #if !DXX_USE_OGL |
||
1228 | ToggleLighting(); |
||
1229 | #endif |
||
1230 | rval = window_event_result::handled; |
||
1231 | break; |
||
1232 | case KEY_F1: |
||
1233 | render_3d_in_big_window = !render_3d_in_big_window; |
||
1234 | Update_flags |= UF_ALL; |
||
1235 | rval = window_event_result::handled; |
||
1236 | break; |
||
1237 | default: |
||
1238 | if (rval == window_event_result::ignored) |
||
1239 | { |
||
1240 | char kdesc[100]; |
||
1241 | GetKeyDescription( kdesc, keypress ); |
||
1242 | editor_status_fmt("Error: %s isn't bound to anything.", kdesc ); |
||
1243 | } |
||
1244 | } |
||
1245 | |||
1246 | //================================================================ |
||
1247 | |||
1248 | if (ModeFlag) |
||
1249 | { |
||
1250 | return window_event_result::close; |
||
1251 | } |
||
1252 | |||
1253 | // if (EditorWindow->keyboard_focus_gadget == GameViewBox) current_view=NULL; |
||
1254 | // if (EditorWindow->keyboard_focus_gadget == GroupViewBox) current_view=NULL; |
||
1255 | |||
1256 | new_cv = current_view; |
||
1257 | |||
1258 | #if ORTHO_VIEWS |
||
1259 | if (EditorWindow->keyboard_focus_gadget == LargeViewBox) new_cv=&LargeView; |
||
1260 | if (EditorWindow->keyboard_focus_gadget == TopViewBox) new_cv=&TopView; |
||
1261 | if (EditorWindow->keyboard_focus_gadget == FrontViewBox) new_cv=&FrontView; |
||
1262 | if (EditorWindow->keyboard_focus_gadget == RightViewBox) new_cv=&RightView; |
||
1263 | #endif |
||
1264 | if (new_cv != current_view ) { |
||
1265 | current_view->ev_changed = 1; |
||
1266 | new_cv->ev_changed = 1; |
||
1267 | current_view = new_cv; |
||
1268 | } |
||
1269 | |||
1270 | // DO TEXTURE STUFF |
||
1271 | if (texpage_do(event)) |
||
1272 | rval = window_event_result::handled; |
||
1273 | |||
1274 | if (objpage_do(event)) |
||
1275 | rval = window_event_result::handled; |
||
1276 | |||
1277 | |||
1278 | // Process selection of Cursegp using mouse. |
||
1279 | if (GADGET_PRESSED(LargeViewBox.get()) && !render_3d_in_big_window) |
||
1280 | { |
||
1281 | int xcrd,ycrd; |
||
1282 | xcrd = LargeViewBox->b1_drag_x1; |
||
1283 | ycrd = LargeViewBox->b1_drag_y1; |
||
1284 | |||
1285 | find_segments(xcrd,ycrd,LargeViewBox->canvas.get(),&LargeView,Cursegp,Big_depth); // Sets globals N_found_segs, Found_segs |
||
1286 | |||
1287 | // If shift is down, then add segment to found list |
||
1288 | if (keyd_pressed[ KEY_LSHIFT ] || keyd_pressed[ KEY_RSHIFT ]) |
||
1289 | subtract_found_segments_from_selected_list(); |
||
1290 | else |
||
1291 | add_found_segments_to_selected_list(); |
||
1292 | |||
1293 | Found_seg_index = 0; |
||
1294 | |||
1295 | if (!Found_segs.empty()) |
||
1296 | { |
||
1297 | sort_seg_list(Found_segs,ConsoleObject->pos); |
||
1298 | Cursegp = imsegptridx(Found_segs[0]); |
||
1299 | med_create_new_segment_from_cursegp(); |
||
1300 | if (Lock_view_to_cursegp) |
||
1301 | { |
||
1302 | auto &vcvertptr = Vertices.vcptr; |
||
1303 | set_view_target_from_segment(vcvertptr, Cursegp); |
||
1304 | } |
||
1305 | } |
||
1306 | |||
1307 | Update_flags |= UF_ED_STATE_CHANGED | UF_VIEWPOINT_MOVED; |
||
1308 | } |
||
1309 | |||
1310 | if ((event.type == EVENT_UI_USERBOX_DRAGGED) && (ui_event_get_gadget(event) == GameViewBox.get())) |
||
1311 | { |
||
1312 | int x, y; |
||
1313 | x = GameViewBox->b1_drag_x2; |
||
1314 | y = GameViewBox->b1_drag_y2; |
||
1315 | |||
1316 | gr_set_current_canvas( GameViewBox->canvas ); |
||
1317 | gr_rect(*grd_curcanv, x-1, y-1, x+1, y+1, 15); |
||
1318 | } |
||
1319 | |||
1320 | // Set current segment and side by clicking on a polygon in game window. |
||
1321 | // If ctrl pressed, also assign current texture map to that side. |
||
1322 | //if (GameViewBox->mouse_onme && (GameViewBox->b1_done_dragging || GameViewBox->b1_clicked)) { |
||
1323 | if ((GADGET_PRESSED(GameViewBox.get()) && !render_3d_in_big_window) || |
||
1324 | (GADGET_PRESSED(LargeViewBox.get()) && render_3d_in_big_window)) |
||
1325 | { |
||
1326 | int xcrd,ycrd; |
||
1327 | int side,face,tmap; |
||
1328 | |||
1329 | if (render_3d_in_big_window) { |
||
1330 | xcrd = LargeViewBox->b1_drag_x1; |
||
1331 | ycrd = LargeViewBox->b1_drag_y1; |
||
1332 | } |
||
1333 | else { |
||
1334 | xcrd = GameViewBox->b1_drag_x1; |
||
1335 | ycrd = GameViewBox->b1_drag_y1; |
||
1336 | } |
||
1337 | |||
1338 | //Int3(); |
||
1339 | |||
1340 | segnum_t seg; |
||
1341 | objnum_t obj; |
||
1342 | if (find_seg_side_face(xcrd,ycrd,seg,obj,side,face)) |
||
1343 | { |
||
1344 | |||
1345 | if (obj != object_none) { //found an object |
||
1346 | |||
1347 | Cur_object_index = obj; |
||
1348 | editor_status_fmt("Object %d selected.",Cur_object_index); |
||
1349 | |||
1350 | Update_flags |= UF_ED_STATE_CHANGED; |
||
1351 | } |
||
1352 | else { |
||
1353 | |||
1354 | // See if either shift key is down and, if so, assign texture map |
||
1355 | if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) { |
||
1356 | Cursegp = imsegptridx(seg); |
||
1357 | Curside = side; |
||
1358 | AssignTexture(); |
||
1359 | med_create_new_segment_from_cursegp(); |
||
1360 | editor_status("Texture assigned"); |
||
1361 | } else if (keyd_pressed[KEY_G]) { |
||
1362 | tmap = Segments[seg].unique_segment::sides[side].tmap_num; |
||
1363 | texpage_grab_current(tmap); |
||
1364 | editor_status( "Texture grabbed." ); |
||
1365 | } else if (keyd_pressed[ KEY_LAPOSTRO] ) { |
||
1366 | move_object_to_mouse_click(); |
||
1367 | } else { |
||
1368 | Cursegp = imsegptridx(seg); |
||
1369 | Curside = side; |
||
1370 | med_create_new_segment_from_cursegp(); |
||
1371 | editor_status("Curseg and curside selected"); |
||
1372 | } |
||
1373 | } |
||
1374 | |||
1375 | Update_flags |= UF_ED_STATE_CHANGED; |
||
1376 | } |
||
1377 | else |
||
1378 | editor_status("Click on non-texture ingored"); |
||
1379 | |||
1380 | } |
||
1381 | |||
1382 | // Allow specification of LargeView using mouse |
||
1383 | if (event.type == EVENT_MOUSE_MOVED && (keyd_pressed[ KEY_LCTRL ] || keyd_pressed[ KEY_RCTRL ])) |
||
1384 | { |
||
1385 | int dx, dy, dz; |
||
1386 | |||
1387 | event_mouse_get_delta(event, &dx, &dy, &dz); |
||
1388 | if ((dx != 0) && (dy != 0)) |
||
1389 | { |
||
1390 | vms_matrix MouseRotMat; |
||
1391 | |||
1392 | GetMouseRotation( dx, dy, &MouseRotMat ); |
||
1393 | LargeView.ev_matrix = vm_matrix_x_matrix(LargeView.ev_matrix,MouseRotMat); |
||
1394 | LargeView.ev_changed = 1; |
||
1395 | Large_view_index = -1; // say not one of the orthogonal views |
||
1396 | rval = window_event_result::handled; |
||
1397 | } |
||
1398 | } |
||
1399 | |||
1400 | if (event.type == EVENT_MOUSE_MOVED) |
||
1401 | { |
||
1402 | int dx, dy, dz; |
||
1403 | |||
1404 | event_mouse_get_delta(event, &dx, &dy, &dz); |
||
1405 | if (dz != 0) |
||
1406 | { |
||
1407 | current_view->ev_dist += dz*10000; |
||
1408 | current_view->ev_changed = 1; |
||
1409 | } |
||
1410 | } |
||
1411 | |||
1412 | return rval; |
||
1413 | } |