Пример #1
0
        public IEnumerable <IRenderable> Render(WorldRenderer wr)
        {
            if (info.ContrailLength > 0)
            {
                yield return(trail);
            }

            if (anim == null || ticks >= length)
            {
                yield break;
            }

            var cell = pos.ToCPos();

            if (!args.SourceActor.World.FogObscures(cell))
            {
                if (info.Shadow)
                {
                    var shadowPos = pos - new WVec(0, 0, pos.Z);
                    foreach (var r in anim.Render(shadowPos, wr.Palette("shadow")))
                    {
                        yield return(r);
                    }
                }

                var palette = wr.Palette(args.Weapon.Underwater ? "shadow" : "effect");
                foreach (var r in anim.Render(pos, palette))
                {
                    yield return(r);
                }
            }
        }
Пример #2
0
        public void Tick(World world)
        {
            // Fade the trail out gradually
            if (ticks > length && info.ContrailLength > 0)
            {
                trail.Update(pos);
                return;
            }

            if (anim != null)
            {
                anim.Tick();
            }

            pos = WPos.LerpQuadratic(args.Source, target, angle, ticks, length);

            if (info.Trail != null && --smokeTicks < 0)
            {
                var delayedPos = WPos.LerpQuadratic(args.Source, target, angle, ticks - info.TrailDelay, length);
                world.AddFrameEndTask(w => w.Add(new Smoke(w, delayedPos, info.Trail)));
                smokeTicks = info.TrailInterval;
            }

            if (info.ContrailLength > 0)
            {
                trail.Update(pos);
            }

            if (ticks++ >= length || (!info.High && world.ActorMap
                                      .GetUnitsAt(pos.ToCPos()).Any(a => a.HasTrait <IBlocksBullets>())))
            {
                Explode(world);
            }
        }
Пример #3
0
 public void SetPosition(Actor self, WPos pos)
 {
     self.World.ActorMap.Remove(self, this);
     CenterPosition = pos;
     TopLeft        = pos.ToCPos();
     self.World.ActorMap.Add(self, this);
 }
Пример #4
0
		public IEnumerable<IRenderable> Render(WorldRenderer wr)
		{
			if (wr.world.FogObscures(pos.ToCPos()))
				yield break;

			yield return new TextRenderable(font, pos, 0, color, text);
		}
Пример #5
0
        public void SetPosition(Actor self, WPos pos)
        {
            var cell = pos.ToCPos();

            SetLocation(cell, fromSubCell, cell, fromSubCell);
            SetVisualPosition(self, pos);
            FinishedMoving(self);
        }
