Пример #1
0
 protected override bool TryCastShot()
 {
     if (caster.def.category == ThingCategory.Pawn)
     {
         Pawn launcherPawn = caster as Pawn;
         AddHediffChance = AddHediffChance * CasterPawn.GetStatValue(StatDefOf.ToxicSensitivity, true);
         var rand = Rand.Value;       // This is a random percentage between 0% and 100%
         if (rand <= AddHediffChance) // If the percentage falls under the chance, success!
         {
             var randomSeverity = Rand.Range(0.05f, 0.15f);
             var effectOnPawn   = launcherPawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffToAdd);
             if (effectOnPawn != null)
             {
                 effectOnPawn.Severity += randomSeverity;
             }
             else
             {
                 Hediff hediff = HediffMaker.MakeHediff(HediffToAdd, launcherPawn, null);
                 hediff.Severity = randomSeverity;
                 launcherPawn.health.AddHediff(hediff, null, null);
             }
         }
     }
     return(base.TryCastShot());
 }
Пример #2
0
 private float GetNonMissChance(LocalTargetInfo target)
 {
     if (surpriseAttack)
     {
         return(1f);
     }
     if (IsTargetImmobile(target))
     {
         return(1f);
     }
     return(CasterPawn.GetStatValue(StatDefOf.MeleeHitChance));
 }
Пример #3
0
        public bool MesaTryStartCastOn(LocalTargetInfo castTarg, bool attack = false,
                                       bool canHitNonTargetPawns             = true)
        {
            if (newWarmupTime > verbProps.warmupTime)
            {
                newWarmupTime = verbProps.warmupTime;
            }

            if (caster == null)
            {
                Log.Error("Verb " + GetUniqueLoadID() + " needs caster to work (possibly lost during saving/loading).");
                return(false);
            }

            if (!caster.Spawned)
            {
                return(false);
            }

            if (state == VerbState.Bursting || !CanHitTarget(castTarg))
            {
                return(false);
            }

            if (CausesTimeSlowdown(castTarg))
            {
                Find.TickManager.slower.SignalForceNormalSpeed();
            }

            surpriseAttack          = attack;
            canHitNonTargetPawnsNow = canHitNonTargetPawns;
            currentTarget           = castTarg;
            if (CasterIsPawn && verbProps.warmupTime > 0f)
            {
                if (!TryFindShootLineFromTo(caster.Position, castTarg, out var newShootLine))
                {
                    return(false);
                }

                CasterPawn.Drawer.Notify_WarmingCastAlongLine(newShootLine, caster.Position);
                var statValue = CasterPawn.GetStatValue(StatDefOf.AimingDelayFactor);
                var ticks     = (newWarmupTime * statValue).SecondsToTicks();
                CasterPawn.stances.SetStance(new Stance_Warmup(ticks, castTarg, this));
            }
            else
            {
                WarmupComplete();
            }

            return(true);
        }
Пример #4
0
 // unmodified
 private float GetHitChance(LocalTargetInfo target)
 {
     if (surpriseAttack)
     {
         return(1f);
     }
     if (IsTargetImmobile(target))
     {
         return(1f);
     }
     if (CasterPawn.skills != null)
     {
         return(CasterPawn.GetStatValue(StatDefOf.MeleeHitChance, true));
     }
     return(DefaultHitChance);
 }
        public bool PreCastShotCheck(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack, bool canHitNonTargetPawns)
        {
            if (caster == null)
            {
                Log.Error("Verb " + GetUniqueLoadID() + " needs caster to work (possibly lost during saving/loading).");
                return(false);
            }
            if (!caster.Spawned)
            {
                return(false);
            }
            if (state == VerbState.Bursting || (!CanHitTarget(castTarg) && verbProps.requireLineOfSight))
            {
                return(false);
            }
            if (CausesTimeSlowdown(castTarg))
            {
                Find.TickManager.slower.SignalForceNormalSpeed();
            }

            this.surpriseAttack          = surpriseAttack;
            this.canHitNonTargetPawnsNow = canHitNonTargetPawns;
            this.currentTarget           = castTarg;
            this.currentDestination      = destTarg;
            if (CasterIsPawn && verbProps.warmupTime > 0f)
            {
                if (verbProps.requireLineOfSight)
                {
                    ShootLine resultingLine;
                    if (!TryFindShootLineFromTo(caster.Position, castTarg, out resultingLine))
                    {
                        Messages.Message("AU_NoLineOfSight".Translate(), MessageTypeDefOf.RejectInput);
                        return(false);
                    }
                    CasterPawn.Drawer.Notify_WarmingCastAlongLine(resultingLine, caster.Position);
                }
                float statValue = CasterPawn.GetStatValue(StatDefOf.AimingDelayFactor);
                int   ticks     = (verbProps.warmupTime * statValue).SecondsToTicks();
                CasterPawn.stances.SetStance(new Stance_Warmup(ticks, castTarg, this));
            }
            else
            {
                WarmupComplete();
            }
            return(true);
        }
