Implemented pelting of rotten tomatoes
Added ability to define listeners for Player interactions and usewith interactions Added ability to flag listeners instant (no path walking) execution
This commit is contained in:
@@ -101,7 +101,7 @@ public class ChristmasEvent extends HolidayEvent {
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
if (isActive()) {
|
||||
ClassScanner.definePlugins(new ChristmasEventOptionPlugin(), new SnowmanItemHandler(), new SnowImpDialogue(), new SnowmanHatComponentPlugin(), new QueenOfSnowDialogue(), new SnowballItemPlugin(), new SnowmanNPC(), new PeltOptionHandler());
|
||||
ClassScanner.definePlugins(new ChristmasEventOptionPlugin(), new SnowmanItemHandler(), new SnowImpDialogue(), new SnowmanHatComponentPlugin(), new QueenOfSnowDialogue(), new SnowmanNPC(), new PeltOptionHandler());
|
||||
}
|
||||
return super.newInstance(arg);
|
||||
}
|
||||
@@ -1079,38 +1079,4 @@ public class ChristmasEvent extends HolidayEvent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the snow ball item plugin.
|
||||
* @author Vexia
|
||||
*
|
||||
*/
|
||||
public class SnowballItemPlugin implements Plugin<Object> {
|
||||
|
||||
@Override
|
||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||
BALL_OF_SNOW.getDefinition().getHandlers().put("equipment", this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fireEvent(String identifier, Object... args) {
|
||||
final Player player = (Player) args[0];
|
||||
@SuppressWarnings("unused")
|
||||
Item item = (Item) args[1];
|
||||
final Item other = args.length == 2 ? null : (Item) args[2];
|
||||
if (other != null) {
|
||||
identifier = "equip";
|
||||
}
|
||||
switch (identifier) {
|
||||
case "equip":
|
||||
player.getInteraction().set(PELT_OPTION);
|
||||
break;
|
||||
case "unequip":
|
||||
player.getInteraction().remove(PELT_OPTION);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,8 +322,11 @@ public final class InteractionPacket implements IncomingPacket {
|
||||
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
|
||||
return;
|
||||
}
|
||||
handleAIPLegion(player, 2, optionIndex, index);
|
||||
target.getInteraction().handle(player, option);
|
||||
|
||||
if (!InteractionListeners.run(-1, InteractionListener.Companion.getPLAYER(), option.getName().toLowerCase(), player, target)) {
|
||||
handleAIPLegion(player, 2, optionIndex, index);
|
||||
target.getInteraction().handle(player, option);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,6 +100,9 @@ public class ItemActionPacket implements IncomingPacket {
|
||||
if(PluginInteractionManager.handle(player,event)){
|
||||
return;
|
||||
}
|
||||
if(InteractionListeners.run(item, target, 4, player)){
|
||||
return;
|
||||
}
|
||||
if(player.getZoneMonitor().useWith(used,player)){
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.world.map.Location
|
||||
import rs09.game.system.SystemLogger
|
||||
|
||||
interface InteractionListener : ContentInterface{
|
||||
val ITEM: Int
|
||||
@@ -15,6 +16,8 @@ interface InteractionListener : ContentInterface{
|
||||
get() = 2
|
||||
val GROUNDITEM: Int
|
||||
get() = 3
|
||||
val PLAYER: Int
|
||||
get() = 4
|
||||
|
||||
fun on(id: Int, type: Int, vararg option: String, handler: (player: Player, node: Node) -> Boolean){
|
||||
InteractionListeners.add(id,type,option,handler)
|
||||
@@ -37,6 +40,9 @@ interface InteractionListener : ContentInterface{
|
||||
fun onUseAnyWith(type: Int, vararg with: Int, handler: (player: Player, used: Node, with: Node) -> Boolean) {
|
||||
InteractionListeners.add(type, with, handler)
|
||||
}
|
||||
fun onUseWithPlayer(vararg used: Int, handler: (player: Player, used: Node, with: Node) -> Boolean) {
|
||||
InteractionListeners.add(PLAYER, used, handler)
|
||||
}
|
||||
// Note: wildcard listeners incur overhead on every use-with interaction, only use them as a space-time tradeoff when something
|
||||
// is actually supposed to have a response to every item used with it (e.g. imp boxes, certain quest npcs)
|
||||
fun onUseWithWildcard(type: Int, predicate: (used: Int, with: Int) -> Boolean, handler: (player: Player, used: Node, with: Node) -> Boolean) {
|
||||
@@ -73,6 +79,11 @@ interface InteractionListener : ContentInterface{
|
||||
SpadeDigListener.registerListener(location,method)
|
||||
}
|
||||
|
||||
fun flagInstant() {
|
||||
val name = this::class.java.name
|
||||
InteractionListeners.instantClasses.add(name)
|
||||
}
|
||||
|
||||
fun defineListeners()
|
||||
|
||||
companion object
|
||||
@@ -81,5 +92,6 @@ interface InteractionListener : ContentInterface{
|
||||
val SCENERY = 1
|
||||
val NPC = 2
|
||||
val GROUNDITEM = 3
|
||||
val PLAYER = 4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ object InteractionListeners {
|
||||
private val useWithWildcardListeners = HashMap<Int, ArrayList<Pair<(Int, Int) -> Boolean, (Player, Node, Node) -> Boolean>>>(10)
|
||||
private val destinationOverrides = HashMap<String,(Entity, Node) -> Location>(100)
|
||||
private val equipListeners = HashMap<String,(Player,Node) -> Boolean>(10)
|
||||
val instantClasses = HashSet<String>()
|
||||
|
||||
@JvmStatic
|
||||
fun add(id: Int, type: Int, option: Array<out String>, method: (Player,Node) -> Boolean){
|
||||
@@ -161,7 +162,7 @@ object InteractionListeners {
|
||||
@JvmStatic
|
||||
fun run(used: Node, with: Node, type: Int,player: Player): Boolean{
|
||||
val flag = when(type){
|
||||
2 -> DestinationFlag.ENTITY
|
||||
2, 4 -> DestinationFlag.ENTITY
|
||||
1 -> DestinationFlag.OBJECT
|
||||
else -> DestinationFlag.OBJECT
|
||||
}
|
||||
@@ -170,7 +171,8 @@ object InteractionListeners {
|
||||
|
||||
var flipped = false
|
||||
|
||||
val method = get(used.id,with.id,type) ?: get(with.id,used.id,type).also { flipped = true } ?: return false
|
||||
val method = if (with is Player) get(-1, used.id, 4) ?: return false
|
||||
else get(used.id,with.id,type) ?: get(with.id,used.id,type).also { flipped = true } ?: return false
|
||||
|
||||
val destOverride = if(flipped) {
|
||||
getOverride(type, used.id, "use") ?: getOverride(type, with.id) ?: getOverride(type, "use")
|
||||
@@ -179,7 +181,7 @@ object InteractionListeners {
|
||||
}
|
||||
|
||||
|
||||
if(type != 0) {
|
||||
if(type != 0 && !isUseWithInstant(method)) {
|
||||
if(player.locks.isMovementLocked) return false
|
||||
player.pulseManager.run(object : MovementPulse(player, with, flag, destOverride) {
|
||||
override fun pulse(): Boolean {
|
||||
@@ -206,6 +208,7 @@ object InteractionListeners {
|
||||
@JvmStatic
|
||||
fun run(id: Int, type: Int, option: String, player: Player, node: Node): Boolean{
|
||||
val flag = when(type){
|
||||
4 -> DestinationFlag.ENTITY
|
||||
3 -> DestinationFlag.ITEM
|
||||
2 -> DestinationFlag.ENTITY
|
||||
1 -> null
|
||||
@@ -226,7 +229,7 @@ object InteractionListeners {
|
||||
return true
|
||||
}
|
||||
|
||||
if(type != 0) {
|
||||
if(type != 0 && !isInstant(method)) {
|
||||
if(player.locks.isMovementLocked) return false
|
||||
player.pulseManager.run(object : MovementPulse(player, node, flag, destOverride) {
|
||||
override fun pulse(): Boolean {
|
||||
@@ -257,4 +260,14 @@ object InteractionListeners {
|
||||
useAnyWithListeners["$w:$type"] = handler
|
||||
}
|
||||
}
|
||||
|
||||
fun isInstant(handler: (Player, Node) -> Boolean): Boolean {
|
||||
val className = handler.javaClass.name.substringBefore("$")
|
||||
return instantClasses.contains(className)
|
||||
}
|
||||
|
||||
fun isUseWithInstant(handler: (player: Player, used: Node, with: Node) -> Boolean): Boolean {
|
||||
val className = handler.javaClass.name.substringBefore("$")
|
||||
return instantClasses.contains(className)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
package rs09.game.interaction.player
|
||||
|
||||
import core.game.interaction.Interaction
|
||||
import core.game.interaction.OptionHandler
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.impl.Projectile
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import org.rs09.consts.Items
|
||||
import rs09.game.world.GameWorld
|
||||
import rs09.tools.stringtools.colorize
|
||||
|
||||
val snowball = Item(Items.SNOWBALL_11951)
|
||||
val THROW_ANIMATION = Animation(7530)
|
||||
val THROW_GRAPHICS = Graphics(860)
|
||||
|
||||
@Initializable
|
||||
class PeltOptionPlugin : OptionHandler() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
player ?: return false
|
||||
val other = node?.asPlayer()
|
||||
val delay = 41
|
||||
val speed = 60
|
||||
val distance = Location.getDistance(player.location, other?.getLocation()).toInt()
|
||||
val projectileSpeed = delay + speed + distance * 5
|
||||
val hitDelay = (projectileSpeed * .02857).toInt()
|
||||
|
||||
if(!Pathfinder.find(player,other,false, Pathfinder.PROJECTILE).isSuccessful){
|
||||
player.dialogueInterpreter.sendDialogue("You can't reach them!")
|
||||
return true
|
||||
}
|
||||
|
||||
if(player.inventory.remove(snowball) || player.equipment.remove(snowball)){
|
||||
player.lock()
|
||||
GameWorld.Pulser.submit(object : Pulse(hitDelay + 1){
|
||||
override fun pulse(): Boolean {
|
||||
other?.animator?.graphics(Graphics(1282))
|
||||
return true
|
||||
}
|
||||
})
|
||||
GameWorld.Pulser.submit(object : Pulse() {
|
||||
var counter = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (counter++) {
|
||||
0 -> {
|
||||
player.lock()
|
||||
player.face(other)
|
||||
player.animator.forceAnimation(THROW_ANIMATION)
|
||||
}
|
||||
1 -> {
|
||||
Projectile.create(player, other, 861, 30, 10).send()
|
||||
player.face(player)
|
||||
player.unlock()
|
||||
}
|
||||
5 -> other?.sendMessage(colorize("%R${player.username} has pelted you with a snowball."))
|
||||
6 -> return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
player.sendMessage("You have no more snowballs.")
|
||||
Interaction.sendOption(player, 0, "null")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isWalk(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package rs09.game.node.entity.equipment
|
||||
|
||||
import api.*
|
||||
import core.game.interaction.Interaction
|
||||
import core.game.interaction.Option
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.impl.Projectile
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import org.rs09.consts.Items
|
||||
import rs09.game.interaction.InteractionListener
|
||||
|
||||
|
||||
class PlayerPeltables : InteractionListener {
|
||||
companion object {
|
||||
private const val PROJECTILE_DELAY = 41
|
||||
private const val PROJECTILE_SPEED = 60
|
||||
private const val PROJECTILE_TIME_CONST = .02857
|
||||
private const val PROJECTILE_DISTANCE_MULT = 5
|
||||
private val PELTABLES = intArrayOf(Items.ROTTEN_TOMATO_2518, Items.SNOWBALL_11951)
|
||||
}
|
||||
|
||||
|
||||
override fun defineListeners() {
|
||||
onEquip(PELTABLES, ::setPlayerOps)
|
||||
onUnequip(PELTABLES, ::removePlayerOps)
|
||||
|
||||
on("pelt", PLAYER, ::handlePeltInteraction)
|
||||
onUseWithPlayer(*PELTABLES) {player, used, with -> handlePeltInteraction(player, with, used) }
|
||||
flagInstant()
|
||||
}
|
||||
|
||||
private fun setPlayerOps(player: Player, _node: Node) : Boolean {
|
||||
player.interaction.set(Option("Pelt", 0))
|
||||
return true
|
||||
}
|
||||
|
||||
private fun removePlayerOps(player: Player, _node: Node) : Boolean {
|
||||
Interaction.sendOption(player, 0, "null")
|
||||
return true
|
||||
}
|
||||
|
||||
private fun handlePeltInteraction(player: Player, node: Node, usedPeltable: Node? = null) : Boolean {
|
||||
val peltable = usedPeltable?.asItem() ?: getPeltable(player) ?: return removePlayerOps(player, node)
|
||||
val gfx = getPeltableGfx(peltable.id)
|
||||
|
||||
val other = node.asPlayer()
|
||||
|
||||
if (!Pathfinder.find(player, other, false, Pathfinder.PROJECTILE).isSuccessful) {
|
||||
sendDialogue(player, "You can't reach them!")
|
||||
return true
|
||||
}
|
||||
|
||||
val distance = player.location.getDistance(other.location)
|
||||
val projectileSpeed = PROJECTILE_DELAY + PROJECTILE_SPEED + distance * PROJECTILE_DISTANCE_MULT
|
||||
val hitDelay = (projectileSpeed * PROJECTILE_TIME_CONST).toInt()
|
||||
|
||||
if (removeItem(player, peltable, Container.INVENTORY) || removeItem(player, peltable, Container.EQUIPMENT)) {
|
||||
lock(player, hitDelay)
|
||||
submitWorldPulse(PeltingPulse(player, other, gfx, hitDelay, peltable.id))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
class PeltingPulse(val player: Player, val other: Player, val gfx: IntArray, val hitDelay: Int, val peltable: Int) : Pulse() {
|
||||
private val throwAnimation = getPeltableAnim(peltable)
|
||||
private var ticks = 0
|
||||
override fun pulse(): Boolean {
|
||||
when (ticks++) {
|
||||
0 -> {
|
||||
player.face(other)
|
||||
visualize(player, throwAnimation, gfx[0])
|
||||
}
|
||||
1 -> {
|
||||
Projectile.create(player, other, gfx[1], 30, 10).send()
|
||||
face(player, player) //reset face flag lel
|
||||
unlock(player)
|
||||
}
|
||||
hitDelay -> {
|
||||
if (gfx[2] != -1) other.graphics(Graphics(gfx[2]))
|
||||
sendMessage(other, "${player.username} has hit you with a ${getItemName(peltable).toLowerCase()}.")
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getPeltableAnim(id: Int) : Int {
|
||||
return when (id) {
|
||||
Items.SNOWBALL_11951 -> 7530
|
||||
Items.ROTTEN_TOMATO_2518 -> 385
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPeltableGfx(id: Int): IntArray {
|
||||
return when (id) {
|
||||
Items.SNOWBALL_11951 -> intArrayOf(-1, 861, 1282)
|
||||
Items.ROTTEN_TOMATO_2518 -> intArrayOf(-1, 29, 31)
|
||||
else -> IntArray(3) {-1}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPeltable(player: Player): Item? {
|
||||
val equipped = getItemFromEquipment(player, EquipmentSlot.WEAPON) ?: return null
|
||||
val id = equipped.id
|
||||
|
||||
if (id !in PELTABLES) return null
|
||||
|
||||
return equipped
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package rs09.game.node.entity.equipment
|
||||
|
||||
import core.cache.def.impl.ItemDefinition
|
||||
import core.game.interaction.Interaction
|
||||
import core.game.interaction.Option
|
||||
import rs09.game.interaction.player.PeltOptionPlugin
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
|
||||
@Initializable
|
||||
class SnowballEquipmentPlugin : Plugin<Item> {
|
||||
override fun newInstance(arg: Item?): Plugin<Item> {
|
||||
ItemDefinition.forId(11951).handlers["equipment"] = this
|
||||
return this
|
||||
}
|
||||
|
||||
override fun fireEvent(identifier: String?, vararg args: Any?): Any {
|
||||
val player = args[0] as Player
|
||||
when(identifier){
|
||||
"equip" -> {
|
||||
player.getInteraction().set(Option("Pelt", 0).setHandler(PeltOptionPlugin()))
|
||||
}
|
||||
"unequip" -> {
|
||||
Interaction.sendOption(player, 0, "null")
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user