Emberveil sourcetests/GodWarsCheck.java
import com.rs2.Constants;
import com.rs2.GameEngine;
import com.rs2.event.CycleEventHandler;
import com.rs2.game.content.emberveil.*;
import com.rs2.game.content.combat.melee.MeleeData;
import com.rs2.game.npcs.*;
import com.rs2.game.players.*;
import com.rs2.game.items.ItemDefinitions;
import org.apollo.cache.IndexedFileSystem;
import org.apollo.cache.decoder.ItemDefinitionDecoder;
import org.apollo.cache.decoder.ObjectDefinitionDecoder;
import org.apollo.cache.def.ItemDefinition;
import com.rs2.world.clip.RegionFactory;
import com.rs2.world.clip.Region;
import java.nio.file.Paths;
import java.util.*;
import java.io.FileReader;
import com.google.gson.Gson;
/** Runs against disposable staged data. Does not connect to or save live accounts. */
public final class GodWarsCheck {
static int checks;
static void check(boolean value,String label){if(!value)throw new AssertionError(label);checks++;System.out.println("PASS: "+label);}
static class Fighter extends Client {
Fighter(int id){super(null,id);getOutStream().packetEncryption=new org.apollo.util.security.IsaacRandom(new int[]{1,2,3,4});
playerName=playerName2="gwdqa"+id;tutorialProgress=36;Arrays.fill(playerEquipment,-1);Arrays.fill(playerLevel,99);Arrays.fill(playerXP,13034431);specAccuracy=specDamage=1;specAmount=10;}
public void flushOutStream(){getOutStream().currentOffset=0;}
}
static void place(Fighter p,int x,int y,int h){p.absX=x;p.absY=y;p.heightLevel=h;p.teleportToX=p.teleportToY=-1;p.stopPlayerPacket=false;p.isDead=false;p.disconnected=false;p.playerLevel[3]=99;}
static void tick(){CycleEventHandler.getSingleton().process();}
static void arrived(Fighter p,int x,int y,int h,String name){tick();tick();check(p.teleportToX==x&&p.teleportToY==y&&p.teleHeight==h&&!p.stopPlayerPacket,name);place(p,x,y,h);}
static void inventory(Fighter p){Arrays.fill(p.playerItems,0);Arrays.fill(p.playerItemsN,0);}
static int amount(Fighter p,int id){return p.getItemAssistant().getItemAmount(id);}
static int slot(int type){for(int i=1;i<NpcHandler.npcs.length;i++)if(NpcHandler.npcs[i]!=null&&NpcHandler.npcs[i].npcType==type)return i;throw new AssertionError("No spawn "+type);}
static final class NeedRoll extends RuntimeException {int bound;NeedRoll(int bound){this.bound=bound;}}
static Map<Integer,Double> probabilities=new HashMap<>();
static void enumerate(int npc,List<Integer> path,double weight){
final int[] index={0};
try{
List<GodWarsLoot.Drop> drops=GodWarsLoot.roll(npc,bound->{if(index[0]==path.size())throw new NeedRoll(bound);int v=path.get(index[0]++);if(v<0||v>=bound)throw new AssertionError("Out of range RNG");return v;});
Set<Integer> found=new HashSet<>();
for(GodWarsLoot.Drop drop:drops){if(drop.id<0||drop.id>=ItemDefinition.count()||drop.min<1||drop.max<drop.min)throw new AssertionError("Invalid drop "+drop.id);if(found.add(drop.id))probabilities.merge(drop.id,weight,Double::sum);}
}catch(NeedRoll need){for(int r=0;r<need.bound;r++){path.add(r);enumerate(npc,path,weight/need.bound);path.remove(path.size()-1);}}
}
static void rate(int item,double expected,String label){check(Math.abs(probabilities.getOrDefault(item,0.0)-expected)<1e-10,label);}
public static void main(String[] args)throws Exception {
IndexedFileSystem cache=new IndexedFileSystem(Paths.get("data/cache"),true);
new ItemDefinitionDecoder(cache).run();new ObjectDefinitionDecoder(cache).run();RegionFactory.load(cache);ItemDefinitions.load();
check(GameEngine.npcHandler!=null&&GodWars.enabled(),"staged world and God Wars definitions load");
check(Region.objectExists(GodWars.objectType(26341),2915,3745,0),"entrance object registered in server map");
for(int[] tile:new int[][]{{2882,5311,2},{2916,5300,1},{2919,5273,0},{2925,5330,2},{2839,5297,2},{2906,5265,0},{2865,5354,2},{2898,3715,0},{2898,3719,0},{2903,3720,0},{2899,3713,0},{2914,3744,0},{2919,5276,1},{2912,5300,2},{2872,5279,2},{2872,5269,2},{2852,5333,2},{2850,5333,2},{2885,5332,2},{2885,5345,2}})check((Region.getClipping(tile[0],tile[1],tile[2])&0x200100)==0,"route destination is walkable "+Arrays.toString(tile));
Fighter p=new Fighter(1),v=new Fighter(2);PlayerHandler.players[1]=p;PlayerHandler.players[2]=v;
for(int npc:new int[]{3900,3919,3944,3957}){
int start=npc==3900?3900:npc;int[] types={start,start+1,start+3,start+5};
for(int type:types){check(slot(type)>0,"boss/bodyguard spawned "+type);probabilities.clear();enumerate(type,new ArrayList<>(),1.0);
for(int item:new int[]{11710,11712,11714})rate(item,1.0/(type==npc?762:1524),"exact shard rate "+type+" / "+item);
if(type==npc){int hilt=npc==3900?11708:npc==3919?11702:npc==3944?11706:11704;rate(hilt,1.0/508,"exact boss hilt rate "+type);
if(npc==3957||npc==3919)for(int item:npc==3957?new int[]{11724,11726,11728}:new int[]{11718,11720,11722})rate(item,1.0/381,"exact boss armour rate "+item);
if(npc==3900){rate(11716,1.0/127,"original Zamorak spear rate");rate(11736,1.0/127,"original steam staff rate");}
if(npc==3944)rate(11730,1.0/127,"original Saradomin sword rate");
}else if(npc==3957)for(int item:new int[]{11724,11726,11728})rate(item,1.0/16256,"exact bodyguard armour rate "+item);
else if(npc==3944)rate(11730,1.0/16256,"exact bodyguard sword rate");
check(!probabilities.containsKey(11791)&&!probabilities.containsKey(11785),"modern weapons absent "+type);
}
}
GodWars.Definition[] definitions;
try(FileReader reader=new FileReader("data/cfg/godwars-npcs.json")){definitions=new Gson().fromJson(reader,GodWars.Definition[].class);}
for(GodWars.Definition definition:definitions)if(definition.name.toLowerCase().contains("spiritual mage")){
probabilities.clear();enumerate(definition.id,new ArrayList<>(),1.0);rate(11732,1.0/128,"spiritual mage dragon boots rate "+definition.id);
}
place(p,2915,3745,0);inventory(p);p.gwdRopes=0;
GodWars.object(p,GodWars.objectType(26341),2914,3744,false);check(!p.stopPlayerPacket&&p.gwdRopes==0,"forged entrance location rejected");
GodWars.object(p,GodWars.objectType(26341),2915,3745,false);check(!p.stopPlayerPacket&&p.gwdRopes==0,"entry without rope rejected");
p.getItemAssistant().addItem(954,3);GodWars.object(p,GodWars.objectType(26341),2915,3745,false);check(amount(p,954)==2&&p.gwdRopes==1,"entrance consumes exactly one rope");
GodWars.object(p,GodWars.objectType(26341),2915,3745,false);check(amount(p,954)==2,"repeat click cannot consume another rope");arrived(p,2882,5311,2,"entrance reaches dungeon floor");
place(p,2913,5300,2);GodWars.object(p,GodWars.objectType(26296),2913,5300,false);arrived(p,2916,5300,1,"upper Saradomin rope descends");
place(p,2920,5276,1);GodWars.object(p,GodWars.objectType(26300),2920,5276,false);arrived(p,2919,5273,0,"lower Saradomin rope descends");check(p.gwdRopes==7&&amount(p,954)==0,"three ropes stored independently");
GodWars.object(p,GodWars.objectType(26301),2919,5274,false);arrived(p,2919,5276,1,"lower Saradomin rope ascends");
place(p,2915,5300,1);GodWars.object(p,GodWars.objectType(26297),2915,5300,false);arrived(p,2912,5300,2,"upper Saradomin rope ascends");
int[][] doors={{GodWars.objectType(26428),2925,5332,2,2925,5330},{GodWars.objectType(26426),2839,5295,2,2839,5297},{GodWars.objectType(26427),2908,5265,0,2906,5265},{GodWars.objectType(26425),2863,5354,2,2865,5354}};
for(int faction=0;faction<4;faction++){int[] d=doors[faction];place(p,d[1],d[2],d[3]);p.gwdKillCount[faction]=39;
GodWars.object(p,d[0],d[1],d[2],false);check(!p.stopPlayerPacket&&p.gwdKillCount[faction]==39,"boss door rejects 39 kills "+faction);
p.gwdKillCount[faction]=40;GodWars.object(p,d[0],d[1],d[2],false);GodWars.object(p,d[0],d[1],d[2],false);check(p.gwdKillCount[faction]==0,"boss door deducts 40 kills once "+faction);
arrived(p,d[4],d[5],d[3],"boss door reaches correct chamber "+faction);
check(GodWars.room(p)==GodWars.Faction.values()[faction],"room detection "+faction);
}
place(p,2885,5333,2);p.playerLevel[5]=99;GodWars.object(p,GodWars.objectType(26439),2885,5333,false);arrived(p,2885,5345,2,"Zamorak bridge crosses");check(p.playerLevel[5]==0,"Zamorak bridge drains prayer");
place(p,2872,5269,2);p.playerEquipment[3]=9185;p.playerEquipment[p.playerArrows]=9419;
GodWars.object(p,GodWars.objectType(26303),2871,5270,false);arrived(p,2872,5279,2,"Armadyl grapple crosses north");
GodWars.object(p,GodWars.objectType(26303),2871,5270,false);arrived(p,2872,5269,2,"Armadyl grapple returns south from full object footprint");
int[][] altars={{26286,2937,5323,2936,5323,2},{26288,2821,5301,2824,5301,2},{26287,2885,5267,2889,5267,0},{26289,2869,5370,2869,5369,2}};
for(int f=0;f<4;f++){int[] a=altars[f];place(p,a[3],a[4],a[5]);p.gwdAltarRecharge=0;p.logoutDelay=0;p.playerLevel[5]=50;
GodWars.object(p,GodWars.objectType(a[0]),a[1],a[2],false);check(p.playerLevel[5]==99&&p.gwdAltarRecharge>System.currentTimeMillis(),"altar restores prayer "+f);
p.playerLevel[5]=50;GodWars.object(p,GodWars.objectType(a[0]),a[1],a[2],false);check(p.playerLevel[5]==50,"altar cooldown prevents repeated recharge "+f);
GodWars.object(p,GodWars.objectType(a[0]),a[1],a[2],true);GodWars.Faction faction=GodWars.Faction.values()[f];arrived(p,faction.exitX,faction.exitY,faction.plane,"altar exits correct room "+f);
}
p.playerEquipment[3]=11694;p.usingMagic=false;check(MeleeData.getAttackDelay(p)==6,"godsword speed is six ticks");p.usingMagic=true;p.spellId=0;check(MeleeData.getAttackDelay(p)==5,"holding godsword preserves spell speed");p.usingMagic=false;
int[] weapons={11694,11696,11698,11700,11730,11716};double[] costs={5,10,5,6,10,2.5};
for(int n=0;n<weapons.length;n++){p.playerEquipment[3]=weapons[n];p.usingSpecial=false;p.specAmount=10;p.getItemAssistant().addSpecialBar(weapons[n]);
check(p.specBarId==(weapons[n]==11716?7686:7711),"correct visible special bar "+weapons[n]);
com.rs2.game.content.combat.Specials.specialClicking(p,weapons[n]==11716?29238:30007);check(p.usingSpecial,"actual special button enables weapon "+weapons[n]);
check(p.getCombatAssistant().checkSpecAmount(weapons[n])&&p.specAmount==10-costs[n],"original special cost "+weapons[n]);p.getOutStream().currentOffset=0;
}
p.playerEquipment[3]=11694;GodWarsEquipment.button(p,18103);check(p.fightMode==0,"godsword Chop trains Attack");GodWarsEquipment.button(p,18104);check(p.fightMode==1,"godsword Block trains Defence");GodWarsEquipment.button(p,18105);check(p.fightMode==2&&MeleeData.getWeaponAnimation(p)==17049,"godsword Smash trains Strength with crush animation");GodWarsEquipment.button(p,18106);check(p.fightMode==2&&!p.gwdCrushStyle,"godsword Slash trains Strength");
place(p,2870,5360,2);place(v,2871,5360,2);p.playerLevel[3]=40;p.playerLevel[5]=40;p.specEffect=101;GodWarsEquipment.effect(p,v,null,40);check(p.playerLevel[3]==60&&p.playerLevel[5]==50,"Saradomin godsword restores half damage and quarter prayer");
p.specEffect=101;GodWarsEquipment.effect(p,v,null,0);check(p.playerLevel[3]==60&&p.specEffect==0,"miss cannot heal or leak special to next hit");
p.specEffect=105;Arrays.fill(v.playerLevel,5);GodWarsEquipment.effect(p,v,null,17);check(v.playerLevel[1]==0&&v.playerLevel[2]==0&&v.playerLevel[5]==0&&v.playerLevel[0]==3,"Bandos drain follows original skill order");
p.specEffect=102;v.freezeTimer=-3;GodWarsEquipment.effect(p,v,null,10);check(v.freezeTimer==33,"Zamorak godsword freezes for twenty seconds");
p.specEffect=102;v.freezeTimer=-1;GodWarsEquipment.effect(p,v,null,10);check(v.freezeTimer==-1,"Zamorak godsword respects freeze immunity");
inventory(p);p.getItemAssistant().addItem(11690,1);p.getItemAssistant().addItem(11702,1);GodWarsEquipment.combine(p,11690,11702);check(amount(p,11694)==1&&amount(p,11690)==0&&amount(p,11702)==0,"blade and hilt combine without duplication");
GodWarsEquipment.dismantle(p,11694);check(amount(p,11694)==0&&amount(p,11690)==1&&amount(p,11702)==1,"godsword dismantles into exact components");
place(p,2835,5300,2);check(!GodWars.canAttack(p,3919,false)&&GodWars.canAttack(p,3919,true),"flying boss requires ranged or magic");
place(p,2865,5354,2);check(NpcHandler.npcs[slot(3957)].inMulti(),"God Wars NPCs permit group combat");
p.npcIndex=slot(3957);p.playerEquipment[3]=11698;p.playerBonus[10]=150;p.playerLevel[3]=40;p.playerLevel[5]=40;
Npc sgsTarget=NpcHandler.npcs[p.npcIndex];sgsTarget.defence=0;
for(int trial=0;trial<20&&p.playerLevel[3]==40;trial++){p.specEffect=101;p.getCombatAssistant().applyNpcMeleeDamage(p.npcIndex,1);}
check(p.playerLevel[3]>40&&p.playerLevel[5]>40&&p.specEffect==0,"Saradomin godsword effect runs through actual melee hit callback");
int bossSlot=slot(3957);Npc boss=NpcHandler.npcs[bossSlot];boss.HP=0;GodWars.recordDamage(p,bossSlot,255);GodWars.processNpc(bossSlot);check(boss.applyDead&&boss.killedBy==1,"boss death chooses damage contributor");
for(int i=0;i<5;i++)GodWars.processNpc(bossSlot);check(boss.needRespawn&&boss.absX==0,"boss corpse disappears after death animation");int kills=p.gwdKillCount[3];
for(int i=0;i<199;i++)GodWars.processNpc(bossSlot);check(boss.isDead&&p.gwdKillCount[3]==kills,"dead boss grants no duplicate loot or kills");
GodWars.processNpc(bossSlot);check(!boss.isDead&&boss.HP==boss.MaxHP&&boss.absX==boss.makeX,"boss respawns at original position with full health");
for(int type:new int[]{3900,3919,3944,3957}){
Npc leader=NpcHandler.npcs[slot(type)];place(p,leader.makeX+leader.size,leader.makeY,leader.heightLevel);place(v,3222,3218,0);
Arrays.fill(p.getPrayer().prayerActive,false);p.npcIndex=slot(type);int dealt=0,attacks=0;
for(int t=0;t<400;t++){p.playerLevel[3]=99;GodWars.processNpc(slot(type));tick();dealt+=99-p.playerLevel[3];if(leader.animUpdateRequired)attacks++;leader.animUpdateRequired=false;p.getOutStream().currentOffset=0;}
check(dealt>0&&attacks>20,"400-tick boss combat run "+type+" attacks="+attacks+" damage="+dealt);
place(p,3222,3218,0);int hp=p.playerLevel[3];GodWars.processNpc(slot(type));tick();check(p.playerLevel[3]==hp,"leaving room cancels boss hits "+type);
}
place(p,3222,3218,0);place(v,3222,3218,0);
Npc first=null,second=null;
for(Npc n:NpcHandler.npcs)if(n!=null&&GodWars.isNpc(n.npcType)&&GodWars.chamber(n.npcType)==null){if(first==null)first=n;else if((GodWars.original(n.npcType)<=6221)!=(GodWars.original(first.npcType)<=6221)){second=n;break;}}
check(first!=null&&second!=null,"opposing army NPCs exist");
first.absX=2882;first.absY=5311;second.absX=2883;second.absY=5311;first.heightLevel=second.heightLevel=3;first.HP=second.HP=100;first.attackTimer=second.attackTimer=0;
for(int t=0;t<60&&first.HP>0&&second.HP>0;t++){GodWars.processNpc(first.npcId);GodWars.processNpc(second.npcId);}
check(first.HP<100||second.HP<100,"opposing factions fight without players present");
// Disposable characters for separate real-client rendering checks.
if(args.length>0&&args[0].equals("prepare-clients")){
int[][] positions={{2882,5311,2},{2862,5354,2},{2839,5294,2},{2925,5333,2},{2909,5265,0},{2914,3744,0}};
for(int i=0;i<positions.length;i++){
Fighter qa=new Fighter(10+i);qa.playerName=qa.playerName2="gwdqa"+i;qa.playerPass="gwd-local-qa";
qa.saveFile=qa.saveCharacter=true;qa.newPlayer=false;qa.gwdRopes=7;Arrays.fill(qa.gwdKillCount,40);
qa.absX=positions[i][0];qa.absY=positions[i][1];qa.heightLevel=positions[i][2];
qa.playerEquipment[3]=i==0?11716:11694;qa.playerEquipmentN[3]=1;qa.playerEquipment[4]=11724;qa.playerEquipmentN[4]=1;qa.playerEquipment[0]=11718;qa.playerEquipmentN[0]=1;
qa.playerEquipment[1]=2412;qa.playerEquipmentN[1]=1;qa.playerEquipment[2]=1724;qa.playerEquipmentN[2]=1;
PlayerHandler.players[qa.playerId]=qa;
check(PlayerSave.saveGame(qa),"staged client fixture saved "+i);
PlayerHandler.players[qa.playerId]=null;
}
}
PlayerHandler.players[1]=PlayerHandler.players[2]=null;
System.out.println("GOD WARS CHECKS: "+checks+" passed");
}
}