Skip to content

Commit

Permalink
Add OPNPCU message and its implementation
Browse files Browse the repository at this point in the history
Close issue #148
  • Loading branch information
Tomm0017 committed May 28, 2019
1 parent 960cd19 commit b303791
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 9 deletions.
30 changes: 24 additions & 6 deletions data/packets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,30 @@ in-packets:
type: SHORT
trans: ADD

- message: gg.rsmod.game.message.impl.OpNpcUMessage
type: FIXED
opcode: 23
length: 11
structure:
- name: item
sign: UNSIGNED
order: LITTLE
type: SHORT
trans: ADD
- name: slot
sign: UNSIGNED
type: SHORT
- name: npc_index
sign: UNSIGNED
order: LITTLE
type: SHORT
trans: ADD
- name: movement_type
type: BYTE
trans: NEGATE
- name: component_hash
type: INT

- message: gg.rsmod.game.message.impl.OpNpc1Message
type: FIXED
opcode: 71
Expand Down Expand Up @@ -1266,12 +1290,6 @@ in-packets:
type: VARIABLE_SHORT
opcode: 16

- message: gg.rsmod.game.message.impl.IgnoreMessage # TODO: OPNPCU
type: FIXED
opcode: 23
length: 11
ignore: true

- message: gg.rsmod.game.message.impl.IgnoreMessage # TODO: MESSAGE_PRIVATE
type: VARIABLE_SHORT
opcode: 25
Expand Down
35 changes: 34 additions & 1 deletion game/src/main/kotlin/gg/rsmod/game/action/PawnPathAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import java.lang.ref.WeakReference
*/
object PawnPathAction {

private const val ITEM_USE_OPCODE = -1

val walkPlugin: Plugin.() -> Unit = {
val pawn = ctx as Pawn
val world = pawn.world
Expand All @@ -49,6 +51,31 @@ object PawnPathAction {
}
}

val itemUsePlugin: Plugin.() -> Unit = s@ {
val pawn = ctx as Pawn
val world = pawn.world
val other = pawn.attr[INTERACTING_NPC_ATTR]?.get() ?: pawn.attr[INTERACTING_PLAYER_ATTR]?.get()!!

/*
* Some interactions only require line-of-sight range, such as npcs
* behind cells or booths. This allows for diagonal interaction.
*
* Set to null for default interaction range.
*/
val lineOfSightRange = if (other is Npc) world.plugins.getNpcInteractionDistance(other.id) else null

pawn.queue(TaskPriority.STANDARD) {
terminateAction = {
pawn.stopMovement()
if (pawn is Player) {
pawn.write(SetMapFlagMessage(255, 255))
}
}

walk(this, pawn, other, ITEM_USE_OPCODE, lineOfSightRange)
}
}

private suspend fun walk(it: QueueTask, pawn: Pawn, other: Pawn, opt: Int, lineOfSightRange: Int?) {
val world = pawn.world
val initialTile = Tile(other.tile)
Expand Down Expand Up @@ -111,7 +138,13 @@ object PawnPathAction {
}

val npcId = other.getTransform(pawn)
val handled = world.plugins.executeNpc(pawn, npcId, opt)
val handled = if (opt != ITEM_USE_OPCODE) {
world.plugins.executeNpc(pawn, npcId, opt)
} else {
val item = pawn.attr[INTERACTING_ITEM]?.get() ?: return
world.plugins.executeItemOnNpc(pawn, npcId, item.id)
}

if (!handled) {
pawn.writeMessage(Entity.NOTHING_INTERESTING_HAPPENS)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class MessageDecoderSet {
put(OpNpc4Message::class.java, OpNpc4Decoder(), OpNpc4Handler(), structures)
put(OpNpc5Message::class.java, OpNpc5Decoder(), OpNpc5Handler(), structures)
put(OpNpc6Message::class.java, OpNpc6Decoder(), OpNpc6Handler(), structures)
put(OpNpcTMessage::class.java, OpNpcTDecoder(), OpNpcTHandler(), structures)
put(OpNpcUMessage::class.java, OpNpcUDecoder(), OpNpcUHandler(), structures)

put(OpPlayer1Message::class.java, OpPlayer1Decoder(), OpPlayer1Handler(), structures)
put(OpPlayer2Message::class.java, OpPlayer2Decoder(), OpPlayer2Handler(), structures)
Expand All @@ -93,8 +95,6 @@ class MessageDecoderSet {
put(OpPlayer6Message::class.java, OpPlayer6Decoder(), OpPlayer6Handler(), structures)
put(OpPlayer7Message::class.java, OpPlayer7Decoder(), OpPlayer7Handler(), structures)
put(OpPlayer8Message::class.java, OpPlayer8Decoder(), OpPlayer8Handler(), structures)

put(OpNpcTMessage::class.java, OpNpcTDecoder(), OpNpcTHandler(), structures)
}

private fun <T : Message> put(messageType: Class<T>, decoderType: MessageDecoder<T>, handlerType: MessageHandler<T>, structures: MessageStructureSet) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package gg.rsmod.game.message.decoder

import gg.rsmod.game.message.MessageDecoder
import gg.rsmod.game.message.impl.OpNpcUMessage

/**
* @author Tom <rspsmods@gmail.com>
*/
class OpNpcUDecoder : MessageDecoder<OpNpcUMessage>() {

override fun decode(opcode: Int, opcodeIndex: Int, values: HashMap<String, Number>, stringValues: HashMap<String, String>): OpNpcUMessage {
val item = values["item"]!!.toInt()
val slot = values["slot"]!!.toInt()
val componentHash = values["component_hash"]!!.toInt()
val npcIndex = values["npc_index"]!!.toInt()
val movementType = values["movement_type"]!!.toInt()
return OpNpcUMessage(componentHash, npcIndex, item, slot, movementType)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package gg.rsmod.game.message.handler

import gg.rsmod.game.action.PawnPathAction
import gg.rsmod.game.message.MessageHandler
import gg.rsmod.game.message.impl.OpNpcUMessage
import gg.rsmod.game.model.World
import gg.rsmod.game.model.attr.INTERACTING_ITEM
import gg.rsmod.game.model.attr.INTERACTING_ITEM_ID
import gg.rsmod.game.model.attr.INTERACTING_ITEM_SLOT
import gg.rsmod.game.model.attr.INTERACTING_NPC_ATTR
import gg.rsmod.game.model.entity.Client
import gg.rsmod.game.model.priv.Privilege
import java.lang.ref.WeakReference

/**
* @author Tom <rspsmods@gmail.com>
*/
class OpNpcUHandler : MessageHandler<OpNpcUMessage> {

override fun handle(client: Client, world: World, message: OpNpcUMessage) {
val index = message.npcIndex
val npc = world.npcs[index] ?: return

if (!client.lock.canNpcInteract() || !client.lock.canItemInteract()) {
return
}

val movementType = message.movementType
val itemId = message.item
val itemSlot = message.slot

val item = client.inventory[itemSlot] ?: return

if (item.id != itemId) {
return
}

log(client, "Item on npc: movement=%d, item=%s, slot=%d, npc=%s, index=%d", movementType, item, itemSlot, npc, index)

if (movementType == 1 && world.privileges.isEligible(client.privilege, Privilege.ADMIN_POWER)) {
client.moveTo(world.findRandomTileAround(npc.tile, 1) ?: npc.tile)
}

client.closeInterfaceModal()
client.interruptQueues()
client.resetInteractions()

client.attr[INTERACTING_NPC_ATTR] = WeakReference(npc)
client.attr[INTERACTING_ITEM] = WeakReference(item)
client.attr[INTERACTING_ITEM_ID] = item.id
client.attr[INTERACTING_ITEM_SLOT] = itemSlot
client.executePlugin(PawnPathAction.itemUsePlugin)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package gg.rsmod.game.message.impl

import gg.rsmod.game.message.Message

/**
* @author Tom <rspsmods@gmail.com>
*/
data class OpNpcUMessage(val componentHash: Int, val npcIndex: Int, val item: Int, val slot: Int, val movementType: Int) : Message

0 comments on commit b303791

Please sign in to comment.