Skip to content

Commit

Permalink
Merge pull request #92 from rune-js/equipment-screen
Browse files Browse the repository at this point in the history
Item action plugins + player equipment stats screen
  • Loading branch information
TheBlackParade authored Feb 28, 2020
2 parents 6c2938a + a34207e commit 04a5cf9
Show file tree
Hide file tree
Showing 13 changed files with 350 additions and 130 deletions.
2 changes: 2 additions & 0 deletions src/game-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { setItemOnItemPlugins } from '@server/world/actor/player/action/item-on-
import { setButtonPlugins } from '@server/world/actor/player/action/button-action';
import { setCommandPlugins } from '@server/world/actor/player/action/input-command-action';
import { setWidgetPlugins } from '@server/world/actor/player/action/widget-action';
import { setItemPlugins } from '@server/world/actor/player/action/item-action';

export let serverConfig: ServerConfig;
export let gameCache377: EarlyFormatGameCache;
Expand All @@ -39,6 +40,7 @@ export async function injectPlugins(): Promise<void> {
setNpcPlugins(actionTypes[ActionType.NPC_ACTION]);
setObjectPlugins(actionTypes[ActionType.OBJECT_ACTION]);
setItemOnItemPlugins(actionTypes[ActionType.ITEM_ON_ITEM]);
setItemPlugins(actionTypes[ActionType.ITEM_ACTION]);
setCommandPlugins(actionTypes[ActionType.COMMAND]);
setWidgetPlugins(actionTypes[ActionType.WIDGET_ACTION]);
}
Expand Down
28 changes: 2 additions & 26 deletions src/net/incoming-packets/item-equip-packet.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,13 @@
import { incomingPacket } from '../incoming-packet';
import { Player } from '../../world/actor/player/player';
import { RsBuffer } from '@server/net/rs-buffer';
import { logger } from '@runejs/logger/dist/logger';
import { widgetIds } from '../../world/config/widget';
import { equipItemAction } from '../../world/actor/player/action/equip-item-action';
import { itemAction } from '@server/world/actor/player/action/item-action';

export const itemEquipPacket: incomingPacket = (player: Player, packetId: number, packetSize: number, packet: RsBuffer): void => {
const containerId = packet.readShortLE();
const widgetId = packet.readShortLE();
const slot = packet.readNegativeOffsetShortLE();
const itemId = packet.readShortBE();

if(widgetId !== widgetIds.inventory.widgetId || containerId !== widgetIds.inventory.containerId) {
logger.warn(`${player.username} attempted to equip item from incorrect widget ${widgetId}:${containerId}.`);
return;
}

if(slot < 0 || slot > 27) {
logger.warn(`${player.username} attempted to equip item ${itemId} in invalid slot ${slot}.`);
return;
}

const itemInSlot = player.inventory.items[slot];

if(!itemInSlot) {
logger.warn(`${player.username} attempted to equip item ${itemId} in slot ${slot}, but they do not have that item.`);
return;
}

if(itemInSlot.itemId !== itemId) {
logger.warn(`${player.username} attempted to equip item ${itemId} in slot ${slot}, but ${itemInSlot.itemId} was found there instead.`);
return;
}

equipItemAction(player, itemId, slot);
itemAction(player, itemId, slot, widgetId, containerId, 'equip');
};
13 changes: 6 additions & 7 deletions src/net/incoming-packets/item-option-1-packet.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { incomingPacket } from '../incoming-packet';
import { RsBuffer } from '@server/net/rs-buffer';
import { Player } from '../../world/actor/player/player';
import { widgetIds } from '../../world/config/widget';
import { logger } from '@runejs/logger/dist/logger';
import { unequipItemAction } from '../../world/actor/player/action/unequip-item-action';
import { ItemContainer } from '@server/world/items/item-container';
import { buyItemValueAction } from '@server/world/actor/player/action/buy-item-value-action';
import { sellItemValueAction } from '@server/world/actor/player/action/sell-item-value-action';
import { itemAction } from '@server/world/actor/player/action/item-action';

