Skip to content

Commit

Permalink
Rename Pickup to Take, and add Taken events to remove overrides from …
Browse files Browse the repository at this point in the history
…FloorItemOption #582
  • Loading branch information
GregHib committed Jan 27, 2025
1 parent bafbaef commit 74f54db
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 74 deletions.
2 changes: 1 addition & 1 deletion data/definitions/sounds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ gate_close: 70
gate_open: 71
fell_tree: 2734
drop_item: 2739
pickup_item: 2582
take_item: 2582
prayer_drain: 2672
teleport: 200
teleport_land: 201
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,51 +25,51 @@ data class FloorItemOption<C : Character>(
}
}

fun floorItemOperate(option: String, item: String = "*", arrive: Boolean = true, override: Boolean = true, handler: suspend FloorItemOption<Player>.() -> Unit) {
Events.handle<FloorItemOption<Player>>("player_operate_floor_item", option, item, "player", override = override) {
fun floorItemOperate(option: String, item: String = "*", arrive: Boolean = true, handler: suspend FloorItemOption<Player>.() -> Unit) {
Events.handle<FloorItemOption<Player>>("player_operate_floor_item", option, item, "player") {
if (arrive) {
arriveDelay()
}
handler.invoke(this)
}
}

fun floorItemApproach(option: String, item: String = "*", override: Boolean = true, handler: suspend FloorItemOption<Player>.() -> Unit) {
Events.handle<FloorItemOption<Player>>("player_approach_floor_item", option, item, "player", override = override) {
fun floorItemApproach(option: String, item: String = "*", handler: suspend FloorItemOption<Player>.() -> Unit) {
Events.handle<FloorItemOption<Player>>("player_approach_floor_item", option, item, "player") {
handler.invoke(this)
}
}

fun npcOperateFloorItem(option: String, item: String = "*", npc: String = "*", arrive: Boolean = true, override: Boolean = true, handler: suspend FloorItemOption<NPC>.() -> Unit) {
Events.handle<FloorItemOption<NPC>>("npc_operate_floor_item", option, item, npc, override = override) {
fun npcOperateFloorItem(option: String, item: String = "*", npc: String = "*", arrive: Boolean = true, handler: suspend FloorItemOption<NPC>.() -> Unit) {
Events.handle<FloorItemOption<NPC>>("npc_operate_floor_item", option, item, npc) {
if (arrive) {
arriveDelay()
}
handler.invoke(this)
}
}

fun npcApproachFloorItem(option: String, item: String = "*", npc: String = "*", override: Boolean = true, handler: suspend FloorItemOption<NPC>.() -> Unit) {
Events.handle<FloorItemOption<NPC>>("npc_approach_floor_item", option, item, npc, override = override) {
fun npcApproachFloorItem(option: String, item: String = "*", npc: String = "*", handler: suspend FloorItemOption<NPC>.() -> Unit) {
Events.handle<FloorItemOption<NPC>>("npc_approach_floor_item", option, item, npc) {
handler.invoke(this)
}
}

fun characterOperateFloorItem(option: String, item: String = "*", arrive: Boolean = true, override: Boolean = true, block: suspend FloorItemOption<Character>.() -> Unit) {
fun characterOperateFloorItem(option: String, item: String = "*", arrive: Boolean = true, block: suspend FloorItemOption<Character>.() -> Unit) {
val handler: suspend FloorItemOption<Character>.(Character) -> Unit = {
if (arrive) {
arriveDelay()
}
block.invoke(this)
}
Events.handle("player_operate_floor_item", option, item, "player", override = override, handler = handler)
Events.handle("npc_operate_floor_item", option, item, "*", override = override, handler = handler)
Events.handle("player_operate_floor_item", option, item, "player", handler = handler)
Events.handle("npc_operate_floor_item", option, item, "*", handler = handler)
}

fun characterApproachFloorItem(option: String, item: String = "*", override: Boolean = true, block: suspend FloorItemOption<Character>.() -> Unit) {
fun characterApproachFloorItem(option: String, item: String = "*", block: suspend FloorItemOption<Character>.() -> Unit) {
val handler: suspend FloorItemOption<Character>.(Character) -> Unit = {
block.invoke(this)
}
Events.handle("player_approach_floor_item", option, item, "player", override = override, handler = handler)
Events.handle("npc_approach_floor_item", option, item, "*", override = override, handler = handler)
Events.handle("player_approach_floor_item", option, item, "player", handler = handler)
Events.handle("npc_approach_floor_item", option, item, "*", handler = handler)
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
package content.area.asgarnia.port_sarim

import content.entity.player.inv.item.take.canTake
import content.entity.player.inv.item.take.taken
import world.gregs.voidps.engine.client.message
import world.gregs.voidps.engine.entity.character.player.chat.inventoryFull
import world.gregs.voidps.engine.entity.item.floor.FloorItems
import world.gregs.voidps.engine.entity.item.floor.floorItemOperate
import world.gregs.voidps.engine.inject
import world.gregs.voidps.engine.inv.add
import world.gregs.voidps.engine.inv.holdsItem
import world.gregs.voidps.engine.inv.inventory
import content.entity.sound.playSound

val items: FloorItems by inject()

floorItemOperate("Take", "white_apron_port_sarim", override = false) {
canTake("white_apron_port_sarim") { player ->
if (player.holdsItem("white_apron")) {
player.message("You already have one of those.")
cancel()
} else if (player.inventory.isFull() && (!player.inventory.stackable(target.id) || !player.inventory.contains(target.id))) {
player.inventoryFull()
cancel()
} else {
player.anim("take")
player.playSound("pickup_item")
items.remove(target)
player.inventory.add("white_apron")
player.message("You take an apron. It feels freshly starched and smells of laundry.")
cancel()
}
item = "white_apron"
}

taken("white_apron_port_sarim") { player ->
player.anim("take")
player.message("You take an apron. It feels freshly starched and smells of laundry.")
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package content.area.misthalin.lumbridge.chicken_farm

import content.entity.player.bank.ownsItem
import content.entity.player.inv.item.take.canTake
import content.quest.questCompleted
import world.gregs.voidps.engine.client.message
import world.gregs.voidps.engine.entity.character.player.chat.inventoryFull
import world.gregs.voidps.engine.entity.item.floor.floorItemOperate
import world.gregs.voidps.engine.entity.obj.objectOperate
import world.gregs.voidps.engine.entity.obj.replace
import world.gregs.voidps.engine.inv.add
import world.gregs.voidps.engine.inv.holdsItem
import world.gregs.voidps.engine.inv.inventory
import world.gregs.voidps.engine.timer.toTicks
import content.entity.player.bank.bank
import content.quest.questCompleted
import java.util.concurrent.TimeUnit

objectOperate("Take-hatchet", "hatchet_logs") {
Expand All @@ -21,11 +20,11 @@ objectOperate("Take-hatchet", "hatchet_logs") {
}
}

floorItemOperate("Take", "super_large_egg", override = false) {
canTake("super_large_egg") { player ->
if (player.questCompleted("cooks_assistant")) {
player.message("You've no reason to pick that up; eggs of that size are only useful for royal cakes.")
cancel()
} else if (player.holdsItem("super_large_egg") || player.bank.contains("super_large_egg")) {
} else if (player.ownsItem("super_large_egg")) {
player.message("You've already got one of those eggs and one's enough.")
cancel()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package content.entity.player.inv.item
package content.entity.player.inv.item.take

import com.github.michaelbull.logging.InlineLogger
import world.gregs.voidps.engine.client.message
Expand All @@ -12,13 +12,20 @@ import world.gregs.voidps.engine.inv.transact.TransactionError
import world.gregs.voidps.engine.inv.transact.operation.AddItem.add
import world.gregs.voidps.engine.inv.transact.operation.SetCharge.setCharge
import content.entity.sound.playSound
import world.gregs.voidps.engine.entity.item.Item

val floorItems: FloorItems by inject()
val logger = InlineLogger()

floorItemOperate("Take") {
approachRange(-1)
if (player.inventory.isFull() && (!player.inventory.stackable(target.id) || !player.inventory.contains(target.id))) {
val takeable = Takeable(target.id)
player.emit(takeable)
if (takeable.cancelled) {
return@floorItemOperate
}
val item = takeable.item
if (player.inventory.isFull() && (!player.inventory.stackable(item) || !player.inventory.contains(item))) {
player.inventoryFull()
return@floorItemOperate
}
Expand All @@ -29,7 +36,7 @@ floorItemOperate("Take") {

player.inventory.transaction {
val freeIndex = inventory.freeIndex()
add(target.id, target.amount)
add(item, target.amount)
if (target.charges > 0) {
setCharge(freeIndex, target.charges)
}
Expand All @@ -40,16 +47,17 @@ floorItemOperate("Take") {
player.face(target.tile.delta(player.tile))
player.anim("take")
}
player.playSound("pickup_item")
player.playSound("take_item")
player.emit(Taken(target, item))
}
is TransactionError.Full -> player.inventoryFull()
else -> logger.warn { "Error picking up item $target ${player.inventory.transaction.error}" }
else -> logger.warn { "Error taking item $target ${player.inventory.transaction.error}" }
}
}

npcOperateFloorItem("Take") {
if (!floorItems.remove(target)) {
logger.warn { "$npc unable to pick up $target." }
logger.warn { "$npc unable to take $target." }
}
if (npc.id == "ash_cleaner") {
npc.anim("cleaner_sweeping")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package content.entity.player.inv.item.take

import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.event.CancellableEvent
import world.gregs.voidps.engine.event.EventDispatcher
import world.gregs.voidps.engine.event.Events

/**
* Checks that an item can be taken off of the floor. Continues unless [cancelled].
*/
data class Takeable(var item: String) : CancellableEvent() {

override val size = 2

override fun parameter(dispatcher: EventDispatcher, index: Int) = when (index) {
0 -> "can_take"
1 -> item
else -> null
}
}

fun canTake(vararg items: String = arrayOf("*"), handler: Takeable.(Player) -> Unit) {
for (item in items) {
Events.handle("can_take", item, handler = handler)
}
}
28 changes: 28 additions & 0 deletions game/src/main/kotlin/content/entity/player/inv/item/take/Taken.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package content.entity.player.inv.item.take

import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.entity.item.floor.FloorItem
import world.gregs.voidps.engine.event.CancellableEvent
import world.gregs.voidps.engine.event.EventDispatcher
import world.gregs.voidps.engine.event.Events

/**
* @param floorItem The item which was taken off of the floor
* @param item The item which was given to the player
*/
data class Taken(val floorItem: FloorItem, val item: String) : CancellableEvent() {

override val size = 2

override fun parameter(dispatcher: EventDispatcher, index: Int) = when (index) {
0 -> "taken"
1 -> floorItem.id
else -> null
}
}

fun taken(vararg items: String = arrayOf("*"), handler: Taken.(Player) -> Unit) {
for (item in items) {
Events.handle("taken", item, handler = handler)
}
}
27 changes: 0 additions & 27 deletions game/src/test/kotlin/content/entity/player/inv/DropTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,6 @@ internal class DropTest : WorldTest() {
assertTrue(floorItems[player.tile].any { it.id == "bronze_sword" })
}

@Test
fun `Pickup item off the floor`() {
val tile = emptyTile
val player = createPlayer("player", tile)
val item = floorItems.add(tile.add(0, 2), "bronze_sword")

player.floorItemOption(item, "Take")
tick(5)

assertTrue(player.inventory.contains("bronze_sword"))
assertTrue(floorItems[tile.add(0, 2)].isEmpty())
}

@Test
fun `Floor item respawns after delay`() {
val tile = Tile(3244, 3157)
Expand Down Expand Up @@ -105,18 +92,4 @@ internal class DropTest : WorldTest() {
assertFalse(floorItems[tile.addX(1)].any { it.id == "toolkit" })
}

@Test
fun `Pickup item up off a table`() {
val tile = Tile(3212, 3218, 1)
val player = createPlayer("player", tile)
val item = floorItems.add(tile.add(1, 0), "bronze_sword")

player.floorItemOption(item, "Take")
tick(5)

assertTrue(player.inventory.contains("bronze_sword"))
assertTrue(floorItems[tile.add(1, 0)].isEmpty())
assertEquals(tile, player.tile)
}

}
45 changes: 45 additions & 0 deletions game/src/test/kotlin/content/entity/player/inv/TakeTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package content.entity.player.inv

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import world.gregs.voidps.engine.entity.item.Item
import world.gregs.voidps.engine.inv.add
import world.gregs.voidps.engine.inv.inventory
import world.gregs.voidps.type.Tile
import WorldTest
import floorItemOption
import interfaceOption
import itemOnObject
import kotlin.test.assertFalse

internal class TakeTest : WorldTest() {

@Test
fun `Take item off the floor`() {
val tile = emptyTile
val player = createPlayer("player", tile)
val item = floorItems.add(tile.add(0, 2), "bronze_sword")

player.floorItemOption(item, "Take")
tick(5)

assertTrue(player.inventory.contains("bronze_sword"))
assertTrue(floorItems[tile.add(0, 2)].isEmpty())
}

@Test
fun `Take item up off a table`() {
val tile = Tile(3212, 3218, 1)
val player = createPlayer("player", tile)
val item = floorItems.add(tile.add(1, 0), "bronze_sword")

player.floorItemOption(item, "Take")
tick(5)

assertTrue(player.inventory.contains("bronze_sword"))
assertTrue(floorItems[tile.add(1, 0)].isEmpty())
assertEquals(tile, player.tile)
}

}

0 comments on commit 74f54db

Please sign in to comment.