Пример #1
0
    public Battlefield()
    {
        _instance = this;
		//InitBattleField(new MapObject(){ w = 3, h = 3 });
		su = new Submarine();
		sh = new Ship();
    }
Пример #2
0
    public Ship(int field_w, int field_h)
    {
        InitShip(field_w, field_h);

        bf = Battlefield.Instance;
        su = Submarine.Instance;
        _instance = this;
    }
Пример #3
0
	public Ship()
    {
		//InitShip(_possiblePositions);

        bf = Battlefield.Instance;
        su = Submarine.Instance;
		history = new List<List<Point>> ();
        _instance = this;
    }
Пример #4
0
	protected void Init() {
		bf = BattlefieldScript.Instance;
		//bfc = bf.bf;
		su = Submarine.Instance;
		sh = Ship.Instance;
		//la = LanguageScript.Instance;
		mo = move.Instance;
		la = LanguageScript.Instance;
	}
Пример #5
0
	void Start() {
		_instance = this;
		bf = BattlefieldScript.Instance;
		//bfc = bf.bf;
		su = Submarine.Instance;
		sh = Ship.Instance;
		//la = LanguageScript.Instance;
		mo = move.Instance;
		reward = new Reward (false, 2);
	}
Пример #6
0
	void Start() {
		Debug.Log ("!!! MULTIPLAYER INITIATED !!!");
		_instance = this;
		bf = BattlefieldScript.Instance;
		bfc = bf.bf;
		su = Submarine.Instance;
		sh = Ship.Instance;
		la = LanguageScript.Instance;
		mo = move.Instance;
		reward = new Reward (false, 5);
	}
Пример #7
0
 // Use this for initialization
 void Start () {
     _instance = this;
     bf = new Battlefield();
     bf = Battlefield.Instance;
     su = Submarine.Instance;
     sh = Ship.Instance;
     
     InitField();
     
     transform.FindChild("autoMove_btn").GetComponent<Button>().onClick.AddListener(DoAutoMove);
     transform.FindChild("shMove_btn").GetComponent<Button>().onClick.AddListener(DoShipMove);
     transform.FindChild("suMove_btn").GetComponent<Button>().onClick.AddListener(DoSubmarineMove);
 }
Пример #8
0
    public void InitSubmarine()
    {
		List<Point> su_pp = new List<Point> ();
		foreach (Point p in MapObject.Su_possiblePositions) {
			su_pp.Add (p);
			//Debug.Log ("point addd");
		}
		
        if (Submarine.Instance == null)
        {
			su = new Submarine();
            su = Submarine.Instance;
        }
        else
        {
			su.InitSubmarine(su_pp);
        }
        
    }
Пример #9
0
        public void RenderLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor = null)
        {
            if (!LightingEnabled)
            {
                return;
            }

            if (Math.Abs(currLightMapScale - GameMain.Config.LightMapScale) > 0.01f)
            {
                //lightmap scale has changed -> recreate render targets
                CreateRenderTargets(graphics);
            }

            Matrix spriteBatchTransform = cam.Transform * Matrix.CreateScale(new Vector3(GameMain.Config.LightMapScale, GameMain.Config.LightMapScale, 1.0f));
            Matrix transform            = cam.ShaderTransform
                                          * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;

            bool highlightsVisible = UpdateHighlights(graphics, spriteBatch, spriteBatchTransform, cam);

            Rectangle viewRect = cam.WorldView;

            viewRect.Y -= cam.WorldView.Height;
            //check which lights need to be drawn
            activeLights.Clear();
            foreach (LightSource light in lights)
            {
                if (!light.Enabled)
                {
                    continue;
                }
                if ((light.Color.A < 1 || light.Range < 1.0f) && !light.LightSourceParams.OverrideLightSpriteAlpha.HasValue)
                {
                    continue;
                }
                if (light.ParentBody != null)
                {
                    light.Position = light.ParentBody.DrawPosition;
                    if (light.ParentSub != null)
                    {
                        light.Position -= light.ParentSub.DrawPosition;
                    }
                }

                float range = light.LightSourceParams.TextureRange;
                if (light.LightSprite != null)
                {
                    float spriteRange = Math.Max(
                        light.LightSprite.size.X * light.SpriteScale.X * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.X - 0.5f)),
                        light.LightSprite.size.Y * light.SpriteScale.Y * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.Y - 0.5f)));
                    range = Math.Max(spriteRange, range);
                }
                if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, range, viewRect))
                {
                    continue;
                }
                activeLights.Add(light);
            }

            //draw light sprites attached to characters
            //render into a separate rendertarget using alpha blending (instead of on top of everything else with alpha blending)
            //to prevent the lights from showing through other characters or other light sprites attached to the same character
            //---------------------------------------------------------------------------------------------------
            graphics.SetRenderTarget(LimbLightMap);
            graphics.Clear(Color.Black);
            graphics.BlendState = BlendState.NonPremultiplied;
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
            foreach (LightSource light in activeLights)
            {
                if (light.IsBackground || light.CurrentBrightness <= 0.0f)
                {
                    continue;
                }
                //draw limb lights at this point, because they were skipped over previously to prevent them from being obstructed
                if (light.ParentBody?.UserData is Limb limb && !limb.Hide)
                {
                    light.DrawSprite(spriteBatch, cam);
                }
            }
            spriteBatch.End();

            //draw background lights
            //---------------------------------------------------------------------------------------------------
            graphics.SetRenderTarget(LightMap);
            graphics.Clear(AmbientLight);
            graphics.BlendState = BlendState.Additive;
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
            Level.Loaded?.BackgroundCreatureManager?.DrawLights(spriteBatch, cam);
            foreach (LightSource light in activeLights)
            {
                if (!light.IsBackground || light.CurrentBrightness <= 0.0f)
                {
                    continue;
                }
                light.DrawSprite(spriteBatch, cam);
                light.DrawLightVolume(spriteBatch, lightEffect, transform);
            }
            GameMain.ParticleManager.Draw(spriteBatch, true, null, Particles.ParticleBlendState.Additive);
            spriteBatch.End();

            //draw a black rectangle on hulls to hide background lights behind subs
            //---------------------------------------------------------------------------------------------------

            if (backgroundObstructor != null)
            {
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
                spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
                                                                     (int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
                spriteBatch.End();
            }

            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
            Dictionary <Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);

            foreach (KeyValuePair <Hull, Rectangle> hull in visibleHulls)
            {
                GUI.DrawRectangle(spriteBatch,
                                  new Vector2(hull.Value.X, -hull.Value.Y),
                                  new Vector2(hull.Value.Width, hull.Value.Height),
                                  hull.Key.AmbientLight == Color.TransparentBlack ? Color.Black : hull.Key.AmbientLight.Multiply(hull.Key.AmbientLight.A / 255.0f), true);
            }
            spriteBatch.End();

            SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
            SolidColorEffect.Parameters["color"].SetValue(AmbientLight.ToVector4());
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform, effect: SolidColorEffect);
            Submarine.DrawDamageable(spriteBatch, null);
            spriteBatch.End();

            graphics.BlendState = BlendState.Additive;


            //draw the focused item and character to highlight them,
            //and light sprites (done before drawing the actual light volumes so we can make characters obstruct the highlights and sprites)
            //---------------------------------------------------------------------------------------------------
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
            foreach (LightSource light in activeLights)
            {
                //don't draw limb lights at this point, they need to be drawn after lights have been obstructed by characters
                if (light.IsBackground || light.ParentBody?.UserData is Limb || light.CurrentBrightness <= 0.0f)
                {
                    continue;
                }
                light.DrawSprite(spriteBatch, cam);
            }
            spriteBatch.End();

            if (highlightsVisible)
            {
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
                spriteBatch.Draw(HighlightMap, Vector2.Zero, Color.White);
                spriteBatch.End();
            }

            //draw characters to obstruct the highlighted items/characters and light sprites
            //---------------------------------------------------------------------------------------------------

            SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidVertexColor"];
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
            foreach (Character character in Character.CharacterList)
            {
                if (character.CurrentHull == null || !character.Enabled || !character.IsVisible)
                {
                    continue;
                }
                if (Character.Controlled?.FocusedCharacter == character)
                {
                    continue;
                }
                Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
                                   Color.Black :
                                   character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
                foreach (Limb limb in character.AnimController.Limbs)
                {
                    if (limb.DeformSprite != null)
                    {
                        continue;
                    }
                    limb.Draw(spriteBatch, cam, lightColor);
                }
            }
            spriteBatch.End();

            DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidVertexColor"];
            DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
            foreach (Character character in Character.CharacterList)
            {
                if (character.CurrentHull == null || !character.Enabled || !character.IsVisible)
                {
                    continue;
                }
                if (Character.Controlled?.FocusedCharacter == character)
                {
                    continue;
                }
                Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
                                   Color.Black :
                                   character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
                foreach (Limb limb in character.AnimController.Limbs)
                {
                    if (limb.DeformSprite == null)
                    {
                        continue;
                    }
                    limb.Draw(spriteBatch, cam, lightColor);
                }
            }
            spriteBatch.End();
            DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShader"];
            graphics.BlendState = BlendState.Additive;

            //draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
            //---------------------------------------------------------------------------------------------------
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);

            spriteBatch.Draw(LimbLightMap, new Rectangle(cam.WorldView.X, -cam.WorldView.Y, cam.WorldView.Width, cam.WorldView.Height), Color.White);

            foreach (ElectricalDischarger discharger in ElectricalDischarger.List)
            {
                discharger.DrawElectricity(spriteBatch);
            }

            foreach (LightSource light in activeLights)
            {
                if (light.IsBackground || light.CurrentBrightness <= 0.0f)
                {
                    continue;
                }
                light.DrawLightVolume(spriteBatch, lightEffect, transform);
            }

            lightEffect.World = transform;

            GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);

            if (Character.Controlled != null)
            {
                DrawHalo(Character.Controlled);
            }
            else
            {
                foreach (Character character in Character.CharacterList)
                {
                    if (character.Submarine == null || character.IsDead || !character.IsHuman)
                    {
                        continue;
                    }
                    DrawHalo(character);
                }
            }

            void DrawHalo(Character character)
            {
                if (character == null || character.Removed)
                {
                    return;
                }
                Vector2 haloDrawPos = character.DrawPosition;

                haloDrawPos.Y = -haloDrawPos.Y;

                //ambient light decreases the brightness of the halo (no need for a bright halo if the ambient light is bright enough)
                float ambientBrightness = (AmbientLight.R + AmbientLight.B + AmbientLight.G) / 255.0f / 3.0f;
                Color haloColor         = Color.White.Multiply(0.3f - ambientBrightness);

                if (haloColor.A > 0)
                {
                    float scale = 512.0f / LightSource.LightTexture.Width;
                    spriteBatch.Draw(
                        LightSource.LightTexture, haloDrawPos, null, haloColor, 0.0f,
                        new Vector2(LightSource.LightTexture.Width, LightSource.LightTexture.Height) / 2, scale, SpriteEffects.None, 0.0f);
                }
            }

            spriteBatch.End();

            //draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
            //---------------------------------------------------------------------------------------------------

            graphics.SetRenderTarget(null);
            graphics.BlendState = BlendState.NonPremultiplied;
        }
Пример #10
0
        public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
        {
            if (sections.Count == 0 && !IsActive || Hidden)
            {
                Drawable = false;
                return;
            }

            Vector2   drawOffset = Vector2.Zero;
            Submarine sub        = item.Submarine;

            if (IsActive && sub == null) // currently being rewired, we need to get the sub from the connections in case the wire has been taken outside
            {
                if (connections[0] != null && connections[0].Item.Submarine != null)
                {
                    sub = connections[0].Item.Submarine;
                }
                if (connections[1] != null && connections[1].Item.Submarine != null)
                {
                    sub = connections[1].Item.Submarine;
                }
            }

            if (sub != null)
            {
                drawOffset = sub.DrawPosition + sub.HiddenSubPosition;
            }

            float depth = item.IsSelected ? 0.0f : wireSprite.Depth + ((item.ID % 100) * 0.00001f);

            if (item.IsHighlighted)
            {
                foreach (WireSection section in sections)
                {
                    section.Draw(spriteBatch, this, Color.Gold, drawOffset, depth + 0.00001f, 0.7f);
                }
            }
            else if (item.IsSelected)
            {
                foreach (WireSection section in sections)
                {
                    section.Draw(spriteBatch, this, Color.Red, drawOffset, depth + 0.00001f, 0.7f);
                }
            }

            foreach (WireSection section in sections)
            {
                section.Draw(spriteBatch, this, item.Color, drawOffset, depth, 0.3f);
            }

            if (nodes.Count > 0)
            {
                if (!IsActive)
                {
                    if (connections[0] == null)
                    {
                        DrawHangingWire(spriteBatch, nodes[0] + drawOffset, depth);
                    }
                    if (connections[1] == null)
                    {
                        DrawHangingWire(spriteBatch, nodes.Last() + drawOffset, depth);
                    }
                }
                if (IsActive && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance)
                {
                    WireSection.Draw(
                        spriteBatch,
                        this,
                        new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
                        new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
                        item.Color * 0.5f,
                        depth,
                        0.3f);
                }
            }

            if (!editing || !GameMain.SubEditorScreen.WiringMode)
            {
                return;
            }

            for (int i = 0; i < nodes.Count; i++)
            {
                Vector2 drawPos = nodes[i];
                if (item.Submarine != null)
                {
                    drawPos += item.Submarine.Position + item.Submarine.HiddenSubPosition;
                }
                drawPos.Y = -drawPos.Y;

                if ((highlightedNodeIndex == i && item.IsHighlighted) || (selectedNodeIndex == i && item.IsSelected))
                {
                    GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-10, -10), new Vector2(20, 20), Color.Red, false, 0.0f);
                }

                if (item.IsSelected)
                {
                    GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-5, -5), new Vector2(10, 10), item.Color, true, 0.0f);
                }
                else
                {
                    GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-3, -3), new Vector2(6, 6), item.Color, true, 0.0f);
                }
            }
        }
Пример #11
0
 public Submarine(int field_w, int field_h)
 {
     x = field_w - 2;
     y = field_h - 2;
     _instance = this;
 }
Пример #12
0
        private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List <Body> ignoredBodies)
        {
            var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair;

            //if the item can cut off limbs, activate nearby bodies to allow the raycast to hit them
            if (statusEffectLists != null && statusEffectLists.ContainsKey(ActionType.OnUse))
            {
                if (statusEffectLists[ActionType.OnUse].Any(s => s.SeverLimbsProbability > 0.0f))
                {
                    float rangeSqr = ConvertUnits.ToSimUnits(Range);
                    rangeSqr *= rangeSqr;
                    foreach (Character c in Character.CharacterList)
                    {
                        if (!c.Enabled || !c.AnimController.BodyInRest)
                        {
                            continue;
                        }
                        //do a broad check first
                        if (Math.Abs(c.WorldPosition.X - item.WorldPosition.X) > 1000.0f)
                        {
                            continue;
                        }
                        if (Math.Abs(c.WorldPosition.Y - item.WorldPosition.Y) > 1000.0f)
                        {
                            continue;
                        }
                        foreach (Limb limb in c.AnimController.Limbs)
                        {
                            if (Vector2.DistanceSquared(limb.SimPosition, item.SimPosition) < rangeSqr && Vector2.Dot(rayEnd - rayStart, limb.SimPosition - rayStart) > 0)
                            {
                                c.AnimController.BodyInRest = false;
                                break;
                            }
                        }
                    }
                }
            }

            float lastPickedFraction = 0.0f;

            if (RepairMultiple)
            {
                var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories,
                                                  ignoreSensors: false,
                                                  customPredicate: (Fixture f) =>
                {
                    if (RepairThroughHoles && f.IsSensor && f.Body?.UserData is Structure)
                    {
                        return(false);
                    }
                    if (f.Body?.UserData as string == "ruinroom")
                    {
                        return(false);
                    }
                    return(true);
                },
                                                  allowInsideFixture: true);
                lastPickedFraction = Submarine.LastPickedFraction;
                Type lastHitType = null;
                hitCharacters.Clear();
                foreach (Body body in bodies)
                {
                    Type bodyType = body.UserData?.GetType();
                    if (!RepairThroughWalls && bodyType != null && bodyType != lastHitType)
                    {
                        //stop the ray if it already hit a door/wall and is now about to hit some other type of entity
                        if (lastHitType == typeof(Item) || lastHitType == typeof(Structure))
                        {
                            break;
                        }
                    }

                    Character hitCharacter = null;
                    if (body.UserData is Limb limb)
                    {
                        hitCharacter = limb.character;
                    }
                    else if (body.UserData is Character character)
                    {
                        hitCharacter = character;
                    }
                    //only do damage once to each character even if they ray hit multiple limbs
                    if (hitCharacter != null)
                    {
                        if (hitCharacters.Contains(hitCharacter))
                        {
                            continue;
                        }
                        hitCharacters.Add(hitCharacter);
                    }

                    if (FixBody(user, deltaTime, degreeOfSuccess, body))
                    {
                        lastPickedFraction = Submarine.LastPickedBodyDist(body);
                        if (bodyType != null)
                        {
                            lastHitType = bodyType;
                        }
                    }
                }
            }
            else
            {
                FixBody(user, deltaTime, degreeOfSuccess,
                        Submarine.PickBody(rayStart, rayEnd,
                                           ignoredBodies, collisionCategories,
                                           ignoreSensors: false,
                                           customPredicate: (Fixture f) =>
                {
                    if (RepairThroughHoles && f.IsSensor && f.Body?.UserData is Structure)
                    {
                        return(false);
                    }
                    if (f.Body?.UserData as string == "ruinroom")
                    {
                        return(false);
                    }
                    if (f.Body?.UserData is Item targetItem)
                    {
                        if (!HitItems)
                        {
                            return(false);
                        }
                        if (HitBrokenDoors)
                        {
                            if (targetItem.GetComponent <Door>() == null && targetItem.Condition <= 0)
                            {
                                return(false);
                            }
                        }
                        else
                        {
                            if (targetItem.Condition <= 0)
                            {
                                return(false);
                            }
                        }
                    }
                    return(f.Body?.UserData != null);
                },
                                           allowInsideFixture: true));
                lastPickedFraction = Submarine.LastPickedFraction;
            }

            if (ExtinguishAmount > 0.0f && item.CurrentHull != null)
            {
                fireSourcesInRange.Clear();
                //step along the ray in 10% intervals, collecting all fire sources in the range
                for (float x = 0.0f; x <= lastPickedFraction; x += 0.1f)
                {
                    Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * x);
                    if (item.CurrentHull.Submarine != null)
                    {
                        displayPos += item.CurrentHull.Submarine.Position;
                    }

                    Hull hull = Hull.FindHull(displayPos, item.CurrentHull);
                    if (hull == null)
                    {
                        continue;
                    }
                    foreach (FireSource fs in hull.FireSources)
                    {
                        if (fs.IsInDamageRange(displayPos, 100.0f) && !fireSourcesInRange.Contains(fs))
                        {
                            fireSourcesInRange.Add(fs);
                        }
                    }
                }

                foreach (FireSource fs in fireSourcesInRange)
                {
                    fs.Extinguish(deltaTime, ExtinguishAmount);
#if SERVER
                    GameMain.Server.KarmaManager.OnExtinguishingFire(user, deltaTime);
#endif
                }
            }


            if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
            {
                if (Rand.Range(0.0f, 1.0f) < FireProbability * deltaTime)
                {
                    Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * lastPickedFraction * 0.9f);
                    if (item.CurrentHull.Submarine != null)
                    {
                        displayPos += item.CurrentHull.Submarine.Position;
                    }
                    new FireSource(displayPos);
                }
            }
        }
