mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-02-09 02:10:18 +01:00
Corrections + admin full screen
This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
- [x] Refaire les flèches de chasse sur la map
|
||||
- [x] Pouvoir définir la zone de départ de chaque équipe
|
||||
- [x] Nommer les polygons par des lettres de l'alphabet
|
||||
- [ ] Plein écran
|
||||
- [x] Plein écran
|
||||
- [ ] Pouvoir faire pause dans la partie
|
||||
- [ ] Mettre en évidence le menu paramètre
|
||||
- [ ] Afficher un feedback quand un paramètre est sauvegardé
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function Display() {
|
||||
|
||||
// Activating geolocation tracking
|
||||
useEffect(() => {
|
||||
if (loggedIn && (gameState == GameState.SETUP || gameState == GameState.PLAYING || gameState == GameState.PLACEMENT) && !captured) {
|
||||
if (loggedIn) {
|
||||
startLocationTracking();
|
||||
} else {
|
||||
stopLocationTracking();
|
||||
@@ -89,8 +89,9 @@ export default function Display() {
|
||||
|
||||
// Update the average speed
|
||||
useEffect(() => {
|
||||
const time = finishDate ? (finishDate - startDate) : timeSinceStart;
|
||||
setAvgSpeed(distance/time);
|
||||
const hours = (finishDate ? (finishDate - startDate) : timeSinceStart*1000) / 1000 / 3600;
|
||||
const km = distance / 1000;
|
||||
setAvgSpeed(Math.floor(km / hours * 10) / 10);
|
||||
}, [distance, finishDate, timeSinceStart]);
|
||||
|
||||
function toggleCollapsible() {
|
||||
@@ -172,11 +173,11 @@ export default function Display() {
|
||||
const GameLog = () => {
|
||||
return (
|
||||
<TouchableOpacity style={{width:"100%"}}>
|
||||
{ gameState == GameState.SETUP && <Text style={styles.gameState}>Préparation de la partie</Text>}
|
||||
{ gameState == GameState.SETUP && <Text style={styles.gameState}>{messages?.waiting || "Préparation de la partie"}</Text>}
|
||||
{ gameState == GameState.PLACEMENT && <Text style={styles.gameState}>Phase de placement</Text>}
|
||||
{ gameState == GameState.PLAYING && !outOfZone && <Text style={styles.gameState}>La partie est en cours</Text>}
|
||||
{ gameState == GameState.PLAYING && outOfZone && !hasHandicap && <Text style={styles.gameStateOutOfZone}>Hors zone (handicap dans {formatTimeMinutes(-timeLeftOutOfZone)})</Text>}
|
||||
{ gameState == GameState.PLAYING && hasHandicap && <Text style={styles.gameStateOutOfZone}>Hors zone (position révélée en continue)</Text>}
|
||||
{ gameState == GameState.PLAYING && outOfZone && !hasHandicap && <Text style={styles.gameStateOutOfZone}>{`Veuillez retourner dans la zone\nHandicap dans ${formatTimeMinutes(-timeLeftOutOfZone)}`}</Text>}
|
||||
{ gameState == GameState.PLAYING && hasHandicap && <Text style={styles.gameStateOutOfZone}>{`Veuillez retourner dans la zone\nVotre position est révélée en continue`}</Text>}
|
||||
{ gameState == GameState.FINISHED && <Text style={styles.gameState}>La partie est terminée</Text>}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
@@ -243,44 +244,34 @@ export default function Display() {
|
||||
const Zones = () => {
|
||||
const latToLatitude = (pos) => ({latitude: pos.lat, longitude: pos.lng});
|
||||
|
||||
switch (zoneType) {
|
||||
case zoneTypes.circle:
|
||||
return (
|
||||
<Fragment>
|
||||
{ zoneExtremities.begin && <Circle center={latToLatitude(zoneExtremities.begin.center)} radius={zoneExtremities.begin.radius} strokeColor="red" fillColor="rgba(255,0,0,0.1)" strokeWidth={2} />}
|
||||
{ zoneExtremities.end && <Circle center={latToLatitude(zoneExtremities.end.center)} radius={zoneExtremities.end.radius} strokeColor="green" fillColor="rgba(0,255,0,0.1)" strokeWidth={2} />}
|
||||
{ zoneType == zoneTypes.circle && zoneExtremities.begin && <Circle center={latToLatitude(zoneExtremities.begin.center)} radius={zoneExtremities.begin.radius} strokeColor="red" fillColor="rgba(255,0,0,0.1)" strokeWidth={2} />}
|
||||
{ zoneType == zoneTypes.circle && zoneExtremities.end && <Circle center={latToLatitude(zoneExtremities.end.center)} radius={zoneExtremities.end.radius} strokeColor="green" fillColor="rgba(0,255,0,0.1)" strokeWidth={2} />}
|
||||
{ zoneType == zoneTypes.polygon && zoneExtremities.begin && <Polygon coordinates={zoneExtremities.begin.polygon.map(pos => latToLatitude(pos))} strokeColor="red" fillColor="rgba(255,0,0,0.1)" strokeWidth={2} /> }
|
||||
{ zoneType == zoneTypes.polygon && zoneExtremities.end && <Polygon coordinates={zoneExtremities.end.polygon.map(pos => latToLatitude(pos))} strokeColor="green" fillColor="rgba(0,255,0,0.1)" strokeWidth={2} /> }
|
||||
</Fragment>
|
||||
);
|
||||
case zoneTypes.polygon:
|
||||
return (
|
||||
<Fragment>
|
||||
{ zoneExtremities.begin && <Polygon coordinates={zoneExtremities.begin.polygon.map(pos => latToLatitude(pos))} strokeColor="red" fillColor="rgba(255,0,0,0.1)" strokeWidth={2} /> }
|
||||
{ zoneExtremities.end && <Polygon coordinates={zoneExtremities.end.polygon.map(pos => latToLatitude(pos))} strokeColor="green" fillColor="rgba(0,255,0,0.1)" strokeWidth={2} /> }
|
||||
</Fragment>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const Map = () => {
|
||||
return (
|
||||
<MapView ref={mapRef} style={{flex: 1}} initialRegion={initialRegion} mapType="standard" onTouchMove={() => setCenterMap(false)}>
|
||||
<MapView ref={mapRef} style={{flex: 1}} initialRegion={initialRegion} mapType="standard" onTouchMove={() => setCenterMap(false)} toolbarEnabled={false}>
|
||||
{ gameState == GameState.PLACEMENT && startingArea && circle("0, 0, 255", startingArea)}
|
||||
{ gameState == GameState.PLAYING && zoneExtremities && <Zones/>}
|
||||
{ location &&
|
||||
<Marker coordinate={{ latitude: location[0], longitude: location[1] }} anchor={{ x: 0.33, y: 0.33 }}>
|
||||
<Marker coordinate={{ latitude: location[0], longitude: location[1] }} anchor={{ x: 0.33, y: 0.33 }} onPress={() => Alert.alert("Position actuelle", "Ceci est votre position")}>
|
||||
<Image source={require("../assets/images/marker/blue.png")} style={{width: 24, height: 24}} resizeMode="contain"/>
|
||||
</Marker>
|
||||
}
|
||||
{ gameState == GameState.PLAYING && lastSentLocation && !hasHandicap &&
|
||||
<Marker coordinate={{ latitude: lastSentLocation[0], longitude: lastSentLocation[1] }} anchor={{ x: 0.33, y: 0.33 }}>
|
||||
<Marker coordinate={{ latitude: lastSentLocation[0], longitude: lastSentLocation[1] }} anchor={{ x: 0.33, y: 0.33 }} onPress={() => Alert.alert("Position envoyée", "Ceci est votre dernière position connue par le serveur")}>
|
||||
<Image source={require("../assets/images/marker/grey.png")} style={{width: 24, height: 24}} resizeMode="contain"/>
|
||||
</Marker>
|
||||
}
|
||||
{ gameState == GameState.PLAYING && enemyLocation && !hasHandicap &&
|
||||
<Marker coordinate={{ latitude: enemyLocation[0], longitude: enemyLocation[1] }} anchor={{ x: 0.33, y: 0.33 }}>
|
||||
<Image source={require("../assets/images/marker/red.png")} style={{width: 24, height: 24}} resizeMode="contain"/>
|
||||
<Image source={require("../assets/images/marker/red.png")} style={{width: 24, height: 24}} resizeMode="contain" onPress={() => Alert.alert("Position ennemie", "Ceci est la dernière position de vos ennemis connue")}/>
|
||||
</Marker>
|
||||
}
|
||||
</MapView>
|
||||
@@ -329,7 +320,6 @@ export default function Display() {
|
||||
return (
|
||||
<View style={styles.imageContainer}>
|
||||
{<Text style={{fontSize: 15, margin: 5}}>{"Cible (" + (enemyName ?? "Indisponible") + ")"}</Text>}
|
||||
{enemyHasHandicap && <Text style={{fontSize: 15, margin: 5}}>Position ennemie révélée en continue</Text>}
|
||||
{<CustomImage source={{ uri : enemyImageURI }} canZoom/>}
|
||||
</View>
|
||||
);
|
||||
@@ -357,9 +347,9 @@ export default function Display() {
|
||||
return (
|
||||
<View style={{gap: 15, width: "100%", marginVertical: 15}}>
|
||||
<View style={{flexDirection: "row", justifyContent: "space-around"}}>
|
||||
<Stat source={require('../assets/images/distance.png')} description={"Distance parcourue"}>{(distance / 1000).toFixed(1)}km</Stat>
|
||||
<Stat source={require('../assets/images/distance.png')} description={"Distance parcourue"}>{Math.floor(distance / 100) / 10}km</Stat>
|
||||
<Stat source={require('../assets/images/time.png')} description={"Temps écoulé au format HH:MM:SS"}>{formatTimeHours((finishDate ? Math.floor((finishDate - startDate) / 1000) : timeSinceStart))}</Stat>
|
||||
<Stat source={require('../assets/images/running.png')} description={"Vitesse moyenne"}>{(avgSpeed*3.6).toFixed(1)}km/h</Stat>
|
||||
<Stat source={require('../assets/images/running.png')} description={"Vitesse moyenne"}>{avgSpeed}km/h</Stat>
|
||||
</View>
|
||||
<View style={{flexDirection: "row", justifyContent: "space-around"}}>
|
||||
<Stat source={require('../assets/images/target/black.png')} description={"Nombre total de captures par votre équipe"}>{nCaptures}</Stat>
|
||||
@@ -394,6 +384,7 @@ export default function Display() {
|
||||
{ gameState == GameState.FINISHED &&
|
||||
EndGameMessage()
|
||||
}
|
||||
{enemyHasHandicap && <Text style={{fontSize: 18, marginTop: 6, fontWeight: "bold"}}>Position ennemie révélée en continue !</Text>}
|
||||
</View>
|
||||
<View style={styles.bottomContainer} onLayout={(event) => {setBottomContainerHeight(event.nativeEvent.layout.height)}}>
|
||||
<View style={styles.mapContainer}>
|
||||
@@ -411,15 +402,15 @@ export default function Display() {
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
{ gameState == GameState.PLAYING && !captured &&
|
||||
{ (gameState == GameState.PLAYING || gameState == GameState.FINISHED) &&
|
||||
<View style={styles.outerDrawerContainer}>
|
||||
<LinearGradient colors={['rgba(0,0,0,0)', 'rgba(0,0,0,0.5)']} style={{height: 70, width: "100%", position: "absolute", top: -30}}/>
|
||||
<View style={styles.innerDrawerContainer}>
|
||||
{ CollapsibleButton() }
|
||||
<Collapsible style={[styles.collapsibleWindow, {height: bottomContainerHeight - 44}]} title="Collapse" collapsed={collapsibleState}>
|
||||
<ScrollView contentContainerStyle={styles.collapsibleContent}>
|
||||
{ TeamCaptureCode() }
|
||||
{ !hasHandicap && <Fragment>
|
||||
{ gameState == GameState.PLAYING && TeamCaptureCode() }
|
||||
{ gameState == GameState.PLAYING && !hasHandicap && <Fragment>
|
||||
{ ChasedTeamImage() }
|
||||
<View style={styles.actionsContainer}>
|
||||
{ CaptureCode() }
|
||||
@@ -468,7 +459,7 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 10,
|
||||
width: "100%",
|
||||
backgroundColor: 'white',
|
||||
fontSize: 20,
|
||||
fontSize: 18,
|
||||
padding: 10,
|
||||
},
|
||||
gameStateOutOfZone: {
|
||||
@@ -476,7 +467,7 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 10,
|
||||
width: "100%",
|
||||
backgroundColor: 'white',
|
||||
fontSize: 20,
|
||||
fontSize: 18,
|
||||
padding: 10,
|
||||
borderColor: 'red'
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createContext, useContext, useMemo } from "react";
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const HOST = '192.168.15.129'; // IP of the machine hosting the server
|
||||
const HOST = 'traque.rezel.net'; // IP of the machine hosting the server
|
||||
|
||||
const SOCKET_URL = (HOST == "traque.rezel.net" ? "wss://" : "ws://") + HOST + "/player";
|
||||
const SERVER_URL = (HOST == "traque.rezel.net" ? "https://" : "http://") + HOST + "/back";
|
||||
|
||||
@@ -8,11 +8,6 @@ import { useTeamConnexion } from "./teamConnexionContext";
|
||||
|
||||
const teamContext = createContext();
|
||||
|
||||
const zoneTypes = {
|
||||
circle: "circle",
|
||||
polygon: "polygon"
|
||||
}
|
||||
|
||||
function TeamProvider({children}) {
|
||||
const {teamSocket} = useSocket();
|
||||
const [location, getLocationAuthorization, startLocationTracking, stopLocationTracking] = useLocation(5000, 10);
|
||||
|
||||
@@ -50,14 +50,15 @@ export function initAdminSocketHandler() {
|
||||
socket.emit("teams", game.teams);
|
||||
socket.emit("game_state", {
|
||||
state: game.state,
|
||||
date: game.stateDate
|
||||
date: game.startDate
|
||||
});
|
||||
socket.emit("current_zone", {
|
||||
begin: zoneManager.getCurrentZone(),
|
||||
end: zoneManager.getNextZone(),
|
||||
endDate: zoneManager.currentZone.endDate,
|
||||
endDate: zoneManager.currentZone?.endDate,
|
||||
});
|
||||
socket.emit("settings", game.getAdminSettings());
|
||||
socket.emit("login_response", true);
|
||||
});
|
||||
|
||||
socket.on("add_team", (teamName) => {
|
||||
@@ -77,7 +78,7 @@ export function initAdminSocketHandler() {
|
||||
|
||||
socket.on("capture_team", (teamId) => {
|
||||
if (!loggedIn) return;
|
||||
game.captureTeam(teamId);
|
||||
game.switchCapturedTeam(teamId);
|
||||
});
|
||||
|
||||
socket.on("placement_team", (teamId, placementZone) => {
|
||||
|
||||
@@ -40,7 +40,7 @@ export default {
|
||||
// Current state of the game
|
||||
state: GameState.SETUP,
|
||||
// Date since the state changed
|
||||
stateDate: Date.now(),
|
||||
startDate: null,
|
||||
// Messages
|
||||
messages: {
|
||||
waiting: "",
|
||||
@@ -84,7 +84,7 @@ export default {
|
||||
}
|
||||
// Update of enemyLocation now we have the lastSentLocation of the enemy
|
||||
for (const team of this.teams) {
|
||||
team.enemyLocation = this.getTeam(team.chasing).lastSentLocation;
|
||||
team.enemyLocation = this.getTeam(team.chasing)?.lastSentLocation;
|
||||
sendUpdatedTeamInformations(team.id);
|
||||
}
|
||||
// Broadcast new infos
|
||||
@@ -153,6 +153,7 @@ export default {
|
||||
|
||||
setState(newState) {
|
||||
const dateNow = Date.now();
|
||||
if (newState == this.state) return true;
|
||||
switch (newState) {
|
||||
case GameState.SETUP:
|
||||
trajectory.stop();
|
||||
@@ -160,29 +161,32 @@ export default {
|
||||
sendPositionTimeouts.clearAll();
|
||||
outOfZoneTimeouts.clearAll();
|
||||
this.resetTeamsInfos();
|
||||
this.startDate = null;
|
||||
break;
|
||||
case GameState.PLACEMENT:
|
||||
if (this.teams.length < 3) {
|
||||
secureAdminBroadcast("game_state", {state: this.state, date: this.stateDate});
|
||||
if (this.state == GameState.FINISHED || this.teams.length < 3) {
|
||||
secureAdminBroadcast("game_state", {state: this.state, date: this.startDate});
|
||||
return false;
|
||||
}
|
||||
trajectory.stop();
|
||||
zoneManager.stop();
|
||||
sendPositionTimeouts.clearAll();
|
||||
outOfZoneTimeouts.clearAll();
|
||||
this.startDate = null;
|
||||
break;
|
||||
case GameState.PLAYING:
|
||||
if (this.teams.length < 3) {
|
||||
secureAdminBroadcast("game_state", {state: this.state, date: this.stateDate});
|
||||
if (this.state == GameState.FINISHED || this.teams.length < 3) {
|
||||
secureAdminBroadcast("game_state", {state: this.state, date: this.startDate});
|
||||
return false;
|
||||
}
|
||||
trajectory.start();
|
||||
zoneManager.start();
|
||||
this.initLastSentLocations();
|
||||
this.startDate = dateNow;
|
||||
break;
|
||||
case GameState.FINISHED:
|
||||
if (this.state != GameState.PLAYING) {
|
||||
secureAdminBroadcast("game_state", {state: this.state, date: this.stateDate});
|
||||
secureAdminBroadcast("game_state", {state: this.state, date: this.startDate});
|
||||
return false;
|
||||
}
|
||||
trajectory.stop();
|
||||
@@ -195,10 +199,9 @@ export default {
|
||||
}
|
||||
// Update the state
|
||||
this.state = newState;
|
||||
this.stateDate = dateNow;
|
||||
// Broadcast new infos
|
||||
secureAdminBroadcast("game_state", {state: newState, date: this.stateDate});
|
||||
playersBroadcast("game_state", {state: newState, date: this.stateDate});
|
||||
secureAdminBroadcast("game_state", {state: newState, date: this.startDate});
|
||||
playersBroadcast("game_state", {state: newState, date: this.startDate});
|
||||
return true;
|
||||
},
|
||||
|
||||
@@ -257,7 +260,7 @@ export default {
|
||||
// Identification
|
||||
sockets: [],
|
||||
name: teamName,
|
||||
id: this.getNewTeamId(this.teams),
|
||||
id: this.getNewTeamId(),
|
||||
captureCode: randint(10_000),
|
||||
// Chasing
|
||||
captured: false,
|
||||
@@ -319,19 +322,28 @@ export default {
|
||||
return true;
|
||||
},
|
||||
|
||||
captureTeam(teamId) {
|
||||
switchCapturedTeam(teamId) {
|
||||
// Test of parameters
|
||||
if (!this.hasTeam(teamId)) return false;
|
||||
// Variables
|
||||
const team = this.getTeam(teamId);
|
||||
const dateNow = Date.now();
|
||||
// Make the capture
|
||||
// Switch team.captured
|
||||
if (this.state != GameState.PLAYING) return false;
|
||||
if (team.captured) {
|
||||
team.captured = false;
|
||||
team.finishDate = null;
|
||||
team.lastSentLocation = team.currentLocation;
|
||||
team.locationSendDeadline = dateNow + sendPositionTimeouts.delay * 60 * 1000;
|
||||
sendPositionTimeouts.set(team.id);
|
||||
} else {
|
||||
team.captured = true;
|
||||
team.finishDate = dateNow;
|
||||
team.chasing = null;
|
||||
team.chased = null;
|
||||
sendPositionTimeouts.clear(team.id);
|
||||
outOfZoneTimeouts.clear(team.id);
|
||||
}
|
||||
this.updateChasingChain();
|
||||
this.checkEndGame();
|
||||
// Broadcast new infos
|
||||
@@ -384,21 +396,24 @@ export default {
|
||||
updateLocation(teamId, location) {
|
||||
// Test of parameters
|
||||
if (!this.hasTeam(teamId)) return false;
|
||||
if (!this.hasTeam(this.getTeam(teamId).chasing)) return false;
|
||||
if (!location) return false;
|
||||
// Variables
|
||||
const team = this.getTeam(teamId);
|
||||
const enemyTeam = this.getTeam(team.chasing);
|
||||
const dateNow = Date.now();
|
||||
// Update distance
|
||||
if (team.currentLocation) team.distance += Math.floor(getDistanceFromLatLon({lat: location[0], lng: location[1]}, {lat: team.currentLocation[0], lng: team.currentLocation[1]}));
|
||||
if (this.state == GameState.PLAYING && team.currentLocation) {
|
||||
team.distance += Math.floor(getDistanceFromLatLon({lat: location[0], lng: location[1]}, {lat: team.currentLocation[0], lng: team.currentLocation[1]}));
|
||||
}
|
||||
// Update of currentLocation
|
||||
team.currentLocation = location;
|
||||
team.lastCurrentLocationDate = dateNow;
|
||||
if (team.hasHandicap) {
|
||||
if (this.state == GameState.PLAYING && team.hasHandicap) {
|
||||
team.lastSentLocation = team.currentLocation;
|
||||
}
|
||||
// Update of enemyLocation
|
||||
if (enemyTeam.hasHandicap) {
|
||||
if (this.state == GameState.PLAYING && enemyTeam.hasHandicap) {
|
||||
team.enemyLocation = enemyTeam.currentLocation;
|
||||
}
|
||||
// Update of ready
|
||||
@@ -406,6 +421,7 @@ export default {
|
||||
team.ready = isInCircle({ lat: location[0], lng: location[1] }, team.startingArea.center, team.startingArea.radius);
|
||||
}
|
||||
// Update out of zone
|
||||
if (this.state == GameState.PLAYING) {
|
||||
const teamCurrentlyOutOfZone = !zoneManager.isInZone({ lat: location[0], lng: location[1] })
|
||||
if (teamCurrentlyOutOfZone && !team.outOfZone) {
|
||||
team.outOfZone = true;
|
||||
@@ -421,6 +437,7 @@ export default {
|
||||
}
|
||||
outOfZoneTimeouts.clear(teamId);
|
||||
}
|
||||
}
|
||||
// Broadcast new infos
|
||||
secureAdminBroadcast("teams", this.teams);
|
||||
sendUpdatedTeamInformations(team.id);
|
||||
@@ -430,8 +447,11 @@ export default {
|
||||
},
|
||||
|
||||
sendLocation(teamId) {
|
||||
// Conditions
|
||||
if (this.state != GameState.PLAYING) return false;
|
||||
// Test of parameters
|
||||
if (!this.hasTeam(teamId)) return false;
|
||||
if (!this.hasTeam(this.getTeam(teamId).chasing)) return false;
|
||||
// Variables
|
||||
const team = this.getTeam(teamId);
|
||||
const enemyTeam = this.getTeam(team.chasing);
|
||||
@@ -454,8 +474,11 @@ export default {
|
||||
},
|
||||
|
||||
tryCapture(teamId, captureCode) {
|
||||
// Conditions
|
||||
if (this.state != GameState.PLAYING) return false;
|
||||
// Test of parameters
|
||||
if (!this.hasTeam(teamId)) return false;
|
||||
if (!this.hasTeam(this.getTeam(teamId).chasing)) return false;
|
||||
// Variables
|
||||
const team = this.getTeam(teamId);
|
||||
const enemyTeam = this.getTeam(team.chasing);
|
||||
|
||||
@@ -59,7 +59,6 @@ export function sendUpdatedTeamInformations(teamId) {
|
||||
distance: team.distance,
|
||||
nCaptures: team.nCaptures,
|
||||
nSentLocation: team.nSentLocation,
|
||||
stateDate: game.stateDate,
|
||||
finishDate: team.finishDate,
|
||||
});
|
||||
}
|
||||
@@ -99,12 +98,12 @@ export function initTeamSocket() {
|
||||
sendUpdatedTeamInformations(loginTeamId);
|
||||
socket.emit("game_state", {
|
||||
state: game.state,
|
||||
date: game.stateDate
|
||||
date: game.startDate
|
||||
});
|
||||
socket.emit("current_zone", {
|
||||
begin: zoneManager.getCurrentZone(),
|
||||
end: zoneManager.getNextZone(),
|
||||
endDate: zoneManager.currentZone.endDate,
|
||||
endDate: zoneManager.currentZone?.endDate,
|
||||
});
|
||||
socket.emit("settings", game.getPlayerSettings());
|
||||
callback({ isLoggedIn : true, message: "Logged in"});
|
||||
|
||||
21
traque-back/trajectories/367440.txt
Normal file
21
traque-back/trajectories/367440.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
1758151340243,position,48.7119647,2.202376
|
||||
1758151348183,position,48.7119684,2.2023519
|
||||
1758151356935,position,48.7119613,2.2023486
|
||||
1758151364187,position,48.7119464,2.2023686
|
||||
1758151372354,position,48.7119567,2.2023589
|
||||
1758151380901,position,48.7119705,2.2023828
|
||||
1758151388892,position,48.7119695,2.2023512
|
||||
1758151397527,position,48.7119742,2.2023338
|
||||
1758151405867,position,48.7119592,2.2023596
|
||||
1758151414004,position,48.7119691,2.2023728
|
||||
1758151424855,position,48.7119702,2.2023816
|
||||
1758151430282,position,48.7119739,2.2023721
|
||||
1758151438203,position,48.7119633,2.2023841
|
||||
1758151446373,position,48.7119647,2.2023806
|
||||
1758151454699,position,48.7119593,2.2023871
|
||||
1758151462553,position,48.7119616,2.2023903
|
||||
1758151470342,position,48.7119594,2.2023859
|
||||
1758151478473,position,48.7119605,2.2023748
|
||||
1758151486112,position,48.7119559,2.2023561
|
||||
1758151494133,position,48.7119617,2.2023674
|
||||
1758151502319,position,48.7119549,2.2023335
|
||||
@@ -173,21 +173,25 @@ function polygonSettingsToZones(settings) {
|
||||
export default {
|
||||
isRunning: false,
|
||||
zones: [], // A zone has to be connected space that doesn't contain an earth pole
|
||||
currentZone: { id: 0, timeoutId: null, endDate: null },
|
||||
currentZone: null,
|
||||
settings: defaultPolygonSettings,
|
||||
|
||||
start() {
|
||||
if (this.isRunning) return;
|
||||
this.isRunning = true;
|
||||
this.currentZone.id = -1;
|
||||
this.currentZone = { id: -1, timeoutId: null, endDate: null };
|
||||
this.goNextZone();
|
||||
},
|
||||
|
||||
stop() {
|
||||
this.isRunning = false;
|
||||
if (!this.isRunning) return;
|
||||
clearTimeout(this.currentZone.timeoutId);
|
||||
this.isRunning = false;
|
||||
this.currentZone = null;
|
||||
},
|
||||
|
||||
goNextZone() {
|
||||
if (!this.isRunning) return;
|
||||
this.currentZone.id++;
|
||||
if (this.currentZone.id >= this.zones.length - 1) {
|
||||
this.currentZone.endDate = Date.now();
|
||||
@@ -199,10 +203,12 @@ export default {
|
||||
},
|
||||
|
||||
getCurrentZone() {
|
||||
if (!this.isRunning) return null;
|
||||
return this.zones[this.currentZone.id];
|
||||
},
|
||||
|
||||
getNextZone() {
|
||||
if (!this.isRunning) return null;
|
||||
if (this.currentZone.id + 1 < this.zones.length) {
|
||||
return this.zones[this.currentZone.id + 1];
|
||||
} else {
|
||||
@@ -211,6 +217,7 @@ export default {
|
||||
},
|
||||
|
||||
isInZone(location) {
|
||||
if (!this.isRunning) return false;
|
||||
if (this.zones.length == 0) {
|
||||
return true;
|
||||
} else {
|
||||
@@ -227,13 +234,17 @@ export default {
|
||||
this.zones = polygonSettingsToZones(settings);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
this.zones = [];
|
||||
break;
|
||||
}
|
||||
this.settings = settings;
|
||||
this.stop();
|
||||
this.start();
|
||||
this.zoneBroadcast();
|
||||
},
|
||||
|
||||
zoneBroadcast() {
|
||||
if (!this.isRunning) return;
|
||||
const zone = {
|
||||
begin: this.getCurrentZone(),
|
||||
end: this.getNextZone(),
|
||||
|
||||
@@ -8,6 +8,8 @@ import { mapZooms } from "@/util/configurations";
|
||||
export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsFocusing, mapStyle, showZones, showNames, showArrows }) {
|
||||
const { zoneType, zoneExtremities, teams, nextZoneDate, getTeam, gameState } = useAdmin();
|
||||
const [timeLeftNextZone, setTimeLeftNextZone] = useState(null);
|
||||
const [isFullScreen, setIsFullScreen] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (nextZoneDate) {
|
||||
@@ -50,8 +52,7 @@ export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsF
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='h-full w-full flex flex-col'>
|
||||
{gameState == GameState.PLAYING && <p>{`Next zone in : ${formatTime(timeLeftNextZone)}`}</p>}
|
||||
<div className={`${isFullScreen ? "fixed inset-0 z-[9999]" : "relative h-full w-full"}`}>
|
||||
<CustomMapContainer mapStyle={mapStyle}>
|
||||
{isFocusing && <MapPan center={getTeam(selectedTeamId)?.currentLocation} zoom={mapZooms.high} animate />}
|
||||
<MapEventListener onDragStart={() => setIsFocusing(false)}/>
|
||||
@@ -60,12 +61,21 @@ export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsF
|
||||
<CircleZone circle={team.startingArea} color="blue" display={gameState == GameState.PLACEMENT && showZones}>
|
||||
<Tag text={team.name} display={showNames} />
|
||||
</CircleZone>
|
||||
<Arrow pos1={team.currentLocation} pos2={getTeam(team.chased)?.currentLocation} display={showArrows}/>
|
||||
<Arrow pos1={team.currentLocation} pos2={getTeam(team.chasing)?.currentLocation} display={showArrows}/>
|
||||
<Position position={team.currentLocation} color={"blue"} onClick={() => onSelected(team.id)} display={!team.captured}>
|
||||
<Tag text={team.name} display={showNames} />
|
||||
</Position>
|
||||
</Fragment>)}
|
||||
</CustomMapContainer>
|
||||
{ gameState == GameState.PLAYING &&
|
||||
<div className="absolute top-4 left-1/2 -translate-x-1/2 z-[1000] pointer-events-none flex flex-col items-center bg-white p-2 rounded-lg shadow-lg drop-shadow">
|
||||
<p className="text-sm">Durée zone</p>
|
||||
<p className="text-2xl font-bold">{formatTime(timeLeftNextZone)}</p>
|
||||
</div>
|
||||
}
|
||||
<button className="absolute top-4 right-4 z-[1000] cursor-pointer bg-white p-3 rounded-full shadow-lg drop-shadow" onClick={() => setIsFullScreen(!isFullScreen)}>
|
||||
<img src={`/icons/fullscreen.png`} className="w-8 h-8" />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { env } from 'next-runtime-env';
|
||||
import { useEffect, useState } from "react";
|
||||
import useAdmin from "@/hook/useAdmin";
|
||||
import { getStatus } from '@/util/functions';
|
||||
import { Colors } from '@/util/types';
|
||||
import { teamStatus } from '@/util/configurations';
|
||||
import { Colors, GameState } from '@/util/types';
|
||||
|
||||
function DotLine({ label, value }) {
|
||||
return (
|
||||
@@ -32,6 +31,7 @@ function IconValue({ color, icon, value }) {
|
||||
export default function TeamSidePanel({ selectedTeamId, onClose }) {
|
||||
const { getTeam, startDate, gameState } = useAdmin();
|
||||
const [imgSrc, setImgSrc] = useState("");
|
||||
const [_, setRefreshKey] = useState(0);
|
||||
const team = getTeam(selectedTeamId);
|
||||
const NO_VALUE = "XX";
|
||||
const NEXT_PUBLIC_SOCKET_HOST = env("NEXT_PUBLIC_SOCKET_HOST");
|
||||
@@ -43,6 +43,14 @@ export default function TeamSidePanel({ selectedTeamId, onClose }) {
|
||||
|
||||
if (!team) return null;
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setRefreshKey(prev => prev + 1);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
function formatTime(startDate, endDate) {
|
||||
// startDate in milliseconds
|
||||
if (endDate == null || startDate == null || startDate < 0) return NO_VALUE + ":" + NO_VALUE;
|
||||
@@ -92,18 +100,22 @@ export default function TeamSidePanel({ selectedTeamId, onClose }) {
|
||||
<DotLine label="ID d'équipe" value={String(selectedTeamId).padStart(6, '0').replace(/(\d{3})(\d{3})/, "$1 $2")} />
|
||||
<DotLine label="ID de capture" value={team.captureCode ? String(team.captureCode).padStart(4, '0') : NO_VALUE} />
|
||||
</div>
|
||||
{ gameState != GameState.FINISHED &&
|
||||
<div>
|
||||
<DotLine label="Chasse" value={getTeam(team.chasing)?.name ?? NO_VALUE} />
|
||||
<DotLine label="Chassé par" value={getTeam(team.chased)?.name ?? NO_VALUE} />
|
||||
</div>
|
||||
}
|
||||
{ (gameState == GameState.PLAYING || gameState == GameState.FINISHED) &&
|
||||
<div>
|
||||
<DotLine label="Distance" value={formatDistance(team.distance)} />
|
||||
<DotLine label="Temps de survie" value={formatTime(startDate, team.captured ? team.finishDate : Date.now())} />
|
||||
<DotLine label="Vitesse moyenne" value={formatSpeed(team.distance, startDate, team.captured ? team.finishDate : Date.now())} />
|
||||
<DotLine label="Temps de survie" value={formatTime(startDate, team.finishDate || Date.now())} />
|
||||
<DotLine label="Vitesse moyenne" value={formatSpeed(team.distance, startDate, team.finishDate || Date.now())} />
|
||||
<DotLine label="Captures" value={team.nCaptures ?? NO_VALUE} />
|
||||
<DotLine label="Observations" value={team.nSentLocation ?? NO_VALUE} />
|
||||
<DotLine label="Observé" value={team.nObserved ?? NO_VALUE} />
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
<DotLine label="Modèle" value={team.phoneModel ?? NO_VALUE} />
|
||||
<DotLine label="Nom" value={team.phoneName ?? NO_VALUE} />
|
||||
|
||||
@@ -17,9 +17,9 @@ export default function AdminLoginPage() {
|
||||
return (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
<form className="flex flex-col items-center gap-3 bg-white p-8 rounded-lg ring-1 ring-black" onSubmit={handleSubmit}>
|
||||
<h1 className="text-2xl font-bold text-center text-gray-700">Admin login</h1>
|
||||
<input name="team-id" className="w-60 h-12 text-center rounded ring-1 ring-inset ring-black placeholder:text-gray-400" placeholder="Admin password" value={value} onChange={(e) => setValue(e.target.value)}/>
|
||||
<button className=" w-40 h-12 bg-blue-600 hover:bg-blue-500 text-l text-white rounded ease-out duration-200" type="submit">Login</button>
|
||||
<h1 className="text-2xl font-bold text-center text-gray-700">Connexion admin</h1>
|
||||
<input name="team-id" className="w-60 h-12 text-center rounded ring-1 ring-inset ring-black placeholder:text-gray-400" placeholder="Mot de passe admin" value={value} onChange={(e) => setValue(e.target.value)}/>
|
||||
<button className=" w-40 h-12 bg-blue-600 hover:bg-blue-500 text-l text-white rounded ease-out duration-200" type="submit">Se connecter</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function AdminPage() {
|
||||
const [mapStyle, setMapStyle] = useState(mapStyles.default);
|
||||
const [showZones, setShowZones] = useState(true);
|
||||
const [showNames, setShowNames] = useState(true);
|
||||
const [showArrows, setShowArrows] = useState(false);
|
||||
const [showArrows, setShowArrows] = useState(true);
|
||||
const [isFocusing, setIsFocusing] = useState(true);
|
||||
|
||||
useProtect();
|
||||
|
||||
@@ -89,21 +89,21 @@ export default function CircleZoneSelector({ display }) {
|
||||
</CustomMapContainer>
|
||||
</div>
|
||||
<div className="h-full w-1/6 flex flex-col gap-3">
|
||||
{editMode == EditMode.MIN && <button className="w-full h-16 text-lg text-white rounded bg-blue-600 hover:bg-blue-500" onClick={() => setEditMode(EditMode.MAX)}>Click to edit first zone</button>}
|
||||
{editMode == EditMode.MAX && <button className="w-full h-16 text-lg text-white rounded bg-red-600 hover:bg-red-500" onClick={() => setEditMode(EditMode.MIN)}>Click to edit last zone</button>}
|
||||
{editMode == EditMode.MAX && <button className="w-full h-16 text-lg text-white rounded bg-blue-600 hover:bg-blue-500" onClick={() => setEditMode(EditMode.MIN)}>Édition première zone</button>}
|
||||
{editMode == EditMode.MIN && <button className="w-full h-16 text-lg text-white rounded bg-red-600 hover:bg-red-500" onClick={() => setEditMode(EditMode.MAX)}>Édition dernière zone</button>}
|
||||
<div className="w-full flex flex-row gap-2 items-center justify-between">
|
||||
<p>Reduction number</p>
|
||||
<p>Nombre de rétrécissements</p>
|
||||
<NumberInput id="reduction-number" value={localZoneSettings.reductionCount ?? ""} onChange={updateReductionCount} />
|
||||
</div>
|
||||
<div className="w-full flex flex-row gap-2 items-center justify-between">
|
||||
<p>Zone duration</p>
|
||||
<p>Durée d'une zone</p>
|
||||
<NumberInput id="duration" value={localZoneSettings.duration ?? ""} onChange={updateDuration} />
|
||||
</div>
|
||||
<div className="w-full flex flex-row gap-2 items-center justify-between">
|
||||
<p>Timeout</p>
|
||||
<p>Temps permis hors zone</p>
|
||||
<NumberInput id="timeout-circle-selector" value={localOutOfZoneDelay ?? ""} onChange={setLocalOutOfZoneDelay} />
|
||||
</div>
|
||||
<button className="w-full h-16 text-lg text-white rounded bg-green-600 hover:bg-green-500" onClick={handleSubmit}>Apply</button>
|
||||
<button className="w-full h-16 text-lg text-white rounded bg-green-600 hover:bg-green-500" onClick={handleSubmit}>Appliquer</button>
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function Messages() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Section title="Message" innerClassName="w-full h-full flex flex-col gap-3 items-center">
|
||||
<Section title="Messages" innerClassName="w-full h-full flex flex-col gap-3 items-center">
|
||||
<MessageInput id="waiting" title="Attente :" value={localGameSettings?.waiting ?? ""} onChange={(e) => modifyLocalZoneSettings("waiting", e.target.value)} onBlur={applyLocalGameSettings}/>
|
||||
<MessageInput id="captured" title="Capture :" value={localGameSettings?.captured ?? ""} onChange={(e) => modifyLocalZoneSettings("captured", e.target.value)} onBlur={applyLocalGameSettings}/>
|
||||
<MessageInput id="winner" title="Victoire :" value={localGameSettings?.winner ?? ""} onChange={(e) => modifyLocalZoneSettings("winner", e.target.value)} onBlur={applyLocalGameSettings}/>
|
||||
|
||||
@@ -54,7 +54,7 @@ export default function PlacementZoneSelector({ display }) {
|
||||
</div>
|
||||
<div className="h-full w-1/6 flex flex-col gap-3">
|
||||
<div className="w-full text-center">
|
||||
<h2 className="text-xl">Teams</h2>
|
||||
<h2 className="text-xl">Équipes</h2>
|
||||
</div>
|
||||
<List array={teams} selectedId={selectedTeamId} onSelected={(id) => setSelectedTeamId(selectedTeamId != id ? id : null)}>
|
||||
{ (team) =>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { ZoneTypes } from "@/util/types";
|
||||
import useLocalVariable from "@/hook/useLocalVariable";
|
||||
import useAdmin from "@/hook/useAdmin";
|
||||
|
||||
// Imported at runtime and not at compile time
|
||||
const CircleZoneSelector = dynamic(() => import('./circleZoneSelector'), { ssr: false });
|
||||
@@ -18,18 +19,19 @@ function ZoneTypeButton({title, onClick, isSelected}) {
|
||||
}
|
||||
|
||||
export default function PlayingZoneSelector({ display }) {
|
||||
const [zoneType, setZoneType] = useState(ZoneTypes.POLYGON);
|
||||
const { zoneType } = useAdmin();
|
||||
const [localZoneType, setLocalZoneType] = useLocalVariable(zoneType, () => {});
|
||||
|
||||
return (
|
||||
<div className={display ? 'w-full h-full gap-3 flex flex-col' : "hidden"}>
|
||||
<div className="w-full flex flex-row gap-3 items-center">
|
||||
<p className="text-l">Type de zone :</p>
|
||||
<ZoneTypeButton title="Cercles" onClick={() => setZoneType(ZoneTypes.CIRCLE)} isSelected={zoneType == ZoneTypes.CIRCLE} />
|
||||
<ZoneTypeButton title="Polygones" onClick={() => setZoneType(ZoneTypes.POLYGON)} isSelected={zoneType == ZoneTypes.POLYGON} />
|
||||
<ZoneTypeButton title="Cercles" onClick={() => setLocalZoneType(ZoneTypes.CIRCLE)} isSelected={localZoneType == ZoneTypes.CIRCLE} />
|
||||
<ZoneTypeButton title="Polygones" onClick={() => setLocalZoneType(ZoneTypes.POLYGON)} isSelected={localZoneType == ZoneTypes.POLYGON} />
|
||||
</div>
|
||||
<div className="w-full flex-1">
|
||||
<CircleZoneSelector display={zoneType == ZoneTypes.CIRCLE} />
|
||||
<PolygonZoneSelector display={zoneType == ZoneTypes.POLYGON} />
|
||||
<CircleZoneSelector display={localZoneType == ZoneTypes.CIRCLE} />
|
||||
<PolygonZoneSelector display={localZoneType == ZoneTypes.POLYGON} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -106,7 +106,7 @@ export default function PolygonZoneSelector({ display }) {
|
||||
</div>
|
||||
<div className="h-full w-1/6 flex flex-col gap-3">
|
||||
<div className="w-full text-center">
|
||||
<h2 className="text-xl">Reduction order</h2>
|
||||
<h2 className="text-xl">Ordre de réduction</h2>
|
||||
</div>
|
||||
<ReorderList droppableId="zones-order" array={localZoneSettings.polygons} setArray={setLocalZoneSettingsPolygons}>
|
||||
{ (zone) =>
|
||||
@@ -117,10 +117,10 @@ export default function PolygonZoneSelector({ display }) {
|
||||
}
|
||||
</ReorderList>
|
||||
<div className="w-full flex flex-row gap-2 items-center justify-between">
|
||||
<p>Timeout</p>
|
||||
<p>Temps permis hors zone</p>
|
||||
<NumberInput id="timeout-polygon-selector" value={localOutOfZoneDelay ?? ""} onChange={setLocalOutOfZoneDelay}/>
|
||||
</div>
|
||||
<button className="w-full h-16 text-lg text-white rounded bg-green-600 hover:bg-green-500" onClick={handleSubmit}>Apply</button>
|
||||
<button className="w-full h-16 text-lg text-white rounded bg-green-600 hover:bg-green-500" onClick={handleSubmit}>Appliquer</button>
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,7 @@ export default function TeamManager() {
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="Équipe" outerClassName="flex-1 min-h-0" innerClassName="flex flex-col items-center gap-3">
|
||||
<Section title="Équipes" outerClassName="flex-1 min-h-0" innerClassName="flex flex-col items-center gap-3">
|
||||
<form className='w-full flex flex-row gap-3' onSubmit={handleTeamSubmit}>
|
||||
<div className='w-full'>
|
||||
<input name="teamName" label='Team name' value={teamName} onChange={(e) => setTeamName(e.target.value)} type="text" className="w-full h-full p-4 ring-1 ring-inset ring-gray-300" />
|
||||
@@ -51,7 +51,7 @@ export default function TeamManager() {
|
||||
</ReorderList>
|
||||
</div>
|
||||
<div className="w-full flex flex-row gap-2 items-center justify-between">
|
||||
<p>Interval between position updates</p>
|
||||
<p>Intervalle entre les envois de position</p>
|
||||
<NumberInput id="position-update" value={localSendPositionDelay ?? ""} onChange={setLocalSendPositionDelay} onBlur={applyLocalSendPositionDelay} />
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
@@ -158,7 +158,7 @@ export function Arrow({ pos1, pos2, color = 'black', weight = 5, arrowSize = 20,
|
||||
map.removeLayer(polyline);
|
||||
map.removeLayer(decorator);
|
||||
};
|
||||
}, [insetPositions])
|
||||
}, [display, insetPositions])
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function usePasswordProtect(loginPath, redirectPath, loading, log
|
||||
redirect(loginPath);
|
||||
}
|
||||
if(loggedIn && !loading && path === loginPath) {
|
||||
redirect(redirectPath)
|
||||
redirect(redirectPath);
|
||||
}
|
||||
}, [loggedIn, loading, path]);
|
||||
}
|
||||
|
||||
@@ -14,15 +14,13 @@ export default function useSocketAuth(socket, passwordName) {
|
||||
const [savedPassword, setSavedPassword, savedPasswordLoading] = useLocalStorage(passwordName, null);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Checking saved password", savedPassword, loggedIn);
|
||||
if (savedPassword && !loggedIn) {
|
||||
console.log("Logging in with saved password", savedPassword);
|
||||
console.log("Try to log with :", savedPassword);
|
||||
socket.emit(LOGIN_MESSAGE, savedPassword);
|
||||
}
|
||||
}, [savedPassword]);
|
||||
|
||||
function login(password) {
|
||||
console.log("Logging", password);
|
||||
setSavedPassword(password)
|
||||
}
|
||||
|
||||
@@ -35,6 +33,7 @@ export default function useSocketAuth(socket, passwordName) {
|
||||
useSocketListener(socket, LOGIN_RESPONSE_MESSAGE, (loginResponse) => {
|
||||
setWaitingForResponse(false);
|
||||
setLoggedIn(loginResponse);
|
||||
console.log(loginResponse ? "Logged in" : "Not logged in");
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -33,4 +33,6 @@ export const teamStatus = {
|
||||
ready: { label: "Placée", color: Colors.green },
|
||||
notready: { label: "Non placée", color: Colors.red },
|
||||
waiting: { label: "En attente", color: Colors.grey },
|
||||
victory: { label: "Victoire", color: Colors.green },
|
||||
defeat: { label: "Défaite", color: Colors.red },
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export function getStatus(team, gamestate) {
|
||||
case GameState.PLAYING:
|
||||
return team.captured ? teamStatus.captured : team.outOfZone ? teamStatus.outofzone : teamStatus.playing;
|
||||
case GameState.FINISHED:
|
||||
return team.captured ? teamStatus.captured : teamStatus.playing;
|
||||
return team.captured ? teamStatus.defeat : teamStatus.victory;
|
||||
default:
|
||||
return teamStatus.default;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user