Ejemplo n.º 1
0
        private static void ApplyNormalDamageToTarget(Verb_MeleeAttack vMA, Pawn attacker, LocalTargetInfo target)
        {
            MRpawntoken token = MainController.GetPawnToken(attacker);
            Pawn        tpawn = target.Thing as Pawn;
            // Immobile targets receive full damage on normal hits (The only possible result against them) with independence of the Attack Mode selected
            bool immobile = (target.Thing.def.category != ThingCategory.Pawn) || tpawn.Downed || (tpawn.GetPosture() != PawnPosture.Standing);

            if (token.amode.solver == 3 && !immobile)
            {
                return;                                       // On Disarm Mode we do no damage at all
            }
            var DamageInfosToApply = Traverse.Create(vMA).Method("DamageInfosToApply", new Type[] { typeof(LocalTargetInfo) });

            foreach (DamageInfo current in (DamageInfosToApply.GetValue <IEnumerable <DamageInfo> >(target)))
            {
                if (target.ThingDestroyed)
                {
                    break;
                }
                if (!immobile && (token.amode.solver == 1 || token.amode.solver == 2))
                {
                    // On Capture & Stun we do half the damage on normal hits
                    current.SetAmount(Mathf.Max(1, Mathf.RoundToInt(current.Amount * 0.5f)));
                }
                target.Thing.TakeDamage(current);
            }
        }
Ejemplo n.º 2
0
        private static void ApplyParryDamageToTarget(Verb_MeleeAttack vMA, Pawn attacker, LocalTargetInfo target)
        {
            // The main differences between a regular hit and a parried one regarding damage are the following:
            // - If the target has an active shield with energy it will absorb the FULL damage of the attack
            // - If the target is wielding a melee weapon it will absorb all the damage of the attack suffering
            //   Original Damage * ParryReduction * (1-Melee Skill) (minimum of 1) of damage
            // - If the target is unarmed, the damage received will be reduced by ParryReduction
            MRpawntoken token = MainController.GetPawnToken(attacker);

            if (token.amode.solver == 3)
            {
                return;                          // On Disarm Mode we do no damage at all on parried hits
            }
            bool rollback           = false;
            Pawn tpawn              = target.Thing as Pawn;
            var  DamageInfosToApply = Traverse.Create(vMA).Method("DamageInfosToApply", new Type[] { typeof(LocalTargetInfo) });

            foreach (DamageInfo current in (DamageInfosToApply.GetValue <IEnumerable <DamageInfo> >(target)))
            {
                if (target.ThingDestroyed)
                {
                    break;
                }
                if (token.amode.solver == 1 || token.amode.solver == 2)
                {
                    // On Capture & Stun we do half the damage on parry hits
                    current.SetAmount(Mathf.Max(1, Mathf.RoundToInt(current.Amount * 0.5f)));
                }
                rollback = current.Def.isExplosive;        // We briefly active isExplosive to make Vanilla Personal Shields able to intercept melee damage
                current.Def.isExplosive = true;
                if (PawnHasActiveAbsorber(current, tpawn)) // We have to do a double check so Apparel absorbers take precedence over wield weapon damage
                {
                    target.Thing.TakeDamage(current);
                }
                else if (tpawn.equipment != null && tpawn.equipment.Primary != null && tpawn.equipment.Primary.def.IsMeleeWeapon)
                {
                    // The target has an equiped melee weapon after a parry, it will deny any damage to the target but the weapon will suffer some damage itself
                    current.SetAmount(Mathf.Max(1, Mathf.RoundToInt(current.Amount * Constants.ParryReduction * (1f - tpawn.GetStatValue(StatDefOf.MeleeHitChance, true)))));
                    // If the current damage is enough to destroy the weapon we try to drop it instead. If there is not enough room nearby, it will be destroyed
                    if (tpawn.equipment.Primary.HitPoints <= current.Amount)
                    {
                        ThingWithComps thingwithcomps = new ThingWithComps();
                        if (tpawn.equipment.TryDropEquipment(tpawn.equipment.Primary, out thingwithcomps, tpawn.Position))
                        {
                            current.Def.isExplosive = rollback;
                            break;
                        }
                    }
                    tpawn.equipment.Primary.TakeDamage(current);
                }
                else
                {
                    // Unarmed defender, it just takes reduced damage
                    current.SetAmount(Mathf.Max(1, Mathf.RoundToInt(current.Amount * Constants.ParryReduction)));
                    target.Thing.TakeDamage(current);
                }
                current.Def.isExplosive = rollback;
            }
        }
Ejemplo n.º 3
0
        public static void Postfix(Pawn_DraftController controller, ref IEnumerable <Gizmo> __result)
        {
            // We add the command toggle corresponding to the token in the value
            MRpawntoken       token = MainController.GetPawnToken(controller.pawn);
            AttackModeCommand optF  = new AttackModeCommand(token);
            List <Gizmo>      list  = __result.ToList <Gizmo>();

            list.Add(optF);
            __result = (IEnumerable <Gizmo>)list;
        }
