132 lines
4.2 KiB
TypeScript
132 lines
4.2 KiB
TypeScript
import { Server } from 'socket.io'
|
|
import { TSocket, ExtendedCharacter } from '../../utilities/types'
|
|
import { CharacterMoveService } from '../../services/character/characterMoveService'
|
|
import { ZoneEventTileService } from '../../services/zoneEventTileService'
|
|
import { MovementValidator } from '../../utilities/character/movementValidator'
|
|
import prisma from '../../utilities/prisma'
|
|
import { ZoneEventTile, ZoneEventTileTeleport } from '@prisma/client'
|
|
import Rotation from '../../utilities/character/rotation'
|
|
import logger from '../../utilities/logger'
|
|
|
|
type ZoneEventTileWithTeleport = ZoneEventTile & {
|
|
teleport: ZoneEventTileTeleport
|
|
}
|
|
|
|
export default class CharacterMoveEvent {
|
|
private characterMoveService: CharacterMoveService
|
|
private zoneEventTileService: ZoneEventTileService
|
|
private movementValidator: MovementValidator
|
|
private nextPath: { [index: number]: { x: number; y: number }[] } = []
|
|
|
|
constructor(
|
|
private readonly io: Server,
|
|
private readonly socket: TSocket
|
|
) {
|
|
this.characterMoveService = new CharacterMoveService()
|
|
this.zoneEventTileService = new ZoneEventTileService()
|
|
this.movementValidator = new MovementValidator()
|
|
}
|
|
|
|
public listen(): void {
|
|
this.socket.on('character:initMove', this.handleCharacterMove.bind(this))
|
|
}
|
|
|
|
private async handleCharacterMove({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
|
|
const { character } = this.socket
|
|
if (!character) {
|
|
logger.error('character:move error', 'Character not found')
|
|
return
|
|
}
|
|
|
|
const path = await this.characterMoveService.calculatePath(character, positionX, positionY)
|
|
if (!path) {
|
|
this.io.in(character.zoneId.toString()).emit('character:moveError', 'No valid path found')
|
|
return
|
|
}
|
|
|
|
if (character.isMoving && !character.resetMovement) {
|
|
character.resetMovement = true
|
|
this.nextPath[character.id] = path
|
|
} else {
|
|
await this.moveAlongPath(character, path)
|
|
}
|
|
}
|
|
|
|
private async moveAlongPath(character: ExtendedCharacter, path: Array<{ x: number; y: number }>): Promise<void> {
|
|
for (let i = 0; i < path.length - 1; i++) {
|
|
const start = path[i]
|
|
const end = path[i + 1]
|
|
|
|
if (!(await this.movementValidator.isValidMove(character, end))) {
|
|
break
|
|
}
|
|
|
|
if (character.isMoving && character.resetMovement) {
|
|
character.isMoving = false
|
|
character.resetMovement = false
|
|
const nextPath = this.nextPath[character.id]
|
|
this.moveAlongPath(character, nextPath)
|
|
break
|
|
}
|
|
|
|
if (!character.isMoving) {
|
|
character.isMoving = true
|
|
}
|
|
|
|
character.rotation = Rotation.calculate(start.x, start.y, end.x, end.y)
|
|
|
|
const zoneEventTile = await prisma.zoneEventTile.findFirst({
|
|
where: {
|
|
zoneId: character.zoneId,
|
|
positionX: Math.floor(end.x),
|
|
positionY: Math.floor(end.y)
|
|
}
|
|
})
|
|
|
|
if (zoneEventTile) {
|
|
if (zoneEventTile.type === 'BLOCK') {
|
|
break
|
|
}
|
|
|
|
if (zoneEventTile.type === 'TELEPORT') {
|
|
const teleportTile = (await prisma.zoneEventTile.findFirst({
|
|
where: { id: zoneEventTile.id },
|
|
include: { teleport: true }
|
|
})) as ZoneEventTileWithTeleport
|
|
|
|
if (teleportTile) {
|
|
await this.handleZoneEventTile(teleportTile)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
await this.characterMoveService.updatePosition(character, end)
|
|
this.io.in(character.zoneId.toString()).emit('character:move', character)
|
|
|
|
await this.characterMoveService.applyMovementDelay()
|
|
}
|
|
|
|
this.finalizeMovement(character)
|
|
}
|
|
|
|
private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise<void> {
|
|
const { character } = this.socket
|
|
if (!character) {
|
|
logger.error('character:move error', 'Character not found')
|
|
return
|
|
}
|
|
|
|
const teleport = zoneEventTile.teleport
|
|
if (teleport) {
|
|
await this.zoneEventTileService.handleTeleport(this.io, this.socket, character, teleport)
|
|
return
|
|
}
|
|
}
|
|
|
|
private finalizeMovement(character: ExtendedCharacter): void {
|
|
character.isMoving = false
|
|
this.io.in(character.zoneId.toString()).emit('character:move', character)
|
|
}
|
|
}
|