{$UNDEF SCRIPT_ID}{$DEFINE SCRIPT_ID := '5d89af42-7819-45b6-b4fb-886971d700bf'} {$UNDEF SCRIPT_REVISION}{$DEFINE SCRIPT_REVISION := '7'} {$IFDEF WINDOWS}{$DEFINE SCRIPT_GUI}{$ENDIF} {$I SRL-B/osr.simba} {$I BashLib/osr.simba} {$I BashLib/optional/handlers/aichat.simba} { ---------------------------------------------------------------------------------- ~~~ Need Support? Contact Me ~~~ Discord Server: https://discord.gg/qsmKs5uKfR Discord ID: big.aussie Email: thebigaussie@proton.me Github: https://github.com/BigAussie ---------------------------------------------------------------------------------- } var STONYBASALTINPUT: Integer = 10; ICYBASALTINPUT: Integer = 10; TESALTMINEINPUT: Integer = 10; EFHSALTMINEINPUT: Integer = 1000; URTSALTMINEINPUT: Integer = 1000; BASALTONLYCHECK: Boolean = False; RSW: TRSWalker; begin Login.PlayerIndex := 1; end; type EState = ( STATE_DESCENT_STAIRS, STATE_WALKTOMINESPOTS, STATE_MINEROCK, STATE_MINEBASALT, STATE_MINEEFHSALT, STATE_MINETESALT, STATE_MINEURTSALT, STATE_ASCEND_STAIRS, STATE_NOTEBASALT, STATE_CRAFTBASALT ); SaltMiner = record (TBaseBankScript) CurrentState: EState; Basalt: TRSitem; NotedBasalt: TRSitem; EfhSalt: TRSitem; TeSalt: TRSitem; UrtSalt: TRSitem; StonyBasalt: TRSitem; IcyBasalt: TRSitem; StartXP: Integer; CurrentXP: Integer; DesiredSaltCount: Integer; CraftedStonyBasalt: Integer; CraftedIcyBasalt: Integer; StartTeSaltCount: Integer; StartEfhSaltCount: Integer; StartUrtSaltCount: Integer; StartStonyBasaltCount: Integer; StartIcyBasaltCount: Integer; BasaltType: string; ItemTotal: Int32; BasaltValue: Int32; StonyBasaltValue: Int32; IcyBastaltValue: Int32; EfhSaltValue: Int32; TeSaltValue: Int32; UrtSaltValue: Int32; Snowflake: TRSNPC; StairsDescend: TRSObject; StairsAscend: TRSObject; BasaltRock: TRSObject; EfhSaltRock: TRSObject; TeSaltRock: TRSObject; UrtSaltRock: TRSObject; end; var Timer: TStopWatch; procedure TAntiban.Setup(); override; begin Antiban.Skills := [ERSSkill.TOTAL, ERSSKILL.MINING]; Antiban.MinZoom := 20; Antiban.MaxZoom := 40; inherited; end; procedure SaltMiner.SetupNPC(); begin with Snowflake do begin Setup(6, 8, [[6882, 710]]); // Needs to be 6 because the RSW is a little inaccurate here. Setup(['Snowflake']); Filter.MinimapDot := True; Finder.ColorClusters += [ CTS2(10261136, 35, 0.11, 0.09), CTS2(3475818, 15, 0.26, 1.10), 4 ]; end; end; procedure SaltMiner.SetupObjects(); begin StairsDescend.Setup(1, [ [6862, 688], [6863, 683] ]); StairsDescend.UpText := ['Stairs']; StairsAscend.Setup(4, [ [10431, 4512], [10431, 4512], [10431, 4512], [10436, 4512], [10432, 4505], [10437, 4507] ]); StairsAscend.UpText := ['Steps']; with BasaltRock do begin Setup(6, [[10416, 4572], [10402, 4585], [10427, 4593], [10387, 4589], [10384, 4602], [10378, 4577], [10391, 4561]]); Setup(['Basalt rocks']); Finder.Colors += CTS2(1776416, 1, 0.01, 0.01); Finder.MinShortSide := 20; end; with EfhSaltRock do begin Setup(6, [[10412, 4586], [10404, 4590], [10403, 4577], [10399, 4565], [10403, 4558], [10411, 4557], [10396, 4594], [10391, 4590]]); Setup(['Efh salt rocks']); Finder.Colors += CTS2(10781312, 20, 0.05, 0.37); Finder.MinShortSide := 20; end; with TeSaltRock do begin Setup(6, [[10424, 4586], [10424, 4598], [10419, 4603], [10416, 4598], [10408, 4598]]); Setup(['Te salt rocks']); Finder.Colors += CTS2(1321945, 17, 0.02, 0.80); Finder.MinShortSide := 20; end; with UrtSaltRock do begin Setup(6, [[10389, 4581], [10400, 4569], [10383, 4574], [10399, 4558], [10383, 4563], [10379, 4567], [10375, 4587], [10371, 4594]]); Setup(['Urt salt rocks']); Finder.Colors += CTS2(8824452, 19, 0.06, 0.37); Finder.MinShortSide := 20; end; end; function SaltMiner.FindSnowflake(): Boolean; var Attempts: Integer; ApproachTiles: TPointArray; Approach: TPoint; begin Attempts := 0; ApproachTiles := [[6878, 706], [6886, 706], [6878, 714], [6886, 714]]; while Attempts < 3 do begin if Snowflake.IsVisible() then Exit(True); Approach := ApproachTiles[Attempts mod Length(ApproachTiles)]; if RSW.AtTile([6882, 710], 8) then RSW.WalkBlind(Approach, 4) else RSW.WalkBlind(Approach, 8); RSW.MakePointVisible([6882, 710]); if Snowflake.IsVisible() then Exit(True); Antiban.RandomRotate(); Inc(Attempts); end; Result := Snowflake.IsVisible(); end; function SaltMiner.DESCENT_STAIRS(): Boolean; begin if not StairsDescend.IsVisible() then begin RSW.WalkBlind([6870, 683], 35); end; if StairsDescend.IsVisible() then begin StairsDescend.Click(); WaitUntil(Minimap.PercentBlack() >= 10, 100, 5000); while Minimap.IsPlayerMoving() do Wait(100); end; end; function SaltMiner.ASCEND_STAIRS(): Boolean; begin Result := False; if not StairsAscend.IsVisible() then begin RSW.WalkBlind([10431, 4521], 35); end; if StairsAscend.IsVisible() then begin StairsAscend.Click(); WaitUntil(Minimap.PercentBlack() <= 10, 100, 5000); while Minimap.IsPlayerMoving() do Wait(100); Result := True; end; end; function SaltMiner.WALKTOMINESPOTS(): Boolean; begin RSW.WalkBlind([10408, 4578], 35); while Minimap.IsPlayerMoving() do begin if BasaltRock.IsVisible() then Exit(False); Wait(100); end; end; function SaltMiner.MineRock(Rock: TRSObject; Salt: TRSItem; DesiredSaltCount: Integer): Boolean; var PlayerBox: TBox; XP: Integer; T, ReportTimer: TStopWatch; MiningDuration: Int32; begin PlayerBox := MainScreen.GetPlayerBox(); XP := XPBar.Read(); ReportTimer.Start(); while Inventory.CountItemStack(Salt) < DesiredSaltCount do begin if not Rock.IsVisible() then Antiban.RandomRotate(); if Rock.IsVisible() then begin Rock.Click(); MiningDuration := RandomRange(600, 750); T.Start(); while (T.ElapsedTime < MiningDuration) do begin if XPBar.Read() > XP then begin XP := XPBar.Read(); T.Start(); end; if (SRL.PercentShift(PlayerBox, 500) >= 14) then T.Start(); if Inventory.CountItemStack(Salt) >= DesiredSaltCount then break; Wait(100); WL.Activity.Restart(); // Report every 3 seconds so its not so spammy if ReportTimer.ElapsedTime >= 3000 then begin Self.Report(); ReportTimer.Start(); end; end; end; end; Result := Inventory.CountItemStack(Salt) >= DesiredSaltCount; end; function SaltMiner.MINEBASALT(): Boolean; var PlayerBox: TBox; XP: Integer; T, ReportTimer: TStopWatch; MiningDuration: Int32; ItemCount: Int32; begin PlayerBox := MainScreen.GetPlayerBox(); XP := XPBar.Read(); ReportTimer.Start(); while not Inventory.IsFull() do begin if not BasaltRock.IsVisible() then Antiban.RandomRotate(); if BasaltRock.IsVisible() then begin BasaltRock.Click(); MiningDuration := RandomRange(600, 750); T.Start(); while (T.ElapsedTime < MiningDuration) do begin if XPBar.Read() > XP then begin XP := XPBar.Read(); T.Start(); end; if (SRL.PercentShift(PlayerBox, 500) >= 14) then T.Start(); Wait(100); WL.Activity.Restart(); if ReportTimer.ElapsedTime >= 3000 then begin Self.Report(); ReportTimer.Start(); end; end; end; end; ItemCount := Inventory.CountItem(Basalt); ItemTotal += ItemCount; Result := not Inventory.IsFull(); end; function SaltMiner.CRAFTBASALT(BasaltType: string): Boolean; var CraftedAmount: Integer; begin WriteLn('Crafting ' + BasaltType); Inventory.Use(Basalt, TeSalt); WaitUntil(Make.IsOpen(), 375, 1500); if Make.IsOpen(2000, 100) then begin CraftedAmount := Inventory.CountItem(Basalt); Make.Select(BasaltType, Make.QUANTITY_ALL, True); Wait(RandomRange(500, 1000)); if BasaltType = 'Stony basalt' then Self.CraftedStonyBasalt := Self.CraftedStonyBasalt + CraftedAmount else if BasaltType = 'Icy basalt' then Self.CraftedIcyBasalt := Self.CraftedIcyBasalt + CraftedAmount; Result := True; end else begin Result := False; end; end; function SaltMiner.NOTEBASALT(): Boolean; begin if not Snowflake.IsVisible() then if not FindSnowflake() then begin WriteLn('Failed to find Snowflake'); Exit(False); end; if Inventory.SetSelectedItem(Basalt) then begin if Snowflake.SelectOption(['Use']) then begin Minimap.WaitFlag(); Result := WaitUntil(not Inventory.IsFull(), 100, 15000); end; end else WriteLn('Failed to click on Basalt in the inventory'); end; procedure SaltMiner.GetState(); var StonyBasaltCount, IcyBasaltCount, TeSaltCount, UrtSaltCount, EfhSaltCount: Integer; begin StonyBasaltCount := Inventory.CountItemStack(StonyBasalt); IcyBasaltCount := Inventory.CountItemStack(IcyBasalt); TeSaltCount := Inventory.CountItemStack(TeSalt); UrtSaltCount := Inventory.CountItemStack(UrtSalt); EfhSaltCount := Inventory.CountItemStack(EfhSalt); if BASALTONLYCHECK then begin if Inventory.IsFull() then begin if Minimap.PercentBlack() > 10 then Self.CurrentState := STATE_ASCEND_STAIRS else Self.CurrentState := STATE_NOTEBASALT; end else begin if Minimap.PercentBlack() > 10 then begin if BasaltRock.IsVisible() or RSW.AtTile([10411, 4565], 12) then Self.CurrentState := STATE_MINEBASALT else Self.CurrentState := STATE_WALKTOMINESPOTS; end else Self.CurrentState := STATE_DESCENT_STAIRS; end; end else begin if (((TESALTMINEINPUT = 0) or (TeSaltCount >= TESALTMINEINPUT)) and ((EFHSALTMINEINPUT = 0) or (EfhSaltCount >= EFHSALTMINEINPUT)) and ((URTSALTMINEINPUT = 0) or (UrtSaltCount >= URTSALTMINEINPUT)) and ((STONYBASALTINPUT = 0) or (Self.CraftedStonyBasalt >= STONYBASALTINPUT)) and ((ICYBASALTINPUT = 0) or (Self.CraftedIcyBasalt >= ICYBASALTINPUT))) then begin WriteLn('Desired amount reached.'); Logout.ClickLogout(); TerminateScript(); end else begin if (TESALTMINEINPUT > 0) and (TeSaltCount < TESALTMINEINPUT) then begin Self.CurrentState := STATE_MINETESALT; Self.DesiredSaltCount := TESALTMINEINPUT; end else if (EFHSALTMINEINPUT > 0) and (EfhSaltCount < EFHSALTMINEINPUT) then begin Self.CurrentState := STATE_MINEEFHSALT; Self.DesiredSaltCount := EFHSALTMINEINPUT; end else if (URTSALTMINEINPUT > 0) and (UrtSaltCount < URTSALTMINEINPUT) then begin Self.CurrentState := STATE_MINEURTSALT; Self.DesiredSaltCount := URTSALTMINEINPUT; end else begin if ((STONYBASALTINPUT > 0) and (Self.CraftedStonyBasalt >= STONYBASALTINPUT)) and ((ICYBASALTINPUT > 0) and (Self.CraftedIcyBasalt >= ICYBASALTINPUT)) then begin WriteLn('Desired amount of both Stony Basalt and Icy Basalt reached.'); Logout.ClickLogout(); TerminateScript(); end else if ((STONYBASALTINPUT > 0) and (Self.CraftedStonyBasalt >= STONYBASALTINPUT)) and ((ICYBASALTINPUT = 0) or (Self.CraftedIcyBasalt >= ICYBASALTINPUT)) then begin WriteLn('Desired amount of Stony Basalt reached.'); Logout.ClickLogout(); TerminateScript(); end else if ((ICYBASALTINPUT > 0) and (Self.CraftedIcyBasalt >= ICYBASALTINPUT)) and ((STONYBASALTINPUT = 0) or (Self.CraftedStonyBasalt >= STONYBASALTINPUT)) then begin WriteLn('Desired amount of Icy Basalt reached.'); Logout.ClickLogout(); TerminateScript(); end else begin if (STONYBASALTINPUT > 0) and (Self.CraftedStonyBasalt < STONYBASALTINPUT) then begin if TeSaltCount < STONYBASALTINPUT - Self.CraftedStonyBasalt then begin Self.CurrentState := STATE_MINETESALT; Self.DesiredSaltCount := STONYBASALTINPUT - Self.CraftedStonyBasalt; end else if UrtSaltCount < 3 * (STONYBASALTINPUT - Self.CraftedStonyBasalt) then begin Self.CurrentState := STATE_MINEURTSALT; Self.DesiredSaltCount := 3 * (STONYBASALTINPUT - Self.CraftedStonyBasalt); end else if Inventory.IsFull() then begin Self.CurrentState := STATE_CRAFTBASALT; Self.BasaltType := 'Stony basalt'; end else Self.CurrentState := STATE_MINEBASALT; end else if (ICYBASALTINPUT > 0) and (Self.CraftedIcyBasalt < ICYBASALTINPUT) then begin if TeSaltCount < ICYBASALTINPUT - Self.CraftedIcyBasalt then begin Self.CurrentState := STATE_MINETESALT; Self.DesiredSaltCount := ICYBASALTINPUT - Self.CraftedIcyBasalt; end else if EfhSaltCount < 3 * (ICYBASALTINPUT - Self.CraftedIcyBasalt) then begin Self.CurrentState := STATE_MINEEFHSALT; Self.DesiredSaltCount := 3 * (ICYBASALTINPUT - Self.CraftedIcyBasalt); end else if Inventory.IsFull() then begin Self.CurrentState := STATE_CRAFTBASALT; Self.BasaltType := 'Icy basalt'; end else Self.CurrentState := STATE_MINEBASALT; end else Self.CurrentState := STATE_DESCENT_STAIRS; end; end; end; end; // WriteLn('Current state: ', Self.CurrentState); end; procedure SaltMiner.DoAction(); begin case Self.CurrentState of STATE_MINEBASALT: MINEBASALT(); STATE_MINEEFHSALT: MineRock(EfhSaltRock, EfhSalt, Self.DesiredSaltCount); STATE_MINETESALT: MineRock(TeSaltRock, TeSalt, Self.DesiredSaltCount); STATE_MINEURTSALT: MineRock(UrtSaltRock, UrtSalt, Self.DesiredSaltCount); STATE_DESCENT_STAIRS: DESCENT_STAIRS(); STATE_WALKTOMINESPOTS: WALKTOMINESPOTS(); STATE_ASCEND_STAIRS: ASCEND_STAIRS(); STATE_NOTEBASALT: NOTEBASALT(); STATE_CRAFTBASALT: CRAFTBASALT(Self.BasaltType); end; end; function FormatRoundedNumber(Number: Integer): String; begin // If the number is >= 1 million, format it with 1 decimal place and add "M" suffix if Number >= 1000000 then Result := FormatFloat('0.0M', Number / 1000000) // If the number is >= 1 thousand, format it with no decimal places and add "K" suffix else if Number >= 1000 then Result := FormatFloat('0K', Number / 1000) // For smaller numbers, use the regular SRL.FormatNumber function else Result := SRL.FormatNumber(Number); end; procedure SaltMiner.Report(); var Runtime: Integer; XPPerHour: Integer; CurrentXP: Integer; GainedXP: Integer; Profit: Integer; begin ClearDebug(); CurrentXP := XPBar.Read(); GainedXP := CurrentXP - StartXP; Runtime := Timer.ElapsedTime; XPPerHour := Round(((CurrentXP - StartXP) / Runtime) * 3600); Profit := 0; if BASALTONLYCHECK then Profit := ItemTotal * BasaltValue else begin if TESALTMINEINPUT > 0 then Profit := Profit + ((Inventory.CountItemStack(TeSalt) - StartTeSaltCount) * TeSaltValue); if EFHSALTMINEINPUT > 0 then Profit := Profit + ((Inventory.CountItemStack(EfhSalt) - StartEfhSaltCount) * EfhSaltValue); if URTSALTMINEINPUT > 0 then Profit := Profit + ((Inventory.CountItemStack(UrtSalt) - StartUrtSaltCount) * UrtSaltValue); if STONYBASALTINPUT > 0 then Profit := Profit + ((Self.CraftedStonyBasalt - StartStonyBasaltCount) * StonyBasaltValue); if ICYBASALTINPUT > 0 then Profit := Profit + ((Self.CraftedIcyBasalt - StartIcyBasaltCount) * IcyBastaltValue); end; WriteLn('========================================'); WriteLn(' BigAussies Salt Miner '); WriteLn('========================================'); WriteLn(' Runtime: ' + SRL.MsToTime(GetTimeRunning, Time_Short)); WriteLn(' XP Gained: ' + FormatRoundedNumber(GainedXP)); WriteLn(' Profit: ' + IntToStr(Profit)); WriteLn('----------------------------------------'); WriteLn(' XP/Hour: ' + FormatRoundedNumber(Round((GainedXP) / (GetTimeRunning() / 3600000)))); WriteLn(' Profit/Hour: ' + FormatRoundedNumber(Round((Profit) / (GetTimeRunning() / 3600000)))); if BASALTONLYCHECK then begin WriteLn(' Total Basalt Mined: ' + IntToStr(ItemTotal)); end; if TESALTMINEINPUT > 0 then begin WriteLn(' TE Salt Mined: ' + IntToStr(Inventory.CountItemStack(TeSalt)) + ' / ' + IntToStr(TESALTMINEINPUT) + ' Target'); end; if EFHSALTMINEINPUT > 0 then begin WriteLn(' EFH Salt Mined: ' + IntToStr(Inventory.CountItemStack(EfhSalt)) + ' / ' + IntToStr(EFHSALTMINEINPUT) + ' Target'); end; if URTSALTMINEINPUT > 0 then begin WriteLn(' URT Salt Mined: ' + IntToStr(Inventory.CountItemStack(UrtSalt)) + ' / ' + IntToStr(URTSALTMINEINPUT) + ' Target'); end; if STONYBASALTINPUT > 0 then begin WriteLn(' Stony Basalt Target: ' + IntToStr(STONYBASALTINPUT)); WriteLn(' Stony Basalt Crafted: ' + IntToStr(Self.CraftedStonyBasalt)); end; if ICYBASALTINPUT > 0 then begin WriteLn(' Icy Basalt Target: ' + IntToStr(ICYBASALTINPUT)); WriteLn(' Icy Basalt Crafted: ' + IntToStr(Self.CraftedIcyBasalt)); end; WriteLn('========================================'); WriteLn(' BigAussies Salt Miner '); WriteLn(' Version: ' + {$MACRO SCRIPT_REVISION}); WriteLn('========================================'); end; procedure SaltMiner.Init(MaxActions: UInt32; MaxTime: UInt64); override; begin inherited; if AIChatbot.Enabled then begin WriteLn('[AI Chatbot] Enabled - initializing'); AIChatbot.Init(); end else WriteLn('[AI Chatbot] Disabled'); StatsPayload.Setup({$macro SCRIPT_ID}); APIClient.TimeStamp := GetTickCount(); RSW.Setup([[10271, 4466, 10544, 4666], [6593, 479, 7271, 891]]); Basalt := ('Basalt'); NotedBasalt := ('Noted basalt'); EfhSalt := ('Efh salt'); TeSalt := ('Te salt'); UrtSalt := ('Urt salt'); StonyBasalt := ('Stony basalt'); IcyBasalt := ('Icy basalt'); BasaltValue := ItemData.GetAverage(Basalt); StonyBasaltValue := ItemData.GetAverage(StonyBasalt); IcyBastaltValue := ItemData.GetAverage(IcyBasalt); EfhSaltValue := ItemData.GetAverage(EfhSalt); TeSaltValue := ItemData.GetAverage(TeSalt); UrtSaltValue := ItemData.GetAverage(UrtSalt); self.SetupObjects(); self.SetupNPC(); Options.SetZoomLevel(Random(20, 40)); Mouse.Speed := Random(16, 22); Mouse.Distribution := MOUSE_DISTRIBUTION_GAUSS; StartXP := XPBar.Read(); ItemTotal := 0; Self.CraftedStonyBasalt := 0; Self.CraftedIcyBasalt := 0; StartTeSaltCount := Inventory.CountItemStack(TeSalt); StartEfhSaltCount := Inventory.CountItemStack(EfhSalt); StartUrtSaltCount := Inventory.CountItemStack(UrtSalt); StartStonyBasaltCount := Self.CraftedStonyBasalt; StartIcyBasaltCount := Self.CraftedIcyBasalt; end; procedure SaltMiner.Run(MaxActions: UInt32; MaxTime: UInt64); begin Self.Init(MaxActions, MaxTime); repeat Self.GetState(); Self.doAction(); if WL.Activity.IsFinished() then begin WriteLn('No activity detected in 5 minutes! Shutting down.'); Break; end; Self.DoAntiban; Self.Report(); until Self.ShouldStop(); end; var Script: SaltMiner; {$IFDEF SCRIPT_GUI} const SM_GUI_NAV = $F0EBE4; SM_GUI_BG = $FFFFFF; SM_GUI_STATUS = $F7F4F1; SM_GUI_DIVIDER = $D4C9BC; SM_GUI_CARD = $F7F4F1; SM_GUI_ACCENT = $E0C9AE; SM_GUI_NAV_IDLE = $E7DED4; SM_GUI_START = $C9B094; SM_GUI_TEXT = $1C1C1E; SM_GUI_MUTED = $6B6B70; SM_GUI_W = 1120; SM_GUI_H = 700; SM_GUI_NAV_W = 190; SM_GUI_STATUS_H = 56; SM_GUI_BTN_H = 42; SM_GUI_EDIT_W = 260; SM_GUI_COL2 = 308; SM_GUI_BOTTOM_INSET = 34; type TConfig = record(TScriptForm) NavPanel, ContentPanel, StatusPanel, DividerPanel, StatusDivider, StatusPad: TPanel; BrandLabel: TLabel; ScriptNav, AccountsNav, AntibanNav, AIChatNav: TImage; StartChip: TImage; ActiveNav: TImage; ScriptSection, AccountsSection, AntibanSection, AIChatSection: TPanel; Message: TLabel; StonyInputBox, IcyInputBox, TeSaltMineInputBox, EfhSaltMineInputBox, UrtSaltMineInputBox: TLabeledEdit; BasaltOnlyCheckBox: TLabeledCheckBox; MaxActionsInput, MaxTimeInput: TLabeledEdit; end; function TConfig.MakePanel( parent: TWinControl; left, top, width, height, color: Int32 ): TPanel; begin Result.Create(parent); Result.SetLeft(TControl.AdjustToDPI(left)); Result.SetTop(TControl.AdjustToDPI(top)); Result.SetWidth(TControl.AdjustToDPI(width)); Result.SetHeight(TControl.AdjustToDPI(height)); Result.SetColor(color); Result.SetBevelOuter(bvNone); end; procedure TConfig.PaintRoundChip( img: TImage; labelText: String; fill, parentBg: Int32; selected: Boolean = False; centered: Boolean = False ); var bmp: TBitmap; c: TCanvas; w, h, r, tw, th, tx: Int32; begin w := img.GetWidth(); h := img.GetHeight(); if (w <= 0) or (h <= 0) then Exit; r := TControl.AdjustToDPI(6); if r * 2 > h then r := h div 2; if r * 2 > w then r := w div 2; bmp := img.GetPicture().GetBitmap(); bmp.SetWidth(w); bmp.SetHeight(h); c := bmp.GetCanvas(); c.GetBrush().SetColor(parentBg); c.GetPen().SetColor(parentBg); c.FillRect(0, 0, w, h); c.GetBrush().SetColor(fill); c.GetPen().SetColor(fill); c.RoundRect(0, 0, w - 1, h - 1, r * 2, r * 2); c.GetBrush().SetColor(fill); c.GetFont().SetColor(SM_GUI_TEXT); c.GetFont().SetSize(11); if selected then c.GetFont().SetStyle([fsBold]) else c.GetFont().SetStyle([]); tw := c.TextWidth(labelText); th := c.TextHeight(labelText); if centered then tx := (w - tw) div 2 else tx := TControl.AdjustToDPI(16); c.TextOut(tx, (h - th) div 2, labelText); img.SetHint(labelText); img.SetShowHint(False); img.Invalidate(); end; function TConfig.MakeNavItem( parent: TWinControl; labelText: String; left, top: Int32; selected: Boolean = False ): TImage; var fill: Int32; begin Result.Create(parent); Result.SetLeft(TControl.AdjustToDPI(left)); Result.SetTop(TControl.AdjustToDPI(top)); Result.SetWidth(TControl.AdjustToDPI(SM_GUI_NAV_W - 28)); Result.SetHeight(TControl.AdjustToDPI(SM_GUI_BTN_H)); Result.SetCursor(crHandPoint); if selected then fill := SM_GUI_ACCENT else fill := SM_GUI_NAV_IDLE; Self.PaintRoundChip(Result, labelText, fill, SM_GUI_NAV, selected); end; function TConfig.MakeLabel( parent: TWinControl; labelText: String; left, top, fontSize, fontColor: Int32; bold: Boolean = False ): TLabel; begin Result.Create(parent); Result.SetLeft(TControl.AdjustToDPI(left)); Result.SetTop(TControl.AdjustToDPI(top)); Result.SetCaption(labelText); Result.GetFont().SetSize(fontSize); Result.GetFont().SetColor(fontColor); if bold then Result.GetFont().SetStyle([fsBold]); end; procedure TConfig.AddCheck( parent: TWinControl; var box: TLabeledCheckBox; ctrlName, labelText: String; left, top: Int32; checked: Boolean ); begin box.Create(parent); box.SetLeft(TControl.AdjustToDPI(left)); box.SetTop(TControl.AdjustToDPI(top)); box.SetName(ctrlName); box.SetFontColor(SM_GUI_TEXT); box.SetCaption(labelText); if checked then box.CheckBox.SetChecked(True); end; procedure TConfig.AddEdit( parent: TWinControl; var box: TLabeledEdit; ctrlName, labelText, text: String; left, top, width: Int32 ); begin box.Create(parent); box.SetLeft(TControl.AdjustToDPI(left)); box.SetTop(TControl.AdjustToDPI(top)); box.SetWidth(TControl.AdjustToDPI(width)); box.SetName(ctrlName); box.SetCaption(labelText); box.SetText(text); box.SetFontColor(SM_GUI_TEXT); end; procedure TConfig.AddHeader(parent: TPanel; titleText, subtitleText: String); var header: TPanel; headerW: Int32; begin headerW := parent.GetWidth(); if headerW <= 0 then headerW := TControl.AdjustToDPI(SM_GUI_W - SM_GUI_NAV_W - 2); header := Self.MakePanel(parent, 0, 0, 1, 88, SM_GUI_CARD); header.SetWidth(headerW); header.SetHeight(TControl.AdjustToDPI(88)); Self.MakeLabel(header, titleText, 24, 18, 18, SM_GUI_TEXT, True); Self.MakeLabel(header, subtitleText, 24, 52, 10, SM_GUI_MUTED, False); end; procedure TConfig.StyleNav(selected: TImage); begin Self.ActiveNav := selected; Self.PaintRoundChip(Self.ScriptNav, Self.ScriptNav.GetHint(), SM_GUI_NAV_IDLE, SM_GUI_NAV, False); Self.PaintRoundChip(Self.AccountsNav, Self.AccountsNav.GetHint(), SM_GUI_NAV_IDLE, SM_GUI_NAV, False); Self.PaintRoundChip(Self.AntibanNav, Self.AntibanNav.GetHint(), SM_GUI_NAV_IDLE, SM_GUI_NAV, False); Self.PaintRoundChip(Self.AIChatNav, Self.AIChatNav.GetHint(), SM_GUI_NAV_IDLE, SM_GUI_NAV, False); Self.PaintRoundChip(selected, selected.GetHint(), SM_GUI_ACCENT, SM_GUI_NAV, True); end; procedure TConfig.ShowSection(section: TPanel; selected: TImage); begin Self.ScriptSection.SetVisible(False); Self.AccountsSection.SetVisible(False); Self.AntibanSection.SetVisible(False); Self.AIChatSection.SetVisible(False); section.SetVisible(True); Self.StyleNav(selected); end; procedure TConfig.ShowScript({$H-}sender: TObject); {$H+} begin Self.ShowSection(Self.ScriptSection, Self.ScriptNav); end; procedure TConfig.ShowAccounts({$H-}sender: TObject); {$H+} begin Self.ShowSection(Self.AccountsSection, Self.AccountsNav); end; procedure TConfig.ShowAntiban({$H-}sender: TObject); {$H+} begin Self.ShowSection(Self.AntibanSection, Self.AntibanNav); end; procedure TConfig.ShowAIChat({$H-}sender: TObject); {$H+} begin Self.ShowSection(Self.AIChatSection, Self.AIChatNav); end; procedure TConfig.BasaltOnlyCheckBoxClicked(Sender: TObject); var showSalt: Boolean; begin if Sender = nil then; showSalt := not Self.BasaltOnlyCheckBox.IsChecked(); Self.StonyInputBox.SetVisible(showSalt); Self.IcyInputBox.SetVisible(showSalt); Self.TeSaltMineInputBox.SetVisible(showSalt); Self.EfhSaltMineInputBox.SetVisible(showSalt); Self.UrtSaltMineInputBox.SetVisible(showSalt); Self.Message.SetVisible(showSalt); end; procedure TConfig.StartScript(Sender: TObject); override; var Username: String; begin if Sender = nil then; if (Login.PlayerIndex < 0) or (Login.PlayerIndex > High(Login.Players)) then Username := 'NoUserNameSelected' else Username := Login.Players[Login.PlayerIndex].User; STONYBASALTINPUT := StrToIntDef(Self.StonyInputBox.GetText(), 0); ICYBASALTINPUT := StrToIntDef(Self.IcyInputBox.GetText(), 0); TESALTMINEINPUT := StrToIntDef(Self.TeSaltMineInputBox.GetText(), 0); EFHSALTMINEINPUT := StrToIntDef(Self.EfhSaltMineInputBox.GetText(), 0); URTSALTMINEINPUT := StrToIntDef(Self.UrtSaltMineInputBox.GetText(), 0); BASALTONLYCHECK := Self.BasaltOnlyCheckBox.IsChecked(); WLSettings.Put('max_actions', StrToIntDef(Self.MaxActionsInput.GetText(), 0)); WLSettings.Put('max_time', StrToIntDef(Self.MaxTimeInput.GetText(), 0)); WLSettings.SaveConfig(); WriteINI(Username + ' Salt Miner Settings', 'BasaltOnly', BoolToStr(BASALTONLYCHECK, 'true', 'false'), 'Configs/BASettings.ini'); WriteINI(Username + ' Salt Miner Settings', 'StonyBasalt', IntToStr(STONYBASALTINPUT), 'Configs/BASettings.ini'); WriteINI(Username + ' Salt Miner Settings', 'IcyBasalt', IntToStr(ICYBASALTINPUT), 'Configs/BASettings.ini'); WriteINI(Username + ' Salt Miner Settings', 'TeSalt', IntToStr(TESALTMINEINPUT), 'Configs/BASettings.ini'); WriteINI(Username + ' Salt Miner Settings', 'EfhSalt', IntToStr(EFHSALTMINEINPUT), 'Configs/BASettings.ini'); WriteINI(Username + ' Salt Miner Settings', 'UrtSalt', IntToStr(URTSALTMINEINPUT), 'Configs/BASettings.ini'); try Self._WarmBuildCache(); except end; AIChatbot.ApplyFromGUI(); Self.Form.SetOnClose(nil); Self.Form.Close(); end; procedure TConfig.BuildScriptSection( SavedBasaltOnly: Boolean; SavedStony, SavedIcy, SavedTe, SavedEfh, SavedUrt: Integer ); begin Self.AddHeader(Self.ScriptSection, 'Action', 'Mine salts and craft basalt in Weiss.'); Self.AddCheck(Self.ScriptSection, Self.BasaltOnlyCheckBox, 'cb_sm_basalt_only', 'Mine/Note Basalt Only', 24, 110, SavedBasaltOnly); Self.BasaltOnlyCheckBox.SetTooltip('Enabled to Mine and Note BASALT ONLY'); Self.BasaltOnlyCheckBox.CheckBox.SetOnChange(@Self.BasaltOnlyCheckBoxClicked); Self.AddEdit(Self.ScriptSection, Self.StonyInputBox, 'le_sm_stony', 'Stony Basalt to make', IntToStr(SavedStony), 24, 170, SM_GUI_EDIT_W); Self.StonyInputBox.Edit.SetOnKeyPress(@Self.StonyInputBox.Edit.NumberField); Self.AddEdit(Self.ScriptSection, Self.IcyInputBox, 'le_sm_icy', 'Icy Basalt to make', IntToStr(SavedIcy), 24, 240, SM_GUI_EDIT_W); Self.IcyInputBox.Edit.SetOnKeyPress(@Self.IcyInputBox.Edit.NumberField); Self.Message := Self.MakeLabel(Self.ScriptSection, 'Amounts below for mining just salts.', SM_GUI_COL2, 110, 10, $0000C8, False); Self.Message.SetWidth(TControl.AdjustToDPI(400)); Self.AddEdit(Self.ScriptSection, Self.TeSaltMineInputBox, 'le_sm_te', 'Te salt to mine', IntToStr(SavedTe), SM_GUI_COL2, 170, SM_GUI_EDIT_W); Self.TeSaltMineInputBox.Edit.SetOnKeyPress(@Self.TeSaltMineInputBox.Edit.NumberField); Self.AddEdit(Self.ScriptSection, Self.EfhSaltMineInputBox, 'le_sm_efh', 'Efh salt to mine', IntToStr(SavedEfh), SM_GUI_COL2, 240, SM_GUI_EDIT_W); Self.EfhSaltMineInputBox.Edit.SetOnKeyPress(@Self.EfhSaltMineInputBox.Edit.NumberField); Self.AddEdit(Self.ScriptSection, Self.UrtSaltMineInputBox, 'le_sm_urt', 'Urt salt to mine', IntToStr(SavedUrt), SM_GUI_COL2, 310, SM_GUI_EDIT_W); Self.UrtSaltMineInputBox.Edit.SetOnKeyPress(@Self.UrtSaltMineInputBox.Edit.NumberField); end; procedure TConfig.BuildAccountsSection(); var am: TPanel; selectorPanel, userPanel, passPanel, pinPanel, worldsPanel: TPanel; addBtn, deleteBtn, generateBtn: TButton; leftColW, passW, pinW, worldsLeft, btnW, btnGap: Int32; begin Self.AddHeader(Self.AccountsSection, 'Accounts', 'Login account and hop worlds list.'); am := Self.CreateAccountManager(Self.AccountsSection); am.SetLeft(TControl.AdjustToDPI(16)); am.SetTop(TControl.AdjustToDPI(100)); am.SetColor(SM_GUI_BG); leftColW := TControl.AdjustToDPI(280); passW := Floor(leftColW * 0.6); pinW := Floor(leftColW * 0.3); selectorPanel := Self.Form.GetChild('am_selector_panel'); userPanel := Self.Form.GetChild('am_user_panel'); passPanel := Self.Form.GetChild('am_pass_panel'); pinPanel := Self.Form.GetChild('am_pin_panel'); worldsPanel := Self.Form.GetChild('am_worlds_panel'); if selectorPanel <> nil then selectorPanel.SetWidth(leftColW); if userPanel <> nil then userPanel.SetWidth(leftColW); if passPanel <> nil then passPanel.SetWidth(passW); if (pinPanel <> nil) and (selectorPanel <> nil) then begin pinPanel.SetWidth(pinW); pinPanel.SetLeft(selectorPanel.GetLeft() + leftColW - pinW); end; if (worldsPanel <> nil) and (selectorPanel <> nil) then begin worldsLeft := selectorPanel.GetLeft() + leftColW + TControl.AdjustToDPI(48); worldsPanel.SetLeft(worldsLeft); addBtn := Self.Form.GetChild('am_add_button'); deleteBtn := Self.Form.GetChild('am_delete_button'); generateBtn := Self.Form.GetChild('am_generate_worlds_button'); btnGap := TControl.AdjustToDPI(8); btnW := Floor((worldsPanel.GetWidth() - btnGap) / 2); if generateBtn <> nil then begin generateBtn.SetLeft(worldsLeft); generateBtn.SetWidth(worldsPanel.GetWidth()); end; if addBtn <> nil then begin addBtn.SetLeft(worldsLeft); addBtn.SetWidth(btnW); end; if deleteBtn <> nil then begin deleteBtn.SetLeft(worldsLeft + worldsPanel.GetWidth() - btnW - TControl.AdjustToDPI(1)); deleteBtn.SetWidth(btnW); end; end; end; procedure TConfig.BuildAntibanSection(SavedMaxActions, SavedMaxTime: Integer); begin Self.AddHeader(Self.AntibanSection, 'Antiban', 'Session limits.'); Self.AddEdit(Self.AntibanSection, Self.MaxActionsInput, 'le_sm_maxactions', 'Max actions (0 = unlimited)', IntToStr(SavedMaxActions), 24, 110, SM_GUI_EDIT_W); Self.MaxActionsInput.Edit.SetOnKeyPress(@Self.MaxActionsInput.Edit.NumberField); Self.AddEdit(Self.AntibanSection, Self.MaxTimeInput, 'le_sm_maxtime', 'Max time minutes (0 = unlimited)', IntToStr(SavedMaxTime), SM_GUI_COL2, 110, SM_GUI_EDIT_W); Self.MaxTimeInput.Edit.SetOnKeyPress(@Self.MaxTimeInput.Edit.NumberField); end; procedure TConfig.BuildShell( SavedBasaltOnly: Boolean; SavedStony, SavedIcy, SavedTe, SavedEfh, SavedUrt, SavedMaxActions, SavedMaxTime: Integer ); var tab: TTabSheet; contentH, startW, startH, shellW, shellH, statusTop, statusH, mainLeft, mainW, navW, bottomInset: Int32; begin Self.AddTab('Salt Miner'); tab := Self.Tabs[High(Self.Tabs)]; Self.Start.SetAlign(alNone); Self.Start.SetVisible(False); Self.Start.SetHeight(0); Self.Start.SetWidth(0); bottomInset := TControl.AdjustToDPI(SM_GUI_BOTTOM_INSET); navW := TControl.AdjustToDPI(SM_GUI_NAV_W); statusH := TControl.AdjustToDPI(SM_GUI_STATUS_H); shellW := Self.Size.X; shellH := Self.Size.Y; mainLeft := navW + TControl.AdjustToDPI(2); mainW := shellW - mainLeft; statusTop := shellH - statusH - bottomInset; contentH := statusTop; startW := TControl.AdjustToDPI(132); startH := TControl.AdjustToDPI(SM_GUI_BTN_H); Self.NavPanel.Create(tab); Self.NavPanel.SetLeft(0); Self.NavPanel.SetTop(0); Self.NavPanel.SetWidth(navW); Self.NavPanel.SetHeight(shellH); Self.NavPanel.SetColor(SM_GUI_NAV); Self.NavPanel.SetBevelOuter(bvNone); Self.DividerPanel.Create(tab); Self.DividerPanel.SetLeft(navW); Self.DividerPanel.SetTop(0); Self.DividerPanel.SetWidth(TControl.AdjustToDPI(2)); Self.DividerPanel.SetHeight(shellH); Self.DividerPanel.SetColor(SM_GUI_DIVIDER); Self.DividerPanel.SetBevelOuter(bvNone); Self.ContentPanel.Create(tab); Self.ContentPanel.SetLeft(mainLeft); Self.ContentPanel.SetTop(0); Self.ContentPanel.SetWidth(mainW); Self.ContentPanel.SetHeight(contentH); Self.ContentPanel.SetColor(SM_GUI_BG); Self.ContentPanel.SetBevelOuter(bvNone); Self.StatusDivider.Create(tab); Self.StatusDivider.SetLeft(mainLeft); Self.StatusDivider.SetTop(statusTop); Self.StatusDivider.SetWidth(mainW); Self.StatusDivider.SetHeight(TControl.AdjustToDPI(2)); Self.StatusDivider.SetColor(SM_GUI_DIVIDER); Self.StatusDivider.SetBevelOuter(bvNone); Self.StatusPanel.Create(tab); Self.StatusPanel.SetLeft(mainLeft); Self.StatusPanel.SetTop(statusTop + Self.StatusDivider.GetHeight()); Self.StatusPanel.SetWidth(mainW); Self.StatusPanel.SetHeight(statusH - Self.StatusDivider.GetHeight()); Self.StatusPanel.SetColor(SM_GUI_STATUS); Self.StatusPanel.SetBevelOuter(bvNone); Self.StatusPad.Create(tab); Self.StatusPad.SetLeft(mainLeft); Self.StatusPad.SetTop(Self.StatusPanel.GetTop() + Self.StatusPanel.GetHeight()); Self.StatusPad.SetWidth(mainW); Self.StatusPad.SetHeight(shellH - Self.StatusPad.GetTop()); Self.StatusPad.SetColor(SM_GUI_STATUS); Self.StatusPad.SetBevelOuter(bvNone); Self.BrandLabel := Self.MakeLabel(Self.NavPanel, 'Salt Miner', 16, 28, 14, SM_GUI_TEXT, True); Self.MakeLabel(Self.NavPanel, 'BigAussie', 16, 54, 9, SM_GUI_MUTED, False); Self.ScriptNav := Self.MakeNavItem(Self.NavPanel, 'Action', 12, 100, True); Self.AccountsNav := Self.MakeNavItem(Self.NavPanel, 'Accounts', 12, 152); Self.AntibanNav := Self.MakeNavItem(Self.NavPanel, 'Antiban', 12, 204); Self.AIChatNav := Self.MakeNavItem(Self.NavPanel, 'AI Chat', 12, 256); Self.ScriptSection := Self.MakePanel(Self.ContentPanel, 0, 0, 100, 100, SM_GUI_BG); Self.AccountsSection := Self.MakePanel(Self.ContentPanel, 0, 0, 100, 100, SM_GUI_BG); Self.AntibanSection := Self.MakePanel(Self.ContentPanel, 0, 0, 100, 100, SM_GUI_BG); Self.AIChatSection := Self.MakePanel(Self.ContentPanel, 0, 0, 100, 100, SM_GUI_BG); Self.ScriptSection.SetWidth(mainW); Self.ScriptSection.SetHeight(contentH); Self.AccountsSection.SetWidth(mainW); Self.AccountsSection.SetHeight(contentH); Self.AntibanSection.SetWidth(mainW); Self.AntibanSection.SetHeight(contentH); Self.AIChatSection.SetWidth(mainW); Self.AIChatSection.SetHeight(contentH); Self.BuildScriptSection(SavedBasaltOnly, SavedStony, SavedIcy, SavedTe, SavedEfh, SavedUrt); Self.BuildAccountsSection(); Self.BuildAntibanSection(SavedMaxActions, SavedMaxTime); AIChatbot.BuildSettings(Self.AIChatSection, mainW); Self.ScriptNav.SetOnClick(@Self.ShowScript); Self.AccountsNav.SetOnClick(@Self.ShowAccounts); Self.AntibanNav.SetOnClick(@Self.ShowAntiban); Self.AIChatNav.SetOnClick(@Self.ShowAIChat); Self.StartChip.Create(Self.StatusPanel); Self.StartChip.SetLeft(mainW - startW - TControl.AdjustToDPI(24)); Self.StartChip.SetTop((Self.StatusPanel.GetHeight() - startH) div 2 + 2); Self.StartChip.SetWidth(startW); Self.StartChip.SetHeight(startH); Self.StartChip.SetCursor(crHandPoint); Self.PaintRoundChip(Self.StartChip, 'Start', SM_GUI_START, SM_GUI_STATUS, True, True); Self.StartChip.SetOnClick(@Self.StartScript); Self.BasaltOnlyCheckBoxClicked(nil); Self.ShowScript(Self.ScriptNav); end; procedure TConfig.Run(); override; var Username: String; SavedBasaltOnly: Boolean; SavedStony, SavedIcy, SavedTe, SavedEfh, SavedUrt, SavedMaxActions, SavedMaxTime: Integer; begin BashPromptIfUpdateAvailable(); if (Login.PlayerIndex < 0) or (Login.PlayerIndex > High(Login.Players)) then Username := 'NoUserNameSelected' else Username := Login.Players[Login.PlayerIndex].User; SavedBasaltOnly := StrToBoolDef(ReadINI(Username + ' Salt Miner Settings', 'BasaltOnly', 'Configs/BASettings.ini'), BASALTONLYCHECK); SavedStony := StrToIntDef(ReadINI(Username + ' Salt Miner Settings', 'StonyBasalt', 'Configs/BASettings.ini'), STONYBASALTINPUT); SavedIcy := StrToIntDef(ReadINI(Username + ' Salt Miner Settings', 'IcyBasalt', 'Configs/BASettings.ini'), ICYBASALTINPUT); SavedTe := StrToIntDef(ReadINI(Username + ' Salt Miner Settings', 'TeSalt', 'Configs/BASettings.ini'), TESALTMINEINPUT); SavedEfh := StrToIntDef(ReadINI(Username + ' Salt Miner Settings', 'EfhSalt', 'Configs/BASettings.ini'), EFHSALTMINEINPUT); SavedUrt := StrToIntDef(ReadINI(Username + ' Salt Miner Settings', 'UrtSalt', 'Configs/BASettings.ini'), URTSALTMINEINPUT); if WLSettings.Has('max_actions') then SavedMaxActions := WLSettings.GetInt('max_actions') else SavedMaxActions := 0; if WLSettings.Has('max_time') then SavedMaxTime := WLSettings.GetInt('max_time') else SavedMaxTime := 0; AIChatbot.Setup('Gemini', ''); AIChatbot.Enabled := False; AIChatbot.LoadSettings(); AIChatbot.SetScriptDefaults('mining salt'); Self.Setup('BigAussies Salt Miner', [SM_GUI_W, SM_GUI_H], False); Self.BuildShell(SavedBasaltOnly, SavedStony, SavedIcy, SavedTe, SavedEfh, SavedUrt, SavedMaxActions, SavedMaxTime); inherited; end; var Config: TConfig; {$ENDIF} begin {$IFDEF SCRIPT_GUI} Sync(@Config.Run); {$ENDIF} Script.Run(WLSettings.MaxActions, WLSettings.MaxTime); end.