Yet Another Forage Macro - yafm

Post your completed (working) macros here. Only for macros using MQ2Data syntax!

Moderator: MacroQuest Developers

pettdogg1
orc pawn
orc pawn
Posts: 24
Joined: Thu Nov 03, 2005 9:43 pm

Re: Yet Another Forage Macro - yafm

Post by pettdogg1 » Sun Apr 05, 2020 11:18 pm

I did quite a bit of revamping to this to let you set the ini to DESTROY for the ones you want to destroy. It will handle multiple foraged items now with no issues. It will stop foraging while you are attacking, have an xtar 1 or 2, or if you are hovering. I may tweak it a bit more to have it as an include for my main autoassist macro, but for now it seems to be working pretty good.

Code: Select all

|yafm2.mac
|Version 2.12
|Yet Another Forage Macro
|Ini File: yafm2.ini
|
|DESTROY = destroy
|x = keep at most x of this item (can set this to anything except 0.  0 will think you don't have it and set it to DefatulMax)
|EXAMPLE INI Settings:
|  [Default]
|  MaxSave=1000
|  [ForageList]
|  Air-Infused Spring Water=1000
|  Amber Water Worm=DESTROY
|
|New foraged items are added to the ini file automatically and are kept by default.
|
|Macro automatically ends when inventory is full to prevent infinite calls of HandleItem
|
|Release Notes
|v2.12 updated by pettdogg1
|Added some /echo options to let you know what you are foraged and quantities, could get crazier with this if we wanted
|Moved multiple foraged items outside of the handleitem function in to a While loop in the main function so it calls them in proper order
|Added a condition to halt foraging while you are fighting or have a mob on xtarget 1 or 2

#Event InventoryFull "#*#There are no open slots for the held item in your inventory.#*#"

||||||||||||||||||||
| Main
||||||||||||||||||||
sub Main
   /echo ${Macro} is now running, enjoy the goodies!!!
   /declare DefaultMaxSave int outer
   /declare IAmForaging int outer 0 |Lets the macro know you are actually foraging and not just grabbing something, not perfect but it helps
   /declare NumberOfItemsForaged int outer 0
   /declare WasSitting int outer 0
   /declare foragedItemCount int outer 0
   /declare destroyedItemCount int outer 0
   /declare keptItemCount int outer 0
   | Set DefaultMaxSave from Ini
   /varset DefaultMaxSave ${Ini[yafm2.ini,Default,MaxSave]}
   | If the DefaultMaxSave is not in Ini, enter it
   /if (!${DefaultMaxSave}) {
     /ini "yafm2.ini" "Default" "MaxSave" "1000"
     /varset DefaultMaxSave 1000
   }
   /echo DefaultMaxSave is ${DefaultMaxSave}
   | Verify that we have the ability to forage.
   /if (${Me.Skill[Forage]}==0) {
      /echo You cannot forage, silly person!
      /call Exit
   }
   |Main Forage Loop
   :Forage
   | If we can forage then do so as long as you are not fighting or have mobs on extended window
   /if (${Me.AbilityReady[Forage]} && !${Me.CombatState.Equal[Combat]} && !${Me.XTarget[1].ID} && !${Me.XTarget[2].ID} && !${Me.Hovering}) {
      | Stand up. Can't forage while sitting.
      /if (${Me.State.Equal[SIT]}) {
         /varset WasSitting 1
         /stand
         /delay 5
      }
      |Clears your cursor before attempting a forage
      /if (${Cursor.ID}) {
	      /autoinventory
         /delay 5
      }
      /doability forage
      /varset IAmForaging 1
      /delay 5
   }
   |If we successfully foraged something then take care of it.  This works for multiple foraged items, hence the while loop.
   /while (${Cursor.ID} && ${IAmForaging}) {
      /call HandleItem ${Cursor.ID}
      /varcalc foragedItemCount ${foragedItemCount}+1
   }
   /if ( ${WasSitting} && ${Me.Standing} ) {
      /echo Sitting back down now.
      /delay 2s
      /sit
      /varset WasSitting 0
      }
   /if ( ${IAmForaging} ) {
      /echo So far you have foraged ${foragedItemCount} items
      /echo You have kept ${keptItemCount} items
      /echo You have destroyed ${destroyedItemCount} items
   }
   /varset IAmForaging 0
   /goto :Forage
/return

||||||||||||||||||||
| HandleItem
||||||||||||||||||||
sub HandleItem(Item)
   /declare ItemSetting int local
   /declare ItemsHave int local
   |Make sure item currently on cursor is the one we foraged
   |Ensures we don't delete things we picked up between forages 
   /if (${Cursor.ID} == ${Item} && ${IAmForaging}) {
      /if  (${Ini[yafm2.ini,ForageList,${Cursor.Name}].Equal[DESTROY]}) {
         |Look up this item in yafm2.ini and DESTROY it if it's set to DESTROY
         /echo Destroying ${Cursor} per your INI Setting
         /destroy
         /varcalc destroyedItemCount ${destroyedItemCount}+1
      } else /if  (${Ini[yafm2.ini,ForageList,${Cursor.Name}]}) {
         |Keep it if its under your set limit
         /varset ItemSetting ${Ini[yafm2.ini,ForageList,${Cursor.Name}]} 
         /varset ItemsHave ${FindItemCount[=${Cursor}]} 
         /if (${ItemSetting}>${ItemsHave} && ${IAmForaging}) {
            |This will keep the item if you don't have the number set in your ini
            /echo You have ${ItemsHave} ${Cursor}. Keeping until ${ItemSetting}.
            /autoinventory
            |Check to see if our inventory is full
            /doevents
            /varcalc keptItemCount ${keptItemCount}+1
         } else /if (${ItemSetting}<=${ItemsHave} && ${IAmForaging} && ${ItemSetting}>0) {
            |This will destroy the item once it reaches the number in your ini
            /echo Destroying ${Cursor} because you only wanted ${Math.Calc[${ItemSetting}-1]} and you have ${ItemsHave}
            /destroy
            /varcalc destroyedItemCount ${destroyedItemCount}+1
         } 
      } else /if (!${ItemSetting} && ${IAmForaging}) {
            |Adds it to your ini if you do not have it set yet
            /ini "yafm2.ini" "ForageList" "${Cursor}" "${DefaultMaxSave}"
	         /echo Added ${Cursor} to ini, will keep ${ItemSetting} of them
            /varcalc keptItemCount ${keptItemCount}+1
         }  
   }
   /delay 5
/return

||||||||||||||||||||
| Event_InventoryFull
||||||||||||||||||||
Sub Event_InventoryFull
  /echo Inventory Full
  /call Exit
/return

||||||||||||||||||||
| Exit
||||||||||||||||||||
Sub Exit
  /echo Exiting
  /endmacro
/return
~Jax12

pettdogg1
orc pawn
orc pawn
Posts: 24
Joined: Thu Nov 03, 2005 9:43 pm

Re: Yet Another Forage Macro - yafm

Post by pettdogg1 » Thu Apr 23, 2020 10:08 pm

Updated a bit more to prepare to move this to an inc file for those that want to use it. Actually you can do that now, by just saving as an inc and taking out the Sub Main function and adding in something like:
/declare ForageOn int outer 1
/while ( ${ForageOn} ) {
/call Forage
}
to your main macro.

Code: Select all

|yafm2.mac
|Version 3.0
|
|Yet Another Forage Macro
|
|Ini File: yafm2.ini
|
| DESTROY = destroy
| x = keep at most x of this item (can set this to anything except 0.  0 will think you don't have it and set it to DefatulMax)
|EXAMPLE INI Settings:
|  [Default]
|  MaxSave=1000
|  [ForageList]
|  Air-Infused Spring Water=1000
|  Amber Water Worm=DESTROY
|
|New foraged items are added to the ini file automatically and are kept by default.
|
|Macro automatically ends when inventory is full to prevent infinite calls of HandleItem
|
|Release Notes
|v3.0 updated by pettdogg1 aka Jax12
|Moved forage to a function call as well to prepare to make this an include for those that want to use it elsewhere
|Added an event to stop the macro if you die
|Added bind options so you can type /forage on or /forage off or /forage to turn the forage function on and off or toggle it (its on by default)
|v2.12 updated by pettdogg1 aka Jax12
|Added some /echo options to let you know what you are foraged and quantities, could get crazier with this if we wanted
|Moved multiple foraged items outside of the handleitem function in to a While loop in the main function so it calls them in proper order
|Added a condition to halt foraging while you are fighting or have a mob on xtarget 1 or 2

#warning
#Event InventoryFull "#*#There are no open slots for the held item in your inventory.#*#"
#Event DelayOnZone "#*#You have entered#*#"
#Event DelayOnZone "#*#LOADING, PLEASE WAIT.#*#"
#bind ForageToggle /forage

||||||||||||||||||||
| Main
||||||||||||||||||||
sub Main
/declare ForageOn int outer 1
/call Do_Events
/while ( ${ForageOn} ) {
   /call Forage  
}
/return

sub Forage
   
   /if ( !${Defined[DefaultMaxSave]} ) /declare DefaultMaxSave int outer
   /if ( !${Defined[IAmForaging]} ) /declare IAmForaging int outer 0 |Lets the macro know you are actually foraging and not just grabbing something, not perfect but it helps
   /if ( !${Defined[NumberOfItemsForaged]} ) /declare NumberOfItemsForaged int outer 0
   /if ( !${Defined[WasSitting]} ) /declare WasSitting int outer 0
   /if ( !${Defined[foragedItemCount]} ) /declare foragedItemCount int outer 0
   /if ( !${Defined[destroyedItemCount]} ) /declare destroyedItemCount int outer 0
   /if ( !${Defined[keptItemCount]} ) /declare keptItemCount int outer 0
   /if ( !${Defined[ForagedInitialized]} ) /declare ForagedInitialized int outer 0
   /if ( !${ForagedInitialized}) {
      /varset ForagedInitialized 1
      |Set DefaultMaxSave from Ini
      /varset DefaultMaxSave ${Ini[yafm2.ini,Default,MaxSave]}
      |If the DefaultMaxSave is not in Ini, enter it
      /if (!${DefaultMaxSave}) {
         /ini "yafm2.ini" "Default" "MaxSave" "1000"
         /varset DefaultMaxSave 1000
      }
      /echo DefaultMaxSave is ${DefaultMaxSave}
      |Verify that we have the ability to forage.
      /if (${Me.Skill[Forage]}==0) {
         /echo You cannot forage, silly person!
         /call Exit
      }
   }
   |Main Forage Loop
   /if ( ${ForageOn} ) {
   /if ( ${Window[SpellBookWnd].Open}) {
	  /return
   }
   | If we can forage then do so as long as you are not fighting or have mobs on extended window
   /if (${Me.AbilityReady[Forage]} && ${Me.CombatState.NotEqual[Combat]} && !${Me.XTarget[1].ID} && !${Me.XTarget[2].ID} && !${Me.Hovering}) {
      | Stand up. Can't forage while sitting.
      /if (${Me.State.Equal[SIT]}) {
         /varset WasSitting 1
         /stand
         /delay 5
      }
      |Clears your cursor before attempting a forage
      /if (${Cursor.ID}) {
	      /autoinventory
         /delay 5
      }
      /doability forage
      /echo Trying to forage some stuff.  
      /delay 5
      /if (${Cursor.ID}) {
         /varset IAmForaging 1
         /echo Looks like forage worked, let me handle the items.
      }
   }
   |If we successfully foraged something then take care of it.  This works for multiple foraged items, hence the while loop.
   /while (${Cursor.ID} && ${IAmForaging}) {
      /call HandleItem ${Cursor.ID}
   }
   /if ( ${WasSitting} && ${Me.Standing} ) {
      /echo Sitting back down now.
      /delay 2s
      /sit
      /varset WasSitting 0
      }
   }
/return

||||||||||||||||||||
| HandleItem
||||||||||||||||||||
sub HandleItem(Item)
   /declare ItemSetting int local
   /declare ItemsHave int local
   |Make sure item currently on cursor is the one we foraged
   |Ensures we don't delete things we picked up between forages 
   |/echo Handling ${Cursor}. Stay tuned!
   /if (${Cursor.ID} == ${Item} && ${IAmForaging}) {
      /if  (${Ini[yafm2.ini,ForageList,${Cursor.Name}].Equal[DESTROY]}) {
         |Look up this item in yafm2.ini and DESTROY it if it's set to DESTROY
         /echo Destroying ${Cursor} per your INI Setting
         /destroy
         /varcalc destroyedItemCount ${destroyedItemCount}+1
      } else /if  (${Ini[yafm2.ini,ForageList,${Cursor.Name}]}) {
         |Keep it if its under your set limit
         /varset ItemSetting ${Ini[yafm2.ini,ForageList,${Cursor.Name}]} 
         /varset ItemsHave ${FindItemCount[=${Cursor}]} 
         /if (${ItemSetting}>${ItemsHave}) {
            |This will keep the item if you don't have as many as the number set in your ini
            /echo You have ${ItemsHave} ${Cursor}. Keeping until ${ItemSetting}.
            /autoinventory
            |Check to see if our inventory is full
            /doevents
            /varcalc keptItemCount ${keptItemCount}+1
         } else /if (${ItemSetting}<=${ItemsHave} && ${IAmForaging} && ${ItemSetting}>0) {
            |This will destroy the item once it reaches the number in your ini
            /echo Destroying ${Cursor} because you only wanted ${Math.Calc[${ItemSetting}-1]} and you have ${ItemsHave}
            /destroy
            /varcalc destroyedItemCount ${destroyedItemCount}+1
         } 
      } else /if (!${ItemSetting}) {
            |Adds it to your ini if you do not have it set yet
            /ini "yafm2.ini" "ForageList" "${Cursor}" "${DefaultMaxSave}"
	         /echo Added ${Cursor} to ini, will keep ${DefaultMaxSave} of them
            |Check to see if our inventory is full
            /doevents
            /varcalc keptItemCount ${keptItemCount}+1
      }  
   /varcalc foragedItemCount ${foragedItemCount}+1
   }
   /delay 5
   /if (!${Cursor.ID}) {
      /varset IAmForaging 0
      /echo Cursor is clear, all foraged items handled.
      /echo So far you have foraged ${foragedItemCount} items
      /echo You have kept ${keptItemCount} items
      /echo You have destroyed ${destroyedItemCount} items
   }
/return

|||||||||||||||||
|||BINDS
|||||||||||||||||
Sub Bind_ForageToggle(toggle)
/echo ${toggle}
	/if ( ${toggle.Equal[on]} || ${toggle.Equal[0]}  ) {
  	/echo Forage is now on, type /forage off to turn if off
 	/varset ForageOn 1
	} else /if ( ${toggle.Equal[off]} || ${toggle.Equal[0]}) {
  	/echo Forage is now off, type /forage on to turn if on
 	/varset ForageOn 0
	} else /if ( ${ForageOn} ) {
	/varset ForageOn 0
	} else /if (!${ForageOn} ) {
	/varset ForageOn 1
	}
/return

||||||||||||||||
|||EVENTS
||||||||||||||||
Sub Do_Events
	/doevents
/return
||||||||||||||||||||
| Event_InventoryFull
||||||||||||||||||||
Sub Event_InventoryFull
  /echo Inventory Full
  /call Exit
/return
||||||||Zoning!
Sub Event_DelayOnZone
    /echo Zoning, clearing cursor and turning off macro
    /afollow off
    /if (${Cursor.ID}) /call HandleItem ${Cursor.ID}
    |/endmacro
/return

||||||||||||||||||||
| Exit
||||||||||||||||||||
Sub Exit
  /echo Exiting
  /endmacro
/return
~Jax12

felismalum
decaying skeleton
decaying skeleton
Posts: 6
Joined: Sat Jan 09, 2021 3:12 pm

Re: Yet Another Forage Macro - yafm

Post by felismalum » Tue Apr 13, 2021 8:45 pm

Fixed the counting logic and fixed a bug where items would get stuck on the cursor. Few other minor details too.

Code: Select all

|yafm2.mac
|Version 3.1
|
|Yet Another Forage Macro
|
|Ini File: yafm2.ini
|
| DESTROY = destroy
| x = keep at most x of this item (can set this to anything except 0.  0 will think you don't have it and set it to DefatulMax)
|EXAMPLE INI Settings:
|  [Default]
|  MaxSave=1000
|  [ForageList]
|  Air-Infused Spring Water=1000
|  Amber Water Worm=DESTROY
|
|New foraged items are added to the ini file automatically and are kept by default.
|
|Macro automatically ends when inventory is full to prevent infinite calls of HandleItem
|
|Release Notes
|v3.1 updated by FelisMalum
|Fixed the math logic so it keeps the exact number of items specified.
|Changed the event to a /While loop to clear multiple items off the cursor outside of the forage functions.
|Adjusted delays so multiple items are less likely to get stuck on the cursor after foraging. On a multiple item forage this was causing 1
|item to get perpetually stuck on the cursor and increase item counts over the limit. In the event this does happen it will be cleared off by the new /while statement.
|Since the item is foraged on the the front end of the skill timer the new delays will not slow the overall speed of foraging.
|Added some color to the variables.
|v3.0 updated by pettdogg1 aka Jax12
|Moved forage to a function call as well to prepare to make this an include for those that want to use it elsewhere
|Added an event to stop the macro if you die
|Added bind options so you can type /forage on or /forage off or /forage to turn the forage function on and off or toggle it (its on by default)
|v2.12 updated by pettdogg1 aka Jax12
|Added some /echo options to let you know what you are foraged and quantities, could get crazier with this if we wanted
|Moved multiple foraged items outside of the handleitem function in to a While loop in the main function so it calls them in proper order
|Added a condition to halt foraging while you are fighting or have a mob on xtarget 1 or 2

#warning
#Event InventoryFull "#*#There are no open slots for the held item in your inventory.#*#"
#Event DelayOnZone "#*#You have entered#*#"
#Event DelayOnZone "#*#LOADING, PLEASE WAIT.#*#"
#bind ForageToggle /forage

||||||||||||||||||||
| Main
||||||||||||||||||||
sub Main
/declare ForageOn int outer 1
/echo \arMacro YAFM \ayv3.1 \arstarting.....
/call Do_Events
/while (${ForageOn}) {
    /call Forage  
}
/return

sub Forage
/if (!${Defined[DefaultMaxSave]}) /declare DefaultMaxSave int outer
/if (!${Defined[IAmForaging]}) /declare IAmForaging int outer 0 |Lets the macro know you are actually foraging and not just grabbing something, not perfect but it helps
/if (!${Defined[NumberOfItemsForaged]}) /declare NumberOfItemsForaged int outer 0
/if (!${Defined[WasSitting]}) /declare WasSitting int outer 0
/if (!${Defined[foragedItemCount]}) /declare foragedItemCount int outer 0
/if (!${Defined[destroyedItemCount]}) /declare destroyedItemCount int outer 0
/if (!${Defined[keptItemCount]}) /declare keptItemCount int outer 0
/if (!${Defined[ForagedInitialized]}) /declare ForagedInitialized int outer 0
/if (!${ForagedInitialized}) {
    /varset ForagedInitialized 1
    |Set DefaultMaxSave from Ini
    /varset DefaultMaxSave ${Ini[yafm2.ini,Default,MaxSave]}
    |If the DefaultMaxSave is not in Ini, enter it
    /if (!${DefaultMaxSave}) {
        /ini "yafm2.ini" "Default" "MaxSave" "1000"
        /varset DefaultMaxSave 1000
    }
    /echo DefaultMaxSave is \ay ${DefaultMaxSave}
    |Verify that we have the ability to forage.
    /if (${Me.Skill[Forage]}==0) {
        /echo You cannot forage, silly person!
        /call Exit
    }
}
|Main Forage Loop
/if ( ${ForageOn} ) {
    /if ( ${Window[SpellBookWnd].Open}) {
	   /return
    }
    |If we can forage then do so as long as you are not fighting or have mobs on extended window
    /if (${Me.AbilityReady[Forage]} && ${Me.CombatState.NotEqual[Combat]} && !${Me.XTarget[1].ID} && !${Me.XTarget[2].ID} && !${Me.Hovering}) {
        /delay 5
        |Stand up. Can't forage while sitting.
        /if (${Me.State.Equal[SIT]}) {
            /varset WasSitting 1
            /stand
            /delay 5
        }
        |Clears your cursor before attempting a forage
        /while (${Cursor.ID}) {
            /autoinventory
            /delay 5
        }
        /doability forage
        /echo Trying to forage some stuff.
        /delay 2s
        /if (${Cursor.ID}) {
            /varset IAmForaging 1
            /echo Looks like forage worked, let me handle the items.
        } else {
            /echo \agYou failed to forage anything
        }
    }
    |If we successfully foraged something then take care of it.  This works for multiple foraged items, hence the while loop.
    /while (${Cursor.ID} && ${IAmForaging}) {
        /call HandleItem ${Cursor.ID}
    }
    /if (${WasSitting} && ${Me.Standing}) {
        /echo Sitting back down now.
        /delay 2s
        /sit
        /varset WasSitting 0
    }
}
/return

||||||||||||||||||||
| HandleItem
||||||||||||||||||||
sub HandleItem(Item)
/declare ItemSetting int local
/declare ItemsHave int local
|Make sure item currently on cursor is the one we foraged
|Ensures we don't delete things we picked up between forages 
|/echo Handling ${Cursor}. Stay tuned!
/if (${Cursor.ID} == ${Item} && ${IAmForaging}) {
    /if  (${Ini[yafm2.ini,ForageList,${Cursor.Name}].Equal[DESTROY]}) {
        |Look up this item in yafm2.ini and DESTROY it if it's set to DESTROY
        /echo Destroying \ar ${Cursor} per your INI Setting
        /destroy
        /varcalc destroyedItemCount ${destroyedItemCount}+1
    } else /if  (${Ini[yafm2.ini,ForageList,${Cursor.Name}]}) {
        |Keep it if its under your set limit
        /varset ItemSetting ${Ini[yafm2.ini,ForageList,${Cursor.Name}]} 
        /varset ItemsHave ${FindItemCount[=${Cursor}]} 
        /if (${ItemSetting}>=${ItemsHave}) {
            |This will keep the item if you don't have as many as the number set in your ini
            /echo \atYou have now have \ay ${ItemsHave} \ar ${Cursor}\at. Keeping until \ay ${ItemSetting}.
            /autoinventory
            |Check to see if our inventory is full
            /doevents
            /varcalc keptItemCount ${keptItemCount}+1
        } else /if (${ItemSetting}<${ItemsHave} && ${IAmForaging} && ${ItemSetting}>0) {
            |This will destroy the item once it reaches the number in your ini
            /echo \atDestroying \ar ${Cursor} \atbecause you only wanted \ay ${ItemSetting} \atand you have \ay ${Math.Calc[${ItemsHave}-1]}
            /destroy
            /varcalc destroyedItemCount ${destroyedItemCount}+1
        } 
    } else /if (!${ItemSetting}) {
        |Adds it to your ini if you do not have it set yet
        /ini "yafm2.ini" "ForageList" "${Cursor}" "${DefaultMaxSave}"
	    /echo Added \ar ${Cursor} to ini, will keep \ay ${DefaultMaxSave} of them
        |Check to see if our inventory is full
        /doevents
        /varcalc keptItemCount ${keptItemCount}+1
    }  
    /varcalc foragedItemCount ${foragedItemCount}+1
}
/delay 5
/if (!${Cursor.ID}) {
    /varset IAmForaging 0
    /echo Cursor is clear, all foraged items handled.
    /echo So far you have foraged ${foragedItemCount} items
    /echo You have kept ${keptItemCount} items
    /echo You have destroyed ${destroyedItemCount} items
}
/return

|||||||||||||||||
|||BINDS
|||||||||||||||||
Sub Bind_ForageToggle(toggle)
/echo ${toggle}
/if (${toggle.Equal[on]} || ${toggle.Equal[0]}) {
    /echo Forage is now on, type /forage off to turn if off
 	/varset ForageOn 1
} else /if (${toggle.Equal[off]} || ${toggle.Equal[0]}) {
  	/echo Forage is now off, type /forage on to turn it on
 	/varset ForageOn 0
} else /if (${ForageOn}) {
	/varset ForageOn 0
} else /if (!${ForageOn}) {
	/varset ForageOn 1
}
/return

||||||||||||||||
|||EVENTS
||||||||||||||||
Sub Do_Events
/doevents
/return
||||||||||||||||||||
| Event_InventoryFull
||||||||||||||||||||
Sub Event_InventoryFull
/echo Inventory Full
/call Exit
/return
||||||||Zoning!
Sub Event_DelayOnZone
/echo Zoning, clearing cursor and turning off macro
/afollow off
/if (${Cursor.ID}) /call HandleItem ${Cursor.ID}
    |/endmacro
/return

||||||||||||||||||||
| Exit
||||||||||||||||||||
Sub Exit
/echo Exiting
/endmacro
/return

FrankJScott
naggy
naggy
Posts: 2128
Joined: Sun Feb 19, 2023 7:11 am

Updated Product Tips

Post by FrankJScott » Fri Jan 12, 2024 6:10 am

Please try Google before asking about Best Product Website 86b3ce3