Skip to content

Commit

Permalink
Merge pull request #259 from rune-js/feature/player-region-changed-hook
Browse files Browse the repository at this point in the history
Adding player_region_changed action hook and removed old scenery spawns
  • Loading branch information
Tynarus authored Mar 6, 2021
2 parents 9bd8543 + ec410a5 commit c668421
Show file tree
Hide file tree
Showing 11 changed files with 509 additions and 863 deletions.
600 changes: 0 additions & 600 deletions data/config/scenery-spawns.yaml

Large diffs are not rendered by default.

36 changes: 25 additions & 11 deletions src/plugins/music/music-regions-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
import { logger } from '@runejs/core';
import { Player } from '@server/world/actor/player/player';
import { musicRegionMap, musicRegions } from '@server/config';
import { songs } from '@server/world/config/songs';
import { playerRegionChangedHook } from '@server/world/action/player-region-changed';
import { playerInitAction } from '@server/world/actor/player/player';

musicRegions.forEach(song => song.regionIds.forEach(region => musicRegionMap.set(region, song.songId)));

export function playSongForRegion(player: Player): void {
const regionId = ((player.position.x >> 6) * 256) + (player.position.y >> 6);
const songId: number = musicRegionMap.get(regionId);
logger.info('Playing: ' + getByValue(songs, songId) + ' (Song ID: ' + songId + ' Region ID: ' + regionId + ')');

player.playSong(songId);
player.metadata['updateMusic'] = false;
}
musicRegions.forEach(song => song.regionIds.forEach(region => musicRegionMap.set(region, song.songId)));

function getByValue(map, searchValue) {
for (const [key, value] of map.entries()) {
if (value === searchValue)
return key;
}
}

const regionChangedHandler = ({ player, currentMapRegionId }): void => {
const songId: number = musicRegionMap.get(currentMapRegionId);
player.sendMessage(`Playing ${songId}:${getByValue(songs, songId)} at region ${currentMapRegionId}`);
player.playSong(songId);
player.metadata['updateMusic'] = false;
};

const playerInitHandler: playerInitAction = ({ player }): void => {
// Plays the appropriate location's song on player init
regionChangedHandler({ player,
currentMapRegionId: ((player.position.x >> 6) << 8) + (player.position.y >> 6) });
};

export default [{
type: 'player_region_changed',
regionType: 'map',
handler: regionChangedHandler
}, {
type: 'player_init',
action: playerInitHandler
}];
23 changes: 15 additions & 8 deletions src/plugins/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Player } from '@server/world/actor/player/player';
import { Action } from '@server/world/action';
import { basicNumberFilter } from '@server/plugins/plugin-loader';
import { Quest } from '@server/world/actor/player/quest';
import { QuestKey } from '@server/config/quest-config';


export interface QuestRequirement {
questId: string;
stage?: number;
stage?: QuestKey;
stages?: number[];
}

Expand All @@ -26,13 +27,19 @@ export function questFilter(player: Player, plugin: Action): boolean {
return plugin.questRequirement.stage === 0;
}

