393 lines
12 KiB
JavaScript
Raw Normal View History

2022-08-13 12:40:42 +02:00
import {EventProcessor} from "./EventProcessor.js";
2022-10-06 20:35:28 +02:00
import {Player} from "./Player.js";
2022-11-06 15:37:41 +01:00
import {InventorySlot, SoundType} from "./Enums.js";
2022-10-21 12:35:24 +02:00
import {SoundRepository} from "./SoundRepository.js";
2022-08-13 12:40:42 +02:00
export class Game {
2022-10-22 21:35:14 +02:00
#world
#hud
#stats
#pointer
2022-08-13 12:40:42 +02:00
#round = 1
2022-10-06 20:35:28 +02:00
#paused = false
2022-08-13 12:40:42 +02:00
#started = false
#options = false
#readyCallback
#endCallback
2022-10-21 12:35:24 +02:00
#soundRepository
2022-10-13 17:26:52 +02:00
#hudDebounceTicks = 1
2022-10-30 15:07:24 +01:00
#bombTimerId = null;
2022-08-13 12:40:42 +02:00
eventProcessor
2022-10-06 20:35:28 +02:00
score = null
alivePlayers = [0, 0]
2022-10-09 13:28:35 +02:00
buyList = []
2022-08-13 12:40:42 +02:00
players = []
2022-10-06 20:35:28 +02:00
playerMe = null
2022-11-02 17:29:35 +01:00
playerSpectate = null
2022-08-13 12:40:42 +02:00
2022-10-05 16:09:55 +02:00
constructor(world, hud, stats) {
2022-08-13 12:40:42 +02:00
this.#world = world
this.#hud = hud
2022-10-05 16:09:55 +02:00
this.#stats = stats
2022-08-13 12:40:42 +02:00
this.eventProcessor = new EventProcessor(this)
2022-10-21 12:35:24 +02:00
this.#soundRepository = new SoundRepository()
2022-08-13 12:40:42 +02:00
}
2022-10-06 20:35:28 +02:00
pause(msg, score, timeMs) {
console.log("Pause: " + msg + " for " + timeMs + "ms")
2022-11-03 14:51:13 +01:00
clearInterval(this.#bombTimerId)
2022-11-05 17:12:25 +01:00
this.#world.reset()
2022-11-03 14:51:13 +01:00
2022-09-24 19:28:57 +02:00
const game = this
this.players.forEach(function (player) {
2022-11-15 12:16:18 +01:00
if (player.getId() === game.playerMe.getId()) { // reset spectate camera to our player
const camera = game.#world.getCamera()
camera.removeFromParent()
camera.rotation.set(0, serverHorizontalRotationToThreeRadian(player.data.look.horizontal), 0)
if (game.#pointer) {
game.#pointer.reset()
2022-11-02 17:29:35 +01:00
}
2022-11-15 12:16:18 +01:00
player.get3DObject().getObjectByName('head').add(camera)
game.playerSpectate = game.playerMe
game.requestPointerLock()
2022-11-02 17:29:35 +01:00
} else {
2022-11-03 14:51:13 +01:00
player.respawn()
2022-09-24 19:28:57 +02:00
}
})
2022-10-21 12:35:24 +02:00
if (!this.#started) {
2022-11-03 14:51:13 +01:00
this.#gameStartOrHalfTimeOrEnd()
2022-10-21 12:35:24 +02:00
this.#started = true
}
2022-08-13 12:40:42 +02:00
this.#paused = true
2022-10-06 20:35:28 +02:00
this.score = score
2022-08-13 12:40:42 +02:00
this.#hud.pause(msg, timeMs)
2022-10-07 15:44:35 +02:00
this.#hud.requestFullScoreBoardUpdate(this.score)
2022-08-13 12:40:42 +02:00
}
unpause() {
this.#paused = false
this.#hud.clearTopMessage()
console.log("Game unpause")
}
end(msg) {
console.log('Game ended')
2022-11-03 14:51:13 +01:00
this.#gameStartOrHalfTimeOrEnd()
2022-08-13 12:40:42 +02:00
if (this.#endCallback) {
this.#endCallback(msg)
}
}
roundStart(aliveAttackers, aliveDefenders) {
console.log("Starting round " + this.#round)
2022-10-06 20:35:28 +02:00
this.alivePlayers[0] = aliveDefenders
this.alivePlayers[1] = aliveAttackers
2022-08-13 12:40:42 +02:00
this.#hud.clearAlerts()
this.#hud.roundStart(this.#options.setting.round_time_ms)
}
2022-10-06 20:35:28 +02:00
roundEnd(attackersWins, newRoundNumber, score) {
2022-08-13 12:40:42 +02:00
let winner = attackersWins ? 'Attackers' : 'Defenders'
console.log("Round " + this.#round + " ended. Round wins: " + winner)
2022-10-06 20:35:28 +02:00
this.score = score;
2022-10-05 20:08:33 +02:00
this.#round = newRoundNumber
2022-08-13 12:40:42 +02:00
this.#hud.displayTopMessage(winner + ' wins')
2022-10-07 15:44:35 +02:00
this.#hud.requestFullScoreBoardUpdate(this.score)
2022-08-13 12:40:42 +02:00
}
2022-11-03 14:51:13 +01:00
halfTime() {
this.#gameStartOrHalfTimeOrEnd()
}
#gameStartOrHalfTimeOrEnd() {
2022-10-19 12:23:08 +02:00
this.#world.playSound('538422__rosa-orenes256__referee-whistle-sound.wav', null, true)
}
2022-10-10 14:54:48 +02:00
playSound(data) {
2022-11-02 17:29:35 +01:00
if (data.type === SoundType.ITEM_ATTACK && data.player === this.playerSpectate.getId()) {
this.attackFeedback(data.item)
}
2022-11-05 17:12:25 +01:00
if (data.type === SoundType.ITEM_PICKUP) {
this.#world.itemPickup(data.position, data.item)
}
2022-11-06 15:37:41 +01:00
if (data.type === SoundType.BULLET_HIT && data.surface && (data.item.slot === InventorySlot.SLOT_PRIMARY || data.item.slot === InventorySlot.SLOT_SECONDARY)) {
this.#world.bulletWallHit(data.position, data.surface, (data.item.slot === InventorySlot.SLOT_PRIMARY ? 1.2 : 0.8))
2022-11-06 13:29:50 +01:00
}
2022-11-05 17:12:25 +01:00
if (data.type === SoundType.ITEM_DROP) {
this.#world.itemDrop(data.position, data.item)
if (data.player === this.playerSpectate.getId()) {
this.dropFeedback(data.item)
}
}
2022-11-10 17:06:08 +01:00
if (data.type === SoundType.BOMB_DEFUSED) {
this.#bombDefused()
}
2022-11-02 17:29:35 +01:00
let soundName = this.#soundRepository.getSoundName(data.type, data.item, data.player, data.surface, this.playerSpectate.getId())
2022-10-19 12:23:08 +02:00
if (!soundName) {
2022-10-18 12:20:51 +02:00
return
2022-10-17 14:30:50 +02:00
}
2022-10-18 12:20:51 +02:00
2022-11-07 15:54:54 +01:00
const alwaysInHeadTypes = [
SoundType.BOMB_PLANTED, SoundType.BOMB_DEFUSED,
]
const myPlayerTypes = [
SoundType.ITEM_RELOAD, SoundType.ITEM_PICKUP, SoundType.ITEM_ATTACK, SoundType.ITEM_ATTACK2, SoundType.ITEM_BUY,
SoundType.PLAYER_STEP, SoundType.ATTACK_NO_AMMO,
SoundType.BOMB_PLANTING, SoundType.BOMB_DEFUSING,
]
let inPlayerSpectateHead = (alwaysInHeadTypes.includes(data.type) || (data.player && data.player === this.playerSpectate.getId() && myPlayerTypes.includes(data.type)))
this.#world.playSound(soundName, data.position, inPlayerSpectateHead)
2022-10-17 14:30:50 +02:00
}
2022-10-30 15:07:24 +01:00
bombPlanted(timeMs, position) {
const world = this.#world
2022-11-02 17:29:35 +01:00
world.spawnBomb(position)
2022-10-30 15:07:24 +01:00
2022-11-03 14:51:13 +01:00
const bombSecCount = Math.round(timeMs / 1000)
this.#hud.bombPlanted(bombSecCount)
const tenSecWarningSecCount = Math.round(timeMs / 1000 - 10)
2022-10-30 15:07:24 +01:00
let tickSecondsCount = 0;
2022-11-03 14:51:13 +01:00
let bombTimerId = setInterval(function () {
if (tickSecondsCount === bombSecCount) {
clearInterval(bombTimerId)
}
2022-10-30 15:07:24 +01:00
if (tickSecondsCount === tenSecWarningSecCount) {
world.playSound('88532__northern87__woosh-northern87.wav', null, true)
}
world.playSound('536422__rudmer-rotteveel__setting-electronic-timer-1-beep.wav', position, false)
tickSecondsCount++;
}, 1000)
2022-11-03 14:51:13 +01:00
this.#bombTimerId = bombTimerId
2022-10-30 15:07:24 +01:00
}
2022-11-10 17:06:08 +01:00
#bombDefused() {
2022-10-30 15:07:24 +01:00
clearInterval(this.#bombTimerId)
}
2022-10-21 12:35:24 +02:00
isPaused() {
return this.#paused
2022-10-10 14:54:48 +02:00
}
2022-08-13 12:40:42 +02:00
isPlaying() {
return this.#started
}
onReady(callback) {
this.#readyCallback = callback
}
onEnd(callback) {
this.#endCallback = callback
}
2022-10-21 12:35:24 +02:00
gameStart(options) {
2022-08-13 12:40:42 +02:00
this.#options = options
this.#hud.startWarmup(options.warmupSec * 1000)
const playerId = options.playerId
if (this.players[playerId]) {
throw new Error("My Player is already set!")
}
2022-10-06 20:35:28 +02:00
this.playerMe = new Player(options.player, this.#world.createPlayerMe())
this.players[playerId] = this.playerMe;
2022-11-02 17:29:35 +01:00
this.playerSpectate = this.playerMe
2022-08-13 12:40:42 +02:00
if (this.#readyCallback) {
this.#readyCallback(this.#options)
}
}
playerKilled(playerIdDead, playerIdCulprit, wasHeadshot, killItemId) {
2022-11-02 17:29:35 +01:00
const culpritPlayer = this.players[playerIdCulprit]
const deadPlayer = this.players[playerIdDead]
2022-10-07 15:44:35 +02:00
2022-11-03 14:51:13 +01:00
deadPlayer.died()
2022-10-06 20:35:28 +02:00
this.alivePlayers[deadPlayer.getTeamIndex()]--
2022-08-13 12:40:42 +02:00
this.#hud.showKill(
2022-10-07 15:44:35 +02:00
culpritPlayer.data,
2022-10-06 20:35:28 +02:00
deadPlayer.data,
2022-08-13 12:40:42 +02:00
wasHeadshot,
2022-11-03 14:51:13 +01:00
this.playerMe.data,
2022-08-13 12:40:42 +02:00
killItemId
)
2022-11-02 17:29:35 +01:00
if (playerIdDead === this.playerSpectate.getId()) {
2022-11-09 12:33:06 +01:00
this.requestPointerUnLock()
2022-11-02 17:29:35 +01:00
this.spectatePlayer()
}
}
spectatePlayer(directionNext = true) {
if (this.playerMe.isAlive() || this.alivePlayers[this.playerMe.getTeamIndex()] === 0) {
return
}
2022-11-09 12:33:06 +01:00
const myId = this.playerSpectate.getId()
let aliveAvailableSpectateMates = this.getMyTeamPlayers().filter((player) => player.isAlive() && myId !== player.getId())
if (aliveAvailableSpectateMates.length === 0) {
return;
}
let ids = aliveAvailableSpectateMates.map((player) => player.getId()).sort()
2022-11-02 17:29:35 +01:00
if (!directionNext) {
2022-11-09 12:33:06 +01:00
ids.reverse()
2022-11-02 17:29:35 +01:00
}
2022-11-09 12:33:06 +01:00
let playerId = ids.find((id) => myId > id)
if (!playerId) {
playerId = ids.shift()
2022-11-02 17:29:35 +01:00
}
const camera = this.#world.getCamera()
camera.removeFromParent()
2022-11-09 12:33:06 +01:00
camera.rotation.set(0, degreeToRadian(-90), 0)
const player = this.players[playerId]
player.get3DObject().getObjectByName('head').add(camera)
player.get3DObject().visible = false
2022-11-09 15:14:54 +01:00
if (this.playerSpectate.isAlive()) {
this.playerSpectate.get3DObject().visible = true
}
2022-11-09 12:33:06 +01:00
this.playerSpectate = player
2022-08-13 12:40:42 +02:00
}
2022-10-06 20:35:28 +02:00
createPlayer(data) {
2022-10-23 21:03:13 +02:00
const player = new Player(data, this.#world.spawnPlayer(data.color, this.playerMe.isAttacker() !== data.isAttacker))
2022-10-06 20:35:28 +02:00
if (this.players[data.id]) {
throw new Error('Player already exist with id ' + data.id)
2022-08-13 12:40:42 +02:00
}
2022-10-06 20:35:28 +02:00
this.players[data.id] = player
return player
2022-08-13 12:40:42 +02:00
}
2022-11-02 17:29:35 +01:00
attackFeedback(item) {
if (this.playerSpectate.data.ammo > 0) {
2022-11-05 17:12:25 +01:00
this.#hud.showShot(item)
2022-10-19 12:23:08 +02:00
}
2022-10-05 20:08:33 +02:00
}
2022-11-05 17:12:25 +01:00
dropFeedback(item) {
this.#hud.showDropAnimation(item)
}
2022-08-13 12:40:42 +02:00
equip(slotId) {
2022-11-02 17:29:35 +01:00
if (!this.playerSpectate.data.slots[slotId]) {
2022-08-13 12:40:42 +02:00
return false
}
2022-11-02 17:29:35 +01:00
this.playerSpectate.equip(slotId)
this.#hud.equip(slotId, this.playerSpectate.data.slots)
2022-08-13 12:40:42 +02:00
return true
}
tick(state) {
2022-10-21 12:35:24 +02:00
this.#stats.begin()
2022-08-13 12:40:42 +02:00
const game = this
2022-11-15 12:16:18 +01:00
if (this.playerMe !== null) {
state.players.forEach(function (serverState) {
let player = game.players[serverState.id]
if (player === undefined) {
player = game.createPlayer(serverState)
}
game.updatePlayerData(player, serverState)
})
}
2022-10-07 15:44:35 +02:00
state.events.forEach(function (event) {
game.eventProcessor.process(event)
})
2022-08-13 12:40:42 +02:00
2022-10-21 12:35:24 +02:00
this.#render()
this.#stats.end()
2022-08-13 12:40:42 +02:00
}
2022-10-07 15:44:35 +02:00
updatePlayerData(player, serverState) {
2022-11-03 14:51:13 +01:00
player.get3DObject().getObjectByName('head').position.y = serverState.heightSight
player.get3DObject().position.set(serverState.position.x, serverState.position.y, -serverState.position.z)
2022-10-07 15:44:35 +02:00
if (player.data.isAttacker === this.playerMe.data.isAttacker) { // if player on my team
if (player.data.money !== serverState.money) {
this.#hud.updateMyTeamPlayerMoney(player.data, serverState.money)
}
player.updateData(serverState)
} else {
player.data.item = serverState.item
player.data.isAttacker = serverState.isAttacker
}
2022-10-23 13:02:58 +02:00
2022-11-02 17:29:35 +01:00
if (this.playerMe.getId() === serverState.id || this.playerSpectate.getId() === serverState.id) {
if (this.playerSpectate.isInventoryChanged(serverState)) {
2022-10-23 13:02:58 +02:00
this.equip(serverState.item.slot)
}
2022-11-09 12:33:06 +01:00
}
if (this.playerMe.getId() !== serverState.id) {
2022-10-23 13:02:58 +02:00
this.updateOtherPlayersModels(player.get3DObject(), serverState)
}
2022-10-07 15:44:35 +02:00
}
2022-10-06 20:35:28 +02:00
updateOtherPlayersModels(playerObject, data) {
2022-10-18 15:14:38 +02:00
playerObject.rotation.y = serverHorizontalRotationToThreeRadian(data.look.horizontal)
2022-11-09 12:33:06 +01:00
const rotationVertical = this.playerMe.isAlive() ? Math.max(Math.min(data.look.vertical, 60), -50) : data.look.vertical
playerObject.getObjectByName('head').rotation.x = serverVerticalRotationToThreeRadian(rotationVertical)
2022-10-07 15:44:35 +02:00
const body = playerObject.getObjectByName('body')
if (body.position.y !== data.heightBody) { // update body height position if changed
body.position.y = data.heightBody
}
2022-08-13 12:40:42 +02:00
}
2022-10-21 12:35:24 +02:00
getMyTeamPlayers() {
let meIsAttacker = this.playerMe.isAttacker()
return this.players.filter((player) => player.isAttacker() === meIsAttacker)
}
meIsAlive() {
return this.playerMe.isAlive()
}
2022-11-02 17:29:35 +01:00
meIsSpectating() {
return (!this.meIsAlive())
}
2022-10-22 21:35:14 +02:00
setPointer(pointer) {
this.#pointer = pointer
}
getPlayerMeRotation() {
return threeRotationToServer(this.#pointer.getObject().rotation)
}
2022-11-02 17:29:35 +01:00
getPlayerSpectateRotation() {
if (this.playerSpectate.getId() === this.playerMe.getId()) {
return this.getPlayerMeRotation()
}
return [this.playerSpectate.data.look.horizontal, this.playerSpectate.data.look.vertical]
}
2022-10-22 21:35:14 +02:00
requestPointerLock() {
2022-11-09 12:33:06 +01:00
if (this.#pointer.isLocked || (this.playerMe && this.playerMe.getId() !== this.playerSpectate.getId())) {
2022-10-22 21:35:14 +02:00
return
}
this.#pointer.lock()
}
requestPointerUnLock() {
if (!this.#pointer.isLocked) {
return
}
this.#pointer.unlock()
}
2022-10-21 12:35:24 +02:00
#render() {
2022-10-13 17:26:52 +02:00
if (this.#started && --this.#hudDebounceTicks === 0) {
this.#hudDebounceTicks = 4
2022-11-02 17:29:35 +01:00
this.#hud.updateHud(this.playerSpectate.data)
2022-10-06 20:35:28 +02:00
}
2022-08-13 12:40:42 +02:00
this.#world.render()
}
}