示例#1
0
 protected override bool TryCastShot()
 {
     //Reduce ammunition
     if (compAmmo != null)
     {
         if (!compAmmo.TryReduceAmmoCount())
         {
             if (compAmmo.hasMagazine)
             {
                 compAmmo.TryStartReload();
             }
             return(false);
         }
     }
     if (base.TryCastShot())
     {
         //Drop casings
         if (verbPropsCR.ejectsCasings && projectilePropsCR.dropsCasings)
         {
             CR_Utility.ThrowEmptyCasing(this.caster.DrawPos, caster.Map, ThingDef.Named(this.projectilePropsCR.casingMoteDefname));
         }
         return(true);
     }
     return(false);
 }
示例#2
0
        /// <summary>
        /// Checks if the shooter can hit the target from a certain position with regards to cover height
        /// </summary>
        /// <param name="root">The position from which to check</param>
        /// <param name="targ">The target to check for line of sight</param>
        /// <returns>True if shooter can hit target from root position, false otherwise</returns>
        public override bool CanHitTargetFrom(IntVec3 root, LocalTargetInfo targ)
        {
            //Sanity check for flyOverhead projectiles, they should not attack things under thick roofs
            if (projectileDef.projectile.flyOverhead)
            {
                RoofDef roofDef = caster.Map.roofGrid.RoofAt(targ.Cell);
                if (roofDef != null && roofDef.isThickRoof)
                {
                    return(false);
                }
                return(base.CanHitTargetFrom(root, targ));
            }

            if (base.CanHitTargetFrom(root, targ))
            {
                //Check if target is obstructed behind cover
                Thing coverTarg;
                if (this.GetPartialCoverBetween(root.ToVector3Shifted(), targ.Cell.ToVector3Shifted(), out coverTarg))
                {
                    float targetHeight = CR_Utility.GetCollisionHeight(targ.Thing);
                    if (targetHeight <= CR_Utility.GetCollisionHeight(coverTarg))
                    {
                        return(false);
                    }
                }
                //Check if shooter is obstructed by cover
                Thing coverShoot;
                if (this.GetPartialCoverBetween(targ.Cell.ToVector3Shifted(), root.ToVector3Shifted(), out coverShoot))
                {
                    float shotHeight = CR_Utility.GetCollisionHeight(this.caster);
                    if (this.CasterPawn != null)
                    {
                        shotHeight *= shotHeightFactor;
                    }
                    if (shotHeight <= CR_Utility.GetCollisionHeight(coverShoot))
                    {
                        return(false);
                    }
                }
                return(true);
            }
            return(false);
        }
示例#3
0
        /// <summary>
        ///     Takes into account the target being downed and the projectile having been fired while the target was downed, and
        ///     the target's bodySize
        /// </summary>
        private bool ImpactThroughBodySize(Thing thing, float height)
        {
            Pawn pawn = thing as Pawn;

            if (pawn != null)
            {
                PersonalShield shield = null;
                if (pawn.RaceProps.Humanlike)
                {
                    // check for shield user

                    List <Apparel> wornApparel = pawn.apparel.WornApparel;
                    for (int i = 0; i < wornApparel.Count; i++)
                    {
                        if (wornApparel[i] is PersonalShield)
                        {
                            shield = (PersonalShield)wornApparel[i];
                            break;
                        }
                    }
                }
                //Add suppression
                CompSuppressable compSuppressable = pawn.TryGetComp <CompSuppressable>();
                if (compSuppressable != null)
                {
                    if (shield == null || (shield != null && shield?.ShieldState == ShieldState.Resetting))
                    {
                        /*
                         * if (pawn.skills.GetSkill(SkillDefOf.Shooting).level >= 1)
                         * {
                         *  suppressionAmount = (def.projectile.damageAmountBase * (1f - ((pawn.skills.GetSkill(SkillDefOf.Shooting).level) / 100) * 3));
                         * }
                         * else suppressionAmount = def.projectile.damageAmountBase;
                         */
                        suppressionAmount = def.projectile.damageAmountBase;
                        ProjectilePropertiesCR propsCR = def.projectile as ProjectilePropertiesCR;
                        float penetrationAmount        = propsCR == null ? 0f : propsCR.armorPenetration;
                        suppressionAmount *= 1 - Mathf.Clamp(compSuppressable.parentArmor - penetrationAmount, 0, 1);
                        compSuppressable.AddSuppression(suppressionAmount, origin.ToIntVec3());
                    }
                }

                //Check horizontal distance
                Vector3 dest              = destination;
                Vector3 orig              = origin;
                Vector3 pawnPos           = pawn.DrawPos;
                float   closestDistToPawn = Math.Abs((dest.z - orig.z) * pawnPos.x - (dest.x - orig.x) * pawnPos.z +
                                                     dest.x * orig.z - dest.z * orig.x)
                                            /
                                            (float)
                                            Math.Sqrt((dest.z - orig.z) * (dest.z - orig.z) +
                                                      (dest.x - orig.x) * (dest.x - orig.x));
                if (closestDistToPawn <= CR_Utility.GetCollisionWidth(pawn))
                {
                    //Check vertical distance
                    float pawnHeight = CR_Utility.GetCollisionHeight(pawn);
                    if (height < pawnHeight)
                    {
                        Impact(thing);
                        return(true);
                    }
                }
            }
            if (thing.def.fillPercent > 0 || thing.def.Fillage == FillCategory.Full)
            {
                if (height < CR_Utility.GetCollisionHeight(thing) || thing.def.Fillage == FillCategory.Full)
                {
                    Impact(thing);
                    return(true);
                }
            }
            return(false);
        }
