using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using FarseerPhysics; using FarseerPhysics.Collision.Shapes; using FarseerPhysics.Common; using FarseerPhysics.Dynamics; using FarseerPhysics.Dynamics.Joints; using FarseerPhysics.Factories; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Barotrauma.Items.Components { class Rope : ItemComponent, IDrawableComponent { PhysicsBody[] ropeBodies; RevoluteJoint[] ropeJoints; DistanceJoint gunJoint; float pullForce; Sprite sprite; float reload; float prevDir; float sectionLength; Item projectile; Vector2 projectileAnchor; private Vector2 BarrelPos { get { Vector2 barrelPos = Vector2.Zero; //RangedWeapon weapon = item.GetComponent(); //if (weapon != null) barrelPos = weapon.barrelPos; return barrelPos; } } private Vector2 TransformedBarrelPos { get { Vector2 barrelPos = Vector2.Zero; RangedWeapon weapon = item.GetComponent(); if (weapon != null) barrelPos = weapon.TransformedBarrelPos; return barrelPos; } } public Rope(Item item, XElement element) : base(item, element) { string spritePath = ToolBox.GetAttributeString(element, "sprite", ""); if (spritePath == "") DebugConsole.ThrowError("Sprite "+spritePath+" in "+element+" not found!"); float length = ConvertUnits.ToSimUnits(ToolBox.GetAttributeFloat(element, "length", 200.0f)); pullForce = ToolBox.GetAttributeFloat(element, "pullforce", 10.0f); projectileAnchor = Vector2.Zero; projectileAnchor.X = ToolBox.GetAttributeFloat(element, "projectileanchorx", 0.0f); projectileAnchor.Y = ToolBox.GetAttributeFloat(element, "projectileanchory", 0.0f); projectileAnchor = ConvertUnits.ToSimUnits(projectileAnchor); characterUsable = ToolBox.GetAttributeBool(element, "characterusable", false); sprite = new Sprite(spritePath, new Vector2(0.5f,0.5f)); sectionLength = ConvertUnits.ToSimUnits(sprite.size.X); Path ropePath = new Path(); ropePath.Add(item.body.SimPosition); ropePath.Add(item.body.SimPosition + new Vector2(length, 0.0f)); ropePath.Closed = false; Vertices box = PolygonTools.CreateRectangle(sectionLength, 0.05f); PolygonShape shape = new PolygonShape(box, 5); ListropeList = PathManager.EvenlyDistributeShapesAlongPath(GameMain.World, ropePath, shape, BodyType.Dynamic, (int)(length/sectionLength)); ropeBodies = new PhysicsBody[ropeList.Count]; for (int i = 0; i joints = PathManager.AttachBodiesWithRevoluteJoint(GameMain.World, ropeList, new Vector2(-sectionLength/2, 0.0f), new Vector2(sectionLength/2, 0.0f), false, false); ropeJoints = new RevoluteJoint[joints.Count+1]; //ropeJoints[0] = JointFactory.CreateRevoluteJoint(Game1.world, item.body, ropeList[0], new Vector2(0f, -0.0f)); for (int i = 0; i < joints.Count; i++) { var distanceJoint = JointFactory.CreateDistanceJoint(GameMain.World, ropeList[i], ropeList[i + 1]); distanceJoint.Length = sectionLength; distanceJoint.DampingRatio = 1.0f; ropeJoints[i] = joints[i]; } } public override void SecondaryUse(float deltaTime, Character character = null) { if (reload > 0.0f) return; bool first = true; for (int i = 0; i < ropeBodies.Length - 1; i++) { if (ropeBodies[i].UserData == null || (bool)ropeBodies[i].UserData) continue; if (first) { Vector2 dist = gunJoint.WorldAnchorA - ropeJoints[i].WorldAnchorA; float length = dist.Length(); if (gunJoint.Length < 0.011 && length*0.5f0.0f) reload -= deltaTime; //for (int i = 0; i < ropeBodies.Length - 1; i++) //{ // if (ropeBodies[i].UserData == null || (bool)ropeBodies[i].UserData == true) continue; // ropeBodies[i].SmoothRotate(item.body.Rotation); //} int len = 1; for (int i = 0; i < ropeBodies.Length - 1; i++) { if (ropeBodies[i].UserData == null || (bool)ropeBodies[i].UserData) continue; len++; } if (Vector2.Distance(TransformedBarrelPos, projectile.SimPosition)>len*sectionLength) { Vector2 stopForce = projectile.SimPosition - ropeBodies[ropeBodies.Length-1].SimPosition; stopForce = Vector2.Normalize(stopForce); float dotProduct = Vector2.Dot(stopForce, Vector2.Normalize(projectile.body.LinearVelocity)); if (dotProduct<0) projectile.body.ApplyLinearImpulse(-stopForce*dotProduct * projectile.body.LinearVelocity.Length() * projectile.body.Mass); } if (item.body.Dir!=prevDir) { gunJoint.LocalAnchorA = new Vector2( -gunJoint.LocalAnchorA.X, BarrelPos.Y); prevDir = -prevDir; } if (!projectile.body.Enabled || !item.body.Enabled) { //attempt to recontain the projectile in the launcher //eq automatically reload a spear into a speargun when picking the spear up if (!projectile.body.Enabled) item.Combine(projectile); foreach (PhysicsBody b in ropeBodies) { b.Enabled = false; } foreach (var joint in ropeJoints) { if (joint != null) joint.Enabled = false; } IsActive = false; } } public void Draw(SpriteBatch spriteBatch, bool editing = false) { if (!IsActive) return; RevoluteJoint firstJoint = null; for (int i = 0; i(); foreach (PhysicsBody b in ropeBodies) { b.SetTransform(item.body.SimPosition, 0.0f); b.UserData = false; b.Enabled = true; } foreach (var joint in ropeJoints) { if (joint!=null) joint.Enabled = true; } ropeBodies[ropeBodies.Length - 1].SetTransform(projectile.body.SimPosition, projectile.body.Rotation); //attach projectile to the last section of the rope if (ropeJoints[ropeJoints.Length-1] != null) GameMain.World.RemoveJoint(ropeJoints[ropeJoints.Length-1]); ropeJoints[ropeJoints.Length - 1] = JointFactory.CreateRevoluteJoint(GameMain.World, projectile.body.FarseerBody, ropeBodies[ropeBodies.Length - 1].FarseerBody, projectileAnchor, new Vector2(sectionLength / 2, 0.0f)); AttachGunJoint(ropeBodies[0].FarseerBody); prevDir = item.body.Dir; } private void AttachGunJoint(Body body) { float rotation = (item.body.Dir == -1.0f) ? item.body.Rotation - MathHelper.Pi : item.body.Rotation; body.SetTransform(TransformedBarrelPos, rotation); //Vector2 axis = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)); if (gunJoint != null) GameMain.World.RemoveJoint(gunJoint); gunJoint = new DistanceJoint(item.body.FarseerBody, body, BarrelPos, new Vector2(sectionLength / 2, 0.0f)); gunJoint.Length = sectionLength; //gunJoint.LocalAnchorA = BarrelPos; //gunJoint.LocalAnchorB = new Vector2(sectionLength / 2, 0.0f); //gunJoint.UpperLimit = sectionLength; //gunJoint.LowerLimit = 0.0f; //gunJoint.LimitEnabled = true; //gunJoint.ReferenceAngle = 0.0f; GameMain.World.AddJoint(gunJoint); } } }