Пример #6
0
 public Explosion(World world, WPos pos, string style)
 {
     this.world = world;
     this.pos = pos;
     this.cell = pos.ToCPos();
     anim = new Animation("explosion");
     anim.PlayThen(style, () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Пример #7
0
 public Explosion(World world, WPos pos, string style)
 {
     this.world = world;
     this.pos   = pos;
     this.cell  = pos.ToCPos();
     anim       = new Animation("explosion");
     anim.PlayThen(style, () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Пример #8
0
 public Corpse(World world, WPos pos, string image, string sequence, string paletteName)
 {
     this.world       = world;
     this.pos         = pos;
     this.cell        = pos.ToCPos();
     this.paletteName = paletteName;
     anim             = new Animation(image);
     anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Пример #9
0
 public Smoke(World world, WPos pos, string trail)
 {
     this.world = world;
     this.pos = pos;
     this.cell = pos.ToCPos();
     anim = new Animation(trail);
     anim.PlayThen("idle",
         () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Пример #10
0
 public Explosion(World world, WPos pos, string sequence, string palette)
 {
     this.world = world;
     this.pos = pos;
     this.cell = pos.ToCPos();
     this.palette = palette;
     anim = new Animation(world, "explosion");
     anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Пример #11
0
 public Explosion(World world, WPos pos, string sequence, string palette)
 {
     this.world   = world;
     this.pos     = pos;
     this.cell    = pos.ToCPos();
     this.palette = palette;
     anim         = new Animation(world, "explosion");
     anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Пример #12
0
 public Corpse(World world, WPos pos, string image, string sequence, string paletteName)
 {
     this.world = world;
     this.pos = pos;
     this.cell = pos.ToCPos();
     this.paletteName = paletteName;
     anim = new Animation(image);
     anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Пример #13
0
 public Smoke(World world, WPos pos, string trail)
 {
     this.world = world;
     this.pos   = pos;
     this.cell  = pos.ToCPos();
     anim       = new Animation(trail);
     anim.PlayThen("idle",
                   () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Пример #14
0
 public void SetPosition(Actor self, WPos pos)
 {
     self.World.ActorMap.RemoveInfluence(self, this);
     CenterPosition = pos;
     TopLeft        = pos.ToCPos();
     self.World.ActorMap.AddInfluence(self, this);
     self.World.ActorMap.UpdatePosition(self, this);
     self.World.ScreenMap.Update(self);
 }
Пример #15
0
        public IEnumerable <IRenderable> Render(WorldRenderer wr)
        {
            if (info.ContrailLength > 0)
            {
                yield return(trail);
            }

            if (!args.SourceActor.World.FogObscures(pos.ToCPos()))
            {
                var palette = wr.Palette(args.Weapon.Palette);
                foreach (var r in anim.Render(pos, palette))
                {
                    yield return(r);
                }
            }
        }
Пример #16
0
        public Parachute(Actor cargo, WPos dropPosition)
        {
            this.cargo = cargo;

            var pai = cargo.Info.Traits.GetOrDefault<ParachuteAttachmentInfo>();
            paraAnim = new Animation(cargo.World, pai != null ? pai.ParachuteSprite : "parach");
            paraAnim.PlayThen("open", () => paraAnim.PlayRepeating("idle"));

            if (pai != null)
                parachuteOffset = pai.Offset;

            // Adjust x,y to match the target subcell
            cargo.Trait<IPositionable>().SetPosition(cargo, dropPosition.ToCPos());
            var cp = cargo.CenterPosition;
            pos = new WPos(cp.X, cp.Y, dropPosition.Z);
        }
Пример #17
0
		public Parachute(Actor cargo, WPos dropPosition)
		{
			this.cargo = cargo;

			var pai = cargo.Info.Traits.GetOrDefault<ParachuteAttachmentInfo>();
			paraAnim = new Animation(pai != null ? pai.ParachuteSprite : "parach");
			paraAnim.PlayThen("open", () => paraAnim.PlayRepeating("idle"));

			if (pai != null)
				parachuteOffset = pai.Offset;

			// Adjust x,y to match the target subcell
			cargo.Trait<IPositionable>().SetPosition(cargo, dropPosition.ToCPos());
			var cp = cargo.CenterPosition;
			pos = new WPos(cp.X, cp.Y, dropPosition.Z);
		}
Пример #18
0
        public IEnumerable <IRenderable> Render(WorldRenderer wr)
        {
            var cell = pos.ToCPos();

            if (!args.SourceActor.World.FogObscures(cell))
            {
                if (info.Shadow)
                {
                    var shadowPos = pos - new WVec(0, 0, pos.Z);
                    foreach (var r in anim.Render(shadowPos, wr.Palette("shadow")))
                    {
                        yield return(r);
                    }
                }

                var palette = wr.Palette(args.Weapon.Palette);
                foreach (var r in anim.Render(pos, palette))
                {
                    yield return(r);
                }
            }
        }
Пример #19
0
        public List <CPos> FindUnitPathToRange(CPos src, SubCell srcSub, WPos target, WRange range, Actor self)
        {
            using (new PerfSample("Pathfinder"))
            {
                var mi           = self.Info.Traits.Get <MobileInfo>();
                var targetCell   = target.ToCPos();
                var rangeSquared = range.Range * range.Range;

                // Correct for SubCell offset
                target -= MobileInfo.SubCellOffsets[srcSub];

                // Select only the tiles that are within range from the requested SubCell
                // This assumes that the SubCell does not change during the path traversal
                var tilesInRange = world.FindTilesInCircle(targetCell, range.Range / 1024 + 1)
                                   .Where(t => (t.CenterPosition - target).LengthSquared <= rangeSquared &&
                                          mi.CanEnterCell(self.World, self, t, null, true, true));

                // See if there is any cell within range that does not involve a cross-domain request
                // Really, we only need to check the circle perimeter, but it's not clear that would be a performance win
                var domainIndex = self.World.WorldActor.TraitOrDefault <DomainIndex>();
                if (domainIndex != null)
                {
                    var passable = mi.GetMovementClass(world.TileSet);
                    tilesInRange = new List <CPos>(tilesInRange.Where(t => domainIndex.IsPassable(src, t, (uint)passable)));
                    if (tilesInRange.Count() == 0)
                    {
                        return(emptyPath);
                    }
                }

                var path = FindBidiPath(
                    PathSearch.FromPoints(world, mi, self, tilesInRange, src, true),
                    PathSearch.FromPoint(world, mi, self, src, targetCell, true).InReverse()
                    );

                return(path);
            }
        }
Пример #20
0
        public void Tick(World world)
        {
            ticks++;
            anim.Tick();

            // Missile tracks target
            if (args.GuidedTarget.IsValidFor(args.SourceActor))
            {
                targetPosition = args.GuidedTarget.CenterPosition;
            }

            var dist            = targetPosition + offset - pos;
            var desiredFacing   = Traits.Util.GetFacing(dist, facing);
            var desiredAltitude = targetPosition.Z;
            var jammed          = info.Jammable && world.ActorsWithTrait <JamsMissiles>().Any(j => JammedBy(j));

            if (jammed)
            {
                desiredFacing   = facing + world.SharedRandom.Next(-20, 21);
                desiredAltitude = world.SharedRandom.Next(-43, 86);
            }
            else if (!args.GuidedTarget.IsValidFor(args.SourceActor))
            {
                desiredFacing = facing;
            }

            facing = Traits.Util.TickFacing(facing, desiredFacing, info.ROT);
            var move = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing)) * info.Speed.Range / 1024;

            if (targetPosition.Z > 0 && info.TurboBoost)
            {
                move = (move * 3) / 2;
            }

            if (pos.Z != desiredAltitude)
            {
                var delta = move.HorizontalLength * info.MaximumPitch.Tan() / 1024;
                var dz    = (targetPosition.Z - pos.Z).Clamp(-delta, delta);
                move += new WVec(0, 0, dz);
            }

            pos += move;

            if (info.Trail != null && --ticksToNextSmoke < 0)
            {
                world.AddFrameEndTask(w => w.Add(new Smoke(w, pos - 3 * move / 2, info.Trail)));
                ticksToNextSmoke = info.TrailInterval;
            }

            if (info.ContrailLength > 0)
            {
                trail.Update(pos);
            }

            var cell = pos.ToCPos();

            var shouldExplode = (pos.Z < 0) ||          // Hit the ground
                                (dist.LengthSquared < MissileCloseEnough.Range * MissileCloseEnough.Range) || // Within range
                                (info.RangeLimit != 0 && ticks > info.RangeLimit) || // Ran out of fuel
                                (!info.High && world.ActorMap.GetUnitsAt(cell)
                                 .Any(a => a.HasTrait <IBlocksBullets>())) ||    // Hit a wall
                                (!string.IsNullOrEmpty(info.BoundToTerrainType) && world.GetTerrainType(cell) != info.BoundToTerrainType);    // Hit incompatible terrain

            if (shouldExplode)
            {
                Explode(world);
            }
        }
Пример #21
0
        public void Tick(World world)
        {
            ticks++;
            anim.Tick();

            // Missile tracks target
            if (args.GuidedTarget.IsValidFor(args.SourceActor))
                targetPosition = args.GuidedTarget.CenterPosition;

            var dist = targetPosition + offset - pos;
            var desiredFacing = Traits.Util.GetFacing(dist, facing);
            var desiredAltitude = targetPosition.Z;
            var jammed = info.Jammable && world.ActorsWithTrait<JamsMissiles>().Any(j => JammedBy(j));

            if (jammed)
            {
                desiredFacing = facing + world.SharedRandom.Next(-20, 21);
                desiredAltitude = world.SharedRandom.Next(-43, 86);
            }
            else if (!args.GuidedTarget.IsValidFor(args.SourceActor))
                desiredFacing = facing;

            facing = Traits.Util.TickFacing(facing, desiredFacing, info.ROT);
            var move = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing)) * info.Speed.Range / 1024;
            if (targetPosition.Z > 0 && info.TurboBoost)
                move = (move * 3) / 2;

            if (pos.Z != desiredAltitude)
            {
                var delta = move.HorizontalLength * info.MaximumPitch.Tan() / 1024;
                var dz = (targetPosition.Z - pos.Z).Clamp(-delta, delta);
                move += new WVec(0, 0, dz);
            }

            pos += move;

            if (info.Trail != null && --ticksToNextSmoke < 0)
            {
                world.AddFrameEndTask(w => w.Add(new Smoke(w, pos - 3 * move / 2, info.Trail)));
                ticksToNextSmoke = info.TrailInterval;
            }

            if (info.ContrailLength > 0)
                trail.Update(pos);

            var cell = pos.ToCPos();

            var shouldExplode = (pos.Z < 0) // Hit the ground
                || (dist.LengthSquared < MissileCloseEnough.Range * MissileCloseEnough.Range) // Within range
                || (info.RangeLimit != 0 && ticks > info.RangeLimit) // Ran out of fuel
                || (!info.High && world.ActorMap.GetUnitsAt(cell)
                    .Any(a => a.HasTrait<IBlocksBullets>())) // Hit a wall
                || (!string.IsNullOrEmpty(info.BoundToTerrainType) && world.GetTerrainType(cell) != info.BoundToTerrainType); // Hit incompatible terrain

            if (shouldExplode)
                Explode(world);
        }
Пример #22
0
 public void SetVisualPosition(Actor self, WPos pos)
 {
     SetPosition(self, pos.ToCPos());
 }
Пример #23
0
        public static void DoImpact(WPos pos, WarheadInfo warhead, WeaponInfo weapon, Actor firedBy, float firepowerModifier)
        {
            var world = firedBy.World;
            var targetTile = pos.ToCPos();

            if (!world.Map.IsInMap(targetTile))
                return;

            var isWater = pos.Z == 0 && world.GetTerrainInfo(targetTile).IsWater;
            var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion;

            if (explosionType != null)
                world.AddFrameEndTask(w => w.Add(new Explosion(w, pos, explosionType)));

            Sound.Play(GetImpactSound(warhead, isWater), pos);

            var smudgeLayers = world.WorldActor.TraitsImplementing<SmudgeLayer>().ToDictionary(x => x.Info.Type);

            if (warhead.Size[0] > 0)
            {
                var resLayer = world.WorldActor.Trait<ResourceLayer>();
                var allCells = world.FindTilesInCircle(targetTile, warhead.Size[0]).ToList();

                // `smudgeCells` might want to just be an outer shell of the cells:
                IEnumerable<CPos> smudgeCells = allCells;
                if (warhead.Size.Length == 2)
                    smudgeCells = smudgeCells.Except(world.FindTilesInCircle(targetTile, warhead.Size[1]));

                // Draw the smudges:
                foreach (var sc in smudgeCells)
                {
                    var smudgeType = world.GetTerrainInfo(sc).AcceptsSmudgeType.FirstOrDefault(t => warhead.SmudgeType.Contains(t));
                    if (smudgeType == null) continue;

                    SmudgeLayer smudgeLayer;
                    if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer))
                        throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType));

                    smudgeLayer.AddSmudge(sc);
                    if (warhead.Ore)
                        resLayer.Destroy(sc);
                }

                // Destroy all resources in range, not just the outer shell:
                foreach (var cell in allCells)
                {
                    if (warhead.Ore)
                        resLayer.Destroy(cell);
                }
            }
            else
            {
                var smudgeType = world.GetTerrainInfo(targetTile).AcceptsSmudgeType.FirstOrDefault(t => warhead.SmudgeType.Contains(t));
                if (smudgeType != null)
                {
                    SmudgeLayer smudgeLayer;
                    if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer))
                        throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType));

                    smudgeLayer.AddSmudge(targetTile);
                }
            }

            if (warhead.Ore)
                world.WorldActor.Trait<ResourceLayer>().Destroy(targetTile);

            switch (warhead.DamageModel)
            {
                case DamageModel.Normal:
                    {
                        var maxSpread = warhead.Spread * (float)Math.Log(Math.Abs(warhead.Damage), 2);
                        var range = new WRange((int)maxSpread * 1024 / Game.CellSize);
                        var hitActors = world.FindActorsInCircle(pos, range);

                        foreach (var victim in hitActors)
                        {
                            var damage = (int)GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier);
                            victim.InflictDamage(firedBy, damage, warhead);
                        }
                    } break;

                case DamageModel.PerCell:
                    {
                        foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0]))
                            foreach (var unit in world.FindActorsInBox(t, t))
                                unit.InflictDamage(firedBy,
                                    (int)(warhead.Damage * warhead.EffectivenessAgainst(unit.Info)), warhead);
                    } break;
            }
        }
