Jump to content
Frequently Asked Questions
  • Are you not able to open the client? Try following our getting started guide
  • Still not working? Try downloading and running JarFix
  • Help! My bot doesn't do anything! Enable fresh start in client settings and restart the client
  • How to purchase with PayPal/OSRS/Crypto gold? You can purchase vouchers from other users
  • Free vorkath script


    lsjc12911

    Recommended Posts

    Posted (edited)

    I've removed all the unnecessary banking, restoring things like that and left the main vorkath fighting source code.

    source-code.zip

    Disclaimer

    Every computer has it's own spec and speed is all different for everyone. If you have a slow computer, the script is going to miss or be delayed in some critical situations. What i'm trying to say is this code is static. It's close to hard code so indicating specific situations might not fall into the exact hands for some.

    Plus this script is running on 0 millisecond loop to indicate all precise movements from vorkath. So if you dont have a medium tier spec computer, then oh well.

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Assuming you all have knowledge to fight vorkath,

    This is where the vorkathService instance begins.

    public int fightVorkath() {
        checkIfVorkathIsKilled();
        vorkathNormalCntAttack();
        int num = indicateCurrentState();
        switch (num) {
            case 2:
            case 4:
                resetPitchAngle();
                log("[VORKATH][END] Can't fight");
                remainingInventorySpace();
                log("[VORKATH][END] Teleporting to house");
                Inventory.interact(itemLibrary.getTeleportToHouseTab(), "Inside");
                Sleep.sleep(4500, 5000);
                return num;
            case 3:
                return num;
        }
        return 1;
    }

    The return hard coded numbers was for the Class to pass the vorkathService's status so that it can do the next of when player is dead needs to restore, bank and etc.

    I set 2 to be restoring and banking, 4 to be end of cycle so the player can take breaks (Custom break was used), 3 on death

    Every miliseconds we will be checking if

    - vorkath has been killed

    - the number of vorkath's attack

    - indicating current state

    1. status

    In order to know the mechanism of this script you must be aware of the statuses.

    There is a `Stage status` for the current stage, a `player status`

    So stage status is pretty much the status for the current situation, and player status is the status for the player.

     

    2. indicateCurrentState()

     

    private int indicateCurrentState() {
        if(validateIfPlayerIsDead()) {
            Sleep.sleep(5000, 6000);
            return 3;
        }
    
        switch (stageStatus) {
            case ACID_PHASE:
                toggleRun(false);
                enableMouseHop();
                acidPhase();
                break;
            case NORMAL_ATTACK_PHASE:
                normalAttackPhase();
                break;
            case UNDEAD_PHASE:
                undeadPhase();
                break;
            case INITIALIZING_INSTANCE:
                defaultAttackTileIndicator();
                break;
            case WAKING_VORKATH:
                wakingVorkath();
                break;
            case INDICATING_AGROED_MODE:
                indicatingAgroedMode();
                break;
            case LOOT:
                return looting();
            case BEFORE_WAKING_VORKATH:
                return beforeWakingVorkath();
            case RUNNING_TO_DEFAULT_ATTACK_STANCE:
                runningToDefaultAttackStance();
                break;
        }
        return 1;
    }

    So what we are doing here is we are indicating the current status. The main initial statuses on running the script are the status below

    - Is the player inside of the instance for the first time? (Initial)

    - Does the character have enough food and potion to fight vorkath?

    When creating the vorkathService class, StageStatus will be initialized to INITIALIZING_INSTANCE which will automatically indicate the boundaries for the players attack tiles, wooxWalking.

    private void defaultAttackTileIndicator() {
        if(defaultStanceTile == null) {
            log("[VORKATH][DEFAULT] Indicating default attack stance tile");
            NPC vorkath = clickableNpcHandler.getClosestNpc("Vorkath");
            vorkathTile = vorkath.getTile();
            int vorkathX = vorkath.getX();
            int vorkathY = vorkath.getY();
            this.defaultStanceTile = new Tile(vorkathX+3, vorkathY-10);
            this.defaultStanceTile2 = new Tile(this.defaultStanceTile.getX()-1, this.defaultStanceTile.getY());
            for(int i = 0; i < wooxWalkingTile[0].length; i++) {
                wooxWalkingTile[0][i] = new Tile(defaultStanceTile.getX() - i, defaultStanceTile.getY());
                wooxWalkingTile[1][i] = new Tile(defaultStanceTile.getX() - i, defaultStanceTile.getY()-1);
            }
    
            attackLine = new Area(wooxWalkingTile[0][6], wooxWalkingTile[0][0]);
            stageStatus = StageStatus.BEFORE_WAKING_VORKATH;
        }
    }

    The code above is finding the two rows for vorkath, it will start from vorkath's position and making its way up to the rows. 

    image.png.9e6c94f67b100cee936f8d9d139f12bf.png

    The reason for the Default attack stance to be in the black spot is because for wooxWalking. Later when I explain the wooxWalking method, the dynmaic algorithm for each acid phase will calculate the acid tiles and find the valid safe tiles for the character to woox walk. If the black tile is not your choice of default attack stance then set it to your liking. After the default tiles has been indicated, This method won't be called unless the player has been teleported out or the script has been stopped. It will then set the next stage status to BEFORE_WAKING_VORKATH

    private int beforeWakingVorkath() {
        NPC vorkath;
        // Haven't fully analyzed why getting vorkath object sometimes returns null but this is the best I can do to prevent nullPointerExceptions
        if(vorkathTile == null) {
            vorkath = NPCs.closest(c -> c != null && c.getName().contentEquals("Vorkath"));
        }
        else {
            vorkath = NPCs.closest(c -> c != null && c.getName().contentEquals("Vorkath") && movementUtil.isOnTile(c.getTile(), vorkathTile));
        }
        try {
            if(vorkath.getID() == vorkathSleepingId) {
                if(!inventoryHandler.validateVorkathCombatItems(potionHandler.isPotionActive(Potion.EXTENDED_SUPER_ANTIFIRE), potionHandler.isPotionActive(Potion.DIVINE_RANGING), potionHandler.isPotionActive(Potion.SUPER_ANTIVENOM))) {
                    resetingEverything();
                    return 2;
                }
                else {
                    if(validatePotions(Potion.EXTENDED_SUPER_ANTIFIRE, itemLibrary.getExtendedSuperAntiFirePots())) {
                        inventoryHandler.drinkPotions(itemLibrary.getExtendedSuperAntiFirePots());
                        log("[VORKATH] Drink EXTENDED FIRE POT");
                        Sleep.sleep(1500, 2000);
                    }
                    if(validatePotions(Potion.DIVINE_RANGING, itemLibrary.getDivineRangingPots())) {
                        inventoryHandler.drinkPotions(itemLibrary.getDivineRangingPots());
                        log("[VORKATH] Drink DIVINE RANGING POT");
                        Sleep.sleep(1500, 2000);
                    }
                    if(validatePotions(Potion.SUPER_ANTIVENOM, itemLibrary.getAntiVenomPots())) {
                        inventoryHandler.drinkPotions(itemLibrary.getAntiVenomPots());
                        log("[VORKATH] Drink SUPER ANTI VENOM");
                        Sleep.sleep(1500, 2000);
                    }
                    if(playerHandler.setAutoRetaliate(false)) {
                        Sleep.sleep(600, 800);
                    }
                    disableChatBox();
                    if(toggleRun(true)) {
                        Sleep.sleep(600, 800);
                    }
                    validatePitchAngle();
                    stageStatus = StageStatus.WAKING_VORKATH;
                }
            }
        } catch (Exception ignored) {
        }
        return 1;
    }

    In this method, the script is going to indicate if Vorkath is sleeping by comparing it to the Globalized vorkath sleep id. If vorkath is sleeping, then it will indicate the corresponding factors

    - does it have the valid amount of items to fight vorkath?

    If it does

    - is Fire immune on?

    - is Divine ranging potion potted?

    - is Venom immune on? (This will reset everytime the script is stopped and started, haven't quite found the API for venom immune)

    After it will disable the "All" chatbox, and set autoRetaliate to off, Set the camera pitch angle to the best angle (for my tested perspective) and Poke vorkath

    Since poking vorkath is straight forward, will skip this explanation and move right on to the next method.

    So walking up vorkath will process of WAKING_VORKATH RUNNING_TO_DEFAULT_ATTACK_STANCE . (Like I mentioned earlier, I chose the default attack stance to be the black spot in the image because of no reason. I learned vorkath that way, and when acid phase occurs, it's just easy for me to make my way up the wooxWalking tile (where its 99% safe) and find the corresponding wooxWalking tiles)

    After the player has reached the default attack stance the stage status will change to INDICATING_AGROED_MODE

    and wait till vorkath's NPC id has changed from sleeping to agroed (See the globalized final variables for vorkath's npc ids) Once vorkath has been agroed, the status will the n be changed to NORMAL_ATTACK_PHASE  and vorkathAgroed boolean will be TRUE.

    vorkathAgroed = true; will access and repetitively check normalAttackPhase(), checkIfVorkathIsKilled(), vorkathNormalCntAttack() which are the most important methods for fighting vorkath.

    3. normalAttackPhase() && vorkathNormalCntAttack()

    For the sake being, i'll simply explain vorkath's phases.

    Vorkath has 3 phases. One I call it being normal attack phase where vorkath attacks with the mixture of (Normal fire attack, Venom fire attack, Prayer deactivate fire attack and Huge fire ball mortar attack)

    Every intial 6 attacks will leads to a random phase called "Acid phase" where vorkath spits acids on random tiles and spit out huge amounts of fire balls at you, or it will freeze you and spawn a ZombiedSpawn called "Undead phase".

    So for example the phase cycles goes, Normal phase -> (Initial random phase) acid phase -> Normal phase -> undead phase -> normal phase -> acid phase etc...

    - Normal phase

    - Acid phase

    - Undead phase

    In the normal phase

    private void normalAttackPhase() {
        if(vorkathAttackCnt > 5) return;
        vorkathNormalCntAttack();
        if(Players.getLocal().getServerTile().getY() > defaultStanceTile.getY()) {
            vorkathNormalCntAttack();
            Tile curTile = Players.getLocal().getServerTile();
            returningTile = new Tile(curTile.getX(), defaultStanceTile.getY());
            movementUtil.walkToTile(returningTile);
            returningToTile = true;
        }
        else if (Players.getLocal().getServerTile().getY() < defaultStanceTile.getY()) {
            vorkathNormalCntAttack();
            attackVorkath();
        }
        if(returningToTile) {
            vorkathNormalCntAttack();
            if(movementUtil.isOnTile(returningTile, Players.getLocal().getServerTile())) {
                vorkathNormalCntAttack();
                attackVorkath();
                returningToTile = false;
                returningTile = null;
            }
        }
        turnOnQuickPrayer();
        switchToDiamondBolts();
        if(attackLine.contains(Players.getLocal().getServerTile())) {
            toggleRun(true);
        }
    }

    We are indicating

    - If vorkath attack cnt is bigger than 5 because due to vorkath's normal attack, every 6 normal attacks will result into either Acid and Undead phase. So once they have entered does, phases were don't want the script to handle normal attack phase at that situation.

    - Indicating if player is on the default attack ROW, due to the player something mis-clicking vorkath results it to run up to it. So we're going to need to tell the player to get back to the default attack row.

    - Indicate if prayer has been deactivated from vorkath's purple attack (Prayer deactivation fire attack)

    - Switching bolts referencing Vorkath strategies 

    image.png.bf2e7fe8f87e8a0ab8757cc6a4b9472d.png

    - and lastly toggling run mode when player is on the attack line.

     

    Okay now here's where the explanation gets tricky.

    I haven't managed to figure out how to count vorkath's attacks and keep track efficiently. But I manged to work around it and fiddle around with vorkath's animation.

    I'll try to do my best to explain this method and divide it into two separate parts.

    Vorkath attack count is less than 6

    private void vorkathNormalCntAttackifvorkathAgroedreturn;
        ifvorkathAttackCnt 7return;
        closestvorkathAgoredId;
        ifnullreturn;
        int ;
        if1vorkathAttacked false;
            vorkathAttackStyle null;
            return;
        ifvorkathAttackCnt 6closestvorkathAgoredId;
            ifvorkathAttackedreturn;
            ifvorkathNormalAttackAnimationthisvorkathAttackCnt;
                ;
                vorkathAttackStyle NORMAL;
                log"[VORKATH] Normal attack, cnt: " vorkathAttackCnt;
                vorkathAttacked true;
            else if, vorkathTiltHeadUpAnimationthisvorkathAttackCnt;
                log"[VORKATH] Fireball attack cnt: " vorkathAttackCnt;
                vorkathAttackStyle FIREBALL;
                playerStatus AVOID_FIRE_BALL;
                vorkathAttacked true;
                ;
            else 

    So as I metioned above about vorkath's mechanism, Vorkath attacks a random style of 4 mixtures in normal attack mode. (Normal fire, Venom and prayer deactivation and fire ball)

    Every attack will count vorkath's attack count to +1. Here's the catch, since we've set our script speed to return 0 milliseconds, we need to find a way to stop counting after it's been indicated. So what i've done is no matter how many times, it enters vorkathNormalCntAttack() once we've added the attackCount, we are going to set vorkathAttacked to TRUE to prevent unnecessary counting.

    And to reset this, were going to indicate if vorkath's animation id has turned to idle id which is -1 for all npcs. Then we are going to set the vorkathAttacked to FALSE to reset the counter.

    Normal fire, Venom and prayer deactivation has the animation of the same of vorkathNormalAttackAnimation

    But when vorkath tilts its head up, where going to need to avoid the Fire ball mortar so, in that animation where going to call avoidFireBall()

    private int avoidFireBall() {
        vorkathAttackStyle = null;
        playerStatus = PlayerStatus.IDLE;
        log("[VORKATH] Avoiding fire ball");
        validatePlayerPosition();
        enableMouseHop();
    
        if(playerInPosition) {
            avoidFireBallDestinationTile = new Tile(Players.getLocal().getServerTile().getX()-2, Players.getLocal().getServerTile().getY());
            playerInPosition = false;
        }
        else {
            avoidFireBallDestinationTile = defaultStanceTile;
            playerInPosition = true;
        }
        boolean loop = true;
        int clickCount = 0;
        int returnInt = 0;
        while(loop) {
            if(clickCount < 1) {
                movementUtil.walkToTile(avoidFireBallDestinationTile);
                clickCount++;
            }
            Tile currentTile = Players.getLocal().getServerTile();
            if(movementUtil.isOnTile(currentTile, avoidFireBallDestinationTile)) {
                avoidFireBallDestinationTile = null;
                returnInt = 1;
                loop = false;
                disableMouseHop();
                attackVorkath();
            }
            else if(lumbridgeRespawnArea.contains(currentTile)) {
                returnInt = 3;
                loop = false;
            }
        }
        disableMouseHop();
    
        return returnInt;
    }

    validatePlayerPosition()is going to indicate if the player is on (defaultAttackStance || defaultAttackStance - 1x ) and avoid the two tiles from where they have currently stood. 

    Mouse hop will be activated for quick avoiding.

    Vorkath attack count is greater than 5

    private void vorkathNormalCntAttack() {
        if(!vorkathAgroed) return;
        if(vorkathAttackCnt == 7) return;
        NPC vorkath = NPCs.closest(vorkathAgoredId);
        if(vorkath == null) return;
        int vorkathAnimation = vorkath.getAnimation();
        if(vorkathAnimation == -1) {
            vorkathAttacked = false;
            vorkathAttackStyle = null;
            return;
        }
        if(vorkathAttackCnt < 6) {
            (...)
        }
        else {
            vorkathAttackCnt++;
            vorkathAttacked = false;
            vorkathAttackStyle = null;
            if(nextPhase == null) {
                boolean validateRun = true;
                int newAnimation = 0;
                int cnt = 0;
    
                log("[VORKATH] Validating phase");
                while(validateRun) {
                    vorkath = NPCs.closest(vorkathAgoredId);
                    int animation = vorkath.getAnimation();
    
                    if(animation == 7498 || animation == 7948) {
                        continue;
                    }
                    if(animation != -1 && cnt == 0) {
                        log("[VORKATH] Previous animation id: " + animation);
                        if(animation == vorkathAcidAnimation) {
                            newAnimation = animation;
                            validateRun = false;
                        }
                        cnt++;
                    }
                    else if(cnt == 1 && animation == -1) {
                        log("[VORKATH] Vorkath idle");
                        cnt++;
                    }
                    else if(cnt == 2 && animation != -1) {
                        newAnimation = vorkath.getAnimation();
                        log("[VORKATH] Indicated real animation id: " + newAnimation);
                        validateRun = false;
                    }
                }
                if(newAnimation == vorkathAcidAnimation) {
                    log("[VORKATH][ACID] Acid phase indicated!");
                    stageStatus = StageStatus.ACID_PHASE;
                    playerStatus = PlayerStatus.BACKING_UP;
                    nextPhase = StageStatus.ACID_PHASE;
                }
                else if(newAnimation == vorkathNormalAttackAnimation || newAnimation == vorkathTiltHeadUpAnimation){
                    log("[VORKATH][UNDEAD] undead phase indicated!");
                    stageStatus = StageStatus.UNDEAD_PHASE;
                    playerStatus = PlayerStatus.READY;
                    nextPhase = StageStatus.UNDEAD_PHASE;
                }
            }
            else {
                stageStatus = nextPhase;
                if(stageStatus == StageStatus.ACID_PHASE) {
                    playerStatus = PlayerStatus.BACKING_UP;
                }
                else {
                    playerStatus = PlayerStatus.READY;
                }
            }
        }
    }

    I've mentioned that every initial normal attack phase, vorkath picks a random ACID or UNDEAD phase. This is the part where we indicate the initial phase.

    This was the hard part.

    while(validateRun) {
        vorkath = NPCs.closest(vorkathAgoredId);
        int animation = vorkath.getAnimation();
    
        if(animation == 7498 || animation == 7948) {
            continue;
        }
        if(animation != -1 && cnt == 0) {
            log("[VORKATH] Previous animation id: " + animation);
            if(animation == vorkathAcidAnimation) {
                newAnimation = animation;
                validateRun = false;
            }
            cnt++;
        }
        else if(cnt == 1 && animation == -1) {
            log("[VORKATH] Vorkath idle");
            cnt++;
        }
        else if(cnt == 2 && animation != -1) {
            newAnimation = vorkath.getAnimation();
            log("[VORKATH] Indicated real animation id: " + newAnimation);
            validateRun = false;
        }
    }
    

    For the code above, we are in the corresponding state shown in the image below. Right in between when vorkath has attacked it's 6th normal attack and indicating the random phase.

    image.thumb.png.a74f92d1d02557c42a8c750fb1a2651b.png

    So as you can see in the code shown above, if nextPhase is equaled to NULL, we can indicate that the vorkath's acid or undead phase has not been identified yet so, after the 6th normal attack, we are going to set a infinite loop to indicate vorkath's recent attack style,

    - Skip animations 7498 7948 (When your computer is slow, it won't make it to this method in time to indicate vorkath's recent attack style so, sometimes when the method haven't reached vorkath in time, vorkath sometimes animates to the corresponding two animations which i'm not sure what it is. I guess its another type of idling)

    - Validate 6th attack style to anything but -1

    - Validate idling preparation for the 7th

    - Quickly take the 7th animation id and compare it to the below to initiate the next phase

    if(newAnimation == vorkathAcidAnimation) {
        log("[VORKATH][ACID] Acid phase indicated!");
        stageStatus = StageStatus.ACID_PHASE;
        playerStatus = PlayerStatus.BACKING_UP;
        nextPhase = StageStatus.ACID_PHASE;
    }
    else if(newAnimation == vorkathNormalAttackAnimation || newAnimation == vorkathTiltHeadUpAnimation){
        log("[VORKATH][UNDEAD] undead phase indicated!");
        stageStatus = StageStatus.UNDEAD_PHASE;
        playerStatus = PlayerStatus.READY;
        nextPhase = StageStatus.UNDEAD_PHASE;
    }

    Rather than the initial phase indication, next phase is going to be the opposite of the current stage. No need to indicate it like this.

    4. wooxWalking

    Before explaining vorkath's woox walk,

    My wooxwalking method is some what different to methods out there, I'm not sure if its well known but i've learned my woox walking from this video: https://www.youtube.com/watch?v=tgiw7Ml01uc&t=77s

    image.png.3522b75157bad1d0294fe18b0c919fbb.png
    Basically we are going to need three things. One, Three tile and vorkath's position.

    1. When true server tile hits tile one, we are going to attack vorkath

    2. When player has animated the ranging animation or true tile has reached the tile in front of one

    3. We are going to quickly click the tile 3

    4. Once true tile reaches 3, rinse and repeat

    When vorkath's stage has been set to acid phase the code below comes into play

    private void acidPhase() {
        switch(playerStatus) {
            case BACKING_UP: playerBackingUp();
                break;
            case BACKED_UP: playerBackedUp();
                break;
            case WOOX_WALKING:
                wooxWalking();
                break;
            case AVOIDING_ACID: avoidingAcid();
                break;
        }
    }

    Backing up

    As I mentioned above, we are going to use two rows of tiles, the front row being the attack tile and the row behind being the safe spot for the player to walk round and avoid fire ball spits.

    Once vorkath's animation hits the acid phase, we are going turn off prayer, toggle off run energy and back the player up.

    private void playerBackingUp() {
        NPC vorkath = clickableNpcHandler.getClosestNpc("Vorkath");
        if(vorkath == null) return;
        if(!validateAnimation(vorkath, vorkathAcidAnimation)) return;
        turnOffQuickPrayer();
        Tile currentTile = Players.getLocal().getServerTile();
        backingUpTile = new Tile(currentTile.getX(), currentTile.getY()-1);
        movementUtil.vorkathWalkToTile(backingUpTile);
        playerStatus = PlayerStatus.BACKED_UP;
    }

    Pre avoiding acid

    When the player has been backed up, we are going to make the character walk to the opposite direction while woox walking tiles are being calculated. That's what I call pre avoiding acid.

    private void playerBackedUp() {
        if(Players.getLocal().isMoving()) {
            preAvoidingAcid();
            validateIfWooxWalkingIsPossible();
        }
    }
    public void preAvoidingAcid(){
        if(preAcidAvoid) return;
        log("[VORKATH][ACID] Pre avoiding acid");
        Tile curTile = Players.getLocal().getServerTile();
        Tile newTile;
        if(curTile.getX() > wooxWalkingTile[1][3].getX()) {
            newTile = new Tile(wooxWalkingTile[1][6].getX() - 4, wooxWalkingTile[1][6].getY());
            avoidAcidDirection = AvoidDirection.DOWN;
        }
        else if(curTile.getX() < wooxWalkingTile[1][3].getX()) {
            newTile = new Tile(wooxWalkingTile[1][0].getX() + 4, wooxWalkingTile[1][0].getY());
            avoidAcidDirection = AvoidDirection.UP;
        }
        else
        {
            newTile = new Tile(wooxWalkingTile[1][6].getX() - 4, wooxWalkingTile[1][6].getY());
            avoidAcidDirection = AvoidDirection.DOWN;
        }
        movementUtil.vorkathWalkToTile(newTile);
        movementUtil.vorkathWalkToTile(newTile);
        preAcidAvoid = true;
    }

    The criteria is the middle tile. If the player's current tile is lower than the middle tile it will make it move to the left, if its higher than the middle tile its going to make it to move to the right.

    (Left, right is when your camera is set to the North)

    Calculating woox walking

    Now we are going to need to find the woox walking tiles for the player.

    private void validateIfWooxWalkingIsPossible() {
        GameObject object = GameObjects.closest("Acid pool");
        if(object != null) {
            GameObject[] topObjects = new GameObject[wooxWalkingTile[0].length];
            for (int i = 0; i < wooxWalkingTile[0].length; i++) {
                topObjects[i] = GameObjects.getTopObjectOnTile(wooxWalkingTile[0][i]);
            }
    
            for (int i = 1; i < topObjects.length - 1; i++) {
                GameObject obj1 = topObjects[i + 1];
                GameObject obj2 = topObjects[i];
    
                if(obj1 == null && obj2 == null) {
                    wooxWalkCombo[0] = wooxWalkingTile[1][i + 1].getTile();
                    wooxWalkCombo[2] = wooxWalkingTile[1][i - 1].getTile();
                    log("[VORKATH][ACID] Woox walking available");
                    playerStatus = PlayerStatus.WOOX_WALKING;
                    Sleep.sleep(1100);
                    return;
                }
            }
            log("[VORKATH][ACID] Just avoiding acid");
            playerStatus = PlayerStatus.AVOIDING_ACID;
            Sleep.sleep(300, 500);
        }
    }

    The calculation is going to start from the default attack stance. Which is wooxWalking[0][1]

    We are going to validate every two tiles and making our way up to see if there are any acid pools.

    image.png.d40835fbf2def1ab08f19008f8b19ad0.png

    image.png.93cada0334c379a61b0ca591639311bf.png

    Once the tiles have been found we are going to set the status to WOOX_WALKING

    private void wooxWalking() {
        NPC vorkath = NPCs.closest(vorkathAgoredId);
        if(!validateAnimation(vorkath, vorkathAcidAnimation)) {
            resetNormalAttackPhase();
            attackVorkath();
            return;
        }
        switch (wooxPhase) {
            case NOTHING:
                if(movementUtil.isOnTile(Players.getLocal().getServerTile(), wooxWalkCombo[0])) {
                    interactionUtil.noRotationInteractForceLeft(vorkathAgoredId, "Attack");
                    wooxPhase = WooxPhase.WOOX3;
                }
                else {
                    movementUtil.vorkathWalkToTile(wooxWalkCombo[0]);
                    wooxPhase = WooxPhase.WOOX2;
                }
                break;
            case WOOX1:
                if(movementUtil.isOnTile(Players.getLocal().getServerTile(), wooxWalkCombo[2])) {
                    wooxPhase = WooxPhase.WOOX2;
                    movementUtil.vorkathWalkToTile(wooxWalkCombo[0]);
                }
                break;
            case WOOX2:
                if(movementUtil.isOnTile(Players.getLocal().getServerTile(), wooxWalkCombo[0])) {
                    interactionUtil.noRotationInteractForceLeft(vorkathAgoredId, "Attack");
                    wooxPhase = WooxPhase.WOOX3;
                }
                break;
            case WOOX3:
                if(movementUtil.isOnTile(Players.getLocal().getServerTile(), new Tile(wooxWalkCombo[0].getX(), wooxWalkCombo[0].getY() + 1))
                    || Players.getLocal().getAnimation() == rangingAnimation)
                {
                    movementUtil.vorkathWalkToTile(wooxWalkCombo[2]);
                    wooxPhase = WooxPhase.WOOX1;
                }
                break;
        }
    }

    Default woox walking status will be NOTHING to indicate whether if the player is on the first tile or isn't.

    - If the player is on the first tile then attack vorkath -> when attacked or to the tile in front of the first tile -> click the third tile ...

    - If the player is not one the first tile -> move to the first tile -> attack vorkath -> when attacked or to the tile in front of the first tile -> click the third tile ...

    - Finally if vorkath's animation of acid has been stopped, reset everything to normal attack phase.

    (Will not explain the reset method because its straight forward)

    Just avoiding acid

    Sometimes, vorkath will not give us two safe tiles on the attack line, then we are just going to go up and down the safe tile rows until the acid phase ends.

    private void avoidingAcid() {
        NPC vorkath = NPCs.closest(vorkathAgoredId);
        if(vorkath == null) return;
        if(!validateAnimation(vorkath, vorkathAcidAnimation)) {
            resetNormalAttackPhase();
            attackVorkath();
            return;
        }
        switch (avoidAcidDirection) {
            case NOTHING:
                movementUtil.vorkathWalkToTile(wooxWalkingTile[1][6]);
                movementUtil.vorkathWalkToTile(wooxWalkingTile[1][6]);
                avoidAcidDirection = AvoidDirection.DOWN;
                break;
            case DOWN:
                if(movementUtil.isOnTile(Players.getLocal().getServerTile(), wooxWalkingTile[1][6])) {
                    movementUtil.vorkathWalkToTile(wooxWalkingTile[1][0]);
                    avoidAcidDirection = AvoidDirection.UP;
                }
                break;
            case UP:
                if(movementUtil.isOnTile(Players.getLocal().getServerTile(), wooxWalkingTile[1][0])) {
                    movementUtil.vorkathWalkToTile(wooxWalkingTile[1][6]);
                    avoidAcidDirection = AvoidDirection.DOWN;
                }
                break;
        }
    }

     

    5. Undead phase

    This phase is also pretty straight forward

    private void undeadPhase() {
        if(playerStatus == PlayerStatus.READY || playerStatus == PlayerStatus.IDLE) {
            movementUtil.vorkathWalkToTile(Players.getLocal().getServerTile());
            movementUtil.vorkathWalkToTile(Players.getLocal().getServerTile());
            turnOffQuickPrayer();
            playerStatus = PlayerStatus.WAITING_FOR_ZOMBIFIED_SPAWN;
        }
        else {
            enableMouseHop();
            switch (playerStatus) {
                case WAITING_FOR_ZOMBIFIED_SPAWN:
                    Magic.castSpell(Normal.CRUMBLE_UNDEAD);
                    playerStatus = PlayerStatus.MAGIC_SPELL_SELECTED;
                    break;
                case MAGIC_SPELL_SELECTED:
                    NPC npc = clickableNpcHandler.getClosestNpc("Zombified Spawn");
                    if(npc != null) {
                        Sleep.sleep(100);
                        Mouse.click(npc);
                        playerStatus = PlayerStatus.CASTING_MAGIC;
                    }
                    break;
                case CASTING_MAGIC:
                    if(Players.getLocal().getAnimation() == castingMagicAnimation) {
                        validatePlayerStatus();
                        resetNormalAttackPhase();
                        attackVorkath();
                    }
                    break;
            }
        }
    }

    - Player will first turn off quick prayer

    - Set mouse mode to hop

    - Pre cast Crumble undead spell

    - Standby for Zombified spawn NPC

    - Once spawned, Click on it and reset to normal attack phase

     

    6. Eating and potting

    So I really haven't found the best way of efficiency to eat of pot without losing DPS. As to the structure of my code and with a lot of tests, I found eating at vorkath's normal attack phases were the best and least percentile to death and to miss vorkath's attack counts when computer's speed is not a valid dependency.

    boolean comboEat(double prayer, boolean hasManta, int health, int prayerThreshold, int[] potionItems, boolean potionStat, Potion potion, String logMessage) {
        if(health < 70 && hasManta) {
            if(prayer < prayerThreshold) {
                inventoryHandler.eat();
                log(logMessage);
                inventoryHandler.drinkPotions(potionItems);
                attackVorkath();
                return true;
            }
            else if(!potionStat && potion != Potion.PRAYER) {
                inventoryHandler.eat();
                log(logMessage);
                inventoryHandler.drinkPotions(potionItems);
                attackVorkath();
                return true;
            }
        }
        return false;
    }
    
    private boolean validatePlayerStatus() {
        int healthPercent = Players.getLocal().getHealthPercent();
        double prayerPercent = playerHandler.getPrayerPercentage();
        boolean hasMantaray = inventoryHandler.containsItem(itemLibrary.getMantaray());
        boolean hasKarambwan = inventoryHandler.containsItem(itemLibrary.getKarambwan());
    
        // Combo eat scenarios
        if(healthPercent < 35 && hasMantaray && hasKarambwan) {
            inventoryHandler.comboEat(this.itemLibrary.getMantaray(), this.itemLibrary.getKarambwan());
            log("[VORKATH] Combo eat Mantaray + karambwan");
            return false;
        }
        if(comboEat(
                prayerPercent,
                hasMantaray,
                healthPercent,
                50,
                itemLibrary.getPrayerPots(),
                false,
                Potion.PRAYER,
                "[VORKATH] Combo eat Mantaray + Prayer pot"
        )) return false;
        if(comboEat(
                prayerPercent,
                hasMantaray,
                healthPercent,
                50,
                itemLibrary.getExtendedSuperAntiFirePots(),
                potionHandler.isPotionActive(Potion.EXTENDED_SUPER_ANTIFIRE),
                Potion.EXTENDED_SUPER_ANTIFIRE,
                "[VORKATH] Combo eat Mantaray + Extended fire"
        )) return false;
        if(comboEat(
                prayerPercent,
                hasMantaray,
                healthPercent,
                50,
                itemLibrary.getDivineRangingPots(),
                potionHandler.isPotionActive(Potion.DIVINE_RANGING),
                Potion.DIVINE_RANGING,
                "[VORKATH] Combo eat Mantaray + Divine ranging"
        )) return false;
        if(comboEat(
                prayerPercent,
                hasMantaray,
                healthPercent,
                50,
                itemLibrary.getAntiVenomPots(),
                potionHandler.isPotionActive(Potion.SUPER_ANTIVENOM),
                Potion.SUPER_ANTIVENOM,
                "[VORKATH] Combo eat Mantaray + Antivenom"
        )) return false;
    
        // Simple eat
        if(healthPercent < 70) {
            if(hasMantaray) {
                Inventory.interact(itemLibrary.getMantaray());
                attackVorkath();
                log("[VORKATH] Mantaray");
                return false;
            }
            else if(hasKarambwan) {
                Inventory.interact(itemLibrary.getKarambwan());
                attackVorkath();
                log("[VORKATH] Karambwan");
                return false;
            }
        }
        // Prayer pot usage
        if(prayerPercent < 50 && inventoryHandler.containsItems(itemLibrary.getPrayerPots())) {
            inventoryHandler.drinkPotions(itemLibrary.getPrayerPots());
            attackVorkath();
            log("[VORKATH] Prayer pot");
            return false;
        }
        // Other potions
        if(validatePotions(Potion.EXTENDED_SUPER_ANTIFIRE, itemLibrary.getExtendedSuperAntiFirePots())) {
            inventoryHandler.drinkPotions(itemLibrary.getExtendedSuperAntiFirePots());
            attackVorkath();
            log("[VORKATH] Extended fire pot");
            return false;
        }
        if(validatePotions(Potion.DIVINE_RANGING, itemLibrary.getDivineRangingPots())) {
            inventoryHandler.drinkPotions(itemLibrary.getDivineRangingPots());
            attackVorkath();
            log("[VORKATH] Divine ranging pot");
            return false;
        }
        if(validatePotions(Potion.SUPER_ANTIVENOM, itemLibrary.getAntiVenomPots())) {
            inventoryHandler.drinkPotions(itemLibrary.getAntiVenomPots());
            attackVorkath();
            log("[VORKATH] Anti venom pot");
            return false;
        }
    
        return true;
    }
    
    private boolean validatePotions(Potion potion, int[] itemIds) {
        if(potionHandler.isPotionActive(potion) || !inventoryHandler.containsItems(itemIds)) {
            return false;
        } else return true;
    }
    

    Here are the priorities the script will indicate for the player

    - Health is lower than 35 percent, combo eat Manta ray & Karambwans

    - Health is lower than 70 && prayer percentile is lower than 50 percent (combo eat Manta ray and prayer pot)

    - Same goes for health and other immune pots

    - Single eat to the following order of priorities

    - Manta ray

    - Prayer

    - etc.

     

    7. Conclusion

    I actually had more code rather than fighting vorkath. Restoring on Rimmington ad houses or player own house, banking, heading back to vorkath... and also had custom breaks, notifications to be alerted using Slack API so that when I was running beta tests, I would not find my character doing suspicious bot movements. Had created separate server to return random break times, keep track of kills and deaths and gp made per hour and such. But these things could be managed in a different way for different people so I detached all of those dependencies to let one use it for their own way.

    It took over a month and a half with multiple refactoring codes to get the player to die once or never a day. When running it on my high spec PC, it will mostly never die but when it's been running on my laptop, It sometimes misses vorkath attack counts so reminder again, this code will vary depending on computer specs.

    Questions you might have: This long ass project could have been some side money project, why share?

    Answer: Dunno, I used to have a never botted 10 year old main, until I lost my google authenticator code resulting the account to never be restored again, made me think, It's time finally stop playing this game and move on with my life.

    image.thumb.png.585cfd5abd20eeddaecba08b0fa0cfa5.png

    Hope this could find some of you useful & reck the shit out of Jagex for me.

    Edited by lsjc12911
    Link to comment
    Share on other sites

    Awesome share! I will definitely look into this script and see if I can rebuild it "my way" once I get to complete Dragon Slayer 2.
    Thanks for sharing with the community, should be more posts like these!

    In the spirit of your post, I will also be making one of my scripts public:
    https://github.com/StanlyLife/LuxeLiteWoodcutting

    Sorry about losing your account!

    Link to comment
    Share on other sites

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now
    ×
    ×
    • Create New...

    Important Information

    We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.