/* MapEditorWindow::loadMapScripts * Loads any scripts from [map] into the script editor *******************************************************************/ void MapEditorWindow::loadMapScripts(Archive::mapdesc_t map) { // Don't bother if no scripting language specified if (theGameConfiguration->scriptLanguage().IsEmpty()) { // Hide script editor wxAuiManager* m_mgr = wxAuiManager::GetManager(this); wxAuiPaneInfo& p_inf = m_mgr->GetPane("script_editor"); p_inf.Show(false); m_mgr->Update(); return; } // Don't bother if new map if (!map.head) { panel_script_editor->openScripts(NULL, NULL); return; } // Check for pk3 map if (map.archive) { WadArchive* wad = new WadArchive(); wad->open(map.head->getMCData()); vector<Archive::mapdesc_t> maps = wad->detectMaps(); if (!maps.empty()) { loadMapScripts(maps[0]); wad->close(); delete wad; return; } } // Go through map entries ArchiveEntry* entry = map.head->nextEntry(); ArchiveEntry* scripts = NULL; ArchiveEntry* compiled = NULL; while (entry && entry != map.end->nextEntry()) { // Check for SCRIPTS/BEHAVIOR if (theGameConfiguration->scriptLanguage() == "acs_hexen" || theGameConfiguration->scriptLanguage() == "acs_zdoom") { if (S_CMPNOCASE(entry->getName(), "SCRIPTS")) scripts = entry; if (S_CMPNOCASE(entry->getName(), "BEHAVIOR")) compiled = entry; } // Next entry entry = entry->nextEntry(); } // Open scripts/compiled if found panel_script_editor->openScripts(scripts, compiled); }
/* MapEditorWindow::saveMapAs * Saves the current map to a new archive *******************************************************************/ bool MapEditorWindow::saveMapAs() { // Show dialog SFileDialog::fd_info_t info; if (!SFileDialog::saveFile(info, "Save Map As", "Wad Archives (*.wad)|*.wad", this)) return false; // Create new, empty wad WadArchive wad; ArchiveEntry* head = wad.addNewEntry(mdesc_current.name); ArchiveEntry* end = NULL; if (mdesc_current.format == MAP_UDMF) { wad.addNewEntry("TEXTMAP"); end = wad.addNewEntry("ENDMAP"); } else { wad.addNewEntry("THINGS"); wad.addNewEntry("LINEDEFS"); wad.addNewEntry("SIDEDEFS"); wad.addNewEntry("VERTEXES"); end = wad.addNewEntry("SECTORS"); } // Save map data mdesc_current.head = head; mdesc_current.archive = false; mdesc_current.end = end; saveMap(); // Write wad to file wad.save(info.filenames[0]); Archive* archive = theArchiveManager->openArchive(info.filenames[0], true, true); theArchiveManager->addRecentFile(info.filenames[0]); // Update current map description vector<Archive::mapdesc_t> maps = archive->detectMaps(); if (!maps.empty()) { mdesc_current.head = maps[0].head; mdesc_current.archive = false; mdesc_current.end = maps[0].end; } // Set window title SetTitle(S_FMT("SLADE - %s of %s", mdesc_current.name, wad.getFilename(false))); return true; }
/* EntryOperations::openMapDB2 * Opens the map at [entry] with Doom Builder 2, including all open * resource archives. Sets up a FileMonitor to update the map in the * archive if any changes are made to it in DB2 *******************************************************************/ bool EntryOperations::openMapDB2(ArchiveEntry* entry) { #ifdef __WXMSW__ // Windows only string path = path_db2; if (path.IsEmpty()) { // Check for DB2 location registry key wxRegKey key(wxRegKey::HKLM, "SOFTWARE\\CodeImp\\Doom Builder"); key.QueryValue("Location", path); // Can't proceed if DB2 isn't installed if (path.IsEmpty()) { wxMessageBox("Doom Builder 2 must be installed to use this feature.", "Doom Builder 2 Not Found"); return false; } // Add default executable name path += "\\Builder.exe"; } // Get map info for entry Archive::mapdesc_t map = entry->getParent()->getMapInfo(entry); // Check valid map if (map.format == MAP_UNKNOWN) return false; // Export the map to a temp .wad file string filename = appPath(entry->getParent()->getFilename(false) + "-" + entry->getName(true) + ".wad", DIR_TEMP); filename.Replace("/", "-"); if (map.archive) { entry->exportFile(filename); entry->lock(); } else { // Write map entries to temporary wad archive if (map.head) { WadArchive archive; // Add map entries to archive ArchiveEntry* e = map.head; while (true) { archive.addEntry(e, "", true); e->lock(); if (e == map.end) break; e = e->nextEntry(); } // Write archive to file archive.save(filename); } } // Generate Doom Builder command line string cmd = S_FMT("%s \"%s\" -map %s", path, filename, entry->getName()); // Add base resource archive to command line Archive* base = theArchiveManager->baseResourceArchive(); if (base) { if (base->getType() == ARCHIVE_WAD) cmd += S_FMT(" -resource wad \"%s\"", base->getFilename()); else if (base->getType() == ARCHIVE_ZIP) cmd += S_FMT(" -resource pk3 \"%s\"", base->getFilename()); } // Add resource archives to command line for (int a = 0; a < theArchiveManager->numArchives(); ++a) { Archive* archive = theArchiveManager->getArchive(a); // Check archive type (only wad and zip supported by db2) if (archive->getType() == ARCHIVE_WAD) cmd += S_FMT(" -resource wad \"%s\"", archive->getFilename()); else if (archive->getType() == ARCHIVE_ZIP) cmd += S_FMT(" -resource pk3 \"%s\"", archive->getFilename()); } // Run DB2 FileMonitor* fm = new DB2MapFileMonitor(filename, entry->getParent(), entry->getName(true)); wxExecute(cmd, wxEXEC_ASYNC, fm->getProcess()); return true; #else return false; #endif//__WXMSW__ }
/* MapEditorWindow::saveMap * Saves the current map to its archive, or opens the 'save as' * dialog if it doesn't currently belong to one *******************************************************************/ bool MapEditorWindow::saveMap() { // Check for newly created map if (!mdesc_current.head) return saveMapAs(); // Write map to temp wad WadArchive* wad = writeMap(); if (!wad) return false; // Check for map archive Archive* tempwad = NULL; Archive::mapdesc_t map = mdesc_current; if (mdesc_current.archive && mdesc_current.head) { tempwad = new WadArchive(); tempwad->open(mdesc_current.head); vector<Archive::mapdesc_t> amaps = tempwad->detectMaps(); if (amaps.size() > 0) map = amaps[0]; else return false; } // Unlock current map entries lockMapEntries(false); // Delete current map entries ArchiveEntry* entry = map.end; Archive* archive = map.head->getParent(); while (entry && entry != map.head) { ArchiveEntry* prev = entry->prevEntry(); archive->removeEntry(entry); entry = prev; } // Create backup if (!backup_manager->writeBackup(map_data, map.head->getTopParent()->getFilename(false), map.head->getName(true))) LOG_MESSAGE(1, "Warning: Failed to backup map data"); // Add new map entries for (unsigned a = 1; a < wad->numEntries(); a++) entry = archive->addEntry(wad->getEntry(a), archive->entryIndex(map.head) + a, NULL, true); // Clean up delete wad; if (tempwad) { tempwad->save(); delete tempwad; } else { // Update map description mdesc_current.end = entry; } // Finish lockMapEntries(); editor.getMap().setOpenedTime(); return true; }
/* MapEditorWindow::writeMap * Writes the current map as [name] to a wad archive and returns it *******************************************************************/ WadArchive* MapEditorWindow::writeMap(string name, bool nodes) { // Get map data entries vector<ArchiveEntry*> new_map_data; SLADEMap& map = editor.getMap(); if (mdesc_current.format == MAP_DOOM) map.writeDoomMap(new_map_data); else if (mdesc_current.format == MAP_HEXEN) map.writeHexenMap(new_map_data); else if (mdesc_current.format == MAP_UDMF) { ArchiveEntry* udmf = new ArchiveEntry("TEXTMAP"); map.writeUDMFMap(udmf); new_map_data.push_back(udmf); } else // TODO: doom64 return NULL; // Check script language bool acs = false; if (theGameConfiguration->scriptLanguage() == "acs_hexen" || theGameConfiguration->scriptLanguage() == "acs_zdoom") acs = true; // Force ACS on for Hexen map format, and off for Doom map format if (mdesc_current.format == MAP_DOOM) acs = false; if (mdesc_current.format == MAP_HEXEN) acs = true; bool dialogue = false; if (theGameConfiguration->scriptLanguage() == "usdf" || theGameConfiguration->scriptLanguage() == "zsdf") dialogue = true; // Add map data to temporary wad WadArchive* wad = new WadArchive(); wad->addNewEntry(name); // Handle fragglescript and similar content in the map header if (mdesc_current.head && mdesc_current.head->getSize() && !mdesc_current.archive) { wad->getEntry(name)->importMemChunk(mdesc_current.head->getMCData()); } for (unsigned a = 0; a < new_map_data.size(); a++) wad->addEntry(new_map_data[a]); if (acs) // BEHAVIOR wad->addEntry(panel_script_editor->compiledEntry(), "", true); if (acs && panel_script_editor->scriptEntry()->getSize() > 0) // SCRIPTS (if any) wad->addEntry(panel_script_editor->scriptEntry(), "", true); if (mdesc_current.format == MAP_UDMF) { // Add extra UDMF entries for (unsigned a = 0; a < map.udmfExtraEntries().size(); a++) wad->addEntry(map.udmfExtraEntries()[a], -1, NULL, true); wad->addNewEntry("ENDMAP"); } // Build nodes if (nodes) buildNodes(wad); // Clear current map data for (unsigned a = 0; a < map_data.size(); a++) delete map_data[a]; map_data.clear(); // Update map data for (unsigned a = 0; a < wad->numEntries(); a++) map_data.push_back(new ArchiveEntry(*(wad->getEntry(a)))); return wad; }
/* MapEditorWindow::openMap * Opens [map] in the editor *******************************************************************/ bool MapEditorWindow::openMap(Archive::mapdesc_t map) { // If a map is currently open and modified, prompt to save changes if (editor.getMap().isModified()) { wxMessageDialog md(this, S_FMT("Save changes to map %s?", currentMapDesc().name), "Unsaved Changes", wxYES_NO | wxCANCEL); int answer = md.ShowModal(); if (answer == wxID_YES) saveMap(); else if (answer == wxID_CANCEL) return true; } // Show blank map this->Show(true); map_canvas->Refresh(); Layout(); Update(); Refresh(); // Clear current map data for (unsigned a = 0; a < map_data.size(); a++) delete map_data[a]; map_data.clear(); // Get map parent archive Archive* archive = NULL; if (map.head) { archive = map.head->getParent(); // Load map data if (map.archive) { WadArchive temp; temp.open(map.head->getMCData()); for (unsigned a = 0; a < temp.numEntries(); a++) map_data.push_back(new ArchiveEntry(*(temp.getEntry(a)))); } else { ArchiveEntry* entry = map.head; while (entry) { bool end = (entry == map.end); map_data.push_back(new ArchiveEntry(*entry)); entry = entry->nextEntry(); if (end) break; } } } // Set texture manager archive tex_man.setArchive(archive); // Clear current map closeMap(); // Attempt to open map theSplashWindow->show("Loading Map", true, this); bool ok = editor.openMap(map); theSplashWindow->hide(); // Show window if opened ok if (ok) { mdesc_current = map; // Read DECORATE definitions if any theGameConfiguration->parseDecorateDefs(theArchiveManager->baseResourceArchive()); for (int i = 0; i < theArchiveManager->numArchives(); ++i) theGameConfiguration->parseDecorateDefs(theArchiveManager->getArchive(i)); // Load scripts if any loadMapScripts(map); // Lock map entries lockMapEntries(); // Reset map checks panel panel_checks->reset(); map_canvas->viewFitToMap(true); map_canvas->Refresh(); // Set window title if (archive) SetTitle(S_FMT("SLADE - %s of %s", map.name, archive->getFilename(false))); else SetTitle(S_FMT("SLADE - %s (UNSAVED)", map.name)); // Create backup if (map.head && !backup_manager->writeBackup(map_data, map.head->getTopParent()->getFilename(false), map.head->getName(true))) LOG_MESSAGE(1, "Warning: Failed to backup map data"); } return ok; }
/* MapEditorWindow::handleAction * Handles the action [id]. Returns true if the action was handled, * false otherwise *******************************************************************/ bool MapEditorWindow::handleAction(string id) { // Don't handle actions if hidden if (!IsShown()) return false; // Map->Save if (id == "mapw_save") { // Save map if (saveMap()) { // Save archive Archive* a = currentMapDesc().head->getParent(); if (a && save_archive_with_map) a->save(); } return true; } // Map->Save As if (id == "mapw_saveas") { saveMapAs(); return true; } // Map->Restore Backup if (id == "mapw_backup") { if (mdesc_current.head) { Archive* data = backup_manager->openBackup(mdesc_current.head->getTopParent()->getFilename(false), mdesc_current.name); if (data) { vector<Archive::mapdesc_t> maps = data->detectMaps(); if (!maps.empty()) { editor.getMap().clearMap(); editor.openMap(maps[0]); loadMapScripts(maps[0]); } } } return true; } // Edit->Undo if (id == "mapw_undo") { editor.doUndo(); return true; } // Edit->Redo if (id == "mapw_redo") { editor.doRedo(); return true; } // Editor->Set Base Resource Archive if (id == "mapw_setbra") { wxDialog dialog_ebr(this, -1, "Edit Base Resource Archives", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER); BaseResourceArchivesPanel brap(&dialog_ebr); wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(&brap, 1, wxEXPAND|wxALL, 4); sizer->Add(dialog_ebr.CreateButtonSizer(wxOK|wxCANCEL), 0, wxEXPAND|wxLEFT|wxRIGHT|wxDOWN, 4); dialog_ebr.SetSizer(sizer); dialog_ebr.Layout(); dialog_ebr.SetInitialSize(wxSize(500, 300)); dialog_ebr.CenterOnParent(); if (dialog_ebr.ShowModal() == wxID_OK) theArchiveManager->openBaseResource(brap.getSelectedPath()); return true; } // Editor->Preferences if (id == "mapw_preferences") { PreferencesDialog::openPreferences(this); return true; } // View->Item Properties if (id == "mapw_showproperties") { wxAuiManager* m_mgr = wxAuiManager::GetManager(this); wxAuiPaneInfo& p_inf = m_mgr->GetPane("item_props"); // Toggle window and focus p_inf.Show(!p_inf.IsShown()); map_canvas->SetFocus(); m_mgr->Update(); return true; } // View->Console else if (id == "mapw_showconsole") { wxAuiManager* m_mgr = wxAuiManager::GetManager(this); wxAuiPaneInfo& p_inf = m_mgr->GetPane("console"); // Toggle window and focus if (p_inf.IsShown()) { p_inf.Show(false); map_canvas->SetFocus(); } else { p_inf.Show(true); p_inf.window->SetFocus(); } p_inf.MinSize(200, 128); m_mgr->Update(); return true; } // View->Script Editor else if (id == "mapw_showscripteditor") { wxAuiManager* m_mgr = wxAuiManager::GetManager(this); wxAuiPaneInfo& p_inf = m_mgr->GetPane("script_editor"); // Toggle window and focus if (p_inf.IsShown()) { p_inf.Show(false); map_canvas->SetFocus(); } else if (!theGameConfiguration->scriptLanguage().IsEmpty()) { p_inf.Show(true); p_inf.window->SetFocus(); } p_inf.MinSize(200, 128); m_mgr->Update(); return true; } // View->Map Checks else if (id == "mapw_showchecks") { wxAuiManager* m_mgr = wxAuiManager::GetManager(this); wxAuiPaneInfo& p_inf = m_mgr->GetPane("map_checks"); // Toggle window and focus if (p_inf.IsShown()) { p_inf.Show(false); map_canvas->SetFocus(); } else { p_inf.Show(true); p_inf.window->SetFocus(); } //p_inf.MinSize(200, 128); m_mgr->Update(); return true; } // View->Undo History else if (id == "mapw_showundohistory") { wxAuiManager* m_mgr = wxAuiManager::GetManager(this); wxAuiPaneInfo& p_inf = m_mgr->GetPane("undo_history"); // Toggle window p_inf.Show(!p_inf.IsShown()); m_mgr->Update(); return true; } // Run Map else if (id == "mapw_run_map") { Archive* archive = NULL; if (mdesc_current.head) archive = mdesc_current.head->getParent(); RunDialog dlg(this, archive); if (dlg.ShowModal() == wxID_OK) { WadArchive* wad = writeMap(mdesc_current.name); if (wad) wad->save(appPath("sladetemp_run.wad", DIR_TEMP)); string command = dlg.getSelectedCommandLine(archive, mdesc_current.name, wad->getFilename()); if (!command.IsEmpty()) { // Set working directory string wd = wxGetCwd(); wxSetWorkingDirectory(dlg.getSelectedExeDir()); // Run wxExecute(command, wxEXEC_ASYNC); // Restore working directory wxSetWorkingDirectory(wd); } } return true; } return false; }