From b9328d40f4a4d8759b0db4aa261566258b956a98 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Mon, 18 Oct 2021 22:00:06 -0400 Subject: [PATCH] Make use of the next/previous arrows in the interface used for `::stats`, tracking all npc kills and tracking drops of items tagged with `"rare_item": "true"`, and displaying a curated subset of them. --- Server/data/configs/item_configs.json | 29 ++- .../java/core/game/node/entity/npc/NPC.java | 2 + .../node/entity/npc/drop/NPCDropTables.java | 8 +- .../skill/runecrafting/RuneCraftPulse.java | 10 +- .../core/game/system/SystemTermination.java | 4 +- Server/src/main/kotlin/api/ContentAPI.kt | 10 + Server/src/main/kotlin/rs09/Server.kt | 2 + .../content/activity/barrows/RewardChest.kt | 4 +- .../game/content/global/GlobalKillCounter.kt | 107 +++++++++ .../player/info/stats/StatAttributeKeys.kt | 1 + .../player/info/stats/StatsCommandSet.kt | 227 ++++++++++++++---- 11 files changed, 344 insertions(+), 60 deletions(-) create mode 100644 Server/src/main/kotlin/rs09/game/content/global/GlobalKillCounter.kt 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) } }