Пример #13
0
        public void Dock(DockingPort target)
        {
            if (item.Submarine.DockedTo.Contains(target.item.Submarine))
            {
                return;
            }

            if (dockingTarget != null)
            {
                Undock();
            }

            if (target.item.Submarine == item.Submarine)
            {
                DebugConsole.ThrowError("Error - tried to dock a submarine to itself");
                dockingTarget = null;
                return;
            }

#if CLIENT
            PlaySound(ActionType.OnUse, item.WorldPosition);
#endif

            if (!item.linkedTo.Contains(target.item))
            {
                item.linkedTo.Add(target.item);
            }
            if (!target.item.linkedTo.Contains(item))
            {
                target.item.linkedTo.Add(item);
            }

            if (!target.item.Submarine.DockedTo.Contains(item.Submarine))
            {
                target.item.Submarine.DockedTo.Add(item.Submarine);
            }
            if (!item.Submarine.DockedTo.Contains(target.item.Submarine))
            {
                item.Submarine.DockedTo.Add(target.item.Submarine);
            }

            dockingTarget = target;
            dockingTarget.dockingTarget = this;

            docked = true;
            dockingTarget.Docked = true;

            if (Character.Controlled != null &&
                (Character.Controlled.Submarine == dockingTarget.item.Submarine || Character.Controlled.Submarine == item.Submarine))
            {
                GameMain.GameScreen.Cam.Shake = Vector2.Distance(dockingTarget.item.Submarine.Velocity, item.Submarine.Velocity);
            }

            dockingDir = IsHorizontal ?
                         Math.Sign(dockingTarget.item.WorldPosition.X - item.WorldPosition.X) :
                         Math.Sign(dockingTarget.item.WorldPosition.Y - item.WorldPosition.Y);
            dockingTarget.dockingDir = -dockingDir;


            foreach (WayPoint wp in WayPoint.WayPointList)
            {
                if (wp.Submarine != item.Submarine || wp.SpawnType != SpawnType.Path)
                {
                    continue;
                }

                if (!Submarine.RectContains(item.Rect, wp.Position))
                {
                    continue;
                }

                foreach (WayPoint wp2 in WayPoint.WayPointList)
                {
                    if (wp2.Submarine != dockingTarget.item.Submarine || wp2.SpawnType != SpawnType.Path)
                    {
                        continue;
                    }

                    if (!Submarine.RectContains(dockingTarget.item.Rect, wp2.Position))
                    {
                        continue;
                    }

                    wp.linkedTo.Add(wp2);
                    wp2.linkedTo.Add(wp);
                }
            }

            CreateJoint(false);

            if (GameMain.Server != null)
            {
                item.CreateServerEvent(this);
            }
        }
Пример #14
0
        /// <summary>
        /// Enables a workshop item by moving it to the game folder.
        /// </summary>
        public static bool EnableWorkShopItem(Workshop.Item item, bool allowFileOverwrite, out string errorMsg)
        {
            if (!item.Installed)
            {
                errorMsg = TextManager.Get("WorkshopErrorInstallRequiredToEnable").Replace("[itemname]", item.Title);
                DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                return(false);
            }

            string         metaDataFilePath      = Path.Combine(item.Directory.FullName, MetadataFileName);
            ContentPackage contentPackage        = new ContentPackage(metaDataFilePath);
            string         newContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage);

            var           allPackageFiles = Directory.GetFiles(item.Directory.FullName, "*", SearchOption.AllDirectories);
            List <string> nonContentFiles = new List <string>();

            foreach (string file in allPackageFiles)
            {
                if (file == metaDataFilePath)
                {
                    continue;
                }
                string relativePath = UpdaterUtil.GetRelativePath(file, item.Directory.FullName);
                string fullPath     = Path.GetFullPath(relativePath);
                if (contentPackage.Files.Any(f => { string fp = Path.GetFullPath(f.Path); return(fp == fullPath); }))
                {
                    continue;
                }
                if (ContentPackage.IsModFilePathAllowed(relativePath))
                {
                    nonContentFiles.Add(relativePath);
                }
            }

            if (!allowFileOverwrite)
            {
                // TODO: If you create a new mod via the workshop interface and enable it, it will show the error msg, but still allows you to enable the content.

                if (File.Exists(newContentPackagePath))
                {
                    errorMsg = TextManager.Get("WorkshopErrorOverwriteOnEnable")
                               .Replace("[itemname]", item.Title)
                               .Replace("[filename]", newContentPackagePath);
                    DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                    return(false);
                }

                foreach (ContentFile contentFile in contentPackage.Files)
                {
                    string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path);
                    if (File.Exists(sourceFile) && File.Exists(contentFile.Path))
                    {
                        errorMsg = TextManager.Get("WorkshopErrorOverwriteOnEnable")
                                   .Replace("[itemname]", item.Title)
                                   .Replace("[filename]", contentFile.Path);
                        DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                        return(false);
                    }
                }
            }

            try
            {
                foreach (ContentFile contentFile in contentPackage.Files)
                {
                    string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path);
                    if (!File.Exists(sourceFile))
                    {
                        continue;
                    }
                    if (!ContentPackage.IsModFilePathAllowed(contentFile))
                    {
                        DebugConsole.ThrowError(TextManager.Get("WorkshopErrorIllegalPathOnEnable").Replace("[filename]", contentFile.Path));
                        continue;
                    }

                    //make sure the destination directory exists
                    Directory.CreateDirectory(Path.GetDirectoryName(contentFile.Path));
                    File.Copy(sourceFile, contentFile.Path, overwrite: true);
                }

                foreach (string nonContentFile in nonContentFiles)
                {
                    string sourceFile = Path.Combine(item.Directory.FullName, nonContentFile);
                    if (!File.Exists(sourceFile))
                    {
                        continue;
                    }
                    if (!ContentPackage.IsModFilePathAllowed(nonContentFile))
                    {
                        DebugConsole.ThrowError(TextManager.Get("WorkshopErrorIllegalPathOnEnable").Replace("[filename]", nonContentFile));
                        continue;
                    }
                    Directory.CreateDirectory(Path.GetDirectoryName(nonContentFile));
                    File.Copy(sourceFile, nonContentFile, overwrite: true);
                }
            }
            catch (Exception e)
            {
                errorMsg = TextManager.Get("WorkshopErrorEnableFailed").Replace("[itemname]", item.Title) + " " + e.Message;
                DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                return(false);
            }

            var newPackage = new ContentPackage(contentPackage.Path, newContentPackagePath)
            {
                SteamWorkshopUrl = item.Url,
                InstallTime      = item.Modified > item.Created ? item.Modified : item.Created
            };

            newPackage.Save(newContentPackagePath);
            ContentPackage.List.Add(newPackage);
            if (newPackage.CorePackage)
            {
                //if enabling a core package, disable all other core packages
                GameMain.Config.SelectedContentPackages.RemoveWhere(cp => cp.CorePackage);
            }
            GameMain.Config.SelectedContentPackages.Add(newPackage);
            GameMain.Config.SaveNewPlayerConfig();

            if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
            {
                Submarine.RefreshSavedSubs();
            }

            errorMsg = "";
            return(true);
        }
Пример #15
0
        public override bool Use(float deltaTime, Character character = null)
        {
            if (character == null || character.Removed)
            {
                return(false);
            }
            if ((item.RequireAimToUse && !character.IsKeyDown(InputType.Aim)) || reloadTimer > 0.0f)
            {
                return(false);
            }
            IsActive    = true;
            reloadTimer = reload;

            List <Body> limbBodies = new List <Body>();

            foreach (Limb l in character.AnimController.Limbs)
            {
                limbBodies.Add(l.body.FarseerBody);
            }

            float degreeOfFailure = 1.0f - DegreeOfSuccess(character);

            degreeOfFailure *= degreeOfFailure;

            if (degreeOfFailure > Rand.Range(0.0f, 1.0f))
            {
                ApplyStatusEffects(ActionType.OnFailure, 1.0f, character);
            }

            Projectile projectile     = null;
            var        containedItems = item.ContainedItems;

            if (containedItems == null)
            {
                return(true);
            }

            foreach (Item item in containedItems)
            {
                projectile = item.GetComponent <Projectile>();
                if (projectile != null)
                {
                    break;
                }
            }
            //projectile not found, see if one of the contained items contains projectiles
            if (projectile == null)
            {
                foreach (Item item in containedItems)
                {
                    projectile = item.GetComponent <Projectile>();
                    if (projectile != null)
                    {
                        break;
                    }
                }
                //projectile not found, see if one of the contained items contains projectiles
                if (projectile == null)
                {
                    foreach (Item item in containedItems)
                    {
                        var containedSubItems = item.ContainedItems;
                        if (containedSubItems == null)
                        {
                            continue;
                        }
                        foreach (Item subItem in containedSubItems)
                        {
                            projectile = subItem.GetComponent <Projectile>();
                            //apply OnUse statuseffects to the container in case it has to react to it somehow
                            //(play a sound, spawn more projectiles, reduce condition...)
                            if (subItem.Condition > 0.0f)
                            {
                                subItem.GetComponent <ItemContainer>()?.Item.ApplyStatusEffects(ActionType.OnUse, deltaTime);
                            }
                            if (projectile != null)
                            {
                                break;
                            }
                        }
                    }
                }
            }

            if (projectile == null)
            {
                return(true);
            }

            float spread   = MathHelper.ToRadians(MathHelper.Lerp(Spread, UnskilledSpread, degreeOfFailure));
            float rotation = (item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi;

            rotation += spread * Rand.Range(-0.5f, 0.5f);

            projectile.User = character;
            //add the limbs of the shooter to the list of bodies to be ignored
            //so that the player can't shoot himself
            projectile.IgnoredBodies = new List <Body>(limbBodies);

            Vector2 projectilePos = item.SimPosition;
            Vector2 sourcePos     = character?.AnimController == null ? item.SimPosition : character.AnimController.AimSourceSimPos;
            Vector2 barrelPos     = TransformedBarrelPos;

            //make sure there's no obstacles between the base of the weapon (or the shoulder of the character) and the end of the barrel
            if (Submarine.PickBody(sourcePos, barrelPos, projectile.IgnoredBodies, Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking) == null)
            {
                //no obstacles -> we can spawn the projectile at the barrel
                projectilePos = barrelPos;
            }
            else if ((sourcePos - barrelPos).LengthSquared() > 0.0001f)
            {
                //spawn the projectile body.GetMaxExtent() away from the position where the raycast hit the obstacle
                projectilePos = sourcePos - Vector2.Normalize(barrelPos - projectilePos) * Math.Max(projectile.Item.body.GetMaxExtent(), 0.1f);
            }

            projectile.Item.body.ResetDynamics();
            projectile.Item.SetTransform(projectilePos, rotation);

            projectile.Use(deltaTime);
            if (projectile.Item.Removed)
            {
                return(true);
            }
            projectile.User = character;

            projectile.Item.body.ApplyTorque(projectile.Item.body.Mass * degreeOfFailure * Rand.Range(-10.0f, 10.0f));

            //set the rotation of the projectile again because dropping the projectile resets the rotation
            projectile.Item.SetTransform(projectilePos,
                                         rotation + (projectile.Item.body.Dir * projectile.LaunchRotationRadians));

            //recoil
            item.body.ApplyLinearImpulse(
                new Vector2((float)Math.Cos(projectile.Item.body.Rotation), (float)Math.Sin(projectile.Item.body.Rotation)) * item.body.Mass * -50.0f,
                maxVelocity: NetConfig.MaxPhysicsBodyVelocity);

            item.RemoveContained(projectile.Item);

            Rope rope = item.GetComponent <Rope>();

            if (rope != null)
            {
                rope.Attach(projectile.Item);
            }

            return(true);
        }
Пример #16
0
        private void UpdateAutoPilot(float deltaTime)
        {
            if (controlledSub == null)
            {
                return;
            }
            if (posToMaintain != null)
            {
                Vector2 steeringVel = GetSteeringVelocity((Vector2)posToMaintain, 10.0f);
                TargetVelocity      = Vector2.Lerp(TargetVelocity, steeringVel, AutoPilotSteeringLerp);
                showIceSpireWarning = false;
                return;
            }

            autopilotRayCastTimer         -= deltaTime;
            autopilotRecalculatePathTimer -= deltaTime;
            if (autopilotRecalculatePathTimer <= 0.0f)
            {
                //periodically recalculate the path in case the sub ends up to a position
                //where it can't keep traversing the initially calculated path
                UpdatePath();
                autopilotRecalculatePathTimer = RecalculatePathInterval;
            }

            if (steeringPath == null)
            {
                showIceSpireWarning = false;
                return;
            }
            steeringPath.CheckProgress(ConvertUnits.ToSimUnits(controlledSub.WorldPosition), 10.0f);

            connectedSubUpdateTimer -= deltaTime;
            if (connectedSubUpdateTimer <= 0.0f)
            {
                connectedSubs.Clear();
                connectedSubs           = controlledSub?.GetConnectedSubs();
                connectedSubUpdateTimer = ConnectedSubUpdateInterval;
            }

            if (autopilotRayCastTimer <= 0.0f && steeringPath.NextNode != null)
            {
                Vector2 diff = ConvertUnits.ToSimUnits(steeringPath.NextNode.Position - controlledSub.WorldPosition);

                //if the node is close enough, check if it's visible
                float lengthSqr = diff.LengthSquared();
                if (lengthSqr > 0.001f && lengthSqr < AutopilotMinDistToPathNode * AutopilotMinDistToPathNode)
                {
                    diff = Vector2.Normalize(diff);

                    //check if the next waypoint is visible from all corners of the sub
                    //(i.e. if we can navigate directly towards it or if there's obstacles in the way)
                    bool nextVisible = true;
                    for (int x = -1; x < 2; x += 2)
                    {
                        for (int y = -1; y < 2; y += 2)
                        {
                            Vector2 cornerPos =
                                new Vector2(controlledSub.Borders.Width * x, controlledSub.Borders.Height * y) / 2.0f;

                            cornerPos = ConvertUnits.ToSimUnits(cornerPos * 1.1f + controlledSub.WorldPosition);

                            float dist = Vector2.Distance(cornerPos, steeringPath.NextNode.SimPosition);

                            if (Submarine.PickBody(cornerPos, cornerPos + diff * dist, null, Physics.CollisionLevel) == null)
                            {
                                continue;
                            }

                            nextVisible = false;
                            x           = 2;
                            y           = 2;
                        }
                    }

                    if (nextVisible)
                    {
                        steeringPath.SkipToNextNode();
                    }
                }

                autopilotRayCastTimer = AutopilotRayCastInterval;
            }

            Vector2 newVelocity = Vector2.Zero;

            if (steeringPath.CurrentNode != null)
            {
                newVelocity = GetSteeringVelocity(steeringPath.CurrentNode.WorldPosition, 2.0f);
            }

            Vector2 avoidDist = new Vector2(
                Math.Max(1000.0f * Math.Abs(controlledSub.Velocity.X), controlledSub.Borders.Width * 0.75f),
                Math.Max(1000.0f * Math.Abs(controlledSub.Velocity.Y), controlledSub.Borders.Height * 0.75f));

            float avoidRadius             = avoidDist.Length();
            float damagingWallAvoidRadius = MathHelper.Clamp(avoidRadius * 1.5f, 5000.0f, 10000.0f);

            Vector2 newAvoidStrength = Vector2.Zero;

            debugDrawObstacles.Clear();

            //steer away from nearby walls
            showIceSpireWarning = false;
            var closeCells = Level.Loaded.GetCells(controlledSub.WorldPosition, 4);

            foreach (VoronoiCell cell in closeCells)
            {
                if (cell.DoesDamage)
                {
                    foreach (GraphEdge edge in cell.Edges)
                    {
                        Vector2 closestPoint = MathUtils.GetClosestPointOnLineSegment(edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, controlledSub.WorldPosition);
                        Vector2 diff         = closestPoint - controlledSub.WorldPosition;
                        float   dist         = diff.Length() - Math.Max(controlledSub.Borders.Width, controlledSub.Borders.Height) / 2;
                        if (dist > damagingWallAvoidRadius)
                        {
                            continue;
                        }

                        Vector2 normalizedDiff = Vector2.Normalize(diff);
                        float   dot            = Vector2.Dot(normalizedDiff, controlledSub.Velocity);

                        float   avoidStrength = MathHelper.Clamp(MathHelper.Lerp(1.0f, 0.0f, dist / damagingWallAvoidRadius - dot), 0.0f, 1.0f);
                        Vector2 avoid         = -normalizedDiff * avoidStrength;
                        newAvoidStrength += avoid;
                        debugDrawObstacles.Add(new ObstacleDebugInfo(edge, edge.Center, 1.0f, avoid, cell.Translation));

                        if (dot > 0.0f)
                        {
                            showIceSpireWarning = true;
                        }
                    }
                    continue;
                }

                foreach (GraphEdge edge in cell.Edges)
                {
                    if (MathUtils.GetLineIntersection(edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, controlledSub.WorldPosition, cell.Center, out Vector2 intersection))
                    {
                        Vector2 diff = controlledSub.WorldPosition - intersection;
                        //far enough -> ignore
                        if (Math.Abs(diff.X) > avoidDist.X && Math.Abs(diff.Y) > avoidDist.Y)
                        {
                            debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, 0.0f, Vector2.Zero, Vector2.Zero));
                            continue;
                        }
                        if (diff.LengthSquared() < 1.0f)
                        {
                            diff = Vector2.UnitY;
                        }

                        Vector2 normalizedDiff = Vector2.Normalize(diff);
                        float   dot            = controlledSub.Velocity == Vector2.Zero ?
                                                 0.0f : Vector2.Dot(controlledSub.Velocity, -normalizedDiff);

                        //not heading towards the wall -> ignore
                        if (dot < 1.0)
                        {
                            debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, dot, Vector2.Zero, cell.Translation));
                            continue;
                        }

                        Vector2 change = (normalizedDiff * Math.Max((avoidRadius - diff.Length()), 0.0f)) / avoidRadius;
                        if (change.LengthSquared() < 0.001f)
                        {
                            continue;
                        }
                        newAvoidStrength += change * (dot - 1.0f);
                        debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, dot - 1.0f, change * (dot - 1.0f), cell.Translation));
                    }
                }
            }

            avoidStrength  = Vector2.Lerp(avoidStrength, newAvoidStrength, deltaTime * 10.0f);
            TargetVelocity = Vector2.Lerp(TargetVelocity, newVelocity + avoidStrength * 100.0f, AutoPilotSteeringLerp);

            //steer away from other subs
            foreach (Submarine sub in Submarine.Loaded)
            {
                if (sub == controlledSub || connectedSubs.Contains(sub))
                {
                    continue;
                }
                Point   sizeSum          = controlledSub.Borders.Size + sub.Borders.Size;
                Vector2 minDist          = sizeSum.ToVector2() / 2;
                Vector2 diff             = controlledSub.WorldPosition - sub.WorldPosition;
                float   xDist            = Math.Abs(diff.X);
                float   yDist            = Math.Abs(diff.Y);
                Vector2 maxAvoidDistance = minDist * 2;
                if (xDist > maxAvoidDistance.X || yDist > maxAvoidDistance.Y)
                {
                    //far enough -> ignore
                    continue;
                }
                float dot = controlledSub.Velocity == Vector2.Zero ? 0.0f : Vector2.Dot(Vector2.Normalize(controlledSub.Velocity), -diff);
                if (dot < 0.0f)
                {
                    //heading away -> ignore
                    continue;
                }
                float distanceFactor = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(maxAvoidDistance.X + maxAvoidDistance.Y, minDist.X + minDist.Y, xDist + yDist));
                float velocityFactor = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, 3, controlledSub.Velocity.Length()));
                TargetVelocity += 100 * Vector2.Normalize(diff) * distanceFactor * velocityFactor;
            }

            //clamp velocity magnitude to 100.0f (Is this required? The X and Y components are clamped in the property setter)
            float velMagnitude = TargetVelocity.Length();

            if (velMagnitude > 100.0f)
            {
                TargetVelocity *= 100.0f / velMagnitude;
            }

