// Copy-constructor public ShiftVecReport(ShiftVecReport report) { this.target = report.target; this.aimEfficiency = report.aimEfficiency; this.aimingAccuracy = report.aimingAccuracy; this.circularMissRadius = report.circularMissRadius; this.indirectFireShift = report.indirectFireShift; this.lightingShift = report.lightingShift; this.shotSpeed = report.shotSpeed; this.shotDist = report.shotDist; this.isAiming = report.isAiming; this.swayDegrees = report.swayDegrees; this.spreadDegrees = report.spreadDegrees; this.cover = report.cover; }
/// <summary> /// Fires a projectile using the new aiming system /// </summary> /// <returns>True for successful shot, false otherwise</returns> protected override bool TryCastShot() { ShootLine shootLine; if (!base.TryFindShootLineFromTo(this.caster.Position, this.currentTarget, out shootLine)) { return(false); } if (this.projectilePropsCR.pelletCount < 1) { Log.Error(this.ownerEquipment.LabelBaseCap + " tried firing with pelletCount less than 1."); return(false); } for (int i = 0; i < this.projectilePropsCR.pelletCount; i++) { Vector3 casterExactPosition = this.caster.DrawPos; ProjectileCR projectile = (ProjectileCR)ThingMaker.MakeThing(projectileDef, null); GenSpawn.Spawn(projectile, shootLine.Source); float lengthHorizontalSquared = (this.currentTarget.Cell - this.caster.Position).LengthHorizontalSquared; //New aiming algorithm projectile.canFreeIntercept = true; ShiftVecReport report = this.ShiftVecReportFor(this.currentTarget); Vector3 targetVec3 = this.ShiftTarget(report); projectile.shotAngle = this.shotAngle; projectile.shotHeight = this.shotHeight; projectile.shotSpeed = this.shotSpeed; if (this.currentTarget.Thing != null) { projectile.Launch(this.caster, casterExactPosition, new TargetInfo(this.currentTarget.Thing), targetVec3, this.ownerEquipment); } else { projectile.Launch(this.caster, casterExactPosition, new TargetInfo(shootLine.Dest), targetVec3, this.ownerEquipment); } } this.numShotsFired++; return(true); }
protected override bool TryCastShot() { ArtilleryMarker marker = ThingMaker.MakeThing(ThingDef.Named(ArtilleryMarker.MarkerDef)) as ArtilleryMarker; ShiftVecReport report = ShiftVecReportFor(currentTarget); marker.aimEfficiency = report.aimEfficiency; marker.aimingAccuracy = report.aimingAccuracy; marker.lightingShift = report.lightingShift; marker.weatherShift = report.weatherShift; GenSpawn.Spawn(marker, this.currentTarget.Cell, caster.Map); // Check for something to attach marker to if (this.currentTarget.HasThing) { CompAttachBase comp = this.currentTarget.Thing.TryGetComp <CompAttachBase>(); if (comp != null) { marker.AttachTo(this.currentTarget.Thing); } } return(true); }
/// <summary> /// Shifts the original target position in accordance with target leading, range estimation and weather/lighting effects /// </summary> protected virtual Vector3 ShiftTarget(ShiftVecReport report) { // ----------------------------------- STEP 0: Actual location Vector3 targetLoc = report.targetPawn != null?Vector3.Scale(report.targetPawn.DrawPos, new Vector3(1, 0, 1)) : report.target.Cell.ToVector3Shifted(); Vector3 sourceLoc = this.CasterPawn != null?Vector3.Scale(this.CasterPawn.DrawPos, new Vector3(1, 0, 1)) : this.caster.Position.ToVector3Shifted(); // ----------------------------------- STEP 1: Shift for visibility Vector2 circularShiftVec = report.GetRandCircularVec(); Vector3 newTargetLoc = targetLoc; newTargetLoc.x += circularShiftVec.x; newTargetLoc.z += circularShiftVec.y; // ----------------------------------- STEP 2: Estimated shot to hit location // On first shot of burst do a range estimate if (this.estimatedTargDist < 0) { this.estimatedTargDist = report.GetRandDist(); } newTargetLoc = sourceLoc + (newTargetLoc - sourceLoc).normalized * this.estimatedTargDist; // Lead a moving target newTargetLoc += report.GetRandLeadVec(); // ----------------------------------- STEP 3: Recoil, Skewing, Skill checks, Cover calculations Vector2 skewVec = new Vector2(0, 0); skewVec += this.GetSwayVec(); skewVec += this.GetRecoilVec(); // Height difference calculations for ShotAngle float heightDifference = 0; float targetableHeight = 0; // Projectiles with flyOverhead target the ground below the target and ignore cover if (!projectileDef.projectile.flyOverhead) { targetableHeight = Utility.GetCollisionHeight(this.currentTarget.Thing); if (report.cover != null) { targetableHeight += Utility.GetCollisionHeight(report.cover); } heightDifference += targetableHeight * 0.5f; //Optimal hit level is halfway } this.shotHeight = Utility.GetCollisionHeight(this.caster); if (this.CasterPawn != null) { this.shotHeight *= shotHeightFactor; } heightDifference -= this.shotHeight; skewVec += new Vector2(0, GetShotAngle(this.shotSpeed, (newTargetLoc - sourceLoc).magnitude, heightDifference) * (180 / (float)Math.PI)); // ----------------------------------- STEP 4: Mechanical variation // Get shotvariation Vector2 spreadVec = report.GetRandSpreadVec(); skewVec += spreadVec; // Skewing - Applied after the leading calculations to not screw them up float distanceTraveled = GetDistanceTraveled(this.shotSpeed, (float)(skewVec.y * (Math.PI / 180)), this.shotHeight); newTargetLoc = sourceLoc + ((newTargetLoc - sourceLoc).normalized * distanceTraveled); newTargetLoc = sourceLoc + (Quaternion.AngleAxis(skewVec.x, Vector3.up) * (newTargetLoc - sourceLoc)); this.shotAngle = (float)(skewVec.y * (Math.PI / 180)); return(newTargetLoc); }