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

0@ = 0

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

0@ = 1

if
    0AAB: does_file_exist "cleo\PropertyPriceTweaker.ini"
jf @ILoveMyGirlfriendJessica

0@ = 0

int iBuffer, iBufferIndex, iCounter, iPickupHdle, iIndex, iLastPickup, iCPickupSize, iPoolPtr, iPickupPtr, iType, iMissionsPassed, iGameSaved, i
float fPriceMult, fPriceMultTemp, f

read_float_from_ini_file fPriceMult "cleo\PropertyPriceTweaker.ini" section "SETTINGS" key "Multiplier"
clamp_float fPriceMult min 0.0 max 100.0 store_to fPriceMult
if or
    fPriceMult == 0.0
    fPriceMult == 1.0
then
    terminate_this_custom_script
end

get_label_pointer iBuffer = label @Buffer

for i = 0 to 396 step 4
    write_struct_offset iBuffer offset i size 4 value -1
end   

// Property Pickup Money Display Patch for values > 300.000
write_memory 0x455B42 size 1 value 0x8B virtual_protect 0
write_memory 0x455B43 size 1 value 0x44 virtual_protect 0
write_memory 0x455B44 size 1 value 0x24 virtual_protect 0
write_memory 0x455B45 size 1 value 0x1C virtual_protect 0
write_memory 0x455B46 size 1 value 0x8B virtual_protect 0
write_memory 0x455B47 size 1 value 0x40 virtual_protect 0
write_memory 0x455B48 size 1 value 0x08 virtual_protect 0
write_memory 0x455B50 size 1 value 0x89 virtual_protect 0
write_memory 0x455B51 size 1 value 0xC2 virtual_protect 0
write_memory 0x455B52 size 1 value 0x90 virtual_protect 0

// Find pickup pool parameters
read_memory iCPickupSize 0x48AE39 size 1 virtual_protect 0  //  CPickupObjectSize 0x20   
read_memory iPoolPtr 0x48ADC3 size 4 virtual_protect 0  //  pickup pool start 0x9788C0
read_memory iIndex 0x457190 size 4 virtual_protect 0    //  maxObjects 620
iIndex -= 1 //  last index

iLastPickup = iIndex * iCPickupSize
iLastPickup += iPoolPtr

set_script_event_save_confirmation 1 label @CleanUpBeforeSave var_slot iGameSaved


while true
    wait 1000
    get_int_stat i = integer_stat 147  // Missions Passed    
    if or
        i <> iMissionsPassed
        iGameSaved > -1
    then
        iMissionsPassed = i
        wait 0
        wait 0
        wait 2000
        if
            iGameSaved == -1
        then
            gosub @RevertPickups
        end
        iGameSaved = -1
        wait 0    
        gosub @PatchPickups
    end
end    

{
// CPickup Structure
00000000 m_fRevenueValue dd ?
00000004 m_pObject       dd ?         
00000008 m_dwAmmo        dd ?
0000000C m_dwRegenerationTime dd ?
00000010 m_vPos CCompressedVector ?
00000016 m_nMoneyPerDay  dw ?         
00000018 m_wModelId      dw ?
0000001A m_wReferenceIndex dw ?       
0000001C m_PickupType    db ?
0000001D m_nFlags        db ?
0000001E _pad            db 2 dup(?)
00000020 CPickup         ends
}

:PatchPickups
fPriceMultTemp = fPriceMult
iCounter = 0
iBufferIndex = 0

for iPickupPtr = iPoolPtr to iLastPickup step iCPickupSize
    read_struct_offset iType iPickupPtr offset 0x1C size 1
    if
        iType == 18 // PropertyForSale
    then
        if
            iBufferIndex < 400
        return_if_false
        i = iPickupPtr - iPoolPtr
        iIndex = i / iCPickupSize 
        read_struct_offset i iPickupPtr offset 0x1A size 2
        i *= 0x10000    // shift reference index to the upper word
        iPickupHdle = i + iIndex   // add the index to create a handle
        write_struct_offset iBuffer offset iBufferIndex size 4 value iPickupHdle  // Write handle into buffer for reverting it later
        iBufferIndex += 4
        gosub @SetPrice        
    end
    iCounter += 1
    if
        iCounter > 100
    then
        wait 0  // Reduce overheat
        iCounter = 0
    end
end
return


:RevertPickups
fPriceMultTemp = 1.0
fPriceMultTemp /= fPriceMult

for iBufferIndex = 0 to 396 step 4
    read_struct_offset iPickupHdle iBuffer offset iBufferIndex size 4
    if
        iPickupHdle > -1
    return_if_false
    if
        does_pickup_exist iPickupHdle
    then
        get_pickup_pointer iPickupHdle store_to iPickupPtr
        read_struct_offset iType iPickupPtr offset 0x1C size 1
        if
            iType == 18 // PropertyForSale
        then
            gosub @SetPrice
        end
    end
    write_struct_offset iBuffer offset iBufferIndex size 4 value -1
end
return


:SetPrice
read_struct_offset i iPickupPtr offset 0x08 size 4
cset_lvar_float_to_lvar_int f = i 
f *= fPriceMultTemp
f += 0.2    // Prevent float precision problem
cset_lvar_int_to_lvar_float i = f
write_struct_offset iPickupPtr offset 0x08 size 4 value i
return


:CleanUpBeforeSave
gosub @RevertPickups
return_script_event


:Buffer
hex
    00(400)
end


:ILoveMyGirlfriendJessica
TIMERA = 0

repeat
    if
        0@ == 0
    then
        0AD1: print_formatted_now "Property Price Tweaker: CLEO+ 1.2.0 or newer required. Please download and install it in cleo folder." time 100
    else
        0AD1: print_formatted_now "Property Price Tweaker: Failed to find the .ini file. Check the file path or file name." time 100
    end
    wait 0
    if or
        89E7: not is_player_control_on $PLAYER_CHAR
        016B: fading
    then
        TIMERA = 0
    end
until TIMERA > 8000         

terminate_this_custom_script