{$CLEO .cs}
{$USE cleo+}
{$USE ini}
nop
script_name 'IMPTTRI'
wait 0
wait 0

0@ = 2

if
    load_dynamic_library 31@ "CLEO+.cleo"
jf @ILoveMyGirlfriendJessica
if
    get_dynamic_library_procedure 30@ "GetCleoPlusVersion" library 31@
then
    call_function_return 30@ num_params 0 pop 0 29@
end
free_dynamic_library 31@
if
    29@ >= 0x1020000
jf @ILoveMyGirlfriendJessica

31@ = 0
30@ = 0
29@ = 0

0@ = 1

if
    load_dynamic_library 31@ "CLEO.asi"
jf @ILoveMyGirlfriendJessica
if
    get_dynamic_library_procedure 30@ "_CLEO_GetVersion@0" library 31@
then
    call_function_return 30@ num_params 0 pop 0 29@
end
free_dynamic_library 29@
if
    29@ >= 0x5000000
jf @ILoveMyGirlfriendJessica

0@ = 0

if
    does_file_exist "cleo\ImprovedTargetTriangle.ini"
jf @ILoveMyGirlfriendJessica

if
    is_on_samp
then
    31@ = 0
    read_int_from_ini_file 31@ "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "DisableOnSAMP"
    if
        31@ > 0
    then
        terminate_this_custom_script
    end
end

if
    not is_game_first_start
then
    terminate_this_custom_script
end

31@ = 0
30@ = 0
29@ = 0

int iCodeCavePtr = 0
int iActiveFlag
int iVerifyValue, iTime
int iRed, iGreen, iBlue, iAlpha
int iBaseRedAddr, iBaseGreenAddr, iBaseBlueAddr
int iRedOutAddr, iGreenOutAddr, iBlueOutAddr, iColorMaxAddr
int iRangeAddr, iDistAddr
int iFadeRangeAddr, iFadeMultAddr, iAlphaAddr
int iJumpAddr, iRelativeJump
int i

float fGlobalSize, fPulseSize, fFadeRange
float fRed, fGreen, fBlue, fAlpha
float f1 , f2


// ============================================================
// Reduce target persistence delay
// 0x60B89A: add edx, 0x3E8 (1000 ms in vanilla)
// 0x60B89C: immediate DWORD, set to iTime milliseconds.
// ============================================================

iTime = 1000
read_int_from_ini_file iTime "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "PersistenceDelay"
clamp_int iTime min -1 max 10000 store_to iTime

read_memory iVerifyValue 0x60B89C size 4 virtual_protect 0
if and
    iVerifyValue == 1000
    iTime <> 1000
    iTime <> -1
then
    write_memory 0x60B89C size 4 value iTime virtual_protect 0
end

// Reuse iVerifyValue as the result of the optional size-hook validation.
iVerifyValue = 0

// ============================================================
// Triangle base color and alpha
// These values define the color at full health.
// Damage still blends the color toward pure red, like vanilla.
// ============================================================

iRed = 0
read_int_from_ini_file iRed "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "Red"
clamp_int iRed min 0 max 255 store_to iRed

iGreen = 255
read_int_from_ini_file iGreen "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "Green"
clamp_int iGreen min 0 max 255 store_to iGreen

iBlue = 0
read_int_from_ini_file iBlue "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "Blue"
clamp_int iBlue min 0 max 255 store_to iBlue

iAlpha = 255
read_int_from_ini_file iAlpha "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "Alpha"
clamp_int iAlpha min 0 max 255 store_to iAlpha

cset_lvar_float_to_lvar_int fRed = integer iRed
cset_lvar_float_to_lvar_int fGreen = integer iGreen
cset_lvar_float_to_lvar_int fBlue = integer iBlue
cset_lvar_float_to_lvar_int fAlpha = integer iAlpha

// ============================================================
// Fade distance beyond the original weapon.dat target range.
// ============================================================

fFadeRange = 0.0
read_float_from_ini_file fFadeRange "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "FadeRange"
clamp_float fFadeRange min 0.0 max 10000.0 store_to fFadeRange

// ============================================================
// Size & Pulse parameters
// ============================================================

fGlobalSize = 1.0
read_float_from_ini_file fGlobalSize "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "SizeMultiplier"
clamp_float fGlobalSize min 0.0 max 10.0 store_to fGlobalSize

iTime = 0
read_int_from_ini_file iTime "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "PulseDuration"
clamp_int iTime min 0 max 10000 store_to iTime

fPulseSize = 1.5
read_float_from_ini_file fPulseSize "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "PulseSize"
clamp_float fPulseSize min 0.0 max 10.0 store_to fPulseSize

// A value of 0.0 disables the size pulse; 1.0 has no visible size change.
iActiveFlag = 0
if
    fGlobalSize <> 1.0
then
    iActiveFlag = 1
end
if and
    iTime > 0
    fPulseSize > 0.0
    fPulseSize <> 1.0
then
    iActiveFlag = 1
end

if or
    iRed <> 0
    iGreen <> 255
    iBlue <> 0
    iAlpha <> 255
    fFadeRange <> 0.0
    iActiveFlag == 1
jf @ChangeScalingFactor

// ============================================================
// Validate original GTA SA 1.0 US bytes
// ============================================================

// Compute3rdPersonMouseTarget:
// mov ecx, [eax+4]
// mov eax, [esi+14]
read_memory iVerifyValue 0x60B6A0 size 4 virtual_protect 0
if
    iVerifyValue == 0x8B04488B
jf @ChangeScalingFactor

read_memory iVerifyValue 0x60B6A4 size 2 virtual_protect 0
if
    iVerifyValue == 0x1446
jf @ChangeScalingFactor