if(plugin.questRequirement.stage !== undefined) {
if(!basicNumberFilter(plugin.questRequirement.stage, playerQuest.progress)) {
return false;
}
} else if(plugin.questRequirement.stages !== undefined) {
if(!basicNumberFilter(plugin.questRequirement.stages, playerQuest.progress)) {
return false;
if(plugin.questRequirement.stage === 'complete') {
return playerQuest.progress === 'complete';
}

if(typeof playerQuest.progress === 'number') {
if(plugin.questRequirement.stage !== undefined) {
if(!basicNumberFilter(plugin.questRequirement.stage, playerQuest.progress)) {
return false;
}
} else if(plugin.questRequirement.stages !== undefined) {
if(!basicNumberFilter(plugin.questRequirement.stages, playerQuest.progress)) {
return false;
}
}
}

Expand Down
24 changes: 15 additions & 9 deletions src/world/action/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,24 @@ export interface Action {
export type ActionType =
'button'
| 'widget_action'
| 'item_on_item'
| 'item_action'
| 'equip_action'
| 'world_item_action'

| 'npc_init'
| 'npc_action'

| 'object_action'

| 'item_on_object'
| 'item_on_npc'
| 'player_command'
| 'player_init'
| 'npc_init'
| 'swap_items'
| 'move_item'
| 'world_item_action'
| 'item_on_item'
| 'item_action'
| 'equip_action'

| 'quest'

| 'player_init'
| 'player_command'
| 'player_action'
| 'swap_items'
| 'move_item';
| 'player_region_changed';
7 changes: 4 additions & 3 deletions src/world/action/player-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface PlayerActionData {
}

/**
* Defines a player interaction plugin.
* Defines a player interaction action.
* The option selected, the action to be performed, and whether or not the player must first walk to the other player.
*/
export interface PlayerAction extends Action {
Expand All @@ -42,7 +42,8 @@ const playerActionHandler = (player: Player, otherPlayer: Player, position: Posi
}

// Find all player action plugins that reference this option
let interactionActions = getActionList('player_action').filter(plugin => questFilter(player, plugin) && basicStringFilter(plugin.options, option));
let interactionActions = getActionList('player_action')
.filter(plugin => questFilter(player, plugin) && basicStringFilter(plugin.options, option));
const questActions = interactionActions.filter(plugin => plugin.questRequirement !== undefined);

if(questActions.length !== 0) {
Expand All @@ -54,7 +55,7 @@ const playerActionHandler = (player: Player, otherPlayer: Player, position: Posi
return;
}

player.actionsCancelled.next();
player.actionsCancelled.next(null);

// Separate out walk-to actions from immediate actions
const walkToPlugins = interactionActions.filter(plugin => plugin.walkTo);
Expand Down
162 changes: 162 additions & 0 deletions src/world/action/player-region-changed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { Player } from '@server/world/actor/player/player';
import { Coords, Position } from '@server/world/position';
import { Action, getActionList } from '@server/world/action/index';
import { RegionType } from '@server/world/map/region';


/**
* The definition for a player action function.
*/
export type playerRegionChangedHook = (playerActionData: PlayerRegionChangedData) => void;

/**
* Details about a player being interacted with.
*/
export interface PlayerRegionChangedData {
// The player performing the action.
player: Player;
// Whether or not the player is teleporting to their new location
teleporting: boolean;
// The original position that the player was at before moving to the new region.
originalPosition: Position;
// The position that the player ended up at in the new region.
currentPosition: Position;
// The player's original chunk coordinates
originalChunkCoords: Coords;
// The player's current chunk coordinates
currentChunkCoords: Coords;
// The player's original map region coordinates
originalMapRegionCoords: Coords;
// The player's current map region coordinates
currentMapRegionCoords: Coords;
// The player's original map region id
originalMapRegionId: number;
// The player's current map region id
currentMapRegionId: number;
// The region types that changed for the player.
regionTypes: RegionType[];
}

/**
* Defines a player region changed action.
*/
export interface PlayerRegionChangedAction extends Action {
// The action function to be performed.
handler: playerRegionChangedHook;
// Optional single region type for the action hook to apply to.
regionType?: RegionType;
// Optional multiple region types for the action hook to apply to.
regionTypes?: RegionType[];
// Optional teleporting requirement
teleporting?: boolean;
}

/**
* Creates a PlayerRegionChangedData object from the given inputs.
* @param player The player.
* @param originalPosition The player's original position.
* @param currentPosition The player's current position.
* @param teleporting Whether or not the player is teleporting; defaults to false.
*/
export const regionChangedDataFactory = (player: Player,
originalPosition: Position, currentPosition: Position,
teleporting: boolean = false): PlayerRegionChangedData => {
const regionTypes: RegionType[] = [];
const originalMapRegionId: number = ((originalPosition.x >> 6) << 8) + (originalPosition.y >> 6);
const currentMapRegionId: number = ((currentPosition.x >> 6) << 8) + (currentPosition.y >> 6);
const originalChunkCoords: Coords = {
x: originalPosition.chunkX,
y: originalPosition.chunkY,
level: originalPosition.level
};
const currentChunkCoords: Coords = {
x: currentPosition.chunkX,
y: currentPosition.chunkY,
level: currentPosition.level
};

if(originalMapRegionId !== currentMapRegionId) {
regionTypes.push('map');
}

if(!Coords.equals(originalChunkCoords, currentChunkCoords)) {
regionTypes.push('chunk');
}

if(regionTypes.length === 0) {
return null;
}

return {
player, regionTypes, teleporting,

originalPosition,
originalChunkCoords,
originalMapRegionCoords: {
x: originalPosition.x >> 6,
y: originalPosition.y >> 6,
level: originalPosition.level
},
originalMapRegionId,

currentPosition: player.position,
currentChunkCoords,
currentMapRegionCoords: {
x: currentPosition.x >> 6,
y: currentPosition.y >> 6,
level: currentPosition.level
},
currentMapRegionId
};
};

const playerRegionChangedHandler = (actionData: PlayerRegionChangedData): void => {
if(!actionData) {
return;
}

const { regionTypes } = actionData;

if(!regionTypes || regionTypes.length === 0) {
return;
}

// Find all action hooks that match the provided input
const actionList = getActionList('player_region_changed')?.filter((actionHook: PlayerRegionChangedAction) => {
if(actionHook.teleporting && !actionData.teleporting) {
return false;
}

if(actionHook.regionType) {
return regionTypes.indexOf(actionHook.regionType) !== -1;
} else if(actionHook.regionTypes && actionHook.regionTypes.length !== 0) {
let valid = false;
for(const type of actionHook.regionTypes) {
if(regionTypes.indexOf(type) !== -1) {
valid = true;
break;
}
}

return valid;
}

return false;
}) || null;

if(!actionList || actionList.length === 0) {
// No matching actions found
return;
}

actionList.forEach(async actionHook =>
new Promise<void>(resolve => {
actionHook.handler(actionData);
resolve();
}));
};

export default {
action: 'player_region_changed',
handler: playerRegionChangedHandler
};
8 changes: 6 additions & 2 deletions src/world/actor/player/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { InterfaceState } from '@server/world/actor/player/interface-state';
import { dialogue } from '@server/world/actor/dialogue';
import { PlayerQuest, QuestKey } from '@server/config/quest-config';
import { Quest } from '@server/world/actor/player/quest';
import { regionChangedDataFactory } from '@server/world/action/player-region-changed';


export const playerOptions: { option: string, index: number, placement: 'TOP' | 'BOTTOM' }[] = [
Expand Down Expand Up @@ -233,7 +234,6 @@ export class Player extends Actor {
this.updateBonuses();
this.updateCarryWeight(true);
this.modifyWidget(widgets.musicPlayerTab, { childId: 82, textColor: colors.green }); // Set "Harmony" to green/unlocked on the music tab
this.playSong(songs.harmony);
this.updateQuestTab();

this.inventory.containerUpdated.subscribe(event => this.inventoryUpdated(event));
Expand Down Expand Up @@ -592,7 +592,8 @@ export class Player extends Actor {
* @param newPosition The player's new position.
*/
public teleport(newPosition: Position): void {
const oldChunk = world.chunkManager.getChunkForWorldPosition(this.position);
const originalPosition = this.position;
const oldChunk = world.chunkManager.getChunkForWorldPosition(originalPosition);
const newChunk = world.chunkManager.getChunkForWorldPosition(newPosition);

this.walkingQueue.clear();
Expand All @@ -604,6 +605,9 @@ export class Player extends Actor {

if(!oldChunk.equals(newChunk)) {
this.metadata['updateChunk'] = { newChunk, oldChunk };

actionHandler.call('player_region_changed', regionChangedDataFactory(
this, originalPosition, newPosition, true));
}
}

Expand Down
Loading

0 comments on commit c668421

Please sign in to comment.