|
1 |
| - |
2 |
| -import { |
3 |
| - ObjectInteractionAction, |
4 |
| - TaskExecutor |
5 |
| -} from '@engine/action'; |
6 | 1 | import { Skill } from '@engine/world/actor/skills';
|
7 | 2 | import { canInitiateHarvest } from '@engine/world/skill-util/harvest-skill';
|
8 |
| -import { getTreeFromHealthy, getTreeIds, IHarvestable } from '@engine/world/config/harvestable-object'; |
| 3 | +import { getTreeFromHealthy, IHarvestable } from '@engine/world/config/harvestable-object'; |
9 | 4 | import { randomBetween } from '@engine/util/num';
|
10 | 5 | import { colorText } from '@engine/util/strings';
|
11 | 6 | import { colors } from '@engine/util/colors';
|
12 | 7 | import { rollBirdsNestType } from '@engine/world/skill-util/harvest-roll';
|
13 | 8 | import { soundIds } from '@engine/world/config/sound-ids';
|
14 |
| -import { Axe, getAxe, HarvestTool } from '@engine/world/config/harvest-tool'; |
15 |
| -import { findItem } from '@engine/config/config-handler'; |
| 9 | +import { findItem, findObject } from '@engine/config/config-handler'; |
16 | 10 | import { activeWorld } from '@engine/world';
|
17 | 11 | import { canCut } from './chance';
|
18 |
| - |
19 |
| -export const canActivate = (task: TaskExecutor<ObjectInteractionAction>, taskIteration: number): boolean => { |
20 |
| - const { actor, actionData: { position, object, player } } = task; |
21 |
| - const tree = getTreeFromHealthy(object.objectId); |
22 |
| - |
23 |
| - if(!tree) { |
24 |
| - return false; |
25 |
| - } |
26 |
| - |
27 |
| - const tool = actor.isPlayer ? canInitiateHarvest(player, tree, Skill.WOODCUTTING) : getAxe(Axe.STEEL); |
28 |
| - |
29 |
| - if(!tool) { |
30 |
| - return false; |
31 |
| - } |
32 |
| - |
33 |
| - task.session.tool = tool; |
34 |
| - task.session.tree = tree; |
35 |
| - |
36 |
| - if(taskIteration === 0) { |
37 |
| - // First run |
38 |
| - |
39 |
| - if(actor.isPlayer) { |
40 |
| - player.sendMessage('You swing your axe at the tree.'); |
| 12 | +import { ActorLandscapeObjectInteractionTask } from '@engine/task/impl'; |
| 13 | +import { Player } from '@engine/world/actor'; |
| 14 | +import { LandscapeObject } from '@runejs/filestore'; |
| 15 | +import { logger } from '@runejs/common'; |
| 16 | + |
| 17 | +class WoodcuttingTask extends ActorLandscapeObjectInteractionTask<Player> { |
| 18 | + private treeInfo: IHarvestable; |
| 19 | + private elapsedTicks = 0; |
| 20 | + |
| 21 | + constructor( |
| 22 | + player: Player, |
| 23 | + landscapeObject: LandscapeObject, |
| 24 | + sizeX: number, |
| 25 | + sizeY: number |
| 26 | + ) { |
| 27 | + super( |
| 28 | + player, |
| 29 | + landscapeObject, |
| 30 | + sizeX, |
| 31 | + sizeY |
| 32 | + ); |
| 33 | + |
| 34 | + if (!landscapeObject) { |
| 35 | + this.stop(); |
| 36 | + return; |
41 | 37 | }
|
42 | 38 |
|
43 |
| - actor.face(position); |
44 |
| - actor.playAnimation(tool.animation); |
| 39 | + this.treeInfo = getTreeFromHealthy(landscapeObject.objectId); |
| 40 | + if (!this.treeInfo) { |
| 41 | + this.stop(); |
| 42 | + return; |
| 43 | + } |
45 | 44 | }
|
46 | 45 |
|
47 |
| - return true; |
48 |
| -}; |
49 |
| - |
50 |
| - |
51 |
| -export const activate = (task: TaskExecutor<ObjectInteractionAction>, taskIteration: number): boolean => { |
52 |
| - const { actor, player, actionData, session } = task.getDetails(); |
53 |
| - const { position: objectPosition, object: actionObject } = actionData; |
54 |
| - const tree: IHarvestable = session.tree; |
55 |
| - const tool: HarvestTool = session.tool; |
| 46 | + public execute(): void { |
| 47 | + super.execute(); |
56 | 48 |
|
57 |
| - // Cancel if the actor no longer has their tool or level requirements. |
58 |
| - if(!tool || !tree) { |
59 |
| - return false; |
60 |
| - } |
| 49 | + if (!this.isActive || !this.landscapeObject) { |
| 50 | + return; |
| 51 | + } |
61 | 52 |
|
62 |
| - // Grab the tree manually every loop so that we can make sure it's still alive. |
63 |
| - const { object } = activeWorld.findObjectAtLocation(actor, actionObject.objectId, objectPosition); |
| 53 | + // store the tick count before incrementing so we don't need to keep track of it in all the separate branches |
| 54 | + const taskIteration = this.elapsedTicks++; |
64 | 55 |
|
65 |
| - if(!object) { |
66 |
| - // Tree has been chopped down, cancel. |
67 |
| - return false; |
68 |
| - } |
| 56 | + const tool = canInitiateHarvest(this.actor, this.treeInfo, Skill.WOODCUTTING); |
69 | 57 |
|
70 |
| - // Check if the amount of ticks passed equal the tools pulses. |
71 |
| - if(taskIteration % 3 === 0 && taskIteration != 0) { |
| 58 | + if (!tool) { |
| 59 | + this.stop(); |
| 60 | + return; |
| 61 | + } |
72 | 62 |
|
73 |
| - let toolLevel = tool.level - 1; |
74 |
| - if(tool.itemId === 1349 || tool.itemId === 1267) { |
75 |
| - toolLevel = 2; |
| 63 | + if(taskIteration === 0) { |
| 64 | + this.actor.sendMessage('You swing your axe at the tree.'); |
| 65 | + this.actor.face(this.landscapeObjectPosition); |
| 66 | + this.actor.playAnimation(tool.animation); |
| 67 | + return; |
76 | 68 | }
|
77 | 69 |
|
78 |
| - const succeeds = canCut(tree, toolLevel, actor.skills.woodcutting.level); |
79 |
| - if(succeeds) { |
80 |
| - const targetName: string = findItem(tree.itemId).name.toLowerCase(); |
81 |
| - |
82 |
| - if(actor.inventory.hasSpace()) { |
83 |
| - const itemToAdd = tree.itemId; |
84 |
| - const roll = randomBetween(1, 256); |
85 |
| - |
86 |
| - if(roll === 1) { // Bird nest chance |
87 |
| - player?.sendMessage(colorText(`A bird's nest falls out of the tree.`, colors.red)); |
88 |
| - activeWorld.globalInstance.spawnWorldItem(rollBirdsNestType(), actor.position, |
89 |
| - { owner: player || null, expires: 300 }); |
90 |
| - } else { // Standard log chopper |
91 |
| - player?.sendMessage(`You manage to chop some ${targetName}.`); |
92 |
| - actor.giveItem(itemToAdd); |
93 |
| - } |
| 70 | + if(taskIteration % 3 === 0) { |
94 | 71 |
|
95 |
| - player?.skills.woodcutting.addExp(tree.experience); |
| 72 | + let toolLevel = tool.level - 1; |
| 73 | + if(tool.itemId === 1349 || tool.itemId === 1267) { |
| 74 | + toolLevel = 2; |
| 75 | + } |
96 | 76 |
|
97 |
| - if(randomBetween(0, 100) <= tree.break) { |
98 |
| - player?.playSound(soundIds.oreDepeleted); |
99 |
| - actor.instance.replaceGameObject(tree.objects.get(actionObject.objectId), |
100 |
| - object, randomBetween(tree.respawnLow, tree.respawnHigh)); |
101 |
| - return false; |
| 77 | + const succeeds = canCut(this.treeInfo, toolLevel, this.actor.skills.woodcutting.level); |
| 78 | + if(succeeds) { |
| 79 | + const targetName: string = findItem(this.treeInfo.itemId).name.toLowerCase(); |
| 80 | + |
| 81 | + if(this.actor.inventory.hasSpace()) { |
| 82 | + const itemToAdd = this.treeInfo.itemId; |
| 83 | + const roll = randomBetween(1, 256); |
| 84 | + |
| 85 | + if(roll === 1) { // Bird nest chance |
| 86 | + this.actor.sendMessage(colorText(`A bird's nest falls out of the tree.`, colors.red)); |
| 87 | + activeWorld.globalInstance.spawnWorldItem(rollBirdsNestType(), this.actor.position, |
| 88 | + { owner: this.actor || null, expires: 300 }); |
| 89 | + } else { // Standard log chopper |
| 90 | + this.actor.sendMessage(`You manage to chop some ${targetName}.`); |
| 91 | + this.actor.giveItem(itemToAdd); |
| 92 | + } |
| 93 | + |
| 94 | + this.actor.skills.woodcutting.addExp(this.treeInfo.experience); |
| 95 | + |
| 96 | + if(randomBetween(0, 100) <= this.treeInfo.break) { |
| 97 | + this.actor.playSound(soundIds.oreDepeleted); |
| 98 | + this.actor.instance.replaceGameObject(this.treeInfo.objects.get(this.landscapeObject.objectId), |
| 99 | + this.landscapeObject, randomBetween(this.treeInfo.respawnLow, this.treeInfo.respawnHigh)); |
| 100 | + this.stop(); |
| 101 | + return; |
| 102 | + } |
| 103 | + } else { |
| 104 | + this.actor.sendMessage(`Your inventory is too full to hold any more ${targetName}.`, true); |
| 105 | + this.actor.playSound(soundIds.inventoryFull); |
| 106 | + this.stop(); |
| 107 | + return; |
102 | 108 | }
|
103 |
| - } else { |
104 |
| - player?.sendMessage( |
105 |
| - `Your inventory is too full to hold any more ${targetName}.`, true); |
106 |
| - player?.playSound(soundIds.inventoryFull); |
107 |
| - return false; |
| 109 | + } |
| 110 | + } else { |
| 111 | + if(taskIteration % 1 === 0) { |
| 112 | + const randomSoundIdx = Math.floor(Math.random() * soundIds.axeSwing.length); |
| 113 | + this.actor.playSound(soundIds.axeSwing[randomSoundIdx], 7, 0); |
108 | 114 | }
|
109 | 115 | }
|
110 |
| - } else { |
111 |
| - if(taskIteration % 1 === 0 && taskIteration !== 0) { |
112 |
| - const randomSoundIdx = Math.floor(Math.random() * soundIds.axeSwing.length); |
113 |
| - player?.playSound(soundIds.axeSwing[randomSoundIdx], 7, 0); |
| 116 | + |
| 117 | + if(taskIteration % 3 === 0) { |
| 118 | + this.actor.playAnimation(tool.animation); |
114 | 119 | }
|
| 120 | + |
| 121 | + } |
| 122 | + |
| 123 | + public onStop(): void { |
| 124 | + super.onStop(); |
| 125 | + |
| 126 | + this.actor.stopAnimation(); |
115 | 127 | }
|
| 128 | +} |
| 129 | + |
| 130 | +export function runWoodcuttingTask(player: Player, landscapeObject: LandscapeObject): void { |
| 131 | + const objectConfig = findObject(landscapeObject.objectId); |
116 | 132 |
|
117 |
| - if(taskIteration % 3 === 0 && taskIteration !== 0) { |
118 |
| - actor.playAnimation(tool.animation); |
| 133 | + if (!objectConfig) { |
| 134 | + logger.warn(`Player ${player.username} attempted to run a woodcutting task on an invalid object (id: ${landscapeObject.objectId})`); |
| 135 | + return; |
119 | 136 | }
|
120 | 137 |
|
121 |
| - return true; |
122 |
| -}; |
| 138 | + const sizeX = objectConfig.rendering.sizeX; |
| 139 | + const sizeY = objectConfig.rendering.sizeY; |
123 | 140 |
|
124 |
| -export const onComplete = (task: TaskExecutor<ObjectInteractionAction>): void => { |
125 |
| - task.actor.stopAnimation(); |
126 |
| -}; |
| 141 | + player.enqueueTask(WoodcuttingTask, [ landscapeObject, sizeX, sizeY ]); |
| 142 | +} |
0 commit comments