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); }
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--; } }
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); }
private LocAndOffsets AverageLocation(LocAndOffsets a, LocAndOffsets b) { var averaged = (a.ToInches3D() + b.ToInches3D()) / 2; return(LocAndOffsets.FromInches(averaged)); }
public ProxListObj(GameObject obj, float radius, LocAndOffsets loc) { this.obj = obj; this.radius = radius; this.loc = loc; }
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); }
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; }
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); }
public static void Move(this GameObject obj, LocAndOffsets location) { GameSystems.MapObject.Move(obj, location); }
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; }
public AttackOfOpportunity(GameObject interrupter, float distance, LocAndOffsets location) { Interrupter = interrupter; Distance = distance; Location = location; }
public GoalDestination(GameObject obj, LocAndOffsets loc) { this.obj = obj; this.loc = loc; }
// 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); }