Пример #6
0
 public override bool ValidateTarget(LocalTargetInfo target)
 {
     if (!base.ValidateTarget(target))
     {
         return(false);
     }
     if (CasterPawn.GetStatValue(StatDefOf.PsychicSensitivity) < float.Epsilon)
     {
         Messages.Message("CommandPsycastZeroPsychicSensitivity".Translate(), caster, MessageTypeDefOf.RejectInput);
         return(false);
     }
     if (Psycast.def.EntropyGain > float.Epsilon && CasterPawn.psychicEntropy.WouldOverflowEntropy(Psycast.def.EntropyGain + PsycastUtility.TotalEntropyFromQueuedPsycasts(CasterPawn)))
     {
         Messages.Message("CommandPsycastWouldExceedEntropy".Translate(), caster, MessageTypeDefOf.RejectInput);
         return(false);
     }
     return(true);
 }
Пример #7
0
        public virtual bool TryStartCastOn(GlobalTargetInfo castTarg, float heading, bool surpriseAttack = false, bool canHitNonTargetPawns = true)
        {
            if (caster is null)
            {
                Log.Error("Verb " + GetUniqueLoadID() + " needs caster to work (possibly lost during saving/loading).", false);
                return(false);
            }
            if (!caster.Spawned)
            {
                return(false);
            }
            if (state == VerbState.Bursting || !CanHitTarget(castTarg))
            {
                return(false);
            }
            this.heading = heading;
            IntVec3 exitTarget = caster.Position.CellFromDistAngle(Building_Artillery.MaxMapDistance, this.heading);

            if (CausesTimeSlowdown(castTarg))
            {
                Find.TickManager.slower.SignalForceNormalSpeed();
            }
            this.surpriseAttack     = surpriseAttack;
            canHitNonTargetPawnsNow = canHitNonTargetPawns;
            target = castTarg;
            if (CasterIsPawn && verbProps.warmupTime > 0f)
            {
                CasterPawn.Drawer.Notify_WarmingCastAlongLine(new ShootLine(caster.Position, exitTarget), caster.Position);
                float statValue = CasterPawn.GetStatValue(StatDefOf.AimingDelayFactor, true);
                int   ticks     = (verbProps.warmupTime * statValue).SecondsToTicks();
                CasterPawn.stances.SetStance(new Stance_Warmup(ticks, exitTarget, this));
            }
            else
            {
                WarmupComplete();
            }
            return(true);
        }
