using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using FarseerPhysics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using System.Collections.ObjectModel; namespace Subsurface { public enum SpawnType { None, Human, Enemy, Cargo }; class WayPoint : MapEntity { public static List WayPointList = new List(); private SpawnType spawnType; //characters spawning at the waypoint will be given an ID card with these tags private string[] idCardTags; //only characters with this job will be spawned at the waypoint private JobPrefab assignedJob; public SpawnType SpawnType { get { return spawnType; } set { spawnType = value; } } public string[] IdCardTags { get { return idCardTags; } private set { idCardTags = value; for (int i = 0; i(); idCardTags = new string[0]; mapEntityList.Add(this); WayPointList.Add(this); } public override void Draw(SpriteBatch spriteBatch, bool editing) { if (!editing && !GameMain.DebugDraw) return; Point pos = new Point((int)Position.X, (int)Position.Y); Color clr = (isSelected) ? Color.Red : Color.LightGreen; GUI.DrawRectangle(spriteBatch, new Rectangle(pos.X - rect.Width / 2, -pos.Y - rect.Height / 2, rect.Width, rect.Height), clr, true); foreach (MapEntity e in linkedTo) { GUI.DrawLine(spriteBatch, new Vector2(pos.X, -pos.Y), new Vector2(e.Position.X + e.Rect.Width / 2, -e.Position.Y + e.Rect.Height / 2), Color.Green); } } public override void DrawEditing(SpriteBatch spriteBatch, Camera cam) { if (editingHUD == null || editingHUD.UserData != this) { editingHUD = CreateEditingHUD(); } editingHUD.Update((float)Physics.step); editingHUD.Draw(spriteBatch); if (!PlayerInput.LeftButtonClicked()) return; Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); foreach (MapEntity e in mapEntityList) { if (e.GetType()!=typeof(WayPoint)) continue; if (e == this) continue; if (!Submarine.RectContains(e.Rect, position)) continue; linkedTo.Add(e); e.linkedTo.Add(this); } } private bool ChangeSpawnType(GUIButton button, object obj) { GUITextBlock spawnTypeText = button.Parent as GUITextBlock; spawnType += (int)button.UserData; if (spawnType > SpawnType.Cargo) spawnType = SpawnType.None; if (spawnType < SpawnType.None) spawnType = SpawnType.Enemy; spawnTypeText.Text = spawnType.ToString(); return true; } private bool EnterIDCardTags(GUITextBox textBox, string text) { IdCardTags = text.Split(','); textBox.Text = text; textBox.Color = Color.White; return true; } private bool EnterAssignedJob(GUITextBox textBox, string text) { string trimmedName = text.ToLower().Trim(); assignedJob = JobPrefab.List.Find(jp => jp.Name.ToLower() == trimmedName); if (assignedJob !=null && trimmedName!="none") { textBox.Color = Color.White; textBox.Text = (assignedJob == null) ? "None" : assignedJob.Name; } return true; } private bool TextBoxChanged(GUITextBox textBox, string text) { textBox.Color = Color.Red; return true; } private GUIComponent CreateEditingHUD(bool inGame = false) { int width = 500; int x = GameMain.GraphicsWidth / 2 - width / 2, y = 10; editingHUD = new GUIFrame(new Rectangle(x, y, width, 150), Color.Black * 0.5f); editingHUD.Padding = new Vector4(10, 10, 0, 0); editingHUD.UserData = this; new GUITextBlock(new Rectangle(0, 0, 100, 20), "Editing waypoint", GUI.Style, editingHUD); new GUITextBlock(new Rectangle(0, 20, 100, 20), "Hold space to link to another entity", GUI.Style, editingHUD); new GUITextBlock(new Rectangle(0, 40, 100, 20), "Spawnpoint: ", GUI.Style, editingHUD); var spawnTypeText = new GUITextBlock(new Rectangle(0, 40, 200, 20), spawnType.ToString(), GUI.Style, Alignment.Right, Alignment.TopLeft, editingHUD); var button = new GUIButton(new Rectangle(-30,0,20,20), "-", Alignment.Right, GUI.Style, spawnTypeText); button.UserData = -1; button.OnClicked = ChangeSpawnType; button = new GUIButton(new Rectangle(0, 0, 20, 20), "+", Alignment.Right, GUI.Style, spawnTypeText); button.UserData = 1; button.OnClicked = ChangeSpawnType; //spriteBatch.DrawString(GUI.font, "Spawnpoint: " + spawnType.ToString() + " +/-", new Vector2(x, y + 40), Color.Black); y = 40+20; new GUITextBlock(new Rectangle(0, y, 100, 20), "ID Card tags:", Color.Transparent, Color.Black, Alignment.TopLeft, null, editingHUD); GUITextBox propertyBox = new GUITextBox(new Rectangle(100, y, 200, 20), GUI.Style, editingHUD); propertyBox.Text = string.Join(", ", idCardTags); propertyBox.OnEnter = EnterIDCardTags; propertyBox.OnTextChanged = TextBoxChanged; y = y + 30; new GUITextBlock(new Rectangle(0, y, 100, 20), "Assigned job:", Color.Transparent, Color.Black, Alignment.TopLeft, null, editingHUD); propertyBox = new GUITextBox(new Rectangle(100, y, 200, 20), GUI.Style, editingHUD); propertyBox.Text = (assignedJob == null) ? "None" : assignedJob.Name; propertyBox.OnEnter = EnterAssignedJob; propertyBox.OnTextChanged = TextBoxChanged; y = y + 30; return editingHUD; } public static WayPoint GetRandom(SpawnType spawnType = SpawnType.None, Job assignedJob = null) { List wayPoints = new List(); foreach (WayPoint wp in WayPointList) { if (spawnType != SpawnType.None && wp.spawnType != spawnType) continue; if (assignedJob != null && wp.assignedJob != assignedJob.Prefab) continue; wayPoints.Add(wp); } if (!wayPoints.Any()) return null; return wayPoints[Rand.Int(wayPoints.Count())]; } public static WayPoint[] SelectCrewSpawnPoints(List crew) { List unassignedWayPoints = new List(); foreach (WayPoint wp in WayPointList) { if (wp.spawnType == SpawnType.Human) unassignedWayPoints.Add(wp); } WayPoint[] assignedWayPoints = new WayPoint[crew.Count]; for (int i = 0; i < crew.Count; i++ ) { //try to give the crew member a spawnpoint that hasn't been assigned to anyone and matches their job for (int n = 0; n < unassignedWayPoints.Count; n++) { if (crew[i].Job.Prefab != unassignedWayPoints[n].assignedJob) continue; assignedWayPoints[i] = unassignedWayPoints[n]; unassignedWayPoints.RemoveAt(n); break; } } //go through the crewmembers that don't have a spawnpoint yet (if any) for (int i = 0; i < crew.Count; i++) { if (assignedWayPoints[i] != null) continue; //try to assign a spawnpoint that matches the job, even if the spawnpoint is already assigned to someone else foreach (WayPoint wp in WayPointList) { if (wp.spawnType != SpawnType.Human || wp.assignedJob != crew[i].Job.Prefab) continue; assignedWayPoints[i] = wp; break; } if (assignedWayPoints[i] != null) continue; //everything else failed -> just give a random spawnpoint assignedWayPoints[i] = GetRandom(SpawnType.Human); } return assignedWayPoints; } public override XElement Save(XDocument doc) { if (MoveWithLevel) return null; XElement element = new XElement("WayPoint"); element.Add(new XAttribute("ID", ID), new XAttribute("x", rect.X), new XAttribute("y", rect.Y), new XAttribute("spawn", spawnType)); if (idCardTags.Length > 0) { element.Add(new XAttribute("idcardtags", string.Join(",", idCardTags))); } if (assignedJob != null) { element.Add(new XAttribute("job", assignedJob.Name)); } doc.Root.Add(element); if (linkedTo != null) { int i = 0; foreach (MapEntity e in linkedTo) { element.Add(new XAttribute("linkedto" + i, e.ID)); i += 1; } } return element; } public static void Load(XElement element) { Rectangle rect = new Rectangle( int.Parse(element.Attribute("x").Value), int.Parse(element.Attribute("y").Value), (int)Submarine.GridSize.X, (int)Submarine.GridSize.Y); WayPoint w = new WayPoint(rect); w.ID = int.Parse(element.Attribute("ID").Value); w.spawnType = (SpawnType)Enum.Parse(typeof(SpawnType), ToolBox.GetAttributeString(element, "spawn", "None")); string idCardTagString = ToolBox.GetAttributeString(element, "idcardtags", ""); if (!string.IsNullOrWhiteSpace(idCardTagString)) { w.IdCardTags = idCardTagString.Split(','); } string jobName = ToolBox.GetAttributeString(element, "job", "").ToLower(); if (!string.IsNullOrWhiteSpace(jobName)) { w.assignedJob = JobPrefab.List.Find(jp => jp.Name.ToLower() == jobName); } w.linkedToID = new List(); int i = 0; while (element.Attribute("linkedto" + i) != null) { w.linkedToID.Add(int.Parse(element.Attribute("linkedto" + i).Value)); i += 1; } } public override void Remove() { base.Remove(); WayPointList.Remove(this); } } }