4 using Microsoft.Xna.Framework;
5 using Microsoft.Xna.Framework.Graphics;
7 using System.Collections.Generic;
10 using Microsoft.Xna.Framework.Input;
24 private GUIFrame leftPanel, rightPanel, bottomPanel, topPanel;
31 private GUIListBox paramsList, ruinParamsList, caveParamsList, outpostParamsList, levelObjectList;
38 private GUITickBox lightingEnabled, cursorLightEnabled, allowInvalidOutpost, mirrorLevel;
45 private Sprite editingSprite;
49 private readonly Color[] tunnelDebugColors =
new Color[] { Color.White, Color.Cyan, Color.LightGreen, Color.Red, Color.LightYellow, Color.LightSeaGreen };
51 private LevelData currentLevelData;
53 private void RefreshUI(
bool forceCreate =
false)
60 GUI.PreventPauseMenuToggle =
false;
61 pointerLightSource =
new LightSource(Vector2.Zero, 1000.0f, Color.White, submarine:
null);
62 GameMain.LightManager.AddLight(pointerLightSource);
68 UpdateRuinParamsList();
69 UpdateCaveParamsList();
70 UpdateOutpostParamsList();
71 UpdateLevelObjectsList();
74 private void CreateUI()
78 leftPanel =
new GUIFrame(
new RectTransform(
new Vector2(0.125f, 0.8f),
Frame.
RectTransform) { MinSize = new Point(150, 0) });
79 var paddedLeftPanel =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.9f, 0.95f), leftPanel.
RectTransform,
Anchor.CenterLeft) { RelativeOffset = new Vector2(0.02f, 0.0f) })
82 RelativeSpacing = 0.01f
85 paramsList =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.3f), paddedLeftPanel.RectTransform))
87 PlaySoundOnSelect =
true
89 paramsList.
OnSelected += (GUIComponent component,
object obj) =>
91 selectedParams = obj as LevelGenerationParams;
92 currentLevelData = LevelData.CreateRandom(seedBox.
Text, generationParams: selectedParams);
94 SortLevelObjectsList(currentLevelData);
95 new SerializableEntityEditor(editorContainer.
Content.
RectTransform, selectedParams, inGame:
false, showName:
true, elementHeight: 20, titleFont: GUIStyle.LargeFont);
96 forceDifficultyInput.
FloatValue = (selectedParams.MinLevelDifficulty + selectedParams.MaxLevelDifficulty) / 2f;
100 var ruinTitle =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), paddedLeftPanel.RectTransform), TextManager.Get(
"leveleditor.ruinparams"), font: GUIStyle.SubHeadingFont);
102 ruinParamsList =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.1f), paddedLeftPanel.RectTransform))
104 PlaySoundOnSelect =
true
106 ruinParamsList.
OnSelected += (GUIComponent component,
object obj) =>
108 if (selectedRuinGenerationParams == obj)
111 CoroutineManager.StartCoroutine(DeselectRuinParams());
113 IEnumerable<CoroutineStatus> DeselectRuinParams()
115 if (
Screen.Selected !=
this)
121 selectedRuinGenerationParams =
null;
122 CreateOutpostGenerationParamsEditor(
null);
129 CreateOutpostGenerationParamsEditor(selectedRuinGenerationParams);
135 var caveTitle =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), paddedLeftPanel.RectTransform), TextManager.Get(
"leveleditor.caveparams"), font: GUIStyle.SubHeadingFont);
137 caveParamsList =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.1f), paddedLeftPanel.RectTransform))
139 PlaySoundOnSelect =
true
141 caveParamsList.
OnSelected += (GUIComponent component,
object obj) =>
143 CreateCaveParamsEditor(obj as CaveGenerationParams);
147 var outpostTitle =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), paddedLeftPanel.RectTransform), TextManager.Get(
"leveleditor.outpostparams"), font: GUIStyle.SubHeadingFont);
148 GUITextBlock.AutoScaleAndNormalize(ruinTitle, caveTitle, outpostTitle);
150 outpostParamsList =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.2f), paddedLeftPanel.RectTransform))
152 PlaySoundOnSelect =
true
154 outpostParamsList.
OnSelected += (GUIComponent component,
object obj) =>
156 selectedOutpostGenerationParams = obj as OutpostGenerationParams;
157 CreateOutpostGenerationParamsEditor(selectedOutpostGenerationParams);
161 var createLevelObjButton =
new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
162 TextManager.Get(
"leveleditor.createlevelobj"))
164 OnClicked = (btn, obj) =>
166 Wizard.Instance.Create();
170 GUITextBlock.AutoScaleAndNormalize(createLevelObjButton.TextBlock);
172 lightingEnabled =
new GUITickBox(
new RectTransform(
new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform),
173 TextManager.Get(
"leveleditor.lightingenabled"));
175 cursorLightEnabled =
new GUITickBox(
new RectTransform(
new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform),
176 TextManager.Get(
"leveleditor.cursorlightenabled"));
178 new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
179 TextManager.Get(
"leveleditor.reloadtextures"))
181 OnClicked = (btn, obj) =>
183 Level.Loaded?.ReloadTextures();
188 new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
189 TextManager.Get(
"editor.saveall"))
191 OnClicked = (btn, obj) =>
194 GUI.AddMessage(TextManager.Get(
"leveleditor.allsaved"), GUIStyle.Green);
199 rightPanel =
new GUIFrame(
new RectTransform(
new Vector2(0.25f, 1.0f),
Frame.
RectTransform,
Anchor.TopRight) { MinSize = new Point(450, 0) });
200 var paddedRightPanel =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.95f, 0.95f), rightPanel.
RectTransform,
Anchor.Center) { RelativeOffset = new Vector2(0.02f, 0.0f) })
203 RelativeSpacing = 0.01f
206 editorContainer =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 1.0f), paddedRightPanel.RectTransform));
208 var seedContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.04f), paddedRightPanel.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft);
209 Vector2 randomizeButtonRelativeSize = GetRandomizeButtonRelativeSize();
210 Vector2 elementRelativeSize = GetSeedElementRelativeSize();
211 var seedLabel =
new GUITextBlock(
new RectTransform(elementRelativeSize, seedContainer.RectTransform), TextManager.Get(
"leveleditor.levelseed"));
212 seedBox =
new GUITextBox(
new RectTransform(elementRelativeSize, seedContainer.RectTransform), GetLevelSeed());
213 var seedButton =
new GUIButton(
new RectTransform(randomizeButtonRelativeSize, seedContainer.RectTransform), style:
"RandomizeButton")
215 OnClicked = (button, userData) =>
217 if (seedBox ==
null) {
return false; }
218 seedBox.
Text = GetLevelSeed();
222 seedContainer.RectTransform.SizeChanged += () =>
224 Vector2 randomizeButtonRelativeSize = GetRandomizeButtonRelativeSize();
225 Vector2 elementRelativeSize = GetSeedElementRelativeSize();
226 seedLabel.RectTransform.RelativeSize = elementRelativeSize;
228 seedButton.RectTransform.RelativeSize = randomizeButtonRelativeSize;
230 Vector2 GetRandomizeButtonRelativeSize() => 0.2f * seedContainer.Rect.Width > seedContainer.Rect.Height ?
231 new Vector2(Math.Min((
float)seedContainer.Rect.Height / seedContainer.Rect.Width, 0.2f), 1.0f) :
232 new Vector2(0.15f, Math.Min((0.2f * seedContainer.Rect.Width) / seedContainer.Rect.Height, 1.0f));
233 Vector2 GetSeedElementRelativeSize() =>
new Vector2(0.5f * (1.0f - randomizeButtonRelativeSize.X), 1.0f);
234 static string GetLevelSeed() => ToolBox.RandomSeed(8);
236 var subDropDownContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), isHorizontal:
true);
237 new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), subDropDownContainer.RectTransform), TextManager.Get(
"submarine"));
238 selectedSubDropDown =
new GUIDropDown(
new RectTransform(
new Vector2(0.5f, 1.0f), subDropDownContainer.RectTransform));
239 foreach (SubmarineInfo sub
in SubmarineInfo.SavedSubmarines)
242 selectedSubDropDown.
AddItem(sub.DisplayName, userData: sub);
246 var beaconStationDropDownContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), isHorizontal:
true);
247 new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), beaconStationDropDownContainer.RectTransform), TextManager.Get(
"submarinetype.beaconstation"));
248 selectedBeaconStationDropdown =
new GUIDropDown(
new RectTransform(
new Vector2(0.5f, 1.0f), beaconStationDropDownContainer.RectTransform));
249 selectedBeaconStationDropdown.
AddItem(TextManager.Get(
"Any"), userData:
null);
250 foreach (SubmarineInfo beaconStation
in SubmarineInfo.SavedSubmarines)
252 if (beaconStation.Type !=
SubmarineType.BeaconStation) {
continue; }
253 selectedBeaconStationDropdown.
AddItem(beaconStation.DisplayName, userData: beaconStation);
257 var wreckDropDownContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), isHorizontal:
true);
258 new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), wreckDropDownContainer.RectTransform), TextManager.Get(
"submarinetype.wreck"));
259 selectedWreckDropdown =
new GUIDropDown(
new RectTransform(
new Vector2(0.5f, 1.0f), wreckDropDownContainer.RectTransform));
260 selectedWreckDropdown.
AddItem(TextManager.Get(
"Any"), userData:
null);
261 foreach (SubmarineInfo wreck
in SubmarineInfo.SavedSubmarines)
264 selectedWreckDropdown.
AddItem(wreck.DisplayName, userData: wreck);
268 var forceDifficultyContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), isHorizontal:
true);
269 new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), forceDifficultyContainer.RectTransform), TextManager.Get(
"leveldifficulty"));
270 forceDifficultyInput =
new GUINumberInput(
new RectTransform(
new Vector2(0.5f, 1.0f), forceDifficultyContainer.RectTransform),
NumberType.Float)
274 FloatValue = Level.ForcedDifficulty ?? selectedParams?.MinLevelDifficulty ?? 0f,
275 OnValueChanged = (numberInput) =>
277 if (Level.ForcedDifficulty ==
null) {
return; }
278 Level.ForcedDifficulty = numberInput.
FloatValue;
281 forceDifficultyContainer.RectTransform.MinSize =
new Point(0, forceDifficultyInput.
RectTransform.
MinSize.Y);
283 var tickBoxContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.04f), paddedRightPanel.RectTransform), isHorizontal:
true);
284 mirrorLevel =
new GUITickBox(
new RectTransform(
new Vector2(0.5f, 0.02f), tickBoxContainer.RectTransform), TextManager.Get(
"mirrorentityx"));
286 allowInvalidOutpost =
new GUITickBox(
new RectTransform(
new Vector2(0.5f, 0.025f), tickBoxContainer.RectTransform),
287 TextManager.Get(
"leveleditor.allowinvalidoutpost"))
289 ToolTip = TextManager.Get(
"leveleditor.allowinvalidoutpost.tooltip")
292 new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
293 TextManager.Get(
"leveleditor.generate"))
295 OnClicked = (btn, obj) =>
297 bool wasLevelLoaded = Level.Loaded !=
null;
300 if (selectedSubDropDown.
SelectedData is SubmarineInfo subInfo)
304 GameMain.LightManager.ClearLights();
305 currentLevelData = LevelData.CreateRandom(seedBox.
Text, difficulty: forceDifficultyInput.
FloatValue, generationParams: selectedParams);
306 currentLevelData.ForceOutpostGenerationParams = outpostParamsList.
SelectedData as OutpostGenerationParams;
307 currentLevelData.ForceBeaconStation = selectedBeaconStationDropdown.
SelectedData as SubmarineInfo;
308 currentLevelData.ForceWreck = selectedWreckDropdown.
SelectedData as SubmarineInfo;
309 currentLevelData.ForceRuinGenerationParams = selectedRuinGenerationParams;
310 currentLevelData.AllowInvalidOutpost = allowInvalidOutpost.
Selected;
311 var dummyLocations = GameSession.CreateDummyLocations(currentLevelData);
312 Level.Generate(currentLevelData, mirror: mirrorLevel.
Selected, startLocation: dummyLocations[0], endLocation: dummyLocations[1]);
316 Vector2 startPos = Level.Loaded.StartPosition;
317 if (Level.Loaded.StartOutpost !=
null)
319 startPos.Y -= Level.Loaded.StartOutpost.Borders.Height / 2 +
Submarine.MainSub.Borders.Height / 2;
321 Submarine.MainSub?.SetPosition(startPos);
324 GameMain.LightManager.AddLight(pointerLightSource);
327 Cam.
Position =
new Vector2(Level.Loaded.Size.X / 2, Level.Loaded.Size.Y / 2);
331 param.TextColor = param.UserData == selectedParams ? GUIStyle.Green : param.Style.TextColor;
338 new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
339 TextManager.Get(
"leveleditor.test"))
341 OnClicked = (btn, obj) =>
343 if (Level.Loaded?.LevelData ==
null) {
return false; }
345 GameMain.GameScreen.Select();
347 var currEntities = Entity.GetEntities().ToList();
350 var toRemove = Entity.GetEntities().Where(e => e.Submarine ==
Submarine.MainSub).ToList();
351 foreach (Entity ent
in toRemove)
358 var nonPlayerFiles = ContentPackageManager.EnabledPackages.All.SelectMany(p => p
359 .GetFiles<BaseSubFile>()
360 .Where(f => f is not SubmarineFile)).ToArray();
361 SubmarineInfo subInfo = selectedSubDropDown.
SelectedData as SubmarineInfo;
362 subInfo ??= SubmarineInfo.SavedSubmarines.GetRandomUnsynced(s =>
364 !nonPlayerFiles.Any(f => f.Path == s.FilePath));
365 GameSession gameSession =
new GameSession(subInfo, Option.None, CampaignDataPath.Empty, GameModePreset.TestMode, CampaignSettings.Empty,
null);
366 gameSession.StartRound(Level.Loaded.LevelData);
367 (gameSession.GameMode as TestGameMode).OnRoundEnd = () =>
369 GameMain.LevelEditorScreen.Select();
372 var toRemove = Entity.GetEntities().Where(e => !currEntities.Contains(e)).ToList();
373 foreach (Entity ent
in toRemove)
381 GameMain.GameSession = gameSession;
388 { MaxSize = new Point(GameMain.GraphicsWidth - rightPanel.Rect.Width, 1000) }, style:
"GUIFrameBottom");
390 levelObjectList =
new GUIListBox(
new RectTransform(
new Vector2(0.99f, 0.85f), bottomPanel.
RectTransform,
Anchor.Center))
392 PlaySoundOnSelect =
true,
395 levelObjectList.
OnSelected += (GUIComponent component,
object obj) =>
397 selectedLevelObject = obj as LevelObjectPrefab;
398 CreateLevelObjectEditor(selectedLevelObject);
402 spriteEditDoneButton =
new GUIButton(
new RectTransform(
new Point(200, 30), anchor:
Anchor.BottomRight) { AbsoluteOffset = new Point(20, 20) },
403 TextManager.Get(
"leveleditor.spriteeditdone"))
405 OnClicked = (btn, userdata) =>
407 editingSprite =
null;
412 topPanel =
new GUIFrame(
new RectTransform(
new Point(400, 100), GUI.Canvas)
413 { RelativeOffset = new Vector2(leftPanel.RectTransform.RelativeSize.X * 2, 0.0f) }, style:
"GUIFrameTop");
424 RefreshUI(forceCreate:
true);
429 CoroutineManager.StartCoroutine(GenerateLevels());
431 IEnumerable<CoroutineStatus> GenerateLevels()
433 using var errorCatcher = DebugConsole.ErrorCatcher.Create();
434 for (
int i = 0; i < amountOfLevelsToGenerate; i++)
444 currentLevelData.AllowInvalidOutpost = allowInvalidOutpost.
Selected;
446 DebugConsole.NewMessage(
"*****************************************************************************");
447 DebugConsole.NewMessage($
"Generating level {(i + 1)}/{amountOfLevelsToGenerate}: ");
448 DebugConsole.NewMessage(
" Seed: " + currentLevelData.Seed);
449 DebugConsole.NewMessage(
" Outpost parameters: " + (currentLevelData.ForceOutpostGenerationParams?.Name ??
"None"));
450 DebugConsole.NewMessage(
" Level generation params: " + selectedParams.Identifier);
451 DebugConsole.NewMessage(
" Mirrored: " + mirrorLevel.
Selected);
452 DebugConsole.NewMessage(
" Adjacent locations: " + (dummyLocations[0]?.Type.Identifier ??
"none".ToIdentifier()) +
", " + (dummyLocations[1]?.Type.Identifier ??
"none".ToIdentifier()));
456 Level.
Generate(currentLevelData, mirror: mirrorLevel.
Selected, startLocation: dummyLocations[0], endLocation: dummyLocations[1]);
461 if (errorCatcher.Errors.Any())
463 DebugConsole.ThrowError(
"Error while generating level:");
464 errorCatcher.Errors.ToList().ForEach(e => DebugConsole.ThrowError(e.Text));
476 RefreshUI(forceCreate:
false);
481 pointerLightSource?.
Remove();
482 pointerLightSource =
null;
485 private void UpdateParamsList()
495 Padding = Vector4.Zero,
501 private void UpdateCaveParamsList()
506 foreach (CaveGenerationParams genParams
in CaveGenerationParams.CaveParams.OrderBy(p => p.Name))
508 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.05f), caveParamsList.
Content.
RectTransform) { MinSize = new Point(0, 20) },
511 Padding = Vector4.Zero,
517 private void UpdateRuinParamsList()
524 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.05f), ruinParamsList.
Content.
RectTransform) { MinSize = new Point(0, 20) },
527 Padding = Vector4.Zero,
533 private void UpdateOutpostParamsList()
538 foreach (OutpostGenerationParams genParams
in OutpostGenerationParams.OutpostParams.OrderBy(p => p.Name))
540 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.05f), outpostParamsList.
Content.
RectTransform) { MinSize = new Point(0, 20) },
543 Padding = Vector4.Zero,
549 private void UpdateLevelObjectsList()
554 int objectsPerRow = (int)Math.Ceiling(levelObjectList.
Content.
Rect.Width / Math.Max(100 * GUI.Scale, 100));
555 float relWidth = 1.0f / objectsPerRow;
557 foreach (LevelObjectPrefab levelObjPrefab
in LevelObjectPrefab.Prefabs)
559 var frame =
new GUIFrame(
new RectTransform(
560 new Vector2(relWidth, relWidth * ((
float)levelObjectList.
Content.
Rect.Width / levelObjectList.
Content.
Rect.Height)),
561 levelObjectList.
Content.
RectTransform) { MinSize = new Point(0, 60) }, style:
"ListBoxElementSquare")
563 UserData = levelObjPrefab
565 var paddedFrame =
new GUIFrame(
new RectTransform(
new Vector2(0.9f, 0.9f), frame.RectTransform,
Anchor.Center), style:
null);
567 GUITextBlock textBlock =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), paddedFrame.RectTransform,
Anchor.BottomCenter),
568 text: ToolBox.LimitString(levelObjPrefab.Name, GUIStyle.SmallFont, paddedFrame.Rect.Width), textAlignment: Alignment.Center, font: GUIStyle.SmallFont)
570 CanBeFocused =
false,
571 ToolTip = levelObjPrefab.Name
574 Sprite sprite = levelObjPrefab.Sprites.FirstOrDefault() ?? levelObjPrefab.DeformableSprite?.Sprite;
575 new GUIImage(
new RectTransform(
new Point(paddedFrame.Rect.Height, paddedFrame.Rect.Height - textBlock.Rect.Height),
576 paddedFrame.RectTransform,
Anchor.TopCenter), sprite, scaleToFit:
true)
578 LoadAsynchronously =
true,
584 private void CreateCaveParamsEditor(CaveGenerationParams caveGenerationParams)
587 var editor =
new SerializableEntityEditor(editorContainer.
Content.
RectTransform, caveGenerationParams,
false,
true, elementHeight: 20);
589 if (selectedParams !=
null)
591 var commonnessContainer =
new GUILayoutGroup(
new RectTransform(
new Point(editor.Rect.Width, 70)) { IsFixedSize = true },
592 isHorizontal:
false, childAnchor:
Anchor.TopCenter)
597 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.4f), commonnessContainer.RectTransform),
598 TextManager.GetWithVariable(
"leveleditor.levelobjcommonness",
"[leveltype]", selectedParams.Identifier.Value), textAlignment: Alignment.Center);
599 new GUINumberInput(
new RectTransform(
new Vector2(0.5f, 0.4f), commonnessContainer.RectTransform),
NumberType.Float)
603 FloatValue = caveGenerationParams.GetCommonness(currentLevelData, abyss:
false),
604 OnValueChanged = (numberInput) =>
606 caveGenerationParams.OverrideCommonness[selectedParams.Identifier] = numberInput.FloatValue;
609 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.2f), commonnessContainer.RectTransform), style:
null);
610 editor.AddCustomContent(commonnessContainer, 1);
614 private void CreateOutpostGenerationParamsEditor(OutpostGenerationParams outpostGenerationParams)
617 if (outpostGenerationParams ==
null) {
return; }
618 var outpostParamsEditor =
new SerializableEntityEditor(editorContainer.
Content.
RectTransform, outpostGenerationParams,
false,
true, elementHeight: 20);
622 var locationTypeGroup =
new GUILayoutGroup(
new RectTransform(
new Point(editorContainer.
Content.
Rect.Width, 20)), isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
627 new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1f), locationTypeGroup.RectTransform), TextManager.Get(
"outpostmoduleallowedlocationtypes"), textAlignment: Alignment.CenterLeft);
628 HashSet<Identifier> availableLocationTypes =
new HashSet<Identifier> {
"any".ToIdentifier() };
629 foreach (LocationType locationType
in LocationType.Prefabs) { availableLocationTypes.Add(locationType.Identifier); }
631 var locationTypeDropDown =
new GUIDropDown(
new RectTransform(
new Vector2(0.5f, 1f), locationTypeGroup.RectTransform),
632 text: LocalizedString.Join(
", ", outpostGenerationParams.AllowedLocationTypes.Select(lt => TextManager.Capitalize(lt.Value)) ?? ((LocalizedString)
"any").ToEnumerable()), selectMultiple:
true);
633 foreach (Identifier locationType
in availableLocationTypes)
635 locationTypeDropDown.AddItem(TextManager.Capitalize(locationType.Value), locationType);
636 if (outpostGenerationParams.AllowedLocationTypes.Contains(locationType))
638 locationTypeDropDown.SelectItem(locationType);
641 if (!outpostGenerationParams.AllowedLocationTypes.Any())
643 locationTypeDropDown.SelectItem(
"any");
646 locationTypeDropDown.AfterSelected += (_, __) =>
648 outpostGenerationParams.SetAllowedLocationTypes(locationTypeDropDown.SelectedDataMultiple.Cast<Identifier>());
649 locationTypeDropDown.Text = ToolBox.LimitString(locationTypeDropDown.Text, locationTypeDropDown.Font, locationTypeDropDown.Rect.Width);
652 locationTypeGroup.RectTransform.MinSize =
new Point(locationTypeGroup.Rect.Width, locationTypeGroup.RectTransform.Children.Max(c => c.MinSize.Y));
654 outpostParamsEditor.AddCustomContent(locationTypeGroup, 100);
658 foreach (var moduleCount
in outpostGenerationParams.ModuleCounts)
660 var editor =
new SerializableEntityEditor(editorContainer.
Content.
RectTransform, moduleCount, inGame:
false, showName:
true, elementHeight: 20, titleFont: GUIStyle.Font);
661 foreach (var componentList
in editor.Fields.Values)
663 foreach (var component
in componentList)
665 if (component is GUINumberInput numberInput)
667 numberInput.OnValueChanged += (numInput) =>
669 if (moduleCount.Count == 0)
678 editor.RectTransform.MaxSize =
new Point(
int.MaxValue, editor.Rect.Height);
679 outpostParamsEditor.AddCustomContent(editor, 100);
680 editor.Recalculate();
685 var addModuleCountGroup =
new GUILayoutGroup(
new RectTransform(
new Point(editorContainer.
Content.
Rect.Width, (
int)(40 * GUI.Scale))), isHorizontal:
true, childAnchor:
Anchor.Center);
687 HashSet<Identifier> availableFlags =
new HashSet<Identifier>();
688 foreach (Identifier flag
in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Identifier))) { availableFlags.Add(flag); }
689 foreach (var sub
in SubmarineInfo.SavedSubmarines)
691 if (sub.OutpostModuleInfo ==
null) {
continue; }
692 foreach (Identifier flag
in sub.OutpostModuleInfo.ModuleFlags) { availableFlags.Add(flag); }
695 var moduleTypeDropDown =
new GUIDropDown(
new RectTransform(
new Vector2(0.8f, 0.8f), addModuleCountGroup.RectTransform),
696 text: TextManager.Get(
"leveleditor.addmoduletype"));
697 foreach (Identifier flag
in availableFlags)
699 if (outpostGenerationParams.ModuleCounts.Any(mc => mc.Identifier == flag)) {
continue; }
700 moduleTypeDropDown.AddItem(TextManager.Capitalize(flag.Value), flag);
702 moduleTypeDropDown.OnSelected += (_, userdata) =>
704 outpostGenerationParams.SetModuleCount((Identifier)userdata, 1);
708 addModuleCountGroup.RectTransform.MinSize =
new Point(addModuleCountGroup.Rect.Width, addModuleCountGroup.RectTransform.Children.Max(c => c.MinSize.Y));
709 outpostParamsEditor.AddCustomContent(addModuleCountGroup, 100);
710 outpostParamsEditor.Recalculate();
713 private void CreateLevelObjectEditor(LevelObjectPrefab levelObjectPrefab)
717 var editor =
new SerializableEntityEditor(editorContainer.
Content.
RectTransform, levelObjectPrefab,
false,
true, elementHeight: 20, titleFont: GUIStyle.LargeFont);
719 if (selectedParams !=
null)
721 List<Identifier> availableIdentifiers =
new List<Identifier>();
722 if (selectedParams !=
null) { availableIdentifiers.Add(selectedParams.Identifier); }
723 foreach (var caveParam
in CaveGenerationParams.CaveParams)
725 if (selectedParams !=
null && caveParam.GetCommonness(currentLevelData, abyss:
false) <= 0.0f) {
continue; }
726 availableIdentifiers.Add(caveParam.Identifier);
728 availableIdentifiers.Reverse();
730 foreach (Identifier paramsId
in availableIdentifiers)
732 var commonnessContainer =
new GUILayoutGroup(
new RectTransform(
new Point(editor.Rect.Width, 70)) { IsFixedSize = true },
733 isHorizontal:
false, childAnchor:
Anchor.TopCenter)
738 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.4f), commonnessContainer.RectTransform),
739 TextManager.GetWithVariable(
"leveleditor.levelobjcommonness",
"[leveltype]", paramsId.Value), textAlignment: Alignment.Center);
740 new GUINumberInput(
new RectTransform(
new Vector2(0.5f, 0.4f), commonnessContainer.RectTransform),
NumberType.Float)
744 FloatValue = selectedParams.Identifier == paramsId ? levelObjectPrefab.GetCommonness(currentLevelData) : levelObjectPrefab.GetCommonness(CaveGenerationParams.CaveParams.Find(p => p.Identifier == paramsId)),
745 OnValueChanged = (numberInput) =>
747 levelObjectPrefab.OverrideCommonness[paramsId] = numberInput.FloatValue;
750 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.2f), commonnessContainer.RectTransform), style:
null);
751 editor.AddCustomContent(commonnessContainer, 1);
755 Sprite sprite = levelObjectPrefab.Sprites.FirstOrDefault() ?? levelObjectPrefab.DeformableSprite?.Sprite;
758 editor.AddCustomContent(
new GUIButton(
new RectTransform(
new Point(editor.Rect.Width / 2, (
int)(25 * GUI.Scale))) { IsFixedSize = true },
759 TextManager.Get(
"leveleditor.editsprite"))
761 OnClicked = (btn, userdata) =>
763 editingSprite = sprite;
764 GameMain.SpriteEditorScreen.SelectSprite(editingSprite);
770 if (levelObjectPrefab.DeformableSprite !=
null)
772 var deformEditor = levelObjectPrefab.DeformableSprite.CreateEditor(editor, levelObjectPrefab.SpriteDeformations, levelObjectPrefab.Name);
773 deformEditor.GetChild<GUIDropDown>().OnSelected += (selected, userdata) =>
775 CreateLevelObjectEditor(selectedLevelObject);
778 editor.AddCustomContent(deformEditor, editor.ContentCount);
781 new GUITextBlock(
new RectTransform(
new Point(editor.Rect.Width, 40), editorContainer.
Content.
RectTransform),
782 TextManager.Get(
"leveleditor.childobjects"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomCenter);
783 foreach (LevelObjectPrefab.ChildObject childObj in levelObjectPrefab.ChildObjects)
785 var childObjFrame =
new GUIFrame(
new RectTransform(
new Point(editor.Rect.Width, 30)));
786 var paddedFrame =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.95f, 0.9f), childObjFrame.RectTransform,
Anchor.Center), isHorizontal:
true)
789 RelativeSpacing = 0.05f
791 var selectedChildObj = childObj;
792 var dropdown =
new GUIDropDown(
new RectTransform(
new Vector2(0.5f, 1.0f), paddedFrame.RectTransform), elementCount: 10, selectMultiple:
true);
793 foreach (LevelObjectPrefab objPrefab
in LevelObjectPrefab.Prefabs)
795 dropdown.AddItem(objPrefab.Name, objPrefab);
796 if (childObj.AllowedNames.Contains(objPrefab.Name)) { dropdown.SelectItem(objPrefab); }
798 dropdown.AfterSelected = (selected, obj) =>
800 childObj.AllowedNames = dropdown.SelectedDataMultiple.Select(d => ((LevelObjectPrefab)d).Name).ToList();
803 new GUINumberInput(
new RectTransform(
new Vector2(0.2f, 1.0f), paddedFrame.RectTransform),
NumberType.Int)
807 OnValueChanged = (numberInput) =>
809 selectedChildObj.MinCount = numberInput.IntValue;
810 selectedChildObj.MaxCount = Math.Max(selectedChildObj.MaxCount, selectedChildObj.MinCount);
812 }.IntValue = childObj.MinCount;
813 new GUINumberInput(
new RectTransform(
new Vector2(0.2f, 1.0f), paddedFrame.RectTransform),
NumberType.Int)
817 OnValueChanged = (numberInput) =>
819 selectedChildObj.MaxCount = numberInput.IntValue;
820 selectedChildObj.MinCount = Math.Min(selectedChildObj.MaxCount, selectedChildObj.MinCount);
822 }.IntValue = childObj.MaxCount;
824 new GUIButton(
new RectTransform(
new Vector2(0.1f, 1.0f), paddedFrame.RectTransform, scaleBasis:
ScaleBasis.BothHeight), style:
"GUICancelButton")
826 OnClicked = (btn, userdata) =>
828 selectedLevelObject.
ChildObjects.Remove(selectedChildObj);
829 CreateLevelObjectEditor(selectedLevelObject);
837 var buttonContainer =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.01f), editorContainer.
Content.
RectTransform), style:
null);
838 new GUIButton(
new RectTransform(
new Point(editor.Rect.Width / 2, 20), buttonContainer.RectTransform,
Anchor.Center),
839 TextManager.Get(
"leveleditor.addchildobject"))
841 OnClicked = (btn, userdata) =>
843 selectedLevelObject.
ChildObjects.Add(
new LevelObjectPrefab.ChildObject());
844 CreateLevelObjectEditor(selectedLevelObject);
848 buttonContainer.RectTransform.MinSize = buttonContainer.RectTransform.Children.First().MinSize;
851 new GUITextBlock(
new RectTransform(
new Point(editor.Rect.Width, 40), editorContainer.
Content.
RectTransform),
852 TextManager.Get(
"leveleditor.lightsources"), textAlignment: Alignment.BottomCenter, font: GUIStyle.SubHeadingFont);
855 new SerializableEntityEditor(editorContainer.
Content.
RectTransform, lightSourceParams, inGame:
false, showName:
true);
857 buttonContainer =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.01f), editorContainer.
Content.
RectTransform), style:
null);
858 new GUIButton(
new RectTransform(
new Point(editor.Rect.Width / 2, 20), buttonContainer.RectTransform,
Anchor.Center),
859 TextManager.Get(
"leveleditor.addlightsource"))
861 OnClicked = (btn, userdata) =>
865 CreateLevelObjectEditor(selectedLevelObject);
869 buttonContainer.RectTransform.MinSize = buttonContainer.RectTransform.Children.First().MinSize;
872 private void SortLevelObjectsList(LevelData levelData)
875 foreach (GUIComponent levelObjFrame
in levelObjectList.
Content.
Children)
877 var levelObj = levelObjFrame.UserData as LevelObjectPrefab;
878 float commonness = levelObj.GetCommonness(levelData);
879 levelObjFrame.Color = commonness > 0.0f ? GUIStyle.Green * 0.4f : Color.Transparent;
880 levelObjFrame.SelectedColor = commonness > 0.0f ? GUIStyle.Green * 0.6f : Color.White * 0.5f;
881 levelObjFrame.HoverColor = commonness > 0.0f ? GUIStyle.Green * 0.7f : Color.White * 0.6f;
883 levelObjFrame.GetAnyChild<GUIImage>().Color = commonness > 0.0f ? Color.White : Color.DarkGray;
884 if (commonness <= 0.0f)
886 levelObjFrame.GetAnyChild<GUITextBlock>().TextColor = Color.DarkGray;
893 var levelObj1 = c1.GUIComponent.UserData as LevelObjectPrefab;
894 var levelObj2 = c2.GUIComponent.UserData as LevelObjectPrefab;
895 return Math.Sign(levelObj2.GetCommonness(levelData) - levelObj1.GetCommonness(levelData));
901 base.AddToGUIUpdateList();
903 if (editingSprite !=
null)
914 public override void Draw(
double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
920 graphics.Clear(Color.Black);
926 spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.DepthRead, transformMatrix: Cam.Transform);
936 Color tunnelColor = tunnelDebugColors[i % tunnelDebugColors.Length] * 0.2f;
937 for (
int j = 1; j < tunnel.Nodes.Count; j++)
939 Vector2 start =
new Vector2(tunnel.Nodes[j - 1].X, -tunnel.Nodes[j - 1].Y);
940 Vector2 end =
new Vector2(tunnel.Nodes[j].X, -tunnel.Nodes[j].Y);
941 GUI.DrawLine(spriteBatch, start, end, tunnelColor, width: (
int)(2.0f / Cam.Zoom));
947 if (interestingPos.Position.X < Cam.WorldView.X || interestingPos.Position.X > Cam.WorldView.Right ||
948 interestingPos.Position.Y > Cam.WorldView.Y || interestingPos.Position.Y < Cam.WorldView.Y - Cam.WorldView.Height)
953 Vector2 pos =
new Vector2(interestingPos.Position.X, -interestingPos.Position.Y);
954 spriteBatch.DrawCircle(pos, 500, 6, Color.White * 0.5f, thickness: (
int)(2 / Cam.Zoom));
955 GUI.DrawString(spriteBatch, pos, interestingPos.PositionType.ToString(), Color.White, font: GUIStyle.LargeFont);
961 Vector2 pathPointPos =
new Vector2(pathPoint.Position.X, -pathPoint.Position.Y);
962 foreach (var location
in pathPoint.ClusterLocations)
964 if (location.Resources ==
null) {
continue; }
965 foreach (var resource
in location.Resources)
967 Vector2 resourcePos =
new Vector2(resource.Position.X, -resource.Position.Y);
968 spriteBatch.DrawCircle(resourcePos, 100, 6, Color.DarkGreen * 0.5f, thickness: (
int)(2 / Cam.Zoom));
969 GUI.DrawString(spriteBatch, resourcePos, resource.Name, Color.DarkGreen, font: GUIStyle.LargeFont);
970 var dist = Vector2.Distance(resourcePos, pathPointPos);
971 var lineStartPos = Vector2.Lerp(resourcePos, pathPointPos, 110 / dist);
972 var lineEndPos = Vector2.Lerp(pathPointPos, resourcePos, 310 / dist);
973 GUI.DrawLine(spriteBatch, lineStartPos, lineEndPos, Color.DarkGreen * 0.5f, width: (
int)(2 / Cam.Zoom));
976 var color = pathPoint.ShouldContainResources ? Color.DarkGreen : Color.DarkRed;
977 spriteBatch.DrawCircle(pathPointPos, 300, 6, color * 0.5f, thickness: (
int)(2 / Cam.Zoom));
978 GUI.DrawString(spriteBatch, pathPointPos,
"Path Point\n" + pathPoint.Id, color, font: GUIStyle.LargeFont);
983 if (location.Resources ==
null) {
continue; }
984 foreach (var resource
in location.Resources)
986 Vector2 resourcePos =
new Vector2(resource.Position.X, -resource.Position.Y);
987 spriteBatch.DrawCircle(resourcePos, 100, 6, Color.DarkGreen * 0.5f, thickness: (
int)(2 / Cam.Zoom));
988 GUI.DrawString(spriteBatch, resourcePos, resource.Name, Color.DarkGreen, font: GUIStyle.LargeFont);
1013 spriteBatch.Begin(SpriteSortMode.Immediate, Lights.CustomBlendStates.Multiplicative,
null, DepthStencilState.None,
null,
null,
null);
1019 if (editingSprite !=
null)
1024 spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState:
GameMain.
ScissorTestEnable);
1027 float hullUpgradePrcIncrease = UpgradePrefab.CrushDepthUpgradePrc / 100f;
1028 for (
int upgradeLevel = 0; upgradeLevel <= UpgradePrefab.IncreaseWallHealthMaxLevel; upgradeLevel++)
1032 string labelText = $
"Crush depth (upgrade level {upgradeLevel})";
1033 if (upgradeLevel == 0)
1035 labelText = $
"Crush depth (no upgrade)";
1037 DrawCrushDepth(subCrushDepth, labelText, Color.Red);
1040 float abyssStartScreen = Cam.WorldToScreen(
new Vector2(0.0f,
Level.
Loaded.
AbyssArea.Bottom)).Y;
1043 GUI.DrawLine(spriteBatch,
new Vector2(0, abyssStartScreen),
new Vector2(
GameMain.
GraphicsWidth, abyssStartScreen), GUIStyle.Blue * 0.25f, width: 5);
1044 GUI.DrawString(spriteBatch,
new Vector2(
GameMain.
GraphicsWidth / 2, abyssStartScreen),
"Abyss start", GUIStyle.Blue, backgroundColor: Color.Black);
1049 GUI.DrawLine(spriteBatch,
new Vector2(0, abyssEndScreen),
new Vector2(
GameMain.
GraphicsWidth, abyssEndScreen), GUIStyle.Blue * 0.25f, width: 5);
1050 GUI.DrawString(spriteBatch,
new Vector2(
GameMain.
GraphicsWidth / 2, abyssEndScreen),
"Abyss end", GUIStyle.Blue, backgroundColor: Color.Black);
1053 GUI.Draw(Cam, spriteBatch);
1056 void DrawCrushDepth(
float crushDepth,
string labelText, Color color)
1058 float crushDepthScreen = Cam.WorldToScreen(
new Vector2(0.0f, -crushDepth)).Y;
1061 GUI.DrawLine(spriteBatch,
new Vector2(0, crushDepthScreen),
new Vector2(
GameMain.
GraphicsWidth, crushDepthScreen), color * 0.25f, width: 5);
1062 GUI.DrawString(spriteBatch,
new Vector2(
GameMain.
GraphicsWidth / 2, crushDepthScreen), labelText, GUIStyle.Red, backgroundColor: Color.Black);
1067 public override void Update(
double deltaTime)
1073 if (item ==
null || item.
IsHidden) {
continue; }
1074 foreach (var light
in item.GetComponents<Items.
Components.LightComponent>())
1076 light.Update((
float)deltaTime, Cam);
1085 Cam.MoveCamera((
float)deltaTime, allowZoom: GUI.MouseOn ==
null);
1086 Cam.UpdateTransform();
1089 if (editingSprite !=
null)
1103 RefreshUI(forceCreate:
true);
1108 private void SerializeAll()
1110 IEnumerable<ContentPackage> packages = ContentPackageManager.LocalPackages;
1112 packages = packages.Union(ContentPackageManager.VanillaCorePackage.ToEnumerable());
1115 System.Xml.XmlWriterSettings settings =
new System.Xml.XmlWriterSettings
1118 NewLineOnAttributes =
true
1120 foreach (var configFile
in packages.SelectMany(p => p.GetFiles<LevelGenerationParametersFile>()))
1122 XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
1123 if (doc ==
null) {
continue; }
1125 foreach (LevelGenerationParams genParams
in LevelGenerationParams.LevelParams)
1127 foreach (XElement element
in doc.Root.Elements())
1129 if (element.IsOverride())
1131 foreach (var subElement
in element.Elements())
1133 string id = element.GetAttributeString(
"identifier",
null) ?? element.Name.ToString();
1134 if (!
id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) {
continue; }
1135 SerializableProperty.SerializeProperties(genParams, element,
true);
1140 string id = element.GetAttributeString(
"identifier",
null) ?? element.Name.ToString();
1141 if (!
id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) {
continue; }
1142 SerializableProperty.SerializeProperties(genParams, element,
true);
1147 using (var writer =
XmlWriter.
Create(configFile.Path.Value, settings))
1149 doc.WriteTo(writer);
1154 foreach (var configFile
in packages.SelectMany(p => p.GetFiles<CaveGenerationParametersFile>()))
1156 XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
1157 if (doc ==
null) {
continue; }
1159 foreach (CaveGenerationParams genParams
in CaveGenerationParams.CaveParams)
1161 foreach (XElement element
in doc.Root.Elements())
1163 if (element.IsOverride())
1165 foreach (var subElement
in element.Elements())
1167 string id = subElement.GetAttributeString(
"identifier",
null) ?? subElement.Name.ToString();
1168 if (!
id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) {
continue; }
1169 genParams.Save(subElement);
1174 string id = element.GetAttributeString(
"identifier",
null) ?? element.Name.ToString();
1175 if (!
id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) {
continue; }
1176 genParams.Save(element);
1181 using (var writer =
XmlWriter.
Create(configFile.Path.Value, settings))
1183 doc.WriteTo(writer);
1188 settings.NewLineOnAttributes =
false;
1189 foreach (var configFile
in packages.SelectMany(p => p.GetFiles<LevelObjectPrefabsFile>()))
1191 XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
1192 if (doc ==
null) {
continue; }
1194 foreach (LevelObjectPrefab levelObjPrefab
in LevelObjectPrefab.Prefabs)
1196 foreach (XElement element
in doc.Root.Elements())
1198 Identifier identifier = element.GetAttributeIdentifier(
"identifier",
"");
1199 if (identifier != levelObjPrefab.Identifier) {
continue; }
1200 levelObjPrefab.Save(element);
1204 using (var writer =
XmlWriter.
Create(configFile.Path.Value, settings))
1206 doc.WriteTo(writer);
1214 private void Serialize(LevelGenerationParams genParams)
1216 foreach (var configFile
in ContentPackageManager.AllPackages.SelectMany(p => p.GetFiles<LevelGenerationParametersFile>()))
1218 XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
1219 if (doc ==
null) {
continue; }
1221 bool elementFound =
false;
1222 foreach (XElement element
in doc.Root.Elements())
1224 string id = element.GetAttributeString(
"identifier",
null) ?? element.Name.ToString();
1225 if (!
id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) {
continue; }
1226 SerializableProperty.SerializeProperties(genParams, element,
true);
1227 elementFound =
true;
1232 System.Xml.XmlWriterSettings settings =
new System.Xml.XmlWriterSettings
1235 NewLineOnAttributes =
true
1238 using (var writer =
XmlWriter.
Create(configFile.Path.Value, settings))
1240 doc.WriteTo(writer);
1249 #region LevelObject Wizard
1250 private class Wizard
1252 private LevelObjectPrefab newPrefab;
1254 private static Wizard instance;
1255 public static Wizard Instance
1259 if (instance ==
null)
1261 instance =
new Wizard();
1267 public void AddToGUIUpdateList()
1272 public GUIMessageBox Create()
1274 var box =
new GUIMessageBox(TextManager.Get(
"leveleditor.createlevelobj"),
string.Empty,
1275 new LocalizedString[] { TextManager.Get(
"cancel"), TextManager.Get(
"done") },
new Vector2(0.5f, 0.8f));
1277 box.Content.ChildAnchor =
Anchor.TopCenter;
1278 box.Content.AbsoluteSpacing = 20;
1279 int elementSize = 30;
1280 var listBox =
new GUIListBox(
new RectTransform(
new Vector2(1, 0.75f), box.Content.RectTransform));
1282 new GUITextBlock(
new RectTransform(
new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform),
1283 TextManager.Get(
"leveleditor.levelobjname")) { CanBeFocused =
false };
1284 var nameBox =
new GUITextBox(
new RectTransform(
new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform));
1286 new GUITextBlock(
new RectTransform(
new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform),
1287 TextManager.Get(
"leveleditor.levelobjtexturepath")) { CanBeFocused =
false };
1288 var texturePathBox =
new GUITextBox(
new RectTransform(
new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform));
1289 foreach (LevelObjectPrefab prefab
in LevelObjectPrefab.Prefabs)
1291 if (prefab.Sprites.FirstOrDefault() ==
null) {
continue; }
1292 texturePathBox.Text = Path.GetDirectoryName(prefab.Sprites.FirstOrDefault().FilePath.Value);
1297 newPrefab =
new LevelObjectPrefab(
null,
null,
new Identifier(
"No identifier"));
1299 new SerializableEntityEditor(listBox.Content.RectTransform, newPrefab,
false,
false);
1301 box.Buttons[0].OnClicked += (b, d) =>
1307 box.Buttons[1].OnClicked += (b, d) =>
1309 if (
string.IsNullOrEmpty(nameBox.Text))
1311 nameBox.Flash(GUIStyle.Red);
1312 GUI.AddMessage(TextManager.Get(
"leveleditor.levelobjnameempty"), GUIStyle.Red);
1316 if (LevelObjectPrefab.Prefabs.Any(obj => obj.Identifier == nameBox.Text))
1318 nameBox.Flash(GUIStyle.Red);
1319 GUI.AddMessage(TextManager.Get(
"leveleditor.levelobjnametaken"), GUIStyle.Red);
1323 if (!File.Exists(texturePathBox.Text))
1325 texturePathBox.Flash(GUIStyle.Red);
1326 GUI.AddMessage(TextManager.Get(
"leveleditor.levelobjtexturenotfound"), GUIStyle.Red);
1330 System.Xml.XmlWriterSettings settings =
new System.Xml.XmlWriterSettings { Indent =
true };
1332 var newElement =
new XElement(nameBox.Text);
1333 newPrefab.Save(newElement);
1334 newElement.Add(
new XElement(
"Sprite",
1335 new XAttribute(
"texture", texturePathBox.Text),
1336 new XAttribute(
"sourcerect",
"0,0,100,100"),
1337 new XAttribute(
"origin",
"0.5,0.5")));
1340 #warning TODO: add a clear way to tack it into an existing content package?
1341 string modDir = Path.Combine(ContentPackage.LocalModsDir, nameBox.Text);
1342 Directory.CreateDirectory(modDir);
1344 string fileListPath = Path.Combine(modDir, ContentPackage.FileListFileName);
1345 string prefabFilePath = Path.Combine(modDir, $
"{nameBox.Text}.xml");
1347 var newMod =
new ModProject { Name = nameBox.Text };
1348 var newFile = ModProject.File.FromPath<LevelObjectPrefabsFile>(prefabFilePath);
1349 newMod.AddFile(newFile);
1351 XDocument fileListDoc = newMod.ToXDocument();
1352 Directory.CreateDirectory(Path.GetDirectoryName(fileListPath));
1355 XDocument prefabDoc =
new XDocument();
1356 var prefabFileRoot =
new XElement(
"LevelObjects");
1357 prefabFileRoot.Add(newElement);
1358 prefabDoc.Add(prefabFileRoot);
1361 ContentPackageManager.UpdateContentPackageList();
1363 var newRegularList = ContentPackageManager.EnabledPackages.Regular.ToList();
1364 newRegularList.Add(ContentPackageManager.RegularPackages.First(p => p.Name == nameBox.Text));
1365 ContentPackageManager.EnabledPackages.SetRegular(newRegularList);
1367 GameMain.LevelEditorScreen.UpdateLevelObjectsList();
static CoroutineStatus Running
static CoroutineStatus Success
virtual void AddToGUIUpdateList(bool ignoreChildren=false, int order=0)
virtual void ClearChildren()
RectTransform RectTransform
IEnumerable< GUIComponent > Children
GUIComponent AddItem(LocalizedString text, object userData=null, LocalizedString toolTip=null, Color? color=null, Color? textColor=null)
OnSelectedHandler OnSelected
Triggers when some element is clicked on the listbox. Note that SelectedData is not set yet when this...
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
void Select(object userData, Force force=Force.No, AutoScroll autoScroll=AutoScroll.Enabled)
override void ClearChildren()
static SpriteEditorScreen SpriteEditorScreen
static RasterizerState ScissorTestEnable
static int GraphicsHeight
static Lights.LightManager LightManager
static Location[] CreateDummyLocations(LevelData levelData, LocationType? forceLocationType=null)
static XmlWriter Create(string path, System.Xml.XmlWriterSettings settings)
static readonly List< Item > ItemList
List< ItemComponent > Components
static LevelData CreateRandom(string seed="", float? difficulty=null, LevelGenerationParams generationParams=null, Identifier biomeId=default, bool requireOutpost=false, bool pvpOnly=false)
OutpostGenerationParams ForceOutpostGenerationParams
readonly int InitialDepth
The depth at which the level starts at, in in-game coordinates. E.g. if this was set to 100 000 (= 10...
override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
override void AddToGUIUpdateList()
By default, submits the screen's main GUIFrame and, if requested upon construction,...
override void DeselectEditorSpecific()
void TestLevelGenerationForErrors(int amountOfLevelsToGenerate)
override void Update(double deltaTime)
static readonly PrefabCollection< LevelGenerationParams > LevelParams
static ? float ForcedDifficulty
void DrawBack(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam)
readonly LevelData LevelData
List< ClusterLocation > AbyssResources
List< PathPoint > PathPoints
void DrawDebugOverlay(SpriteBatch spriteBatch, Camera cam)
void Update(float deltaTime, Camera cam)
static Level Generate(LevelData levelData, bool mirror, Location startLocation, Location endLocation, SubmarineInfo startOutpost=null, SubmarineInfo endOutpost=null)
const float DefaultRealWorldCrushDepth
void DrawFront(SpriteBatch spriteBatch, Camera cam)
List< InterestingPosition > PositionsOfInterest
List< int > LightSourceTriggerIndex
List< LightSourceParams > LightSourceParams
List< ChildObject > ChildObjects
void Update(float deltaTime)
void RenderLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor=null)
void AddLight(LightSource light)
LightSourceParams LightSourceParams
bool IsBackground
Background lights are drawn behind submarines and they don't cast shadows.
bool IsHidden
Is the entity hidden due to HiddenInGame being enabled or the layer the entity is in being hidden?
readonly Identifier Identifier
static readonly PrefabCollection< RuinGenerationParams > RuinParams
override void Update(double deltaTime)
override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
static void DrawFront(SpriteBatch spriteBatch, bool editing=false, Predicate< MapEntity > predicate=null)
static void DrawDamageable(SpriteBatch spriteBatch, Effect damageEffect, bool editing=false, Predicate< MapEntity > predicate=null)
static void Draw(SpriteBatch spriteBatch, bool editing=false)
static Submarine MainSub
Note that this can be null in some situations, e.g. editors and missions that don't load a submarine.
void SetPosition(Vector2 position, List< Submarine > checkd=null, bool forceUndockFromStaticSubmarines=true)