// Original target-range stack code (TEST + MOV [ESP+0C], ECX)
read_memory iVerifyValue 0x60B6A9 size 2 virtual_protect 0
if
    iVerifyValue == 0xC085
jf @ChangeScalingFactor

read_memory iVerifyValue 0x60B6AB size 4 virtual_protect 0
if
    iVerifyValue == 0x0C244C89
jf @ChangeScalingFactor

// Original distance calculation
read_memory iVerifyValue 0x60BBC2 size 4 virtual_protect 0
if
    iVerifyValue == 0x862C25D8
jf @ChangeScalingFactor

read_memory iVerifyValue 0x60BBC6 size 2 virtual_protect 0
if
    iVerifyValue == 0x0085
jf @ChangeScalingFactor

// Original vertex-color instruction
read_memory iVerifyValue 0x60BFCC size 4 virtual_protect 0
if
    iVerifyValue == 0xD9703589
jf @ChangeScalingFactor

read_memory iVerifyValue 0x60BFD0 size 2 virtual_protect 0
if
    iVerifyValue == 0x00C4
jf @ChangeScalingFactor

// Original health-based color calculation at 0x60BB27.
read_memory iVerifyValue 0x60BB27 size 1 virtual_protect 0
if
    iVerifyValue == 0xD9
jf @ChangeScalingFactor

read_memory iVerifyValue 0x60BB28 size 4 virtual_protect 0
if
    iVerifyValue == 0x85862405
jf @ChangeScalingFactor

// Original zero-health branch at 0x60BB72.
read_memory iVerifyValue 0x60BB72 size 2 virtual_protect 0
if
    iVerifyValue == 0xDB32
jf @ChangeScalingFactor

read_memory iVerifyValue 0x60BB74 size 4 virtual_protect 0
if
    iVerifyValue == 0x0F245C88
jf @ChangeScalingFactor

read_memory iVerifyValue 0x60BB78 size 4 virtual_protect 0
if
    iVerifyValue == 0x0E245C88
jf @ChangeScalingFactor

// Validate the final-size hook independently from the color/fade hooks.
// 0x60BC08: fadd dword ptr [0x85A5C8] ; 0x60BC0E: conditional branch.
// iVerifyValue: 0 = size hook unavailable, 1 = size hook valid.
iVerifyValue = 0
if
    iActiveFlag == 1
then
    read_memory i 0x60BC08 size 4 virtual_protect 0
    if
        i == 0xA5C805D8
    then
        read_memory i 0x60BC0C size 2 virtual_protect 0
        if
            i == 0x0085
        then
            iVerifyValue = 1
        end
    end
end

// ============================================================
// Allocate code cave and data.
// Highest used byte: offset 0x980 + 3 = 0x983.
// 2440 bytes (0x988) leave four bytes of safety padding.
// ============================================================

allocate_memory iCodeCavePtr size 2440
if
    iCodeCavePtr == 0
then
    terminate_this_custom_script
end

// Data addresses
iRangeAddr = iCodeCavePtr + 0xC0
iDistAddr = iCodeCavePtr + 0xC4
iFadeRangeAddr = iCodeCavePtr + 0xC8
iFadeMultAddr = iCodeCavePtr + 0xCC
iAlphaAddr = iCodeCavePtr + 0xD0

// Data used by the configurable RGB calculation.
iBaseRedAddr = iCodeCavePtr + 0x960
iBaseGreenAddr = iCodeCavePtr + 0x964
iBaseBlueAddr = iCodeCavePtr + 0x968
iRedOutAddr = iCodeCavePtr + 0x96C
iGreenOutAddr = iCodeCavePtr + 0x970
iBlueOutAddr = iCodeCavePtr + 0x974
iColorMaxAddr = iCodeCavePtr + 0x978

// The configured alpha is the maximum alpha before the distance fade.
// With FadeRange=0, use a fixed multiplier instead of dividing by zero;
// a custom Alpha can therefore still use the alpha hook on its own.
f1 = 255.0
if
    fFadeRange <> 0.0
then
    f1 = fAlpha
    f1 /= fFadeRange
end

write_struct_offset iCodeCavePtr offset 0xC0 size 4 value 0.0
write_struct_offset iCodeCavePtr offset 0xC4 size 4 value 0.0
write_struct_offset iCodeCavePtr offset 0xC8 size 4 value fFadeRange
write_struct_offset iCodeCavePtr offset 0xCC size 4 value f1
write_struct_offset iCodeCavePtr offset 0xD0 size 4 value 0

// Base RGB values are stored separately from executable code.
write_struct_offset iCodeCavePtr offset 0x960 size 4 value fRed
write_struct_offset iCodeCavePtr offset 0x964 size 4 value fGreen
write_struct_offset iCodeCavePtr offset 0x968 size 4 value fBlue
write_struct_offset iCodeCavePtr offset 0x96C size 4 value 0
write_struct_offset iCodeCavePtr offset 0x970 size 4 value 0
write_struct_offset iCodeCavePtr offset 0x974 size 4 value 0
write_struct_offset iCodeCavePtr offset 0x978 size 4 value 255.0

// Runtime state for the timer-driven color and size pulse.
// The current health ratio is captured directly from Vanilla's ST(0) at 0x60BB27.
// CTimer::m_snTimeInMilliseconds at 0xB7CB84 provides the pulse clock.
write_struct_offset iCodeCavePtr offset 0x900 size 4 value 0            // Last target ped
write_struct_offset iCodeCavePtr offset 0x904 size 4 value 0.0          // Last health ratio (raw bits)
write_struct_offset iCodeCavePtr offset 0x908 size 4 value 1.0          // Displayed health ratio
write_struct_offset iCodeCavePtr offset 0x90C size 4 value 1.0          // Health ratio at pulse start
write_struct_offset iCodeCavePtr offset 0x910 size 4 value 1.0          // Target health ratio
write_struct_offset iCodeCavePtr offset 0x914 size 4 value 0            // Pulse start time
write_struct_offset iCodeCavePtr offset 0x918 size 4 value 0            // Pulse active flag
write_struct_offset iCodeCavePtr offset 0x91C size 4 value iTime        // Pulse duration in ms

