command: state => (vendor, args, player) => { const vendorConfig = vendor.getBehavior('vendor'); const tell = genTell(state, vendor, player); if (!args || !args.length) { return tell("Well, what do you want to buy?"); } const items = getVendorItems(state, vendorConfig.items); const item = Parser.parseDot(args, items); if (!item) { return tell("I don't carry that item and no, I won't check in back."); } const vendorItem = vendorConfig.items[item.entityReference]; const currencyKey = 'currencies.' + vendorItem.currency; const playerCurrency = player.getMeta(currencyKey); if (!playerCurrency || playerCurrency < vendorItem.cost) { return tell(`You can't afford that, it costs ${vendorItem.cost} ${friendlyCurrencyName(vendorItem.currency)}.`); } if (player.isInventoryFull()) { return tell("I don't think you can carry any more."); } player.setMeta(currencyKey, playerCurrency - vendorItem.cost); item.hydrate(state); state.ItemManager.add(item); player.addItem(item); say(player, `<green>You spend <b><white>${vendorItem.cost} ${friendlyCurrencyName(vendorItem.currency)}</white></b> to purchase ${item.display}.</green>`); player.save(); }
command: state => (options, player) => { if (options.length < 2) { return say(player, "Start which quest from whom? 'quest start <npc> <number>'"); } let [search, questIndex] = options; questIndex = parseInt(questIndex, 10); const npc = Parser.parseDot(search, player.room.npcs); if (!npc) { return say(player, `No quest giver [${search}] found.`); } if (!npc.quests) { return say(player, `${npc.name} has no quests.`); } if (isNaN(questIndex) || questIndex < 0 || questIndex > npc.quests.length) { return say(player, `Invalid quest, use 'quest list ${search}' to see their quests.`); } let availableQuests = npc.quests .map(qid => state.QuestFactory.create(state, qid, player)) .filter(quest => (player.questTracker.canStart(quest) || player.questTracker.isActive(quest.id))) ; const targetQuest = availableQuests[questIndex - 1]; if (player.questTracker.isActive(targetQuest.id)) { return say(player, "You've already started that quest. Use 'quest log' to see your active quests."); } player.questTracker.start(targetQuest); player.save(); }
files.forEach(function (file) { let absFile = Path.resolve(path, file + '/botmodule.json'); if (FileSystem.existsSync(absFile) && FileSystem.statSync(absFile).isFile()) { try { let conf = require(absFile); if (conf.id && this.config.loadmodules[conf.id] !== false) { let mod = new BotMod(Path.resolve(path, file), conf, this); this.modules[mod.id] = mod; this.parser.addCommands(mod.commands); this.multilang.addLangFiles(mod.langfiles, Path.resolve(path, file)); console.log('NEW MODULE: ' + mod.name); } else if (!this.modules[conf.id]) { this.modules[conf.id] = { id: conf.id, name: conf.name, description: conf.description, commands: {}, system: null, enabled: false, }; } } catch (err) { console.log('Error: Cannot load module "' + file + '" - ' + err.message + '\n' + err.stack); } } }.bind(this));
command: state => (vendor, args, player) => { const tell = genTell(state, vendor, player); const [ itemArg, confirm ] = args.split(' '); if (!args || !args.length) { tell("What did you want to sell?"); } const item = Parser.parseDot(itemArg, player.inventory); if (!item) { return say(player, "You don't have that."); } const sellable = item.getBehavior('sellable'); if (!sellable) { return say(player, "You can't sell that item."); } if (!['poor', 'common'].includes(item.quality) && confirm !== 'sure') { return say(player, "To sell higher quality items use '<b>sell <item> sure</b>'."); } const currencyKey = 'currencies.' + sellable.currency; if (!player.getMeta('currencies')) { player.setMeta('currencies', {}); } player.setMeta(currencyKey, (player.getMeta(currencyKey) || 0) + sellable.value); say(player, `<green>You sell ${item.display} for <b><white>${sellable.value} ${friendlyCurrencyName(sellable.currency)}</white></b>.</green>`); state.ItemManager.remove(item); }
command: state => (arg, player) => { if (!arg || !arg.length) { return Broadcast.sayAt(player, 'Ditch whom?'); } let target = CommandParser.parseDot(arg, player.followers); if (!target) { return Broadcast.sayAt(player, "They aren't following you."); } Broadcast.sayAt(player, `You ditch ${target.name} and they stop following you.`); Broadcast.sayAt(target, `${player.name} ditches you and you stop following them.`); target.unfollow(); }
command : state => (arg, player) => { if (!arg.length) { return Broadcast.sayAt(player, 'Remove what?'); } const [slot, item] = Parser.parseDot(arg, player.equipment, true); if (!item) { return Broadcast.sayAt(player, "You aren't wearing anything like that."); } player.unequip(slot); Broadcast.sayAt(player, `<green>You un-equip: </green>${item.display}<green>.</green>`); item.emit('unequip', player); player.emit('unequip', slot, item); }
files.forEach(function (file) { let absFile = Path.resolve(path, file + '/botmodule.json'); if (FileSystem.existsSync(absFile) && FileSystem.statSync(absFile).isFile()) { try { uncacheTree(absFile); let conf = require(absFile); if (conf.commands) { for (let i = 0; i < conf.commands.length; i++) { let cmdFile = Path.resolve(path, file, conf.commands[i]); try { uncacheTree(cmdFile); } catch (e) {} let commands = require(cmdFile); this.parser.addCommands(commands); } } } catch (err) { console.log('Error: Cannot load module "' + file + '" - ' + err.message); } } }.bind(this));
command: state => (vendor, args, player) => { const tell = genTell(state, vendor, player); if (!args || !args.length) { return tell("What did you want me to appraise?"); } const [ itemArg, confirm ] = args.split(' '); const targetItem = Parser.parseDot(itemArg, player.inventory); if (!targetItem) { return say(player, "You don't have that."); } const sellable = targetItem.getBehavior('sellable'); if (!sellable) { return say(player, "You can't sell that item."); } tell(`I could give you <b><white>${sellable.value} ${friendlyCurrencyName(sellable.currency)}</white></b> for ${targetItem.display}.</green>`); }
command: state => (options, player) => { if (!options.length) { return say(player, "List quests from whom? quest list <npc>"); } const search = options[0]; const npc = Parser.parseDot(search, player.room.npcs); if (!npc) { return say(player, `No quest giver [${search}] found.`); } if (!npc.quests) { return say(player, `${npc.name} has no quests.`); } let availableQuests = npc.quests .map(qid => state.QuestFactory.create(state, qid, player)) .filter(quest => (player.questTracker.canStart(quest) || player.questTracker.isActive(quest.id))) ; if (!availableQuests.length) { return say(player, `${npc.name} has no quests.`); } for (let i in availableQuests) { let quest = availableQuests[i]; const displayIndex = parseInt(i, 10) + 1; if (player.questTracker.canStart(quest)) { say(player, `[<b><yellow>!</yellow></b>] - ${displayIndex}. ${quest.config.title}`); } else if (player.questTracker.isActive(quest.id)) { quest = player.questTracker.get(quest.id); const symbol = quest.getProgress().percent >= 100 ? '?' : '%'; say(player, `[<b><yellow>${symbol}</yellow></b>] - ${displayIndex}. ${quest.config.title}`); } } }
command: state => (args, player) => { if (!args || !args.length) { return B.sayAt(player, 'Unlock which door?'); } const parts = args.split(' '); if (parts[0] === 'door' && parts.length >= 2) { const exitDirection = parts[1]; const exit = state.RoomManager.findExit(player.room, exitDirection); if (!exit) { return B.sayAt(player, "There is no door there."); } const nextRoom = state.RoomManager.getRoom(exit.roomId); let doorRoom = player.room; let targetRoom = nextRoom; let door = doorRoom.getDoor(targetRoom); if (!door) { doorRoom = nextRoom; targetRoom = player.room; door = doorRoom.getDoor(targetRoom); } if (!door) { return B.sayAt(player, "That exit doesn't have a door."); } if (!door.locked) { return B.sayAt(player, 'The door is already unlocked.'); } if (!door.lockedBy) { return B.sayAt(player, "You can't unlock that door."); } const playerKey = player.hasItem(door.lockedBy); if (!playerKey) { const keyItem = state.ItemFactory.getDefinition(door.lockedBy); if (!keyItem) { return B.sayAt(player, "You don't have the key."); } return B.sayAt(player, `The door can only be unlocked with ${keyItem.name}.`); } doorRoom.unlockDoor(targetRoom); return B.sayAt(player, '*click* The door unlocks.'); } // otherwise trying to open an item let item = Parser.parseDot(args, player.inventory); item = item || Parser.parseDot(args, player.room.items); if (!item) { return B.sayAt(player, "You don't see that here."); } if (!item.closed) { return B.sayAt(player, `${item.display} isn't closed...`); } if (!item.locked) { return B.sayAt(player, `${item.display} isn't locked...`); } if (item.locked) { if (item.lockedBy) { const playerKey = player.hasItem(item.lockedBy); if (playerKey) { B.sayAt(player, `*click* You unlock ${item.display} with ${playerKey.display}.`); item.unlock(); return; } } return B.sayAt(player, "The item is locked and you don't have the key."); } B.sayAt(player, `*click* You unlock ${item.display}.`); return item.unlock(); }
this.bot.on('pm', function (by, msg) { this.parser.parse(msg, null, by); }.bind(this));
this.bot.on('userchat', function (room, time, by, msg) { this.parser.parse(msg, room, by); }.bind(this));
command: state => (vendor, args, player) => { const vendorConfig = vendor.getBehavior('vendor'); const items = getVendorItems(state, vendorConfig.items); const tell = genTell(state, vendor, player); // show item to player before purchasing if (args) { const item = Parser.parseDot(args, items); if (!item) { return tell("I don't carry that item and no, I won't check in back."); } item.hydrate(state); const vendorItem = vendorConfig.items[item.entityReference]; B.sayAt(player, renderItem(state, item, player)); B.sayAt(player, `Cost: <b><white>[${friendlyCurrencyName(vendorItem.currency)}]</white></b> x ${vendorItem.cost}`); return; } // group vendor's items by category then display them let itemCategories = { [ItemType.POTION]: { title: 'Potions', items: [], }, [ItemType.ARMOR]: { title: 'Armor', items: [], }, [ItemType.WEAPON]: { title: 'Weapons', items: [], }, [ItemType.CONTAINER]: { title: 'Containers', items: [], }, [ItemType.OBJECT]: { title: 'Miscellaneous', items: [], }, }; for (const item of items) { itemCategories[item.type].items.push(item); } for (const [, itemCategory] of Object.entries(ItemType)) { const category = itemCategories[itemCategory]; if (!category || !category.items.length) { continue; } B.sayAt(player, '.' + B.center(78, category.title, 'yellow', '-') + '.'); for (const item of category.items) { const vendorItem = vendorConfig.items[item.entityReference]; B.sayAt(player, '<yellow>|</yellow> ' + item.qualityColorize(sprintf('%-48s', `[${item.name}]`)) + sprintf(' <yellow>|</yellow> <b>%-26s</b>', B.center(26, friendlyCurrencyName(vendorItem.currency) + ' x ' + vendorItem.cost)) + '<yellow>|</yellow> ' ); } B.sayAt(player, "'" + B.line(78, '-', 'yellow') + "'"); B.sayAt(player); } }
function lookEntity(state, player, args) { const room = player.room; args = args.split(' '); let search = null; if (args.length > 1) { search = args[0] === 'in' ? args[1] : args[0]; } else { search = args[0]; } let entity = CommandParser.parseDot(search, room.items); entity = entity || CommandParser.parseDot(search, room.players); entity = entity || CommandParser.parseDot(search, room.npcs); entity = entity || CommandParser.parseDot(search, player.inventory); if (!entity) { return B.sayAt(player, "You don't see anything like that here."); } if (entity instanceof Player) { // TODO: Show player equipment? B.sayAt(player, `You see fellow player ${entity.name}.`); return; } B.sayAt(player, entity.description, 80); if (entity.timeUntilDecay) { B.sayAt(player, `You estimate that ${entity.name} will rot away in ${humanize(entity.timeUntilDecay)}.`); } const usable = entity.getBehavior('usable'); if (usable) { if (usable.spell) { const useSpell = state.SpellManager.get(usable.spell); if (useSpell) { useSpell.options = usable.options; B.sayAt(player, useSpell.info(player)); } } if (usable.effect && usable.config.description) { B.sayAt(player, usable.config.description); } if (usable.charges) { B.sayAt(player, `There are ${usable.charges} charges remaining.`); } } if (entity instanceof Item) { switch (entity.type) { case ItemType.WEAPON: case ItemType.ARMOR: return B.sayAt(player, renderItem(state, entity, player)); case ItemType.CONTAINER: { if (!entity.inventory || !entity.inventory.size) { return B.sayAt(player, `${entity.name} is empty.`); } B.at(player, 'Contents'); if (isFinite(entity.inventory.getMax())) { B.at(player, ` (${entity.inventory.size}/${entity.inventory.getMax()})`); } B.sayAt(player, ':'); for (const [, item ] of entity.inventory) { B.sayAt(player, ' ' + item.display); } break; } } } }