Пример #1
0
    public bool SetConeTargets(LocAndOffsets targetLocation)
    {
        result.flags    = PickerResultFlags.PRF_HAS_LOCATION | PickerResultFlags.PRF_HAS_MULTI_OBJ;
        result.location = targetLocation;
        result.offsetz  = 0;
        result.handle   = null;

        var originPos  = caster.GetLocationFull();
        var coneOrigin = originPos.ToInches2D();
        var coneTarget = targetLocation.ToInches2D();

        float radiusInches;

        if (!flagsTarget.HasFlag(UiPickerFlagsTarget.FixedRadius))
        {
            radiusInches = (coneTarget - coneOrigin).Length();
        }
        else
        {
            radiusInches = radiusTarget * locXY.INCH_PER_FEET;
        }

        var arcRad   = Angles.ToRadians(degreesTarget);
        var arcStart = (coneTarget - coneOrigin).GetWorldRotation() - arcRad;

        using var objList = ObjList.ListCone(originPos, radiusInches, arcStart, arcRad, ObjectListFilter.OLC_ALL);
        result.objList    = new List <GameObject>(objList);

        if (!flagsTarget.HasFlag(UiPickerFlagsTarget.Unknown80h))
        {
            RemoveTargetsNotInLineOfSightOf(originPos);
        }

        DoExclusions();

        return(true);
    }
    public bool IsValid(LocAndOffsets center)
    {
        if (CenterTile != center.location)
        {
            return(false);
        }

        // Determine which sub-tile of the tile the critter is standing on
        var subtileX = SubtileFromOffset(center.off_x);

        if (subtileX != _centerSubtile.X)
        {
            return(false);
        }

        var subtileY = SubtileFromOffset(center.off_y);

        if (subtileY != _centerSubtile.Y)
        {
            return(false);
        }

        return(true);
    }
Пример #3
0
    public Subtile(LocAndOffsets location)
    {
        // The tile address is converted into the center subtile
        X = 3 * location.location.locx + 1;
        Y = 3 * location.location.locy + 1;

        if (location.off_x > HalfSubtile)
        {
            X++;
        }
        else if (location.off_x < -HalfSubtile)
        {
            X--;
        }

        if (location.off_y > HalfSubtile)
        {
            Y++;
        }
        else if (location.off_y < -HalfSubtile)
        {
            Y--;
        }
    }