// PulseSize=0 disables only the size pulse; values below 1.0 shrink, above 1.0 enlarge.
f1 = 0.0
if
    fPulseSize > 0.0
then
    f1 = fPulseSize
    f1 -= 1.0
end
write_struct_offset iCodeCavePtr offset 0x920 size 4 value f1            // PulseSize - 1.0 (or 0 when disabled)
write_struct_offset iCodeCavePtr offset 0x924 size 4 value 1.0          // Current pulse size multiplier
write_struct_offset iCodeCavePtr offset 0x928 size 4 value fGlobalSize  // Global size multiplier
write_struct_offset iCodeCavePtr offset 0x92C size 4 value 1.0          // Current health sample from Vanilla
write_struct_offset iCodeCavePtr offset 0x930 size 4 value 0            // Elapsed time
write_struct_offset iCodeCavePtr offset 0x934 size 4 value 0.0          // Normalized elapsed time
write_struct_offset iCodeCavePtr offset 0x938 size 4 value 0.0          // Smoothstep temporary
write_struct_offset iCodeCavePtr offset 0x93C size 4 value 1.0          // Smoothstep progress
write_struct_offset iCodeCavePtr offset 0x940 size 4 value 3.0          // Smoothstep constant
f1 = 255.0
f1 -= fRed
write_struct_offset iCodeCavePtr offset 0x944 size 4 value f1            // Red headroom
write_struct_offset iCodeCavePtr offset 0x948 size 4 value 64.0         // Maximum red boost
write_struct_offset iCodeCavePtr offset 0x94C size 4 value 0.0          // Current red boost
write_struct_offset iCodeCavePtr offset 0x954 size 4 value 1.0          // Multiplier baseline

// Precalculate 1 / PulseDuration once. The timer helper uses FMUL instead
// of the slower per-frame FIDIV.
f1 = 0.0
if
    iTime > 0
then
    cset_lvar_float_to_lvar_int f2 = integer iTime
    f1 = 1.0
    f1 /= f2
end
write_struct_offset iCodeCavePtr offset 0x958 size 4 value f1

// Keep the ScalingFactor storage clear of the executable code above.
write_struct_offset iCodeCavePtr offset 0x980 size 4 value 0.82499999

// ============================================================
// 1. Capture original range and extend target acquisition range
// Hook: 0x60B6A9
//
// ECX still contains CWeaponInfo::m_fTargetRange here. Save the original
// value for alpha fading, then give vanilla code range + FadeRange.
// TEST runs before the MOVs; subsequent MOV/x87 instructions preserve EFLAGS
// for the original JE at 0x60B6AF.
// ============================================================

// test eax, eax
write_struct_offset iCodeCavePtr offset 0x00 size 2 value 0xC085

// mov [rangeAddr], ecx
write_struct_offset iCodeCavePtr offset 0x02 size 2 value 0x0D89
write_struct_offset iCodeCavePtr offset 0x04 size 4 value iRangeAddr

// mov [esp+0C], ecx
write_struct_offset iCodeCavePtr offset 0x08 size 4 value 0x0C244C89

// fld dword ptr [esp+0C]
write_struct_offset iCodeCavePtr offset 0x0C size 4 value 0x0C2444D9

// fadd dword ptr [FadeRangeAddr]
write_struct_offset iCodeCavePtr offset 0x10 size 2 value 0x05D8
write_struct_offset iCodeCavePtr offset 0x12 size 4 value iFadeRangeAddr

// fstp dword ptr [esp+0C]
write_struct_offset iCodeCavePtr offset 0x16 size 4 value 0x0C245CD9

// jmp back to 0x60B6AF
write_struct_offset iCodeCavePtr offset 0x1A size 1 value 0xE9
iJumpAddr = iCodeCavePtr + 0x1F
iRelativeJump = 0x60B6AF - iJumpAddr
write_struct_offset iCodeCavePtr offset 0x1B size 4 value iRelativeJump


// ============================================================
// 2. Capture player-to-target distance
// Hook: 0x60BBC2
// ============================================================

// fst dword ptr [DistAddr]
write_struct_offset iCodeCavePtr offset 0x40 size 2 value 0x15D9
write_struct_offset iCodeCavePtr offset 0x42 size 4 value iDistAddr

// Execute original: fsub dword ptr [0x85862C]
write_struct_offset iCodeCavePtr offset 0x46 size 2 value 0x25D8
write_struct_offset iCodeCavePtr offset 0x48 size 4 value 0x85862C

// jmp back to 0x60BBC8
write_struct_offset iCodeCavePtr offset 0x4C size 1 value 0xE9
iJumpAddr = iCodeCavePtr + 0x51
iRelativeJump = 0x60BBC8 - iJumpAddr
write_struct_offset iCodeCavePtr offset 0x4D size 4 value iRelativeJump


// ============================================================
// 3. Calculate fade alpha and modify original vertex color
// Hook: 0x60BFCC
//
// alpha = clamp((originalRange + FadeRange - Dist) * (Alpha / FadeRange), 0, Alpha)
// Preserve incoming EFLAGS because the original MOV does not modify them.
// ============================================================

// pushfd
write_struct_offset iCodeCavePtr offset 0x60 size 1 value 0x9C

// push eax
write_struct_offset iCodeCavePtr offset 0x61 size 1 value 0x50

// push edx
write_struct_offset iCodeCavePtr offset 0x62 size 1 value 0x52