#if CLIENT
            HintManager.OnAutoPilotPathUpdated(this);
#endif
        }
Пример #17
0
        public override bool Use(float deltaTime, Character character = null)
        {
            if (character == null || character.Removed)
            {
                return(false);
            }
            if ((item.RequireAimToUse && !character.IsKeyDown(InputType.Aim)) || reloadTimer > 0.0f)
            {
                return(false);
            }

            IsActive    = true;
            reloadTimer = reload;

            if (item.AiTarget != null)
            {
                item.AiTarget.SoundRange = item.AiTarget.MaxSoundRange;
                item.AiTarget.SightRange = item.AiTarget.MaxSightRange;
            }

            limbBodies.Clear();
            foreach (Limb l in character.AnimController.Limbs)
            {
                if (l.IsSevered)
                {
                    continue;
                }
                limbBodies.Add(l.body.FarseerBody);
            }

            float degreeOfFailure = 1.0f - DegreeOfSuccess(character);

            degreeOfFailure *= degreeOfFailure;
            if (degreeOfFailure > Rand.Range(0.0f, 1.0f))
            {
                ApplyStatusEffects(ActionType.OnFailure, 1.0f, character);
            }

            for (int i = 0; i < ProjectileCount; i++)
            {
                Projectile projectile = FindProjectile(triggerOnUseOnContainers: true);
                if (projectile == null)
                {
                    return(true);
                }

                float spread   = GetSpread(character);
                float rotation = (item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi;
                rotation += spread * Rand.Range(-0.5f, 0.5f);

                projectile.User = character;
                //add the limbs of the shooter to the list of bodies to be ignored
                //so that the player can't shoot himself
                projectile.IgnoredBodies = new List <Body>(limbBodies);

                Vector2 projectilePos = item.SimPosition;
                Vector2 sourcePos     = character?.AnimController == null ? item.SimPosition : character.AnimController.AimSourceSimPos;
                Vector2 barrelPos     = TransformedBarrelPos + item.body.SimPosition;
                //make sure there's no obstacles between the base of the weapon (or the shoulder of the character) and the end of the barrel
                if (Submarine.PickBody(sourcePos, barrelPos, projectile.IgnoredBodies, Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking) == null)
                {
                    //no obstacles -> we can spawn the projectile at the barrel
                    projectilePos = barrelPos;
                }
                else if ((sourcePos - barrelPos).LengthSquared() > 0.0001f)
                {
                    //spawn the projectile body.GetMaxExtent() away from the position where the raycast hit the obstacle
                    projectilePos = sourcePos - Vector2.Normalize(barrelPos - projectilePos) * Math.Max(projectile.Item.body.GetMaxExtent(), 0.1f);
                }

                projectile.Item.body.ResetDynamics();
                projectile.Item.SetTransform(projectilePos, rotation);

                projectile.Use(deltaTime);
                projectile.Item.GetComponent <Rope>()?.Attach(item, projectile.Item);
                if (projectile.Item.Removed)
                {
                    continue;
                }
                projectile.User = character;

                projectile.Item.body.ApplyTorque(projectile.Item.body.Mass * degreeOfFailure * Rand.Range(-10.0f, 10.0f));

                //set the rotation of the projectile again because dropping the projectile resets the rotation
                projectile.Item.SetTransform(projectilePos,
                                             rotation + (projectile.Item.body.Dir * projectile.LaunchRotationRadians));

                item.RemoveContained(projectile.Item);

                if (i == 0)
                {
                    //recoil
                    item.body.ApplyLinearImpulse(
                        new Vector2((float)Math.Cos(projectile.Item.body.Rotation), (float)Math.Sin(projectile.Item.body.Rotation)) * item.body.Mass * -50.0f,
                        maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
                }
            }

            LaunchProjSpecific();

            return(true);
        }
Пример #18
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            var projectiles = GetLoadedProjectiles();

            if (projectiles.Count == 0 || (projectiles.Count == 1 && objective.Option.ToLowerInvariant() != "fire at will"))
            {
                ItemContainer container = null;
                foreach (MapEntity e in item.linkedTo)
                {
                    var containerItem = e as Item;
                    if (containerItem == null)
                    {
                        continue;
                    }

                    container = containerItem.GetComponent <ItemContainer>();
                    if (container != null)
                    {
                        break;
                    }
                }

                if (container == null || container.ContainableItems.Count == 0)
                {
                    return(true);
                }

                var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Names[0], container);
                containShellObjective.IgnoreAlreadyContainedItems = true;
                objective.AddSubObjective(containShellObjective);
                return(false);
            }
            else if (GetAvailablePower() < powerConsumption)
            {
                var batteries = item.GetConnectedComponents <PowerContainer>();

                float          lowestCharge  = 0.0f;
                PowerContainer batteryToLoad = null;
                foreach (PowerContainer battery in batteries)
                {
                    if (batteryToLoad == null || battery.Charge < lowestCharge)
                    {
                        batteryToLoad = battery;
                        lowestCharge  = battery.Charge;
                    }
                }

                if (batteryToLoad == null)
                {
                    return(true);
                }

                if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f)
                {
                    objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, "", false));
                    return(false);
                }
            }

            //enough shells and power
            Character closestEnemy = null;
            float     closestDist  = 3000.0f;

            foreach (Character enemy in Character.CharacterList)
            {
                //ignore humans and characters that are inside the sub
                if (enemy.IsDead || enemy.SpeciesName == "human" || enemy.AnimController.CurrentHull != null)
                {
                    continue;
                }

                float dist = Vector2.Distance(enemy.WorldPosition, item.WorldPosition);
                if (dist < closestDist)
                {
                    closestEnemy = enemy;
                    closestDist  = dist;
                }
            }

            if (closestEnemy == null)
            {
                return(false);
            }

            character.CursorPosition = closestEnemy.WorldPosition;
            if (item.Submarine != null)
            {
                character.CursorPosition -= item.Submarine.Position;
            }
            character.SetInput(InputType.Aim, false, true);

            float enemyAngle  = MathUtils.VectorToAngle(closestEnemy.WorldPosition - item.WorldPosition);
            float turretAngle = -rotation;

            if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.01f)
            {
                return(false);
            }

            var pickedBody = Submarine.PickBody(ConvertUnits.ToSimUnits(item.WorldPosition), closestEnemy.SimPosition, null);

            if (pickedBody != null && !(pickedBody.UserData is Limb))
            {
                return(false);
            }

            if (objective.Option.ToLowerInvariant() == "fire at will")
            {
                Use(deltaTime, character);
            }

            return(false);
        }
Пример #19
0
        public override void Update(float deltaTime, Camera cam)
        {
            if (!searchedConnectedDockingPort)
            {
                FindConnectedDockingPort();
            }
            networkUpdateTimer -= deltaTime;
            if (unsentChanges)
            {
                if (networkUpdateTimer <= 0.0f)
                {
#if CLIENT
                    if (GameMain.Client != null)
                    {
                        item.CreateClientEvent(this);
                        correctionTimer = CorrectionDelay;
                    }
                    else
#endif
#if SERVER
                    if (GameMain.Server != null)
                    {
                        item.CreateServerEvent(this);
                    }
#endif

                    networkUpdateTimer = 0.1f;
                    unsentChanges      = false;
                }
            }

            controlledSub = item.Submarine;
            var sonar = item.GetComponent <Sonar>();
            if (sonar != null && sonar.UseTransducers)
            {
                controlledSub = sonar.ConnectedTransducers.Any() ? sonar.ConnectedTransducers.First().Item.Submarine : null;
            }

            currPowerConsumption = powerConsumption;

            if (Voltage < MinVoltage)
            {
                return;
            }

            if (user != null && user.Removed)
            {
                user = null;
            }

            ApplyStatusEffects(ActionType.OnActive, deltaTime, null);

            float userSkill = 0.0f;
            if (user != null && controlledSub != null &&
                (user.SelectedConstruction == item || item.linkedTo.Contains(user.SelectedConstruction)))
            {
                userSkill = user.GetSkillLevel("helm") / 100.0f;
            }

            // override autopilot pathing while the AI rams, and go full speed ahead
            if (AIRamTimer > 0f)
            {
                AIRamTimer    -= deltaTime;
                TargetVelocity = GetSteeringVelocity(AITacticalTarget, 0f);
            }
            else if (AutoPilot)
            {
                UpdateAutoPilot(deltaTime);
                float throttle = 1.0f;
                if (controlledSub != null)
                {
                    //if the sub is heading in the correct direction, throttle the speed according to the user's skill
                    //if it's e.g. sinking due to extra water, don't throttle, but allow emptying up the ballast completely
                    throttle = MathHelper.Clamp(Vector2.Dot(controlledSub.Velocity, TargetVelocity) / 100.0f, 0.0f, 1.0f);
                }
                float maxSpeed = MathHelper.Lerp(AutoPilotMaxSpeed, AIPilotMaxSpeed, userSkill) * 100.0f;
                TargetVelocity = TargetVelocity.ClampLength(MathHelper.Lerp(100.0f, maxSpeed, throttle));
            }
            else
            {
                showIceSpireWarning = false;
                if (user != null && user.Info != null &&
                    user.SelectedConstruction == item &&
                    controlledSub != null && controlledSub.Velocity.LengthSquared() > 0.01f)
                {
                    IncreaseSkillLevel(user, deltaTime);
                }

                Vector2 velocityDiff = steeringInput - targetVelocity;
                if (velocityDiff != Vector2.Zero)
                {
                    if (steeringAdjustSpeed >= 0.99f)
                    {
                        TargetVelocity = steeringInput;
                    }
                    else
                    {
                        float steeringChange = 1.0f / (1.0f - steeringAdjustSpeed);
                        steeringChange *= steeringChange * 10.0f;

                        TargetVelocity += Vector2.Normalize(velocityDiff) *
                                          Math.Min(steeringChange * deltaTime, velocityDiff.Length());
                    }
                }
            }

            float velX = targetVelocity.X;
            if (controlledSub != null && controlledSub.FlippedX)
            {
                velX *= -1;
            }
            item.SendSignal(new Signal(velX.ToString(CultureInfo.InvariantCulture), sender: user), "velocity_x_out");

            float velY = MathHelper.Lerp((neutralBallastLevel * 100 - 50) * 2, -100 * Math.Sign(targetVelocity.Y), Math.Abs(targetVelocity.Y) / 100.0f);
            item.SendSignal(new Signal(velY.ToString(CultureInfo.InvariantCulture), sender: user), "velocity_y_out");

            // if our tactical AI pilot has left, revert back to maintaining position
            if (navigateTactically && (user == null || user.SelectedConstruction != item))
            {
                navigateTactically = false;
                AIRamTimer         = 0f;
                SetMaintainPosition();
            }
        }
 private void Awake()
 {
     _submarine      = GetComponentInParent <Submarine>();
     _particleSystem = GetComponent <ParticleSystem>();
 }
