diff --git a/data/config/items/other.json b/data/config/items/other.json index 044e92719..d61bde3b5 100644 --- a/data/config/items/other.json +++ b/data/config/items/other.json @@ -1,6 +1,10 @@ { - "rs:dwarf_remains": { - "game_id": 0, - "tradable": false - } + "rs:dwarf_remains": { + "game_id": 0, + "tradable": false + }, + "rs:newcomer_map": { + "game_id": 550, + "tradable": true + } } diff --git a/data/config/shops/lumbridge/lumbridge-general-store.json b/data/config/shops/lumbridge/lumbridge-general-store.json index 29245cb6f..5e541a960 100644 --- a/data/config/shops/lumbridge/lumbridge-general-store.json +++ b/data/config/shops/lumbridge/lumbridge-general-store.json @@ -1,18 +1,25 @@ { + "presets": { + "rs:general_store_base": { + "stock": [ + [ "rs:pot", 5 ], + [ "rs:jug", 2 ], + [ "rs:shears", 2 ], + [ "rs:bucket", 3 ], + [ "rs:cake_tin", 2 ], + [ "rs:tinderbox", 2 ], + [ "rs:chisel", 2 ], + [ "rs:spade", 5 ] + ] + } + }, "rs:lumbridge_general_store": { - "name": "Lumbridge General Store", - "general_store": true, - "shop_sell_rate": 1.3, - "stock": [ - [ "rs:pot", 5 ], - [ "rs:jug", 2 ], - [ "rs:shears", 2 ], - [ "rs:bucket", 3 ], - [ "rs:cake_tin", 2 ], - [ "rs:tinderbox", 2 ], - [ "rs:chisel", 2 ], - [ "rs:spade", 5 ], - [ "rs:hammer", 5 ] + "name": "Lumbridge General Store", + "extends": "rs:general_store_base", + "general_store": true, + "shop_sell_rate": 1.3, + "stock": [ + ["rs:newcomer_map", 7 ] ] } } diff --git a/src/game-engine/config/index.ts b/src/game-engine/config/index.ts index 06cf8c3e4..e2652e6f4 100644 --- a/src/game-engine/config/index.ts +++ b/src/game-engine/config/index.ts @@ -16,7 +16,13 @@ import { translateNpcConfig } from '@engine/config/npc-config'; import { loadNpcSpawnConfigurations, NpcSpawn } from '@engine/config/npc-spawn-config'; -import { loadShopConfigurations, Shop } from '@engine/config/shop-config'; +import { + loadShopConfigurations, + Shop, + shopFactory, + ShopPresetConfiguration, + translateShopConfig +} from '@engine/config/shop-config'; import { Quest } from '@engine/world/actor/player/quest'; import { ItemSpawn, loadItemSpawnConfigurations } from '@engine/config/item-spawn-config'; import { loadSkillGuideConfigurations, SkillGuide } from '@engine/config/skill-guide-config'; @@ -53,6 +59,7 @@ export let npcSpawns: NpcSpawn[] = []; export let musicRegions: MusicTrack[] = []; export let itemSpawns: ItemSpawn[] = []; export let shopMap: { [key: string]: Shop }; +export let shopPresetMap: ShopPresetConfiguration; export let skillGuides: SkillGuide[] = []; export const musicRegionMap = new Map(); @@ -77,7 +84,9 @@ export async function loadConfigurations(): Promise { musicRegions.forEach(song => song.regionIds.forEach(region => musicRegionMap.set(region, song.songId))); itemSpawns = await loadItemSpawnConfigurations('data/config/item-spawns'); - shopMap = await loadShopConfigurations('data/config/shops'); + const { shops, shopPresets } = await loadShopConfigurations('data/config/shops'); + shopMap = shops; + shopPresetMap = shopPresets; skillGuides = await loadSkillGuideConfigurations('data/config/skill-guides'); logger.info(`Loaded ${musicRegions.length} music regions, ${Object.keys(itemMap).length} items, ${itemSpawns.length} item spawns, ` + @@ -189,8 +198,26 @@ export const findShop = (shopKey: string): Shop | null => { if(!shopKey) { return null; } + let shop: Shop; + + if(shopKey) { + shop = shopMap[shopKey]; + + if(shop.extends) { + let extensions = shop.extends; + if(typeof extensions === 'string') { + extensions = [ extensions ]; + } - return shopMap[shopKey] || null; + extensions.forEach(extKey => { + const extensionShop = shopPresetMap[extKey]; + if(extensionShop) { + shop = _.merge(shop, shopFactory( )); + } + }); + } + } + return shop; }; diff --git a/src/game-engine/config/shop-config.ts b/src/game-engine/config/shop-config.ts index 193304ced..65d9eff9f 100644 --- a/src/game-engine/config/shop-config.ts +++ b/src/game-engine/config/shop-config.ts @@ -1,13 +1,14 @@ import { ItemContainer } from '@engine/world/items/item-container'; import { findItem, loadConfigurationFiles, widgets } from '@engine/config/index'; import { Player } from '@engine/world/actor/player/player'; -import { ItemDetails } from '@engine/config/item-config'; +import { ItemConfiguration, ItemDetails, ItemPresetConfiguration, translateItemConfig } from '@engine/config/item-config'; +import { logger } from '@runejs/core'; export type ShopStock = [ [ string, number ] ]; export class Shop { - + public readonly extends?: string | string[]; public readonly key: string; public readonly originalStock: ShopStock; public readonly container: ItemContainer; @@ -19,8 +20,9 @@ export class Shop { public buyRate: number; public rateModifier: number; - public constructor(key: string, name: string, generalStore: boolean, stock: ShopStock, sellRate: number, buyRate: number, modifier: number) { + public constructor(key: string, extensions: string | string[], name: string, generalStore: boolean, stock: ShopStock, sellRate: number, buyRate: number, modifier: number) { this.key = key; + this.extends = extensions; this.name = name; this.generalStore = generalStore; this.buyRate = buyRate; @@ -108,6 +110,7 @@ export class Shop { } export interface ShopConfiguration { + extends?: string | string[]; name: string; general_store?: boolean; shop_sell_rate?: number; @@ -116,21 +119,45 @@ export interface ShopConfiguration { stock: ShopStock; } +export interface ShopPresetConfiguration { + [key: string]: ShopConfiguration; +} + export function shopFactory(key: string, config: ShopConfiguration): Shop { - return new Shop(key, config.name, config.general_store || false, config.stock, + return new Shop(key, config.extends, config.name, config.general_store || false, config.stock, config.shop_sell_rate || 100, config.shop_buy_rate || 0.65, config.rate_modifier || 0.2); } -export async function loadShopConfigurations(path: string): Promise<{ [key: string]: Shop }> { +export function translateShopConfig(key: string, config: ShopConfiguration): any { + logger.info('config stock: ' + config.stock.length + ' ' + config.stock[0]) + return { + key: key, + name: config.name, + extends: config.extends || undefined, + general_store: config.general_store || false, + shop_sell_rate: config.shop_sell_rate || 100, + shop_buy_rate: config.shop_buy_rate || 0.65, + rate_modifier: config.rate_modifier || 0.2, + stock: config.stock + }; +} + +export async function loadShopConfigurations(path: string): Promise<{ shops: { [key: string]: Shop }, shopPresets: ShopPresetConfiguration }> { const shops: { [key: string]: Shop } = {}; + let shopPresets: ShopPresetConfiguration = {}; const files = await loadConfigurationFiles(path); files.forEach(shopConfigs => { const shopKeys = Object.keys(shopConfigs); shopKeys.forEach(key => { - shops[key] = shopFactory(key, shopConfigs[key]); + if(key === 'presets') { + shopPresets = { ...shopPresets, ...shopConfigs[key] }; + logger.debug('shopPresets: ' + shopPresets['rs:general_store_base'].stock) + } else { + shops[key] = shopFactory(key, shopConfigs[key]); + } }); }); - return shops; + return { shops, shopPresets }; }