A* pathfinding, autopilot, WIP radar rendering, proper location names, character skills shown in menus, got rid of PreviewCharacter, mantis
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class PathNode
|
||||
{
|
||||
private WayPoint wayPoint;
|
||||
|
||||
private int wayPointID;
|
||||
|
||||
public int state;
|
||||
|
||||
public PathNode Parent;
|
||||
|
||||
private Vector2 position;
|
||||
|
||||
public float F,G,H;
|
||||
|
||||
public List<PathNode> connections;
|
||||
public float[] distances;
|
||||
|
||||
public WayPoint Waypoint
|
||||
{
|
||||
get { return wayPoint; }
|
||||
}
|
||||
|
||||
public Vector2 Position
|
||||
{
|
||||
get {return position;}
|
||||
}
|
||||
|
||||
public PathNode(WayPoint wayPoint)
|
||||
{
|
||||
this.wayPoint = wayPoint;
|
||||
this.position = wayPoint.SimPosition;
|
||||
wayPointID = wayPoint.ID;
|
||||
|
||||
connections = new List<PathNode>();
|
||||
}
|
||||
|
||||
public static List<PathNode> GenerateNodes(List<WayPoint> wayPoints)
|
||||
{
|
||||
var nodes = new Dictionary<int, PathNode>();
|
||||
foreach (WayPoint wayPoint in wayPoints)
|
||||
{
|
||||
nodes.Add(wayPoint.ID, new PathNode(wayPoint));
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<int,PathNode> node in nodes)
|
||||
{
|
||||
foreach (MapEntity linked in node.Value.wayPoint.linkedTo)
|
||||
{
|
||||
PathNode connectedNode = null;
|
||||
nodes.TryGetValue(linked.ID, out connectedNode);
|
||||
if (connectedNode == null) continue;
|
||||
|
||||
node.Value.connections.Add(connectedNode);
|
||||
}
|
||||
}
|
||||
|
||||
var nodeList = nodes.Values.ToList();
|
||||
foreach (PathNode node in nodeList)
|
||||
{
|
||||
node.distances = new float[node.connections.Count];
|
||||
for (int i = 0; i< node.distances.Length; i++)
|
||||
{
|
||||
node.distances[i] = Vector2.Distance(node.position, node.connections[i].position);
|
||||
}
|
||||
}
|
||||
return nodeList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PathFinder
|
||||
{
|
||||
List<PathNode> nodes;
|
||||
|
||||
private bool insideSubmarine;
|
||||
|
||||
public PathFinder(List<WayPoint> wayPoints, bool insideSubmarine = false)
|
||||
{
|
||||
nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => w.MoveWithLevel != insideSubmarine));
|
||||
|
||||
this.insideSubmarine = insideSubmarine;
|
||||
}
|
||||
|
||||
public SteeringPath FindPath(Vector2 start, Vector2 end)
|
||||
{
|
||||
float closestDist = 0.0f;
|
||||
PathNode startNode = null;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
float dist = Vector2.Distance(start,node.Position);
|
||||
if (dist<closestDist || startNode==null)
|
||||
{
|
||||
closestDist = dist;
|
||||
startNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
closestDist = 0.0f;
|
||||
PathNode endNode = null;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
float dist = Vector2.Distance(end, node.Position);
|
||||
if (dist < closestDist || endNode == null)
|
||||
{
|
||||
closestDist = dist;
|
||||
endNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
if (startNode == null || endNode == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Pathfinding error, couldn't find pathnodes");
|
||||
return null;
|
||||
}
|
||||
|
||||
return FindPath(startNode,endNode);
|
||||
}
|
||||
|
||||
public SteeringPath FindPath(WayPoint start, WayPoint end)
|
||||
{
|
||||
PathNode startNode=null, endNode=null;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
if (node.Waypoint == start)
|
||||
{
|
||||
startNode = node;
|
||||
if (endNode != null) break;
|
||||
}
|
||||
if (node.Waypoint == end)
|
||||
{
|
||||
endNode = node;
|
||||
if (startNode != null) break;
|
||||
}
|
||||
|
||||
if (startNode==null || endNode==null)
|
||||
{
|
||||
DebugConsole.ThrowError("Pathfinding error, couldn't find matching pathnodes to waypoints");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return FindPath(startNode, endNode);
|
||||
}
|
||||
|
||||
private SteeringPath FindPath(PathNode start, PathNode end)
|
||||
{
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
node.state = 0;
|
||||
node.F = 0.0f;
|
||||
node.G = 0.0f;
|
||||
node.H = 0.0f;
|
||||
}
|
||||
|
||||
start.state = 1;
|
||||
while (true)
|
||||
{
|
||||
|
||||
PathNode currNode = null;
|
||||
float dist = 10000.0f;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
if (node.state != 1) continue;
|
||||
if (node.F < dist)
|
||||
{
|
||||
dist = node.F;
|
||||
currNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
if (currNode == null || currNode == end) break;
|
||||
|
||||
currNode.state = 2;
|
||||
|
||||
for (int i = 0; i < currNode.connections.Count; i++)
|
||||
{
|
||||
PathNode nextNode = currNode.connections[i];
|
||||
|
||||
//a node that hasn't been searched yet
|
||||
if (nextNode.state==0)
|
||||
{
|
||||
nextNode.H = Vector2.Distance(nextNode.Position,end.Position);
|
||||
nextNode.G = currNode.G + currNode.distances[i];
|
||||
nextNode.F = nextNode.G + nextNode.H;
|
||||
nextNode.Parent = currNode;
|
||||
nextNode.state = 1;
|
||||
}
|
||||
//node that has been searched
|
||||
else if (nextNode.state==1)
|
||||
{
|
||||
float tempG = currNode.G + currNode.distances[i];
|
||||
//only use if this new route is better than the
|
||||
//route the node was a part of
|
||||
if (tempG < nextNode.G)
|
||||
{
|
||||
nextNode.G = tempG;
|
||||
nextNode.F = nextNode.G + nextNode.H;
|
||||
nextNode.Parent = currNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (end.state==0)
|
||||
{
|
||||
//path not found
|
||||
return new SteeringPath();
|
||||
}
|
||||
|
||||
SteeringPath path = new SteeringPath();
|
||||
List<WayPoint> finalPath = new List<WayPoint>();
|
||||
|
||||
PathNode pathNode = end;
|
||||
while (pathNode != start && pathNode != null)
|
||||
{
|
||||
finalPath.Add(pathNode.Waypoint);
|
||||
|
||||
pathNode = pathNode.Parent;
|
||||
}
|
||||
|
||||
finalPath.Reverse();
|
||||
|
||||
foreach (WayPoint wayPoint in finalPath)
|
||||
{
|
||||
path.AddNode(wayPoint);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,32 +5,30 @@ namespace Subsurface
|
||||
{
|
||||
class SteeringPath
|
||||
{
|
||||
private Queue<Vector2> nodes;
|
||||
|
||||
const float MinDistance = 0.1f;
|
||||
|
||||
Vector2 currentNode;
|
||||
private Queue<WayPoint> nodes;
|
||||
|
||||
WayPoint currentNode;
|
||||
|
||||
public SteeringPath()
|
||||
{
|
||||
nodes = new Queue<Vector2>();
|
||||
nodes = new Queue<WayPoint>();
|
||||
}
|
||||
|
||||
public void AddNode(Vector2 node)
|
||||
public void AddNode(WayPoint node)
|
||||
{
|
||||
if (node == Vector2.Zero) return;
|
||||
if (node == null) return;
|
||||
nodes.Enqueue(node);
|
||||
}
|
||||
|
||||
public Vector2 CurrentNode
|
||||
public WayPoint CurrentNode
|
||||
{
|
||||
get { return currentNode; }
|
||||
}
|
||||
|
||||
public Vector2 GetNode(Vector2 pos)
|
||||
public WayPoint GetNode(Vector2 pos, float minDistance = 0.1f)
|
||||
{
|
||||
if (nodes.Count == 0) return Vector2.Zero;
|
||||
if (currentNode == Vector2.Zero || Vector2.Distance(pos, currentNode) < MinDistance) currentNode = nodes.Dequeue();
|
||||
if (nodes.Count == 0) return null;
|
||||
if (currentNode == null || Vector2.Distance(pos, currentNode.SimPosition) < minDistance) currentNode = nodes.Dequeue();
|
||||
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -94,6 +95,11 @@ namespace Subsurface
|
||||
}
|
||||
}
|
||||
|
||||
public float Mass
|
||||
{
|
||||
get { return AnimController.Mass; }
|
||||
}
|
||||
|
||||
public Inventory Inventory
|
||||
{
|
||||
get { return inventory; }
|
||||
@@ -397,6 +403,11 @@ namespace Subsurface
|
||||
}
|
||||
}
|
||||
|
||||
public int GetSkillLevel(string skillName)
|
||||
{
|
||||
return Info.Job.GetSkillLevel(skillName);
|
||||
}
|
||||
|
||||
public void Control(float deltaTime, Camera cam, bool forcePick = false)
|
||||
{
|
||||
if (isDead) return;
|
||||
@@ -509,12 +520,23 @@ namespace Subsurface
|
||||
if (moveCam)
|
||||
{
|
||||
cam.TargetPos = ConvertUnits.ToDisplayUnits(AnimController.limbs[0].SimPosition);
|
||||
cam.OffsetAmount = 250.0f;
|
||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, 0.05f);
|
||||
}
|
||||
|
||||
cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
|
||||
|
||||
Body body = Submarine.PickBody(AnimController.limbs[0].SimPosition, mouseSimPos);
|
||||
Structure structure = null;
|
||||
if (body != null) structure = body.UserData as Structure;
|
||||
if (structure!=null)
|
||||
{
|
||||
if (!structure.CastShadow && moveCam)
|
||||
{
|
||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 500.0f, 0.05f);
|
||||
}
|
||||
}
|
||||
|
||||
if (AnimController.onGround &&
|
||||
!AnimController.InWater &&
|
||||
AnimController.Anim != AnimController.Animation.UsingConstruction)
|
||||
@@ -780,14 +802,12 @@ namespace Subsurface
|
||||
if (torso == null) torso = AnimController.GetLimb(LimbType.Head);
|
||||
|
||||
Vector2 centerOfMass = Vector2.Zero;
|
||||
float totalMass = 0.0f;
|
||||
foreach (Limb limb in AnimController.limbs)
|
||||
{
|
||||
centerOfMass += limb.Mass * limb.SimPosition;
|
||||
totalMass += limb.Mass;
|
||||
}
|
||||
|
||||
centerOfMass /= totalMass;
|
||||
centerOfMass /= AnimController.Mass;
|
||||
|
||||
health = 0.0f;
|
||||
|
||||
|
||||
@@ -15,7 +15,17 @@ namespace Subsurface
|
||||
|
||||
public Job Job;
|
||||
|
||||
public Gender Gender;
|
||||
private Gender gender;
|
||||
public Gender Gender
|
||||
{
|
||||
get { return gender; }
|
||||
set
|
||||
{
|
||||
if (gender == value) return;
|
||||
gender = value;
|
||||
LoadHeadSprite();
|
||||
}
|
||||
}
|
||||
|
||||
public int Salary;
|
||||
|
||||
@@ -26,6 +36,16 @@ namespace Subsurface
|
||||
// return gender.ToString();
|
||||
//}
|
||||
|
||||
private Sprite headSprite;
|
||||
public Sprite HeadSprite
|
||||
{
|
||||
get
|
||||
{
|
||||
if (headSprite == null) LoadHeadSprite();
|
||||
return headSprite;
|
||||
}
|
||||
}
|
||||
|
||||
public CharacterInfo(string file, string name = "", Gender gender = Gender.None, JobPrefab jobPrefab = null)
|
||||
{
|
||||
this.File = file;
|
||||
@@ -42,11 +62,11 @@ namespace Subsurface
|
||||
if (gender == Gender.None)
|
||||
{
|
||||
float femaleRatio = ToolBox.GetAttributeFloat(doc.Root, "femaleratio", 0.5f);
|
||||
this.Gender = (Rand.Range(0.0f, 1.0f, false) < femaleRatio) ? Gender.Female : Gender.Male;
|
||||
this.gender = (Rand.Range(0.0f, 1.0f, false) < femaleRatio) ? Gender.Female : Gender.Male;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Gender = gender;
|
||||
this.gender = gender;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +75,7 @@ namespace Subsurface
|
||||
{
|
||||
headSpriteRange = ToolBox.GetAttributeVector2(
|
||||
doc.Root,
|
||||
this.Gender == Gender.Female ? "femaleheadid" : "maleheadid",
|
||||
this.gender == Gender.Female ? "femaleheadid" : "maleheadid",
|
||||
Vector2.Zero);
|
||||
}
|
||||
|
||||
@@ -77,26 +97,82 @@ namespace Subsurface
|
||||
string firstNamePath = ToolBox.GetAttributeString(doc.Root.Element("name"), "firstname", "");
|
||||
if (firstNamePath != "")
|
||||
{
|
||||
firstNamePath = firstNamePath.Replace("[GENDER]", (this.Gender == Gender.Female) ? "f" : "");
|
||||
firstNamePath = firstNamePath.Replace("[GENDER]", (this.gender == Gender.Female) ? "f" : "");
|
||||
this.Name = ToolBox.GetRandomLine(firstNamePath);
|
||||
}
|
||||
|
||||
string lastNamePath = ToolBox.GetAttributeString(doc.Root.Element("name"), "lastname", "");
|
||||
if (lastNamePath != "")
|
||||
{
|
||||
lastNamePath = lastNamePath.Replace("[GENDER]", (this.Gender == Gender.Female) ? "f" : "");
|
||||
lastNamePath = lastNamePath.Replace("[GENDER]", (this.gender == Gender.Female) ? "f" : "");
|
||||
if (this.Name != "") this.Name += " ";
|
||||
this.Name += ToolBox.GetRandomLine(lastNamePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadHeadSprite()
|
||||
{
|
||||
XDocument doc = ToolBox.TryLoadXml(File);
|
||||
if (doc == null) return;
|
||||
|
||||
XElement ragdollElement = doc.Root.Element("ragdoll");
|
||||
foreach (XElement limbElement in ragdollElement.Elements())
|
||||
{
|
||||
if (ToolBox.GetAttributeString(limbElement, "type", "").ToLower() != "head") continue;
|
||||
|
||||
XElement spriteElement = limbElement.Element("sprite");
|
||||
|
||||
string spritePath = spriteElement.Attribute("texture").Value;
|
||||
|
||||
spritePath = spritePath.Replace("[GENDER]", (this.gender == Gender.Female) ? "f" : "");
|
||||
spritePath = spritePath.Replace("[HEADID]", HeadSpriteId.ToString());
|
||||
|
||||
headSprite = new Sprite(spriteElement, "", spritePath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public GUIFrame CreateInfoFrame(Rectangle rect)
|
||||
{
|
||||
GUIFrame frame = new GUIFrame(rect, Color.Transparent);
|
||||
frame.Padding = new Vector4(10.0f,10.0f,10.0f,10.0f);
|
||||
|
||||
return CreateInfoFrame(frame);
|
||||
}
|
||||
|
||||
public GUIFrame CreateInfoFrame(GUIFrame frame)
|
||||
{
|
||||
GUIImage image = new GUIImage(new Rectangle(0,0,30,30), HeadSprite, Alignment.TopLeft, frame);
|
||||
|
||||
int x = 0, y = 0;
|
||||
new GUITextBlock(new Rectangle(x+80, y, 200, 20), Name, GUI.style, frame);
|
||||
y += 20;
|
||||
new GUITextBlock(new Rectangle(x+80, y, 200, 20), Job.Name, GUI.style, frame);
|
||||
y += 30;
|
||||
|
||||
var skills = Job.Skills;
|
||||
skills.Sort((s1, s2) => -s1.Level.CompareTo(s2.Level));
|
||||
|
||||
new GUITextBlock(new Rectangle(x, y, 200, 20), "Skills:", GUI.style, frame);
|
||||
y += 20;
|
||||
foreach (Skill skill in skills)
|
||||
{
|
||||
Color textColor = Color.White * (0.5f + skill.Level/200.0f);
|
||||
new GUITextBlock(new Rectangle(x+20, y, 200, 20), skill.Name, Color.Transparent, textColor, Alignment.Left, GUI.style, frame);
|
||||
new GUITextBlock(new Rectangle(x + 20, y, 200, 20), skill.Level.ToString(), Color.Transparent, textColor, Alignment.Right, GUI.style, frame);
|
||||
y += 20;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
public CharacterInfo(XElement element)
|
||||
{
|
||||
Name = ToolBox.GetAttributeString(element, "name", "unnamed");
|
||||
|
||||
string genderStr = ToolBox.GetAttributeString(element, "gender", "male").ToLower();
|
||||
Gender = (genderStr == "male") ? Gender.Male : Gender.Female;
|
||||
gender = (genderStr == "male") ? Gender.Male : Gender.Female;
|
||||
|
||||
File = ToolBox.GetAttributeString(element, "file", "");
|
||||
Salary = ToolBox.GetAttributeInt(element, "salary", 1000);
|
||||
@@ -119,7 +195,7 @@ namespace Subsurface
|
||||
charElement.Add(
|
||||
new XAttribute("name", Name),
|
||||
new XAttribute("file", File),
|
||||
new XAttribute("gender", Gender == Gender.Male ? "male" : "female"),
|
||||
new XAttribute("gender", gender == Gender.Male ? "male" : "female"),
|
||||
new XAttribute("salary", Salary),
|
||||
new XAttribute("headspriteid", HeadSpriteId),
|
||||
new XAttribute("startitemsgiven", StartItemsGiven));
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace Subsurface
|
||||
|
||||
private float flipTimer;
|
||||
|
||||
private float? footRotation;
|
||||
|
||||
public FishAnimController(Character character, XElement element)
|
||||
: base(character, element)
|
||||
{
|
||||
@@ -31,6 +33,12 @@ namespace Subsurface
|
||||
walkSpeed = ToolBox.GetAttributeFloat(element, "walkspeed", 1.0f);
|
||||
swimSpeed = ToolBox.GetAttributeFloat(element, "swimspeed", 1.0f);
|
||||
|
||||
float footRot = ToolBox.GetAttributeFloat(element,"footrotation", float.NaN);
|
||||
if (!float.IsNaN(footRot))
|
||||
{
|
||||
footRotation = MathHelper.ToRadians(footRot);
|
||||
}
|
||||
|
||||
rotateTowardsMovement = ToolBox.GetAttributeBool(element, "rotatetowardsmovement", true);
|
||||
}
|
||||
|
||||
@@ -202,19 +210,20 @@ namespace Subsurface
|
||||
Limb torso = GetLimb(LimbType.Torso);
|
||||
Limb head = GetLimb(LimbType.Head);
|
||||
|
||||
|
||||
if (torso!=null)
|
||||
{
|
||||
colliderLimb = torso;
|
||||
colliderHeight = TorsoPosition;
|
||||
|
||||
colliderLimb.body.SmoothRotate(TorsoAngle*Dir, 5.0f);
|
||||
colliderLimb.body.SmoothRotate(TorsoAngle*Dir, 10.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
colliderLimb = head;
|
||||
colliderHeight = HeadPosition;
|
||||
|
||||
colliderLimb.body.SmoothRotate(HeadAngle*Dir, 10.0f);
|
||||
colliderLimb.body.SmoothRotate(HeadAngle*Dir, 100.0f);
|
||||
}
|
||||
|
||||
Vector2 colliderPos = colliderLimb.SimPosition;
|
||||
@@ -270,7 +279,9 @@ namespace Subsurface
|
||||
colliderLimb.Move(new Vector2(colliderPos.X + movement.X * 0.2f, floorY + colliderHeight), 5.0f);
|
||||
}
|
||||
|
||||
float walkCycleSpeed = head.LinearVelocity.X * 0.08f;
|
||||
//colliderLimb.body.SetTransform(Vector2.Zero, colliderLimb.Rotation);
|
||||
|
||||
float walkCycleSpeed = head.LinearVelocity.X * 0.05f;
|
||||
|
||||
walkPos -= walkCycleSpeed;
|
||||
|
||||
@@ -308,6 +319,9 @@ namespace Subsurface
|
||||
(-transformedStepSize.Y > 0.0f) ? -transformedStepSize.Y : 0.0f),
|
||||
8.0f);
|
||||
}
|
||||
|
||||
if (footRotation!=null) limb.body.SmoothRotate((float)footRotation*Dir, 50.0f);
|
||||
|
||||
break;
|
||||
case LimbType.LeftLeg:
|
||||
case LimbType.RightLeg:
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Subsurface
|
||||
{
|
||||
Vector2 colliderPos = GetLimb(LimbType.Torso).SimPosition;
|
||||
|
||||
if (inWater) stairs = null;
|
||||
|
||||
Vector2 rayStart = colliderPos; // at the bottom of the player sprite
|
||||
Vector2 rayEnd = rayStart - new Vector2(0.0f, TorsoPosition);
|
||||
if (stairs != null) rayEnd.Y -= 0.5f;
|
||||
@@ -31,10 +33,11 @@ namespace Subsurface
|
||||
switch (fixture.CollisionCategories)
|
||||
{
|
||||
case Physics.CollisionStairs:
|
||||
if (inWater) return -1;
|
||||
Structure structure = fixture.Body.UserData as Structure;
|
||||
if (stairs == null && !inWater && structure!=null)
|
||||
if (stairs == null && structure!=null)
|
||||
{
|
||||
if (LowestLimb.SimPosition.Y<structure.SimPosition.Y)
|
||||
if (LowestLimb.SimPosition.Y < structure.SimPosition.Y)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -92,8 +95,7 @@ namespace Subsurface
|
||||
if (closestFraction == 1) //raycast didn't hit anything
|
||||
{
|
||||
floorY = (currentHull == null) ? -1000.0f : ConvertUnits.ToSimUnits(currentHull.Rect.Y - currentHull.Rect.Height);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
floorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * closestFraction;
|
||||
|
||||
@@ -7,12 +7,34 @@ 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
|
||||
{
|
||||
|
||||
private JobPrefab prefab;
|
||||
|
||||
private Dictionary<string, float> skills;
|
||||
private Dictionary<string, Skill> skills;
|
||||
|
||||
public string Name
|
||||
{
|
||||
@@ -34,15 +56,26 @@ namespace Subsurface
|
||||
get { return prefab.ItemNames; }
|
||||
}
|
||||
|
||||
public List<Skill> Skills
|
||||
{
|
||||
get { return skills.Values.ToList(); }
|
||||
}
|
||||
|
||||
//public List<float> SkillLevels
|
||||
//{
|
||||
// get { return skills.Values.ToList(); }
|
||||
//}
|
||||
|
||||
public Job(JobPrefab jobPrefab)
|
||||
{
|
||||
prefab = jobPrefab;
|
||||
|
||||
skills = new Dictionary<string, float>();
|
||||
skills = new Dictionary<string, Skill>();
|
||||
foreach (KeyValuePair<string, Vector2> skill in prefab.Skills)
|
||||
{
|
||||
skills.Add(skill.Key, Rand.Range(skill.Value.X, skill.Value.Y, false));
|
||||
skills.Add(
|
||||
skill.Key,
|
||||
new Skill( skill.Key, (int)Rand.Range(skill.Value.X, skill.Value.Y, false)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,10 +86,12 @@ namespace Subsurface
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
skills.Add(subElement.Name.ToString(), ToolBox.GetAttributeFloat(subElement, "level", 0.0f));
|
||||
skills.Add(
|
||||
subElement.Name.ToString(),
|
||||
new Skill(subElement.Name.ToString(), ToolBox.GetAttributeInt(subElement, "level", 0)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Job Random()
|
||||
{
|
||||
JobPrefab prefab = JobPrefab.List[Rand.Int(JobPrefab.List.Count-1, false)];
|
||||
@@ -64,12 +99,12 @@ namespace Subsurface
|
||||
return new Job(prefab);
|
||||
}
|
||||
|
||||
public float GetSkill(string skillName)
|
||||
public int GetSkillLevel(string skillName)
|
||||
{
|
||||
float skillLevel = 0.0f;
|
||||
skills.TryGetValue(skillName.ToLower(), out skillLevel);
|
||||
Skill skill = null;
|
||||
skills.TryGetValue(skillName, out skill);
|
||||
|
||||
return skillLevel;
|
||||
return (skill==null) ? 0 : skill.Level;
|
||||
}
|
||||
|
||||
public virtual XElement Save(XElement parentElement)
|
||||
@@ -78,9 +113,9 @@ namespace Subsurface
|
||||
|
||||
jobElement.Add(new XAttribute("name", Name));
|
||||
|
||||
foreach (KeyValuePair<string, float> skill in skills)
|
||||
foreach (KeyValuePair<string, Skill> skill in skills)
|
||||
{
|
||||
jobElement.Add(new XElement(skill.Key, new XAttribute("level", skill.Value)));
|
||||
jobElement.Add(new XElement(skill.Key, new XAttribute("level", skill.Value.Level)));
|
||||
}
|
||||
|
||||
parentElement.Add(jobElement);
|
||||
|
||||
@@ -85,17 +85,18 @@ namespace Subsurface
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
string skillName = subElement.Name.ToString();
|
||||
if (Skills.ContainsKey(skillName)) continue;
|
||||
string skillName = ToolBox.GetAttributeString(subElement, "name", "");
|
||||
|
||||
var levelAttribute = subElement.Attribute("level").ToString();
|
||||
if (levelAttribute.Contains("'"))
|
||||
if (string.IsNullOrEmpty(skillName) || Skills.ContainsKey(skillName)) continue;
|
||||
|
||||
var levelString = ToolBox.GetAttributeString(subElement, "level", "");
|
||||
if (levelString.Contains(","))
|
||||
{
|
||||
Skills.Add(skillName, ToolBox.ParseToVector2(levelAttribute, false));
|
||||
Skills.Add(skillName, ToolBox.ParseToVector2(levelString, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
float skillLevel = float.Parse(levelAttribute, CultureInfo.InvariantCulture);
|
||||
float skillLevel = float.Parse(levelString, CultureInfo.InvariantCulture);
|
||||
Skills.Add(skillName, new Vector2(skillLevel, skillLevel));
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,12 @@ namespace Subsurface
|
||||
get { return lowestLimb; }
|
||||
}
|
||||
|
||||
public float Mass
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Vector2 TargetMovement
|
||||
{
|
||||
get { return (correctionMovement == Vector2.Zero) ? targetMovement : correctionMovement; }
|
||||
@@ -173,6 +179,7 @@ namespace Subsurface
|
||||
limb.body.FarseerBody.OnCollision += OnLimbCollision;
|
||||
|
||||
limbs[ID] = limb;
|
||||
Mass += limb.Mass;
|
||||
if (!limbDictionary.ContainsKey(limb.type)) limbDictionary.Add(limb.type, limb);
|
||||
break;
|
||||
case "joint":
|
||||
@@ -257,7 +264,7 @@ namespace Subsurface
|
||||
}
|
||||
else if (structure.StairDirection!=Direction.None)
|
||||
{
|
||||
if (inWater || (!(targetMovement.Y>Math.Abs(targetMovement.X/2.0f)) && lowestLimb.body.Position.Y < ConvertUnits.ToSimUnits(structure.Rect.Y - structure.Rect.Height) + 0.5f))
|
||||
if (inWater || !(targetMovement.Y>Math.Abs(targetMovement.X/2.0f)) && lowestLimb.body.Position.Y < ConvertUnits.ToSimUnits(structure.Rect.Y - structure.Rect.Height) + 0.5f)
|
||||
{
|
||||
stairs = null;
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user