Converted vinesweeper to new systems

This commit is contained in:
ceikry 2022-04-05 01:22:54 -05:00
parent 6553ed1e4c
commit 4557ac03de
5 changed files with 379 additions and 376 deletions

View file

@ -13,6 +13,6 @@ interface MapArea {
fun defineAreaBorders() : Array<ZoneBorders>
fun getRestrictions() : Array<ZoneRestriction> {return arrayOf()}
fun areaEnter(entity: Entity) {}
fun areaLeave(entity: Entity) {}
fun areaLeave(entity: Entity, logout: Boolean) {}
fun entityStep(entity: Entity, location: Location, lastLocation: Location) {}
}

View file

@ -1,3 +1,17 @@
package rs09.game.content.activity.vinesweeper
import BlinkinDialogue
import WinkinDialogue
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.DEAD_PLANT_OBJ
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.FARMERS
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.FARMER_CLEAR_RADIUS
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.HOLES
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.NUMBERS
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.RABBIT
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.SEED_LOCS
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.populateSeeds
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.scheduleNPCs
import rs09.game.content.activity.vinesweeper.Vinesweeper.Companion.sendUpdatedPoints
import api.*
import core.game.component.Component
import core.game.node.entity.Entity
@ -13,164 +27,52 @@ import core.game.node.scenery.SceneryBuilder
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.map.RegionManager
import core.game.world.map.zone.MapZone
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneBuilder
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import core.plugin.Initializable
import core.tools.RandomFunction
import org.rs09.consts.Components
import org.rs09.consts.Items
import rs09.game.content.dialogue.DialogueFile
import rs09.game.interaction.InteractionListener
import rs09.game.interaction.InterfaceListener
import rs09.game.world.GameWorld;
val AVACH_NIMPORTO_LOC = Location.create(1637, 4709)
val PORTAL = 29534
val SIGNS = intArrayOf(29461, 29462, 29463, 29464)
val HOLES = intArrayOf(29476, 29477, 29478)
val NUMBERS = intArrayOf(29447, 29448, 29449, 29450, 29451, 29452, 29453, 29454, 29455)
val DEAD_PLANT_OBJ = 29456
val FLAG_OBJ = 29457
class Vinesweeper : InteractionListener, InterfaceListener, MapArea {
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(getRegionBorders(6473))
}
val TUTORIAL = 685
override fun areaEnter(entity: Entity) {
if(entity is Player)
{
openOverlay(entity, Components.RABBIT_OVERLAY_689)
sendUpdatedPoints(entity)
}
}
val INSTRUCTION_SIGNS = hashMapOf(
29463 to 684,
29464 to 687,
29462 to 688,
29461 to 690
)
override fun areaLeave(entity: Entity, logout: Boolean) {
if(entity is Player) {
entity.interfaceManager.closeOverlay()
if(!logout) {
entity.sendMessage("Winkin's Farm thanks you for your visit.")
entity.sendMessage("Leftover ogleroots and flags have been returned to the establishment.")
entity.sendMessage("You have been reimbursed at a rate of 10gp per ogleroot and the flags have been collected.")
val flags = entity.inventory.getAmount(Item(Items.FLAG_12625))
if(flags > 0) {
entity.setAttribute("/save:vinesweeper:stored-flags", flags)
entity.inventory.remove(Item(Items.FLAG_12625, flags))
}
val roots = entity.inventory.getAmount(Item(Items.OGLEROOT_12624))
if(roots > 0) {
entity.inventory.remove(Item(Items.OGLEROOT_12624, roots))
entity.inventory.add(Item(Items.COINS_995, roots * 10))
}
}
}
}
val RABBIT = 7125
val FARMERS = intArrayOf(7128, 7129, 7130)
val FARMER_BLINKIN = 7131
val MRS_WINKIN = 7132
val MAX_SEEDS = 300
val FARMER_CLEAR_RADIUS = 3
val VINESWEEPER_BORDERS = ZoneBorders(1600,4672,1663,4735)
fun sendUpdatedPoints(player: Player) {
val points = player.getAttribute("vinesweeper:points", 0);
player.varpManager.get(1195).setVarbit(6, points).send(player)
}
data class SeedDestination(val player: Player, val loc: Location, val alive: Boolean) {
override fun equals(other: Any?): Boolean {
if(other is SeedDestination) {
return loc.equals(other.loc)
} else {
return false
}
}
}
var SEED_LOCS: HashSet<Location> = HashSet()
fun isSeed(loc: Location): Boolean {
val scenery = getScenery(loc)
return scenery != null && SEED_LOCS.contains(scenery.location)
}
fun populateSeeds() {
while(SEED_LOCS.size < MAX_SEEDS) {
val loc = VINESWEEPER_BORDERS.getRandomLoc()
val scenery = getScenery(loc)
if(scenery != null && HOLES.contains(scenery.id)) {
SEED_LOCS.add(loc)
}
}
}
fun isHole(loc: Location): Boolean {
val scenery = getScenery(loc)
return scenery != null && HOLES.contains(scenery.id)
}
fun scheduleNPCs(player: Player, loc: Location, alive: Boolean, rabbit: Boolean) {
val dest = SeedDestination(player, loc, alive)
val ids = if(rabbit) { intArrayOf(RABBIT, *FARMERS) } else { FARMERS }
for(npc in findLocalNPCs(player, ids, 30)) {
if(npc is VinesweeperNPC) {
npc.seedDestinations.add(dest)
npc.resetWalk()
}
}
}
object VinesweeperTeleport {
@JvmStatic
fun teleport(npc: NPC, player: Player) {
npc.animate(Animation(437))
npc.faceTemporary(player, 1)
npc.graphics(Graphics(108))
player.lock()
player.audioManager.send(125)
Projectile.create(npc, player, 109).send()
npc.sendChat("Avach nimporto!")
GameWorld.Pulser.submit(object : Pulse(1) {
var counter = 0
override fun pulse(): Boolean {
when (counter++) {
2 -> {
player.savedData.globalData.essenceTeleporter = npc.id
player.setAttribute("/save:vinesweeper:return-tele:x", npc.location.x)
player.setAttribute("/save:vinesweeper:return-tele:y", npc.location.y)
player.properties.teleportLocation = AVACH_NIMPORTO_LOC
}
3 -> {
player.graphics(Graphics(110))
player.unlock()
return true
}
}
return false
}
})
}
}
class VinesweeperListener : InteractionListener {
fun dig(player: Player, loc: Location) {
if(isSeed(loc)) {
val oldPoints = player.getAttribute("vinesweeper:points", 0)
player.setAttribute("/save:vinesweeper:points", Math.max(oldPoints-10, 0))
sendUpdatedPoints(player)
player.sendMessage("Oh dear! It looks like you dug up a potato seed by mistake.");
scheduleNPCs(player, loc, false, false)
val scenery = getScenery(loc)
if(scenery != null) {
SceneryBuilder.replace(scenery, scenery.transform(DEAD_PLANT_OBJ))
}
} else {
player.incrementAttribute("/save:vinesweeper:points", 1)
sendUpdatedPoints(player)
var count = 0
for(dx in -1..1) {
for(dy in -1..1) {
if(isSeed(loc.transform(dx, dy, 0))) {
count += 1
}
}
}
val scenery = getScenery(loc)
if(scenery != null) {
SceneryBuilder.replace(scenery, scenery.transform(NUMBERS[count]))
}
if(count == 0) {
for(dx in -1..1) {
for(dy in -1..1) {
val newLoc = loc.transform(dx, dy, 0)
if(isHole(newLoc))
dig(player, newLoc)
}
}
}
}
}
override fun defineListeners() {
ZoneBuilder.configure(VinesweeperZone())
populateSeeds()
on(PORTAL, SCENERY, "enter") { player, _ ->
val x = player.getAttribute("vinesweeper:return-tele:x", 3052)
@ -280,166 +182,85 @@ class VinesweeperListener : InteractionListener {
return@on true
}
}
}
@Initializable
class VinesweeperNPC : AbstractNPC {
fun compareDistance(a: SeedDestination, b: SeedDestination): Int {
val da = a.loc.getDistance(location).toInt()
val db = b.loc.getDistance(location).toInt()
return db - da
override fun defineInterfaceListeners() {
on(IFACE) { player, _, opcode, buttonID, _, _ ->
when(opcode) {
Opcode.VALUE.value -> {
when(buttonID) {
TRADE_FOR_XP_BUTTON -> {
player.packetDispatch.sendInterfaceConfig(686, 60, false)
}
XP_CONFIRM -> {
player.packetDispatch.sendInterfaceConfig(686, 60, true)
val level = player.skills.getStaticLevel(Skills.FARMING)
// TODO: more precise formula
val points_per_xp = if (level < 40) { 2.0*(40.0 - level.toDouble())/10.0 } else { 1.0 }
val points = player.getAttribute("vinesweeper:points", 0)
val xp = points / points_per_xp;
player.skills.addExperience(Skills.FARMING, xp)
player.setAttribute("/save:vinesweeper:points", 0)
sendUpdatedPoints(player)
}
XP_DENY -> {
player.packetDispatch.sendInterfaceConfig(686, 60, true)
}
else -> {
val reward = REWARDS[buttonID] ?: return@on true
player.sendMessage("${Item(reward.itemID).name}: ${reward.points} vinesweeper points")
}
}
}
Opcode.BUY1.value -> {
buy(player, buttonID, 1)
return@on true
}
Opcode.BUY5.value -> {
buy(player, buttonID, 5)
return@on true
}
Opcode.BUY10.value -> {
buy(player, buttonID, 10)
return@on true
}
Opcode.BUYX.value -> {
player.setAttribute("runscript") { amount: Int ->
buy(player, buttonID, amount)
}
player.dialogueInterpreter.sendInput(false, "Enter the amount:")
return@on true
}
else -> {}
}
return@on true
}
var seedDestinations: ArrayList<SeedDestination> = ArrayList();
constructor() : super(RABBIT, null, true) {}
private constructor(id: Int, location: Location) : super(id, location) {}
override fun construct(id: Int, location: Location, vararg objects: Any?): AbstractNPC {
return VinesweeperNPC(id, location)
}
init {
walkRadius = 22
}
override fun getIds(): IntArray {
return intArrayOf(RABBIT, *FARMERS)
}
override fun handleTickActions() {
val dest = seedDestinations.find { sd -> sd.loc == location }
if(dest != null) {
for(npc in RegionManager.getRegionPlane(location).npcs) {
if(npc is VinesweeperNPC) {
npc.seedDestinations.remove(dest)
npc.resetWalk()
}
}
val scenery = getScenery(dest.loc)
if(scenery != null) {
if(id == RABBIT) {
val replacement = if(SEED_LOCS.contains(dest.loc)) { DEAD_PLANT_OBJ } else { HOLES[0] }
SceneryBuilder.replace(scenery, scenery.transform(replacement))
scheduleNPCs(dest.player, dest.loc, false, false)
data class SeedDestination(val player: Player, val loc: Location, val alive: Boolean) {
override fun equals(other: Any?): Boolean {
return if(other is SeedDestination) {
loc == other.loc
} else {
if(dest.alive) {
handleFarmerFlag(scenery, dest)
} else {
sendChat("Hmm. Looks like there's a plant here.")
lock(3)
GameWorld.Pulser.submit(object : Pulse(3) {
override fun pulse(): Boolean {
sendChat("Gracious me! This one's dead")
SceneryBuilder.replace(scenery, scenery.transform(HOLES[0]))
farmerClear(dest)
return true
}
})
}
}
}
seedDestinations.remove(dest)
}
super.handleTickActions()
}
override fun getMovementDestination(): Location? {
if(seedDestinations.size > 0) {
seedDestinations.sortBy { a -> a.loc.getDistance(location).toInt() }
return seedDestinations.first().loc
} else {
return super.getMovementDestination()
false
}
}
fun handleFarmerFlag(scenery: Scenery, dest: SeedDestination) {
sendChat("Ah, another flag to clear. Let's see what's there.")
lock(3)
animate(Animation(451))
if(SEED_LOCS.contains(dest.loc)) {
val npc = this
GameWorld.Pulser.submit(object : Pulse(3) {
override fun pulse(): Boolean {
sendChat("Ah! A seed. Points for everyone near me!")
val level = dest.player.skills.getStaticLevel(Skills.FARMING)
val points = RandomFunction.random(level, 4 * level)
dest.player.incrementAttribute("/save:vinesweeper:points", points)
dest.player.inventory.add(Item(Items.FLAG_12625, 1))
sendUpdatedPoints(dest.player)
for(neighbor in RegionManager.getLocalPlayers(npc)) {
if(neighbor != dest.player) {
neighbor.incrementAttribute("/save:vinesweeper:points", points / 2)
sendUpdatedPoints(neighbor)
}
}
SceneryBuilder.replace(scenery, scenery.transform(HOLES[0]))
farmerClear(dest)
return true
}
})
} else {
SceneryBuilder.replace(scenery, scenery.transform(HOLES[0]))
var i = 0
val lines = arrayOf("Hmm, no seeds planted here, I'm afraid.", "I'll have to keep this 'ere flag. Sorry.")
GameWorld.Pulser.submit(object : Pulse(3) {
override fun pulse(): Boolean {
sendChat(lines[i++])
return i >= lines.size
}
})
}
}
fun farmerClear(dest: SeedDestination) {
for(dx in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) {
for(dy in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) {
val toClear = getScenery(dest.loc.transform(dx, dy, 0))
if(toClear != null && intArrayOf(DEAD_PLANT_OBJ, *NUMBERS).contains(toClear.id)) {
SceneryBuilder.replace(toClear, toClear.transform(HOLES[0]))
}
}
}
SEED_LOCS.remove(dest.loc)
populateSeeds()
}
}
class VinesweeperZone : MapZone("Vinesweeper", true) {
override fun enter(e: Entity): Boolean {
if(e is Player) {
e.interfaceManager.openOverlay(Component(689))
sendUpdatedPoints(e)
}
return super.enter(e)
}
override fun leave(e: Entity, logout: Boolean): Boolean {
if(e is Player) {
e.interfaceManager.closeOverlay()
if(!logout) {
e.sendMessage("Winkin's Farm thanks you for your visit.")
e.sendMessage("Leftover ogleroots and flags have been returned to the establishment.")
e.sendMessage("You have been reimbursed at a rate of 10gp per ogleroot and the flags have been collected.")
val flags = e.inventory.getAmount(Item(Items.FLAG_12625))
if(flags > 0) {
e.setAttribute("/save:vinesweeper:stored-flags", flags)
e.inventory.remove(Item(Items.FLAG_12625, flags))
}
val roots = e.inventory.getAmount(Item(Items.OGLEROOT_12624))
if(roots > 0) {
e.inventory.remove(Item(Items.OGLEROOT_12624, roots))
e.inventory.add(Item(Items.COINS_995, roots * 10))
}
override fun hashCode(): Int {
return loc.hashCode()
}
}
return super.leave(e, logout)
}
companion object
{
val AVACH_NIMPORTO_LOC = Location.create(1637, 4709)
val PORTAL = 29534
val SIGNS = intArrayOf(29461, 29462, 29463, 29464)
val HOLES = intArrayOf(29476, 29477, 29478)
val NUMBERS = intArrayOf(29447, 29448, 29449, 29450, 29451, 29452, 29453, 29454, 29455)
val DEAD_PLANT_OBJ = 29456
val FLAG_OBJ = 29457
override fun configure() {
super.registerRegion(6473)
}
}
class VinesweeperRewards : InterfaceListener {
val IFACE = 686
val TRADE_FOR_XP_BUTTON = 53
val XP_CONFIRM = 72
@ -506,66 +327,247 @@ class VinesweeperRewards : InterfaceListener {
}
}
override fun defineInterfaceListeners() {
onOpen(IFACE) { _, _ ->
/*for((buttonID, reward) in REWARDS) {
sendItemOnInterface(player, IFACE, buttonID, reward.itemID, 5)
}*/
//player.packetDispatch.sendRunScript(2003, "")
return@onOpen true
}
on(IFACE) { player, _, opcode, buttonID, _, _ ->
when(opcode) {
Opcode.VALUE.value -> {
when(buttonID) {
TRADE_FOR_XP_BUTTON -> {
player.packetDispatch.sendInterfaceConfig(686, 60, false)
}
XP_CONFIRM -> {
player.packetDispatch.sendInterfaceConfig(686, 60, true)
val level = player.skills.getStaticLevel(Skills.FARMING)
// TODO: more precise formula
val points_per_xp = if (level < 40) { 2.0*(40.0 - level.toDouble())/10.0 } else { 1.0 }
val points = player.getAttribute("vinesweeper:points", 0)
val xp = points / points_per_xp;
player.skills.addExperience(Skills.FARMING, xp)
player.setAttribute("/save:vinesweeper:points", 0)
sendUpdatedPoints(player)
val TUTORIAL = 685
val INSTRUCTION_SIGNS = hashMapOf(
29463 to 684,
29464 to 687,
29462 to 688,
29461 to 690
)
val RABBIT = 7125
val FARMERS = intArrayOf(7128, 7129, 7130)
val FARMER_BLINKIN = 7131
val MRS_WINKIN = 7132
val MAX_SEEDS = 300
val FARMER_CLEAR_RADIUS = 3
val VINESWEEPER_BORDERS = ZoneBorders(1600,4672,1663,4735)
fun sendUpdatedPoints(player: Player) {
val points = player.getAttribute("vinesweeper:points", 0);
player.varpManager.get(1195).setVarbit(6, points).send(player)
}
XP_DENY -> {
player.packetDispatch.sendInterfaceConfig(686, 60, true)
var SEED_LOCS: HashSet<Location> = HashSet()
fun isSeed(loc: Location): Boolean {
val scenery = getScenery(loc)
return scenery != null && SEED_LOCS.contains(scenery.location)
}
else -> {
val reward = REWARDS[buttonID] ?: return@on true
player.sendMessage("${Item(reward.itemID).name}: ${reward.points} vinesweeper points")
fun populateSeeds() {
while(SEED_LOCS.size < MAX_SEEDS) {
val loc = VINESWEEPER_BORDERS.getRandomLoc()
val scenery = getScenery(loc)
if(scenery != null && HOLES.contains(scenery.id)) {
SEED_LOCS.add(loc)
}
}
}
Opcode.BUY1.value -> {
buy(player, buttonID, 1)
return@on true
fun dig(player: Player, loc: Location) {
if(isSeed(loc)) {
val oldPoints = player.getAttribute("vinesweeper:points", 0)
player.setAttribute("/save:vinesweeper:points", Math.max(oldPoints-10, 0))
sendUpdatedPoints(player)
player.sendMessage("Oh dear! It looks like you dug up a potato seed by mistake.");
scheduleNPCs(player, loc, false, false)
val scenery = getScenery(loc)
if(scenery != null) {
SceneryBuilder.replace(scenery, scenery.transform(DEAD_PLANT_OBJ))
}
Opcode.BUY5.value -> {
buy(player, buttonID, 5)
return@on true
} else {
player.incrementAttribute("/save:vinesweeper:points", 1)
sendUpdatedPoints(player)
var count = 0
for(dx in -1..1) {
for(dy in -1..1) {
if(isSeed(loc.transform(dx, dy, 0))) {
count += 1
}
Opcode.BUY10.value -> {
buy(player, buttonID, 10)
return@on true
}
Opcode.BUYX.value -> {
player.setAttribute("runscript") { amount: Int ->
buy(player, buttonID, amount)
}
player.dialogueInterpreter.sendInput(false, "Enter the amount:")
return@on true
val scenery = getScenery(loc)
if(scenery != null) {
SceneryBuilder.replace(scenery, scenery.transform(NUMBERS[count]))
}
else -> {}
if(count == 0) {
for(dx in -1..1) {
for(dy in -1..1) {
val newLoc = loc.transform(dx, dy, 0)
if(isHole(newLoc))
dig(player, newLoc)
}
return@on true
}
}
}
}
fun isHole(loc: Location): Boolean {
val scenery = getScenery(loc)
return scenery != null && HOLES.contains(scenery.id)
}
fun scheduleNPCs(player: Player, loc: Location, alive: Boolean, rabbit: Boolean) {
val dest = SeedDestination(player, loc, alive)
val ids = if(rabbit) { intArrayOf(RABBIT, *FARMERS) } else { FARMERS }
for(npc in findLocalNPCs(player, ids, 30)) {
if(npc is VinesweeperNPC) {
npc.seedDestinations.add(dest)
npc.resetWalk()
}
}
}
object VinesweeperTeleport {
@JvmStatic
fun teleport(npc: NPC, player: Player) {
npc.animate(Animation(437))
npc.faceTemporary(player, 1)
npc.graphics(Graphics(108))
player.lock()
player.audioManager.send(125)
Projectile.create(npc, player, 109).send()
npc.sendChat("Avach nimporto!")
GameWorld.Pulser.submit(object : Pulse(1) {
var counter = 0
override fun pulse(): Boolean {
when (counter++) {
2 -> {
player.savedData.globalData.essenceTeleporter = npc.id
player.setAttribute("/save:vinesweeper:return-tele:x", npc.location.x)
player.setAttribute("/save:vinesweeper:return-tele:y", npc.location.y)
player.properties.teleportLocation = AVACH_NIMPORTO_LOC
}
3 -> {
player.graphics(Graphics(110))
player.unlock()
return true
}
}
return false
}
})
}
}
}
}
@Initializable
class VinesweeperNPC : AbstractNPC {
var seedDestinations: ArrayList<Vinesweeper.SeedDestination> = ArrayList();
constructor() : super(RABBIT, null, true) {}
private constructor(id: Int, location: Location) : super(id, location) {}
override fun construct(id: Int, location: Location, vararg objects: Any?): AbstractNPC {
return VinesweeperNPC(id, location)
}
init {
walkRadius = 22
}
override fun getIds(): IntArray {
return intArrayOf(RABBIT, *FARMERS)
}
override fun handleTickActions() {
val dest = seedDestinations.find { sd -> sd.loc == location }
if(dest != null) {
for(npc in RegionManager.getRegionPlane(location).npcs) {
if(npc is VinesweeperNPC) {
npc.seedDestinations.remove(dest)
npc.resetWalk()
}
}
val scenery = getScenery(dest.loc)
if(scenery != null) {
if(id == RABBIT) {
val replacement = if(SEED_LOCS.contains(dest.loc)) { DEAD_PLANT_OBJ } else { HOLES[0] }
SceneryBuilder.replace(scenery, scenery.transform(replacement))
scheduleNPCs(dest.player, dest.loc, alive = false, rabbit = false)
} else {
if(dest.alive) {
handleFarmerFlag(scenery, dest)
} else {
sendChat("Hmm. Looks like there's a plant here.")
lock(3)
GameWorld.Pulser.submit(object : Pulse(3) {
override fun pulse(): Boolean {
sendChat("Gracious me! This one's dead")
SceneryBuilder.replace(scenery, scenery.transform(HOLES[0]))
farmerClear(dest)
return true
}
})
}
}
}
seedDestinations.remove(dest)
}
super.handleTickActions()
}
override fun getMovementDestination(): Location? {
if(seedDestinations.size > 0) {
seedDestinations.sortBy { a -> a.loc.getDistance(location).toInt() }
return seedDestinations.first().loc
} else {
return super.getMovementDestination()
}
}
fun handleFarmerFlag(scenery: Scenery, dest: Vinesweeper.SeedDestination) {
sendChat("Ah, another flag to clear. Let's see what's there.")
lock(3)
animate(Animation(451))
if(SEED_LOCS.contains(dest.loc)) {
val npc = this
GameWorld.Pulser.submit(object : Pulse(3) {
override fun pulse(): Boolean {
sendChat("Ah! A seed. Points for everyone near me!")
val level = dest.player.skills.getStaticLevel(Skills.FARMING)
val points = RandomFunction.random(level, 4 * level)
dest.player.incrementAttribute("/save:vinesweeper:points", points)
dest.player.inventory.add(Item(Items.FLAG_12625, 1))
sendUpdatedPoints(dest.player)
for(neighbor in RegionManager.getLocalPlayers(npc)) {
if(neighbor != dest.player) {
neighbor.incrementAttribute("/save:vinesweeper:points", points / 2)
sendUpdatedPoints(neighbor)
}
}
SceneryBuilder.replace(scenery, scenery.transform(HOLES[0]))
farmerClear(dest)
return true
}
})
} else {
SceneryBuilder.replace(scenery, scenery.transform(HOLES[0]))
var i = 0
val lines = arrayOf("Hmm, no seeds planted here, I'm afraid.", "I'll have to keep this 'ere flag. Sorry.")
GameWorld.Pulser.submit(object : Pulse(3) {
override fun pulse(): Boolean {
sendChat(lines[i++])
return i >= lines.size
}
})
}
}
fun farmerClear(dest: Vinesweeper.SeedDestination) {
for(dx in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) {
for(dy in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) {
val toClear = getScenery(dest.loc.transform(dx, dy, 0))
if(toClear != null && intArrayOf(DEAD_PLANT_OBJ, *NUMBERS).contains(toClear.id)) {
SceneryBuilder.replace(toClear, toClear.transform(HOLES[0]))
}
}
}
SEED_LOCS.remove(dest.loc)
populateSeeds()
}
}

View file

@ -27,7 +27,7 @@ class FarmingPatchZone : MapArea, TickListener {
}
}
override fun areaLeave(entity: Entity) {
override fun areaLeave(entity: Entity, logout: Boolean) {
if(entity is Player)
playersInZone.remove(entity)
}

View file

@ -11,6 +11,7 @@ import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Components
import org.rs09.consts.NPCs
import rs09.game.content.activity.vinesweeper.Vinesweeper
val TL_IDS = arrayOf(NPCs.TOOL_LEPRECHAUN_3021,NPCs.GOTH_LEPRECHAUN_8000,NPCs.TOOL_LEPRECHAUN_4965,NPCs.TECLYN_2861)
@Initializable
@ -28,7 +29,7 @@ class ToolLeprechaunHandler : OptionHandler() {
node ?: return false
when(option){
"exchange" -> player?.interfaceManager?.open(Component(Components.FARMING_TOOLS_125))
"teleport" -> VinesweeperTeleport.teleport(node!! as NPC, player!!)
"teleport" -> Vinesweeper.Companion.VinesweeperTeleport.teleport(node!! as NPC, player!!)
}
return true
}

View file

@ -101,7 +101,7 @@ object ClassScanner {
}
override fun leave(e: Entity?, logout: Boolean): Boolean {
clazz.areaLeave(e ?: return super.leave(null, logout))
clazz.areaLeave(e ?: return super.leave(null, logout), logout)
return super.leave(e, logout)
}