430 lines
17 KiB
C#
430 lines
17 KiB
C#
using System;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using Subsurface.Networking;
|
|
using System.IO;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Subsurface
|
|
{
|
|
class MainMenuScreen : Screen
|
|
{
|
|
public enum Tabs { NewGame = 1, LoadGame = 2, HostServer = 3 }
|
|
|
|
GUIFrame buttonsTab;
|
|
|
|
private GUIFrame[] menuTabs;
|
|
private GUIListBox mapList;
|
|
|
|
private GUIListBox saveList;
|
|
|
|
private GUITextBox saveNameBox, seedBox;
|
|
|
|
private GUITextBox serverNameBox, portBox, passwordBox, maxPlayersBox;
|
|
private GUITickBox isPublicBox, useUpnpBox;
|
|
|
|
private Game1 game;
|
|
|
|
int selectedTab;
|
|
|
|
public MainMenuScreen(Game1 game)
|
|
{
|
|
menuTabs = new GUIFrame[Enum.GetValues(typeof(Tabs)).Length+1];
|
|
|
|
|
|
|
|
buttonsTab = new GUIFrame(new Rectangle(50, 200, 200, 500), Color.Transparent, Alignment.Left);
|
|
//menuTabs[(int)Tabs.Main].Padding = GUI.style.smallPadding;
|
|
|
|
Rectangle panelRect = new Rectangle(
|
|
Game1.GraphicsWidth / 2 - 250,
|
|
buttonsTab.Rect.Y,
|
|
500, 360);
|
|
|
|
GUIButton button = new GUIButton(new Rectangle(0, 0, 0, 30), "Tutorial", Alignment.CenterX, GUI.Style, buttonsTab);
|
|
button.OnClicked = TutorialButtonClicked;
|
|
|
|
button = new GUIButton(new Rectangle(0, 70, 0, 30), "New Game", Alignment.CenterX, GUI.Style, buttonsTab);
|
|
button.UserData = (int)Tabs.NewGame;
|
|
button.OnClicked = SelectTab;
|
|
|
|
button = new GUIButton(new Rectangle(0, 130, 0, 30), "Load Game", Alignment.CenterX, GUI.Style, buttonsTab);
|
|
button.UserData = (int)Tabs.LoadGame;
|
|
button.OnClicked = SelectTab;
|
|
|
|
button = new GUIButton(new Rectangle(0, 200, 0, 30), "Join Server", Alignment.CenterX, GUI.Style, buttonsTab);
|
|
//button.UserData = (int)Tabs.JoinServer;
|
|
button.OnClicked = JoinServerClicked;
|
|
|
|
button = new GUIButton(new Rectangle(0, 260, 0, 30), "Host Server", Alignment.CenterX, GUI.Style, buttonsTab);
|
|
button.UserData = (int)Tabs.HostServer;
|
|
button.OnClicked = SelectTab;
|
|
|
|
button = new GUIButton(new Rectangle(0, 330, 0, 30), "Quit", Alignment.CenterX, GUI.Style, buttonsTab);
|
|
button.OnClicked = QuitClicked;
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
menuTabs[(int)Tabs.NewGame] = new GUIFrame(panelRect, GUI.Style);
|
|
//menuTabs[(int)Tabs.NewGame].Padding = GUI.style.smallPadding;
|
|
|
|
//new GUITextBlock(new Rectangle(0, -20, 0, 30), "New Game", null, null, Alignment.CenterX, GUI.style, menuTabs[(int)Tabs.NewGame]);
|
|
|
|
new GUITextBlock(new Rectangle(0, 0, 0, 30), "Selected submarine:", null, null, Alignment.Left, GUI.Style, menuTabs[(int)Tabs.NewGame]);
|
|
mapList = new GUIListBox(new Rectangle(0, 30, 200, panelRect.Height-100), GUI.Style, menuTabs[(int)Tabs.NewGame]);
|
|
|
|
foreach (Submarine sub in Submarine.SavedSubmarines)
|
|
{
|
|
GUITextBlock textBlock = new GUITextBlock(
|
|
new Rectangle(0, 0, 0, 25),
|
|
sub.Name,
|
|
GUI.Style,
|
|
Alignment.Left, Alignment.Left, mapList);
|
|
textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f);
|
|
textBlock.UserData = sub;
|
|
}
|
|
if (Submarine.SavedSubmarines.Count > 0) mapList.Select(Submarine.SavedSubmarines[0]);
|
|
|
|
new GUITextBlock(new Rectangle((int)(mapList.Rect.Width + 20), 0, 100, 20),
|
|
"Save name: ", GUI.Style, Alignment.Left, Alignment.Left, menuTabs[(int)Tabs.NewGame]);
|
|
|
|
saveNameBox = new GUITextBox(new Rectangle((int)(mapList.Rect.Width + 20), 30, 180, 20),
|
|
Alignment.TopLeft, GUI.Style, menuTabs[(int)Tabs.NewGame]);
|
|
saveNameBox.Text = SaveUtil.CreateSavePath();
|
|
|
|
new GUITextBlock(new Rectangle((int)(mapList.Rect.Width + 20), 60, 100, 20),
|
|
"Map Seed: ", GUI.Style, Alignment.Left, Alignment.Left, menuTabs[(int)Tabs.NewGame]);
|
|
|
|
seedBox = new GUITextBox(new Rectangle((int)(mapList.Rect.Width + 20), 90, 180, 20),
|
|
Alignment.TopLeft, GUI.Style, menuTabs[(int)Tabs.NewGame]);
|
|
seedBox.Text = ToolBox.RandomSeed(8);
|
|
|
|
|
|
button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.BottomRight, GUI.Style, menuTabs[(int)Tabs.NewGame]);
|
|
button.OnClicked = StartGame;
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
menuTabs[(int)Tabs.LoadGame] = new GUIFrame(panelRect, GUI.Style);
|
|
//menuTabs[(int)Tabs.LoadGame].Padding = GUI.style.smallPadding;
|
|
|
|
|
|
menuTabs[(int)Tabs.HostServer] = new GUIFrame(panelRect, GUI.Style);
|
|
//menuTabs[(int)Tabs.JoinServer].Padding = GUI.style.smallPadding;
|
|
|
|
//new GUITextBlock(new Rectangle(0, -25, 0, 30), "Host Server", GUI.style, Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.HostServer], false, GUI.LargeFont);
|
|
|
|
new GUITextBlock(new Rectangle(0, 0, 0, 30), "Server Name:", GUI.Style, Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tabs.HostServer]);
|
|
serverNameBox = new GUITextBox(new Rectangle(160, 0, 200, 30), null, null, Alignment.TopLeft, Alignment.Left, GUI.Style, menuTabs[(int)Tabs.HostServer]);
|
|
|
|
new GUITextBlock(new Rectangle(0, 50, 0, 30), "Server port:", GUI.Style, Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tabs.HostServer]);
|
|
portBox = new GUITextBox(new Rectangle(160, 50, 200, 30), null, null, Alignment.TopLeft, Alignment.Left, GUI.Style, menuTabs[(int)Tabs.HostServer]);
|
|
portBox.Text = NetConfig.DefaultPort.ToString();
|
|
portBox.ToolTip = "Server port";
|
|
|
|
new GUITextBlock(new Rectangle(0, 100, 100, 30), "Max players:", GUI.Style, Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tabs.HostServer]);
|
|
maxPlayersBox = new GUITextBox(new Rectangle(195, 100, 30, 30), null, null, Alignment.TopLeft, Alignment.Center, GUI.Style, menuTabs[(int)Tabs.HostServer]);
|
|
maxPlayersBox.Text = "8";
|
|
maxPlayersBox.Enabled = false;
|
|
|
|
var plusPlayersBox = new GUIButton(new Rectangle(230, 100, 30, 30), "+", GUI.Style, menuTabs[(int)Tabs.HostServer]);
|
|
plusPlayersBox.UserData = 1;
|
|
plusPlayersBox.OnClicked = ChangeMaxPlayers;
|
|
|
|
var minusPlayersBox = new GUIButton(new Rectangle(160, 100, 30, 30), "-", GUI.Style, menuTabs[(int)Tabs.HostServer]);
|
|
minusPlayersBox.UserData = -1;
|
|
minusPlayersBox.OnClicked = ChangeMaxPlayers;
|
|
|
|
new GUITextBlock(new Rectangle(0, 150, 0, 30), "Password (optional):", GUI.Style, Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tabs.HostServer]);
|
|
passwordBox = new GUITextBox(new Rectangle(160, 170, 200, 30), null, null, Alignment.TopLeft, Alignment.Left, GUI.Style, menuTabs[(int)Tabs.HostServer]);
|
|
|
|
isPublicBox = new GUITickBox(new Rectangle(10, 200, 20, 20), "Public server", Alignment.TopLeft, menuTabs[(int)Tabs.HostServer]);
|
|
isPublicBox.ToolTip = "Public servers are shown in the list of available servers in the ''Join Server'' -tab";
|
|
|
|
|
|
useUpnpBox = new GUITickBox(new Rectangle(10, 250, 20, 20), "Attempt UPnP port forwarding", Alignment.TopLeft, menuTabs[(int)Tabs.HostServer]);
|
|
useUpnpBox.ToolTip = "UPnP can be used for forwarding ports on your router to allow players join the server."
|
|
+ " However, UPnP isn't supported by all routers, so you may need to setup port forwards manually"
|
|
+" if players are unable to join the server (see the readme for instructions).";
|
|
|
|
GUIButton hostButton = new GUIButton(new Rectangle(0, 0, 200, 30), "Start", Alignment.BottomRight, GUI.Style, menuTabs[(int)Tabs.HostServer]);
|
|
hostButton.OnClicked = HostServerClicked;
|
|
|
|
this.game = game;
|
|
}
|
|
|
|
public override void Select()
|
|
{
|
|
base.Select();
|
|
|
|
selectedTab = 0;
|
|
}
|
|
|
|
public bool SelectTab(GUIButton button, object obj)
|
|
{
|
|
selectedTab = (int)obj;
|
|
|
|
if (button != null) button.Selected = true;
|
|
|
|
foreach (GUIComponent child in buttonsTab.children)
|
|
{
|
|
GUIButton otherButton = child as GUIButton;
|
|
if (otherButton == null || otherButton == button) continue;
|
|
|
|
otherButton.Selected = false;
|
|
}
|
|
|
|
if (selectedTab == (int)Tabs.LoadGame) UpdateLoadScreen();
|
|
|
|
if (Selected != this) this.Select();
|
|
return true;
|
|
}
|
|
|
|
private bool TutorialButtonClicked(GUIButton button, object obj)
|
|
{
|
|
TutorialMode.Start();
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool JoinServerClicked(GUIButton button, object obj)
|
|
{
|
|
Game1.ServerListScreen.Select();
|
|
return true;
|
|
}
|
|
|
|
private bool ChangeMaxPlayers(GUIButton button, object obj)
|
|
{
|
|
int currMaxPlayers = 10;
|
|
|
|
int.TryParse(maxPlayersBox.Text, out currMaxPlayers);
|
|
currMaxPlayers = (int)MathHelper.Clamp(currMaxPlayers+(int)button.UserData, 1, 10);
|
|
|
|
maxPlayersBox.Text = currMaxPlayers.ToString();
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool HostServerClicked(GUIButton button, object obj)
|
|
{
|
|
string name = serverNameBox.Text;
|
|
if (string.IsNullOrEmpty(name))
|
|
{
|
|
serverNameBox.Flash();
|
|
return false;
|
|
}
|
|
|
|
int port;
|
|
if (!int.TryParse(portBox.Text, out port) || port < 0 || port > 65535)
|
|
{
|
|
portBox.Text = NetConfig.DefaultPort.ToString();
|
|
portBox.Flash();
|
|
|
|
return false;
|
|
}
|
|
|
|
Game1.NetworkMember = new GameServer(name, port, isPublicBox.Selected, passwordBox.Text, useUpnpBox.Selected, int.Parse(maxPlayersBox.Text));
|
|
|
|
Game1.NetLobbyScreen.IsServer = true;
|
|
//Game1.NetLobbyScreen.Select();
|
|
return true;
|
|
}
|
|
|
|
private bool QuitClicked(GUIButton button, object obj)
|
|
{
|
|
game.Exit();
|
|
return true;
|
|
}
|
|
|
|
private void UpdateLoadScreen()
|
|
{
|
|
menuTabs[(int)Tabs.LoadGame].ClearChildren();
|
|
|
|
string[] saveFiles = SaveUtil.GetSaveFiles();
|
|
|
|
saveList = new GUIListBox(new Rectangle(0, 0, 200, menuTabs[(int)Tabs.LoadGame].Rect.Height - 80), Color.White, GUI.Style, menuTabs[(int)Tabs.LoadGame]);
|
|
saveList.OnSelected = SelectSaveFile;
|
|
|
|
foreach (string saveFile in saveFiles)
|
|
{
|
|
GUITextBlock textBlock = new GUITextBlock(
|
|
new Rectangle(0, 0, 0, 25),
|
|
saveFile,
|
|
GUI.Style,
|
|
Alignment.Left,
|
|
Alignment.Left,
|
|
saveList);
|
|
textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f);
|
|
textBlock.UserData = saveFile;
|
|
}
|
|
|
|
var button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.Right | Alignment.Bottom, GUI.Style, menuTabs[(int)Tabs.LoadGame]);
|
|
button.OnClicked = LoadGame;
|
|
|
|
}
|
|
|
|
private bool SelectSaveFile(GUIComponent component, object obj)
|
|
{
|
|
string fileName = (string)obj;
|
|
|
|
XDocument doc = SaveUtil.LoadGameSessionDoc(fileName);
|
|
|
|
if (doc==null)
|
|
{
|
|
DebugConsole.ThrowError("Error loading save file ''"+fileName+"''. The file may be corrupted.");
|
|
return false;
|
|
}
|
|
|
|
RemoveSaveFrame();
|
|
|
|
string saveTime = ToolBox.GetAttributeString(doc.Root, "savetime", "unknown");
|
|
|
|
XElement modeElement = null;
|
|
foreach (XElement element in doc.Root.Elements())
|
|
{
|
|
if (element.Name.ToString().ToLower() != "gamemode") continue;
|
|
|
|
modeElement = element;
|
|
break;
|
|
}
|
|
|
|
string mapseed = ToolBox.GetAttributeString(modeElement, "mapseed", "unknown");
|
|
|
|
GUIFrame saveFileFrame = new GUIFrame(new Rectangle((int)(saveList.Rect.Width + 20), 0, 200, 200), Color.Black*0.4f, GUI.Style, menuTabs[(int)Tabs.LoadGame]);
|
|
saveFileFrame.UserData = "savefileframe";
|
|
saveFileFrame.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f);
|
|
|
|
new GUITextBlock(new Rectangle(0,0,0,20), fileName, GUI.Style, saveFileFrame);
|
|
|
|
new GUITextBlock(new Rectangle(0, 30, 0, 20), "Last saved: ", GUI.Style, saveFileFrame).Font = GUI.SmallFont;
|
|
new GUITextBlock(new Rectangle(15, 45, 0, 20), saveTime, GUI.Style, saveFileFrame).Font = GUI.SmallFont;
|
|
|
|
new GUITextBlock(new Rectangle(0, 65, 0, 20), "Map seed: ", GUI.Style, saveFileFrame).Font = GUI.SmallFont;
|
|
new GUITextBlock(new Rectangle(15, 80, 0, 20), mapseed, GUI.Style, saveFileFrame).Font = GUI.SmallFont;
|
|
|
|
var deleteSaveButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Delete", Alignment.BottomCenter, GUI.Style, saveFileFrame);
|
|
deleteSaveButton.UserData = fileName;
|
|
deleteSaveButton.OnClicked = DeleteSave;
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool DeleteSave(GUIButton button, object obj)
|
|
{
|
|
string saveFile = obj as string;
|
|
|
|
if (obj == null) return false;
|
|
|
|
SaveUtil.DeleteSave(saveFile);
|
|
|
|
UpdateLoadScreen();
|
|
|
|
return true;
|
|
}
|
|
|
|
private void RemoveSaveFrame()
|
|
{
|
|
GUIComponent prevFrame = null;
|
|
foreach (GUIComponent child in menuTabs[(int)Tabs.LoadGame].children)
|
|
{
|
|
if (child.UserData as string != "savefileframe") continue;
|
|
|
|
prevFrame = child;
|
|
break;
|
|
}
|
|
menuTabs[(int)Tabs.LoadGame].RemoveChild(prevFrame);
|
|
}
|
|
|
|
public override void Update(double deltaTime)
|
|
{
|
|
buttonsTab.Update((float)deltaTime);
|
|
if (selectedTab>0) menuTabs[selectedTab].Update((float)deltaTime);
|
|
|
|
Game1.TitleScreen.TitlePosition =
|
|
Vector2.Lerp(Game1.TitleScreen.TitlePosition, new Vector2(
|
|
Game1.TitleScreen.TitleSize.X / 2.0f * Game1.TitleScreen.Scale + 30.0f,
|
|
Game1.TitleScreen.TitleSize.Y / 2.0f * Game1.TitleScreen.Scale + 30.0f),
|
|
0.1f);
|
|
|
|
}
|
|
|
|
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
|
{
|
|
graphics.Clear(Color.CornflowerBlue);
|
|
|
|
Game1.TitleScreen.Draw(spriteBatch, graphics, -1.0f, (float)deltaTime);
|
|
|
|
//Game1.GameScreen.DrawMap(graphics, spriteBatch);
|
|
|
|
spriteBatch.Begin();
|
|
|
|
buttonsTab.Draw(spriteBatch);
|
|
if (selectedTab>0) menuTabs[selectedTab].Draw(spriteBatch);
|
|
|
|
GUI.Draw((float)deltaTime, spriteBatch, null);
|
|
|
|
spriteBatch.DrawString(GUI.Font, "Subsurface v"+Game1.Version, new Vector2(10, Game1.GraphicsHeight-20), Color.White);
|
|
|
|
spriteBatch.End();
|
|
}
|
|
|
|
private bool StartGame(GUIButton button, object obj)
|
|
{
|
|
if (string.IsNullOrEmpty(saveNameBox.Text)) return false;
|
|
|
|
string[] existingSaveFiles = SaveUtil.GetSaveFiles();
|
|
|
|
if (Array.Find(existingSaveFiles, s => s == saveNameBox.Text)!=null)
|
|
{
|
|
new GUIMessageBox("Save name already in use", "Please choose another name for the save file");
|
|
return false;
|
|
}
|
|
|
|
Submarine selectedSub = mapList.SelectedData as Submarine;
|
|
if (selectedSub == null) return false;
|
|
|
|
Game1.GameSession = new GameSession(selectedSub, saveNameBox.Text, GameModePreset.list.Find(gm => gm.Name == "Single Player"));
|
|
(Game1.GameSession.gameMode as SinglePlayerMode).GenerateMap(seedBox.Text);
|
|
|
|
Game1.LobbyScreen.Select();
|
|
|
|
new GUIMessageBox("Welcome to Subsurface!", "Please note that the single player mode is very unfinished at the moment; "+
|
|
"for example, the NPCs don't have an AI yet and there are only a couple of different quests to complete. The multiplayer "+
|
|
"mode should be much more enjoyable to play at the moment, so my recommendation is to try out and get a hang of the game mechanics "+
|
|
"in the single player mode and then move on to multiplayer. Have fun!\n - Regalis, the main dev of Subsurface", 400, 350);
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool PreviousTab(GUIButton button, object obj)
|
|
{
|
|
//selectedTab = (int)Tabs.Main;
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool LoadGame(GUIButton button, object obj)
|
|
{
|
|
|
|
string saveFile = saveList.SelectedData as string;
|
|
if (string.IsNullOrWhiteSpace(saveFile)) return false;
|
|
|
|
try
|
|
{
|
|
SaveUtil.LoadGame(saveFile);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
DebugConsole.ThrowError("Loading map ''"+saveFile+"'' failed", e);
|
|
return false;
|
|
}
|
|
|
|
|
|
Game1.LobbyScreen.Select();
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|
|
}
|