Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 83 additions & 30 deletions src/plugins/item-on-item/firemaking/firemaking-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { itemOnItemAction, ItemOnItemActionPlugin } from '@server/world/mob/player/action/item-on-item-action';
import { world } from '@server/game-server';
import { Skill, skillDetails } from '@server/world/mob/skills';
import { Skill } from '@server/world/mob/skills';
import { loopingAction } from '@server/world/mob/player/action/action';
import { LandscapeObject } from '@runejs/cache-parser';
import { Player } from '@server/world/mob/player/player';
import { WorldItem } from '@server/world/items/world-item';
import { Position } from '@server/world/position';
import { randomBetween } from '@server/util/num';

const logs = [
{
Expand All @@ -19,9 +23,55 @@ const failedToLight = (logLevel: number, playerLevel: number): boolean => {
return hostRatio < clientRatio;
};

const canChain = (logLevel: number, playerLevel: number): boolean => {
playerLevel++;
const hostRatio = Math.random() * logLevel;
const clientRatio = Math.random() * ((playerLevel - logLevel) * (1 + (logLevel * 0.01)));
return clientRatio - hostRatio < 3.5;
};

const fireDuration = (): number => {
return randomBetween(100, 200); // 1-2 minutes
};

const lightFire = (player: Player, position: Position, worldItemLog: WorldItem, burnExp: number): void => {
world.chunkManager.removeWorldItem(worldItemLog);
const fireObject: LandscapeObject = {
objectId: 2732,
x: position.x,
y: position.y,
level: position.level,
type: 10,
rotation: 0
};

world.chunkManager.addTemporaryLandscapeObject(fireObject, position, fireDuration()).then(() => {
world.chunkManager.spawnWorldItem({ itemId: 592, amount: 1 }, position, null, 300);
});
player.packetSender.playSound(240, 7);
player.playAnimation(-1);
player.packetSender.chatboxMessage(`The fire catches and the logs begin to burn.`);
player.skills.addExp(Skill.FIREMAKING, burnExp);

if(!player.walkingQueue.moveIfAble(-1, 0)) {
if(!player.walkingQueue.moveIfAble(1, 0)) {
if(!player.walkingQueue.moveIfAble(0, -1)) {
player.walkingQueue.moveIfAble(0, 1);
}
}
}

player.face(position);
player.metadata['lastFire'] = Date.now();
};

const action: itemOnItemAction = (details) => {
const { player, usedItem, usedWithItem, usedSlot, usedWithSlot } = details;
const tinderBox = usedItem.itemId === 590 ? usedItem : usedWithItem;

if(player.metadata['lastFire'] && Date.now() - player.metadata['lastFire'] < 600) {
return;
}

const log = usedItem.itemId !== 590 ? usedItem : usedWithItem;
const removeFromSlot = usedItem.itemId !== 590 ? usedSlot : usedWithSlot;
const skillInfo = logs.find(l => l.logId === log.itemId);
Expand All @@ -38,36 +88,39 @@ const action: itemOnItemAction = (details) => {
player.removeItem(removeFromSlot);
const worldItemLog = world.chunkManager.spawnWorldItem(log, player.position, player);

let elapsedTicks = 0;
if(player.metadata['lastFire'] && Date.now() - player.metadata['lastFire'] < 1200 && canChain(skillInfo.requiredLevel, player.skills.values[Skill.WOODCUTTING].level)) {
lightFire(player, position, worldItemLog, skillInfo.burnExp);
} else {
player.packetSender.chatboxMessage(`You attempt to light the logs.`);

const loop = loopingAction(player);
loop.event.subscribe(() => {
if(elapsedTicks === 0 || elapsedTicks % 12 === 0) {
player.playAnimation(733);
}
let elapsedTicks = 0;
const loop = loopingAction(player);
loop.event.subscribe(() => {
if(worldItemLog.removed) {
loop.cancel();
return;
}

const lightFire = !failedToLight(skillInfo.requiredLevel, player.skills.values[Skill.WOODCUTTING].level);

if(lightFire) {
loop.cancel();

world.chunkManager.removeWorldItem(worldItemLog);
const fireObject: LandscapeObject = {
objectId: 2732,
x: position.x,
y: position.y,
level: position.level,
type: 10,
rotation: 0
};

world.chunkManager.addLandscapeObject(fireObject, position);
player.skills.addExp(Skill.FIREMAKING, skillInfo.burnExp);
player.playAnimation(-1);
} else {
elapsedTicks++;
}
});
// @TODO check for existing location objects again (incase one spawned here during this loop)
// @TODO check for tinderbox incase it was removed

if(elapsedTicks === 0 || elapsedTicks % 12 === 0) {
player.playAnimation(733);
}
if(elapsedTicks !== 0 && (elapsedTicks === 2 || (elapsedTicks - 2) % 4 === 0)) {
player.packetSender.playSound(375, 7, 1);
}

const canLightFire = elapsedTicks > 0 && !failedToLight(skillInfo.requiredLevel, player.skills.values[Skill.WOODCUTTING].level);

if(canLightFire) {
loop.cancel();
lightFire(player, position, worldItemLog, skillInfo.burnExp);
} else {
elapsedTicks++;
}
});
}
};

export default { items: [ { item1: 590, item2: 1511 } ], action } as ItemOnItemActionPlugin;
1 change: 1 addition & 0 deletions src/world/items/world-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export interface WorldItem {
position: Position;
initiallyVisibleTo?: Player;
expires?: number;
removed?: boolean;
}
13 changes: 13 additions & 0 deletions src/world/map/chunk-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export class ChunkManager {
}

private deleteWorldItemForPlayers(worldItem: WorldItem, chunk: Chunk): Promise<void> {
worldItem.removed = true;

return new Promise(resolve => {
const nearbyPlayers = this.getSurroundingChunks(chunk).map(chunk => chunk.players).flat();

Expand Down Expand Up @@ -104,6 +106,17 @@ export class ChunkManager {
chunk.removedLandscapeObjects.delete(`${position.x},${position.y},${object.objectId}`);
}

public addTemporaryLandscapeObject(object: LandscapeObject, position: Position, expireTicks: number): Promise<void> {
return new Promise(resolve => {
this.addLandscapeObject(object, position);

setTimeout(() => {
this.removeLandscapeObject(object, position);
resolve();
}, expireTicks * World.TICK_LENGTH);
});
}

public removeLandscapeObject(object: LandscapeObject, position: Position): Promise<void> {
const chunk = this.getChunkForWorldPosition(position);
chunk.removeObject(object, position);
Expand Down
6 changes: 6 additions & 0 deletions src/world/mob/mob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Npc } from './npc/npc';
import { Entity } from '../entity';
import { Skills } from '@server/world/mob/skills';
import { Item } from '@server/world/items/item';
import { Position } from '@server/world/position';

/**
* Handles a mobile entity within the game world.
Expand All @@ -31,6 +32,11 @@ export abstract class Mob extends Entity {
this.skills = new Skills(this);
}

// @TODO facing other mobs
public face(position: Position): void {
this.updateFlags.facePosition = position;
}

public playAnimation(animation: number | Animation): void {
if(typeof animation === 'number') {
animation = { id: animation, delay: 0 };
Expand Down
2 changes: 0 additions & 2 deletions src/world/mob/player/action/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ export const loopingAction = (player: Player, ticks?: number, delayTicks?: numbe
const actionCancelled = player.actionsCancelled.subscribe(() => {
subscription.unsubscribe();
actionCancelled.unsubscribe();
player.packetSender.chatboxMessage('Unsubscribed');
});

return { event, cancel: () => {
subscription.unsubscribe();
actionCancelled.unsubscribe();
player.packetSender.chatboxMessage('Completed');
} };
};

Expand Down
1 change: 1 addition & 0 deletions src/world/mob/player/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export class Player extends Mob {
private _walkingTo: Position;
private _nearbyChunks: Chunk[];
public readonly actionsCancelled: Subject<boolean>;
public readonly metadata: { [key: string]: any } = {};

public constructor(socket: Socket, inCipher: Isaac, outCipher: Isaac, clientUuid: number, username: string, password: string, isLowDetail: boolean) {
super();
Expand Down
5 changes: 4 additions & 1 deletion src/world/mob/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ export class Skills {

if(this.mob instanceof Player) {
const achievementDetails = skillDetails[skillId];
if(achievementDetails && achievementDetails.advancementInterfaceId) {
this.mob.packetSender.chatboxMessage(`Congratulations, you've just advanced a ${achievementDetails.name} level. ` +
`You are now level ${finalLevel}.`);

if(achievementDetails.advancementInterfaceId) {
dialogueAction(this.mob, { type: 'LEVEL_UP', skillId, lines: [
`@dbl@Congratulations, you've just advanced a ${achievementDetails.name} level.`,
`Your ${achievementDetails.name} level is now ${finalLevel}.` ] }).then(d => d.close());
Expand Down
25 changes: 21 additions & 4 deletions src/world/mob/walking-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class WalkingQueue {
}
}

public add(x: number, y: number): void {
public add(x: number, y: number, positionMetadata?: { [key: string ]: any}): void {
let lastPosition = this.getLastPosition();

let lastX = lastPosition.x;
Expand All @@ -61,6 +61,7 @@ export class WalkingQueue {

if(this.canMoveTo(lastPosition, newPosition)) {
lastPosition = newPosition;
newPosition.metadata = positionMetadata;
this.queue.push(newPosition);
} else {
this.valid = false;
Expand All @@ -72,13 +73,28 @@ export class WalkingQueue {
const newPosition = new Position(x, y);

if(this.canMoveTo(lastPosition, newPosition)) {
newPosition.metadata = positionMetadata;
this.queue.push(newPosition);
} else {
this.valid = false;
}
}
}

public moveIfAble(xDiff: number, yDiff: number): boolean {
const position = this.mob.position;
const newPosition = new Position(position.x + xDiff, position.y + yDiff, position.level);

if(this.canMoveTo(position, newPosition)) {
this.clear();
this.valid = true;
this.add(newPosition.x, newPosition.y, { ignoreInterfaces: true });
return true;
}

return false;
}

public canMoveTo(origin: Position, destination: Position): boolean {
let destinationChunk: Chunk = world.chunkManager.getChunkForWorldPosition(destination);
const positionAbove: Position = new Position(destination.x, destination.y, destination.level + 1);
Expand Down Expand Up @@ -246,11 +262,13 @@ export class WalkingQueue {
return;
}

const walkPosition = this.queue.shift();

if(this.mob instanceof Player) {
this.mob.actionsCancelled.next();
this.mob.actionsCancelled.next(true);

const activeInterface = this.mob.activeInterface;
if(activeInterface) {
if(activeInterface && (!walkPosition.metadata || !walkPosition.metadata.ignoreInterfaces)) {
if(activeInterface.disablePlayerMovement) {
this.resetDirections();
return;
Expand All @@ -264,7 +282,6 @@ export class WalkingQueue {
}
}

const walkPosition = this.queue.shift();
const currentPosition = this.mob.position;

if(this.canMoveTo(currentPosition, walkPosition)) {
Expand Down
1 change: 1 addition & 0 deletions src/world/position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class Position {
private _x: number;
private _y: number;
private _level: number;
public metadata: { [key: string]: any } = {};

public constructor(x: number, y: number, level?: number) {
this.move(x, y, level);
Expand Down