Пример #8
0
        /// <summary>
        /// Calculates primary DamageInfo from verb, as well as secondary DamageInfos to apply (i.e. surprise attack stun damage).
        /// Also calculates the maximum body height an attack can target, so we don't get rabbits biting out a colonist's eye or something.
        /// </summary>
        /// <param name="target">The target damage is to be applied to</param>
        /// <returns>Collection with primary DamageInfo, followed by secondary types</returns>
        private IEnumerable <DamageInfo> DamageInfosToApply(LocalTargetInfo target, bool isCrit = false)
        {
            //START 1:1 COPY Verb_MeleeAttack.DamageInfosToApply
            float damAmount    = verbProps.AdjustedMeleeDamageAmount(this, CasterPawn);
            var   critModifier = isCrit && verbProps.meleeDamageDef.armorCategory == DamageArmorCategoryDefOf.Sharp &&
                                 !CasterPawn.def.race.Animal
                ? 2
                : 1;
            var              armorPenetration = (verbProps.meleeDamageDef.armorCategory == DamageArmorCategoryDefOf.Sharp ? ArmorPenetrationSharp : ArmorPenetrationBlunt) * critModifier;
            DamageDef        damDef           = verbProps.meleeDamageDef;
            BodyPartGroupDef bodyPartGroupDef = null;
            HediffDef        hediffDef        = null;

            if (EquipmentSource != null)
            {
                //melee weapon damage variation
                damAmount *= Rand.Range(StatWorker_MeleeDamage.GetDamageVariationMin(CasterPawn), StatWorker_MeleeDamage.GetDamageVariationMax(CasterPawn));
            }
            else if (!CE_StatDefOf.UnarmedDamage.Worker.IsDisabledFor(CasterPawn))  //ancient soldiers can punch even if non-violent, this prevents the disabled stat from being used
            {
                //unarmed damage bonus offset
                damAmount += CasterPawn.GetStatValue(CE_StatDefOf.UnarmedDamage);
            }

            if (CasterIsPawn)
            {
                bodyPartGroupDef = verbProps.AdjustedLinkedBodyPartsGroup(tool);
                if (damAmount >= 1f)
                {
                    if (HediffCompSource != null)
                    {
                        hediffDef = HediffCompSource.Def;
                    }
                }
                else
                {
                    damAmount = 1f;
                    damDef    = DamageDefOf.Blunt;
                }
            }

            var       source    = EquipmentSource != null ? EquipmentSource.def : CasterPawn.def;
            Vector3   direction = (target.Thing.Position - CasterPawn.Position).ToVector3();
            DamageDef def       = damDef;
            //END 1:1 COPY
            BodyPartHeight bodyRegion = GetBodyPartHeightFor(target);                                                                                           //Custom // Add check for body height
            //START 1:1 COPY
            DamageInfo mainDinfo = new DamageInfo(def, damAmount, armorPenetration, -1f, caster, null, source, DamageInfo.SourceCategory.ThingOrUnknown, null); //Alteration

            // Predators get a neck bite on immobile targets
            if (caster.def.race.predator && IsTargetImmobile(target) && target.Thing is Pawn pawn)
            {
                var neck = pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Top, BodyPartDepth.Outside)
                           .FirstOrDefault(r => r.def == BodyPartDefOf.Neck);
                mainDinfo.SetHitPart(neck);
            }

            mainDinfo.SetBodyRegion(bodyRegion); //Alteration
            mainDinfo.SetWeaponBodyPartGroup(bodyPartGroupDef);
            mainDinfo.SetWeaponHediff(hediffDef);
            mainDinfo.SetAngle(direction);
            yield return(mainDinfo);

            DamageInfo damageInfo = new DamageInfo(def, damAmount, armorPenetration, -1f, this.caster, null, source, DamageInfo.SourceCategory.ThingOrUnknown, null);

            damageInfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside);
            damageInfo.SetWeaponBodyPartGroup(bodyPartGroupDef);
            damageInfo.SetWeaponHediff(hediffDef);
            damageInfo.SetAngle(direction);
            yield return(damageInfo);

            if (this.tool != null && this.tool.extraMeleeDamages != null)
            {
                foreach (ExtraDamage extraDamage in this.tool.extraMeleeDamages)
                {
                    if (Rand.Chance(extraDamage.chance))
                    {
                        damAmount  = extraDamage.amount;
                        damAmount  = Rand.Range(damAmount * 0.8f, damAmount * 1.2f);
                        damageInfo = new DamageInfo(extraDamage.def, damAmount, extraDamage.AdjustedArmorPenetration(this, this.CasterPawn), -1f, this.caster, null, source, DamageInfo.SourceCategory.ThingOrUnknown, null);
                        damageInfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside);
                        damageInfo.SetWeaponBodyPartGroup(bodyPartGroupDef);
                        damageInfo.SetWeaponHediff(hediffDef);
                        damageInfo.SetAngle(direction);
                        yield return(damageInfo);
                    }
                }
                List <ExtraDamage> .Enumerator enumerator = default(List <ExtraDamage> .Enumerator);
            }

            // Apply critical damage
            if (isCrit && !CasterPawn.def.race.Animal && verbProps.meleeDamageDef.armorCategory != DamageArmorCategoryDefOf.Sharp && target.Thing.def.race.IsFlesh)
            {
                var critAmount = GenMath.RoundRandom(mainDinfo.Amount * 0.25f);
                var critDinfo  = new DamageInfo(DamageDefOf.Stun, critAmount, armorPenetration,
                                                -1, caster, null, source);
                critDinfo.SetBodyRegion(bodyRegion, BodyPartDepth.Outside);
                critDinfo.SetWeaponBodyPartGroup(bodyPartGroupDef);
                critDinfo.SetWeaponHediff(hediffDef);
                critDinfo.SetAngle(direction);
                yield return(critDinfo);
            }
        }
Пример #9
0
 protected override int TicksToNextHit()
 {
     return((int)Math.Round(BaseTicksBetweenPickHits / (double)CasterPawn.GetStatValue(StatDefOf.MiningSpeed)));
 }