Ejemplo n.º 4
0
 public AttackModeCommand(MRpawntoken token)
 {
     this.Token         = token;
     this.icon          = token.amode.icontex;
     this.defaultLabel  = token.amode.label;
     this.defaultDesc   = token.amode.desc;
     this.hotKey        = KeyBindingDefOf.Misc7;
     this.activateSound = SoundDef.Named("Click");
     this.action        = token.NextAttackMode;
     this.groupKey      = Constants.CommandGroupKey;
 }
Ejemplo n.º 5
0
        private static void ApplyCriticalDamageToTarget(Verb_MeleeAttack vMA, Pawn attacker, LocalTargetInfo target)
        {
            Pawn        tpawn = target.Thing as Pawn;
            var         DamageInfosToApply = Traverse.Create(vMA).Method("DamageInfosToApply", new Type[] { typeof(LocalTargetInfo) });
            MRpawntoken token = MainController.GetPawnToken(attacker);

            switch (token.amode.solver)
            {
            case 0:     // Kill
                // Double damage on all applied damage
                foreach (DamageInfo current in (DamageInfosToApply.GetValue <IEnumerable <DamageInfo> >(target)))
                {
                    if (target.ThingDestroyed)
                    {
                        break;
                    }
                    current.SetAmount(Mathf.Max(1, Mathf.RoundToInt(current.Amount * 2f)));
                    target.Thing.TakeDamage(current);
                }
                break;

            case 1:     // Capture
                // We replace all damage by an anesthesize effect
                if (target.Thing.def.category == ThingCategory.Pawn)
                {
                    HealthUtility.TryAnesthesize(tpawn);
                }
                break;

            case 2:     // Stun
                // We replace ALL damage by a short stun effect instead
                target.Thing.TakeDamage(new DamageInfo(DamageDefOf.Stun, 20));
                break;

            case 3:     // Disarm
                // We replace ALL damage by removing currently equiped weapon
                if (tpawn.equipment != null && tpawn.equipment.Primary != null)
                {
                    ThingWithComps thingwithcomps = new ThingWithComps();
                    tpawn.equipment.TryDropEquipment(tpawn.equipment.Primary, out thingwithcomps, tpawn.Position);
                }
                break;

            default:
                Log.Warning(string.Concat(new object[]
                {
                    "Melee Rebalance: Critical Special effect not registered for ", attacker
                }));
                break;
            }
        }
Ejemplo n.º 6
0
        private static int ResolveMeleeAttack(Pawn attacker, Thing defender, bool surprise)
        {
            // We generate the result of a melee attack based on skills involved and some extra factors
            // 0: Miss, 1: Hit, 2: Parry, 3: Critical
            // Surprise attacks ALWAYS hit
            MRpawntoken atoken = MainController.GetPawnToken(attacker);

            if (surprise)
            {
                atoken.ehc = 1f;
                return(1);
            }
            // Attacks against immobile/downed targets or things that aren't pawns ALWAYS hit and can't trigger special effects
            Pawn tpawn = defender as Pawn;

            if (defender.def.category != ThingCategory.Pawn || tpawn.Downed || tpawn.GetPosture() != PawnPosture.Standing)
            {
                atoken.ehc = 1f;
                return(1);
            }
            // Against regular targets the effective melee skill of the defender reduces multiplicatively the chance to hit of the attacker.
            // Max Parry Chances are capped at MaxParryChance.
            float       roll   = Rand.Value;
            float       abh    = attacker.GetStatValue(StatDefOf.MeleeHitChance, true);
            float       dbh    = tpawn.GetStatValue(StatDefOf.MeleeHitChance, true);
            MRpawntoken dtoken = MainController.GetPawnToken(tpawn);

            // We reduce the base defensive skill based on the registered parry counters for target pawn.
            dbh -= Constants.ParryCounterPenalty * (float)dtoken.counter;
            if (dbh < 0f)
            {
                dbh = 0f;
            }
            else if (dbh > Constants.MaxParryChance)
            {
                dbh = Constants.MaxParryChance;
            }
            atoken.ehc = abh * (1f - dbh);

            //Log.Warning(string.Concat(new object[]
            //    {
            //    attacker,"(BHC ",abh,") tried to hit ",tpawn,"(BHC ",dbh,") with effective hit chance ",atoken.ehc," and rolled ",roll
            //    }));

            // If the attacker is NOT a player controller entity we choose the attack mode
            if (!attacker.IsColonistPlayerControlled)
            {
                atoken.ChooseAttackMode(tpawn);
            }
            if (roll > abh)
            {
                return(0);
            }
            else
            {
                // The attempt was not a miss so we increase the parry counters of the target
                dtoken.counter++;
                // Now we check for critical effects
                if ((atoken.ehc > atoken.amode.threshold) && (roll <= (atoken.ehc * atoken.amode.chance)))
                {
                    return(3);
                }
                if (roll <= atoken.ehc)
                {
                    return(1);
                }
            }
            return(2);
        }