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-10-17 14:30:50 +02:00
|
|
|
import {InventorySlot, SoundType} from "./Enums.js";
|
2022-08-13 12:40:42 +02:00
|
|
|
|
|
|
|
export class Game {
|
|
|
|
#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
|
|
|
|
#hud
|
2022-10-05 16:09:55 +02:00
|
|
|
#stats
|
2022-08-13 12:40:42 +02:00
|
|
|
#world
|
2022-10-13 17:26:52 +02:00
|
|
|
#hudDebounceTicks = 1
|
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-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-06 20:35:28 +02:00
|
|
|
pause(msg, score, timeMs) {
|
|
|
|
console.log("Pause: " + msg + " for " + timeMs + "ms")
|
2022-09-24 19:28:57 +02:00
|
|
|
const game = this
|
|
|
|
this.players.forEach(function (player) {
|
2022-10-06 20:35:28 +02:00
|
|
|
if (player.getId() !== game.playerMe.getId()) {
|
|
|
|
player.get3DObject().visible = true // respawn (show) all beside me
|
2022-09-24 19:28:57 +02:00
|
|
|
}
|
|
|
|
})
|
2022-09-23 18:33:03 +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-10-19 12:23:08 +02: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-10-19 12:23:08 +02:00
|
|
|
gameStartOrHalfTimeOrEnd() {
|
|
|
|
this.#world.playSound('538422__rosa-orenes256__referee-whistle-sound.wav', null, true)
|
|
|
|
}
|
|
|
|
|
2022-10-10 14:54:48 +02:00
|
|
|
playSound(data) {
|
2022-10-19 12:23:08 +02:00
|
|
|
let soundName = this.#getSoundName(data.type, data.item, data.player, data.surface)
|
|
|
|
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
|
|
|
|
|
|
|
let myPlayerTypes = [SoundType.ITEM_RELOAD, SoundType.PLAYER_STEP, SoundType.ITEM_ATTACK, SoundType.ITEM_BUY]
|
|
|
|
let myPlayerSound = (data.player && data.player === this.playerMe.getId() && myPlayerTypes.includes(data.type))
|
2022-10-19 12:23:08 +02:00
|
|
|
this.#world.playSound(soundName, data.position, myPlayerSound)
|
2022-10-17 14:30:50 +02:00
|
|
|
}
|
|
|
|
|
2022-10-19 12:23:08 +02:00
|
|
|
#getSoundName(type, item, playerId, surfaceStrength) {
|
|
|
|
if (type === SoundType.PLAYER_STEP) {
|
|
|
|
if (playerId === this.playerMe.getId()) {
|
|
|
|
return '422990__dkiller2204__sfxrunground1.wav'
|
|
|
|
} else {
|
|
|
|
return '221626__moodpie__body-impact.wav'
|
|
|
|
}
|
|
|
|
}
|
2022-10-17 14:30:50 +02:00
|
|
|
|
2022-10-19 12:23:08 +02:00
|
|
|
if (type === SoundType.ITEM_ATTACK) {
|
2022-10-17 14:30:50 +02:00
|
|
|
if (item.slot === InventorySlot.SLOT_SECONDARY) {
|
2022-10-19 12:23:08 +02:00
|
|
|
return '387480__cosmicembers__dart-thud-2.wav'
|
|
|
|
} else if (item.slot === InventorySlot.SLOT_PRIMARY) {
|
|
|
|
return '513421__pomeroyjoshua__anu-clap-09.wav'
|
2022-10-17 14:30:50 +02:00
|
|
|
} else {
|
2022-10-19 12:23:08 +02:00
|
|
|
return '558117__abdrtar__move.mp3'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === SoundType.ITEM_RELOAD) {
|
|
|
|
if (item.slot === InventorySlot.SLOT_SECONDARY) {
|
|
|
|
return '618047__mono832__reload.mp3'
|
|
|
|
} else {
|
|
|
|
return '15545__lagthenoggin__reload.mp3'
|
2022-10-17 14:30:50 +02:00
|
|
|
}
|
|
|
|
// shotgun 621155__ktfreesound__reload-escopeta-m7.wav
|
2022-10-19 12:23:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type === SoundType.BULLET_HIT_HEADSHOT) {
|
|
|
|
return (playerId === this.playerMe.getId()) ? '249821__spookymodem__weapon-blow.wav' : '632704__adh-dreaming__fly-on-the-wall-snare.wav'
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === SoundType.BULLET_HIT) {
|
2022-10-17 14:30:50 +02:00
|
|
|
if (surfaceStrength) {
|
|
|
|
if (surfaceStrength > 2000) {
|
2022-10-19 12:23:08 +02:00
|
|
|
return '51381__robinhood76__00119-trzepak-3.wav'
|
2022-10-17 14:30:50 +02:00
|
|
|
} else {
|
2022-10-19 12:23:08 +02:00
|
|
|
return '108737__branrainey__boing.wav'
|
2022-10-17 14:30:50 +02:00
|
|
|
}
|
|
|
|
} else if (playerId) {
|
2022-10-19 12:23:08 +02:00
|
|
|
return '512138__beezlefm__item-sound.wav'
|
2022-10-17 14:30:50 +02:00
|
|
|
}
|
2022-10-19 12:23:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type === SoundType.PLAYER_GROUND_TOUCH) {
|
|
|
|
return '211500__taira-komori__knocking-wall.mp3'
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === SoundType.ITEM_DROP) {
|
|
|
|
return '12734__leady__dropping-a-gun.wav'
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === SoundType.ATTACK_NO_AMMO) {
|
2022-10-17 14:30:50 +02:00
|
|
|
if (item.slot === InventorySlot.SLOT_SECONDARY) {
|
2022-10-19 12:23:08 +02:00
|
|
|
return '323403__gosfx__sound-1.mp3'
|
2022-10-17 14:30:50 +02:00
|
|
|
} else if (item.slot === InventorySlot.SLOT_PRIMARY) {
|
2022-10-19 12:23:08 +02:00
|
|
|
return '448987__matrixxx__weapon-ready.wav'
|
2022-10-17 14:30:50 +02:00
|
|
|
} else {
|
2022-10-19 12:23:08 +02:00
|
|
|
return '369009__flying-deer-fx__hit-01-mouth-fx-impact-with-object.wav'
|
2022-10-17 14:30:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-19 12:23:08 +02:00
|
|
|
if (type === SoundType.BOMB_PLANTED) {
|
|
|
|
return '555042__bittermelonheart__soccer-ball-kick.wav'
|
|
|
|
}
|
2022-10-17 14:30:50 +02:00
|
|
|
|
2022-10-19 12:23:08 +02:00
|
|
|
if (type === SoundType.ITEM_BUY) {
|
|
|
|
return '434781__stephenbist__luggage-drop-1.wav'
|
2022-10-17 14:30:50 +02:00
|
|
|
}
|
2022-10-19 12:23:08 +02:00
|
|
|
|
2022-10-17 14:30:50 +02:00
|
|
|
console.log("No song defined for: " + arguments)
|
|
|
|
return null
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
setOptions(options) {
|
|
|
|
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-08-13 12:40:42 +02:00
|
|
|
|
|
|
|
if (this.#readyCallback) {
|
|
|
|
this.#readyCallback(this.#options)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
playerKilled(playerIdDead, playerIdCulprit, wasHeadshot, killItemId) {
|
2022-10-07 15:44:35 +02:00
|
|
|
const culpritPlayer = this.players[playerIdCulprit];
|
2022-10-06 20:35:28 +02:00
|
|
|
const deadPlayer = this.players[playerIdDead];
|
2022-10-07 15:44:35 +02:00
|
|
|
|
2022-10-06 20:35:28 +02:00
|
|
|
deadPlayer.get3DObject().visible = false
|
|
|
|
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-10-06 20:35:28 +02:00
|
|
|
this.playerMe.data,
|
2022-08-13 12:40:42 +02:00
|
|
|
killItemId
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-10-06 20:35:28 +02:00
|
|
|
createPlayer(data) {
|
2022-10-07 15:44:35 +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-10-05 20:08:33 +02:00
|
|
|
attack() {
|
2022-10-19 12:23:08 +02:00
|
|
|
if (this.playerMe.data.ammo > 0) {
|
|
|
|
this.#hud.showShot()
|
|
|
|
}
|
2022-10-05 20:08:33 +02:00
|
|
|
}
|
|
|
|
|
2022-08-13 12:40:42 +02:00
|
|
|
equip(slotId) {
|
2022-10-06 20:35:28 +02:00
|
|
|
if (!this.playerMe.data.slots[slotId]) {
|
2022-08-13 12:40:42 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-10-06 20:35:28 +02:00
|
|
|
this.playerMe.equip(slotId)
|
|
|
|
this.#hud.equip(slotId, this.playerMe.data.slots)
|
2022-08-13 12:40:42 +02:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
tick(state) {
|
|
|
|
const game = this
|
|
|
|
|
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
|
|
|
|
|
|
|
if (this.#options === false) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
state.players.forEach(function (playerState) {
|
|
|
|
let player = game.players[playerState.id]
|
|
|
|
if (player === undefined) {
|
2022-10-06 20:35:28 +02:00
|
|
|
player = game.createPlayer(playerState)
|
2022-08-13 12:40:42 +02:00
|
|
|
}
|
|
|
|
|
2022-10-07 15:44:35 +02:00
|
|
|
player.get3DObject().getObjectByName('head').position.y = playerState.heightSight
|
|
|
|
player.get3DObject().position.set(playerState.position.x, playerState.position.y, -1 * (playerState.position.z))
|
|
|
|
|
|
|
|
game.updatePlayerData(player, playerState)
|
2022-08-13 12:40:42 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
this.render()
|
|
|
|
}
|
|
|
|
|
2022-10-07 15:44:35 +02:00
|
|
|
updatePlayerData(player, serverState) {
|
|
|
|
if (this.playerMe.getId() === serverState.id) { // if me
|
|
|
|
if (this.playerMe.getEquippedSlotId() !== serverState.item.slot) {
|
|
|
|
this.equip(serverState.item.slot)
|
|
|
|
}
|
2022-10-18 15:14:38 +02:00
|
|
|
} else {
|
|
|
|
this.updateOtherPlayersModels(player.get3DObject(), serverState)
|
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-06 20:35:28 +02:00
|
|
|
meIsAlive() {
|
|
|
|
return this.playerMe.isAlive()
|
2022-08-13 12:40:42 +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-10-07 15:44:35 +02:00
|
|
|
|
|
|
|
const body = playerObject.getObjectByName('body')
|
|
|
|
if (body.position.y !== data.heightBody) { // update body height position if changed
|
|
|
|
// TODO probably keyframe time based animation from userData like body.position = body.userData.animation[data.playerAnimationId]
|
|
|
|
body.position.y = data.heightBody
|
|
|
|
}
|
2022-08-13 12:40:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2022-10-05 16:09:55 +02:00
|
|
|
this.#stats.begin()
|
2022-10-13 17:26:52 +02:00
|
|
|
if (this.#started && --this.#hudDebounceTicks === 0) {
|
|
|
|
this.#hudDebounceTicks = 4
|
|
|
|
this.#hud.updateHud(this.playerMe.data)
|
2022-10-06 20:35:28 +02:00
|
|
|
}
|
2022-08-13 12:40:42 +02:00
|
|
|
this.#world.render()
|
2022-10-05 16:09:55 +02:00
|
|
|
this.#stats.end()
|
2022-08-13 12:40:42 +02:00
|
|
|
}
|
|
|
|
}
|