All scripts

Tin/Copper Miner Varrock East

by SolemnVanguard ·Mining

Mines in Varock East with banking, build in sleep, bank from chest and mod protection

0

Installed

1.0

Version

22 Aug 2026

Updated

Builds

VersionKindPublishedSizeWhat changed
1.0 current text script 22 Aug 2026 9 KB First upload.

Source of 1.0

Published by the author. This is the current build, exactly as it will be delivered.

script "Tin & Copper Miner Varrock"
author "SolemnVanguard"
version "1.0"
every 600

setting string depositIds = "202,150,160,159,154,153,157" "Comma-separated item ids to deposit at the bank"

# Mines ONLY the Tin rock (id 104) at exact tile(78, 547) and the Copper
# rock (id 100) at exact tile(76, 547), standing at tile(77, 547) -
# ignores any other rock with the same ids elsewhere. Alternates between
# the two on every attempt (tin is closer to the standing tile and would
# otherwise always be picked first), so both get mined even without
# knowing when either one is actually depleted. When the inventory is
# full, walks the same path as Iron Miner Varrock East to Bank Chest
# (id 942) near tile(99, 512), deposits each item id from the depositIds
# setting (Tin ore 202, Copper ore 150, plus gems - one per pass, 650ms
# apart, skipping any id the inventory doesn't actually contain), then
# walks back and resumes mining. Uses Sleeping Bag (id 1263) at 100%
# fatigue.
#
# Teleport protection: if the character's tile jumps more than 20 tiles
# between passes, the script halts (shows a red warning) rather than
# continuing from an unknown location.
#
# Fatigue failsafe: if fatigue jumps more than 25 points in a single
# pass, that is treated as suspicious (e.g. a mod forcing it up to test
# you) and the script halts (shows an orange warning) instead of using
# the Sleeping Bag as if it were normal.

var stuckCount = 0
var lastMinedWasTin = false

var lastTile = tile(0, 0)
var haveLastTile = false
var pendingJump = false
var haltedTeleport = false

var prevFatigueVal = -1
var haltedFatigueJump = false
var FatigueJumpLimit = 25

var depositIdList = range(0, 0)   # filled in on start from the setting
var depositIndex = 0

fun halted() -> bool {
    return haltedTeleport or haltedFatigueJump
}

fun teleportCheck() {
    let now = myTile()
    if haveLastTile {
        let jumped = distance(lastTile, now)
        if jumped > 20 {
            if pendingJump {
                print("Jumped", jumped, "tiles, confirmed on second check - halting")
                haltedTeleport = true
                lastTile = now
            } else {
                print("Jumped", jumped, "tiles - unconfirmed, checking again next pass")
                pendingJump = true
            }
        } else {
            pendingJump = false
            lastTile = now
        }
    } else {
        lastTile = now
        haveLastTile = true
    }
}

fun fatigueSuspiciousCheck() {
    let curFatigue = fatigue()
    if prevFatigueVal >= 0 {
        let jump = curFatigue - prevFatigueVal
        if jump > FatigueJumpLimit {
            print("Fatigue spike detected:", prevFatigueVal, "->", curFatigue, "- halting")
            haltedFatigueJump = true
        }
    }
    prevFatigueVal = curFatigue
}

on start {
    if not bankAvailable() {
        print("Bank not available")
    }
    if not minimapAvailable() {
        print("Warning: minimap hooks not ready yet - walkPath may misbehave")
    }

    for piece in split(depositIds, ",") {
        let parsed = parseInt(piece)
        if parsed != none {
            depositIdList = append(depositIdList, parsed)
        }
    }
    print("Deposit ids loaded:", count(depositIdList))

    pathStart("route", "mine", tile(75, 543))
    pathTile("route", tile(74, 543))
    pathTile("route", tile(75, 536))
    pathTile("route", tile(75, 530))
    pathTile("route", tile(79, 522))
    pathTile("route", tile(83, 514))
    pathTile("route", tile(90, 511))
    pathFinish("route", "bank", tile(99, 512))
}

state mining {
    teleportCheck()
    fatigueSuspiciousCheck()
    if halted() { return 999999 }

    if isSleeping() {
        print("Sleeping, fatigue left to sleep off:", sleepFatigue())
        return 2000
    }
    if fatigue() >= 100 {
        print("Fatigue is 100 - using Sleeping Bag")
        let bag = invItem(1263)
        if bag != none {
            interact(bag, "Sleep")
        }
        return random(600, 900)
    }

    if invIsFull() { become goingToBank }

    if batchActive() { return 100 }

    if lastMinedWasTin {
        for rock in objectsByDistance(within: 5) {
            if rock.id == 100 and rock.tile == tile(76, 547) {
                if reach(rock) == "DRAWN" {
                    interact(rock, "Mine")
                }
                lastMinedWasTin = false
                return random(900, 1400)
            }
        }
        for rock in objectsByDistance(within: 5) {
            if rock.id == 104 and rock.tile == tile(78, 547) {
                if reach(rock) == "DRAWN" {
                    interact(rock, "Mine")
                }
                lastMinedWasTin = true
                return random(900, 1400)
            }
        }
    } else {
        for rock in objectsByDistance(within: 5) {
            if rock.id == 104 and rock.tile == tile(78, 547) {
                if reach(rock) == "DRAWN" {
                    interact(rock, "Mine")
                }
                lastMinedWasTin = true
                return random(900, 1400)
            }
        }
        for rock in objectsByDistance(within: 5) {
            if rock.id == 100 and rock.tile == tile(76, 547) {
                if reach(rock) == "DRAWN" {
                    interact(rock, "Mine")
                }
                lastMinedWasTin = false
                return random(900, 1400)
            }
        }
    }

    print("No tin/copper rock found - waiting")
    return 1000
}

