diff --git a/Subsurface/Content/Characters/TigerThresher/tigerthresher.xml b/Subsurface/Content/Characters/TigerThresher/tigerthresher.xml index 6a0aae69a..03f133667 100644 --- a/Subsurface/Content/Characters/TigerThresher/tigerthresher.xml +++ b/Subsurface/Content/Characters/TigerThresher/tigerthresher.xml @@ -1,5 +1,5 @@  - + diff --git a/Subsurface/Content/Jobs.xml b/Subsurface/Content/Jobs.xml index 8316e2e55..a9dc5be55 100644 --- a/Subsurface/Content/Jobs.xml +++ b/Subsurface/Content/Jobs.xml @@ -1,6 +1,6 @@  - + @@ -11,9 +11,9 @@ - + - + @@ -22,9 +22,9 @@ - + - + @@ -33,9 +33,20 @@ - + - + + + + + + + + + + + + @@ -44,5 +55,5 @@ - + \ No newline at end of file diff --git a/Subsurface/Content/UI/statusIcons.png b/Subsurface/Content/UI/statusIcons.png new file mode 100644 index 000000000..47cd340f3 Binary files /dev/null and b/Subsurface/Content/UI/statusIcons.png differ diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index dfbcd2c07..1fc4b3131 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -124,6 +124,16 @@ namespace Subsurface get { return cursorPosition; } } + public Character ClosestCharacter + { + get { return closestCharacter; } + } + + public Character SelectedCharacter + { + get { return selectedCharacter; } + } + //public AITarget AiTarget //{ // get { return aiTarget; } @@ -152,7 +162,7 @@ namespace Subsurface { get { return oxygen; } set - { + { oxygen = MathHelper.Clamp(value, 0.0f, 100.0f); if (oxygen == 0.0f) Kill(); } @@ -163,27 +173,25 @@ namespace Subsurface get { return health; - //float totalHealth = 0.0f; - //foreach (Limb l in animController.limbs) - //{ - // totalHealth += (l.MaxHealth - l.Damage); - - //} - //return totalHealth/animController.limbs.Count(); } set { health = MathHelper.Clamp(value, 0.0f, maxHealth); - if (health==0.0f) Kill(); + if (health == 0.0f) Kill(); } } + public float MaxHealth + { + get { return maxHealth; } + } + public float Bleeding { get { return bleeding; } set { - if (float.IsNaN(value) || float.IsInfinity(value)) return; + if (MathUtils.IsValid(value)) return; bleeding = Math.Max(value, 0.0f); } } @@ -287,6 +295,8 @@ namespace Subsurface public Character(string file, Vector2 position, CharacterInfo characterInfo = null, bool isNetworkPlayer = false) { + + keys = new Key[Enum.GetNames(typeof(InputType)).Length]; keys[(int)InputType.Select] = new Key(false); keys[(int)InputType.ActionHeld] = new Key(true); @@ -513,22 +523,55 @@ namespace Subsurface if (controlled == this) { Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cam.ScreenToWorld(PlayerInput.MousePosition)); - closestItem = FindClosestItem(mouseSimPos); - - if (closestItem != null) + + closestCharacter = FindClosestCharacter(mouseSimPos); + if (closestCharacter != null) { - closestItem.IsHighlighted = true; - if (GetInputState(InputType.Select) && closestItem.Pick(this, forcePick)) + if (closestCharacter != selectedCharacter) selectedCharacter = null; + if (!closestCharacter.isHumanoid) closestCharacter = null; + } + + + closestItem = FindClosestItem(mouseSimPos); + + if (closestCharacter != null && closestItem != null) + { + if (Vector2.Distance(closestCharacter.SimPosition, mouseSimPos) < Vector2.Distance(closestItem.SimPosition, mouseSimPos)) { - new NetworkEvent(NetworkEventType.PickItem, ID, true, closestItem.ID); + if (selectedConstruction!=closestItem) closestItem = null; + } + else + { + closestCharacter = null; } } - closestCharacter = FindClosestCharacter(mouseSimPos); - if (closestCharacter != selectedCharacter) selectedCharacter = null; - if (closestCharacter!=null) + if (selectedCharacter==null) + { + if (closestItem != null) + { + closestItem.IsHighlighted = true; + if (GetInputState(InputType.Select) && closestItem.Pick(this, forcePick)) + { + new NetworkEvent(NetworkEventType.PickItem, ID, true, closestItem.ID); + } + } + } + else { - if (GetInputState(InputType.Select)) selectedCharacter = (selectedCharacter == null) ? closestCharacter : null; + if (Vector2.Distance(selectedCharacter.SimPosition, SimPosition) > 2.0f) selectedCharacter = null; + } + + if (GetInputState(InputType.Select)) + { + if (selectedCharacter!=null) + { + selectedCharacter = null; + } + else if (closestCharacter!=null && closestCharacter.isDead && closestCharacter.isHumanoid) + { + selectedCharacter = closestCharacter; + } } } @@ -686,7 +729,11 @@ namespace Subsurface return; } - if (controlled == this) ControlLocalPlayer(cam); + if (controlled == this) + { + CharacterHUD.Update(deltaTime,this); + ControlLocalPlayer(cam); + } Control(deltaTime, cam); @@ -711,15 +758,11 @@ namespace Subsurface PressureProtection -= deltaTime*100.0f; } - - - //foreach (Limb limb in animController.limbs) - //{ - Health = health - bleeding * deltaTime; - //} - + Health = health - bleeding * deltaTime; } + + private void UpdateSightRange() { aiTarget.SightRange = 0.0f; @@ -747,6 +790,11 @@ namespace Subsurface // ConvertUnits.ToDisplayUnits(animController.targetMovement.X, animController.targetMovement.Y), Color.Green); } + public void DrawHUD(SpriteBatch spriteBatch, Camera cam) + { + CharacterHUD.Draw(spriteBatch, this, cam); + } + public void DrawFront(SpriteBatch spriteBatch) { Vector2 pos = ConvertUnits.ToDisplayUnits(AnimController.Limbs[0].SimPosition); @@ -772,67 +820,7 @@ namespace Subsurface } - private static GUIProgressBar drowningBar, healthBar; - public void DrawHud(SpriteBatch spriteBatch, Camera cam) - { - if (drowningBar == null) - { - int width = 100, height = 20; - drowningBar = new GUIProgressBar(new Rectangle(20, GameMain.GraphicsHeight / 2, width, height), Color.Blue, 1.0f); - healthBar = new GUIProgressBar(new Rectangle(20, GameMain.GraphicsHeight / 2 + 30, width, height), Color.Red, 1.0f); - } - - drowningBar.BarSize = Controlled.Oxygen / 100.0f; - if (drowningBar.BarSize < 0.95f) drowningBar.Draw(spriteBatch); - - healthBar.BarSize = health / maxHealth; - if (healthBar.BarSize < 1.0f) healthBar.Draw(spriteBatch); - - if (Controlled.Inventory != null) Controlled.Inventory.DrawOwn(spriteBatch); - - Color color = Color.Orange; - - if (closestCharacter != null && closestCharacter.isDead && closestCharacter.isHumanoid) - { - Vector2 startPos = Position + (closestCharacter.Position - Position) * 0.7f; - startPos = cam.WorldToScreen(startPos); - - Vector2 textPos = startPos; - - float stringWidth = GUI.Font.MeasureString(closestCharacter.Info.Name).X; - textPos -= new Vector2(stringWidth / 2, 20); - spriteBatch.DrawString(GUI.Font, closestCharacter.Info.Name, textPos, Color.Black); - spriteBatch.DrawString(GUI.Font, closestCharacter.Info.Name, textPos + new Vector2(1, -1), Color.Orange); - - if (selectedCharacter==closestCharacter) closestCharacter.inventory.Draw(spriteBatch); - } - else if (closestItem != null && selectedConstruction==null) - { - - Vector2 startPos = Position + (closestItem.Position - Position) * 0.7f; - startPos = cam.WorldToScreen(startPos); - - Vector2 textPos = startPos; - - float stringWidth = GUI.Font.MeasureString(closestItem.Prefab.Name).X; - textPos -= new Vector2(stringWidth / 2, 20); - spriteBatch.DrawString(GUI.Font, closestItem.Prefab.Name, textPos, Color.Black); - spriteBatch.DrawString(GUI.Font, closestItem.Prefab.Name, textPos + new Vector2(1, -1), Color.Orange); - - textPos.Y += 50.0f; - foreach (ColoredText coloredText in closestItem.GetHUDTexts(Controlled)) - { - textPos.X = startPos.X - GUI.Font.MeasureString(coloredText.Text).X / 2; - - spriteBatch.DrawString(GUI.Font, coloredText.Text, textPos, Color.Black); - spriteBatch.DrawString(GUI.Font, coloredText.Text, textPos + new Vector2(1, -1), coloredText.Color); - - textPos.Y += 25; - } - } - - } public void PlaySound(AIController.AiState state) { @@ -856,20 +844,23 @@ namespace Subsurface } } - public virtual AttackResult AddDamage(IDamageable attacker, Vector2 position, Attack attack, bool playSound = false) + public virtual AttackResult AddDamage(IDamageable attacker, Vector2 simPosition, Attack attack, bool playSound = false) { - return AddDamage(position, attack.DamageType, attack.Damage, attack.BleedingDamage, attack.Stun, playSound); + return AddDamage(simPosition, attack.DamageType, attack.Damage, attack.BleedingDamage, attack.Stun, playSound); } - public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound) + public AttackResult AddDamage(Vector2 simPosition, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound) { AnimController.StunTimer = Math.Max(AnimController.StunTimer, stun); + if (controlled == this) CharacterHUD.TakeDamage(); + + Limb closestLimb = null; float closestDistance = 0.0f; foreach (Limb limb in AnimController.Limbs) { - float distance = Vector2.Distance(position, limb.SimPosition); + float distance = Vector2.Distance(simPosition, limb.SimPosition); if (closestLimb == null || distance < closestDistance) { closestLimb = limb; @@ -877,12 +868,12 @@ namespace Subsurface } } - Vector2 pull = position - closestLimb.SimPosition; + Vector2 pull = simPosition - closestLimb.SimPosition; if (pull != Vector2.Zero) pull = Vector2.Normalize(pull); closestLimb.body.ApplyForce(pull*Math.Min(amount*100.0f, 100.0f)); - AttackResult attackResult = closestLimb.AddDamage(position, damageType, amount, bleedingAmount, playSound); + AttackResult attackResult = closestLimb.AddDamage(simPosition, damageType, amount, bleedingAmount, playSound); health -= attackResult.Damage; bleeding += attackResult.Bleeding; @@ -938,6 +929,8 @@ namespace Subsurface private IEnumerable DeathAnim(Camera cam) { + if (controlled != this) yield return CoroutineStatus.Success; + float dimDuration = 8.0f; float timer = 0.0f; @@ -967,9 +960,9 @@ namespace Subsurface } float lerpLightBack = 0.0f; - while (lerpLightBack<1.0f) + while (lerpLightBack < 1.0f) { - lerpLightBack = Math.Min(lerpLightBack+0.05f,1.0f); + lerpLightBack = Math.Min(lerpLightBack + 0.05f, 1.0f); GameMain.LightManager.AmbientLight = Color.Lerp(Color.DarkGray, prevAmbientLight, lerpLightBack); yield return CoroutineStatus.Running; diff --git a/Subsurface/Source/Characters/CharacterHUD.cs b/Subsurface/Source/Characters/CharacterHUD.cs new file mode 100644 index 000000000..703fc9108 --- /dev/null +++ b/Subsurface/Source/Characters/CharacterHUD.cs @@ -0,0 +1,142 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Subsurface +{ + class CharacterHUD + { + + private static Sprite statusIcons; + + private static GUIProgressBar drowningBar, healthBar; + + private static float pressureTimer; + + public static void TakeDamage() + { + healthBar.Flash(); + } + + public static void Update(float deltaTime, Character character) + { + if (drowningBar != null) + { + drowningBar.Update(deltaTime); + if (character.Oxygen < 10.0f) drowningBar.Flash(); + } + if (healthBar != null) healthBar.Update(deltaTime); + + pressureTimer += ((character.AnimController.CurrentHull == null) ? + 100.0f : character.AnimController.CurrentHull.LethalPressure)*deltaTime; + } + + public static void Draw(SpriteBatch spriteBatch, Character character, Camera cam) + { + if (statusIcons==null) + { + statusIcons = new Sprite("Content/UI/statusIcons.png", Vector2.Zero); + } + + DrawStatusIcons(spriteBatch, character); + + if (character.Inventory != null) character.Inventory.DrawOwn(spriteBatch); + + Color color = Color.Orange; + + if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory!=null) + { + character.SelectedCharacter.Inventory.Draw(spriteBatch); + + //if (Vector2.Distance(selectedCharacter.SimPosition, SimPosition) > 2.0f) selectedCharacter = null; + } + + if (character.ClosestCharacter != null && character.ClosestCharacter.IsDead) + { + Vector2 startPos = character.Position + (character.ClosestCharacter.Position - character.Position) * 0.7f; + startPos = cam.WorldToScreen(startPos); + + Vector2 textPos = startPos; + + float stringWidth = GUI.Font.MeasureString(character.ClosestCharacter.Info.Name).X; + textPos -= new Vector2(stringWidth / 2, 20); + spriteBatch.DrawString(GUI.Font, character.ClosestCharacter.Info.Name, textPos, Color.Black); + spriteBatch.DrawString(GUI.Font, character.ClosestCharacter.Info.Name, textPos + new Vector2(1, -1), Color.Orange); + } + else if (character.SelectedCharacter == null && character.ClosestItem != null && character.SelectedConstruction == null) + { + + Vector2 startPos = character.Position + (character.ClosestItem.Position - character.Position) * 0.7f; + startPos = cam.WorldToScreen(startPos); + + Vector2 textPos = startPos; + + float stringWidth = GUI.Font.MeasureString(character.ClosestItem.Prefab.Name).X; + textPos -= new Vector2(stringWidth / 2, 20); + spriteBatch.DrawString(GUI.Font, character.ClosestItem.Prefab.Name, textPos, Color.Black); + spriteBatch.DrawString(GUI.Font, character.ClosestItem.Prefab.Name, textPos + new Vector2(1, -1), Color.Orange); + + textPos.Y += 50.0f; + foreach (ColoredText coloredText in character.ClosestItem.GetHUDTexts(character)) + { + textPos.X = startPos.X - GUI.Font.MeasureString(coloredText.Text).X / 2; + + spriteBatch.DrawString(GUI.Font, coloredText.Text, textPos, Color.Black); + spriteBatch.DrawString(GUI.Font, coloredText.Text, textPos + new Vector2(1, -1), coloredText.Color); + + textPos.Y += 25; + } + } + } + + private static void DrawStatusIcons(SpriteBatch spriteBatch, Character character) + { + if (drowningBar == null) + { + int width = 100, height = 20; + + drowningBar = new GUIProgressBar(new Rectangle(30, GameMain.GraphicsHeight - 200, width, height), Color.Blue, 1.0f); + new GUIImage(new Rectangle(-27, -7, 20, 20), new Rectangle(17, 0, 20, 24), statusIcons, Alignment.TopLeft, drowningBar); + + healthBar = new GUIProgressBar(new Rectangle(30, GameMain.GraphicsHeight - 230, width, height), Color.Red, 1.0f); + new GUIImage(new Rectangle(-26, -7, 20, 20), new Rectangle(0, 0, 13, 24), statusIcons, Alignment.TopLeft, healthBar); + } + + drowningBar.BarSize = character.Oxygen / 100.0f; + if (drowningBar.BarSize < 0.99f) + { + drowningBar.Draw(spriteBatch); + } + + healthBar.BarSize = character.Health / character.MaxHealth; + if (healthBar.BarSize < 1.0f) + { + healthBar.Draw(spriteBatch); + } + + int bloodDropCount = (int)Math.Floor(character.Bleeding); + bloodDropCount = MathHelper.Clamp(bloodDropCount, 0, 5); + for (int i = 1; i < bloodDropCount; i++) + { + spriteBatch.Draw(statusIcons.Texture, new Vector2(5.0f + 20 * i, healthBar.Rect.Y - 20.0f), new Rectangle(39, 3, 15, 19), Color.White * 0.8f); + } + + float pressureFactor = (character.AnimController.CurrentHull == null) ? + 100.0f : Math.Min(character.AnimController.CurrentHull.LethalPressure,100.0f); + if (character.PressureProtection > 0.0f) pressureFactor = 0.0f; + + if (pressureFactor>0.0f) + { + float indicatorAlpha = ((float)Math.Sin(pressureTimer * 0.1f) + 1.0f) * 0.5f; + + indicatorAlpha = MathHelper.Clamp(indicatorAlpha, 0.1f, pressureFactor/100.0f); + + spriteBatch.Draw(statusIcons.Texture, new Vector2(10.0f, healthBar.Rect.Y - 60.0f), new Rectangle(0, 24, 24, 25), Color.White * indicatorAlpha); + + } + } + } +} diff --git a/Subsurface/Source/Characters/Jobs/Job.cs b/Subsurface/Source/Characters/Jobs/Job.cs index d6d5addd0..616db3808 100644 --- a/Subsurface/Source/Characters/Jobs/Job.cs +++ b/Subsurface/Source/Characters/Jobs/Job.cs @@ -7,28 +7,6 @@ using System.Xml.Linq; namespace Subsurface { - class Skill - { - string name; - int level; - - public string Name - { - get { return name; } - } - - public int Level - { - get { return level; } - } - - public Skill(string name, int level) - { - this.name = name; - this.level = level; - } - } - class Job { @@ -76,11 +54,9 @@ namespace Subsurface prefab = jobPrefab; skills = new Dictionary(); - foreach (KeyValuePair skill in prefab.Skills) + foreach (SkillPrefab skillPrefab in prefab.Skills) { - skills.Add( - skill.Key, - new Skill( skill.Key, (int)Rand.Range(skill.Value.X, skill.Value.Y, false))); + skills.Add(skillPrefab.Name, new Skill(skillPrefab)); } } diff --git a/Subsurface/Source/Characters/Jobs/JobPrefab.cs b/Subsurface/Source/Characters/Jobs/JobPrefab.cs index b5f3a58aa..af0919b85 100644 --- a/Subsurface/Source/Characters/Jobs/JobPrefab.cs +++ b/Subsurface/Source/Characters/Jobs/JobPrefab.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Xml.Linq; +using System.Linq; namespace Subsurface { @@ -30,7 +31,7 @@ namespace Subsurface public List ItemNames; public List EquipItem; - public Dictionary Skills; + public List Skills; public string Name { @@ -54,7 +55,7 @@ namespace Subsurface public JobPrefab(XElement element) { - name = element.Name.ToString(); + name = ToolBox.GetAttributeString(element, "name", "name not found"); description = ToolBox.GetAttributeString(element, "description", ""); @@ -66,7 +67,7 @@ namespace Subsurface ItemNames = new List(); EquipItem = new List(); - Skills = new Dictionary(); + Skills = new List(); foreach (XElement subElement in element.Elements()) { @@ -82,10 +83,15 @@ namespace Subsurface } break; case "skills": - LoadSkills(subElement); + foreach (XElement skillElement in subElement.Elements()) + { + Skills.Add(new SkillPrefab(skillElement)); + } break; } } + + Skills.Sort((x,y) => y.LevelRange.X.CompareTo(x.LevelRange.X)); } public static JobPrefab Random() @@ -93,28 +99,51 @@ namespace Subsurface return List[Rand.Int(List.Count)]; } - private void LoadSkills(XElement element) + public GUIFrame CreateInfoFrame() { - foreach (XElement subElement in element.Elements()) + int width = 500, height = 400; + + GUIFrame frame = new GUIFrame(new Rectangle(GameMain.GraphicsWidth / 2 - width / 2, GameMain.GraphicsHeight / 2 - height / 2, width, height), GUI.Style); + frame.Padding = new Vector4(30.0f, 30.0f, 30.0f, 30.0f); + + new GUITextBlock(new Rectangle(0,0,100,20), name, GUI.Style, Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont); + + var descriptionBlock = new GUITextBlock(new Rectangle(0, 40, 0, 0), description, GUI.Style, Alignment.TopLeft, Alignment.TopLeft, frame, true, GUI.SmallFont); + + new GUITextBlock(new Rectangle(0, 40 + descriptionBlock.Rect.Height + 20, 100, 20), "Skills: ", GUI.Style, Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont); + + int y = 40 + descriptionBlock.Rect.Height + 50; + foreach (SkillPrefab skill in Skills) { - string skillName = ToolBox.GetAttributeString(subElement, "name", ""); + string skillDescription = Skill.GetLevelName((int)skill.LevelRange.X); + string skillDescription2 = Skill.GetLevelName((int)skill.LevelRange.Y); - if (string.IsNullOrEmpty(skillName) || Skills.ContainsKey(skillName)) continue; - - var levelString = ToolBox.GetAttributeString(subElement, "level", ""); - if (levelString.Contains(",")) + if (skillDescription2!= skillDescription) { - Skills.Add(skillName, ToolBox.ParseToVector2(levelString, false)); - } - else - { - float skillLevel = float.Parse(levelString, CultureInfo.InvariantCulture); - Skills.Add(skillName, new Vector2(skillLevel, skillLevel)); + skillDescription += "/"+skillDescription2; } + new GUITextBlock(new Rectangle(0, y, 100, 20), + " - " + skill.Name + ": " + skillDescription, GUI.Style, Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.SmallFont); + y += 20; } - } + new GUITextBlock(new Rectangle(250, 40 + descriptionBlock.Rect.Height + 20, 0, 20), "Items: ", GUI.Style, Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont); + + y = 40 + descriptionBlock.Rect.Height + 50; + foreach (string itemName in ItemNames) + { + new GUITextBlock(new Rectangle(250, y, 100, 20), + " - " + itemName, GUI.Style, Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.SmallFont); + + y += 20; + } + + + + + return frame; + } public static void LoadAll(List filePaths) { diff --git a/Subsurface/Source/Characters/Jobs/Skill.cs b/Subsurface/Source/Characters/Jobs/Skill.cs new file mode 100644 index 000000000..5ae509916 --- /dev/null +++ b/Subsurface/Source/Characters/Jobs/Skill.cs @@ -0,0 +1,57 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Subsurface +{ + class Skill + { + SkillPrefab prefab; + + string name; + int level; + + static string[] levelNames = new string[] { + "Untrained", "Incompetent", "Novice", + "Adequate", "Competent", "Proficient", + "Professional", "Master", "Legendary" }; + + public string Name + { + get { return name; } + } + + public int Level + { + get { return level; } + } + + public Skill(SkillPrefab prefab) + { + this.prefab = prefab; + this.name = prefab.Name; + + this.level = (int)Rand.Range(prefab.LevelRange.X, prefab.LevelRange.Y); + } + + public Skill(string name, int level) + { + this.name = name; + + this.level = level; + } + + /// + /// returns the "name" of some skill level (0-10 -> untrained, etc) + /// + public static string GetLevelName(int level) + { + level = MathHelper.Clamp(level, 0, 100); + int scaledLevel = (int)Math.Floor((level / 100.0f) * levelNames.Length); + + return levelNames[Math.Min(scaledLevel, levelNames.Length - 1)]; + } + } +} diff --git a/Subsurface/Source/Characters/Jobs/SkillPrefab.cs b/Subsurface/Source/Characters/Jobs/SkillPrefab.cs new file mode 100644 index 000000000..82737a87f --- /dev/null +++ b/Subsurface/Source/Characters/Jobs/SkillPrefab.cs @@ -0,0 +1,51 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Subsurface +{ + class SkillPrefab + { + string name; + + string description; + + private Vector2 levelRange; + + public string Name + { + get { return name; } + } + + public string Description + { + get { return description; } + } + + public Vector2 LevelRange + { + get { return levelRange; } + } + + public SkillPrefab(XElement element) + { + name = ToolBox.GetAttributeString(element, "name", ""); + + var levelString = ToolBox.GetAttributeString(element, "level", ""); + if (levelString.Contains(",")) + { + levelRange = ToolBox.ParseToVector2(levelString, false); + } + else + { + float skillLevel = float.Parse(levelString, System.Globalization.CultureInfo.InvariantCulture); + levelRange = new Vector2(skillLevel, skillLevel); + } + } + + + } +} diff --git a/Subsurface/Source/Characters/Limb.cs b/Subsurface/Source/Characters/Limb.cs index e83497293..243105f59 100644 --- a/Subsurface/Source/Characters/Limb.cs +++ b/Subsurface/Source/Characters/Limb.cs @@ -285,7 +285,7 @@ namespace Subsurface body.ApplyLinearImpulse((deltaPos - vel * 0.5f) * body.Mass, pullPos); } - public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, bool playSound) + public AttackResult AddDamage(Vector2 simPosition, DamageType damageType, float amount, float bleedingAmount, bool playSound) { DamageSoundType damageSoundType = (damageType == DamageType.Blunt) ? DamageSoundType.LimbBlunt : DamageSoundType.LimbSlash; @@ -299,7 +299,7 @@ namespace Subsurface float mid = (armorLimits.X + armorLimits.Y) / 2.0f; - float angleDiff = MathUtils.GetShortestAngle(MathUtils.VectorToAngle(position - SimPosition), mid); + float angleDiff = MathUtils.GetShortestAngle(MathUtils.VectorToAngle(simPosition - SimPosition), mid); if (Math.Abs(angleDiff) < (armorSector.Y - armorSector.X) / 2.0f) { @@ -310,9 +310,9 @@ namespace Subsurface } } - if (playSound) + if (playSound && amount>0.0f) { - AmbientSoundManager.PlayDamageSound(damageSoundType, amount, position); + AmbientSoundManager.PlayDamageSound(damageSoundType, amount, ConvertUnits.ToDisplayUnits(simPosition)); } //Bleeding += bleedingAmount; @@ -322,7 +322,7 @@ namespace Subsurface for (int i = 0; i < bloodAmount; i++) { - Vector2 particleVel = SimPosition - position; + Vector2 particleVel = SimPosition - simPosition; if (particleVel != Vector2.Zero) particleVel = Vector2.Normalize(particleVel); GameMain.ParticleManager.CreateParticle("blood", diff --git a/Subsurface/Source/GUI/GUI.cs b/Subsurface/Source/GUI/GUI.cs index 4f6fdddef..8ae08d3d6 100644 --- a/Subsurface/Source/GUI/GUI.cs +++ b/Subsurface/Source/GUI/GUI.cs @@ -320,7 +320,7 @@ namespace Subsurface } } - if (Character.Controlled != null && cam!=null) Character.Controlled.DrawHud(spriteBatch, cam); + if (Character.Controlled != null && cam!=null) Character.Controlled.DrawHUD(spriteBatch, cam); if (GameMain.NetworkMember != null) GameMain.NetworkMember.Draw(spriteBatch); DrawMessages(spriteBatch, (float)deltaTime); diff --git a/Subsurface/Source/GUI/GUIImage.cs b/Subsurface/Source/GUI/GUIImage.cs index d5eb06d38..379595291 100644 --- a/Subsurface/Source/GUI/GUIImage.cs +++ b/Subsurface/Source/GUI/GUIImage.cs @@ -47,6 +47,11 @@ namespace Subsurface } public GUIImage(Rectangle rect, Sprite sprite, Alignment alignment, GUIComponent parent = null) + : this(rect, sprite.SourceRect, sprite, alignment, parent) + { + } + + public GUIImage(Rectangle rect, Rectangle sourceRect, Sprite sprite, Alignment alignment, GUIComponent parent = null) : base(null) { this.rect = rect; @@ -60,12 +65,12 @@ namespace Subsurface Scale = 1.0f; this.sprite = sprite; - + if (rect.Width == 0) this.rect.Width = (int)sprite.size.X; if (rect.Height == 0) this.rect.Height = (int)Math.Min(sprite.size.Y, sprite.size.Y * (this.rect.Width / sprite.size.X)); - sourceRect = sprite.SourceRect; - + this.sourceRect = sourceRect; + if (parent != null) parent.AddChild(this); } diff --git a/Subsurface/Source/Items/Components/Machines/Controller.cs b/Subsurface/Source/Items/Components/Machines/Controller.cs index 9bd231f5a..8959a38ea 100644 --- a/Subsurface/Source/Items/Components/Machines/Controller.cs +++ b/Subsurface/Source/Items/Components/Machines/Controller.cs @@ -131,13 +131,11 @@ namespace Subsurface.Items.Components public override bool Use(float deltaTime, Character activator = null) { - //character = activator; - //foreach (MapEntity e in item.linkedTo) - //{ - // Item linkedItem = e as Item; - // if (linkedItem == null) continue; - // linkedItem.Use(deltaTime, activator); - //} + if (character.SelectedConstruction != item) + { + character = null; + return false; + } item.SendSignal("1", "trigger_out"); @@ -149,6 +147,11 @@ namespace Subsurface.Items.Components public override void SecondaryUse(float deltaTime, Character character = null) { if (character == null) return; + if (character.SelectedConstruction!=item) + { + character = null; + return; + } foreach (Connection c in item.Connections) { diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index b607bced5..38029eec5 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -420,7 +420,7 @@ namespace Subsurface { foreach (Item containedItem in containedItems) { - if (containedItem == null || containedItem.condition==0.0f) continue; + if (containedItem == null) continue; if (effect.TargetNames != null && !effect.TargetNames.Contains(containedItem.Name)) continue; hasTargets = true; @@ -719,7 +719,7 @@ namespace Subsurface return; } - if (!HasInGameEditableProperties) + if (HasInGameEditableProperties) { if (editingHUD == null || editingHUD.UserData as Item != this) { diff --git a/Subsurface/Source/Map/Explosion.cs b/Subsurface/Source/Map/Explosion.cs index 6d3355c2e..6669418f0 100644 --- a/Subsurface/Source/Map/Explosion.cs +++ b/Subsurface/Source/Map/Explosion.cs @@ -60,8 +60,6 @@ namespace Subsurface Rand.Vector(Rand.Range(50f, 100.0f)), 0.0f); } - - float displayRange = ConvertUnits.ToDisplayUnits(attack.Range); light = new LightSource(displayPosition, displayRange, Color.LightYellow); diff --git a/Subsurface/Source/Map/Gap.cs b/Subsurface/Source/Map/Gap.cs index 072e6a328..c6ddf01d3 100644 --- a/Subsurface/Source/Map/Gap.cs +++ b/Subsurface/Source/Map/Gap.cs @@ -239,7 +239,6 @@ namespace Subsurface public override void Update(Camera cam, float deltaTime) { - soundVolume = soundVolume + ((flowForce.Length() < 100.0f) ? -deltaTime * 0.5f : deltaTime * 0.5f); soundVolume = MathHelper.Clamp(soundVolume, 0.0f, 1.0f); @@ -254,7 +253,6 @@ namespace Subsurface UpdateOxygen(); - if (linkedTo.Count == 1) { //gap leading from a room to outside @@ -266,7 +264,7 @@ namespace Subsurface UpdateRoomToRoom(deltaTime); } - lerpedFlowForce = Vector2.Lerp(lerpedFlowForce, flowForce, 0.1f); + lerpedFlowForce = Vector2.Lerp(lerpedFlowForce, flowForce, 0.05f); if (FlowForce.Length() > 150.0f && flowTargetHull != null && flowTargetHull.Volume < flowTargetHull.FullVolume) { diff --git a/Subsurface/Source/Screens/MainMenu.cs b/Subsurface/Source/Screens/MainMenuScreen.cs similarity index 99% rename from Subsurface/Source/Screens/MainMenu.cs rename to Subsurface/Source/Screens/MainMenuScreen.cs index 29531d7c0..9d17a98b8 100644 --- a/Subsurface/Source/Screens/MainMenu.cs +++ b/Subsurface/Source/Screens/MainMenuScreen.cs @@ -147,7 +147,7 @@ namespace Subsurface + " 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]); + GUIButton hostButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.BottomRight, GUI.Style, menuTabs[(int)Tabs.HostServer]); hostButton.OnClicked = HostServerClicked; this.game = game; diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index b50245723..0779ac6cf 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -27,6 +27,8 @@ namespace Subsurface private GUIFrame playerFrame; + private GUIFrame jobInfoFrame; + private float camAngle; public bool IsServer; @@ -305,7 +307,7 @@ namespace Subsurface if (IsServer && GameMain.Server != null) { - var playYourself = new GUITickBox(new Rectangle(0, -20, 20, 20), "Play yourself", Alignment.TopLeft, playerFrame); + var playYourself = new GUITickBox(new Rectangle(-30, -30, 20, 20), "Play yourself", Alignment.TopLeft, playerFrame); playYourself.Selected = GameMain.Server.CharacterInfo != null; playYourself.OnSelected = TogglePlayYourself; playYourself.UserData = "playyourself"; @@ -332,21 +334,25 @@ namespace Subsurface new GUITextBlock(new Rectangle(0, 150, 200, 30), "Job preferences:", GUI.Style, playerFrame); - jobList = new GUIListBox(new Rectangle(0, 180, 180, 0), GUI.Style, playerFrame); + jobList = new GUIListBox(new Rectangle(0, 180, 250, 0), GUI.Style, playerFrame); jobList.Enabled = false; int i = 1; foreach (JobPrefab job in JobPrefab.List) { - GUITextBlock jobText = new GUITextBlock(new Rectangle(0, 0, 0, 20), i + ". " + job.Name, GUI.Style, Alignment.Left, Alignment.Right, jobList); + GUITextBlock jobText = new GUITextBlock(new Rectangle(0, 0, 0, 20), i + ". " + job.Name+" ", GUI.Style, Alignment.Left, Alignment.Right, jobList); jobText.UserData = job; - GUIButton upButton = new GUIButton(new Rectangle(0, 0, 15, 15), "u", GUI.Style, jobText); + GUIButton infoButton = new GUIButton(new Rectangle(0, 0, 15, 15), "?", GUI.Style, jobText); + infoButton.UserData = -1; + infoButton.OnClicked += ViewJobInfo; + + GUIButton upButton = new GUIButton(new Rectangle(30, 0, 15, 15), "^", GUI.Style, jobText); upButton.UserData = -1; upButton.OnClicked += ChangeJobPreference; - GUIButton downButton = new GUIButton(new Rectangle(25, 0, 15, 15), "d", GUI.Style, jobText); + GUIButton downButton = new GUIButton(new Rectangle(50, 0, 15, 15), "˅", GUI.Style, jobText); downButton.UserData = 1; downButton.OnClicked += ChangeJobPreference; } @@ -460,6 +466,8 @@ namespace Subsurface GameMain.GameScreen.Cam.MoveCamera((float)deltaTime); menu.Update((float)deltaTime); + + if (jobInfoFrame != null) jobInfoFrame.Update((float)deltaTime); //durationBar.BarScroll = Math.Max(durationBar.BarScroll, 1.0f / 60.0f); } @@ -474,6 +482,8 @@ namespace Subsurface menu.Draw(spriteBatch); + if (jobInfoFrame != null) jobInfoFrame.Draw(spriteBatch); + //if (previewPlayer!=null) previewPlayer.Draw(spriteBatch); GUI.Draw((float)deltaTime, spriteBatch, null); @@ -531,17 +541,14 @@ namespace Subsurface private bool SwitchGender(GUIButton button, object obj) { - try - { - Gender gender = (Gender)obj; - GameMain.Client.CharacterInfo.Gender = gender; - GameMain.Client.SendCharacterData(); + Gender gender = (Gender)obj; + GameMain.NetworkMember.CharacterInfo.Gender = gender; + GameMain.Client.SendCharacterData(); - //CreatePreviewCharacter(); - } - catch {} + //CreatePreviewCharacter(); + - UpdatePreviewPlayer(GameMain.Client.CharacterInfo); + UpdatePreviewPlayer(GameMain.NetworkMember.CharacterInfo); return true; } @@ -594,6 +601,25 @@ namespace Subsurface return true; } + private bool ViewJobInfo(GUIButton button, object obj) + { + GUIComponent jobText = button.Parent; + + JobPrefab jobPrefab = jobText.UserData as JobPrefab; + if (jobPrefab == null) return false; + + jobInfoFrame = jobPrefab.CreateInfoFrame(); + GUIButton closeButton = new GUIButton(new Rectangle(0,0,100,20), "Close", Alignment.BottomRight, GUI.Style, jobInfoFrame); + closeButton.OnClicked = CloseJobInfo; + return true; + } + + private bool CloseJobInfo(GUIButton button, object obj) + { + jobInfoFrame = null; + return true; + } + private bool ChangeJobPreference(GUIButton button, object obj) { GUIComponent jobText = button.Parent; diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 65735f615..70e1a2df3 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -67,6 +67,7 @@ + @@ -74,6 +75,8 @@ + + @@ -217,7 +220,7 @@ - + @@ -530,6 +533,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest Designer diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 569993ce4..f58a4d26c 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