// fld dword ptr [rangeAddr]
write_struct_offset iCodeCavePtr offset 0x63 size 2 value 0x05D9
write_struct_offset iCodeCavePtr offset 0x65 size 4 value iRangeAddr

// fadd dword ptr [FadeRangeAddr]
write_struct_offset iCodeCavePtr offset 0x69 size 2 value 0x05D8
write_struct_offset iCodeCavePtr offset 0x6B size 4 value iFadeRangeAddr

// fsub dword ptr [DistAddr]
write_struct_offset iCodeCavePtr offset 0x6F size 2 value 0x25D8
write_struct_offset iCodeCavePtr offset 0x71 size 4 value iDistAddr

// fmul dword ptr [fadeMultiplierAddr]
write_struct_offset iCodeCavePtr offset 0x75 size 2 value 0x0DD8
write_struct_offset iCodeCavePtr offset 0x77 size 4 value iFadeMultAddr

// fistp dword ptr [alphaAddr]
write_struct_offset iCodeCavePtr offset 0x7B size 2 value 0x1DDB
write_struct_offset iCodeCavePtr offset 0x7D size 4 value iAlphaAddr

// mov edx, [alphaAddr]
write_struct_offset iCodeCavePtr offset 0x81 size 2 value 0x158B
write_struct_offset iCodeCavePtr offset 0x83 size 4 value iAlphaAddr

// cmp edx, 0
write_struct_offset iCodeCavePtr offset 0x87 size 2 value 0xFA83
write_struct_offset iCodeCavePtr offset 0x89 size 1 value 0x00

// jge +2
write_struct_offset iCodeCavePtr offset 0x8A size 2 value 0x027D

// xor edx, edx
write_struct_offset iCodeCavePtr offset 0x8C size 2 value 0xD231

// cmp edx, Alpha
write_struct_offset iCodeCavePtr offset 0x8E size 2 value 0xFA81
write_struct_offset iCodeCavePtr offset 0x90 size 4 value iAlpha

// jle +5
write_struct_offset iCodeCavePtr offset 0x94 size 2 value 0x057E

// mov edx, Alpha
write_struct_offset iCodeCavePtr offset 0x96 size 1 value 0xBA
write_struct_offset iCodeCavePtr offset 0x97 size 4 value iAlpha

// and esi, 0x00FFFFFF
write_struct_offset iCodeCavePtr offset 0x9B size 2 value 0xE681
write_struct_offset iCodeCavePtr offset 0x9D size 4 value 0x00FFFFFF

// shl edx, 24
write_struct_offset iCodeCavePtr offset 0xA1 size 2 value 0xE2C1
write_struct_offset iCodeCavePtr offset 0xA3 size 1 value 0x18

// or esi, edx
write_struct_offset iCodeCavePtr offset 0xA4 size 2 value 0xD609

// pop edx
write_struct_offset iCodeCavePtr offset 0xA6 size 1 value 0x5A

// pop eax
write_struct_offset iCodeCavePtr offset 0xA7 size 1 value 0x58

// popfd: restore the original flags before the original MOV instruction
write_struct_offset iCodeCavePtr offset 0xA8 size 1 value 0x9D

// Execute original: mov [0xC4D970], esi
write_struct_offset iCodeCavePtr offset 0xA9 size 2 value 0x3589
write_struct_offset iCodeCavePtr offset 0xAB size 4 value 0x00C4D970

// jmp back to 0x60BFD2
write_struct_offset iCodeCavePtr offset 0xAF size 1 value 0xE9
iJumpAddr = iCodeCavePtr + 0xB4
iRelativeJump = 0x60BFD2 - iJumpAddr
write_struct_offset iCodeCavePtr offset 0xB0 size 4 value iRelativeJump


// ============================================================
// 4. Timer-driven target-health and pulse hooks
//
// At 0x60BB27, ST(0) already contains the normalized health ratio.
// The positive-health hook samples it with a non-popping FST, then uses that
// same value for the existing RGB routine. No second CPed health read occurs.
// ESI is the target-ped pointer at this point, matching the Rev6 target check.
//
// The zero-health hook only intercepts Vanilla's existing black branch.
// The size hook applies the pulse after distance scaling and the global size.
// A shared timer helper calculates smoothstep progress once per draw in either
// the positive-health or zero-health path; the size hook reuses that progress.
//
// Code regions: RGB +100..+2B3, size +300..+33F, zero-health +400..+4BF, timer helper +600.
// Runtime data: +900..+954; base RGB data: +960..+978; ScalingFactor: +980.
// ============================================================

