Esempio n. 1
0
            private static OnCreatureAttack[] GetAttackEvents(void *pCreature, void *pTarget, int nAttacks)
            {
                CNWSCreature?creature = CNWSCreature.FromPointer(pCreature);
                NwGameObject?target   = CNWSObject.FromPointer(pTarget).ToNwObject <NwGameObject>();

                if (creature == null || target == null)
                {
                    return(Array.Empty <OnCreatureAttack>());
                }

                NwCreature nwCreature = creature.ToNwObject <NwCreature>() !;

                // m_nCurrentAttack points to the attack after this flurry.
                int             attackNumberOffset = creature.m_pcCombatRound.m_nCurrentAttack - nAttacks;
                CNWSCombatRound combatRound        = creature.m_pcCombatRound;

                // Create an event for each attack in the flurry
                OnCreatureAttack[] attackEvents = new OnCreatureAttack[nAttacks];
                for (int i = 0; i < nAttacks; i++)
                {
                    attackEvents[i] = GetEventData(nwCreature, target, combatRound, attackNumberOffset + i);
                }

                return(attackEvents);
            }
Esempio n. 2
0
            private static void OnStartCombatRound(void *pCombatRound, uint oidTarget)
            {
                CNWSCombatRound combatRound = CNWSCombatRound.FromPointer(pCombatRound);

                ProcessEvent(new OnCombatRoundStart
                {
                    Creature = combatRound.m_pBaseCreature.ToNwObject <NwCreature>() !,
                    Target   = oidTarget.ToNwObject <NwGameObject>() !,
                });
Esempio n. 3
0
        private int OnGetEpicWeaponDevastatingCritical(void *pStats, void *pWeapon)
        {
            CNWSCreatureStats stats  = CNWSCreatureStats.FromPointer(pStats);
            CNWSItem          weapon = CNWSItem.FromPointer(pWeapon);
            uint weaponType          = weapon == null ? (uint)BaseItem.Gloves : CNWSItem.FromPointer(pWeapon).m_nBaseItem;

            bool hasApplicableFeat    = false;
            bool applicableFeatExists = epicWeaponDevastatingCriticalMap.TryGetValue(weaponType, out HashSet <ushort>?types);

            if (applicableFeatExists)
            {
                foreach (ushort feat in types !)
                {
                    hasApplicableFeat = stats.HasFeat(feat).ToBool();
                    if (hasApplicableFeat)
                    {
                        break;
                    }
                }
            }

            bool canUseFeat = applicableFeatExists && hasApplicableFeat || getEpicWeaponDevastatingCriticalHook.CallOriginal(pStats, pWeapon).ToBool();

            if (weapon != null && canUseFeat && OnDevastatingCriticalHit != null)
            {
                CNWSCreature         creature    = stats.m_pBaseCreature;
                CNWSCombatRound      combatRound = creature.m_pcCombatRound;
                CNWSCombatAttackData attackData  = combatRound.GetAttack(combatRound.m_nCurrentAttack);

                DevastatingCriticalData devastatingCriticalData = new DevastatingCriticalData
                {
                    Weapon = weapon.ToNwObject <NwItem>() !,
                    Target = creature.m_oidAttackTarget.ToNwObject <NwGameObject>() !,
                    Damage = attackData.GetTotalDamage(1),
                };

                OnDevastatingCriticalHit(devastatingCriticalData);
                if (devastatingCriticalData.Bypass)
                {
                    attackData.m_bKillingBlow = 0;
                    return(0);
                }
            }

            return(canUseFeat.ToInt());
        }
Esempio n. 4
0
            private static OnCreatureAttack GetEventData(NwCreature creature, NwGameObject target, CNWSCombatRound combatRound, int attackNumber)
            {
                CNWSCombatAttackData combatAttackData = combatRound.GetAttack(attackNumber);

                return(new OnCreatureAttack
                {
                    CombatAttackData = combatAttackData,
                    Attacker = creature,
                    Target = target,
                    AttackNumber = attackNumber + 1, // 1-based for backwards compatibility
                    WeaponAttackType = (WeaponAttackType)combatAttackData.m_nWeaponAttackType,
                    SneakAttack = (SneakAttack)(combatAttackData.m_bSneakAttack + (combatAttackData.m_bDeathAttack << 1)),
                    KillingBlow = combatAttackData.m_bKillingBlow.ToBool(),
                    AttackType = combatAttackData.m_nAttackType,
                    AttackRoll = combatAttackData.m_nToHitRoll,
                    AttackModifier = combatAttackData.m_nToHitMod,
                    IsRangedAttack = combatAttackData.m_bRangedAttack.ToBool(),
                    IsCoupDeGrace = combatAttackData.m_bCoupDeGrace.ToBool(),
                    IsAttackDeflected = combatAttackData.m_bAttackDeflected.ToBool(),
                    IsCriticalThreat = combatAttackData.m_bCriticalThreat.ToBool(),
                    DamageData = new DamageData <short>(combatAttackData.m_nDamage),
                    TotalDamage = combatAttackData.GetTotalDamage(),
                });
            }
Esempio n. 5
0
        private int OnGetAttackModifierVersus(void *pStats, void *pCreature)
        {
            int attackMod = getAttackModifierVersusHook.CallOriginal(pStats, pCreature);

            CNWSCreatureStats stats       = CNWSCreatureStats.FromPointer(pStats);
            CNWSCreature      creature    = stats.m_pBaseCreature;
            CNWSCombatRound   combatRound = creature.m_pcCombatRound;

            if (combatRound == null)
            {
                return(attackMod);
            }

            CNWSItem weapon = combatRound.GetCurrentAttackWeapon(combatRound.GetWeaponAttackType());

            if (weapon == null)
            {
                return(attackMod);
            }

            uint baseItem             = weapon.m_nBaseItem;
            bool hasApplicableFeat    = false;
            bool applicableFeatExists = greaterWeaponFocusMap.TryGetValue(baseItem, out HashSet <ushort>?types);

            if (applicableFeatExists)
            {
                foreach (ushort feat in types !)
                {
                    hasApplicableFeat = stats.HasFeat(feat).ToBool();
                    if (hasApplicableFeat)
                    {
                        break;
                    }
                }
            }

            if (applicableFeatExists && hasApplicableFeat)
            {
                attackMod += GreaterWeaponFocusAttackBonus;

                if ((*NWNXLib.EnableCombatDebugging()).ToBool() && stats.m_bIsPC.ToBool())
                {
                    CNWSCombatAttackData currentAttack = combatRound.GetAttack(combatRound.m_nCurrentAttack);
                    StringBuilder        debugMessage  = new StringBuilder(currentAttack.m_sDamageDebugText.ToString());
                    debugMessage.Append(" + ");
                    debugMessage.Append(GreaterWeaponFocusAttackBonus);
                    debugMessage.Append(" (Greater Weapon Focus Feat)");

                    currentAttack.m_sDamageDebugText = debugMessage.ToString().ToExoString();
                }
            }

            if (EnableSlingGoodAimFeat && baseItem == (uint)BaseItem.Sling && stats.m_nRace != (ushort)RacialType.Halfling && stats.HasFeat((ushort)Feat.GoodAim).ToBool())
            {
                int goodAimModifier = NWNXLib.Rules().GetRulesetIntEntry("GOOD_AIM_MODIFIER".ToExoString(), 1);
                attackMod += goodAimModifier;

                if ((*NWNXLib.EnableCombatDebugging()).ToBool() && stats.m_bIsPC.ToBool())
                {
                    CNWSCombatAttackData currentAttack = combatRound.GetAttack(combatRound.m_nCurrentAttack);
                    StringBuilder        debugMessage  = new StringBuilder(currentAttack.m_sDamageDebugText.ToString());
                    debugMessage.Append(" + ");
                    debugMessage.Append(goodAimModifier);
                    debugMessage.Append(" (Good Aim Feat)");

                    currentAttack.m_sDamageDebugText = debugMessage.ToString().ToExoString();
                }
            }

            return(attackMod);
        }