示例#4
0
        /// <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 = CR_Utility.GetCollisionHeight(this.currentTarget.Thing);
                if (report.cover != null)
                {
                    targetableHeight += CR_Utility.GetCollisionHeight(report.cover);
                }
                heightDifference += targetableHeight * 0.5f;    //Optimal hit level is halfway
            }

            this.shotHeight = CR_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);
        }
示例#5
0
        private void ApplyDamagePartial(DamageInfo dinfo, Pawn pawn, ref LocalInjuryResult result)
        {
            BodyPartRecord exactPartFromDamageInfo = GetExactPartFromDamageInfo(dinfo, pawn);

            if (exactPartFromDamageInfo == null)
            {
                return;
            }

            // Only apply armor if we propagate damage to the outside or the body part itself is outside, secondary damage types should directly damage organs, bypassing armor
            bool involveArmor = !dinfo.InstantOldInjury &&
                                !result.deflected &&
                                (dinfo.Def.harmAllLayersUntilOutside || exactPartFromDamageInfo.depth == BodyPartDepth.Outside);
            int damageAmount = dinfo.Amount;

            if (involveArmor)
            {
                damageAmount = CR_Utility.GetAfterArmorDamage(pawn, dinfo.Amount, exactPartFromDamageInfo, dinfo, true, ref result.deflected);
            }
            if ((double)damageAmount < 0.001)
            {
                result.absorbed = true;
                return;
            }

            // Shot absorbed and converted into blunt
            DamageDef_CR damageDefCR = dinfo.Def as DamageDef_CR;

            if (damageDefCR != null &&
                damageDefCR.deflectable &&
                result.deflected &&
                dinfo.Def != CR_Utility.absorbDamageDef)
            {
                // Get outer parent of struck part
                BodyPartRecord currentPart = exactPartFromDamageInfo;
                while (currentPart != null && currentPart.parent != null && currentPart.depth != BodyPartDepth.Outside)
                {
                    currentPart = currentPart.parent;
                }
                DamageInfo dinfo2 = new DamageInfo(CR_Utility.absorbDamageDef, damageAmount, dinfo.Angle, dinfo.Instigator, currentPart, dinfo.WeaponGear);
                ApplyDamagePartial(dinfo2, pawn, ref result);
                return;
            }

            //Creating the Hediff
            HediffDef     hediffDefFromDamage = HealthUtility.GetHediffDefFromDamage(dinfo.Def, pawn, exactPartFromDamageInfo);
            Hediff_Injury hediff_Injury       = (Hediff_Injury)HediffMaker.MakeHediff(hediffDefFromDamage, pawn, null);

            hediff_Injury.Part   = exactPartFromDamageInfo;
            hediff_Injury.source = dinfo.WeaponGear;
            hediff_Injury.sourceBodyPartGroup = dinfo.WeaponBodyPartGroup;
            hediff_Injury.sourceHediffDef     = dinfo.WeaponLinkedHediff;
            hediff_Injury.Severity            = (float)damageAmount;
            if (dinfo.InstantOldInjury)
            {
                HediffComp_GetsOld hediffComp_GetsOld = hediff_Injury.TryGetComp <HediffComp_GetsOld>();
                if (hediffComp_GetsOld != null)
                {
                    hediffComp_GetsOld.IsOld = true;
                }
                else
                {
                    Log.Error(string.Concat(new object[]
                    {
                        "Tried to create instant old injury on Hediff without a GetsOld comp: ",
                        hediffDefFromDamage,
                        " on ",
                        pawn
                    }));
                }
            }
            result.wounded     = true;
            result.lastHitPart = hediff_Injury.Part;
            if (IsHeadshot(dinfo, hediff_Injury, pawn))
            {
                result.headshot = true;
            }
            if (dinfo.InstantOldInjury && (hediff_Injury.def.CompPropsFor(typeof(HediffComp_GetsOld)) == null || hediff_Injury.Part.def.oldInjuryBaseChance == 0f || hediff_Injury.Part.def.IsSolid(hediff_Injury.Part, pawn.health.hediffSet.hediffs) || pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(hediff_Injury.Part)))
            {
                return;
            }
            FinalizeAndAddInjury(pawn, hediff_Injury, dinfo, ref result);
            CheckPropagateDamageToInnerSolidParts(dinfo, pawn, hediff_Injury, !dinfo.InstantOldInjury, damageAmount, ref result);
            CheckDuplicateDamageToOuterParts(dinfo, pawn, hediff_Injury, !dinfo.InstantOldInjury, damageAmount, ref result);
        }