// Machine code block: CodeCave + 0x100..0x2B3
write_struct_offset iCodeCavePtr offset 0x100 size 4 value 0x0000BD55
// fst dword ptr [ebp+92C]: sample ST(0) without popping the health ratio.
// The following six NOPs replace the old FLD/FSTP pair; ST(0) remains the
// same health ratio that vanilla later consumes at 0x60BB7F.
write_struct_offset iCodeCavePtr offset 0x104 size 4 value 0x95D90000
write_struct_offset iCodeCavePtr offset 0x108 size 4 value 0x0000092C
write_struct_offset iCodeCavePtr offset 0x10C size 4 value 0x90909090
write_struct_offset iCodeCavePtr offset 0x110 size 4 value 0x509C9090
write_struct_offset iCodeCavePtr offset 0x114 size 4 value 0xF0895251
write_struct_offset iCodeCavePtr offset 0x118 size 4 value 0x0900853B
write_struct_offset iCodeCavePtr offset 0x11C size 4 value 0x850F0000
write_struct_offset iCodeCavePtr offset 0x120 size 4 value 0x00000093
write_struct_offset iCodeCavePtr offset 0x124 size 4 value 0x092C958B
write_struct_offset iCodeCavePtr offset 0x128 size 4 value 0x953B0000
write_struct_offset iCodeCavePtr offset 0x12C size 4 value 0x00000904
write_struct_offset iCodeCavePtr offset 0x130 size 4 value 0x840F3772
write_struct_offset iCodeCavePtr offset 0x134 size 4 value 0x000000B7
write_struct_offset iCodeCavePtr offset 0x138 size 4 value 0x09049589
write_struct_offset iCodeCavePtr offset 0x13C size 4 value 0x95890000
write_struct_offset iCodeCavePtr offset 0x140 size 4 value 0x00000910
write_struct_offset iCodeCavePtr offset 0x144 size 4 value 0x09089589
write_struct_offset iCodeCavePtr offset 0x148 size 4 value 0x95890000
write_struct_offset iCodeCavePtr offset 0x14C size 4 value 0x0000090C
write_struct_offset iCodeCavePtr offset 0x150 size 4 value 0x091885C7
write_struct_offset iCodeCavePtr offset 0x154 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x158 size 4 value 0x85C70000
write_struct_offset iCodeCavePtr offset 0x15C size 4 value 0x0000094C
write_struct_offset iCodeCavePtr offset 0x160 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x164 size 4 value 0x000086E9
write_struct_offset iCodeCavePtr offset 0x168 size 4 value 0x04958900
write_struct_offset iCodeCavePtr offset 0x16C size 4 value 0x8B000009
write_struct_offset iCodeCavePtr offset 0x170 size 4 value 0x00090885
write_struct_offset iCodeCavePtr offset 0x174 size 4 value 0x0C858900
write_struct_offset iCodeCavePtr offset 0x178 size 4 value 0x89000009
write_struct_offset iCodeCavePtr offset 0x17C size 4 value 0x00091095
write_struct_offset iCodeCavePtr offset 0x180 size 4 value 0x1CBD8300
write_struct_offset iCodeCavePtr offset 0x184 size 4 value 0x00000009
write_struct_offset iCodeCavePtr offset 0x188 size 4 value 0x84A11774
write_struct_offset iCodeCavePtr offset 0x18C size 4 value 0x8900B7CB
write_struct_offset iCodeCavePtr offset 0x190 size 4 value 0x00091485
write_struct_offset iCodeCavePtr offset 0x194 size 4 value 0x1885C700
write_struct_offset iCodeCavePtr offset 0x198 size 4 value 0x01000009
write_struct_offset iCodeCavePtr offset 0x19C size 4 value 0xEB000000
write_struct_offset iCodeCavePtr offset 0x1A0 size 4 value 0x1885C74E
write_struct_offset iCodeCavePtr offset 0x1A4 size 4 value 0x00000009
write_struct_offset iCodeCavePtr offset 0x1A8 size 4 value 0xC7000000
write_struct_offset iCodeCavePtr offset 0x1AC size 4 value 0x00094C85
write_struct_offset iCodeCavePtr offset 0x1B0 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x1B4 size 4 value 0x8938EB00
write_struct_offset iCodeCavePtr offset 0x1B8 size 4 value 0x00090085
write_struct_offset iCodeCavePtr offset 0x1BC size 4 value 0x2C958B00
write_struct_offset iCodeCavePtr offset 0x1C0 size 4 value 0x89000009
write_struct_offset iCodeCavePtr offset 0x1C4 size 4 value 0x00090495
write_struct_offset iCodeCavePtr offset 0x1C8 size 4 value 0x10958900
write_struct_offset iCodeCavePtr offset 0x1CC size 4 value 0x89000009
write_struct_offset iCodeCavePtr offset 0x1D0 size 4 value 0x00090895
write_struct_offset iCodeCavePtr offset 0x1D4 size 4 value 0x0C958900
write_struct_offset iCodeCavePtr offset 0x1D8 size 4 value 0xC7000009
write_struct_offset iCodeCavePtr offset 0x1DC size 4 value 0x00091885
write_struct_offset iCodeCavePtr offset 0x1E0 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x1E4 size 4 value 0x4C85C700
write_struct_offset iCodeCavePtr offset 0x1E8 size 4 value 0x00000009
write_struct_offset iCodeCavePtr offset 0x1EC size 4 value 0x5A000000
write_struct_offset iCodeCavePtr offset 0x1F0 size 4 value 0x09E85859
write_struct_offset iCodeCavePtr offset 0x1F4 size 4 value 0xD9000004
write_struct_offset iCodeCavePtr offset 0x1F8 size 4 value 0x00091085
write_struct_offset iCodeCavePtr offset 0x1FC size 4 value 0x0CA5D800
write_struct_offset iCodeCavePtr offset 0x200 size 4 value 0xD8000009
write_struct_offset iCodeCavePtr offset 0x204 size 4 value 0x00093C8D
write_struct_offset iCodeCavePtr offset 0x208 size 4 value 0x0C85D800
write_struct_offset iCodeCavePtr offset 0x20C size 4 value 0xD9000009
write_struct_offset iCodeCavePtr offset 0x210 size 4 value 0x0009089D
write_struct_offset iCodeCavePtr offset 0x214 size 4 value 0x1085D900
write_struct_offset iCodeCavePtr offset 0x218 size 4 value 0xD8000009
write_struct_offset iCodeCavePtr offset 0x21C size 4 value 0x0009448D
write_struct_offset iCodeCavePtr offset 0x220 size 4 value 0x4885D900
write_struct_offset iCodeCavePtr offset 0x224 size 4 value 0xDF000009
write_struct_offset iCodeCavePtr offset 0x228 size 4 value 0xEB0272F1
write_struct_offset iCodeCavePtr offset 0x22C size 4 value 0xD9D8DD08
write_struct_offset iCodeCavePtr offset 0x230 size 4 value 0x00094885
write_struct_offset iCodeCavePtr offset 0x234 size 4 value 0xD8E8D900
write_struct_offset iCodeCavePtr offset 0x238 size 4 value 0x00093CA5
write_struct_offset iCodeCavePtr offset 0x23C size 4 value 0xD9C9DE00
write_struct_offset iCodeCavePtr offset 0x240 size 4 value 0x00094C9D
write_struct_offset iCodeCavePtr offset 0x244 size 4 value 0x85D99D00
write_struct_offset iCodeCavePtr offset 0x248 size 4 value 0x00000908
write_struct_offset iCodeCavePtr offset 0x24C size 4 value 0x091085D9
write_struct_offset iCodeCavePtr offset 0x250 size 4 value 0xC0D90000
write_struct_offset iCodeCavePtr offset 0x254 size 4 value 0x09608DD8
write_struct_offset iCodeCavePtr offset 0x258 size 4 value 0xE8D90000
write_struct_offset iCodeCavePtr offset 0x25C size 4 value 0x8DD8E2D8
write_struct_offset iCodeCavePtr offset 0x260 size 4 value 0x00000978
write_struct_offset iCodeCavePtr offset 0x264 size 4 value 0x85D8C1DE
write_struct_offset iCodeCavePtr offset 0x268 size 4 value 0x0000094C
write_struct_offset iCodeCavePtr offset 0x26C size 4 value 0x096C9DDB
write_struct_offset iCodeCavePtr offset 0x270 size 4 value 0xD8DD0000
write_struct_offset iCodeCavePtr offset 0x274 size 4 value 0x8DD8C0D9
write_struct_offset iCodeCavePtr offset 0x278 size 4 value 0x00000964
write_struct_offset iCodeCavePtr offset 0x27C size 4 value 0x09709DDB
write_struct_offset iCodeCavePtr offset 0x280 size 4 value 0xC0D90000
write_struct_offset iCodeCavePtr offset 0x284 size 4 value 0x09688DD8
write_struct_offset iCodeCavePtr offset 0x288 size 4 value 0x9DDB0000
write_struct_offset iCodeCavePtr offset 0x28C size 4 value 0x00000974
write_struct_offset iCodeCavePtr offset 0x290 size 4 value 0x096C858B
write_struct_offset iCodeCavePtr offset 0x294 size 4 value 0x44880000
write_struct_offset iCodeCavePtr offset 0x298 size 4 value 0x858B1224
write_struct_offset iCodeCavePtr offset 0x29C size 4 value 0x00000970
write_struct_offset iCodeCavePtr offset 0x2A0 size 4 value 0x13244488
write_struct_offset iCodeCavePtr offset 0x2A4 size 4 value 0x0974858B
write_struct_offset iCodeCavePtr offset 0x2A8 size 4 value 0xC3880000
write_struct_offset iCodeCavePtr offset 0x2AC size 4 value 0x0000E95D
write_struct_offset iCodeCavePtr offset 0x2B0 size 4 value 0x00000000

