mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-02-09 10:20:16 +01:00
basic penalty backend implemented
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { isInCircle } from "./map_utils.js";
|
import { isInCircle } from "./map_utils.js";
|
||||||
import { ZoneManager } from "./zone_manager.js";
|
import { ZoneManager } from "./zone_manager.js";
|
||||||
|
|
||||||
const GameState = {
|
export const GameState = {
|
||||||
SETUP: "setup",
|
SETUP: "setup",
|
||||||
PLACEMENT: "placement",
|
PLACEMENT: "placement",
|
||||||
PLAYING: "playing",
|
PLAYING: "playing",
|
||||||
@@ -10,8 +10,6 @@ const GameState = {
|
|||||||
|
|
||||||
export default class Game {
|
export default class Game {
|
||||||
constructor(onUpdateZone,onUpdateNewZone) {
|
constructor(onUpdateZone,onUpdateNewZone) {
|
||||||
//Number of penalties needed to be eliminated
|
|
||||||
this.MAX_PENALTIES = 3;
|
|
||||||
this.teams = [];
|
this.teams = [];
|
||||||
this.state = GameState.SETUP;
|
this.state = GameState.SETUP;
|
||||||
this.zone = new ZoneManager(onUpdateZone, onUpdateNewZone)
|
this.zone = new ZoneManager(onUpdateZone, onUpdateNewZone)
|
||||||
@@ -58,6 +56,7 @@ export default class Game {
|
|||||||
chased: null,
|
chased: null,
|
||||||
currentLocation: null,
|
currentLocation: null,
|
||||||
lastSentLocation: null,
|
lastSentLocation: null,
|
||||||
|
lastSentLocationDate: null,
|
||||||
enemyLocation: null,
|
enemyLocation: null,
|
||||||
captureCode: this.createCaptureCode(),
|
captureCode: this.createCaptureCode(),
|
||||||
sockets: [],
|
sockets: [],
|
||||||
@@ -70,8 +69,18 @@ export default class Game {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playingTeamCount() {
|
||||||
|
let res = 0;
|
||||||
|
this.teams.forEach((t) => {
|
||||||
|
if(!t.captured) {
|
||||||
|
res++;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
updateTeamChasing() {
|
updateTeamChasing() {
|
||||||
if(this.teams.length <= 1) {
|
if(this.playingTeamCount() <= 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let firstTeam = null;
|
let firstTeam = null;
|
||||||
@@ -139,8 +148,11 @@ export default class Game {
|
|||||||
if(team == undefined) {
|
if(team == undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
team.lastSentLocationDate = new Date();
|
||||||
team.lastSentLocation = team.currentLocation;
|
team.lastSentLocation = team.currentLocation;
|
||||||
|
if(this.getTeam(team.chasing) != null) {
|
||||||
team.enemyLocation = this.getTeam(team.chasing).lastSentLocation;
|
team.enemyLocation = this.getTeam(team.chasing).lastSentLocation;
|
||||||
|
}
|
||||||
return team;
|
return team;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { config } from "dotenv";
|
|||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import { initAdminSocketHandler, secureAdminBroadcast } from "./admin_socket.js";
|
import { initAdminSocketHandler, secureAdminBroadcast } from "./admin_socket.js";
|
||||||
import { initTeamSocket, playersBroadcast } from "./team_socket.js";
|
import { initTeamSocket, playersBroadcast } from "./team_socket.js";
|
||||||
|
import { PenaltyController } from "./penalty_controller.js";
|
||||||
//extract admin password from .env file
|
//extract admin password from .env file
|
||||||
config();
|
config();
|
||||||
const HOST = process.env.HOST;
|
const HOST = process.env.HOST;
|
||||||
@@ -41,6 +42,8 @@ function onUpdateZone(zone) {
|
|||||||
|
|
||||||
|
|
||||||
export const game = new Game(onUpdateZone, onUpdateNewZone);
|
export const game = new Game(onUpdateZone, onUpdateNewZone);
|
||||||
|
const penaltyController = new PenaltyController(game);
|
||||||
|
penaltyController.init()
|
||||||
|
|
||||||
|
|
||||||
initAdminSocketHandler();
|
initAdminSocketHandler();
|
||||||
|
|||||||
@@ -1,27 +1,92 @@
|
|||||||
import { game } from ".";
|
import { config } from "dotenv";
|
||||||
import { sendUpdatedTeamInformations, teamBroadcast } from "./team_socket";
|
import { getDistanceFromLatLon, isInCircle } from "./map_utils.js";
|
||||||
|
import { sendUpdatedTeamInformations, teamBroadcast } from "./team_socket.js";
|
||||||
|
import { GameState } from "./game.js";
|
||||||
|
config()
|
||||||
|
|
||||||
export class PenaltyController {
|
export class PenaltyController {
|
||||||
constructor(game) {
|
constructor(game) {
|
||||||
|
//Number of penalties needed to be eliminated
|
||||||
|
this.game = game;
|
||||||
|
this.outOfBoundsSince = {};
|
||||||
|
this.checkIntervalId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.outOfBoundsSince = {};
|
||||||
|
if(this.checkIntervalId) {
|
||||||
|
clearInterval(this.checkIntervalId)
|
||||||
|
}
|
||||||
|
//Watch periodically if all teams need are following the rules
|
||||||
|
this.checkIntervalId = setInterval(() => {
|
||||||
|
if(this.game.state == GameState.PLAYING) {
|
||||||
|
this.watchPositionUpdate();
|
||||||
|
this.watchZone();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the penalty score of a team, send a message to the team and eliminated if necessary
|
||||||
|
* @param {Number} teamId The team that will recieve a penalty
|
||||||
|
*/
|
||||||
addPenalty(teamId) {
|
addPenalty(teamId) {
|
||||||
let team = game.getTeam(teamId);
|
let team = this.game.getTeam(teamId);
|
||||||
if(team.captured) {
|
if (team.captured) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
team.penalties++;
|
team.penalties++;
|
||||||
if(team.penalties == game.MAX_PENALTIES) {
|
if (team.penalties >= process.env.MAX_PENALTIES) {
|
||||||
game.requestCapture(team.chased);
|
this.game.capture(team.id);
|
||||||
sendUpdatedTeamInformations(teamId);
|
sendUpdatedTeamInformations(teamId);
|
||||||
sendUpdatedTeamInformations(team.chased);
|
sendUpdatedTeamInformations(team.chased);
|
||||||
teamBroadcast(teamId, "warning", "You have been eliminated (reason: too many penalties)")
|
teamBroadcast(teamId, "warning", "You have been eliminated (reason: too many penalties)")
|
||||||
teamBroadcast(team.chased, "success", "The team you are chasing has changed")
|
teamBroadcast(team.chased, "success", "The team you were chasing has been eliminated")
|
||||||
|
} else {
|
||||||
|
teamBroadcast(teamId, "warning", `You recieved a penalty (${team.penalties}/${process.env.MAX_PENALTIES})`)
|
||||||
|
sendUpdatedTeamInformations(teamId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watchZone() {
|
watchZone() {
|
||||||
|
this.game.teams.forEach((team) => {
|
||||||
|
if (team.captured) { return }
|
||||||
|
//All the informations are not ready yet
|
||||||
|
if(team.currentLocation == null || this.game.zone.currentZone == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isInCircle({lat: team.currentLocation[0], lng: team.currentLocation[1]}, this.game.zone.currentZone.center, this.game.zone.currentZone.radius)) {
|
||||||
|
//The team was not previously out of the zone
|
||||||
|
if (!this.outOfBoundsSince[team.id]) {
|
||||||
|
this.outOfBoundsSince[team.id] = new Date();
|
||||||
|
teamBroadcast(team.id, "warning", `You left the zone, you have ${process.env.ALLOWED_TIME_OUT_OF_ZONE_IN_MINUTES} minutes to get back in the marked area.`)
|
||||||
|
} else {
|
||||||
|
if (new Date() - this.outOfBoundsSince[team.id] > process.env.ALLOWED_TIME_OUT_OF_ZONE_IN_MINUTES * 60 * 1000) {
|
||||||
|
this.addPenalty(team.id)
|
||||||
|
this.outOfBoundsSince[team.id] = new Date();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.outOfBoundsSince[team.id]) {
|
||||||
|
delete this.outOfBoundsSince[team.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watchPositionUpdate() {
|
||||||
|
this.game.teams.forEach((team) => {
|
||||||
|
//If the team has not sent their location for more than the allowed period, automatically send it and add a penalty
|
||||||
|
if (team.captured) { return }
|
||||||
|
if(team.lastSentLocationDate == null) {
|
||||||
|
team.lastSentLocationDate = new Date();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (new Date() - team.lastSentLocationDate > process.env.ALLOWED_TIME_BETWEEN_POSITION_UPDATE_IN_MINUTES * 60 * 1000) {
|
||||||
|
this.addPenalty(team.id);
|
||||||
|
this.game.sendLocation(team.id);
|
||||||
|
sendUpdatedTeamInformations(team.id);
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,4 +5,6 @@ HOST = '10.192.64.61'
|
|||||||
PORT = 3001
|
PORT = 3001
|
||||||
SSL_KEY = "key.pem"
|
SSL_KEY = "key.pem"
|
||||||
SSL_CERT = "server.crt"
|
SSL_CERT = "server.crt"
|
||||||
|
ALLOWED_TIME_OUT_OF_ZONE_IN_MINUTES = 0.1
|
||||||
|
ALLOWED_TIME_BETWEEN_POSITION_UPDATE_IN_MINUTES = 1
|
||||||
```
|
```
|
||||||
@@ -42,10 +42,12 @@ export function sendUpdatedTeamInformations(teamId) {
|
|||||||
enemyLocation: team.enemyLocation,
|
enemyLocation: team.enemyLocation,
|
||||||
currentLocation: team.currentLocation,
|
currentLocation: team.currentLocation,
|
||||||
lastSentLocation: team.lastSentLocation,
|
lastSentLocation: team.lastSentLocation,
|
||||||
|
lastSentLocationDate: team.lastSentLocationDate,
|
||||||
captureCode: team.captureCode,
|
captureCode: team.captureCode,
|
||||||
startingArea: team.startingArea,
|
startingArea: team.startingArea,
|
||||||
ready: team.ready,
|
ready: team.ready,
|
||||||
captured: team.captured
|
captured: team.captured,
|
||||||
|
penalties: team.penalties,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ export class ZoneManager {
|
|||||||
this.nextZoneTimeoutId = setTimeout(() => this.startShrinking(), 1000 * 60 * this.zoneSettings.reductionInterval)
|
this.nextZoneTimeoutId = setTimeout(() => this.startShrinking(), 1000 * 60 * this.zoneSettings.reductionInterval)
|
||||||
this.currentZoneCount++;
|
this.currentZoneCount++;
|
||||||
}
|
}
|
||||||
|
this.onZoneUpdate(JSON.parse(JSON.stringify(this.currentStartZone)))
|
||||||
this.onNextZoneUpdate({
|
this.onNextZoneUpdate({
|
||||||
begin: JSON.parse(JSON.stringify(this.currentStartZone)),
|
begin: JSON.parse(JSON.stringify(this.currentStartZone)),
|
||||||
end: JSON.parse(JSON.stringify(this.nextZone))
|
end: JSON.parse(JSON.stringify(this.nextZone))
|
||||||
|
|||||||
Reference in New Issue
Block a user