baseline from krumiro's [WotC] RW Realistic Aiming Angles

rohan
Aug 24, 2022, 7:44 AM
X4IR7ZAH5HH56FIYSSOUKOQDRLNKH5LOHQ5ZYQGQQLML67RLZGMQC

Dependencies

Change contents

  • file addition: RWRealisticAimingAnglesHL.XCOM_sln (----------)
    [2.1]
    
    Microsoft Visual Studio Solution File, Format Version 12.00
    # XCOM ModBuddy Solution File, Format Version 11.00
    VisualStudioVersion = 12.0.21005.1
    MinimumVisualStudioVersion = 10.0.40219.1
    Project("{5DAE07AF-E217-45C1-8DE7-FF99D6011E8A}") = "RWRealisticAimingAnglesHL", "RWRealisticAimingAnglesHL\RWRealisticAimingAnglesHL.x2proj", "{A648FC6C-8BC2-4D75-B7E4-B90EA1FA4D3B}"
    EndProject
    Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
    Debug|XCOM 2 = Debug|XCOM 2
    Default|XCOM 2 = Default|XCOM 2
    EndGlobalSection
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
    {A648FC6C-8BC2-4D75-B7E4-B90EA1FA4D3B}.Debug|XCOM 2.ActiveCfg = Debug|XCOM 2
    {A648FC6C-8BC2-4D75-B7E4-B90EA1FA4D3B}.Debug|XCOM 2.Build.0 = Debug|XCOM 2
    {A648FC6C-8BC2-4D75-B7E4-B90EA1FA4D3B}.Default|XCOM 2.ActiveCfg = Default|XCOM 2
    {A648FC6C-8BC2-4D75-B7E4-B90EA1FA4D3B}.Default|XCOM 2.Build.0 = Default|XCOM 2
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
    HideSolutionNode = FALSE
    EndGlobalSection
    EndGlobal
  • file addition: RWRealisticAimingAnglesHL (d--r------)
    [2.1]
  • file addition: Src (d--r------)
    [0.1113]
  • file addition: RWRealisticAimingAnglesHL (d--r------)
    [0.1152]
  • file addition: Classes (d--r------)
    [0.1169]
  • file addition: RWRealisticAimingAngles.uc (---r------)
    [0.1208]
    class RWRealisticAimingAngles
    extends UIScreenListener
    config (RWRealisticAimingAngles);
    var bool ModInjected;
    event OnInit(UIScreen Screen) {
    if (ModInjected == false) {
    ModInjected = true;
    ReplaceStandardAimAlsoInAbilitiesWithUnusuallyDefinedHitCalc();}}
    //SOME ABILITIES CALL DEFAULT.SIMPLESTANDARDAIM INSTEAD OF CONVENTIONAL CLASS HABILITYTOHITCALC_STANDARDAIM
    static function ReplaceStandardAimAlsoInAbilitiesWithUnusuallyDefinedHitCalc() {
    local X2DataTemplate DataTemplate;
    local X2AbilityTemplate AbilityTemplate;
    // local X2AbilityToHitCalc_StandardAim OldAbilityToHitCalc;
    // local Override_X2AbilityToHitCalc_StandardAim NewAbilityToHitCalc;
    local X2AbilityToHitCalc_StandardAim AbilityToHitCalc;
    local X2AbilityToHitCalc_StandardMelee AbilityToHitCalcMelee;
    foreach class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager().IterateTemplates(DataTemplate, None) {
    AbilityTemplate = X2AbilityTemplate(DataTemplate);
    /* if (AbilityTemplate.AbilityToHitCalc.class == class'X2AbilityToHitCalc_StandardAim' ){//&&
    // AbilityTemplate.AbilityToHitCalc.class != class'X2AbilityToHitCalc_StandardMelee'){ //JUST IN CASE... _STANDARDMELEE IS THE (ONLY) CHILD OF _STANDARDMELEE...
    OldAbilityToHitCalc = X2AbilityToHitCalc_StandardAim(AbilityTemplate.AbilityToHitCalc);
    NewAbilityToHitCalc = new class'Override_X2AbilityToHitCalc_StandardAim';
    NewAbilityToHitCalc.HitModifiers = OldAbilityToHitCalc.HitModifiers; // Configured in the ability template to provide always-on modifiers.
    NewAbilityToHitCalc.bIndirectFire = OldAbilityToHitCalc.bIndirectFire; // Indirect fire is stuff like grenades. Hit chance is 100, but crit and dodge and armor mitigation still exists.
    NewAbilityToHitCalc.bMeleeAttack = OldAbilityToHitCalc.bMeleeAttack; // Melee attacks ignore cover and get their own instrinsic hit bonus.
    NewAbilityToHitCalc.bReactionFire = OldAbilityToHitCalc.bReactionFire; // Reaction fire suffers specific penalties to the hit roll. Reaction fire also causes the Flanking hit bonus to be ignored.
    NewAbilityToHitCalc.bAllowCrit = OldAbilityToHitCalc.bAllowCrit; // Ability will build crit into the hit table as applicable
    NewAbilityToHitCalc.bHitsAreCrits = OldAbilityToHitCalc.bHitsAreCrits; // After the roll is made, eHit_Success will always change into eHit_Crit
    NewAbilityToHitCalc.bMultiTargetOnly = OldAbilityToHitCalc.bMultiTargetOnly; // Guarantees a success for the ability when there is no primary target.
    NewAbilityToHitCalc.bOnlyMultiHitWithSuccess = OldAbilityToHitCalc.bOnlyMultiHitWithSuccess; // Multi hit targets will only be hit as long as there is a successful roll (e.g. Sharpshooter's Faceoff ability)
    NewAbilityToHitCalc.bGuaranteedHit = OldAbilityToHitCalc.bGuaranteedHit; // Skips all of the normal hit mods but does allow for armor mitigation rolls as normal.
    NewAbilityToHitCalc.bIgnoreCoverBonus = OldAbilityToHitCalc.bIgnoreCoverBonus; // Standard high/low cover bonuses do not apply
    NewAbilityToHitCalc.FinalMultiplier = OldAbilityToHitCalc.FinalMultiplier; // Modifier applied to otherwise final aim chance. Will calculate an amount and display the ability as the reason for the modifier.
    NewAbilityToHitCalc.BuiltInHitMod = OldAbilityToHitCalc.BuiltInHitMod; // Initial modifiers that are always used by the ability. ModReason will be the ability name.
    NewAbilityToHitCalc.BuiltInCritMod = OldAbilityToHitCalc.BuiltInCritMod; // Initial modifiers that are always used by the ability. ModReason will be the ability name.
    AbilityTemplate.AbilityToHitCalc = NewAbilityToHitCalc;
    if (AbilityTemplate.AbilityToHitOwnerOnMissCalc.class == class'X2AbilityToHitCalc_StandardAim'){ //ABILITIES ALSO HAVING .ABILITYTOHITOWNERONMISSCALC
    AbilityTemplate.AbilityToHitOwnerOnMissCalc = NewAbilityToHitCalc;}}}} //ALWAYS HAVE IT IDENTICAL TO .ABILITYTOHITCALC
    */ // if (AbilityTemplate.AbilityToHitCalc .Name == 'DefaultSimpleStandardAim') AbilityTemplate.AbilityToHitCalc = new class'Override_X2AbilityToHitCalc_StandardAim';
    // if (AbilityTemplate.AbilityToHitOwnerOnMissCalc.Name == 'DefaultSimpleStandardAim') AbilityTemplate.AbilityToHitOwnerOnMissCalc = new class'Override_X2AbilityToHitCalc_StandardAim';
    // if (AbilityTemplate.AbilityToHitCalc .Name == 'SimpleStandardAim') AbilityTemplate.AbilityToHitCalc = new class'Override_X2AbilityToHitCalc_StandardAim';
    // if (AbilityTemplate.AbilityToHitOwnerOnMissCalc.Name == 'SimpleStandardAim') AbilityTemplate.AbilityToHitOwnerOnMissCalc = new class'Override_X2AbilityToHitCalc_StandardAim';}}
    AbilityToHitCalc = X2AbilityToHitCalc_StandardAim(AbilityTemplate.AbilityToHitCalc); if (AbilityToHitCalc == None) continue;
    if (AbilityToHitCalc.bIndirectFire == true || //HITABILITIESTEMPLATE WITH THESE VARIABLES PRESENT
    AbilityToHitCalc.bReactionFire == true || //ALREADY CORRECTLY USE THE OVERRIDDEN HITABILITY CLASS
    AbilityToHitCalc.bAllowCrit == false || //WHILE THE REMAINING ONES USED AN UNCONVENTIONAL
    AbilityToHitCalc.bHitsAreCrits == true || //DEFINITION NOT REFERENCING DIRECTLY TO HABILITYTOHITCALC
    AbilityToHitCalc.bMultiTargetOnly == true || //AND THEREFORE USING THE UNOVERRIDDEN HITABILITY CLASS
    AbilityToHitCalc.bOnlyMultiHitWithSuccess == true || //... ?? ... ONLYMULTIHITWITHSUCCESS DEFINED ONLY ON SHARPSHOOTER'S FACEOFF ABILITY (AS FALSE)... BUT UNDEFINED BOOLS ARE ALWAYS FALSE... MAYBE FIRAXIS IS STILL "THINKING ABOUT IT"???
    AbilityToHitCalc.bGuaranteedHit == true ||
    AbilityToHitCalc.FinalMultiplier != 1 ||
    AbilityToHitCalc.BuiltInHitMod > 0 || //) continue;
    AbilityToHitCalc.BuiltInCritMod > 0 ||
    AbilityToHitCalc.bMeleeAttack == true ) continue; //BEFORE THE BMELEEATTACK WAS NOT SEEN AS TRUE WITH MY OVERRIDE (APPLYING THEREFORE COVER, GOODANGLE,ETC..)... STRANGE... SO TRIED TO ADD THIS LAST CHECK TO LEAVE THE X2ABILITYTOHIT_STANDARDMELEE ALONE...
    AbilityToHitCalcMelee = X2AbilityToHitCalc_StandardMelee(AbilityTemplate.AbilityToHitCalc); if (AbilityToHitCalcMelee != None) continue; //EVEN THIS LINE... JUST IN CASE X2ABILITYTOHITCALC_STANDARDMELEE'S FATHER (_STANDARDAIM) DOESNT SEE THE .BMELEEATTACK VARIABLES SET...
    AbilityTemplate.AbilityToHitCalc = new class'Override_X2AbilityToHitCalc_StandardAim';
    AbilityToHitCalc = X2AbilityToHitCalc_StandardAim(AbilityTemplate.AbilityToHitOwnerOnMissCalc); if (AbilityToHitCalc == None) continue;
    AbilityTemplate.AbilityToHitOwnerOnMissCalc = new class'Override_X2AbilityToHitCalc_StandardAim';}}
    // class'X2DataTemplateManager'.static.RebuildAllTemplateGameCaches();}
    defaultproperties {
    ModInjected = false;
    ScreenClass = none;}
  • file addition: PerfectInformation_X2Action_Fire.uc (---r------)
    [0.1208]
    class PerfectInformation_X2Action_Fire extends X2Action_Fire;
    var PerfectInformation_Observer CurrentVO;
    simulated state Executing
    {
    simulated function RaiseRollEvent()
    {
    local PerfectInformation_Notification NotifyEntry;
    local int TargetID;
    if (AbilityContext == none)
    return;
    `log("Pre block got context",, 'EUAimRollsVis');
    TargetID = -1;
    if (XGUnit(PrimaryTarget) != none)
    {
    TargetID = XGUnit(PrimaryTarget).ObjectID;
    }
    foreach CurrentVO.PendingNotifications(NotifyEntry)
    {
    if (NotifyEntry.StateRef == AbilityContext.InputContext.AbilityRef.ObjectID)
    {
    if (TargetID == NotifyEntry.RollTarget)
    {
    CurrentVO.PendingNotifications.RemoveItem(NotifyEntry);
    if (!class'Override_X2AbilityToHitCalc_StandardAim'.default.ShowOnlyForAllies || NotifyEntry.IsAlly)
    NotifyEntry.Notify();
    break;
    }
    }
    }
    }
    function HideFOW()
    {
    `log("Hide FOW Called",, 'EUAimRollsVis');
    super.HideFOW();
    CurrentVO = class'PerfectInformation_TacticalVisualizationManager'.static.GetCurrentVisObs();
    // if (CurrentVO != none && class'Override_X2AbilityToHitCalc_StandardAim'.default.DIRTY_CINEMATIC)
    if (CurrentVO != none && false )
    {
    RaiseRollEvent();
    }
    }
    }
  • file addition: PerfectInformation_TacticalVisualizationManager.uc (---r------)
    [0.1208]
    class PerfectInformation_TacticalVisualizationManager extends UIScreenListener;
    function UninitializeVisObs(PerfectInformation_Observer VOPanel)
    {
    if (VOPanel != none)
    {
    VOPanel.PendingNotifications.Length = 0;
    `XEVENTMGR.UnRegisterFromAllEvents(VOPanel);
    `XCOMVISUALIZATIONMGR.RemoveObserver(VOPanel);
    VOPanel.Remove();
    }
    }
    event OnInit(UIScreen Screen)
    {
    local PerfectInformation_Observer VisObs;
    VisObs = PerfectInformation_Observer(Screen.GetChildByName('EUAimRollPIListener', false));
    UninitializeVisObs(VisObs);
    VisObs = Screen.Spawn(class'PerfectInformation_Observer', Screen);
    VisObs.InitPanel('EUAimRollPIListener');
    VisObs.Hide();
    VisObs.InitObs();
    }
    static function PerfectInformation_Observer GetCurrentVisObs()
    {
    local UITacticalHUD tacHUD;
    local PerfectInformation_Observer VisObsR;
    if (`PRES == none)
    return none;
    tacHUD = UITacticalHUD(`PRES.ScreenStack.GetFirstInstanceOf(class'UITacticalHUD'));
    if (tacHUD == none)
    return none;
    VisObsR = PerfectInformation_Observer(tacHUD.GetChildByName('EUAimRollPIListener', false));
    `log("Found our VisObs", VisObsR != none, 'EUAimRollsVis');
    return VisObsR;
    }
    event OnRemoved(UIScreen Screen)
    {
    local PerfectInformation_Observer VisObs;
    VisObs = PerfectInformation_Observer(Screen.GetChildByName('EUAimRollPIListener'));
    UninitializeVisObs(VisObs);
    }
    defaultproperties
    {
    ScreenClass = class'UITacticalHUD';
    }
  • file addition: PerfectInformation_Observer.uc (---r------)
    [0.1208]
    class PerfectInformation_Observer extends UIPanel implements (X2VisualizationMgrObserverInterface);
    var array<PerfectInformation_Notification> PendingNotifications;
    var array<PerfectInformation_Notification> NotificationsToAssociate;
    function InitObs()
    {
    local Object ThisObj;
    `log("Initializing PERFECT INFORMATION",, 'EUAimRollsVis');
    ThisObj = self;
    `XCOMVISUALIZATIONMGR.RegisterObserver(self);
    //`XEVENTMGR.RegisterForEvent(ThisObj, 'AbilityActivated', ListenForAbilityGameState, ELD_Immediate);
    `XEVENTMGR.RegisterForEvent(ThisObj, 'RequestNotifyOnVisualization', OnNotificationRequested, ELD_Immediate);
    `XEVENTMGR.RegisterForEvent(ThisObj, 'PlayerTurnEnded', ClearAllNotifications, ELD_OnStateSubmitted); // Clean up extra rolls on turn end
    /* if (class'Override_X2AbilityToHitCalc_StandardAim'.default.DIRTY_CINEMATIC)
    {
    `XEVENTMGR.RegisterForEvent(ThisObj, 'AbilityActivated', OnNotifyBeforeVis, ELD_OnVisualizationBlockStarted);
    `PRES.m_kEventNotices.bShowDuringCinematic = true;
    }
    */ `log("Finshed initializing PERFECT INFORMATION",, 'EUAimRollsVis');
    }
    function EventListenerReturn ListenForAbilityGameState(Object EventData, Object EventSource, XComGameState NewGameState, Name EventID)
    {
    local PerfectInformation_Notification Notif;
    local Object NotifyObj;
    local int i;
    local XComGameState_Ability AbilityState;
    AbilityState = XComGameState_Ability(EventData);
    //`log("Event: AbilityActivated ID=" $ AbilityState.ObjectID,, 'EUAimRollsVis');
    if (XComGameStateContext_Ability(NewGameState.GetContext()) != none && NewGameState.GetNumGameStateObjects() > 0)
    {
    //`log("AbilityActivated is a XComGameStateContext_Ability:" @ XComGameStateContext_Ability(NewGameState.GetContext()).SummaryString(),, 'EUAimRollsVis');
    //`log("Context:" @ NewGameState.GetContext().ToString(),, 'EUAimRollsVis');
    for (i = 0; i < NotificationsToAssociate.Length; i++)
    {
    Notif = NotificationsToAssociate[i];
    if (Notif.StateRef == AbilityState.ObjectID)
    {
    //`log("Notif transferred for HACK event listener",, 'EUAimRollsVis');
    Notif.GameState = NewGameState;
    PendingNotifications.AddItem(Notif);
    NotifyObj = Notif;
    // `XEVENTMGR.RegisterForEvent(NotifyObj, 'HACK_VisualizeNotify', Notif.DisplayThisEvent, class'Override_X2AbilityToHitCalc_StandardAim'.default.DIRTY_CINEMATIC ? ELD_OnVisualizationBlockStarted : ELD_OnVisualizationBlockCompleted);
    `XEVENTMGR.RegisterForEvent(NotifyObj, 'HACK_VisualizeNotify', Notif.DisplayThisEvent, false ? ELD_OnVisualizationBlockStarted : ELD_OnVisualizationBlockCompleted);
    `XEVENTMGR.TriggerEvent('HACK_VisualizeNotify', self, Notif, NewGameState);
    //`log("Notif HACK completed",, 'EUAimRollsVis');
    NotificationsToAssociate.Remove(i, 1);
    i--;
    }
    }
    //if (j == 0)
    //{
    //`log("Generating empty HACK event listener",, 'EUAimRollsVis');
    //Notif = new class'PerfectInformation_Notification';
    //Notif.StateRef = AbilityState.ObjectID;
    //Notif.Message = "[No Notify]" @ NewGameState.GetContext().ToString();
    //Notif.IsAlly = true;
    //Notif.RollTarget = XComGameStateContext_Ability(NewGameState.GetContext()).InputContext.PrimaryTarget.ObjectID;
    //NotifyObj = Notif;
    //`XEVENTMGR.RegisterForEvent(NotifyObj, 'HACK_VisualizeNotify', Notif.DisplayThisEvent, class'Override_X2AbilityToHitCalc_StandardAim'.default.DIRTY_CINEMATIC ? ELD_OnVisualizationBlockStarted : ELD_OnVisualizationBlockCompleted);
    //`XEVENTMGR.RegisterForEvent(NotifyObj, 'HACK_VisualizeNotify2', Notif.DebugEvent, ELD_Immediate);
    //`XEVENTMGR.RegisterForEvent(NotifyObj, 'HACK_VisualizeNotify3', Notif.DebugEventSS, ELD_OnStateSubmitted);
    //`XEVENTMGR.TriggerEvent('HACK_VisualizeNotify', self, Notif, NewGameState);
    //`XEVENTMGR.TriggerEvent('HACK_VisualizeNotify2', self, Notif, NewGameState);
    //`XEVENTMGR.TriggerEvent('HACK_VisualizeNotify3', self, Notif, NewGameState);
    //`log("Notif HACK completed",, 'EUAimRollsVis');
    //}
    }
    return ELR_NoInterrupt;
    }
    function EventListenerReturn ClearAllNotifications(Object EventData, Object EventSource, XComGameState GameState, Name EventID, Object CallbackData)
    {
    PendingNotifications.Length = 0;
    NotificationsToAssociate.Length = 0;
    return ELR_NoInterrupt;
    }
    function EventListenerReturn OnNotifyBeforeVis(Object EventData, Object EventSource, XComGameState GameState, Name EventID, Object CallbackData)
    {
    local XComGameStateContext_Ability Context;
    local array<PerfectInformation_Notification> MatchedNotifications;
    local PerfectInformation_Notification NotifyEntry;
    if (GameState == none)
    return ELR_NoInterrupt;
    Context = XComGameStateContext_Ability(GameState.GetContext());
    `log("Pre block notified",, 'EUAimRollsVis');
    if (Context == none)
    return ELR_NoInterrupt;
    // if (class'Override_X2AbilityToHitCalc_StandardAim'.default.OVERWATCH_ABILITIES.Find(Context.InputContext.AbilityTemplateName) != INDEX_NONE)
    // return ELR_NoInterrupt;
    `log("Pre block got context",, 'EUAimRollsVis');
    foreach PendingNotifications(NotifyEntry)
    {
    if (NotifyEntry.StateRef == Context.InputContext.AbilityRef.ObjectID)
    {
    if (Context.InputContext.PrimaryTarget.ObjectID != NotifyEntry.RollTarget && Context.InputContext.MultiTargets.Find('ObjectID', NotifyEntry.RollTarget) == INDEX_NONE)
    {
    // This ability was used multiple times before the first visualization block, suppress irreleavant messages until its turn
    continue;
    }
    MatchedNotifications.AddItem(NotifyEntry);
    }
    }
    foreach MatchedNotifications(NotifyEntry)
    {
    PendingNotifications.RemoveItem(NotifyEntry);
    if (!class'Override_X2AbilityToHitCalc_StandardAim'.default.ShowOnlyForAllies || NotifyEntry.IsAlly)
    NotifyEntry.Notify();
    }
    return ELR_NoInterrupt;
    }
    function EventListenerReturn OnNotificationRequested(Object EventData, Object EventSource, XComGameState GameState, Name EventID, Object CallbackData)
    {
    local PerfectInformation_Notification Notification;
    Notification = PerfectInformation_Notification(EventData);
    `log("Notif event requested",, 'EUAimRollsVis');
    if (Notification != none)
    {
    //NotificationsToAssociate.AddItem(Notification);
    PendingNotifications.AddItem(Notification);
    }
    return ELR_NoInterrupt;
    }
    //function AddNotification(XComGameState_Ability GameState, String Message)
    //{
    //local PerfectInformation_Notification Notification;
    //Notification = new class'PerfectInformation_Notification';
    //Notification.StateRef = GameState.ObjectID;
    //Notification.Message = Message;
    //PendingNotifications.AddItem(Notification);
    //}
    event OnVisualizationBlockComplete(XComGameState AssociatedGameState)
    {
    local XComGameStateContext_Ability Context;
    local array<PerfectInformation_Notification> MatchedNotifications;
    local PerfectInformation_Notification NotifyEntry;
    Context = XComGameStateContext_Ability(AssociatedGameState.GetContext());
    // if (Context == none || class'Override_X2AbilityToHitCalc_StandardAim'.default.DIRTY_CINEMATIC)
    if (Context == none || false )
    return;
    foreach PendingNotifications(NotifyEntry)
    {
    if (NotifyEntry.StateRef == Context.InputContext.AbilityRef.ObjectID)
    {
    if (Context.InputContext.PrimaryTarget.ObjectID != NotifyEntry.RollTarget && Context.InputContext.MultiTargets.Find('ObjectID', NotifyEntry.RollTarget) == INDEX_NONE)
    {
    // This ability was used multiple times before the first visualization block, suppress irreleavant messages until its turn
    continue;
    }
    MatchedNotifications.AddItem(NotifyEntry);
    }
    }
    foreach MatchedNotifications(NotifyEntry)
    {
    PendingNotifications.RemoveItem(NotifyEntry);
    if (!class'Override_X2AbilityToHitCalc_StandardAim'.default.ShowOnlyForAllies || NotifyEntry.IsAlly)
    NotifyEntry.Notify();
    }
    }
    /// <summary>
    /// Called when the visualizer runs out of active and pending blocks, and becomes idle
    /// </summary>
    event OnVisualizationIdle();
    /// <summary>
    /// Called when the active unit selection changes
    /// </summary>
    event OnActiveUnitChanged(XComGameState_Unit NewActiveUnit);
  • file addition: PerfectInformation_Notification.uc (---r------)
    [0.1208]
    class PerfectInformation_Notification extends Object;
    var array<String> Message;
    var int StateRef;
    var bool IsAlly;
    var int RollTarget;
    var XComGameState GameState;
    var bool Used;
    function EventListenerReturn DisplayThisEvent(Object EventData, Object EventSource, XComGameState NewGameState, Name EventID, Object CallbackData)
    {
    //`log("Notif received visualization event",, 'EUAimRollsVis');
    if ((!class'Override_X2AbilityToHitCalc_StandardAim'.default.ShowOnlyForAllies || IsAlly) && !Used)
    {
    Used = true;
    Notify();
    }
    `XEVENTMGR.UnRegisterFromAllEvents(EventSource);
    return ELR_NoInterrupt;
    }
    function Notify()
    {
    local string s;
    foreach Message(s)
    {
    `PRES.Notify(s);
    }
    }
  • file addition: Override_X2AbilityToHitCalc_StandardAim.uc (---r------)
    [0.1208]
    class Override_X2AbilityToHitCalc_StandardAim
    extends X2AbilityToHitCalc_StandardAim
    config (RWRealisticAimingAngles);
    //extends X2AbilityToHitCalc
    //config(GameCore);
    //WATCHOUT!!! CHECK FOR FUNCTION PASSESWEAPONCHECK IN X2EVENTLISTENER_ABILITYPOINTS CLASS WHICH "SPECIFICALLY"
    //CHECKS FOR SPECIAL HITS FROM THE "UNOVERRIDDEN" X2ABILITYTOHITCALC_STANDARDAIM!!!
    //WHICH MEANS THAT THIS OVERRIDE COULD PREVENT WINNING SPECIAL ABILITYPOINTS...!!!
    //NO... IT SEEMS THAT ABILITYPOINTS ARE WON EVEN WITH THIS MOD... ;)
    /*
    ;PERFECT INFORMATION: MID-ACTION TEXT
    ShowChances = true
    ShowCriticalAndDodgeChances = true
    ShowDiceRolls = true
    ShowOnlyForAllies = false
    */
    //ADDED THIS PARAGRAPH!!!
    var config float MinimumGoodAngleBonusCoverReductionPercentage;
    var config float MaximumGoodAngleBonusCoverReductionPercentage;
    var config float MinimumGoodAngleBonusStartsAtThisHorizontalAngleBetweenLineOfFireAndCoverSurface;
    var config float MaximumGoodAngleBonusEndsAtThisHorizontalAngleBetweenLineOfFireAndCoverSurface;
    var config float MinimumHeightAdvantageBonusCoverReductionPercentage;
    var config float MaximumHeightAdvantageBonusCoverReductionPercentage;
    var config float MinimumHeightAdvantageBonusStartsAtThisVerticalAngleBetweenLineOfFireAndCoverSurface;
    var config float MaximumHeightAdvantageBonusEndsAtThisVerticalAngleBetweenLineOfFireAndCoverSurface;
    var config bool ApplyGoodAngleBonusNotOnlyForXComSoldiersButAlsoForAnyoneShooting;
    var config bool ApplyGoodAngleBonusEvenFartherThan11TilesAway;
    var config float TargetingObjectsRealisticallyAllowsToMissThemAndUsesConventionalHitChanceStatsPlusThisAimingBonus;
    var config bool ApplyVerticalGoodAngleAgainstLowerTargetAsProportionalHeightAdvantage;
    var config bool ApplyVerticalBadAngleAgainstHigherTargetAsProportionalHeightDisadvantage;
    var config bool AllowFarCoverToGiveSomeCoverProtection;
    var config bool GiveHitChanceZeroWhenTargetableEnemiesAreInsteadNotTrulyInLineOfSight;
    var config bool OnlyAlertedTargetsCanHaveTheExtraProtectionOfFarCoverAndHeightDisadvantage;
    var float FarCoverBonus;
    var bool ShowChances;
    var bool ShowCriticalAndDodgeChances;
    var bool ShowDiceRolls;
    var bool ShowOnlyForAllies;
    var bool UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance;
    var bool PrioritizeCriticalChanceOverDodgeChance;
    var bool AlwaysRollForBothDodgeAndCriticalEvenWhenOneUnsuccesful;
    var bool GuaranteedHitsCannotDodge;
    var bool IndirectFireGuaranteesHit;
    var bool EnableGamblerFallacySystemRoll;
    //END OF ADDED PARAGRAPH!!!
    //static function StaticInternalRollForAbilityHit(X2AbilityToHitCalc_StandardAim Aim, XComGameState_Ability kAbility, AvailableTarget kTarget, bool bIsPrimaryTarget, const out AbilityResultContext ResultContext, out EAbilityHitResult Result, out ArmorMitigationResults ArmorMitigated, out int HitChance)
    function InternalRollForAbilityHit( XComGameState_Ability kAbility, AvailableTarget kTarget, bool bIsPrimaryTarget, const out AbilityResultContext ResultContext, out EAbilityHitResult Result, out ArmorMitigationResults ArmorMitigated, out int HitChance)
    {
    local int i, RandRoll, Current, ModifiedHitChance;
    local EAbilityHitResult DebugResult, ChangeResult;
    local ArmorMitigationResults Armor;
    local XComGameState_Unit TargetState, UnitState;
    local XComGameState_Player PlayerState;
    local XComGameStateHistory History;
    local StateObjectReference EffectRef;
    local XComGameState_Effect EffectState;
    local bool bRolledResultIsAMiss, bModHitRoll;
    local bool HitsAreCrits;
    local string LogMsg;
    local ETeam CurrentPlayerTeam;
    local ShotBreakdown m_ShotBreakdown;
    //ADDED THIS PARAGRAPH!!!
    local int OriginalHitRoll;
    local float DodgeChance;
    local String AbilityName;
    local String TargetName;
    local bool IsAlien;
    local array<string> PINotify;
    local int RealHitChance;
    local int TotalHitChance;
    local string DebugRollOutput;
    //END OF ADDED PARAGRAPH!!!
    History = `XCOMHISTORY;
    `log("===" $ GetFuncName() $ "===", true, 'XCom_HitRolls');
    `log("Attacker ID:" @ kAbility.OwnerStateObject.ObjectID, true, 'XCom_HitRolls');
    `log("Target ID:" @ kTarget.PrimaryTarget.ObjectID, true, 'XCom_HitRolls');
    `log("Ability:" @ kAbility.GetMyTemplate().LocFriendlyName @ "(" $ kAbility.GetMyTemplateName() $ ")", true, 'XCom_HitRolls');
    ArmorMitigated = Armor; // clear out fields just in case
    HitsAreCrits = bHitsAreCrits;
    if (`CHEATMGR != none)
    {
    if (`CHEATMGR.bForceCritHits)
    HitsAreCrits = true;
    if (`CHEATMGR.bNoLuck)
    {
    `log("NoLuck cheat forcing a miss.", true, 'XCom_HitRolls');
    Result = eHit_Miss;
    return;
    }
    if (`CHEATMGR.bDeadEye)
    {
    UnitState = XComGameState_Unit(History.GetGameStateForObjectID(kAbility.OwnerStateObject.ObjectID));
    // if( !`CHEATMGR.bXComOnlyDeadEye || !UnitState.ControllingPlayerIsAI() )
    if( !`CHEATMGR.bXComOnlyDeadEye || !UnitState.ControllingPlayerIsAI() || default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == true)
    {
    `log("DeadEye cheat forcing a hit.", true, 'XCom_HitRolls');
    Result = eHit_Success;
    if( HitsAreCrits )
    Result = eHit_Crit;
    return;
    }
    }
    }
    HitChance = GetHitChance(kAbility, kTarget, m_ShotBreakdown, true);
    // RandRoll = `SYNC_RAND_TYPED(100, ESyncRandType_Generic);
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == false) RandRoll = `SYNC_RAND_TYPED(100, ESyncRandType_Generic);
    Result = eHit_Miss;
    `log("=" $ GetFuncName() $ "=", true, 'XCom_HitRolls');
    `log("Final hit chance:" @ HitChance, true, 'XCom_HitRolls');
    //ADDED THIS PARAGRAPH!!!
    //HEART OF EUROLLS INJECTION FROM XCOM1
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance)
    {
    UnitState = XComGameState_Unit(History.GetGameStateForObjectID(kAbility.OwnerStateObject.ObjectID));
    TargetState = XComGameState_Unit(History.GetGameStateForObjectID(kTarget.PrimaryTarget.ObjectID));
    IsAlien = UnitState.GetTeam() != eTeam_XCom;
    // Revert real hit chance manipulated by FinalizeHitChance()
    RealHitChance = Clamp(HitChance, 0, 100);
    // Roll for hit
    if (default.EnableGamblerFallacySystemRoll)
    {
    // RandRoll = class'XComGameState_GamblerRolls'.static.StaticRoll(RealHitChance, false, false, IsAlien);
    }
    else
    {
    RandRoll = class'Engine'.static.GetEngine().SyncRand(100, string(Name)@string(GetStateName())@string(GetFuncName()));
    }
    OriginalHitRoll = RandRoll;
    DebugResult = EAbilityHitResult(eHit_Success);
    `log("Checking table" @ DebugResult @ "(" $ RealHitChance $ ")...", true, 'XCom_HitRolls');
    `log("Random roll:" @ RandRoll, true, 'XCom_HitRolls');
    DebugRollOutput = "Hit roll:"@RandRoll;
    }
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance)
    {
    TotalHitChance = RealHitChance;
    // EU aim rolls
    if (RandRoll < RealHitChance)
    {
    Result = eHit_Success;
    `log("MATCH!", true, 'XCom_HitRolls');
    // Hits, now roll for crits (Super priority)
    if (default.PrioritizeCriticalChanceOverDodgeChance)
    {
    if (default.EnableGamblerFallacySystemRoll)
    {
    // RandRoll = class'XComGameState_GamblerRolls'.static.StaticRoll(m_ShotBreakdown.ResultTable[eHit_Crit], true, false, IsAlien);
    }
    else
    {
    RandRoll = class'Engine'.static.GetEngine().SyncRand(100, string(Name)@string(GetStateName())@string(GetFuncName()));
    }
    DebugResult = EAbilityHitResult(eHit_Crit);
    if (default.ShowCriticalAndDodgeChances)
    {
    DebugRollOutput = DebugRollOutput@", Crit roll:"@RandRoll;
    }
    `log("Checking table" @ DebugResult @ "(" $ m_ShotBreakdown.ResultTable[eHit_Crit] $ ")...", true, 'XCom_HitRolls');
    `log("Random roll:" @ RandRoll, true, 'XCom_HitRolls');
    if (RandRoll < m_ShotBreakdown.ResultTable[eHit_Crit])
    {
    Result = eHit_Crit;
    `log("MATCH!", true, 'XCom_HitRolls');
    if (default.AlwaysRollForBothDodgeAndCriticalEvenWhenOneUnsuccesful && m_ShotBreakdown.ResultTable[eHit_Graze] > 0)
    {
    if (default.EnableGamblerFallacySystemRoll)
    {
    // RandRoll = class'XComGameState_GamblerRolls'.static.StaticRoll(m_ShotBreakdown.ResultTable[eHit_Graze] * 100 / RealHitChance, false, true, IsAlien) * 100 / RealHitChance;
    }
    else
    {
    RandRoll = class'Engine'.static.GetEngine().SyncRand(RealHitChance, string(Name)@string(GetStateName())@string(GetFuncName()));
    }
    DebugResult = EAbilityHitResult(eHit_Graze);
    if (default.ShowCriticalAndDodgeChances && m_ShotBreakdown.ResultTable[eHit_Graze] > 0)
    {
    DebugRollOutput = DebugRollOutput@", Dodge roll:"@RandRoll;
    }
    `log("Checking table" @ DebugResult @ "(" $ m_ShotBreakdown.ResultTable[eHit_Graze] $ ")...", true, 'XCom_HitRolls');
    `log("Random roll over hit chance:" @ RandRoll, true, 'XCom_HitRolls');
    // Roll dodge over hit chance (Because of a function earlier multiplied dodge chance by actual hit chance)
    if (RandRoll < m_ShotBreakdown.ResultTable[eHit_Graze])
    {
    Result = eHit_Success; // Dodge cancels crit and becomes a standard hit.
    `log("MATCH!", true, 'XCom_HitRolls');
    }
    }
    }
    else if (m_ShotBreakdown.ResultTable[eHit_Graze] > 0)
    {
    if (default.EnableGamblerFallacySystemRoll)
    {
    // RandRoll = class'XComGameState_GamblerRolls'.static.StaticRoll(m_ShotBreakdown.ResultTable[eHit_Graze] * 100 / RealHitChance, false, true, IsAlien) * 100 / RealHitChance;
    }
    else
    {
    RandRoll = class'Engine'.static.GetEngine().SyncRand(RealHitChance, string(Name)@string(GetStateName())@string(GetFuncName()));
    }
    DebugResult = EAbilityHitResult(eHit_Graze);
    if (default.ShowCriticalAndDodgeChances && m_ShotBreakdown.ResultTable[eHit_Graze] > 0)
    {
    DebugRollOutput = DebugRollOutput@", Dodge roll:"@RandRoll;
    }
    `log("Checking table" @ DebugResult @ "(" $ m_ShotBreakdown.ResultTable[eHit_Graze] $ ")...", true, 'XCom_HitRolls');
    `log("Random roll over hit chance:" @ RandRoll, true, 'XCom_HitRolls');
    // Roll dodge over hit chance (Because of a function earlier multiplied dodge chance by actual hit chance)
    if (RandRoll < m_ShotBreakdown.ResultTable[eHit_Graze])
    {
    Result = eHit_Graze;
    `log("MATCH!", true, 'XCom_HitRolls');
    }
    }
    }
    else
    {
    if (default.EnableGamblerFallacySystemRoll && m_ShotBreakdown.ResultTable[eHit_Graze] > 0)
    {
    // RandRoll = class'XComGameState_GamblerRolls'.static.StaticRoll(m_ShotBreakdown.ResultTable[eHit_Graze] * 100 / RealHitChance, false, true, IsAlien) * 100 / RealHitChance;
    }
    else
    {
    RandRoll = class'Engine'.static.GetEngine().SyncRand(RealHitChance, string(Name)@string(GetStateName())@string(GetFuncName()));
    }
    DebugResult = EAbilityHitResult(eHit_Graze);
    if (default.ShowCriticalAndDodgeChances && m_ShotBreakdown.ResultTable[eHit_Graze] > 0)
    {
    DebugRollOutput = DebugRollOutput@", Dodge roll:"@RandRoll;
    }
    `log("Checking table" @ DebugResult @ "(" $ m_ShotBreakdown.ResultTable[eHit_Graze] $ ")...", true, 'XCom_HitRolls');
    `log("Random roll over hit chance:" @ RandRoll, true, 'XCom_HitRolls');
    // Roll dodge over hit chance (Because of a function earlier multiplied dodge chance by actual hit chance)
    if (RandRoll < m_ShotBreakdown.ResultTable[eHit_Graze])
    {
    Result = eHit_Graze;
    `log("MATCH!", true, 'XCom_HitRolls');
    if (default.AlwaysRollForBothDodgeAndCriticalEvenWhenOneUnsuccesful)
    {
    if (default.EnableGamblerFallacySystemRoll)
    {
    // RandRoll = class'XComGameState_GamblerRolls'.static.StaticRoll(m_ShotBreakdown.ResultTable[eHit_Crit], true, false, IsAlien);
    }
    else
    {
    RandRoll = class'Engine'.static.GetEngine().SyncRand(100, string(Name)@string(GetStateName())@string(GetFuncName()));
    }
    DebugResult = EAbilityHitResult(eHit_Crit);
    if (default.ShowCriticalAndDodgeChances)
    {
    DebugRollOutput = DebugRollOutput@", Crit roll:"@RandRoll;
    }
    `log("Checking table" @ DebugResult @ "(" $ m_ShotBreakdown.ResultTable[eHit_Crit] $ ")...", true, 'XCom_HitRolls');
    `log("Random roll:" @ RandRoll, true, 'XCom_HitRolls');
    if (RandRoll < m_ShotBreakdown.ResultTable[eHit_Crit])
    {
    Result = eHit_Success; // Crit cancels dodge and becomes a standard hit.
    `log("MATCH!", true, 'XCom_HitRolls');
    }
    }
    }
    else
    {
    if (default.EnableGamblerFallacySystemRoll)
    {
    // RandRoll = class'XComGameState_GamblerRolls'.static.StaticRoll(m_ShotBreakdown.ResultTable[eHit_Crit], true, false, IsAlien);
    }
    else
    {
    RandRoll = class'Engine'.static.GetEngine().SyncRand(100, string(Name)@string(GetStateName())@string(GetFuncName()));
    }
    DebugResult = EAbilityHitResult(eHit_Crit);
    if (default.ShowCriticalAndDodgeChances)
    {
    DebugRollOutput = DebugRollOutput@", Crit roll:"@RandRoll;
    }
    `log("Checking table" @ DebugResult @ "(" $ m_ShotBreakdown.ResultTable[eHit_Crit] $ ")...", true, 'XCom_HitRolls');
    `log("Random roll:" @ RandRoll, true, 'XCom_HitRolls');
    if (RandRoll < m_ShotBreakdown.ResultTable[eHit_Crit])
    {
    Result = eHit_Crit;
    `log("MATCH!", true, 'XCom_HitRolls');
    }
    }
    }
    }
    }
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == false)
    {
    TotalHitChance = m_ShotBreakdown.ResultTable[eHit_Success] + m_ShotBreakdown.ResultTable[eHit_Crit] + m_ShotBreakdown.ResultTable[eHit_Graze];
    TotalHitChance = Clamp(TotalHitChance, 0, 100);
    // Vanilla aim rolls
    Result = eHit_Miss;
    //THIS ABOVE WAS THE HEART OF EUROLLS INJECTION...
    //END OF ADDED PARAGRAPH!!
    `log("Random roll:" @ RandRoll, true, 'XCom_HitRolls');
    // GetHitChance fills out m_ShotBreakdown and its ResultTable
    for (i = 0; i < eHit_Miss; ++i) // If we don't match a result before miss, then it's a miss.
    {
    Current += m_ShotBreakdown.ResultTable[i];
    DebugResult = EAbilityHitResult(i);
    `log("Checking table" @ DebugResult @ "(" $ Current $ ")...", true, 'XCom_HitRolls');
    if (RandRoll < Current)
    {
    Result = EAbilityHitResult(i);
    `log("MATCH!", true, 'XCom_HitRolls');
    break;
    }
    }
    } //ADDED THIS LINE!!!
    if (HitsAreCrits && Result == eHit_Success)
    Result = eHit_Crit;
    // UnitState = XComGameState_Unit(History.GetGameStateForObjectID(kAbility.OwnerStateObject.ObjectID));
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == false) UnitState = XComGameState_Unit(History.GetGameStateForObjectID(kAbility.OwnerStateObject.ObjectID));
    // TargetState = XComGameState_Unit(History.GetGameStateForObjectID(kTarget.PrimaryTarget.ObjectID));
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == false) TargetState = XComGameState_Unit(History.GetGameStateForObjectID(kTarget.PrimaryTarget.ObjectID));
    //ADDED THIS PARAGRAPH!!!
    if (default.GuaranteedHitsCannotDodge && (bIndirectFire || bGuaranteedHit || TargetState == none)) // No target states are supposed to be guarantee hits
    {
    if (Result == eHit_Graze)
    Result = eHit_Success;
    }
    if (default.IndirectFireGuaranteesHit && bIndirectFire)
    {
    if (Result == eHit_Miss) // Countering the unintended effect of graze band for LW2
    Result = eHit_Success;
    }
    if (default.ShowChances && !bIndirectFire && !bGuaranteedHit && TargetState != none)
    {
    TargetName = TargetState.GetFullName();
    AbilityName = kAbility.GetMyFriendlyName();
    if (AbilityName == "")
    {
    AbilityName = string(kAbility.GetMyTemplateName());
    }
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance)
    {
    DodgeChance = (m_ShotBreakdown.ResultTable[eHit_Graze] * 100.00) / RealHitChance;
    DodgeChance = Clamp(DodgeChance, 0, 100);
    PINotify.AddItem(UnitState.GetFullName()@"uses"@AbilityName@"against"@TargetName@"for"@RealHitChance$"%."
    @ default.ShowCriticalAndDodgeChances ? "Crit:" @ m_ShotBreakdown.ResultTable[eHit_Crit] $ "%, Dodge:"
    @ Round(DodgeChance) $ "%" : "");
    }
    else
    {
    PINotify.AddItem(UnitState.GetFullName()@"uses"@AbilityName@"against"@TargetName@"for"
    @ RealHitChance$"%." $ (RealHitChance != TotalHitChance ? "(" $ TotalHitChance $ "%)" : "")
    @ default.ShowCriticalAndDodgeChances ? "Crit:" @ m_ShotBreakdown.ResultTable[eHit_Crit] $ "%, Dodge:"
    @ m_ShotBreakdown.ResultTable[eHit_Graze] $ "% Roll thresold:"
    @ m_ShotBreakdown.ResultTable[eHit_Success] $ "/"
    $ m_ShotBreakdown.ResultTable[eHit_Success] + m_ShotBreakdown.ResultTable[eHit_Crit] $ "/"
    $ TotalHitChance : "");
    }
    if (default.ShowDiceRolls)
    {
    PINotify.AddItem(DebugRollOutput);
    }
    }
    //END OF ADDED PARAGRAPH!!!
    if (UnitState != none && TargetState != none)
    {
    foreach UnitState.AffectedByEffects(EffectRef)
    {
    EffectState = XComGameState_Effect(History.GetGameStateForObjectID(EffectRef.ObjectID));
    if (EffectState != none)
    {
    if (EffectState.GetX2Effect().ChangeHitResultForAttacker(UnitState, TargetState, kAbility, Result, ChangeResult))
    {
    `log("Effect" @ EffectState.GetX2Effect().FriendlyName @ "changing hit result for attacker:" @ ChangeResult,true,'XCom_HitRolls');
    Result = ChangeResult;
    //ADDED THIS LINE!!!
    if (default.ShowChances && default.ShowDiceRolls) PINotify.AddItem(UnitState.GetFullName()@"used an effect to change hit result to"@ ChangeResult);
    }
    }
    }
    foreach TargetState.AffectedByEffects(EffectRef)
    {
    EffectState = XComGameState_Effect(History.GetGameStateForObjectID(EffectRef.ObjectID));
    if (EffectState != none)
    {
    if (EffectState.GetX2Effect().ChangeHitResultForTarget(EffectState, UnitState, TargetState, kAbility, bIsPrimaryTarget, Result, ChangeResult))
    {
    `log("Effect" @ EffectState.GetX2Effect().FriendlyName @ "changing hit result for target:" @ ChangeResult, true, 'XCom_HitRolls');
    Result = ChangeResult;
    //ADDED THIS LINE!!!
    if (default.ShowChances && default.ShowDiceRolls) PINotify.AddItem(TargetState.GetFullName()@"has an effect that changes hit result to"@ ChangeResult);
    }
    }
    }
    }
    // Aim Assist (miss streak prevention)
    bRolledResultIsAMiss = class'XComGameStateContext_Ability'.static.IsHitResultMiss(Result);
    // reaction fire shots and guaranteed hits do not get adjusted for difficulty
    if( UnitState != None &&
    !bReactionFire &&
    !bGuaranteedHit &&
    m_ShotBreakdown.SpecialGuaranteedHit == '')
    {
    PlayerState = XComGameState_Player(History.GetGameStateForObjectID(UnitState.GetAssociatedPlayerID()));
    CurrentPlayerTeam = PlayerState.GetTeam();
    if( bRolledResultIsAMiss && CurrentPlayerTeam == eTeam_XCom )
    {
    ModifiedHitChance = GetModifiedHitChanceForCurrentDifficulty(PlayerState, TargetState, HitChance);
    //ADDED THIS PARAGRAPH!!!
    if (default.ShowChances && ModifiedHitChance != HitChance && !bIndirectFire && !bGuaranteedHit && TargetState != none)
    {
    PINotify.AddItem("Aim assist modified hit chance to"@ModifiedHitChance$"%, using previous hit roll.");
    }
    //END OF ADDED PARAGRAPH!!!
    //ADDED THIS PARAGRAPH!!!
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == true)
    {
    if( ModifiedHitChance != HitChance && OriginalHitRoll < ModifiedHitChance )
    {
    Result = eHit_Success;
    bModHitRoll = true;
    `log("*** AIM ASSIST forcing an XCom MISS to become a HIT!", true, 'XCom_HitRolls');
    }
    }
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == false)
    {
    //END OF ADDED PARAGRAPH!!!
    if( RandRoll < ModifiedHitChance )
    {
    Result = eHit_Success;
    bModHitRoll = true;
    `log("*** AIM ASSIST forcing an XCom MISS to become a HIT!", true, 'XCom_HitRolls');
    }
    } //ADDED THIS LINE!!!
    }
    else if( !bRolledResultIsAMiss && (CurrentPlayerTeam == eTeam_Alien || CurrentPlayerTeam == eTeam_TheLost) )
    {
    ModifiedHitChance = GetModifiedHitChanceForCurrentDifficulty(PlayerState, TargetState, HitChance);
    //ADDED THIS PARAGRAPH!!!
    if (default.ShowChances && ModifiedHitChance != HitChance && !bIndirectFire && !bGuaranteedHit && TargetState != none)
    {
    PINotify.AddItem("Aim assist modified hit chance to"@ModifiedHitChance$"%, using previous hit roll.");
    }
    //END OF ADDED PARAGRAPH!!!
    //ADDED THIS PARAGRAPH!!!
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == true)
    {
    if( ModifiedHitChance != HitChance && OriginalHitRoll >= ModifiedHitChance )
    {
    Result = eHit_Miss;
    bModHitRoll = true;
    `log("*** AIM ASSIST forcing an Alien HIT to become a MISS!", true, 'XCom_HitRolls');
    }
    }
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance == false)
    {
    //END OF ADDED PARAGRAPH!!!
    if( RandRoll >= ModifiedHitChance )
    {
    Result = eHit_Miss;
    bModHitRoll = true;
    `log("*** AIM ASSIST forcing an Alien HIT to become a MISS!", true, 'XCom_HitRolls');
    }
    } //ADDED THIS LINE!!!
    }
    }
    /* if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance) */ NotifyEventList(kAbility, kTarget, PINotify, !IsAlien); //ADDED THIS LINE!!!
    `log("***HIT" @ Result, !bRolledResultIsAMiss, 'XCom_HitRolls');
    `log("***MISS" @ Result, bRolledResultIsAMiss, 'XCom_HitRolls');
    if (TargetState != none)
    {
    // Check for Lightning Reflexes
    if (bReactionFire && TargetState.bLightningReflexes && !bRolledResultIsAMiss)
    {
    Result = eHit_LightningReflexes;
    `log("Lightning Reflexes triggered! Shot will miss.", true, 'XCom_HitRolls');
    }
    //ADDED THIS LINE!!!
    if (default.UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance) class'X2AbilityArmorHitRolls'.static.RollArmorMitigation(m_ShotBreakdown.ArmorMitigation, ArmorMitigated, TargetState); // add armor mitigation (regardless of hit/miss as some shots deal damage on a miss)
    }
    if (UnitState != none && TargetState != none)
    {
    LogMsg = class'XLocalizedData'.default.StandardAimLogMsg;
    LogMsg = repl(LogMsg, "#Shooter", UnitState.GetName(eNameType_RankFull));
    LogMsg = repl(LogMsg, "#Target", TargetState.GetName(eNameType_RankFull));
    LogMsg = repl(LogMsg, "#Ability", kAbility.GetMyTemplate().LocFriendlyName);
    LogMsg = repl(LogMsg, "#Chance", bModHitRoll ? ModifiedHitChance : HitChance);
    LogMsg = repl(LogMsg, "#Roll", RandRoll);
    LogMsg = repl(LogMsg, "#Result", class'X2TacticalGameRulesetDataStructures'.default.m_aAbilityHitResultStrings[Result]);
    `COMBATLOG(LogMsg);
    }
    }
    //ADDED THIS PARAGRAPH!!!
    static function NotifyEventList(XComGameState_Ability kAbility, AvailableTarget kTarget, array<String> message, optional bool IsXCOM=true)
    {
    local PerfectInformation_Notification Notification;
    Notification = new class'PerfectInformation_Notification';
    Notification.StateRef = kAbility.ObjectID;
    Notification.Message = message;
    Notification.IsAlly = IsXCOM;
    Notification.RollTarget = kTarget.PrimaryTarget.ObjectID;
    `XEVENTMGR.TriggerEvent('RequestNotifyOnVisualization', Notification);
    }
    //END OF ADDED PARAGRAPH!!!
    protected function int GetHitChance(XComGameState_Ability kAbility, AvailableTarget kTarget, optional out ShotBreakdown m_ShotBreakdown, optional bool bDebugLog = false)
    {
    local XComGameState_Unit UnitState, TargetState;
    local XComGameState_Item SourceWeapon;
    local GameRulesCache_VisibilityInfo VisInfo;
    local array<X2WeaponUpgradeTemplate> WeaponUpgrades;
    local int i, iWeaponMod, iRangeModifier, Tiles;
    local ShotBreakdown EmptyShotBreakdown;
    local array<ShotModifierInfo> EffectModifiers;
    local StateObjectReference EffectRef;
    local XComGameState_Effect EffectState;
    local XComGameStateHistory History;
    local bool bFlanking, bIgnoreGraze, bSquadsight;
    local string IgnoreGrazeReason;
    local X2AbilityTemplate AbilityTemplate;
    local array<XComGameState_Effect> StatMods;
    local array<float> StatModValues;
    local X2Effect_Persistent PersistentEffect;
    local array<X2Effect_Persistent> UniqueToHitEffects;
    local float FinalAdjust, CoverValue, AngleToCoverModifier, Alpha;
    local bool bShouldAddAngleToCoverBonus;
    local TTile UnitTileLocation, TargetTileLocation;
    local ECoverType NextTileOverCoverType;
    local int TileDistance;
    //ADDED THIS PARAGRAPH!!!
    local TTile ShooterTile;
    local TTile TargetTile;
    local TTile ShooterHead;
    local TTile TargetHead;
    local TTile ShooterTorso;
    // local TTile TargetTorso;
    local TTile TargetLegs;
    local TTile ShooterBelowFeet;
    local float ShooterTargetDistance;
    local float ShooterHeadRelativeElevation;
    local float VerticalAngle;
    local float GoodAngleBonus;
    local float ExtendedLowCoverPreventingGoodAngleBonus;
    local float HeightAdvantageBonus; //ALWAYS FLOATS INSTEAD OF INTS!!!!
    local float HeightDisadvantageMalus; //OR YOU WILL LOOSE HOURS TRYING TO UNDERSTAND WHY
    local float NoLineOfSightMalus; //THEY DIDN'T APPLY MULTIPLIERS!!! BECAUSE INT AUTO-ROUND!!! MOTHERFUCKERS!!!
    local string FarCoverText;
    local TTile NextTile;
    local int FarCover;
    local GameRulesCache_VisibilityInfo VisibilityInfo;
    // local XComGameState NewGameStateForDestructibleObject;
    // local XComGameState_Destructible TargetStateDestructibleObject;
    local ECoverType CoverTypeOfTileAboveTarget;
    //END OF ADDED PARAGRAPH!!!
    `log("=" $ GetFuncName() $ "=", bDebugLog, 'XCom_HitRolls');
    // @TODO gameplay handle non-unit targets
    History = `XCOMHISTORY;
    UnitState = XComGameState_Unit(History.GetGameStateForObjectID( kAbility.OwnerStateObject.ObjectID ));
    TargetState = XComGameState_Unit(History.GetGameStateForObjectID( kTarget.PrimaryTarget.ObjectID ));
    //ADDED THIS PARAGRAPH!!!
    // ShooterLocation = `XWORLD.GetPositionFromTileCoordinates(ShooterTile);
    // TargetLocation = `XWORLD.GetPositionFromTileCoordinates(TargetTile);
    UnitState .GetKeystoneVisibilityLocation(ShooterTile);
    TargetState.GetKeystoneVisibilityLocation(TargetTile );
    `TACTICALRULES.VisibilityMgr.GetVisibilityInfo(UnitState.ObjectID, TargetState.ObjectID, VisInfo);
    CoverTypeOfTileAboveTarget = CoverTypeOfTileAboveCover (ShooterTile, TargetTile, VisInfo.TargetCoverAngle);
    NextTileOverCoverType = NextTileOverCoverInSameDirection(ShooterTile, TargetTile);
    GoodAngleBonus = 0; //JUST IN CASE... WIERD BEHAVIOR
    //END OF ADDED PARAGRAPH!!!
    if (kAbility != none)
    {
    AbilityTemplate = kAbility.GetMyTemplate();
    SourceWeapon = kAbility.GetSourceWeapon();
    }
    // reset shot breakdown
    m_ShotBreakdown = EmptyShotBreakdown;
    // check for a special guaranteed hit
    m_ShotBreakdown.SpecialGuaranteedHit = UnitState.CheckSpecialGuaranteedHit(kAbility, SourceWeapon, TargetState);
    m_ShotBreakdown.SpecialCritLabel = UnitState.CheckSpecialCritLabel(kAbility, SourceWeapon, TargetState);
    // add all of the built-in modifiers
    if (bGuaranteedHit || m_ShotBreakdown.SpecialGuaranteedHit != '')
    {
    // call the super version to bypass our check to ignore success mods for guaranteed hits
    super .AddModifier(100, AbilityTemplate.LocFriendlyName, m_ShotBreakdown, eHit_Success, bDebugLog); //WATCHOUT!!! SUPER. IS NOT ANYMORE THE PARENT
    super(X2AbilitytoHitCalc).AddModifier(100, AbilityTemplate.LocFriendlyName, m_ShotBreakdown, eHit_Success, bDebugLog); //OF ABILITYTOHIT_STANDARDAIM BUT BUT THE PARENT
    }
    else if (bIndirectFire)
    {
    m_ShotBreakdown.HideShotBreakdown = true;
    AddModifier(100, AbilityTemplate.LocFriendlyName, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    AddModifier(BuiltInHitMod, AbilityTemplate.LocFriendlyName, m_ShotBreakdown, eHit_Success, bDebugLog);
    AddModifier(BuiltInCritMod, AbilityTemplate.LocFriendlyName, m_ShotBreakdown, eHit_Crit, bDebugLog);
    if (UnitState != none && TargetState == none)
    {
    //ADDED THIS PARAGRAPH!!! (GUARANTEED HIT MY ASS...)
    /* TargetingObjectsRealisticallyAllowsToMissThemAndUsesConventionalHitChanceStatsPlusThisAimingBonus = 15
    if(default.TargetingObjectsRealisticallyAllowsToMissThemAndUsesConventionalHitChanceStatsPlusThisAimingBonus != 100) {
    TargetStateDestructibleObject = XComGameState_Destructible(History.GetGameStateForObjectID( kTarget.PrimaryTarget.ObjectID ));
    NewGameStateForDestructibleObject = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Conversion From Unit to Destructible for Aiming Stats");
    TargetState = XComGameState_Unit(NewGameStateForDestructibleObject.CreateNewStateObject(class'XComGameState_Unit'));
    TargetState.SetVisibilityLocation(TargetStateDestructibleObject.TileLocation); //KEYSTONEVISIBILITYLOCATION EVEN FOR OBJECTS??? REMEMBER HOW .TILELOCATION WAS BUGGY FOR UNITS!!!!
    AddModifier(default.TargetingObjectsRealisticallyAllowsToMissThemAndUsesConventionalHitChanceStatsPlusThisAimingBonus, class'XLocalizedData'.default.DefenseStat, m_ShotBreakdown, eHit_Success, bDebugLog);}
    else {
    */ //END OF ADDED PARAGRAPH!!!
    // when targeting non-units, we have a 100% chance to hit. They can't dodge or otherwise
    // mess up our shots
    m_ShotBreakdown.HideShotBreakdown = true;
    AddModifier(100 , class'XLocalizedData'.default.OffenseStat, m_ShotBreakdown, eHit_Success, bDebugLog);
    // } //ADDED THIS LINE!!!
    }
    else if (UnitState != none && TargetState != none)
    {
    if (!bIndirectFire)
    {
    // StandardAim (with direct fire) will require visibility info between source and target (to check cover).
    if (`TACTICALRULES.VisibilityMgr.GetVisibilityInfo(UnitState.ObjectID, TargetState.ObjectID, VisInfo))
    {
    if (UnitState.CanFlank() && TargetState.GetMyTemplate().bCanTakeCover && VisInfo.TargetCover == CT_None)
    bFlanking = true;
    if (VisInfo.bClearLOS && !VisInfo.bVisibleGameplay)
    bSquadsight = true;
    // Add basic offense and defense values
    AddModifier(UnitState.GetBaseStat(eStat_Offense), class'XLocalizedData'.default.OffenseStat, m_ShotBreakdown, eHit_Success, bDebugLog);
    UnitState.GetStatModifiers(eStat_Offense, StatMods, StatModValues);
    for (i = 0; i < StatMods.Length; ++i)
    {
    AddModifier(int(StatModValues[i]), StatMods[i].GetX2Effect().FriendlyName, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    // Flanking bonus (do not apply to overwatch shots)
    if (bFlanking && !bReactionFire && !bMeleeAttack)
    {
    AddModifier(UnitState.GetCurrentStat(eStat_FlankingAimBonus), class'XLocalizedData'.default.FlankingAimBonus, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    // Squadsight penalty
    if (bSquadsight)
    {
    Tiles = UnitState.TileDistanceBetween(TargetState);
    // remove number of tiles within visible range (which is in meters, so convert to units, and divide that by tile size)
    Tiles -= UnitState.GetVisibilityRadius() * class'XComWorldData'.const.WORLD_METERS_TO_UNITS_MULTIPLIER / class'XComWorldData'.const.WORLD_StepSize;
    if (Tiles > 0) // pretty much should be since a squadsight target is by definition beyond sight range. but...
    AddModifier(default.SQUADSIGHT_DISTANCE_MOD * Tiles, class'XLocalizedData'.default.SquadsightMod, m_ShotBreakdown, eHit_Success, bDebugLog);
    else if (Tiles == 0) // right at the boundary, but squadsight IS being used so treat it like one tile
    AddModifier(default.SQUADSIGHT_DISTANCE_MOD, class'XLocalizedData'.default.SquadsightMod, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    // Check for modifier from weapon
    if (SourceWeapon != none)
    {
    iWeaponMod = SourceWeapon.GetItemAimModifier();
    AddModifier(iWeaponMod, class'XLocalizedData'.default.WeaponAimBonus, m_ShotBreakdown, eHit_Success, bDebugLog);
    WeaponUpgrades = SourceWeapon.GetMyWeaponUpgradeTemplates();
    for (i = 0; i < WeaponUpgrades.Length; ++i)
    {
    if (WeaponUpgrades[i].AddHitChanceModifierFn != None)
    {
    if (WeaponUpgrades[i].AddHitChanceModifierFn(WeaponUpgrades[i], VisInfo, iWeaponMod))
    {
    AddModifier(iWeaponMod, WeaponUpgrades[i].GetItemFriendlyName(), m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    }
    }
    }
    // Target defense
    AddModifier(-TargetState.GetCurrentStat(eStat_Defense), class'XLocalizedData'.default.DefenseStat, m_ShotBreakdown, eHit_Success, bDebugLog);
    // Add weapon range
    if (SourceWeapon != none)
    {
    iRangeModifier = GetWeaponRangeModifier(UnitState, TargetState, SourceWeapon);
    AddModifier(iRangeModifier, class'XLocalizedData'.default.WeaponRange, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    // Cover modifiers
    if (bMeleeAttack)
    {
    AddModifier(MELEE_HIT_BONUS, class'XLocalizedData'.default.MeleeBonus, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    else
    {
    // Add cover penalties
    if (TargetState.CanTakeCover())
    {
    // if any cover is being taken, factor in the angle to attack
    if( VisInfo.TargetCover != CT_None && !bIgnoreCoverBonus )
    {
    switch( VisInfo.TargetCover )
    {
    case CT_MidLevel: // half cover
    AddModifier(-LOW_COVER_BONUS, class'XLocalizedData'.default.TargetLowCover, m_ShotBreakdown, eHit_Success, bDebugLog);
    CoverValue = LOW_COVER_BONUS;
    break;
    case CT_Standing: // High Cover
    AddModifier(-HIGH_COVER_BONUS, class'XLocalizedData'.default.TargetHighCover, m_ShotBreakdown, eHit_Success, bDebugLog);
    CoverValue = HIGH_COVER_BONUS;
    break;
    }
    TileDistance = UnitState.TileDistanceBetween(TargetState);
    // from Angle 0 -> MIN_ANGLE_TO_COVER, receive full MAX_ANGLE_BONUS_MOD
    // As Angle increases from MIN_ANGLE_TO_COVER -> MAX_ANGLE_TO_COVER, reduce bonus received by lerping MAX_ANGLE_BONUS_MOD -> MIN_ANGLE_BONUS_MOD
    // Above MAX_ANGLE_TO_COVER, receive no bonus
    //`assert(VisInfo.TargetCoverAngle >= 0); // if the target has cover, the target cover angle should always be greater than 0
    // if( VisInfo.TargetCoverAngle < MAX_ANGLE_TO_COVER && TileDistance <= MAX_TILE_DISTANCE_TO_COVER )
    if( VisInfo.TargetCoverAngle < 90-default.MinimumGoodAngleBonusStartsAtThisHorizontalAngleBetweenLineOfFireAndCoverSurface && (TileDistance <= MAX_TILE_DISTANCE_TO_COVER || default.ApplyGoodAngleBonusEvenFartherThan11TilesAway))
    {
    bShouldAddAngleToCoverBonus = (UnitState.GetTeam() == eTeam_XCom);
    if (default.ApplyGoodAngleBonusNotOnlyForXComSoldiersButAlsoForAnyoneShooting) bShouldAddAngleToCoverBonus = true; //GOODANGLE FOR ENEMIES TOO!!!
    // We have to avoid the weird visual situation of a unit standing behind low cover
    // and that low cover extends at least 1 tile in the direction of the attacker.
    // if( (SHOULD_DISABLE_BONUS_ON_ANGLE_TO_EXTENDED_LOW_COVER && VisInfo.TargetCover == CT_MidLevel) || (SHOULD_ENABLE_PENALTY_ON_ANGLE_TO_EXTENDED_HIGH_COVER && VisInfo.TargetCover == CT_Standing) )
    if( (true && VisInfo.TargetCover == CT_MidLevel) || (false && VisInfo.TargetCover == CT_Standing) )
    {
    UnitState.GetKeystoneVisibilityLocation(UnitTileLocation);
    TargetState.GetKeystoneVisibilityLocation(TargetTileLocation);
    NextTileOverCoverType = NextTileOverCoverInSameDirection(UnitTileLocation, TargetTileLocation );
    // if( SHOULD_DISABLE_BONUS_ON_ANGLE_TO_EXTENDED_LOW_COVER && VisInfo.TargetCover == CT_MidLevel && NextTileOverCoverType == CT_MidLevel ) //EXTENDED LOW-HIGH COVER HIBRID
    // if(true && (VisInfo.TargetCover == CT_MidLevel || VisInfo.TargetCover == CT_Standing) && (NextTileOverCoverType == CT_MidLevel || NextTileOverCoverType == CT_Standing))
    if(true && VisInfo.TargetCover == CT_MidLevel && (NextTileOverCoverType == CT_MidLevel || NextTileOverCoverType == CT_Standing))
    {
    bShouldAddAngleToCoverBonus = false;
    }
    // else if(SHOULD_ENABLE_PENALTY_ON_ANGLE_TO_EXTENDED_HIGH_COVER && VisInfo.TargetCover == CT_Standing && NextTileOverCoverType == CT_Standing )
    else if(false && VisInfo.TargetCover == CT_Standing && NextTileOverCoverType == CT_Standing )
    {
    bShouldAddAngleToCoverBonus = false;
    Alpha = FClamp((VisInfo.TargetCoverAngle - MIN_ANGLE_TO_COVER ) / (MAX_ANGLE_TO_COVER - MIN_ANGLE_TO_COVER ), 0.0, 1.0);
    AngleToCoverModifier = Lerp(MAX_ANGLE_PENALTY , MIN_ANGLE_PENALTY , Alpha);
    AddModifier(Round(-1.0 * AngleToCoverModifier), class'XLocalizedData'.default.BadAngleToTargetCover, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    }
    if( bShouldAddAngleToCoverBonus )
    {
    // Alpha = FClamp((VisInfo.TargetCoverAngle - MIN_ANGLE_TO_COVER ) / (MAX_ANGLE_TO_COVER - MIN_ANGLE_TO_COVER ), 0.0, 1.0);
    // Alpha = FClamp((VisInfo.TargetCoverAngle - 0 ) / (45 - 0 ), 0.0, 1.0);
    Alpha = FClamp((VisInfo.TargetCoverAngle - default.MaximumGoodAngleBonusEndsAtThisHorizontalAngleBetweenLineOfFireAndCoverSurface) / (default.MinimumGoodAngleBonusStartsAtThisHorizontalAngleBetweenLineOfFireAndCoverSurface - default.MaximumGoodAngleBonusEndsAtThisHorizontalAngleBetweenLineOfFireAndCoverSurface), 0.0, 1.0);
    // AngleToCoverModifier = Lerp(MAX_ANGLE_BONUS_MOD , MIN_ANGLE_BONUS_MOD , Alpha);
    AngleToCoverModifier = Lerp(default.MaximumGoodAngleBonusCoverReductionPercentage /100, default.MinimumGoodAngleBonusCoverReductionPercentage /100, Alpha);
    // AngleToCoverModifier = Lerp(1 , 0 , Alpha);
    // AddModifier(Round(CoverValue * AngleToCoverModifier) , class'XLocalizedData'.default.AngleToTargetCover, m_ShotBreakdown, eHit_Success, bDebugLog);
    GoodAngleBonus = Round(CoverValue * AngleToCoverModifier);
    AddModifier(GoodAngleBonus , class'XLocalizedData'.default.AngleToTargetCover, m_ShotBreakdown, eHit_Success, bDebugLog);
    // if (VisInfo.TargetCover == CT_Standing && NextTileOverCoverType == CT_MidLevel) AddModifier(-Round(GoodAngleBonus / 2) , "ExtendedLowCover preventing GoodAngle" , m_ShotBreakdown, eHit_Success, bDebugLog);
    // if ((VisInfo.TargetCover == CT_MidLevel || VisInfo.TargetCover == CT_Standing) && (NextTileOverCoverType == CT_MidLevel || NextTileOverCoverType == CT_Standing)) AddModifier(-Round(GoodAngleBonus / 2) , "ExtendedLowCover preventing GoodAngle" , m_ShotBreakdown, eHit_Success, bDebugLog);
    if ( (NextTileOverCoverType == CT_MidLevel || NextTileOverCoverType == CT_Standing)) {
    ExtendedLowCoverPreventingGoodAngleBonus = -Round(GoodAngleBonus / 2);
    AddModifier(ExtendedLowCoverPreventingGoodAngleBonus , "ExtendedLowCover preventing GoodAngle" , m_ShotBreakdown, eHit_Success, bDebugLog);} //WHEN ONLY "HALF OF" THE HIGHCOVER IS REDUCED BY THE GOODANGLE BECAUSE THE OTHER HALF IS COVERED BY LOWCOVER... ;)
    }
    }
    }
    }
    // Add height advantage
    // if (UnitState.HasHeightAdvantageOver(TargetState, true) )
    if (UnitState.HasHeightAdvantageOver(TargetState, true) && default.ApplyVerticalGoodAngleAgainstLowerTargetAsProportionalHeightAdvantage != true)
    {
    AddModifier(class'X2TacticalGameRuleset'.default.UnitHeightAdvantageBonus, class'XLocalizedData'.default.HeightAdvantage, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    // Check for height disadvantage
    // if (TargetState.HasHeightAdvantageOver(UnitState, false) )
    if (TargetState.HasHeightAdvantageOver(UnitState, false) && default.ApplyVerticalGoodAngleAgainstLowerTargetAsProportionalHeightAdvantage != true)
    {
    AddModifier(class'X2TacticalGameRuleset'.default.UnitHeightDisadvantagePenalty, class'XLocalizedData'.default.HeightDisadvantage, m_ShotBreakdown, eHit_Success, bDebugLog);
    // AddModifier(-10 , class'XLocalizedData'.default.HeightDisadvantage, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    //REPLACED 'STUPID' PARAGRAPH ABOVE
    //WITH PARAGRAPH BELOW!!!
    // PI = 3.141592; //ALMIGHTY UNIVERSAL CONSTANT
    // ShooterHead = ShooterTile; ShooterHead.Z += 2;
    // TargetHead = TargetTile; TargetHead .Z += 2;
    // ShooterHead = ShooterTile; ShooterHead.Z += UnitState .UnitHeight -1;
    // TargetHead = TargetTile; TargetHead .Z += TargetState.UnitHeight -1;
    ShooterHead = ShooterTile; ShooterHead.Z = `XWORLD.GetFloorTileZ(ShooterHead) + UnitState .UnitHeight -1;
    TargetHead = TargetTile; TargetHead .Z = `XWORLD.GetFloorTileZ(TargetHead ) + TargetState.UnitHeight -1;
    ShooterTorso = ShooterHead; ShooterTorso.Z -= 0.5;
    // TargetTorso = TargetHead ; TargetTorso .Z -= 0.5;
    ShooterBelowFeet = ShooterTile; ShooterBelowFeet.Z -= 2;
    TargetLegs = TargetTile;
    ShooterHeadRelativeElevation = ShooterHead.Z - TargetHead.Z; //TARGETEXTRAHEIGHT MUST NOT BE CONSIDERED BUT TEST IT FOR A WHILE TO SEE IF IT IS CONSIDERED WHILE ALIENS ARE USING THIS FUNCTION
    TileDistance = UnitState.TileDistanceBetween(TargetState);
    VerticalAngle = atan(ShooterHeadRelativeElevation / TileDistance) / (2*PI) * 360; //GOD BLESS TRIGONOMETRY
    if (default.ApplyVerticalGoodAngleAgainstLowerTargetAsProportionalHeightAdvantage &&
    ShooterHeadRelativeElevation > 0 &&
    ((VisInfo.TargetCover == CT_MidLevel ) || //HEIGHT ADVANTAGE REDUCES ONLY LOW COVER .... OR SHOULD IT???
    (VisInfo.TargetCover == CT_Standing && CoverTypeOfTileAboveTarget == CT_None) ) ){ //...WELL DEPENDS ON WETHER IT'S A VERTICAL TREE OR AN ORIZONTAL HIGHCOVER FENCE... ;)
    if (GoodAngleBonus != 0) CoverValue = CoverValue - GoodAngleBonus; //HEIGHT ADVANTAGE APPLIED "AFTER" GOOD ANGLE IS APPLIED (NOT SEPARATELY,
    //OTHERWISE IT COULD SUBTRACT 2 VALUES CUMULATEVELY HIGHER THAN COVERVALUE ITSELF)
    Alpha = FClamp(((90-VerticalAngle) - default.MaximumHeightAdvantageBonusEndsAtThisVerticalAngleBetweenLineOfFireAndCoverSurface) / (default.MinimumHeightAdvantageBonusStartsAtThisVerticalAngleBetweenLineOfFireAndCoverSurface - default.MaximumHeightAdvantageBonusEndsAtThisVerticalAngleBetweenLineOfFireAndCoverSurface), 0.0, 1.0);
    // Alpha = FClamp((VisInfo.TargetCoverAngle - 0 ) / (45 - 0 ), 0.0, 1.0);
    // Alpha = FClamp(((90-VerticalAngle) - 30 ) / (90 - 30 ), 0.0, 1.0);
    AngleToCoverModifier = Lerp(default.MaximumHeightAdvantageBonusCoverReductionPercentage/100, default.MinimumHeightAdvantageBonusCoverReductionPercentage/100 , Alpha);
    // AngleToCoverModifier = Lerp(1 , 0 , Alpha);
    HeightAdvantageBonus = round(AngleToCoverModifier * CoverValue);
    // HeightAdvantageBonus = round(VerticalAngle/90 * CoverValue);
    AddModifier(HeightAdvantageBonus, class'XLocalizedData'.default.HeightAdvantage, m_ShotBreakdown, eHit_Success, bDebugLog);}
    if (default.GiveHitChanceZeroWhenTargetableEnemiesAreInsteadNotTrulyInLineOfSight// &&
    /* ShooterHeadRelativeElevation > 0 */ ){ //'FAR' COVER BLOCKING VISIBILITY CHECK...
    if (ShooterHead.Z - TargetLegs.Z >= 0){ //SAME HEIGHT OR BELOW SHOOTER
    NextTile = ShooterTile;
    NextTile = NextWalkableTile(ShooterTile, NextTile, TargetTile, FarCover); if (NextTile.Z>=ShooterTile.Z && FarCover>0 && !`XWORLD.CanSeeTileToTile(ShooterTorso, TargetHead, VisibilityInfo)) NoLineOfSightMalus = -1000;
    NextTile = NextWalkableTile(ShooterTile, NextTile, TargetTile, FarCover); if (NextTile.Z>=ShooterTile.Z && FarCover>0 && !`XWORLD.CanSeeTileToTile(ShooterTorso, TargetHead, VisibilityInfo)) NoLineOfSightMalus = -1000; //LOW COVER IN CALCULATING VISIBILITY.
    NextTile = NextWalkableTile(ShooterTile, NextTile, TargetTile, FarCover); if (NextTile.Z>=ShooterTile.Z && FarCover>0 && !`XWORLD.CanSeeTileToTile(ShooterTorso, TargetHead, VisibilityInfo)) NoLineOfSightMalus = -1000;} //THIS NONSENSE HAD TO BE MODDED AWAY...
    if (ShooterHead.Z - TargetLegs.Z < 0){ //ABOVE SHOOTER
    NextTile = ShooterTile;
    NextTile = NextWalkableTile(ShooterTile, NextTile, TargetTile, FarCover); if (FarCover == 1 && !`XWORLD.CanSeeTileToTile(ShooterBelowFeet, TargetLegs, VisibilityInfo)) NoLineOfSightMalus = -1000; //DIFFERENT CHECK FOR HIGH GROUNDS
    NextTile = NextWalkableTile(ShooterTile, NextTile, TargetTile, FarCover); if (FarCover == 1 && !`XWORLD.CanSeeTileToTile(ShooterBelowFeet, TargetLegs, VisibilityInfo)) NoLineOfSightMalus = -1000; //IN CALCULATING VISIBILITY.
    NextTile = NextWalkableTile(ShooterTile, NextTile, TargetTile, FarCover); if (FarCover == 1 && !`XWORLD.CanSeeTileToTile(ShooterBelowFeet, TargetLegs, VisibilityInfo)) NoLineOfSightMalus = -1000;}
    If (NoLineOfSightMalus != 0) AddModifier(NoLineOfSightMalus, "No Line of Sight", m_ShotBreakdown, eHit_Success, bDebugLog);}
    if (default.AllowFarCoverToGiveSomeCoverProtection &&
    (TargetState.GetCurrentStat(eStat_AlertLevel)==`ALERT_LEVEL_RED || (TargetState.GetCurrentStat(eStat_AlertLevel)!=`ALERT_LEVEL_RED && !default.OnlyAlertedTargetsCanHaveTheExtraProtectionOfFarCoverAndHeightDisadvantage)) &&
    (VisInfo.TargetCover==CT_None || (GoodAngleBonus > 0 && ExtendedLowCoverPreventingGoodAngleBonus == 0)) && //FAR COVER ONLY IF NOT IN COVER OR IF THE COVER TAKEN IS NOT IN THE DIRECTION OF THE SHOOTER (MORE FLANKING THAN COVER)
    TileDistance > 2 &&
    TargetState.GetMyTemplate().bCanTakeCover == true){
    // ShooterTargetDistance = class'Helpers'.static.DistanceBetweenTiles(TargetTile, ShooterTile, false ); //FORGETTING THE "FALSE" VARIABLE WILL GIVE "SQUARED" DISTANCE!!!! MOTHERFUCKER!!! HOW GAVE SUCH A WRONG NAME TO
    ShooterTargetDistance = TilesDistance(TargetTile, ShooterTile ); //SUCH A DANGERIOUSLY MISLEADING FUNCTION!!!!??? HOWRS TRYING TO UNDERSTAND WHY DISTANCE WAS WRONGLY CALCULATED!!!
    // ShooterTargetDistance = VSize(TargetLocation, ShooterLocation); // * 0.8; //NO FAR COVER 20% NEAR THE SHOOTER... NONSENSE.. ;)
    FarCoverText = "Far Cover";
    if (ShooterHeadRelativeElevation == 0){ NextTile = TargetTile; FarCoverBonus = 0;
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (FarCover>0) FarCoverBonus = 20 / (ShooterTargetDistance*0.7) * Max(0, TilesDistance(ShooterTile, NextTile) - ShooterTargetDistance*0.3);} }
    if (ShooterHead.Z - TargetLegs.Z < 0){ NextTile = TargetTile; //ABOVE SHOOTER
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (NextTile.Z>=TargetTile.Z && FarCover>0) FarCoverBonus = 20;} //DIFFERENT VALUE FOR FAR COVER
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (NextTile.Z>=TargetTile.Z && FarCover>0) FarCoverBonus = 20;} //ON ELEVATED GROUND
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (NextTile.Z>=TargetTile.Z && FarCover>0) FarCoverBonus = 20;}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (NextTile.Z>=TargetTile.Z && FarCover>0) FarCoverBonus = 20;}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (NextTile.Z>=TargetTile.Z && FarCover>0) FarCoverBonus = 20;}
    if(FarCoverBonus==0 && NextTile.Z == TargetTile.Z) {NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (NextTile.Z>=TargetTile.Z && FarCover>0) FarCoverBonus = 20;}}
    if (TilesDistance(TargetTile, NextTile) >= ShooterTargetDistance) {FarCoverBonus = 0;} //DON'T CONSIDER FAR COVER "BEHIND" SHOOTER... ;)
    if (FarCoverBonus > 0 && GoodAngleBonus > 0) {FarCoverBonus = Min(GoodAngleBonus, FarCoverBonus); FarCoverText = "FarCover Preventing GoodAngle";}
    // AddModifier( -FarCoverBonus , FarCoverText, m_ShotBreakdown, eHit_Success, bDebugLog);}
    AddModifier(round(-FarCoverBonus), FarCoverText, m_ShotBreakdown, eHit_Success, bDebugLog);}
    if (default.ApplyVerticalBadAngleAgainstHigherTargetAsProportionalHeightDisadvantage &&
    ShooterHead.Z - TargetLegs.Z < 0 && //TARGET STANDING ON A SURFACE HIGHER THAN THE SHOOTER'S HEAD
    (TargetState.GetCurrentStat(eStat_AlertLevel)==`ALERT_LEVEL_RED || (TargetState.GetCurrentStat(eStat_AlertLevel)!=`ALERT_LEVEL_RED && !default.OnlyAlertedTargetsCanHaveTheExtraProtectionOfFarCoverAndHeightDisadvantage)) &&
    TargetState.GetMyTemplate().bCanTakeCover == true //&& //HIGHER, LOWER OR SAME LEVEL, FAR COVER MUST GIVE SOME ADVANTAGE NO MATTER THE HEIGHT
    // VisInfo.TargetCover == CT_None
    ){ //HEIGHT DISADVANTAGE DOESN'T INCREASE TARGET'S HIGH/LOW COVER... BUT ONLY ADDS FROM 1 TO 19 COVER WHEN BUILDING/CLIFF PARTIALLY ACTS AS LOW COVER
    // Alpha = FClamp((VisInfo.TargetCoverAngle - MIN_ANGLE_TO_COVER ) / (MAX_ANGLE_TO_COVER - MIN_ANGLE_TO_COVER ), 0.0, 1.0);
    // Alpha = FClamp((VisInfo.TargetCoverAngle - 0 ) / (45 - 0 ), 0.0, 1.0);
    Alpha = FClamp((90-(-VerticalAngle) - 0 ) / (85 - 0 ), 0.0, 1.0);
    // AngleToCoverModifier = Lerp(MAX_ANGLE_BONUS_MOD , MIN_ANGLE_BONUS_MOD , Alpha);
    AngleToCoverModifier = Lerp(1 , 0 , Alpha);
    // HeightDisadvantageMalus = round(VerticalAngle/90*(20)); //NEGATIVE RELATIVEELEVATION --> NEGATIVE VERTICALANGLE --> NEGATIVE MALUS//SOMETIMES YOU ARE SHOOTING FROM THE "SIDE OF HIS LOWCOVER" AND THE SIDE HAS ROOFCEILING AS PROTECTION...
    HeightDisadvantageMalus = round(-AngleToCoverModifier*(20)); NextTile = TargetTile;
    /* NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); //EACH "STEP BACKWARDS"//THE ROOFTOP-BORDER UNTIL
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);} //NEGATIVE RELATIVEELEVATION --> NEGATIVE VERTICALANGLE --> NEGATIVE MALUS
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover);}
    if (NextTile.Z >= TargetTile.Z) {HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); }
    */ if (VisInfo.TargetCover == CT_MidLevel) FarCover = 1;
    if (VisInfo.TargetCover != CT_MidLevel) {
    for (i=1;i==20;++i){
    NextTile = NextWalkableTile(TargetTile, NextTile, ShooterTile, FarCover); if (NextTile.Z < TargetTile.Z) break;
    // HeightDisadvantageMalus = round(HeightDisadvantageMalus + HeightDisadvantageMalus/2); //ROUNDING SMALL PERCENTAGES NEVER
    HeightDisadvantageMalus = HeightDisadvantageMalus + HeightDisadvantageMalus/2 ; //GIVES LARGE SUMS! ROUND AT THE END!!!
    }}
    // HeightDisadvantageMalus = HeightDisadvantageMalus/(TargetState.UnitHeight-1); // TALL FACELESS/SECTOPODS DON'T HIDE MUCH BEHIND HIGH BUILDINGS/CLIFFS BORDERS
    // if (HeightDisadvantageMalus < -1000) HeightDisadvantageMalus = -1000;
    // else if (HeightDisadvantageMalus < -20) HeightDisadvantageMalus = -20;
    if (FarCover==1) HeightDisadvantageMalus = 2 * HeightDisadvantageMalus;
    // AddModifier( HeightDisadvantageMalus , class'XLocalizedData'.default.HeightDisadvantage, m_ShotBreakdown, eHit_Success, bDebugLog);} //POSITIVE OR NEGATIVE???
    AddModifier(round(HeightDisadvantageMalus), class'XLocalizedData'.default.HeightDisadvantage, m_ShotBreakdown, eHit_Success, bDebugLog);} //POSITIVE OR NEGATIVE???
    //END OF REPLACED
    //PARAGRAPH... ;)
    }
    }
    if (UnitState.IsConcealed())
    {
    `log("Shooter is concealed, target cannot dodge.", bDebugLog, 'XCom_HitRolls');
    }
    else
    {
    if (SourceWeapon == none || SourceWeapon.CanWeaponBeDodged())
    {
    if (TargetState.CanDodge(UnitState, kAbility))
    {
    AddModifier(TargetState.GetCurrentStat(eStat_Dodge), class'XLocalizedData'.default.DodgeStat, m_ShotBreakdown, eHit_Graze, bDebugLog);
    }
    else
    {
    `log("Target cannot dodge due to some gameplay effect.", bDebugLog, 'XCom_HitRolls');
    }
    }
    }
    }
    // Now check for critical chances.
    if (bAllowCrit)
    {
    AddModifier(UnitState.GetBaseStat(eStat_CritChance), class'XLocalizedData'.default.CharCritChance, m_ShotBreakdown, eHit_Crit, bDebugLog);
    UnitState.GetStatModifiers(eStat_CritChance, StatMods, StatModValues);
    for (i = 0; i < StatMods.Length; ++i)
    {
    AddModifier(int(StatModValues[i]), StatMods[i].GetX2Effect().FriendlyName, m_ShotBreakdown, eHit_Crit, bDebugLog);
    }
    if (bSquadsight)
    {
    AddModifier(default.SQUADSIGHT_CRIT_MOD, class'XLocalizedData'.default.SquadsightMod, m_ShotBreakdown, eHit_Crit, bDebugLog);
    }
    if (SourceWeapon != none)
    {
    AddModifier(SourceWeapon.GetItemCritChance(), class'XLocalizedData'.default.WeaponCritBonus, m_ShotBreakdown, eHit_Crit, bDebugLog);
    }
    if (bFlanking && !bMeleeAttack)
    {
    if (`XENGINE.IsMultiplayerGame())
    {
    AddModifier(default.MP_FLANKING_CRIT_BONUS, class'XLocalizedData'.default.FlankingCritBonus, m_ShotBreakdown, eHit_Crit, bDebugLog);
    }
    else
    {
    AddModifier(UnitState.GetCurrentStat(eStat_FlankingCritChance), class'XLocalizedData'.default.FlankingCritBonus, m_ShotBreakdown, eHit_Crit, bDebugLog);
    }
    }
    }
    foreach UnitState.AffectedByEffects(EffectRef)
    {
    EffectModifiers.Length = 0;
    EffectState = XComGameState_Effect(History.GetGameStateForObjectID(EffectRef.ObjectID));
    if (EffectState == none)
    continue;
    PersistentEffect = EffectState.GetX2Effect();
    if (PersistentEffect == none)
    continue;
    if (UniqueToHitEffects.Find(PersistentEffect) != INDEX_NONE)
    continue;
    // PersistentEffect.GetToHitModifiers(EffectState, UnitState, TargetState, kAbility, self.Class , bMeleeAttack, bFlanking, bIndirectFire, EffectModifiers);
    PersistentEffect.GetToHitModifiers(EffectState, UnitState, TargetState, kAbility, class'X2AbilitytoHitCalc_StandardAim', bMeleeAttack, bFlanking, bIndirectFire, EffectModifiers);
    if (EffectModifiers.Length > 0)
    {
    if (PersistentEffect.UniqueToHitModifiers())
    UniqueToHitEffects.AddItem(PersistentEffect);
    for (i = 0; i < EffectModifiers.Length; ++i)
    {
    if (!bAllowCrit && EffectModifiers[i].ModType == eHit_Crit)
    {
    if (!PersistentEffect.AllowCritOverride())
    continue;
    }
    AddModifier(EffectModifiers[i].Value, EffectModifiers[i].Reason, m_ShotBreakdown, EffectModifiers[i].ModType, bDebugLog);
    }
    }
    if (PersistentEffect.ShotsCannotGraze())
    {
    bIgnoreGraze = true;
    IgnoreGrazeReason = PersistentEffect.FriendlyName;
    }
    }
    UniqueToHitEffects.Length = 0;
    if (TargetState.AffectedByEffects.Length > 0)
    {
    foreach TargetState.AffectedByEffects(EffectRef)
    {
    EffectModifiers.Length = 0;
    EffectState = XComGameState_Effect(History.GetGameStateForObjectID(EffectRef.ObjectID));
    if (EffectState == none)
    continue;
    PersistentEffect = EffectState.GetX2Effect();
    if (PersistentEffect == none)
    continue;
    if (UniqueToHitEffects.Find(PersistentEffect) != INDEX_NONE)
    continue;
    // PersistentEffect.GetToHitAsTargetModifiers(EffectState, UnitState, TargetState, kAbility , self.Class, bMeleeAttack, bFlanking, bIndirectFire, EffectModifiers);
    PersistentEffect.GetToHitAsTargetModifiers(EffectState, UnitState, TargetState, kAbility, class'X2AbilitytoHitCalc_StandardAim', bMeleeAttack, bFlanking, bIndirectFire, EffectModifiers);
    if (EffectModifiers.Length > 0)
    {
    if (PersistentEffect.UniqueToHitAsTargetModifiers())
    UniqueToHitEffects.AddItem(PersistentEffect);
    for (i = 0; i < EffectModifiers.Length; ++i)
    {
    if (!bAllowCrit && EffectModifiers[i].ModType == eHit_Crit)
    continue;
    if (bIgnoreGraze && EffectModifiers[i].ModType == eHit_Graze)
    continue;
    AddModifier(EffectModifiers[i].Value, EffectModifiers[i].Reason, m_ShotBreakdown, EffectModifiers[i].ModType, bDebugLog);
    }
    }
    }
    }
    // Remove graze if shooter ignores graze chance.
    if (bIgnoreGraze)
    {
    AddModifier(-m_ShotBreakdown.ResultTable[eHit_Graze], IgnoreGrazeReason, m_ShotBreakdown, eHit_Graze, bDebugLog);
    }
    // Remove crit from reaction fire. Must be done last to remove all crit.
    if (bReactionFire)
    {
    AddReactionCritModifier(UnitState, TargetState, m_ShotBreakdown, bDebugLog);
    }
    }
    // Final multiplier based on end Success chance
    if (bReactionFire && !bGuaranteedHit)
    {
    FinalAdjust = m_ShotBreakdown.ResultTable[eHit_Success] * GetReactionAdjust(UnitState, TargetState);
    AddModifier(-int(FinalAdjust), AbilityTemplate.LocFriendlyName, m_ShotBreakdown, eHit_Success, bDebugLog);
    AddReactionFlatModifier(UnitState, TargetState, m_ShotBreakdown, bDebugLog);
    }
    else if (FinalMultiplier != 1.0f)
    {
    FinalAdjust = m_ShotBreakdown.ResultTable[eHit_Success] * FinalMultiplier;
    AddModifier(-int(FinalAdjust), AbilityTemplate.LocFriendlyName, m_ShotBreakdown, eHit_Success, bDebugLog);
    }
    FinalizeHitChance(m_ShotBreakdown, bDebugLog);
    return m_ShotBreakdown.FinalHitChance;
    }
    //ADDED THIS SECTION
    function TTile NextWalkableTile( TTile OriginTile , // Y
    TTile MidTile , // ^
    TTile DestinationTile, // |
    out int FarCover ){ // X <--
    local TTile TileDifference;
    local TTile NextTile;
    local int Direction;
    local int OriginDestinationAngle;
    local int MidTileDestinationAngle;
    local TileData NextTileData;
    OriginDestinationAngle = Abs(DestinationTile.X - OriginTile.X) / Abs(DestinationTile.Y - OriginTile.Y);
    MidTileDestinationAngle = Abs(DestinationTile.X - MidTile .X) / Abs(DestinationTile.Y - MidTile .Y);
    NextTile = MidTile;
    TileDifference.X = DestinationTile.X - MidTile.X;
    TileDifference.Y = DestinationTile.Y - MidTile.Y;
    Direction = 0;
    FarCover = 0;
    // if (Abs(TileDifference.X) > Abs(TileDifference.Y) && OriginDestinationAngle >= MidTileDestinationAngle ||
    // Abs(TileDifference.X) <= Abs(TileDifference.Y) && OriginDestinationAngle < MidTileDestinationAngle ){
    if (OriginDestinationAngle <= MidTileDestinationAngle){
    if( TileDifference.X > 0) {++NextTile.X;}
    if( TileDifference.X <=0) {--NextTile.X;}}
    // if (Abs(TileDifference.X) <= Abs(TileDifference.Y) && OriginDestinationAngle >= MidTileDestinationAngle ||
    // Abs(TileDifference.X) > Abs(TileDifference.Y) && OriginDestinationAngle < MidTileDestinationAngle ){
    if (OriginDestinationAngle > MidTileDestinationAngle){
    if( TileDifference.Y > 0) {++NextTile.Y;}
    if( TileDifference.Y <=0) {--NextTile.Y;}}
    if (Abs(TileDifference.X) > Abs(TileDifference.Y)){
    if( TileDifference.X > 0) {Direction = `XWORLD.COVER_WLow;}
    if( TileDifference.X <=0) {Direction = `XWORLD.COVER_ELow;}}
    if (Abs(TileDifference.X) <= Abs(TileDifference.Y)){
    if( TileDifference.Y > 0) {Direction = `XWORLD.COVER_NLow;}
    if( TileDifference.Y <=0) {Direction = `XWORLD.COVER_SLow;}}
    NextTile.Z = `XWORLD.GetFloorTileZ(NextTile);
    `XWORLD.GetTileData(NextTile, NextTileData);
    if ((NextTileData.CoverFlags & Direction) != 0) FarCover = 1;
    return NextTile;}
    // arrEnemyInfos[EnemyInfoIndex].TargetCover = World.GetCoverTypeForTarget(vEnemyPos, vLoc, arrEnemyInfos[EnemyInfoIndex].TargetCoverAngle);
    function ECoverType CoverTypeOfTileAboveCover(const out TTile SourceTile, const out TTile DestTile, int TargetCoverAngle) {
    local TTile TileDifference;
    local TTile TileAboveCover;
    TileDifference.X = SourceTile.X - DestTile.X;
    TileDifference.Y = SourceTile.Y - DestTile.Y;
    /* if( (Abs(TileDifference.X) > Abs(TileDifference.Y) && TargetCoverAngle>45) || //FROM FRONT OF X-AXIS COVER
    (Abs(TileDifference.X) > Abs(TileDifference.Y) && TargetCoverAngle<45) ){ //FROM SIDE OF X-AXIS COVER
    if( TileDifference.X > 0) {TileAboveCover.X += 1;}
    if( TileDifference.X <=0) {TileAboveCover.X -= 1;}}
    if( (Abs(TileDifference.X) <= Abs(TileDifference.Y) && TargetCoverAngle>45) || //FROM FRONT OF Y-AXIS COVER
    (Abs(TileDifference.X) <= Abs(TileDifference.Y) && TargetCoverAngle<45) ){ //FROM SIDE OF Y-AXIS COVER
    if( TileDifference.Y > 0) {TileAboveCover.Y += 1;}
    if( TileDifference.Y <=0) {TileAboveCover.Y -= 1;}}
    */
    TileAboveCover = DestTile; TileAboveCover.Z += 2;
    if( TileDifference.X > 0) TileAboveCover.X += 1; else TileAboveCover.X -= 1;
    if(`XWORLD.IsTileFullyOccupied(TileAboveCover) ||
    `XWORLD.IsTileOccupied (TileAboveCover) ) return CT_Standing;
    TileAboveCover = DestTile; TileAboveCover.Z += 2;
    if( TileDifference.Y > 0) TileAboveCover.Y += 1; else TileAboveCover.Y -= 1;
    if(`XWORLD.IsTileFullyOccupied(TileAboveCover) ||
    `XWORLD.IsTileOccupied (TileAboveCover) ) return CT_Standing;
    /*
    TileAboveCover = DestTile; TileAboveCover.Z += 1; TileAboveCover.X += 1;
    if(`XWORLD.IsTileFullyOccupied(TileAboveCover) ||
    `XWORLD.IsTileOccupied (TileAboveCover) ) return CT_Standing;
    TileAboveCover = DestTile; TileAboveCover.Z += 1; TileAboveCover.X -= 1;
    if(`XWORLD.IsTileFullyOccupied(TileAboveCover) ||
    `XWORLD.IsTileOccupied (TileAboveCover) ) return CT_Standing;
    TileAboveCover = DestTile; TileAboveCover.Z += 1; TileAboveCover.Y += 1;
    if(`XWORLD.IsTileFullyOccupied(TileAboveCover) ||
    `XWORLD.IsTileOccupied (TileAboveCover) ) return CT_Standing;
    TileAboveCover = DestTile; TileAboveCover.Z += 1; TileAboveCover.Y -= 1;
    if(`XWORLD.IsTileFullyOccupied(TileAboveCover) ||
    `XWORLD.IsTileOccupied (TileAboveCover) ) return CT_Standing;
    */
    }
    function bool CoverOnBothSides( TTile ShooterTile,
    TTile TargetTile) {
    local TTile TileDifference;
    local int DirectionX;
    local int DirectionY;
    local TileData TargetTileData;
    TileDifference.X = TargetTile.X - ShooterTile.X;
    TileDifference.Y = TargetTile.Y - ShooterTile.Y;
    DirectionX = 0;
    DirectionY = 0;
    if( Abs(TileDifference.X) > Abs(TileDifference.Y) ) {
    if( TileDifference.X > 0) {DirectionX = `XWORLD.COVER_West;}
    if( TileDifference.X <=0) {DirectionX = `XWORLD.COVER_East;}}
    if( Abs(TileDifference.X) <= Abs(TileDifference.Y) ) {
    if( TileDifference.Y > 0) {DirectionY = `XWORLD.COVER_North;}
    if( TileDifference.Y <=0) {DirectionY = `XWORLD.COVER_South;}}
    `XWORLD.GetTileData(TargetTile, TargetTileData);
    if ((TargetTileData.CoverFlags & DirectionX) != 0 &&
    (TargetTileData.CoverFlags & DirectionY) != 0 ) return true;}
    static function float TilesDistance(TTile TileA, TTile TileB)
    {
    local XComWorldData World;
    local vector LocA, LocB;
    World = `XWORLD;
    LocA = World.GetPositionFromTileCoordinates(TileA);
    LocB = World.GetPositionFromTileCoordinates(TileB);
    return VSize(LocA - LocB);
    }
  • file addition: ReadMe.txt (----------)
    [0.1113]
    X2ModBuildCommon v1.2.1 successfully installed.
    Edit .scripts\build.ps1 if you want to enable cooking.
    Enjoy making your mod, and may the odds be ever in your favor.
    Created with Enhanced Mod Project Template v1.0
    Get news and updates here:
    https://github.com/Iridar/EnhancedModProjectTemplate
  • file addition: RWRealisticAimingAnglesHL.x2proj (----------)
    [0.1113]
    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="12.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
    <Guid>77b6db48-e453-45b7-a9af-fd61825b87ef</Guid>
    <Name>[WotC] RW Realistic Aiming Angles - Highlander compatible</Name>
    <Description>This is an unofficial update to krumiro's [WotC] RW Realistic Aiming Angle to make it compatible with X2WOTCCommunityHighlander v1.24.0</Description>
    <SteamPublishID>0</SteamPublishID>
    <AssemblyName>RWRealisticAimingAnglesHL</AssemblyName>
    <RootNamespace>RWRealisticAimingAnglesHL</RootNamespace>
    </PropertyGroup>
    <ItemGroup>
    <Folder Include=".scripts\" />
    <Folder Include=".scripts\X2ModBuildCommon\" />
    <Folder Include="Config\" />
    <Folder Include="Config\Base\" />
    <Folder Include="Localization\" />
    <Folder Include="Src\" />
    <Folder Include="Content\" />
    <Folder Include="ContentForCook\" />
    <Folder Include="Src\RWRealisticAimingAnglesHL" />
    <Folder Include="Src\RWRealisticAimingAnglesHL\Classes" />
    </ItemGroup>
    <ItemGroup>
    <Content Include=".scripts\build.ps1" />
    <Content Include=".scripts\X2ModBuildCommon\build_common.ps1" />
    <Content Include=".scripts\X2ModBuildCommon\CHANGELOG.md" />
    <Content Include=".scripts\X2ModBuildCommon\clean.ps1" />
    <Content Include=".scripts\X2ModBuildCommon\clean_cooker_output.ps1" />
    <Content Include=".scripts\X2ModBuildCommon\EmptyUMap" />
    <Content Include=".scripts\X2ModBuildCommon\InvokePowershellTask.cs" />
    <Content Include=".scripts\X2ModBuildCommon\LICENSE" />
    <Content Include=".scripts\X2ModBuildCommon\README.md" />
    <Content Include=".scripts\X2ModBuildCommon\XCOM2.targets" />
    <Content Include=".gitignore" />
    <Content Include="replace_text.exe" />
    <Content Include="RUN_THIS.bat" />
    <Content Include="ReadMe.txt" />
    <Content Include="ModPreview.jpg" />
    <Content Include="ContentOptions.json" />
    <Content Include="Config\Base\XComEditor.ini" />
    <Content Include="Config\Base\XComEngine.ini" />
    <Content Include="Config\Base\XComGame.ini" />
    <Content Include="Config\XComTemplateCreator.ini" />
    <Content Include="Config\XComTemplateEditor.ini" />
    <Content Include="Localization\XComGame.int" />
    <Content Include="Localization\[WotC]RWRealisticAimingAngles-Highlandercompatible.int" />
    <Content Include="Src\extra_globals.uci" />
    <Content Include="Src\RWRealisticAimingAnglesHL\Classes\X2DLCInfo_RWRealisticAimingAnglesHL.uc" />
    <Content Include="Src\RWRealisticAimingAnglesHL\Classes\Help.uc" />
    <Content Include="Src\RWRealisticAimingAnglesHL\Classes\ConfigEngine.uc" />
    </ItemGroup>
    <PropertyGroup>
    <SolutionRoot>$(MSBuildProjectDirectory)\</SolutionRoot>
    <ScriptsDir>$(SolutionRoot).scripts\</ScriptsDir>
    <BuildCommonRoot>$(ScriptsDir)X2ModBuildCommon\</BuildCommonRoot>
    </PropertyGroup>
    <Import Project="$(BuildCommonRoot)XCOM2.targets" />
    </Project>
  • file addition: ModPreview.jpg (----------)
    [0.1113]
  • file addition: Localization (d--r------)
    [0.1113]
  • file addition: ContentOptions.json (----------)
    [0.1113]
    {
    "sfStandalone": [
    "PackageName1",
    "PackageName2"
    ]
    }
  • file addition: ContentForCook (d--r------)
    [0.1113]
  • file addition: Content (d--r------)
    [0.1113]
  • file addition: Config (d--r------)
    [0.1113]
  • file addition: XComRWRealisticAimingAngles.ini (---r------)
    [0.259945]
    [RWRealisticAimingAngles.Override_X2AbilityToHitCalc_StandardAim]
    ;My "Good Angle" Bonus against Cover is not absurdly applied ONLY by my troops, not ONLY within a distance of 11 Tiles, not ONLY to Horizontal Angles but also to Vertical Angles (instead of the absurdly constant +20 Height Advantage) not ONLY as a proportional Bonus against lower targets but also as a proportional Malus against higher targets and my higher targets can now FINALLY realistically use as Cover the "buildings' ceilings" they're standing on (depending on how much of the border "hides them" from the shooter's view) and my Low Covers now FINALLY count as "Far Cover" when not immediately in front of the target but still partially hiding him from the shooter's view, yours?
    ;RESTRICTIONS MY ASS ;)
    ApplyGoodAngleBonusEvenFartherThan11TilesAway = true
    ApplyGoodAngleBonusNotOnlyForXComSoldiersButAlsoForAnyoneShooting = true
    ;Donations: paypal.me/krumiro
    ;GOOD ANGLE (HORIZONTAL ANGLE BONUS)
    ;You can change at which angle the Good Angle Bonus "starts and ends", either within a "full range" (from Perfectly Frontal to Fully Flanking) or within a shorter range.
    ;Personally, from 45 degrees (Half Flanking) to 5 degrees (almost Fully Flanking) seems appropriate BECAUSE when people use a tree (for example) to take High Cover, they don't just place themselves just North, East, South or West especially when the shooter is aiming from South-West but instead they realistically "conveniently adjust" their position "slightly" rotating around the tree (or slightly shifting behind the wall) as much as they can.
    MinimumGoodAngleBonusCoverReductionPercentage = 0 ;( 0% means Cover unchanged)
    MaximumGoodAngleBonusCoverReductionPercentage = 100 ;(100% means Cover completely ignored)
    MinimumGoodAngleBonusStartsAtThisHorizontalAngleBetweenLineOfFireAndCoverSurface = 45 ;(90 means Fully Frontal )
    MaximumGoodAngleBonusEndsAtThisHorizontalAngleBetweenLineOfFireAndCoverSurface = 5 ;( 0 means Fully Flanaking)
    ;HEIGHT ADVANTAGE (VERTICAL ANGLE BONUS AGAINST LOWER TARGETS IN COVER)
    ;Why just horizontal aiming angles had to affect cover protection?
    ;I always hated Default-XCom2 +20 Height Advantage not only for being absurdly constant independently from the vertical angle but also for being absurdly applied to anyone independently by their taking cover or not. Nonsense, had to stop. Now that target's Low/High Cover will be protective as intended only if at the same height of the shooter and gradually decreasing with increasing vertical aiming angle (from 0deg to 90deg).
    ;Collateral effect: "tall shooters" (such as Sparks or Sectopods) have a natural Height Advantage Aiming Bonus proportional to the height difference with the Target. ;)
    ;Change to your desired values but, personally, the Target's Cover should be completely ignored (100% Cover Reduction) not when the Shooter is completely above the target (0deg = Fully Vertical Line of Fire) but a little bit before (30deg).
    ApplyVerticalGoodAngleAgainstLowerTargetAsProportionalHeightAdvantage = true
    MinimumHeightAdvantageBonusCoverReductionPercentage = 0 ;( 0% means Cover unchanged)
    MaximumHeightAdvantageBonusCoverReductionPercentage = 100 ;(100% means Cover completely ignored)
    MinimumHeightAdvantageBonusStartsAtThisVerticalAngleBetweenLineOfFireAndCoverSurface = 90 ;(90 means Fully Horizontal Line of Fire)
    MaximumHeightAdvantageBonusEndsAtThisVerticalAngleBetweenLineOfFireAndCoverSurface = 30 ;( 0 means Fully Vertical Line of Fire)
    ;HEIGHT DISADVANTAGE (VERTICAL ANGLE MALUS AGAINST HIGHER TARGETS)
    ApplyVerticalBadAngleAgainstHigherTargetAsProportionalHeightDisadvantage = true
    ;The opposite is true for Targets in cover above the Shooter. This proportional Height Disadvantage Malus gives additional protection (negative value to the shooter) proportionally to how much the low cover on top of a building hides the target more than usual because of the vertical line of sight.
    ;YES! Finally a Building's or Mountain's Border now works as Cover! And the Cover Value it gives varies depending on how much the Border hides the target from the shooter's view, and therefore the more the target is away from the Border, the more he is hidden. ;)
    ;With the two effects combined if, for example, a target taking Low Cover on top of a building "takes a step back" (1 tile) he will receive much more that +20 Cover.
    ;HEIGHT ADVANTAGE/DISADVANTAGE DIFFICULTY BALANCE
    ;Therefore, although climbing on buildings/mountains doesn't give anymore a "constant" +20 Bonus against "anyone" below (but a realistically "proportional" one against lower enemies "in cover") it is compensated by receiving a lot of realistically proportional extra cover protection, thus elegantly preserving the difficulty balance originally intended by Firaxis and still making high positions as favourable as before (but in a realistic way). ;)
    ;HORIZONTAL AND VERTICAL ANGLE BONUSES COMBINED
    ;Automatic High Cover “Type Detection”!: “Simple”, “Tall”, “Long” High Cover or a combination of them. Determining whether to apply only Horizontal Aiming Good Angle Bonus, only Vertical Aiming Height Advantage Bonus or both simultaneously. For example: On a Target taking a “Simple” High Cover (such as a 1-Tile Rock) both Good Angle and Height Advantage Bonuses can as before be applied (BUT never cumulatively higher than the Cover Value they are reducing, for example: -40LowCover +28GoodAngle +12HeightAdvantage), on a Target taking instead a “Tall” High Cover (such as a tall Tree/Pillar) only Horizontal Aiming Angle Bonus can be applied (for as high as the Shooter climbs, the vertical Tree/Pillar still never offers a Vertical Angle Bonus), on a Target taking instead a “Long” High Cover (such as a long fence, standing the Target NOT at its edge) only Vertical Good Angle Bonus can with this update be applied (for as much as the Shooter on the building tries to “partially flank” the Target, the long fence still never offers an Horizontal Good Angle).
    ;FAR COVER
    AllowFarCoverToGiveSomeCoverProtection = true
    ;Personal concept: Low Cover between shooter and target but not immediately near target. Who said that your soldier cannot use that trashcan as cover only because he is not immediately in front of it? Nonsense, in my book if something is partially hiding you from view then it's partially giving you cover (between +1 and +20, proportionally to how far/much that far Low Cover is hiding the target from the shooter's view). ;)
    ;Far Cover is applied obviously only to Targets NOT already taking cover (because the Far Cover would not cover them but their already existing Cover) EXCEPT if they are taking Cover AND a Good Angle is reducing that Cover Value: Only in that case Far Cover can help the Target BUT never with a value higher than the existing Good Angle Bonus (So that the Target will never have cumulative Cover Values above 40/20). Example: 40HighCover -14GoodAngle +14FarCoverPreventingGoodAngle (Instead of +19FarCover). ;)
    ;EXTENDED COVER
    ;Other personal concept: High Cover extended by Low Cover: When a Target taking High Cover “with a Low Cover next to it” is being partially flanked, then the Horizontal Good Angle reducing the High Cover will be only “half applied” since the the Shooter is only flanking the “upper half” of the Target while his “lower half” is still protected by the Extended Low Cover. (Example: -40HighCover +38GoodAngle -19ExtendedLowCoverPreventingGoodAngle). This way a Target using High/Low Covers on 2 sides, the more he is flanked, the more his cover will be reduced from 40 to 20 (realistically gradually switching from High to Low Cover).
    ;CHECK TRUE LINE OF SIGHT
    GiveHitChanceZeroWhenTargetableEnemiesAreInsteadNotTrulyInLineOfSight = true
    ;Personally designed check to prevent shooting aliens behind walls. Why give 0% Hit Chance instead of simply preventing to target? Because I like that it gives me the opportunity to shoot anyway which, sometimes as a result, does environmental damage sometimes destroying or punching a hole in "what was blocking my view" for, possibly, a second regular shot in the next turn or by a squad-mate.
    ;FAIRLY APPLIED
    ;The modifiers apply also to Enemies targeting your Squad-mates (oR it wouldn't be fair) and don't apply against units who refuse to or cannot take cover (Sparks, Faceless, Berserkers...) or who are unaware of your presence (therefore not "taking" cover because unaware of danger) unless altering this variable below:
    OnlyAlertedTargetsCanHaveTheExtraProtectionOfFarCoverAndHeightDisadvantage = true
    ;CLASS OVERRIDES:
    ;+ModClassOverrides=(BaseGameClass="X2AbilityToHitCalc_StandardAim"
    ;EU ROLLS: XCOM 1 DICE-ROLL SYSTEM
    UseIndividualConsecutiveRollsForHitChanceCriticalChanceDodgeChance = false ;"false" will ignore the other 2 variables
    PrioritizeCriticalChanceOverDodgeChance = true ; Hit?Yes-->Critical?No-->Dodge? OR Hit?Yes-->Dodge?No-->Critical?
    AlwaysRollForBothDodgeAndCriticalEvenWhenOneUnsuccesful = false ;If both successful then they cancel out becoming Normal Hit
    ;Example: 90% Hit Chance with 10% Critical Chance on a Chrissalyd with 20% Dodge Chance
    ;XCOM1 - 3Rolls: FirstRoll90%Hit --> SecondRoll(10%of90%=)9%CriticalHit --> ThirdRoll(20%of81%=)16%Dodge
    ;XCOM1 - 3Rolls: (10%of 90%=) 9%CriticalHit, (90%- 9%-16%=)65%NormalHit, (20%of 81%=)16%Dodge, (100%-90%=)10%Miss
    ;XCOM2 - 1Roll : (10%of100%=)10%CriticalHit, (90%-10%-20%=)60%NormalHit, (20%of100%=)20%Dodge, (100%-90%=)10%Miss
    ;Example: 30% Hit Chance with 10% Critical Chance on a Chrissalyd with 20% Dodge Chance
    ;XCOM1 - 3Rolls: FirstRoll30%Hit --> SecondRoll(10%of30%=)3%CriticalHit --> ThirdRoll(20%of27%=)5%Dodge
    ;XCOM1 - 3Rolls: (10%of 30%=) 3%CriticalHit, (30%- 3%- 5%=)22%NormalHit, (20%of 27%=) 5%Dodge, (100%-30%=)70%Miss
    ;XCOM2 - 1Roll : (10%of100%=)10%CriticalHit, (30%-10%-20%=) 0%NormalHit, (20%of100%=)20%Dodge, (100%-30%=)70%Miss
    ;In XCOM2 the %Hit is "eaten" from the "left" by %Critical and from the "right" by Dodge "cutting" the %Hit into 3 parts %CriticalHit+%NormalHit+%Dodge and if %Dodge is large enough then it can "eat" all of the remaining %NormalHit or even some of the %CriticalHit
    ;EXTRA DICE-ROLL OPTIONS
    GuaranteedHitsCannotDodge = false
    IndirectFireGuaranteesHit = false
  • file addition: Base (d--r------)
    [0.259945]
  • file addition: XComGame.ini (----------)
    [0.270320]
    [RWRealisticAimingAnglesHL.X2DLCInfo_RWRealisticAimingAnglesHL]
    DLCIdentifier="RWRealisticAimingAnglesHL"
    [RWRealisticAimingAnglesHL CHModDependency]
    DisplayName="[WotC] RW Realistic Aiming Angles - Highlander compatible"
    +IncompatibleMods="RWRealisticAimingAngles"
    [RWRealisticAimingAngles CHModDependency]
    DisplayName="[WotC] RW Realistic Aiming Angles"
  • file addition: XComEngine.ini (----------)
    [0.270320]
    [Engine.ScriptPackages]
    +NonNativePackages=RWRealisticAimingAnglesHL
    [Engine.Engine]
    +ModClassOverrides=(BaseGameClass="X2AbilityToHitCalc_StandardAim", ModClass="Override_X2AbilityToHitCalc_StandardAim" )
  • file addition: XComEditor.ini (----------)
    [0.270320]
    [ModPackages]
    +ModPackages=RWRealisticAimingAnglesHL