Пример #24
0
        public static void DoImpact(WPos pos, WarheadInfo warhead, WeaponInfo weapon, Actor firedBy, float firepowerModifier)
        {
            var world      = firedBy.World;
            var targetTile = pos.ToCPos();

            if (!world.Map.IsInMap(targetTile))
            {
                return;
            }

            var isWater       = pos.Z == 0 && world.GetTerrainInfo(targetTile).IsWater;
            var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion;

            if (explosionType != null)
            {
                world.AddFrameEndTask(w => w.Add(new Explosion(w, pos, explosionType)));
            }

            Sound.Play(GetImpactSound(warhead, isWater), pos);

            var smudgeLayers = world.WorldActor.TraitsImplementing <SmudgeLayer>().ToDictionary(x => x.Info.Type);

            if (warhead.Size[0] > 0)
            {
                var resLayer = world.WorldActor.Trait <ResourceLayer>();
                var allCells = world.FindTilesInCircle(targetTile, warhead.Size[0]).ToList();

                // `smudgeCells` might want to just be an outer shell of the cells:
                IEnumerable <CPos> smudgeCells = allCells;
                if (warhead.Size.Length == 2)
                {
                    smudgeCells = smudgeCells.Except(world.FindTilesInCircle(targetTile, warhead.Size[1]));
                }

                // Draw the smudges:
                foreach (var sc in smudgeCells)
                {
                    var smudgeType = world.GetTerrainInfo(sc).AcceptsSmudgeType.FirstOrDefault(t => warhead.SmudgeType.Contains(t));
                    if (smudgeType == null)
                    {
                        continue;
                    }

                    SmudgeLayer smudgeLayer;
                    if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer))
                    {
                        throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType));
                    }

                    smudgeLayer.AddSmudge(sc);
                    if (warhead.Ore)
                    {
                        resLayer.Destroy(sc);
                    }
                }

                // Destroy all resources in range, not just the outer shell:
                foreach (var cell in allCells)
                {
                    if (warhead.Ore)
                    {
                        resLayer.Destroy(cell);
                    }
                }
            }
            else
            {
                var smudgeType = world.GetTerrainInfo(targetTile).AcceptsSmudgeType.FirstOrDefault(t => warhead.SmudgeType.Contains(t));
                if (smudgeType != null)
                {
                    SmudgeLayer smudgeLayer;
                    if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer))
                    {
                        throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType));
                    }

                    smudgeLayer.AddSmudge(targetTile);
                }
            }

            if (warhead.Ore)
            {
                world.WorldActor.Trait <ResourceLayer>().Destroy(targetTile);
            }

            switch (warhead.DamageModel)
            {
            case DamageModel.Normal:
            {
                var maxSpread = warhead.Spread * (float)Math.Log(Math.Abs(warhead.Damage), 2);
                var range     = new WRange((int)maxSpread * 1024 / Game.CellSize);
                var hitActors = world.FindActorsInCircle(pos, range);

                foreach (var victim in hitActors)
                {
                    var damage = (int)GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier, true);
                    victim.InflictDamage(firedBy, damage, warhead);
                }
            } break;

            case DamageModel.PerCell:
            {
                foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0]))
                {
                    foreach (var unit in world.ActorMap.GetUnitsAt(t))
                    {
                        var damage = (int)GetDamageToInflict(pos, unit, warhead, weapon, firepowerModifier, false);
                        unit.InflictDamage(firedBy, damage, warhead);
                    }
                }
            } break;

            case DamageModel.HealthPercentage:
            {
                var range     = new WRange(warhead.Size[0] * 1024);
                var hitActors = world.FindActorsInCircle(pos, range);

                foreach (var victim in hitActors)
                {
                    var damage = GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier, false);
                    if (damage != 0)                                     // will be 0 if the target doesn't have HealthInfo
                    {
                        var healthInfo = victim.Info.Traits.Get <HealthInfo>();
                        damage = (float)(damage / 100 * healthInfo.HP);
                    }
                    victim.InflictDamage(firedBy, (int)damage, warhead);
                }
            } break;
            }
        }
Пример #25
0
        public void Tick(World world)
        {
            if (anim != null)
                anim.Tick();

            pos = WPos.LerpQuadratic(args.Source, target, angle, ticks, length);

            if (info.Trail != null && --smokeTicks < 0)
            {
                var delayedPos = WPos.LerpQuadratic(args.Source, target, angle, ticks - info.TrailDelay, length);
                world.AddFrameEndTask(w => w.Add(new Smoke(w, delayedPos, info.Trail)));
                smokeTicks = info.TrailInterval;
            }

            if (info.ContrailLength > 0)
                trail.Update(pos);

            if (ticks++ >= length || (!info.High && world.ActorMap
                .GetUnitsAt(pos.ToCPos()).Any(a => a.HasTrait<IBlocksBullets>())))
            {
                Explode(world);
            }
        }