From 09a4df426fda8c25d6f22c3c979a03117842bb12 Mon Sep 17 00:00:00 2001 From: Tynarus Date: Sat, 6 Mar 2021 12:44:32 -0600 Subject: [PATCH 1/2] Adding player_region_changed action hook and removed old scenery spawns --- data/config/scenery-spawns.yaml | 600 ---------------------- src/plugins/music/music-regions-plugin.ts | 36 +- src/plugins/plugin.ts | 23 +- src/world/action/index.ts | 24 +- src/world/action/player-action.ts | 7 +- src/world/action/player-region-changed.ts | 162 ++++++ src/world/actor/player/player.ts | 8 +- src/world/actor/walking-queue.ts | 455 ++++++++-------- src/world/index.ts | 1 - src/world/map/region.ts | 21 + src/world/position.ts | 35 +- 11 files changed, 509 insertions(+), 863 deletions(-) create mode 100644 src/world/action/player-region-changed.ts create mode 100644 src/world/map/region.ts diff --git a/data/config/scenery-spawns.yaml b/data/config/scenery-spawns.yaml index b3747c4e4..336f8c629 100644 --- a/data/config/scenery-spawns.yaml +++ b/data/config/scenery-spawns.yaml @@ -1,603 +1,3 @@ -- objectId: 5439 - x: 3140 - 'y': 3297 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3140 - 'y': 3296 - level: 0 - type: 10 - orientation: 2 -- objectId: 306 - x: 3141 - 'y': 3294 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3140 - 'y': 3294 - level: 0 - type: 10 - orientation: 4 -- objectId: 4421 - x: 3141 - 'y': 3293 - level: 0 - type: 10 - orientation: 7 -- objectId: 4421 - x: 3141 - 'y': 3292 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3142 - 'y': 3293 - level: 0 - type: 10 - orientation: 2 -- objectId: 6881 - x: 3139 - 'y': 3292 - level: 0 - type: 10 - orientation: 3 -- objectId: 6881 - x: 3139 - 'y': 3298 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3138 - 'y': 3296 - level: 0 - type: 10 - orientation: 6 -- objectId: 849 - x: 3140 - 'y': 3293 - level: 0 - type: 10 - orientation: 2 -- objectId: 849 - x: 3140 - 'y': 3291 - level: 0 - type: 10 - orientation: 2 -- objectId: 4421 - x: 3137 - 'y': 3282 - level: 0 - type: 10 - orientation: 2 -- objectId: 849 - x: 3137 - 'y': 3283 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3136 - 'y': 3283 - level: 0 - type: 10 - orientation: 5 -- objectId: 327 - x: 3136 - 'y': 3282 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3135 - 'y': 3283 - level: 0 - type: 10 - orientation: 0 -- objectId: 849 - x: 3135 - 'y': 3284 - level: 0 - type: 10 - orientation: 3 -- objectId: 6420 - x: 3135 - 'y': 3282 - level: 0 - type: 10 - orientation: 3 -- objectId: 6881 - x: 3134 - 'y': 3283 - level: 0 - type: 10 - orientation: 5 -- objectId: 4421 - x: 3133 - 'y': 3284 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3133 - 'y': 3283 - level: 0 - type: 10 - orientation: 1 -- objectId: 4421 - x: 3132 - 'y': 3283 - level: 0 - type: 10 - orientation: 6 -- objectId: 6881 - x: 3136 - 'y': 3285 - level: 0 - type: 10 - orientation: 3 -- objectId: 6881 - x: 3132 - 'y': 3286 - level: 0 - type: 10 - orientation: 2 -- objectId: 327 - x: 3134 - 'y': 3287 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3144 - 'y': 3306 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3145 - 'y': 3306 - level: 0 - type: 10 - orientation: 3 -- objectId: 849 - x: 3146 - 'y': 3307 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3146 - 'y': 3306 - level: 0 - type: 10 - orientation: 4 -- objectId: 4421 - x: 3146 - 'y': 3305 - level: 0 - type: 10 - orientation: 3 -- objectId: 306 - x: 3154 - 'y': 3308 - level: 0 - type: 10 - orientation: 4 -- objectId: 357 - x: 3153 - 'y': 3307 - level: 0 - type: 10 - orientation: 0 -- objectId: 357 - x: 3153 - 'y': 3308 - level: 0 - type: 10 - orientation: 3 -- objectId: 849 - x: 3153 - 'y': 3310 - level: 0 - type: 10 - orientation: 2 -- objectId: 4421 - x: 3152 - 'y': 3309 - level: 0 - type: 10 - orientation: 0 -- objectId: 6881 - x: 3151 - 'y': 3310 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3150 - 'y': 3308 - level: 0 - type: 10 - orientation: 3 -- objectId: 10293 - x: 3154 - 'y': 3311 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3155 - 'y': 3312 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3155 - 'y': 3311 - level: 0 - type: 10 - orientation: 5 -- objectId: 5439 - x: 3154 - 'y': 3313 - level: 0 - type: 10 - orientation: 3 -- objectId: 306 - x: 3124 - 'y': 3264 - level: 0 - type: 10 - orientation: 1 -- objectId: 4421 - x: 3125 - 'y': 3263 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3126 - 'y': 3263 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3127 - 'y': 3260 - level: 0 - type: 10 - orientation: 0 -- objectId: 6881 - x: 3128 - 'y': 3261 - level: 0 - type: 10 - orientation: 3 -- objectId: 327 - x: 3122 - 'y': 3260 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3124 - 'y': 3261 - level: 0 - type: 10 - orientation: 0 -- objectId: 849 - x: 3123 - 'y': 3262 - level: 0 - type: 10 - orientation: 2 -- objectId: 4421 - x: 3118 - 'y': 3258 - level: 0 - type: 10 - orientation: 0 -- objectId: 849 - x: 3117 - 'y': 3259 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3117 - 'y': 3258 - level: 0 - type: 10 - orientation: 1 -- objectId: 849 - x: 3113 - 'y': 3255 - level: 0 - type: 10 - orientation: 2 -- objectId: 849 - x: 3113 - 'y': 3256 - level: 0 - type: 10 - orientation: 2 -- objectId: 4421 - x: 3114 - 'y': 3255 - level: 0 - type: 10 - orientation: 7 -- objectId: 5439 - x: 3108 - 'y': 3244 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3109 - 'y': 3243 - level: 0 - type: 10 - orientation: 0 -- objectId: 849 - x: 3108 - 'y': 3242 - level: 0 - type: 10 - orientation: 2 -- objectId: 10293 - x: 3108 - 'y': 3241 - level: 0 - type: 10 - orientation: 3 -- objectId: 306 - x: 3109 - 'y': 3240 - level: 0 - type: 10 - orientation: 5 -- objectId: 306 - x: 3107 - 'y': 3238 - level: 0 - type: 10 - orientation: 6 -- objectId: 4421 - x: 3105 - 'y': 3239 - level: 0 - type: 10 - orientation: 0 -- objectId: 849 - x: 3104 - 'y': 3240 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3104 - 'y': 3239 - level: 0 - type: 10 - orientation: 3 -- objectId: 327 - x: 3103 - 'y': 3239 - level: 0 - type: 10 - orientation: 0 -- objectId: 357 - x: 3102 - 'y': 3239 - level: 0 - type: 10 - orientation: 3 -- objectId: 10293 - x: 3101 - 'y': 3240 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3100 - 'y': 3240 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3101 - 'y': 3239 - level: 0 - type: 10 - orientation: 0 -- objectId: 357 - x: 3098 - 'y': 3241 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3099 - 'y': 3239 - level: 0 - type: 10 - orientation: 5 -- objectId: 6881 - x: 3100 - 'y': 3238 - level: 0 - type: 10 - orientation: 5 -- objectId: 6420 - x: 3097 - 'y': 3239 - level: 0 - type: 10 - orientation: 2 -- objectId: 4421 - x: 3087 - 'y': 3246 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3086 - 'y': 3246 - level: 0 - type: 10 - orientation: 0 -- objectId: 849 - x: 3083 - 'y': 3246 - level: 0 - type: 10 - orientation: 3 -- objectId: 357 - x: 3084 - 'y': 3245 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3076 - 'y': 3245 - level: 0 - type: 10 - orientation: 0 -- objectId: 357 - x: 3075 - 'y': 3246 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3074 - 'y': 3246 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3074 - 'y': 3247 - level: 0 - type: 10 - orientation: 0 -- objectId: 849 - x: 3073 - 'y': 3246 - level: 0 - type: 10 - orientation: 3 -- objectId: 6881 - x: 3072 - 'y': 3248 - level: 0 - type: 10 - orientation: 4 -- objectId: 5358 - x: 3074 - 'y': 3249 - level: 0 - type: 10 - orientation: 0 -- objectId: 5359 - x: 3075 - 'y': 3247 - level: 0 - type: 10 - orientation: 2 -- objectId: 10293 - x: 3076 - 'y': 3244 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3077 - 'y': 3244 - level: 0 - type: 10 - orientation: 1 -- objectId: 5439 - x: 3077 - 'y': 3243 - level: 0 - type: 10 - orientation: 1 -- objectId: 4421 - x: 3076 - 'y': 3242 - level: 0 - type: 10 - orientation: 4 -- objectId: 4421 - x: 3076 - 'y': 3241 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3240 - 'y': 3334 - level: 0 - type: 10 - orientation: 0 -- objectId: 306 - x: 3267 - 'y': 3328 - level: 0 - type: 10 - orientation: 0 -- objectId: 357 - x: 3270 - 'y': 3329 - level: 0 - type: 10 - orientation: 0 -- objectId: 10293 - x: 3269 - 'y': 3327 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3270 - 'y': 3328 - level: 0 - type: 10 - orientation: 0 -- objectId: 5358 - x: 3270 - 'y': 3327 - level: 0 - type: 10 - orientation: 0 -- objectId: 4421 - x: 3206 - 'y': 3341 - level: 0 - type: 10 - orientation: 0 -- objectId: 849 - x: 3205 - 'y': 3341 - level: 0 - type: 10 - orientation: 3 -- objectId: 4421 - x: 3205 - 'y': 3340 - level: 0 - type: 10 - orientation: 0 - objectId: 4306 # anvil in lumbridge x: 3227 'y': 3252 diff --git a/src/plugins/music/music-regions-plugin.ts b/src/plugins/music/music-regions-plugin.ts index ba461bec1..68730713b 100644 --- a/src/plugins/music/music-regions-plugin.ts +++ b/src/plugins/music/music-regions-plugin.ts @@ -1,18 +1,10 @@ -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()) { @@ -20,3 +12,25 @@ function getByValue(map, 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 +}]; diff --git a/src/plugins/plugin.ts b/src/plugins/plugin.ts index b8fefee74..30b304cd1 100644 --- a/src/plugins/plugin.ts +++ b/src/plugins/plugin.ts @@ -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[]; } @@ -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; + } } } diff --git a/src/world/action/index.ts b/src/world/action/index.ts index 5021bce89..da9439ea6 100644 --- a/src/world/action/index.ts +++ b/src/world/action/index.ts @@ -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'; diff --git a/src/world/action/player-action.ts b/src/world/action/player-action.ts index 4c13ca306..551a0b45f 100644 --- a/src/world/action/player-action.ts +++ b/src/world/action/player-action.ts @@ -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 { @@ -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) { @@ -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); diff --git a/src/world/action/player-region-changed.ts b/src/world/action/player-region-changed.ts new file mode 100644 index 000000000..7f70ae2a2 --- /dev/null +++ b/src/world/action/player-region-changed.ts @@ -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(actionHook => + new Promise(async resolve => { + await actionHook.handler(actionData); + resolve(); + })); +}; + +export default { + action: 'player_region_changed', + handler: playerRegionChangedHandler +}; diff --git a/src/world/actor/player/player.ts b/src/world/actor/player/player.ts index 1db800315..236294aa5 100644 --- a/src/world/actor/player/player.ts +++ b/src/world/actor/player/player.ts @@ -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' }[] = [ @@ -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)); @@ -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(); @@ -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)); } } diff --git a/src/world/actor/walking-queue.ts b/src/world/actor/walking-queue.ts index 8f20a9ee3..95de89d46 100644 --- a/src/world/actor/walking-queue.ts +++ b/src/world/actor/walking-queue.ts @@ -3,237 +3,238 @@ import { Position } from '../position'; import { Player } from './player/player'; import { world } from '@server/game-server'; import { Npc } from './npc/npc'; -import { playSongForRegion } from '@server/plugins/music/music-regions-plugin'; +import { regionChangedDataFactory } from '@server/world/action/player-region-changed'; +import { actionHandler } from '@server/world/action'; + /** * Controls an actor's movement. */ export class WalkingQueue { - private queue: Position[]; - private _valid: boolean; - - public constructor(private readonly actor: Actor) { - this.queue = []; - this._valid = false; - } - - public moving(): boolean { - return this.queue.length !== 0; - } - - public clear(): void { - this.queue = []; - } - - public getLastPosition(): Position { - if (this.queue.length === 0) { - return this.actor.position; - } else { - return this.queue[this.queue.length - 1]; - } - } - - public add(x: number, y: number, positionMetadata?: { [key: string]: any }): void { - let lastPosition = this.getLastPosition(); - - let lastX = lastPosition.x; - let lastY = lastPosition.y; - let diffX = x - lastX; - let diffY = y - lastY; - - const stepsBetween = Math.max(Math.abs(diffX), Math.abs(diffY)); - - for (let i = 0; i < stepsBetween; i++) { - if (diffX !== 0) { - diffX += diffX < 0 ? 1 : -1; - } - - if (diffY !== 0) { - diffY += diffY < 0 ? 1 : -1; - } - - lastX = x - diffX; - lastY = y - diffY; - - const newPosition = new Position(lastX, lastY, this.actor.position.level); - - if (this.actor.pathfinding.canMoveTo(lastPosition, newPosition)) { - lastPosition = newPosition; - newPosition.metadata = positionMetadata; - this.queue.push(newPosition); - } else { - this.valid = false; - break; - } - } - - if (lastX !== x || lastY !== y && this.valid) { - const newPosition = new Position(x, y, this.actor.position.level); - - if (this.actor.pathfinding.canMoveTo(lastPosition, newPosition)) { - newPosition.metadata = positionMetadata; - this.queue.push(newPosition); - } else { - this.valid = false; - } - } - } - - public moveIfAble(xDiff: number, yDiff: number): boolean { - const position = this.actor.position; - const newPosition = new Position(position.x + xDiff, position.y + yDiff, position.level); - - if (this.actor.pathfinding.canMoveTo(position, newPosition)) { - this.clear(); - this.valid = true; - this.add(newPosition.x, newPosition.y, { ignoreWidgets: true }); - return true; - } - - return false; - } - - public resetDirections(): void { - this.actor.walkDirection = -1; - this.actor.runDirection = -1; - } - - public calculateDirection(diffX: number, diffY: number): number { - if (diffX < 0) { - if (diffY < 0) { - return 5; - } else if (diffY > 0) { - return 0; - } else { - return 3; - } - } else if (diffX > 0) { - if (diffY < 0) { - return 7; - } else if (diffY > 0) { - return 2; - } else { - return 4; - } - } else { - if (diffY < 0) { - return 6; - } else if (diffY > 0) { - return 1; - } else { - return -1; - } - } - } - - public process(): void { - if (this.actor.busy || this.queue.length === 0 || !this.valid) { - this.resetDirections(); - return; - } - - const walkPosition = this.queue.shift(); - - if (this.actor instanceof Player) { - this.actor.actionsCancelled.next('pathing-movement'); - // if(activeWidget.disablePlayerMovement) { - // this.resetDirections(); - // return; - // } - //this.actor.interfaceState.closeAllSlots(); - } - - if (this.actor.metadata['faceActorClearedByWalking'] === undefined || this.actor.metadata['faceActorClearedByWalking']) { - this.actor.clearFaceActor(); - } - - const currentPosition = this.actor.position; - - if (this.actor.pathfinding.canMoveTo(currentPosition, walkPosition)) { - const oldChunk = world.chunkManager.getChunkForWorldPosition(currentPosition); - const lastMapRegionUpdatePosition = this.actor.lastMapRegionUpdatePosition; - - const walkDiffX = walkPosition.x - currentPosition.x; - const walkDiffY = walkPosition.y - currentPosition.y; - const walkDir = this.calculateDirection(walkDiffX, walkDiffY); - - if (walkDir === -1) { - this.resetDirections(); - return; - } - - this.actor.lastMovementPosition = this.actor.position; - this.actor.position = walkPosition; - - let runDir = -1; - - // @TODO npc running - if (this.actor instanceof Player) { - if (this.actor.settings.runEnabled && this.queue.length !== 0) { - const runPosition = this.queue.shift(); - - if (this.actor.pathfinding.canMoveTo(walkPosition, runPosition)) { - const runDiffX = runPosition.x - walkPosition.x; - const runDiffY = runPosition.y - walkPosition.y; - runDir = this.calculateDirection(runDiffX, runDiffY); - - if (runDir != -1) { - this.actor.lastMovementPosition = this.actor.position; - this.actor.position = runPosition; - } - } else { - this.resetDirections(); - this.clear(); - } - } - } - - this.actor.walkDirection = walkDir; - this.actor.runDirection = runDir; - - if (runDir !== -1) { - this.actor.faceDirection = runDir; - } else { - this.actor.faceDirection = walkDir; - } - - const newChunk = world.chunkManager.getChunkForWorldPosition(this.actor.position); - - this.actor.movementEvent.next(this.actor.position); - - if (this.actor instanceof Player) { - const mapDiffX = this.actor.position.x - (lastMapRegionUpdatePosition.chunkX * 8); - const mapDiffY = this.actor.position.y - (lastMapRegionUpdatePosition.chunkY * 8); - if (mapDiffX < 16 || mapDiffX > 87 || mapDiffY < 16 || mapDiffY > 87) { - this.actor.updateFlags.mapRegionUpdateRequired = true; - this.actor.lastMapRegionUpdatePosition = this.actor.position; - } - } - - if (!oldChunk.equals(newChunk)) { - if (this.actor instanceof Player) { - const regionChanged = world.chunkManager.getMapRegionChanged(currentPosition, this.actor.position); - if (regionChanged) { - playSongForRegion(this.actor) - } - this.actor.metadata['updateChunk'] = { newChunk, oldChunk }; - } else if (this.actor instanceof Npc) { - oldChunk.removeNpc(this.actor); - newChunk.addNpc(this.actor); - } - } - } else { - this.resetDirections(); - this.clear(); - } - } - - get valid(): boolean { - return this._valid; - } - - set valid(value: boolean) { - this._valid = value; - } + private queue: Position[]; + private _valid: boolean; + + public constructor(private readonly actor: Actor) { + this.queue = []; + this._valid = false; + } + + public moving(): boolean { + return this.queue.length !== 0; + } + + public clear(): void { + this.queue = []; + } + + public getLastPosition(): Position { + if(this.queue.length === 0) { + return this.actor.position; + } else { + return this.queue[this.queue.length - 1]; + } + } + + public add(x: number, y: number, positionMetadata?: { [key: string]: any }): void { + let lastPosition = this.getLastPosition(); + + let lastX = lastPosition.x; + let lastY = lastPosition.y; + let diffX = x - lastX; + let diffY = y - lastY; + + const stepsBetween = Math.max(Math.abs(diffX), Math.abs(diffY)); + + for(let i = 0; i < stepsBetween; i++) { + if(diffX !== 0) { + diffX += diffX < 0 ? 1 : -1; + } + + if(diffY !== 0) { + diffY += diffY < 0 ? 1 : -1; + } + + lastX = x - diffX; + lastY = y - diffY; + + const newPosition = new Position(lastX, lastY, this.actor.position.level); + + if(this.actor.pathfinding.canMoveTo(lastPosition, newPosition)) { + lastPosition = newPosition; + newPosition.metadata = positionMetadata; + this.queue.push(newPosition); + } else { + this.valid = false; + break; + } + } + + if(lastX !== x || lastY !== y && this.valid) { + const newPosition = new Position(x, y, this.actor.position.level); + + if(this.actor.pathfinding.canMoveTo(lastPosition, newPosition)) { + newPosition.metadata = positionMetadata; + this.queue.push(newPosition); + } else { + this.valid = false; + } + } + } + + public moveIfAble(xDiff: number, yDiff: number): boolean { + const position = this.actor.position; + const newPosition = new Position(position.x + xDiff, position.y + yDiff, position.level); + + if(this.actor.pathfinding.canMoveTo(position, newPosition)) { + this.clear(); + this.valid = true; + this.add(newPosition.x, newPosition.y, { ignoreWidgets: true }); + return true; + } + + return false; + } + + public resetDirections(): void { + this.actor.walkDirection = -1; + this.actor.runDirection = -1; + } + + public calculateDirection(diffX: number, diffY: number): number { + if(diffX < 0) { + if(diffY < 0) { + return 5; + } else if(diffY > 0) { + return 0; + } else { + return 3; + } + } else if(diffX > 0) { + if(diffY < 0) { + return 7; + } else if(diffY > 0) { + return 2; + } else { + return 4; + } + } else { + if(diffY < 0) { + return 6; + } else if(diffY > 0) { + return 1; + } else { + return -1; + } + } + } + + public process(): void { + if(this.actor.busy || this.queue.length === 0 || !this.valid) { + this.resetDirections(); + return; + } + + const walkPosition = this.queue.shift(); + + if(this.actor instanceof Player) { + this.actor.actionsCancelled.next('pathing-movement'); + // if(activeWidget.disablePlayerMovement) { + // this.resetDirections(); + // return; + // } + //this.actor.interfaceState.closeAllSlots(); + } + + if(this.actor.metadata['faceActorClearedByWalking'] === undefined || this.actor.metadata['faceActorClearedByWalking']) { + this.actor.clearFaceActor(); + } + + const originalPosition = this.actor.position; + + if(this.actor.pathfinding.canMoveTo(originalPosition, walkPosition)) { + const oldChunk = world.chunkManager.getChunkForWorldPosition(originalPosition); + const lastMapRegionUpdatePosition = this.actor.lastMapRegionUpdatePosition; + + const walkDiffX = walkPosition.x - originalPosition.x; + const walkDiffY = walkPosition.y - originalPosition.y; + const walkDir = this.calculateDirection(walkDiffX, walkDiffY); + + if(walkDir === -1) { + this.resetDirections(); + return; + } + + this.actor.lastMovementPosition = this.actor.position; + this.actor.position = walkPosition; + + let runDir = -1; + + // @TODO npc running + if(this.actor instanceof Player) { + if(this.actor.settings.runEnabled && this.queue.length !== 0) { + const runPosition = this.queue.shift(); + + if(this.actor.pathfinding.canMoveTo(walkPosition, runPosition)) { + const runDiffX = runPosition.x - walkPosition.x; + const runDiffY = runPosition.y - walkPosition.y; + runDir = this.calculateDirection(runDiffX, runDiffY); + + if(runDir != -1) { + this.actor.lastMovementPosition = this.actor.position; + this.actor.position = runPosition; + } + } else { + this.resetDirections(); + this.clear(); + } + } + } + + this.actor.walkDirection = walkDir; + this.actor.runDirection = runDir; + + if(runDir !== -1) { + this.actor.faceDirection = runDir; + } else { + this.actor.faceDirection = walkDir; + } + + const newChunk = world.chunkManager.getChunkForWorldPosition(this.actor.position); + + this.actor.movementEvent.next(this.actor.position); + + if(this.actor instanceof Player) { + const mapDiffX = this.actor.position.x - (lastMapRegionUpdatePosition.chunkX * 8); + const mapDiffY = this.actor.position.y - (lastMapRegionUpdatePosition.chunkY * 8); + if(mapDiffX < 16 || mapDiffX > 87 || mapDiffY < 16 || mapDiffY > 87) { + this.actor.updateFlags.mapRegionUpdateRequired = true; + this.actor.lastMapRegionUpdatePosition = this.actor.position; + } + } + + if(!oldChunk.equals(newChunk)) { + if(this.actor instanceof Player) { + this.actor.metadata['updateChunk'] = { newChunk, oldChunk }; + + actionHandler.call('player_region_changed', regionChangedDataFactory( + this.actor, originalPosition, this.actor.position)); + } else if(this.actor instanceof Npc) { + oldChunk.removeNpc(this.actor); + newChunk.addNpc(this.actor); + } + } + } else { + this.resetDirections(); + this.clear(); + } + } + + get valid(): boolean { + return this._valid; + } + + set valid(value: boolean) { + this._valid = value; + } } diff --git a/src/world/index.ts b/src/world/index.ts index f4d5e3ee5..dec66d8dc 100644 --- a/src/world/index.ts +++ b/src/world/index.ts @@ -17,7 +17,6 @@ import { NpcDetails } from '@server/config/npc-config'; import { WorldInstance } from '@server/world/instances'; import { Direction } from '@server/world/direction'; import { NpcSpawn } from '@server/config/npc-spawn-config'; -import { ItemSpawn } from '@server/config/item-spawn-config'; export interface QuadtreeKey { diff --git a/src/world/map/region.ts b/src/world/map/region.ts new file mode 100644 index 000000000..752b6be41 --- /dev/null +++ b/src/world/map/region.ts @@ -0,0 +1,21 @@ +/** + * Different types of world regions. + * map: 64x64 tile (13x13 tile chunks) full map region file. + * chunk: 8x8 tile chunk within a map. + */ +export type RegionType = 'map' | 'chunk'; + +/** + * A type for defining region tile sizes. + */ +export type RegionSizeMap = { + [key in RegionType]: number; +}; + +/** + * A map of region types to tile sizes. + */ +export const regionSizes: RegionSizeMap = { + 'map': 64, + 'chunk': 8 +}; diff --git a/src/world/position.ts b/src/world/position.ts index c9fddc05a..0138217cf 100644 --- a/src/world/position.ts +++ b/src/world/position.ts @@ -5,6 +5,19 @@ import { cache } from '@server/game-server'; const directionDeltaX = [-1, 0, 1, -1, 1, -1, 0, 1]; const directionDeltaY = [1, 1, 1, 0, 0, -1, -1, -1]; +/** + * A simplified x/y/level coordinate class. + */ +export class Coords { + x: number; + y: number; + level: number; + + static equals(a: Coords, b: Coords): boolean { + return a.x === b.x && a.y === b.y && a.level === b.level; + } +} + /** * Represents a single position, or coordinate, within the game world. */ @@ -15,8 +28,15 @@ export class Position { private _y: number; private _level: number; - public constructor(x: number, y: number, level?: number) { - this.move(x, y, level); + public constructor(position: Position); + public constructor(coords: Coords); + public constructor(x: number, y: number, level?: number); + public constructor(arg0: number | Coords | Position, y?: number, level?: number) { + if(typeof arg0 === 'number') { + this.move(arg0, y, level); + } else { + this.move(arg0.x, arg0.y, arg0.level); + } } public clone(): Position { @@ -124,6 +144,17 @@ export class Position { return this._y - 8 * position.chunkY; } + /** + * Converts this Position into a simple Coords object. + */ + public get coords(): Coords { + return { + x: this._x, + y: this._y, + level: this._level + }; + } + public get chunkX(): number { return (this._x >> 3) - 6; } From ec410a5b05c00d53b04a93ca007d80873fd51c9a Mon Sep 17 00:00:00 2001 From: Tynarus Date: Sat, 6 Mar 2021 13:54:28 -0600 Subject: [PATCH 2/2] Fixing linter errors --- src/world/action/player-region-changed.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/world/action/player-region-changed.ts b/src/world/action/player-region-changed.ts index 7f70ae2a2..c9dd78ede 100644 --- a/src/world/action/player-region-changed.ts +++ b/src/world/action/player-region-changed.ts @@ -149,9 +149,9 @@ const playerRegionChangedHandler = (actionData: PlayerRegionChangedData): void = return; } - actionList.forEach(actionHook => - new Promise(async resolve => { - await actionHook.handler(actionData); + actionList.forEach(async actionHook => + new Promise(resolve => { + actionHook.handler(actionData); resolve(); })); };