Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

item on npc, and abusing sheep #111

Merged
merged 5 commits into from
Mar 2, 2020
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
24 changes: 24 additions & 0 deletions data/config/npc-spawns.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,27 @@
x: 3253
y: 3274
radius: 1
- npcId: 3579
x: 3197
y: 3262
radius: 10
- npcId: 43
x: 3199
y: 3267
radius: 10
- npcId: 43
x: 3203
y: 3271
radius: 10
- npcId: 43
x: 3199
y: 3273
radius: 10
- npcId: 43
x: 3208
y: 3273
radius: 10
- npcId: 43
x: 3209
y: 3260
radius: 10
2 changes: 2 additions & 0 deletions src/game-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { setWidgetPlugins } from '@server/world/actor/player/action/widget-actio
import { setItemPlugins } from '@server/world/actor/player/action/item-action';
import { setWorldItemPlugins } from '@server/world/actor/player/action/world-item-action';
import { setItemOnObjectPlugins } from '@server/world/actor/player/action/item-on-object-action';
import { setItemOnNpcPlugins } from '@server/world/actor/player/action/item-on-npc-action';
import { setPlayerInitPlugins } from '@server/world/actor/player/player';
import { setNpcInitPlugins } from '@server/world/actor/npc/npc';

Expand All @@ -44,6 +45,7 @@ export async function injectPlugins(): Promise<void> {
setNpcPlugins(actionTypes[ActionType.NPC_ACTION]);
setObjectPlugins(actionTypes[ActionType.OBJECT_ACTION]);
setItemOnObjectPlugins(actionTypes[ActionType.ITEM_ON_OBJECT_ACTION]);
setItemOnNpcPlugins(actionTypes[ActionType.ITEM_ON_NPC_ACTION]);
setItemOnItemPlugins(actionTypes[ActionType.ITEM_ON_ITEM]);
setItemPlugins(actionTypes[ActionType.ITEM_ACTION]);
setWorldItemPlugins(actionTypes[ActionType.WORLD_ITEM_ACTION]);
Expand Down
2 changes: 2 additions & 0 deletions src/net/incoming-packet-directory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { pickupItemPacket } from '@server/net/incoming-packets/pickup-item-packe
import { itemInteractionPacket } from '@server/net/incoming-packets/item-interaction-packet';
import { itemOnObjectPacket } from '@server/net/incoming-packets/item-on-object-packet';
import { numberInputPacket } from '@server/net/incoming-packets/number-input-packet';
import { itemOnNpcPacket } from '@server/net/incoming-packets/item-on-npc-packet';

const ignore = [ 234, 160, 58 /* camera move */ ];

Expand Down Expand Up @@ -52,6 +53,7 @@ const packets: { [key: number]: incomingPacket } = {
63: npcInteractionPacket,
116: npcInteractionPacket,
24: itemOnObjectPacket,
208: itemOnNpcPacket,

30: objectInteractionPacket,
164: objectInteractionPacket,
Expand Down
2 changes: 1 addition & 1 deletion src/net/incoming-packet-sizes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const incomingPacketSizes: number[] = [
-3, -3, -3, -3, -3, -3, 0, -3, 0, -3, //170
-3, -3, -3, 6, -3, -3, -3, -3, -3, -3, //180
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, //190
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, //200
-3, -3, -3, -3, -3, -3, -3, -3, 10, -3, //200
-3, -3, -3, -3, -3, -3, 0, -3, -3, -3, //210
-3, -3, -3, -3, -3, -3, -3, -3, 8, -3, //220
-3, 13, -3, -3, 4, -3, -1, -3, 4, -3, //230
Expand Down
60 changes: 60 additions & 0 deletions src/net/incoming-packets/item-on-npc-packet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { incomingPacket } from '../incoming-packet';
import { Player } from '../../world/actor/player/player';
import { RsBuffer } from '@server/net/rs-buffer';
import { widgets } from '@server/world/config/widget';
import { logger } from '@runejs/logger/dist/logger';
import { itemOnItemAction } from '@server/world/actor/player/action/item-on-item-action';
import { Position } from '@server/world/position';
import { gameCache, world } from '@server/game-server';
import { objectAction } from '@server/world/actor/player/action/object-action';
import { itemOnObjectAction } from '@server/world/actor/player/action/item-on-object-action';
import { World } from '@server/world/world';
import { npcAction } from '@server/world/actor/player/action/npc-action';
import { itemOnNpcAction } from '@server/world/actor/player/action/item-on-npc-action';

export const itemOnNpcPacket: incomingPacket = (player: Player, packetId: number, packetSize: number, packet: RsBuffer): void => {
const npcIndex = packet.readNegativeOffsetShortBE();
const itemId = packet.readNegativeOffsetShortBE();
const itemSlot = packet.readNegativeOffsetShortLE();
const itemWidgetId = packet.readShortBE();
const itemContainerId = packet.readShortBE();

let usedItem;
if (itemWidgetId === widgets.inventory.widgetId && itemContainerId === widgets.inventory.containerId) {
if (itemSlot < 0 || itemSlot > 27) {
return;
}

usedItem = player.inventory.items[itemSlot];
if (!usedItem) {
return;
}

if (usedItem.itemId !== itemId) {
return;
}
} else {
logger.warn(`Unhandled item on object case using widget ${itemWidgetId}:${itemContainerId}`);
}


if (npcIndex < 0 || npcIndex > World.MAX_NPCS - 1) {
return;
}

const npc = world.npcList[npcIndex];
if (!npc) {
return;
}

const position = npc.position;
const distance = Math.floor(position.distanceBetween(player.position));

// Too far away
if (distance > 16) {
return;
}

itemOnNpcAction(player, npc, position, usedItem, itemWidgetId, itemContainerId);

};
53 changes: 32 additions & 21 deletions src/net/outgoing-packets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ export class OutgoingPackets {
this.queue(packet);
}

public playSoundAtPosition(chunk: Chunk, soundId: number, soundX: number, soundY: number, volume: number, radius: number = 5, delay: number = 0): void {
const packet = new Packet(9);
const offset = 0;
packet.writeUnsignedByte(offset);
packet.writeUnsignedShortBE(soundId);
packet.writeUnsignedByte((volume & 7) + (radius << 4));
packet.writeUnsignedByte(delay);

this.queue(packet);
}

private getChunkPositionOffset(x: number, y: number, chunk: Chunk): number {
const offsetX = x - ((chunk.position.x + 6) * 8);
const offsetY = y - ((chunk.position.y + 6) * 8);
Expand All @@ -63,32 +74,32 @@ export class OutgoingPackets {
offsetX -= (this.player.lastMapRegionUpdatePosition.chunkX * 8);
offsetY -= (this.player.lastMapRegionUpdatePosition.chunkY * 8);

return { offsetX, offsetY };
return {offsetX, offsetY};
}

public updateChunk(chunk: Chunk, chunkUpdates: ChunkUpdateItem[]): void {
const { offsetX, offsetY } = this.getChunkOffset(chunk);
const {offsetX, offsetY} = this.getChunkOffset(chunk);

const packet = new Packet(63, PacketType.DYNAMIC_LARGE);
packet.writeByteInverted(offsetX);
packet.writeNegativeOffsetByte(offsetY);

chunkUpdates.forEach(update => {
if(update.type === 'ADD') {
if(update.object) {
if (update.type === 'ADD') {
if (update.object) {
const offset = this.getChunkPositionOffset(update.object.x, update.object.y, chunk);
packet.writeUnsignedByte(241);
packet.writeByteInverted((update.object.type << 2) + (update.object.rotation & 3));
packet.writeUnsignedShortBE(update.object.objectId);
packet.writeUnsignedOffsetByte(offset);
} else if(update.worldItem) {
} else if (update.worldItem) {
const offset = this.getChunkPositionOffset(update.worldItem.position.x, update.worldItem.position.y, chunk);
packet.writeUnsignedByte(175);
packet.writeUnsignedShortLE(update.worldItem.itemId);
packet.writeUnsignedShortBE(update.worldItem.amount);
packet.writeUnsignedByte(offset);
}
} else if(update.type === 'REMOVE') {
} else if (update.type === 'REMOVE') {
const offset = this.getChunkPositionOffset(update.object.x, update.object.y, chunk);
packet.writeUnsignedByte(143);
packet.writeUnsignedOffsetByte(offset);
Expand All @@ -100,7 +111,7 @@ export class OutgoingPackets {
}

public clearChunk(chunk: Chunk): void {
const { offsetX, offsetY } = this.getChunkOffset(chunk);
const {offsetX, offsetY} = this.getChunkOffset(chunk);

const packet = new Packet(64);
packet.writeUnsignedByte(offsetY);
Expand Down Expand Up @@ -195,7 +206,7 @@ export class OutgoingPackets {
this.queue(packet);
}

public showScreenAndTabWidgets(widgetId: number, tabWidgetId: number) : void {
public showScreenAndTabWidgets(widgetId: number, tabWidgetId: number): void {
const packet = new Packet(84);
packet.writeUnsignedShortBE(tabWidgetId);
packet.writeUnsignedOffsetShortLE(widgetId);
Expand All @@ -205,7 +216,7 @@ export class OutgoingPackets {
public updateClientConfig(configId: number, value: number): void {
let packet: Packet;

if(value > 128) {
if (value > 128) {
packet = new Packet(2);
packet.writeIntME2(value);
packet.writeUnsignedShortBE(configId);
Expand Down Expand Up @@ -252,12 +263,12 @@ export class OutgoingPackets {
packet.writeIntBE(widget.widgetId << 16 | widget.containerId);
packet.writeSmart(slot);

if(!item) {
if (!item) {
packet.writeUnsignedShortBE(0);
} else {
packet.writeUnsignedShortBE(item.itemId + 1); // +1 because 0 means an empty slot

if(item.amount >= 255) {
if (item.amount >= 255) {
packet.writeUnsignedByte(255);
packet.writeIntBE(item.amount);
} else {
Expand All @@ -275,12 +286,12 @@ export class OutgoingPackets {

const items = container.items;
items.forEach(item => {
if(!item) {
if (!item) {
// Empty slot
packet.writeUnsignedOffsetByte(0);
packet.writeOffsetShortBE(0);
} else {
if(item.amount >= 255) {
if (item.amount >= 255) {
packet.writeUnsignedByteOffset(255);
packet.writeIntBE(item.amount);
} else {
Expand All @@ -300,7 +311,7 @@ export class OutgoingPackets {
packet.writeShortBE(itemIds.length);

itemIds.forEach(itemId => {
if(!itemId) {
if (!itemId) {
// Empty slot
packet.writeUnsignedOffsetByte(0);
packet.writeOffsetShortBE(0);
Expand Down Expand Up @@ -426,9 +437,9 @@ export class OutgoingPackets {
packet.writeOffsetShortLE(this.player.position.chunkY + 6);
packet.writeByteInverted(this.player.position.level);

for(let xCalc = Math.floor(this.player.position.chunkX / 8); xCalc <= Math.floor((this.player.position.chunkX + 12) / 8); xCalc++) {
for(let yCalc = Math.floor(this.player.position.chunkY / 8); yCalc <= Math.floor((this.player.position.chunkY + 12) / 8); yCalc++) {
for(let seeds = 0; seeds < 4; seeds++){
for (let xCalc = Math.floor(this.player.position.chunkX / 8); xCalc <= Math.floor((this.player.position.chunkX + 12) / 8); xCalc++) {
for (let yCalc = Math.floor(this.player.position.chunkY / 8); yCalc <= Math.floor((this.player.position.chunkY + 12) / 8); yCalc++) {
for (let seeds = 0; seeds < 4; seeds++) {
packet.writeIntME1(0);
}
}
Expand All @@ -438,12 +449,12 @@ export class OutgoingPackets {
}

public flushQueue(): void {
if(!this.socket || this.socket.destroyed) {
if (!this.socket || this.socket.destroyed) {
return;
}

const buffer = Buffer.concat([ ...this.packetQueue, ...this.updatingQueue ]);
if(buffer.length !== 0) {
const buffer = Buffer.concat([...this.packetQueue, ...this.updatingQueue]);
if (buffer.length !== 0) {
this.socket.write(buffer);
}

Expand All @@ -452,7 +463,7 @@ export class OutgoingPackets {
}

public queue(packet: Packet, updateTask: boolean = false): void {
if(!this.socket || this.socket.destroyed) {
if (!this.socket || this.socket.destroyed) {
return;
}

Expand Down
54 changes: 54 additions & 0 deletions src/plugins/npcs/lumbridge/sheep-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ActionType, RunePlugin } from '@server/plugins/plugin';
import { npcIds } from '@server/world/config/npc-ids';
import { npcInitAction } from '@server/world/actor/npc/npc';
import { World } from '@server/world/world';
import { itemOnNpcAction } from '@server/world/actor/player/action/item-on-npc-action';
import { itemIds } from '@server/world/config/item-ids';
import { soundIds } from '@server/world/config/sound-ids';
import { animationIds } from '@server/world/config/animation-ids';

const initAction: npcInitAction = (details) => {
setInterval(() => {
if (Math.random() >= 0.66) {
details.npc.updateFlags.addChatMessage({message: `Baa!`});
details.npc.sendSound(soundIds.sheepBaa, 4);
}
}, (Math.floor(Math.random() * 20) + 10) * World.TICK_LENGTH);
};

export const shearAction: itemOnNpcAction = (details) => {
details.player.busy = true;
details.player.playAnimation(animationIds.shearSheep);
details.player.outgoingPackets.playSound(soundIds.shearSheep, 5);

setTimeout(() => {
if (Math.random() >= 0.66) {
details.player.outgoingPackets.chatboxMessage('The sheep manages to get away from you!');
// TODO: move sheep backwards about 5 tiles, moonwalk, not turn around
} else {
details.player.outgoingPackets.chatboxMessage('You get some wool.');
details.player.giveItem(itemIds.wool);
details.npc.updateFlags.addChatMessage({message: 'Baa!'});
details.npc.sendSound(soundIds.sheepBaa, 4);
//TODO: Replace with naked sheep

}
details.player.busy = false;
}, World.TICK_LENGTH);

};
export default new RunePlugin([
{
type: ActionType.NPC_INIT,
npcIds: npcIds.sheep,
action: initAction
},
{
type: ActionType.ITEM_ON_NPC_ACTION,
npcsIds: [npcIds.sheep],
itemIds: [itemIds.shears, itemIds.recruitmentDrive.shears],
walkTo: true,
action: shearAction
}
]
);
Loading