Пример #4
0
    public void Render(IGameViewport viewport, LocAndOffsets loc, LocAndOffsets tgtLoc,
                       float degreesTarget,
                       IMdfRenderMaterial materialInside,
                       IMdfRenderMaterial materialOutside)
    {
        Span <IntgameVertex> vertices = stackalloc IntgameVertex[38];

        var elevation      = MathF.Sin(-0.77539754f) * -1.5f;
        var outerConeAngle = Angles.ToRadians(degreesTarget);

        var originPos = loc.ToInches3D();

        var targetPos = tgtLoc.ToInches3D();

        var d          = targetPos - originPos;
        var coneRadius = d.Length();
        // The normal pointing in the direction of the target straight down the middle of the cone
        var coneNormal = d / coneRadius;

        // A portion of the full cone will be rendered as a "rim" on the outside, which
        // will have this radius:
        var ringRadius = MathF.Min(24.0f, coneRadius / 7.0f);

        var innerConeRadius = coneRadius - ringRadius;

        // Set the origin point
        vertices[0].pos     = new Vector4(originPos.X, elevation, originPos.Z, 1);
        vertices[0].normal  = Vector4.UnitY;
        vertices[0].uv      = new Vector2(0, 0);
        vertices[0].diffuse = PackedLinearColorA.White;

        var   innerConeAngle     = (1.0f - (ringRadius + ringRadius) / (outerConeAngle * coneRadius)) * outerConeAngle;
        var   innerConeAngleHalf = innerConeAngle * 0.5f;
        float angleStepInner     = innerConeAngle / 18;

        // This is the point at the center of the cone, but on the inner rim
        var coneNearX = innerConeRadius * coneNormal.X;
        var coneNearY = innerConeRadius * coneNormal.Z;

        for (var i = 1; i < 20; i++)
        {
            // angle=0 is straight down the center of the cone, so it is shifted to the left by coneAngle/2
            var angle = (i - 1) * angleStepInner - innerConeAngleHalf;
            vertices[i].pos = new Vector4(
                originPos.X + MathF.Cos(angle) * coneNearX - MathF.Sin(angle) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(angle) * coneNearX + MathF.Cos(angle) * coneNearY,
                1
                );

            vertices[i].normal  = Vector4.UnitY;
            vertices[i].diffuse = PackedLinearColorA.White;
            vertices[i].uv      = new Vector2(
                (i + 1) % 2,
                1.0f
                );
        }

        _fanVertexBuffer.Resource.Update <IntgameVertex>(vertices.Slice(0, 20));
        _fanBufferBinding.Resource.Bind();
        _device.SetIndexBuffer(_fanIndexBuffer);
        materialInside.Bind(viewport, _device, new List <Light3d>());
        _device.DrawIndexed(PrimitiveType.TriangleList, 20, FanIndices.Length);

        var slice = 0.0f;
        // Far center point of the cone, on the outside rim
        var coneFarX = coneRadius * coneNormal.X;
        var coneFarY = coneRadius * coneNormal.Z;

        for (var i = 0; i < 38; i += 2)
        {
            var angle = slice * angleStepInner - innerConeAngleHalf;

            vertices[i].pos = new Vector4(
                originPos.X + MathF.Cos(angle) * coneNearX - MathF.Sin(angle) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(angle) * coneNearX + MathF.Cos(angle) * coneNearY,
                1
                );
            vertices[i].normal  = Vector4.UnitY;
            vertices[i].uv      = new Vector2(slice, 0);
            vertices[i].diffuse = PackedLinearColorA.White;

            vertices[i + 1].pos = new Vector4(
                originPos.X + MathF.Cos(angle) * coneFarX - MathF.Sin(angle) * coneFarY,
                elevation,
                originPos.Z + MathF.Cos(angle) * coneFarY + MathF.Sin(angle) * coneFarX,
                1
                );
            vertices[i + 1].normal  = Vector4.UnitY;
            vertices[i + 1].uv      = new Vector2(slice, 1);
            vertices[i + 1].diffuse = PackedLinearColorA.White;

            slice += 1;
        }

        _ringVertexBuffer.Resource.Update <IntgameVertex>(vertices.Slice(0, 38));
        _ringBufferBinding.Resource.Bind();
        _device.SetIndexBuffer(_ringIndexBuffer);
        materialOutside.Bind(viewport, _device, new List <Light3d>());
        _device.DrawIndexed(PrimitiveType.TriangleList, 38, RingIndices.Length);

        // Render the left and right side of the cone using the same texture as the outside ring

        var innerConeAngleHalfInv = -innerConeAngleHalf;
        var outerConeAngleHalf    = outerConeAngle * 0.5f;
        var outerConeAngleHalfInv = -outerConeAngleHalf;
        var v71 = innerConeRadius / ringRadius;

        // Right flank of the cone
        vertices[0] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(innerConeAngleHalfInv) * coneFarX - MathF.Sin(innerConeAngleHalfInv) * coneFarY,
                elevation,
                originPos.Z + MathF.Sin(innerConeAngleHalfInv) * coneFarX + MathF.Cos(innerConeAngleHalfInv) * coneFarY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[1] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(outerConeAngleHalfInv) * coneFarX - MathF.Sin(outerConeAngleHalfInv) * coneFarY,
                elevation,
                originPos.Z + MathF.Sin(outerConeAngleHalfInv) * coneFarX + MathF.Cos(outerConeAngleHalfInv) * coneFarY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[2] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(innerConeAngleHalfInv) * coneNearX - MathF.Sin(innerConeAngleHalfInv) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(innerConeAngleHalfInv) * coneNearX + MathF.Cos(innerConeAngleHalfInv) * coneNearY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 0),
            diffuse = PackedLinearColorA.White
        };
        vertices[3] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(outerConeAngleHalfInv) * coneNearX - MathF.Sin(outerConeAngleHalfInv) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(outerConeAngleHalfInv) * coneNearX + MathF.Cos(outerConeAngleHalfInv) * coneNearY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[4] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X,
                elevation,
                originPos.Z,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(-v71, 0.5f),
            diffuse = PackedLinearColorA.White
        };

        // Left flank of the cone
        vertices[5] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(innerConeAngleHalf) * coneFarX - MathF.Sin(innerConeAngleHalf) * coneFarY,
                elevation,
                originPos.Z + MathF.Sin(innerConeAngleHalf) * coneFarX + MathF.Cos(innerConeAngleHalf) * coneFarY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[6] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(outerConeAngleHalf) * coneFarX - MathF.Sin(outerConeAngleHalf) * coneFarY,
                elevation,
                originPos.Z + MathF.Sin(outerConeAngleHalf) * coneFarX + MathF.Cos(outerConeAngleHalf) * coneFarY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[7] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(innerConeAngleHalf) * coneNearX - MathF.Sin(innerConeAngleHalf) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(innerConeAngleHalf) * coneNearX + MathF.Cos(innerConeAngleHalf) * coneNearY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 0),
            diffuse = PackedLinearColorA.White
        };
        vertices[8] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(outerConeAngleHalf) * coneNearX - MathF.Sin(outerConeAngleHalf) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(outerConeAngleHalf) * coneNearX + MathF.Cos(outerConeAngleHalf) * coneNearY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        // This could reuse vertices[4], but was here in vanilla also
        vertices[9] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X,
                elevation,
                originPos.Z,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(v71, 0.5f),
            diffuse = PackedLinearColorA.White
        };

        _flankVertexBuffer.Resource.Update <IntgameVertex>(vertices.Slice(0, 10));
        _flankBufferBinding.Resource.Bind();
        _device.SetIndexBuffer(_flankIndexBuffer);
        materialOutside.Bind(viewport, _device, new List <Light3d>());
        _device.DrawIndexed(PrimitiveType.TriangleList, 10, FlankIndices.Length);
    }
Пример #5
0
    private LocAndOffsets AverageLocation(LocAndOffsets a, LocAndOffsets b)
    {
        var averaged = (a.ToInches3D() + b.ToInches3D()) / 2;

        return(LocAndOffsets.FromInches(averaged));
    }
Пример #6
0
 public ProxListObj(GameObject obj, float radius, LocAndOffsets loc)
 {
     this.obj    = obj;
     this.radius = radius;
     this.loc    = loc;
 }
