{$UNDEF SCRIPT_ID}{$DEFINE SCRIPT_ID := 'cf2ed007-5328-4914-b6fc-cd521759f893'} {$UNDEF SCRIPT_REVISION}{$DEFINE SCRIPT_REVISION := '6'} {$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 ID: big.aussie Discord Server: https://discord.gg/qsmKs5uKfR Email: thebigaussie@proton.me Github: https://github.com/BigAussie/BASH ---------------------------------------------------------------------------------- } var POWERMINING: Boolean = False; IGNOREWATERFALLS: Boolean = False; ENABLEWEBHOOKS: Boolean = True; WEBHOOKURL: String = ''; DiscordUID: String = ''; PINGONTERMINATED: Boolean = True; begin WLSettings.Antiban.Chat := False; Mouse.Speed := Random(22, 28); end; type EState = ( STATE_MINECALCIFIEDROCKS, STATE_PROCESSDEPOSITS, STATE_WALKTOBLACKSMITH, STATE_WALKTOMINESITE, STATE_OPENBANK, STATE_HANDLEBANKING, STATE_DROPITEMS ); ELocation = ( BLACKSMITH, BANKAREA, EASTMINESITE, WESTMINESITE ); CalcifiedMiner = record (TBaseBankScript) CurrentState: EState; CalcifiedDeposit: TRSitem; HammerItem: TRSitem; CalcifiedMoths: TRSitem; HammerBank: TRSBankItem; ItemsToKeep: TRSItemArray; StartXP: Integer; CurrentXP: Integer; TotalShardsMined: Integer; TotalCalcifiedMoths: Integer; CalcifiedMothValue: Integer; StartingShards: Integer; MyPos: TPoint; CalcifiedRocks: TRSObject; WetCalcifiedRocks: TRSObject; CamTorumAnvil: TRSObject; BankersTable: TRSObject; end; var Timer: TStopWatch; RSW: TRSWalker; CamTorumMine : TWebGraph; procedure TRSWalker.InternalSetup(); override; begin inherited; CamTorumMine.LoadNodesFromString('xgAAAHicTY3BDcQwCARbcQkG1gfUYqX/NrIbR7r8RsMAG94D2deGrYE2whTIwI+JtmMi5wfqGbHJKaM7QSjGSw1oQqOIgVnX9u4D5vWH6EXgrygQEgcUB9T8aJAvuL1bjxHw+w3F/C2g'); CamTorumMine.LoadPathsFromString('iwAAAHicJYzRFQQxCAJbmRKCm2ySWnz238bh3pcgDCmeykFUimlVGSx25eStXJxWh1u5+7GRKxfJwEDNCT3IiAJ5o93ymeglurj+mbfkgUt443Pny2M08AMgryD8'); CamTorumMine.LoadNamesFromString('WAAAAHici1Y2iI2mAQYA/MUW8w=='); Self.WebGraph := CamTorumMine; end; procedure CalcifiedMiner.SendWebhook(msg: String; FilePath: String = ''); var HTTP: Int32; Response, Payload: String; begin if WEBHOOKURL = "" then Exit; if DiscordUID <> '' then msg := '<@' + DiscordUID + '> ' + msg; // First attempt with JSON payload Payload := '{"content": "' + msg + '"}'; HTTP := InitializeHTTPClient(False); try SetHTTPHeader(HTTP, 'Content-Type', 'application/json'); Response := PostHTTPPage(HTTP, WEBHOOKURL, Payload); if Response = '' then WriteLn('Webhook successfully sent with JSON payload.') else WriteLn('Webhook sent with JSON payload. Response: ', Response); // Fallback to FORMS if JSON Fails - We had to fallback as some users had issues with JSON Thanks @Chandler for all the help testing this. if Pos('"code": 50006', Response) > 0 then begin FreeHTTPClient(HTTP); HTTP := InitializeHTTPClient(False); AddPostVariable(HTTP, 'content', msg); Response := PostHTTPPageEx(HTTP, WEBHOOKURL); if Response = '' then WriteLn('Webhook fallback successfully sent with form data after code 50006 error.') else WriteLn('Webhook fallback sent with form data after code 50006 error. Response: ', Response); end; finally FreeHTTPClient(HTTP); end; end; procedure CalcifiedMiner.SendTerminationNotification(); begin Self.SendWebhook('Calcified Miner has terminated or crashed.'); end; procedure CalcifiedMiner.SetupObjects(); begin writeln('Setting up objects'); with self.CalcifiedRocks do begin SetupEx([1, 1, 10], [[354, 483], [354, 496], [354, 487], [363, 468], [358, 468], {East Wall} [452, 486], [452, 490], [452, 482], [436, 470], [432, 470], [424, 470]]); SetupUpText(['Calcified rocks']); Finder.ColorClusters += [CTS2(4082774, 4, 0.14, 0.46), CTS2(3289654, 6, 0.01, 0.34), 5]; end; with self.WetCalcifiedRocks do begin SetupEx([1, 1, 10], [[354, 483], [354, 496], [354, 487], [363, 468], [358, 468], {East Wall} [452, 486], [452, 490], [452, 482], [436, 470], [432, 470], [424, 470]]); SetupUpText(['Calcified rocks']); Finder.Colors += CTS2(10388048, 13, 0.02, 1.02); end; with self.CamTorumAnvil do begin Setup(2, [[150, 326]]); SetupUpText(['Anvil']); Finder.Colors += CTS2(4942722, 10, 0.06, 0.44); end; with self.BankersTable do begin Setup(2, [[171, 377]]); SetupUpText(['Bank table']); Finder.ColorClusters += [CTS2(5138813, 5, 0.09, 0.08), CTS2(5412524, 7, 0.04, 0.75), 5]; end; end; function CalcifiedMiner.GetLocation(): ELocation; begin if (not RSClient.IsLoggedIn) then Exit; MyPos := Self.RSW.GetMyPos; if MyPos.InBox([136, 299, 191, 341]) then Exit(BLACKSMITH); if MyPos.InBox([159, 369, 199, 402]) then Exit(BANKAREA); if MyPos.InBox([413, 455, 468, 514]) then Exit(EASTMINESITE); if MyPos.InBox([350, 460, 388, 515]) then Exit(WESTMINESITE); end; procedure CalcifiedMiner.WALKTOBLACKSMITH(); begin writeln('Walking to blacksmith.'); RSW.WebWalk([156, 326]); end; procedure CalcifiedMiner.HANDLEBANKING(); begin if not Bank.IsOpen then begin Bank.Walkopen(BankersTable); if not WaitUntil(Bank.IsOpen, 120, 3000) then Exit; end; TotalCalcifiedMoths += Inventory.CountItemStack(CalcifiedMoths); writeln('Depositing items.'); if Inventory.ContainsItem('Open gem bag') then Inventory.ClickItem('Open gem bag', 'Empty'); WaitUntil(Inventory.ContainsItem('Open gem bag'), 120, 3000); if Inventory.ContainsRandomItems(itemsToKeep) then Bank.DepositRandomItems(itemsToKeep); if not (Inventory.ContainsItem(HammerItem) or Inventory.ContainsItem('Imcando hammer')) then Bank.WithdrawItem(HammerBank, TRUE); Bank.Close(); end; procedure CalcifiedMiner.OPENBANK(); begin writeln('Opening bank.'); RSW.WebWalk([172, 382]); if not Bank.Walkopen(BankersTable) then Exit; if not WaitUntil(Bank.IsOpen, 120, 3000) then Exit; HANDLEBANKING(); end; procedure CalcifiedMiner.DROPITEMS(); var Slots: TIntegerArray; DropList: TRSItemArray; begin writeln('Dropping...'); DropList := ['Calcified deposit', 'Uncut sapphire', 'Uncut emerald', 'Uncut ruby', 'Uncut diamond']; Inventory.FindItems(DropList, Slots); Inventory.ShiftDrop(DropList, DROP_PATTERN_SNAKE); end; procedure CalcifiedMiner.WALKTOMINESITE(); var destination: TPoint; begin writeln('Returning to mine site.'); if Antiban.BioDice() then destination := Point(436, 486) // West Mine Site else destination := Point(368, 486); // East Mine Site RSW.WebWalk(destination); end; // It's a meme but thanks club and student for helping me tidy up this (Oh also CJ said check uptext which was a good idea to) procedure CalcifiedMiner.PROCESSDEPOSITS(); var ATPA: T2DPointArray; TPA: TPointArray; begin if not Inventory.SetSelectedItem(CalcifiedDeposit) then Exit; CamTorumAnvil.Find(ATPA); if (ATPA.Len <= 0) then Exit; TPA := ATPA[0]; Mouse.Move(TPA.Mean()); if not MainScreen.IsUpText('Anvil', 250) then Exit; Mouse.Click(MOUSE_LEFT); if not WaitUntil(Make.IsOpen, 100, 3000) then Exit; if Make.Select('Calcified deposit', Make.QUANTITY_ALL) then WaitUntil(not Inventory.ContainsItem(CalcifiedDeposit), 100, 70000); end; // full Credits to SkunkGUIworks procedure TRSMinimap.RotateWithinAngles(min, max: Int32); var minMaxAvg: Int32 := Floor((min + max) div 2); preferredAngle: Int32 := SRL.SkewedRand(minMaxAvg, min, max); begin if preferredAngle < 0 then preferredAngle := preferredAngle + 360; Minimap.SetCompassAngle(preferredAngle); end; procedure CalcifiedMiner.MINECALCIFIEDROCKS(); var PlayerBox: TBox; XP: Integer; ATPA: T2DPointArray; TPA: TPointArray; T, ReportTimer: TStopWatch; MiningDuration: Int32; InitialShards: Integer; CurrentShards: Integer; MiningWetRock: Boolean; begin if Inventory.ContainsItem('Gem bag') then Inventory.ClickItem('Gem bag', 'Open'); PlayerBox := MainScreen.GetPlayerBox(); XP := XPBar.Read(); ReportTimer.Start(); InitialShards := Inventory.CountItemStack('Blessed bone shards');; begin if (not Inventory.ContainsItem('Hammer') and not Inventory.ContainsItem('Imcando hammer')) and not POWERMINING then begin writeln('No hammer in inventory, attempting to withdraw.'); OPENBANK(); Exit; end; if (Self.GetLocation() = WESTMINESITE) and ((Minimap.GetCompassAngle() < 10) or (Minimap.GetCompassAngle() > 95)) then Minimap.RotateWithinAngles(15, 85); if (Self.GetLocation() = EASTMINESITE) and ((Minimap.GetCompassAngle() > 10) or (Minimap.GetCompassAngle() < 267)) then Minimap.RotateWithinAngles(-93, 10); if (not IGNOREWATERFALLS) and WetCalcifiedRocks.Find(ATPA) and (not MiningWetRock) then begin WriteLn('Wet Calcified Rock spawned, switching target.'); TPA := ATPA[0]; Mouse.Move(TPA.Mean()); WetCalcifiedRocks.WalkClick(); MiningWetRock := True; WaitUntil(Minimap.IsPlayerMoving, 120, 2000); MiningDuration := RandomRange(1000, 1100); T.Start(); end; ATPA := MainScreen.FindObject(CalcifiedRocks.Finder); if (ATPA.Len > 0) and (not MiningWetRock) then begin CalcifiedRocks.Click(); WaitUntil(Minimap.IsPlayerMoving, 120, 2000); MiningDuration := RandomRange(1000, 1100); T.Start(); end; while (T.ElapsedTime < MiningDuration) do begin Inventory.Open(); if Inventory.CountEmptySlots <= 1 then begin WriteLn('Inventory full or almost full, moving to smash.'); Exit; end; if (not IGNOREWATERFALLS) and WetCalcifiedRocks.Find(ATPA) and (not MiningWetRock) then begin WriteLn('Wet Calcified Rock spawned, switching target.'); TPA := ATPA[0]; Mouse.Move(TPA.Mean()); WetCalcifiedRocks.WalkClick(); MiningWetRock := True; WaitUntil(Minimap.IsPlayerMoving, 120, 2000); MiningDuration := RandomRange(1000, 1100); T.Start(); end; if XPBar.Read() > XP then begin XP := XPBar.Read(); T.Start(); end; if (SRL.PercentShift(PlayerBox, 500) >= 14) then begin T.Start(); end; Wait(100); WL.Activity.Restart(); if ReportTimer.ElapsedTime >= 4000 then begin CurrentShards := Inventory.CountItemStack('Blessed bone shards'); if CurrentShards > InitialShards then begin Self.TotalShardsMined += CurrentShards - InitialShards; InitialShards := CurrentShards; end; Self.Report(); ReportTimer.Start(); end; end; MiningWetRock := False; Self.DoAntiban; end; Self.TotalShardsMined += Inventory.CountItemStack('Blessed bone shards') - InitialShards; end; procedure CalcifiedMiner.doAction(); begin case Self.GetState() of STATE_MINECALCIFIEDROCKS: MINECALCIFIEDROCKS(); STATE_PROCESSDEPOSITS: PROCESSDEPOSITS(); STATE_WALKTOMINESITE: WALKTOMINESITE(); STATE_WALKTOBLACKSMITH: WALKTOBLACKSMITH(); STATE_OPENBANK: OPENBANK(); STATE_HANDLEBANKING: HANDLEBANKING(); STATE_DROPITEMS: DROPITEMS(); end; end; function CalcifiedMiner.GetState(): EState; begin if Inventory.ContainsItem(CalcifiedDeposit) and (Self.GetLocation() = BLACKSMITH) then Exit(STATE_PROCESSDEPOSITS) else if (Inventory.CountEmptySlots <= 1) and Inventory.ContainsItem(CalcifiedDeposit) then begin if POWERMINING then Exit(STATE_DROPITEMS) else Exit(STATE_WALKTOBLACKSMITH); end else if Inventory.ContainsItem(CalcifiedDeposit) and not (Self.GetLocation() in [EASTMINESITE, WESTMINESITE]) then Exit(STATE_WALKTOBLACKSMITH) else if (not Inventory.ContainsItem(CalcifiedDeposit)) and Inventory.ContainsRandomItems(itemsToKeep) and not (Self.GetLocation() in [EASTMINESITE, WESTMINESITE]) then Exit(STATE_OPENBANK) else if (Self.GetLocation() = WESTMINESITE) or (Self.GetLocation() = EASTMINESITE) then Exit(STATE_MINECALCIFIEDROCKS) else Exit(STATE_WALKTOMINESITE); 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 CalcifiedMiner.Report(); var Runtime: Integer; CurrentXP, GainedXP, PrayerXP, SunfirePrayerXP, Currentshards, Totalshards: Integer; CurrentStateName: String; begin CurrentXP := XPBar.Read(); GainedXP := CurrentXP - startXP; ClearDebug(); Runtime := Timer.ElapsedTime; Totalshards := 0; Currentshards := Inventory.CountItemStack('Blessed bone shards'); Totalshards := Currentshards - StartingShards; PrayerXP := Totalshards * 5; // Each bone shard is worth 5 prayer XP SunfirePrayerXP := Totalshards * 6; // Each bone shard is worth 6 prayer XP with Sunfire wine APIClient.SubmitStats(APIClient.GetUUID()); case Self.CurrentState of STATE_MINECALCIFIEDROCKS: CurrentStateName := 'Mining Calcified Rocks'; STATE_PROCESSDEPOSITS: CurrentStateName := 'Processing Deposits'; STATE_WALKTOBLACKSMITH: CurrentStateName := 'Walking to Blacksmith'; STATE_WALKTOMINESITE: CurrentStateName := 'Walking to Mine Site'; STATE_OPENBANK: CurrentStateName := 'Opening Bank'; STATE_HANDLEBANKING: CurrentStateName := 'Handling Banking'; end; WriteLn('========================================'); WriteLn(' BigAussies Calcified Mining '); WriteLn('========================================'); WriteLn(' Current State: ' + CurrentStateName); WriteLn(' Runtime: ' + SRL.MsToTime(GetTimeRunning, Time_Short)); WriteLn(' Mining XP Gained: ' + FormatRoundedNumber(GainedXP)); WriteLn(' Bone Shards: ' + IntToStr(Totalshards)); WriteLn(' Prayer XP: ' + FormatRoundedNumber(PrayerXP) + ' / Sunfire ' + FormatRoundedNumber(SunfirePrayerXP)); if TotalCalcifiedMoths > 0 then begin WriteLn(' Calcified Moths: ' + IntToStr(TotalCalcifiedMoths)); WriteLn(' Total Moth Profit: ' + FormatRoundedNumber(TotalCalcifiedMoths * CalcifiedMothValue)); end; WriteLn('----------------------------------------'); WriteLn(' Mining XP/Hour: ' + FormatRoundedNumber(Round((GainedXP / (GetTimeRunning / 3600000))))); WriteLn(' Shards/Hour: ' + FormatRoundedNumber(Round((Totalshards) / (GetTimeRunning / 3600000)))); WriteLn(' Prayer XP/Hour: ' + FormatRoundedNumber(Round((PrayerXP) / (GetTimeRunning / 3600000))) + ' / Sunfire ' + FormatRoundedNumber(Round((SunfirePrayerXP) / (GetTimeRunning / 3600000)))); WriteLn('========================================'); WriteLn(' BigAussies Calcified Mining '); WriteLn(' Version: ' + {$MACRO SCRIPT_REVISION}); WriteLn('========================================'); end; procedure CalcifiedMiner.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'); RSW.AdaptiveWalk := True; RSW.Setup('CamTorumMap'); CalcifiedDeposit := ('Calcified deposit'); HammerItem := ('Hammer'); HammerBank := TRSBankItem.Setup(HammerItem, 1, FALSE); CalcifiedMoths := ('Calcified moth'); itemsToKeep := ['Blessed bone shards', 'Gem bag', 'Open gem bag', 'Hammer', 'Imcando hammer', 'Gem bag', 'Bronze pickaxe', 'Adamant pickaxe', 'Crystal pickaxe', 'Dragon pickaxe', 'Rune pickaxe', 'Mithril pickaxe', 'Black pickaxe', 'Steel pickaxe', 'Iron pickaxe', 'Gilded pickaxe', 'Dragon pickaxe (or)', 'Infernal pickaxe (or)', '3rd age pickaxe', 'Infernal pickaxe']; StartXP := XPBar.Read(); Antiban.MinZoom := 15; Antiban.MaxZoom := 30; Antiban.Skills := [ERSSkill.MINING, ERSSkill.PRAYER, ERSSkill.TOTAL]; SetupObjects(); Options.SetZoomLevel(RandomRange(10,24)); CalcifiedMothValue := ItemData.GetAverage(29090); StartingShards := Inventory.CountItemStack('Blessed bone shards'); if PINGONTERMINATED then AddOnTerminate(@Self.SendTerminationNotification); HANDLEBANKING(); end; procedure CalcifiedMiner.Run(MaxActions: UInt32; MaxTime: UInt64); begin Self.Init(MaxActions, MaxTime); repeat Self.doAction(); if WL.Activity.IsFinished() then begin WriteLn('No activity detected in 5 minutes! Shutting down.'); Break; end; Self.DoAntiban; until Self.ShouldStop(); end; var Script: CalcifiedMiner; {$IFDEF SCRIPT_GUI} const CM_GUI_NAV = $F0EBE4; CM_GUI_BG = $FFFFFF; CM_GUI_STATUS = $F7F4F1; CM_GUI_DIVIDER = $D4C9BC; CM_GUI_CARD = $F7F4F1; CM_GUI_ACCENT = $E0C9AE; CM_GUI_NAV_IDLE = $E7DED4; CM_GUI_START = $C9B094; CM_GUI_TEXT = $1C1C1E; CM_GUI_MUTED = $6B6B70; CM_GUI_W = 1120; CM_GUI_H = 700; CM_GUI_NAV_W = 190; CM_GUI_STATUS_H = 56; CM_GUI_BTN_H = 42; CM_GUI_EDIT_W = 260; CM_GUI_COL2 = 308; CM_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; PowerMineCheckbox: TLabeledCheckBox; IgnoreWaterfallsCheckBox, PingOnTerminatedCheckBox, EnableWebhooksCheckBox: TLabeledCheckBox; WebhookInfo, DiscordUIDInfo: TLabel; WebHookInput, DiscordUIDInput: TLabeledEdit; 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(CM_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(CM_GUI_NAV_W - 28)); Result.SetHeight(TControl.AdjustToDPI(CM_GUI_BTN_H)); Result.SetCursor(crHandPoint); if selected then fill := CM_GUI_ACCENT else fill := CM_GUI_NAV_IDLE; Self.PaintRoundChip(Result, labelText, fill, CM_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(CM_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(CM_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(CM_GUI_W - CM_GUI_NAV_W - 2); header := Self.MakePanel(parent, 0, 0, 1, 88, CM_GUI_CARD); header.SetWidth(headerW); header.SetHeight(TControl.AdjustToDPI(88)); Self.MakeLabel(header, titleText, 24, 18, 18, CM_GUI_TEXT, True); Self.MakeLabel(header, subtitleText, 24, 52, 10, CM_GUI_MUTED, False); end; procedure TConfig.StyleNav(selected: TImage); begin Self.ActiveNav := selected; Self.PaintRoundChip(Self.ScriptNav, Self.ScriptNav.GetHint(), CM_GUI_NAV_IDLE, CM_GUI_NAV, False); Self.PaintRoundChip(Self.AccountsNav, Self.AccountsNav.GetHint(), CM_GUI_NAV_IDLE, CM_GUI_NAV, False); Self.PaintRoundChip(Self.AntibanNav, Self.AntibanNav.GetHint(), CM_GUI_NAV_IDLE, CM_GUI_NAV, False); Self.PaintRoundChip(Self.AIChatNav, Self.AIChatNav.GetHint(), CM_GUI_NAV_IDLE, CM_GUI_NAV, False); Self.PaintRoundChip(selected, selected.GetHint(), CM_GUI_ACCENT, CM_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.OpenURL(Sender: TObject); begin if Sender = Self.WebhookInfo then OpenWebPage('https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks') else if Sender = Self.DiscordUIDInfo then OpenWebPage('https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID'); end; procedure TConfig.WebhooksCheckboxChanged(Sender: TObject); begin if Sender = nil then; Self.WebhookInfo.SetVisible(Self.EnableWebhooksCheckBox.IsChecked()); Self.DiscordUIDInfo.SetVisible(Self.EnableWebhooksCheckBox.IsChecked()); Self.DiscordUIDInput.SetVisible(Self.EnableWebhooksCheckBox.IsChecked()); Self.WebHookInput.SetVisible(Self.EnableWebhooksCheckBox.IsChecked()); Self.PingOnTerminatedCheckBox.SetVisible(Self.EnableWebhooksCheckBox.IsChecked()); end; procedure TConfig.StartScript(Sender: TObject); override; begin if Sender = nil then; POWERMINING := Self.PowerMineCheckbox.IsChecked(); IGNOREWATERFALLS := Self.IgnoreWaterfallsCheckBox.IsChecked(); ENABLEWEBHOOKS := Self.EnableWebhooksCheckBox.IsChecked(); DiscordUID := Self.DiscordUIDInput.GetText(); WEBHOOKURL := Self.WebHookInput.GetText(); PINGONTERMINATED := Self.PingOnTerminatedCheckBox.IsChecked(); WLSettings.Put('max_actions', StrToIntDef(Self.MaxActionsInput.GetText(), 0)); WLSettings.Put('max_time', StrToIntDef(Self.MaxTimeInput.GetText(), 0)); WLSettings.SaveConfig(); WriteINI('Webhook Settings', 'DiscordUID', DiscordUID, 'Configs/BASettings.ini'); WriteINI('Webhook Settings', 'WebhookURL', WEBHOOKURL, 'Configs/BASettings.ini'); WriteINI('Webhook Settings', 'PingOnTerminated', BoolToStr(PINGONTERMINATED, 'true', 'false'), 'Configs/BASettings.ini'); WriteINI('Webhook Settings', 'EnableWebhooks', BoolToStr(ENABLEWEBHOOKS, 'true', 'false'), 'Configs/BASettings.ini'); WriteINI('Calcified Mining Settings', 'PowerMining', BoolToStr(POWERMINING, 'true', 'false'), 'Configs/BASettings.ini'); WriteINI('Calcified Mining Settings', 'IgnoreWaterfalls', BoolToStr(IGNOREWATERFALLS, 'true', 'false'), 'Configs/BASettings.ini'); try Self._WarmBuildCache(); except end; AIChatbot.ApplyFromGUI(); Self.Form.SetOnClose(nil); Self.Form.Close(); end; procedure TConfig.BuildScriptSection(SavedIgnoreWaterfalls, SavedPowerMining: Boolean); begin Self.AddHeader(Self.ScriptSection, 'Action', 'Mine calcified rocks and process deposits in Cam Torum.'); Self.AddCheck(Self.ScriptSection, Self.IgnoreWaterfallsCheckBox, 'cb_cm_ignore_waterfalls', 'Ignore Waterfalls', 24, 110, SavedIgnoreWaterfalls); Self.IgnoreWaterfallsCheckBox.SetTooltip('When enabled, waterfalls will be ignored.'); Self.AddCheck(Self.ScriptSection, Self.PowerMineCheckbox, 'cb_cm_power_mine', 'Power Mining', 24, 150, SavedPowerMining); Self.PowerMineCheckbox.SetTooltip('Disables banking and breaking of deposits.'); end; procedure TConfig.BuildAccountsSection( SavedEnableWebhooks, SavedPingOnTerminated: Boolean; SavedDiscordUID, SavedWebhookURL: String ); 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 optional Discord webhook notifications.'); am := Self.CreateAccountManager(Self.AccountsSection); am.SetLeft(TControl.AdjustToDPI(16)); am.SetTop(TControl.AdjustToDPI(100)); am.SetColor(CM_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; Self.MakeLabel(Self.AccountsSection, 'Discord', 24, 340, 11, CM_GUI_TEXT, True); Self.AddCheck(Self.AccountsSection, Self.EnableWebhooksCheckBox, 'cb_cm_webhooks', 'Enable webhooks', 24, 370, SavedEnableWebhooks); Self.EnableWebhooksCheckBox.SetTooltip('Enable or Disable Discord Webhooks.'); Self.EnableWebhooksCheckBox.CheckBox.SetOnChange(@Self.WebhooksCheckboxChanged); Self.WebhookInfo := Self.MakeLabel(Self.AccountsSection, 'Click here to learn how to generate a Discord webhook URL', 24, 410, 10, $C07020, False); Self.WebhookInfo.SetOnClick(@Self.OpenURL); Self.WebhookInfo.SetCursor(crHandPoint); Self.WebhookInfo.SetTooltip('Opens a guide for creating a Discord webhook URL.'); Self.AddEdit(Self.AccountsSection, Self.DiscordUIDInput, 'le_cm_discord_uid', 'Discord UID (Optional)', SavedDiscordUID, 24, 440, CM_GUI_EDIT_W); Self.DiscordUIDInput.SetTooltip('This will mention you in the discord message.'); Self.DiscordUIDInfo := Self.MakeLabel(Self.AccountsSection, 'Click here to learn how to find your Discord User ID', CM_GUI_COL2, 458, 10, $C07020, False); Self.DiscordUIDInfo.SetOnClick(@Self.OpenURL); Self.DiscordUIDInfo.SetCursor(crHandPoint); Self.DiscordUIDInfo.SetTooltip('Opens a guide for finding your Discord User ID.'); Self.AddEdit(Self.AccountsSection, Self.WebHookInput, 'le_cm_webhook', 'Webhook URL', SavedWebhookURL, 24, 510, 520); Self.WebHookInput.SetTooltip('Paste your Discord webhook URL here.'); Self.AddCheck(Self.AccountsSection, Self.PingOnTerminatedCheckBox, 'cb_cm_ping_terminated', 'Ping on terminated', 24, 580, SavedPingOnTerminated); Self.PingOnTerminatedCheckBox.SetTooltip('Enable to ping when the script terminates cleanly'); end; procedure TConfig.BuildAntibanSection(SavedMaxActions, SavedMaxTime: Integer); begin Self.AddHeader(Self.AntibanSection, 'Antiban', 'Session limits.'); Self.AddEdit(Self.AntibanSection, Self.MaxActionsInput, 'le_cm_maxactions', 'Max actions (0 = unlimited)', IntToStr(SavedMaxActions), 24, 110, CM_GUI_EDIT_W); Self.MaxActionsInput.Edit.SetOnKeyPress(@Self.MaxActionsInput.Edit.NumberField); Self.AddEdit(Self.AntibanSection, Self.MaxTimeInput, 'le_cm_maxtime', 'Max time minutes (0 = unlimited)', IntToStr(SavedMaxTime), CM_GUI_COL2, 110, CM_GUI_EDIT_W); Self.MaxTimeInput.Edit.SetOnKeyPress(@Self.MaxTimeInput.Edit.NumberField); end; procedure TConfig.BuildShell( SavedIgnoreWaterfalls, SavedPowerMining, SavedEnableWebhooks, SavedPingOnTerminated: Boolean; SavedDiscordUID, SavedWebhookURL: String; SavedMaxActions, SavedMaxTime: Integer ); var tab: TTabSheet; contentH, startW, startH, shellW, shellH, statusTop, statusH, mainLeft, mainW, navW, bottomInset: Int32; begin Self.AddTab('Calcified Mining'); 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(CM_GUI_BOTTOM_INSET); navW := TControl.AdjustToDPI(CM_GUI_NAV_W); statusH := TControl.AdjustToDPI(CM_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(CM_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(CM_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(CM_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(CM_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(CM_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(CM_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(CM_GUI_STATUS); Self.StatusPad.SetBevelOuter(bvNone); Self.BrandLabel := Self.MakeLabel(Self.NavPanel, 'Calcified Mining', 16, 28, 14, CM_GUI_TEXT, True); Self.MakeLabel(Self.NavPanel, 'BigAussie', 16, 54, 9, CM_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, CM_GUI_BG); Self.AccountsSection := Self.MakePanel(Self.ContentPanel, 0, 0, 100, 100, CM_GUI_BG); Self.AntibanSection := Self.MakePanel(Self.ContentPanel, 0, 0, 100, 100, CM_GUI_BG); Self.AIChatSection := Self.MakePanel(Self.ContentPanel, 0, 0, 100, 100, CM_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(SavedIgnoreWaterfalls, SavedPowerMining); Self.BuildAccountsSection(SavedEnableWebhooks, SavedPingOnTerminated, SavedDiscordUID, SavedWebhookURL); 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', CM_GUI_START, CM_GUI_STATUS, True, True); Self.StartChip.SetOnClick(@Self.StartScript); Self.WebhooksCheckboxChanged(nil); Self.ShowScript(Self.ScriptNav); end; procedure TConfig.Run(); override; var SavedIgnoreWaterfalls, SavedPowerMining, SavedEnableWebhooks, SavedPingOnTerminated: Boolean; SavedDiscordUID, SavedWebhookURL: String; SavedMaxActions, SavedMaxTime: Integer; begin BashPromptIfUpdateAvailable(); SavedDiscordUID := ReadINI('Webhook Settings', 'DiscordUID', 'Configs/BASettings.ini'); if SavedDiscordUID = '' then SavedDiscordUID := DiscordUID; SavedWebhookURL := ReadINI('Webhook Settings', 'WebhookURL', 'Configs/BASettings.ini'); if SavedWebhookURL = '' then SavedWebhookURL := WEBHOOKURL; SavedEnableWebhooks := StrToBoolDef(ReadINI('Webhook Settings', 'EnableWebhooks', 'Configs/BASettings.ini'), ENABLEWEBHOOKS); SavedPingOnTerminated := StrToBoolDef(ReadINI('Webhook Settings', 'PingOnTerminated', 'Configs/BASettings.ini'), PINGONTERMINATED); SavedPowerMining := StrToBoolDef(ReadINI('Calcified Mining Settings', 'PowerMining', 'Configs/BASettings.ini'), POWERMINING); SavedIgnoreWaterfalls := StrToBoolDef(ReadINI('Calcified Mining Settings', 'IgnoreWaterfalls', 'Configs/BASettings.ini'), IGNOREWATERFALLS); 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('calcified mining'); Self.Setup('BigAussies Calcified Mining', [CM_GUI_W, CM_GUI_H], False); Self.BuildShell( SavedIgnoreWaterfalls, SavedPowerMining, SavedEnableWebhooks, SavedPingOnTerminated, SavedDiscordUID, SavedWebhookURL, SavedMaxActions, SavedMaxTime ); inherited; end; var Config: TConfig; {$ENDIF} begin {$IFDEF SCRIPT_GUI} Sync(@Config.Run); {$ENDIF} Script.Run(WLSettings.MaxActions, WLSettings.MaxTime); end; end.