diff --git a/client/index.mjs b/client/index.mjs index fc193e8..b7b8fce 100644 --- a/client/index.mjs +++ b/client/index.mjs @@ -17,6 +17,10 @@ alt.onServer('player:notify', message => { native.endTextCommandThefeedPostTicker(false, false) }) +alt.onServer('player:showMidsizedMessage', (message, description, delay) => { + NativeUI.MidsizedMessage.ShowMidsizedMessage(message, description, delay) +}) + alt.onServer('player:setInvincible', () => { native.setEntityInvincible(alt.Player.local.scriptID, true) }) diff --git a/client/ui.mjs b/client/ui.mjs index 3fcfe98..b66caca 100644 --- a/client/ui.mjs +++ b/client/ui.mjs @@ -818,6 +818,19 @@ const weapons = { } } +const helpMenu = new Menu("Помощь", "Помощь по игре на сервере", menuPos) +const listCommandsMenu = new Menu("Команды", "Узнайте список доступных команд", menuPos) + +const commandsItem = new UIMenuItem('Достуные команды', `Узнайте список доступных команд`) + +helpMenu.BindMenuToItem(listCommandsMenu, commandsItem) + +listCommandsMenu.AddItem(new UIMenuItem('Играть в copchase', `/copchase`)) +listCommandsMenu.AddItem(new UIMenuItem('Сменить скин', `/skin [0 - 700]`)) +listCommandsMenu.AddItem(new UIMenuItem('Появиться на спауне', `/spawn`)) +listCommandsMenu.AddItem(new UIMenuItem('Узнать текущий онлайн', `/online`)) +listCommandsMenu.AddItem(new UIMenuItem('Узнать Social Club ID', `/scid`)) + const adminMenu = new Menu("Админ Панель", "Выполняйте админ-функции", menuPos) const kickPlayerMenu = new Menu("Кикнуть игрока", "Сервер кикнет любого игрока", menuPos) const killPlayerMenu = new Menu('Убить игрока', "Сервер моментально убьет игрока", menuPos) @@ -890,14 +903,43 @@ weaponsMenu.ItemSelect.on(item => { }) alt.on('keyup', key => { - if (key === 113) { // F2 - alt.emitServer('showAdminPanel') - } + if (key === 112) { + if ( + listCommandsMenu.Visible + || adminMenu.Visible + || kickPlayerMenu.Visible + || killPlayerMenu.Visible + || carSpawnMenu.Visible + || teleportToLocationMenu.Visible + || myPersonMenu.Visible + || weaponsMenu.Visible + || teleportToPlayerMenu.Visible + || teleportToMeMenu.Visible + ) { + listCommandsMenu.Close() + adminMenu.Close() + kickPlayerMenu.Close() + killPlayerMenu.Close() + carSpawnMenu.Close() + teleportToLocationMenu.Close() + myPersonMenu.Close() + weaponsMenu.Close() + teleportToPlayerMenu.Close() + teleportToMeMenu.Close() + } + helpMenu.Visible ? helpMenu.Close() : helpMenu.Open() + } + + if (key === 113) { + alt.emitServer('showAdminPanel') + } }) alt.onServer('ui:showAdminPanel', () => { if ( - kickPlayerMenu.Visible + helpMenu.Visible + || listCommandsMenu.Visible + || kickPlayerMenu.Visible || killPlayerMenu.Visible || carSpawnMenu.Visible || teleportToLocationMenu.Visible @@ -907,6 +949,8 @@ alt.onServer('ui:showAdminPanel', () => { || teleportToMeMenu.Visible ) { + helpMenu.Close() + listCommandsMenu.Close() kickPlayerMenu.Close() killPlayerMenu.Close() carSpawnMenu.Close() diff --git a/server/config.mjs b/server/config.mjs index 0e33594..dd4ae97 100644 --- a/server/config.mjs +++ b/server/config.mjs @@ -12,7 +12,8 @@ export default { epsilon: { x:-695.025, y: 82.955, z: 55.855 } }, admins: [ - { socialId: '370262977' } + { socialId: '370262977' }, + { socialId: '401448051' } ], defaultModel: 'mp_m_freemode_01' } \ No newline at end of file diff --git a/server/index.mjs b/server/index.mjs index 7dc17e9..b038d23 100644 --- a/server/index.mjs +++ b/server/index.mjs @@ -17,6 +17,7 @@ import './modules/events/ui/admin/teleportToMe.mjs' import './modules/events/playerConnect.mjs' import './modules/events/playerDisconnect.mjs' import './modules/events/playerDeath.mjs' +import './modules/events/playerLeftVehicle.mjs' /* Commands @@ -38,6 +39,8 @@ import './modules/commands/player/spawn.mjs' import './modules/commands/player/online.mjs' import './modules/commands/player/skin.mjs' import './modules/commands/player/scid.mjs' +import './modules/commands/player/copchase.mjs' +import './modules/commands/player/mydimension.mjs' /* Default text labels diff --git a/server/modules/commands/admin/car.mjs b/server/modules/commands/admin/car.mjs index 89ea2c4..46150e6 100644 --- a/server/modules/commands/admin/car.mjs +++ b/server/modules/commands/admin/car.mjs @@ -12,6 +12,7 @@ registerCmd('car', (player, args) => { try { const newVehicle = new alt.Vehicle(args[0], player.pos.x, player.pos.y, player.pos.z, 0, 0, 0) newVehicle.numberPlateText = 'ADMIN' + newVehicle.dimension = player.dimension alt.emitClient(player, 'vehicle:setInto', newVehicle) } catch (error) { diff --git a/server/modules/commands/player/copchase.mjs b/server/modules/commands/player/copchase.mjs new file mode 100644 index 0000000..342dcd9 --- /dev/null +++ b/server/modules/commands/player/copchase.mjs @@ -0,0 +1,27 @@ +import alt from 'alt-server' +import { registerCmd, send } from 'chat' +import { copchase } from '../../copchase.mjs' + +import config from '../../../config.mjs' + +registerCmd('copchase', player => { + if (copchase.isPlayerInWaitingRoom(player)) return false + if (copchase.isPlayerInGame(player)) return false + + player.dimension = copchase.waitingRoomDimension + player.pos = config.waitingRoom + + copchase.addPlayerToWaitingRoom(player) + alt.emitClient(player, 'player:setInvincible') + + if (copchase.isStarted && copchase.players.length > 0) { + // copchase.addPlayerToWaitingRoom(player) + return alt.emitClient(player, 'player:showMidsizedMessage', '~b~Игра уже начата', 'Ожидание игроков...') + } + + if (copchase.waitingPlayers.length < copchase.minPlayers) { + return alt.emitClient(player, 'player:showMidsizedMessage', '~b~Ожидание игроков...', '') + } + + copchase.startGame() +}) \ No newline at end of file diff --git a/server/modules/commands/player/mydimension.mjs b/server/modules/commands/player/mydimension.mjs new file mode 100644 index 0000000..aa6ea52 --- /dev/null +++ b/server/modules/commands/player/mydimension.mjs @@ -0,0 +1,5 @@ +import { registerCmd, send } from 'chat' + +registerCmd('mydimension', player => { + return send(player, `{EE9A00}[SERVER]: {FFF}Dimension: ${player.dimension}`) +}) \ No newline at end of file diff --git a/server/modules/copchase.mjs b/server/modules/copchase.mjs new file mode 100644 index 0000000..0475650 --- /dev/null +++ b/server/modules/copchase.mjs @@ -0,0 +1,318 @@ +import alt from 'alt-server' +import { send, broadcast } from 'chat' + +import config from '../config.mjs' +import skins from '../skins.json' + +class Copchase { + constructor({ dimension, waitingRoomDimension, minPlayers, maxPlayers, timeRemaining, timeToStart }) { + this.dimension = dimension + this.waitingRoomDimension = waitingRoomDimension + this.minPlayers = minPlayers + this.maxPlayers = maxPlayers + this.timeRemaining = timeRemaining + this.timeRemainingInterval = null + this.timeToStart = timeToStart + this.isStarted = false + this.suspectCars = [ + 'asea', + 'bison', + 'bobcatxl', + 'burrito', + 'emperor', + 'emperor2', + 'ardent', + 'ingot', + 'journey', + 'clique', + 'vamos', + 'tulip', + 'stafford', + 'cheburek', + 'streiter', + 'nebula', + 'hellion', + 'gauntlet4' + ] + this.policeCars = [ + 'police2', + 'police3' + ] + this.weather = [ + 'EXTRASUNNY', + 'CLEAR', + 'CLOUDS', + 'SMOG', + 'FOGGY', + 'OVERCAST', + 'RAIN', + 'THUNDER', + 'CLEARING', + 'NEUTRAL', + 'SNOW', + 'BLIZZARD', + 'SNOWLIGHT', + 'XMAS', + 'HALLOWEEN' + ] + this.players = [] + this.waitingPlayers = [] + this.cars = [] + this.blips = {} + this.suspect = null + this.positions = { + suspect: [ + { x: 395.185, y: -999.645, z: 28.755 }, + { x: 404.691, y: -1907.0604, z: 24.723 }, + { x: 2619.436, y: 3374.145, z: 55.619 } + ], + police: [ + { x: 442.308, y: -1025.066, z: 28.231 }, + { x: 348.865, y: -1966.507, z:24.133 }, + { x: 2678.454, y: 3459.637, z: 55.340 } + ] + } + } + + setDefaultState() { + this.timeRemainingInterval = null + this.isStarted = false + this.suspect = null + this.players = [] + // this.waitingPlayers = [] + this.blips = {} + + setTimeout(() => { + this.cars.forEach(car => car.destroy()) + this.cars = [] + }, 5000) + } + + isPlayerInGame(player) { + if(this.players.find(_player => _player.name === player.name) !== undefined) { + send(player, '{EE9A00}[COPCHASE]: {FF0000}Дождитесь окончания игры!') + return true + } else { + return false + } + } + + isPlayerInWaitingRoom(player) { + if(this.waitingPlayers.find(_player => _player.name === player.name) !== undefined) { + send(player, '{EE9A00}[COPCHASE]: {FF0000}Вы уже в комнате ожидания!') + return true + } else { + return false + } + } + + addPlayerToWaitingRoom(player) { + this.waitingPlayers.push(player) + } + + pushWaitingPlayersToGame(waitingPlayers) { + waitingPlayers.forEach(_player => this.players.push(_player)) + this.waitingPlayers = [] + } + + selectSuspect() { + this.suspect = this.players[Math.floor(Math.random() * (this.players.length - 1 - 0 + 1) + 0)] + } + + messageToPlayersInGame(message) { + this.players.forEach(_player => send(_player, message)) + } + + messageToWaitingPlayers(message) { + this.waitingPlayers.forEach(_player => send(_player, message)) + } + + notifyPolicePlayers(message) { + this.players.forEach(_player => _player.name !== this.suspect.name ? alt.emitClient(_player, 'player:notify', message) : false) + } + + notifySuspectPlayer(message) { + alt.emitClient(this.suspect, 'player:notify', message) + } + + spawnPlayers() { + let suspectRandomNumber = Math.floor(Math.random() * this.positions.suspect.length) + let suspectPosition = this.positions.suspect[suspectRandomNumber] + + this.players.forEach(_player => { + if (_player.name === this.suspect.name) { + _player.pos = suspectPosition + _player.dimension = this.dimension + _player.model = skins[Math.floor(Math.random() * (430 - 1 - 422) + 422)] + alt.emitClient(_player, 'player:delInvincible') + alt.emitClient(_player, 'player:showMidsizedMessage', '~r~Вы саспект!', 'Уйдите от полицейских.', 5000) + + // this.blips[_player.id] = mp.blips.new(1, suspectPosition) + // this.blips[_player.id].name = _player.name + // this.blips[_player.id].dimension = this.dimension + // this.blips[_player.id].color = 1 + } else { + _player.pos = { + x: this.positions.police[suspectRandomNumber].x + 2, + y: this.positions.police[suspectRandomNumber].y, + z: this.positions.police[suspectRandomNumber].z + } + // _player.heading = 260 + _player.dimension = this.dimension + _player.model = 's_m_y_cop_01' + _player.giveWeapon('0x3656C8C1', 100, true) + alt.emitClient(_player, 'player:delInvincible') + alt.emitClient(_player, 'player:showMidsizedMessage', `~w~Саспект: ~r~${this.suspect.name}`, 'Нейтрализуйте саспекта.', 5000) + + // this.blips[_player.id] = mp.blips.new(1, suspectPosition) + // this.blips[_player.id].name = _player.name + // this.blips[_player.id].dimension = this.dimension + // this.blips[_player.id].color = 38 + } + }) + } + + spawnCars() { + this.players.forEach(_player => { + if (_player.name === this.suspect.name) { + const carSuspect = new alt.Vehicle( + this.suspectCars[Math.floor(Math.random() * (this.suspectCars.length - 1 - 0) + 0)], + _player.pos.x, _player.pos.y, _player.pos.z, + 0, 0, 0 + ) + + carSuspect.numberPlateText = 'SUSPECT' + carSuspect.dimension = this.dimension + + alt.emitClient(_player, 'vehicle:setInto', carSuspect) + carSuspect.engineHealth = 500 + + this.cars.push(carSuspect) + } else { + const carPolice = new alt.Vehicle( + this.policeCars[Math.floor(Math.random() * (this.policeCars.length - 1 - 0) + 0)], + _player.pos.x, _player.pos.y, _player.pos.z, + 0, 0, 0 + ) + + carPolice.numberPlateText = 'POLICE' + carPolice.dimension = this.dimension + + alt.emitClient(_player, 'vehicle:setInto', carPolice) + this.cars.push(carPolice) + } + }) + } + + startGame() { + let timeToStart = this.timeToStart + const interval = setInterval(() => { + timeToStart = timeToStart - 1 + + if (timeToStart <= 0) { + // if (this.waitingPlayers.length >= 2) { + // broadcast(`Недостаточно игроков для старта!`) + // return + // } + + this.isStarted = true + + this.pushWaitingPlayersToGame(this.waitingPlayers) + this.selectSuspect() + + this.notifyPolicePlayers(`~w~ Остановите саспекта!`) + this.notifySuspectPlayer(`~w~ Уйдите от полицейских!`) + + this.spawnPlayers() + this.spawnCars() + // setInterval(() => { + // this.players.forEach((player, id) => { + // if (this.blips[player.id] && player.health > 0) { + // this. [player.id].position = player.position; + // } + // }) + // }, 1000) + + let timeRemaining = this.timeRemaining + this.timeRemainingInterval = setInterval(() => { + timeRemaining = timeRemaining - 1 + if (timeRemaining !== 0) { + this.players.forEach(_player => alt.emitClient(_player, 'player:showMidsizedMessage', `Осталось: ~b~${timeRemaining} ~w~мин.`, '', 5000)) + } + + if (timeRemaining <= 0) { + this.stopGame({ winner: 'suspect' }) + + clearInterval(this.timeRemainingInterval) + return true + } + }, 60000) + + clearInterval(interval) + return true + } + + this.waitingPlayers.forEach(_player => { + alt.emitClient(_player, 'player:showMidsizedMessage', `${timeToStart}`, '', 1000) + }) + // this.messageToWaitingPlayers(`[COPCHASE]: Игра начнется через: ${timeToStart}`) + }, 1000) + } + + stopGame({ winner }) { + + clearInterval(this.timeRemainingInterval) + + this.players.forEach(_player => { + // if (this.blips[_player.id]) { + // this.blips[_player.id].destroy(); + // } + + + _player.removeAllWeapons() + + alt.setTimeout(() => { + _player.spawn(config.spawn.x, config.spawn.y,config.spawn.z) + _player.dimension = 0 + alt.emitClient(_player, 'player:setInvincible') + }, 5000) + + }) + + if (winner === 'police') { + this.players.forEach(_player => { + if (_player.name !== this.suspect.name) { + alt.emitClient(_player, 'player:showMidsizedMessage', '~g~Вы выиграли', 'Саспект был нейтрализован.') + } + }) + console.log(`[COPCHASE]: Игра закончилась! Саспект был нейтрализован.`) + } + + if (winner === 'suspect') { + this.players.forEach(_player => { + if (_player.name === this.suspect.name) { + alt.emitClient(_player, 'player:showMidsizedMessage', '~g~Вы выиграли', 'Вы успешно ушли от полиции.') + } else { + alt.emitClient(_player, 'player:showMidsizedMessage', '~r~Вы проиграли', 'Саспект скрылся.') + } + }) + console.log(`[COPCHASE]: Игра закончилась! Саспект скрылся.`) + } + + this.setDefaultState() + } + +} + +const copchase = new Copchase({ + dimension: 10, + waitingRoomDimension: 5, + maxPlayers: 11, + minPlayers: 2, + timeRemaining: 2, + timeToStart: 5 +}) + +export { + copchase +} \ No newline at end of file diff --git a/server/modules/events/playerDeath.mjs b/server/modules/events/playerDeath.mjs index ae2d2d8..2da34eb 100644 --- a/server/modules/events/playerDeath.mjs +++ b/server/modules/events/playerDeath.mjs @@ -1,10 +1,20 @@ import alt from 'alt-server' +import { copchase } from '../copchase.mjs' import config from '../../config.mjs' alt.on('playerDeath', (player) => { alt.emitClient(player, 'player:death') alt.Player.all.forEach(_player => alt.emitClient(_player, 'player:notify', `Игрок ${player.name} погиб`)) + + if (copchase.isStarted) { + if (player.name === copchase.suspect.name) copchase.stopGame({ winner: 'police' }) + + const policemanIndex = copchase.players.findIndex(_player => _player.name === player.name && _player.name !== copchase.suspect.name) + if (policemanIndex !== -1) copchase.players.splice(policemanIndex, 1) + if (copchase.players.length <= 1 && copchase.suspect !== null) copchase.stopGame({ winner: 'suspect' }) + } + alt.setTimeout(() => { player.spawn(config.spawn.x, config.spawn.y,config.spawn.z) player.removeAllWeapons() diff --git a/server/modules/events/playerDisconnect.mjs b/server/modules/events/playerDisconnect.mjs index 7512b18..7acd001 100644 --- a/server/modules/events/playerDisconnect.mjs +++ b/server/modules/events/playerDisconnect.mjs @@ -1,6 +1,25 @@ import alt from 'alt-server' import { broadcast } from 'chat' +import { copchase } from '../copchase.mjs' alt.on('playerDisconnect', (player) => { broadcast(`{EE9A00}[SERVER]: {1CD8FD}😭 ${player.name} {FFF}покинул нас`) + + if (copchase.isPlayerInWaitingRoom(player)) { + const disconnectedPlayerIndex = copchase.waitingPlayers.findIndex(_player => _player.name === player.name) + copchase.waitingPlayers.splice(disconnectedPlayerIndex, 1) + } + + if (copchase.isStarted) { + if (player.name === copchase.suspect.name) { + const suspectIndex = copchase.players.findIndex(_player => _player.name === copchase.suspect.name) + copchase.players.splice(suspectIndex, 1) + copchase.stopGame({ winner: 'police' }) + } + + const policemanIndex = copchase.players.findIndex(_player => _player.name === player.name && _player.name !== copchase.suspect.name) + + if (policemanIndex !== -1) copchase.players.splice(policemanIndex, 1) + if (copchase.players.length <= 1 && copchase.suspect !== null) copchase.stopGame({ winner: 'suspect' }) + } }) \ No newline at end of file diff --git a/server/modules/events/playerLeftVehicle.mjs b/server/modules/events/playerLeftVehicle.mjs new file mode 100644 index 0000000..ab47dc8 --- /dev/null +++ b/server/modules/events/playerLeftVehicle.mjs @@ -0,0 +1,14 @@ +import alt from 'alt-server' +import { copchase } from '../copchase.mjs' + +alt.on('playerLeftVehicle', player => { + if (copchase.isStarted && player.name === copchase.suspect.name) { + player.giveWeapon('0x1B06D571', 25, true); + + copchase.players.forEach(_player => { + if (_player.name !== copchase.suspect.name) { + _player.giveWeapon('0x1B06D571', 50, true); + } + }) + } +}) \ No newline at end of file diff --git a/server/modules/events/ui/admin/spawnCar.mjs b/server/modules/events/ui/admin/spawnCar.mjs index da71a84..980a31a 100644 --- a/server/modules/events/ui/admin/spawnCar.mjs +++ b/server/modules/events/ui/admin/spawnCar.mjs @@ -8,6 +8,7 @@ alt.onClient('spawnCar', (player, carRef) => { try { const newVehicle = new alt.Vehicle(carRef, player.pos.x, player.pos.y, player.pos.z, 0, 0, 0) newVehicle.numberPlateText = 'ADMIN' + newVehicle.dimension = player.dimension alt.emitClient(player, 'vehicle:setInto', newVehicle) } catch (error) {