// Machine code block: CodeCave + 0x300..0x33F
write_struct_offset iCodeCavePtr offset 0x300 size 4 value 0x0000BD55
write_struct_offset iCodeCavePtr offset 0x304 size 4 value 0x85D91000
write_struct_offset iCodeCavePtr offset 0x308 size 4 value 0x0000093C
write_struct_offset iCodeCavePtr offset 0x30C size 4 value 0xE1D8E8D9
write_struct_offset iCodeCavePtr offset 0x310 size 4 value 0x09208DD8
write_struct_offset iCodeCavePtr offset 0x314 size 4 value 0x85D80000
write_struct_offset iCodeCavePtr offset 0x318 size 4 value 0x00000954
write_struct_offset iCodeCavePtr offset 0x31C size 4 value 0x09249DD9
write_struct_offset iCodeCavePtr offset 0x320 size 4 value 0xD8DD0000
write_struct_offset iCodeCavePtr offset 0x324 size 4 value 0xA5C805D8
write_struct_offset iCodeCavePtr offset 0x328 size 4 value 0x8DD80085
write_struct_offset iCodeCavePtr offset 0x32C size 4 value 0x00000928
write_struct_offset iCodeCavePtr offset 0x330 size 4 value 0x09248DD8
write_struct_offset iCodeCavePtr offset 0x334 size 4 value 0xE95D0000
write_struct_offset iCodeCavePtr offset 0x338 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x33C size 4 value 0x00000000

