Emberveil source

tests/BossCheck.java

import com.rs2.Constants;
import com.rs2.GameEngine;
import com.rs2.game.content.StaticNpcList;
import com.rs2.game.content.combat.AttackType;
import com.rs2.game.content.combat.npcs.NpcCombat;
import com.rs2.game.content.minigames.FightCaves;
import com.rs2.game.items.ItemDefinitions;
import com.rs2.game.npcs.Npc;
import com.rs2.game.npcs.NpcHandler;
import com.rs2.game.players.PlayerHandler;
import com.rs2.game.players.PlayerSave;
import org.apollo.cache.IndexedFileSystem;
import org.apollo.cache.decoder.ItemDefinitionDecoder;
import java.nio.file.*;
import java.lang.reflect.Field;
import java.util.Arrays;

public class BossCheck {
    static int checks;
    static void check(boolean value,String label) { if(!value)throw new AssertionError(label); checks++; }
    static int count(int type) { int n=0; for(Npc npc:NpcHandler.npcs)if(npc!=null && npc.npcType==type)n++; return n; }
    static void clear(EmberveilCheck.TestPlayer p) { Arrays.fill(p.playerItems,0);Arrays.fill(p.playerItemsN,0); }
    public static void main(String[] args) throws Exception {
        new ItemDefinitionDecoder(new IndexedFileSystem(Paths.get("data/cache"),true)).run(); ItemDefinitions.load();
        EmberveilCheck.TestPlayer p=new EmberveilCheck.TestPlayer(); p.playerName=p.playerName2="evbossqa"; p.playerPass="local-qa";
        PlayerHandler.players[1]=p;
        // Initialising the real engine handlers also loads NPC definitions and spawns.
        check(GameEngine.npcHandler!=null,"NPC handlers load");
        for(int id:new int[]{50,1158,2881,2882,2883,3200,3340}) check(count(id)>0,"boss is spawned: "+id);
        Constants.XP_RATE=4; Constants.VARIABLE_XP_RATE=false;
        check(p.getPlayerAssistant().addSkillXP(100,0) && p.playerXP[0]==400,"configured 4x XP applied");
        p.playerXP[0]=199999999;
        check(p.getPlayerAssistant().addSkillXP(10,0) && p.playerXP[0]==200000000,"XP cap holds after multiplier");
        check(!p.getPlayerAssistant().addSkillXP(Double.NaN,0),"NaN XP rejected");
        check(!p.getPlayerAssistant().addSkillXP(Double.POSITIVE_INFINITY,0),"infinite XP rejected");
        check(!p.getPlayerAssistant().addSkillXP(1,-1),"invalid skill rejected");
        check(!p.getPlayerAssistant().addSkillXP(-1,0),"negative XP rejected");
        p.absX=3551;p.absY=9694;p.heightLevel=3;
        check(!p.getBarrows().checkBarrows(),"empty Barrows cannot claim");
        p.barrowsNpcs[0][1]=2;p.barrowsKillCount=150;
        p.getBarrows().useChest();check(p.getNpcKillCount(100000)==0,"crypt kills do not bypass missing brothers");
        for(int[] brother:p.barrowsNpcs)brother[1]=2;
        check(p.getBarrows().checkBarrows(),"all six brothers qualify");
        Arrays.fill(p.playerItems,1512);Arrays.fill(p.playerItemsN,1);
        p.getBarrows().useChest();check(p.barrowsKillCount==150,"full inventory preserves Barrows run");
        clear(p);p.getBarrows().useChest();
        check(p.getNpcKillCount(100000)==1 && p.barrowsKillCount==0,"Barrows reward resets run once");
        p.getBarrows().useChest();check(p.getNpcKillCount(100000)==1,"Barrows chest cannot repeat reward");
        for(int[] brother:p.barrowsNpcs)brother[1]=2;p.barrowsNpcs[4][1]=0;p.barrowsKillCount=5;
        int before=count(2026);p.getBarrows().checkCoffins();p.getBarrows().checkCoffins();
        check(count(2026)==before+1 && p.barrowsNpcs[4][1]==1,"Dharok cannot be repeatedly spawned");
        boolean correctFloor=false;for(Npc npc:NpcHandler.npcs)if(npc!=null&&npc.npcType==2026&&npc.spawnedBy==1&&npc.heightLevel==3)correctFloor=true;
        check(correctFloor,"Dharok spawns on player's floor");
        NpcHandler.npcs[3998]=new Npc(3998,StaticNpcList.TZHAARXIL_2607);
        NpcCombat.loadSpell(p,3998);check(NpcHandler.npcs[3998].attackType==AttackType.RANGE.getValue(),"ranged TzHaar keeps ranged attack");
        Field wavesField=FightCaves.class.getDeclaredField("WAVES");wavesField.setAccessible(true);
        int[][] waves=(int[][])wavesField.get(GameEngine.fightCaves);
        check(waves.length==63 && waves[62][0]==2745,"Fight Caves has 63 waves ending in Jad");
        p.absX=2413;p.absY=5117;p.heightLevel=4;p.waveId=0;
        int first=count(FightCaves.TZ_KIH);GameEngine.fightCaves.spawnNextWave(p);
        check(count(FightCaves.TZ_KIH)==first+1 && p.tzhaarToKill==1,"first cave wave spawns");
        p.waveId=62;GameEngine.fightCaves.spawnNextWave(p);
        int jad=-1;for(int i=0;i<NpcHandler.npcs.length;i++)if(NpcHandler.npcs[i]!=null&&NpcHandler.npcs[i].npcType==2745&&NpcHandler.npcs[i].spawnedBy==1)jad=i;
        check(jad>=0 && NpcHandler.npcs[jad].heightLevel==4,"Jad spawns in player's instance");
        Arrays.fill(p.playerItems,1512);Arrays.fill(p.playerItemsN,1);
        FightCaves.handleJadDeath(jad);
        check(p.pendingFireCapes==1&&p.pendingJadTokkul==8032,"full inventory retains all Jad rewards");
        check(!p.killedJad && p.waveId==300,"Jad victory cleanup resets transient flag");
        FightCaves.handleJadDeath(jad);check(p.pendingFireCapes==1&&p.pendingJadTokkul==8032,"duplicate Jad callback cannot duplicate reward");
        Path saved=Paths.get("data/characters/evbossqa.txt");check(!Files.exists(saved),"QA save must be new");
        try {
            p.saveFile=true;p.saveCharacter=true;p.newPlayer=false;
            check(PlayerSave.saveGame(p),"pending boss rewards save");
            EmberveilCheck.TestPlayer loaded=new EmberveilCheck.TestPlayer();loaded.playerName="evbossqa";
            PlayerSave.loadPlayerInfo(loaded,"evbossqa","local-qa",false);
            check(loaded.pendingFireCapes==1&&loaded.pendingJadTokkul==8032,"pending boss rewards survive reload");
        } finally {Files.deleteIfExists(saved);Files.deleteIfExists(Paths.get(saved+".bak"));}
        clear(p);p.absX=0;p.absY=0;p.heightLevel=0;FightCaves.claimRewards(p);
        check(p.pendingFireCapes==1,"pending reward cannot be claimed remotely");
        p.absX=2438;p.absY=5168;FightCaves.claimRewards(p);
        check(p.pendingFireCapes==0&&p.pendingJadTokkul==0&&p.getItemAssistant().playerHasItem(6570)&&p.getItemAssistant().playerHasItem(6529,8032),"pending Jad rewards collected at entrance");
        FightCaves.claimRewards(p);check(p.getItemAssistant().getItemAmount(6529)==8032,"no duplicate Tokkul or failure bonus");
        Npc[] original=NpcSnapshot();
        try {
            Arrays.fill(NpcHandler.npcs,null);
            Npc queen=new Npc(3997,1158);queen.absX=queen.makeX=3478;queen.absY=queen.makeY=9498;
            queen.MaxHP=255;queen.HP=0;queen.isDead=true;queen.randomWalk=false;
            NpcHandler.npcs[3997]=queen;
            p.absX=0;p.absY=0;p.lastNpcAttacked=3997;p.totalDamageDealt=1;
            for(int tick=0;tick<5;tick++)GameEngine.npcHandler.process();
            check(queen.npcType==1160&&!queen.isDead&&queen.HP==255,"Queen first death transforms to a living second form");
            check(p.getNpcKillCount(1158)==0,"Queen first form does not award a full boss kill");
            queen.isDead=true;queen.applyDead=false;queen.needRespawn=false;queen.actionTimer=0;queen.HP=0;
            p.lastNpcAttacked=3997;p.totalDamageDealt=1;p.randomEventsEnabled=false;
            for(int tick=0;tick<5;tick++)GameEngine.npcHandler.process();
            check(p.getNpcKillCount(1158)==1 && p.getNpcKillCount(1160)==0,"complete Queen kill increments canonical boss counter once");
            queen.actionTimer=1;
            GameEngine.npcHandler.process();
            check(count(1158)==1&&count(1160)==0,"Queen respawns in first form after final death");
        } finally { System.arraycopy(original,0,NpcHandler.npcs,0,original.length); }
        PlayerHandler.players[1]=null;
        System.out.println("PASS: "+checks+" boss and progression checks.");System.exit(0);
    }
    static Npc[] NpcSnapshot() { return NpcHandler.npcs.clone(); }
}