Пример #21
0
        public RespawnManager(NetworkMember networkMember, SubmarineInfo shuttleInfo)
            : base(null)
        {
            this.networkMember = networkMember;

            if (shuttleInfo != null)
            {
                RespawnShuttle = new Submarine(shuttleInfo, true);
                RespawnShuttle.PhysicsBody.FarseerBody.OnCollision += OnShuttleCollision;

                //prevent wifi components from communicating between the respawn shuttle and other subs
                List <WifiComponent> wifiComponents = new List <WifiComponent>();
                foreach (Item item in Item.ItemList)
                {
                    if (item.Submarine == RespawnShuttle)
                    {
                        wifiComponents.AddRange(item.GetComponents <WifiComponent>());
                    }
                }
                foreach (WifiComponent wifiComponent in wifiComponents)
                {
                    wifiComponent.TeamID = Character.TeamType.FriendlyNPC;
                }

                ResetShuttle();

                shuttleDoors = new List <Door>();
                foreach (Item item in Item.ItemList)
                {
                    if (item.Submarine != RespawnShuttle)
                    {
                        continue;
                    }

                    var steering = item.GetComponent <Steering>();
                    if (steering != null)
                    {
                        shuttleSteering = steering;
                    }

                    var door = item.GetComponent <Door>();
                    if (door != null)
                    {
                        shuttleDoors.Add(door);
                    }

                    //lock all wires to prevent the players from messing up the electronics
                    var connectionPanel = item.GetComponent <ConnectionPanel>();
                    if (connectionPanel != null)
                    {
                        foreach (Connection connection in connectionPanel.Connections)
                        {
                            foreach (Wire wire in connection.Wires)
                            {
                                if (wire != null)
                                {
                                    wire.Locked = true;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                RespawnShuttle = null;
            }

#if SERVER
            if (networkMember is GameServer server)
            {
                maxTransportTime = server.ServerSettings.MaxTransportTime;
            }
#endif
        }
Пример #22
0
        private bool LoadElemProjSpecific(XElement subElement)
        {
            switch (subElement.Name.ToString().ToLowerInvariant())
            {
            case "guiframe":
                if (subElement.Attribute("rect") != null)
                {
                    DebugConsole.ThrowError("Error in item config \"" + item.ConfigFile + "\" - GUIFrame defined as rect, use RectTransform instead.");
                    break;
                }
                GuiFrameSource = subElement;
                ReloadGuiFrame();
                break;

            case "alternativelayout":
                AlternativeLayout = GUILayoutSettings.Load(subElement);
                break;

            case "itemsound":
            case "sound":
                string filePath = subElement.GetAttributeString("file", "");

                if (filePath == "")
                {
                    filePath = subElement.GetAttributeString("sound", "");
                }

                if (filePath == "")
                {
                    DebugConsole.ThrowError("Error when instantiating item \"" + item.Name + "\" - sound with no file path set");
                    break;
                }

                if (!filePath.Contains("/") && !filePath.Contains("\\") && !filePath.Contains(Path.DirectorySeparatorChar))
                {
                    filePath = Path.Combine(Path.GetDirectoryName(item.Prefab.FilePath), filePath);
                }

                ActionType type;
                try
                {
                    type = (ActionType)Enum.Parse(typeof(ActionType), subElement.GetAttributeString("type", ""), true);
                }
                catch (Exception e)
                {
                    DebugConsole.ThrowError("Invalid sound type in " + subElement + "!", e);
                    break;
                }

                RoundSound sound = Submarine.LoadRoundSound(subElement);
                if (sound == null)
                {
                    break;
                }
                ItemSound itemSound = new ItemSound(sound, type, subElement.GetAttributeBool("loop", false))
                {
                    VolumeProperty = subElement.GetAttributeString("volumeproperty", "").ToLowerInvariant()
                };

                if (soundSelectionModes == null)
                {
                    soundSelectionModes = new Dictionary <ActionType, SoundSelectionMode>();
                }
                if (!soundSelectionModes.ContainsKey(type) || soundSelectionModes[type] == SoundSelectionMode.Random)
                {
                    SoundSelectionMode selectionMode = SoundSelectionMode.Random;
                    Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out selectionMode);
                    soundSelectionModes[type] = selectionMode;
                }

                List <ItemSound> soundList = null;
                if (!sounds.TryGetValue(itemSound.Type, out soundList))
                {
                    soundList = new List <ItemSound>();
                    sounds.Add(itemSound.Type, soundList);
                    hasSoundsOfType[(int)itemSound.Type] = true;
                }

                soundList.Add(itemSound);
                break;

            default:
                return(false); //unknown element
            }
            return(true);      //element processed
        }
Пример #23
0
        private Item?ScanForTargets(VineTile branch)
        {
            Hull    parent   = Behavior.Parent;
            Vector2 worldPos = Behavior.GetWorldPosition() + branch.Position;
            Vector2 pos      = parent.Position + Behavior.Offset + branch.Position;

            Vector2 diameter    = ConvertUnits.ToSimUnits(new Vector2(branch.Rect.Width / 2f, branch.Rect.Height / 2f));
            Vector2 topLeft     = ConvertUnits.ToSimUnits(pos) - diameter;
            Vector2 bottomRight = ConvertUnits.ToSimUnits(pos) + diameter;

            int  highestPriority = 0;
            Item?currentItem     = null;

            foreach (Item item in Item.ItemList.Where(it => !Behavior.ClaimedTargets.Contains(it)))
            {
                if (Behavior.IgnoredTargets.ContainsKey(item))
                {
                    continue;
                }

                int priority = 0;
                foreach (BallastFloraBehavior.AITarget target in Behavior.Targets)
                {
                    if (!target.Matches(item) || target.Priority <= highestPriority)
                    {
                        continue;
                    }
                    priority = target.Priority;
                    break;
                }

                if (priority == 0)
                {
                    continue;
                }

                if (item.Submarine != parent.Submarine || Vector2.Distance(worldPos, item.WorldPosition) > Behavior.Sight)
                {
                    continue;
                }

                Vector2 itemSimPos = ConvertUnits.ToSimUnits(item.Position);

#if DEBUG
                Tuple <Vector2, Vector2> debugLine1 = Tuple.Create(parent.Position - ConvertUnits.ToDisplayUnits(topLeft), parent.Position - ConvertUnits.ToDisplayUnits(itemSimPos - diameter));
                Tuple <Vector2, Vector2> debugLine2 = Tuple.Create(parent.Position - ConvertUnits.ToDisplayUnits(bottomRight), parent.Position - ConvertUnits.ToDisplayUnits(itemSimPos + diameter));
                Behavior.debugSearchLines.Add(debugLine2);
                Behavior.debugSearchLines.Add(debugLine1);
#endif

                Body?body1 = Submarine.CheckVisibility(itemSimPos - diameter, topLeft);
                if (Blocks(body1, item))
                {
                    continue;
                }

                Body?body2 = Submarine.CheckVisibility(itemSimPos + diameter, bottomRight);
                if (Blocks(body2, item))
                {
                    continue;
                }

                highestPriority = priority;
                currentItem     = item;
            }

            if (currentItem != null)
            {
                foreach (BallastFloraBranch existingBranch in Behavior.Branches)
                {
                    if (Behavior.BranchContainsTarget(existingBranch, currentItem))
                    {
                        Behavior.ClaimTarget(currentItem, existingBranch);
                        return(null);
                    }
                }

                return(currentItem);
            }

            return(null);
Пример #24
0
        private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List <Body> ignoredBodies)
        {
            var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair;

            float lastPickedFraction = 0.0f;

            if (RepairMultiple)
            {
                var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: RepairThroughHoles, allowInsideFixture: true);
                lastPickedFraction = Submarine.LastPickedFraction;
                Type lastHitType = null;
                hitCharacters.Clear();
                foreach (Body body in bodies)
                {
                    Type bodyType = body.UserData?.GetType();
                    if (!RepairThroughWalls && bodyType != null && bodyType != lastHitType)
                    {
                        //stop the ray if it already hit a door/wall and is now about to hit some other type of entity
                        if (lastHitType == typeof(Item) || lastHitType == typeof(Structure))
                        {
                            break;
                        }
                    }

                    Character hitCharacter = null;
                    if (body.UserData is Limb limb)
                    {
                        hitCharacter = limb.character;
                    }
                    else if (body.UserData is Character character)
                    {
                        hitCharacter = character;
                    }
                    //only do damage once to each character even if they ray hit multiple limbs
                    if (hitCharacter != null)
                    {
                        if (hitCharacters.Contains(hitCharacter))
                        {
                            continue;
                        }
                        hitCharacters.Add(hitCharacter);
                    }

                    if (FixBody(user, deltaTime, degreeOfSuccess, body))
                    {
                        lastPickedFraction = Submarine.LastPickedBodyDist(body);
                        if (bodyType != null)
                        {
                            lastHitType = bodyType;
                        }
                    }
                }
            }
            else
            {
                FixBody(user, deltaTime, degreeOfSuccess,
                        Submarine.PickBody(rayStart, rayEnd,
                                           ignoredBodies, collisionCategories, ignoreSensors: RepairThroughHoles,
                                           customPredicate: (Fixture f) => { return(f?.Body?.UserData != null); },
                                           allowInsideFixture: true));
                lastPickedFraction = Submarine.LastPickedFraction;
            }

            if (ExtinguishAmount > 0.0f && item.CurrentHull != null)
            {
                fireSourcesInRange.Clear();
                //step along the ray in 10% intervals, collecting all fire sources in the range
                for (float x = 0.0f; x <= lastPickedFraction; x += 0.1f)
                {
                    Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * x);
                    if (item.CurrentHull.Submarine != null)
                    {
                        displayPos += item.CurrentHull.Submarine.Position;
                    }

                    Hull hull = Hull.FindHull(displayPos, item.CurrentHull);
                    if (hull == null)
                    {
                        continue;
                    }
                    foreach (FireSource fs in hull.FireSources)
                    {
                        if (fs.IsInDamageRange(displayPos, 100.0f) && !fireSourcesInRange.Contains(fs))
                        {
                            fireSourcesInRange.Add(fs);
                        }
                    }
                }

                foreach (FireSource fs in fireSourcesInRange)
                {
                    fs.Extinguish(deltaTime, ExtinguishAmount);
#if SERVER
                    GameMain.Server.KarmaManager.OnExtinguishingFire(user, deltaTime);
#endif
                }
            }


            if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
            {
                if (Rand.Range(0.0f, 1.0f) < FireProbability * deltaTime)
                {
                    Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * lastPickedFraction * 0.9f);
                    if (item.CurrentHull.Submarine != null)
                    {
                        displayPos += item.CurrentHull.Submarine.Position;
                    }
                    new FireSource(displayPos);
                }
            }
        }
Пример #25
0
        private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List <Body> ignoredBodies)
        {
            if (ExtinquishAmount > 0.0f && item.CurrentHull != null)
            {
                Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * Submarine.LastPickedFraction * 0.9f);

                displayPos += item.CurrentHull.Submarine.Position;

                Hull hull = Hull.FindHull(displayPos, item.CurrentHull);
                if (hull != null)
                {
                    hull.Extinguish(deltaTime, ExtinquishAmount, displayPos);
                    if (hull != item.CurrentHull)
                    {
                        item.CurrentHull.Extinguish(deltaTime, ExtinquishAmount, displayPos);
                    }
                }
            }

            Body targetBody = Submarine.PickBody(rayStart, rayEnd, ignoredBodies);

            if (targetBody == null || targetBody.UserData == null)
            {
                return;
            }

            pickedPosition = Submarine.LastPickedPosition;

            Structure targetStructure;
            Limb      targetLimb;
            Item      targetItem;

            if ((targetStructure = (targetBody.UserData as Structure)) != null)
            {
                if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Name))
                {
                    return;
                }
                if (targetStructure.IsPlatform)
                {
                    return;
                }

                int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition));
                if (sectionIndex < 0)
                {
                    return;
                }

#if CLIENT
                Vector2 progressBarPos = targetStructure.SectionPosition(sectionIndex);
                if (targetStructure.Submarine != null)
                {
                    progressBarPos += targetStructure.Submarine.DrawPosition;
                }

                var progressBar = user.UpdateHUDProgressBar(
                    targetStructure,
                    progressBarPos,
                    1.0f - targetStructure.SectionDamage(sectionIndex) / targetStructure.Health,
                    Color.Red, Color.Green);

                if (progressBar != null)
                {
                    progressBar.Size = new Vector2(60.0f, 20.0f);
                }
#endif

                targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess);

                //if the next section is small enough, apply the effect to it as well
                //(to make it easier to fix a small "left-over" section)
                for (int i = -1; i < 2; i += 2)
                {
                    int nextSectionLength = targetStructure.SectionLength(sectionIndex + i);
                    if ((sectionIndex == 1 && i == -1) ||
                        (sectionIndex == targetStructure.SectionCount - 2 && i == 1) ||
                        (nextSectionLength > 0 && nextSectionLength < Structure.wallSectionSize * 0.3f))
                    {
                        //targetStructure.HighLightSection(sectionIndex + i);
                        targetStructure.AddDamage(sectionIndex + i, -StructureFixAmount * degreeOfSuccess);
                    }
                }
            }
            else if ((targetLimb = (targetBody.UserData as Limb)) != null)
            {
                targetLimb.character.AddDamage(CauseOfDeath.Damage, -LimbFixAmount * degreeOfSuccess, user);
            }
            else if ((targetItem = (targetBody.UserData as Item)) != null)
            {
                targetItem.IsHighlighted = true;

                ApplyStatusEffects(ActionType.OnUse, targetItem.AllPropertyObjects, deltaTime);
            }
        }
Пример #26
0
        public void ThalamusOperate(WreckAI ai, float deltaTime, bool targetHumans, bool targetOtherCreatures, bool targetSubmarines, bool ignoreDelay)
        {
            if (ai == null)
            {
                return;
            }

            IsActive = true;

            if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
            {
                return;
            }

            if (updatePending)
            {
                if (updateTimer < 0.0f)
                {
#if SERVER
                    item.CreateServerEvent(this);
#endif
                    prevTargetRotation = targetRotation;
                    updateTimer        = 0.25f;
                }
                updateTimer -= deltaTime;
            }

            if (!ignoreDelay && waitTimer > 0)
            {
                waitTimer -= deltaTime;
                return;
            }
            Submarine      closestSub    = null;
            float          maxDistance   = 10000.0f;
            float          shootDistance = AIRange;
            ISpatialEntity target        = null;
            float          closestDist   = shootDistance * shootDistance;
            if (targetHumans || targetOtherCreatures)
            {
                foreach (var character in Character.CharacterList)
                {
                    if (character == null || character.Removed || character.IsDead)
                    {
                        continue;
                    }
                    if (character.Params.Group.Equals(ai.Config.Entity, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }
                    bool isHuman = character.IsHuman || character.Params.Group.Equals(CharacterPrefab.HumanSpeciesName, StringComparison.OrdinalIgnoreCase);
                    if (isHuman)
                    {
                        if (!targetHumans)
                        {
                            // Don't target humans if not defined to.
                            continue;
                        }
                    }
                    else if (!targetOtherCreatures)
                    {
                        // Don't target other creatures if not defined to.
                        continue;
                    }
                    float dist = Vector2.DistanceSquared(character.WorldPosition, item.WorldPosition);
                    if (dist > closestDist)
                    {
                        continue;
                    }
                    target      = character;
                    closestDist = dist;
                }
            }
            if (targetSubmarines)
            {
                if (target == null || target.Submarine != null)
                {
                    closestDist = maxDistance * maxDistance;
                    foreach (Submarine sub in Submarine.Loaded)
                    {
                        if (sub.Info.Type != SubmarineType.Player)
                        {
                            continue;
                        }
                        float dist = Vector2.DistanceSquared(sub.WorldPosition, item.WorldPosition);
                        if (dist > closestDist)
                        {
                            continue;
                        }
                        closestSub  = sub;
                        closestDist = dist;
                    }
                    closestDist = shootDistance * shootDistance;
                    if (closestSub != null)
                    {
                        foreach (var hull in Hull.hullList)
                        {
                            if (!closestSub.IsEntityFoundOnThisSub(hull, true))
                            {
                                continue;
                            }
                            float dist = Vector2.DistanceSquared(hull.WorldPosition, item.WorldPosition);
                            if (dist > closestDist)
                            {
                                continue;
                            }
                            target      = hull;
                            closestDist = dist;
                        }
                    }
                }
            }
            if (!ignoreDelay)
            {
                if (target == null)
                {
                    // Random movement
                    waitTimer      = Rand.Value(Rand.RandSync.Unsynced) < 0.98f ? 0f : Rand.Range(5f, 20f);
                    targetRotation = Rand.Range(minRotation, maxRotation);
                    updatePending  = true;
                    return;
                }
                if (disorderTimer < 0)
                {
                    // Random disorder
                    disorderTimer  = Rand.Range(0f, 3f);
                    waitTimer      = Rand.Range(0.25f, 1f);
                    targetRotation = MathUtils.WrapAngleTwoPi(targetRotation += Rand.Range(-1f, 1f));
                    updatePending  = true;
                    return;
                }
                else
                {
                    disorderTimer -= deltaTime;
                }
            }
            if (target == null)
            {
                return;
            }

            float angle = -MathUtils.VectorToAngle(target.WorldPosition - item.WorldPosition);
            targetRotation = MathUtils.WrapAngleTwoPi(angle);

            if (Math.Abs(targetRotation - prevTargetRotation) > 0.1f)
            {
                updatePending = true;
            }

            if (target is Hull targetHull)
            {
                Vector2 barrelDir = new Vector2((float)Math.Cos(rotation), -(float)Math.Sin(rotation));
                if (!MathUtils.GetLineRectangleIntersection(item.WorldPosition, item.WorldPosition + barrelDir * AIRange, targetHull.WorldRect, out _))
                {
                    return;
                }
            }
            else
            {
                float midRotation = (minRotation + maxRotation) / 2.0f;
                while (midRotation - angle < -MathHelper.Pi)
                {
                    angle -= MathHelper.TwoPi;
                }
                while (midRotation - angle > MathHelper.Pi)
                {
                    angle += MathHelper.TwoPi;
                }
                if (angle < minRotation || angle > maxRotation)
                {
                    return;
                }
                float enemyAngle  = MathUtils.VectorToAngle(target.WorldPosition - item.WorldPosition);
                float turretAngle = -rotation;
                if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f)
                {
                    return;
                }
            }

            Vector2 start = ConvertUnits.ToSimUnits(item.WorldPosition);
            Vector2 end   = ConvertUnits.ToSimUnits(target.WorldPosition);
            if (target.Submarine != null)
            {
                start -= target.Submarine.SimPosition;
                end   -= target.Submarine.SimPosition;
            }
            var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel;
            var pickedBody          = Submarine.PickBody(start, end, null, collisionCategories, allowInsideFixture: true,
                                                         customPredicate: (Fixture f) => { return(!item.StaticFixtures.Contains(f)); });
            if (pickedBody == null)
            {
                return;
            }
            Character targetCharacter = null;
            if (pickedBody.UserData is Character c)
            {
                targetCharacter = c;
            }
            else if (pickedBody.UserData is Limb limb)
            {
                targetCharacter = limb.character;
            }
            if (targetCharacter != null)
            {
                if (targetCharacter.Params.Group.Equals(ai.Config.Entity, StringComparison.OrdinalIgnoreCase))
                {
                    // Don't shoot friendly characters
                    return;
                }
            }
            else
            {
                if (pickedBody.UserData is ISpatialEntity e)
                {
                    Submarine sub = e.Submarine;
                    if (sub == null)
                    {
                        return;
                    }
                    if (!targetSubmarines)
                    {
                        return;
                    }
                    if (sub == Item.Submarine)
                    {
                        return;
                    }
                    // Don't shoot non-player submarines, i.e. wrecks or outposts.
                    if (!sub.Info.IsPlayer)
                    {
                        return;
                    }
                }
                else
                {
                    // Hit something else, probably a level wall
                    return;
                }
            }
            TryLaunch(deltaTime, ignorePower: true);
        }