Пример #7
0
    public void TestRaycast()
    {
        var origin = new LocAndOffsets(new locXY(496, 458), -9.42809f, -8.42809f);
        var target = new LocAndOffsets(new locXY(512, 611), -7.42809f, -7.42809f);
        var radius = 17.5f;

        var ray_search = new RaycastPointSearchPacket();

        ray_search.origin = origin.ToInches2D();
        ray_search.target = target.ToInches2D();
        ray_search.radius = radius;

        ray_search.direction  = ray_search.target - ray_search.origin;
        ray_search.rangeInch  = ray_search.direction.Length();
        ray_search.direction /= ray_search.rangeInch;

        ray_search.absOdotU = Vector2.Dot(ray_search.direction, ray_search.origin);

        var locBeforeCover = target;
        SearchPointAlongRay search_func = RaycastPacket.IsPointCloseToSegment;

        var tileRadius = 1 + (int)(radius / locXY.INCH_PER_TILE);

        TestContext.Out.WriteLine(tileRadius.ToString());
        var tile_rect = RaycastPacket.BuildSearchRectangle(ray_search.origin, ray_search.target);

        var canFly = false;

        foreach (var s in tile_rect)
        {
            //int left = Math.Max(0, s.TileRectangle.Left - tileRadius);
            //int top = Math.Max(0, s.TileRectangle.Top - tileRadius);
            //int right = Math.Min(64, s.TileRectangle.Right + tileRadius);
            //int bottom = Math.Min(64, s.TileRectangle.Bottom + tileRadius);

            int left   = s.TileRectangle.Left;
            int top    = s.TileRectangle.Top;
            int right  = s.TileRectangle.Right;
            int bottom = s.TileRectangle.Bottom;

            TestContext.Out.WriteLine($"{s.SectorLoc.X} {s.SectorLoc.Y} {left},{top} {right},{bottom}");
        }
        TestContext.Out.WriteLine("OLD OLD OLD");

        if (!PreciseSectorRows.Build(tile_rect, out var sector_tiles))
        {
            return;
        }

        var local_254 = Math.Min(origin.location.locx, target.location.locx);
        var local_25c = Math.Max(origin.location.locx, target.location.locx);
        var local_2a4 = Math.Min(origin.location.locy, target.location.locy);
        var local_2b4 = Math.Max(origin.location.locy, target.location.locy);

/*
 *          local_254 -= tileRadius;
 *          local_2a4 -= tileRadius;
 *          local_25c += tileRadius;
 *          local_2b4 += tileRadius;
 */
        for (var local_2dc = 0; local_2dc < sector_tiles.RowCount; local_2dc++)
        {
            ref var pPVar2 = ref sector_tiles.Rows[local_2dc];

            Span <int> local_208 = stackalloc int[pPVar2.colCount];
            Span <int> local_1d8 = stackalloc int[pPVar2.colCount];

            for (var i = 0; i < pPVar2.colCount; i++)
            {
                local_208[i] = pPVar2.startTiles[i];
                local_1d8[i] = 64 - pPVar2.strides[i];
            }

            for (var local_2f0 = 0; local_2f0 < pPVar2.colCount; local_2f0++)
            {
                var sectorBaseTile = pPVar2.sectors[local_2f0].GetBaseTile();
                var sectorTileMinX = local_254 - sectorBaseTile.locx;
                var sectorTileMaxX = local_25c - sectorBaseTile.locx;
                var sectorTileMinY = local_2a4 - sectorBaseTile.locy;
                var sectorTileMaxY = local_2b4 - sectorBaseTile.locy;
                if (sectorTileMinX < 0)
                {
                    sectorTileMinX = 0;
                }

                if (sectorTileMinY < 0)
                {
                    sectorTileMinY = 0;
                }

                if (sectorTileMaxX > 63)
                {
                    sectorTileMaxX = 63;
                }

                if (sectorTileMaxY > 63)
                {
                    sectorTileMaxY = 63;
                }

                TestContext.Out.WriteLine($"{pPVar2.sectors[local_2f0].X} {pPVar2.sectors[local_2f0].Y} {sectorTileMinX},{sectorTileMinY}->{sectorTileMaxX},{sectorTileMaxY}");
            }
        }
    public override bool OnTrap(TrapSprungEvent trap, GameObject triggerer)
    {
        if ((trap.Type.Id == 2))
        {
            // numP = 210 / (game.party_npc_size() + game.party_pc_size())
            // for obj in game.obj_list_vicinity( triggerer.location, OLC_CRITTERS ):
            // obj.stat_base_set(stat_experience, (obj.stat_level_get(stat_experience) - numP))
            AttachParticles(trap.Type.ParticleSystemId, trap.Object);
            Sound(4023, 1);
            var result = trap.Attack(triggerer, 10, 20, false);
            if (((result & D20CAF.HIT)) != D20CAF.NONE)
            {
                if ((!triggerer.SavingThrow(15, SavingThrowType.Fortitude, D20SavingThrowFlag.POISON, trap.Object)))
                {
                    triggerer.AddCondition("Poisoned", trap.Type.Damage[0].Dice.Modifier, 0);
                }

                var d = trap.Type.Damage[1].Dice.Copy();
                if (((result & D20CAF.CRITICAL)) != D20CAF.NONE)
                {
                    d = d.WithCount(d.Count * 2);
                    d = d.WithModifier(d.Modifier * 2);
                }

                triggerer.Damage(trap.Object, trap.Type.Damage[1].Type, d);
            }

            foreach (var obj in ObjList.ListVicinity(triggerer.GetLocation(), ObjectListFilter.OLC_CRITTERS))
            {
                if ((obj.DistanceTo(trap.Object) <= 15))
                {
                    if ((obj.HasLineOfSight(trap.Object)))
                    {
                        if ((!obj.SavingThrow(15, SavingThrowType.Fortitude, D20SavingThrowFlag.POISON, trap.Object)))
                        {
                            obj.AddCondition("Poisoned", trap.Type.Damage[2].Dice.Modifier, 0);
                        }
                    }
                }
            }

            DetachScript();
        }

        if ((trap.Type.Id == 3))
        {
            // numP = 210 / (game.party_npc_size() + game.party_pc_size())
            // for obj in game.obj_list_vicinity( triggerer.location, OLC_CRITTERS ):
            // obj.stat_base_set(stat_experience, (obj.stat_level_get(stat_experience) - numP))
            AttachParticles(trap.Type.ParticleSystemId, trap.Object);
            Sound(4023, 1);
            var result = trap.Attack(triggerer, 8, 20, false);
            if (((result & D20CAF.HIT)) != D20CAF.NONE)
            {
                if ((!triggerer.SavingThrow(13, SavingThrowType.Fortitude, D20SavingThrowFlag.POISON, trap.Object)))
                {
                    triggerer.AddCondition("Poisoned", trap.Type.Damage[0].Dice.Modifier, 0);
                }

                var d = trap.Type.Damage[1].Dice.Copy();
                if (((result & D20CAF.CRITICAL)) != D20CAF.NONE)
                {
                    d = d.WithCount(d.Count * 2);
                    d = d.WithModifier(d.Modifier * 2);
                }

                triggerer.Damage(trap.Object, trap.Type.Damage[1].Type, d);
            }

            DetachScript();
        }

        if ((trap.Type.Id == 4))
        {
            // numP = 210 / (game.party_npc_size() + game.party_pc_size())
            // for obj in game.obj_list_vicinity( triggerer.location, OLC_CRITTERS ):
            // obj.stat_base_set(stat_experience, (obj.stat_level_get(stat_experience) - numP))
            AttachParticles(trap.Type.ParticleSystemId, trap.Object);
            Sound(4023, 1);
            var result = trap.Attack(triggerer, 11, 20, false);
            if (((result & D20CAF.HIT)) != D20CAF.NONE)
            {
                if ((!triggerer.SavingThrow(16, SavingThrowType.Fortitude, D20SavingThrowFlag.POISON, trap.Object)))
                {
                    triggerer.AddCondition("Poisoned", trap.Type.Damage[0].Dice.Modifier, 0);
                }

                var d = trap.Type.Damage[1].Dice.Copy();
                if (((result & D20CAF.CRITICAL)) != D20CAF.NONE)
                {
                    d = d.WithCount(d.Count * 2);
                    d = d.WithModifier(d.Modifier * 2);
                }

                triggerer.Damage(trap.Object, trap.Type.Damage[1].Type, d);
            }

            foreach (var obj in ObjList.ListVicinity(triggerer.GetLocation(), ObjectListFilter.OLC_CRITTERS))
            {
                if ((obj.DistanceTo(trap.Object) <= 15))
                {
                    if ((obj.HasLineOfSight(trap.Object)))
                    {
                        obj.ReflexSaveAndDamage(trap.Object, 20, D20SavingThrowReduction.Half, D20SavingThrowFlag.SPELL_DESCRIPTOR_ACID, trap.Type.Damage[2].Dice, trap.Type.Damage[2].Type, D20AttackPower.NORMAL);
                    }
                }
            }

            DetachScript();
        }

        if ((trap.Type.Id == 7))
        {
            // numP = 210 / (game.party_npc_size() + game.party_pc_size())
            // for obj in game.obj_list_vicinity( triggerer.location, OLC_CRITTERS ):
            // obj.stat_base_set(stat_experience, (obj.stat_level_get(stat_experience) - numP))
            AttachParticles(trap.Type.ParticleSystemId, trap.Object);
            Sound(4023, 1);
            var result = trap.Attack(triggerer, 13, 20, false);
            if (((result & D20CAF.HIT)) != D20CAF.NONE)
            {
                if ((!triggerer.SavingThrow(18, SavingThrowType.Fortitude, D20SavingThrowFlag.POISON, trap.Object)))
                {
                    triggerer.AddCondition("Poisoned", trap.Type.Damage[0].Dice.Modifier, 0);
                }

                var d = trap.Type.Damage[1].Dice.Copy();
                if (((result & D20CAF.CRITICAL)) != D20CAF.NONE)
                {
                    d = d.WithCount(d.Count * 2);
                    d = d.WithModifier(d.Modifier * 2);
                }

                triggerer.Damage(trap.Object, trap.Type.Damage[1].Type, d);
            }

            foreach (var obj in ObjList.ListVicinity(triggerer.GetLocation(), ObjectListFilter.OLC_CRITTERS))
            {
                if ((obj.DistanceTo(trap.Object) <= 10))
                {
                    if ((obj.HasLineOfSight(trap.Object)))
                    {
                        if ((!obj.SavingThrow(18, SavingThrowType.Fortitude, D20SavingThrowFlag.POISON, trap.Object)))
                        {
                            obj.AddCondition("Poisoned", trap.Type.Damage[2].Dice.Modifier, 0);
                        }
                    }
                }
            }

            DetachScript();
        }

        // code to retain TRAP!!!
        if ((trap.Type.Id == 11 && triggerer.GetMap() == 5080))
        {
            // numP = 210 / (game.party_npc_size() + game.party_pc_size())
            // for obj in game.obj_list_vicinity( triggerer.location, OLC_CRITTERS ):
            // obj.stat_base_set(stat_experience, (obj.stat_level_get(stat_experience) - numP))
            LocAndOffsets loct = LocAndOffsets.Zero;
            foreach (var chest in ObjList.ListVicinity(triggerer.GetLocation(), ObjectListFilter.OLC_CONTAINER))
            {
                if ((chest.GetNameId() == 1055 && chest.DistanceTo(trap.Object) <= 5))
                {
                    var loc1 = new locXY(484, 566);
                    var loc2 = new locXY(476, 582);
                    var loc  = chest.GetLocation();
                    loct = trap.Object.GetLocationFull();
                    if ((loc1 >= loc))
                    {
                        chest.Destroy();
                        var item = GameSystems.MapObject.CreateObject(1055, new locXY(484, 566));
                    }

                    if ((loc2 >= loc && loc1 <= loc))
                    {
                        chest.Destroy();
                        var item = GameSystems.MapObject.CreateObject(1055, new locXY(476, 582));
                    }
                }
            }

            if (loct != LocAndOffsets.Zero)
            {
                var npc = GameSystems.MapObject.CreateObject(14605, loct);
                triggerer.BeginDialog(npc, 1000);
            }
        }

        return(SkipDefault);
    }
Пример #9
0
    public static void encounter_create(RandomEncounter encounter)
    {
        Logger.Info("Testing encounter_create with id={0}", encounter.Id);
        var is_sleep_encounter = false;

        LocAndOffsets location;

        if ((encounter.Id >= 4000))
        {
            location           = SelectedPartyLeader.GetLocationFull();
            is_sleep_encounter = true;
        }
        else
        {
            location = new LocAndOffsets(encounter.Location);
        }

        var i = 0;

        var total = encounter.Enemies.Count;

        while ((i < total))
        {
            var j = 0;

            while ((j < encounter.Enemies[i].Count))
            {
                if (is_sleep_encounter)
                {
                    var party = new List <GameObject>();

                    foreach (var pc in GameSystems.Party.PartyMembers)
                    {
                        if (!pc.IsUnconscious())
                        {
                            party.Add(pc);
                        }
                    }

                    if (party.Count > 0)
                    {
                        location = party[i % party.Count].GetLocationFull();
                    }
                }

                var npc = GameSystems.MapObject.CreateObject(encounter.Enemies[i].ProtoId, location);

                if ((npc != null))
                {
                    npc.TurnTowards(SelectedPartyLeader);
                    if (((encounter.Id < 2000) || (encounter.Id >= 4000)))
                    {
                        npc.Attack(SelectedPartyLeader);
                        npc.SetNpcFlag(NpcFlag.KOS);
                    }
                }

                j = j + 1;
            }

            i = i + 1;
        }

        return;
    }
Пример #10
0
    public List <Light3d> FindLights(LocAndOffsets atLocation, float radius)
    {
        List <Light3d> lights = new List <Light3d>();

        if (GameSystems.Light.IsGlobalLightEnabled)
        {
            Light3d light       = new Light3d();
            var     legacyLight = GameSystems.Light.GlobalLight;
            light.type  = (Light3dType)legacyLight.type;
            light.color = legacyLight.Color;
            light.dir.X = legacyLight.dir.X;
            light.dir.Y = legacyLight.dir.Y;
            light.dir.Z = legacyLight.dir.Z;
            light.pos.X = legacyLight.pos.X;
            light.pos.Y = legacyLight.pos.Y;
            light.pos.Z = legacyLight.pos.Z;
            light.range = legacyLight.range;
            light.phi   = legacyLight.phi;
            lights.Add(light);
        }

        if (radius == 0)
        {
            return(lights);
        }

        // Build a box that has twice the radius convert to tiles as it's width/height
        // For some reason, ToEE will add one more INCH_PER_TILE here, which translates to
        // roughly 28 tiles more search radius than is needed
        var boxDimensions = (int)(radius / locXY.INCH_PER_TILE + locXY.INCH_PER_TILE);
        var tileX1        = atLocation.location.locx - 1 - boxDimensions;
        var tileX2        = atLocation.location.locx + 1 + boxDimensions;
        var tileY1        = atLocation.location.locy - 1 - boxDimensions;
        var tileY2        = atLocation.location.locy + 1 + boxDimensions;

        using var sectorIterator = new SectorIterator(tileX1, tileX2, tileY1, tileY2);

        var atPos = atLocation.ToInches2D();

        while (sectorIterator.HasNext)
        {
            using var sector = sectorIterator.Next();

            foreach (ref var light in sector.Lights)
            {
                int         type;
                LinearColor color;
                Vector3     direction;
                float       range, phi;
                var         lightPos = light.position.ToInches2D();

                if ((light.flags & 0x40) != 0)
                {
                    if (GameSystems.Light.IsNight)
                    {
                        type      = light.light2.type;
                        color     = light.light2.color;
                        direction = light.light2.direction;
                        range     = light.range; // Notice how it's using light 1's range
                        phi       = light.light2.phi;

                        /*
                         * Kill the daytime particle system if it's night and the
                         * daytime particle system is still alive.
                         */
                        if (light.partSys.handle != null)
                        {
                            GameSystems.ParticleSys.Remove(light.partSys.handle);
                            light.partSys.handle = null;
                        }

                        /*
                         * If the nighttime particle system has not yet been started,
                         * do it here.
                         */
                        ref var nightPartSys = ref light.light2.partSys;
                        if (nightPartSys.handle == null && nightPartSys.hashCode != 0)
                        {
                            var centerOfTile = light.position.ToInches3D(light.offsetZ);
                            nightPartSys.handle = GameSystems.ParticleSys.CreateAt(
                                nightPartSys.hashCode, centerOfTile
                                );
                        }
                    }
                    else
                    {
                        type      = light.type;
                        color     = light.color;
                        direction = light.direction;
                        range     = light.range;
                        phi       = light.phi;

                        // This is just the inverse of what we're doing at night (see above)
                        ref var nightPartSys = ref light.light2.partSys;
                        if (nightPartSys.handle != null)
                        {
                            GameSystems.ParticleSys.Remove(nightPartSys.handle);
                            nightPartSys.handle = null;
                        }

                        ref var dayPartSys = ref light.partSys;
                        if (dayPartSys.handle == null && dayPartSys.hashCode != 0)
                        {
                            var centerOfTile = light.position.ToInches3D(light.offsetZ);
                            dayPartSys.handle = GameSystems.ParticleSys.CreateAt(
                                dayPartSys.hashCode, centerOfTile
                                );
                        }
                    }
                }
    private void PartySelectedFormationMoveToPosition_FindPath(GameObject partyMember, int count,
                                                               LocAndOffsets from, LocAndOffsets plannedPos, out LocAndOffsets actualPos)
    {
        actualPos = plannedPos;

        if (IsBlocked(plannedPos.ToInches2D(), partyMember.GetRadius()))
        {
            var pq = new PathQuery();
            pq.flags2  = (int)AnimPathDataFlags.UNK_2000;
            pq.flags   = PathQueryFlags.PQF_FORCED_STRAIGHT_LINE | PathQueryFlags.PQF_HAS_CRITTER;
            pq.critter = partyMember;
            pq.from    = from;
            pq.to      = plannedPos;
            pq.flags   = PathQueryFlags.PQF_FORCED_STRAIGHT_LINE | PathQueryFlags.PQF_HAS_CRITTER |
                         PathQueryFlags.PQF_TO_EXACT | PathQueryFlags.PQF_800;
            pq.distanceToTargetMin = count * locXY.INCH_PER_TILE;
            if (!GameSystems.Combat.IsCombatActive())
            {
                pq.flags |= PathQueryFlags.PQF_IGNORE_CRITTERS;
            }

            if (GameSystems.PathX.FindPath(pq, out var pathResult))
            {
                actualPos = pathResult.nodes[pathResult.nodeCount - 1];
            }
        }
    }
    public int PartySelectedFormationMoveToPosition(LocAndOffsets loc, bool mayWalk)
    {
        var selectedMembers = GameSystems.Party.Selected;

        if (selectedMembers.Count == 0)
        {
            return(1);
        }

        var maxRadius = float.MinValue;

        foreach (var selectedMember in selectedMembers)
        {
            if (!GameSystems.Critter.IsDeadNullDestroyed(selectedMember))
            {
                maxRadius = Math.Max(maxRadius, selectedMember.GetRadius());
            }
        }

        Span <LocAndOffsets> plannedPositions = stackalloc LocAndOffsets[selectedMembers.Count];

        if (!FindFreeTargetPos(ref loc, maxRadius))
        {
            return(1);
        }

        // NOTE: There seems to have been a bug in Vanilla where it wanted to
        // find the average center of the party, but never actually updated the obj
        // it took the position of. So it ended up just taking the leader's position.
        var leaderPos = selectedMembers[0].GetLocationFull().ToInches2D();
        var targetPos = loc.ToInches2D();

        // This rotation is used to rotate the formation at the target point
        var formationRotation = MathF.PI - MathF.Atan2(targetPos.X - leaderPos.X, targetPos.Y - leaderPos.Y);

        if (!GameSystems.Critter.IsDeadNullDestroyed(selectedMembers[0]))
        {
            plannedPositions[0] = loc;
        }

        for (var selectedIdx = 0; selectedIdx < selectedMembers.Count; selectedIdx++)
        {
            var obj = selectedMembers[selectedIdx];
            if (GameSystems.Critter.IsDeadNullDestroyed(obj))
            {
                continue;
            }

            var partyMemberRadius = obj.GetRadius();

            GetFormationOffset(obj, formationRotation, out var formationOffX, out var formationOffY);
            if (selectedMembers.Count < 2)
            {
                plannedPositions[selectedIdx] = loc;
            }
            else
            {
                var formationOffLen = MathF.Sqrt(formationOffY * formationOffY + formationOffX * formationOffX);
                // Remember that the length of the formation offset can be 0 in case it's dead-center
                if (formationOffLen > locXY.INCH_PER_SUBTILE)
                {
                    // Normalize the formation offset
                    var formationOffNormX = formationOffX / formationOffLen;
                    var formationOffNormY = formationOffY / formationOffLen;
                    var formationOffDir   = new Vector2(formationOffNormX, formationOffNormY);

                    var local_90 = 0.0f;
                    for (; local_90 < formationOffLen; local_90 += locXY.INCH_PER_SUBTILE)
                    {
                        var formationShift = local_90 * formationOffDir;
                        var formationPos   = targetPos + formationShift;

                        if (!IsBlocked(formationPos, maxRadius))
                        {
                            plannedPositions[selectedIdx] = LocAndOffsets.FromInches(formationPos);
                            break;
                        }
                    }

                    if (local_90 >= locXY.INCH_PER_SUBTILE)
                    {
                        // It somehow falls back to the previous location even if unblocked ???
                        var formationPos = targetPos + (local_90 - locXY.INCH_PER_SUBTILE) * formationOffDir;
                        plannedPositions[selectedIdx] = LocAndOffsets.FromInches(formationPos);
                    }
                }
                else
                {
                    plannedPositions[selectedIdx] = loc;
                }
            }

            var previousPositions = plannedPositions.Slice(0, selectedIdx);

            // We have to do conflict resolution if another party member before this one
            // chose a colliding position
            if (FindIntersectingPosition(selectedMembers, previousPositions,
                                         plannedPositions[selectedIdx].ToInches2D(), partyMemberRadius))
            {
                int upperBound;
                for (upperBound = 1; upperBound < 18; upperBound++)
                {
                    var local_84 = upperBound * locXY.INCH_PER_SUBTILE;

                    int local_8c;
                    var alternatePos = plannedPositions[selectedIdx].ToInches2D();
                    for (local_8c = -upperBound; local_8c < upperBound; local_8c++)
                    {
                        alternatePos    = plannedPositions[selectedIdx].ToInches2D();
                        alternatePos.X += local_8c * locXY.INCH_PER_SUBTILE;
                        alternatePos.Y -= local_84;
                        if (!FindIntersectingPosition(selectedMembers, previousPositions, alternatePos,
                                                      partyMemberRadius) &&
                            !IsBlocked(alternatePos, partyMemberRadius))
                        {
                            break;
                        }

                        alternatePos    = plannedPositions[selectedIdx].ToInches2D();
                        alternatePos.X -= local_8c * locXY.INCH_PER_SUBTILE;
                        alternatePos.Y += local_84;
                        if (!FindIntersectingPosition(selectedMembers, previousPositions, alternatePos,
                                                      partyMemberRadius) &&
                            !IsBlocked(alternatePos, partyMemberRadius))
                        {
                            break;
                        }

                        alternatePos    = plannedPositions[selectedIdx].ToInches2D();
                        alternatePos.X -= local_8c * locXY.INCH_PER_SUBTILE;
                        alternatePos.Y -= local_84;
                        if (!FindIntersectingPosition(selectedMembers, previousPositions, alternatePos,
                                                      partyMemberRadius) &&
                            !IsBlocked(alternatePos, partyMemberRadius))
                        {
                            break;
                        }

                        alternatePos    = plannedPositions[selectedIdx].ToInches2D();
                        alternatePos.X += local_8c * locXY.INCH_PER_SUBTILE;
                        alternatePos.Y += local_84;
                        if (!FindIntersectingPosition(selectedMembers, previousPositions, alternatePos,
                                                      partyMemberRadius) &&
                            !IsBlocked(alternatePos, partyMemberRadius))
                        {
                            break;
                        }
                    }

                    if (local_8c != upperBound)
                    {
                        plannedPositions[selectedIdx] = LocAndOffsets.FromInches(alternatePos);
                        break;
                    }
                }

                if (upperBound == 18)
                {
                    Logger.Info("Unable to find suitable formation position after 18 iterations.");
                }
            }
        }

        for (var i = 0; i < selectedMembers.Count; i++)
        {
            var obj = selectedMembers[i];
            if (!GameSystems.Critter.IsDeadNullDestroyed(obj))
            {
                PartySelectedFormationMoveToPosition_FindPath(obj, selectedMembers.Count, loc,
                                                              plannedPositions[i], out var actualTargetPos);
                if (!mayWalk)
                {
                    GameSystems.Anim.PushRunToTile(obj, actualTargetPos);
                    GameSystems.Anim.TurnOnRunning();
                }
                else
                {
                    GameSystems.Anim.PushMoveToTile(obj, actualTargetPos);
                }
            }
        }

        return(1);
    }
Пример #13
0
 public static void Move(this GameObject obj, LocAndOffsets location)
 {
     GameSystems.MapObject.Move(obj, location);
 }
Пример #14
0
    public override void OnSpellEffect(SpellPacketBody spell)
    {
        Logger.Info("Dimension Door OnSpellEffect");
        AttachParticles("sp-Dimension Door", spell.caster);
        var target = spell.caster;

        if (spell.caster.GetNameId() == 8042 && spell.caster.GetMap() == 5121) // Iuz teleport in Verbobonc
        {
            var stop_condition = 0;
            var target_loc     = Utilities.party_closest(spell.caster, exclude_warded: true).GetLocation();
            var(xx_o, yy_o) = target_loc;
            var xx            = xx_o;
            var yy            = yy_o;
            var attempt_count = 0;
            while (stop_condition == 0 && attempt_count < 15)
            {
                attempt_count += 1;
                var loc_list = new List <locXY>();
                foreach (var obj in ObjList.ListVicinity(target_loc, ObjectListFilter.OLC_NPC | ObjectListFilter.OLC_PC))
                {
                    if (!obj.IsUnconscious())
                    {
                        loc_list.Add(obj.GetLocation());
                    }
                }

                if (dist_from_set(xx, yy, loc_list) < 2 * locXY.INCH_PER_TILE || (xx >= 516 && xx <= 528 && yy >= 629 && yy <= 641))
                {
                    xx = xx_o + RandomRange(-4, 3);
                    yy = yy_o + RandomRange(-4, 3);
                }
                else if (attempt_count >= 15)
                {
                    xx = xx_o;
                    yy = yy_o;
                }
                else
                {
                    // game.global_vars[498] = (xx_o - xx)**2 + 1000* (yy_o-yy)**2
                    // game.global_vars[499] = attempt_count
                    stop_condition = 1;
                }
            }

            target_loc = new locXY(xx, yy);
            target.FadeTo(0, 10, 40);
            // WIP! SMM: added timeevent to trigger fadein (in realtime)
            AttachParticles("sp-Dimension Door", target);
            var target_loc_precise = new LocAndOffsets(target_loc);
            StartTimer(750, () => fade_back_in(target, target_loc_precise, spell), true);
        }
        else if (!target.HasCondition(SpellEffects.SpellDimensionalAnchor))
        {
            target.FadeTo(0, 10, 40);
            // WIP! SMM: added timeevent to trigger fadein (in realtime)
            AttachParticles("sp-Dimension Door", target);
            StartTimer(750, () => fade_back_in(target, spell.aoeCenter, spell), true);
        }
        else
        {
            target.FloatMesFileLine("mes/spell.mes", 30011);
            AttachParticles("Fizzle", target);
            spell.RemoveTarget(target);
            spell.EndSpell();
        }
    }
 public PendingObjectMovement(GameObject obj, LocAndOffsets from, LocAndOffsets to)
 {
     Obj  = obj;
     From = from;
     To   = to;
 }
Пример #16
0
 public AttackOfOpportunity(GameObject interrupter, float distance, LocAndOffsets location)
 {
     Interrupter = interrupter;
     Distance    = distance;
     Location    = location;
 }
Пример #17
0
 public GoalDestination(GameObject obj, LocAndOffsets loc)
 {
     this.obj = obj;
     this.loc = loc;
 }
Пример #18
0
    // TODO: Separate logic+rendering
    public void AdvanceAndRender(
        IGameViewport viewport,
        GameObject giantFrog,
        AnimatedModelParams animParams,
        IAnimatedModel model,
        IList <Light3d> lights,
        float alpha)
    {
        var grappleState = GetGrappleState(giantFrog);

        if (grappleState.state == 0)
        {
            return;
        }

        model.GetBoneWorldMatrixByName(animParams, "Tongue_Ref", out var worldMatrixFrog);

        var   grappledOpponent = GetGrappledOpponent(giantFrog);
        float tongueLength, tonguePosX, tonguePosZ;

        if (grappledOpponent != null)
        {
            var opponentModel      = grappledOpponent.GetOrCreateAnimHandle();
            var opponentAnimParams = grappledOpponent.GetAnimParams();
            opponentModel.GetBoneWorldMatrixByName(opponentAnimParams, "Bip01 Spine1", out var worldMatrixOpponent);

            tonguePosX = worldMatrixOpponent.M41;
            tonguePosZ = worldMatrixOpponent.M43;

            var tongueDirX = worldMatrixOpponent.M41 - worldMatrixFrog.M41;
            var tongueDirY = worldMatrixOpponent.M42 - worldMatrixFrog.M42;
            var tongueDirZ = worldMatrixOpponent.M43 - worldMatrixFrog.M43;
            tongueLength        = MathF.Sqrt(tongueDirX * tongueDirX + tongueDirY * tongueDirY + tongueDirZ * tongueDirZ);
            worldMatrixFrog.M31 = tongueDirX / tongueLength;
            worldMatrixFrog.M32 = tongueDirY / tongueLength;
            worldMatrixFrog.M33 = tongueDirZ / tongueLength;
            if (tongueLength > 0)
            {
                tongueLength -= 6.0f;
            }
        }
        else
        {
            tongueLength = 120.0f;
            tonguePosX   = worldMatrixFrog.M31 * 120.0f + worldMatrixFrog.M41;
            tonguePosZ   = worldMatrixFrog.M33 * 120.0f + worldMatrixFrog.M43;
        }

        switch (grappleState.state)
        {
        // This state seems to mean . Extending tongue to full length
        case 1:
            grappleState.currentLength += locXY.INCH_PER_TILE;
            if (grappleState.currentLength > tongueLength)
            {
                grappleState.state         = 2;
                grappleState.currentLength = tongueLength;
            }

            break;

        // This state seems to mean . Retracting tongue
        case 2:
            grappleState.currentLength -= locXY.INCH_PER_TILE;
            if (grappleState.currentLength <= 0)
            {
                grappleState.state         = 0;
                grappleState.currentLength = 0;
            }

            break;

        case 3:
            grappleState.currentLength += locXY.INCH_PER_TILE;
            if (grappleState.currentLength > tongueLength)
            {
                grappleState.state         = 4;
                grappleState.currentLength = tongueLength;
                var frogAnim = GameSystems.Critter.GetAnimId(giantFrog,
                                                             WeaponAnim.Special2);
                giantFrog.SetAnimId(frogAnim);

                var opponentAnim = GameSystems.Critter.GetAnimId(grappledOpponent,
                                                                 WeaponAnim.Panic);
                grappledOpponent.SetAnimId(opponentAnim);
            }

            break;

        case 4:
            // Maintain Tongue between frog and opponent without progressing
            grappleState.currentLength = tongueLength;
            break;

        case 5:
        case 6:
        {
            if (grappleState.state == 5)
            {
                grappleState.targetLength = tongueLength - 12.0f;
                if (grappleState.targetLength < 0)
                {
                    grappleState.targetLength = 0;
                }

                grappleState.state = 6;
            }

            grappleState.currentLength = grappleState.currentLength - locXY.INCH_PER_HALFTILE;
            // Move the opponent closer to the frog
            float newX   = tonguePosX - worldMatrixFrog.M31 * locXY.INCH_PER_HALFTILE;
            float newZ   = tonguePosZ - worldMatrixFrog.M33 * locXY.INCH_PER_HALFTILE;
            var   newLoc = LocAndOffsets.FromInches(newX, newZ);
            GameSystems.MapObject.Move(grappledOpponent, newLoc);

            if (grappleState.currentLength < grappleState.targetLength)
            {
                newX   = worldMatrixFrog.M41 + grappleState.targetLength * worldMatrixFrog.M31;
                newZ   = worldMatrixFrog.M43 + grappleState.targetLength * worldMatrixFrog.M33;
                newLoc = LocAndOffsets.FromInches(newX, newZ);
                GameSystems.MapObject.Move(grappledOpponent, newLoc);
                grappleState.currentLength = grappleState.targetLength;
                grappleState.state         = 4;
            }
        }
        break;

        case 7:
        {
            grappleState.currentLength = grappleState.currentLength - locXY.INCH_PER_HALFTILE;
            // Move the opponent closer to the frog
            float newX   = tonguePosX - worldMatrixFrog.M31 * locXY.INCH_PER_HALFTILE;
            float newZ   = tonguePosZ - worldMatrixFrog.M33 * locXY.INCH_PER_HALFTILE;
            var   newLoc = LocAndOffsets.FromInches(newX, newZ);
            GameSystems.MapObject.Move(grappledOpponent, newLoc);

            if (grappleState.currentLength < 0)
            {
                newX   = worldMatrixFrog.M41;
                newZ   = worldMatrixFrog.M43;
                newLoc = LocAndOffsets.FromInches(newX, newZ);
                GameSystems.MapObject.Move(grappledOpponent, newLoc);
                GameSystems.ObjFade.FadeTo(grappledOpponent, 0, 0, 16, 0);
                grappleState.currentLength = 0;
                grappleState.state         = 0;

                // Probably the swallow animation
                var animId = GameSystems.Critter.GetAnimId(giantFrog, WeaponAnim.Special3);
                giantFrog.SetAnimId(animId);
            }
        }
        break;

        default:
            break;
        }

        // Update to the new grapple state
        SetGrappleState(giantFrog, grappleState);

        // The directional vector of the tongue ref point on the frog
        var tongueUp    = worldMatrixFrog.GetRow(0).ToVector3();
        var tongueRight = worldMatrixFrog.GetRow(1).ToVector3();
        var tongueDir   = worldMatrixFrog.GetRow(2).ToVector3();
        var tonguePos   = worldMatrixFrog.GetRow(3).ToVector3();

        RenderTongue(viewport, grappleState, tongueDir, tongueUp, tongueRight, tonguePos, lights, alpha);
    }