// Machine code block: CodeCave + 0x400..0x4BF
write_struct_offset iCodeCavePtr offset 0x400 size 4 value 0x0000BD55
write_struct_offset iCodeCavePtr offset 0x404 size 4 value 0x509C1000
write_struct_offset iCodeCavePtr offset 0x408 size 4 value 0x3BF08952
write_struct_offset iCodeCavePtr offset 0x40C size 4 value 0x00090085
write_struct_offset iCodeCavePtr offset 0x410 size 4 value 0x8B4F7500
write_struct_offset iCodeCavePtr offset 0x414 size 4 value 0x00090495
write_struct_offset iCodeCavePtr offset 0x418 size 4 value 0x0FD28500
write_struct_offset iCodeCavePtr offset 0x41C size 4 value 0x00008384
write_struct_offset iCodeCavePtr offset 0x420 size 4 value 0x0485C700
write_struct_offset iCodeCavePtr offset 0x424 size 4 value 0x00000009
write_struct_offset iCodeCavePtr offset 0x428 size 4 value 0x8B000000
write_struct_offset iCodeCavePtr offset 0x42C size 4 value 0x00090885
write_struct_offset iCodeCavePtr offset 0x430 size 4 value 0x0C858900
write_struct_offset iCodeCavePtr offset 0x434 size 4 value 0xC7000009
write_struct_offset iCodeCavePtr offset 0x438 size 4 value 0x00091085
write_struct_offset iCodeCavePtr offset 0x43C size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x440 size 4 value 0x4C85C700
write_struct_offset iCodeCavePtr offset 0x444 size 4 value 0x00000009
write_struct_offset iCodeCavePtr offset 0x448 size 4 value 0xA1000000
write_struct_offset iCodeCavePtr offset 0x44C size 4 value 0x00B7CB84
write_struct_offset iCodeCavePtr offset 0x450 size 4 value 0x09148589
write_struct_offset iCodeCavePtr offset 0x454 size 4 value 0x85C70000
write_struct_offset iCodeCavePtr offset 0x458 size 4 value 0x00000918
write_struct_offset iCodeCavePtr offset 0x45C size 4 value 0x00000001
write_struct_offset iCodeCavePtr offset 0x460 size 4 value 0x858942EB
write_struct_offset iCodeCavePtr offset 0x464 size 4 value 0x00000900
write_struct_offset iCodeCavePtr offset 0x468 size 4 value 0x090485C7
write_struct_offset iCodeCavePtr offset 0x46C size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x470 size 4 value 0x85C70000
write_struct_offset iCodeCavePtr offset 0x474 size 4 value 0x00000910
write_struct_offset iCodeCavePtr offset 0x478 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x47C size 4 value 0x090885C7
write_struct_offset iCodeCavePtr offset 0x480 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x484 size 4 value 0x85C70000
write_struct_offset iCodeCavePtr offset 0x488 size 4 value 0x0000090C
write_struct_offset iCodeCavePtr offset 0x48C size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x490 size 4 value 0x091885C7
write_struct_offset iCodeCavePtr offset 0x494 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x498 size 4 value 0x85C70000
write_struct_offset iCodeCavePtr offset 0x49C size 4 value 0x0000094C
write_struct_offset iCodeCavePtr offset 0x4A0 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x4A4 size 4 value 0xE89D585A
write_struct_offset iCodeCavePtr offset 0x4A8 size 4 value 0x00000154
write_struct_offset iCodeCavePtr offset 0x4AC size 4 value 0x88DB305D
write_struct_offset iCodeCavePtr offset 0x4B0 size 4 value 0x880F245C
write_struct_offset iCodeCavePtr offset 0x4B4 size 4 value 0xE90E245C
write_struct_offset iCodeCavePtr offset 0x4B8 size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x4BC size 4 value 0x00000000

// Machine code block: CodeCave + 0x600..0x67F
write_struct_offset iCodeCavePtr offset 0x600 size 4 value 0xBD83509C
write_struct_offset iCodeCavePtr offset 0x604 size 4 value 0x00000918
write_struct_offset iCodeCavePtr offset 0x608 size 4 value 0xA1677400
write_struct_offset iCodeCavePtr offset 0x60C size 4 value 0x00B7CB84
write_struct_offset iCodeCavePtr offset 0x610 size 4 value 0x0914852B
write_struct_offset iCodeCavePtr offset 0x614 size 4 value 0x853B0000
write_struct_offset iCodeCavePtr offset 0x618 size 4 value 0x0000091C
write_struct_offset iCodeCavePtr offset 0x61C size 4 value 0x85894A73
write_struct_offset iCodeCavePtr offset 0x620 size 4 value 0x00000930
write_struct_offset iCodeCavePtr offset 0x624 size 4 value 0x093085DB
// fmul dword ptr [ebp+958]: multiply elapsed milliseconds by the
// precomputed reciprocal of PulseDuration instead of using FIDIV each frame.
write_struct_offset iCodeCavePtr offset 0x628 size 4 value 0x8DD80000
write_struct_offset iCodeCavePtr offset 0x62C size 4 value 0x00000958
write_struct_offset iCodeCavePtr offset 0x630 size 4 value 0x09349DD9
write_struct_offset iCodeCavePtr offset 0x634 size 4 value 0x85D90000
write_struct_offset iCodeCavePtr offset 0x638 size 4 value 0x00000934
write_struct_offset iCodeCavePtr offset 0x63C size 4 value 0x85D9C0D8
write_struct_offset iCodeCavePtr offset 0x640 size 4 value 0x00000940
write_struct_offset iCodeCavePtr offset 0x644 size 4 value 0x9DD9E1D8
write_struct_offset iCodeCavePtr offset 0x648 size 4 value 0x00000938
write_struct_offset iCodeCavePtr offset 0x64C size 4 value 0x85D9D8DD
write_struct_offset iCodeCavePtr offset 0x650 size 4 value 0x00000934
write_struct_offset iCodeCavePtr offset 0x654 size 4 value 0x09348DD8
write_struct_offset iCodeCavePtr offset 0x658 size 4 value 0x8DD80000
write_struct_offset iCodeCavePtr offset 0x65C size 4 value 0x00000938
write_struct_offset iCodeCavePtr offset 0x660 size 4 value 0x093C9DD9
write_struct_offset iCodeCavePtr offset 0x664 size 4 value 0x14EB0000
write_struct_offset iCodeCavePtr offset 0x668 size 4 value 0x091885C7
write_struct_offset iCodeCavePtr offset 0x66C size 4 value 0x00000000
write_struct_offset iCodeCavePtr offset 0x670 size 4 value 0x85C70000
write_struct_offset iCodeCavePtr offset 0x674 size 4 value 0x0000093C
write_struct_offset iCodeCavePtr offset 0x678 size 4 value 0x3F800000
write_struct_offset iCodeCavePtr offset 0x67C size 4 value 0x00C39D58

// Patch the three MOV EBP, immediate instructions with the allocated cave base.
iJumpAddr = iCodeCavePtr
write_struct_offset iCodeCavePtr offset 0x102 size 4 value iJumpAddr
write_struct_offset iCodeCavePtr offset 0x302 size 4 value iJumpAddr
write_struct_offset iCodeCavePtr offset 0x402 size 4 value iJumpAddr