Пример #27
0
        /// <summary>
        /// Disables a workshop item by removing the files from the game folder.
        /// </summary>
        public static bool DisableWorkShopItem(Workshop.Item item, out string errorMsg)
        {
            if (!item.Installed)
            {
                errorMsg = "Cannot disable workshop item \"" + item.Title + "\" because it has not been installed.";
                DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                return(false);
            }

            ContentPackage contentPackage = new ContentPackage(Path.Combine(item.Directory.FullName, MetadataFileName));
            string         installedContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage);

            var           allPackageFiles = Directory.GetFiles(item.Directory.FullName, "*", SearchOption.AllDirectories);
            List <string> nonContentFiles = new List <string>();

            foreach (string file in allPackageFiles)
            {
                if (file == MetadataFileName)
                {
                    continue;
                }
                string relativePath = UpdaterUtil.GetRelativePath(file, item.Directory.FullName);
                string fullPath     = Path.GetFullPath(relativePath);
                if (contentPackage.Files.Any(f => { string fp = Path.GetFullPath(f.Path); return(fp == fullPath); }))
                {
                    continue;
                }
                if (ContentPackage.IsModFilePathAllowed(relativePath))
                {
                    nonContentFiles.Add(relativePath);
                }
            }
            if (File.Exists(installedContentPackagePath))
            {
                File.Delete(installedContentPackagePath);
            }

            bool wasSub = contentPackage.Files.Any(f => f.Type == ContentType.Submarine);

            HashSet <string> directories = new HashSet <string>();

            try
            {
                foreach (ContentFile contentFile in contentPackage.Files)
                {
                    if (!ContentPackage.IsModFilePathAllowed(contentFile))
                    {
                        //Workshop items are not allowed to add or modify files in the Content or Data folders;
                        continue;
                    }
                    if (!File.Exists(contentFile.Path))
                    {
                        continue;
                    }
                    File.Delete(contentFile.Path);
                    directories.Add(Path.GetDirectoryName(contentFile.Path));
                }
                foreach (string nonContentFile in nonContentFiles)
                {
                    if (!ContentPackage.IsModFilePathAllowed(nonContentFile))
                    {
                        //Workshop items are not allowed to add or modify files in the Content or Data folders;
                        continue;
                    }
                    if (!File.Exists(nonContentFile))
                    {
                        continue;
                    }
                    File.Delete(nonContentFile);
                    directories.Add(Path.GetDirectoryName(nonContentFile));
                }

                foreach (string directory in directories)
                {
                    if (string.IsNullOrWhiteSpace(directory) || !Directory.Exists(directory))
                    {
                        continue;
                    }
                    if (Directory.GetFiles(directory, "*", SearchOption.AllDirectories).Count() == 0)
                    {
                        Directory.Delete(directory, recursive: true);
                    }
                }

                ContentPackage.List.RemoveAll(cp => System.IO.Path.GetFullPath(cp.Path) == System.IO.Path.GetFullPath(installedContentPackagePath));
                GameMain.Config.SelectedContentPackages.RemoveWhere(cp => !ContentPackage.List.Contains(cp));
                GameMain.Config.SaveNewPlayerConfig();
            }
            catch (Exception e)
            {
                errorMsg = "Disabling the workshop item \"" + item.Title + "\" failed. " + e.Message;
                DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                return(false);
            }

            if (wasSub)
            {
                Submarine.RefreshSavedSubs();
            }

            errorMsg = "";
            return(true);
        }
Пример #28
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            if (character.AIController.SelectedAiTarget?.Entity is Character previousTarget &&
                previousTarget.IsDead)
            {
                character?.Speak(TextManager.Get("DialogTurretTargetDead"), null, 0.0f, "killedtarget" + previousTarget.ID, 30.0f);
                character.AIController.SelectTarget(null);
            }

            if (GetAvailableBatteryPower() < powerConsumption)
            {
                var batteries = item.GetConnectedComponents <PowerContainer>();

                float          lowestCharge  = 0.0f;
                PowerContainer batteryToLoad = null;
                foreach (PowerContainer battery in batteries)
                {
                    if (battery.Item.NonInteractable)
                    {
                        continue;
                    }
                    if (batteryToLoad == null || battery.Charge < lowestCharge)
                    {
                        batteryToLoad = battery;
                        lowestCharge  = battery.Charge;
                    }
                }

                if (batteryToLoad == null)
                {
                    return(true);
                }

                if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f)
                {
                    objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, objective.objectiveManager, option: "", requireEquip: false));
                    return(false);
                }
            }

            int usableProjectileCount = 0;
            int maxProjectileCount    = 0;

            foreach (MapEntity e in item.linkedTo)
            {
                if (item.NonInteractable)
                {
                    continue;
                }
                if (e is Item projectileContainer)
                {
                    var containedItems = projectileContainer.ContainedItems;
                    if (containedItems != null)
                    {
                        var container = projectileContainer.GetComponent <ItemContainer>();
                        maxProjectileCount += container.Capacity;

                        int projectiles = containedItems.Count(it => it.Condition > 0.0f);
                        usableProjectileCount += projectiles;
                    }
                }
            }

            if (usableProjectileCount == 0)
            {
                ItemContainer container     = null;
                Item          containerItem = null;
                foreach (MapEntity e in item.linkedTo)
                {
                    containerItem = e as Item;
                    if (containerItem == null)
                    {
                        continue;
                    }
                    if (containerItem.NonInteractable)
                    {
                        continue;
                    }
                    if (character.AIController is HumanAIController aiController && aiController.IgnoredItems.Contains(containerItem))
                    {
                        continue;
                    }
                    container = containerItem.GetComponent <ItemContainer>();
                    if (container != null)
                    {
                        break;
                    }
                }
                if (container == null || container.ContainableItems.Count == 0)
                {
                    character.Speak(TextManager.GetWithVariable("DialogCannotLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "cannotloadturret", 30.0f);
                    return(true);
                }
                if (objective.SubObjectives.None())
                {
                    if (!AIDecontainEmptyItems(character, objective, equip: true, sourceContainer: container))
                    {
                        return(false);
                    }
                }
                if (objective.SubObjectives.None())
                {
                    var loadItemsObjective = AIContainItems <Turret>(container, character, objective, usableProjectileCount + 1, equip: true, removeEmpty: true, dropItemOnDeselected: true);
                    if (loadItemsObjective == null)
                    {
                        if (usableProjectileCount == 0)
                        {
                            character.Speak(TextManager.GetWithVariable("DialogCannotLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "cannotloadturret", 30.0f);
                            return(true);
                        }
                    }
                    else
                    {
                        loadItemsObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
                        character.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "loadturret", 30.0f);
                        return(false);
                    }
                }
                if (objective.SubObjectives.Any())
                {
                    return(false);
                }
            }

            //enough shells and power
            Character closestEnemy = null;
            float     closestDist  = AIRange * AIRange;

            foreach (Character enemy in Character.CharacterList)
            {
                // Ignore dead, friendly, and those that are inside the same sub
                if (enemy.IsDead || !enemy.Enabled || enemy.Submarine == character.Submarine)
                {
                    continue;
                }
                if (HumanAIController.IsFriendly(character, enemy))
                {
                    continue;
                }

                float dist = Vector2.DistanceSquared(enemy.WorldPosition, item.WorldPosition);
                if (dist > closestDist)
                {
                    continue;
                }

                float angle       = -MathUtils.VectorToAngle(enemy.WorldPosition - item.WorldPosition);
                float midRotation = (minRotation + maxRotation) / 2.0f;
                while (midRotation - angle < -MathHelper.Pi)
                {
                    angle -= MathHelper.TwoPi;
                }
                while (midRotation - angle > MathHelper.Pi)
                {
                    angle += MathHelper.TwoPi;
                }

                if (angle < minRotation || angle > maxRotation)
                {
                    continue;
                }

                closestEnemy = enemy;
                closestDist  = dist;
            }

            if (closestEnemy == null)
            {
                return(false);
            }

            character.AIController.SelectTarget(closestEnemy.AiTarget);

            character.CursorPosition = closestEnemy.WorldPosition;
            if (character.Submarine != null)
            {
                character.CursorPosition -= character.Submarine.Position;
            }

            float enemyAngle  = MathUtils.VectorToAngle(closestEnemy.WorldPosition - item.WorldPosition);
            float turretAngle = -rotation;

            if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f)
            {
                return(false);
            }


            Vector2 start = ConvertUnits.ToSimUnits(item.WorldPosition);
            Vector2 end   = ConvertUnits.ToSimUnits(closestEnemy.WorldPosition);

            if (closestEnemy.Submarine != null)
            {
                start -= closestEnemy.Submarine.SimPosition;
                end   -= closestEnemy.Submarine.SimPosition;
            }
            var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel;
            var pickedBody          = Submarine.PickBody(start, end, null, collisionCategories, allowInsideFixture: true,
                                                         customPredicate: (Fixture f) => { return(!item.StaticFixtures.Contains(f)); });

            if (pickedBody == null)
            {
                return(false);
            }
            Character targetCharacter = null;

            if (pickedBody.UserData is Character c)
            {
                targetCharacter = c;
            }
            else if (pickedBody.UserData is Limb limb)
            {
                targetCharacter = limb.character;
            }
            if (targetCharacter != null)
            {
                if (HumanAIController.IsFriendly(character, targetCharacter))
                {
                    // Don't shoot friendly characters
                    return(false);
                }
            }
            else
            {
                if (pickedBody.UserData is ISpatialEntity e)
                {
                    Submarine sub = e.Submarine;
                    if (sub == null)
                    {
                        return(false);
                    }
                    if (sub == Item.Submarine)
                    {
                        return(false);
                    }
                    // Don't shoot non-player submarines, i.e. wrecks or outposts.
                    if (!sub.Info.IsPlayer)
                    {
                        return(false);
                    }
                    // Don't shoot friendly submarines.
                    if (sub.TeamID == Item.Submarine.TeamID)
                    {
                        return(false);
                    }
                }
                else
                {
                    // Hit something else, probably a level wall
                    return(false);
                }
            }
            character?.Speak(TextManager.GetWithVariable("DialogFireTurret", "[itemname]", item.Name, true), null, 0.0f, "fireturret", 5.0f);
            character.SetInput(InputType.Shoot, true, true);
            return(false);
        }
Пример #29
0
        public override bool Use(float deltaTime, Character character = null)
        {
            if (character != null)
            {
                if (item.RequireAimToUse && !character.IsKeyDown(InputType.Aim))
                {
                    return(false);
                }
            }

            float degreeOfSuccess = character == null ? 0.5f : DegreeOfSuccess(character);

            if (Rand.Range(0.0f, 0.5f) > degreeOfSuccess)
            {
                ApplyStatusEffects(ActionType.OnFailure, deltaTime, character);
                return(false);
            }

            if (UsableIn == UseEnvironment.None)
            {
                ApplyStatusEffects(ActionType.OnFailure, deltaTime, character);
                return(false);
            }

            if (item.InWater)
            {
                if (UsableIn == UseEnvironment.Air)
                {
                    ApplyStatusEffects(ActionType.OnFailure, deltaTime, character);
                    return(false);
                }
            }
            else
            {
                if (UsableIn == UseEnvironment.Water)
                {
                    ApplyStatusEffects(ActionType.OnFailure, deltaTime, character);
                    return(false);
                }
            }

            Vector2 rayStart;
            Vector2 sourcePos = character?.AnimController == null ? item.SimPosition : character.AnimController.AimSourceSimPos;
            Vector2 barrelPos = item.SimPosition + ConvertUnits.ToSimUnits(TransformedBarrelPos);

            //make sure there's no obstacles between the base of the item (or the shoulder of the character) and the end of the barrel
            if (Submarine.PickBody(sourcePos, barrelPos, collisionCategory: Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking) == null)
            {
                //no obstacles -> we start the raycast at the end of the barrel
                rayStart = ConvertUnits.ToSimUnits(item.WorldPosition + TransformedBarrelPos);
            }
            else
            {
                rayStart = Submarine.LastPickedPosition + Submarine.LastPickedNormal * 0.1f;
                if (item.Submarine != null)
                {
                    rayStart += item.Submarine.SimPosition;
                }
            }

            float   spread = MathHelper.ToRadians(MathHelper.Lerp(UnskilledSpread, Spread, degreeOfSuccess));
            float   angle  = item.body.Rotation + spread * Rand.Range(-0.5f, 0.5f);
            Vector2 rayEnd = rayStart +
                             ConvertUnits.ToSimUnits(new Vector2(
                                                         (float)Math.Cos(angle),
                                                         (float)Math.Sin(angle)) * Range * item.body.Dir);

            ignoredBodies.Clear();
            if (character != null)
            {
                foreach (Limb limb in character.AnimController.Limbs)
                {
                    if (Rand.Range(0.0f, 0.5f) > degreeOfSuccess)
                    {
                        continue;
                    }
                    ignoredBodies.Add(limb.body.FarseerBody);
                }
                ignoredBodies.Add(character.AnimController.Collider.FarseerBody);
            }

            IsActive    = true;
            activeTimer = 0.1f;

            debugRayStartPos = ConvertUnits.ToDisplayUnits(rayStart);
            debugRayEndPos   = ConvertUnits.ToDisplayUnits(rayEnd);

            Submarine parentSub = character?.Submarine ?? item.Submarine;

            if (parentSub == null)
            {
                foreach (Submarine sub in Submarine.Loaded)
                {
                    Rectangle subBorders = sub.Borders;
                    subBorders.Location += new Point((int)sub.WorldPosition.X, (int)sub.WorldPosition.Y - sub.Borders.Height);
                    if (!MathUtils.CircleIntersectsRectangle(item.WorldPosition, Range * 5.0f, subBorders))
                    {
                        continue;
                    }
                    Repair(rayStart - sub.SimPosition, rayEnd - sub.SimPosition, deltaTime, character, degreeOfSuccess, ignoredBodies);
                }
                Repair(rayStart, rayEnd, deltaTime, character, degreeOfSuccess, ignoredBodies);
            }
            else
            {
                Repair(rayStart - parentSub.SimPosition, rayEnd - parentSub.SimPosition, deltaTime, character, degreeOfSuccess, ignoredBodies);
            }

            UseProjSpecific(deltaTime, rayStart);

            return(true);
        }
Пример #30
0
    public override IEnumerator CounterMeasureEffect(Submarine submarine)
    {
        submarine.PickRandomInterrestPoint();

        yield return(base.CounterMeasureEffect(submarine));
    }
Пример #31
0
        public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
        {
            if (!(objective.OperateTarget is Gap leak))
            {
                return(true);
            }
            if (leak.Submarine == null)
            {
                return(true);
            }
            Vector2 fromCharacterToLeak = leak.WorldPosition - character.WorldPosition;
            float   dist  = fromCharacterToLeak.Length();
            float   reach = Range + ConvertUnits.ToDisplayUnits(((HumanoidAnimController)character.AnimController).ArmLength);

            //too far away -> consider this done and hope the AI is smart enough to move closer
            if (dist > reach * 2)
            {
                return(true);
            }
            character.AIController.SteeringManager.Reset();
            //steer closer if almost in range
            if (dist > reach)
            {
                if (character.AnimController.InWater)
                {
                    if (character.AIController.SteeringManager is IndoorsSteeringManager indoorSteering)
                    {
                        // Swimming inside the sub
                        if (indoorSteering.CurrentPath != null && !indoorSteering.IsPathDirty && indoorSteering.CurrentPath.Unreachable)
                        {
                            Vector2 dir = Vector2.Normalize(fromCharacterToLeak);
                            character.AIController.SteeringManager.SteeringManual(deltaTime, dir);
                        }
                        else
                        {
                            character.AIController.SteeringManager.SteeringSeek(character.GetRelativeSimPosition(leak));
                        }
                    }
                    else
                    {
                        // Swimming outside the sub
                        character.AIController.SteeringManager.SteeringSeek(character.GetRelativeSimPosition(leak));
                    }
                }
                else
                {
                    // TODO: use the collider size?
                    if (!character.AnimController.InWater && character.AnimController is HumanoidAnimController &&
                        Math.Abs(fromCharacterToLeak.X) < 100.0f && fromCharacterToLeak.Y < 0.0f && fromCharacterToLeak.Y > -150.0f)
                    {
                        ((HumanoidAnimController)character.AnimController).Crouching = true;
                    }
                    Vector2 standPos = new Vector2(Math.Sign(-fromCharacterToLeak.X), Math.Sign(-fromCharacterToLeak.Y)) / 2;
                    if (leak.IsHorizontal)
                    {
                        standPos.X *= 2;
                        standPos.Y  = 0;
                    }
                    else
                    {
                        standPos.X = 0;
                    }
                    character.AIController.SteeringManager.SteeringSeek(standPos);
                }
            }
            else
            {
                if (dist < reach / 2)
                {
                    // Too close -> steer away
                    character.AIController.SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(character.SimPosition - leak.SimPosition));
                }
                else if (dist <= reach)
                {
                    // In range
                    character.CursorPosition  = leak.Position;
                    character.CursorPosition += VectorExtensions.Forward(Item.body.TransformedRotation + (float)Math.Sin(sinTime) / 2, dist / 2);
                    if (character.AnimController.InWater)
                    {
                        var torso = character.AnimController.GetLimb(LimbType.Torso);
                        // Turn facing the target when not moving (handled in the animcontroller if not moving)
                        Vector2 mousePos    = ConvertUnits.ToSimUnits(character.CursorPosition);
                        Vector2 diff        = (mousePos - torso.SimPosition) * character.AnimController.Dir;
                        float   newRotation = MathUtils.VectorToAngle(diff);
                        character.AnimController.Collider.SmoothRotate(newRotation, 5.0f);

                        if (VectorExtensions.Angle(VectorExtensions.Forward(torso.body.TransformedRotation), fromCharacterToLeak) < MathHelper.PiOver4)
                        {
                            // Swim past
                            Vector2 moveDir = leak.IsHorizontal ? Vector2.UnitY : Vector2.UnitX;
                            moveDir *= character.AnimController.Dir;
                            character.AIController.SteeringManager.SteeringManual(deltaTime, moveDir);
                        }
                    }
                }
            }
            if (item.RequireAimToUse)
            {
                bool isOperatingButtons = false;
                if (character.AIController.SteeringManager is IndoorsSteeringManager indoorSteering)
                {
                    var door = indoorSteering.CurrentPath?.CurrentNode?.ConnectedDoor;
                    if (door != null && !door.IsOpen)
                    {
                        isOperatingButtons = door.HasIntegratedButtons || door.Item.GetConnectedComponents <Controller>(true).Any();
                    }
                }
                if (!isOperatingButtons)
                {
                    character.SetInput(InputType.Aim, false, true);
                }
                sinTime += deltaTime * 5;
            }
            // Press the trigger only when the tool is approximately facing the target.
            Vector2 fromItemToLeak = leak.WorldPosition - item.WorldPosition;
            var     angle          = VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak);

            if (angle < MathHelper.PiOver4)
            {
                // Check that we don't hit any friendlies
                if (Submarine.PickBodies(item.SimPosition, leak.SimPosition, collisionCategory: Physics.CollisionCharacter).None(hit =>
                {
                    if (hit.UserData is Character c)
                    {
                        if (c == character)
                        {
                            return(false);
                        }
                        return(HumanAIController.IsFriendly(character, c));
                    }
                    return(false);
                }))
                {
                    character.SetInput(InputType.Shoot, false, true);
                    Use(deltaTime, character);
                }
            }

            bool leakFixed = (leak.Open <= 0.0f || leak.Removed) &&
                             (leak.ConnectedWall == null || leak.ConnectedWall.Sections.Average(s => s.damage) < 1);

            if (leakFixed && leak.FlowTargetHull != null)
            {
                if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
                {
                    character.Speak(TextManager.GetWithVariable("DialogLeaksFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leaksfixed", 10.0f);
                }
                else
                {
                    character.Speak(TextManager.GetWithVariable("DialogLeakFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leakfixed", 10.0f);
                }
            }

            return(leakFixed);
        }
Пример #32
0
 private void InitSubmarine()
 {
     su = new Submarine(w, h);
     su = Submarine.Instance;
 }
Пример #33
0
        private void CreateHull()
        {
            var hullRects = new Rectangle[] { item.WorldRect, dockingTarget.item.WorldRect };
            var subs      = new Submarine[] { item.Submarine, dockingTarget.item.Submarine };

            hulls  = new Hull[2];
            bodies = new Body[4];

            if (dockingTarget.door != null)
            {
                CreateDoorBody();
            }

            if (door != null)
            {
                dockingTarget.CreateDoorBody();
            }

            if (IsHorizontal)
            {
                if (hullRects[0].Center.X > hullRects[1].Center.X)
                {
                    hullRects = new Rectangle[] { dockingTarget.item.WorldRect, item.WorldRect };
                    subs      = new Submarine[] { dockingTarget.item.Submarine, item.Submarine };
                }

                hullRects[0] = new Rectangle(hullRects[0].Center.X, hullRects[0].Y, ((int)DockedDistance / 2), hullRects[0].Height);
                hullRects[1] = new Rectangle(hullRects[1].Center.X - ((int)DockedDistance / 2), hullRects[1].Y, ((int)DockedDistance / 2), hullRects[1].Height);

                for (int i = 0; i < 2; i++)
                {
                    hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
                    hulls[i] = new Hull(MapEntityPrefab.list.Find(m => m.Name == "Hull"), hullRects[i], subs[i]);
                    hulls[i].AddToGrid(subs[i]);

                    for (int j = 0; j < 2; j++)
                    {
                        bodies[i + j * 2] = BodyFactory.CreateEdge(GameMain.World,
                                                                   ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X, hullRects[i].Y - hullRects[i].Height * j)),
                                                                   ConvertUnits.ToSimUnits(new Vector2(hullRects[i].Right, hullRects[i].Y - hullRects[i].Height * j)));
                    }
                }

                gap = new Gap(new Rectangle(hullRects[0].Right - 2, hullRects[0].Y, 4, hullRects[0].Height), true, subs[0]);
                if (gapId != null)
                {
                    gap.ID = (ushort)gapId;
                }

                LinkHullsToGap();
            }
            else
            {
                if (hullRects[0].Center.Y > hullRects[1].Center.Y)
                {
                    hullRects = new Rectangle[] { dockingTarget.item.WorldRect, item.WorldRect };
                    subs      = new Submarine[] { dockingTarget.item.Submarine, item.Submarine };
                }

                hullRects[0] = new Rectangle(hullRects[0].X, hullRects[0].Y + (int)(-hullRects[0].Height + DockedDistance) / 2, hullRects[0].Width, ((int)DockedDistance / 2));
                hullRects[1] = new Rectangle(hullRects[1].X, hullRects[1].Y - hullRects[1].Height / 2, hullRects[1].Width, ((int)DockedDistance / 2));

                for (int i = 0; i < 2; i++)
                {
                    hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
                    hulls[i] = new Hull(MapEntityPrefab.list.Find(m => m.Name == "Hull"), hullRects[i], subs[i]);
                    hulls[i].AddToGrid(subs[i]);

                    if (hullIds[i] != null)
                    {
                        hulls[i].ID = (ushort)hullIds[i];
                    }
                }

                gap = new Gap(new Rectangle(hullRects[0].X, hullRects[0].Y + 2, hullRects[0].Width, 4), false, subs[0]);
                if (gapId != null)
                {
                    gap.ID = (ushort)gapId;
                }

                LinkHullsToGap();
            }

            item.linkedTo.Add(hulls[0]);
            item.linkedTo.Add(hulls[1]);

            hullIds[0] = hulls[0].ID;
            hullIds[1] = hulls[1].ID;

            gap.DisableHullRechecks = true;
            gapId = gap.ID;

            item.linkedTo.Add(gap);

            foreach (Body body in bodies)
            {
                if (body == null)
                {
                    continue;
                }
                body.BodyType = BodyType.Static;
                body.Friction = 0.5f;

                body.CollisionCategories = Physics.CollisionWall;
            }
        }
