Skip to content
9 changes: 9 additions & 0 deletions .data/raw-cache/server/inv.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,12 @@ id = "inv.skill_guide_hunting_tracking"
inherit = "inv.skill_guide_hunting_tracking"
stack = "Never"

[[inventory]]
isServerOnly = true
id = "inv.collection_transmit"
inherit = "inv.collection_transmit"
size = 2000
scope = "Perm"
stack = "Always"
protect = false

Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ package org.rsmod.api.net.rsprot.handlers
import com.github.michaelbull.logging.InlineLogger
import dev.openrune.ServerCacheManager
import dev.openrune.definition.type.widget.IfEvent
import dev.openrune.rscm.RSCM
import dev.openrune.rscm.RSCMType
import dev.openrune.types.aconverted.interf.IfButtonOp
import jakarta.inject.Inject
import net.rsprot.protocol.game.incoming.buttons.If3Button
import org.rsmod.annotations.InternalApi
import org.rsmod.api.net.rsprot.player.InterfaceEvents
import org.rsmod.api.player.debug.componentClickDebug
import org.rsmod.api.player.output.mes
import org.rsmod.api.player.protect.ProtectedAccessLauncher
import org.rsmod.api.player.ui.IfModalButton
import org.rsmod.api.player.ui.IfOverlayButton
Expand Down Expand Up @@ -48,6 +52,12 @@ constructor(private val eventBus: EventBus, private val protectedAccess: Protect
val comsub = message.sub
val buttonOp = message.buttonOp

if (player.componentClickDebug) {
val name = RSCM.getReverseMapping(RSCMType.COMPONENT, message.asComponent.packed)
.ifEmpty { "component.<unmapped:${message.asComponent.packed}>" }
player.mes("[componentdebug] $name comsub=$comsub op=$buttonOp")
}

val opEnabled =
InterfaceEvents.isEnabled(player.ui, componentType, comsub, buttonOp.toIfEvent())
if (!opEnabled) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.rsmod.api.player.debug

import org.rsmod.api.attr.AttributeKey
import org.rsmod.game.entity.Player

private val COMPONENT_CLICK_DEBUG_ATTR = AttributeKey<Boolean>(temp = true)

/**
* When enabled, [org.rsmod.api.net.rsprot.handlers.If3ButtonHandler] reports every button click
* this player sends to the client (component RSCM name, comsub, and op)
*/
public var Player.componentClickDebug: Boolean
get() = attr[COMPONENT_CLICK_DEBUG_ATTR] == true
set(value) {
attr[COMPONENT_CLICK_DEBUG_ATTR] = value
}
1 change: 1 addition & 0 deletions content/areas/city/prifddinas/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ dependencies {
implementation(projects.api.pluginCommons)
implementation(projects.api.dropTable)
implementation(projects.api.dropTablePlugin)
implementation(projects.content.interfaces.collectionLog)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.rsmod.api.repo.loc.LocRepository
import org.rsmod.api.repo.obj.ObjRepository
import org.rsmod.api.script.onOpLoc1
import org.rsmod.api.script.onOpLoc2
import org.rsmod.content.interfaces.collectionlog.CollectionLog
import org.rsmod.game.loc.BoundLocInfo
import org.rsmod.plugin.scripts.PluginScript
import org.rsmod.plugin.scripts.ScriptContext
Expand Down Expand Up @@ -73,6 +74,8 @@ class ElvenCrystalChestScript @Inject constructor(
private fun ProtectedAccess.giveDrop(drop: DropRollItem) {
if (drop.isNothing || !drop.condition(player)) return
val obj = drop.transformObj(player) ?: drop.obj
invAddOrDrop(objRepo, obj, drop.rollCount(random))
val count = drop.rollCount(random)
CollectionLog.grant(player, obj, count)
invAddOrDrop(objRepo, obj, count)
}
}
2 changes: 2 additions & 0 deletions content/areas/godwars/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ plugins {
}

dependencies {
implementation(projects.api.areaChecker)
implementation(projects.api.pluginCommons)
implementation(projects.engine.utilsBits)
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
package org.rsmod.content.areas.godwars

import dev.openrune.ServerCacheManager
import dev.openrune.rscm.RSCM.asRSCM
import dev.openrune.rscm.RSCMType
import jakarta.inject.Inject
import org.rsmod.api.area.checker.AreaChecker
import org.rsmod.api.death.NpcDeathKillContext
import org.rsmod.api.death.NpcDeathKillHook
import org.rsmod.api.player.vars.VarPlayerIntMapSetter
import org.rsmod.game.entity.Npc
import org.rsmod.game.entity.Player
import dev.openrune.types.varp.bits
import org.rsmod.plugin.module.PluginModule
import org.rsmod.utils.bits.bitMask

public class GodwarsModule : PluginModule() {
override fun bind() {
addSetBinding<NpcDeathKillHook>(GodwarsKillCountHook::class.java)
}
}

internal class GodwarsKillCountHook @Inject constructor() : NpcDeathKillHook {
internal class GodwarsKillCountHook @Inject constructor(private val areas: AreaChecker) :
NpcDeathKillHook {
override fun onKill(context: NpcDeathKillContext) {
val player = context.hero
val npc = context.npc
if (!areas.inArea("area.godwars_dungeon", player.coords)) return
val faction = FACTIONS.firstOrNull { it.matches(npc) } ?: return
player.increment(faction.counterVarbit)
}

private fun Player.increment(varp: String) {
VarPlayerIntMapSetter.set(this, varp, vars[varp] + 1)
private fun Player.increment(varbit: String) {
val next = vars[varbit] + 1
val type = ServerCacheManager.getVarbit(varbit.asRSCM(RSCMType.VARBIT))
val max = type?.bits?.bitMask ?: Int.MAX_VALUE.toLong()
VarPlayerIntMapSetter.set(this, varbit, next.coerceAtMost(max.toInt()))
}

private class Faction(
Expand Down
1 change: 1 addition & 0 deletions content/areas/wilderness/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ dependencies {
implementation(projects.api.attr)
implementation(projects.api.dropTable)
implementation(projects.api.dropTablePlugin)
implementation(projects.content.interfaces.collectionLog)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.rsmod.api.repo.loc.LocRepository
import org.rsmod.api.repo.obj.ObjRepository
import org.rsmod.api.script.onOpLoc1
import org.rsmod.api.script.onOpLoc2
import org.rsmod.content.interfaces.collectionlog.CollectionLog
import org.rsmod.game.loc.BoundLocInfo
import org.rsmod.plugin.scripts.PluginScript
import org.rsmod.plugin.scripts.ScriptContext
Expand Down Expand Up @@ -78,6 +79,8 @@ class LarransChestScript @Inject constructor(
private fun ProtectedAccess.giveDrop(drop: DropRollItem) {
if (drop.isNothing || !drop.condition(player)) return
val obj = drop.transformObj(player) ?: drop.obj
invAddOrDrop(objRepo, obj, drop.rollCount(random))
val count = drop.rollCount(random)
CollectionLog.grant(player, obj, count)
invAddOrDrop(objRepo, obj, count)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.rsmod.api.repo.loc.LocRepository
import org.rsmod.api.repo.obj.ObjRepository
import org.rsmod.api.script.onOpHeld1
import org.rsmod.api.script.onOpLoc1
import org.rsmod.content.interfaces.collectionlog.CollectionLog
import org.rsmod.game.inv.isType
import org.rsmod.game.loc.BoundLocInfo
import org.rsmod.plugin.scripts.PluginScript
Expand Down Expand Up @@ -71,7 +72,9 @@ constructor(
if (player.front.isType("obj.wild_cave_amulet")) {
obj = ocCert(obj).internalName
}
invAddOrDrop(objRepo, obj, drop.rollCount(random))
val count = drop.rollCount(random)
CollectionLog.grant(player, obj, count)
invAddOrDrop(objRepo, obj, count)
}

private suspend fun ProtectedAccess.unlockBlipScroll() {
Expand Down
1 change: 1 addition & 0 deletions content/areas/zeah/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ dependencies {
implementation(projects.api.pluginCommons)
implementation(projects.api.dropTable)
implementation(projects.api.dropTablePlugin)
implementation(projects.content.interfaces.collectionLog)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.rsmod.api.repo.loc.LocRepository
import org.rsmod.api.repo.obj.ObjRepository
import org.rsmod.api.script.onOpLoc1
import org.rsmod.api.script.onOpLoc2
import org.rsmod.content.interfaces.collectionlog.CollectionLog
import org.rsmod.game.loc.BoundLocInfo
import org.rsmod.plugin.scripts.PluginScript
import org.rsmod.plugin.scripts.ScriptContext
Expand Down Expand Up @@ -68,6 +69,8 @@ class BrimstoneChestScript @Inject constructor(
private fun ProtectedAccess.giveDrop(drop: DropRollItem) {
if (drop.isNothing || !drop.condition(player)) return
val obj = drop.transformObj(player) ?: drop.obj
invAddOrDrop(objRepo, obj, drop.rollCount(random))
val count = drop.rollCount(random)
CollectionLog.grant(player, obj, count)
invAddOrDrop(objRepo, obj, count)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.rsmod.api.player.vars.VarPlayerIntMapSetter
import org.rsmod.api.repo.obj.ObjRepository
import org.rsmod.api.script.onOpLoc1
import org.rsmod.api.script.onOpLoc2
import org.rsmod.content.interfaces.collectionlog.CollectionLog
import org.rsmod.plugin.scripts.PluginScript
import org.rsmod.plugin.scripts.ScriptContext

Expand Down Expand Up @@ -65,6 +66,8 @@ class GrubbyChestScript @Inject constructor(
private fun ProtectedAccess.giveDrop(drop: DropRollItem) {
if (drop.isNothing || !drop.condition(player)) return
val obj = drop.transformObj(player) ?: drop.obj
invAddOrDrop(objRepo, obj, drop.rollCount(random))
val count = drop.rollCount(random)
CollectionLog.grant(player, obj, count)
invAddOrDrop(objRepo, obj, count)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.rsmod.api.repo.loc.LocRepository
import org.rsmod.api.repo.obj.ObjRepository
import org.rsmod.api.script.onOpHeldU
import org.rsmod.api.script.onOpLoc1
import org.rsmod.content.interfaces.collectionlog.CollectionLog
import org.rsmod.game.loc.BoundLocInfo
import org.rsmod.plugin.scripts.PluginScript
import org.rsmod.plugin.scripts.ScriptContext
Expand Down Expand Up @@ -67,7 +68,9 @@ constructor(
private fun ProtectedAccess.giveDrop(drop: DropRollItem) {
if (drop.isNothing || !drop.condition(player)) return
val obj = drop.transformObj(player) ?: drop.obj
invAddOrDrop(objRepo, obj, drop.rollCount(random))
val count = drop.rollCount(random)
CollectionLog.grant(player, obj, count)
invAddOrDrop(objRepo, obj, count)
}

private fun ProtectedAccess.combineKeyHalves() {
Expand Down
1 change: 1 addition & 0 deletions content/drops/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies {
implementation(projects.api.playerOutput)
implementation(projects.api.random)
implementation(projects.api.repo)
implementation(projects.content.interfaces.collectionLog)
implementation(projects.content.skills.slayer)
implementation(projects.content.quest)
implementation(projects.engine.game)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.rsmod.api.droptable.rollCount
import org.rsmod.api.player.output.ClientScripts
import org.rsmod.api.random.GameRandom
import org.rsmod.api.repo.obj.ObjRepository
import org.rsmod.content.interfaces.collectionlog.CollectionLog
import org.rsmod.game.entity.Npc
import org.rsmod.game.entity.Player
import org.rsmod.map.CoordGrid
Expand Down Expand Up @@ -88,6 +89,7 @@ constructor(
}
val obj = drop.transformObj(receiver) ?: drop.obj
val count = drop.rollCount(random)
CollectionLog.grant(receiver, obj, count)
val spawned = objRepo.add(obj, coords, duration, receiver, count)
ClientScripts.lootTrackerAddLoot(receiver, npc.id, eventId, spawned.type, spawned.count)
for (bonus in drop.bonusDrops) {
Expand Down
8 changes: 8 additions & 0 deletions content/interfaces/collection-log/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
plugins {
id("base-conventions")
}

dependencies {
implementation(projects.api.pluginCommons)
implementation(projects.engine.utilsBits)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.rsmod.content.interfaces.collectionlog

import dev.openrune.rscm.RSCM.asRSCM
import dev.openrune.rscm.RSCMType
import org.rsmod.api.invtx.invAdd
import org.rsmod.api.player.vars.VarPlayerIntMapSetter
import org.rsmod.game.entity.Player

public object CollectionLog {
/** Central entry point for marking an item as obtained for the collection log */
public fun grant(player: Player, obj: String, count: Int = 1) {
grant(player, obj.asRSCM(RSCMType.OBJ), count)
}

public fun grant(player: Player, objId: Int, count: Int = 1) {
if (count <= 0) {
return
}
if (!CollectionLogItems.contains(objId)) {
return
}
player.invAdd(player.collectionTransmit, objId, count)
checkCategoryCompletion(player, objId)
}

private fun checkCategoryCompletion(player: Player, itemId: Int) {
val inv = player.collectionTransmit
for (category in CollectionLogCategories.categoriesContaining(itemId)) {
if (player.vars[category.completedVarbit] != 0) {
continue
}
val allObtained = category.itemIds.all { inv.countOf(it) > 0 }
if (allObtained) {
VarPlayerIntMapSetter.set(player, category.completedVarbit, 1)
}
}
}
}
Loading
Loading