public static void MakeNew(Pawn actor, Pawn victim) { string dmgLabel; float dmgAmount; DamageDef dmgDef; RulePackDef dmgRules; if (TryGetFangsDmgInfo(actor.GetVampFangs(), out dmgLabel, out dmgAmount, out dmgDef, out dmgRules)) { BodyPartRecord neckPart = victim.health.hediffSet.GetNotMissingParts().FirstOrDefault(x => x.def == BodyPartDefOf.Neck); if (neckPart == null) { neckPart = victim.health.hediffSet.GetNotMissingParts().FirstOrDefault(x => x.depth == BodyPartDepth.Outside); } if (neckPart == null) { neckPart = victim.health.hediffSet.GetNotMissingParts().RandomElement(); } if (neckPart != null) { GenClamor.DoClamor(actor, 10f, ClamorDefOf.Harm); actor.Drawer.Notify_MeleeAttackOn(victim); victim.TakeDamage(new DamageInfo(dmgDef, (int)(dmgAmount * BITEFACTOR), 0, -1, actor, neckPart)); BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = new BattleLogEntry_MeleeCombat(dmgRules, true, actor, victim, ImplementOwnerTypeDefOf.Bodypart, dmgLabel); Find.BattleLog.Add(battleLogEntry_MeleeCombat); } } }
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest) { //dest.Pawn?.records?.Increment(RecordDefOf.DamageDealt); Pawn targetPawn = target.Pawn; if (targetPawn != null && parent.pawn != targetPawn && targetPawn?.def != AlienSayersDef) { //BattleLogEntry_MeleeCombat battleLogEntry_RangedImpact = new BattleLogEntry_MeleeCombat(launcher, hitThing, intendedTarget.Thing, equipmentDef, def, targetCoverDef); BattleLogEntry_MeleeCombat battleLogEntry = new BattleLogEntry_MeleeCombat( ruleDef: DefDatabase <RulePackDef> .GetNamed("Maneuver_Slash_MeleeHit"), alwaysShowInCompact: true, initiator: parent.pawn, recipient: targetPawn, implementType: ImplementOwnerTypeDefOf.NativeVerb, toolLabel: "", ownerEquipmentDef: null, ownerHediffDef: null, def: LogEntryDefOf.MeleeAttack ); Find.BattleLog.Add(battleLogEntry); bool atLeatHitOnce = false; if (Props.injuryOnHit != null) { int num = Mathf.Min(Props.injuryCount.RandomInRange); for (int i = 0; i < num; i++) { if ( Rand.Chance(Mathf.Clamp( parent.pawn.GetStatValue(StatDefOf.MeleeHitChance) * (targetPawn.CurJobDef == JobDefOf.AttackStatic ? 0f : targetPawn.GetStatValue(StatDefOf.MeleeDodgeChance)) , 0.0f, 1.0f)) ) { atLeatHitOnce = true; targetPawn.TakeDamage( new DamageInfo( Props.injuryOnHit, Props.injuryDamage.RandomInRange, instigator: parent.pawn, weapon: parent.pawn.def ) ); } } } if (!targetPawn.def.race.IsMechanoid && atLeatHitOnce) { base.Apply(target, dest); } } }
public BattleLogEntry_MeleeCombat CreateCombatLog(RulePackDef rulePack) { if (this.maneuver == null) { return null; } if (this.tool == null) { return null; } BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = new BattleLogEntry_MeleeCombat(rulePack, this.maneuver.combatLogRules, base.CasterPawn, this.currentTarget.Thing, this.implementOwnerType, (!this.tool.labelUsedInLogging) ? string.Empty : this.tool.label, (this.ownerEquipment != null) ? this.ownerEquipment.def : null, (this.ownerHediffComp != null) ? this.ownerHediffComp.Def : null); Find.BattleLog.Add(battleLogEntry_MeleeCombat); return battleLogEntry_MeleeCombat; }
public BattleLogEntry_MeleeCombat CreateCombatLog(Func <ManeuverDef, RulePackDef> rulePackGetter, bool alwaysShow) { if (this.maneuver == null) { return(null); } if (this.tool == null) { return(null); } BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = new BattleLogEntry_MeleeCombat(rulePackGetter(this.maneuver), alwaysShow, base.CasterPawn, this.currentTarget.Thing, base.ImplementOwnerType, (!this.tool.labelUsedInLogging) ? string.Empty : this.tool.label, (base.EquipmentSource != null) ? base.EquipmentSource.def : null, (base.HediffCompSource != null) ? base.HediffCompSource.Def : null, this.maneuver.logEntryDef); Find.BattleLog.Add(battleLogEntry_MeleeCombat); return(battleLogEntry_MeleeCombat); }
public BattleLogEntry_MeleeCombat CreateCombatLog(Func <ManeuverDef, RulePackDef> rulePackGetter, bool alwaysShow) { if (maneuver == null) { return(null); } if (tool == null) { return(null); } BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = new BattleLogEntry_MeleeCombat(rulePackGetter(maneuver), alwaysShow, CasterPawn, currentTarget.Thing, base.ImplementOwnerType, tool.labelUsedInLogging ? tool.label : "", (base.EquipmentSource == null) ? null : base.EquipmentSource.def, (base.HediffCompSource == null) ? null : base.HediffCompSource.Def, maneuver.logEntryDef); Find.BattleLog.Add(battleLogEntry_MeleeCombat); return(battleLogEntry_MeleeCombat); }
public BattleLogEntry_MeleeCombat CreateCombatLog(Func <ManeuverDef, RulePackDef> rulePackGetter, bool alwaysShow) { BattleLogEntry_MeleeCombat result; if (this.maneuver == null) { result = null; } else if (this.tool == null) { result = null; } else { BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = new BattleLogEntry_MeleeCombat(rulePackGetter(this.maneuver), alwaysShow, base.CasterPawn, this.currentTarget.Thing, this.implementOwnerType, (!this.tool.labelUsedInLogging) ? "" : this.tool.label, (this.ownerEquipment != null) ? this.ownerEquipment.def : null, (this.ownerHediffComp != null) ? this.ownerHediffComp.Def : null, this.maneuver.logEntryDef); Find.BattleLog.Add(battleLogEntry_MeleeCombat); result = battleLogEntry_MeleeCombat; } return(result); }
/// <summary> /// Performs the actual melee attack part. Awards XP, calculates and applies whether an attack connected and the outcome. /// </summary> /// <returns>True if the attack connected, false otherwise</returns> protected override bool TryCastShot() { Pawn casterPawn = CasterPawn; if (casterPawn.stances.FullBodyBusy) { return(false); } Thing targetThing = currentTarget.Thing; if (!CanHitTarget(targetThing)) { Log.Warning(string.Concat(new object[] { casterPawn, " meleed ", targetThing, " from out of melee position." })); } casterPawn.rotationTracker.Face(targetThing.DrawPos); // Award XP as per vanilla bool targetImmobile = IsTargetImmobile(currentTarget); if (!targetImmobile && casterPawn.skills != null) { casterPawn.skills.Learn(SkillDefOf.Melee, HitXP, false); } // Hit calculations bool result; string moteText = ""; SoundDef soundDef; Pawn defender = targetThing as Pawn; //var hitRoll = Rand.Value; if (Rand.Chance(GetHitChance(targetThing))) { // Check for dodge if (!targetImmobile && !surpriseAttack && Rand.Chance(defender.GetStatValue(StatDefOf.MeleeDodgeChance))) { // Attack is evaded result = false; soundDef = SoundMiss(); CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesDodge, false); moteText = "TextMote_Dodge".Translate(); defender.skills?.Learn(SkillDefOf.Melee, DodgeXP, false); } else { // Attack connects, calculate resolution //var resultRoll = Rand.Value; var parryBonus = 1 / EquipmentSource?.GetStatValue(CE_StatDefOf.MeleeCounterParryBonus) ?? 1; var parryChance = GetComparativeChanceAgainst(defender, casterPawn, CE_StatDefOf.MeleeParryChance, BaseParryChance, parryBonus); if (!surpriseAttack && defender != null && CanDoParry(defender) && Rand.Chance(parryChance)) { // Attack is parried Apparel shield = defender.apparel.WornApparel.FirstOrDefault(x => x is Apparel_Shield); bool isShieldBlock = shield != null && Rand.Chance(ShieldBlockChance); Thing parryThing = isShieldBlock ? shield : defender.equipment?.Primary ?? defender; if (Rand.Chance(GetComparativeChanceAgainst(defender, casterPawn, CE_StatDefOf.MeleeCritChance, BaseCritChance))) { // Do a riposte DoParry(defender, parryThing, true); moteText = "CE_TextMote_Riposted".Translate(); CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesDeflect, false); //placeholder defender.skills?.Learn(SkillDefOf.Melee, CritXP + ParryXP, false); } else { // Do a parry DoParry(defender, parryThing); moteText = "CE_TextMote_Parried".Translate(); CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesMiss, false); //placeholder defender.skills?.Learn(SkillDefOf.Melee, ParryXP, false); } result = false; soundDef = SoundMiss(); // TODO Set hit sound to something more appropriate } else { BattleLogEntry_MeleeCombat log = this.CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesHit, false); // Attack connects if (surpriseAttack || Rand.Chance(GetComparativeChanceAgainst(casterPawn, defender, CE_StatDefOf.MeleeCritChance, BaseCritChance))) { // Do a critical hit isCrit = true; ApplyMeleeDamageToTarget(currentTarget).AssociateWithLog(log); moteText = casterPawn.def.race.Animal ? "CE_TextMote_Knockdown".Translate() : "CE_TextMote_CriticalHit".Translate(); casterPawn.skills?.Learn(SkillDefOf.Melee, CritXP, false); } else { // Do a regular hit as per vanilla ApplyMeleeDamageToTarget(currentTarget).AssociateWithLog(log); } result = true; soundDef = targetThing.def.category == ThingCategory.Building ? SoundHitBuilding() : SoundHitPawn(); } } } else { // Attack missed result = false; soundDef = SoundMiss(); CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesMiss, false); } if (!moteText.NullOrEmpty()) { MoteMaker.ThrowText(targetThing.PositionHeld.ToVector3Shifted(), targetThing.MapHeld, moteText); } soundDef.PlayOneShot(new TargetInfo(targetThing.PositionHeld, targetThing.MapHeld)); casterPawn.Drawer.Notify_MeleeAttackOn(targetThing); if (defender != null && !defender.Dead) { defender.stances.StaggerFor(95); if (casterPawn.MentalStateDef != MentalStateDefOf.SocialFighting || defender.MentalStateDef != MentalStateDefOf.SocialFighting) { defender.mindState.meleeThreat = casterPawn; defender.mindState.lastMeleeThreatHarmTick = Find.TickManager.TicksGame; } } casterPawn.rotationTracker.FaceCell(targetThing.Position); if (casterPawn.caller != null) { casterPawn.caller.Notify_DidMeleeAttack(); } return(result); }
protected override bool TryCastShot() { Pawn casterPawn = base.CasterPawn; if (!casterPawn.Spawned) { return(false); } if (casterPawn.stances.FullBodyBusy) { return(false); } Thing thing = this.currentTarget.Thing; if (!base.CanHitTarget(thing)) { Log.Warning(string.Concat(new object[] { casterPawn, " meleed ", thing, " from out of melee position." }), false); } casterPawn.rotationTracker.Face(thing.DrawPos); if (!this.IsTargetImmobile(this.currentTarget) && casterPawn.skills != null) { casterPawn.skills.Learn(SkillDefOf.Melee, 200f * this.verbProps.AdjustedFullCycleTime(this, casterPawn), false); } Pawn pawn = thing as Pawn; if (pawn != null && !pawn.Dead && (casterPawn.MentalStateDef != MentalStateDefOf.SocialFighting || pawn.MentalStateDef != MentalStateDefOf.SocialFighting)) { pawn.mindState.meleeThreat = casterPawn; pawn.mindState.lastMeleeThreatHarmTick = Find.TickManager.TicksGame; } Map map = thing.Map; Vector3 drawPos = thing.DrawPos; SoundDef soundDef; bool result; if (Rand.Chance(this.GetNonMissChance(thing))) { if (!Rand.Chance(this.GetDodgeChance(thing))) { if (thing.def.category == ThingCategory.Building) { soundDef = this.SoundHitBuilding(); } else { soundDef = this.SoundHitPawn(); } if (this.verbProps.impactMote != null) { MoteMaker.MakeStaticMote(drawPos, map, this.verbProps.impactMote, 1f); } BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = this.CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesHit, true); result = true; DamageWorker.DamageResult damageResult = this.ApplyMeleeDamageToTarget(this.currentTarget); damageResult.AssociateWithLog(battleLogEntry_MeleeCombat); if (damageResult.deflected) { battleLogEntry_MeleeCombat.RuleDef = this.maneuver.combatLogRulesDeflect; battleLogEntry_MeleeCombat.alwaysShowInCompact = false; } } else { result = false; soundDef = this.SoundMiss(); MoteMaker.ThrowText(drawPos, map, "TextMote_Dodge".Translate(), 1.9f); this.CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesDodge, false); } } else { result = false; soundDef = this.SoundMiss(); this.CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesMiss, false); } soundDef.PlayOneShot(new TargetInfo(thing.Position, map, false)); if (casterPawn.Spawned) { casterPawn.Drawer.Notify_MeleeAttackOn(thing); } if (pawn != null && !pawn.Dead && pawn.Spawned) { pawn.stances.StaggerFor(95); } if (casterPawn.Spawned) { casterPawn.rotationTracker.FaceCell(thing.Position); } if (casterPawn.caller != null) { casterPawn.caller.Notify_DidMeleeAttack(); } return(result); }
public static void MakeNew(Pawn actor, Pawn victim) { string dmgLabel; float dmgAmount; DamageDef dmgDef; RulePackDef dmgRules; if (TryGetFangsDmgInfo(actor.GetVampFangs(), out dmgLabel, out dmgAmount, out dmgDef, out dmgRules)) { BodyPartRecord neckPart = victim.health.hediffSet.GetNotMissingParts().FirstOrDefault(x => x.def == BodyPartDefOf.Neck); if (neckPart == null) { neckPart = victim.health.hediffSet.GetNotMissingParts().FirstOrDefault(x => x.depth == BodyPartDepth.Outside); } if (neckPart == null) { neckPart = victim.health.hediffSet.GetNotMissingParts().RandomElement(); } if (neckPart != null) { //Make the sound and mote GenClamor.DoClamor(actor, 10f, ClamorDefOf.Harm); actor.Drawer.Notify_MeleeAttackOn(victim); //Create the battle log entry BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = new BattleLogEntry_MeleeCombat(dmgRules, true, actor, victim, ImplementOwnerTypeDefOf.Hediff, dmgLabel); battleLogEntry_MeleeCombat.def = LogEntryDefOf.MeleeAttack; //Apply the melee damage DamageWorker.DamageResult damageResult = new DamageWorker.DamageResult(); damageResult = victim.TakeDamage(new DamageInfo(dmgDef, (int)(dmgAmount * BITEFACTOR), 0.5f, -1, actor, neckPart)); damageResult.AssociateWithLog(battleLogEntry_MeleeCombat); //Add to the battle log Find.BattleLog.Add(battleLogEntry_MeleeCombat); //Transfer any alcohol bool addHediff = false; if (victim?.health?.hediffSet?.GetHediffs <Hediff_Alcohol>()?.FirstOrDefault(x => x.def == HediffDefOf.AlcoholHigh) is Hediff victimAlcohol) { Hediff actorAlcohol; if (actor?.health?.hediffSet?.GetHediffs <Hediff_Alcohol>()?.FirstOrDefault(x => x.def == HediffDefOf.AlcoholHigh) is Hediff findActorAlcohol) { actorAlcohol = findActorAlcohol; } else { addHediff = true; actorAlcohol = HediffMaker.MakeHediff(HediffDefOf.AlcoholHigh, actor, null); } actorAlcohol.Severity += victimAlcohol.Severity; if (addHediff) { actor.health.AddHediff(actorAlcohol); } victim.health.RemoveHediff(victimAlcohol); } } } }
protected override bool TryCastShot() { Pawn casterPawn = base.CasterPawn; if (casterPawn.stances.FullBodyBusy) { return(false); } Thing thing = base.currentTarget.Thing; if (!base.CanHitTarget(thing)) { Log.Warning(casterPawn + " meleed " + thing + " from out of melee position."); } casterPawn.rotationTracker.Face(thing.DrawPos); if (!this.IsTargetImmobile(base.currentTarget) && casterPawn.skills != null) { casterPawn.skills.Learn(SkillDefOf.Melee, 250f, false); } bool result; SoundDef soundDef; if (Rand.Value < this.GetNonMissChance(thing)) { if (Rand.Value > this.GetDodgeChance(thing)) { BattleLogEntry_MeleeCombat log = this.CreateCombatLog(RulePackDefOf.Combat_Hit); result = true; this.ApplyMeleeDamageToTarget(base.currentTarget).InsertIntoLog(log); soundDef = ((thing.def.category != ThingCategory.Building) ? this.SoundHitPawn() : this.SoundHitBuilding()); } else { result = false; soundDef = this.SoundMiss(); MoteMaker.ThrowText(thing.DrawPos, thing.Map, "TextMote_Dodge".Translate(), 1.9f); this.CreateCombatLog(RulePackDefOf.Combat_Dodge); } } else { result = false; soundDef = this.SoundMiss(); this.CreateCombatLog(RulePackDefOf.Combat_Miss); } soundDef.PlayOneShot(new TargetInfo(thing.Position, casterPawn.Map, false)); casterPawn.Drawer.Notify_MeleeAttackOn(thing); Pawn pawn = thing as Pawn; if (pawn != null && !pawn.Dead) { pawn.stances.StaggerFor(95); if (casterPawn.MentalStateDef != MentalStateDefOf.SocialFighting || pawn.MentalStateDef != MentalStateDefOf.SocialFighting) { pawn.mindState.meleeThreat = casterPawn; pawn.mindState.lastMeleeThreatHarmTick = Find.TickManager.TicksGame; } } casterPawn.rotationTracker.FaceCell(thing.Position); if (casterPawn.caller != null) { casterPawn.caller.Notify_DidMeleeAttack(); } return(result); }
public static bool TryCastShot(Verb_MeleeAttack __instance, ref bool __result) { Pawn casterPawn = __instance.CasterPawn; if (!casterPawn.Spawned) { return(false); } if (casterPawn.stances.FullBodyBusy) { return(false); } Thing thing = currentTargetFieldRef(__instance).Thing; if (!__instance.CanHitTarget(thing)) { Log.Warning(string.Concat(casterPawn, " meleed ", thing, " from out of melee position.")); } casterPawn.rotationTracker.Face(thing.DrawPos); if (!funcIsTargetImmobile(__instance, currentTargetFieldRef(__instance)) && casterPawn.skills != null) { casterPawn.skills.Learn(SkillDefOf.Melee, 200f * __instance.verbProps.AdjustedFullCycleTime(__instance, casterPawn)); } Pawn pawn = thing as Pawn; if (pawn != null && !pawn.Dead && (casterPawn.MentalStateDef != MentalStateDefOf.SocialFighting || pawn.MentalStateDef != MentalStateDefOf.SocialFighting)) { pawn.mindState.meleeThreat = casterPawn; pawn.mindState.lastMeleeThreatHarmTick = Find.TickManager.TicksGame; } Map map = thing.Map; Vector3 drawPos = thing.DrawPos; SoundDef soundDef; bool result; if (Rand.Chance(funcGetNonMissChance(__instance, thing))) { if (!Rand.Chance(funcGetDodgeChance(__instance, thing))) { soundDef = ((thing.def.category != ThingCategory.Building) ? funcSoundHitPawn(__instance) : funcSoundHitBuilding(__instance)); if (__instance.verbProps.impactMote != null) { MoteMaker.MakeStaticMote(drawPos, map, __instance.verbProps.impactMote); } BattleLogEntry_MeleeCombat battleLogEntry_MeleeCombat = __instance.CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesHit, alwaysShow: true); result = true; DamageWorker.DamageResult damageResult = funcApplyMeleeDamageToTarget(__instance, currentTargetFieldRef(__instance)); if (damageResult.stunned && damageResult.parts.NullOrEmpty()) { Find.BattleLog.RemoveEntry(battleLogEntry_MeleeCombat); } else { damageResult.AssociateWithLog(battleLogEntry_MeleeCombat); if (damageResult.deflected) { battleLogEntry_MeleeCombat.RuleDef = __instance.maneuver.combatLogRulesDeflect; battleLogEntry_MeleeCombat.alwaysShowInCompact = false; } } } else { result = false; soundDef = funcSoundDodge(__instance, thing); MoteMaker.ThrowText(drawPos, map, "TextMote_Dodge".Translate(), 1.9f); __instance.CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesDodge, alwaysShow: false); } } else { result = false; soundDef = funcSoundMiss(__instance); __instance.CreateCombatLog((ManeuverDef maneuver) => maneuver.combatLogRulesMiss, alwaysShow: false); } soundDef.PlayOneShot(new TargetInfo(thing.Position, map)); if (casterPawn.Spawned) { casterPawn.Drawer.Notify_MeleeAttackOn(thing); } if (pawn != null && !pawn.Dead && pawn.Spawned) { pawn.stances.StaggerFor(95); } if (casterPawn.Spawned) { casterPawn.rotationTracker.FaceCell(thing.Position); } if (casterPawn.caller != null) { casterPawn.caller.Notify_DidMeleeAttack(); } return(result); }