Пример #34
0
        public static void UpdateEditing(List <Wire> wires)
        {
            //dragging a node of some wire
            if (draggingWire != null)
            {
                //cancel dragging
                if (!PlayerInput.LeftButtonHeld())
                {
                    draggingWire      = null;
                    selectedNodeIndex = null;
                }
                //update dragging
                else
                {
                    MapEntity.DisableSelect = true;

                    Submarine sub = null;
                    if (draggingWire.connections[0] != null && draggingWire.connections[0].Item.Submarine != null)
                    {
                        sub = draggingWire.connections[0].Item.Submarine;
                    }
                    if (draggingWire.connections[1] != null && draggingWire.connections[1].Item.Submarine != null)
                    {
                        sub = draggingWire.connections[1].Item.Submarine;
                    }

                    Vector2 nodeWorldPos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition) - sub.HiddenSubPosition - sub.Position;// Nodes[(int)selectedNodeIndex];

                    nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f);
                    nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f);

                    draggingWire.nodes[(int)selectedNodeIndex] = nodeWorldPos;
                    draggingWire.UpdateSections();

                    MapEntity.SelectEntity(draggingWire.item);
                }

                return;
            }

            //a wire has been selected -> check if we should start dragging one of the nodes
            float nodeSelectDist = 10, sectionSelectDist = 5;

            highlightedNodeIndex = null;
            if (MapEntity.SelectedList.Count == 1 && MapEntity.SelectedList[0] is Item)
            {
                Wire selectedWire = ((Item)MapEntity.SelectedList[0]).GetComponent <Wire>();

                if (selectedWire != null)
                {
                    Vector2 mousePos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                    if (selectedWire.item.Submarine != null)
                    {
                        mousePos -= (selectedWire.item.Submarine.Position + selectedWire.item.Submarine.HiddenSubPosition);
                    }

                    //left click while holding ctrl -> check if the cursor is on a wire section,
                    //and add a new node if it is
                    if (PlayerInput.KeyDown(Keys.RightControl) || PlayerInput.KeyDown(Keys.LeftControl))
                    {
                        if (PlayerInput.LeftButtonClicked())
                        {
                            float temp = 0.0f;
                            int   closestSectionIndex = selectedWire.GetClosestSectionIndex(mousePos, sectionSelectDist, out temp);

                            if (closestSectionIndex > -1)
                            {
                                selectedWire.nodes.Insert(closestSectionIndex + 1, mousePos);
                                selectedWire.UpdateSections();
                            }
                        }
                    }
                    else
                    {
                        //check if close enough to a node
                        float temp         = 0.0f;
                        int   closestIndex = selectedWire.GetClosestNodeIndex(mousePos, nodeSelectDist, out temp);
                        if (closestIndex > -1)
                        {
                            highlightedNodeIndex = closestIndex;
                            //start dragging the node
                            if (PlayerInput.LeftButtonHeld())
                            {
                                draggingWire      = selectedWire;
                                selectedNodeIndex = closestIndex;
                            }
                            //remove the node
                            else if (PlayerInput.RightButtonClicked() && closestIndex > 0 && closestIndex < selectedWire.nodes.Count - 1)
                            {
                                selectedWire.nodes.RemoveAt(closestIndex);
                                selectedWire.UpdateSections();
                            }
                        }
                    }
                }
            }

            //check which wire is highlighted with the cursor
            Wire  highlighted = null;
            float closestDist = float.PositiveInfinity;

            foreach (Wire w in wires)
            {
                Vector2 mousePos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                if (w.item.Submarine != null)
                {
                    mousePos -= (w.item.Submarine.Position + w.item.Submarine.HiddenSubPosition);
                }

                float dist            = 0.0f;
                int   highlightedNode = w.GetClosestNodeIndex(mousePos, highlighted == null ? nodeSelectDist : closestDist, out dist);
                if (highlightedNode > -1)
                {
                    if (dist < closestDist)
                    {
                        highlightedNodeIndex = highlightedNode;
                        highlighted          = w;
                        closestDist          = dist;
                    }
                }

                if (w.GetClosestSectionIndex(mousePos, highlighted == null ? sectionSelectDist : closestDist, out dist) > -1)
                {
                    //prefer nodes over sections
                    if (dist + nodeSelectDist * 0.5f < closestDist)
                    {
                        highlightedNodeIndex = null;
                        highlighted          = w;
                        closestDist          = dist + nodeSelectDist * 0.5f;
                    }
                }
            }

            if (highlighted != null)
            {
                highlighted.item.IsHighlighted = true;

                if (PlayerInput.LeftButtonClicked())
                {
                    MapEntity.DisableSelect = true;
                    MapEntity.SelectEntity(highlighted.item);
                }
            }
        }
Пример #35
0
 public MainGameScreen(Submarine owner)
     : base(owner)
 {
 }
Пример #36
0
        /// <summary>
        /// Enables a workshop item by moving it to the game folder.
        /// </summary>
        public static bool EnableWorkShopItem(Workshop.Item item, bool allowFileOverwrite, out string errorMsg)
        {
            if (!item.Installed)
            {
                errorMsg = TextManager.GetWithVariable("WorkshopErrorInstallRequiredToEnable", "[itemname]", item.Title);
                DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                return(false);
            }

            string         metaDataFilePath      = Path.Combine(item.Directory.FullName, MetadataFileName);
            ContentPackage contentPackage        = new ContentPackage(metaDataFilePath);
            string         newContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage);

            if (!contentPackage.IsCompatible())
            {
                errorMsg = TextManager.GetWithVariables(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
                                                        new string[3] {
                    "[packagename]", "[packageversion]", "[gameversion]"
                }, new string[3] {
                    contentPackage.Name, contentPackage.GameVersion.ToString(), GameMain.Version.ToString()
                });
                return(false);
            }

            if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List <ContentType> missingContentTypes))
            {
                errorMsg = TextManager.GetWithVariables("ContentPackageMissingCoreFiles", new string[2] {
                    "[packagename]", "[missingfiletypes]"
                },
                                                        new string[2] {
                    contentPackage.Name, string.Join(", ", missingContentTypes)
                }, new bool[2] {
                    false, true
                });
                return(false);
            }

            var           allPackageFiles = Directory.GetFiles(item.Directory.FullName, "*", SearchOption.AllDirectories);
            List <string> nonContentFiles = new List <string>();

            foreach (string file in allPackageFiles)
            {
                if (file == metaDataFilePath)
                {
                    continue;
                }
                string relativePath = UpdaterUtil.GetRelativePath(file, item.Directory.FullName);
                string fullPath     = Path.GetFullPath(relativePath);
                if (contentPackage.Files.Any(f => { string fp = Path.GetFullPath(f.Path); return(fp == fullPath); }))
                {
                    continue;
                }
                if (ContentPackage.IsModFilePathAllowed(relativePath))
                {
                    nonContentFiles.Add(relativePath);
                }
            }

            if (!allowFileOverwrite)
            {
                if (File.Exists(newContentPackagePath) && !CheckFileEquality(newContentPackagePath, metaDataFilePath))
                {
                    errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] {
                        "[itemname]", "[filename]"
                    }, new string[2] {
                        item.Title, newContentPackagePath
                    });
                    DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                    return(false);
                }

                foreach (ContentFile contentFile in contentPackage.Files)
                {
                    string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path);
                    if (File.Exists(sourceFile) && File.Exists(contentFile.Path) && !CheckFileEquality(sourceFile, contentFile.Path))
                    {
                        errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] {
                            "[itemname]", "[filename]"
                        }, new string[2] {
                            item.Title, contentFile.Path
                        });
                        DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                        return(false);
                    }
                }
            }

            try
            {
                foreach (ContentFile contentFile in contentPackage.Files)
                {
                    string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path);

                    //path not allowed -> the content file must be a reference to an external file (such as some vanilla file outside the Mods folder)
                    if (!ContentPackage.IsModFilePathAllowed(contentFile))
                    {
                        //the content package is trying to copy a file to a prohibited path, which is not allowed
                        if (File.Exists(sourceFile))
                        {
                            errorMsg = TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", contentFile.Path);
                            return(false);
                        }
                        //not trying to copy anything, so this is a reference to an external file
                        //if the external file doesn't exist, we cannot enable the package
                        else if (!File.Exists(contentFile.Path))
                        {
                            errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
                            return(false);
                        }
                        continue;
                    }
                    else if (!File.Exists(sourceFile))
                    {
                        if (File.Exists(contentFile.Path))
                        {
                            //the file is already present in the game folder, all good
                            continue;
                        }
                        else
                        {
                            //file not present in either the mod or the game folder -> cannot enable the package
                            errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
                            return(false);
                        }
                    }

                    //make sure the destination directory exists
                    Directory.CreateDirectory(Path.GetDirectoryName(contentFile.Path));
                    File.Copy(sourceFile, contentFile.Path, overwrite: true);
                }

                foreach (string nonContentFile in nonContentFiles)
                {
                    string sourceFile = Path.Combine(item.Directory.FullName, nonContentFile);
                    if (!File.Exists(sourceFile))
                    {
                        continue;
                    }
                    if (!ContentPackage.IsModFilePathAllowed(nonContentFile))
                    {
                        DebugConsole.ThrowError(TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", nonContentFile));
                        continue;
                    }
                    Directory.CreateDirectory(Path.GetDirectoryName(nonContentFile));
                    File.Copy(sourceFile, nonContentFile, overwrite: true);
                }
            }
            catch (Exception e)
            {
                errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item.Title) + " {" + e.Message + "}";
                DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
                return(false);
            }

            var newPackage = new ContentPackage(contentPackage.Path, newContentPackagePath)
            {
                SteamWorkshopUrl = item.Url,
                InstallTime      = item.Modified > item.Created ? item.Modified : item.Created
            };

            newPackage.Save(newContentPackagePath);
            ContentPackage.List.Add(newPackage);
            if (newPackage.CorePackage)
            {
                //if enabling a core package, disable all other core packages
                GameMain.Config.SelectedContentPackages.RemoveWhere(cp => cp.CorePackage);
            }
            GameMain.Config.SelectedContentPackages.Add(newPackage);
            GameMain.Config.SaveNewPlayerConfig();

            if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
            {
                Submarine.RefreshSavedSubs();
            }

            errorMsg = "";
            return(true);
        }