示例#6
0
        public string GetTextReadout()
        {
            StringBuilder stringBuilder = new StringBuilder();

            if (visibilityShift > 0)
            {
                stringBuilder.AppendLine("   " + "CR_VisibilityError".Translate() + "\t" + GenText.ToStringByStyle(visibilityShift, ToStringStyle.FloatTwo) + " c");

                if (lightingShift > 0)
                {
                    stringBuilder.AppendLine("      " + "Darkness".Translate() + "\t" + AsPercent(lightingShift));
                }
                if (weatherShift > 0)
                {
                    stringBuilder.AppendLine("      " + "Weather".Translate() + "\t" + AsPercent(weatherShift));
                }
            }
            if (leadShift > 0)
            {
                stringBuilder.AppendLine("   " + "CR_LeadError".Translate() + "\t" + GenText.ToStringByStyle(leadShift, ToStringStyle.FloatTwo) + " c");
            }
            if (distShift > 0)
            {
                stringBuilder.AppendLine("   " + "CR_RangeError".Translate() + "\t" + GenText.ToStringByStyle(distShift, ToStringStyle.FloatTwo) + " c");
            }
            if (swayDegrees > 0)
            {
                stringBuilder.AppendLine("   " + "CR_Sway".Translate() + "\t\t" + GenText.ToStringByStyle(swayDegrees, ToStringStyle.FloatTwo) + "°");
            }
            if (spreadDegrees > 0)
            {
                stringBuilder.AppendLine("   " + "CR_Spread".Translate() + "\t\t" + GenText.ToStringByStyle(spreadDegrees, ToStringStyle.FloatTwo) + "°");
            }
            // Don't display cover and target size if our weapon has a CEP
            if (circularMissRadius > 0)
            {
                stringBuilder.AppendLine("   " + "CR_MissRadius".Translate() + "\t" + GenText.ToStringByStyle(circularMissRadius, ToStringStyle.FloatTwo) + " c");
                if (indirectFireShift > 0)
                {
                    stringBuilder.AppendLine("   " + "CR_IndirectFire".Translate() + "\t" + GenText.ToStringByStyle(indirectFireShift, ToStringStyle.FloatTwo) + " c");
                }
            }
            else
            {
                if (cover != null)
                {
                    stringBuilder.AppendLine("   " + "CR_CoverHeight".Translate() + "\t" + GenText.ToStringByStyle(CR_Utility.GetCollisionHeight(cover), ToStringStyle.FloatTwo) + " c");
                }
                if (target.Thing != null)
                {
                    stringBuilder.AppendLine("   " + "CR_TargetHeight".Translate() + "\t" + GenText.ToStringByStyle(CR_Utility.GetCollisionHeight(target.Thing), ToStringStyle.FloatTwo) + " c");
                    stringBuilder.AppendLine("   " + "CR_TargetWidth".Translate() + "\t" + GenText.ToStringByStyle(CR_Utility.GetCollisionWidth(target.Thing) * 2, ToStringStyle.FloatTwo) + " c");
                }
            }
            return(stringBuilder.ToString());
        }
示例#7
0
        public Vector2 GetRandCircularVec()
        {
            Vector2 vec = CR_Utility.GenRandInCircle(visibilityShift + circularMissRadius + indirectFireShift);

            return(vec);
        }