state goingToBank {
    teleportCheck()
    fatigueSuspiciousCheck()
    if halted() { return 999999 }

    if isSleeping() {
        print("Sleeping, fatigue left to sleep off:", sleepFatigue())
        return 2000
    }
    if fatigue() >= 100 {
        print("Fatigue is 100 - using Sleeping Bag")
        let bag = invItem(1263)
        if bag != none {
            interact(bag, "Sleep")
        }
        return random(600, 900)
    }

    let how = walkPath("route", "bank")

    if how == "ARRIVED" {
        stuckCount = 0
        depositIndex = 0
        become banking
    } else if how == "WALKING" {
        stuckCount = 0
        return 900
    } else if how == "CROSSING" {
        stuckCount = 0
        return 1500
    } else if how == "BLOCKED" or how == "STUCK" {
        stuckCount = stuckCount + 1
        print("Blocked/stuck (", stuckCount, ") - waiting for it to clear")
        if stuckCount >= 10 {
            print("Been stuck too long - resetting path")
            pathReset("route")
            stuckCount = 0
        }
        return 1200
    } else {
        print("goingToBank status:", how)
        return 1000
    }
}

state banking {
    teleportCheck()
    fatigueSuspiciousCheck()
    if halted() { return 999999 }

    if isSleeping() {
        print("Sleeping, fatigue left to sleep off:", sleepFatigue())
        return 2000
    }
    if fatigue() >= 100 {
        if bankIsOpen() {
            bankClose()
            return 600
        }
        print("Fatigue is 100 - using Sleeping Bag")
        let bag = invItem(1263)
        if bag != none {
            interact(bag, "Sleep")
        }
        return random(600, 900)
    }

    let chest = nearestObject(id: 942, within: 5)
    if chest == none {
        print("No Bank Chest (942) found - waiting")
        return 1000
    }

    if not bankIsOpen() {
        let howReach = reach(chest)
        print("reach(chest) =", howReach)
        if howReach == "DRAWN" {
            let opened = interact(chest, "open")
            print("interact(chest, 'open') =", opened)
            wait until bankIsOpen() timeout 2000 else { return 300 }
        }
        return 1000
    }

    let id = depositIdList[depositIndex]
    if id == none {
        depositIndex = 0
        bankClose()
        become goingToMine
    } else {
        if invContains(id) {
            bankDepositAll(id)
        }
        depositIndex = depositIndex + 1
        return 650
    }
}

state goingToMine {
    teleportCheck()
    fatigueSuspiciousCheck()
    if halted() { return 999999 }

    if isSleeping() {
        print("Sleeping, fatigue left to sleep off:", sleepFatigue())
        return 2000
    }
    if fatigue() >= 100 {
        print("Fatigue is 100 - using Sleeping Bag")
        let bag = invItem(1263)
        if bag != none {
            interact(bag, "Sleep")
        }
        return random(600, 900)
    }

    let how = walkPath("route", "mine")

    if how == "ARRIVED" {
        stuckCount = 0
        become mining
    } else if how == "WALKING" {
        stuckCount = 0
        return 900
    } else if how == "CROSSING" {
        stuckCount = 0
        return 1500
    } else if how == "BLOCKED" or how == "STUCK" {
        stuckCount = stuckCount + 1
        print("Blocked/stuck (", stuckCount, ") - waiting for it to clear")
        if stuckCount >= 10 {
            print("Been stuck too long - resetting path")
            pathReset("route")
            stuckCount = 0
        }
        return 1200
    } else {
        print("goingToMine status:", how)
        return 1000
    }
}

on render {
    if halted() {
        let flashOn = wrap(nowMillis(), 0, 999) < 500
        let bg = "#cc0000ee"
        if haltedTeleport {
            if not flashOn { bg = "#660000ee" }
            paintRoundFill(4, 300, 220, 60, 12, bg)
            paintTextCenteredSized(114, 322, "TELEPORTED", "white", 16)
        } else {
            bg = "#cc6600ee"
            if not flashOn { bg = "#663300ee" }
            paintRoundFill(4, 300, 220, 60, 12, bg)
            paintTextCenteredSized(114, 322, "FATIGUE SPIKE", "white", 16)
        }
        paintTextCenteredSized(114, 344, "SCRIPT STOPPED", "white", 12)
    }
}