Пример #37
0
        public virtual AIAction NextAction(Submarine sub, GameField field)
        {
            for (int i = 0; i < 5; i++)
            {
                switch (rnd.Next(5))
                {
                case 0:
                    addMarker(new Aim(field.Field[rnd.Next(field.Height), rnd.Next(field.Width)]));
                    break;

                case 1:
                    addMarker(new Circle(field.Field[rnd.Next(field.Height), rnd.Next(field.Width)]));
                    break;

                case 2:
                    addMarker(new Check(field.Field[rnd.Next(field.Height), rnd.Next(field.Width)]));
                    break;

                case 3:
                    addMarker(new Flag(field.Field[rnd.Next(field.Height), rnd.Next(field.Width)]));
                    break;

                case 4:
                    addMarker(new XMark(field.Field[rnd.Next(field.Height), rnd.Next(field.Width)]));
                    break;
                }
            }
            List <Cell> path;

            switch (rnd.Next(3))
            {
            case 0:
                int count = rnd.Next(3) + 1;
                int moveX = rnd.Next(Config.FIELD_HEIGHT);
                int moveY = rnd.Next(Config.FIELD_WIDTH);
                while (field.Field[moveX, moveY].Type == CellType.LAND)
                {
                    moveX = rnd.Next(Config.FIELD_HEIGHT);
                    moveY = rnd.Next(Config.FIELD_WIDTH);
                }
                path = field.getPath(sub.Cell, field.Field[moveX, moveY]);
                if (path == null)
                {
                    path = new List <Cell>();
                }
                return(new Move(path));

            case 1:
                count = rnd.Next(3) + 1;
                moveX = rnd.Next(Config.FIELD_HEIGHT);
                moveY = rnd.Next(Config.FIELD_WIDTH);
                while (field.Field[moveX, moveY].Type == CellType.LAND)
                {
                    moveX = rnd.Next(Config.FIELD_HEIGHT);
                    moveY = rnd.Next(Config.FIELD_WIDTH);
                }
                path = field.getPath(sub.Cell, field.Field[moveX, moveY]);
                if (path == null)
                {
                    path = new List <Cell>();
                }
                return(new PlaceMine(path));

            case 2:
                int x = rnd.Next(Config.FIELD_HEIGHT);
                int y = rnd.Next(Config.FIELD_WIDTH);
                while ((field.Field[x, y].Type == CellType.LAND) || ((x == sub.Cell.I) && (y == sub.Cell.J)))
                {
                    x = rnd.Next(Config.FIELD_HEIGHT);
                    y = rnd.Next(Config.FIELD_WIDTH);
                }
                path = field.getPath(sub.Cell, field.Field[x, y]);
                return(new LaunchTorpedo(path));

            default:
                return(null);
            }
        }
Пример #38
0
        public override IEnumerable <object> UpdateState()
        {
            //spawn some fish next to the player
            GameMain.GameScreen.BackgroundCreatureManager.SpawnSprites(2,
                                                                       Submarine.MainSub.Position + Character.Controlled.Position);

            foreach (Item item in Item.ItemList)
            {
                var wire = item.GetComponent <Wire>();
                if (wire != null && wire.Connections.Any(c => c != null))
                {
                    wire.Locked = true;
                }
            }

            yield return(new WaitForSeconds(4.0f));

            infoBox = CreateInfoFrame("Use WASD to move and the mouse to look around");

            yield return(new WaitForSeconds(5.0f));

            //-----------------------------------

            infoBox = CreateInfoFrame("Open the door at your right side by highlighting the button next to it with your cursor and pressing E");

            Door tutorialDoor = Item.ItemList.Find(i => i.HasTag("tutorialdoor")).GetComponent <Door>();

            while (!tutorialDoor.IsOpen && Character.Controlled.WorldPosition.X < tutorialDoor.Item.WorldPosition.X)
            {
                yield return(CoroutineStatus.Running);
            }

            yield return(new WaitForSeconds(2.0f));

            //-----------------------------------

            infoBox = CreateInfoFrame("Hold W or S to walk up or down stairs. Use shift to run.", true);

            while (infoBox != null)
            {
                yield return(CoroutineStatus.Running);
            }

            //-----------------------------------

            infoBox = CreateInfoFrame("At the moment the submarine has no power, which means that crucial systems such as the oxygen generator or the engine aren't running. Let's fix this: go to the upper left corner of the submarine, where you'll find a nuclear reactor.");

            Reactor reactor = Item.ItemList.Find(i => i.HasTag("tutorialreactor")).GetComponent <Reactor>();

            reactor.MeltDownTemp = 20000.0f;

            while (Vector2.Distance(Character.Controlled.Position, reactor.Item.Position) > 200.0f)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("The reactor requires fuel rods to generate power. You can grab one from the steel cabinet by walking next to it and pressing E.");

            while (Character.Controlled.SelectedConstruction == null || Character.Controlled.SelectedConstruction.Name != "Steel Cabinet")
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Pick up one of the fuel rods either by double-clicking or dragging and dropping it into your inventory.");

            while (!HasItem("Fuel Rod"))
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Select the reactor by walking next to it and pressing E.");

            while (Character.Controlled.SelectedConstruction != reactor.Item)
            {
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(0.5f));

            infoBox = CreateInfoFrame("Load the fuel rod into the reactor by dropping it into any of the 5 slots.");

            while (reactor.AvailableFuel <= 0.0f)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("The reactor is now fueled up. Try turning it on by increasing the fission rate.");

            while (reactor.FissionRate <= 0.0f)
            {
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(0.5f));

            infoBox = CreateInfoFrame("The reactor core has started generating heat, which in turn generates power for the submarine. The power generation is very low at the moment,"
                                      + " because the reactor is set to shut itself down when the temperature rises above 500 degrees Celsius. You can adjust the temperature limit by changing the \"Shutdown Temperature\" in the control panel.", true);

            while (infoBox != null)
            {
                reactor.ShutDownTemp = Math.Min(reactor.ShutDownTemp, 5000.0f);
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(0.5f));

            infoBox = CreateInfoFrame("The amount of power generated by the reactor should be kept close to the amount of power consumed by the devices in the submarine. "
                                      + "If there isn't enough power, devices won't function properly (or at all), and if there's too much power, some devices may be damaged."
                                      + " Try to raise the temperature of the reactor close to 3000 degrees by adjusting the fission and cooling rates.", true);

            while (Math.Abs(reactor.Temperature - 3000.0f) > 100.0f)
            {
                reactor.AutoTemp     = false;
                reactor.ShutDownTemp = Math.Min(reactor.ShutDownTemp, 5000.0f);
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(0.5f));

            infoBox = CreateInfoFrame("Looks like we're up and running! Now you should turn on the \"Automatic temperature control\", which will make the reactor "
                                      + "automatically adjust the temperature to a suitable level. Even though it's an easy way to keep the reactor up and running most of the time, "
                                      + "you should keep in mind that it changes the temperature very slowly and carefully, which may cause issues if there are sudden changes in grid load.");

            while (!reactor.AutoTemp)
            {
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(0.5f));

            infoBox = CreateInfoFrame("That's the basics of operating the reactor! Now that there's power available for the engines, it's time to get the submarine moving. "
                                      + "Deselect the reactor by pressing E and head to the command room at the right edge of the vessel.");

            Steering steering = Item.ItemList.Find(i => i.HasTag("tutorialsteering")).GetComponent <Steering>();
            Radar    radar    = steering.Item.GetComponent <Radar>();

            while (Vector2.Distance(Character.Controlled.Position, steering.Item.Position) > 150.0f)
            {
                yield return(CoroutineStatus.Running);
            }

            CoroutineManager.StartCoroutine(KeepReactorRunning(reactor));

            infoBox = CreateInfoFrame("Select the navigation terminal by walking next to it and pressing E.");

            while (Character.Controlled.SelectedConstruction != steering.Item)
            {
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(0.5f));

            infoBox = CreateInfoFrame("There seems to be something wrong with the navigation terminal." +
                                      " There's nothing on the monitor, so it's probably out of power. The reactor must still be"
                                      + " running or the lights would've gone out, so it's most likely a problem with the wiring."
                                      + " Deselect the terminal by pressing E to start checking the wiring.");

            while (Character.Controlled.SelectedConstruction == steering.Item)
            {
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(1.0f));

            infoBox = CreateInfoFrame("You need a screwdriver to check the wiring of the terminal."
                                      + " Equip a screwdriver by pulling it to either of the slots with a hand symbol, and then use it on the terminal by left clicking.");

            while (Character.Controlled.SelectedConstruction != steering.Item ||
                   Character.Controlled.SelectedItems.FirstOrDefault(i => i != null && i.Name == "Screwdriver") == null)
            {
                yield return(CoroutineStatus.Running);
            }


            infoBox = CreateInfoFrame("Here you can see all the wires connected to the terminal. Apparently there's no wire"
                                      + " going into the to the power connection - that's why the monitor isn't working."
                                      + " You should find a piece of wire to connect it. Try searching some of the cabinets scattered around the sub.");

            while (!HasItem("Wire"))
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Head back to the navigation terminal to fix the wiring.");

            PowerTransfer junctionBox = Item.ItemList.Find(i => i != null && i.HasTag("tutorialjunctionbox")).GetComponent <PowerTransfer>();

            while ((Character.Controlled.SelectedConstruction != junctionBox.Item &&
                    Character.Controlled.SelectedConstruction != steering.Item) ||
                   Character.Controlled.SelectedItems.FirstOrDefault(i => i != null && i.Name == "Screwdriver") == null)
            {
                yield return(CoroutineStatus.Running);
            }

            if (Character.Controlled.SelectedItems.FirstOrDefault(i => i != null && i.GetComponent <Wire>() != null) == null)
            {
                infoBox = CreateInfoFrame("Equip the wire by dragging it to one of the slots with a hand symbol.");

                while (Character.Controlled.SelectedItems.FirstOrDefault(i => i != null && i.GetComponent <Wire>() != null) == null)
                {
                    yield return(CoroutineStatus.Running);
                }
            }

            infoBox = CreateInfoFrame("You can see the equipped wire at the middle of the connection panel. Drag it to the power connector.");

            var steeringConnection = steering.Item.Connections.Find(c => c.Name.Contains("power"));

            while (steeringConnection.Wires.FirstOrDefault(w => w != null) == null)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Now you have to connect the other end of the wire to a power source. "
                                      + "The junction box in the room just below the command room should do.");

            while (Character.Controlled.SelectedConstruction != null)
            {
                yield return(CoroutineStatus.Running);
            }

            yield return(new WaitForSeconds(2.0f));

            infoBox = CreateInfoFrame("You can now move the other end of the wire around, and attach it on the wall by left clicking or "
                                      + "remove the previous attachment by right clicking. Or if you don't care for neatly laid out wiring, you can just "
                                      + "run it straight to the junction box.");

            while (Character.Controlled.SelectedConstruction == null || Character.Controlled.SelectedConstruction.GetComponent <PowerTransfer>() == null)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Connect the wire to the junction box by pulling it to the power connection, the same way you did with the navigation terminal.");

            while (radar.Voltage < 0.1f)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Great! Now we should be able to get moving.");


            while (Character.Controlled.SelectedConstruction != steering.Item)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("You can take a look at the area around the sub by selecting the \"Sonar\" checkbox.");

            while (!radar.IsActive)
            {
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(0.5f));

            infoBox = CreateInfoFrame("The green rectangle in the middle is the submarine, and the flickering shapes outside it are the walls of an underwater cavern. "
                                      + "Try moving the submarine by clicking somewhere on the monitor and dragging the pointer to the direction you want to go to.");

            while (steering.TargetVelocity == Vector2.Zero && steering.TargetVelocity.Length() < 50.0f)
            {
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(4.0f));

            infoBox = CreateInfoFrame("The submarine moves up and down by pumping water in and out of the two ballast tanks at the bottom of the submarine. "
                                      + "The engine at the back of the sub moves it forwards and backwards.", true);

            while (infoBox != null)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Steer the submarine downwards, heading further into the cavern.");

            while (Submarine.MainSub.WorldPosition.Y > 40000.0f)
            {
                yield return(CoroutineStatus.Running);
            }
            yield return(new WaitForSeconds(1.0f));

            var moloch = Character.Create(
                "Content/Characters/Moloch/moloch.xml",
                steering.Item.WorldPosition + new Vector2(3000.0f, -500.0f));

            moloch.PlaySound(CharacterSound.SoundType.Attack);

            yield return(new WaitForSeconds(1.0f));

            infoBox = CreateInfoFrame("Uh-oh... Something enormous just appeared on the radar.");

            List <Structure> windows = new List <Structure>();

            foreach (Structure s in Structure.WallList)
            {
                if (s.CastShadow || !s.HasBody)
                {
                    continue;
                }

                if (s.Rect.Right > steering.Item.CurrentHull.Rect.Right)
                {
                    windows.Add(s);
                }
            }

            float slowdownTimer = 1.0f;
            bool  broken        = false;

            do
            {
                steering.TargetVelocity = Vector2.Zero;

                slowdownTimer = Math.Max(0.0f, slowdownTimer - CoroutineManager.DeltaTime * 0.3f);
                Submarine.MainSub.Velocity *= slowdownTimer;

                moloch.AIController.SelectTarget(steering.Item.CurrentHull.AiTarget);
                Vector2 steeringDir = windows[0].WorldPosition - moloch.WorldPosition;
                if (steeringDir != Vector2.Zero)
                {
                    steeringDir = Vector2.Normalize(steeringDir);
                }

                moloch.AIController.SteeringManager.SteeringManual(CoroutineManager.DeltaTime, steeringDir * 100.0f);

                foreach (Structure window in windows)
                {
                    for (int i = 0; i < window.SectionCount; i++)
                    {
                        if (!window.SectionIsLeaking(i))
                        {
                            continue;
                        }
                        broken = true;
                        break;
                    }
                    if (broken)
                    {
                        break;
                    }
                }
                if (broken)
                {
                    break;
                }

                yield return(CoroutineStatus.Running);
            } while (!broken);

            //fix everything except the command windows
            foreach (Structure w in Structure.WallList)
            {
                bool isWindow = windows.Contains(w);

                for (int i = 0; i < w.SectionCount; i++)
                {
                    if (!w.SectionIsLeaking(i))
                    {
                        continue;
                    }

                    if (isWindow)
                    {
                        //decrease window damage to slow down the leaking
                        w.AddDamage(i, -w.SectionDamage(i) * 0.48f);
                    }
                    else
                    {
                        w.AddDamage(i, -100000.0f);
                    }
                }
            }

            Submarine.MainSub.GodMode = true;

            var capacitor1 = Item.ItemList.Find(i => i.HasTag("capacitor1")).GetComponent <PowerContainer>();
            var capacitor2 = Item.ItemList.Find(i => i.HasTag("capacitor1")).GetComponent <PowerContainer>();

            CoroutineManager.StartCoroutine(KeepEnemyAway(moloch, new PowerContainer[] { capacitor1, capacitor2 }));

            infoBox = CreateInfoFrame("The hull has been breached! Close all the doors to the command room to stop the water from flooding the entire sub!");

            Door commandDoor1 = Item.ItemList.Find(i => i.HasTag("commanddoor1")).GetComponent <Door>();
            Door commandDoor2 = Item.ItemList.Find(i => i.HasTag("commanddoor2")).GetComponent <Door>();
            Door commandDoor3 = Item.ItemList.Find(i => i.HasTag("commanddoor3")).GetComponent <Door>();

            //wait until the player is out of the room and the doors are closed
            while (Character.Controlled.WorldPosition.X > commandDoor1.Item.WorldPosition.X ||
                   (commandDoor1.IsOpen || (commandDoor2.IsOpen || commandDoor3.IsOpen)))
            {
                //prevent the hull from filling up completely and crushing the player
                steering.Item.CurrentHull.Volume = Math.Min(steering.Item.CurrentHull.Volume, steering.Item.CurrentHull.FullVolume * 0.9f);
                yield return(CoroutineStatus.Running);
            }


            infoBox = CreateInfoFrame("You should quickly find yourself a diving mask or a diving suit. " +
                                      "There are some in the room next to the airlock.");

            bool divingMaskSelected = false;

            while (!HasItem("Diving Mask") && !HasItem("Diving Suit"))
            {
                if (!divingMaskSelected &&
                    Character.Controlled.FocusedItem != null && Character.Controlled.FocusedItem.Name == "Diving Suit")
                {
                    infoBox = CreateInfoFrame("There can only be one item in each inventory slot, so you need to take off "
                                              + "the jumpsuit if you wish to wear a diving suit.");

                    divingMaskSelected = true;
                }

                yield return(CoroutineStatus.Running);
            }

            if (HasItem("Diving Mask"))
            {
                infoBox = CreateInfoFrame("The diving mask will let you breathe underwater, but it won't protect from the water pressure outside the sub. " +
                                          "It should be fine for the situation at hand, but you still need to find an oxygen tank and drag it into the same slot as the mask." +
                                          "You should grab one or two from one of the cabinets.");
            }
            else if (HasItem("Diving Suit"))
            {
                infoBox = CreateInfoFrame("In addition to letting you breathe underwater, the suit will protect you from the water pressure outside the sub " +
                                          "(unlike the diving mask). However, you still need to drag an oxygen tank into the same slot as the suit to supply oxygen. " +
                                          "You should grab one or two from one of the cabinets.");
            }

            while (!HasItem("Oxygen Tank"))
            {
                yield return(CoroutineStatus.Running);
            }

            yield return(new WaitForSeconds(5.0f));

            infoBox = CreateInfoFrame("Now you should stop the creature attacking the submarine before it does any more damage. Head to the railgun room at the upper right corner of the sub.");

            var railGun = Item.ItemList.Find(i => i.GetComponent <Turret>() != null);

            while (Vector2.Distance(Character.Controlled.Position, railGun.Position) > 500)
            {
                yield return(new WaitForSeconds(1.0f));
            }

            infoBox = CreateInfoFrame("The railgun requires a large power surge to fire. The reactor can't provide a surge large enough, so we need to use the "
                                      + " supercapacitors in the railgun room. The capacitors need to be charged first; select them and crank up the recharge rate.");

            while (capacitor1.RechargeSpeed < 0.5f && capacitor2.RechargeSpeed < 0.5f)
            {
                yield return(new WaitForSeconds(1.0f));
            }

            infoBox = CreateInfoFrame("The capacitors take some time to recharge, so now is a good " +
                                      "time to head to the room below and load some shells for the railgun.");


            var loader = Item.ItemList.Find(i => i.Name == "Railgun Loader").GetComponent <ItemContainer>();

            while (Math.Abs(Character.Controlled.Position.Y - loader.Item.Position.Y) > 80)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Grab one of the shells. You can load it by selecting the railgun loader and dragging the shell to. "
                                      + "one of the free slots. You need two hands to carry a shell, so make sure you don't have anything else in either hand.");

            while (loader.Item.ContainedItems.FirstOrDefault(i => i != null && i.Name == "Railgun Shell") == null)
            {
                moloch.Health = 50.0f;

                capacitor1.Charge += 5.0f;
                capacitor2.Charge += 5.0f;
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("Now we're ready to shoot! Select the railgun controller.");

            while (Character.Controlled.SelectedConstruction == null || Character.Controlled.SelectedConstruction.Name != "Railgun Controller")
            {
                yield return(CoroutineStatus.Running);
            }

            moloch.AnimController.SetPosition(ConvertUnits.ToSimUnits(Character.Controlled.WorldPosition + Vector2.UnitY * 600.0f));

            infoBox = CreateInfoFrame("Use the right mouse button to aim and wait for the creature to come closer. When you're ready to shoot, "
                                      + "press the left mouse button.");

            while (!moloch.IsDead)
            {
                if (moloch.WorldPosition.Y > Character.Controlled.WorldPosition.Y + 600.0f)
                {
                    moloch.AIController.SteeringManager.SteeringManual(CoroutineManager.DeltaTime, Character.Controlled.WorldPosition - moloch.WorldPosition);
                }

                moloch.AIController.SelectTarget(Character.Controlled.AiTarget);
                yield return(CoroutineStatus.Running);
            }

            Submarine.MainSub.GodMode = false;

            infoBox = CreateInfoFrame("The creature has died. Now you should fix the damages in the control room: " +
                                      "Grab a welding tool from the closet in the railgun room.");

            while (!HasItem("Welding Tool"))
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("The welding tool requires fuel to work. Grab a welding fuel tank and attach it to the tool " +
                                      "by dragging it into the same slot.");

            do
            {
                var weldingTool = Character.Controlled.Inventory.Items.FirstOrDefault(i => i != null && i.Name == "Welding Tool");
                if (weldingTool != null &&
                    weldingTool.ContainedItems.FirstOrDefault(contained => contained != null && contained.Name == "Welding Fuel Tank") != null)
                {
                    break;
                }

                yield return(CoroutineStatus.Running);
            } while (true);


            infoBox = CreateInfoFrame("You can aim with the tool using the right mouse button and weld using the left button. " +
                                      "Head to the command room to fix the leaks there.");

            do
            {
                broken = false;
                foreach (Structure window in windows)
                {
                    for (int i = 0; i < window.SectionCount; i++)
                    {
                        if (!window.SectionIsLeaking(i))
                        {
                            continue;
                        }
                        broken = true;
                        break;
                    }
                    if (broken)
                    {
                        break;
                    }
                }

                yield return(new WaitForSeconds(1.0f));
            } while (broken);

            infoBox = CreateInfoFrame("The hull is fixed now, but there's still quite a bit of water inside the sub. It should be pumped out "
                                      + "using the bilge pump in the room at the bottom of the submarine.");

            Pump pump = Item.ItemList.Find(i => i.HasTag("tutorialpump")).GetComponent <Pump>();

            while (Vector2.Distance(Character.Controlled.Position, pump.Item.Position) > 100.0f)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("The two pumps inside the ballast tanks "
                                      + "are connected straight to the navigation terminal and can't be manually controlled unless you mess with their wiring, " +
                                      "so you should only use the pump in the middle room to pump out the water. Select it, turn it on and adjust the pumping speed " +
                                      "to start pumping water out.", true);

            while (infoBox != null)
            {
                yield return(CoroutineStatus.Running);
            }


            bool brokenMsgShown = false;

            Item brokenBox = null;

            while (pump.FlowPercentage > 0.0f || pump.CurrFlow <= 0.0f || !pump.IsActive)
            {
                if (!brokenMsgShown && pump.Voltage < pump.MinVoltage && Character.Controlled.SelectedConstruction == pump.Item)
                {
                    brokenMsgShown = true;

                    infoBox = CreateInfoFrame("Looks like the pump isn't getting any power. The water must have short-circuited some of the junction "
                                              + "boxes. You can check which boxes are broken by selecting them.");

                    while (true)
                    {
                        if (Character.Controlled.SelectedConstruction != null &&
                            Character.Controlled.SelectedConstruction.GetComponent <PowerTransfer>() != null &&
                            Character.Controlled.SelectedConstruction.Condition == 0.0f)
                        {
                            brokenBox = Character.Controlled.SelectedConstruction;

                            infoBox = CreateInfoFrame("Here's our problem: this junction box is broken. Luckily engineers are adept at fixing electrical devices - "
                                                      + "you just need to find a spare wire and click the \"Fix\"-button to repair the box.");
                            break;
                        }

                        if (pump.Voltage > pump.MinVoltage)
                        {
                            break;
                        }

                        yield return(CoroutineStatus.Running);
                    }
                }

                if (brokenBox != null && brokenBox.Condition > 50.0f && pump.Voltage < pump.MinVoltage)
                {
                    yield return(new WaitForSeconds(1.0f));

                    if (pump.Voltage < pump.MinVoltage)
                    {
                        infoBox = CreateInfoFrame("The pump is still not running. Check if there are more broken junction boxes between the pump and the reactor.");
                    }
                    brokenBox = null;
                }

                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("The pump is up and running. Wait for the water to be drained out.");

            while (pump.Item.CurrentHull.Volume > 1000.0f)
            {
                yield return(CoroutineStatus.Running);
            }

            infoBox = CreateInfoFrame("That was all there is to this tutorial! Now you should be able to handle " +
                                      "most of the basic tasks on board the submarine.");

            yield return(new WaitForSeconds(4.0f));

            Character.Controlled = null;
            GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
            GameMain.LightManager.LosEnabled  = false;

            var cinematic = new TransitionCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, 5.0f);

            while (cinematic.Running)
            {
                yield return(CoroutineStatus.Running);
            }

            Submarine.Unload();
            GameMain.MainMenuScreen.Select();

            yield return(CoroutineStatus.Success);
        }
