Skip to content

Commit

Permalink
Merge pull request #67 from nicknick-io/implement-shops
Browse files Browse the repository at this point in the history
Extremely simple implementation of shops.
  • Loading branch information
TheBlackParade committed Feb 20, 2020
2 parents ad7fab5 + 7ed7550 commit 5cde103
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 1 deletion.
8 changes: 8 additions & 0 deletions data/config/npc-spawns.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,11 @@
x: 3222
y: 3220
radius: 4
- npcId: 520
x: 3211
y: 3247
radius: 1
- npcId: 519
x: 3230
y: 3203
radius: 1
70 changes: 70 additions & 0 deletions data/config/shops.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
- identification: LUMBRIDGE_GENERAL_STORE
name: Lumbridge General Store
items:
- id: 1931
text: Pot
price: 1
amountInStock: 5
- id: 1935
text: Jug
price: 1
amountInStock: 2
- id: 5603
text: Shears
price: 1
amountInStock: 2
- id: 1925
text: Bucket
price: 2
amountInStock: 3
- id: 1887
text: Cake tin
price: 13
amountInStock: 2
- id: 590
text: Tinderbox
price: 1
amountInStock: 2
- id: 1755
text: Chisel
price: 1
amountInStock: 2
- id: 952
text: Spade
price: 3
amountInStock: 5
- id: 2347
text: Hammer
price: 1
amountInStock: 5
- identification: BOBS_AXES
name: Bob's Brilliant Axes
items:
- id: 1265
text: Bronze pickaxe
price: 1
amountInStock: 5
- id: 1351
text: Bronze axe
price: 16
amountInStock: 10
- id: 1349
text: Iron axe
price: 56
amountInStock: 5
- id: 1353
text: Steel axe
price: 200
amountInStock: 3
- id: 1363
text: Iron battleaxe
price: 182
amountInStock: 5
- id: 1365
text: Steel battleaxe
price: 650
amountInStock: 2
- id: 1369
text: Mithril battleaxe
price: 1690
amountInStock: 1
4 changes: 4 additions & 0 deletions src/net/rs-buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ export class RsBuffer {
return value;
}

public writeUnsignedByteInverted(value: number): void {
this.writeUnsignedByte(~value & 0xff);
}

