(61d00a474) v0.9.7.1
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BlurEffect
|
||||
{
|
||||
public readonly Effect Effect;
|
||||
|
||||
public BlurEffect(Effect effect, float dx, float dy)
|
||||
{
|
||||
Effect = effect;
|
||||
|
||||
SetParameters(dx, dy);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Computes sample weightings and texture coordinate offsets
|
||||
/// for one pass of a separable gaussian blur filter.
|
||||
/// </summary>
|
||||
public void SetParameters(float dx, float dy)
|
||||
{
|
||||
EffectParameter weightsParameter = Effect.Parameters["SampleWeights"];
|
||||
EffectParameter offsetsParameter = Effect.Parameters["SampleOffsets"];
|
||||
|
||||
// Look up how many samples our gaussian blur effect supports.
|
||||
int sampleCount = weightsParameter.Elements.Count;
|
||||
|
||||
// Create temporary arrays for computing our filter settings.
|
||||
float[] sampleWeights = new float[sampleCount];
|
||||
Vector2[] sampleOffsets = new Vector2[sampleCount];
|
||||
|
||||
sampleWeights[0] = ComputeGaussian(0);
|
||||
sampleOffsets[0] = new Vector2(0);
|
||||
|
||||
float totalWeights = sampleWeights[0];
|
||||
|
||||
// Add pairs of additional sample taps, positioned
|
||||
// along a line in both directions from the center.
|
||||
for (int i = 0; i < sampleCount / 2; i++)
|
||||
{
|
||||
// Store weights for the positive and negative taps.
|
||||
float weight = ComputeGaussian(i + 1);
|
||||
|
||||
sampleWeights[i * 2 + 1] = weight;
|
||||
sampleWeights[i * 2 + 2] = weight;
|
||||
|
||||
totalWeights += weight * 2;
|
||||
|
||||
// To get the maximum amount of blurring from a limited number of
|
||||
// pixel shader samples, we take advantage of the bilinear filtering
|
||||
// hardware inside the texture fetch unit. If we position our texture
|
||||
// coordinates exactly halfway between two texels, the filtering unit
|
||||
// will average them for us, giving two samples for the price of one.
|
||||
// This allows us to step in units of two texels per sample, rather
|
||||
// than just one at a time. The 1.5 offset kicks things off by
|
||||
// positioning us nicely in between two texels.
|
||||
float sampleOffset = i * 2 + 1.5f;
|
||||
|
||||
Vector2 delta = new Vector2(dx, dy) * sampleOffset;
|
||||
|
||||
// Store texture coordinate offsets for the positive and negative taps.
|
||||
sampleOffsets[i * 2 + 1] = delta;
|
||||
sampleOffsets[i * 2 + 2] = -delta;
|
||||
}
|
||||
|
||||
// Normalize the list of sample weightings, so they will always sum to one.
|
||||
for (int i = 0; i < sampleWeights.Length; i++)
|
||||
{
|
||||
sampleWeights[i] /= totalWeights;
|
||||
}
|
||||
|
||||
weightsParameter.SetValue(sampleWeights);
|
||||
offsetsParameter.SetValue(sampleOffsets);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates a single point on the gaussian falloff curve.
|
||||
/// Used for setting up the blur filter weightings.
|
||||
/// </summary>
|
||||
float ComputeGaussian(float n)
|
||||
{
|
||||
float theta = 2.0f;
|
||||
|
||||
return (float)((1.0 / Math.Sqrt(2 * Math.PI * theta)) *
|
||||
Math.Exp(-(n * n) / (2 * theta * theta)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,598 @@
|
||||
using Barotrauma.Tutorials;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class CampaignSetupUI
|
||||
{
|
||||
private GUIComponent newGameContainer, loadGameContainer;
|
||||
|
||||
private GUIListBox subList;
|
||||
private GUIListBox saveList;
|
||||
|
||||
private GUITextBox saveNameBox, seedBox;
|
||||
|
||||
private GUILayoutGroup subPreviewContainer;
|
||||
|
||||
private GUIButton loadGameButton, deleteMpSaveButton;
|
||||
|
||||
public Action<Submarine, string, string> StartNewGame;
|
||||
public Action<string> LoadGame;
|
||||
|
||||
public GUIButton StartButton
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private readonly bool isMultiplayer;
|
||||
|
||||
public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<Submarine> submarines, IEnumerable<string> saveFiles = null)
|
||||
{
|
||||
this.isMultiplayer = isMultiplayer;
|
||||
this.newGameContainer = newGameContainer;
|
||||
this.loadGameContainer = loadGameContainer;
|
||||
|
||||
var columnContainer = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = isMultiplayer ? 0.0f : 0.02f
|
||||
};
|
||||
|
||||
var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.015f
|
||||
};
|
||||
|
||||
var rightColumn = new GUILayoutGroup(new RectTransform(isMultiplayer ? Vector2.Zero : new Vector2(1.5f, 1.0f), columnContainer.RectTransform))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.015f
|
||||
};
|
||||
|
||||
columnContainer.Recalculate();
|
||||
|
||||
// New game left side
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SaveName"), font: GUI.SubHeadingFont);
|
||||
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, string.Empty)
|
||||
{
|
||||
textFilterFunction = (string str) => { return ToolBox.RemoveInvalidFileNameChars(str); }
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUI.SubHeadingFont);
|
||||
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
|
||||
|
||||
if (!isMultiplayer)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SelectedSub"), font: GUI.SubHeadingFont);
|
||||
|
||||
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform)) { ScrollBarVisible = true };
|
||||
|
||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
|
||||
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
||||
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
||||
searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; };
|
||||
|
||||
subList.OnSelected = OnSubSelected;
|
||||
}
|
||||
else // Spacing to fix the multiplayer campaign setup layout
|
||||
{
|
||||
//spacing
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), leftColumn.RectTransform), style: null);
|
||||
}
|
||||
|
||||
// New game right side
|
||||
subPreviewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform))
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.13f),
|
||||
(isMultiplayer ? leftColumn : rightColumn).RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.TopRight);
|
||||
if (!isMultiplayer) { buttonContainer.IgnoreLayoutGroups = true; }
|
||||
|
||||
StartButton = new GUIButton(new RectTransform(isMultiplayer ? new Vector2(0.5f, 1.0f) : Vector2.One,
|
||||
buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) },
|
||||
TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge")
|
||||
{
|
||||
OnClicked = (GUIButton btn, object userData) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(saveNameBox.Text))
|
||||
{
|
||||
saveNameBox.Flash(GUI.Style.Red);
|
||||
return false;
|
||||
}
|
||||
|
||||
Submarine selectedSub = null;
|
||||
|
||||
if (!isMultiplayer)
|
||||
{
|
||||
if (!(subList.SelectedData is Submarine)) { return false; }
|
||||
selectedSub = subList.SelectedData as Submarine;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameMain.NetLobbyScreen.SelectedSub == null) { return false; }
|
||||
selectedSub = GameMain.NetLobbyScreen.SelectedSub;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
|
||||
{
|
||||
((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
|
||||
subList.SelectedComponent.CanBeFocused = false;
|
||||
subList.Deselect();
|
||||
return false;
|
||||
}
|
||||
|
||||
string savePath = SaveUtil.CreateSavePath(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer, saveNameBox.Text);
|
||||
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
|
||||
|
||||
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
|
||||
{
|
||||
if (!hasRequiredContentPackages)
|
||||
{
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
|
||||
TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
|
||||
msgBox.Buttons[0].OnClicked = msgBox.Close;
|
||||
msgBox.Buttons[0].OnClicked += (button, obj) =>
|
||||
{
|
||||
if (GUIMessageBox.MessageBoxes.Count == 0)
|
||||
{
|
||||
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text);
|
||||
if (isMultiplayer)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
}
|
||||
|
||||
if (selectedSub.HasTag(SubmarineTag.Shuttle))
|
||||
{
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("ShuttleSelected"),
|
||||
TextManager.Get("ShuttleWarning"),
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (button, obj) =>
|
||||
{
|
||||
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text);
|
||||
if (isMultiplayer)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text);
|
||||
if (isMultiplayer)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (!isMultiplayer)
|
||||
{
|
||||
var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point(5) }, style: "GUINotificationButton")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
OnClicked = (btn, userdata) => { GameMain.Instance.ShowCampaignDisclaimer(); return true; }
|
||||
};
|
||||
disclaimerBtn.RectTransform.MaxSize = new Point((int)(30 * GUI.Scale));
|
||||
}
|
||||
|
||||
columnContainer.Recalculate();
|
||||
leftColumn.Recalculate();
|
||||
rightColumn.Recalculate();
|
||||
|
||||
if (submarines != null) { UpdateSubList(submarines); }
|
||||
UpdateLoadMenu(saveFiles);
|
||||
}
|
||||
|
||||
public void RandomizeSeed()
|
||||
{
|
||||
seedBox.Text = ToolBox.RandomSeed(8);
|
||||
}
|
||||
|
||||
private void FilterSubs(GUIListBox subList, string filter)
|
||||
{
|
||||
foreach (GUIComponent child in subList.Content.Children)
|
||||
{
|
||||
var sub = child.UserData as Submarine;
|
||||
if (sub == null) { return; }
|
||||
child.Visible = string.IsNullOrEmpty(filter) ? true : sub.DisplayName.ToLower().Contains(filter.ToLower());
|
||||
}
|
||||
}
|
||||
|
||||
private bool OnSubSelected(GUIComponent component, object obj)
|
||||
{
|
||||
if (subPreviewContainer == null) { return false; }
|
||||
(subPreviewContainer.Parent as GUILayoutGroup)?.Recalculate();
|
||||
subPreviewContainer.ClearChildren();
|
||||
|
||||
Submarine sub = obj as Submarine;
|
||||
if (sub == null) { return true; }
|
||||
|
||||
sub.CreatePreviewWindow(subPreviewContainer);
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerable<object> WaitForCampaignSetup()
|
||||
{
|
||||
GUI.SetCursorWaiting();
|
||||
string headerText = TextManager.Get("CampaignStartingPleaseWait");
|
||||
var msgBox = new GUIMessageBox(headerText, TextManager.Get("CampaignStarting"), new string[] { TextManager.Get("Cancel") });
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
GameMain.NetLobbyScreen.HighlightMode(GameMain.NetLobbyScreen.SelectedModeIndex);
|
||||
GameMain.NetLobbyScreen.SelectMode(GameMain.NetLobbyScreen.SelectedModeIndex);
|
||||
GUI.ClearCursorWait();
|
||||
CoroutineManager.StopCoroutines("WaitForCampaignSetup");
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
|
||||
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
|
||||
while (GameMain.NetLobbyScreen.CampaignUI == null && DateTime.Now < timeOut)
|
||||
{
|
||||
msgBox.Header.Text = headerText + new string('.', ((int)Timing.TotalTime % 3 + 1));
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
msgBox.Close();
|
||||
GUI.ClearCursorWait();
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void CreateDefaultSaveName()
|
||||
{
|
||||
string savePath = SaveUtil.CreateSavePath(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer);
|
||||
saveNameBox.Text = Path.GetFileNameWithoutExtension(savePath);
|
||||
}
|
||||
|
||||
public void UpdateSubList(IEnumerable<Submarine> submarines)
|
||||
{
|
||||
#if !DEBUG
|
||||
var subsToShow = submarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus));
|
||||
#else
|
||||
var subsToShow = submarines;
|
||||
#endif
|
||||
|
||||
subList.ClearChildren();
|
||||
|
||||
foreach (Submarine sub in subsToShow)
|
||||
{
|
||||
var textBlock = new GUITextBlock(
|
||||
new RectTransform(new Vector2(1, 0.1f), subList.Content.RectTransform) { MinSize = new Point(0, 30) },
|
||||
ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Rect.Width - 65), style: "ListBoxElement")
|
||||
{
|
||||
ToolTip = sub.Description,
|
||||
UserData = sub
|
||||
};
|
||||
|
||||
if(!sub.RequiredContentPackagesInstalled)
|
||||
{
|
||||
textBlock.TextColor = Color.Lerp(textBlock.TextColor, Color.DarkRed, .5f);
|
||||
textBlock.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + textBlock.RawToolTip;
|
||||
}
|
||||
|
||||
if (sub.HasTag(SubmarineTag.Shuttle))
|
||||
{
|
||||
textBlock.TextColor = textBlock.TextColor * 0.85f;
|
||||
|
||||
var shuttleText = new GUITextBlock(new RectTransform(new Point(100, textBlock.Rect.Height), textBlock.RectTransform, Anchor.CenterRight)
|
||||
{
|
||||
IsFixedSize = false
|
||||
},
|
||||
TextManager.Get("Shuttle", fallBackTag: "RespawnShuttle"), textAlignment: Alignment.Right, font: GUI.SmallFont)
|
||||
{
|
||||
TextColor = textBlock.TextColor * 0.8f,
|
||||
ToolTip = textBlock.RawToolTip
|
||||
};
|
||||
}
|
||||
}
|
||||
if (Submarine.SavedSubmarines.Any())
|
||||
{
|
||||
var nonShuttles = subsToShow.Where(s => !s.HasTag(SubmarineTag.Shuttle)).ToList();
|
||||
if (nonShuttles.Count > 0)
|
||||
{
|
||||
subList.Select(nonShuttles[Rand.Int(nonShuttles.Count)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> prevSaveFiles;
|
||||
public void UpdateLoadMenu(IEnumerable<string> saveFiles = null)
|
||||
{
|
||||
prevSaveFiles?.Clear();
|
||||
loadGameContainer.ClearChildren();
|
||||
|
||||
if (saveFiles == null)
|
||||
{
|
||||
saveFiles = SaveUtil.GetSaveFiles(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer);
|
||||
}
|
||||
|
||||
var leftColumn = new GUILayoutGroup(new RectTransform(isMultiplayer ? new Vector2(1.0f, 0.85f) : new Vector2(0.5f, 1.0f), loadGameContainer.RectTransform), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.03f
|
||||
};
|
||||
|
||||
saveList = new GUIListBox(new RectTransform(Vector2.One, leftColumn.RectTransform))
|
||||
{
|
||||
OnSelected = SelectSaveFile
|
||||
};
|
||||
|
||||
if (!isMultiplayer)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(0.6f, 0.08f), leftColumn.RectTransform), TextManager.Get("showinfolder"))
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ToolBox.OpenFileWithShell(SaveUtil.SaveFolder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("error"),
|
||||
TextManager.GetWithVariables("showinfoldererror", new string[] { "[folder]", "[errormessage]" }, new string[] { SaveUtil.SaveFolder, e.Message }));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
foreach (string saveFile in saveFiles)
|
||||
{
|
||||
string fileName = saveFile;
|
||||
string subName = "";
|
||||
string saveTime = "";
|
||||
string contentPackageStr = "";
|
||||
var saveFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), saveList.Content.RectTransform) { MinSize = new Point(0, 45) }, style: "ListBoxElement")
|
||||
{
|
||||
UserData = saveFile
|
||||
};
|
||||
|
||||
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform), "")
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
if (!isMultiplayer)
|
||||
{
|
||||
nameText.Text = Path.GetFileNameWithoutExtension(saveFile);
|
||||
XDocument doc = SaveUtil.LoadGameSessionDoc(saveFile);
|
||||
if (doc.Root.GetChildElement("multiplayercampaign") != null)
|
||||
{
|
||||
//multiplayer campaign save in the wrong folder -> don't show the save
|
||||
saveList.Content.RemoveChild(saveFrame);
|
||||
continue;
|
||||
}
|
||||
if (doc?.Root == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error loading save file \"" + saveFile + "\". The file may be corrupted.");
|
||||
nameText.TextColor = GUI.Style.Red;
|
||||
continue;
|
||||
}
|
||||
subName = doc.Root.GetAttributeString("submarine", "");
|
||||
saveTime = doc.Root.GetAttributeString("savetime", "");
|
||||
contentPackageStr = doc.Root.GetAttributeString("selectedcontentpackages", "");
|
||||
|
||||
prevSaveFiles?.Add(saveFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] splitSaveFile = saveFile.Split(';');
|
||||
saveFrame.UserData = splitSaveFile[0];
|
||||
fileName = nameText.Text = Path.GetFileNameWithoutExtension(splitSaveFile[0]);
|
||||
prevSaveFiles?.Add(fileName);
|
||||
if (splitSaveFile.Length > 1) { subName = splitSaveFile[1]; }
|
||||
if (splitSaveFile.Length > 2) { saveTime = splitSaveFile[2]; }
|
||||
if (splitSaveFile.Length > 3) { contentPackageStr = splitSaveFile[3]; }
|
||||
}
|
||||
if (!string.IsNullOrEmpty(saveTime) && long.TryParse(saveTime, out long unixTime))
|
||||
{
|
||||
DateTime time = ToolBox.Epoch.ToDateTime(unixTime);
|
||||
saveTime = time.ToString();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(contentPackageStr))
|
||||
{
|
||||
List<string> contentPackagePaths = contentPackageStr.Split('|').ToList();
|
||||
if (!GameSession.IsCompatibleWithSelectedContentPackages(contentPackagePaths, out string errorMsg))
|
||||
{
|
||||
nameText.TextColor = GUI.Style.Red;
|
||||
saveFrame.ToolTip = string.Join("\n", errorMsg, TextManager.Get("campaignmode.contentpackagemismatchwarning"));
|
||||
}
|
||||
}
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform, Anchor.BottomLeft),
|
||||
text: subName, font: GUI.SmallFont)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
UserData = fileName
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), saveFrame.RectTransform),
|
||||
text: saveTime, textAlignment: Alignment.Right, font: GUI.SmallFont)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
UserData = fileName
|
||||
};
|
||||
}
|
||||
|
||||
saveList.Content.RectTransform.SortChildren((c1, c2) =>
|
||||
{
|
||||
string file1 = c1.GUIComponent.UserData as string;
|
||||
string file2 = c2.GUIComponent.UserData as string;
|
||||
DateTime file1WriteTime = DateTime.MinValue;
|
||||
DateTime file2WriteTime = DateTime.MinValue;
|
||||
try
|
||||
{
|
||||
file1WriteTime = File.GetLastWriteTime(file1);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//do nothing - DateTime.MinValue will be used and the element will get sorted at the bottom of the list
|
||||
};
|
||||
try
|
||||
{
|
||||
file2WriteTime = File.GetLastWriteTime(file2);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//do nothing - DateTime.MinValue will be used and the element will get sorted at the bottom of the list
|
||||
};
|
||||
return file2WriteTime.CompareTo(file1WriteTime);
|
||||
});
|
||||
|
||||
loadGameButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomRight), TextManager.Get("LoadButton"))
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(saveList.SelectedData as string)) { return false; }
|
||||
LoadGame?.Invoke(saveList.SelectedData as string);
|
||||
if (isMultiplayer)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||
}
|
||||
return true;
|
||||
},
|
||||
Enabled = false
|
||||
};
|
||||
deleteMpSaveButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomLeft),
|
||||
TextManager.Get("Delete"), style: "GUIButtonSmall")
|
||||
{
|
||||
OnClicked = DeleteSave,
|
||||
Visible = false
|
||||
};
|
||||
}
|
||||
|
||||
private bool SelectSaveFile(GUIComponent component, object obj)
|
||||
{
|
||||
string fileName = (string)obj;
|
||||
|
||||
if (isMultiplayer)
|
||||
{
|
||||
loadGameButton.Enabled = true;
|
||||
deleteMpSaveButton.Visible = deleteMpSaveButton.Enabled = GameMain.Client.IsServerOwner;
|
||||
deleteMpSaveButton.Enabled = GameMain.GameSession?.SavePath != fileName;
|
||||
if (deleteMpSaveButton.Visible)
|
||||
{
|
||||
deleteMpSaveButton.UserData = obj as string;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
XDocument doc = SaveUtil.LoadGameSessionDoc(fileName);
|
||||
if (doc == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error loading save file \"" + fileName + "\". The file may be corrupted.");
|
||||
return false;
|
||||
}
|
||||
|
||||
loadGameButton.Enabled = true;
|
||||
|
||||
RemoveSaveFrame();
|
||||
|
||||
string subName = doc.Root.GetAttributeString("submarine", "");
|
||||
string saveTime = doc.Root.GetAttributeString("savetime", "unknown");
|
||||
if (long.TryParse(saveTime, out long unixTime))
|
||||
{
|
||||
DateTime time = ToolBox.Epoch.ToDateTime(unixTime);
|
||||
saveTime = time.ToString();
|
||||
}
|
||||
|
||||
string mapseed = doc.Root.GetAttributeString("mapseed", "unknown");
|
||||
|
||||
var saveFileFrame = new GUIFrame(new RectTransform(new Vector2(0.45f, 0.6f), loadGameContainer.RectTransform, Anchor.TopRight)
|
||||
{
|
||||
RelativeOffset = new Vector2(0.0f, 0.1f)
|
||||
}, style: "InnerFrame")
|
||||
{
|
||||
UserData = "savefileframe"
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0.2f), saveFileFrame.RectTransform, Anchor.TopCenter)
|
||||
{
|
||||
RelativeOffset = new Vector2(0, 0.05f)
|
||||
},
|
||||
Path.GetFileNameWithoutExtension(fileName), font: GUI.LargeFont, textAlignment: Alignment.Center);
|
||||
|
||||
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.5f), saveFileFrame.RectTransform, Anchor.Center)
|
||||
{
|
||||
RelativeOffset = new Vector2(0, 0.1f)
|
||||
});
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), $"{TextManager.Get("Submarine")} : {subName}", font: GUI.SmallFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), $"{TextManager.Get("LastSaved")} : {saveTime}", font: GUI.SmallFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), $"{TextManager.Get("MapSeed")} : {mapseed}", font: GUI.SmallFont);
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.4f, 0.15f), saveFileFrame.RectTransform, Anchor.BottomCenter)
|
||||
{
|
||||
RelativeOffset = new Vector2(0, 0.1f)
|
||||
}, TextManager.Get("Delete"), style: "GUIButtonSmall")
|
||||
{
|
||||
UserData = fileName,
|
||||
OnClicked = DeleteSave
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DeleteSave(GUIButton button, object obj)
|
||||
{
|
||||
string saveFile = obj as string;
|
||||
if (obj == null) { return false; }
|
||||
|
||||
SaveUtil.DeleteSave(saveFile);
|
||||
prevSaveFiles?.Remove(saveFile);
|
||||
UpdateLoadMenu(prevSaveFiles);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RemoveSaveFrame()
|
||||
{
|
||||
GUIComponent prevFrame = null;
|
||||
foreach (GUIComponent child in loadGameContainer.Children)
|
||||
{
|
||||
if (child.UserData as string != "savefileframe") continue;
|
||||
|
||||
prevFrame = child;
|
||||
break;
|
||||
}
|
||||
loadGameContainer.RemoveChild(prevFrame);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+5482
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class CreditsPlayer : GUIComponent
|
||||
{
|
||||
private GUIListBox listBox;
|
||||
|
||||
private XElement configElement;
|
||||
|
||||
private float scrollSpeed;
|
||||
|
||||
public CreditsPlayer(RectTransform rectT, string configFile) : base(null, rectT)
|
||||
{
|
||||
GameMain.Instance.OnResolutionChanged += () => { ClearChildren(); Load(); };
|
||||
|
||||
var doc = XMLExtensions.TryLoadXml(configFile);
|
||||
if (doc == null) { return; }
|
||||
configElement = doc.Root;
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
scrollSpeed = configElement.GetAttributeFloat("scrollspeed", 100.0f);
|
||||
int spacing = configElement.GetAttributeInt("spacing", 0);
|
||||
|
||||
listBox = new GUIListBox(new RectTransform(Vector2.One, RectTransform), style: null)
|
||||
{
|
||||
Spacing = spacing
|
||||
};
|
||||
|
||||
foreach (XElement subElement in configElement.Elements())
|
||||
{
|
||||
GUIComponent.FromXML(subElement, listBox.Content.RectTransform);
|
||||
}
|
||||
foreach (GUIComponent child in listBox.Content.Children)
|
||||
{
|
||||
child.CanBeFocused = false;
|
||||
}
|
||||
|
||||
listBox.RecalculateChildren();
|
||||
listBox.UpdateScrollBarSize();
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
listBox.BarScroll = 0.0f;
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
listBox.BarScroll += scrollSpeed / listBox.TotalSize * deltaTime;
|
||||
|
||||
if (listBox.BarScroll >= 1.0f)
|
||||
{
|
||||
listBox.BarScroll = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using FarseerPhysics;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class GameScreen : Screen
|
||||
{
|
||||
private RenderTarget2D renderTargetBackground;
|
||||
private RenderTarget2D renderTarget;
|
||||
private RenderTarget2D renderTargetWater;
|
||||
private RenderTarget2D renderTargetFinal;
|
||||
|
||||
private Effect damageEffect;
|
||||
private Texture2D damageStencil;
|
||||
private Texture2D distortTexture;
|
||||
|
||||
public Effect PostProcessEffect { get; private set; }
|
||||
public Effect GradientEffect { get; private set; }
|
||||
|
||||
public GameScreen(GraphicsDevice graphics, ContentManager content)
|
||||
{
|
||||
cam = new Camera();
|
||||
cam.Translate(new Vector2(-10.0f, 50.0f));
|
||||
|
||||
CreateRenderTargets(graphics);
|
||||
GameMain.Instance.OnResolutionChanged += () =>
|
||||
{
|
||||
CreateRenderTargets(graphics);
|
||||
};
|
||||
|
||||
#if LINUX || OSX
|
||||
//var blurEffect = content.Load<Effect>("Effects/blurshader_opengl");
|
||||
damageEffect = content.Load<Effect>("Effects/damageshader_opengl");
|
||||
PostProcessEffect = content.Load<Effect>("Effects/postprocess_opengl");
|
||||
GradientEffect = content.Load<Effect>("Effects/gradientshader_opengl");
|
||||
#else
|
||||
//var blurEffect = content.Load<Effect>("Effects/blurshader");
|
||||
damageEffect = content.Load<Effect>("Effects/damageshader");
|
||||
PostProcessEffect = content.Load<Effect>("Effects/postprocess");
|
||||
GradientEffect = content.Load<Effect>("Effects/gradientshader");
|
||||
#endif
|
||||
|
||||
damageStencil = TextureLoader.FromFile("Content/Map/walldamage.png");
|
||||
damageEffect.Parameters["xStencil"].SetValue(damageStencil);
|
||||
damageEffect.Parameters["aMultiplier"].SetValue(50.0f);
|
||||
damageEffect.Parameters["cMultiplier"].SetValue(200.0f);
|
||||
|
||||
distortTexture = TextureLoader.FromFile("Content/Effects/distortnormals.png");
|
||||
PostProcessEffect.Parameters["xDistortTexture"].SetValue(distortTexture);
|
||||
}
|
||||
|
||||
private void CreateRenderTargets(GraphicsDevice graphics)
|
||||
{
|
||||
renderTarget?.Dispose();
|
||||
renderTargetBackground?.Dispose();
|
||||
renderTargetWater?.Dispose();
|
||||
renderTargetFinal?.Dispose();
|
||||
renderTarget = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight, false, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
|
||||
renderTargetBackground = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
renderTargetWater = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
renderTargetFinal = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight, false, SurfaceFormat.Color, DepthFormat.None);
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null && Character.Controlled.CanInteractWith(Character.Controlled.SelectedConstruction))
|
||||
{
|
||||
Character.Controlled.SelectedConstruction.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null) GameMain.GameSession.AddToGUIUpdateList();
|
||||
|
||||
Character.AddAllToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||
{
|
||||
cam.UpdateTransform(true);
|
||||
Submarine.CullEntities(cam);
|
||||
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
c.AnimController.Limbs.ForEach(l => l.body.UpdateDrawPosition());
|
||||
bool wasVisible = c.IsVisible;
|
||||
c.DoVisibilityCheck(cam);
|
||||
if (c.IsVisible != wasVisible)
|
||||
{
|
||||
c.AnimController.Limbs.ForEach(l =>
|
||||
{
|
||||
if (l.LightSource != null)
|
||||
{
|
||||
l.LightSource.Enabled = c.IsVisible;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
DrawMap(graphics, spriteBatch, deltaTime);
|
||||
|
||||
sw.Stop();
|
||||
GameMain.PerformanceCounter.AddElapsedTicks("DrawMap", sw.ElapsedTicks);
|
||||
sw.Restart();
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
|
||||
|
||||
if (Character.Controlled != null && cam != null) Character.Controlled.DrawHUD(spriteBatch, cam);
|
||||
|
||||
if (GameMain.GameSession != null) GameMain.GameSession.Draw(spriteBatch);
|
||||
|
||||
if (Character.Controlled == null && !GUI.DisableHUD)
|
||||
{
|
||||
for (int i = 0; i < Submarine.MainSubs.Length; i++)
|
||||
{
|
||||
if (Submarine.MainSubs[i] == null) continue;
|
||||
if (Level.Loaded != null && Submarine.MainSubs[i].WorldPosition.Y < Level.MaxEntityDepth) continue;
|
||||
|
||||
Color indicatorColor = i == 0 ? Color.LightBlue * 0.5f : GUI.Style.Red * 0.5f;
|
||||
GUI.DrawIndicator(
|
||||
spriteBatch, Submarine.MainSubs[i].WorldPosition, cam,
|
||||
Math.Max(Submarine.MainSub.Borders.Width, Submarine.MainSub.Borders.Height),
|
||||
GUI.SubmarineIcon, indicatorColor);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Draw(cam, spriteBatch);
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
sw.Stop();
|
||||
GameMain.PerformanceCounter.AddElapsedTicks("DrawHUD", sw.ElapsedTicks);
|
||||
sw.Restart();
|
||||
}
|
||||
|
||||
public void DrawMap(GraphicsDevice graphics, SpriteBatch spriteBatch, double deltaTime)
|
||||
{
|
||||
foreach (Submarine sub in Submarine.Loaded)
|
||||
{
|
||||
sub.UpdateTransform();
|
||||
}
|
||||
|
||||
GameMain.ParticleManager.UpdateTransforms();
|
||||
|
||||
GameMain.LightManager.ObstructVision = Character.Controlled != null && Character.Controlled.ObstructVision;
|
||||
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
GameMain.LightManager.UpdateObstructVision(graphics, spriteBatch, cam, Character.Controlled.CursorWorldPosition);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
graphics.SetRenderTarget(renderTarget);
|
||||
graphics.Clear(Color.Transparent);
|
||||
//Draw background structures and wall background sprites
|
||||
//(= the background texture that's revealed when a wall is destroyed) into the background render target
|
||||
//These will be visible through the LOS effect.
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
Submarine.DrawBack(spriteBatch, false, e => e is Structure s && (e.SpriteDepth >= 0.9f || s.Prefab.BackgroundSprite != null));
|
||||
spriteBatch.End();
|
||||
|
||||
graphics.SetRenderTarget(null);
|
||||
GameMain.LightManager.UpdateLightMap(graphics, spriteBatch, cam, renderTarget);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
graphics.SetRenderTarget(renderTargetBackground);
|
||||
if (Level.Loaded == null)
|
||||
{
|
||||
graphics.Clear(new Color(11, 18, 26, 255));
|
||||
}
|
||||
else
|
||||
{
|
||||
//graphics.Clear(new Color(255, 255, 255, 255));
|
||||
Level.Loaded.DrawBack(graphics, spriteBatch, cam);
|
||||
}
|
||||
|
||||
//draw alpha blended particles that are in water and behind subs
|
||||
#if LINUX || OSX
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
#else
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
#endif
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.AlphaBlend);
|
||||
spriteBatch.End();
|
||||
|
||||
//draw additive particles that are in water and behind subs
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.Additive);
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None);
|
||||
spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
spriteBatch.End();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//Start drawing to the normal render target (stuff that can't be seen through the LOS effect)
|
||||
graphics.SetRenderTarget(renderTarget);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, null);
|
||||
spriteBatch.Draw(renderTargetBackground, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
spriteBatch.End();
|
||||
//Draw the rest of the structures, characters and front structures
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
Submarine.DrawBack(spriteBatch, false, e => !(e is Structure) || e.SpriteDepth < 0.9f);
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (!c.IsVisible || c.AnimController.Limbs.Any(l => l.DeformSprite != null)) { continue; }
|
||||
c.Draw(spriteBatch, Cam);
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
//draw characters with deformable limbs last, because they can't be batched into SpriteBatch
|
||||
//pretty hacky way of preventing draw order issues between normal and deformable sprites
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
//backwards order to render the most recently spawned characters in front (characters spawned later have a larger sprite depth)
|
||||
for (int i = Character.CharacterList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Character c = Character.CharacterList[i];
|
||||
if (!c.IsVisible || c.AnimController.Limbs.All(l => l.DeformSprite == null)) { continue; }
|
||||
c.Draw(spriteBatch, Cam);
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
//draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
|
||||
graphics.SetRenderTarget(renderTargetWater);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque);
|
||||
spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);// waterColor);
|
||||
spriteBatch.End();
|
||||
|
||||
//draw alpha blended particles that are inside a sub
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform);
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.AlphaBlend);
|
||||
spriteBatch.End();
|
||||
|
||||
graphics.SetRenderTarget(renderTarget);
|
||||
|
||||
//draw alpha blended particles that are not in water
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform);
|
||||
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.AlphaBlend);
|
||||
spriteBatch.End();
|
||||
|
||||
//draw additive particles that are not in water
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
|
||||
spriteBatch.End();
|
||||
|
||||
graphics.DepthStencilState = DepthStencilState.DepthRead;
|
||||
graphics.SetRenderTarget(renderTargetFinal);
|
||||
|
||||
WaterRenderer.Instance.ResetBuffers();
|
||||
Hull.UpdateVertices(graphics, cam, WaterRenderer.Instance);
|
||||
WaterRenderer.Instance.RenderWater(spriteBatch, renderTargetWater, cam);
|
||||
WaterRenderer.Instance.RenderAir(graphics, cam, renderTarget, Cam.ShaderTransform);
|
||||
graphics.DepthStencilState = DepthStencilState.None;
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Immediate,
|
||||
BlendState.NonPremultiplied, SamplerState.LinearWrap,
|
||||
null, null,
|
||||
damageEffect,
|
||||
cam.Transform);
|
||||
Submarine.DrawDamageable(spriteBatch, damageEffect, false);
|
||||
spriteBatch.End();
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
Submarine.DrawFront(spriteBatch, false, null);
|
||||
spriteBatch.End();
|
||||
|
||||
//draw additive particles that are inside a sub
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.Default, null, null, cam.Transform);
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.Additive);
|
||||
foreach (var discharger in Items.Components.ElectricalDischarger.List)
|
||||
{
|
||||
discharger.DrawElectricity(spriteBatch);
|
||||
}
|
||||
spriteBatch.End();
|
||||
if (GameMain.LightManager.LightingEnabled)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, Lights.CustomBlendStates.Multiplicative, null, DepthStencilState.None, null, null, null);
|
||||
spriteBatch.Draw(GameMain.LightManager.LightMap, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.None, null, null, cam.Transform);
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
c.DrawFront(spriteBatch, cam);
|
||||
}
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
Level.Loaded.DrawFront(spriteBatch, cam);
|
||||
}
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
MapEntity.mapEntityList.ForEach(me => me.AiTarget?.Draw(spriteBatch));
|
||||
Character.CharacterList.ForEach(c => c.AiTarget?.Draw(spriteBatch));
|
||||
if (GameMain.GameSession?.EventManager != null)
|
||||
{
|
||||
GameMain.GameSession.EventManager.DebugDraw(spriteBatch);
|
||||
}
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
if (GameMain.LightManager.LosEnabled && GameMain.LightManager.LosMode != LosMode.None && Character.Controlled != null)
|
||||
{
|
||||
GameMain.LightManager.LosEffect.CurrentTechnique = GameMain.LightManager.LosEffect.Techniques["LosShader"];
|
||||
|
||||
GameMain.LightManager.LosEffect.Parameters["xTexture"].SetValue(renderTargetBackground);
|
||||
GameMain.LightManager.LosEffect.Parameters["xLosTexture"].SetValue(GameMain.LightManager.LosTexture);
|
||||
|
||||
Color losColor;
|
||||
if (GameMain.LightManager.LosMode == LosMode.Transparent)
|
||||
{
|
||||
//convert the los color to HLS and make sure the luminance of the color is always the same
|
||||
//as the luminance of the ambient light color
|
||||
float r = Character.Controlled?.CharacterHealth == null ?
|
||||
0.0f : Math.Min(Character.Controlled.CharacterHealth.DamageOverlayTimer * 0.5f, 0.5f);
|
||||
Vector3 ambientLightHls = GameMain.LightManager.AmbientLight.RgbToHLS();
|
||||
Vector3 losColorHls = Color.Lerp(GameMain.LightManager.AmbientLight, Color.Red, r).RgbToHLS();
|
||||
losColorHls.Y = ambientLightHls.Y;
|
||||
losColor = ToolBox.HLSToRGB(losColorHls);
|
||||
}
|
||||
else
|
||||
{
|
||||
losColor = Color.Black;
|
||||
}
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, GameMain.LightManager.LosEffect, null);
|
||||
spriteBatch.Draw(renderTargetBackground, new Rectangle(0, 0, spriteBatch.GraphicsDevice.Viewport.Width, spriteBatch.GraphicsDevice.Viewport.Height), losColor);
|
||||
spriteBatch.End();
|
||||
}
|
||||
graphics.SetRenderTarget(null);
|
||||
|
||||
float BlurStrength = 0.0f;
|
||||
float DistortStrength = 0.0f;
|
||||
Vector3 chromaticAberrationStrength = GameMain.Config.ChromaticAberrationEnabled ?
|
||||
new Vector3(-0.02f, -0.01f, 0.0f) : Vector3.Zero;
|
||||
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
BlurStrength = Character.Controlled.BlurStrength * 0.005f;
|
||||
DistortStrength = Character.Controlled.DistortStrength;
|
||||
chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength;
|
||||
chromaticAberrationStrength += new Vector3(-0.03f, -0.015f, 0.0f) * Character.Controlled.ChromaticAberrationStrength;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlurStrength = 0.0f;
|
||||
DistortStrength = 0.0f;
|
||||
}
|
||||
|
||||
string postProcessTechnique = "";
|
||||
if (BlurStrength > 0.0f)
|
||||
{
|
||||
postProcessTechnique += "Blur";
|
||||
PostProcessEffect.Parameters["blurDistance"].SetValue(BlurStrength);
|
||||
}
|
||||
if (chromaticAberrationStrength != Vector3.Zero)
|
||||
{
|
||||
postProcessTechnique += "ChromaticAberration";
|
||||
PostProcessEffect.Parameters["chromaticAberrationStrength"].SetValue(chromaticAberrationStrength);
|
||||
}
|
||||
if (DistortStrength > 0.0f)
|
||||
{
|
||||
postProcessTechnique += "Distort";
|
||||
PostProcessEffect.Parameters["distortScale"].SetValue(Vector2.One * DistortStrength);
|
||||
PostProcessEffect.Parameters["distortUvOffset"].SetValue(WaterRenderer.Instance.WavePos * 0.001f);
|
||||
#if LINUX || OSX
|
||||
PostProcessEffect.Parameters["xTexture"].SetValue(distortTexture);
|
||||
#else
|
||||
PostProcessEffect.Parameters["xTexture"].SetValue(renderTargetFinal);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(postProcessTechnique))
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
PostProcessEffect.CurrentTechnique = PostProcessEffect.Techniques[postProcessTechnique];
|
||||
PostProcessEffect.CurrentTechnique.Passes[0].Apply();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, effect: PostProcessEffect);
|
||||
}
|
||||
#if LINUX || OSX
|
||||
spriteBatch.Draw(renderTargetFinal, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
#else
|
||||
spriteBatch.Draw(DistortStrength > 0.0f ? distortTexture : renderTargetFinal, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
#endif
|
||||
spriteBatch.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,721 @@
|
||||
using Barotrauma.Lights;
|
||||
using Barotrauma.RuinGeneration;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class LevelEditorScreen : Screen
|
||||
{
|
||||
private readonly Camera cam;
|
||||
public override Camera Cam
|
||||
{
|
||||
get { return cam; }
|
||||
}
|
||||
|
||||
private GUIFrame leftPanel, rightPanel, bottomPanel, topPanel;
|
||||
|
||||
private LevelGenerationParams selectedParams;
|
||||
private LevelObjectPrefab selectedLevelObject;
|
||||
|
||||
private GUIListBox paramsList, ruinParamsList, levelObjectList;
|
||||
private GUIListBox editorContainer;
|
||||
|
||||
private GUIButton spriteEditDoneButton;
|
||||
|
||||
private GUITextBox seedBox;
|
||||
|
||||
private GUITickBox lightingEnabled, cursorLightEnabled;
|
||||
|
||||
private Sprite editingSprite;
|
||||
|
||||
private LightSource pointerLightSource;
|
||||
|
||||
public LevelEditorScreen()
|
||||
{
|
||||
cam = new Camera()
|
||||
{
|
||||
MinZoom = 0.01f,
|
||||
MaxZoom = 1.0f
|
||||
};
|
||||
|
||||
leftPanel = new GUIFrame(new RectTransform(new Vector2(0.125f, 0.8f), Frame.RectTransform) { MinSize = new Point(150, 0) });
|
||||
var paddedLeftPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), leftPanel.RectTransform, Anchor.CenterLeft) { RelativeOffset = new Vector2(0.02f, 0.0f) })
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
|
||||
paramsList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.3f), paddedLeftPanel.RectTransform));
|
||||
paramsList.OnSelected += (GUIComponent component, object obj) =>
|
||||
{
|
||||
selectedParams = obj as LevelGenerationParams;
|
||||
editorContainer.ClearChildren();
|
||||
SortLevelObjectsList(selectedParams);
|
||||
new SerializableEntityEditor(editorContainer.Content.RectTransform, selectedParams, false, true, elementHeight: 20);
|
||||
return true;
|
||||
};
|
||||
|
||||
ruinParamsList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), paddedLeftPanel.RectTransform));
|
||||
ruinParamsList.OnSelected += (GUIComponent component, object obj) =>
|
||||
{
|
||||
var ruinGenerationParams = obj as RuinGenerationParams;
|
||||
editorContainer.ClearChildren();
|
||||
new SerializableEntityEditor(editorContainer.Content.RectTransform, ruinGenerationParams, false, true, elementHeight: 20);
|
||||
return true;
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
|
||||
TextManager.Get("leveleditor.createlevelobj"))
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
Wizard.Instance.Create();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
lightingEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform),
|
||||
TextManager.Get("leveleditor.lightingenabled"));
|
||||
|
||||
cursorLightEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform),
|
||||
TextManager.Get("leveleditor.cursorlightenabled"));
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
|
||||
TextManager.Get("leveleditor.reloadtextures"))
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
Level.Loaded?.ReloadTextures();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
|
||||
TextManager.Get("editor.saveall"))
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
SerializeAll();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
rightPanel = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), Frame.RectTransform, Anchor.TopRight) { MinSize = new Point(450, 0) });
|
||||
var paddedRightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), rightPanel.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.02f, 0.0f) })
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
|
||||
editorContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), paddedRightPanel.RectTransform));
|
||||
|
||||
var seedContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform), isHorizontal: true);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), TextManager.Get("leveleditor.levelseed"));
|
||||
seedBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), ToolBox.RandomSeed(8));
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
|
||||
TextManager.Get("leveleditor.generate"))
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
Submarine.Unload();
|
||||
GameMain.LightManager.ClearLights();
|
||||
Level.CreateRandom(seedBox.Text, generationParams: selectedParams).Generate(mirror: false);
|
||||
GameMain.LightManager.AddLight(pointerLightSource);
|
||||
cam.Position = new Vector2(Level.Loaded.Size.X / 2, Level.Loaded.Size.Y / 2);
|
||||
foreach (GUITextBlock param in paramsList.Content.Children)
|
||||
{
|
||||
param.TextColor = param.UserData == selectedParams ? GUI.Style.Green : param.Style.TextColor;
|
||||
}
|
||||
seedBox.Deselect();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bottomPanel = new GUIFrame(new RectTransform(new Vector2(0.75f, 0.22f), Frame.RectTransform, Anchor.BottomLeft)
|
||||
{ MaxSize = new Point(GameMain.GraphicsWidth - rightPanel.Rect.Width, 1000) }, style: "GUIFrameBottom");
|
||||
|
||||
levelObjectList = new GUIListBox(new RectTransform(new Vector2(0.99f, 0.85f), bottomPanel.RectTransform, Anchor.Center))
|
||||
{
|
||||
UseGridLayout = true
|
||||
};
|
||||
levelObjectList.OnSelected += (GUIComponent component, object obj) =>
|
||||
{
|
||||
selectedLevelObject = obj as LevelObjectPrefab;
|
||||
CreateLevelObjectEditor(selectedLevelObject);
|
||||
return true;
|
||||
};
|
||||
|
||||
spriteEditDoneButton = new GUIButton(new RectTransform(new Point(200, 30), anchor: Anchor.BottomRight) { AbsoluteOffset = new Point(20, 20) },
|
||||
TextManager.Get("leveleditor.spriteeditdone"))
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
editingSprite = null;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
topPanel = new GUIFrame(new RectTransform(new Point(400, 100), GUI.Canvas)
|
||||
{ RelativeOffset = new Vector2(leftPanel.RectTransform.RelativeSize.X * 2, 0.0f) }, style: "GUIFrameTop");
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
|
||||
foreach (LevelObjectPrefab levelObjPrefab in LevelObjectPrefab.List)
|
||||
{
|
||||
foreach (Sprite sprite in levelObjPrefab.Sprites)
|
||||
{
|
||||
sprite?.EnsureLazyLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
pointerLightSource = new LightSource(Vector2.Zero, 1000.0f, Color.White, submarine: null);
|
||||
GameMain.LightManager.AddLight(pointerLightSource);
|
||||
topPanel.ClearChildren();
|
||||
new SerializableEntityEditor(topPanel.RectTransform, pointerLightSource.LightSourceParams, false, true);
|
||||
|
||||
editingSprite = null;
|
||||
UpdateParamsList();
|
||||
UpdateRuinParamsList();
|
||||
UpdateLevelObjectsList();
|
||||
}
|
||||
|
||||
public override void Deselect()
|
||||
{
|
||||
base.Deselect();
|
||||
pointerLightSource?.Remove();
|
||||
pointerLightSource = null;
|
||||
}
|
||||
|
||||
private void UpdateParamsList()
|
||||
{
|
||||
editorContainer.ClearChildren();
|
||||
paramsList.Content.ClearChildren();
|
||||
|
||||
foreach (LevelGenerationParams genParams in LevelGenerationParams.LevelParams)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paramsList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
genParams.Name)
|
||||
{
|
||||
Padding = Vector4.Zero,
|
||||
UserData = genParams
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRuinParamsList()
|
||||
{
|
||||
editorContainer.ClearChildren();
|
||||
ruinParamsList.Content.ClearChildren();
|
||||
|
||||
foreach (RuinGenerationParams genParams in RuinGenerationParams.List)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), ruinParamsList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
genParams.Name)
|
||||
{
|
||||
Padding = Vector4.Zero,
|
||||
UserData = genParams
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLevelObjectsList()
|
||||
{
|
||||
editorContainer.ClearChildren();
|
||||
levelObjectList.Content.ClearChildren();
|
||||
|
||||
int objectsPerRow = (int)Math.Ceiling(levelObjectList.Content.Rect.Width / Math.Max(100 * GUI.Scale, 100));
|
||||
float relWidth = 1.0f / objectsPerRow;
|
||||
|
||||
foreach (LevelObjectPrefab levelObjPrefab in LevelObjectPrefab.List)
|
||||
{
|
||||
var frame = new GUIFrame(new RectTransform(
|
||||
new Vector2(relWidth, relWidth * ((float)levelObjectList.Content.Rect.Width / levelObjectList.Content.Rect.Height)),
|
||||
levelObjectList.Content.RectTransform) { MinSize = new Point(0, 60) }, style: "ListBoxElementSquare")
|
||||
{
|
||||
UserData = levelObjPrefab
|
||||
};
|
||||
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), frame.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform, Anchor.BottomCenter),
|
||||
text: ToolBox.LimitString(levelObjPrefab.Name, GUI.SmallFont, paddedFrame.Rect.Width), textAlignment: Alignment.Center, font: GUI.SmallFont)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
};
|
||||
|
||||
Sprite sprite = levelObjPrefab.Sprites.FirstOrDefault() ?? levelObjPrefab.DeformableSprite?.Sprite;
|
||||
GUIImage img = new GUIImage(new RectTransform(new Point(paddedFrame.Rect.Height, paddedFrame.Rect.Height - textBlock.Rect.Height),
|
||||
paddedFrame.RectTransform, Anchor.TopCenter), sprite, scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateLevelObjectEditor(LevelObjectPrefab levelObjectPrefab)
|
||||
{
|
||||
editorContainer.ClearChildren();
|
||||
|
||||
var editor = new SerializableEntityEditor(editorContainer.Content.RectTransform, levelObjectPrefab, false, true, elementHeight: 20, titleFont: GUI.LargeFont);
|
||||
|
||||
if (selectedParams != null)
|
||||
{
|
||||
var commonnessContainer = new GUILayoutGroup(new RectTransform(new Point(editor.Rect.Width, 70)) { IsFixedSize = true },
|
||||
isHorizontal: false, childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = 5,
|
||||
Stretch = true
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), commonnessContainer.RectTransform),
|
||||
TextManager.GetWithVariable("leveleditor.levelobjcommonness", "[leveltype]", selectedParams.Name), textAlignment: Alignment.Center);
|
||||
new GUINumberInput(new RectTransform(new Vector2(0.5f, 0.4f), commonnessContainer.RectTransform), GUINumberInput.NumberType.Float)
|
||||
{
|
||||
MinValueFloat = 0,
|
||||
MaxValueFloat = 100,
|
||||
FloatValue = levelObjectPrefab.GetCommonness(selectedParams.Name),
|
||||
OnValueChanged = (numberInput) =>
|
||||
{
|
||||
levelObjectPrefab.OverrideCommonness[selectedParams.Name] = numberInput.FloatValue;
|
||||
}
|
||||
};
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), commonnessContainer.RectTransform), style: null);
|
||||
editor.AddCustomContent(commonnessContainer, 1);
|
||||
}
|
||||
|
||||
Sprite sprite = levelObjectPrefab.Sprites.FirstOrDefault() ?? levelObjectPrefab.DeformableSprite?.Sprite;
|
||||
if (sprite != null)
|
||||
{
|
||||
editor.AddCustomContent(new GUIButton(new RectTransform(new Point(editor.Rect.Width / 2, (int)(25 * GUI.Scale))) { IsFixedSize = true },
|
||||
TextManager.Get("leveleditor.editsprite"))
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
editingSprite = sprite;
|
||||
GameMain.SpriteEditorScreen.SelectSprite(editingSprite);
|
||||
return true;
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
if (levelObjectPrefab.DeformableSprite != null)
|
||||
{
|
||||
var deformEditor = levelObjectPrefab.DeformableSprite.CreateEditor(editor, levelObjectPrefab.SpriteDeformations, levelObjectPrefab.Name);
|
||||
deformEditor.GetChild<GUIDropDown>().OnSelected += (selected, userdata) =>
|
||||
{
|
||||
CreateLevelObjectEditor(selectedLevelObject);
|
||||
return true;
|
||||
};
|
||||
editor.AddCustomContent(deformEditor, editor.ContentCount);
|
||||
}
|
||||
//child object editing
|
||||
new GUITextBlock(new RectTransform(new Point(editor.Rect.Width, 40), editorContainer.Content.RectTransform),
|
||||
TextManager.Get("leveleditor.childobjects"), font: GUI.SubHeadingFont, textAlignment: Alignment.BottomCenter);
|
||||
foreach (LevelObjectPrefab.ChildObject childObj in levelObjectPrefab.ChildObjects)
|
||||
{
|
||||
var childObjFrame = new GUIFrame(new RectTransform(new Point(editor.Rect.Width, 30)));
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), childObjFrame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
var selectedChildObj = childObj;
|
||||
var dropdown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1.0f), paddedFrame.RectTransform), elementCount: 10, selectMultiple: true);
|
||||
foreach (LevelObjectPrefab objPrefab in LevelObjectPrefab.List)
|
||||
{
|
||||
dropdown.AddItem(objPrefab.Name, objPrefab);
|
||||
if (childObj.AllowedNames.Contains(objPrefab.Name)) dropdown.SelectItem(objPrefab);
|
||||
}
|
||||
dropdown.OnSelected = (selected, obj) =>
|
||||
{
|
||||
childObj.AllowedNames = dropdown.SelectedDataMultiple.Select(d => ((LevelObjectPrefab)d).Name).ToList();
|
||||
return true;
|
||||
};
|
||||
new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), paddedFrame.RectTransform), GUINumberInput.NumberType.Int)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueInt = 10,
|
||||
OnValueChanged = (numberInput) =>
|
||||
{
|
||||
selectedChildObj.MinCount = numberInput.IntValue;
|
||||
selectedChildObj.MaxCount = Math.Max(selectedChildObj.MaxCount, selectedChildObj.MinCount);
|
||||
}
|
||||
}.IntValue = childObj.MinCount;
|
||||
new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), paddedFrame.RectTransform), GUINumberInput.NumberType.Int)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueInt = 10,
|
||||
OnValueChanged = (numberInput) =>
|
||||
{
|
||||
selectedChildObj.MaxCount = numberInput.IntValue;
|
||||
selectedChildObj.MinCount = Math.Min(selectedChildObj.MaxCount, selectedChildObj.MinCount);
|
||||
}
|
||||
}.IntValue = childObj.MaxCount;
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), paddedFrame.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUICancelButton")
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
selectedLevelObject.ChildObjects.Remove(selectedChildObj);
|
||||
CreateLevelObjectEditor(selectedLevelObject);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
childObjFrame.RectTransform.Parent = editorContainer.Content.RectTransform;
|
||||
}
|
||||
|
||||
var buttonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), editorContainer.Content.RectTransform), style: null);
|
||||
new GUIButton(new RectTransform(new Point(editor.Rect.Width / 2, 20), buttonContainer.RectTransform, Anchor.Center),
|
||||
TextManager.Get("leveleditor.addchildobject"))
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
selectedLevelObject.ChildObjects.Add(new LevelObjectPrefab.ChildObject());
|
||||
CreateLevelObjectEditor(selectedLevelObject);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
buttonContainer.RectTransform.MinSize = buttonContainer.RectTransform.Children.First().MinSize;
|
||||
|
||||
//light editing
|
||||
new GUITextBlock(new RectTransform(new Point(editor.Rect.Width, 40), editorContainer.Content.RectTransform),
|
||||
TextManager.Get("leveleditor.lightsources"), textAlignment: Alignment.BottomCenter, font: GUI.SubHeadingFont);
|
||||
foreach (LightSourceParams lightSourceParams in selectedLevelObject.LightSourceParams)
|
||||
{
|
||||
new SerializableEntityEditor(editorContainer.Content.RectTransform, lightSourceParams, inGame: false, showName: true);
|
||||
}
|
||||
buttonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), editorContainer.Content.RectTransform), style: null);
|
||||
new GUIButton(new RectTransform(new Point(editor.Rect.Width / 2, 20), buttonContainer.RectTransform, Anchor.Center),
|
||||
TextManager.Get("leveleditor.addlightsource"))
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
selectedLevelObject.LightSourceTriggerIndex.Add(-1);
|
||||
selectedLevelObject.LightSourceParams.Add(new LightSourceParams(100.0f, Color.White));
|
||||
CreateLevelObjectEditor(selectedLevelObject);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
buttonContainer.RectTransform.MinSize = buttonContainer.RectTransform.Children.First().MinSize;
|
||||
}
|
||||
|
||||
private void SortLevelObjectsList(LevelGenerationParams selectedParams)
|
||||
{
|
||||
//fade out levelobjects that don't spawn in this type of level
|
||||
foreach (GUIComponent levelObjFrame in levelObjectList.Content.Children)
|
||||
{
|
||||
var levelObj = levelObjFrame.UserData as LevelObjectPrefab;
|
||||
float commonness = levelObj.GetCommonness(selectedParams.Name);
|
||||
levelObjFrame.Color = commonness > 0.0f ? GUI.Style.Green * 0.4f : Color.Transparent;
|
||||
levelObjFrame.SelectedColor = commonness > 0.0f ? GUI.Style.Green * 0.6f : Color.White * 0.5f;
|
||||
levelObjFrame.HoverColor = commonness > 0.0f ? GUI.Style.Green * 0.7f : Color.White * 0.6f;
|
||||
|
||||
levelObjFrame.GetAnyChild<GUIImage>().Color = commonness > 0.0f ? Color.White : Color.DarkGray;
|
||||
if (commonness <= 0.0f)
|
||||
{
|
||||
levelObjFrame.GetAnyChild<GUITextBlock>().TextColor = Color.DarkGray;
|
||||
}
|
||||
}
|
||||
|
||||
//sort the levelobjects according to commonness in this level
|
||||
levelObjectList.Content.RectTransform.SortChildren((c1, c2) =>
|
||||
{
|
||||
var levelObj1 = c1.GUIComponent.UserData as LevelObjectPrefab;
|
||||
var levelObj2 = c2.GUIComponent.UserData as LevelObjectPrefab;
|
||||
return Math.Sign(levelObj2.GetCommonness(selectedParams.Name) - levelObj1.GetCommonness(selectedParams.Name));
|
||||
});
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
base.AddToGUIUpdateList();
|
||||
rightPanel.Visible = leftPanel.Visible = bottomPanel.Visible = editingSprite == null;
|
||||
if (editingSprite != null)
|
||||
{
|
||||
GameMain.SpriteEditorScreen.TopPanel.AddToGUIUpdateList();
|
||||
spriteEditDoneButton.AddToGUIUpdateList();
|
||||
}
|
||||
else if (lightingEnabled.Selected && cursorLightEnabled.Selected)
|
||||
{
|
||||
topPanel.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||
{
|
||||
if (lightingEnabled.Selected)
|
||||
{
|
||||
GameMain.LightManager.UpdateLightMap(graphics, spriteBatch, cam);
|
||||
}
|
||||
graphics.Clear(Color.Black);
|
||||
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
Level.Loaded.DrawBack(graphics, spriteBatch, cam);
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.DepthRead, transformMatrix: cam.Transform);
|
||||
Level.Loaded.DrawFront(spriteBatch, cam);
|
||||
Submarine.Draw(spriteBatch, false);
|
||||
Submarine.DrawFront(spriteBatch);
|
||||
Submarine.DrawDamageable(spriteBatch, null);
|
||||
spriteBatch.End();
|
||||
|
||||
if (lightingEnabled.Selected)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Immediate, Lights.CustomBlendStates.Multiplicative, null, DepthStencilState.None, null, null, null);
|
||||
spriteBatch.Draw(GameMain.LightManager.LightMap, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
spriteBatch.End();
|
||||
}
|
||||
}
|
||||
|
||||
if (editingSprite != null)
|
||||
{
|
||||
GameMain.SpriteEditorScreen.Draw(deltaTime, graphics, spriteBatch);
|
||||
}
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
pointerLightSource.Position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
pointerLightSource.Enabled = cursorLightEnabled.Selected;
|
||||
pointerLightSource.IsBackground = true;
|
||||
cam.MoveCamera((float)deltaTime);
|
||||
cam.UpdateTransform();
|
||||
Level.Loaded?.Update((float)deltaTime, cam);
|
||||
|
||||
if (editingSprite != null)
|
||||
{
|
||||
GameMain.SpriteEditorScreen.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void SerializeAll()
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.LevelGenerationParameters))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
||||
if (doc == null) { continue; }
|
||||
|
||||
foreach (LevelGenerationParams genParams in LevelGenerationParams.LevelParams)
|
||||
{
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
XElement levelParamElement = element;
|
||||
if (element.IsOverride())
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().Equals(genParams.Name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
SerializableProperty.SerializeProperties(genParams, subElement, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (element.Name.ToString().Equals(genParams.Name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
SerializableProperty.SerializeProperties(genParams, element, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
using (var writer = XmlWriter.Create(configFile.Path, settings))
|
||||
{
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
settings.NewLineOnAttributes = false;
|
||||
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.LevelObjectPrefabs))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
||||
if (doc == null) { continue; }
|
||||
|
||||
foreach (LevelObjectPrefab levelObjPrefab in LevelObjectPrefab.List)
|
||||
{
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
if (!element.Name.ToString().Equals(levelObjPrefab.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
levelObjPrefab.Save(element);
|
||||
break;
|
||||
}
|
||||
}
|
||||
using (var writer = XmlWriter.Create(configFile.Path, settings))
|
||||
{
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
RuinGenerationParams.SaveAll();
|
||||
}
|
||||
|
||||
private void Serialize(LevelGenerationParams genParams)
|
||||
{
|
||||
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.LevelGenerationParameters))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
||||
if (doc == null) { continue; }
|
||||
|
||||
bool elementFound = false;
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
if (!element.Name.ToString().Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
SerializableProperty.SerializeProperties(genParams, element, true);
|
||||
elementFound = true;
|
||||
}
|
||||
|
||||
if (elementFound)
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
using (var writer = XmlWriter.Create(configFile.Path, settings))
|
||||
{
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region LevelObject Wizard
|
||||
private class Wizard
|
||||
{
|
||||
private LevelObjectPrefab newPrefab;
|
||||
|
||||
private static Wizard instance;
|
||||
public static Wizard Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new Wizard();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddToGUIUpdateList()
|
||||
{
|
||||
//activeView?.Box.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public GUIMessageBox Create()
|
||||
{
|
||||
var box = new GUIMessageBox(TextManager.Get("leveleditor.createlevelobj"), string.Empty,
|
||||
new string[] { TextManager.Get("cancel"), TextManager.Get("done") }, new Vector2(0.5f, 0.8f));
|
||||
|
||||
box.Content.ChildAnchor = Anchor.TopCenter;
|
||||
box.Content.AbsoluteSpacing = 20;
|
||||
int elementSize = 30;
|
||||
var listBox = new GUIListBox(new RectTransform(new Vector2(1, 0.9f), box.Content.RectTransform));
|
||||
|
||||
new GUITextBlock(new RectTransform(new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform),
|
||||
TextManager.Get("leveleditor.levelobjname")) { CanBeFocused = false };
|
||||
var nameBox = new GUITextBox(new RectTransform(new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform));
|
||||
|
||||
new GUITextBlock(new RectTransform(new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform),
|
||||
TextManager.Get("leveleditor.levelobjtexturepath")) { CanBeFocused = false };
|
||||
var texturePathBox = new GUITextBox(new RectTransform(new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform));
|
||||
foreach (LevelObjectPrefab prefab in LevelObjectPrefab.List)
|
||||
{
|
||||
if (prefab.Sprites.FirstOrDefault() == null) continue;
|
||||
texturePathBox.Text = Path.GetDirectoryName(prefab.Sprites.FirstOrDefault().FilePath);
|
||||
break;
|
||||
}
|
||||
|
||||
newPrefab = new LevelObjectPrefab(null);
|
||||
|
||||
new SerializableEntityEditor(listBox.Content.RectTransform, newPrefab, false, false);
|
||||
|
||||
box.Buttons[0].OnClicked += (b, d) =>
|
||||
{
|
||||
box.Close();
|
||||
return true;
|
||||
};
|
||||
// Next
|
||||
box.Buttons[1].OnClicked += (b, d) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(nameBox.Text))
|
||||
{
|
||||
nameBox.Flash(GUI.Style.Red);
|
||||
GUI.AddMessage(TextManager.Get("leveleditor.levelobjnameempty"), GUI.Style.Red);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LevelObjectPrefab.List.Any(obj => obj.Name.ToLower() == nameBox.Text.ToLower()))
|
||||
{
|
||||
nameBox.Flash(GUI.Style.Red);
|
||||
GUI.AddMessage(TextManager.Get("leveleditor.levelobjnametaken"), GUI.Style.Red);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File.Exists(texturePathBox.Text))
|
||||
{
|
||||
texturePathBox.Flash(GUI.Style.Red);
|
||||
GUI.AddMessage(TextManager.Get("leveleditor.levelobjtexturenotfound"), GUI.Style.Red);
|
||||
return false;
|
||||
}
|
||||
|
||||
newPrefab.Name = nameBox.Text;
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings { Indent = true };
|
||||
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.LevelObjectPrefabs))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
||||
if (doc == null) { continue; }
|
||||
var newElement = new XElement(newPrefab.Name);
|
||||
newPrefab.Save(newElement);
|
||||
newElement.Add(new XElement("Sprite",
|
||||
new XAttribute("texture", texturePathBox.Text),
|
||||
new XAttribute("sourcerect", "0,0,100,100"),
|
||||
new XAttribute("origin", "0.5,0.5")));
|
||||
|
||||
doc.Root.Add(newElement);
|
||||
using (var writer = XmlWriter.Create(configFile.Path, settings))
|
||||
{
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
// Recreate the prefab so that the sprite loads correctly: TODO: consider a better way to do this
|
||||
newPrefab = new LevelObjectPrefab(newElement);
|
||||
break;
|
||||
}
|
||||
|
||||
LevelObjectPrefab.List.Add(newPrefab);
|
||||
GameMain.LevelEditorScreen.UpdateLevelObjectsList();
|
||||
|
||||
box.Close();
|
||||
return true;
|
||||
};
|
||||
return box;
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class LobbyScreen : Screen
|
||||
{
|
||||
private CampaignUI campaignUI;
|
||||
|
||||
private GUIFrame campaignUIContainer;
|
||||
|
||||
private CrewManager CrewManager
|
||||
{
|
||||
get { return GameMain.GameSession.CrewManager; }
|
||||
}
|
||||
|
||||
public CampaignUI CampaignUI
|
||||
{
|
||||
get { return campaignUI; }
|
||||
}
|
||||
|
||||
public string GetMoney()
|
||||
{
|
||||
return campaignUI == null ? "" : campaignUI.GetMoney();
|
||||
}
|
||||
|
||||
public LobbyScreen()
|
||||
{
|
||||
campaignUIContainer = new GUIFrame(new RectTransform(Vector2.One, Frame.RectTransform, Anchor.Center), style: null);
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
|
||||
CampaignMode campaign = GameMain.GameSession.GameMode as CampaignMode;
|
||||
if (campaign == null) { return; }
|
||||
|
||||
campaign.Map.SelectLocation(-1);
|
||||
|
||||
campaignUIContainer.ClearChildren();
|
||||
campaignUI = new CampaignUI(campaign, campaignUIContainer)
|
||||
{
|
||||
StartRound = StartRound,
|
||||
OnLocationSelected = SelectLocation
|
||||
};
|
||||
campaignUI.UpdateCharacterLists();
|
||||
|
||||
GameAnalyticsManager.SetCustomDimension01("singleplayer");
|
||||
}
|
||||
|
||||
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||
{
|
||||
graphics.Clear(Color.Black);
|
||||
|
||||
GUI.DrawBackgroundSprite(spriteBatch,
|
||||
GameMain.GameSession.Map.CurrentLocation.Type.GetPortrait(GameMain.GameSession.Map.CurrentLocation.PortraitId));
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
public void SelectLocation(Location location, LocationConnection locationConnection)
|
||||
{
|
||||
}
|
||||
|
||||
private void StartRound()
|
||||
{
|
||||
if (GameMain.GameSession.Map.SelectedConnection == null) return;
|
||||
|
||||
GameMain.Instance.ShowLoading(LoadRound());
|
||||
}
|
||||
|
||||
private IEnumerable<object> LoadRound()
|
||||
{
|
||||
GameMain.GameSession.StartRound(campaignUI.SelectedLevel,
|
||||
reloadSub: true,
|
||||
mirrorLevel: GameMain.GameSession.Map.CurrentLocation != GameMain.GameSession.Map.SelectedConnection.Locations[0]);
|
||||
GameMain.GameScreen.Select();
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public bool QuitToMainMenu(GUIButton button, object selection)
|
||||
{
|
||||
GameMain.MainMenuScreen.Select();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,358 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Particles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml;
|
||||
using System.Text;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class ParticleEditorScreen : Screen
|
||||
{
|
||||
class Emitter : ISerializableEntity
|
||||
{
|
||||
public float EmitTimer;
|
||||
|
||||
public float BurstTimer;
|
||||
|
||||
[Editable(), Serialize("0.0,360.0", false)]
|
||||
public Vector2 AngleRange { get; private set; }
|
||||
|
||||
[Editable(), Serialize("0.0,0.0", false)]
|
||||
public Vector2 VelocityRange { get; private set; }
|
||||
|
||||
[Editable(), Serialize("1.0,1.0", false)]
|
||||
public Vector2 ScaleRange { get; private set; }
|
||||
|
||||
[Editable(), Serialize(0, false)]
|
||||
public int ParticleBurstAmount { get; private set; }
|
||||
|
||||
[Editable(), Serialize(1.0f, false)]
|
||||
public float ParticleBurstInterval { get; private set; }
|
||||
|
||||
[Editable(), Serialize(1.0f, false)]
|
||||
public float ParticlesPerSecond { get; private set; }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return TextManager.Get("particleeditor.emitter");
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Emitter()
|
||||
{
|
||||
ScaleRange = Vector2.One;
|
||||
AngleRange = new Vector2(0.0f, 360.0f);
|
||||
ParticleBurstAmount = 1;
|
||||
ParticleBurstInterval = 1.0f;
|
||||
|
||||
SerializableProperties = SerializableProperty.GetProperties(this);
|
||||
}
|
||||
}
|
||||
|
||||
private GUIComponent rightPanel, leftPanel;
|
||||
private GUIListBox prefabList;
|
||||
private GUITextBox filterBox;
|
||||
private GUITextBlock filterLabel;
|
||||
|
||||
private ParticlePrefab selectedPrefab;
|
||||
|
||||
private Emitter emitter;
|
||||
|
||||
private readonly Camera cam;
|
||||
|
||||
public override Camera Cam
|
||||
{
|
||||
get
|
||||
{
|
||||
return cam;
|
||||
}
|
||||
}
|
||||
|
||||
public ParticleEditorScreen()
|
||||
{
|
||||
cam = new Camera();
|
||||
GameMain.Instance.OnResolutionChanged += CreateUI;
|
||||
CreateUI();
|
||||
|
||||
}
|
||||
|
||||
private void CreateUI()
|
||||
{
|
||||
Frame.ClearChildren();
|
||||
|
||||
leftPanel = new GUIFrame(new RectTransform(new Vector2(0.125f, 1.0f), Frame.RectTransform) { MinSize = new Point(150, 0) },
|
||||
style: "GUIFrameLeft");
|
||||
var paddedLeftPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), leftPanel.RectTransform, Anchor.CenterLeft) { RelativeOffset = new Vector2(0.02f, 0.0f) })
|
||||
{
|
||||
RelativeSpacing = 0.01f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
rightPanel = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), Frame.RectTransform, Anchor.TopRight) { MinSize = new Point(350, 0) },
|
||||
style: "GUIFrameRight");
|
||||
var paddedRightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), rightPanel.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.02f, 0.0f) })
|
||||
{
|
||||
RelativeSpacing = 0.01f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var saveAllButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.03f), paddedRightPanel.RectTransform),
|
||||
TextManager.Get("editor.saveall"))
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
SerializeAll();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var serializeToClipBoardButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.03f), paddedRightPanel.RectTransform),
|
||||
TextManager.Get("editor.copytoclipboard"))
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
SerializeToClipboard(selectedPrefab);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
emitter = new Emitter();
|
||||
var emitterEditorContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), paddedRightPanel.RectTransform), style: null);
|
||||
var emitterEditor = new SerializableEntityEditor(emitterEditorContainer.RectTransform, emitter, false, true, elementHeight: 20, titleFont: GUI.SubHeadingFont);
|
||||
emitterEditor.RectTransform.RelativeSize = Vector2.One;
|
||||
emitterEditorContainer.RectTransform.Resize(new Point(emitterEditorContainer.RectTransform.NonScaledSize.X, emitterEditor.ContentHeight), false);
|
||||
|
||||
var listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.6f), paddedRightPanel.RectTransform));
|
||||
|
||||
var filterArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.03f), paddedLeftPanel.RectTransform) { MinSize = new Point(0, 20) }, isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
UserData = "filterarea"
|
||||
};
|
||||
|
||||
filterLabel = new GUITextBlock(new RectTransform(Vector2.One, filterArea.RectTransform), TextManager.Get("serverlog.filter"), font: GUI.Font) { IgnoreLayoutGroups = true };
|
||||
filterBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1.0f), filterArea.RectTransform), font: GUI.Font);
|
||||
filterBox.OnTextChanged += (textBox, text) => { FilterEmitters(text); return true; };
|
||||
new GUIButton(new RectTransform(new Vector2(0.05f, 1.0f), filterArea.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUICancelButton")
|
||||
{
|
||||
OnClicked = (btn, userdata) => { FilterEmitters(""); filterBox.Text = ""; filterBox.Flash(Color.White); return true; }
|
||||
};
|
||||
|
||||
prefabList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), paddedLeftPanel.RectTransform));
|
||||
prefabList.OnSelected += (GUIComponent component, object obj) =>
|
||||
{
|
||||
selectedPrefab = obj as ParticlePrefab;
|
||||
listBox.ClearChildren();
|
||||
new SerializableEntityEditor(listBox.Content.RectTransform, selectedPrefab, false, true, elementHeight: 20, titleFont: GUI.SubHeadingFont);
|
||||
//listBox.Content.RectTransform.NonScaledSize = particlePrefabEditor.RectTransform.NonScaledSize;
|
||||
//listBox.UpdateScrollBarSize();
|
||||
return true;
|
||||
};
|
||||
|
||||
if (GameMain.ParticleManager != null) { RefreshPrefabList(); }
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
GameMain.ParticleManager.Camera = cam;
|
||||
RefreshPrefabList();
|
||||
}
|
||||
|
||||
public override void Deselect()
|
||||
{
|
||||
base.Deselect();
|
||||
GameMain.ParticleManager.Camera = GameMain.GameScreen.Cam;
|
||||
filterBox.Text = "";
|
||||
}
|
||||
|
||||
private void RefreshPrefabList()
|
||||
{
|
||||
prefabList.ClearChildren();
|
||||
|
||||
var particlePrefabs = GameMain.ParticleManager.GetPrefabList();
|
||||
foreach (ParticlePrefab particlePrefab in particlePrefabs)
|
||||
{
|
||||
var prefabText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), prefabList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
particlePrefab.DisplayName)
|
||||
{
|
||||
Padding = Vector4.Zero,
|
||||
UserData = particlePrefab
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void Emit(Vector2 position)
|
||||
{
|
||||
float angle = MathHelper.ToRadians(Rand.Range(emitter.AngleRange.X, emitter.AngleRange.Y));
|
||||
Vector2 velocity = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * Rand.Range(emitter.VelocityRange.X, emitter.VelocityRange.Y);
|
||||
|
||||
var particle = GameMain.ParticleManager.CreateParticle(selectedPrefab, position, velocity, 0.0f);
|
||||
|
||||
if (particle != null)
|
||||
{
|
||||
particle.Size *= Rand.Range(emitter.ScaleRange.X, emitter.ScaleRange.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private void FilterEmitters(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
filterLabel.Visible = true;
|
||||
prefabList.Content.Children.ForEach(c => c.Visible = true);
|
||||
return;
|
||||
}
|
||||
|
||||
text = text.ToLower();
|
||||
filterLabel.Visible = false;
|
||||
foreach (GUIComponent child in prefabList.Content.Children)
|
||||
{
|
||||
if (!(child is GUITextBlock textBlock)) { continue; }
|
||||
textBlock.Visible = textBlock.Text.ToLower().Contains(text);
|
||||
}
|
||||
}
|
||||
|
||||
private void SerializeAll()
|
||||
{
|
||||
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.Particles))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
||||
if (doc == null) { continue; }
|
||||
|
||||
var prefabList = GameMain.ParticleManager.GetPrefabList();
|
||||
foreach (ParticlePrefab prefab in prefabList)
|
||||
{
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
if (!element.Name.ToString().Equals(prefab.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
SerializableProperty.SerializeProperties(prefab, element, true);
|
||||
}
|
||||
}
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
OmitXmlDeclaration = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
using (var writer = XmlWriter.Create(configFile.Path, settings))
|
||||
{
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SerializeToClipboard(ParticlePrefab prefab)
|
||||
{
|
||||
#if WINDOWS
|
||||
if (prefab == null) return;
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
OmitXmlDeclaration = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
XElement element = new XElement(prefab.Name);
|
||||
SerializableProperty.SerializeProperties(prefab, element, true);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
using (var writer = XmlWriter.Create(sb, settings))
|
||||
{
|
||||
element.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
Clipboard.SetText(sb.ToString());
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
cam.MoveCamera((float)deltaTime, true);
|
||||
|
||||
if (selectedPrefab != null)
|
||||
{
|
||||
emitter.EmitTimer += (float)deltaTime;
|
||||
emitter.BurstTimer += (float)deltaTime;
|
||||
|
||||
|
||||
if (emitter.ParticlesPerSecond > 0)
|
||||
{
|
||||
float emitInterval = 1.0f / emitter.ParticlesPerSecond;
|
||||
while (emitter.EmitTimer > emitInterval)
|
||||
{
|
||||
Emit(Vector2.Zero);
|
||||
emitter.EmitTimer -= emitInterval;
|
||||
}
|
||||
}
|
||||
|
||||
if (emitter.BurstTimer > emitter.ParticleBurstInterval)
|
||||
{
|
||||
for (int i = 0; i < emitter.ParticleBurstAmount; i++)
|
||||
{
|
||||
Emit(Vector2.Zero);
|
||||
}
|
||||
emitter.BurstTimer = 0.0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GameMain.ParticleManager.Update((float)deltaTime);
|
||||
}
|
||||
|
||||
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||
{
|
||||
cam.UpdateTransform();
|
||||
GameMain.ParticleManager.UpdateTransforms();
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred,
|
||||
BlendState.NonPremultiplied,
|
||||
null, null, null, null,
|
||||
cam.Transform);
|
||||
|
||||
graphics.Clear(new Color(0.051f, 0.149f, 0.271f, 1.0f));
|
||||
|
||||
GameMain.ParticleManager.Draw(spriteBatch, false, false, ParticleBlendState.AlphaBlend);
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, false, ParticleBlendState.AlphaBlend);
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred,
|
||||
BlendState.Additive,
|
||||
null, null, null, null,
|
||||
cam.Transform);
|
||||
|
||||
GameMain.ParticleManager.Draw(spriteBatch, false, false, ParticleBlendState.Additive);
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, false, ParticleBlendState.Additive);
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
|
||||
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
|
||||
spriteBatch.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Screen
|
||||
{
|
||||
private GUIFrame frame;
|
||||
public GUIFrame Frame
|
||||
{
|
||||
get
|
||||
{
|
||||
if (frame == null)
|
||||
{
|
||||
frame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// By default, creates a new frame for the screen and adds all elements to the gui update list.
|
||||
/// </summary>
|
||||
public virtual void AddToGUIUpdateList()
|
||||
{
|
||||
Frame.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public virtual void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||
{
|
||||
}
|
||||
|
||||
public void ColorFade(Color from, Color to, float duration)
|
||||
{
|
||||
if (duration <= 0.0f) return;
|
||||
|
||||
CoroutineManager.StartCoroutine(UpdateColorFade(from, to, duration));
|
||||
}
|
||||
|
||||
private IEnumerable<object> UpdateColorFade(Color from, Color to, float duration)
|
||||
{
|
||||
while (Selected != this)
|
||||
{
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
float timer = 0.0f;
|
||||
|
||||
while (timer < duration)
|
||||
{
|
||||
GUI.ScreenOverlayColor = Color.Lerp(from, to, Math.Min(timer / duration, 1.0f));
|
||||
|
||||
timer += CoroutineManager.UnscaledDeltaTime;
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
GUI.ScreenOverlayColor = to;
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user