public void DrawWorkerAnimated(Vector3 loc, Rot4 rot, int index, float extraRotation, bool rotatePoints = false) { Mesh mesh = MeshAt(rot); Vector3 newLoc = loc; Quaternion quaternion = QuatFromRot(rot); if (extraRotation != 0f) { quaternion *= Quaternion.Euler(Vector3.up * extraRotation); } Vector3 offset = DrawOffset(rot); if (rotatePoints && extraRotation != 0) { offset = Ext_Math.RotatePoint(offset, Vector3.zero, extraRotation); } newLoc += offset; Material mat = SubGraphicForIndex(index).MatSingle; DrawMeshInt(mesh, newLoc, quaternion, mat); if (ShadowGraphic != null) { ShadowGraphic.DrawWorker(newLoc, rot, null, null, extraRotation); } }
public static IEnumerable <AirDefense> CheckNearbyObjects(AerialVehicleInFlight aerialVehicle, float speedPctPerTick) { float halfTicksPerTileTraveled = Ext_Math.RoundTo(speedPctPerTick * 100, 0.001f); Vector3 start = aerialVehicle.DrawPos; for (int i = 0; i < aerialVehicle.flightPath.Path.Count; i++) { int destination = aerialVehicle.flightPath[i].tile; Vector3 destinationPos = Find.WorldGrid.GetTileCenter(destination); Vector3 position = start; for (float transition = 0; transition < 1; transition += halfTicksPerTileTraveled) { Vector3 partition = Vector3.Slerp(position, destinationPos, transition); foreach (KeyValuePair <WorldObject, AirDefense> defenseCache in airDefenseCache) { float distance = Ext_Math.SphericalDistance(partition, defenseCache.Key.DrawPos); if (distance < defenseCache.Value.MaxDistance) { yield return(defenseCache.Value); } } } start = destinationPos; } }
/// <summary> /// Calculate VehicleTurret draw offset given <paramref name="rot"/> /// </summary> /// <param name="rot"></param> /// <param name="xOffset"></param> /// <param name="yOffset"></param> /// <param name="rotationOffset"></param> /// <param name="turretRotation"></param> /// <param name="attachedTo"></param> /// <returns></returns> public static Pair <float, float> ShipDrawOffset(Rot8 rot, float xOffset, float yOffset, out Pair <float, float> rotationOffset, float turretRotation = 0, VehicleTurret attachedTo = null) { rotationOffset = new Pair <float, float>(0, 0); if (attachedTo != null) { return(Ext_Math.RotatePointClockwise(attachedTo.turretRenderLocation.x + xOffset, attachedTo.turretRenderLocation.y + yOffset, turretRotation)); } return(rot.AsInt switch { //North 0 => new Pair <float, float>(xOffset, yOffset), //East 1 => new Pair <float, float>(yOffset, -xOffset), //South 2 => new Pair <float, float>(-xOffset, -yOffset), //West 3 => new Pair <float, float>(-yOffset, xOffset), //NorthEast 4 => Ext_Math.RotatePointClockwise(yOffset, -xOffset, 45f), //SouthEast 5 => Ext_Math.RotatePointCounterClockwise(yOffset, -xOffset, 45f), //SouthWest 6 => Ext_Math.RotatePointClockwise(-yOffset, xOffset, 45f), //NorthWest 7 => Ext_Math.RotatePointCounterClockwise(-yOffset, xOffset, 45f), //Default _ => throw new ArgumentOutOfRangeException("VehicleRotation is not within bounds. RotationInt must be between 0 and 7 for each lateral, longitudinal, and diagonal direction.") });
public virtual bool TryExecuteEvent(AerialVehicleInFlight aerialVehicle, WorldObject shotDownBy, IntVec3?precalculatedCell = null) { try { Map crashSite; int ticksTillArrival = -1; if (Find.WorldObjects.MapParentAt(aerialVehicle.Tile) is MapParent mapParent) { crashSite = mapParent.Map; } else { int num = CaravanIncidentUtility.CalculateIncidentMapSize(aerialVehicle.vehicle.AllPawnsAboard, aerialVehicle.vehicle.AllPawnsAboard); crashSite = GetOrGenerateMapUtility.GetOrGenerateMap(aerialVehicle.Tile, new IntVec3(num, 1, num), WorldObjectDefOfVehicles.CrashedShipSite); if (shotDownBy is Settlement settlement) { ticksTillArrival = (crashSite.Parent as CrashSite).InitiateReinforcementsRequest(settlement); } } bool validator(IntVec3 c) { bool flag = aerialVehicle.vehicle.PawnOccupiedCells(c, Rot4.East).All(c2 => c2.Standable(crashSite) && !c.Roofed(crashSite) && !c.Fogged(crashSite) && c.InBounds(crashSite)); return(flag); } IntVec3 RandomCentercell() { RCellFinder.TryFindRandomCellNearTheCenterOfTheMapWith(validator, crashSite, out IntVec3 result); return(result); } IntVec3 cell = precalculatedCell ?? RandomCentercell(); if (cell == IntVec3.Invalid) { return(false); } AerialVehicleArrivalAction_CrashSpecificCell arrivalAction = new AerialVehicleArrivalAction_CrashSpecificCell(aerialVehicle.vehicle, crashSite.Parent, crashSite.Tile, aerialVehicle.vehicle.CompVehicleLauncher.launchProtocol, cell, Rot4.East); arrivalAction.Arrived(crashSite.Tile); aerialVehicle.Destroy(); string settlementLabel = shotDownBy?.Label ?? string.Empty; if (ticksTillArrival > 0) { string hoursTillArrival = Ext_Math.RoundTo(ticksTillArrival / 2500f, 1).ToString(); SendCrashSiteLetter(shotDownBy, crashSite.Parent, CrashSiteDef.letterLabel, CrashSiteDef.letterTexts[1], CrashSiteDef.letterDef, crashSite.Parent, new NamedArgument[] { aerialVehicle.Label, settlementLabel, hoursTillArrival }); } else { SendCrashSiteLetter(shotDownBy, crashSite.Parent, CrashSiteDef.letterLabel, CrashSiteDef.letterTexts[0], CrashSiteDef.letterDef, crashSite.Parent, new NamedArgument[] { aerialVehicle.Label, settlementLabel }); } return(true); } catch (Exception ex) { Log.Error($"Failed to execute incident {GetType()}. Exception=\"{ex.Message}\""); return(false); } }
/// <summary> /// Calculate VehicleTurret draw offset /// </summary> /// <param name="vehicle"></param> /// <param name="xOffset"></param> /// <param name="yOffset"></param> /// <param name="rotationOffset"></param> /// <param name="turretRotation"></param> /// <param name="attachedTo"></param> public static Pair <float, float> TurretDrawOffset(float angle, float xOffset, float yOffset, out Pair <float, float> rotationOffset, float turretRotation = 0, VehicleTurret attachedTo = null) { rotationOffset = new Pair <float, float>(0, 0); if (attachedTo != null) { return(Ext_Math.RotatePointClockwise(attachedTo.turretRenderLocation.x + xOffset, attachedTo.turretRenderLocation.y + yOffset, turretRotation)); } return(Ext_Math.RotatePointClockwise(xOffset, yOffset, angle)); }
public override void TargeterOnGUI() { if (IsTargeting) { if (!Mouse.IsInputBlockedNow) { GlobalTargetInfo mouseTarget = CurrentTargetUnderMouse(); Vector2 mousePosition = Event.current.mousePosition; Texture2D image = mouseAttachment ?? TexCommand.Attack; Rect position = new Rect(mousePosition.x + 8f, mousePosition.y + 8f, 32f, 32f); GUI.DrawTexture(position, image); CostAndDistanceCalculator(out float fuelOnPathCost, out float tileDistance); Vector3 flightPathPos = originOnMap; if (!FlightPath.NullOrEmpty()) { flightPathPos = Find.WorldGrid.GetTileCenter(FlightPath.LastOrDefault().tile); } float finalFuelCost = fuelOnPathCost; float finalTileDistance = tileDistance; if (mouseTarget.IsValid && Find.WorldGrid.GetTileCenter(mouseTarget.Tile) != flightPathPos) { finalFuelCost += vehicle.CompVehicleLauncher.FuelNeededToLaunchAtDist(flightPathPos, mouseTarget.Tile); finalTileDistance += Ext_Math.SphericalDistance(flightPathPos, Find.WorldGrid.GetTileCenter(mouseTarget.Tile)); } TotalFuelCost = (float)Math.Round(finalFuelCost, 0); TotalDistance = finalTileDistance; string fuelCostLabel = $"{"VehicleFuelCost".Translate()}: {TotalFuelCost}"; Vector2 textSize = Text.CalcSize(fuelCostLabel); Rect labelPosition = new Rect(mousePosition.x, mousePosition.y + textSize.y + 20f, textSize.x, textSize.y); float bgWidth = textSize.x * 1.2f; var color = GUI.color; if (extraLabelGetter != null) { string text = extraLabelGetter(mouseTarget, FlightPath, TotalFuelCost); Vector2 labelGetterText = Text.CalcSize(text); Rect rect = new Rect(position.xMax, position.y, 9999f, 100f); Rect bgRect = new Rect(rect.x - labelGetterText.x * 0.1f, rect.y, labelGetterText.x * 1.2f, labelGetterText.y); var textColor = GUI.color; GUI.color = Color.white; GUI.DrawTexture(bgRect, TexUI.GrayTextBG); GUI.color = textColor; GUI.Label(rect, text); } GUI.color = Color.white; GUI.DrawTexture(new Rect(labelPosition.x - textSize.x * 0.1f, labelPosition.y, bgWidth, textSize.y), TexUI.GrayTextBG); GUI.Label(labelPosition, fuelCostLabel); GUI.color = color; } } }
/// <summary> /// Get nearest tile id to <paramref name="worldCoord"/> /// </summary> /// <param name="worldCoord"></param> public static int GetNearestTile(Vector3 worldCoord) { for (int tile = 0; tile < Find.WorldGrid.TilesCount; tile++) { Vector3 pos = Find.WorldGrid.GetTileCenter(tile); if (Ext_Math.SphericalDistance(worldCoord, pos) <= 0.75f) //0.25 tile length margin of error for quicker calculation { return(tile); } } return(-1); }
public override void Initialize(WorldObject firedFrom, AerialVehicleInFlight target, Vector3 source) { this.target = target; Vector3 misfire = new Vector3(Rand.Range(-Spread, Spread), Rand.Range(-Spread, Spread), Rand.Range(-Spread, Spread)); destination = this.target.DrawPosAhead(50) - misfire; this.source = source; this.firedFrom = firedFrom; speedPctPerTick = Mathf.Max((AerialVehicleInFlight.PctPerTick / Ext_Math.SphericalDistance(this.source, destination)) * Rand.Range(40, 70), MinSpeed); InitializeFacing(); explosionFrame = -1; }
public override void DrawTurret() { Vector3 offset = new Vector3(parentTurret.def.building.turretTopOffset.x, 0f, parentTurret.def.building.turretTopOffset.y).RotatedBy(CurRotation); Vector3 vectorRecoiled = Ext_Math.PointFromAngle(offset, -curRecoil, CurRotation); float drawSize = parentTurret.def.building.turretTopDrawSize; Matrix4x4 matrix = default; matrix.SetTRS(parentTurret.DrawPos + altitudeDrawLayer + Altitudes.AltIncVect + vectorRecoiled, (CurRotation + ArtworkRotation).ToQuat(), new Vector3(drawSize, 1f, drawSize)); Graphics.DrawMesh(MeshPool.plane10, matrix, TurretGraphic?.MatAt(parentTurret.Rotation) ?? parentTurret.def.building.turretTopMat, 0); if (DrawLayer != null) { DrawLayer.DrawExtra(parentTurret.DrawPos + altitudeDrawLayer + Altitudes.AltIncVect + offset, CurRotation); } }
/// <summary> /// Last check when world target has been chosen /// </summary> /// <param name="target"></param> /// <param name="tile"></param> /// <param name="maxLaunchDistance"></param> /// <param name="launchAction"></param> public virtual bool ChoseWorldTarget(GlobalTargetInfo target, Vector3 pos, float fuelCost, Action <int, AerialVehicleArrivalAction, bool> launchAction) { currentMap = vehicle.Map; targetMap = Find.WorldObjects.MapParentAt(target.Tile)?.Map; if (!target.IsValid) { Messages.Message("MessageTransportPodsDestinationIsInvalid".Translate(), MessageTypeDefOf.RejectInput, false); return(false); } else if (Ext_Math.SphericalDistance(pos, Find.WorldGrid.GetTileCenter(target.Tile)) > vehicle.CompVehicleLauncher.MaxLaunchDistance || fuelCost > vehicle.CompFueledTravel.Fuel) { Messages.Message("TransportPodDestinationBeyondMaximumRange".Translate(), MessageTypeDefOf.RejectInput, false); return(false); } IEnumerable <FloatMenuOption> source = GetFloatMenuOptionsAt(target.Tile); if (!source.Any()) { if (!WorldVehiclePathGrid.Instance.Passable(target.Tile, vehicle.VehicleDef)) { Messages.Message("MessageTransportPodsDestinationIsInvalid".Translate(), MessageTypeDefOf.RejectInput, false); return(false); } launchAction(target.Tile, null, false); if (landingProperties.forcedRotation.HasValue && !landing) { vehicle.Rotation = landingProperties.forcedRotation.Value; } return(true); } else { if (source.Count() != 1) { Find.WindowStack.Add(new FloatMenuTargeter(source.ToList())); return(false); } if (!source.First().Disabled) { source.First().action(); if (landingProperties.forcedRotation.HasValue && !landing) { vehicle.Rotation = landingProperties.forcedRotation.Value; } return(true); } return(false); } }
public void CostAndDistanceCalculator(out float fuelCost, out float distance) { fuelCost = 0; distance = 0; Vector3 start = originOnMap; foreach (FlightNode node in FlightPath) { int tile = node.tile; float nodeDistance = Ext_Math.SphericalDistance(start, Find.WorldGrid.GetTileCenter(tile)); fuelCost += vehicle.CompVehicleLauncher.FuelNeededToLaunchAtDist(nodeDistance); distance += nodeDistance; start = Find.WorldGrid.GetTileCenter(tile); } }
public override void WorldComponentTick() { foreach (var defense in searchingDefenses) { AerialVehicleInFlight aerialVehicleSearchingFor = defense.Key; for (int j = defense.Value.Count - 1; j >= 0; j--) { AirDefense airDefense = defense.Value.ElementAt(j); float distance = Ext_Math.SphericalDistance(airDefense.parent.DrawPos, aerialVehicleSearchingFor.DrawPos); bool withinMaxDistance = distance <= airDefense.MaxDistance; if (airDefense.CurrentTarget != aerialVehicleSearchingFor) { airDefense.angle = (airDefense.angle + RotationRate * airDefense.searchDirection).ClampAndWrap(0, 360); float angleToTarget = airDefense.parent.DrawPos.AngleToPoint(aerialVehicleSearchingFor.DrawPos); if (withinMaxDistance && Mathf.Abs(angleToTarget - airDefense.angle) <= (airDefense.Arc / 2)) { airDefense.activeTargets.Add(aerialVehicleSearchingFor); } } else { float headingToTarget = WorldHelper.TryFindHeading(airDefense.parent.DrawPos, airDefense.CurrentTarget.DrawPos); int dirSignMultiplier = headingToTarget < airDefense.angle ? -2 : 2; if (Mathf.Abs(headingToTarget - airDefense.angle) < 1 || Mathf.Abs(headingToTarget - airDefense.angle) > 359) { airDefense.angle = headingToTarget; airDefense.Attack(); } else { airDefense.angle = (airDefense.angle + RotationRate * dirSignMultiplier).ClampAndWrap(0, 360); } if (!withinMaxDistance) { airDefense.activeTargets.Remove(aerialVehicleSearchingFor); } } } } }
public static void DrawTravelPoint(Vector3 start, Vector3 end, Material material = null) { if (material is null) { material = TexData.WorldLineMatWhite; } double distance = Ext_Math.SphericalDistance(start, end); int steps = Mathf.CeilToInt((float)(distance * 100) / 5); start += start.normalized * 0.05f; end += end.normalized * 0.05f; Vector3 previous = start; for (int i = 1; i <= steps; i++) { float t = (float)i / steps; Vector3 midPoint = Vector3.Slerp(start, end, t); GenDraw.DrawWorldLineBetween(previous, midPoint, material, 0.5f); previous = midPoint; } }
public float FuelNeededToLaunchAtDist(Vector3 origin, int destination) { float tileDistance = Ext_Math.SphericalDistance(origin, Find.WorldGrid.GetTileCenter(destination)); return(FuelNeededToLaunchAtDist(tileDistance)); }
private void SetSpeed() { float tileDistance = Ext_Math.SphericalDistance(position, Find.WorldGrid.GetTileCenter(flightPath.First.tile)); speedPctPerTick = (PctPerTick / tileDistance) * vehicle.CompVehicleLauncher.FlySpeed.Clamp(0, 5); }
public override IEnumerable <Gizmo> GetGizmos() { foreach (Gizmo gizmo in base.GetGizmos()) { yield return(gizmo); } if (IsPlayerControlled) { if (vehicle.CompFueledTravel != null) { yield return(vehicle.CompFueledTravel.FuelCountGizmo); foreach (Gizmo fuelGizmo in vehicle.CompFueledTravel.DevModeGizmos()) { yield return(fuelGizmo); } } if (!vehicle.CompVehicleLauncher.inFlight && Find.WorldObjects.SettlementAt(Tile) is Settlement settlement2) { yield return(GizmoHelper.AerialVehicleTradeCommand(this, settlement2.Faction, settlement2.TraderKind)); } if (vehicle.CompVehicleLauncher.ControlInFlight || !vehicle.CompVehicleLauncher.inFlight) { Command_Action launchCommand = new Command_Action() { defaultLabel = "CommandLaunchGroup".Translate(), defaultDesc = "CommandLaunchGroupDesc".Translate(), icon = VehicleTex.LaunchCommandTex, alsoClickIfOtherInGroupClicked = false, action = delegate() { LaunchTargeter.Instance.BeginTargeting(vehicle, new Func <GlobalTargetInfo, float, bool>(ChoseTargetOnMap), this, true, VehicleTex.TargeterMouseAttachment, false, null, (GlobalTargetInfo target, List <FlightNode> path, float fuelCost) => vehicle.CompVehicleLauncher.launchProtocol.TargetingLabelGetter(target, Tile, path, fuelCost)); } }; if (vehicle.CompFueledTravel.EmptyTank) { launchCommand.Disable("VehicleLaunchOutOfFuel".Translate()); } yield return(launchCommand); } if (!vehicle.CompVehicleLauncher.inFlight) { foreach (Settlement settlement in Find.WorldObjects.ObjectsAt(flightPath.First.tile).Where(o => o is Settlement).Cast <Settlement>()) { yield return(GizmoHelper.ShuttleTradeCommand(this, settlement)); if (WorldHelper.CanOfferGiftsTo(this, settlement)) { yield return(new Command_Action { defaultLabel = "CommandOfferGifts".Translate(), defaultDesc = "CommandOfferGiftsDesc".Translate(), icon = VehicleTex.OfferGiftsCommandTex, action = delegate() { Pawn playerNegotiator = WorldHelper.FindBestNegotiator(vehicle, null, null); Find.WindowStack.Add(new Dialog_Trade(playerNegotiator, settlement, true)); } }); } } Command_Settle commandSettle = new Command_Settle { defaultLabel = "CommandSettle".Translate(), defaultDesc = "CommandSettleDesc".Translate(), icon = SettleUtility.SettleCommandTex, action = delegate() { SoundDefOf.Tick_High.PlayOneShotOnCamera(null); void settleHere() { SettlementVehicleUtility.Settle(this); }; SettlementProximityGoodwillUtility.CheckConfirmSettle(Tile, settleHere); } }; if (!TileFinder.IsValidTileForNewSettlement(Tile, tmpSettleFailReason)) { commandSettle.Disable(tmpSettleFailReason.ToString()); } else if (SettleUtility.PlayerSettlementsCountLimitReached) { if (Prefs.MaxNumberOfPlayerSettlements > 1) { commandSettle.Disable("CommandSettleFailReachedMaximumNumberOfBases".Translate()); } else { commandSettle.Disable("CommandSettleFailAlreadyHaveBase".Translate()); } } yield return(commandSettle); } if (Prefs.DevMode) { yield return(new Command_Action { defaultLabel = "Debug: Land at Nearest Player Settlement", action = delegate() { List <Settlement> playerSettlements = Find.WorldObjects.Settlements.Where(s => s.Faction == Faction.OfPlayer).ToList(); Settlement nearestSettlement = playerSettlements.MinBy(s => Ext_Math.SphericalDistance(s.DrawPos, DrawPos)); LaunchProtocol launchProtocol = vehicle.CompVehicleLauncher.launchProtocol; Rot4 vehicleRotation = launchProtocol.landingProperties.forcedRotation ?? Rot4.Random; IntVec3 cell = CellFinderExtended.RandomCenterCell(nearestSettlement.Map, (IntVec3 cell) => !MapHelper.VehicleBlockedInPosition(vehicle, Current.Game.CurrentMap, cell, vehicleRotation)); VehicleSkyfaller_Arriving skyfaller = (VehicleSkyfaller_Arriving)ThingMaker.MakeThing(vehicle.CompVehicleLauncher.Props.skyfallerIncoming); skyfaller.vehicle = vehicle; GenSpawn.Spawn(skyfaller, cell, nearestSettlement.Map, vehicleRotation); Destroy(); } }); yield return(new Command_Action { defaultLabel = "Debug: Initiate Crash Event", action = delegate() { InitiateCrashEvent(null); } }); } } }