public readSmart(): number {
const peek = this.buffer.readUInt8(this.readerIndex);
if(peek < 128) {
Expand Down
9 changes: 9 additions & 0 deletions src/plugins/npc/lumbridge/bobs-axes/bob-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { npcAction, NpcActionPlugin } from '@server/world/mob/player/action/npc-action';
import { openShop } from '@server/world/mob/player/action/shop-action';

const action: npcAction = (details) => {
const { player, npc } = details;
openShop(details.player, 'BOBS_AXES');
};

export default { npcIds: 519, options: 'trade', walkTo: true, action } as NpcActionPlugin;
10 changes: 10 additions & 0 deletions src/plugins/npc/lumbridge/general-store/shopkeeper-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { npcAction, NpcActionPlugin } from '@server/world/mob/player/action/npc-action';
import { openShop } from '@server/world/mob/player/action/shop-action';


const action: npcAction = (details) => {
const { player, npc } = details;
openShop(details.player, 'LUMBRIDGE_GENERAL_STORE');
};

export default { npcIds: 520, options: 'trade', walkTo: true, action } as NpcActionPlugin;
36 changes: 36 additions & 0 deletions src/world/config/shops.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { logger } from '@runejs/logger/dist/logger';
import { JSON_SCHEMA, safeLoad } from 'js-yaml';
import { readFileSync } from 'fs';

export interface Shop {
identification: string;
name: string;
interfaceId: number;
items: ShopItems[];
}

interface ShopItems {
id: number;
name: string;
amountInStock: number;
price: number;
}

export function parseShops(): Shop[] {
try {
logger.info('Parsing shops...');

const shops = safeLoad(readFileSync('data/config/shops.yaml', 'utf8'), { schema: JSON_SCHEMA }) as Shop[];

if(!shops || shops.length === 0) {
throw 'Unable to read shops.';
}

logger.info(`${shops.length} shops found.`);

return shops;
} catch(error) {
logger.error('Error parsing shops: ' + error);
return null;
}
}
4 changes: 4 additions & 0 deletions src/world/items/item-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ export class ItemContainer {
}
}

public amountInStack(index: number): number {
return this._items[index].amount;
}

public removeFirst(item: number | Item, fireEvent: boolean = true): number {
const slot = this.findIndex(item);
if(slot === -1) {
Expand Down
30 changes: 30 additions & 0 deletions src/world/mob/player/action/buy-item-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Player } from '@server/world/mob/player/player';
import { gameCache } from '@server/game-server';
import { widgetIds } from '@server/world/mob/player/widget';

export const buyItemAction = (player: Player, itemId: number, amount: number, slot: number, interfaceId: number) => {

const purchasedItem = gameCache.itemDefinitions.get(itemId);
const coinsInInventoryIndex = player.inventory.findIndex(995);
const amountInStack = player.inventory.amountInStack(coinsInInventoryIndex);
const amountLeftAfterPurchase = amountInStack - (purchasedItem.value * amount);

// Take the money.
player.inventory.set(player.inventory.findIndex(itemId), { itemId, amount: amount});
player.inventory.set(coinsInInventoryIndex, {itemId: 995, amount: amountLeftAfterPurchase});

// Add the purchased item(s) to the inventory.
if (amount > 1) {
for (let i = 0; i < amount; i++) {
player.inventory.add(itemId);
}
}

if(amount === 1) {
player.inventory.add(itemId);
}

// Update the inventory items.
player.packetSender.sendUpdateAllWidgetItems(widgetIds.inventory, player.inventory);

};
43 changes: 43 additions & 0 deletions src/world/mob/player/action/shop-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { world } from '@server/game-server';
import { Player } from '@server/world/mob/player/player';
import { logger } from '@runejs/logger/dist/logger';
import { Shop } from '@server/world/config/shops';

function findShop(identification: string): Shop {
for(let i = 0; i <= world.shops.length; i++) {
if(world.shops[i].identification === identification) return world.shops[i];
}
return undefined;
}

export function openShop(player: Player, identification: string, closeOnWalk: boolean = true): void {
try {
const openedShop = findShop(identification);
if(openedShop === undefined) {
throw `Unable to find the shop with identification of: ${identification}`;
}
player.packetSender.updateWidgetString(3901, openedShop.name);
for(let i = 0; i < 30; i++) {
if(openedShop.items.length <= i) {
player.packetSender.sendUpdateSingleWidgetItem(3900, i, null);
} else {
player.packetSender.sendUpdateSingleWidgetItem(3900, i, {
itemId: openedShop.items[i].id, amount: openedShop.items[i].amountInStock
});
}
}
for(let i = 0; i < openedShop.items.length; i++) {
player.packetSender.sendUpdateSingleWidgetItem(3900, i, {
itemId: openedShop.items[i].id, amount: openedShop.items[i].amountInStock
});
}
player.activeWidget = {
widgetId: 3824,
type: 'SCREEN',
closeOnWalk: closeOnWalk
};
} catch (error) {
logger.error(`Error opening shop ${identification}: ` + error);
}

}
49 changes: 49 additions & 0 deletions src/world/mob/player/packet/impl/buy-item-packet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { incomingPacket } from '@server/world/mob/player/packet/incoming-packet';
import { Player } from '@server/world/mob/player/player';
import { RsBuffer } from '@server/net/rs-buffer';
import { gameCache } from '@server/game-server';
import { buyItemAction } from '@server/world/mob/player/action/buy-item-action';

export const buyItemPacket: incomingPacket = (player: Player, packetId: number, packetSize: number, packet: RsBuffer): void => {

if(packetId === 177) {
const slot = packet.readNegativeOffsetShortBE();
const itemId = packet.readShortLE();
const interfaceId = packet.readShortLE();

if(player.inventory.findItemIndex({itemId: 995, amount: gameCache.itemDefinitions.get(itemId).value}) === undefined) {
player.packetSender.chatboxMessage(`You don't have enough coins.`);
return;
}

buyItemAction(player, itemId, 1, slot, interfaceId);
}

if(packetId === 91) {
const itemId = packet.readShortLE();
const slot = packet.readNegativeOffsetShortLE();
const interfaceId = packet.readShortBE();

if(player.inventory.findItemIndex({itemId: 995, amount: gameCache.itemDefinitions.get(itemId).value * 5}) === undefined) {
player.packetSender.chatboxMessage(`You don't have enough coins.`);
return;
}

buyItemAction(player, itemId, 5, slot, interfaceId);
}

if(packetId === 231) {
const interfaceId = packet.readNegativeOffsetShortLE();
const slot = packet.readShortLE();
const itemId = packet.readShortBE();

if(player.inventory.findItemIndex({itemId: 995, amount: gameCache.itemDefinitions.get(itemId).value * 10}) === undefined) {
player.packetSender.chatboxMessage(`You don't have enough coins.`);
return;
}

buyItemAction(player, itemId, 10, slot, interfaceId);
}

return;
};
7 changes: 6 additions & 1 deletion src/world/mob/player/packet/incoming-packet-directory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { objectInteractionPacket } from '@server/world/mob/player/packet/impl/ob
import { chatPacket } from '@server/world/mob/player/packet/impl/chat-packet';
import { dropItemPacket } from '@server/world/mob/player/packet/impl/drop-item-packet';
import { itemOnItemPacket } from '@server/world/mob/player/packet/impl/item-on-item-packet';
import { buyItemPacket } from '@server/world/mob/player/packet/impl/buy-item-packet';

const packets: { [key: number]: incomingPacket } = {
19: interfaceClickPacket,
Expand Down Expand Up @@ -51,7 +52,11 @@ const packets: { [key: number]: incomingPacket } = {
1: itemOnItemPacket,

49: chatPacket,
56: commandPacket
56: commandPacket,

177: buyItemPacket,
91: buyItemPacket,
231: buyItemPacket
};

export function handlePacket(player: Player, packetId: number, packetSize: number, buffer: Buffer): void {
Expand Down
3 changes: 3 additions & 0 deletions src/world/world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { gameCache } from '@server/game-server';
import { Position } from './position';
import { NpcSpawn, parseNpcSpawns } from './config/npc-spawn';
import { Npc } from './mob/npc/npc';
import { parseShops, Shop } from '@server/world/config/shops';
import Quadtree from 'quadtree-lib';
import { timer } from 'rxjs';
import { Mob } from '@server/world/mob/mob';
Expand All @@ -30,12 +31,14 @@ export class World {
public readonly chunkManager: ChunkManager = new ChunkManager();
public readonly itemData: Map<number, ItemDetails>;
public readonly npcSpawns: NpcSpawn[];
public readonly shops: Shop[];
public readonly playerTree: Quadtree<any>;
public readonly npcTree: Quadtree<any>;

public constructor() {
this.itemData = parseItemData(gameCache.itemDefinitions);
this.npcSpawns = parseNpcSpawns();
this.shops = parseShops();
this.playerTree = new Quadtree<any>({
width: 10000,
height: 10000
Expand Down

0 comments on commit 5cde103

Please sign in to comment.