private void ReallyDeleteLevel(int levelIndex) { // Remove the level from the campaign var levelPath = m_campaign.Levels[levelIndex]; var newCampaign = m_campaign.Copy(); newCampaign.Levels.RemoveAll((s) => (s == levelPath)); // Save the campaign var assetsPath = (m_mod != null) ? Path.Combine(m_mod.Path, "assets") : Path.Combine(App.AssetPath, "main"); var fullCampaignPath = Path.Combine(assetsPath, m_campaign.Path); newCampaign.Save(fullCampaignPath); // Delete the Level var fullLevelPath = Path.Combine(assetsPath, levelPath); if (File.Exists(fullLevelPath)) { File.Delete(fullLevelPath); } // Delete the Thumbnail var thumbnailPath = AssetPath.ChangeExtension(levelPath, "png"); var fullThumbnailPath = Path.Combine(assetsPath, thumbnailPath); if (File.Exists(fullThumbnailPath)) { File.Delete(fullThumbnailPath); } // Reopen the level select screen Assets.Reload(m_campaign.Path); CutToState(new LevelSelectState(Game, m_mod, m_campaign, m_page, -1, m_editor)); }
private void EditScript() { // Assign a script to the level if there isn't one if (Level.Info.ScriptPath == null) { var levelPath = LevelSavePath; var scriptPath = AssetPath.ChangeExtension(levelPath, "lua"); if (scriptPath.IndexOf("levels/") == 0) { scriptPath = "scripts/" + scriptPath.Substring("levels/".Length); } Level.Info.ScriptPath = scriptPath; m_modified = true; SetStatus(Game.Language.Translate("menus.editor.script_changed", scriptPath)); } // Create the script if it doesn't exist var fullScriptPath = (m_mod != null) ? Path.Combine(m_mod.Path, "assets/" + Level.Info.ScriptPath) : Path.Combine(App.AssetPath, "main/" + Level.Info.ScriptPath); if (!File.Exists(fullScriptPath)) { Directory.CreateDirectory(Path.GetDirectoryName(fullScriptPath)); File.Copy( Path.Combine(App.AssetPath, "base/scripts/template.lua"), fullScriptPath ); Assets.Reload(Level.Info.ScriptPath); } // Edit the script Game.Network.OpenTextEditor(fullScriptPath); }
private void DeleteCampaign(Campaign campaign, Mod mod) { var dialog = DialogBox.CreateQueryBox( Game.Screen, Game.Language.Translate("menus.delete_mod_prompt.title"), Game.Language.Translate("menus.delete_mod_prompt.info", campaign.Title), new string[] { Game.Language.Translate("menus.yes"), Game.Language.Translate("menus.no"), }, true ); dialog.OnClosed += delegate(object sender2, DialogBoxClosedEventArgs e) { switch (e.Result) { case 0: { // YES // Delete the campaign var assetPath = campaign.Path; var fullPath = Path.Combine(mod.Path, "assets/" + assetPath); File.Delete(fullPath); // Delete the levels and their thumbnails for (int i = 0; i < campaign.Levels.Count; ++i) { var levelPath = campaign.Levels[i]; var fullLevelPath = Path.Combine(mod.Path, "assets/" + levelPath); if (File.Exists(fullLevelPath)) { File.Delete(fullLevelPath); } var thumbnailPath = AssetPath.ChangeExtension(levelPath, "png"); var fullThumbnailPath = AssetPath.Combine(mod.Path, "assets/" + thumbnailPath); if (File.Exists(fullThumbnailPath)) { File.Delete(fullThumbnailPath); } } // Unload the campaign Assets.Reload(assetPath); var sources = Assets.GetSources(assetPath); if (sources.Count == 0 || (sources.Count == 1 && sources.First() == m_mod.Assets)) { Assets.Unload(assetPath); } m_campaigns.Refresh(); break; } } }; ShowDialog(dialog); }
public LevelThumbnail(string levelPath, float width, float height, Language language) : base(Core.Render.Texture.White, width, height) { m_levelPath = levelPath; if (m_levelPath == "NEW") { m_levelTitle = language.Translate("menus.mod_select.create_new"); } else if (Assets.Exists <LevelData>(levelPath)) { m_levelTitle = Assets.Get <LevelData>(levelPath).Title; } else { m_levelTitle = "Untitled"; } if (m_levelPath == "NEW") { m_texture = Core.Render.Texture.Get("gui/newlevel.png", false); } else { var thumbnailPath = AssetPath.ChangeExtension(levelPath, "png"); if (Assets.Exists <Texture>(thumbnailPath)) { m_texture = Core.Render.Texture.Get(thumbnailPath, true); } else { m_texture = Core.Render.Texture.Get("levels/template.png", true); } } m_geometry = new Geometry(Primitive.Triangles, 4, 6); m_deleteGeometry = new Geometry(Primitive.Triangles, 4, 6); m_moveGeometry = new Geometry(Primitive.Triangles, 8, 12); m_iconGeometry = new Geometry(Primitive.Triangles, 4, 6); m_highlight = false; m_locked = false; m_completed = false; m_canDelete = false; m_justUnlocked = false; m_justCompleted = false; m_animTime = 0.0f; Colour = BORDER_COLOUR; }
public DiskSelector(Screen screen, string initialDiskPath, Mod initialDiskMod, Progress progress) { m_geometry = new Geometry(Primitive.Triangles); m_disks = ArcadeUtils.GetAllDisks().ToArray(); m_disksUnlocked = m_disks.Select(disk => ArcadeUtils.IsDiskUnlocked(disk.Disk, disk.Mod, progress)).ToArray(); m_page = 0; if (m_disks.Length <= COLUMNS_PER_PAGE) { m_numColumns = m_disks.Length; m_numRows = 1; } else if (m_disks.Length < NUM_PER_PAGE) { m_numColumns = (m_disks.Length + ROWS_PER_PAGE - 1) / ROWS_PER_PAGE; m_numRows = ROWS_PER_PAGE; } else { m_numColumns = COLUMNS_PER_PAGE; m_numRows = ROWS_PER_PAGE; } m_highlight = -1; m_backPrompt = new InputPrompt(UIFonts.Smaller, screen.Language.Translate("menus.close"), TextAlignment.Right); m_backPrompt.Key = Key.Escape; m_backPrompt.MouseButton = MouseButton.Left; m_backPrompt.GamepadButton = GamepadButton.B; m_backPrompt.SteamControllerButton = SteamControllerButton.MenuBack; m_backPrompt.Anchor = Anchor.BottomRight; m_backPrompt.LocalPosition = new Vector2(-16.0f, -16.0f - m_backPrompt.Height); m_backPrompt.Parent = this; m_backPrompt.OnClick += delegate(object o, EventArgs args) { m_closeNextFrame = true; }; m_selectPrompt = new InputPrompt(UIFonts.Smaller, screen.Language.Translate("menus.select"), TextAlignment.Left); m_selectPrompt.Key = Key.Return; m_selectPrompt.GamepadButton = GamepadButton.A; m_selectPrompt.SteamControllerButton = SteamControllerButton.MenuSelect; m_selectPrompt.Anchor = Anchor.BottomLeft; m_selectPrompt.LocalPosition = new Vector2(16.0f, -16.0f - m_selectPrompt.Height); m_selectPrompt.Parent = this; m_browseWorkshopPrompt = new InputPrompt(UIFonts.Smaller, screen.Language.Translate("menus.arcade.browse_workshop"), TextAlignment.Right); m_browseWorkshopPrompt.Key = Key.LeftCtrl; m_browseWorkshopPrompt.GamepadButton = GamepadButton.Y; m_browseWorkshopPrompt.SteamControllerButton = SteamControllerButton.MenuAltSelect; m_browseWorkshopPrompt.Anchor = Anchor.BottomRight; m_browseWorkshopPrompt.LocalPosition = new Vector2(-16.0f, -16.0f - m_selectPrompt.Height - m_browseWorkshopPrompt.Height); m_browseWorkshopPrompt.Parent = this; m_previousPageButton = new Button(Texture.Get("gui/arrows.png", true), 32.0f, 32.0f); m_previousPageButton.Region = new Quad(0.0f, 0.5f, 0.5f, 0.5f); m_previousPageButton.HighlightRegion = m_previousPageButton.Region; m_previousPageButton.DisabledRegion = m_previousPageButton.Region; m_previousPageButton.ShortcutButton = GamepadButton.LeftBumper; m_previousPageButton.AltShortcutButton = GamepadButton.LeftTrigger; m_previousPageButton.ShortcutSteamControllerButton = SteamControllerButton.MenuPreviousPage; m_previousPageButton.Colour = UIColours.Title; m_previousPageButton.HighlightColour = UIColours.White; m_previousPageButton.DisabledColour = m_previousPageButton.Colour; m_previousPageButton.Anchor = Anchor.CentreMiddle; m_previousPageButton.LocalPosition = new Vector2( -0.5f * (float)COLUMNS_PER_PAGE * (DISK_SIZE + DISK_PADDING) - m_previousPageButton.Width, -0.5f * m_previousPageButton.Height ); m_previousPageButton.Parent = this; m_previousPageButton.OnClicked += delegate(object o, EventArgs e) { PreviousPage(); }; m_nextPageButton = new Button(Texture.Get("gui/arrows.png", true), 32.0f, 32.0f); m_nextPageButton.Region = new Quad(0.0f, 0.0f, 0.5f, 0.5f); m_nextPageButton.HighlightRegion = m_nextPageButton.Region; m_nextPageButton.DisabledRegion = m_nextPageButton.Region; m_nextPageButton.ShortcutButton = GamepadButton.RightBumper; m_nextPageButton.AltShortcutButton = GamepadButton.RightTrigger; m_nextPageButton.ShortcutSteamControllerButton = SteamControllerButton.MenuNextPage; m_nextPageButton.Colour = UIColours.Title; m_nextPageButton.HighlightColour = UIColours.White; m_nextPageButton.DisabledColour = m_nextPageButton.Colour; m_nextPageButton.Anchor = Anchor.CentreMiddle; m_nextPageButton.LocalPosition = new Vector2( 0.5f * (float)COLUMNS_PER_PAGE * (DISK_SIZE + DISK_PADDING), -0.5f * m_previousPageButton.Height ); m_nextPageButton.Parent = this; m_nextPageButton.OnClicked += delegate(object o, EventArgs e) { NextPage(); }; // Load labels m_diskLabels = new Texture[m_disks.Length]; for (int i = 0; i < m_disks.Length; ++i) { var disk = m_disks[i]; var labelPath = AssetPath.ChangeExtension(disk.Disk.Path, "png"); if (disk.Mod != null) { if (disk.Mod.Assets.CanLoad(labelPath)) { m_diskLabels[i] = disk.Mod.Assets.Load <Texture>(labelPath); m_diskLabels[i].Filter = false; } } else { m_diskLabels[i] = Texture.Get(labelPath, false); } } m_framesOpen = 0; m_closeNextFrame = false; // Determine initial disk index m_initialDisk = -1; if (initialDiskPath != null && m_disks.Length > 0) { for (int i = 0; i < m_disks.Length; ++i) { var disk = m_disks[i]; if (disk.Disk.Path == initialDiskPath && disk.Mod == initialDiskMod && m_disksUnlocked[i]) { m_initialDisk = i; break; } } } }
private void ReallyPublishMod() { // Update game_version m_mod.MinimumGameVersion = App.Info.Version; m_mod.SaveInfo(); // Check every level has a thumbnail and has been completed foreach (var campaign in Assets.Find <Campaign>("campaigns", m_mod.Assets)) { for (int i = 0; i < campaign.Levels.Count; ++i) { var levelPath = campaign.Levels[i]; var levelData = LevelData.Get(levelPath); if (!levelData.EverCompleted) { ShowDialog(DialogBox.CreateQueryBox( Game.Screen, Game.Language.Translate("menus.publishing_error.title"), Game.Language.Translate("menus.publishing_error.level_not_completed", TranslateTitle(levelData.Title)), new string[] { Game.Language.Translate("menus.ok") }, true) ); return; } var levelThumbnailPath = AssetPath.ChangeExtension(levelPath, "png"); var levelThumbnailFullPath = Path.Combine(m_mod.Path, "assets/" + levelThumbnailPath); if (!File.Exists(levelThumbnailFullPath)) { ShowDialog(DialogBox.CreateQueryBox( Game.Screen, Game.Language.Translate("menus.publishing_error.title"), Game.Language.Translate("menus.publishing_error.level_no_thumbnail", TranslateTitle(levelData.Title)), new string[] { Game.Language.Translate("menus.ok") }, true) ); return; } } } // Find source images for the thumbnail var thumbnailSources = new List <string>(); var manualThumbnailPath = Path.Combine(m_mod.Path, "thumbnail.png"); if (File.Exists(manualThumbnailPath)) { // Use thumbnail.png thumbnailSources.Add(manualThumbnailPath); } else { // Use the thumbnails from the levels var campaigns = Assets.List <Campaign>("campaigns", m_mod.Assets).ToArray(); for (int i = 0; i < campaigns.Length; ++i) { var campaign = campaigns[i]; for (int j = 0; j < campaign.Levels.Count; ++j) { var levelPath = campaign.Levels[j]; var levelThumbnailPath = AssetPath.ChangeExtension(levelPath, "png"); var levelThumbnailFullPath = Path.Combine(m_mod.Path, "assets/" + levelThumbnailPath); if (File.Exists(levelThumbnailFullPath)) { thumbnailSources.Add(levelThumbnailFullPath); } } } } if (thumbnailSources.Count == 0) { ShowDialog(DialogBox.CreateQueryBox( Game.Screen, Game.Language.Translate("menus.publishing_error.title"), Game.Language.Translate("menus.publishing_error.no_thumbnail"), new string[] { Game.Language.Translate("menus.ok") }, true) ); return; } // Generate the thumbnail var thumbnailPath = GenerateThumbnail(thumbnailSources); // Determine the tags var tags = new HashSet <string>(); if (Assets.Find <LuaScript>("animation", m_mod.Assets).Count() > 0) { tags.Add("Custom Animation"); } if (Assets.List <Campaign>("campaigns", m_mod.Assets).Count() > 0 && Assets.Find <LevelData>("levels", m_mod.Assets).Count() > 0) { tags.Add("New Levels"); } if (Assets.List <Language>("languages", m_mod.Assets).Where(lang => !lang.IsEnglish).Count() > 0) { tags.Add("Localisation"); } if (Assets.Find <Model>("models", m_mod.Assets).Count() > 0 || Assets.Find <Sky>("skies", m_mod.Assets).Count() > 0) { tags.Add("Custom Art"); } if (Assets.Find <Sound>("sound", m_mod.Assets).Count() > 0 || Assets.Find <Sound>("music", m_mod.Assets).Count() > 0) { tags.Add("Custom Audio"); } if (Assets.List <ArcadeDisk>("arcade", m_mod.Assets).Count() > 0) { tags.Add("Arcade Games"); } // Publish if (m_mod.SteamWorkshopID.HasValue) { // Update existing mod ulong id = m_mod.SteamWorkshopID.Value; var promise = Game.Network.Workshop.UpdateItem( id, "Modified with the Redirection Mod Editor", filePath: m_mod.Path, previewImagePath: thumbnailPath, title: m_mod.Title, tags: tags.ToArray() ); var progressDialog = PromiseDialogBox.Create( Game.Language.Translate("menus.publishing.title"), promise ); progressDialog.OnClosed += delegate(object sender2, DialogBoxClosedEventArgs e2) { if (promise.Status == Status.Complete) { // Show the user the mod ShowInWorkshop(); // Show a dialog var completeDialog = DialogBox.CreateQueryBox( Game.Screen, Game.Language.Translate("menus.mod_published.title"), promise.Result.AgreementNeeded ? Game.Language.Translate("menus.mod_published.info_agreement_needed", m_mod.Title) : Game.Language.Translate("menus.mod_published.info", m_mod.Title), new string[] { Game.Language.Translate("menus.ok") }, true ); ShowDialog(completeDialog); } else if (promise.Status == Status.Error) { // Show the user the error var errorDialog = DialogBox.CreateQueryBox( Game.Screen, Game.Language.Translate("menus.publishing_error.title"), promise.Error, new string[] { Game.Language.Translate("menus.ok") }, true ); ShowDialog(errorDialog); } }; ShowDialog(progressDialog); } else { // Create new mod var description = "Created with the Redirection Mod Editor"; var promise = Game.Network.Workshop.CreateItem( m_mod.Path, thumbnailPath, m_mod.Title, description, tags.ToArray(), true ); var progressDialog = PromiseDialogBox.Create( Game.Language.Translate("menus.publishing.title"), promise ); progressDialog.OnClosed += delegate(object sender2, DialogBoxClosedEventArgs e2) { if (promise.Status == Status.Complete) { // Save the mod ulong id = promise.Result.ID; m_mod.SteamWorkshopID = id; m_mod.SaveInfo(); // Show the user the mod ShowInWorkshop(); // Show a dialog var completeDialog = DialogBox.CreateQueryBox( Game.Screen, Game.Language.Translate("menus.mod_published.title"), promise.Result.AgreementNeeded ? Game.Language.Translate("menus.mod_published.info_agreement_needed", m_mod.Title) : Game.Language.Translate("menus.mod_published.info", m_mod.Title), new string[] { Game.Language.Translate("menus.ok") }, true ); completeDialog.OnClosed += delegate { // Re-enter state so the new "show in workshop" entry appears CutToState(new ModEditorState(Game, m_mod)); }; ShowDialog(completeDialog); } else if (promise.Status == Status.Error) { // Show the user the error var errorDialog = DialogBox.CreateQueryBox( Game.Screen, Game.Language.Translate("menus.publishing_error.title"), promise.Error, new string[] { Game.Language.Translate("menus.ok") }, true ); ShowDialog(errorDialog); } }; ShowDialog(progressDialog); } }
protected override void OnUpdate(float dt) { base.OnUpdate(dt); switch (m_state) { case SubState.Waiting: { // Wait for camera press if (CheckCameraButton()) { m_state = SubState.Capturing; m_timer = 0.0f; } else if (CheckBack()) { BackToEditor(); } break; } case SubState.Capturing: { // Take the screenshot // Stop the action CameraController.AllowUserZoom = false; CameraController.AllowUserRotate = false; // Clear the screen m_cameraHUD.ShowViewfinder = false; m_prompt.Visible = false; // Request the screenshot m_screenshot = Game.QueueScreenshot(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT); m_state = SubState.CameraFlash; break; } case SubState.CameraFlash: { // Wait for screenshot, then flash if (m_screenshot.Status != Status.Waiting) { // Do the effects Game.Audio.PlayMusic(null, 0.0f); m_cameraHUD.Flash(); m_state = SubState.Approving; m_timer = FLASH_DURATION; } break; } case SubState.Approving: { // Wait for a timer, then prompt to save the screenshot if (m_timer > 0.0f) { m_timer -= dt; if (m_timer <= 0.0f) { // Create the texture var screenshot = m_screenshot.Result; var bitmap = new BitmapTexture(screenshot.Bitmap); bitmap.Filter = true; // Show the dialog var dialog = DialogBox.CreateImageQueryBox( Game.Language.Translate("menus.create_thumbnail.confirm_prompt"), bitmap, 427.0f, 240.0f, new string[] { Game.Language.Translate("menus.yes"), Game.Language.Translate("menus.no"), } ); dialog.OnClosed += delegate(object sender, DialogBoxClosedEventArgs e) { // Handle the result if (e.Result == 0) { // Yes // Save the screenshot var screenshotPath = AssetPath.ChangeExtension(m_levelSavePath, "png"); if (m_mod != null) { var fullPath = Path.Combine(m_mod.Path, "assets/" + screenshotPath); screenshot.Save(fullPath); } else { var fullPath = Path.Combine(App.AssetPath, "main/" + screenshotPath); screenshot.Save(fullPath); } Assets.Reload(screenshotPath); // Save the camera position Level.Info.CameraPitch = MathHelper.RadiansToDegrees(CameraController.Pitch); Level.Info.CameraYaw = MathHelper.RadiansToDegrees(CameraController.Yaw); Level.Info.CameraDistance = CameraController.Distance; m_modified = true; // Return BackToEditor(); } else if (e.Result == 1) { // No TryAgain(); } else { // Escape BackToEditor(); } // Dispose things we no longer need bitmap.Dispose(); screenshot.Dispose(); }; ShowDialog(dialog); } } break; } } }
private void Load(IFileStore store) { // Load the material infos var dir = AssetPath.GetDirectoryName(m_path); Material currentMaterial = null; using (var reader = store.OpenTextFile(m_path)) { // For each line: string line; var whitespace = new char[] { ' ', '\t' }; while ((line = reader.ReadLine()) != null) { // Strip comment var commentIdx = line.IndexOf('#'); if (commentIdx >= 0) { line = line.Substring(0, commentIdx); } // Segment var parts = line.Split(whitespace, StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) { continue; } // Parse var type = parts[0].ToLowerInvariant(); switch (type) { case "newmtl": { var name = parts[1]; currentMaterial = new Material(); m_materials.Add(name, currentMaterial); break; } case "map_ka": { var path = AssetPath.Combine(dir, parts[1]); currentMaterial.EmissiveColour = Vector3.One; currentMaterial.EmissiveTexture = path; break; } case "map_kd": { var path = AssetPath.Combine(dir, parts[1]); currentMaterial.DiffuseColour = Vector4.One; currentMaterial.DiffuseTexture = path; break; } case "map_ks": { var path = AssetPath.Combine(dir, parts[1]); currentMaterial.SpecularColour = Vector3.One; currentMaterial.SpecularTexture = path; break; } case "map_bump": case "bump": { var path = AssetPath.Combine(dir, parts[1]); currentMaterial.NormalTexture = path; break; } } } } // Add missing material paths foreach (var material in m_materials.Values) { if (material.EmissiveTexture == null) { material.EmissiveColour = Vector3.One; material.EmissiveTexture = "black.png"; if (material.DiffuseTexture != null) { var potentialPath = AssetPath.ChangeExtension(material.DiffuseTexture, "emit.png"); if (store.FileExists(potentialPath)) { material.EmissiveTexture = potentialPath; } } } if (material.SpecularTexture == null) { material.SpecularColour = Vector3.One; material.SpecularTexture = "black.png"; if (material.DiffuseTexture != null) { var potentialPath = AssetPath.ChangeExtension(material.DiffuseTexture, "spec.png"); if (store.FileExists(potentialPath)) { material.SpecularTexture = potentialPath; } } } if (material.NormalTexture == null) { material.NormalTexture = "flat.png"; if (material.DiffuseTexture != null) { var potentialPath = AssetPath.ChangeExtension(material.DiffuseTexture, "norm.png"); if (store.FileExists(potentialPath)) { material.NormalTexture = potentialPath; } } } if (material.DiffuseTexture == null) { material.DiffuseColour = Vector4.One; material.DiffuseTexture = "white.png"; } } }