diff --git a/Server/data/configs/item_configs.json b/Server/data/configs/item_configs.json
index e151475ee..475e6f2c9 100644
--- a/Server/data/configs/item_configs.json
+++ b/Server/data/configs/item_configs.json
@@ -40578,6 +40578,7 @@
"grand_exchange_price": "29900",
"stand_anim": "1662",
"tradeable": "true",
+ "rare_item": "true",
"run_anim": "1664",
"archery_ticket_price": "0",
"id": "4153",
@@ -45819,6 +45820,7 @@
"grand_exchange_price": "94300",
"name": "Ahrim's hood",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4708",
"bonuses": "0,0,0,6,-2,15,13,16,6,0,15,0,0,0,0"
@@ -45849,6 +45851,7 @@
"grand_exchange_price": "69500",
"stand_anim": "813",
"tradeable": "true",
+ "rare_item": "true",
"run_anim": "1210",
"archery_ticket_price": "0",
"id": "4710",
@@ -45887,6 +45890,7 @@
"grand_exchange_price": "1000000",
"name": "Ahrim's robetop",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4712",
"bonuses": "0,0,0,30,-10,52,37,63,30,0,60,0,0,0,0"
@@ -45914,6 +45918,7 @@
"grand_exchange_price": "1700000",
"name": "Ahrim's robeskirt",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4714",
"bonuses": "0,0,0,22,-7,33,30,36,22,0,30,0,0,0,0"
@@ -45942,6 +45947,7 @@
"grand_exchange_price": "1300000",
"name": "Dharok's helm",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4716",
"bonuses": "0,0,0,-3,-1,45,48,44,-1,51,15,0,0,0,0"
@@ -45972,6 +45978,7 @@
"grand_exchange_price": "516900",
"stand_anim": "2065",
"tradeable": "true",
+ "rare_item": "true",
"run_anim": "824",
"archery_ticket_price": "0",
"id": "4718",
@@ -46009,6 +46016,7 @@
"grand_exchange_price": "511400",
"name": "Dharok's platebody",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4720",
"bonuses": "0,0,0,-30,-10,122,120,107,-6,132,60,0,0,0,0"
@@ -46036,6 +46044,7 @@
"grand_exchange_price": "748800",
"name": "Dharok's platelegs",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4722",
"bonuses": "0,0,0,-21,-7,85,82,83,-4,92,30,0,0,0,0"
@@ -46065,6 +46074,7 @@
"grand_exchange_price": "396300",
"name": "Guthan's helm",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4724",
"bonuses": "0,0,0,-6,-2,55,58,54,-1,62,15,0,0,0,0"
@@ -46095,6 +46105,7 @@
"grand_exchange_price": "588400",
"stand_anim": "813",
"tradeable": "true",
+ "rare_item": "true",
"run_anim": "1210",
"archery_ticket_price": "0",
"id": "4726",
@@ -46132,6 +46143,7 @@
"grand_exchange_price": "316800",
"name": "Guthan's platebody",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4728",
"bonuses": "0,0,0,-30,-10,122,120,107,-6,132,60,0,0,0,0"
@@ -46159,6 +46171,7 @@
"grand_exchange_price": "315600",
"name": "Guthan's chainskirt",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4730",
"bonuses": "0,0,0,-14,-7,75,72,73,-4,82,30,0,0,0,0"
@@ -46187,6 +46200,7 @@
"grand_exchange_price": "38900",
"name": "Karil's coif",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4732",
"bonuses": "0,0,0,-1,3,6,9,12,6,10,15,0,0,0,0"
@@ -46217,6 +46231,7 @@
"grand_exchange_price": "188000",
"stand_anim": "2074",
"tradeable": "true",
+ "rare_item": "true",
"run_anim": "2077",
"archery_ticket_price": "0",
"id": "4734",
@@ -46255,6 +46270,7 @@
"grand_exchange_price": "1800000",
"name": "Karil's leathertop",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4736",
"bonuses": "0,0,0,-15,30,47,42,50,65,57,60,0,0,0,0"
@@ -46282,6 +46298,7 @@
"grand_exchange_price": "217000",
"name": "Karil's leatherskirt",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4738",
"bonuses": "0,0,0,-10,17,26,20,28,35,33,30,0,0,0,0"
@@ -46327,6 +46344,7 @@
"grand_exchange_price": "139000",
"name": "Torag's helm",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4745",
"bonuses": "0,0,0,-6,-2,55,58,54,-1,62,15,0,0,0,0"
@@ -46359,6 +46377,7 @@
"attack_audios": "1332,0,0,0",
"name": "Torag's hammers",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4747",
"bonuses": "-4,-4,85,-4,0,0,0,0,0,0,0,72,0,0,0"
@@ -46387,6 +46406,7 @@
"grand_exchange_price": "346200",
"name": "Torag's platebody",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4749",
"bonuses": "0,0,0,-30,-10,122,120,107,-6,132,60,0,0,0,0"
@@ -46414,6 +46434,7 @@
"grand_exchange_price": "427200",
"name": "Torag's platelegs",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4751",
"bonuses": "0,0,0,-21,-7,85,82,83,-4,92,30,0,0,0,0"
@@ -46443,6 +46464,7 @@
"grand_exchange_price": "687200",
"name": "Verac's helm",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4753",
"bonuses": "0,0,0,-6,-2,55,58,54,0,56,15,0,3,0,0"
@@ -46473,6 +46495,7 @@
"grand_exchange_price": "135500",
"stand_anim": "1832",
"tradeable": "true",
+ "rare_item": "true",
"run_anim": "1831",
"archery_ticket_price": "0",
"id": "4755",
@@ -46511,6 +46534,7 @@
"grand_exchange_price": "270000",
"name": "Verac's brassard",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4757",
"bonuses": "0,0,0,-6,-2,81,95,85,0,81,60,0,5,0,0"
@@ -46538,6 +46562,7 @@
"grand_exchange_price": "411400",
"name": "Verac's plateskirt",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "4759",
"bonuses": "0,0,0,-21,-7,85,82,83,0,84,30,0,4,0,0"
@@ -106101,6 +106126,7 @@
"grand_exchange_price": "95400",
"name": "Dragon boots",
"tradeable": "true",
+ "rare_item": "true",
"archery_ticket_price": "0",
"id": "11732",
"bonuses": "0,0,0,-3,-1,16,17,18,0,0,15,4,0,0,0"
@@ -121161,6 +121187,7 @@
"grand_exchange_price": "43082",
"stand_anim": "813",
"tradeable": "true",
+ "rare_item": "true",
"run_anim": "824",
"archery_ticket_price": "0",
"id": "13290",
@@ -139539,4 +139566,4 @@
"attack_audios": "2555,0,0,0",
"name": "Staff of the raven"
}
-]
\ No newline at end of file
+]
diff --git a/Server/src/main/java/core/game/node/entity/npc/NPC.java b/Server/src/main/java/core/game/node/entity/npc/NPC.java
index 5799b15b4..3bd79964b 100644
--- a/Server/src/main/java/core/game/node/entity/npc/NPC.java
+++ b/Server/src/main/java/core/game/node/entity/npc/NPC.java
@@ -31,6 +31,7 @@ import core.game.world.update.flag.npc.NPCFaceLocation;
import core.game.world.update.flag.npc.NPCForceChat;
import core.game.world.update.flag.npc.NPCSwitchId;
import core.tools.RandomFunction;
+import rs09.game.content.global.GlobalKillCounter;
import rs09.game.content.jobs.JobManager;
import rs09.game.node.entity.combat.CombatSwingHandler;
import rs09.game.system.config.NPCConfigParser;
@@ -534,6 +535,7 @@ public class NPC extends Entity {
Player p = !(killer instanceof Player) ? null : (Player) killer;
if (p != null) {
p.incrementAttribute("/save:" + STATS_BASE + ":" + STATS_ENEMIES_KILLED);
+ GlobalKillCounter.incrementKills(p, originalId);
}
handleDrops(p, killer);
if (!isRespawn()) {
diff --git a/Server/src/main/java/core/game/node/entity/npc/drop/NPCDropTables.java b/Server/src/main/java/core/game/node/entity/npc/drop/NPCDropTables.java
index 347c54d76..9f6177596 100644
--- a/Server/src/main/java/core/game/node/entity/npc/drop/NPCDropTables.java
+++ b/Server/src/main/java/core/game/node/entity/npc/drop/NPCDropTables.java
@@ -1,5 +1,6 @@
package core.game.node.entity.npc.drop;
+import api.ContentAPI;
import core.cache.def.impl.NPCDefinition;
import core.game.content.global.Bones;
import core.game.ge.GrandExchangeDatabase;
@@ -17,6 +18,7 @@ import core.tools.StringUtils;
import rs09.game.ai.AIPlayer;
import rs09.game.ai.AIRepository;
import rs09.game.ai.general.GeneralBotCreator;
+import rs09.game.content.global.GlobalKillCounter;
import rs09.game.content.global.NPCDropTable;
import rs09.game.ge.OfferManager;
import rs09.game.system.config.ItemConfigParser;
@@ -111,9 +113,7 @@ public final class NPCDropTables {
}
return;
}
- if (item.getDefinition().getConfiguration(ItemConfigParser.RARE_ITEM, false)) {
- Repository.sendNews(player.getUsername() + " has just received: " + item.getAmount() + " x " + item.getName() + ".");
- }
+ ContentAPI.announceIfRare(player, item);
if(item.getId() == 6199 && player instanceof Player){
player.sendMessage("
A mystery box has fallen on the ground.");
}
@@ -239,4 +239,4 @@ public final class NPCDropTables {
this.modRate = modRate;
}
-}
\ No newline at end of file
+}
diff --git a/Server/src/main/java/core/game/node/entity/skill/runecrafting/RuneCraftPulse.java b/Server/src/main/java/core/game/node/entity/skill/runecrafting/RuneCraftPulse.java
index 207c26099..6485dc3ac 100644
--- a/Server/src/main/java/core/game/node/entity/skill/runecrafting/RuneCraftPulse.java
+++ b/Server/src/main/java/core/game/node/entity/skill/runecrafting/RuneCraftPulse.java
@@ -1,16 +1,18 @@
package core.game.node.entity.skill.runecrafting;
import core.game.container.impl.EquipmentContainer;
-import core.game.node.entity.skill.SkillPulse;
-import core.game.node.entity.skill.Skills;
import core.game.node.entity.impl.Animator.Priority;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.diary.DiaryType;
+import core.game.node.entity.skill.SkillPulse;
+import core.game.node.entity.skill.Skills;
import core.game.node.item.Item;
-import rs09.game.world.GameWorld;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import core.tools.RandomFunction;
+import static rs09.game.node.entity.player.info.stats.StatAttributeKeysKt.STATS_BASE;
+import static rs09.game.node.entity.player.info.stats.StatAttributeKeysKt.STATS_RC;
+import rs09.game.world.GameWorld;
import java.util.ArrayList;
import java.util.Arrays;
@@ -176,6 +178,7 @@ public final class RuneCraftPulse extends SkillPulse- {
if (player.getInventory().remove(item) && player.getInventory().hasSpaceFor(i)) {
player.getInventory().add(i);
+ player.incrementAttribute("/save:" + STATS_BASE + ":" + STATS_RC, amount);
player.getSkills().addExperience(Skills.RUNECRAFTING, rune.getExperience() * amount, true);
// Achievement Diary handling
@@ -195,6 +198,7 @@ public final class RuneCraftPulse extends SkillPulse
- {
}
} else {
if (player.getInventory().remove(item)) {
+ player.incrementAttribute("/save:" + STATS_BASE + ":" + STATS_RC, amount);
for (int i = 0; i < amount; i++) {
Rune rune = null;
while (rune == null) {
diff --git a/Server/src/main/java/core/game/system/SystemTermination.java b/Server/src/main/java/core/game/system/SystemTermination.java
index b37025ac9..1ce55219b 100644
--- a/Server/src/main/java/core/game/system/SystemTermination.java
+++ b/Server/src/main/java/core/game/system/SystemTermination.java
@@ -7,6 +7,7 @@ import core.game.node.entity.player.info.login.PlayerParser;
import rs09.Server;
import rs09.ServerConstants;
import rs09.ServerStore;
+import rs09.game.content.global.GlobalKillCounter;
import rs09.game.ge.OfferManager;
import rs09.game.system.SystemLogger;
import rs09.game.world.repository.Repository;
@@ -91,6 +92,7 @@ public final class SystemTermination {
} catch (Exception ignored) {}
}
Repository.getDisconnectionQueue().update();
+ GlobalKillCounter.save();
GrandExchangeDatabase.save();
OfferManager.save();
SystemLogger.flushLogs();
@@ -102,4 +104,4 @@ public final class SystemTermination {
// ServerStore.dump(directory + "store/");
SystemLogger.logInfo("[SystemTerminator] Saved player accounts!");
}
-}
\ No newline at end of file
+}
diff --git a/Server/src/main/kotlin/api/ContentAPI.kt b/Server/src/main/kotlin/api/ContentAPI.kt
index baea8195f..8578efe85 100644
--- a/Server/src/main/kotlin/api/ContentAPI.kt
+++ b/Server/src/main/kotlin/api/ContentAPI.kt
@@ -35,7 +35,9 @@ import core.game.world.update.flag.chunk.AnimateObjectUpdateFlag
import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics
import rs09.game.content.dialogue.DialogueFile
+import rs09.game.content.global.GlobalKillCounter;
import rs09.game.system.SystemLogger
+import rs09.game.system.config.ItemConfigParser;
import rs09.game.world.GameWorld
import rs09.game.world.GameWorld.Pulser
import rs09.game.world.repository.Repository
@@ -1254,4 +1256,12 @@ object ContentAPI {
is Graphics -> Graphics.send(gfx, location)
}
}
+
+ @JvmStatic
+ fun announceIfRare(player: Player, item: Item) {
+ if (item.definition.getConfiguration(ItemConfigParser.RARE_ITEM, false)) {
+ ContentAPI.sendNews("${player.username} has just received: ${item.amount} x ${item.name}.");
+ GlobalKillCounter.incrementRareDrop(player, item);
+ }
+ }
}
diff --git a/Server/src/main/kotlin/rs09/Server.kt b/Server/src/main/kotlin/rs09/Server.kt
index 684a7b039..075335240 100644
--- a/Server/src/main/kotlin/rs09/Server.kt
+++ b/Server/src/main/kotlin/rs09/Server.kt
@@ -10,6 +10,7 @@ import core.tools.TimeStamp
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
+import rs09.game.content.global.GlobalKillCounter;
import rs09.game.ge.GEAutoStock
import rs09.game.system.SystemLogger
import rs09.game.system.config.ServerConfigParser
@@ -74,6 +75,7 @@ object Server {
startTime = System.currentTimeMillis()
val t = TimeStamp()
SystemLogger.logInfo("Initializing Server Store...")
+ GlobalKillCounter.init()
ServerStore.init()
SystemLogger.logInfo("Initialized ${ServerStore.counter} store files.")
GameWorld.prompt(true)
diff --git a/Server/src/main/kotlin/rs09/game/content/activity/barrows/RewardChest.kt b/Server/src/main/kotlin/rs09/game/content/activity/barrows/RewardChest.kt
index 4705a3e5c..7e6d25d31 100644
--- a/Server/src/main/kotlin/rs09/game/content/activity/barrows/RewardChest.kt
+++ b/Server/src/main/kotlin/rs09/game/content/activity/barrows/RewardChest.kt
@@ -1,5 +1,6 @@
package rs09.game.content.activity.barrows
+import api.ContentAPI
import core.game.component.Component
import core.game.container.access.InterfaceContainer
import core.game.content.global.BossKillCounter
@@ -93,9 +94,10 @@ object RewardChest {
player.interfaceManager.open(Component(Components.TRAIL_REWARD_364))
BossKillCounter.addtoBarrowsCount(player)
for(item in rewards){
+ ContentAPI.announceIfRare(player, item);
if(!player.inventory.add(item)){
GroundItemManager.create(item,player)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Server/src/main/kotlin/rs09/game/content/global/GlobalKillCounter.kt b/Server/src/main/kotlin/rs09/game/content/global/GlobalKillCounter.kt
new file mode 100644
index 000000000..9be43721d
--- /dev/null
+++ b/Server/src/main/kotlin/rs09/game/content/global/GlobalKillCounter.kt
@@ -0,0 +1,107 @@
+package rs09.game.content.global
+
+import core.game.node.entity.player.Player
+import rs09.game.system.SystemLogger
+import java.io.File
+import java.io.FileReader
+import java.io.FileWriter
+import org.json.simple.JSONArray
+import org.json.simple.JSONObject
+import org.json.simple.parser.JSONParser
+import rs09.ServerConstants
+import core.game.node.item.Item
+
+object GlobalKillCounter {
+ val kills: HashMap> = HashMap()
+ val rare_drops: HashMap> = HashMap()
+
+ fun init() {
+ val file = File(ServerConstants.DATA_PATH + File.separator + "global_kill_stats.json")
+ if(!file.exists()) {
+ return
+ }
+
+ val reader = FileReader(file)
+ val parser = JSONParser()
+ try {
+ val data = parser.parse(reader) as JSONObject
+ val tmp_kills = data.get("kills")
+ populate(kills, tmp_kills)
+ val tmp_rare_drops = data.get("rare_drops")
+ populate(rare_drops, tmp_rare_drops)
+ } catch (e: Exception){
+ SystemLogger.logErr("Failed parsing ${file.name} - stack trace below.")
+ e.printStackTrace()
+ }
+ }
+
+ @JvmStatic
+ fun populate(field: HashMap>, obj: Any?) {
+ if(obj != null && obj is JSONObject) {
+ for((player, tmp_kc) in obj.asIterable()) {
+ if(player is String) {
+ val kc: HashMap = HashMap()
+ for((npc_id, count) in (tmp_kc as JSONObject).asIterable()) {
+ kc.put(java.lang.Long.parseLong(npc_id as String), count as Long)
+ }
+ field.put(player, kc)
+ }
+ }
+ }
+ }
+
+ @JvmStatic
+ fun saveField(field: HashMap>): JSONObject {
+ val tmp_kills = JSONObject()
+ for((player, kc) in field.asIterable()) {
+ val tmp_kc = JSONObject()
+ for((id, count) in kc.asIterable()) {
+ tmp_kc.put(id, count)
+ }
+ tmp_kills.put(player, tmp_kc)
+ }
+ return tmp_kills
+ }
+
+ @JvmStatic
+ fun save() {
+ val data = JSONObject()
+ data.put("kills", saveField(kills))
+ data.put("rare_drops", saveField(rare_drops))
+ val file = File(ServerConstants.DATA_PATH + File.separator + "global_kill_stats.json")
+ FileWriter(file).use { it.write(data.toJSONString()); it.flush(); it.close() }
+ }
+
+ @JvmStatic
+ fun incrementKills(player: Player, npc_id: Int) {
+ val player_kills = kills.getOrPut(player.username, { HashMap() })
+ val old_amount = player_kills.getOrElse(npc_id.toLong(), { 0 })
+ player_kills.put(npc_id.toLong(), 1 + old_amount)
+ }
+
+ @JvmStatic
+ fun incrementRareDrop(player: Player, item: Item) {
+ val player_drops = rare_drops.getOrPut(player.username, { HashMap() })
+ val old_amount = player_drops.getOrElse(item.id.toLong(), { 0 })
+ player_drops.put(item.id.toLong(), item.amount + old_amount)
+ }
+
+ @JvmStatic
+ fun getKills(player: Player, npc_id: Int): Long {
+ return kills.getOrElse(player.username, { HashMap() }).getOrElse(npc_id.toLong(), { 0 })
+ }
+
+ @JvmStatic
+ fun getKills(player: Player, npc_ids: IntArray): Long {
+ var sum: Long = 0
+ for(npc_id in npc_ids) {
+ sum += getKills(player, npc_id)
+ }
+ return sum
+ }
+
+ @JvmStatic
+ fun getRareDrops(player: Player, item_id: Int): Long {
+ return rare_drops.getOrElse(player.username, { HashMap() }).getOrElse(item_id.toLong(), { 0 })
+ }
+}
diff --git a/Server/src/main/kotlin/rs09/game/node/entity/player/info/stats/StatAttributeKeys.kt b/Server/src/main/kotlin/rs09/game/node/entity/player/info/stats/StatAttributeKeys.kt
index bc6aa3127..ee08acd85 100644
--- a/Server/src/main/kotlin/rs09/game/node/entity/player/info/stats/StatAttributeKeys.kt
+++ b/Server/src/main/kotlin/rs09/game/node/entity/player/info/stats/StatAttributeKeys.kt
@@ -6,6 +6,7 @@ const val STATS_DEATHS = "deaths"
const val STATS_LOGS = "logs_chopped"
const val STATS_FISH = "fish_caught"
const val STATS_ROCKS = "rocks_mined"
+const val STATS_RC = "essence_crafted"
const val STATS_ALKHARID_GATE = "alkharid_gate"
const val FISHING_TRAWLER_GAMES_WON = "fishing-trawler-games"
const val FISHING_TRAWLER_LEAKS_PATCHED = "fishing-trawler-leaks-patched"
diff --git a/Server/src/main/kotlin/rs09/game/node/entity/player/info/stats/StatsCommandSet.kt b/Server/src/main/kotlin/rs09/game/node/entity/player/info/stats/StatsCommandSet.kt
index 8ea7c07ec..fb2e5104d 100644
--- a/Server/src/main/kotlin/rs09/game/node/entity/player/info/stats/StatsCommandSet.kt
+++ b/Server/src/main/kotlin/rs09/game/node/entity/player/info/stats/StatsCommandSet.kt
@@ -4,10 +4,168 @@ import core.game.component.Component
import core.game.content.global.BossKillCounter
import core.game.node.entity.player.Player
import core.plugin.Initializable
+import org.rs09.consts.Items;
+import org.rs09.consts.NPCs;
+import rs09.game.content.global.GlobalKillCounter;
+import rs09.game.interaction.InterfaceListener
import rs09.game.system.command.Command
import rs09.game.system.command.sets.CommandSet
import rs09.game.world.repository.Repository
+val TUROTH_IDS = intArrayOf(NPCs.TUROTH_1622, NPCs.TUROTH_1623, NPCs.TUROTH_1626, NPCs.TUROTH_1627, NPCs.TUROTH_1628, NPCs.TUROTH_1629, NPCs.TUROTH_1630)
+val KURASK_IDS = intArrayOf(NPCs.KURASK_1608, NPCs.KURASK_1609, NPCs.KURASK_4229, NPCs.KURASK_7811)
+val GARGOYLE_IDS = intArrayOf(NPCs.GARGOYLE_1610, NPCs.GARGOYLE_1827, NPCs.GARGOYLE_6389)
+val SPIRITUAL_MAGE_IDS = intArrayOf(NPCs.SPIRITUAL_MAGE_6221, NPCs.SPIRITUAL_MAGE_6231, NPCs.SPIRITUAL_MAGE_6257, NPCs.SPIRITUAL_MAGE_6278)
+val GREEN_DRAGON_IDS = intArrayOf(NPCs.GREEN_DRAGON_941, NPCs.GREEN_DRAGON_4677, NPCs.GREEN_DRAGON_4678, NPCs.GREEN_DRAGON_4679, NPCs.GREEN_DRAGON_4680, NPCs.BRUTAL_GREEN_DRAGON_5362)
+val BLUE_DRAGON_IDS = intArrayOf(NPCs.BLUE_DRAGON_55, NPCs.BLUE_DRAGON_4681, NPCs.BLUE_DRAGON_4682, NPCs.BLUE_DRAGON_4683, NPCs.BLUE_DRAGON_4684, NPCs.BLUE_DRAGON_5178)
+val RED_DRAGON_IDS = intArrayOf(NPCs.RED_DRAGON_53, NPCs.RED_DRAGON_4669, NPCs.RED_DRAGON_4670, NPCs.RED_DRAGON_4671, NPCs.RED_DRAGON_4672)
+val BLACK_DRAGON_IDS = intArrayOf(NPCs.BLACK_DRAGON_54, NPCs.BLACK_DRAGON_4673, NPCs.BLACK_DRAGON_4674, NPCs.BLACK_DRAGON_4675, NPCs.BLACK_DRAGON_4676)
+val BRONZE_DRAGON_IDS = intArrayOf(NPCs.BRONZE_DRAGON_1590)
+val IRON_DRAGON_IDS = intArrayOf(NPCs.IRON_DRAGON_1591)
+val STEEL_DRAGON_IDS = intArrayOf(NPCs.STEEL_DRAGON_1592, NPCs.STEEL_DRAGON_3590)
+val MITHRIL_DRAGON_IDS = intArrayOf(NPCs.MITHRIL_DRAGON_5363, NPCs.MITHRIL_DRAGON_8424)
+val SKELETAL_WYVERN_IDS = intArrayOf(NPCs.SKELETAL_WYVERN_3068, NPCs.SKELETAL_WYVERN_3069, NPCs.SKELETAL_WYVERN_3070, NPCs.SKELETAL_WYVERN_3071)
+
+val SPACER = " ";
+val NUM_PAGES = 3
+
+fun sendStats(player: Player, other: Player, page: Int){
+ prepareInterface(player, other, page)
+ val globalData = other.savedData.globalData
+ for(i in (68..97)) {
+ when(page) {
+ 0 -> {
+ when(i) {
+ //Various stats
+ 97 -> sendLine(player,"Easy Clues: ${other.treasureTrailManager.completedClues[0]}",i)
+ 68 -> sendLine(player,"Medium Clues: ${other.treasureTrailManager.completedClues[1]}",i)
+ 69 -> sendLine(player,"Hard Clues: ${other.treasureTrailManager.completedClues[2]}",i)
+ 70 -> sendLine(player,SPACER,i)
+ 71 -> sendLine(player,"Slayer Tasks: ${other.slayer.totalTasks}",i)
+ 72 -> sendLine(player,"Quest Points: ${other.questRepository.points}",i)
+ 73 -> sendLine(player,"Ironman Mode: ${other.ironmanManager.mode.name.toLowerCase()}",i)
+ 74 -> sendLine(player,"Deaths: ${other.getAttribute("$STATS_BASE:$STATS_DEATHS",0)}",i)
+ 75 -> sendLine(player,SPACER,i)
+ 76 -> sendLine(player,"Logs Chopped: ${other.getAttribute("$STATS_BASE:$STATS_LOGS",0)}",i)
+ 77 -> sendLine(player,"Rocks Mined: ${other.getAttribute("$STATS_BASE:$STATS_ROCKS",0)}",i)
+ 78 -> sendLine(player,"Fish Caught: ${other.getAttribute("$STATS_BASE:$STATS_FISH",0)}",i)
+ 79 -> sendLine(player, "Essence Crafted: ${other.getAttribute("$STATS_BASE:$STATS_RC",0)}", i)
+
+ //Boss KC
+ 82 -> sendLine(player, "KBD KC: ${globalData.bossCounters.get(BossKillCounter.KING_BLACK_DRAGON.ordinal)}",i)
+ 83 -> sendLine(player, "TDs KC: ${globalData.bossCounters.get(BossKillCounter.TORMENTED_DEMONS.ordinal)}",i)
+ 84 -> sendLine(player, "Supreme KC: ${globalData.bossCounters.get(BossKillCounter.DAGANNOTH_SUPREME.ordinal)}",i)
+ 85 -> sendLine(player, "Rex KC: ${globalData.bossCounters.get(BossKillCounter.DAGANNOTH_REX.ordinal)}",i)
+ 86 -> sendLine(player, "Prime KC: ${globalData.bossCounters.get(BossKillCounter.DAGANNOTH_PRIME.ordinal)}",i)
+ 87 -> sendLine(player, "Barrows KC: ${globalData.barrowsLoots}",i)
+ 88 -> sendLine(player, "Chaos Ele: ${globalData.bossCounters.get(BossKillCounter.CHAOS_ELEMENTAL.ordinal)}",i)
+ 89 -> sendLine(player, "Mole KC: ${globalData.bossCounters.get(BossKillCounter.GIANT_MOLE.ordinal)}",i)
+ 90 -> sendLine(player, "Sara KC: ${globalData.bossCounters.get(BossKillCounter.SARADOMIN.ordinal)}",i)
+ 91 -> sendLine(player, "Zammy KC: ${globalData.bossCounters.get(BossKillCounter.ZAMORAK.ordinal)}",i)
+ 92 -> sendLine(player, "Bandos KC: ${globalData.bossCounters.get(BossKillCounter.BANDOS.ordinal)}",i)
+ 93 -> sendLine(player, "Arma KC: ${globalData.bossCounters.get(BossKillCounter.ARMADYL.ordinal)}",i)
+ 94 -> sendLine(player, "Jad KC: ${globalData.bossCounters.get(BossKillCounter.JAD.ordinal)}",i)
+ 95 -> sendLine(player, "KQ KC: ${globalData.bossCounters.get(BossKillCounter.KALPHITE_QUEEN.ordinal)}",i)
+ 96 -> sendLine(player, "Corp KC: ${globalData.bossCounters.get(BossKillCounter.CORPOREAL_BEAST.ordinal)}",i)
+ else -> sendLine(player,"",i)
+ }
+ }
+ 1 -> {
+ when(i) {
+ 97 -> sendLine(player, "Turoths: ${GlobalKillCounter.getKills(other, TUROTH_IDS)}", i)
+ 68 -> sendLine(player, "Kurasks: ${GlobalKillCounter.getKills(other, KURASK_IDS)}", i)
+ 69 -> sendLine(player, "Leaf-bladed swords: ${GlobalKillCounter.getRareDrops(other, Items.LEAF_BLADED_SPEAR_4158)}", i)
+ 70 -> sendLine(player,SPACER,i)
+ 71 -> sendLine(player, "Gargoyles: ${GlobalKillCounter.getKills(other, GARGOYLE_IDS)}", i)
+ 72 -> sendLine(player, "Granite mauls: ${GlobalKillCounter.getRareDrops(other, Items.GRANITE_MAUL_4153)}", i)
+ 73 -> sendLine(player,SPACER,i)
+ 74 -> sendLine(player, "Spiritual mages: ${GlobalKillCounter.getKills(other, SPIRITUAL_MAGE_IDS)}", i)
+ 75 -> sendLine(player, "Dragon boots: ${GlobalKillCounter.getRareDrops(other, Items.DRAGON_BOOTS_11732)}", i)
+ 76 -> sendLine(player,SPACER,i)
+ 77 -> sendLine(player, "Abyssal demons: ${GlobalKillCounter.getKills(other, NPCs.ABYSSAL_DEMON_1615)}", i)
+ 78 -> sendLine(player, "Abyssal whips: ${GlobalKillCounter.getRareDrops(other, Items.ABYSSAL_WHIP_4151)}", i)
+ 79 -> sendLine(player,SPACER,i)
+ 80 -> sendLine(player, "Dark beasts: ${GlobalKillCounter.getKills(other, NPCs.DARK_BEAST_2783)}", i)
+ 81 -> sendLine(player, "Dark bows: ${GlobalKillCounter.getRareDrops(other, Items.DARK_BOW_11235)}", i)
+
+ 82 -> sendLine(player, "Green Dragons: ${GlobalKillCounter.getKills(other, GREEN_DRAGON_IDS)}", i)
+ 83 -> sendLine(player, "Blue Dragons: ${GlobalKillCounter.getKills(other, BLUE_DRAGON_IDS)}", i)
+ 84 -> sendLine(player, "Red Dragons: ${GlobalKillCounter.getKills(other, RED_DRAGON_IDS)}", i)
+ 85 -> sendLine(player, "Black Dragons: ${GlobalKillCounter.getKills(other, BLACK_DRAGON_IDS)}", i)
+ 86 -> sendLine(player,SPACER,i)
+ 87 -> sendLine(player, "Bronze Dragons: ${GlobalKillCounter.getKills(other, BRONZE_DRAGON_IDS)}", i)
+ 88 -> sendLine(player, "Iron Dragons: ${GlobalKillCounter.getKills(other, IRON_DRAGON_IDS)}", i)
+ 89 -> sendLine(player, "Steel Dragons: ${GlobalKillCounter.getKills(other, STEEL_DRAGON_IDS)}", i)
+ 90 -> sendLine(player, "Mithril Dragons: ${GlobalKillCounter.getKills(other, MITHRIL_DRAGON_IDS)}", i)
+ 91 -> sendLine(player, "Skeletal Wyverns: ${GlobalKillCounter.getKills(other, SKELETAL_WYVERN_IDS)}", i)
+ 92 -> sendLine(player,SPACER,i)
+ 93 -> sendLine(player, "Draconic visages: ${GlobalKillCounter.getRareDrops(other, Items.DRACONIC_VISAGE_11286)}", i)
+
+ else -> sendLine(player,"",i)
+ }
+ }
+ 2 -> {
+ when(i) {
+ 97 -> sendLine(player, "Ahrim's hood: ${GlobalKillCounter.getRareDrops(other, Items.AHRIMS_HOOD_4708)}", i)
+ 68 -> sendLine(player, "Ahrim's staff: ${GlobalKillCounter.getRareDrops(other, Items.AHRIMS_STAFF_4710)}", i)
+ 69 -> sendLine(player, "Ahrim's robetop: ${GlobalKillCounter.getRareDrops(other, Items.AHRIMS_ROBETOP_4712)}", i)
+ 70 -> sendLine(player, "Ahrim's robeskirt: ${GlobalKillCounter.getRareDrops(other, Items.AHRIMS_ROBESKIRT_4714)}", i)
+ 71 -> sendLine(player,SPACER,i)
+ 72 -> sendLine(player, "Dharok's helm: ${GlobalKillCounter.getRareDrops(other, Items.DHAROKS_HELM_4716)}", i)
+ 73 -> sendLine(player, "Dharok's greataxe: ${GlobalKillCounter.getRareDrops(other, Items.DHAROKS_GREATAXE_4718)}", i)
+ 74 -> sendLine(player, "Dharok's platebody: ${GlobalKillCounter.getRareDrops(other, Items.DHAROKS_PLATEBODY_4720)}", i)
+ 75 -> sendLine(player, "Dharok's platelegs: ${GlobalKillCounter.getRareDrops(other, Items.DHAROKS_PLATELEGS_4722)}", i)
+ 76 -> sendLine(player,SPACER,i)
+ 77 -> sendLine(player, "Guthan's helm: ${GlobalKillCounter.getRareDrops(other, Items.GUTHANS_HELM_4724)}", i)
+ 78 -> sendLine(player, "Guthan's warspear: ${GlobalKillCounter.getRareDrops(other, Items.GUTHANS_WARSPEAR_4726)}", i)
+ 79 -> sendLine(player, "Guthan's platebody: ${GlobalKillCounter.getRareDrops(other, Items.GUTHANS_PLATEBODY_4728)}", i)
+ 80 -> sendLine(player, "Guthan's chainskirt: ${GlobalKillCounter.getRareDrops(other, Items.GUTHANS_CHAINSKIRT_4730)}", i)
+
+ 82 -> sendLine(player, "Karil's coif: ${GlobalKillCounter.getRareDrops(other, Items.KARILS_COIF_4732)}", i)
+ 83 -> sendLine(player, "Karil's crossbow: ${GlobalKillCounter.getRareDrops(other, Items.KARILS_CROSSBOW_4734)}", i)
+ 84 -> sendLine(player, "Karil's leathertop: ${GlobalKillCounter.getRareDrops(other, Items.KARILS_LEATHERTOP_4736)}", i)
+ 85 -> sendLine(player, "Karil's leatherskirt: ${GlobalKillCounter.getRareDrops(other, Items.KARILS_LEATHERSKIRT_4738)}", i)
+ 86 -> sendLine(player,SPACER,i)
+ 87 -> sendLine(player, "Torag's helm: ${GlobalKillCounter.getRareDrops(other, Items.TORAGS_HELM_4745)}", i)
+ 88 -> sendLine(player, "Torag's hammers: ${GlobalKillCounter.getRareDrops(other, Items.TORAGS_HAMMERS_4747)}", i)
+ 89 -> sendLine(player, "Torag's platebody: ${GlobalKillCounter.getRareDrops(other, Items.TORAGS_PLATEBODY_4749)}", i)
+ 90 -> sendLine(player, "Torag's platelegs: ${GlobalKillCounter.getRareDrops(other, Items.TORAGS_PLATELEGS_4751)}", i)
+ 91 -> sendLine(player,SPACER,i)
+ 92 -> sendLine(player, "Verac's helm: ${GlobalKillCounter.getRareDrops(other, Items.VERACS_HELM_4753)}", i)
+ 93 -> sendLine(player, "Verac's flail: ${GlobalKillCounter.getRareDrops(other, Items.VERACS_FLAIL_4755)}", i)
+ 94 -> sendLine(player, "Verac's brassard: ${GlobalKillCounter.getRareDrops(other, Items.VERACS_BRASSARD_4757)}", i)
+ 95 -> sendLine(player, "Verac's plateskirt: ${GlobalKillCounter.getRareDrops(other, Items.VERACS_PLATESKIRT_4759)}", i)
+ else -> sendLine(player,"",i)
+ }
+ }
+ }
+ }
+ player.interfaceManager.open(Component(26))
+}
+
+fun sendLine(player: Player, line: String, child: Int) {
+ player.packetDispatch.sendString(line,26,child)
+}
+
+fun prepareInterface(player: Player,other: Player, page: Int){
+ player.setAttribute("stats-page-info", StatsPageInfo(other, page))
+ if(page == 0) {
+ player.packetDispatch.sendInterfaceConfig(26,62,true)
+ player.packetDispatch.sendInterfaceConfig(26,65,true)
+ } else {
+ sendLine(player, "Previous", 65)
+ }
+ if(page == NUM_PAGES - 1) {
+ player.packetDispatch.sendInterfaceConfig(26,64,true)
+ player.packetDispatch.sendInterfaceConfig(26,66,true)
+ } else {
+ sendLine(player, "Next", 66)
+ }
+ player.packetDispatch.sendString(other.username + "'s Stats - Page ${page + 1}",26,101)
+}
+
+data class StatsPageInfo(val other: Player, val page: Int) {}
+
@Initializable
class StatsCommandSet : CommandSet(Command.Privilege.STANDARD) {
override fun defineCommands() {
@@ -28,64 +186,33 @@ class StatsCommandSet : CommandSet(Command.Privilege.STANDARD) {
return@define
}
- sendStats(player,other)
+ sendStats(player,other, 0)
}
}
fun sendStats(player: Player){
- sendStats(player,player)
+ sendStats(player,player, 0)
}
- fun sendStats(player: Player, other: Player){
- prepareInterface(player,other)
- val globalData = other.savedData.globalData
- for(i in (67..96)){
- when(i){
- //Various stats
- 67 -> sendLine(player,"Easy Clues: ${other.treasureTrailManager.completedClues[0]}",97)
- 68 -> sendLine(player,"Medium Clues: ${other.treasureTrailManager.completedClues[1]}",i)
- 69 -> sendLine(player,"Hard Clues: ${other.treasureTrailManager.completedClues[2]}",i)
- 70 -> sendLine(player," ",i)
- 71 -> sendLine(player,"Slayer Tasks: ${other.slayer.totalTasks}",i)
- 72 -> sendLine(player,"Quest Points: ${other.questRepository.points}",i)
- 73 -> sendLine(player,"Ironman Mode: ${other.ironmanManager.mode.name.toLowerCase()}",i)
- 74 -> sendLine(player,"Deaths: ${other.getAttribute("$STATS_BASE:$STATS_DEATHS",0)}",i)
- 75 -> sendLine(player," ",i)
- 76 -> sendLine(player,"Logs Chopped: ${other.getAttribute("$STATS_BASE:$STATS_LOGS",0)}",i)
- 77 -> sendLine(player,"Rocks Mined: ${other.getAttribute("$STATS_BASE:$STATS_ROCKS",0)}",i)
- 78 -> sendLine(player,"Fish Caught: ${other.getAttribute("$STATS_BASE:$STATS_FISH",0)}",i)
+}
- //Boss KC
- 82 -> sendLine(player, "KBD KC: ${globalData.bossCounters.get(BossKillCounter.KING_BLACK_DRAGON.ordinal)}",i)
- 83 -> sendLine(player, "TDs KC: ${globalData.bossCounters.get(BossKillCounter.TORMENTED_DEMONS.ordinal)}",i)
- 84 -> sendLine(player, "Supreme KC: ${globalData.bossCounters.get(BossKillCounter.DAGANNOTH_SUPREME.ordinal)}",i)
- 85 -> sendLine(player, "Rex KC: ${globalData.bossCounters.get(BossKillCounter.DAGANNOTH_REX.ordinal)}",i)
- 86 -> sendLine(player, "Prime KC: ${globalData.bossCounters.get(BossKillCounter.DAGANNOTH_PRIME.ordinal)}",i)
- 87 -> sendLine(player, "Barrows KC: ${globalData.barrowsLoots}",i)
- 88 -> sendLine(player, "Chaos Ele: ${globalData.bossCounters.get(BossKillCounter.CHAOS_ELEMENTAL.ordinal)}",i)
- 89 -> sendLine(player, "Mole KC: ${globalData.bossCounters.get(BossKillCounter.GIANT_MOLE.ordinal)}",i)
- 90 -> sendLine(player, "Sara KC: ${globalData.bossCounters.get(BossKillCounter.SARADOMIN.ordinal)}",i)
- 91 -> sendLine(player, "Zammy KC: ${globalData.bossCounters.get(BossKillCounter.ZAMORAK.ordinal)}",i)
- 92 -> sendLine(player, "Bandos KC: ${globalData.bossCounters.get(BossKillCounter.BANDOS.ordinal)}",i)
- 93 -> sendLine(player, "Arma KC: ${globalData.bossCounters.get(BossKillCounter.ARMADYL.ordinal)}",i)
- 94 -> sendLine(player, "Jad KC: ${globalData.bossCounters.get(BossKillCounter.JAD.ordinal)}",i)
- 95 -> sendLine(player, "KQ KC: ${globalData.bossCounters.get(BossKillCounter.KALPHITE_QUEEN.ordinal)}",i)
- 96 -> sendLine(player, "Corp KC: ${globalData.bossCounters.get(BossKillCounter.CORPOREAL_BEAST.ordinal)}",i)
- else -> sendLine(player,"",i)
+class StatsInterface : InterfaceListener() {
+ val COMPONENT_ID = 26
+
+ override fun defineListeners() {
+ on(COMPONENT_ID, 61) { player, _, _, _, _, _ ->
+ val info: StatsPageInfo? = player.getAttribute("stats-page-info", null)
+ if(info != null) {
+ sendStats(player, info.other, info.page-1)
}
+ return@on true
+ }
+ on(COMPONENT_ID, 63) { player, _, _, _, _, _ ->
+ val info: StatsPageInfo? = player.getAttribute("stats-page-info", null)
+ if(info != null) {
+ sendStats(player, info.other, info.page+1)
+ }
+ return@on true
}
- player.interfaceManager.open(Component(26))
- }
-
- fun sendLine(player: Player, line: String, child: Int){
- player.packetDispatch.sendString(line,26,child)
- }
-
- fun prepareInterface(player: Player,other: Player){
- player.packetDispatch.sendInterfaceConfig(26,64,true)
- player.packetDispatch.sendInterfaceConfig(26,62,true)
- player.packetDispatch.sendInterfaceConfig(26,65,true)
- player.packetDispatch.sendInterfaceConfig(26,66,true)
- player.packetDispatch.sendString(other.username + "'s Stats",26,101)
}
}