Пример #39
0
	public Submarine()
    {
        _instance = this;
		//InitSubmarine(_possiblePositions);
    }
Пример #40
0
        private static IUnit CreateUnit(UnitType type, int x, int y)
        {
            IUnit unit;

            switch (type)
            {
            case UnitType.Settlers: unit = new Settlers(); break;

            case UnitType.Militia: unit = new Militia(); break;

            case UnitType.Phalanx: unit = new Phalanx(); break;

            case UnitType.Legion: unit = new Legion(); break;

            case UnitType.Musketeers: unit = new Musketeers(); break;

            case UnitType.Riflemen: unit = new Riflemen(); break;

            case UnitType.Cavalry: unit = new Cavalry(); break;

            case UnitType.Knights: unit = new Knights(); break;

            case UnitType.Catapult: unit = new Catapult(); break;

            case UnitType.Cannon: unit = new Cannon(); break;

            case UnitType.Chariot: unit = new Chariot(); break;

            case UnitType.Armor: unit = new Armor(); break;

            case UnitType.MechInf: unit = new MechInf(); break;

            case UnitType.Artillery: unit = new Artillery(); break;

            case UnitType.Fighter: unit = new Fighter(); break;

            case UnitType.Bomber: unit = new Bomber(); break;

            case UnitType.Trireme: unit = new Trireme(); break;

            case UnitType.Sail: unit = new Sail(); break;

            case UnitType.Frigate: unit = new Frigate(); break;

            case UnitType.Ironclad: unit = new Ironclad(); break;

            case UnitType.Cruiser: unit = new Cruiser(); break;

            case UnitType.Battleship: unit = new Battleship(); break;

            case UnitType.Submarine: unit = new Submarine(); break;

            case UnitType.Carrier: unit = new Carrier(); break;

            case UnitType.Transport: unit = new Transport(); break;

            case UnitType.Nuclear: unit = new Nuclear(); break;

            case UnitType.Diplomat: unit = new Diplomat(); break;

            case UnitType.Caravan: unit = new Caravan(); break;

            default: return(null);
            }
            unit.X = x;
            unit.Y = y;
            return(unit);
        }
Пример #41
0
        private void CreateHulls()
        {
            var hullRects = new Rectangle[] { item.WorldRect, DockingTarget.item.WorldRect };
            var subs      = new Submarine[] { item.Submarine, DockingTarget.item.Submarine };

            bodies = new Body[4];

            if (DockingTarget.door != null)
            {
                CreateDoorBody();
            }

            if (door != null)
            {
                DockingTarget.CreateDoorBody();
            }

            if (IsHorizontal)
            {
                if (hullRects[0].Center.X > hullRects[1].Center.X)
                {
                    hullRects = new Rectangle[] { DockingTarget.item.WorldRect, item.WorldRect };
                    subs      = new Submarine[] { DockingTarget.item.Submarine, item.Submarine };
                }

                hullRects[0] = new Rectangle(hullRects[0].Center.X, hullRects[0].Y, ((int)DockedDistance / 2), hullRects[0].Height);
                hullRects[1] = new Rectangle(hullRects[1].Center.X - ((int)DockedDistance / 2), hullRects[1].Y, ((int)DockedDistance / 2), hullRects[1].Height);

                //expand hulls if needed, so there's no empty space between the sub's hulls and docking port hulls
                int leftSubRightSide = int.MinValue, rightSubLeftSide = int.MaxValue;
                foreach (Hull hull in Hull.hullList)
                {
                    for (int i = 0; i < 2; i++)
                    {
                        if (hull.Submarine != subs[i])
                        {
                            continue;
                        }
                        if (hull.WorldRect.Y < hullRects[i].Y - hullRects[i].Height)
                        {
                            continue;
                        }
                        if (hull.WorldRect.Y - hull.WorldRect.Height > hullRects[i].Y)
                        {
                            continue;
                        }

                        if (i == 0) //left hull
                        {
                            leftSubRightSide = Math.Max(hull.WorldRect.Right, leftSubRightSide);
                        }
                        else //upper hull
                        {
                            rightSubLeftSide = Math.Min(hull.WorldRect.X, rightSubLeftSide);
                        }
                    }
                }

                //expand left hull to the rightmost hull of the sub at the left side
                //(unless the difference is more than 100 units - if the distance is very large
                //there's something wrong with the positioning of the docking ports or submarine hulls)
                int leftHullDiff = (hullRects[0].X - leftSubRightSide) + 5;
                if (leftHullDiff > 0)
                {
                    if (leftHullDiff > 100)
                    {
                        DebugConsole.ThrowError("Creating hulls between docking ports failed. The leftmost docking port seems to be very far from any hulls in the left-side submarine.");
                    }
                    else
                    {
                        hullRects[0].X     -= leftHullDiff;
                        hullRects[0].Width += leftHullDiff;
                    }
                }

                int rightHullDiff = (rightSubLeftSide - hullRects[1].Right) + 5;
                if (rightHullDiff > 0)
                {
                    if (rightHullDiff > 100)
                    {
                        DebugConsole.ThrowError("Creating hulls between docking ports failed. The rightmost docking port seems to be very far from any hulls in the right-side submarine.");
                    }
                    else
                    {
                        hullRects[1].Width += rightHullDiff;
                    }
                }

                for (int i = 0; i < 2; i++)
                {
                    hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
                    hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]);
                    hulls[i].AddToGrid(subs[i]);
                    hulls[i].FreeID();

                    for (int j = 0; j < 2; j++)
                    {
                        bodies[i + j * 2] = BodyFactory.CreateEdge(GameMain.World,
                                                                   ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X, hullRects[i].Y - hullRects[i].Height * j)),
                                                                   ConvertUnits.ToSimUnits(new Vector2(hullRects[i].Right, hullRects[i].Y - hullRects[i].Height * j)));
                    }
                }

                gap = new Gap(new Rectangle(hullRects[0].Right - 2, hullRects[0].Y, 4, hullRects[0].Height), true, subs[0]);
            }
            else
            {
                if (hullRects[0].Center.Y > hullRects[1].Center.Y)
                {
                    hullRects = new Rectangle[] { DockingTarget.item.WorldRect, item.WorldRect };
                    subs      = new Submarine[] { DockingTarget.item.Submarine, item.Submarine };
                }

                hullRects[0] = new Rectangle(hullRects[0].X, hullRects[0].Y + (int)(-hullRects[0].Height + DockedDistance) / 2, hullRects[0].Width, ((int)DockedDistance / 2));
                hullRects[1] = new Rectangle(hullRects[1].X, hullRects[1].Y - hullRects[1].Height / 2, hullRects[1].Width, ((int)DockedDistance / 2));

                //expand hulls if needed, so there's no empty space between the sub's hulls and docking port hulls
                int upperSubBottom = int.MaxValue, lowerSubTop = int.MinValue;
                foreach (Hull hull in Hull.hullList)
                {
                    for (int i = 0; i < 2; i++)
                    {
                        if (hull.Submarine != subs[i])
                        {
                            continue;
                        }
                        if (hull.WorldRect.Right < hullRects[i].X)
                        {
                            continue;
                        }
                        if (hull.WorldRect.X > hullRects[i].Right)
                        {
                            continue;
                        }

                        if (i == 0) //lower hull
                        {
                            lowerSubTop = Math.Max(hull.WorldRect.Y, lowerSubTop);
                        }
                        else //upper hull
                        {
                            upperSubBottom = Math.Min(hull.WorldRect.Y - hull.WorldRect.Height, upperSubBottom);
                        }
                    }
                }

                //expand lower hull to the topmost hull of the lower sub
                //(unless the difference is more than 100 units - if the distance is very large
                //there's something wrong with the positioning of the docking ports or submarine hulls)
                int lowerHullDiff = ((hullRects[0].Y - hullRects[0].Height) - lowerSubTop) + 5;
                if (lowerHullDiff > 0)
                {
                    if (lowerHullDiff > 100)
                    {
                        DebugConsole.ThrowError("Creating hulls between docking ports failed. The lower docking port seems to be very far from any hulls in the lower submarine.");
                    }
                    else
                    {
                        hullRects[0].Height += lowerHullDiff;
                    }
                }

                int upperHullDiff = (upperSubBottom - hullRects[1].Y) + 5;
                if (upperHullDiff > 0)
                {
                    if (upperHullDiff > 100)
                    {
                        DebugConsole.ThrowError("Creating hulls between docking ports failed. The upper docking port seems to be very far from any hulls in the upper submarine.");
                    }
                    else
                    {
                        hullRects[1].Y      += upperHullDiff;
                        hullRects[1].Height += upperHullDiff;
                    }
                }

                //difference between the edges of the hulls (to avoid a gap between the hulls)
                //0 is lower
                int midHullDiff = ((hullRects[1].Y - hullRects[1].Height) - hullRects[0].Y) + 2;
                if (midHullDiff > 100)
                {
                    DebugConsole.ThrowError("Creating hulls between docking ports failed. The upper hull seems to be very far from the lower hull.");
                }
                else if (midHullDiff > 0)
                {
                    hullRects[0].Height += midHullDiff / 2 + 1;
                    hullRects[1].Y      -= midHullDiff / 2 + 1;
                    hullRects[1].Height += midHullDiff / 2 + 1;
                }

                for (int i = 0; i < 2; i++)
                {
                    hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
                    hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]);
                    hulls[i].AddToGrid(subs[i]);
                    hulls[i].FreeID();
                }

                gap = new Gap(new Rectangle(hullRects[0].X, hullRects[0].Y + 2, hullRects[0].Width, 4), false, subs[0]);
            }

            LinkHullsToGaps();

            hulls[0].ShouldBeSaved = false;
            hulls[1].ShouldBeSaved = false;
            item.linkedTo.Add(hulls[0]);
            item.linkedTo.Add(hulls[1]);

            gap.FreeID();
            gap.DisableHullRechecks = true;
            gap.ShouldBeSaved       = false;
            item.linkedTo.Add(gap);

            foreach (Body body in bodies)
            {
                if (body == null)
                {
                    continue;
                }
                body.BodyType = BodyType.Static;
                body.Friction = 0.5f;

                body.CollisionCategories = Physics.CollisionWall;
            }
        }
Пример #42
0
 void DealDamage(Submarine submarine)
 {
     submarine.TakeDamage(Side, Damage);
 }