/* * Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/editor/MainFrm.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:38 $ * $Author: kevinb $ * * The editor main frame window * * $Log: not supported by cvs2svn $ * * 164 10/29/99 4:34p Matt * Added code (not being called) to count the number of specular faces in * a level. * * 163 10/27/99 10:37a Matt * Added some code (not being called in this version) to list all the * objects in a level that use lightmaps. * * 162 10/25/99 12:54p Jeff * test1 _really_ destroys all lightmaps * * 161 10/13/99 10:41a Chris * Added 'special forcefields' that have custom bounce factors * * 160 9/15/99 1:56p Matt * Added the option to allow rooms or groups placed on the terrain to * either align with the terrain or with gravity. * * 159 8/18/99 11:29a Matt * Added shortcuts for next vertex and add vert to face. * * 158 8/17/99 4:09p Matt * Added some accelerator keys, and a function to copy face light * multiples. * * 157 8/12/99 9:36a Matt * Changed MoveEntireMine() code to move in both X and Y. * * 156 7/28/99 5:48p Matt * Added test code to scale an entire mine. * * 155 5/22/99 4:40a Matt * Fixed yet another small bug in the show-all-locked-pages code. * * 154 5/21/99 1:29p Matt * Fixed tiny bug. * * 153 5/21/99 12:36p Matt * Added test code to check for destroyable textures without a destroyed * bitmap. * * 152 5/10/99 12:04a Matt * Added function for Luke to shift the entire mine. * * 151 5/08/99 1:01p Matt * Added a function for Luke to scale all the room light multipliers in a * level. * * 150 5/08/99 1:39a Matt * Added a function to delete all objects of a certain type, and support * for placing and attaching groups to the terrain. * * 149 5/05/99 2:02a Matt * Added a function to check for precision-error FVI cracks in the level. * * 148 5/03/99 2:56a Matt * Added a function for Luke to delete all the faces in a room that have * texture 1 on them. * * 147 5/02/99 9:23p Matt * Notify the level keypad when the level has changed, and then re-init * the combo boxes. * * 146 5/02/99 6:41a Jeff * created 'test/temp' function to force unload all osiris modules * * 145 5/02/99 2:01a Jeff * fixed crash in getchangemask * * 144 5/01/99 9:43p Matt * Apparently, there's no longer a page called "DUMMY PAGE" in the list of * locked pages, so remove the assert that checked for it. * * 143 4/29/99 11:51p Matt * Improved viewer move functions. * * 142 4/29/99 3:19p Jeff * test function 3 to grab non-physics set objects * * 141 4/23/99 4:55p Matt * Fixed bug in previous version. * * 140 4/23/99 2:51p Matt * Added function to relink objects from the terrain to the mine to fix * one of Dan's levels. * * 139 4/21/99 10:36p Matt * Fixed typo * * 138 4/21/99 10:20p Matt * Fixed cut room message * * 137 4/17/99 6:15p Samir * replaced gr.h with grdefs.h and fixed resulting compile bugs. * * 136 4/16/99 3:54p Nate * Added Viewer Properties Dialog * * 135 4/12/99 12:50p Matt * Added function to dump goal text to a file. * * 134 4/05/99 11:17a Matt * Added code to list all the objects in the levels. * * 133 4/05/99 10:54a Matt * Added auto-waypoint system * * 131 4/03/99 7:54p Matt * Finished implementing spiffy keypad update system. * * 130 4/02/99 5:08p Matt * Added intro movie. * * 129 3/30/99 6:24p Matt * Added new error system, where instead of putting up an error message, a * function returns a failure code & returns an error message that the * caller can display if it wants. * * 128 3/30/99 4:09p Matt * Fixed very small bug * * 127 3/30/99 11:25a Matt * Re-enabled object reset code * * 126 3/25/99 4:11p Samir * added aureal test code. * * 125 3/18/99 8:41p Jeff * created orphan hunter dialog * * 124 3/15/99 4:04p Matt * Added code to show a list of named rooms. * * 123 3/10/99 7:17p Samir * added function that updates keypads. * * 122 3/01/99 6:26p Matt * Added function to fix bad objects in Dan's level * * 121 2/23/99 11:51p Jeff * new script dll sync dialog * * 120 2/22/99 11:39p Matt * Deleted debris editor menu item, since it' no longer needed. * * 119 2/21/99 4:20p Matt * Added SoundSource objects (and reformatted parts of the object header * files). * * 118 2/05/99 1:29p Matt * Added a function to show the viewer's forward vector. (Also checked * select-object-by-number to use common code to print out the selected * object info.) * * 117 2/03/99 1:10p Matt * Changed the paletted room current faces to be stored in a separate * array, instead of in the room structure. * * 116 2/03/99 1:20a Matt * Added a system to show all pages locked. * * 115 2/01/99 11:36p Matt * Added menu functions to select an object by number and move the viewer * to the current object. * * 114 1/24/99 6:35p Matt * Made view set functions behave differently in Room View * * 113 1/21/99 11:15p Jeff * pulled out some structs and defines from header files and moved them * into separate header files so that multiplayer dlls don't require major * game headers, just those new headers. Side effect is a shorter build * time. Also cleaned up some header file #includes that weren't needed. * This affected polymodel.h, object.h, player.h, vecmat.h, room.h, * manage.h and multi.h * * 112 1/19/99 6:53p Matt * Fixed a problem when the viewer was instantaneously moved from inside * to ourside or vise-versa. * * 111 1/15/99 7:52p Chris * Updated ObjSetPos() to include a f_update_attach_children flag * * 110 1/12/99 12:35p Nate * Clicking on the DALLAS menu item now restores it if it was minimized * * 109 1/11/99 3:34p Jeff * added checks for when going editor->game to see if scripts are out of * date, if so give the option of breaking out. Add some options to mass * script compiler, along with a toolbar shortcut. * * 108 1/08/99 2:56p Samir * Ripped out OSIRIS1. * * 107 12/23/98 4:01p Nate * Added code create Dallas as a modeless dialog * * 106 12/11/98 6:48p Nate * Added support for starting D.A.L.L.A.S. from the main menu * * 105 12/11/98 5:50p Jeff * implemented and added changes regarding Level&Scripting manage system * and compiler interface * * 104 12/01/98 11:17p Matt * Added menu option to disable drawing objects in the wireframe view * * 103 11/01/98 1:58a Jeff * converted the vsprintf calls to use the Pvsprintf, which is a safe * vsprintf, no buffer overflows allowed * * 102 10/21/98 12:50p Sean * Allow for cameras to be placed on external rooms * * 101 10/14/98 4:37p Matt * Made InitD3System() exit with error if there's a problem instead of * returning a status value. Also moved some editor-specific code from * init.cpp to mainfrm.cpp, and cleaned up some other initialization and * error-handling code. * * 100 10/12/98 1:46p Samir * new Program_version parameters. * * 99 10/08/98 4:23p Kevin * Changed code to comply with memory library usage. Always use mem_malloc * , mem_free and mem_strdup * * 98 10/06/98 12:38p Nate * * 97 10/04/98 1:25p Matt * * 96 10/02/98 1:43p Samir * took out FULL_DEVELOPMENT * * 95 9/09/98 12:48p Samir * added script localizer. * * 94 9/03/98 5:29p Matt * Added code to fix cracks in levels. * * 93 9/03/98 2:20p Jeff * flush keyboard after briefeditor exits * * 92 9/02/98 2:55p Jeff * initial creation of briefing editor * * 91 8/31/98 4:37p Matt * Added improved room & mine error checking. * * 90 8/27/98 6:42p Chris * Added the goal keypad and the start of the matcen keypad * * 89 8/20/98 12:35p Matt * Added nice editing for ambient sound patterns * * 88 8/13/98 1:06p Nate * Disabled pausing of Editor when running TableTextEditor * * 87 8/10/98 12:14p Nate * Added Table File Edit dialog. * * 86 7/08/98 6:26p Samir * took out obsolete code. * * 85 7/01/98 4:58p Samir * changed InitD3Systems. * * 84 6/29/98 6:45p Samir * call WM_ACTIVATEAPP Descent Handler from mainframe. * * 83 6/25/98 7:16p Matt * Added code to check for errors in portal linkage * * 82 5/01/98 3:57p Matt * Added function to place a camera in the center of the current face. * * 81 4/21/98 2:40p Matt * Added option to show level stats * * 80 4/16/98 6:39p Kevin * made CKeypadDialog::Activate static. * * 79 4/14/98 7:50p Matt * Added system to keep info for each level * * 78 3/27/98 6:05p Samir * Added key handler for main frame. * * 77 3/23/98 8:03p Samir * A bunch of changes to allow for ALT-TAB to work. * * 76 3/23/98 2:17p Jeff * Included telcom.h * * 75 3/06/98 5:36p Matt * Took out cfile try/catch for editor, since it's probably better to get * the error in the cfile code when debugging, so you can look at the * stack & parms and stuff. I've left try/catch in for the game, but * ideally we'd take that out too when running under the debugger, if we * could figure out how to do that. * * 74 2/17/98 6:13p Jeff * Changed it so TelCom is forced to go into Briefings when called * * 73 2/15/98 7:44p Matt * Added groovy try/catch/throw error checking for cfile functions * * 72 2/09/98 10:54a Matt * Don't allow user to switch to mine view if there are no internal rooms * * 71 2/05/98 3:11p Matt * Don't move the viewer to an external room. * * 70 2/05/98 2:57p Matt * Changed code to use ObjSetPos() * * 69 2/04/98 6:23p Matt * Changed object room number to indicate a terrain cell via a flag. Got * rid of the object flag which used to indicate terrain. * * 68 1/30/98 6:07p Matt * Added code and menu items to deal with camera objects * * 67 1/29/98 2:15p Samir * Implemented ObjectListModeless and Toolbar button. * * 66 1/21/98 1:08p Matt * Made SetViewMode() not take new_viewer parm, since it's not needed * after my revamp of the editor view system. * * 65 1/21/98 12:33p Matt * Revamped viewer system * * 64 12/02/97 4:43p Samir * Repaired MainFrm.cpp * * 63 12/01/97 6:06p Samir * Implemented new FileDialog tracker system. * * 62 11/17/97 3:53p Matt * When deleting objects, set the pointers to them to NULL. * Added test function to play the briefing. * * 61 10/22/97 4:30p Chris * We can now slew between the mine and the terrain * * 60 10/16/97 7:35p Samir * For fullscreen game from editor, hide all user interface elements of * the editor window and use the client area for our display. It's REALLY * hacked, but seems to be the cleanest method of playing the game in * fullscreen. Old method of blanking window doesn't work. * * 59 10/15/97 5:20p Jason * did a HUGE overhaul of the bitmap system * * 58 10/03/97 3:39p Matt * Added separate sets of wireframe view variables for mine & room views * * 57 9/23/97 10:38a Jason * Took out OnTerrain * * 56 9/23/97 10:27a Jason * took premature return from OnFileImportRoom * * 55 9/22/97 5:59p Samir * Changed ObjCScript system, so everything is broken, but it shouldn't * crash the game. * * 53 9/17/97 12:58p Samir * Got rid of Curve Keypad. * * 52 9/17/97 12:48p Samir * Got rid of more obscure segment references. * * 51 9/17/97 11:30a Jason * ripped out segment engine * * 50 9/16/97 4:27p Matt * Got rid of static_light & changed fields in the room struct * * 49 9/11/97 5:38p Jason * initial door coding for room engine * * 48 9/09/97 12:23p Samir * Added a menu item to go to level properties dialog. * * 47 9/02/97 6:41p Matt * Added code for group paste * * 46 8/29/97 5:45p Matt * Made selection & cut/copy/past funcs work with rooms * * 45 8/29/97 2:49p Samir * Nuked SegmentKeypad. * * 44 8/27/97 10:55a Samir * Fixed bug when keypad is initally closed, and you toggle it, and the * control bar looked fine, just no tab control. * * 43 8/21/97 7:48p Matt * Added code to move player object (like old move player to curseg) * * 42 8/20/97 5:28p Samir * Took out Desktop_surf init and put it into init.cpp * * 41 8/15/97 6:32p Samir * Added ScriptWizard! * * 40 8/13/97 5:39p Samir * Use CompileScript to compile a script now, and we compile default * script at startup of editor. * * 39 8/12/97 5:47p Matt * Added menu items to edit debris, clutter, & buildings * Increased number of items in objpage dropdown box * * 38 8/12/97 3:22p Samir * osi_Compile and D3XReallocProgram added parameters. * * 37 8/11/97 1:53p Matt * Ripped out robot & powerup pages, and added generic page * * 36 8/08/97 3:30p Matt * Fixed stupid bug * * 35 8/08/97 3:22p Jeff * Added automatic OGF conversion when extracting HSM * * 34 8/08/97 3:09p Matt * Added testing calls to new generic page dialog * * 33 8/08/97 2:51p Jeff * added code to check if default script is locked * * 32 8/06/97 10:36a Samir * Fixed osi_Compile calls. * * 31 8/04/97 4:12p Samir * Call to osi_Compile uses new prototype. * * 30 8/04/97 12:42p Matt * Made move viewer function work with room engine * * 29 8/01/97 2:36p Jeff * * 28 7/29/97 3:48p Jeff * * 27 7/29/97 2:19p Jason * added filepage editor to mainframe * * 26 7/29/97 2:11p Jeff * Added compile on exit for Osiris * * 25 7/29/97 12:17p Matt * Made room:face display on status bar show different info for room, * mine, and terrain views. * * 24 7/28/97 5:33p Matt * Added function to change the view mode * * 23 7/28/97 10:51a Jeff * Changed cha *DefaultExternalEditor to what it should be called, char * Default_external_editor[256] * * 22 7/26/97 8:48p Jeff * fixed up calls to script editor. Added DefaultExternalEditor global * variable * * 21 7/25/97 6:16p Samir * Fixed the tile-cascade switching/default madness. * * 20 7/24/97 3:00p Matt * Save/load game & editor settings from/to the registry, and added code * to display current keypad. * * 19 7/22/97 7:08p Matt * Cleaned up D3EditState, moving some vars in and some out, and renaming * and changing a few others * * 18 7/21/97 5:55p Jeff * * 17 7/21/97 4:05p Jeff * fixed default path for external editor * * 16 7/21/97 3:21p Jeff * * 15 7/19/97 8:09p Jeff * * 14 7/18/97 5:36p Jason * save changed paletted rooms on exit * * 13 7/18/97 5:17p Jeff * * 93 6/30/97 1:30p Jason * added netherspace stuff * * 92 6/27/97 7:21p Matt * Added function to move player 0 to current segment * * 91 6/27/97 3:10p Jason * * 90 6/27/97 12:19p Samir * Added room keypad dialog * * 89 6/25/97 5:29p Jason * added/modified code to display a room * * 88 6/18/97 11:56a Jason * added some more terrain functions for Mark * * * 87 6/13/97 2:18p Matt * Added functions to change wireframe view target * * 86 6/11/97 1:07p Samir * The removal of gameos and replaced with oeApplication, oeDatabase * * 85 6/10/97 5:08p Jason * added reorderpages menu item * * 84 6/06/97 4:33p Jason * added cool stuff for megacells * * 83 6/05/97 3:37p Samir * Added megacell keypad. * * 82 6/05/97 2:52p Jason * added megacell functions * * 81 6/03/97 4:55p Mark * * 81 6/03/97 4:39p Jeff * Added code for Context sensitive help * * 80 6/02/97 2:31p Samir * Music test code! * * 79 5/19/97 5:10p Jason * changes for our new abstracted renderer code * * 78 5/13/97 7:27p Matt * Added code to set & clear fuelcen flag in segments * * 77 5/13/97 12:04p Matt * Added code to add a floating segment * * 76 5/05/97 3:37p Matt * * 75 4/30/97 5:52p Jason * added ability to switch between 8bit/16bit modes * * 74 4/17/97 4:03p Samir * Apply Tmap 1 and Tmap2 implemented, but no Tmap2 rendering is occurring * yet. * * 73 4/17/97 11:08a Samir * BuildBridge Implemented * * 72 4/16/97 6:11p Matt * Added code to divide a segment into two * * 71 4/15/97 11:29a Samir * Iimplemented menu item object placement and deletion. * * 70 4/11/97 4:59p Samir * Grab texture menu item works. * * 69 4/08/97 10:42a Jason * implemented path following interface * * 68 4/04/97 3:15p Samir * Added paths keypad, removed player keypad since it's joined with object * keypad. * * 67 4/03/97 1:20p Jason * changes to get the sound page system playing * * 66 4/02/97 10:56a Matt * Changed "Other" menu to "Object", and removed obsolete set-player-start * option * * 65 4/01/97 11:00p Matt * Changed editor to keep a viewer object (type camera) separate from the * player object. This camera, and not the player, is now moved by * slewing, the C key, etc. When going into the game, the viewer position * & orientation are copied to the player. When going back to the editor, * the player position is copied to the viewer, and the player object is * reset to its start location. * * 64 3/31/97 5:58p Matt * Revamped mine update flags * * 63 3/28/97 12:20p Jason * added terrain dialog stuff, plus bitmap memory indicator * * 62 3/26/97 6:46p Samir * Fixed order of tabs in dialog box. * * 61 3/26/97 5:48p Samir * Keep splash screen up a bit longer. * * 60 3/26/97 4:37p Samir * Splash screen up and running. * * 59 3/24/97 6:48p Samir * Allow clean delete of door segments. AddDefaultSegment * * 58 3/21/97 12:30p Samir * Added more keypad functionality and NET pane. * * 57 3/20/97 5:01p Matt * Removed obsolete select-from-box code * * 56 3/20/97 11:55a Jason * changes for terrain editing/drawing * * 55 3/17/97 2:26p Matt * Added function to set player view from curseg/curside * * 54 3/17/97 1:32p Matt * Took out redundant and unneeded handlers for View menu items. * * 53 3/17/97 12:25a Matt * Added call to FormJoint(), and changed a bunch of code to use the * SEGNUM() macro. * * 52 3/14/97 6:53p Samir * Took out unused functions and added delete segment function. * * 51 3/14/97 12:50p Samir * Added marked segment pane * * 50 3/13/97 7:02p Samir * Added current segment:side pane. * * 49 3/13/97 12:09p Matt * Switch to data\levels directory, so the Open file dialog will default * to that directory. * * 48 3/12/97 3:25p Matt * Added funcs for cut, copy, paste, & delete, and to save and load * groups. * * 47 3/10/97 11:13a Samir * Changes made to reflect deletion of OSDebug class from system * * 46 3/05/97 7:21p Samir * Added special initialization code for editor and use osD3Winxxxx * classes for os objects. * * 45 3/05/97 11:49a Samir * Added doorway and terrain keypad tabs. * * 44 3/04/97 11:37a Samir * Fixed goofup in tab ordering for trigger keypad. * * 43 3/03/97 5:23p Samir * Create osDatabase and osDebug obejcts. * * 42 3/02/97 4:21p Matt * Added code to select connected segments * * 41 2/28/97 6:40p Matt * Call code to call box selection code * * 40 2/28/97 4:00p Matt * Added code to handle the list of selected segments * * 39 2/28/97 2:37p Mark * * 38 2/28/97 11:09a Samir * Fixed Play in 640x480 menu item. * * 37 2/28/97 11:03a Samir * Changes to reflect newer gameos interface. * * 36 2/27/97 5:29p Mark * * 35 2/26/97 3:35p Mark * * 34 2/20/97 6:05p Samir * Allow for clean activation and deactivation of surfaces in editor when * going into fullscreen mode. * * 33 2/20/97 5:10p Samir * Added Tmap1 and Tmap2 apply accels. Tmap1 works by doing a CTRL-1. * * 32 2/20/97 9:57a Matt * Added Add Segment * * 31 2/19/97 5:39p Matt * Made EditorStatus() take printf-type args, as the D1/D2 function did. * * 30 2/19/97 2:15p Samir * Added keypad info. * * 29 2/18/97 7:04p Samir * Added print status bar message functions * * 28 2/12/97 4:07p Samir * Prompts for hogfile name when staring hog editor. * * 27 2/12/97 2:33p Samir * Added hog dialog. * * 26 2/10/97 1:59p Jason * Better import anim/bitmap functionality * * 25 2/06/97 2:46p Jason * added import bitmap function * * 24 2/05/97 12:16p Samir * Added menu item for preferences. * * 23 2/04/97 5:27p Samir * Instead of GAME_MODE go to EDITOR_GAME_MODE when playing the level. * * 22 2/04/97 5:18p Samir * Added Leaving editor... option in File Menu * * 21 1/30/97 6:43p Samir * stupid forgetting an argument * * 20 1/30/97 6:24p Samir * Reflect changes in ddgr system and game->editor->game stuff * * 19 1/23/97 4:35p Samir * Added floating keypad toggle and support * * 18 1/21/97 12:45p Samir * Toggle to get rid of keypad * * $NoKeywords: $ */ #include #include #include #include "stdafx.h" #include "editor.h" // USER INTERFACE HEADERS #include "MainFrm.h" #include "editorDoc.h" #include "editorView.h" #include "TextureDialog.h" #include "ObjectDialog.h" #include "LightingDialog.h" #include "MegacellKeypad.h" #include "TriggerDialog.h" #include "DoorwayDialog.h" #include "TerrainDialog.h" #include "WorldTexturesDialog.h" #include "WorldWeaponsDialog.h" #include "WorldObjectsDoorDialog.h" #include "WorldObjectsLightDialog.h" #include "WorldObjectsPlayerDialog.h" #include "RoomKeypadDialog.h" #include "MegacellDialog.h" #include "WorldSoundsDialog.h" #include "PathPadDialog.h" #include "GrFontDialog.h" #include "FloatingKeypadDialog.h" #include "PreferencesDialog.h" #include "HogDialog.h" #include "D3Splash.h" #include "filepagedialog.h" #include "LevelDialog.h" #include "ObjectListDialog.h" #include "TelCom.h" #include "Slew.h" #include "AmbientSoundPattern.h" #include "levelkeypad.h" #include "matcenkeypad.h" #include "scriptlevelinterface.h" #include "ScriptMassCompile.h" #include "EditLineDialog.h" // D3 EDITOR HEADERS #include "pserror.h" #include "application.h" #include "AppDatabase.h" #include "program.h" #include "gr.h" #include "init.h" #include "mono.h" #include "ddio.h" #include "descent.h" #include "bitmap.h" #include "gametexture.h" #include "manage.h" #include "vclip.h" #include "erooms.h" #include "HTexture.h" #include "HView.h" #include "selectedroom.h" #include "drawworld.h" #include "Group.h" #include "moveworld.h" #include "worldobjectsgenericdialog.h" #include "objinfo.h" #include "HFile.h" #include "hroom.h" #include "read3ds.h" #include "terrain.h" #include "HObject.h" #include "hotspotmap.h" #include "TableFileEdit.h" #include "BriefEdit.h" #include "TableFileFilter.h" #include "DallasMainDlg.h" #include "ViewerPropDlg.h" #include "mem.h" #include "findintersection.h" #include "renderer.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMainFrame IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_DESTROY() ON_COMMAND(ID_TOOLS_WORLD_TEXTURES, OnToolsWorldTextures) ON_WM_SIZE() ON_COMMAND(ID_TOOLS_WORLD_WEAPONS, OnToolsWorldWeapons) ON_COMMAND(ID_TOOLS_WORLD_OBJECTS_DOOR, OnToolsWorldObjectsDoor) ON_COMMAND(ID_TOOLS_WORLD_OBJECTS_LIGHTS, OnToolsWorldObjectsLights) ON_COMMAND(ID_TOOLS_WORLD_OBJECTS_PLAYER, OnToolsWorldObjectsPlayer) ON_COMMAND(ID_TOOLS_WORLD_OBJECTS_POWERUPS, OnToolsWorldObjectsPowerups) ON_COMMAND(ID_TOOLS_WORLD_OBJECTS_ROBOTS, OnToolsWorldObjectsRobots) ON_COMMAND(ID_SUBEDITORS_FONT, OnSubeditorsFont) ON_COMMAND(ID_FILE_PLAY640X480, OnFilePlayin640x480) ON_UPDATE_COMMAND_UI(ID_VIEW_KEYPAD_TOGGLE, OnUpdateViewKeypadToggle) ON_COMMAND(ID_VIEW_KEYPAD_TOGGLE, OnViewKeypadToggle) ON_COMMAND(ID_FILE_LEAVE_EDITOR, OnFileLeaveEditor) ON_COMMAND(ID_FILE_PREFERENCES, OnFilePreferences) ON_COMMAND(IDM_IMPORT_BITMAP, OnImportBitmap) ON_COMMAND(ID_SUBEDITORS_HOGMAKER, OnSubeditorsHogmaker) ON_COMMAND(ID_NUMPAD0, OnNumpad0) ON_COMMAND(ID_NUMPAD1, OnNumpad1) ON_COMMAND(ID_NUMPAD2, OnNumpad2) ON_COMMAND(ID_NUMPAD3, OnNumpad3) ON_COMMAND(ID_NUMPAD4, OnNumpad4) ON_COMMAND(ID_NUMPAD5, OnNumpad5) ON_COMMAND(ID_NUMPAD6, OnNumpad6) ON_COMMAND(ID_NUMPAD7, OnNumpad7) ON_COMMAND(ID_NUMPAD8, OnNumpad8) ON_COMMAND(ID_NUMPAD9, OnNumpad9) ON_COMMAND(ID_NUMPADDEL, OnNumpaddel) ON_COMMAND(ID_NUMPADMINUS, OnNumpadminus) ON_COMMAND(ID_NUMPADADD, OnNumpadadd) ON_COMMAND(ID_VIEW_CENTERONMINE, OnViewCenterOnMine) ON_COMMAND(ID_VIEW_MOVECAMERATOSELECTEDROOM, OnViewMoveCameraToSelectedRoom) ON_COMMAND(ID_VIEW_CENTERONCUBE, OnViewCenterOnCube) ON_COMMAND(ID_VIEW_CENTERONOBJECT, OnViewCenterOnObject) ON_COMMAND(ID_GROUP_CREATEGROUP, OnGroupCreateGroup) ON_COMMAND(ID_GROUP_LOADGROUP, OnGroupLoadGroup) ON_COMMAND(ID_GROUP_MIRRORGROUP, OnGroupMirrorGroup) ON_COMMAND(ID_GROUP_SAVEGROUP, OnGroupSaveGroup) ON_COMMAND(ID_EDIT_ADDSELECT, OnEditAddSelect) ON_COMMAND(ID_EDIT_CLEARSELECTED, OnEditClearSelected) ON_COMMAND(ID_EDIT_REMOVESELECT, OnEditRemoveSelect) ON_COMMAND(ID_EDIT_SELECTATTACHED, OnEditSelectAttached) ON_COMMAND(ID_EDIT_SAVESCRAP, OnEditSaveScrap) ON_COMMAND(ID_EDIT_LOADSCRAP, OnEditLoadScrap) ON_COMMAND(ID_EDIT_COPY, OnEditCopy) ON_COMMAND(ID_EDIT_CUT, OnEditCut) ON_COMMAND(ID_EDIT_DELETE, OnEditDelete) ON_UPDATE_COMMAND_UI(ID_INDICATOR_CURSEG, OnSegSidePane) ON_UPDATE_COMMAND_UI(ID_INDICATOR_NET, OnNetPane) ON_UPDATE_COMMAND_UI(ID_INDICATOR_BMMEM, OnBMMemPane) ON_UPDATE_COMMAND_UI(ID_INDICATOR_ENGINE, OnEnginePane) ON_UPDATE_COMMAND_UI(ID_INDICATOR_VIEWER, OnViewerPane) ON_COMMAND(ID_NUMPADDIV, OnNumpadDiv) ON_COMMAND(ID_NUMPADENTER, OnNumpadEnter) ON_COMMAND(ID_NUMPADLOCK, OnNumpadLock) ON_COMMAND(ID_NUMPADMUL, OnNumpadMul) ON_COMMAND(ID_OBJECT_DELETEOBJECT, OnObjectDeleteObject) ON_COMMAND(ID_OBJECT_PLACEOBJECT, OnObjectPlaceObject) ON_COMMAND(ID_TOOLS_WORLD_OBJECTS_SOUND, OnToolsWorldObjectsSound) ON_COMMAND(ID_TEST_TEST1, OnTestTest1) ON_COMMAND(ID_TEST_TEST2, OnTestTest2) ON_COMMAND(ID_TEST_TEST3, OnTestTest3) ON_WM_HELPINFO() ON_COMMAND(ID_EDITORS_MEGACELLS, OnEditorsMegacells) ON_COMMAND(IDD_REORDER_PAGES, OnReorderPages) ON_COMMAND(ID_FILE_IMPORT_ROOM, OnFileImportRoom) ON_COMMAND(ID_OBJECT_MOVEPLAYER, OnObjectMovePlayer) ON_COMMAND(ID_ROOM_VIEW, OnRoomView) ON_COMMAND(ID_TERRAIN_VIEW, OnTerrainView) ON_COMMAND(ID_MINE_VIEW, OnMineView) ON_UPDATE_COMMAND_UI(ID_MINE_VIEW, OnUpdateMineView) ON_UPDATE_COMMAND_UI(ID_ROOM_VIEW, OnUpdateRoomView) ON_UPDATE_COMMAND_UI(ID_TERRAIN_VIEW, OnUpdateTerrainView) ON_COMMAND(ID_VIEW_NEWVIEWER, OnViewNewviewer) ON_COMMAND(ID_VIEWER_NEXT, OnViewNextviewer) ON_COMMAND(ID_VIEW_DELETEVIEWER, OnViewDeleteviewer) ON_COMMAND(ID_D3HELP, OnD3help) ON_COMMAND(ID_HOTSPOT_TGA, OnHotspotTga) ON_COMMAND(ID_EDITORS_FILES, OnEditorsFiles) ON_COMMAND(ID_TOOLS_WORLD_OBJECTS_CLUTTER, OnToolsWorldObjectsClutter) ON_COMMAND(ID_TOOLS_WORLD_OBJECTS_BUILDINGS, OnToolsWorldObjectsBuildings) ON_COMMAND(ID_EDIT_PLACE, OnEditPlace) ON_COMMAND(ID_EDIT_ATTACH, OnEditAttach) ON_UPDATE_COMMAND_UI(ID_EDIT_ATTACH, OnUpdateEditAttach) ON_UPDATE_COMMAND_UI(ID_EDIT_SAVESCRAP, OnUpdateEditSaveScrap) ON_COMMAND(ID_FILE_LEVELPROPS, OnFileLevelProps) ON_COMMAND(ID_OBJBUTTON, OnObjbutton) ON_UPDATE_COMMAND_UI(ID_OBJBUTTON, OnUpdateObjbutton) ON_WM_NCDESTROY() ON_COMMAND(ID_OBJECT_SETCAMERAFROMVIEWER, OnObjectSetCameraFromViewer) ON_COMMAND(ID_OBJECT_PLACECAMERAATVIEWER, OnObjectPlaceCameraAtViewer) ON_COMMAND(ID_OBJECT_SETVIEWERFROMCAMERA, OnObjectSetViewerFromCamera) ON_WM_KEYDOWN() ON_COMMAND(ID_FILE_LEVEL_INFO, OnFileLevelInfo) ON_COMMAND(ID_FILE_STATS, OnFileStats) ON_COMMAND(ID_FILE_VERIFY_LEVEL, OnFileVerifyLevel) ON_COMMAND(ID_OBJECT_PLACECAMERAATCURRENTFACE, OnObjectPlaceCameraAtCurrentFace) ON_COMMAND(ID_SUBEDITORS_TABLEFILEEDIT, OnSubEditorsTableFileEdit) ON_COMMAND(ID_EDITORS_AMBIENTSOUNDS, OnEditorsAmbientSounds) ON_COMMAND(ID_BRIEFING_EDITOR, OnBriefingEditor) ON_COMMAND(ID_SCRIPT_LEVEL_INTERFACE, OnScriptLevelInterface) ON_COMMAND(ID_FILE_FIXCRACKS, OnFileFixCracks) ON_COMMAND(ID_VIEW_RESETVIEWRADIUS, OnViewResetViewRadius) ON_COMMAND(ID_SUBEDITORS_TABLEFILEFILTER, OnSubeditorsTablefilefilter) ON_COMMAND(ID_VIEW_SHOWOBJECTSINWIREFRAMEVIEW, OnViewShowObjectsInWireframeView) ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWOBJECTSINWIREFRAMEVIEW, OnUpdateViewShowObjectsInWireframeView) ON_COMMAND(ID_EDITORS_DALLAS, OnEditorsDallas) ON_UPDATE_COMMAND_UI(ID_OSIRISCOMPILE, OnUpdateOsiriscompile) ON_COMMAND(ID_OSIRISCOMPILE, OnOsiriscompile) ON_COMMAND(ID_VIEW_MOVECAMERATOCURRENTOBJECT, OnViewMoveCameraToCurrentObject) ON_COMMAND(ID_OBJECT_SELECTBYNUMBER, OnObjectSelectByNumber) ON_COMMAND(IDD_SHOW_ALL_CHECKED_OUT, OnShowAllCheckedOut) ON_COMMAND(ID_VIEW_SHOWVIEWERFORWARDVECTOR, OnViewShowViewerForwardVector) ON_COMMAND(ID_OBJECT_PLACESOUNDSOURCEATVIEWER, OnObjectPlaceSoundSourceAtViewer) ON_COMMAND(IDD_ORPHANHUNTER, OnOrphanhunter) ON_COMMAND(ID_OBJECT_PLACEWAYPOINTATVIEWER, OnObjectPlaceWaypointAtViewer) ON_COMMAND(ID_FILE_SAVEGOALTEXT, OnFileSaveGoalText) ON_COMMAND(ID_VIEW_VIEWPROP, OnViewViewprop) ON_UPDATE_COMMAND_UI(ID_VIEW_VIEWPROP, OnUpdateViewViewprop) ON_COMMAND(ID_VIEW_MOVECAMERATOSELECTEDFACE, OnViewMoveCameraToSelectedFace) ON_COMMAND(ID_EDIT_PLACE_TERRAIN, OnEditPlaceTerrain) ON_COMMAND(ID_CONTEXT_HELP, OnContextHelp) ON_COMMAND(ID_VIEW_NEXTVIEWER, OnViewNextviewer) ON_COMMAND(ID_ACCEL_COPY_LIGHT_MULTIPLE, OnAccelCopyLightMultiple) ON_COMMAND(ID_ACCEL_SLIDEDOWN, OnAccelSlidedown) ON_COMMAND(ID_ACCEL_SLIDELEFT, OnAccelSlideleft) ON_COMMAND(ID_ACCEL_SLIDERIGHT, OnAccelSlideright) ON_COMMAND(ID_ACCEL_SLIDEUP, OnAccelSlideup) ON_COMMAND(ID_ACCEL_NEXTVERTEX, OnAccelNextVertex) //}}AFX_MSG_MAP ON_COMMAND(ID_HELP_FINDER, CFrameWnd::OnHelpFinder) ON_COMMAND(ID_HELP, CFrameWnd::OnHelp) ON_COMMAND(ID_CONTEXT_HELP, OnContextHelp) ON_COMMAND(ID_DEFAULT_HELP, CFrameWnd::OnHelpFinder) END_MESSAGE_MAP() static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_BMMEM, // How much memory our bitmaps used ID_INDICATOR_NET, // network indicator ID_INDICATOR_CURSEG, // our current seg.side indicator ID_INDICATOR_MARKSEG, // our marked seg.side indicator ID_INDICATOR_NUM, ID_INDICATOR_ENGINE, // which engine is running (mine or room) ID_INDICATOR_VIEWER // which viewer is current }; static CMainFrame *MFC_Main_frame = NULL; ///////////////////////////////////////////////////////////////////////////// // CMainFrame construction/destruction CMainFrame::CMainFrame() { // TODO: add member initialization code here m_KeypadTabDialog = NULL; m_LightingDialog = NULL; m_TextureDialog = NULL; m_ObjectDialog = NULL; m_TriggerDialog = NULL; m_DoorwayDialog = NULL; m_PathPadDialog = NULL; m_TerrainDialog = NULL; m_MegacellKeypad = NULL; m_LevelDialog = NULL; m_MatcenDialog = NULL; m_ObjModeless = NULL; m_KeypadTabCtrl = NULL; m_RoomDialog = NULL; m_FloatingKeypadDialog = NULL; m_D3Splash = NULL; } CMainFrame::~CMainFrame() {} int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // Initializes the ddgr system and prepares for gr. if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators) / sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } // Add keypad dialog bar to the right side of the app. if (!m_wndKeypadBar.Create(this, IDD_KEYPAD_DLGBAR, CBRS_RIGHT, IDC_DLGBAR_KEYPAD)) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } // TODO: Remove this if you don't want tool tips or a resizeable toolbar m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); // TODO: Delete these three lines if you don't want the toolbar to // be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar, AFX_IDW_DOCKBAR_RIGHT); InitKeypadDialog(); DockKeypad(TRUE); // dock if tiled theApp.main_frame = MFC_Main_frame = this; return 0; } BOOL CMainFrame::PreCreateWindow(CREATESTRUCT &cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CFrameWnd::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CMainFrame diagnostics #ifdef _DEBUG void CMainFrame::AssertValid() const { CFrameWnd::AssertValid(); } void CMainFrame::Dump(CDumpContext &dc) const { CFrameWnd::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMainFrame private supporting functions void CMainFrame::InitGraphicsSystem() { // HERE: We create the DDGR Object for general GR use in the editor // HERE: We end the DDGR creating module } // Display current tab dialog void CMainFrame::ShowCurrentKeypad() { switch (D3EditState.keypad_current) { case TAB_TEXTURE_KEYPAD: m_KeypadTabDialog = m_TextureDialog; break; case TAB_OBJECTS_KEYPAD: m_KeypadTabDialog = m_ObjectDialog; break; case TAB_LIGHTING_KEYPAD: m_KeypadTabDialog = m_LightingDialog; break; case TAB_ROOM_KEYPAD: m_KeypadTabDialog = m_RoomDialog; break; case TAB_PATHS_KEYPAD: m_KeypadTabDialog = m_PathPadDialog; break; case TAB_TRIGGER_KEYPAD: m_KeypadTabDialog = m_TriggerDialog; break; case TAB_DOORWAY_KEYPAD: m_KeypadTabDialog = m_DoorwayDialog; break; case TAB_TERRAIN_KEYPAD: m_KeypadTabDialog = m_TerrainDialog; break; case TAB_MEGACELL_KEYPAD: m_KeypadTabDialog = m_MegacellKeypad; break; case TAB_LEVEL_KEYPAD: m_KeypadTabDialog = m_LevelDialog; break; case TAB_MATCEN_KEYPAD: m_KeypadTabDialog = m_MatcenDialog; break; default: Int3(); } if (m_KeypadTabDialog) { CTabCtrl *tab_ctrl = (CTabCtrl *)m_wndKeypadBar.GetDlgItem(IDC_KEYPADS); m_KeypadTabDialog->ShowWindow(SW_SHOW); tab_ctrl->SetCurSel(D3EditState.keypad_current); } } void CMainFrame::InitKeypadDialog() { CTabCtrl *tab_ctrl; TC_ITEM tc_item; m_KeypadTabCtrl = tab_ctrl = (CTabCtrl *)m_wndKeypadBar.GetDlgItem(IDC_KEYPADS); // Add tabs to tabcontrol in the keypad dialog bar. tc_item.mask = TCIF_TEXT; tc_item.pszText = "Texture"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_TEXTURE_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Megacell"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_MEGACELL_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Terrain"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_TERRAIN_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Object"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_OBJECTS_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Room"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_ROOM_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Doorway"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_DOORWAY_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Trigger"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_TRIGGER_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Lighting"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_LIGHTING_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Paths"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_PATHS_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Level"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_LEVEL_KEYPAD, &tc_item); tc_item.mask = TCIF_TEXT; tc_item.pszText = "Matcen"; tc_item.cchTextMax = lstrlen(tc_item.pszText) + 1; tab_ctrl->InsertItem(TAB_MATCEN_KEYPAD, &tc_item); // Get coordinates of dialog bar tab and RECT tab_rect, tab_winrect; int tx, ty, tw, th; tab_ctrl->GetWindowRect(&tab_winrect); ::CopyRect(&tab_rect, &tab_winrect); tab_ctrl->AdjustRect(FALSE, &tab_rect); tx = tab_rect.left - tab_winrect.left; ty = tab_rect.top - tab_winrect.top; tw = tab_rect.right - tab_rect.left; th = tab_rect.bottom - tab_rect.top; // Create tab dialogs // resize them to fit the tab control // set scroll bars accordingly m_TextureDialog = new CTextureDialog(tab_ctrl); m_TextureDialog->Create(); m_TextureDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_MegacellKeypad = new CMegacellKeypad(tab_ctrl); m_MegacellKeypad->Create(); m_MegacellKeypad->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_ObjectDialog = new CObjectDialog(tab_ctrl); m_ObjectDialog->Create(); m_ObjectDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_LightingDialog = new CLightingDialog(tab_ctrl); m_LightingDialog->Create(); m_LightingDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_RoomDialog = new CRoomKeypadDialog(tab_ctrl); m_RoomDialog->Create(); m_RoomDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_TriggerDialog = new CTriggerDialog(tab_ctrl); m_TriggerDialog->Create(); m_TriggerDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_DoorwayDialog = new CDoorwayDialog(tab_ctrl); m_DoorwayDialog->Create(); m_DoorwayDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_TerrainDialog = new CTerrainDialog(tab_ctrl); m_TerrainDialog->Create(); m_TerrainDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_PathPadDialog = new CPathPadDialog(tab_ctrl); m_PathPadDialog->Create(); m_PathPadDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_LevelDialog = new levelkeypad(tab_ctrl); m_LevelDialog->Create(); m_LevelDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); m_MatcenDialog = new matcenkeypad(tab_ctrl); m_MatcenDialog->Create(); m_MatcenDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); } void CMainFrame::DisplaySplashScreen() { m_D3Splash = new CD3Splash(this); m_D3Splash->Create(); m_D3Splash->ShowWindow(SW_SHOW); m_D3Splash->UpdateWindow(); } void CMainFrame::RemoveSplashScreen() { if (!m_D3Splash) return; m_D3Splash->ShowWindow(SW_HIDE); m_D3Splash->DestroyWindow(); m_D3Splash = NULL; } ///////////////////////////////////////////////////////////////////////////// // CMainFrame message handlers void CMainFrame::ActivateFrame(int nCmdShow) { // TODO: Add your specialized code here and/or call the base class nCmdShow = SW_MAXIMIZE; // Force initial maximization RemoveSplashScreen(); // shown when CreateClient DockKeypad(D3EditState.tile_views); // display object modeless if need be. if (D3EditState.objmodeless_on && !m_ObjModeless) { m_ObjModeless = new CObjectListModeless(this); m_ObjModeless->Create(); m_ObjModeless->SetWindowPos(this, D3EditState.objmodeless_x, D3EditState.objmodeless_y, -1, -1, SWP_NOSIZE); m_ObjModeless->ShowWindow(SW_SHOW); } CFrameWnd::ActivateFrame(nCmdShow); } BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) { return CFrameWnd::OnCommand(wParam, lParam); } void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == VK_NUMPAD5) { SlewStop(Viewer_object); } CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags); } BOOL CMainFrame::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult) { // Perform notification requests on the keypad tab dialog bar and other // custom control bars. NMHDR *nmhdr; assert(lParam != 0); nmhdr = (NMHDR *)lParam; switch (wParam) { case IDC_KEYPADS: DoKeypadTabNotify(nmhdr); break; } return CFrameWnd::OnNotify(wParam, lParam, pResult); } void CMainFrame::DoKeypadTabNotify(NMHDR *nmhdr) { CTabCtrl *tab_ctrl; tab_ctrl = (CTabCtrl *)m_wndKeypadBar.GetDlgItem(IDC_KEYPADS); switch (nmhdr->code) { case TCN_SELCHANGE: // Tab control changed. So update the controls currently displayed. D3EditState.keypad_current = (int)tab_ctrl->GetCurSel(); assert(D3EditState.keypad_current > -1); switch (D3EditState.keypad_current) { case TAB_TEXTURE_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_TextureDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_OBJECTS_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_ObjectDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_LIGHTING_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_LightingDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_ROOM_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_RoomDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_PATHS_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_PathPadDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_LEVEL_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_LevelDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_MATCEN_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_MatcenDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_TRIGGER_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_TriggerDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_DOORWAY_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_DoorwayDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_TERRAIN_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_TerrainDialog; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; case TAB_MEGACELL_KEYPAD: if (m_KeypadTabDialog) m_KeypadTabDialog->ShowWindow(SW_HIDE); m_KeypadTabDialog = m_MegacellKeypad; m_KeypadTabDialog->ShowWindow(SW_SHOW); break; } break; } } // Put all non client window destruction here! void CMainFrame::OnNcDestroy() { CFrameWnd::OnNcDestroy(); } void CMainFrame::OnDestroy() { CFrameWnd::OnDestroy(); // Save game & editor variables to the registry SaveGameSettings(); SaveEditorSettings(); // kill game and editor objects outside MFC. if (Desktop_surf) { delete Desktop_surf; Desktop_surf = NULL; } if (Database) { delete Database; Database = NULL; } if (Descent) { delete Descent; Descent = NULL; } } void InitCScripts() { char path[_MAX_PATH]; int dirlen = _MAX_PATH; // Create a default segment. This should probably be in the editor initialization code // This call must come after InitObjects() CreateNewMine(); // Setup include directories for OSIRIS ddio_MakePath(path, cf_GetWritableBaseDirectory().u8string().c_str(), "data", "levels", NULL); } // Copied from winmain.cpp void WinMainInitEditor(unsigned hwnd, unsigned hinst) { tLnxAppInfo appinfo; // TODO: HWnd from SDL2 Window // appinfo.hwnd = (HWnd)hwnd; // appinfo.hinst = (HInstance)hinst; appinfo.flags = OEAPP_WINDOWED; Descent = new oeLnxApplication(&appinfo); Database = new oeLnxAppDatabase; } // Initializes OS components for Descent3. MUST BE DONE BEFORE ANYTHING ELSE! BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext) { // TODO: Add your specialized code here and/or call the base class PreInitD3Systems(); WinMainInitEditor((unsigned)CWnd::m_hWnd, (unsigned)AfxGetInstanceHandle()); ProgramVersion(DEVELOPMENT_VERSION, 0, 0, 0); DisplaySplashScreen(); // Initialize a ton of stuff. InitD3Systems1(true); InitD3Systems2(true); // Initialize scripts InitCScripts(); // Load variables from registry LoadEditorSettings(); // Change to the levels directory, since the most likely thing to open is a level ddio_SetWorkingDir("data\\levels"); return CFrameWnd::OnCreateClient(lpcs, pContext); } void CMainFrame::ResizeKeypad() { if (::IsWindow(m_wndKeypadBar.m_hWnd)) { CTabCtrl *tab_ctrl; RECT tab_rect, tab_winrect, dbar_rect; int tx, ty, tw, th; tab_ctrl = (CTabCtrl *)m_wndKeypadBar.GetDlgItem(IDC_KEYPADS); m_wndKeypadBar.GetClientRect(&dbar_rect); dbar_rect.left += 2; dbar_rect.right -= 2; dbar_rect.top += 2; dbar_rect.bottom -= 2; tab_ctrl->MoveWindow(&dbar_rect); tab_ctrl->GetWindowRect(&tab_winrect); ::CopyRect(&tab_rect, &tab_winrect); tab_ctrl->AdjustRect(FALSE, &tab_rect); tx = tab_rect.left - tab_winrect.left; ty = tab_rect.top - tab_winrect.top; tw = tab_rect.right - tab_rect.left; th = tab_rect.bottom - tab_rect.top; if (m_TextureDialog) m_TextureDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_ObjectDialog) m_ObjectDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_LightingDialog) m_LightingDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_RoomDialog) m_RoomDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_PathPadDialog) m_PathPadDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_TriggerDialog) m_TriggerDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_DoorwayDialog) m_DoorwayDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_TerrainDialog) m_TerrainDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_MegacellKeypad) m_MegacellKeypad->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_LevelDialog) m_LevelDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); if (m_MatcenDialog) m_MatcenDialog->SetWindowPos(tab_ctrl, tx, ty, tw, th, SWP_NOZORDER); } } void CMainFrame::OnSize(UINT nType, int cx, int cy) { CFrameWnd::OnSize(nType, cx, cy); // TODO: Add your message handler code here ResizeKeypad(); } void CMainFrame::OnActivateApp(BOOL bActive, HTASK hTask) { #if 0 CFrameWnd::OnActivateApp(bActive, hTask); if (bActive) { theApp.resume(); } else { theApp.pause(); } ((oeLnxApplication *)Descent)->run_handler(this->m_hWnd, WM_ACTIVATEAPP, (unsigned)bActive, 0); #endif } // --------------------------------------------------------------------------- // These functions handle the status bar and displaying stuff in the status bar. // --------------------------------------------------------------------------- void CMainFrame::SetStatusMessage(char *str) { m_wndStatusBar.SetPaneText(0, str); } void EditorStatus(const char *format, ...) { if (MFC_Main_frame) { char status_line[256]; std::va_list ap; va_start(ap, format); std::vsnprintf(status_line, 256, format, ap); va_end(ap); MFC_Main_frame->SetStatusMessage(status_line); } } void SplashMessage(const char *format, ...) { if (D3_splash_screen) { char status_line[256]; std::va_list ap; va_start(ap, format); std::vsnprintf(status_line, 256, format, ap); va_end(ap); D3_splash_screen->PutText(status_line); } } char Editor_error_message[1000] = ""; // Set the editor error message. A function that's going to return a failure // code should call this with the error message. void SetErrorMessage(const char *fmt, ...) { std::va_list arglist; va_start(arglist, fmt); std::vsnprintf(Editor_error_message, sizeof(Editor_error_message), fmt, arglist); va_end(arglist); mprintf(0, "Editor error: %s\n", Editor_error_message); } // Get the error message from the last function that returned failure const char *GetErrorMessage() { return Editor_error_message; } void CMainFrame::OnSegSidePane(CCmdUI *pCmdUI) { CString strSegSide; pCmdUI->Enable(); if (Editor_view_mode == VM_TERRAIN) { // We could put something here, but I don't know what. Jason? } else if (Editor_view_mode == VM_MINE) { if (Curroomp) strSegSide.Format("Cur %d:%d", ROOMNUM(Curroomp), Curface); else strSegSide.Format("No curroom"); } else if (Editor_view_mode == VM_ROOM) { if (Current_faces[D3EditState.current_room - FIRST_PALETTE_ROOM] != -1) strSegSide.Format("Face %d", Current_faces[D3EditState.current_room - FIRST_PALETTE_ROOM]); else strSegSide.Format("No face"); } else Int3(); pCmdUI->SetText(strSegSide); } void CMainFrame::OnBMMemPane(CCmdUI *pCmdUI) { CString strSegSide; pCmdUI->Enable(); strSegSide.Format("Bitmap memory: %d K", Bitmap_memory_used / 1000); pCmdUI->SetText(strSegSide); } void CMainFrame::OnEnginePane(CCmdUI *pCmdUI) { CString strEngineType; pCmdUI->Enable(); switch (Editor_view_mode) { case VM_MINE: strEngineType.Format("Mine View"); break; case VM_TERRAIN: strEngineType.Format("Terrain View"); break; case VM_ROOM: strEngineType.Format("Room View"); break; } pCmdUI->SetText(strEngineType); } void CMainFrame::OnViewerPane(CCmdUI *pCmdUI) { CString strViewerNum; pCmdUI->Enable(); if (Editor_view_mode == VM_ROOM) strViewerNum.Format(""); // Don't show viewer number in room view else strViewerNum.Format("Viewer %d", GetViewerNum()); pCmdUI->SetText(strViewerNum); } void CMainFrame::OnNetPane(CCmdUI *pCmdUI) { CString strSegSide; pCmdUI->Enable(); if (Network_up) strSegSide.Format("NET"); else strSegSide.Format("NoNet"); pCmdUI->SetText(strSegSide); } // --------------------------------------------------------------------------- // Menu items // --------------------------------------------------------------------------- void CMainFrame::OnToolsWorldTextures() { CWorldTexturesDialog wtexdlg; theApp.pause(); wtexdlg.DoModal(); theApp.resume(); } void CMainFrame::OnToolsWorldWeapons() { CWorldWeaponsDialog wweapdlg; theApp.pause(); wweapdlg.DoModal(); theApp.resume(); } void CMainFrame::OnToolsWorldObjectsDoor() { CWorldObjectsDoorDialog dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } void CMainFrame::OnToolsWorldObjectsLights() { CWorldObjectsLightDialog dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } void CMainFrame::OnToolsWorldObjectsPlayer() { CWorldObjectsPlayerDialog dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } void CMainFrame::OnToolsWorldObjectsPowerups() { CWorldObjectsGenericDialog dlg; dlg.m_type = OBJ_POWERUP; dlg.m_current = D3EditState.current_powerup; theApp.pause(); dlg.DoModal(); theApp.resume(); if (dlg.m_current != -1) D3EditState.current_powerup = dlg.m_current; } void CMainFrame::OnToolsWorldObjectsRobots() { CWorldObjectsGenericDialog dlg; dlg.m_type = OBJ_ROBOT; dlg.m_current = D3EditState.current_robot; theApp.pause(); dlg.DoModal(); theApp.resume(); if (dlg.m_current != -1) D3EditState.current_robot = dlg.m_current; } void CMainFrame::OnToolsWorldObjectsClutter() { CWorldObjectsGenericDialog dlg; dlg.m_type = OBJ_CLUTTER; dlg.m_current = D3EditState.current_clutter; theApp.pause(); dlg.DoModal(); theApp.resume(); if (dlg.m_current != -1) D3EditState.current_clutter = dlg.m_current; } void CMainFrame::OnToolsWorldObjectsBuildings() { CWorldObjectsGenericDialog dlg; dlg.m_type = OBJ_BUILDING; dlg.m_current = D3EditState.current_building; theApp.pause(); dlg.DoModal(); theApp.resume(); if (dlg.m_current != -1) D3EditState.current_building = dlg.m_current; } void CMainFrame::OnSubeditorsFont() { CGrFontDialog dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } void CMainFrame::OnUpdateViewKeypadToggle(CCmdUI *pCmdUI) { pCmdUI->SetCheck((BOOL)D3EditState.keypad_visible); } void CMainFrame::OnViewKeypadToggle() { D3EditState.keypad_visible = !D3EditState.keypad_visible; if (D3EditState.tile_views) { ShowControlBar(&m_wndKeypadBar, (BOOL)D3EditState.keypad_visible, FALSE); ResizeKeypad(); ShowCurrentKeypad(); } else if (!D3EditState.keypad_visible && m_FloatingKeypadDialog) m_FloatingKeypadDialog->ShowWindow(SW_HIDE); else if (D3EditState.keypad_visible && m_FloatingKeypadDialog) m_FloatingKeypadDialog->ShowWindow(SW_SHOW); } void CMainFrame::DockKeypad(BOOL dock) { if (D3EditState.keypad_visible) { if (dock) { // Resize the keypad to the size of the window. if (m_FloatingKeypadDialog) { m_FloatingKeypadDialog->DestroyWindow(); m_FloatingKeypadDialog = NULL; } ShowControlBar(&m_wndKeypadBar, TRUE, FALSE); ResizeKeypad(); ShowCurrentKeypad(); } else { ShowControlBar(&m_wndKeypadBar, FALSE, FALSE); if (!m_FloatingKeypadDialog) { if (!D3EditState.float_keypad_moved) { RECT rect; m_wndKeypadBar.GetWindowRect(&rect); GetActiveFrame()->ScreenToClient(&rect); D3EditState.float_keypad_x = rect.left; D3EditState.float_keypad_y = rect.top; } CWnd *wnd = GetActiveView(); m_FloatingKeypadDialog = new CFloatingKeypadDialog(wnd); m_FloatingKeypadDialog->Create(); if (!D3EditState.float_keypad_moved) { RECT rect; m_FloatingKeypadDialog->GetWindowRect(&rect); D3EditState.float_keypad_w = rect.right - rect.left; D3EditState.float_keypad_h = rect.bottom - rect.top; } } // place keypad at right, top of desktop if not already placed m_FloatingKeypadDialog->SetWindowPos(NULL, D3EditState.float_keypad_x, D3EditState.float_keypad_y, D3EditState.float_keypad_w, D3EditState.float_keypad_h, SWP_NOZORDER); m_FloatingKeypadDialog->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); m_FloatingKeypadDialog->ShowWindow(SW_SHOW); D3EditState.float_keypad_moved = 1; } } else { // keypad is NOT visi . ShowControlBar(&m_wndKeypadBar, FALSE, FALSE); } } // Invoke Descent 3 from D3Edit extern void RunGameFromEditor(); void CMainFrame::OnFilePlayin640x480() { // Returns true if there are out of data files int count = AreScriptsOutofDate(); if (count > 0) { if (OutrageMessageBox(MBOX_YESNO, "There were %d scripts that couldn't be compiled, continue?", count) != IDYES) return; } renderer_type sr_save; bool keypad_was_visible = D3EditState.keypad_visible; DWORD cbar_was_visible = (m_wndToolBar.GetStyle() & WS_VISIBLE); DWORD status_was_visible = (m_wndStatusBar.GetStyle() & WS_VISIBLE); // Shutdown view system m_ViewActivated = FALSE; ((CEditorView *)GetActiveView())->DeactivateView(); if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->Deactivate(); CKeypadDialog::Deactivate(); delete Desktop_surf; // hide keypad if it's visible if (keypad_was_visible) OnViewKeypadToggle(); if (cbar_was_visible) ShowControlBar(&m_wndToolBar, FALSE, FALSE); if (status_was_visible) ShowControlBar(&m_wndStatusBar, FALSE, FALSE); SetFunctionMode(EDITOR_GAME_MODE); sr_save = Renderer_type; // if we have selected the windowed toggle, assert this. if (D3EditState.game_render_mode == GM_WINDOWED) PROGRAM(windowed) = 1; else PROGRAM(windowed) = 0; RunGameFromEditor(); PROGRAM(windowed) = 1; Renderer_type = sr_save; // hide keypad if it's visible if (status_was_visible) ShowControlBar(&m_wndStatusBar, TRUE, FALSE); if (cbar_was_visible) ShowControlBar(&m_wndToolBar, TRUE, FALSE); if (keypad_was_visible) OnViewKeypadToggle(); // Restore view system Desktop_surf = new grSurface(0, 0, 0, SURFTYPE_VIDEOSCREEN, 0); if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->Activate(); CKeypadDialog::Activate(); ((CEditorView *)GetActiveView())->ActivateView(); m_ViewActivated = TRUE; } void CMainFrame::OnFileLeaveEditor() { // Returns true if there are out of data files int count = AreScriptsOutofDate(); if (count > 0) { if (OutrageMessageBox(MBOX_YESNO, "There were %d scripts that couldn't be compiled, continue?", count) != IDYES) return; } bool keypad_was_visible = D3EditState.keypad_visible; DWORD cbar_was_visible = (m_wndToolBar.GetStyle() & WS_VISIBLE); DWORD status_was_visible = (m_wndStatusBar.GetStyle() & WS_VISIBLE); // Shutdown view system m_ViewActivated = FALSE; ((CEditorView *)GetActiveView())->DeactivateView(); if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->Deactivate(); CKeypadDialog::Deactivate(); delete Desktop_surf; // hide keypad if it's visible if (keypad_was_visible) OnViewKeypadToggle(); if (cbar_was_visible) ShowControlBar(&m_wndToolBar, FALSE, FALSE); if (status_was_visible) ShowControlBar(&m_wndStatusBar, FALSE, FALSE); SetFunctionMode(MENU_MODE); // if we have selected the windowed toggle, assert this. if (D3EditState.game_render_mode == GM_WINDOWED) PROGRAM(windowed) = 1; else PROGRAM(windowed) = 0; RunGameFromEditor(); PROGRAM(windowed) = 1; // hide keypad if it's visible if (status_was_visible) ShowControlBar(&m_wndStatusBar, TRUE, FALSE); if (cbar_was_visible) ShowControlBar(&m_wndToolBar, TRUE, FALSE); if (keypad_was_visible) OnViewKeypadToggle(); // Restore view system Desktop_surf = new grSurface(0, 0, 0, SURFTYPE_VIDEOSCREEN, 0); if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->Activate(); CKeypadDialog::Activate(); ((CEditorView *)GetActiveView())->ActivateView(); m_ViewActivated = TRUE; } void CMainFrame::OnFilePreferences() { CPreferencesDialog dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } void CMainFrame::OnImportBitmap() { char filename[200]; int bm_handle, anim = 0; CString filter = "Descent III files (*.tga,*.bbm,*.lbm,*.ogf,*.oaf,*.ilf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;*.oaf;*.ifl||"; if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir))) return; // Okay, we selected a file. Lets do what needs to be done here. bm_handle = LoadTextureImage(filename, &anim, NOT_TEXTURE, 0); if (bm_handle < 0) { OutrageMessageBox("Couldn't open that bitmap/anim file."); return; } mprintf(0, "Making a copy of this bitmap/anim locally...\n"); if (!anim) { sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(), GameBitmaps[bm_handle].name); bm_SaveFileBitmap(filename, bm_handle); bm_FreeBitmap(bm_handle); } else { sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(), GameVClips[bm_handle].name); SaveVClip(filename, bm_handle); FreeVClip(bm_handle); } OutrageMessageBox("Image(s) imported!"); } void CMainFrame::OnSubeditorsHogmaker() { // Open common file open dialog box. CString filter = "Descent III hogfiles (*.hog)|*.hog||"; CFileDialog dlg_open(TRUE, 0, 0, OFN_FILEMUSTEXIST, (LPCTSTR)filter, this); char filename[_MAX_PATH]; if (dlg_open.DoModal() == IDCANCEL) { return; } lstrcpy(filename, dlg_open.GetPathName()); // Open the HOG Dialog CHogDialog dlg(this, filename); theApp.pause(); dlg.DoModal(); theApp.resume(); } // --------------------------------------------------------------------------- // Number PAD functions // --------------------------------------------------------------------------- void CMainFrame::OnNumpad0() { mprintf(0, "NUMPAD0\n"); if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD0); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD0); } void CMainFrame::OnNumpad1() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD1); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD1); } void CMainFrame::OnNumpad2() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD2); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD2); } void CMainFrame::OnNumpad3() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD3); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD3); } void CMainFrame::OnNumpad4() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD4); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD4); } void CMainFrame::OnNumpad5() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD5); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD5); } void CMainFrame::OnNumpad6() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD6); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD6); } void CMainFrame::OnNumpad7() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD7); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD7); } void CMainFrame::OnNumpad8() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD8); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD8); } void CMainFrame::OnNumpad9() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMPAD9); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMPAD9); } void CMainFrame::OnNumpaddel() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_DELETE); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_DELETE); } void CMainFrame::OnNumpadminus() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_SUBTRACT); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_SUBTRACT); } void CMainFrame::OnNumpadadd() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_ADD); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_ADD); } void CMainFrame::OnNumpadDiv() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_DIVIDE); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_DIVIDE); } void CMainFrame::OnNumpadEnter() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_RETURN); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_RETURN); } void CMainFrame::OnNumpadLock() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_NUMLOCK); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_NUMLOCK); } void CMainFrame::OnNumpadMul() { if (!D3EditState.keypad_visible) return; if (m_FloatingKeypadDialog) m_FloatingKeypadDialog->RunKeypadFunction(VK_MULTIPLY); else if (m_KeypadTabDialog) m_KeypadTabDialog->RunKeypadFunction(VK_MULTIPLY); } // --------------------------------------------------------------------------- // Yet more editor functions // --------------------------------------------------------------------------- void CMainFrame::OnViewCenterOnMine() { ResetWireframeView(); } void CMainFrame::OnViewMoveCameraToSelectedRoom() { SetViewerFromRoomFace(Curroomp, Curface, 1); } void CMainFrame::OnViewCenterOnCube() { vector pos; if (Editor_view_mode == VM_ROOM) ComputeRoomCenter(&pos, &Rooms[D3EditState.current_room]); else ComputeRoomCenter(&pos, Curroomp); SetWireframeView(&pos); } void CMainFrame::OnViewCenterOnObject() { SetWireframeView(&Objects[Cur_object_index].pos); } void CMainFrame::OnGroupCreateGroup() { // TODO: Add your command handler code here } void CMainFrame::OnGroupLoadGroup() { // TODO: Add your command handler code here } void CMainFrame::OnGroupMirrorGroup() { // TODO: Add your command handler code here } void CMainFrame::OnGroupSaveGroup() { // TODO: Add your command handler code here } void CMainFrame::OnEditAddSelect() { AddRoomToSelectedList(ROOMNUM(Curroomp)); } void CMainFrame::OnEditClearSelected() { ClearRoomSelectedList(); } void CMainFrame::OnEditRemoveSelect() { RemoveRoomFromSelectedList(ROOMNUM(Curroomp)); } void CMainFrame::OnEditSelectAttached() { int count; count = SelectConnectedRooms(ROOMNUM(Curroomp)); EditorStatus("%d rooms selected", count); } void CMainFrame::OnEditSaveScrap() { if (Scrap == NULL) { OutrageMessageBox("The scrap buffer is empty."); return; } CString filter = "D3 Group Files (*.grp)|*.grp||"; char filename[255]; if (!SaveFileDialog(this, (LPCSTR)filter, filename, Current_scrap_dir, sizeof(Current_scrap_dir))) return; if (!strchr(filename, '.')) strcat(filename, ".grp"); SaveGroup(filename, Scrap); EditorStatus("Group saved to %s", filename); } void CMainFrame::OnEditLoadScrap() { CString filter = "D3 Group Files (*.grp)|*.grp||"; char filename[255]; group *newscrap; if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_scrap_dir, sizeof(Current_scrap_dir))) return; if (!strchr(filename, '.')) strcat(filename, ".grp"); newscrap = LoadGroup(filename); if (newscrap) { if (Scrap) FreeGroup(Scrap); Scrap = newscrap; EditorStatus("Group loaded from %s", filename); } } // Copies the selected rooms to the scrap buffer. // Returns: true if copied ok, 0 if some error int CopySelectedRooms() { if (N_selected_rooms == 0) { OutrageMessageBox("You must have rooms selected for this operation."); return 0; } if (!Markedroomp) { OutrageMessageBox("You must have a marked room for this operation."); return 0; } if (!IsRoomSelected(ROOMNUM(Markedroomp))) { OutrageMessageBox("The Marked room must be selected for this operation."); return 0; } if (!((Markedroomp->faces[Markedface].portal_num == -1) || (Markedroomp->portals[Markedroomp->faces[Markedface].portal_num].croom == -1) || !IsRoomSelected(Markedroomp->portals[Markedroomp->faces[Markedface].portal_num].croom))) { OutrageMessageBox("The Marked room/face must be unattached for this operation."); return 0; } // Get rid of old contents of scrap buffer if (Scrap) FreeGroup(Scrap); Scrap = CopyGroup(N_selected_rooms, Selected_rooms, ROOMNUM(Markedroomp), Markedface); return 1; } void CMainFrame::OnEditCopy() { if (CopySelectedRooms()) EditorStatus("%d rooms copied to Scrap", N_selected_rooms); } void CMainFrame::OnEditPlace() { if (!Scrap) { OutrageMessageBox("There is nothing in the scrap buffer."); return; } if (Curroomp->faces[Curface].portal_num != -1) { OutrageMessageBox("The selected Room/Face must be free for this operation."); return; } PlaceGroup(Curroomp, Curface, Scrap); } void CMainFrame::OnEditPlaceTerrain() { if (!Scrap) { OutrageMessageBox("There is nothing in the scrap buffer."); return; } int cellnum; if (Num_terrain_selected != 1) { OutrageMessageBox("You must have one and only one cell selected this operation"); return; } else { for (cellnum = 0; cellnum < TERRAIN_WIDTH * TERRAIN_DEPTH; cellnum++) if (TerrainSelected[cellnum]) break; ASSERT(cellnum != TERRAIN_WIDTH * TERRAIN_DEPTH); } int result = OutrageMessageBox(MBOX_YESNOCANCEL, "Do you want to align to the terrain? NO will align with gravity."); if (result == IDCANCEL) return; PlaceGroupTerrain(cellnum, Scrap, (result == IDYES)); } void CMainFrame::OnEditAttach() { ASSERT(Placed_group != NULL); AttachGroup(); } void CMainFrame::OnEditCut() { if (CopySelectedRooms()) { int n = N_selected_rooms; DeleteGroup(N_selected_rooms, Selected_rooms); EditorStatus("%d rooms cut to Scrap", n); ClearRoomSelectedList(); } } void CMainFrame::OnEditDelete() { if (N_selected_rooms == 0) { OutrageMessageBox("You must have rooms selected for this operation."); return; } DeleteGroup(N_selected_rooms, Selected_rooms); EditorStatus("%d rooms deleted", N_selected_rooms); ClearRoomSelectedList(); } void CMainFrame::OnObjectDeleteObject() { // TODO: Add your command handler code here if (m_ObjectDialog) m_ObjectDialog->DeleteObject(); } void CMainFrame::OnObjectPlaceObject() { // TODO: Add your command handler code here if (m_ObjectDialog) m_ObjectDialog->PlaceObject(); } void CMainFrame::OnToolsWorldObjectsSound() { CWorldSoundsDialog dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } // Keep this around void ResetObjectOntoTerrain() { if (Cur_object_index != -1) { object *objp = &Objects[Cur_object_index]; if (!OBJECT_OUTSIDE(objp)) { int roomnum = GetTerrainRoomFromPos(&objp->pos); ObjSetPos(objp, &objp->pos, roomnum, NULL, true); EditorStatus("Object %d (\"%s\") moved to cell %d", OBJNUM(objp), objp->name ? objp->name : "", CELLNUM(roomnum)); World_changed = 1; } else EditorStatus("Object %d (\"%s\") already outside (on cell %d)", OBJNUM(objp), objp->name ? objp->name : "", CELLNUM(objp->roomnum)); } } // Keep this around void ResetObjectsIntoMine() { int i, objnum, count = 0; for (i = 0; i < TERRAIN_WIDTH * TERRAIN_DEPTH; i++) { if (TerrainSelected[i]) { for (objnum = Terrain_seg[i].objects; objnum != -1;) { object *objp = &Objects[objnum]; int next = objp->next; if ((objp->type != OBJ_VIEWER) && (objp->type != OBJ_ROOM)) { int roomnum = FindPointRoom(&objp->pos); if (roomnum == -1) OutrageMessageBox("Can't find room for object %d (type = %s)", objnum, Object_type_names[objp->type]); else { mprintf(0, "Moving object %d to room %d\n", objnum, roomnum); ObjSetPos(&Objects[objnum], &objp->pos, roomnum, NULL, true); count++; } } objnum = next; } } } OutrageMessageBox("%d objects were moved from the terrain to the mine.", count); World_changed = 1; } void DeleteAllFacesWithTexture1(room *rp) { int count = 0; if (OutrageMessageBox(MBOX_YESNO, "Are you sure you want to delete all faces in room %d that have texture 1?", ROOMNUM(rp)) != IDYES) return; for (int i = 0; i < rp->num_faces; i++) { if ((rp->faces[i].tmap == 1) && (rp->faces[i].portal_num == -1)) { DeleteRoomFace(rp, i); i--; count++; } } OutrageMessageBox("%d faces deleted from room %d.", count, ROOMNUM(rp)); Curface = Curedge = Curvert = 0; World_changed = 1; } // Put test code here. Feel free to delete any old code. extern float Room_multiplier[]; #include "lightmap_info.h" #include "lightmap.h" #include "polymodel.h" int IsNonRenderableSubmodel(poly_model *pm, int submodelnum); extern uint16_t *Free_lmi_list; void CMainFrame::OnTestTest1() { if (MessageBox("Do you really really want to murder the lightmaps?", "Confirm", MB_YESNO) != IDYES) return; // severly bash lightmaps int r, f; room *rp; face *fp; for (r = 0; r <= Highest_room_index; r++) { if (!Rooms[r].used) continue; rp = &Rooms[r]; for (f = 0; f < rp->num_faces; f++) { fp = &rp->faces[f]; fp->flags &= ~FF_LIGHTMAP; fp->lmi_handle = BAD_LMI_INDEX; } } // now free lightmap infos void CloseLightmapInfos(); CloseLightmapInfos(); InitLightmapInfo(0); Num_of_lightmap_info = 0; Num_lightmap_infos_read = 0; int i, m, t; for (i = 0; i < MAX_OBJECTS; i++) { if (!Objects[i].lm_object.used) continue; poly_model *pm = &Poly_models[Objects[i].rtype.pobj_info.model_num]; for (m = 0; m < pm->n_models; m++) { if (IsNonRenderableSubmodel(pm, m)) continue; for (t = 0; t < Objects[i].lm_object.num_faces[m]; t++) { lightmap_object_face *fp = &Objects[i].lm_object.lightmap_faces[m][t]; fp->lmi_handle = BAD_LMI_INDEX; mem_free(fp->u2); mem_free(fp->v2); } mem_free(Objects[i].lm_object.lightmap_faces[m]); } Objects[i].lm_object.used = 0; } } extern void dump_text_to_clipboard(char *text); // Make a list of all the rooms with names void ShowRooms() { char text_buf[10000], *t; int i, n; t = text_buf; sprintf(t, ""); for (i = n = 0; i <= Highest_room_index; i++) { if (Rooms[i].used && Rooms[i].name) { sprintf(t, "Room %d is named \"%s\"\n", i, Rooms[i].name); n++; t += strlen(t); if ((t - text_buf) > (sizeof(text_buf) - 200)) { sprintf(t, "Out of buffer space\n"); break; } } } dump_text_to_clipboard(text_buf); OutrageMessageBox("There are %d named rooms.\n\nThe list has been written to the clipboard.", n); } void ListAllObjects() { void ListObjectsInAllLevels(); extern bool Stay_paused; if (OutrageMessageBox(MBOX_YESNO, "This will take a long time.\n\nAre you sure you want to continue?") != IDYES) return; theApp.pause(); Stay_paused = 1; SetFunctionMode(EDITOR_GAME_MODE); // keep LoadLevel() from bringing up messages ListObjectsInAllLevels(); SetFunctionMode(EDITOR_MODE); Stay_paused = 0; theApp.resume(); OutrageMessageBox("Object infomation written to clipboard."); } void FindBadDestroyedTextures() { int count = 0; for (int i = 0; i < MAX_TEXTURES; i++) { if ((GameTextures[i].flags & TF_DESTROYABLE) && (GameTextures[i].destroy_handle == 0)) { mprintf(0, "Texture %d, \"%s\" has a bad destroyed bitmap\n", i, GameTextures[i].name); count++; } } OutrageMessageBox("Found %d bad destroyed textures.", count); } // Make a list of all the objects with lightmaps void ListLightmapObjects() { int count = 0, lm_count = 0; for (int i = 0; i <= Highest_object_index; i++) { if (Objects[i].type != OBJ_NONE) { count++; if (IS_GENERIC(Objects[i].type) && (Object_info[Objects[i].id].lighting_info.lighting_render_type == LRT_LIGHTMAPS)) { lm_count++; mprintf(0, "%d: %s %s", i, Object_type_names[Objects[i].type], Object_info[Objects[i].id].name); if (Objects[i].name) mprintf(0, " name=\"%s\"\n", Objects[i].name); else mprintf(0, "\n"); } else ; // mprintf(0,"%d ",i); } } mprintf(0, "Num object = %d. Num with lightmaps = %d\n", count, lm_count); } // Put test code here. Feel free to delete any old code. void CMainFrame::OnTestTest2() { FindBadDestroyedTextures(); } extern char error_buf[]; extern int error_buf_offset; void CheckError(const char *str, ...); uint32_t check_point_to_face(vector *colp, vector *face_normal, int nv, vector **vertex_ptr_list); void LookForFVICracks() { int r, f, v, edgemask, count = 0; room *rp; face *fp; error_buf_offset = 0; for (r = 0, rp = Rooms; r <= Highest_room_index; r++, rp++) { if (rp->used) { for (f = 0, fp = rp->faces; f < rp->num_faces; f++, fp++) { vector *vertex_ptr_list[MAX_VERTS_PER_FACE]; for (v = 0; v < fp->num_verts; v++) vertex_ptr_list[v] = &rp->verts[fp->face_verts[v]]; for (v = 0; v < fp->num_verts; v++) { edgemask = check_point_to_face(vertex_ptr_list[v], &fp->normal, fp->num_verts, vertex_ptr_list); if (edgemask) { CheckError("Vert %d is outside of %d:%d\n", v, r, f); count++; } } } } } DumpTextToClipboard(error_buf); OutrageMessageBox("Found %d FVI face cracks.", count); } void MoveEntireMine() { char buf[10] = ""; strcpy(buf, "0"); if (!InputString(buf, sizeof(buf), "Move Amount", "Enter an amount to move in X")) return; float delta_x = atof(buf); strcpy(buf, "0"); if (!InputString(buf, sizeof(buf), "Move Amount", "Enter an amount to move in Z")) return; float delta_z = atof(buf); int r; room *rp; for (r = 0, rp = Rooms; r <= Highest_room_index; r++, rp++) { if (rp->used) { for (int v = 0; v < rp->num_verts; v++) { rp->verts[v].x += delta_x; rp->verts[v].z += delta_z; } for (int objnum = rp->objects; objnum != -1; objnum = Objects[objnum].next) { Objects[objnum].pos.x += delta_x; Objects[objnum].pos.z += delta_z; } } } World_changed = 1; } void ScaleEntireMine() { char buf[10] = ""; if (!InputString(buf, sizeof(buf), "Scale Amount", "Enter an amount by which to scale the mine")) return; float scale = atof(buf); int r; room *rp; for (r = 0, rp = Rooms; r <= Highest_room_index; r++, rp++) { if (rp->used) { for (int v = 0; v < rp->num_verts; v++) rp->verts[v] *= scale; for (int objnum = rp->objects; objnum != -1; objnum = Objects[objnum].next) Objects[objnum].pos *= scale; } } World_changed = 1; } int CountSpecularFaces() { int i, t; int count = 0; for (i = 0; i < MAX_ROOMS; i++) { if (Rooms[i].used) { if (Rooms[i].flags & RF_NO_LIGHT) continue; room *rp = &Rooms[i]; for (t = 0; t < rp->num_faces; t++) { face *fp = &rp->faces[t]; if (GameTextures[fp->tmap].flags & TF_SPECULAR) { count++; } } } } return count; } // Put test code here. Feel free to delete any old code. void CMainFrame::OnTestTest3() { MoveEntireMine(); return; // ResetObjectsIntoMine(); // Check all powerups and make sure they all have physics on them (for spewing) CFILE *file = cfopen("C:\\physics.txt", "wt"); if (!file) return; char buffer[384]; for (int i = 0; i < MAX_OBJECT_IDS; i++) { if (Object_info[i].type == OBJ_NONE) continue; switch (Object_info[i].type) { case OBJ_POWERUP: { if (!(Object_info[i].flags & OIF_USES_PHYSICS)) { sprintf(buffer, "Powerup: %s", Object_info[i].name); cf_WriteString(file, buffer); } } break; case OBJ_CLUTTER: { if (!(Object_info[i].flags & OIF_USES_PHYSICS)) { sprintf(buffer, "Clutter: %s", Object_info[i].name); cf_WriteString(file, buffer); } } break; case OBJ_BUILDING: { if (!(Object_info[i].flags & OIF_USES_PHYSICS)) { sprintf(buffer, "Building: %s", Object_info[i].name); cf_WriteString(file, buffer); } } break; case OBJ_ROBOT: { if (!(Object_info[i].flags & OIF_USES_PHYSICS)) { sprintf(buffer, "Robot: %s", Object_info[i].name); cf_WriteString(file, buffer); } } break; } } cfclose(file); } int GetChangeMask() { static room *last_curroomp = NULL; static int last_curface = -1, last_curportal = -1, last_curobj = -1; static char last_name[OBJ_NAME_LEN + 1] = ""; int mask = 0; if (Cur_object_index != last_curobj) mask |= KUF_CUROBJ_CHANGED; last_curobj = Cur_object_index; if (Curroomp != last_curroomp) mask |= KUF_CURROOM_CHANGED; last_curroomp = Curroomp; if (Curface != last_curface) mask |= KUF_CURFACE_CHANGED; last_curface = Curface; if (Curportal != last_curportal) mask |= KUF_CURPORTAL_CHANGED; last_curportal = Curportal; if (Cur_object_index != -1) { char *name = Objects[Cur_object_index].name ? Objects[Cur_object_index].name : ""; if (strcmp(last_name, name)) mask |= KUF_CUROBJ_NAME_CHANGED; strcpy(last_name, name); } if (New_mine) mask |= KUF_LEVEL_LOADED; return mask; } // Called from the main idle function void CMainFrame::OnIdle() { // update keypads. int mask = GetChangeMask(); if (m_TextureDialog) { m_TextureDialog->UpdateKeypad(mask); } if (m_ObjectDialog) { m_ObjectDialog->UpdateKeypad(mask); } if (m_LightingDialog) { m_LightingDialog->UpdateKeypad(mask); } if (m_RoomDialog) { m_RoomDialog->UpdateKeypad(mask); } if (m_PathPadDialog) { m_PathPadDialog->UpdateKeypad(mask); } if (m_TriggerDialog) { m_TriggerDialog->UpdateKeypad(mask); } if (m_DoorwayDialog) { m_DoorwayDialog->UpdateKeypad(mask); } if (m_TerrainDialog) { m_TerrainDialog->UpdateKeypad(mask); } if (m_MegacellKeypad) { m_MegacellKeypad->UpdateKeypad(mask); } if (m_LevelDialog) { m_LevelDialog->UpdateKeypad(mask); } if (m_MatcenDialog) { m_MatcenDialog->UpdateKeypad(mask); } } BOOL CMainFrame::OnHelpInfo(HELPINFO *pHelpInfo) { // TODO: Add your message handler code here and/or call default return CFrameWnd::OnHelpInfo(pHelpInfo); } void CMainFrame::OnEditorsMegacells() { CMegacellDialog dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } void ReorderPages(int); void CMainFrame::OnReorderPages() { if (Network_up == 0) { OutrageMessageBox("The network is not up, so this function is unavailable."); return; } int answer = MessageBox("Are you absolutely positively sure you want to do this? I mean, if you have no idea what " "you are doing (ie, a level designer) then please - don't execute this function.", "EXTREME DANGER - YOU MIGHT DIE", MB_YESNO); if (answer == IDNO) { OutrageMessageBox("Damn that was close."); return; } ReorderPages(0); OutrageMessageBox("Done reordering pages!"); } void CMainFrame::OnFileImportRoom() { // Filter out the curious char filename[200]; CString filter = "Outrage 3dsmax files (*.p3d)|*.p3d||"; if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_room_dir, sizeof(Current_room_dir))) return; int n = Read3DSMaxFile(filename); if (n >= 0) { D3EditState.current_room = n; State_changed = 1; OutrageMessageBox("Room imported and saved locally.\n\nPress OK to check room validity."); VerifyRoom(&Rooms[n]); } theApp.resume(); } void CMainFrame::OnObjectMovePlayer() { HObjectMoveToViewer(Player_object); } // Set the editor view mode void SetViewMode(int view_mode) { // Set new view mode Editor_view_mode = view_mode; // Get the correct viewer (terrain or mine or room) SetEditorViewer(); // Set the correct wireframe view if (view_mode == VM_ROOM) Wireframe_view = &Wireframe_view_room; else if (view_mode == VM_MINE) Wireframe_view = &Wireframe_view_mine; // Force the windows to update AfxGetMainWnd()->Invalidate(TRUE); AfxGetMainWnd()->UpdateWindow(); } void CMainFrame::OnRoomView() { SetViewMode(VM_ROOM); } void CMainFrame::OnTerrainView() { SetViewMode(VM_TERRAIN); } void CMainFrame::OnMineView() { // Make sure there's a room to switch to int roomnum; for (roomnum = 0; roomnum <= Highest_room_index; roomnum++) if (Rooms[roomnum].used && !(Rooms[roomnum].flags & RF_EXTERNAL)) break; if (roomnum > Highest_room_index) { OutrageMessageBox("Cannot switch to Mine View: there are no internal rooms."); return; } SetViewMode(VM_MINE); } void CMainFrame::OnUpdateMineView(CCmdUI *pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->SetRadio(Editor_view_mode == VM_MINE); } void CMainFrame::OnUpdateRoomView(CCmdUI *pCmdUI) { // TODO: Add your command update UI handler code here int start, end, roomnum; bool room_loaded = false; start = FIRST_PALETTE_ROOM; end = start + MAX_PALETTE_ROOMS; for (roomnum = start; roomnum < end; roomnum++) if (Rooms[roomnum].used) { room_loaded = true; break; } if (!room_loaded) pCmdUI->Enable(false); else { pCmdUI->Enable(true); pCmdUI->SetRadio(Editor_view_mode == VM_ROOM); } } void CMainFrame::OnUpdateTerrainView(CCmdUI *pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->SetRadio(Editor_view_mode == VM_TERRAIN); } void CMainFrame::OnViewNewviewer() { CreateNewViewer(); } void CMainFrame::OnViewNextviewer() { SelectNextViewer(); } void CMainFrame::OnViewDeleteviewer() { DeleteViewer(); } void CMainFrame::OnD3help() { // TODO: Add your command handler code here WinHelp(HID_GENERAL, HELP_CONTEXT); } // void InitScriptEditor(bool level_script=true); /* void InitScriptEditor(bool level_script) { int size; bool locked=true; CScriptEditorDlg editor; ASSERT(Current_level_script); // Check to see if we even have default script locked if ((!level_script) && ((mng_FindTrackLock ("Default.scr",PAGETYPE_GAMEFILE))==-1)) { OutrageMessageBox ("Warning: You are trying to edit the Default script,but it's not locked. If you want to save your work, lock first."); locked=false; } if(strlen(Default_external_editor)==0) { char buffer[256]; CString default_path; size=GetWindowsDirectory(buffer,256); ASSERT(size<256); buffer[size]='\\'; buffer[size+1]='\0'; default_path=buffer; default_path+="Notepad.exe"; editor.SetExternalEditor(default_path.GetBuffer(1)); } else { editor.SetExternalEditor(Default_external_editor); } if(level_script) { editor.SetScript(Current_level_script, Level_script_prog); } else { if(!LoadDefaultScript()) return; ASSERT(Default_script); editor.SetScript(Default_script, Default_script_prog); } if(editor.DoModal()==IDOK) { if(level_script) { if(Current_level_script) mem_free(Current_level_script); Current_level_script = (char *) mem_malloc(lstrlen(editor.GetScript())+1); if(Current_level_script) strcpy(Current_level_script,editor.GetScript()); else OutrageMessageBox("Couldn't allocate memory to save script!"); } else { if(!locked) { OutrageMessageBox("Default script wasn't locked...not saving\n"); } else { if(Default_script) mem_free(Default_script); Default_script = (char *) mem_malloc(editor.GetScriptLength()); if(Default_script) strcpy(Default_script,editor.GetScript()); else OutrageMessageBox("Couldn't allocate memory to save script!"); OutrageMessageBox("Don't forget to check back in the default script\n"); } } //Try and compile now bool exit_ok=false; if (!CompileScript(editor.GetScript(), editor.m_Program)) { OutrageMessageBox("WARNING!!!: Your script did not compile correctly, please fix!"); if(editor.DoModal()==IDOK) exit_ok=true; } //Save the script if the selected Save and Exit if(exit_ok) { //one last try to compile if (!CompileScript(editor.GetScript(), editor.m_Program)) { OutrageMessageBox("WARNING!!!: Your script still did not compile correctly!"); } if(level_script) { if(Current_level_script) mem_free(Current_level_script); Current_level_script = (char *) mem_malloc(lstrlen(editor.GetScript())+1); if(Current_level_script) strcpy(Current_level_script,editor.GetScript()); else OutrageMessageBox("Couldn't allocate memory to save script!"); } else { if(!locked) { OutrageMessageBox("Default script wasn't locked...not saving\n"); } else { if(Default_script) free(Default_script); Default_script = (char *) mem_malloc(editor.GetScriptLength()); if(Default_script) strcpy(Default_script,editor.GetScript()); else OutrageMessageBox("Couldn't allocate memory to save script!"); OutrageMessageBox("Don't forget to check back in the default script\n"); } } } } if(strcmp(editor.m_ExternalEditor,Default_external_editor)) { strcpy(Default_external_editor,editor.m_ExternalEditor.GetBuffer(1)); } if(!level_script) SaveDefaultScript(true); } */ // Takes a TGA and extracts the hotspot map and ogf from it void CMainFrame::OnHotspotTga() { // TODO: Add your command handler code here CString tga_filter = "TGA (*.tga)|*.tga|All Files (*.*)|*.*||"; CString tga_path; char *buffer; int anim = 0, bm_handle; char filename[200]; CFileDialog dlg(true, 0, 0, OFN_FILEMUSTEXIST, (LPCTSTR)tga_filter, this); if (dlg.DoModal() == IDOK) { tga_path = dlg.GetPathName(); } else { return; } buffer = mem_rmalloc(strlen(tga_path.GetBuffer(1)) + 1); if (!buffer) { Int3(); // find Jeff return; } strcpy(buffer, tga_path.GetBuffer(1)); if (menutga_ConvertTGAtoHSM(buffer)) OutrageMessageBox("HotSpot Map Extracted"); bm_handle = LoadTextureImage(buffer, &anim, NOT_TEXTURE, 0); if (bm_handle < 0) { OutrageMessageBox("Couldn't open that bitmap/anim file."); return; } if (!anim) { sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(), GameBitmaps[bm_handle].name); bm_SaveFileBitmap(filename, bm_handle); bm_FreeBitmap(bm_handle); } if (buffer) mem_free(buffer); } void CMainFrame::OnEditorsFiles() { CFilePageDialog dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } void CMainFrame::OnUpdateEditAttach(CCmdUI *pCmdUI) { pCmdUI->Enable(Placed_group != NULL); } void CMainFrame::OnUpdateEditSaveScrap(CCmdUI *pCmdUI) { pCmdUI->Enable(Scrap != NULL); } void CMainFrame::OnFileLevelProps() { CLevelDialog dlg(this); dlg.DoModal(); } void CMainFrame::OnObjbutton() { if (m_ObjModeless) { RECT rect; m_ObjModeless->GetWindowRect(&rect); GetActiveFrame()->ScreenToClient(&rect); D3EditState.objmodeless_x = rect.left; D3EditState.objmodeless_y = rect.top; D3EditState.objmodeless_on = false; m_ObjModeless->DestroyWindow(); m_ObjModeless = NULL; } else { m_ObjModeless = new CObjectListModeless(this); m_ObjModeless->Create(); m_ObjModeless->SetWindowPos(this, D3EditState.objmodeless_x, D3EditState.objmodeless_y, -1, -1, SWP_NOSIZE); m_ObjModeless->ShowWindow(SW_SHOW); D3EditState.objmodeless_on = true; } } void CMainFrame::OnUpdateObjbutton(CCmdUI *pCmdUI) { if (m_ObjModeless && !D3EditState.objmodeless_on) { m_ObjModeless = NULL; } pCmdUI->SetCheck(D3EditState.objmodeless_on); } void CMainFrame::OnObjectSetCameraFromViewer() { object *objp = &Objects[Cur_object_index]; if (objp->type != OBJ_CAMERA) { OutrageMessageBox("The current object must be a camera for this operation."); return; } ObjSetPos(objp, &Viewer_object->pos, Viewer_object->roomnum, &Viewer_object->orient, false); EditorStatus("Camera object %d moved to viewer", Cur_object_index); World_changed = 1; } void CMainFrame::OnObjectPlaceCameraAtViewer() { int objnum; objnum = ObjCreate(OBJ_CAMERA, 0, Viewer_object->roomnum, &Viewer_object->pos, &Viewer_object->orient); if (objnum == -1) { Int3(); return; } EditorStatus("Camera created as object %d\n", objnum); World_changed = 1; } void CMainFrame::OnObjectPlaceCameraAtCurrentFace() { vector pos; matrix orient; int objnum; int roomnum; ComputeCenterPointOnFace(&pos, Curroomp, Curface); vm_VectorAngleToMatrix(&orient, &Curroomp->faces[Curface].normal, 0); if (Curroomp->flags & RF_EXTERNAL) { roomnum = GetTerrainRoomFromPos(&pos); } else { roomnum = ROOMNUM(Curroomp); } objnum = ObjCreate(OBJ_CAMERA, 0, roomnum, &pos, &orient); if (objnum == -1) { Int3(); return; } EditorStatus("Camera created as object %d\n", objnum); World_changed = 1; } void CMainFrame::OnObjectSetViewerFromCamera() { object *objp = &Objects[Cur_object_index]; if (objp->type != OBJ_CAMERA) { OutrageMessageBox("The current object must be a camera for this operation."); return; } MoveViewer(&objp->pos, objp->roomnum, &objp->orient); EditorStatus("Viewer moved to object %d", Cur_object_index); World_changed = 1; } #include "LevelInfoDialog.h" void CMainFrame::OnFileLevelInfo() { CLevelInfoDialog dlg(&Level_info); dlg.DoModal(); } void CMainFrame::OnFileStats() { ShowLevelStats(); } void CMainFrame::OnFileVerifyLevel() { VerifyMine(); } void CMainFrame::OnSubEditorsTableFileEdit() { // TODO: Add your command handler code here CTableFileEdit dlg; // theApp.pause(); dlg.DoModal(); // theApp.resume(); } void CMainFrame::OnEditorsAmbientSounds() { CAmbientSoundPattern dlg; theApp.pause(); dlg.DoModal(); theApp.resume(); } void CMainFrame::OnBriefingEditor() { CBriefEdit dlg; dlg.DoModal(); ddio_KeyFlush(); } void CMainFrame::OnScriptLevelInterface() { CScriptLevelInterface dlg; dlg.DoModal(); ddio_KeyFlush(); } void CMainFrame::OnFileFixCracks() { FixCracks(); } void CMainFrame::OnViewResetViewRadius() { ResetWireframeViewRad(); } void CMainFrame::OnSubeditorsTablefilefilter() { // TODO: Add your command handler code here TableFileFilter dlg; dlg.DoModal(); } void CMainFrame::OnViewShowObjectsInWireframeView() { D3EditState.objects_in_wireframe = !D3EditState.objects_in_wireframe; State_changed = 1; } void CMainFrame::OnUpdateViewShowObjectsInWireframeView(CCmdUI *pCmdUI) { pCmdUI->SetCheck((BOOL)D3EditState.objects_in_wireframe); } void CMainFrame::OnEditorsDallas() { if (theApp.m_DallasModelessDlgPtr == NULL) { theApp.m_DallasModelessDlgPtr = new CDallasMainDlg; theApp.m_DallasModelessDlgPtr->Create(IDD_DALLAS_MAIN_DIALOG, this); theApp.m_DallasModelessDlgPtr->ShowWindow(SW_SHOW); } else theApp.m_DallasModelessDlgPtr->ShowWindow(SW_RESTORE); } void CMainFrame::OnUpdateOsiriscompile(CCmdUI *pCmdUI) { // TODO: Add your command update UI handler code here } void CMainFrame::OnOsiriscompile() { CScriptMassCompile dlg; dlg.DoModal(); } // Copied here from HObject.cpp #define OBJECT_PLACE_DIST 10.0 bool MoveObject(object *obj, vector *newpos); void CMainFrame::OnViewMoveCameraToCurrentObject() { object *objp = &Objects[Cur_object_index]; vector pos; matrix orient; fvi_query fq; fvi_info hit_info; // Turn the viewer around so facing the object orient.fvec = -objp->orient.fvec; orient.rvec = -objp->orient.rvec; orient.uvec = objp->orient.uvec; // Move the viewer to the object MoveViewer(&objp->pos, objp->roomnum, &orient); // Calculate a position a little in front of the object pos = Viewer_object->pos - (Viewer_object->orient.fvec * OBJECT_PLACE_DIST); // Follow vector from start position to desired end position, & move as far as we can fq.p0 = &Viewer_object->pos; fq.startroom = Viewer_object->roomnum; fq.p1 = &pos; fq.thisobjnum = OBJNUM(Viewer_object); fq.ignore_obj_list = NULL; fq.flags = 0; fq.rad = 0.0; fvi_FindIntersection(&fq, &hit_info); // Move the viewer to the new position MoveViewer(&hit_info.hit_pnt, hit_info.hit_room, NULL); } void SelectObject(int objnum); void CMainFrame::OnObjectSelectByNumber() { int n; if (InputNumber(&n, "Select Object", "Enter object number to select", this)) { if ((n > Highest_object_index) || (Objects[n].type == OBJ_NONE)) { OutrageMessageBox("Invalid object number."); return; } SelectObject(n); } } #include "manage.h" #define MAX_LOCKLIST_ELEMENTS 1000 extern const char *PageNames[]; extern void dump_text_to_clipboard(char *text); void CMainFrame::OnShowAllCheckedOut() { char text_buf[10000], *t; // Get all locked pages mngs_Pagelock *LockList = mem_rmalloc(MAX_LOCKLIST_ELEMENTS); int n = mng_GetListOfLocks(LockList, MAX_LOCKLIST_ELEMENTS, NULL); // ASSERT(n >= 1); //always dummy page? // ASSERT(!strcmp(LockList[0].name,"DUMMY PAGE")); sprintf(text_buf, "Locked pages:\n"); t = text_buf + strlen(text_buf); for (int i = 0; i < n; i++) { sprintf(t, " Type %s, Page = <%s>, Locker = <%s>\n", PageNames[LockList[i].pagetype], LockList[i].name, LockList[i].holder); t += strlen(t); if ((t - text_buf) > (sizeof(text_buf) - 200)) { sprintf(t, "Out of buffer space\n"); break; } } mem_free(LockList); dump_text_to_clipboard(text_buf); OutrageMessageBox("%d pages are checked out.\n\nThe list has been written to the clipboard.", n); } void CMainFrame::OnViewShowViewerForwardVector() { EditorStatus("Viewer forward vector: %.3f, %.3f, %.3f", Viewer_object->orient.fvec.x + 0.0005, Viewer_object->orient.fvec.y + 0.0005, Viewer_object->orient.fvec.z + 0.0005); } void CMainFrame::OnObjectPlaceSoundSourceAtViewer() { int objnum; objnum = ObjCreate(OBJ_SOUNDSOURCE, 0, Viewer_object->roomnum, &Viewer_object->pos, &Viewer_object->orient); if (objnum == -1) { Int3(); return; } object *objp = &Objects[objnum]; objp->ctype.soundsource_info.sound_index = -1; objp->ctype.soundsource_info.volume = 1.0; EditorStatus("SoundSource created as object %d\n", objnum); World_changed = 1; } #include "OrphanRemoveDlg.h" void CMainFrame::OnOrphanhunter() { COrphanRemoveDlg dlg; dlg.DoModal(); } #include "player.h" void CMainFrame::OnObjectPlaceWaypointAtViewer() { int objnum; int count = 0; // Count the number of waypoints for (int i = 0; i <= Highest_object_index; i++) if (Objects[i].type == OBJ_WAYPOINT) count++; if (count >= MAX_WAYPOINTS) { EditorMessageBox("Cannot add waypoint: Already at maximum number of waypoints."); return; } // Check for waypoint already in this room if (OBJECT_OUTSIDE(Viewer_object)) objnum = Terrain_seg[CELLNUM(Viewer_object->roomnum)].objects; else objnum = Rooms[Viewer_object->roomnum].objects; for (objnum = Rooms[Viewer_object->roomnum].objects; objnum != -1; objnum = Objects[objnum].next) { if (Objects[objnum].type == OBJ_WAYPOINT) { EditorMessageBox("Cannot add waypoint: There's alerady a waypoint in this room (object %d)", objnum); return; } } objnum = ObjCreate(OBJ_WAYPOINT, 0, Viewer_object->roomnum, &Viewer_object->pos, &Viewer_object->orient); if (objnum == -1) { Int3(); return; } EditorStatus("Waypoint created as object %d\n", objnum); World_changed = 1; } #include "levelgoal.h" // Writes the level goal text to a file for localization void DumpLevelGoals(char *outname, char *levelname) { int n_goals = Level_goals.GetNumGoals(); char buf[1000]; CFILE *ofile; ofile = cfopen(outname, "wt"); if (!ofile) return; cfprintf(ofile, "!/!Level strings for %s\n\n", levelname); cfprintf(ofile, "!/!Notes on Localizing This File\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/!Line Tokens:\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! Each non-blank line begins with one of the following tokens that\n"); cfprintf(ofile, "!/! identifies it as either a comment or a string in a particular\n"); cfprintf(ofile, "!/! language:\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! !/! = comment (optional)\n"); cfprintf(ofile, "!/! !=! = English version of string\n"); cfprintf(ofile, "!/! !G! = German version of string\n"); cfprintf(ofile, "!/! !S! = Spanish version of string\n"); cfprintf(ofile, "!/! !I! = Italian version of string\n"); cfprintf(ofile, "!/! !F! = French version of string\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/!Rules:\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! 1. There must be an English version of each string.\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! 2. All text when translated should stay very near the\n"); cfprintf(ofile, "!/! length of the English version, unless otherwise noted.\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! 3. The maximum length of any line is 1024 characters.\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! 4. All %%s,%%d,%%f and similar tokens MUST stay in the string.\n"); cfprintf(ofile, "!/! In the game, these tokens will be replaced by:\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! %%s = another string\n"); cfprintf(ofile, "!/! %%d = an integer number\n"); cfprintf(ofile, "!/! %%f = a floating point number (a number with a decimal point)\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! These tokens MUST stay in the same relative order (i.e. in the\n"); cfprintf(ofile, "!/! string \"%%s got %%d points\" the %%s must always come before the %%d).\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/!Special Characters:\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! Special characters can be inserted in strings with the following tokens:\n"); cfprintf(ofile, "!/!\n"); cfprintf(ofile, "!/! \\t = tab\n"); cfprintf(ofile, "!/! \\n = newline\n"); cfprintf(ofile, "!/! \\0 - \\255 = specific ASCII character\n"); cfprintf(ofile, "\n\n"); for (int i = 0; i < n_goals; i++) { Level_goals.GoalGetName(i, buf, sizeof(buf)); ASSERT(strlen(buf) < 1024); // localization code can only handle 1024 chars in a string cfprintf(ofile, "!/!Goal %d Name\n", i); cfprintf(ofile, "!=!%s\n\n", buf); Level_goals.GoalGetItemName(i, buf, sizeof(buf)); ASSERT(strlen(buf) < 1024); // localization code can only handle 1024 chars in a string cfprintf(ofile, "!/!Goal %d Item Name\n", i); cfprintf(ofile, "!=!%s\n\n", buf); Level_goals.GoalGetDesc(i, buf, sizeof(buf)); ASSERT(strlen(buf) < 1024); // localization code can only handle 1024 chars in a string cfprintf(ofile, "!/!Goal %d Description\n", i); cfprintf(ofile, "!=!%s\n\n", buf); // Level_goals.GoalGetCompletionMessage(i,buf,sizeof(buf)); // cfprintf(ofile,"!/!Goal %d Completion Message\n",i); // cfprintf(ofile,"!=!%s\n\n",buf); } cfclose(ofile); } void CMainFrame::OnFileSaveGoalText() { CString path = theApp.main_doc->GetPathName(); char pathname[_MAX_FNAME], filename[_MAX_FNAME], ext[_MAX_FNAME]; ddio_SplitPath(path.GetBuffer(0), pathname, filename, ext); strcat(pathname, filename); strcat(pathname, ".str"); strcat(filename, ext); CFileDialog dlg_open(FALSE, (LPCTSTR) ".str", pathname, 0, NULL, this); if (dlg_open.DoModal() == IDCANCEL) return; DumpLevelGoals(dlg_open.GetPathName().GetBuffer(0), filename); } void CMainFrame::OnViewViewprop() { if (theApp.m_ViewerPropDlgPtr == NULL) { theApp.m_ViewerPropDlgPtr = new CViewerPropDlg; theApp.m_ViewerPropDlgPtr->Create(IDD_VIEWER_DIALOG, this); theApp.m_ViewerPropDlgPtr->ShowWindow(SW_SHOW); } else { theApp.m_ViewerPropDlgPtr->DestroyWindow(); } } void CMainFrame::OnUpdateViewViewprop(CCmdUI *pCmdUI) { if (theApp.m_ViewerPropDlgPtr == NULL) { pCmdUI->SetCheck(0); } else { pCmdUI->SetCheck(1); } } void CMainFrame::OnViewMoveCameraToSelectedFace() { SetViewerFromRoomFace(Curroomp, Curface, 0); } void CMainFrame::OnAccelCopyLightMultiple() { extern void CopyFaceLightMultiple(room * rp, int facenum); CopyFaceLightMultiple(Curroomp, Curface); } void CMainFrame::OnAccelSlidedown() { HTextureSlide(Curroomp, Curface, 0.0f, (float)-1.0 * D3EditState.texscale); } void CMainFrame::OnAccelSlideleft() { HTextureSlide(Curroomp, Curface, (float)-1.0 * D3EditState.texscale, 0.0f); } void CMainFrame::OnAccelSlideright() { HTextureSlide(Curroomp, Curface, (float)1.0 * D3EditState.texscale, 0.0f); } void CMainFrame::OnAccelSlideup() { HTextureSlide(Curroomp, Curface, 0.0f, (float)1.0 * D3EditState.texscale); } void CMainFrame::OnAccelNextVertex() { if (++Curvert >= Curroomp->faces[Curface].num_verts) Curvert = 0; EditorStatus("Vertex %d (%d) selected.", Curvert, Curroomp->faces[Curface].face_verts[Curvert]); State_changed = 1; }