diff --git a/src/engine/plugins/index.ts b/src/engine/plugins/index.ts index a0013b5ee..72a593741 100644 --- a/src/engine/plugins/index.ts +++ b/src/engine/plugins/index.ts @@ -1,3 +1,2 @@ export * from './content-plugin'; export * from './loader'; -export * from './util'; diff --git a/src/engine/plugins/util.ts b/src/engine/plugins/util.ts deleted file mode 100644 index a0ccaa14c..000000000 --- a/src/engine/plugins/util.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Npc, Player } from '@engine/world/actor'; -import { Subject, timer } from 'rxjs'; -import { Position, World } from '@engine/world'; -import { LandscapeObject } from '@runejs/filestore'; - -/** - * A type of action that loops until either one of three things happens: - * 1. A player is specified within `options` who's `actionsCancelled` event has been fired during the loop. - * 2. An npc is specified within `options` who no longer exists at some point during the loop. - * 3. The `cancel()` function is manually called, presumably when the purpose of the loop has been completed. - * @param options Options to provide to the looping action, which include: - * `ticks` the number of game ticks between loop cycles. Defaults to 1 game tick between loops. - * `delayTicks` the number of game ticks to wait before starting the first loop. Defaults to 0 game ticks. - * `player` the player that the loop belongs to. Providing this field will cause the loop to cancel if this - * player's `actionsCancelled` is fired during the loop. - * `npc` the npc that the loop belongs to. This will Providing this field will cause the loop to cancel if - * this npc is flagged to no longer exist during the loop. - * @deprecated - use new Action Hook task system instead. - */ -export const loopingEvent = (options?: { - ticks?: number; - delayTicks?: number; - npc?: Npc; - player?: Player; -}): { event: Subject, cancel: () => void } => { - if(!options) { - options = {}; - } - - const { ticks, delayTicks, npc, player } = options; - const event: Subject = new Subject(); - - const subscription = timer(delayTicks === undefined ? 0 : (delayTicks * World.TICK_LENGTH), - ticks === undefined ? World.TICK_LENGTH : (ticks * World.TICK_LENGTH)).subscribe(() => { - if(npc && !npc.exists) { - event.complete(); - subscription.unsubscribe(); - return; - } - - event.next(); - }); - - let actionCancelled; - - if(player) { - actionCancelled = player.actionsCancelled.subscribe(() => { - subscription.unsubscribe(); - actionCancelled.unsubscribe(); - event.complete(); - }); - } - - return { - event, cancel: () => { - subscription.unsubscribe(); - - if(actionCancelled) { - actionCancelled.unsubscribe(); - } - - event.complete(); - } - }; -}; -/** - * A walk-to type of action that requires the specified player to walk to a specific destination before proceeding. - * Note that this does not force the player to walk, it simply checks to see if the player is walking where specified. - * @param player The player that must walk to a specific position. - * @param position The position that the player needs to end up at. - * @param interactingAction [optional] The information about the interaction that the player is making. Not required. - * @deprecated - use methods provided within the Actor API to force or await movement - */ -export const playerWalkTo = async(player: Player, position: Position, interactingAction?: { - interactingObject?: LandscapeObject; -}): Promise => { - return new Promise((resolve, reject) => { - player.metadata.walkingTo = position; - - const inter = setInterval(() => { - if(!player.metadata.walkingTo || !player.metadata.walkingTo.equals(position)) { - reject(); - clearInterval(inter); - return; - } - - if(!player.walkingQueue.moving()) { - if(!interactingAction) { - if(player.position.distanceBetween(position) > 1) { - reject(); - } else { - resolve(); - } - } else { - if(interactingAction.interactingObject) { - const locationObject = interactingAction.interactingObject; - if(player.position.withinInteractionDistance(locationObject)) { - resolve(); - } else { - reject(); - } - } - } - - clearInterval(inter); - player.metadata.walkingTo = undefined; - } - }, 100); - }); -}; diff --git a/src/engine/world/skill-util/harvest-skill.ts b/src/engine/world/skill-util/harvest-skill.ts index 8053e7a4d..6850f634b 100644 --- a/src/engine/world/skill-util/harvest-skill.ts +++ b/src/engine/world/skill-util/harvest-skill.ts @@ -4,8 +4,6 @@ import { soundIds } from '@engine/world/config/sound-ids'; import { Skill } from '@engine/world/actor/skills'; import { getBestAxe, HarvestTool } from '@engine/world/config/harvest-tool'; import { findItem } from '@engine/config/config-handler'; -import { activeWorld } from '@engine/world'; -import { loopingEvent } from '@engine/plugins'; import { logger } from '@runejs/common'; /** diff --git a/src/plugins/buttons/magic-attack.plugin.ts b/src/plugins/buttons/magic-attack.plugin.ts index 87574f61a..02ef474ab 100644 --- a/src/plugins/buttons/magic-attack.plugin.ts +++ b/src/plugins/buttons/magic-attack.plugin.ts @@ -1,7 +1,6 @@ import { Player } from '@engine/world/actor'; import { TaskExecutor, MagicOnNPCActionHook, MagicOnNPCAction } from '@engine/action'; import { logger } from '@runejs/common'; -import { loopingEvent } from '@engine/plugins'; const buttonIds: number[] = [ 0, // Home Teleport @@ -31,13 +30,13 @@ export const activate = (task: TaskExecutor, elapsedTicks: num player.walkingQueue.clear(); //npc world index would be -1 for players - player.outgoingPackets.sendProjectile(player.position, offsetX, offsetY, 250, 40, 36, 100, npc.worldIndex + 1, 1); + player.outgoingPackets.sendProjectile(player.position, offsetX, offsetY, 250, 40, 36, 100, npc.worldIndex + 1, 1); console.info(`${player.username} smites ${npc.name} with ${spells[buttonId]}`); }; export default { pluginId: 'rs:magic', - hooks: + hooks: { type: 'magic_on_npc', widgetId: 192, diff --git a/src/plugins/commands/player-animation-command.plugin.ts b/src/plugins/commands/player-animation-command.plugin.ts index 1741fb2c4..0e28e27d6 100644 --- a/src/plugins/commands/player-animation-command.plugin.ts +++ b/src/plugins/commands/player-animation-command.plugin.ts @@ -1,6 +1,4 @@ -import { commandActionHandler, PlayerCommandAction } from '@engine/action'; -import { Player } from '@engine/world/actor/player/player'; -import { loopingEvent } from '@engine/plugins'; +import { commandActionHandler, PlayerCommandActionHook } from '@engine/action'; const action: commandActionHandler = (details): void => { const { player, args } = details; @@ -22,14 +20,6 @@ export default { } ], handler: action - }, - { - type: 'player_command', - commands: [ 'yeet' ], - handler: ({ player }: PlayerCommandAction): void => { - loopingEvent({ ticks: 3, player }) - .event.asObservable().subscribe(() => (player as Player).playAnimation(866)) - } - } + } as PlayerCommandActionHook ] }; diff --git a/src/plugins/skills/crafting/spinning-wheel.plugin.ts b/src/plugins/skills/crafting/spinning-wheel.plugin.ts index 71fc8f77a..36b10793c 100644 --- a/src/plugins/skills/crafting/spinning-wheel.plugin.ts +++ b/src/plugins/skills/crafting/spinning-wheel.plugin.ts @@ -6,8 +6,9 @@ import { Skill } from '@engine/world/actor/skills'; import { animationIds } from '@engine/world/config/animation-ids'; import { objectIds } from '@engine/world/config/object-ids'; import { findItem, widgets } from '@engine/config/config-handler'; -import { loopingEvent } from '@engine/plugins'; import { logger } from '@runejs/common'; +import { ActorTask } from '@engine/task/impl'; +import { Player } from '@engine/world/actor'; interface Spinnable { input: number | number[]; @@ -76,35 +77,72 @@ export const openSpinningInterface: objectInteractionActionHandler = (details) = }); }; -const spinProduct: any = (details: ButtonAction, spinnable: Spinnable, count: number) => { - let elapsedTicks = 0; - - let created = 0; - - // As an multiple items can be used for one of the recipes, check if its an array - let currentItem: number; - let currentItemIndex: number = 0; - let isArray = false; - if (Array.isArray(spinnable.input)) { - isArray = true; - currentItem = spinnable.input[0]; - } else { - currentItem = spinnable.input; +/** + * A task to (repeatedly if needed) spin a product from a spinnable. + */ +class SpinProductTask extends ActorTask { + /** + * The number of ticks that `execute` has been called inside this task. + */ + private elapsedTicks = 0; + + /** + * The number of items that should be spun. + */ + private count: number; + + /** + * The number of items that have been spun. + */ + private created = 0; + + /** + * The spinnable that is being used. + */ + private spinnable: Spinnable; + + /** + * The currently being spun input. + */ + private currentItem: number; + + /** + * The index of the current input being spun. + */ + private currentItemIndex = 0; + + constructor( + player: Player, + spinnable: Spinnable, + count: number, + ) { + super(player); + this.spinnable = spinnable; + this.count = count; } - // Create a new tick loop - const loop = loopingEvent({ player: details.player }); - loop.event.subscribe(() => { - if (created === count) { - loop.cancel(); + + public execute(): void { + if (this.created === this.count) { + this.stop(); return; } + + // As an multiple items can be used for one of the recipes, check if its an array + let isArray = false; + if (Array.isArray(this.spinnable.input)) { + isArray = true; + this.currentItem = this.spinnable.input[0]; + } else { + this.currentItem = this.spinnable.input; + } + // Check if out of input material - if (!details.player.hasItemInInventory(currentItem)) { + if (!this.actor.hasItemInInventory(this.currentItem)) { let cancel = false; if (isArray) { - if (currentItemIndex < ( spinnable.input).length) { - currentItemIndex++; - currentItem = ( spinnable.input)[currentItemIndex]; + if (this.currentItemIndex < ( this.spinnable.input).length) { + this.currentItemIndex++; + this.currentItem = ( this.spinnable.input)[this.currentItemIndex]; } else { cancel = true; } @@ -112,27 +150,33 @@ const spinProduct: any = (details: ButtonAction, spinnable: Spinnable, count: nu cancel = true; } if (cancel) { - const itemName = findItem(currentItem)?.name || ''; - details.player.sendMessage(`You don't have any ${itemName.toLowerCase()}.`); - loop.cancel(); + const itemName = findItem(this.currentItem)?.name || ''; + this.actor.sendMessage(`You don't have any ${itemName.toLowerCase()}.`); + this.stop(); return; } } + // Spinning takes 3 ticks for each item - if (elapsedTicks % 3 === 0) { - details.player.removeFirstItem(currentItem); - details.player.giveItem(spinnable.output); - details.player.skills.addExp(Skill.CRAFTING, spinnable.experience); - created++; + if (this.elapsedTicks % 3 === 0) { + this.actor.removeFirstItem(this.currentItem); + this.actor.giveItem(this.spinnable.output); + this.actor.skills.addExp(Skill.CRAFTING, this.spinnable.experience); + this.created++; } + // animation plays once every two items - if (elapsedTicks % 6 === 0) { - details.player.playAnimation(animationIds.spinSpinningWheel); - details.player.outgoingPackets.playSound(soundIds.spinWool, 5); + if (this.elapsedTicks % 6 === 0) { + this.actor.playAnimation(animationIds.spinSpinningWheel); + this.actor.outgoingPackets.playSound(soundIds.spinWool, 5); } - elapsedTicks++; - }); + this.elapsedTicks++; + } +} + +const spinProduct: any = (details: ButtonAction, spinnable: Spinnable, count: number) => { + details.player.enqueueTask(SpinProductTask, [spinnable, count]); }; export const buttonClicked: buttonActionHandler = (details) => { diff --git a/src/plugins/skills/fletching/fletching.plugin.ts b/src/plugins/skills/fletching/fletching.plugin.ts index 653b558a3..142d06918 100644 --- a/src/plugins/skills/fletching/fletching.plugin.ts +++ b/src/plugins/skills/fletching/fletching.plugin.ts @@ -11,11 +11,10 @@ import { colors } from '@engine/util/colors'; import { findItem, widgets } from '@engine/config/config-handler'; import { Fletchable } from '@plugins/skills/fletching/fletching-types'; import { itemInteractionActionHandler } from '@engine/action'; -import { loopingEvent } from '@engine/plugins'; //fletching stuff goes below this! lets do it! export default { pluginId: 'rs:fletching', - + };