export const itemOption1Packet: incomingPacket = (player: Player, packetId: number, packetSize: number, packet: RsBuffer): void => {
const itemId = packet.readNegativeOffsetShortBE();
const slot = packet.readShortLE();
const widgetId = packet.readShortLE();
const containerId = packet.readShortLE();

// @TODO parse widgets and find actual item option NAME to pass to this
itemAction(player, itemId, slot, widgetId, containerId, 'option-1');

/*
// Handles the value option in shops.
if(widgetId === widgetIds.shop.shopInventory) {
buyItemValueAction(player, itemId, slot);
Expand Down Expand Up @@ -56,5 +55,5 @@ export const itemOption1Packet: incomingPacket = (player: Player, packetId: numb
if(widgetId === widgetIds.equipment.widgetId && containerId === widgetIds.equipment.containerId) {
unequipItemAction(player, itemId, slot);
}
}*/
};
8 changes: 4 additions & 4 deletions src/net/outgoing-packets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,10 @@ export class OutgoingPackets {
this.queue(packet);
}

public showScreenAndTabWidgets(widgetId: number, sidebarId: number) : void {
const packet = new Packet(128);
packet.writeNegativeOffsetShortBE(widgetId);
packet.writeNegativeOffsetShortLE(sidebarId);
public showScreenAndTabWidgets(widgetId: number, tabWidgetId: number) : void {
const packet = new Packet(84);
packet.writeUnsignedShortBE(tabWidgetId);
packet.writeUnsignedOffsetShortLE(widgetId);
this.queue(packet);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,57 @@
import { Player } from '../player';
import { world } from '@server/game-server';
import { logger } from '@runejs/logger/dist/logger';
import { ActionType, RunePlugin } from '@server/plugins/plugin';
import { widgetIds } from '@server/world/config/widget';
import { getItemFromContainer, itemAction } from '@server/world/actor/player/action/item-action';
import { updateBonusStrings } from '@server/plugins/equipment/equipment-stats-plugin';
import { EquipmentSlot, equipmentSlotIndex, ItemDetails, WeaponType } from '@server/world/config/item-data';
import { Item } from '@server/world/items/item';
import { widgetIds } from '../../../config/widget';
import { world } from '@server/game-server';
import { Player } from '@server/world/actor/player/player';
import { ItemContainer } from '@server/world/items/item-container';

export const equipItemAction = (player: Player, itemId: number, inventorySlot: number) => {
const itemToEquipData = world.itemData.get(itemId);
function unequipItem(player: Player, inventory: ItemContainer, equipment: ItemContainer, slot: EquipmentSlot): boolean {
const inventorySlot = inventory.getFirstOpenSlot();

if(!itemToEquipData || !itemToEquipData.equipment || !itemToEquipData.equipment.slot) {
logger.warn(`Can not equip item ${itemId}/${itemToEquipData.name}`);
return;
if(inventorySlot === -1) {
player.outgoingPackets.chatboxMessage(`You don't have enough free space to do that.`);
return false;
}

const itemInSlot = equipment.items[slot];

if(!itemInSlot) {
return true;
}

equipment.remove(slot);
inventory.set(inventorySlot, itemInSlot);
return true;
}

export const action: itemAction = (details) => {
const { player, itemId, itemSlot, itemDetails, widgetId } = details;

const inventory = player.inventory;
const equipment = player.equipment;
const equipmentSlot = equipmentSlotIndex(itemToEquipData.equipment.slot);
const itemToEquip = getItemFromContainer(itemId, itemSlot, inventory);

if(!itemToEquip) {
// The specified item was not found in the specified slot.
return;
}

if(!itemDetails || !itemDetails.equipment || !itemDetails.equipment.slot) {
player.outgoingPackets.chatboxMessage(`Unable to equip item ${itemId}/${itemDetails.name}: Missing equipment data.`);
return;
}

const equipmentSlot = equipmentSlotIndex(itemDetails.equipment.slot);

const itemToEquip: Item = inventory.items[inventorySlot];
const itemToUnequip: Item = equipment.items[equipmentSlot];
let shouldUnequipOffHand: boolean = false;
let shouldUnequipMainHand: boolean = false;

if(itemToEquipData && itemToEquipData.equipment) {
if(itemToEquipData.equipment.weaponType === WeaponType.TWO_HANDED) {
if(itemDetails && itemDetails.equipment) {
if(itemDetails.equipment.weaponType === WeaponType.TWO_HANDED) {
shouldUnequipOffHand = true;
}

Expand All @@ -47,13 +74,13 @@ export const equipItemAction = (player: Player, itemId: number, inventorySlot: n
}

equipment.remove(equipmentSlot, false);
inventory.remove(inventorySlot, false);
inventory.remove(itemSlot, false);

equipment.set(equipmentSlot, itemToEquip);
inventory.set(inventorySlot, itemToUnequip);
inventory.set(itemSlot, itemToUnequip);
} else {
equipment.set(equipmentSlot, itemToEquip);
inventory.remove(inventorySlot);
inventory.remove(itemSlot);

if(shouldUnequipOffHand) {
unequipItem(player, inventory, equipment, EquipmentSlot.OFF_HAND);
Expand All @@ -64,28 +91,24 @@ export const equipItemAction = (player: Player, itemId: number, inventorySlot: n
}
}

player.updateBonuses();

// @TODO change packets to only update modified container slots
player.outgoingPackets.sendUpdateAllWidgetItems(widgetIds.inventory, inventory);
player.outgoingPackets.sendUpdateAllWidgetItems(widgetIds.equipment, equipment);
// player.updateBonuses(); @TODO move this to when the equipment widget gets opened
player.updateFlags.appearanceUpdateRequired = true;
};

function unequipItem(player: Player, inventory: ItemContainer, equipment: ItemContainer, slot: EquipmentSlot): boolean {
const inventorySlot = inventory.getFirstOpenSlot();

if(inventorySlot === -1) {
player.outgoingPackets.chatboxMessage(`You don't have enough free space to do that.`);
return false;
if(player.hasWidgetOpen(widgetIds.equipmentStats.widgetId)) {
player.outgoingPackets.sendUpdateAllWidgetItems(widgetIds.equipmentStats, equipment);
updateBonusStrings(player);
}

const itemInSlot = equipment.items[slot];

if(!itemInSlot) {
return true;
}
player.updateFlags.appearanceUpdateRequired = true;
};

equipment.remove(slot);
inventory.set(inventorySlot, itemInSlot);
return true;
}
export default new RunePlugin({
type: ActionType.ITEM_ACTION,
widgets: widgetIds.inventory,
options: 'equip',
action,
cancelOtherActions: false
});
42 changes: 42 additions & 0 deletions src/plugins/equipment/equipment-stats-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { buttonAction } from '@server/world/actor/player/action/button-action';
import { ActionType, RunePlugin } from '@server/plugins/plugin';
import { widgetIds } from '@server/world/config/widget';
import { Player } from '@server/world/actor/player/player';

export function updateBonusStrings(player: Player) {
[
{ id: 108, text: 'Stab', value: player.bonuses.offencive.stab },
{ id: 109, text: 'Slash', value: player.bonuses.offencive.slash },
{ id: 110, text: 'Crush', value: player.bonuses.offencive.crush },
{ id: 111, text: 'Magic', value: player.bonuses.offencive.magic },
{ id: 112, text: 'Range', value: player.bonuses.offencive.ranged },
{ id: 113, text: 'Stab', value: player.bonuses.defencive.stab },
{ id: 114, text: 'Slash', value: player.bonuses.defencive.slash },
{ id: 115, text: 'Crush', value: player.bonuses.defencive.crush },
{ id: 116, text: 'Magic', value: player.bonuses.defencive.magic },
{ id: 117, text: 'Range', value: player.bonuses.defencive.ranged },
{ id: 119, text: 'Strength', value: player.bonuses.skill.strength },
{ id: 120, text: 'Prayer', value: player.bonuses.skill.prayer },
].forEach(bonus => player.outgoingPackets.updateWidgetString(widgetIds.equipmentStats.widgetId, bonus.id,
`${bonus.text}: ${bonus.value > 0 ? `+${bonus.value}` : bonus.value}`));
}

export const action: buttonAction = (details) => {
const { player } = details;

player.updateBonuses();

updateBonusStrings(player);

player.outgoingPackets.sendUpdateAllWidgetItems(widgetIds.equipmentStats, player.equipment);
player.outgoingPackets.sendUpdateAllWidgetItems(widgetIds.inventory, player.inventory);

player.activeWidget = {
widgetId: widgetIds.equipmentStats.widgetId,
secondaryWidgetId: widgetIds.inventory.widgetId,
type: 'SCREEN_AND_TAB',
closeOnWalk: true
};
};

export default new RunePlugin({ type: ActionType.BUTTON, widgetId: widgetIds.equipment.widgetId, buttonIds: 24, action });
50 changes: 50 additions & 0 deletions src/plugins/equipment/unequip-item-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ActionType, RunePlugin } from '@server/plugins/plugin';
import { widgetIds } from '@server/world/config/widget';
import { getItemFromContainer, itemAction } from '@server/world/actor/player/action/item-action';
import { updateBonusStrings } from '@server/plugins/equipment/equipment-stats-plugin';

export const action: itemAction = (details) => {
const { player, itemId, itemSlot, widgetId } = details;

const equipment = player.equipment;
const item = getItemFromContainer(itemId, itemSlot, equipment);

if(!item) {
// The specified item was not found in the specified slot.
return;
}

const inventory = player.inventory;
const inventorySlot = inventory.getFirstOpenSlot();

if(inventorySlot === -1) {
player.outgoingPackets.chatboxMessage(`You don't have enough free space to do that.`);
return;
}

equipment.remove(itemSlot);
inventory.set(inventorySlot, item);

player.updateBonuses();

player.outgoingPackets.sendUpdateSingleWidgetItem(widgetIds.inventory, inventorySlot, item);
player.outgoingPackets.sendUpdateSingleWidgetItem(widgetIds.equipment, itemSlot, null);

if(widgetId === widgetIds.equipmentStats.widgetId) {
player.outgoingPackets.sendUpdateSingleWidgetItem(widgetIds.equipmentStats, itemSlot, null);
updateBonusStrings(player);
}

player.updateFlags.appearanceUpdateRequired = true;
};

export default new RunePlugin({
type: ActionType.ITEM_ACTION,
widgets: [
widgetIds.equipment,
widgetIds.equipmentStats
],
options: 'option-1',
action,
cancelOtherActions: false
});
28 changes: 28 additions & 0 deletions src/plugins/plugin-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,34 @@ import * as fs from 'fs';
import * as util from 'util';
import { RunePlugin } from '@server/plugins/plugin';

export const basicStringFilter = (pluginValues: string | string[], searchValue: string): boolean => {
if(Array.isArray(pluginValues)) {
if(pluginValues.indexOf(searchValue) === -1) {
return false;
}
} else {
if(pluginValues !== searchValue) {
return false;
}
}

return true;
};

export const basicNumberFilter = (pluginValues: number | number[], searchValue: number): boolean => {
if(Array.isArray(pluginValues)) {
if(pluginValues.indexOf(searchValue) === -1) {
return false;
}
} else {
if(pluginValues !== searchValue) {
return false;
}
}

return true;
};

export const pluginFilter = (pluginIds: number | number[], searchId: number, pluginOptions?: string | string[], searchOption?: string): boolean => {
if(Array.isArray(pluginIds)) {
if(pluginIds.indexOf(searchId) === -1) {
Expand Down
8 changes: 5 additions & 3 deletions src/plugins/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { ButtonActionPlugin } from '@server/world/actor/player/action/button-act
import { ItemOnItemActionPlugin } from '@server/world/actor/player/action/item-on-item-action';
import { CommandActionPlugin } from '@server/world/actor/player/action/input-command-action';
import { WidgetActionPlugin } from '@server/world/actor/player/action/widget-action';
import { ItemActionPlugin } from '@server/world/actor/player/action/item-action';

export enum ActionType {
BUTTON = 'button',
WIDGET_ACTION = 'widget_action',
ITEM_ON_ITEM = 'item_on_item',
ITEM_ACTION = 'item_action',
NPC_ACTION = 'npc_action',
OBJECT_ACTION = 'object_action',
COMMAND = 'command'
Expand All @@ -21,12 +23,12 @@ export interface ActionPlugin {
export class RunePlugin {

public actions: (NpcActionPlugin | ObjectActionPlugin | ButtonActionPlugin | ItemOnItemActionPlugin |
CommandActionPlugin | WidgetActionPlugin)[];
CommandActionPlugin | WidgetActionPlugin | ItemActionPlugin)[];

public constructor(actions: NpcActionPlugin | ObjectActionPlugin | ButtonActionPlugin | ItemOnItemActionPlugin |
CommandActionPlugin | WidgetActionPlugin |
CommandActionPlugin | WidgetActionPlugin | ItemActionPlugin |
(NpcActionPlugin | ObjectActionPlugin | ButtonActionPlugin | ItemOnItemActionPlugin |
CommandActionPlugin | WidgetActionPlugin)[]) {
CommandActionPlugin | WidgetActionPlugin | ItemActionPlugin)[]) {
if(!Array.isArray(actions)) {
this.actions = [actions];
} else {
Expand Down
Loading

0 comments on commit 04a5cf9

Please sign in to comment.