// Return from the positive-health RGB hook to the original common color code.
iJumpAddr = iCodeCavePtr + 0x2B2
iRelativeJump = 0x60BB7C - iJumpAddr
write_struct_offset iCodeCavePtr offset 0x2AE size 4 value iRelativeJump

// Return from the final-size hook to the original conditional branch.
iJumpAddr = iCodeCavePtr + 0x33C
iRelativeJump = 0x60BC0E - iJumpAddr
write_struct_offset iCodeCavePtr offset 0x338 size 4 value iRelativeJump

// Return from the zero-health hook after replaying Vanilla's black-color path.
iJumpAddr = iCodeCavePtr + 0x4BC
iRelativeJump = 0x60BB7C - iJumpAddr
write_struct_offset iCodeCavePtr offset 0x4B8 size 4 value iRelativeJump


// ============================================================
// 5. Install hooks independently for each enabled feature
// ============================================================

// Range extension, distance capture, and alpha fade.
if or
    fFadeRange <> 0.0
    iAlpha <> 255
then
    write_memory 0x60B6A9 size 1 value 0xE9 virtual_protect 0
    iRelativeJump = iCodeCavePtr - 0x60B6AE
    write_memory 0x60B6AA size 4 value iRelativeJump virtual_protect 0
    write_memory 0x60B6AE size 1 value 0x90 virtual_protect 0

    write_memory 0x60BBC2 size 1 value 0xE9 virtual_protect 0
    iRelativeJump = iCodeCavePtr + 0x40
    iRelativeJump -= 0x60BBC7
    write_memory 0x60BBC3 size 4 value iRelativeJump virtual_protect 0
    write_memory 0x60BBC7 size 1 value 0x90 virtual_protect 0

    write_memory 0x60BFCC size 1 value 0xE9 virtual_protect 0
    iRelativeJump = iCodeCavePtr + 0x60
    iRelativeJump -= 0x60BFD1
    write_memory 0x60BFCD size 4 value iRelativeJump virtual_protect 0
    write_memory 0x60BFD1 size 1 value 0x90 virtual_protect 0
end

// Positive-health hook: required for custom RGB or for the Rev6-style color pulse.
// ST(0) already holds the health ratio at this hook. The cave stores it
// directly with FST (without popping), then continues the custom RGB path.
if or
    iRed <> 0
    iGreen <> 255
    iBlue <> 0
    iTime > 0
then
    write_memory 0x60BB27 size 1 value 0xE9 virtual_protect 0
    iRelativeJump = iCodeCavePtr + 0x100
    iRelativeJump -= 0x60BB2C
    write_memory 0x60BB28 size 4 value iRelativeJump virtual_protect 0
    make_nop 0x60BB2C size 0x46
end

// Zero-health hook: only installed when a timed pulse is enabled.
// The cave replays the three original black-color instructions unchanged.
if
    iTime > 0
then
    write_memory 0x60BB72 size 1 value 0xE9 virtual_protect 0
    iRelativeJump = iCodeCavePtr + 0x400
    iRelativeJump -= 0x60BB77
    write_memory 0x60BB73 size 4 value iRelativeJump virtual_protect 0
    make_nop 0x60BB77 size 5
end

// Final-size hook: applies global SizeMultiplier and the timer-based PulseSize.
if
    iVerifyValue == 1
then
    write_memory 0x60BC08 size 1 value 0xE9 virtual_protect 0
    iRelativeJump = iCodeCavePtr + 0x300
    iRelativeJump -= 0x60BC0D
    write_memory 0x60BC09 size 4 value iRelativeJump virtual_protect 0
    write_memory 0x60BC0D size 1 value 0x90 virtual_protect 0
end

// ============================================================
// Change Scaling Factor
// ============================================================

:ChangeScalingFactor
f1 = 0.82499999
read_float_from_ini_file f1 "cleo\ImprovedTargetTriangle.ini" section "SETTINGS" key "ScalingFactor"
clamp_float f1 min 0.0 max 10.0 store_to f1

read_memory iVerifyValue 0x60BBFC size 4 virtual_protect 0
if and
    iVerifyValue == 0x86D1DC
    f1 <> 0.82499999
    f1 <> 0.0 
then
    if
        iCodeCavePtr == 0
    then
        allocate_memory iCodeCavePtr size 4
        write_memory iCodeCavePtr size 4 value f1 virtual_protect 1
        write_memory 0x60BBFC size 4 value iCodeCavePtr virtual_protect 0
    else    
        write_struct_offset iCodeCavePtr offset 0x980 size 4 value f1
        i = iCodeCavePtr + 0x980
        write_memory 0x60BBFC size 4 value i virtual_protect 0
    end
end


// Finish installation. The code cave handles the complete color/size pulse; no CLEO loop is needed.
if
    iCodeCavePtr <> 0
then
    forget_memory iCodeCavePtr
end

terminate_this_custom_script



:ILoveMyGirlfriendJessica
TIMERA = 0

repeat
    wait 0
    if
        0@ == 2
    then
        print_formatted_now "Improved Target Triangle: CLEO+ 1.2.0 or newer required. It's a plugin for CLEO. Please download and install it." time 200
    end
    if
        0@ == 1
    then
        print_formatted_now "Improved Target Triangle: CLEO 5.0 or newer required. The mod is disabled." time 200
    end
    if
        0@ == 0
    then
        print_formatted_now "Improved Target Triangle: Failed to find the file 'ImprovedTargetTriangle.ini'. Check the file path or file name." time 200
    end
    if and
        is_player_control_on $PLAYER_CHAR
        not fading
    jf @ILoveMyGirlfriendJessica
until TIMERA > 10000

terminate_this_custom_script