Repository reorganisation
Unified kotlin and java into just src/main Unified the rs09 and core packages Took all content out of the core package, and placed it into the new content package Reorganised all source code relating to content to be easier to find and explore
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import org.rs09.consts.Items
|
||||
|
||||
/**
|
||||
* I don't want to do it this way but jagex has forced my hand
|
||||
*/
|
||||
enum class BasketsAndSacks(val produceID: Int, val baseContainer: Int, val capacity : Int) {
|
||||
POTATO(Items.POTATO_1942, Items.POTATOES1_5420, 10),
|
||||
ONION(Items.ONION_1957, Items.ONIONS1_5440, 10),
|
||||
CABBAGE(Items.CABBAGE_1965, Items.CABBAGES1_5460, 10),
|
||||
APPLE(Items.COOKING_APPLE_1955, Items.APPLES1_5378, 5),
|
||||
BANANA(Items.BANANA_1963, Items.BANANAS1_5408, 5),
|
||||
ORANGE(Items.ORANGE_2108, Items.ORANGES1_5388, 5),
|
||||
STRAWBERRY(Items.STRAWBERRY_5504, Items.STRAWBERRIES1_5398, 5),
|
||||
TOMATO(Items.TOMATO_1982, Items.TOMATOES1_5960, 5);
|
||||
|
||||
val containers = ArrayList<Int>()
|
||||
|
||||
companion object{
|
||||
private val map = HashMap<Int,BasketsAndSacks>()
|
||||
|
||||
init {
|
||||
values().map { it.produceID to it }.toMap(map)
|
||||
for(b in values()){
|
||||
b.containers.add(b.baseContainer)
|
||||
for(i in 1 until b.capacity){
|
||||
map[b.baseContainer + (i * 2)] = b
|
||||
b.containers.add(b.baseContainer + (i * 2))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun forId(itemId: Int): BasketsAndSacks?{
|
||||
return map[itemId]
|
||||
}
|
||||
}
|
||||
|
||||
fun checkIsLast(containerID: Int): Boolean {
|
||||
return containerID == containers.last()
|
||||
}
|
||||
|
||||
fun checkIsFirst(containerID: Int): Boolean {
|
||||
return containerID == containers.first()
|
||||
}
|
||||
|
||||
fun checkWhich(containerID: Int): Int{
|
||||
return containers.indexOf(containerID)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.*
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.audio.Audio
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.tools.RandomFunction
|
||||
import org.json.simple.JSONArray
|
||||
import org.json.simple.JSONObject
|
||||
import org.rs09.consts.Items
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class CompostBin(val player: Player, val bin: CompostBins) {
|
||||
private var items = ArrayList<Int>()
|
||||
var isSuperCompost = true
|
||||
var isTomatoes = true
|
||||
var isClosed = false
|
||||
var finishedTime = 0L
|
||||
var isFinished = false
|
||||
|
||||
fun isFull() : Boolean {
|
||||
return items.size == 15
|
||||
}
|
||||
|
||||
fun close() {
|
||||
isClosed = true
|
||||
player.audioManager.send(2428)
|
||||
finishedTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(RandomFunction.random(35,50).toLong())
|
||||
updateBit()
|
||||
}
|
||||
|
||||
fun open(){
|
||||
isClosed = false
|
||||
player.audioManager.send(2429)
|
||||
updateBit()
|
||||
}
|
||||
|
||||
fun takeItem(): Item?{
|
||||
if(items.isEmpty()) return null
|
||||
val item = items[0]
|
||||
items.remove(item)
|
||||
if(items.isEmpty()){
|
||||
isFinished = false
|
||||
finishedTime = 0L
|
||||
isTomatoes = true
|
||||
isSuperCompost = true
|
||||
isClosed = false
|
||||
}
|
||||
player.audioManager.send(Audio (2443, 1, 1))
|
||||
updateBit()
|
||||
if(isSuperCompost) rewardXP(player, Skills.FARMING, 8.5)
|
||||
else rewardXP(player, Skills.FARMING, 4.5)
|
||||
return Item(item)
|
||||
}
|
||||
|
||||
fun isReady(): Boolean {
|
||||
return System.currentTimeMillis() > finishedTime && finishedTime != 0L
|
||||
}
|
||||
|
||||
fun checkSuperCompostItem(id: Int): Boolean{
|
||||
return when (id){
|
||||
Items.WATERMELON_5982,
|
||||
Items.PINEAPPLE_2114,
|
||||
Items.CALQUAT_FRUIT_5980,
|
||||
Items.OAK_ROOTS_6043,
|
||||
Items.WILLOW_ROOTS_6045,
|
||||
Items.MAPLE_ROOTS_6047,
|
||||
Items.YEW_ROOTS_6049,
|
||||
Items.MAGIC_ROOTS_6051,
|
||||
Items.COCONUT_5974,
|
||||
Items.COCONUT_SHELL_5978,
|
||||
Items.PAPAYA_FRUIT_5972,
|
||||
Items.JANGERBERRIES_247,
|
||||
Items.WHITE_BERRIES_239,
|
||||
Items.POISON_IVY_BERRIES_6018,
|
||||
Items.CLEAN_TOADFLAX_2998,
|
||||
Items.CLEAN_AVANTOE_261,
|
||||
Items.CLEAN_KWUARM_263,
|
||||
Items.CLEAN_CADANTINE_265,
|
||||
Items.CLEAN_DWARF_WEED_267,
|
||||
Items.CLEAN_TORSTOL_269,
|
||||
Items.CLEAN_LANTADYME_2481,
|
||||
Items.CLEAN_SNAPDRAGON_3000,
|
||||
Items.GRIMY_TOADFLAX_3049,
|
||||
Items.GRIMY_KWUARM_213,
|
||||
Items.GRIMY_AVANTOE_211,
|
||||
Items.GRIMY_TORSTOL_219,
|
||||
Items.GRIMY_DWARF_WEED_217,
|
||||
Items.GRIMY_LANTADYME_2485,
|
||||
Items.GRIMY_SNAPDRAGON_3051,
|
||||
Items.GRIMY_CADANTINE_215 -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun addItem(item: Int){
|
||||
if(!isFull()) {
|
||||
items.add(item)
|
||||
if (!checkSuperCompostItem(item)) {
|
||||
isSuperCompost = false
|
||||
}
|
||||
if(item != Items.TOMATO_1982) isTomatoes = false
|
||||
}
|
||||
updateBit()
|
||||
}
|
||||
|
||||
fun addItem(item: Item){
|
||||
val remaining = 15 - items.size
|
||||
val amount = if(item.amount > remaining){
|
||||
remaining
|
||||
} else item.amount
|
||||
for(i in 0 until amount) {
|
||||
|
||||
player.audioManager.send(2441)
|
||||
addItem(item.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateBit(){
|
||||
player.varpManager.get(bin.varpIndex).clearBitRange(bin.varpOffest,bin.varpOffest + 7)
|
||||
if(items.isNotEmpty()) {
|
||||
if (isFinished) {
|
||||
player.varpManager.get(bin.varpIndex).setVarbit(bin.varpOffest + 1, if(items.size == 15) 15 else 14)
|
||||
if (isTomatoes) player.varpManager.get(bin.varpIndex).setVarbit(bin.varpOffest + 7, 1)
|
||||
else if (isSuperCompost) player.varpManager.get(bin.varpIndex).setVarbit(bin.varpOffest + 5, 1)
|
||||
} else {
|
||||
player.varpManager.get(bin.varpIndex).setVarbit(bin.varpOffest, items.size)
|
||||
if (isTomatoes) player.varpManager.get(bin.varpIndex).setVarbit(bin.varpOffest + 7, 1)
|
||||
}
|
||||
if (isClosed) player.varpManager.get(bin.varpIndex).setVarbit(bin.varpOffest + 6, 1)
|
||||
}
|
||||
player.varpManager.get(bin.varpIndex).send(player)
|
||||
}
|
||||
|
||||
fun save(root: JSONObject){
|
||||
val binObject = JSONObject()
|
||||
binObject.put("isSuper",this.isSuperCompost)
|
||||
val items = JSONArray()
|
||||
for(id in this.items){
|
||||
items.add(id)
|
||||
}
|
||||
binObject.put("items",items)
|
||||
binObject.put("finishTime",finishedTime)
|
||||
binObject.put("isTomato",isTomatoes)
|
||||
binObject.put("isClosed",isClosed)
|
||||
binObject.put("isFinished",isFinished)
|
||||
root.put("binData",binObject)
|
||||
}
|
||||
|
||||
fun parse(_data: JSONObject){
|
||||
val isSuper = if(_data.containsKey("isSuper")) (_data["isSuper"] as Boolean) else true
|
||||
if(_data.containsKey("items")){
|
||||
(_data["items"] as JSONArray).forEach {
|
||||
addItem(it.toString().toInt())
|
||||
}
|
||||
}
|
||||
if(_data.containsKey("finishTime")) finishedTime = _data["finishTime"].toString().toLong()
|
||||
if(_data.containsKey("isTomato")) isTomatoes = _data["isTomato"] as Boolean
|
||||
if(_data.containsKey("isClosed")) isClosed = _data["isClosed"] as Boolean
|
||||
if(_data.containsKey("isFinished")) isFinished = _data["isFinished"] as Boolean
|
||||
updateBit()
|
||||
}
|
||||
|
||||
fun finish(){
|
||||
if(isTomatoes) items = items.map { Items.ROTTEN_TOMATO_2518 } as ArrayList<Int>
|
||||
else if(isSuperCompost) items = items.map { Items.SUPERCOMPOST_6034 } as ArrayList<Int>
|
||||
else items = items.map { Items.COMPOST_6032 } as ArrayList<Int>
|
||||
isFinished = true
|
||||
}
|
||||
|
||||
fun convert(){
|
||||
if(!isSuperCompost){
|
||||
items = items.map { Items.SUPERCOMPOST_6034 } as ArrayList<Int>
|
||||
isSuperCompost = true
|
||||
updateBit()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.game.interaction.OptionHandler
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
|
||||
@Initializable
|
||||
class CompostBinOptionHandler : OptionHandler() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
for(i in 7836..7839)
|
||||
SceneryDefinition.forId(i).childrenIds.forEach {
|
||||
val def = SceneryDefinition.forId(it)
|
||||
def.handlers["option:open"] = this
|
||||
def.handlers["option:close"] = this
|
||||
def.handlers["option:take-tomato"] = this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
player ?: return false
|
||||
node ?: return false
|
||||
val cBin = CompostBins.forObject(node.asScenery()) ?: return false
|
||||
val bin = cBin.getBinForPlayer(player)
|
||||
|
||||
when(option){
|
||||
"close" -> if(!bin.isFull()) player.sendMessage("This shouldn't be happening. Report this.") else bin.close()
|
||||
"open" -> if(!bin.isFinished) player.sendMessage("I should probably wait until it is done to open it.") else bin.open()
|
||||
"take-tomato" -> {
|
||||
if (!bin.isTomatoes || !bin.isFinished) {
|
||||
player.sendMessage("This shouldn't be happening. Report this.")
|
||||
} else {
|
||||
if(player.inventory.isFull){
|
||||
player.sendMessage("You don't have enough inventory space to do this.")
|
||||
} else {
|
||||
val reward = bin.takeItem()
|
||||
if (reward != null)
|
||||
player.inventory.add(reward)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.cache.def.impl.VarbitDefinition
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.node.entity.player.Player
|
||||
|
||||
enum class CompostBins(val varpIndex: Int, val varpOffest: Int) {
|
||||
FALADOR_COMPOST(511,0),
|
||||
CATHERBY_COMPOST(511,8),
|
||||
PORT_PHAS_COMPOST(511,16),
|
||||
ARDOUGNE_COMPOST(511,24);
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val bins = values().map { (it.varpIndex shl it.varpOffest) to it }.toMap()
|
||||
|
||||
@JvmStatic
|
||||
fun forObject(obj: Scenery): CompostBins?{
|
||||
return forObjectID(obj.id)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun forObjectID(id: Int): CompostBins?{
|
||||
val objDef = SceneryDefinition.forId(id)
|
||||
val def = VarbitDefinition.forObjectID(objDef.varbitID)
|
||||
return bins[def.varpId shl def.startBit]
|
||||
}
|
||||
}
|
||||
|
||||
fun getBinForPlayer(player: Player) : CompostBin {
|
||||
var state: FarmingState? = player.states.get("farming") as FarmingState?
|
||||
return if(state == null){
|
||||
state = player.registerState("farming") as FarmingState
|
||||
state.getBin(this).also { state.init() }
|
||||
} else
|
||||
state.getBin(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
enum class CompostType {
|
||||
NONE,
|
||||
NORMAL,
|
||||
SUPER
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.*
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.game.interaction.OptionHandler
|
||||
import core.game.node.Node
|
||||
import content.global.skill.summoning.familiar.GiantEntNPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.audio.Audio;
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import org.rs09.consts.Items
|
||||
|
||||
val livesBased = arrayOf(PatchType.HERB, PatchType.CACTUS, PatchType.BELLADONNA, PatchType.HOPS, PatchType.ALLOTMENT,PatchType.EVIL_TURNIP)
|
||||
|
||||
val spadeAnim = Animation(830)
|
||||
|
||||
@Initializable
|
||||
class CropHarvester : OptionHandler() {
|
||||
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
SceneryDefinition.setOptionHandler("harvest",this)
|
||||
SceneryDefinition.setOptionHandler("pick",this)
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun harvestPulse(player: Player?, node: Node?, crop: Int): Pulse? {
|
||||
player ?: return null
|
||||
node ?: return null
|
||||
val fPatch = FarmingPatch.forObject(node.asScenery())
|
||||
fPatch ?: return null
|
||||
val patch = fPatch.getPatchFor(player)
|
||||
val plantable = patch.plantable
|
||||
plantable ?: return null
|
||||
|
||||
return object : Pulse(0) {
|
||||
override fun pulse(): Boolean {
|
||||
var reward = Item(crop, 1)
|
||||
|
||||
val familiar = player.familiarManager.familiar
|
||||
if(familiar != null && familiar is GiantEntNPC) {
|
||||
familiar.modifyFarmingReward(fPatch, reward)
|
||||
}
|
||||
if(!player.inventory.hasSpaceFor(reward)){
|
||||
player.sendMessage("You don't have enough inventory space for that.")
|
||||
return true
|
||||
}
|
||||
var requiredItem = when(fPatch.type){
|
||||
PatchType.HERB -> Items.SECATEURS_5329
|
||||
else -> Items.SPADE_952
|
||||
}
|
||||
if(requiredItem == Items.SECATEURS_5329){
|
||||
if(player.inventory.contains(Items.MAGIC_SECATEURS_7409,1)){
|
||||
requiredItem = Items.MAGIC_SECATEURS_7409
|
||||
}
|
||||
}
|
||||
val anim = when(requiredItem){
|
||||
Items.SPADE_952 -> Animation(830)
|
||||
Items.SECATEURS_5329 -> Animation(7227)
|
||||
Items.MAGIC_SECATEURS_7409 -> Animation(7228)
|
||||
else -> Animation(0)
|
||||
}
|
||||
val sound = when(requiredItem){
|
||||
Items.SPADE_952 -> Audio(1470, 1, 1)
|
||||
Items.SECATEURS_5329 -> Audio(2437, 1, 1)
|
||||
Items.MAGIC_SECATEURS_7409 -> Audio(2437, 1, 1)
|
||||
else -> Audio(0)
|
||||
}
|
||||
if(!player.inventory.containsItem(Item(requiredItem))){
|
||||
player.sendMessage("You lack the needed tool to harvest these crops.")
|
||||
return true
|
||||
}
|
||||
player.animator.animate(anim)
|
||||
player.audioManager.send(sound)
|
||||
delay = 2
|
||||
player.inventory.add(reward)
|
||||
player.skills.addExperience(Skills.FARMING,plantable.harvestXP)
|
||||
if(patch.patch.type in livesBased){
|
||||
patch.rollLivesDecrement(
|
||||
getDynLevel(player, Skills.FARMING),
|
||||
requiredItem == Items.MAGIC_SECATEURS_7409
|
||||
)
|
||||
} else {
|
||||
patch.harvestAmt--
|
||||
if(patch.harvestAmt <= 0 && crop == plantable.harvestItem){
|
||||
patch.clear()
|
||||
}
|
||||
}
|
||||
return patch.cropLives <= 0 || patch.harvestAmt <= 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
player ?: return false
|
||||
node ?: return false
|
||||
val fPatch = FarmingPatch.forObject(node.asScenery())
|
||||
fPatch ?: return false
|
||||
val patch = fPatch.getPatchFor(player)
|
||||
val plantable = patch.plantable
|
||||
plantable ?: return false
|
||||
|
||||
if(patch.isWeedy()){
|
||||
player.sendMessage("Something seems to have gone wrong here. Report this.")
|
||||
return true
|
||||
}
|
||||
|
||||
val pulse = harvestPulse(player, node, plantable.harvestItem) ?: return false
|
||||
player.pulseManager.run(pulse)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.game.dialogue.DialoguePlugin
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.audio.Audio
|
||||
import core.game.node.item.GroundItemManager
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.plugin.Initializable
|
||||
|
||||
@Initializable
|
||||
class DigUpPatchDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player) {
|
||||
var patch: Patch? = null
|
||||
|
||||
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
|
||||
return DigUpPatchDialogue(player)
|
||||
}
|
||||
|
||||
override fun open(vararg args: Any?): Boolean {
|
||||
patch = args[0] as Patch
|
||||
if(patch?.isWeedy() == true){
|
||||
player.dialogueInterpreter.sendDialogue("Use a rake to get rid of weeds.")
|
||||
stage = 1000
|
||||
return true
|
||||
}
|
||||
player.dialogueInterpreter.sendOptions("Dig up this patch?","Yes","No")
|
||||
stage = 0
|
||||
return true
|
||||
}
|
||||
|
||||
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
|
||||
when(stage){
|
||||
0 -> when(buttonId){
|
||||
1 -> {
|
||||
end()
|
||||
player.animator.animate(Animation(830))
|
||||
player.audioManager.send(Audio(1470, 1, 1))
|
||||
player.pulseManager.run(object : Pulse(){
|
||||
override fun pulse(): Boolean {
|
||||
if(patch?.patch?.type == PatchType.TREE){
|
||||
if(patch?.getCurrentState() == (patch?.plantable?.value ?: 0) + (patch?.plantable?.stages ?: 0) + 2 && patch?.isWeedy() != true){
|
||||
if(!player.inventory.add(Item(patch?.plantable?.harvestItem ?: 0))){
|
||||
GroundItemManager.create(Item(patch?.plantable?.harvestItem ?: 0),player)
|
||||
}
|
||||
}
|
||||
}
|
||||
patch?.clear()
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
else -> end()
|
||||
}
|
||||
|
||||
1000 -> end()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getIds(): IntArray {
|
||||
return intArrayOf(67984003)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.game.node.item.Item
|
||||
import org.rs09.consts.Items
|
||||
import core.game.dialogue.DialogueFile
|
||||
import core.tools.END_DIALOGUE
|
||||
import core.tools.START_DIALOGUE
|
||||
|
||||
class FarmerPayOptionDialogue(val patch: Patch): DialogueFile() {
|
||||
var item: Item? = null
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when(stage){
|
||||
START_DIALOGUE -> {
|
||||
item = patch.plantable?.protectionItem
|
||||
val protectionText = when(item?.id){
|
||||
Items.COMPOST_6032 -> if(item?.amount == 1) "bucket of compost" else "buckets of compost"
|
||||
Items.POTATOES10_5438 -> if(item?.amount == 1) "sack of potatoes" else "sacks of potatoes"
|
||||
Items.ONIONS10_5458 -> if(item?.amount == 1) "sack of onions" else "sacks of onions"
|
||||
Items.CABBAGES10_5478 -> if(item?.amount == 1) "sack of cabbages" else "sacks of cabbages"
|
||||
Items.JUTE_FIBRE_5931 -> "jute fibres"
|
||||
Items.APPLES5_5386 -> if(item?.amount == 1) "basket of apples" else "baskets of apples"
|
||||
Items.MARIGOLDS_6010 -> "harvest of marigold"
|
||||
Items.TOMATOES5_5968 -> if(item?.amount == 1) "basket of tomatoes" else "baskets of tomatoes"
|
||||
Items.ORANGES5_5396 -> if(item?.amount == 1) "basket of oranges" else "baskets of oranges"
|
||||
Items.COCONUT_5974 -> "coconuts"
|
||||
Items.CACTUS_SPINE_6016 -> "cactus spines"
|
||||
Items.STRAWBERRIES5_5406 -> if(item?.amount == 1) "basket of strawberries" else "baskets of strawberries"
|
||||
Items.BANANAS5_5416 -> if(item?.amount == 1) "basket of bananas" else "baskets of bananas"
|
||||
else -> item?.name?.toLowerCase()
|
||||
}
|
||||
if(item == null) npc("Sorry, I won't protect that.").also { stage = END_DIALOGUE }
|
||||
else{
|
||||
npc("I would like ${item?.amount} $protectionText","to protect that patch.")
|
||||
stage++
|
||||
}
|
||||
}
|
||||
|
||||
1 -> options("Sure!","No, thanks.").also { stage++ }
|
||||
2 -> {
|
||||
if(player!!.inventory.containsItem(item)){
|
||||
player("Here you go.").also { stage = 10 }
|
||||
} else {
|
||||
item = Item(item!!.noteChange,item!!.amount)
|
||||
if(player!!.inventory.containsItem(item)){
|
||||
player("Here you go.").also { stage = 10 }
|
||||
} else {
|
||||
player("I don't have that to give.").also { stage = 20 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10 -> {
|
||||
if(player!!.inventory.remove(item)){
|
||||
npc("Thank you! I'll keep an eye on this patch.").also { stage = END_DIALOGUE }
|
||||
patch?.protectionPaid = true
|
||||
} else {
|
||||
npc("That stuff just... vanished....").also { stage = END_DIALOGUE }
|
||||
}
|
||||
}
|
||||
|
||||
20 -> {
|
||||
npc("Come back when you do.")
|
||||
stage = END_DIALOGUE
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.interaction.IntType
|
||||
|
||||
class FarmerPayOptionHandler : InteractionListener {
|
||||
|
||||
override fun defineListeners() {
|
||||
on(IntType.NPC,"pay","pay (north)","pay (north-west)"){ player, node ->
|
||||
return@on attemptPay(player,node,0)
|
||||
}
|
||||
|
||||
on(IntType.NPC,"pay (south)","pay (south-east)"){ player, node ->
|
||||
return@on attemptPay(player,node,1)
|
||||
}
|
||||
}
|
||||
|
||||
fun attemptPay(player: Player, node: Node, index: Int): Boolean{
|
||||
val farmer = Farmers.forId(node.id) ?: return false
|
||||
val patch = farmer.patches[index].getPatchFor(player)
|
||||
|
||||
if(patch.plantable == null){
|
||||
player.dialogueInterpreter.sendDialogue("I have nothing to protect in that patch.")
|
||||
return true
|
||||
}
|
||||
|
||||
if(patch.protectionPaid){
|
||||
player.dialogueInterpreter.sendDialogue("I have already paid to protect that patch.")
|
||||
return true
|
||||
}
|
||||
|
||||
if(patch.isGrown()){
|
||||
player.dialogueInterpreter.sendDialogue("This patch is already fully grown!")
|
||||
return true
|
||||
}
|
||||
|
||||
player.dialogueInterpreter.open(FarmerPayOptionDialogue(patch),node.asNpc())
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
enum class Farmers(val id: Int, val patches: Array<FarmingPatch>) {
|
||||
LYRA(2326, arrayOf(FarmingPatch.PORT_PHAS_ALLOTMENT_NW,FarmingPatch.PORT_PHAS_ALLOTMENT_SE)),
|
||||
ELSTAN(2323, arrayOf(FarmingPatch.S_FALADOR_ALLOTMENT_NW,FarmingPatch.S_FALADOR_ALLOTMENT_SE)),
|
||||
HESKEL(2340, arrayOf(FarmingPatch.N_FALADOR_TREE)),
|
||||
ALAIN(2339, arrayOf(FarmingPatch.TAVERLY_TREE)),
|
||||
DANTAERA(2324, arrayOf(FarmingPatch.CATHERBY_ALLOTMENT_N,FarmingPatch.CATHERBY_ALLOTMENT_S)),
|
||||
ELLENA(2331, arrayOf(FarmingPatch.CATHERBY_FRUIT_TREE)),
|
||||
GARTH(2330,arrayOf(FarmingPatch.BRIMHAVEN_FRUIT_TREE)),
|
||||
GILETH(2344,arrayOf(FarmingPatch.TREE_GNOME_VILLAGE_FRUIT_TREE)),
|
||||
AMAETHWR(2860,arrayOf(FarmingPatch.LLETYA_FRUIT_TREE)),
|
||||
SELENA(2332, arrayOf(FarmingPatch.YANILLE_HOPS)),
|
||||
KRAGEN(2325, arrayOf(FarmingPatch.ARDOUGNE_ALLOTMENT_N,FarmingPatch.ARDOUGNE_ALLOTMENT_S)),
|
||||
BOLONGO(2343, arrayOf(FarmingPatch.GNOME_STRONGHOLD_FRUIT_TREE)),
|
||||
PRISSY_SCILLA(1037, arrayOf(FarmingPatch.GNOME_STRONGHOLD_TREE)),
|
||||
FAYETH(2342, arrayOf(FarmingPatch.LUMBRIDGE_TREE)),
|
||||
TREZNOR(2341, arrayOf(FarmingPatch.VARROCK_TREE)),
|
||||
VASQUEN(2333, arrayOf(FarmingPatch.LUMBRIDGE_HOPS)),
|
||||
RHONEN(2334, arrayOf(FarmingPatch.MCGRUBOR_HOPS)),
|
||||
FRANCIS(2327, arrayOf(FarmingPatch.ENTRANA_HOPS)),
|
||||
DREVEN(2335, arrayOf(FarmingPatch.CHAMPIONS_GUILD_BUSH)),
|
||||
TARIA(2336, arrayOf(FarmingPatch.RIMMINGTON_BUSH)),
|
||||
TORRELL(2338, arrayOf(FarmingPatch.ARDOUGNE_BUSH));
|
||||
|
||||
companion object{
|
||||
@JvmField
|
||||
val farmers = values().map { it.id to it }.toMap()
|
||||
|
||||
@JvmStatic
|
||||
fun forId(id: Int): Farmers?{
|
||||
return farmers[id]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.cache.def.impl.VarbitDefinition
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.node.entity.player.Player
|
||||
|
||||
enum class FarmingPatch(val varpIndex: Int, val varpOffset: Int, val type: PatchType) {
|
||||
//Allotments
|
||||
S_FALADOR_ALLOTMENT_NW(504,0,PatchType.ALLOTMENT),
|
||||
S_FALADOR_ALLOTMENT_SE(504,8,PatchType.ALLOTMENT),
|
||||
CATHERBY_ALLOTMENT_N(504,16,PatchType.ALLOTMENT),
|
||||
CATHERBY_ALLOTMENT_S(504,24,PatchType.ALLOTMENT),
|
||||
ARDOUGNE_ALLOTMENT_S(505,8,PatchType.ALLOTMENT),
|
||||
ARDOUGNE_ALLOTMENT_N(505,0,PatchType.ALLOTMENT),
|
||||
PORT_PHAS_ALLOTMENT_NW(505,16,PatchType.ALLOTMENT),
|
||||
PORT_PHAS_ALLOTMENT_SE(505,24,PatchType.ALLOTMENT),
|
||||
HARMONY_ISLAND_ALLOTMENT(982,8,PatchType.ALLOTMENT),
|
||||
|
||||
//Herb
|
||||
CATHERBY_HERB_CE(515,8,PatchType.HERB),
|
||||
S_FALADOR_HERB_NE(515,0,PatchType.HERB),
|
||||
ARDOUGNE_HERB_CE(515,16,PatchType.HERB),
|
||||
PORT_PHAS_HERB_NE(515,24,PatchType.HERB),
|
||||
TROLL_STRONGHOLD_HERB(830,0,PatchType.HERB),
|
||||
|
||||
//Flower
|
||||
S_FALADOR_FLOWER_C(508,0,PatchType.FLOWER),
|
||||
CATHERBY_FLOWER_C(508,8,PatchType.FLOWER),
|
||||
ARDOUGNE_FLOWER_C(508,16,PatchType.FLOWER),
|
||||
PORT_PHAS_FLOWER_C(508,24,PatchType.FLOWER),
|
||||
WILDERNESS_FLOWER(1183,12,PatchType.FLOWER),
|
||||
|
||||
//Tree
|
||||
N_FALADOR_TREE(502,8,PatchType.TREE),
|
||||
TAVERLY_TREE(502,0,PatchType.TREE),
|
||||
GNOME_STRONGHOLD_TREE(830,11,PatchType.TREE),
|
||||
LUMBRIDGE_TREE(502,24,PatchType.TREE),
|
||||
VARROCK_TREE(502,16,PatchType.TREE),
|
||||
|
||||
//Fruit Tree
|
||||
GNOME_STRONGHOLD_FRUIT_TREE(503,0,PatchType.FRUIT_TREE),
|
||||
CATHERBY_FRUIT_TREE(503,24,PatchType.FRUIT_TREE),
|
||||
TREE_GNOME_VILLAGE_FRUIT_TREE(503,8,PatchType.FRUIT_TREE),
|
||||
BRIMHAVEN_FRUIT_TREE(503,16,PatchType.FRUIT_TREE),
|
||||
LLETYA_FRUIT_TREE(830,23,PatchType.FRUIT_TREE),
|
||||
|
||||
//Hops
|
||||
ENTRANA_HOPS(506,8,PatchType.HOPS),
|
||||
LUMBRIDGE_HOPS(506,16,PatchType.HOPS),
|
||||
MCGRUBOR_HOPS(506,24,PatchType.HOPS),
|
||||
YANILLE_HOPS(506,0,PatchType.HOPS),
|
||||
|
||||
//Bushes
|
||||
CHAMPIONS_GUILD_BUSH(509,0,PatchType.BUSH),
|
||||
RIMMINGTON_BUSH(509,8,PatchType.BUSH),
|
||||
ARDOUGNE_BUSH(509,24,PatchType.BUSH),
|
||||
ETCETERIA_BUSH(509,16,PatchType.BUSH),
|
||||
|
||||
//Spirit Tree
|
||||
ETCETERIA_SPIRIT_TREE(507,8,PatchType.SPIRIT_TREE),
|
||||
PORT_SARIM_SPIRIT_TREE(507,0,PatchType.SPIRIT_TREE),
|
||||
KARAMJA_SPIRIT_TREE(507,16,PatchType.SPIRIT_TREE),
|
||||
|
||||
//Other
|
||||
DRAYNOR_BELLADONNA(512, 16, PatchType.BELLADONNA),
|
||||
CANIFIS_MUSHROOM(512, 8, PatchType.MUSHROOM),
|
||||
ALKHARID_CACTUS(512, 0, PatchType.CACTUS),
|
||||
EVIL_TURNIP(1171, 7, PatchType.EVIL_TURNIP);
|
||||
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val patches = FarmingPatch.values().map { (it.varpIndex shl it.varpOffset) to it }.toMap()
|
||||
|
||||
@JvmStatic
|
||||
fun forObject(obj: Scenery): FarmingPatch?{
|
||||
return forObjectID(obj.id)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun forObjectID(id: Int): FarmingPatch?{
|
||||
val objDef = SceneryDefinition.forId(id)
|
||||
val def = VarbitDefinition.forObjectID(objDef.varbitID)
|
||||
return patches[def.varpId shl def.startBit]
|
||||
}
|
||||
}
|
||||
|
||||
fun getPatchFor(player: Player): Patch{
|
||||
var state: FarmingState? = player.states.get("farming") as FarmingState?
|
||||
return if(state == null){
|
||||
state = player.registerState("farming") as FarmingState
|
||||
state.getPatch(this).also { state.init() }
|
||||
} else
|
||||
state.getPatch(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.*
|
||||
import core.game.dialogue.FacialExpression
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import org.rs09.consts.NPCs
|
||||
import core.game.dialogue.DialogueFile
|
||||
|
||||
class FarmingPatchZone : MapArea, TickListener {
|
||||
private val playersInZone = hashMapOf<Player,Int>()
|
||||
|
||||
override fun defineAreaBorders(): Array<ZoneBorders> {
|
||||
return arrayOf(
|
||||
getRegionBorders(12083),
|
||||
getRegionBorders(10548),
|
||||
ZoneBorders(3594,3521,3608,3532)
|
||||
)
|
||||
}
|
||||
|
||||
override fun areaEnter(entity: Entity) {
|
||||
if(entity is Player && playersInZone[entity] == null && getStatLevel(entity, Skills.FARMING) <= 15) {
|
||||
playersInZone[entity] = 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun areaLeave(entity: Entity, logout: Boolean) {
|
||||
if(entity is Player)
|
||||
playersInZone.remove(entity)
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
playersInZone.toList().forEach { (player, ticks) ->
|
||||
if(ticks == 500){
|
||||
val npc = NPC(NPCs.GITHAN_7122)
|
||||
npc.location = player.location
|
||||
npc.init()
|
||||
npc.moveStep()
|
||||
npc.face(player)
|
||||
openDialogue(player, SpiritDialogue(true), npc)
|
||||
} else if (ticks == 1000){
|
||||
val npc = NPC(NPCs.GITHAN_7122)
|
||||
npc.location = player.location
|
||||
npc.init()
|
||||
npc.moveStep()
|
||||
npc.face(player)
|
||||
openDialogue(player, SpiritDialogue(false), npc)
|
||||
playersInZone.remove(player)
|
||||
}
|
||||
|
||||
playersInZone[player] = ticks + 1
|
||||
}
|
||||
}
|
||||
|
||||
internal class SpiritDialogue(val is5: Boolean) : DialogueFile(){
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when(stage){
|
||||
0 -> {
|
||||
if(is5) npcl(core.game.dialogue.FacialExpression.NEUTRAL, "In case you didn't know, you don't have to stand by your Farming patch. Your crops will grow even if you're not around.").also { stage++ }
|
||||
else npcl(core.game.dialogue.FacialExpression.NEUTRAL, " Did you know that if your Farming patch has fully grown, it will never catch disease or die? It will be perfectly safe until you choose to harvest it.").also { stage++ }
|
||||
}
|
||||
1 -> end()
|
||||
}
|
||||
}
|
||||
|
||||
override fun end(){
|
||||
super.end()
|
||||
poofClear(npc ?: return)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.Util.clamp
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.task.Pulse
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.json.simple.JSONArray
|
||||
import org.json.simple.JSONObject
|
||||
import core.game.node.entity.state.PlayerState
|
||||
import core.game.node.entity.state.State
|
||||
import core.tools.SystemLogger
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@PlayerState("farming")
|
||||
class FarmingState(player: Player? = null) : State(player) {
|
||||
private val patchMap = HashMap<FarmingPatch, Patch>()
|
||||
private val binMap = HashMap<CompostBins, CompostBin>()
|
||||
|
||||
|
||||
fun getPatch(patch: FarmingPatch): Patch {
|
||||
return patchMap[patch] ?: (Patch(player!!,patch).also { patchMap[patch] = it })
|
||||
}
|
||||
|
||||
fun getBin(bin: CompostBins) : CompostBin{
|
||||
return binMap[bin] ?: (CompostBin(player!!,bin).also { binMap[bin] = it })
|
||||
}
|
||||
|
||||
fun getPatches(): MutableCollection<Patch>{
|
||||
return patchMap.values
|
||||
}
|
||||
|
||||
fun getBins(): MutableCollection<CompostBin>{
|
||||
return binMap.values
|
||||
}
|
||||
|
||||
override fun save(root: JSONObject) {
|
||||
val patches = JSONArray()
|
||||
for((key,patch) in patchMap){
|
||||
val p = JSONObject()
|
||||
p.put("patch-ordinal",key.ordinal)
|
||||
p.put("patch-plantable-ordinal",patch.plantable?.ordinal ?: -1)
|
||||
p.put("patch-watered",patch.isWatered)
|
||||
p.put("patch-diseased",patch.isDiseased)
|
||||
p.put("patch-dead",patch.isDead)
|
||||
p.put("patch-stage",patch.currentGrowthStage)
|
||||
p.put("patch-state",patch.getCurrentState())
|
||||
p.put("patch-nextGrowth",patch.nextGrowth)
|
||||
p.put("patch-harvestAmt",patch.harvestAmt)
|
||||
p.put("patch-checkHealth",patch.isCheckHealth)
|
||||
p.put("patch-compost",patch.compost.ordinal)
|
||||
p.put("patch-paidprot",patch.protectionPaid)
|
||||
p.put("patch-croplives", patch.cropLives)
|
||||
patches.add(p)
|
||||
}
|
||||
val bins = JSONArray()
|
||||
for((key,bin) in binMap){
|
||||
val b = JSONObject()
|
||||
b.put("bin-ordinal",key.ordinal)
|
||||
bin.save(b)
|
||||
bins.add(b)
|
||||
}
|
||||
root.put("farming-patches",patches)
|
||||
root.put("farming-bins",bins)
|
||||
}
|
||||
|
||||
override fun parse(_data: JSONObject) {
|
||||
player ?: return
|
||||
if(_data.containsKey("farming-bins")){
|
||||
(_data["farming-bins"] as JSONArray).forEach {
|
||||
val bin = it as JSONObject
|
||||
val binOrdinal = bin["bin-ordinal"].toString().toInt()
|
||||
val cBin = CompostBins.values()[binOrdinal]
|
||||
val b = cBin.getBinForPlayer(player)
|
||||
b.parse(bin["binData"] as JSONObject)
|
||||
SystemLogger.logErr(this::class.java, "bin size " + binMap.size)
|
||||
}
|
||||
}
|
||||
if(_data.containsKey("farming-patches")){
|
||||
val data = _data["farming-patches"] as JSONArray
|
||||
for(d in data){
|
||||
val p = d as JSONObject
|
||||
val patchOrdinal = p["patch-ordinal"].toString().toInt()
|
||||
val patchPlantableOrdinal = p["patch-plantable-ordinal"].toString().toInt()
|
||||
val patchWatered = p["patch-watered"] as Boolean
|
||||
val patchDiseased = p["patch-diseased"] as Boolean
|
||||
val patchDead = p["patch-dead"] as Boolean
|
||||
val patchStage = p["patch-stage"].toString().toInt()
|
||||
val nextGrowth = p["patch-nextGrowth"].toString().toLong()
|
||||
val harvestAmt = (p["patch-harvestAmt"] ?: 0).toString().toInt()
|
||||
val checkHealth = p["patch-checkHealth"] as Boolean
|
||||
val savedState = p["patch-state"].toString().toInt()
|
||||
val compostOrdinal = p["patch-compost"].toString().toInt()
|
||||
val protectionPaid = p["patch-paidprot"] as Boolean
|
||||
val cropLives = if(p["patch-croplives"] != null) p["patch-croplives"].toString().toInt() else 3
|
||||
val fPatch = FarmingPatch.values()[patchOrdinal]
|
||||
val plantable = if(patchPlantableOrdinal != -1) Plantable.values()[patchPlantableOrdinal] else null
|
||||
val patch = Patch(player,fPatch,plantable,patchStage,patchDiseased,patchDead,patchWatered,nextGrowth,harvestAmt,checkHealth)
|
||||
|
||||
patch.cropLives = cropLives
|
||||
patch.compost = CompostType.values()[compostOrdinal]
|
||||
patch.protectionPaid = protectionPaid
|
||||
patch.setCurrentState(savedState)
|
||||
|
||||
if((savedState - (patch?.plantable?.value ?: 0)) > patch.currentGrowthStage){
|
||||
patch.setCurrentState(savedState)
|
||||
} else {
|
||||
patch.setCurrentState((patch.plantable?.value ?: 0) + patch.currentGrowthStage)
|
||||
}
|
||||
|
||||
val type = patch.patch.type
|
||||
val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE && patch.getFruitOrBerryCount() < 6)
|
||||
if(shouldPlayCatchup && patch.plantable != null && !patchDead){
|
||||
var stagesToSimulate = if (!patch.isGrown()) patch.plantable!!.stages - patch.currentGrowthStage else 0
|
||||
if (type == PatchType.BUSH)
|
||||
stagesToSimulate += Math.min(4, 4 - patch.getFruitOrBerryCount())
|
||||
if (type == PatchType.FRUIT_TREE)
|
||||
stagesToSimulate += Math.min(6, 6 - patch.getFruitOrBerryCount())
|
||||
|
||||
val nowTime = System.currentTimeMillis()
|
||||
var simulatedTime = patch.nextGrowth
|
||||
|
||||
while (simulatedTime < nowTime && stagesToSimulate-- > 0 && !patch.isDead) {
|
||||
val timeToIncrement = TimeUnit.MINUTES.toMillis(patch.getStageGrowthMinutes().toLong())
|
||||
patch.update()
|
||||
simulatedTime += timeToIncrement
|
||||
}
|
||||
}
|
||||
|
||||
if(patchMap[fPatch] == null) {
|
||||
patchMap[fPatch] = patch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newInstance(player: Player?): State {
|
||||
return FarmingState(player)
|
||||
}
|
||||
|
||||
override fun createPulse() {
|
||||
pulse = object : Pulse(3){
|
||||
override fun pulse(): Boolean {
|
||||
|
||||
GlobalScope.launch {
|
||||
var removeList = ArrayList<FarmingPatch>()
|
||||
for((_,patch) in patchMap){
|
||||
|
||||
if(patch.getCurrentState() in 1..3 && patch.nextGrowth == 0L){
|
||||
patch.nextGrowth = System.currentTimeMillis() + 60000
|
||||
continue
|
||||
}
|
||||
|
||||
if(patch.nextGrowth < System.currentTimeMillis() && !patch.isDead){
|
||||
patch.update()
|
||||
patch.nextGrowth = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(patch.getStageGrowthMinutes().toLong())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for((_,bin) in binMap){
|
||||
if(bin.isReady() && !bin.isFinished){
|
||||
bin.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.*
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.game.interaction.OptionHandler
|
||||
import core.game.node.Node
|
||||
import content.global.skill.summoning.familiar.GiantEntNPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Initializable
|
||||
class FruitAndBerryPicker : OptionHandler() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
SceneryDefinition.setOptionHandler("pick-coconut",this)
|
||||
SceneryDefinition.setOptionHandler("pick-banana",this)
|
||||
SceneryDefinition.setOptionHandler("pick-apple",this)
|
||||
SceneryDefinition.setOptionHandler("pick-orange",this)
|
||||
SceneryDefinition.setOptionHandler("pick-pineapple",this)
|
||||
SceneryDefinition.setOptionHandler("pick-papaya",this)
|
||||
SceneryDefinition.setOptionHandler("pick-leaf",this)
|
||||
SceneryDefinition.setOptionHandler("pick-from",this)
|
||||
SceneryDefinition.setOptionHandler("pick-fruit",this)
|
||||
SceneryDefinition.setOptionHandler("pick-spine",this)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
player ?: return false
|
||||
node ?: return false
|
||||
|
||||
val fPatch = FarmingPatch.forObject(node.asScenery())
|
||||
fPatch ?: return false
|
||||
|
||||
val patch = fPatch.getPatchFor(player)
|
||||
|
||||
val plantable = patch.plantable
|
||||
plantable ?: return false
|
||||
|
||||
val animation = Animation(2281)
|
||||
|
||||
if(patch.getFruitOrBerryCount() <= 0){
|
||||
player.sendMessage("This shouldn't be happening. Please report this.")
|
||||
return true
|
||||
}
|
||||
|
||||
if(!player.inventory.hasSpaceFor(Item(plantable.harvestItem))){
|
||||
player.sendMessage("You do not have enough inventory space for this.")
|
||||
return true
|
||||
}
|
||||
|
||||
if(System.currentTimeMillis() - patch.nextGrowth > TimeUnit.MINUTES.toMillis(45)){
|
||||
patch.nextGrowth = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(45)
|
||||
}
|
||||
|
||||
player.pulseManager.run(object : Pulse(animation.duration){
|
||||
override fun pulse(): Boolean {
|
||||
val reward = Item(plantable.harvestItem, 1)
|
||||
|
||||
val familiar = player.familiarManager.familiar
|
||||
if(familiar != null && familiar is GiantEntNPC) {
|
||||
familiar.modifyFarmingReward(fPatch, reward)
|
||||
}
|
||||
|
||||
player.animator.animate(animation)
|
||||
player.audioManager.send(2437)
|
||||
addItemOrDrop(player,reward.id,reward.amount)
|
||||
player.skills.addExperience(Skills.FARMING,plantable.harvestXP)
|
||||
patch.setCurrentState(patch.getCurrentState() - 1)
|
||||
|
||||
return patch.getFruitOrBerryCount() == 0
|
||||
}
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.game.interaction.OptionHandler
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.tools.SystemLogger
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Initializable
|
||||
class HealthChecker : OptionHandler(){
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
SceneryDefinition.setOptionHandler("check-health",this)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
player ?: return false
|
||||
node ?: return false
|
||||
val fPatch = FarmingPatch.forObject(node.asScenery())
|
||||
fPatch ?: return false
|
||||
val patch = fPatch.getPatchFor(player)
|
||||
val type = patch.patch.type
|
||||
|
||||
if(type != PatchType.BUSH && type != PatchType.FRUIT_TREE && type != PatchType.TREE && type != PatchType.CACTUS){
|
||||
player.sendMessage("This shouldn't be happening. Please report this.")
|
||||
return true
|
||||
}
|
||||
|
||||
if(!patch.isCheckHealth) return true
|
||||
|
||||
player.skills.addExperience(Skills.FARMING,patch.plantable?.checkHealthXP ?: 0.0)
|
||||
patch.isCheckHealth = false
|
||||
when(type){
|
||||
PatchType.TREE -> patch.setCurrentState(patch.getCurrentState() + 1)
|
||||
PatchType.FRUIT_TREE -> patch.setCurrentState(patch.getCurrentState() - 14)
|
||||
PatchType.BUSH -> patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 4)
|
||||
PatchType.CACTUS -> patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 3)
|
||||
else -> SystemLogger.logErr(this::class.java,"Unreachable patch type from when(type) switch in HealthChecker.kt line 36")
|
||||
}
|
||||
|
||||
if(type == PatchType.FRUIT_TREE){
|
||||
patch.nextGrowth = TimeUnit.MINUTES.toMillis(45)
|
||||
}
|
||||
|
||||
patch.update()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.cache.def.impl.SceneryDefinition
|
||||
import core.game.interaction.OptionHandler
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
|
||||
@Initializable
|
||||
class InspectionHandler : OptionHandler() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
SceneryDefinition.setOptionHandler("inspect",this)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
node ?: return false
|
||||
player ?: return false
|
||||
val patch = FarmingPatch.forObject(node.asScenery())
|
||||
if(patch == null){
|
||||
player.sendMessage("This is an improperly handled inspect option. Report this please.")
|
||||
} else {
|
||||
val p = patch.getPatchFor(player)
|
||||
val status1 = if(p.getCurrentState() <= 2) "This patch needs weeding." else if(p.getCurrentState() == 3) "This patch is weed-free." else {
|
||||
if(p.isDiseased && !p.isDead) "This patch has become diseased."
|
||||
else if(p.isDead) "The crops in this patch are dead."
|
||||
else if(p.plantable == Plantable.SCARECROW) "There is a scarecrow in this patch."
|
||||
else "This patch has something growing in it."
|
||||
}
|
||||
val status2 = if(patch.type == PatchType.ALLOTMENT || patch.type == PatchType.FLOWER || patch.type == PatchType.HOPS){
|
||||
if(p.isWatered) {
|
||||
"This patch has been watered."
|
||||
} else if(p.getCurrentState() > 3 && !p.isGrown() && !p.isDead && !p.isDiseased) {
|
||||
"This patch could use some water."
|
||||
} else ""
|
||||
} else ""
|
||||
val status3 = if(p.compost == CompostType.NONE) "This patch has not been treated." else "This patch has been treated with ${p.compost.name.toLowerCase()} compost."
|
||||
player.sendMessage("$status1 $status2")
|
||||
player.sendMessage(status3)
|
||||
val varpValue = player.varpManager.get(patch.varpIndex).getBitRangeValue(patch.varpOffset,patch.varpOffset + 7)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.*
|
||||
import core.game.node.item.Item
|
||||
import org.rs09.consts.NPCs
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.interaction.IntType
|
||||
|
||||
class LeprechaunNoter : InteractionListener {
|
||||
|
||||
val CROPS = Plantable.values().map{ it.harvestItem }.toIntArray()
|
||||
val LEPRECHAUNS = intArrayOf(NPCs.TOOL_LEPRECHAUN_3021,NPCs.GOTH_LEPRECHAUN_8000,NPCs.TOOL_LEPRECHAUN_4965,NPCs.TECLYN_2861)
|
||||
|
||||
override fun defineListeners() {
|
||||
onUseWith(IntType.NPC,CROPS,*LEPRECHAUNS){ player, used, with ->
|
||||
val usedItem = used.asItem()
|
||||
val npc = with.asNpc()
|
||||
val expr = when(npc.id){
|
||||
3021 -> core.game.dialogue.FacialExpression.OLD_NORMAL
|
||||
else -> core.game.dialogue.FacialExpression.FRIENDLY
|
||||
}
|
||||
|
||||
if(usedItem.noteChange != usedItem.id){
|
||||
val amt = player.inventory.getAmount(usedItem.id)
|
||||
if(player.inventory.remove(Item(usedItem.id,amt))){
|
||||
player.inventory.add(Item(usedItem.noteChange,amt))
|
||||
}
|
||||
sendItemDialogue(player,usedItem.id,"The leprechaun exchanges your items for banknotes.")
|
||||
} else {
|
||||
// Unsure why the line below no longer functions, despite only changing the line above to be more correct. Using your note(NOT CROP) on the leprechaun no longer functions because of this. - Crash
|
||||
player.dialogueInterpreter.sendDialogues(npc.id,expr,"That IS a banknote!")
|
||||
}
|
||||
|
||||
return@onUseWith true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
import core.tools.SystemLogger
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.min
|
||||
|
||||
class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantable?, var currentGrowthStage: Int, var isDiseased: Boolean, var isDead: Boolean, var isWatered: Boolean, var nextGrowth: Long, var harvestAmt: Int, var isCheckHealth: Boolean) {
|
||||
constructor(player: Player, patch: FarmingPatch) : this(player,patch,null,0,false,false,false,0L,0,false)
|
||||
|
||||
var diseaseMod = 0
|
||||
var compost = CompostType.NONE
|
||||
var protectionPaid = false
|
||||
var cropLives = 3
|
||||
|
||||
fun setNewHarvestAmount() {
|
||||
val compostMod = when(compost) {
|
||||
CompostType.NONE -> 0
|
||||
CompostType.NORMAL -> 1
|
||||
CompostType.SUPER -> 2
|
||||
}
|
||||
harvestAmt = when (plantable) {
|
||||
Plantable.LIMPWURT_SEED, Plantable.WOAD_SEED -> 3
|
||||
Plantable.MUSHROOM_SPORE -> 6
|
||||
Plantable.WILLOW_SAPLING -> 0
|
||||
else -> 1
|
||||
}
|
||||
if(plantable != null && plantable?.applicablePatch != PatchType.FLOWER) {
|
||||
harvestAmt += compostMod
|
||||
}
|
||||
cropLives = 3 + compostMod
|
||||
}
|
||||
|
||||
fun rollLivesDecrement(farmingLevel: Int, magicSecateurs: Boolean){
|
||||
if(patch.type == PatchType.HERB){
|
||||
//authentic formula thanks to released data.
|
||||
var herbSaveLow = when(plantable){
|
||||
Plantable.GUAM_SEED -> min(24 + farmingLevel, 80)
|
||||
Plantable.MARRENTILL_SEED -> min(28 + farmingLevel, 80)
|
||||
Plantable.TARROMIN_SEED -> min(31 + farmingLevel, 80)
|
||||
Plantable.HARRALANDER_SEED -> min(36 + farmingLevel, 80)
|
||||
Plantable.GOUT_TUBER -> min(39 + farmingLevel, 80)
|
||||
Plantable.RANARR_SEED -> min(39 + farmingLevel, 80)
|
||||
Plantable.SPIRIT_WEED_SEED -> min(43 + farmingLevel, 80)
|
||||
Plantable.TOADFLAX_SEED -> min(43 + farmingLevel, 80)
|
||||
Plantable.IRIT_SEED -> min(46 + farmingLevel, 80)
|
||||
Plantable.AVANTOE_SEED -> min(50 + farmingLevel, 80)
|
||||
Plantable.KWUARM_SEED -> min(54 + farmingLevel, 80)
|
||||
Plantable.SNAPDRAGON_SEED -> min(57 + farmingLevel, 80)
|
||||
Plantable.CADANTINE_SEED -> min(60 + farmingLevel, 80)
|
||||
Plantable.LANTADYME_SEED -> min(64 + farmingLevel, 80)
|
||||
Plantable.DWARF_WEED_SEED -> min(67 + farmingLevel, 80)
|
||||
Plantable.TORSTOL_SEED -> min(71 + farmingLevel, 80)
|
||||
else -> -1
|
||||
}
|
||||
|
||||
if(magicSecateurs) herbSaveLow = ceil(1.10 * herbSaveLow).toInt()
|
||||
|
||||
val rand = RandomFunction.random(256)
|
||||
|
||||
if(rand > herbSaveLow){
|
||||
cropLives -= 1
|
||||
}
|
||||
} else {
|
||||
//inauthentic formulae based on reported averages due to lack of formula
|
||||
var chance = when(patch.type){
|
||||
PatchType.ALLOTMENT -> 8 //average of 8 per life times 3 lives = average 24
|
||||
PatchType.HOPS -> 6 //average of 6 per life times 3 lives = 18
|
||||
PatchType.BELLADONNA -> 2 //average of 2 per life times 3 lives = 6
|
||||
PatchType.EVIL_TURNIP -> 2 //average 2 per, same as BELLADONNA
|
||||
PatchType.CACTUS -> 3 //average of 3 per life times 3 lives = 9
|
||||
else -> 0 // nothing should go here, but if it does, do not give extra crops amd decrement cropLives
|
||||
}
|
||||
|
||||
if(magicSecateurs) chance += ceil(1.10 * chance).toInt() //will increase average yield by roughly 3.
|
||||
|
||||
if(RandomFunction.roll(chance)) cropLives -= 1
|
||||
}
|
||||
|
||||
if(cropLives <= 0) clear()
|
||||
}
|
||||
|
||||
fun isWeedy(): Boolean {
|
||||
return getCurrentState() in 0..3
|
||||
}
|
||||
|
||||
fun getCurrentState(): Int{
|
||||
return player.varpManager.get(patch.varpIndex).getVarbitValue(patch.varpOffset) ?: 0
|
||||
}
|
||||
|
||||
fun setCurrentState(state: Int){
|
||||
player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,state)
|
||||
updateBit()
|
||||
}
|
||||
|
||||
fun isFertilized(): Boolean {
|
||||
return compost != CompostType.NONE
|
||||
}
|
||||
|
||||
fun isGrown(): Boolean{
|
||||
return currentGrowthStage == (plantable?.stages ?: 0)
|
||||
}
|
||||
|
||||
private fun updateBit(){
|
||||
if(isCheckHealth){
|
||||
when(patch.type){
|
||||
PatchType.FRUIT_TREE -> player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,plantable!!.value + plantable!!.stages + 20)
|
||||
PatchType.BUSH -> player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,250 + (plantable!!.ordinal - Plantable.REDBERRY_SEED.ordinal))
|
||||
PatchType.CACTUS -> player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, 31)
|
||||
else -> SystemLogger.logWarn(this::class.java, "Invalid setting of isCheckHealth for patch type: " + patch.type.name)
|
||||
}
|
||||
} else {
|
||||
when(patch.type){
|
||||
PatchType.ALLOTMENT,PatchType.FLOWER,PatchType.HOPS -> {
|
||||
player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset + 6, if (isWatered || isDead) 1 else 0)
|
||||
player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset + 7, if (isDiseased) 1 else 0)
|
||||
}
|
||||
PatchType.BUSH -> {
|
||||
if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,getBushDeathValue())
|
||||
else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,getBushDiseaseValue())
|
||||
//else player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, (plantable?.value ?: 0) + currentGrowthStage)
|
||||
}
|
||||
PatchType.TREE -> {
|
||||
if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset + 7,1)
|
||||
else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset + 6, 1)
|
||||
}
|
||||
PatchType.FRUIT_TREE -> {
|
||||
if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,getFruitTreeDeathValue())
|
||||
else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getFruitTreeDiseaseValue())
|
||||
}
|
||||
PatchType.BELLADONNA -> {
|
||||
if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getBelladonnaDeathValue())
|
||||
else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getBelladonnaDiseaseValue())
|
||||
else player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, (plantable?.value ?: 0) + currentGrowthStage)
|
||||
}
|
||||
PatchType.CACTUS -> {
|
||||
if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getCactusDeathValue())
|
||||
else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getCactusDiseaseValue())
|
||||
}
|
||||
PatchType.HERB -> {
|
||||
if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getHerbDeathValue())
|
||||
else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getHerbDiseaseValue())
|
||||
else player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, (plantable?.value ?: 0) + currentGrowthStage)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
player.varpManager.get(patch.varpIndex).send(player)
|
||||
}
|
||||
|
||||
fun cureDisease() {
|
||||
isDiseased = false
|
||||
when(patch.type){
|
||||
PatchType.BUSH,PatchType.FRUIT_TREE -> player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,(plantable?.value ?: 0) + currentGrowthStage)
|
||||
PatchType.TREE -> player.varpManager.get(patch.varpIndex).clearBitRange(patch.varpOffset + 6, patch.varpOffset + 7)
|
||||
PatchType.CACTUS -> player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, (plantable?.value ?: 0) + currentGrowthStage)
|
||||
else -> {}
|
||||
}
|
||||
updateBit()
|
||||
}
|
||||
|
||||
fun water() {
|
||||
isWatered = true
|
||||
updateBit()
|
||||
}
|
||||
|
||||
private fun getBushDiseaseValue(): Int{
|
||||
if(plantable == Plantable.POISON_IVY_SEED){
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 12
|
||||
} else {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 64
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBushDeathValue(): Int{
|
||||
if(plantable == Plantable.POISON_IVY_SEED){
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 22
|
||||
} else {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 126
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFruitTreeDiseaseValue(): Int {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 12
|
||||
}
|
||||
|
||||
private fun getFruitTreeDeathValue(): Int {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 18
|
||||
}
|
||||
|
||||
private fun getBelladonnaDiseaseValue(): Int {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 4
|
||||
}
|
||||
|
||||
private fun getBelladonnaDeathValue(): Int {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 7
|
||||
}
|
||||
|
||||
private fun getCactusDiseaseValue(): Int {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 10
|
||||
}
|
||||
|
||||
private fun getCactusDeathValue(): Int {
|
||||
return (plantable?.value ?: 0) + currentGrowthStage + 16
|
||||
}
|
||||
|
||||
private fun getHerbDiseaseValue(): Int {
|
||||
return if (plantable?.value ?: -1 <= 103) {
|
||||
128 + (((plantable?.ordinal ?: 0) - Plantable.GUAM_SEED.ordinal) * 3) + currentGrowthStage - 1
|
||||
} else if (plantable == Plantable.SPIRIT_WEED_SEED) {
|
||||
211 + currentGrowthStage - 1
|
||||
} else {
|
||||
198 + currentGrowthStage -1
|
||||
}
|
||||
}
|
||||
|
||||
private fun getHerbDeathValue(): Int {
|
||||
return if(plantable == Plantable.GOUT_TUBER){
|
||||
201 + currentGrowthStage - 1
|
||||
} else 170 + currentGrowthStage - 1
|
||||
}
|
||||
|
||||
private fun grow(){
|
||||
if(isWeedy() && getCurrentState() > 0) {
|
||||
nextGrowth = System.currentTimeMillis() + 60000
|
||||
setCurrentState(getCurrentState() - 1)
|
||||
currentGrowthStage--
|
||||
return
|
||||
}
|
||||
|
||||
if(isDiseased){
|
||||
isDead = true
|
||||
return
|
||||
}
|
||||
|
||||
diseaseMod = when(compost){
|
||||
CompostType.NONE -> 0
|
||||
CompostType.NORMAL -> 8
|
||||
CompostType.SUPER -> 13
|
||||
}
|
||||
|
||||
if(patch != FarmingPatch.TROLL_STRONGHOLD_HERB && RandomFunction.random(128) <= (17 - diseaseMod) && !isWatered && !isGrown() && !protectionPaid && !isFlowerProtected() && patch.type != PatchType.EVIL_TURNIP ){
|
||||
//bush, tree, fruit tree, herb and cactus can not disease on stage 1(0) of growth.
|
||||
if(!((patch.type == PatchType.BUSH || patch.type == PatchType.TREE || patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.CACTUS || patch.type == PatchType.HERB) && currentGrowthStage == 0)) {
|
||||
isDiseased = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if((patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.TREE || patch.type == PatchType.BUSH || patch.type == PatchType.CACTUS) && plantable != null && plantable?.stages == currentGrowthStage + 1){
|
||||
isCheckHealth = true
|
||||
}
|
||||
|
||||
if((patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.BUSH || patch.type == PatchType.CACTUS) && plantable?.stages == currentGrowthStage){
|
||||
if((patch.type == PatchType.BUSH && getFruitOrBerryCount() < 4) || (patch.type == PatchType.FRUIT_TREE && getFruitOrBerryCount() < 6) || (patch.type == PatchType.CACTUS && getFruitOrBerryCount() < 3)){
|
||||
setCurrentState(getCurrentState() + 1)
|
||||
}
|
||||
}
|
||||
if(patch.type == PatchType.TREE) {
|
||||
// Willow branches
|
||||
if(harvestAmt < 6) {
|
||||
harvestAmt++;
|
||||
}
|
||||
}
|
||||
|
||||
if(plantable?.stages ?: 0 > currentGrowthStage && !isGrown()){
|
||||
currentGrowthStage++
|
||||
setCurrentState(getCurrentState() + 1)
|
||||
isWatered = false
|
||||
}
|
||||
|
||||
regrowIfTreeStump()
|
||||
}
|
||||
|
||||
fun regrowIfTreeStump() {
|
||||
if(patch.type == PatchType.TREE && plantable != null) {
|
||||
// plantable.value + plantable.stages is the check-health stage, so +1 is the choppable tree, and +2 is the stump
|
||||
if(getCurrentState() == plantable!!.value + plantable!!.stages + 2) {
|
||||
setCurrentState(getCurrentState() - 1)
|
||||
isWatered = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun update(){
|
||||
grow()
|
||||
updateBit()
|
||||
}
|
||||
|
||||
fun plant(plantable: Plantable){
|
||||
nextGrowth = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(plantable.applicablePatch.stageGrowthTime.toLong())
|
||||
this.plantable = plantable
|
||||
isDead = false
|
||||
isDiseased = false
|
||||
currentGrowthStage = 0
|
||||
setCurrentState(plantable.value)
|
||||
}
|
||||
|
||||
fun clear(){
|
||||
isCheckHealth = false
|
||||
isDiseased = false
|
||||
isDead = false
|
||||
plantable = null
|
||||
player.varpManager.get(patch.varpIndex).clearBitRange(patch.varpOffset,patch.varpOffset + 7)
|
||||
nextGrowth = 0L
|
||||
currentGrowthStage = 3
|
||||
setCurrentState(3)
|
||||
compost = CompostType.NONE
|
||||
protectionPaid = false
|
||||
}
|
||||
|
||||
fun getFruitOrBerryCount() : Int {
|
||||
plantable ?: return 0
|
||||
return getCurrentState() - plantable!!.value - plantable!!.stages
|
||||
}
|
||||
|
||||
fun getStageGrowthMinutes() : Int {
|
||||
var minutes = patch.type.stageGrowthTime
|
||||
if(patch.type == PatchType.FRUIT_TREE && isGrown()) {
|
||||
// Fruit trees take 160 minutes per stage to grow, but
|
||||
// restocking their fruit should take 40 minutes per fruit
|
||||
minutes = 40
|
||||
}
|
||||
return minutes
|
||||
}
|
||||
|
||||
fun isFlowerProtected(): Boolean{
|
||||
if(patch.type != PatchType.ALLOTMENT) return false
|
||||
|
||||
val fpatch = when(patch){
|
||||
FarmingPatch.S_FALADOR_ALLOTMENT_SE,FarmingPatch.S_FALADOR_ALLOTMENT_NW -> FarmingPatch.S_FALADOR_FLOWER_C
|
||||
FarmingPatch.ARDOUGNE_ALLOTMENT_S,FarmingPatch.ARDOUGNE_ALLOTMENT_N -> FarmingPatch.ARDOUGNE_FLOWER_C
|
||||
FarmingPatch.CATHERBY_ALLOTMENT_S,FarmingPatch.CATHERBY_ALLOTMENT_N -> FarmingPatch.CATHERBY_FLOWER_C
|
||||
FarmingPatch.PORT_PHAS_ALLOTMENT_SE,FarmingPatch.PORT_PHAS_ALLOTMENT_NW -> FarmingPatch.PORT_PHAS_FLOWER_C
|
||||
else -> return false
|
||||
}.getPatchFor(player)
|
||||
|
||||
return (fpatch.plantable != null &&
|
||||
(fpatch.plantable == plantable?.protectionFlower || fpatch.plantable == Plantable.forItemID(Items.WHITE_LILY_SEED_14589))
|
||||
&& fpatch.isGrown())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.Items
|
||||
|
||||
object PatchRaker {
|
||||
val RAKE_ANIM = Animation(2273)
|
||||
|
||||
@JvmStatic
|
||||
fun rake(player: Player, patch: FarmingPatch){
|
||||
player.pulseManager.run(object : Pulse(){
|
||||
override fun pulse(): Boolean {
|
||||
var patchStage = patch.getPatchFor(player).getCurrentState()
|
||||
if(patchStage <= 2){
|
||||
player.animator.animate(RAKE_ANIM)
|
||||
player.audioManager.send(2442)
|
||||
}
|
||||
if(delay < 5) {
|
||||
delay = 5
|
||||
} else {
|
||||
patch.getPatchFor(player).currentGrowthStage++
|
||||
patch.getPatchFor(player).setCurrentState(++patchStage)
|
||||
player.inventory.add(Item(Items.WEEDS_6055))
|
||||
player.skills.addExperience(Skills.FARMING,4.0)
|
||||
}
|
||||
return patchStage >= 3
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
enum class PatchType(val stageGrowthTime: Int) {
|
||||
ALLOTMENT(10),
|
||||
HOPS(10),
|
||||
TREE(40),
|
||||
FRUIT_TREE(160),
|
||||
BUSH(20),
|
||||
FLOWER(5),
|
||||
HERB(20),
|
||||
SPIRIT_TREE(293),
|
||||
MUSHROOM(30),
|
||||
BELLADONNA(80),
|
||||
CACTUS(60),
|
||||
EVIL_TURNIP(5)
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.game.node.item.Item
|
||||
import org.rs09.consts.Items
|
||||
|
||||
enum class Plantable(val itemID: Int, val value: Int, val stages: Int, val plantingXP: Double, val harvestXP: Double, val checkHealthXP: Double, val requiredLevel: Int, val applicablePatch: PatchType, val harvestItem: Int, val protectionItem: Item? = null,val protectionFlower: Plantable? = null) {
|
||||
|
||||
//Flowers
|
||||
MARIGOLD_SEED(5096,8,4,8.5,47.0,0.0,2,PatchType.FLOWER,Items.MARIGOLDS_6010),
|
||||
ROSEMARY_SEED(5097,13,4,12.0,66.5,0.0,11,PatchType.FLOWER, Items.ROSEMARY_6014),
|
||||
NASTURTIUM_SEED(5098,18,4,19.5,111.0,0.0,24,PatchType.FLOWER,Items.NASTURTIUMS_6012),
|
||||
WOAD_SEED(5099,23,4,20.5,115.5,0.0,25,PatchType.FLOWER,Items.WOAD_LEAF_1793),
|
||||
LIMPWURT_SEED(5100,28,4,21.5,120.0,0.0,26,PatchType.FLOWER,Items.LIMPWURT_ROOT_225),
|
||||
WHITE_LILY_SEED(14589,37,4,42.0,250.0,0.0,52,PatchType.FLOWER,Items.WHITE_LILY_14583),
|
||||
|
||||
//Flower(Technically)
|
||||
SCARECROW(6059,33,3,0.0,0.0,0.0,23,PatchType.FLOWER,Items.SCARECROW_6059),
|
||||
|
||||
//Allotments
|
||||
POTATO_SEED(5318, 6, 4, 8.0, 9.0, 0.0, 1, PatchType.ALLOTMENT, Items.POTATO_1942,Item(Items.COMPOST_6032,2),MARIGOLD_SEED),
|
||||
ONION_SEED(5319, 13, 4, 9.5, 10.5,0.0, 5, PatchType.ALLOTMENT,Items.ONION_1957,Item(Items.POTATOES10_5438),MARIGOLD_SEED),
|
||||
CABBAGE_SEED(5324, 20, 4, 10.0, 11.5, 0.0,7, PatchType.ALLOTMENT,Items.CABBAGE_1965,Item(Items.ONIONS10_5458),ROSEMARY_SEED),
|
||||
TOMATO_SEED(5322,27,4,12.5,14.0,0.0,12,PatchType.ALLOTMENT,Items.TOMATO_1982,Item(Items.CABBAGES10_5478,2),MARIGOLD_SEED),
|
||||
SWEETCORN_SEED(5320,34,6,17.0,19.0,0.0,20,PatchType.ALLOTMENT,Items.SWEETCORN_5986,Item(Items.JUTE_FIBRE_5931,10),SCARECROW),
|
||||
STRAWBERRY_SEED(5323,43,6,26.0,29.0,0.0,31,PatchType.ALLOTMENT,Items.STRAWBERRY_5504,Item(Items.APPLES5_5386)),
|
||||
WATERMELON_SEED(5321,52,8,48.5,54.5,0.0,47,PatchType.ALLOTMENT,Items.WATERMELON_5982,Item(Items.CURRY_LEAF_5970,10),NASTURTIUM_SEED),
|
||||
|
||||
//Hops
|
||||
BARLEY_SEED(5305,49,4,8.5,9.5,0.0,3,PatchType.HOPS,Items.BARLEY_6006,Item(Items.COMPOST_6032,3)),
|
||||
HAMMERSTONE_SEED(5307,4,4,9.0,10.0,0.0,4,PatchType.HOPS,Items.HAMMERSTONE_HOPS_5994,Item(Items.MARIGOLDS_6010)),
|
||||
ASGARNIAN_SEED(5308,11,5,10.9,12.0,0.0,8,PatchType.HOPS,Items.ASGARNIAN_HOPS_5996,Item(Items.ONIONS10_5458)),
|
||||
JUTE_SEED(5306,56,5,13.0,14.5,0.0,13,PatchType.HOPS,Items.JUTE_FIBRE_5931,Item(Items.BARLEY_MALT_6008,6)),
|
||||
YANILLIAN_SEED(5309,19,6,14.5,16.0,0.0,16,PatchType.HOPS,Items.YANILLIAN_HOPS_5998,Item(Items.TOMATOES5_5968)),
|
||||
KRANDORIAN_SEED(5310,28,7,17.5,19.5,0.0,21,PatchType.HOPS,Items.KRANDORIAN_HOPS_6000,Item(Items.CABBAGES10_5478,3)),
|
||||
WILDBLOOD_SEED(5311,38,8,23.0,26.0,0.0,28,PatchType.HOPS,Items.WILDBLOOD_HOPS_6002,Item(Items.NASTURTIUMS_6012)),
|
||||
|
||||
//Trees
|
||||
OAK_SAPLING(5370,8,4,14.0,0.0,467.3,15,PatchType.TREE,Items.OAK_ROOTS_6043,Item(Items.TOMATOES5_5968)),
|
||||
WILLOW_SAPLING(5371,15,6,25.0,0.0,1456.5,30,PatchType.TREE,Items.WILLOW_ROOTS_6045,Item(Items.APPLES5_5386)),
|
||||
MAPLE_SAPLING(5372,24,8,45.0,0.0,3403.4,45,PatchType.TREE,Items.MAPLE_ROOTS_6047,Item(Items.ORANGES5_5396)),
|
||||
YEW_SAPLING(5373,35,10,81.0,0.0,7069.9,60,PatchType.TREE,Items.YEW_ROOTS_6049,Item(Items.CACTUS_SPINE_6016,10)),
|
||||
MAGIC_SAPLING(5374,48,12,145.5,0.0,13768.3,75,PatchType.TREE,Items.MAGIC_ROOTS_6051,Item(Items.COCONUT_5974,25)),
|
||||
|
||||
//Fruit Trees
|
||||
APPLE_SAPLING(5496,8,6,22.0,8.5,1199.5,27,PatchType.FRUIT_TREE,Items.COOKING_APPLE_1955,Item(Items.SWEETCORN_5986,9)),
|
||||
BANANA_SAPLING(5497,35,6,28.0,10.5,1750.5,33,PatchType.FRUIT_TREE,Items.BANANA_1963,Item(Items.APPLES5_5386,4)),
|
||||
ORANGE_SAPLING(5498,72,6,35.5,13.5,2470.2,39,PatchType.FRUIT_TREE,Items.ORANGE_2108,Item(Items.STRAWBERRIES5_5406,3)),
|
||||
CURRY_SAPLING(5499,99,6,40.0,15.0,2906.9,42,PatchType.FRUIT_TREE,Items.CURRY_LEAF_5970,Item(Items.BANANAS5_5416,5)),
|
||||
PINEAPPLE_SAPLING(5500,136,6,57.0,21.5,4605.7,51,PatchType.FRUIT_TREE,Items.PINEAPPLE_2114,Item(Items.WATERMELON_5982,10)),
|
||||
PAPAYA_SAPLING(5501,163,6,72.0,27.0,6146.4,57,PatchType.FRUIT_TREE,Items.PAPAYA_FRUIT_5972,Item(Items.PINEAPPLE_2114,10)),
|
||||
PALM_SAPLING(5502,200,6,110.5,41.5,10150.1,68,PatchType.FRUIT_TREE,Items.COCONUT_5974,Item(Items.PAPAYA_FRUIT_5972,15)),
|
||||
|
||||
//Bushes
|
||||
REDBERRY_SEED(5101,5,5,11.5,4.5,64.0,10,PatchType.BUSH,Items.REDBERRIES_1951,Item(Items.CABBAGES10_5478,4)),
|
||||
CADAVABERRY_SEED(5102,15,6,18.0,7.0,102.5,22,PatchType.BUSH,Items.CADAVA_BERRIES_753,Item(Items.TOMATOES5_5968,3)),
|
||||
DWELLBERRY_SEED(5103,26,27,31.5,12.0,177.5,36,PatchType.BUSH,Items.DWELLBERRIES_2126,Item(Items.STRAWBERRIES5_5406,3)),
|
||||
JANGERBERRY_SEED(5104,38,8,50.5,19.0,284.5,48,PatchType.BUSH,Items.JANGERBERRIES_247,Item(Items.WATERMELON_5982,6)),
|
||||
WHITEBERRY_SEED(5105,51,8,78.0,29.0,437.5,59,PatchType.BUSH,Items.WHITE_BERRIES_239,null),
|
||||
POISON_IVY_SEED(5106,197,8,120.0,45.0,675.0,70,PatchType.BUSH,Items.POISON_IVY_BERRIES_6018,null),
|
||||
|
||||
//Herbs
|
||||
GUAM_SEED(5291,4,4,11.0,12.5,0.0,9,PatchType.HERB,Items.GRIMY_GUAM_199),
|
||||
MARRENTILL_SEED(5292,11,4,13.5,15.0,0.0,14,PatchType.HERB,Items.GRIMY_MARRENTILL_201),
|
||||
TARROMIN_SEED(5293,18,4,16.0,18.0,0.0,19,PatchType.HERB,Items.GRIMY_TARROMIN_203),
|
||||
HARRALANDER_SEED(5294,25,4,21.5,24.0,0.0,26,PatchType.HERB,Items.GRIMY_HARRALANDER_205),
|
||||
RANARR_SEED(5295,32,4,27.0,30.5,0.0,32,PatchType.HERB,Items.GRIMY_RANARR_207),
|
||||
AVANTOE_SEED(5298,39,4,54.5,61.5,0.0,50,PatchType.HERB,Items.GRIMY_AVANTOE_211),
|
||||
TOADFLAX_SEED(5296,46,4,34.0,38.5,0.0,38,PatchType.HERB,Items.GRIMY_TOADFLAX_3049),
|
||||
IRIT_SEED(5297,53,4,43.0,48.5,0.0,44,PatchType.HERB,Items.GRIMY_IRIT_209),
|
||||
KWUARM_SEED(5299,68,4,69.0,78.0,0.0,56,PatchType.HERB,Items.GRIMY_KWUARM_213),
|
||||
SNAPDRAGON_SEED(5300,75,4,87.5,98.5,0.0,62,PatchType.HERB,Items.GRIMY_SNAPDRAGON_3051),
|
||||
CADANTINE_SEED(5301,82,4,106.5,120.0,0.0,67,PatchType.HERB,Items.GRIMY_CADANTINE_215),
|
||||
LANTADYME_SEED(5302,89,4,134.5,151.5,0.0,73,PatchType.HERB,Items.GRIMY_LANTADYME_2485),
|
||||
DWARF_WEED_SEED(5303,96,4,170.5,192.0,0.0,79,PatchType.HERB,Items.GRIMY_DWARF_WEED_217),
|
||||
TORSTOL_SEED(5304,103,4,199.5,224.5,0.0,85,PatchType.HERB,Items.GRIMY_TORSTOL_219),
|
||||
GOUT_TUBER(6311,192,4,105.0,45.0,0.0,29,PatchType.HERB,Items.GOUTWEED_3261),
|
||||
SPIRIT_WEED_SEED(12176, 204, 4, 32.0, 36.0, 0.0, 36, PatchType.HERB, Items.GRIMY_SPIRIT_WEED_12174),
|
||||
|
||||
//Other
|
||||
BELLADONNA_SEED(5281, 4, 4, 91.0, 128.0, 0.0, 63, PatchType.BELLADONNA, Items.CAVE_NIGHTSHADE_2398),
|
||||
MUSHROOM_SPORE(Items.MUSHROOM_SPORE_5282, 6, 7, 61.5, 57.7, 0.0, 53, PatchType.MUSHROOM, Items.MUSHROOM_6004),
|
||||
CACTUS_SEED(Items.CACTUS_SEED_5280, 8, 7, 66.5, 25.0, 374.0, 55, PatchType.CACTUS, Items.CACTUS_SPINE_6016),
|
||||
EVIL_TURNIP_SEED(Items.EVIL_TURNIP_SEED_12148, 4, 1, 41.0, 46.0, 0.0, 42, PatchType.EVIL_TURNIP, Items.EVIL_TURNIP_12134)
|
||||
;
|
||||
|
||||
constructor(itemID: Int, value: Int, stages: Int, plantingXP: Double, harvestXP: Double, checkHealthXP: Double, requiredLevel: Int, applicablePatch: PatchType, harvestItem: Int, protectionFlower: Plantable)
|
||||
: this(itemID,value,stages,plantingXP,harvestXP,checkHealthXP,requiredLevel,applicablePatch,harvestItem,null,protectionFlower)
|
||||
companion object {
|
||||
@JvmField
|
||||
val plantables = values().map { it.itemID to it }.toMap()
|
||||
|
||||
@JvmStatic
|
||||
fun forItemID(id: Int): Plantable?{
|
||||
return plantables[id]
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun forItem(item: Item): Plantable?{
|
||||
return forItemID(item.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.cache.def.impl.ItemDefinition
|
||||
import core.game.interaction.OptionHandler
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import org.rs09.consts.Items
|
||||
|
||||
@Initializable
|
||||
class SackBasketOptionHandler : OptionHandler() {
|
||||
|
||||
private companion object {
|
||||
val fruit = arrayOf(Items.ORANGE_2108,Items.COOKING_APPLE_1955,Items.BANANA_1963,Items.STRAWBERRY_5504,Items.TOMATO_1982)
|
||||
val produce = arrayOf(Items.POTATO_1942,Items.ONION_1957,Items.CABBAGE_1965)
|
||||
}
|
||||
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
BasketsAndSacks.values().forEach { it.containers.forEach { id ->
|
||||
val def = ItemDefinition.forId(id)
|
||||
def.handlers["option:fill"] = this
|
||||
def.handlers["option:empty"] = this
|
||||
def.handlers["option:remove-one"] = this
|
||||
} }
|
||||
var def = ItemDefinition.forId(Items.EMPTY_SACK_5418)
|
||||
def.handlers["option:fill"] = this
|
||||
def = ItemDefinition.forId(Items.BASKET_5376)
|
||||
def.handlers["option:fill"] = this
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
player ?: return false
|
||||
node ?: return false
|
||||
|
||||
when(option){
|
||||
"fill" -> tryFill(player,node.asItem())
|
||||
"empty" -> tryEmpty(player,node.asItem())
|
||||
"remove-one" -> tryTakeOne(player,node.asItem())
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun tryFill(player: Player?, item: Item){
|
||||
player ?: return
|
||||
val containerID = item.id
|
||||
val appropriateProduce = getAppropriateProduce(player,containerID) ?: return
|
||||
val container = BasketsAndSacks.forId(containerID) ?: BasketsAndSacks.forId(appropriateProduce.id) ?: return
|
||||
val isLast = container.checkIsLast(containerID)
|
||||
val specific = container.checkWhich(containerID)
|
||||
val max = container.containers.size - 1
|
||||
|
||||
if(isLast){
|
||||
player.sendMessage("This is already full.")
|
||||
return
|
||||
}
|
||||
|
||||
if(specific + appropriateProduce.amount > max){
|
||||
appropriateProduce.amount = (max - specific)
|
||||
}
|
||||
|
||||
if(player.inventory.remove(item) && player.inventory.remove(appropriateProduce))
|
||||
player.inventory.add(Item(container.containers[specific + appropriateProduce.amount]))
|
||||
}
|
||||
|
||||
private fun tryEmpty(player: Player?, item: Item){
|
||||
val container = BasketsAndSacks.forId(item.id)
|
||||
if(container == null) return
|
||||
player ?: return
|
||||
|
||||
val emptyItem = if(produce.contains(container.produceID)) Items.EMPTY_SACK_5418 else Items.BASKET_5376
|
||||
val returnItem = Item(container.produceID,container.checkWhich(item.id) + 1)
|
||||
|
||||
if(!player.inventory.hasSpaceFor(returnItem)){
|
||||
player.sendMessage("You don't have enough inventory space to do this.")
|
||||
return
|
||||
}
|
||||
|
||||
if(player.inventory.remove(item)){
|
||||
player.inventory.add(Item(emptyItem))
|
||||
player.inventory.add(returnItem)
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryTakeOne(player: Player?,item: Item){
|
||||
val container = BasketsAndSacks.forId(item.id)
|
||||
if(container == null) return
|
||||
player ?: return
|
||||
|
||||
val emptyItem = if(produce.contains(container.produceID)) Items.EMPTY_SACK_5418 else Items.BASKET_5376
|
||||
val isLast = container.checkIsFirst(item.id)
|
||||
val withdrawnItem = Item(container.produceID)
|
||||
|
||||
if(!player.inventory.hasSpaceFor(withdrawnItem)){
|
||||
player.sendMessage("You don't have enough inventory space to do this.")
|
||||
return
|
||||
}
|
||||
|
||||
if(player.inventory.remove(item)){
|
||||
if(isLast){
|
||||
player.inventory.add(Item(emptyItem))
|
||||
} else {
|
||||
val it = Item(container.containers[container.checkWhich(item.id) - 1])
|
||||
player.inventory.add(it)
|
||||
}
|
||||
player.inventory.add(withdrawnItem)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAppropriateProduce(player: Player?, containerID: Int): Item?{
|
||||
player ?: return null
|
||||
val container = BasketsAndSacks.forId(containerID)
|
||||
val produce = if(container == null){
|
||||
var selected = 0
|
||||
if(containerID == Items.EMPTY_SACK_5418) {
|
||||
for (i in (produce)) {
|
||||
if (player.inventory.contains(i, 1)) {
|
||||
selected = i
|
||||
break
|
||||
}
|
||||
}
|
||||
selected
|
||||
} else {
|
||||
for (i in (fruit)) {
|
||||
if (player.inventory.contains(i, 1)) {
|
||||
selected = i
|
||||
break
|
||||
}
|
||||
}
|
||||
selected
|
||||
}
|
||||
} else {
|
||||
container.produceID
|
||||
}
|
||||
|
||||
return if(produce == 0) null else Item(produce,player.inventory.getAmount(produce))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.addItem
|
||||
import core.api.inInventory
|
||||
import core.api.removeItem
|
||||
import core.api.sendDialogue
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import org.rs09.consts.Items
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
|
||||
class SeedlingListener : InteractionListener {
|
||||
override fun defineListeners() {
|
||||
onUseWith(IntType.ITEM, TREE_SEEDS, Items.PLANT_POT_5354, handler = ::addSeedToPot)
|
||||
onUseWith(IntType.ITEM, TREE_SEEDLINGS, *WATERING_CANS, handler = ::waterSeedling)
|
||||
}
|
||||
|
||||
fun addSeedToPot(player: Player, used: Node, with: Node) : Boolean {
|
||||
val seed = used.asItem() ?: return false
|
||||
val pot = with.asItem() ?: return false
|
||||
|
||||
if(!inInventory(player, Items.GARDENING_TROWEL_5325)){
|
||||
sendDialogue(player, "You need a gardening trowel on you to do this.")
|
||||
return false
|
||||
}
|
||||
|
||||
val seedling = getSeedling(seed.id)
|
||||
if (seedling == -1) return false
|
||||
if (!removeItem(player, seed.id) || !removeItem(player, pot)) return true
|
||||
addItem(player, seedling)
|
||||
return true
|
||||
}
|
||||
|
||||
fun waterSeedling(player: Player, used: Node, with: Node) : Boolean {
|
||||
val seedling = used.asItem() ?: return false
|
||||
val can = with.asItem() ?: return false
|
||||
|
||||
val nextCan = can.id.getNext()
|
||||
val wateredSeedling = if (seedling.id > 5400) seedling.id + 8 else seedling.id + 6
|
||||
|
||||
if (!removeItem(player, can) || !removeItem(player, seedling)) return false
|
||||
addItem(player, wateredSeedling)
|
||||
addItem(player, nextCan)
|
||||
|
||||
var state = player.states["seedling"] as SeedlingState?
|
||||
|
||||
if (state != null) {
|
||||
state.addSeedling(wateredSeedling)
|
||||
return true
|
||||
}
|
||||
|
||||
state = player.registerState("seedling") as SeedlingState?
|
||||
state?.addSeedling(wateredSeedling)
|
||||
state?.init()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun Int.getNext(): Int{
|
||||
val index = WATERING_CANS.indexOf(this)
|
||||
if (index == -1) return Items.WATERING_CAN_5331
|
||||
return if (index != WATERING_CANS.size -1) WATERING_CANS[index + 1] else Items.WATERING_CAN_5331
|
||||
}
|
||||
fun getSeedling(id: Int) : Int {
|
||||
return when (id) {
|
||||
Items.ACORN_5312 -> Items.OAK_SEEDLING_5358
|
||||
Items.WILLOW_SEED_5313 -> Items.WILLOW_SEEDLING_5359
|
||||
Items.MAPLE_SEED_5314 -> Items.MAPLE_SEEDLING_5360
|
||||
Items.YEW_SEED_5315 -> Items.YEW_SEEDLING_5361
|
||||
Items.MAGIC_SEED_5316 -> Items.MAGIC_SEEDLING_5362
|
||||
Items.APPLE_TREE_SEED_5283 -> Items.APPLE_SEEDLING_5480
|
||||
Items.BANANA_TREE_SEED_5284 -> Items.BANANA_SEEDLING_5481
|
||||
Items.ORANGE_TREE_SEED_5285 -> Items.ORANGE_SEEDLING_5482
|
||||
Items.CURRY_TREE_SEED_5286 -> Items.CURRY_SEEDLING_5483
|
||||
Items.PINEAPPLE_SEED_5287 -> Items.PINEAPPLE_SEEDLING_5484
|
||||
Items.PAPAYA_TREE_SEED_5288 -> Items.PAPAYA_SEEDLING_5485
|
||||
Items.PALM_TREE_SEED_5289 -> Items.PALM_SEEDLING_5486
|
||||
Items.SPIRIT_SEED_5317 -> Items.SPIRIT_SEEDLING_5363
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
|
||||
val TREE_SEEDS = intArrayOf(
|
||||
Items.ACORN_5312,
|
||||
Items.WILLOW_SEED_5313,
|
||||
Items.MAPLE_SEED_5314,
|
||||
Items.YEW_SEED_5315,
|
||||
Items.MAGIC_SEED_5316,
|
||||
Items.APPLE_TREE_SEED_5283,
|
||||
Items.BANANA_TREE_SEED_5284,
|
||||
Items.ORANGE_TREE_SEED_5285,
|
||||
Items.CURRY_TREE_SEED_5286,
|
||||
Items.PINEAPPLE_SEED_5287,
|
||||
Items.PAPAYA_TREE_SEED_5288,
|
||||
Items.PALM_TREE_SEED_5289,
|
||||
Items.SPIRIT_SEED_5317
|
||||
)
|
||||
|
||||
val TREE_SEEDLINGS = intArrayOf(
|
||||
Items.OAK_SEEDLING_5358,
|
||||
Items.WILLOW_SEEDLING_5359,
|
||||
Items.MAPLE_SEEDLING_5360,
|
||||
Items.YEW_SEEDLING_5361,
|
||||
Items.MAGIC_SEEDLING_5362,
|
||||
Items.APPLE_SEEDLING_5480,
|
||||
Items.BANANA_SEEDLING_5481,
|
||||
Items.ORANGE_SEEDLING_5482,
|
||||
Items.CURRY_SEEDLING_5483,
|
||||
Items.PINEAPPLE_SEEDLING_5484,
|
||||
Items.PAPAYA_SEEDLING_5485,
|
||||
Items.PALM_SEEDLING_5486,
|
||||
Items.SPIRIT_SEEDLING_5363
|
||||
)
|
||||
|
||||
private val WATERING_CANS = intArrayOf(Items.WATERING_CAN8_5340,Items.WATERING_CAN7_5339,Items.WATERING_CAN6_5338,Items.WATERING_CAN5_5337,Items.WATERING_CAN4_5336,Items.WATERING_CAN3_5335,Items.WATERING_CAN2_5334,Items.WATERING_CAN1_5333)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
class Seedling(val id: Int, val TTL: Long, val sapling: Int) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.json.simple.JSONArray
|
||||
import org.json.simple.JSONObject
|
||||
import core.game.node.entity.state.PlayerState
|
||||
import core.game.node.entity.state.State
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@PlayerState("seedling")
|
||||
class SeedlingState(player: Player? = null) : State(player) {
|
||||
val seedlings = ArrayList<Seedling>()
|
||||
|
||||
fun addSeedling(seedling: Int){
|
||||
seedlings.add(Seedling(seedling, System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5),seedling + if(seedling > 5400) 8 else 6))
|
||||
}
|
||||
|
||||
override fun save(root: JSONObject) {
|
||||
val seedArray = JSONArray()
|
||||
for(s in seedlings){
|
||||
val seed = JSONObject()
|
||||
seed.put("id",s.id)
|
||||
seed.put("ttl",s.TTL)
|
||||
seed.put("sapling",s.sapling)
|
||||
seedArray.add(seed)
|
||||
}
|
||||
root.put("seedlings",seedArray)
|
||||
}
|
||||
|
||||
override fun parse(_data: JSONObject) {
|
||||
if(_data.containsKey("seedlings")){
|
||||
(_data["seedlings"] as JSONArray).forEach {
|
||||
val s = it as JSONObject
|
||||
val id = s["id"].toString().toInt()
|
||||
val ttl = s["ttl"].toString().toLong()
|
||||
val sapling = s["sapling"].toString().toInt()
|
||||
seedlings.add(Seedling(id,ttl,sapling))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newInstance(player: Player?): State {
|
||||
return SeedlingState(player)
|
||||
}
|
||||
|
||||
override fun createPulse() {
|
||||
if(seedlings.isEmpty()) return
|
||||
player ?: return
|
||||
|
||||
pulse = object : Pulse(5){
|
||||
override fun pulse(): Boolean {
|
||||
val removeList = ArrayList<Seedling>()
|
||||
GlobalScope.launch {
|
||||
for (seed in seedlings) {
|
||||
if (System.currentTimeMillis() > seed.TTL) {
|
||||
val inInventory = player.inventory.get(Item(seed.id))
|
||||
if (inInventory != null) {
|
||||
player.inventory.replace(Item(seed.sapling), inInventory.slot)
|
||||
removeList.add(seed)
|
||||
} else {
|
||||
val inBank = player.bank.get(Item(seed.id))
|
||||
if(inBank == null) removeList.add(seed)
|
||||
else {
|
||||
player.bank.remove(Item(inBank.id,1))
|
||||
player.bank.add(Item(seed.sapling))
|
||||
removeList.add(seed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
seedlings.removeAll(removeList)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.cache.def.impl.NPCDefinition
|
||||
import core.game.component.Component
|
||||
import core.game.dialogue.FacialExpression
|
||||
import core.game.interaction.OptionHandler
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import org.rs09.consts.Components
|
||||
import org.rs09.consts.NPCs
|
||||
import content.minigame.vinesweeper.Vinesweeper
|
||||
|
||||
val TL_IDS = arrayOf(NPCs.TOOL_LEPRECHAUN_3021,NPCs.GOTH_LEPRECHAUN_8000,NPCs.TOOL_LEPRECHAUN_4965,NPCs.TECLYN_2861)
|
||||
@Initializable
|
||||
class ToolLeprechaunHandler : OptionHandler() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
for(id in TL_IDS){
|
||||
val def = NPCDefinition.forId(id)
|
||||
def.handlers["option:exchange"] = this
|
||||
def.handlers["option:teleport"] = this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
node ?: return false
|
||||
when(option){
|
||||
"exchange" -> player?.interfaceManager?.open(Component(Components.FARMING_TOOLS_125))
|
||||
"teleport" -> Vinesweeper.Companion.VinesweeperTeleport.teleport(node!! as NPC, player!!)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.*
|
||||
import core.game.component.Component
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import org.rs09.consts.Components
|
||||
import org.rs09.consts.Items
|
||||
import core.game.interaction.InterfaceListener
|
||||
|
||||
private const val varp = 615
|
||||
class ToolLeprechaunInterface : InterfaceListener {
|
||||
|
||||
private val FARMING_TOOLS = Components.FARMING_TOOLS_125
|
||||
private val TOOLS_SIDE = Components.FARMING_TOOLS_SIDE_126
|
||||
|
||||
override fun defineInterfaceListeners() {
|
||||
|
||||
onOpen(FARMING_TOOLS){player, component ->
|
||||
player.varpManager?.flagSave(varp)
|
||||
player.interfaceManager.openSingleTab(Component(TOOLS_SIDE))
|
||||
return@onOpen true
|
||||
}
|
||||
|
||||
onClose(FARMING_TOOLS){player, _ ->
|
||||
player.interfaceManager.closeSingleTab()
|
||||
}
|
||||
|
||||
on(FARMING_TOOLS){player, _, opcode, buttonID, _, _ ->
|
||||
when(buttonID){
|
||||
33 -> doWithdrawal(player, Items.RAKE_5341,::setHasRake,::hasRake)
|
||||
34 -> doWithdrawal(player,Items.SEED_DIBBER_5343,::setHasDibber,::hasDibber)
|
||||
35 -> doWithdrawal(player,Items.SPADE_952,::setHasSpade,::hasSpade)
|
||||
36 -> {
|
||||
val sec = if(hasMagicSecateurs(player)) Items.MAGIC_SECATEURS_7409 else Items.SECATEURS_5329
|
||||
doWithdrawal(player,sec,::setHasSecateurs,::hasSecateurs)
|
||||
}
|
||||
37 -> {
|
||||
if(!hasWateringCan(player)){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those stored.")
|
||||
} else {
|
||||
player.inventory.add(Item(getWateringCan(player)))
|
||||
setNoWateringCan(player)
|
||||
}
|
||||
}
|
||||
38 -> doWithdrawal(player,Items.GARDENING_TROWEL_5325,::setHasGardeningTrowel,::hasGardeningTrowel)
|
||||
39 -> doStackedWithdrawal(player,Items.BUCKET_1925,getAmount(opcode),::updateBuckets,::getNumBuckets)
|
||||
40 -> doStackedWithdrawal(player,Items.COMPOST_6032,getAmount(opcode),::updateCompost,::getNumCompost)
|
||||
41 -> doStackedWithdrawal(player,Items.SUPERCOMPOST_6034,getAmount(opcode),::updateSuperCompost,::getNumSuperCompost)
|
||||
}
|
||||
player.varpManager.get(varp).send(player)
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(TOOLS_SIDE){player, _, opcode, buttonID, _, _ ->
|
||||
when(buttonID){
|
||||
18 -> doDeposit(player,Items.RAKE_5341,::setHasRake,::hasRake)
|
||||
19 -> doDeposit(player,Items.SEED_DIBBER_5343,::setHasDibber,::hasDibber)
|
||||
20 -> doDeposit(player,Items.SPADE_952,::setHasSpade,::hasSpade)
|
||||
21 -> {
|
||||
if(!player.inventory.contains(Items.SECATEURS_5329,1) && !player.inventory.contains(Items.MAGIC_SECATEURS_7409,1)){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those to store.")
|
||||
} else if (!hasSecateurs(player)){
|
||||
if(player.inventory.contains(Items.MAGIC_SECATEURS_7409,1)){
|
||||
player.inventory.remove(Item(Items.MAGIC_SECATEURS_7409))
|
||||
setHasSecateurs(player,true)
|
||||
setHasMagicSecateurs(player,true)
|
||||
} else {
|
||||
player.inventory.remove(Item(Items.SECATEURS_5329))
|
||||
setHasSecateurs(player,true)
|
||||
setHasMagicSecateurs(player,false)
|
||||
}
|
||||
} else {
|
||||
player.dialogueInterpreter.sendDialogue("You already have one of those stored.")
|
||||
}
|
||||
}
|
||||
22 -> {
|
||||
val can = getHighestCan(player)
|
||||
if(can == null){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those to store.")
|
||||
} else if(!hasWateringCan(player)){
|
||||
player.inventory.remove(can)
|
||||
setWateringCan(player,can)
|
||||
} else {
|
||||
player.dialogueInterpreter.sendDialogue("You already have one of those stored.")
|
||||
}
|
||||
}
|
||||
23 -> doDeposit(player,Items.GARDENING_TROWEL_5325,::setHasGardeningTrowel,::hasGardeningTrowel)
|
||||
24 -> doStackedDeposit(player,Items.BUCKET_1925,getAmount(opcode),::updateBuckets,::getNumBuckets)
|
||||
25 -> doStackedDeposit(player,Items.COMPOST_6032,getAmount(opcode),::updateCompost,::getNumCompost)
|
||||
26 -> doStackedDeposit(player,Items.SUPERCOMPOST_6034,getAmount(opcode),::updateSuperCompost,::getNumSuperCompost)
|
||||
}
|
||||
player.varpManager.get(varp).send(player)
|
||||
return@on true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun doWithdrawal(player: Player?, item: Int, withdrawMethod: (Player?,Boolean) -> Unit, checkMethod: (Player?) -> Boolean){
|
||||
player ?: return
|
||||
if(!checkMethod.invoke(player)){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those stored.")
|
||||
} else {
|
||||
if(!player.inventory.hasSpaceFor(Item(item))){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have enough space for that.")
|
||||
return
|
||||
}
|
||||
withdrawMethod.invoke(player,false)
|
||||
player.inventory.add(Item(item))
|
||||
}
|
||||
}
|
||||
|
||||
private fun doDeposit(player: Player?, item: Int, depositMethod: (Player?,Boolean) -> Unit, checkMethod: (Player?) -> Boolean){
|
||||
player ?: return
|
||||
if(!player.inventory.contains(item,1)){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those to store.")
|
||||
}
|
||||
if(!checkMethod.invoke(player)){
|
||||
depositMethod.invoke(player,true)
|
||||
player.inventory.remove(Item(item))
|
||||
} else {
|
||||
player.dialogueInterpreter.sendDialogue("You already have one of those stored.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun doStackedDeposit(player: Player?, item: Int, amount: Int, updateQuantityMethod: (Player?, Int) -> Unit, quantityCheckMethod: (Player?) -> Int){
|
||||
player ?: return
|
||||
val hasAmount = player.inventory.getAmount(item)
|
||||
var finalAmount = amount
|
||||
val spaceLeft = (if(item == Items.BUCKET_1925) 31 else 255) - quantityCheckMethod.invoke(player)
|
||||
|
||||
if(hasAmount == 0){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those to store.")
|
||||
return
|
||||
}
|
||||
|
||||
if(amount == -2){
|
||||
sendInputDialogue(player, true, "Enter the amount:"){value ->
|
||||
var amt = value as Int
|
||||
if(amt > hasAmount){
|
||||
amt = hasAmount
|
||||
}
|
||||
if(amt > spaceLeft){
|
||||
amt = spaceLeft
|
||||
}
|
||||
if(amt == 0){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those to store.")
|
||||
return@sendInputDialogue
|
||||
}
|
||||
player.inventory.remove(Item(item,amt))
|
||||
updateQuantityMethod.invoke(player,amt)
|
||||
player.varpManager.get(varp).send(player)
|
||||
}
|
||||
return
|
||||
}
|
||||
if(amount == -1){
|
||||
finalAmount = hasAmount
|
||||
if(finalAmount > spaceLeft){
|
||||
finalAmount = spaceLeft
|
||||
}
|
||||
}
|
||||
|
||||
if(finalAmount > hasAmount){
|
||||
finalAmount = hasAmount
|
||||
}
|
||||
if(finalAmount > spaceLeft) finalAmount = spaceLeft
|
||||
|
||||
if(!player.inventory.contains(item,finalAmount)){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those to store.")
|
||||
return
|
||||
}
|
||||
|
||||
if(finalAmount > spaceLeft){
|
||||
player.dialogueInterpreter.sendDialogue("You can't store any more of those.")
|
||||
return
|
||||
}
|
||||
|
||||
player.inventory.remove(Item(item,finalAmount))
|
||||
updateQuantityMethod.invoke(player,finalAmount)
|
||||
}
|
||||
|
||||
private fun doStackedWithdrawal(player: Player?,item: Int, amount: Int,updateQuantityMethod: (Player?,Int) -> Unit, quantityCheckMethod: (Player?) -> Int){
|
||||
player ?: return
|
||||
val hasAmount = quantityCheckMethod.invoke(player)
|
||||
var finalAmount = amount
|
||||
if(hasAmount == 0){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have any of those stored.")
|
||||
} else {
|
||||
if(amount == -2){
|
||||
sendInputDialogue(player, true, "Enter the amount:"){value ->
|
||||
var amt = value as Int
|
||||
if(amt > hasAmount){
|
||||
amt = hasAmount
|
||||
}
|
||||
if(amt > player.inventory.freeSlots()){
|
||||
amt = player.inventory.freeSlots()
|
||||
}
|
||||
if(amt <= 0){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have enough inventory space for that.")
|
||||
} else {
|
||||
player.inventory.add(Item(item, amt))
|
||||
updateQuantityMethod.invoke(player, -amt)
|
||||
player.varpManager.get(varp).send(player)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if(amount == -1){
|
||||
finalAmount = player.inventory.freeSlots()
|
||||
}
|
||||
if(finalAmount > hasAmount){
|
||||
finalAmount = hasAmount
|
||||
}
|
||||
if(!player.inventory.hasSpaceFor(Item(item,finalAmount)) || finalAmount == 0){
|
||||
player.dialogueInterpreter.sendDialogue("You don't have enough inventory space for that.")
|
||||
return
|
||||
}
|
||||
player.inventory.add(Item(item,finalAmount))
|
||||
updateQuantityMethod.invoke(player,-finalAmount)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAmount(opcode: Int): Int{
|
||||
return when(opcode) {
|
||||
155 -> 1
|
||||
196 -> 5
|
||||
124 -> -1
|
||||
199 -> -2
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasRake(player: Player?): Boolean{
|
||||
return checkBit(player,0)
|
||||
}
|
||||
|
||||
private fun setHasRake(player: Player?,hasRake: Boolean){
|
||||
player?.varpManager?.get(varp)?.setVarbit(0,if(hasRake) 1 else 0)
|
||||
}
|
||||
|
||||
private fun hasDibber(player: Player?): Boolean{
|
||||
return checkBit(player,1)
|
||||
}
|
||||
|
||||
private fun setHasDibber(player: Player?,hasDibber: Boolean){
|
||||
player?.varpManager?.get(varp)?.setVarbit(1,if(hasDibber) 1 else 0)
|
||||
}
|
||||
|
||||
private fun hasSpade(player: Player?): Boolean{
|
||||
return checkBit(player,2)
|
||||
}
|
||||
|
||||
private fun setHasSpade(player: Player?,hasSpade: Boolean){
|
||||
player?.varpManager?.get(varp)?.setVarbit(2,if(hasSpade) 1 else 0)
|
||||
}
|
||||
|
||||
private fun hasSecateurs(player: Player?): Boolean{
|
||||
return checkBit(player,3)
|
||||
}
|
||||
|
||||
private fun setHasSecateurs(player: Player?,hasSecateurs: Boolean){
|
||||
player?.varpManager?.get(varp)?.setVarbit(3,if(hasSecateurs) 1 else 0)
|
||||
}
|
||||
|
||||
private fun hasWateringCan(player: Player?): Boolean{
|
||||
return checkBitRange(player,4,7) > 0
|
||||
}
|
||||
|
||||
private fun getWateringCan(player: Player?): Int{
|
||||
var can = checkBitRange(player,4,7) //Watering cans are stored in the Varp as a number between 1 and 9. Watering Can(0) is 1 and Watering Can(8) is 9
|
||||
if(can == 1) can = 0
|
||||
return Items.WATERING_CAN_5331 + can
|
||||
}
|
||||
|
||||
private fun setWateringCan(player: Player?, item: Item){
|
||||
val can = when(item.id){
|
||||
Items.WATERING_CAN_5331 -> 1
|
||||
Items.WATERING_CAN1_5333 -> 2
|
||||
Items.WATERING_CAN2_5334 -> 3
|
||||
Items.WATERING_CAN3_5335 -> 4
|
||||
Items.WATERING_CAN4_5336 -> 5
|
||||
Items.WATERING_CAN5_5337 -> 6
|
||||
Items.WATERING_CAN6_5338 -> 7
|
||||
Items.WATERING_CAN7_5339 -> 8
|
||||
Items.WATERING_CAN8_5340 -> 9
|
||||
else -> 0
|
||||
}
|
||||
player?.varpManager?.get(varp)?.setVarbit(4,can)
|
||||
}
|
||||
|
||||
private fun setNoWateringCan(player: Player?){
|
||||
player?.varpManager?.get(varp)?.setVarbit(4,0)
|
||||
}
|
||||
|
||||
private fun hasGardeningTrowel(player: Player?): Boolean {
|
||||
return checkBit(player,8)
|
||||
}
|
||||
|
||||
private fun setHasGardeningTrowel(player: Player?,hasTrowel: Boolean){
|
||||
player?.varpManager?.get(varp)?.setVarbit(8,if(hasTrowel) 1 else 0)
|
||||
}
|
||||
|
||||
private fun getNumBuckets(player: Player?): Int {
|
||||
return checkBitRange(player,9,13)
|
||||
}
|
||||
|
||||
private fun updateBuckets(player: Player?,amount: Int){
|
||||
player?.varpManager?.get(varp)?.setVarbit(9,getNumBuckets(player) + amount)
|
||||
}
|
||||
|
||||
private fun getNumCompost(player: Player?): Int {
|
||||
return checkBitRange(player,14,21)
|
||||
}
|
||||
|
||||
private fun updateCompost(player: Player?,amount: Int){
|
||||
player?.varpManager?.get(varp)?.setVarbit(14,getNumCompost(player) + amount)
|
||||
}
|
||||
|
||||
private fun getNumSuperCompost(player: Player?): Int {
|
||||
return checkBitRange(player,22,29)
|
||||
}
|
||||
|
||||
private fun updateSuperCompost(player: Player?,amount: Int){
|
||||
player?.varpManager?.get(varp)?.setVarbit(22,getNumSuperCompost(player) + amount)
|
||||
}
|
||||
|
||||
private fun hasMagicSecateurs(player: Player?): Boolean {
|
||||
return checkBit(player,30)
|
||||
}
|
||||
|
||||
private fun setHasMagicSecateurs(player: Player?,hasMagic: Boolean){
|
||||
player?.varpManager?.get(varp)?.setVarbit(30,if(hasMagic) 1 else 0)
|
||||
}
|
||||
|
||||
private fun checkBitRange(player: Player?,start: Int, end: Int): Int{
|
||||
return (player?.varpManager?.get(varp)?.getBitRangeValue(start,end) ?: 0) ushr start
|
||||
}
|
||||
|
||||
private fun checkBit(player: Player?,offset: Int): Boolean{
|
||||
return player?.varpManager?.get(varp)?.getVarbitValue(offset) == 1
|
||||
}
|
||||
|
||||
private fun getHighestCan(player: Player?): Item?{
|
||||
player ?: return null
|
||||
var highestCan = Item(0)
|
||||
for(item in player.inventory.toArray()){
|
||||
if(item == null) continue
|
||||
if(item.name.contains("Watering")){
|
||||
if(item.id > highestCan.id) highestCan = item
|
||||
}
|
||||
}
|
||||
return if(highestCan.id == 0) null else highestCan
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.toIntArray
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.Items
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
|
||||
class UseWithBinHandler : InteractionListener {
|
||||
@JvmField
|
||||
val allowedNodes = ArrayList<Int>(100)
|
||||
val fillAnim = Animation(832)
|
||||
val compostPotionAnimation = Animation(2259)
|
||||
val scoopAnimation = Animation(8905)
|
||||
|
||||
val bins = 7836..7840
|
||||
|
||||
override fun defineListeners() {
|
||||
loadNodes()
|
||||
onUseWith(IntType.SCENERY, allowedNodes.toIntArray(), *bins.toIntArray()) { player, usedNode, with ->
|
||||
val cBin = CompostBins.forObject(with.asScenery()) ?: return@onUseWith true
|
||||
val bin = cBin.getBinForPlayer(player)
|
||||
val used = usedNode.id
|
||||
|
||||
|
||||
when(used){
|
||||
Items.COMPOST_POTION1_6476,Items.COMPOST_POTION2_6474, Items.COMPOST_POTION3_6472,Items.COMPOST_POTION4_6470 -> {
|
||||
if(!bin.isSuperCompost && bin.isFinished && !bin.isClosed){
|
||||
player.animator.animate(compostPotionAnimation)
|
||||
player.pulseManager.run(object : Pulse(compostPotionAnimation.duration){
|
||||
override fun pulse(): Boolean {
|
||||
if(player.inventory.remove(usedNode.asItem())) {
|
||||
bin.convert()
|
||||
player.inventory.add(Item(used.getNext()))
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
player.dialogueInterpreter.sendDialogue("You can only do this with an open bin of","finished regular compost.")
|
||||
}
|
||||
}
|
||||
|
||||
Items.BUCKET_1925 -> {
|
||||
if(bin.isFinished && !bin.isClosed){
|
||||
player.pulseManager.run(object : Pulse(scoopAnimation.duration){
|
||||
override fun pulse(): Boolean {
|
||||
if(!player.inventory.containsItem(usedNode.asItem())) return true
|
||||
player.animator.animate(scoopAnimation)
|
||||
val item = bin.takeItem()
|
||||
if(item != null && player.inventory.remove(usedNode.asItem())){
|
||||
player.inventory.add(item)
|
||||
}
|
||||
return item == null || !player.inventory.containsItem(usedNode.asItem())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
player.dialogueInterpreter.sendDialogue("You can only scoop an opened bin of finished compost.")
|
||||
}
|
||||
}
|
||||
|
||||
else ->
|
||||
if(bin.isFull()){
|
||||
player.sendMessage("This compost bin is already full.")
|
||||
return@onUseWith true
|
||||
} else {
|
||||
player.pulseManager.run(object : Pulse(fillAnim.duration){
|
||||
override fun pulse(): Boolean {
|
||||
player.animator.animate(fillAnim)
|
||||
if(player.inventory.remove(usedNode.asItem())){
|
||||
bin.addItem(usedNode.asItem())
|
||||
}
|
||||
return bin.isFull() || player.inventory.getAmount(usedNode.asItem()) == 0
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return@onUseWith true
|
||||
}
|
||||
}
|
||||
|
||||
fun loadNodes() {
|
||||
for(p in Plantable.values()){
|
||||
if(p.harvestItem != Items.SCARECROW_6059) {
|
||||
allowedNodes.add(p.harvestItem)
|
||||
}
|
||||
}
|
||||
allowedNodes.add(Items.COCONUT_SHELL_5978)
|
||||
allowedNodes.add(Items.WEEDS_6055)
|
||||
allowedNodes.add(Items.COMPOST_POTION4_6470)
|
||||
allowedNodes.add(Items.COMPOST_POTION3_6472)
|
||||
allowedNodes.add(Items.COMPOST_POTION2_6474)
|
||||
allowedNodes.add(Items.COMPOST_POTION1_6476)
|
||||
allowedNodes.add(Items.BUCKET_1925)
|
||||
}
|
||||
|
||||
private fun Int.getNext(): Int{
|
||||
if(this != 6476) return this + 2
|
||||
else return Items.VIAL_229
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
package content.global.skill.farming
|
||||
|
||||
import core.api.*
|
||||
import core.game.node.entity.player.link.diary.DiaryType
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.Items
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
|
||||
class UseWithPatchHandler : InteractionListener {
|
||||
val RAKE = Items.RAKE_5341
|
||||
val SEED_DIBBER = Items.SEED_DIBBER_5343
|
||||
val SPADE = Items.SPADE_952
|
||||
val SECATEURS = Items.SECATEURS_5329
|
||||
val TROWEL = Items.GARDENING_TROWEL_5325
|
||||
val pourBucketAnim = Animation(2283)
|
||||
val wateringCanAnim = Animation(2293)
|
||||
val plantCureAnim = Animation(2288)
|
||||
val secateursAnim = Animation(7227)
|
||||
|
||||
@JvmField
|
||||
val allowedNodes = ArrayList<Int>()
|
||||
val patches = ArrayList<Int>()
|
||||
|
||||
override fun defineListeners() {
|
||||
loadNodes()
|
||||
onUseWith(IntType.SCENERY, allowedNodes.toIntArray(), *patches.toIntArray()) { player, used, with ->
|
||||
val patch = FarmingPatch.forObject(with.asScenery()) ?: return@onUseWith true
|
||||
val usedItem = used.asItem()
|
||||
|
||||
player.faceLocation(with.location)
|
||||
when(usedItem.id){
|
||||
RAKE -> PatchRaker.rake(player,patch)
|
||||
SEED_DIBBER -> player.sendMessage("I should plant a seed, not the seed dibber.")
|
||||
SPADE -> player.dialogueInterpreter.open(67984003,patch.getPatchFor(player)) //DigUpPatchDialogue.kt
|
||||
SECATEURS -> {
|
||||
val p = patch.getPatchFor(player)
|
||||
if(patch.type == PatchType.TREE) {
|
||||
if(p.isDiseased && !p.isDead) {
|
||||
player.pulseManager.run(object: Pulse(){
|
||||
override fun pulse(): Boolean {
|
||||
player.animator.animate(secateursAnim)
|
||||
p.cureDisease()
|
||||
return true
|
||||
}
|
||||
})
|
||||
} else if(p.plantable == Plantable.WILLOW_SAPLING && p.harvestAmt > 0) {
|
||||
val pulse = CropHarvester.harvestPulse(player, with, Items.WILLOW_BRANCH_5933) ?: return@onUseWith false
|
||||
player.pulseManager.run(pulse)
|
||||
}
|
||||
}
|
||||
}
|
||||
TROWEL, Items.PLANT_POT_5350 -> {
|
||||
if(!player.inventory.containsAtLeastOneItem(TROWEL)) {
|
||||
player.sendMessage("You need a trowel to fill plant pots with dirt.")
|
||||
return@onUseWith true
|
||||
}
|
||||
val p = patch.getPatchFor(player)
|
||||
if(!p.isWeedy()){
|
||||
player.sendMessage("This patch has something growing in it.")
|
||||
return@onUseWith true
|
||||
} else if (p.currentGrowthStage != 3){
|
||||
player.sendMessage("I should clear this of weeds before trying to take some dirt.")
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
val potAmount = player.inventory.getAmount(Items.PLANT_POT_5350)
|
||||
|
||||
if(potAmount == 0){
|
||||
player.sendMessage("You have no plant pots to fill.")
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
val anim = Animation(2272)
|
||||
|
||||
player.pulseManager.run(object : Pulse(anim.duration){
|
||||
override fun pulse(): Boolean {
|
||||
if(player.inventory.remove(Item(Items.PLANT_POT_5350))){
|
||||
player.animator.animate(anim)
|
||||
player.inventory.add(Item(Items.PLANT_POT_5354))
|
||||
} else return true
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Items.PLANT_CURE_6036 -> {
|
||||
val p = patch.getPatchFor(player)
|
||||
if(p.isDiseased && !p.isDead){
|
||||
player.pulseManager.run(object: Pulse(){
|
||||
override fun pulse(): Boolean {
|
||||
player.animator.animate(plantCureAnim)
|
||||
player.audioManager.send(2438)
|
||||
if(player.inventory.remove(usedItem)){
|
||||
player.inventory.add(Item(Items.VIAL_229))
|
||||
p.cureDisease()
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
player.sendMessage("I have no reason to do this right now.")
|
||||
}
|
||||
}
|
||||
|
||||
Items.WATERING_CAN1_5333,Items.WATERING_CAN2_5334,Items.WATERING_CAN3_5335,Items.WATERING_CAN4_5336,Items.WATERING_CAN5_5337,Items.WATERING_CAN6_5338,Items.WATERING_CAN7_5339,Items.WATERING_CAN8_5340 -> {
|
||||
val p = patch.getPatchFor(player)
|
||||
val t = p.patch.type
|
||||
if(!p.isWatered && (t == PatchType.ALLOTMENT || t == PatchType.FLOWER || t == PatchType.HOPS) && !p.isGrown()){
|
||||
player.pulseManager.run(object : Pulse(){
|
||||
override fun pulse(): Boolean {
|
||||
if(p.isWeedy()){
|
||||
player.sendMessage("You should grow something first.")
|
||||
return true
|
||||
}
|
||||
player.animator.animate(wateringCanAnim)
|
||||
player.audioManager.send(2446)
|
||||
if(player.inventory.remove(usedItem)){
|
||||
player.inventory.add(Item(usedItem.id.getNext()))
|
||||
p.water()
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Items.SUPERCOMPOST_6034, Items.COMPOST_6032 -> {
|
||||
val p = patch.getPatchFor(player)
|
||||
if(p.compost == CompostType.NONE) {
|
||||
player.animator.animate(pourBucketAnim)
|
||||
player.audioManager.send(2427)
|
||||
player.pulseManager.run(object : Pulse(){
|
||||
override fun pulse(): Boolean {
|
||||
if(player.inventory.remove(usedItem,false)){
|
||||
p.compost = if(usedItem.id == Items.SUPERCOMPOST_6034) CompostType.SUPER else CompostType.NORMAL
|
||||
if(p.compost == CompostType.SUPER) rewardXP(player, Skills.FARMING, 26.0) else rewardXP(player, Skills.FARMING, 18.5)
|
||||
if(p.plantable != null && p.plantable?.applicablePatch != PatchType.FLOWER) {
|
||||
p.harvestAmt += if(p.compost == CompostType.NORMAL) 1 else if(p.compost == CompostType.SUPER) 2 else 0
|
||||
}
|
||||
p.cropLives += if(p.compost == CompostType.SUPER) 2 else 1
|
||||
player.inventory.add(Item(Items.BUCKET_1925))
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
player.sendMessage("This patch has already been treated with compost.")
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
val plantable = Plantable.forItemID(usedItem.id) ?: return@onUseWith false
|
||||
|
||||
if(plantable.applicablePatch != patch.type){
|
||||
player.sendMessage("You can't plant that seed in this patch.")
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
if(plantable.requiredLevel > player.skills.getLevel(Skills.FARMING)){
|
||||
player.sendMessage("You need a Farming level of ${plantable.requiredLevel} to plant this.")
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
val p = patch.getPatchFor(player)
|
||||
if(p.getCurrentState() < 3 && p.isWeedy()){
|
||||
player.sendMessage("You must weed your patch before you can plant a seed in it.")
|
||||
return@onUseWith true
|
||||
} else if(p.getCurrentState() > 3){
|
||||
player.sendMessage("There is already something growing in this patch.")
|
||||
return@onUseWith true
|
||||
}
|
||||
|
||||
val plantItem =
|
||||
if(patch.type == PatchType.ALLOTMENT) Item(plantable.itemID,3) else if(patch.type == PatchType.HOPS){
|
||||
if(plantable == Plantable.JUTE_SEED) Item(plantable.itemID,3) else Item(plantable.itemID,4)
|
||||
} else {
|
||||
Item(plantable.itemID,1)
|
||||
}
|
||||
|
||||
if(patch.type == PatchType.ALLOTMENT){
|
||||
if(!player.inventory.containsItem(plantItem)){
|
||||
player.sendMessage("You need 3 seeds to plant an allotment patch.")
|
||||
return@onUseWith true
|
||||
}
|
||||
}
|
||||
if(patch.type != PatchType.FRUIT_TREE && patch.type != PatchType.TREE){
|
||||
if(!player.inventory.contains(Items.SEED_DIBBER_5343,1)){
|
||||
player.sendMessage("You need a seed dibber to plant that.")
|
||||
return@onUseWith true
|
||||
}
|
||||
} else {
|
||||
if(!player.inventory.contains(Items.SPADE_952,1)){
|
||||
player.sendMessage("You need a spade to plant that.")
|
||||
return@onUseWith true
|
||||
}
|
||||
}
|
||||
player.lock()
|
||||
if(player.inventory.remove(plantItem)) {
|
||||
player.animator.animate(Animation(2291))
|
||||
player.audioManager.send(2432)
|
||||
player.pulseManager.run(object : Pulse(3) {
|
||||
override fun pulse(): Boolean {
|
||||
if(plantable == Plantable.JUTE_SEED && patch == FarmingPatch.MCGRUBOR_HOPS && !player.achievementDiaryManager.hasCompletedTask(DiaryType.SEERS_VILLAGE,0,7)){
|
||||
player.achievementDiaryManager.finishTask(player,DiaryType.SEERS_VILLAGE,0,7)
|
||||
}
|
||||
p.plant(plantable)
|
||||
player.skills.addExperience(Skills.FARMING, plantable.plantingXP)
|
||||
p.setNewHarvestAmount()
|
||||
if(p.patch.type == PatchType.TREE || p.patch.type == PatchType.FRUIT_TREE){
|
||||
player.inventory.add(Item(Items.PLANT_POT_5350))
|
||||
}
|
||||
player.unlock()
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return@onUseWith true
|
||||
}
|
||||
}
|
||||
|
||||
fun loadNodes(){
|
||||
patches.addAll(8550..8557) //allotment wrappers
|
||||
patches.addAll(7847..7853) //flower patch wrappers
|
||||
patches.addAll(8150..8156) //herb patch wrappers
|
||||
patches.addAll(8388..8391) // Tree patches
|
||||
patches.add(19147) //Tree patch
|
||||
patches.addAll(7962..7965) //fruit trees
|
||||
patches.addAll(8173..8176) //hops
|
||||
patches.addAll(7577..7580) //bush
|
||||
patches.add(23760) //evil turnip
|
||||
patches.add(7572) //belladonna
|
||||
patches.add(8337) //mushroom
|
||||
patches.add(27197) //jade vine
|
||||
patches.add(7771) //cactus
|
||||
patches.add(7807) //calquat
|
||||
patches.addAll(8382..8383)//spirit trees
|
||||
patches.add(8338) //spirit tree
|
||||
patches.add(18816) //death plateau wrapper
|
||||
for(p in Plantable.values()){
|
||||
allowedNodes.add(p.itemID)
|
||||
}
|
||||
allowedNodes.addAll(arrayListOf(RAKE,SEED_DIBBER,SPADE,SECATEURS,TROWEL,Items.SUPERCOMPOST_6034,Items.COMPOST_6032,Items.PLANT_CURE_6036,Items.WATERING_CAN1_5333,Items.WATERING_CAN2_5334,Items.WATERING_CAN3_5335,Items.WATERING_CAN4_5336,Items.WATERING_CAN5_5337,Items.WATERING_CAN6_5338,Items.WATERING_CAN7_5339,Items.WATERING_CAN8_5340, Items.PLANT_POT_5350))
|
||||
}
|
||||
|
||||
private fun Int.getNext(): Int {
|
||||
if(this == Items.WATERING_CAN1_5333) return Items.WATERING_CAN_5331
|
||||
else return this - 1
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user