protected override bool TryCastShot() { // Log.Message("Try Cast Shot Called"); //Log.Message("Cast"); bool GetsHot = this.UseAbilityProps.GetsHot; bool Jams = this.UseAbilityProps.Jams; bool GetsHotCrit = this.UseAbilityProps.GetsHotCrit; float GetsHotCritChance = this.UseAbilityProps.GetsHotCritChance; bool GetsHotCritExplosion = this.UseAbilityProps.GetsHotCritExplosion; float GetsHotCritExplosionChance = this.UseAbilityProps.GetsHotCritExplosionChance; bool canDamageWeapon = this.UseAbilityProps.HotDamageWeapon || this.UseAbilityProps.JamsDamageWeapon; float extraWeaponDamage = (Jams && this.UseAbilityProps.JamsDamageWeapon) ? this.UseAbilityProps.JamDamage : (GetsHot && this.UseAbilityProps.HotDamageWeapon) ? this.UseAbilityProps.HotDamage : 0f; bool TwinLinked = this.UseAbilityProps.TwinLinked; bool Multishot = this.UseAbilityProps.Multishot; int ScattershotCount = this.UseAbilityProps.ScattershotCount; bool UserEffect = this.UseAbilityProps.EffectsUser; HediffDef UserHediff = this.UseAbilityProps.UserEffect; float AddHediffChance = this.UseAbilityProps.EffectsUserChance; List <string> Immunitylist = this.UseAbilityProps.UserEffectImmuneList; var result = false; TargetsAoE.Clear(); UpdateTargets(); var burstShots = ShotsPerBurst; if (UseAbilityProps.AbilityTargetCategory != AbilityTargetCategory.TargetAoE && TargetsAoE.Count > 1) { TargetsAoE.RemoveRange(0, TargetsAoE.Count - 1); } if (UseAbilityProps.mustHaveTarget && TargetsAoE.Count == 0) { Messages.Message("AU_NoTargets".Translate(), MessageTypeDefOf.RejectInput); Ability.Notify_AbilityFailed(true); return(false); } for (var i = 0; i < TargetsAoE.Count; i++) { // for (int j = 0; j < burstshots; j++) // { if (verbProps.defaultProjectile != null) //ranged attacks WILL have projectiles { if ((GetsHot && AMASettings.Instance.AllowGetsHot) || (Jams && AMASettings.Instance.AllowJams)) { string msg = string.Format(""); string reliabilityString; float failChance; StatPart_Reliability.GetReliability(this.UseAbilityProps, out reliabilityString, out failChance); failChance = GetsHot ? (failChance / 10) : (failChance / 100); if (Rand.Chance(failChance)) { if (GetsHot) { DamageDef damageDef = this.Projectile.projectile.damageDef; HediffDef HediffToAdd = damageDef.hediff; float ArmorPenetration = this.Projectile.projectile.GetArmorPenetration(this.EquipmentSource, null); float DamageAmount = 0; Pawn launcherPawn = this.caster as Pawn; if (Rand.Chance(GetsHotCritChance)) { DamageAmount = this.Projectile.projectile.GetDamageAmount(this.EquipmentSource, null); msg = string.Format("{0}'s {1} critically overheated. ({2} chance) causing {3} damage", this.caster.LabelCap, this.EquipmentSource.LabelCap, failChance.ToStringPercent(), DamageAmount); if (GetsHotCritExplosion && Rand.Chance(GetsHotCritExplosionChance)) { CriticalOverheatExplosion(); } } else { DamageAmount = this.Projectile.projectile.GetDamageAmount(this.EquipmentSource, null); msg = string.Format("{0}'s {1} overheated. ({2} chance) causing {3} damage", this.caster.LabelCap, this.EquipmentSource.LabelCap, failChance.ToStringPercent(), DamageAmount); } float maxburndmg = DamageAmount / 10; while (DamageAmount > 0f) { List <BodyPartRecord> list = launcherPawn.health.hediffSet.GetNotMissingParts().Where(x => x.def.defName.Contains("Finger") || x.def.defName.Contains("Hand")).ToList <BodyPartRecord>(); if (list.NullOrEmpty()) { list = launcherPawn.health.hediffSet.GetNotMissingParts().Where(x => x.def.defName.Contains("Arm") || x.def.defName.Contains("Shoulder")).ToList <BodyPartRecord>(); } if (list.NullOrEmpty()) { list = launcherPawn.health.hediffSet.GetNotMissingParts().Where(x => x.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbCore) || x.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbSegment) || x.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbDigit)).ToList <BodyPartRecord>(); } if (list.NullOrEmpty()) { break; } else { BodyPartRecord part = list.RandomElement(); Hediff hediff; float severity = Rand.Range(Math.Min(0.1f, DamageAmount), Math.Min(DamageAmount, maxburndmg)); hediff = HediffMaker.MakeHediff(HediffToAdd, launcherPawn, null); hediff.Severity = severity; launcherPawn.health.AddHediff(hediff, part, null); DamageAmount -= severity; } } Messages.Message(msg, MessageTypeDefOf.NegativeHealthEvent); } else { msg = string.Format("{0}'s {1} had a weapon jam. ({2} chance)", this.caster.LabelCap, this.EquipmentSource.LabelCap, failChance.ToStringPercent()); Messages.Message(msg, MessageTypeDefOf.SilentInput); } float defaultCooldownTime = this.verbProps.defaultCooldownTime * 2; this.verbProps.defaultCooldownTime = defaultCooldownTime; if (canDamageWeapon) { if (extraWeaponDamage != 0f) { if (this.EquipmentSource != null) { if (this.EquipmentSource.HitPoints - (int)extraWeaponDamage >= 0) { this.EquipmentSource.HitPoints = this.EquipmentSource.HitPoints - (int)extraWeaponDamage; } else if (this.EquipmentSource.HitPoints - (int)extraWeaponDamage < 0) { this.EquipmentSource.HitPoints = 0; this.EquipmentSource.Destroy(); } } if (this.HediffCompSource != null) { /* * if (__instance.HediffCompSource.parent.Part..HitPoints - (int)extraWeaponDamage >= 0) * { * __instance.HediffCompSource.HitPoints = __instance.HediffCompSource.HitPoints - (int)extraWeaponDamage; * } * else if (__instance.HediffCompSource.HitPoints - (int)extraWeaponDamage < 0) * { * __instance.HediffCompSource.HitPoints = 0; * __instance.HediffCompSource.Destroy(); * } */ } } else { if (this.EquipmentSource != null) { if (this.EquipmentSource.HitPoints > 0) { this.EquipmentSource.HitPoints--; } } } } if (Jams) { if (this.EquipmentSource != null) { SpinningLaserGun spinner = (SpinningLaserGun)this.EquipmentSource; if (spinner != null) { spinner.state = SpinningLaserGunBase.State.Idle; spinner.ReachRotationSpeed(0, 0); } } return(false); } } } var attempt = TryLaunchProjectile(verbProps.defaultProjectile, TargetsAoE[i]); if (ScattershotCount > 0 && Multishot && AMASettings.Instance.AllowMultiShot) { // Log.Message(string.Format("AllowMultiShot: {0} Projectile Count: {1}", AMASettings.Instance.AllowMultiShot && Multishot, ScattershotCount)); for (int ii = 0; ii < ScattershotCount; ii++) { // Log.Message(string.Format("Launching extra projectile {0} / {1}", i+1, ScattershotCount)); // AccessTools.Method(typeof(Verb_Shoot).BaseType, "TryCastShot", null, null).Invoke(__instance, null); TryLaunchProjectile(verbProps.defaultProjectile, TargetsAoE[i]); } } else if (TwinLinked) { TryLaunchProjectile(verbProps.defaultProjectile, TargetsAoE[i]); } if (UserEffect && AMASettings.Instance.AllowUserEffects) { if (caster.def.category == ThingCategory.Pawn) { bool Immunityflag = false; Pawn launcherPawn = this.caster as Pawn; if (!Immunitylist.NullOrEmpty()) { foreach (var item in Immunitylist) { Immunityflag = launcherPawn.def.defName.Contains(item); if (Immunityflag) { // Log.Message(string.Format("{0} is immune to their {1}'s UseEffect", launcherPawn.LabelShortCap, __instance.EquipmentSource.LabelShortCap)); } } /* * List<string> list = GunExt.UserEffectImmuneList.Where(x => DefDatabase<ThingDef>.GetNamedSilentFail(x) != null).ToList(); * bool Immunityflag = list.Contains(launcherPawn.def.defName); * if (Immunityflag) * { * return; * } */ } if (!Immunityflag) { var rand = Rand.Value; // This is a random percentage between 0% and 100% // Log.Message(string.Format("GunExt.EffectsUser Effect: {0}, Chance: {1}, Roll: {2}, Result: {3}" + GunExt.ResistEffectStat != null ? ", Resist Stat: "+GunExt.ResistEffectStat.LabelCap+", Resist Amount"+ __instance.caster.GetStatValue(GunExt.ResistEffectStat, true) : null, GunExt.UserEffect.LabelCap, AddHediffChance, rand, rand <= AddHediffChance)); 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(UserHediff); if (effectOnPawn != null) { effectOnPawn.Severity += randomSeverity; } else { Hediff hediff = HediffMaker.MakeHediff(UserHediff, launcherPawn, null); hediff.Severity = randomSeverity; launcherPawn.health.AddHediff(hediff, null, null); } } } } } ////Log.Message(TargetsAoE[i].ToString()); if (attempt != null) { if (attempt == true) { result = true; } if (attempt == false) { result = false; } } } else //melee attacks WON'T have projectiles { // Log.Message("No Projectile"); var victim = TargetsAoE[i].Thing; if (victim != null) { // Log.Message("Yes victim"); if (victim is Pawn pawnVictim) { // Log.Message("Yes victim is pawn"); AbilityEffectUtility.ApplyMentalStates(pawnVictim, CasterPawn, UseAbilityProps.mentalStatesToApply, UseAbilityProps.abilityDef, null); AbilityEffectUtility.ApplyHediffs(pawnVictim, CasterPawn, UseAbilityProps.hediffsToApply, null); AbilityEffectUtility.SpawnSpawnables(UseAbilityProps.thingsToSpawn, pawnVictim, victim.MapHeld, victim.PositionHeld); } } else { // Log.Message("Victim is null"); AbilityEffectUtility.SpawnSpawnables(UseAbilityProps.thingsToSpawn, CasterPawn, CasterPawn.MapHeld, CasterPawn.PositionHeld); } } // } } PostCastShot(result, out result); if (result == false) { Ability.Notify_AbilityFailed(UseAbilityProps.refundsPointsAfterFailing); } return(result); }
public virtual bool CheckFail(ref Verb_Shoot __instance) { string msg = string.Format(""); Thing gun = __instance.EquipmentSource; bool failed = false; float failChance = FailChance(gun, out string reliabilityString); if (failChance > 0f) { Rand.PushState(); failed = Rand.Chance(failChance); Rand.PopState(); if (Debug) { Log.Message((GetsHot ? "Overheat" : "Jam") + " Chance: " + failChance + "% Result: " + (failed ? (GetsHot ? "Overheated" : "Jamed") : "Passed")); } } if (failed) { bool stillFire = true; bool canDamageWeapon = HotDamageWeapon || JamsDamageWeapon; MessageTypeDef msgDef = GetsHot ? MessageTypeDefOf.NegativeHealthEvent : MessageTypeDefOf.SilentInput; float extraWeaponDamage = HotDamageWeapon ? HotDamage : JamDamage; if (GetsHot) { string overheat = "overheated"; string causing = "causing"; DamageDef damageDef = __instance.Projectile.projectile.damageDef; HediffDef HediffToAdd = damageDef.hediff; Pawn launcherPawn = __instance.caster as Pawn; Rand.PushState(); bool crit = Rand.Chance(GetsHotCritChance); Rand.PopState(); bool critExplode = false; if (crit) { overheat = "critically overheated"; if (GetsHotCritExplosion) { critExplode = Rand.Chance(GetsHotCritExplosionChance); if (critExplode) { causing = "causing an explosion"; CriticalOverheatExplosion(__instance); } } } float ArmorPenetration = __instance.Projectile.projectile.GetArmorPenetration(__instance.EquipmentSource, null) * (crit ? 1f : 0.25f); float DamageAmount = __instance.Projectile.projectile.GetDamageAmount(__instance.EquipmentSource, null) * (crit ? 1f : 0.25f); msg = string.Format("{0}'s {1} " + overheat + ". ({2} chance) " + causing + " {3} damage", __instance.caster.LabelCap, __instance.EquipmentSource.LabelCap, failChance.ToStringPercent(), DamageAmount); float damageLeft = DamageAmount; List <BodyPartTagDef> tagDefs = new List <BodyPartTagDef>() { BodyPartTagDefOf.ManipulationLimbDigit, BodyPartTagDefOf.ManipulationLimbSegment }; List <BodyPartRecord> list = launcherPawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Outside, tagDefs).ToList <BodyPartRecord>(); if (!list.NullOrEmpty()) { while (damageLeft > 0f && !list.NullOrEmpty()) { Rand.PushState(); BodyPartRecord part = list.RandomElement(); list.Remove(part); float maxPartDamage = Math.Min(damageLeft, launcherPawn.health.hediffSet.GetPartHealth(part)); float amount = Rand.Range(1f, Math.Min(damageLeft, maxPartDamage)); Rand.PopState(); if (amount > 0) { /* * Hediff hediff = HediffMaker.MakeHediff(HediffToAdd, launcherPawn, part); * hediff.Severity = severity; * launcherPawn.health.AddHediff(hediff, part, null); */ DamageInfo info = new DamageInfo(damageDef, amount, ArmorPenetration, -1, __instance.EquipmentSource, part, __instance.EquipmentSource.def, DamageInfo.SourceCategory.ThingOrUnknown, __instance.CurrentTarget.Thing ?? null); launcherPawn.TakeDamage(info); damageLeft -= amount; } } } } if (Jams) { if (!__instance.GetsHot()) { msg = string.Format("{0}'s {1} had a weapon jam. ({2} chance)", __instance.caster.LabelCap, __instance.EquipmentSource.LabelCap, failChance.ToStringPercent()); } float defaultCooldownTime = __instance.verbProps.defaultCooldownTime * 2; __instance.verbProps.defaultCooldownTime = defaultCooldownTime; if (canDamageWeapon) { if (extraWeaponDamage != 0f) { if (__instance.EquipmentSource != null) { if (__instance.EquipmentSource.HitPoints - (int)extraWeaponDamage >= 0) { __instance.EquipmentSource.HitPoints = __instance.EquipmentSource.HitPoints - (int)extraWeaponDamage; } else if (__instance.EquipmentSource.HitPoints - (int)extraWeaponDamage < 0) { __instance.EquipmentSource.HitPoints = 0; __instance.EquipmentSource.Destroy(); } } if (__instance.HediffCompSource != null) { /* * if (__instance.HediffCompSource.parent.Part.HitPoints - (int)extraWeaponDamage >= 0) * { * __instance.HediffCompSource.HitPoints = __instance.HediffCompSource.HitPoints - (int)extraWeaponDamage; * } * else if (__instance.HediffCompSource.HitPoints - (int)extraWeaponDamage < 0) * { * __instance.HediffCompSource.HitPoints = 0; * __instance.HediffCompSource.Destroy(); * } */ } } else { if (__instance.EquipmentSource != null) { if (__instance.EquipmentSource.HitPoints > 0) { __instance.EquipmentSource.HitPoints--; } } } } if (__instance.EquipmentSource != null) { SpinningLaserGun spinner = __instance.EquipmentSource as SpinningLaserGun; if (spinner != null) { spinner.state = SpinningLaserGunBase.State.Idle; spinner.ReachRotationSpeed(0, 0); } } } Messages.Message(msg, msgDef); } return(failed); }