您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Extension qui ajoute des fonctionnalités (timer, pilote automatique et plan dynamique) dans le jeu PMD.
// ==UserScript== // @name PMD+ // @namespace https://github.com/PieroLB/pmd-plus // @version 0.4.6 // @description Extension qui ajoute des fonctionnalités (timer, pilote automatique et plan dynamique) dans le jeu PMD. // @author PieroLB // @match https://pmdapp.fr/* // @match https://www.pmdapp.fr/* // @icon https://lh3.googleusercontent.com/dJpt27Lfg0upeK1rRqPk8W5pMv5JAdOVeCIlM28XQ3o_SL-pCIPH51dnZzPY7lcCNf_tWSOkC-4lzTCToIPGDI3vizk=s60 // @license MIT // @grant none // ==/UserScript== const auto = () => { var auto = false; const TIME_RINGING_DOORS = 3000; // en millisecondes const TIME_MIN_DOORS_OPENED = 3000; // en millisecondes const TIME_CLOSING_OPENING_DOORS = 3000; // en millisecondes const TIME_MIN_DEPARTURE = 70; // en secondes const SPEED_PADDING_BOTTOM = 2; // en km/h const TIME_IN_STATION = 40; var eventInStation = false; var depart = false; var deceleration = 0; var limiteMaxDecelerationAtteinte = false; var limiteMinDecelerationAtteinte = false; var decelerationComplete = false; var decelerationAvtStation = false; const getTime = (station1, station2) => { let t = 0; let listSpeedLimits = {}; if (typeof speedLimitNG !== "undefined") { listSpeedLimits = speedLimitNG; } else if (typeof speedLimits !== "undefined") { speedLimits.forEach((l) => { listSpeedLimits[l.start] = l.limit; }); } let listPos = Object.keys(listSpeedLimits); let posAvt = listPos[0]; if (station1.end < posAvt && station2.start < posAvt) { // Permet de gérer les garages qui nont pas de speedLimit (elles arrivent après). Ex : ligne 3 let v = localSpeedLimit / 3.6; let d = (station2.start - station1.end) / 75; t = d / v; } else if (station1.end < posAvt) { let v = localSpeedLimit / 3.6; let d = (posAvt - station1.end) / 75; t += d / v; } else if (listPos.length == 1) { // Permet de gérer sil y a quune seule speedLimit sur toute la ligne. Ex : ligne 7bis et 9 let v = listSpeedLimits[posAvt] / 3.6; let d = (station2.start - Math.max(station1.end, posAvt)) / 75; t = d / v; } else if (listPos.length == 0) { // Permet de gérer sil y a aucune speedLimit sur toute la ligne. Ex : ligne 13 et 12 let v = localSpeedLimit / 3.6; let d = (station2.start - station1.end) / 75; t = d / v; } else { for (let i = 1; i < listPos.length; i++) { if (listPos[i] >= station1.end && listPos[i] <= station2.start) { let v = listSpeedLimits[posAvt] / 3.6; let d = (listPos[i] - Math.max(station1.end, posAvt)) / 75; t += d / v; } else if (listPos[i] > station2.start) { let v = listSpeedLimits[posAvt] / 3.6; let d = (station2.start - posAvt) / 75; t += d / v; break; } posAvt = listPos[i]; } } return t; }; var timeToGoNextStation = null; var lastStation = null; var terminus = false; var isDoorOpened = false; const AUTOcloseDoor = (t = TIME_RINGING_DOORS) => { isDoorOpened = false; if (NADOMAS) { KEYBOARD_DOWN["KeyO"] = false; KEYBOARD_DOWN["KeyF"] = true; t = TIME_RINGING_DOORS; } else { closeDoor(); } setTimeout(() => { if (areDoorFullyClosed() == false) { // ECHEC DE LA FERMETURE => REOUVERTURE isDoorOpened = true; if (NADOMAS) { KEYBOARD_DOWN["KeyF"] = false; KEYBOARD_DOWN["KeyO"] = true; } else { doorOpen(); } AUTOcloseDoor(0); } else { if (NADOMAS) { KEYBOARD_DOWN["KeyF"] = false; KEYBOARD_DOWN["KeyO"] = false; } decelerationAvtStation = false; depart = true; } }, t); }; setInterval(() => { if (auto) { if (!eventInStation) { // ON EST DANS UNE STATION ET IL NE FAUT PAS PARTIR if ( !depart && UTILS.isStation() && ((!UTILS.isStation().closed && UTILS.isStation().allowPassengers && UTILS.isStation().freq > 0) || zoneStations.indexOf(UTILS.isStation()) == zoneStations.length - 1) ) { if ( zoneStations.indexOf(UTILS.isStation()) == zoneStations.length - 1 ) terminus = true; if (!terminus && lastStation != UTILS.isStation()) { timeToGoNextStation = getTime( UTILS.isStation(), zoneStations[zoneStations.indexOf(UTILS.isStation()) + 1] ); lastStation = UTILS.isStation(); } // A LARRET if (currentSpeed == 0) { if (!isDoorOpened) { console.log("OUVERTURE DES PORTES"); console.log(KEYBOARD_DOWN); isDoorOpened = true; eventInStation = true; if (NADOMAS) { KEYBOARD_DOWN["KeyF"] = false; KEYBOARD_DOWN["KeyO"] = true; // let loop = setInterval(()=>{ // if (doorOpened){ // KEYBOARD_DOWN["KeyO"] = false; // clearInterval(loop) // } // }); } else { doorOpen(); } setTimeout(() => { eventInStation = false; }, TIME_CLOSING_OPENING_DOORS + TIME_MIN_DOORS_OPENED); // TEMPS MINIMUM DE LOUVERTURE A LA FERMETURE DES PORTES } else if ( (terminus && UTILS.getModule("Passagers").onBoard.length == 0) || (!terminus && timeBeforeArriving <= timeToGoNextStation + (TIME_CLOSING_OPENING_DOORS + TIME_RINGING_DOORS) / 1000 + 8) ) { console.log("FERMETURE DES PORTES"); eventInStation = true; AUTOcloseDoor(); setTimeout(() => { eventInStation = false; }, TIME_RINGING_DOORS + TIME_CLOSING_OPENING_DOORS + 1000); // TEMPS MINIMUM DE LOUVERTURE A LA FERMETURE DES PORTES } } // IL FAUT RALENTIR POUR SARRETER EN STATION else { let virtualSpeed = currentSpeed; let virtualPosition = 0; while (virtualSpeed > 0) { virtualSpeed += 1 * ((-13 / 80) * 1.2) * 1.2; virtualPosition += (virtualSpeed / 3) * 1.3 * 1; } virtualPosition = -globalTranslate + virtualPosition; if (virtualPosition >= UTILS.isStation().end) { currentThrottle = -11; limiteMaxDecelerationAtteinte = true; } else if ( limiteMaxDecelerationAtteinte && !limiteMinDecelerationAtteinte && currentSpeed <= 33 ) { currentThrottle = 0; limiteMinDecelerationAtteinte = true; } else if (!limiteMaxDecelerationAtteinte) { currentThrottle = 0; } } } else { // ON SORT DUNE STATION if (!UTILS.isFullyInStation() && depart) depart = limiteMinDecelerationAtteinte = limiteMaxDecelerationAtteinte = false; // ON RALENTIT AVANT LA STATION TELLEMENT ON VA VITE if ( decelerationAvtStation || (currentSpeed > 80 && nextStation.start + globalTranslate <= 10000) ) { currentThrottle = -5; decelerationAvtStation = true; } // ADAPTION DE LA VITESSE DE ROULEMENT else { let speedLim = UTILS.currentSpeedLimit(); if (currentSpeed < speedLim - SPEED_PADDING_BOTTOM) { currentThrottle = 5; } if (currentSpeed >= speedLim + 1) { currentThrottle = -9; } if (currentSpeed < speedLim + 1 && currentSpeed > speedLim) { if (speedLim > 80) { currentThrottle = 3; } else if (speedLim > 50) { currentThrottle = 1; } else { currentThrottle = 0; } } } } } } }); document.getElementById("auto").addEventListener("click", () => { auto = !auto; if (!auto) { if (currentThrottle > 0) currentThrottle = 0; KEYBOARD_DOWN["KeyF"] = KEYBOARD_DOWN["KeyO"] = false; } document.getElementById("auto").style.backgroundColor = auto ? "green" : "darkred"; }); }; const plan = () => { // document.getElementById("plan").addEventListener("click", (event) => { // if (modules[2].displayMode) modules[2].displayMode = 0; // }); const listLignes = { Metro: { img: null, lignes: { 1: { img: null }, 2: { img: null }, 3: { img: null }, "3bis": { img: null }, 4: { img: null }, 5: { img: null }, 6: { img: null }, 7: { img: null }, "7bis": { img: null }, 8: { img: null }, 9: { img: null }, 10: { img: null }, 11: { img: null }, 12: { img: null }, 13: { img: null }, 14: { img: null }, }, }, RER: { img: null, lignes: { A: { img: null }, B: { img: null }, C: { img: null }, D: { img: null }, E: { img: null }, }, }, Transilien: { img: null, lignes: { H: { img: null }, J: { img: null }, K: { img: null }, L: { img: null }, N: { img: null }, P: { img: null }, R: { img: null }, U: { img: null }, }, }, Tramway: { img: null, lignes: { T1: { img: null }, T2: { img: null }, T3a: { img: null }, T3b: { img: null }, T4: { img: null }, T5: { img: null }, T6: { img: null }, T7: { img: null }, T8: { img: null }, T9: { img: null }, T10: { img: null }, T11: { img: null }, T12: { img: null }, T13: { img: null }, }, }, Autres: { img: null, lignes: { RoissyBus: { img: null }, OrlyBus: { img: null }, OrlyVal: { img: null }, Tvm: { img: null }, TER: { img: null }, }, }, }; var accessibleImg = null; var addImg = null; const urlAssets = "https://raw.githubusercontent.com/PieroLB/pmd-tools-assets/main/plan/"; const refHeight = 190; var padX = 0; class PLANStation { static stations = []; static storage; static planIndex; static canvas; static ctx; static colorLine = "#FECE03"; static photo = false; static logoImg = null; static closedImg = null; static widthTot = 40; static y = 90; static arc = { width: 20 }; static rect = { width: 50, height: 7 }; static bgText = { padding: { y: 3, x: 6 } }; static text = { nom: 10, tourist: 9 }; static rectCorres = { width: 2, height: 10 }; static imgCorres = { width: 15 }; static scrollValue = false; static loadingImg = () => { const promises = []; const accessibleImgPromise = new Promise((resolve, reject) => { let img = new Image(); img.src = `${urlAssets}accessible.svg`; img.onload = () => { accessibleImg = img; resolve(); }; img.onerror = () => reject(new Error(`Failed to load image: ${type}`)); }); promises.push(accessibleImgPromise); const addImgPromise = new Promise((resolve, reject) => { let img = new Image(); img.src = `${urlAssets}add.svg`; img.onload = () => { addImg = img; resolve(); }; img.onerror = () => reject(new Error(`Failed to load image: ${type}`)); }); promises.push(addImgPromise); const logoImgPromise = new Promise((resolve, reject) => { let img = new Image(); img.src = `${urlAssets}PMD.svg`; img.onload = () => { PLANStation.logoImg = img; resolve(); }; img.onerror = () => reject(new Error(`Failed to load image: ${type}`)); }); promises.push(logoImgPromise); const closedImgPromise = new Promise((resolve, reject) => { let img = new Image(); img.src = `${urlAssets}closed.svg`; img.onload = () => { PLANStation.closedImg = img; resolve(); }; img.onerror = () => reject(new Error(`Failed to load image: ${type}`)); }); promises.push(closedImgPromise); Object.keys(listLignes).forEach((type) => { if (type != "Autres") { const mainImgPromise = new Promise((resolve, reject) => { let img = new Image(); img.src = `${urlAssets}${type}/${type}.svg`; img.onload = () => { listLignes[type].img = img; resolve(); }; img.onerror = () => reject(new Error(`Failed to load image: ${type}`)); }); promises.push(mainImgPromise); } Object.keys(listLignes[type].lignes).forEach((ligne) => { const ligneImgPromise = new Promise((resolve, reject) => { let img = new Image(); img.src = `${urlAssets}${type}/${ligne}.svg`; img.onload = () => { listLignes[type].lignes[ligne].img = img; listLignes[type].lignes[ligne].coef = null; if (img.naturalHeight != 0 && img.naturalHeight != 0) listLignes[type].lignes[ligne].coef = img.naturalWidth / img.naturalHeight; resolve(); }; img.onerror = () => reject(new Error(`Failed to load image: ${type}-${ligne}`)); }); promises.push(ligneImgPromise); }); }); return Promise.all(promises) .then(() => { return; }) .catch((error) => { console.error( "Une erreur s'est produite lors du chargement des images :", error ); throw error; }); }; constructor( nom = `PLANStation n°${PLANStation.stations.length + 1}`, lieuTouristique = "", accessible = false, correspondances = [], stationInPMD = null, pos = PLANStation.stations.length ) { this.nom = nom == "" ? `PLANStation n°${PLANStation.stations.length + 1}` : nom; this.lieuTouristique = lieuTouristique; this.correspondances = correspondances; this.accessible = accessible; this.closed = closed; this.clignote = false; this.stationInPMD = stationInPMD; PLANStation.widthTot = Math.min( PLANStation.widthTot + PLANStation.arc.width + PLANStation.rect.width, 1024 ); PLANStation.stations.splice(pos, 0, this); let x = 20; PLANStation.stations.forEach((station) => { station.x = x; x += PLANStation.arc.width + PLANStation.rect.width; }); } render() { // LIGNE if ( PLANStation.stations.indexOf(this) != PLANStation.stations.length - 1 ) { PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = PLANStation.colorLine; PLANStation.ctx.rect( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2 - PLANStation.rect.height / 2, PLANStation.rect.width + (3 / 2) * PLANStation.arc.width, PLANStation.rect.height ); PLANStation.ctx.fill(); PLANStation.ctx.closePath(); } // CORRESPONDANCES if (this.correspondances.length > 0) { PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "#15388D"; PLANStation.ctx.rect( padX + this.x + PLANStation.arc.width / 2 - PLANStation.rectCorres.width / 2, PLANStation.y + PLANStation.arc.width - 2, PLANStation.rectCorres.width, PLANStation.rectCorres.height / 2 ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); let y = 0; Object.keys(listLignes).forEach((type) => { if ( this.correspondances.some((l) => Object.keys(listLignes[type].lignes).includes(l) ) ) { PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "#15388D"; PLANStation.ctx.rect( padX + this.x + PLANStation.arc.width / 2 - PLANStation.rectCorres.width / 2, PLANStation.y + (PLANStation.arc.width - 3) + y + 3, PLANStation.rectCorres.width, PLANStation.rectCorres.height - 3 ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); let X = 0; let n = 0; if (listLignes[type].img != null) { PLANStation.ctx.drawImage( listLignes[type].img, padX + this.x + PLANStation.arc.width / 2 - PLANStation.imgCorres.width / 2, y + PLANStation.y + PLANStation.arc.width + PLANStation.rectCorres.height, PLANStation.imgCorres.width, PLANStation.imgCorres.width ); } else { y -= PLANStation.imgCorres.width + 3; } let yAvt = y; Object.keys(listLignes[type].lignes).forEach((ligne) => { if (this.correspondances.includes(ligne)) { if (listLignes[type].img != null && n != 0 && n % 3 == 0) { y += PLANStation.imgCorres.width + 3; X = 0; } if (listLignes[type].img != null) { X += PLANStation.imgCorres.width + 3; } else { y += PLANStation.imgCorres.width + 3; } let h = PLANStation.imgCorres.width; let w = PLANStation.imgCorres.width; if ( listLignes[type].lignes[ligne].coef != null && listLignes[type].lignes[ligne].coef != 1 ) { h -= 5; w = h * listLignes[type].lignes[ligne].coef; } PLANStation.ctx.drawImage( listLignes[type].lignes[ligne].img, padX + X + this.x + PLANStation.arc.width / 2 - PLANStation.imgCorres.width / 2, y + PLANStation.y + PLANStation.arc.width + PLANStation.rectCorres.height, w, h ); n++; } }); if (listLignes[type].img != null) { PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "#15388D"; PLANStation.ctx.rect( padX + this.x + PLANStation.arc.width / 2 - PLANStation.rectCorres.width / 2, PLANStation.y + (PLANStation.arc.width - 3) + yAvt + 3 + 2 * (PLANStation.imgCorres.width + 3), PLANStation.rectCorres.width, y - yAvt ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); } y += 2 * PLANStation.imgCorres.width - 3; } }); } // CERCLE if ( this.correspondances.length > 0 && (PLANStation.stations.indexOf(this) == 0 || PLANStation.stations.indexOf(this) == PLANStation.stations.length - 1) ) { // Il y a au moins une correspondance et c'est un terminus PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "black"; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "white"; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2 - 3, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = PLANStation.colorLine; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2 - 5, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); } else if ( PLANStation.stations.indexOf(this) == 0 || PLANStation.stations.indexOf(this) == PLANStation.stations.length - 1 ) { // C'est un terminus PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "black"; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = PLANStation.colorLine; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2 - 5, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); } else if (this.correspondances.length > 0) { // C'est une station avec au moins une correspondance PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "black"; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "white"; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2 - 3, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); } else { // C'est une station sans rien PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = PLANStation.colorLine; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); } if (this.closed) { PLANStation.ctx.drawImage( PLANStation.closedImg, padX + this.x - 7, PLANStation.y - 7, PLANStation.arc.width + 14, PLANStation.arc.width + 14 ); } else if (this.clignote) { PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "yellow"; PLANStation.ctx.arc( padX + this.x + PLANStation.arc.width / 2, PLANStation.y + PLANStation.arc.width / 2, PLANStation.arc.width / 2 - 3, 0, 2 * Math.PI ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); } // TEXT PLANStation.ctx.translate( padX + this.x + PLANStation.arc.width / 2, PLANStation.y - 5 ); PLANStation.ctx.rotate(-30 * (Math.PI / 180)); PLANStation.ctx.beginPath(); if (this.lieuTouristique != "") { PLANStation.ctx.font = `italic ${PLANStation.text.tourist}px Arial`; let widthText = PLANStation.ctx.measureText(this.lieuTouristique).width; PLANStation.ctx.fillStyle = "#865200"; PLANStation.ctx.rect( -PLANStation.bgText.padding.x + 15, -PLANStation.text.tourist + PLANStation.text.nom / 2 + PLANStation.bgText.padding.y * 2 + 1, widthText + PLANStation.bgText.padding.x * 2, PLANStation.text.tourist + PLANStation.bgText.padding.y * 2 ); PLANStation.ctx.fill(); PLANStation.ctx.fillStyle = "white"; PLANStation.ctx.fillText( this.lieuTouristique, 15, PLANStation.text.nom / 2 + PLANStation.bgText.padding.y * 2 + 2 ); } PLANStation.ctx.closePath(); PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "#15388D"; PLANStation.ctx.font = `bold ${PLANStation.text.nom}px Arial`; let y = 0; let widthText = PLANStation.ctx.measureText(this.nom).width; if ( PLANStation.stations.indexOf(this) == 0 || PLANStation.stations.indexOf(this) == PLANStation.stations.length - 1 ) { PLANStation.ctx.rect( -PLANStation.bgText.padding.y, -PLANStation.text.nom - PLANStation.bgText.padding.x, widthText + PLANStation.bgText.padding.x * 2, PLANStation.text.nom + PLANStation.bgText.padding.y * 2 ); PLANStation.ctx.fill(); PLANStation.ctx.fillStyle = "white"; y = -PLANStation.bgText.padding.y - 1; } PLANStation.ctx.fillText(this.nom, PLANStation.bgText.padding.x / 4, y); if (this.accessible) PLANStation.ctx.drawImage( accessibleImg, padX + widthText + PLANStation.canvas.height * (10 / refHeight), -PLANStation.text.nom + PLANStation.bgText.padding.y, PLANStation.text.nom, PLANStation.text.nom ); PLANStation.ctx.closePath(); PLANStation.ctx.resetTransform(); } event(type, x, y) { if (type == "click") { let arc = { x: this.x, y: PLANStation.y }; console.log("lol"); if ( x >= arc.x && x <= arc.x + PLANStation.arc.width && y >= arc.y && y <= arc.y + PLANStation.arc.width ) { // Click sur une station pour la modifier this.closed = !this.closed; } } } } let nextStationPLAN; let isInStation = UTILS.isStation() != undefined ? true : false; const update = () => { requestAnimationFrame(update); PLANStation.canvas.height = 200; PLANStation.canvas.width = PLANStation.widthTot; PLANStation.ctx.clearRect( 0, 0, PLANStation.canvas.width, PLANStation.canvas.height ); // Background blanc PLANStation.ctx.beginPath(); PLANStation.ctx.fillStyle = "white"; PLANStation.ctx.rect( 0, 0, PLANStation.canvas.width, PLANStation.canvas.height ); PLANStation.ctx.closePath(); PLANStation.ctx.fill(); // Rendus des stations // if (!modules[2].displayMode) { if (UTILS.isStation() == undefined && isInStation == true) { // Sortie de station document.getElementById("plan").style.display = "none"; isInStation = false; } else if (UTILS.isStation() && isInStation == false) { // Entrée une station setTimeout(() => { document.getElementById("plan").style.display = "block"; isInStation = true; }, 800); } else { isInStation = UTILS.isStation() != undefined ? true : false; } // } nextStationPLAN = getNextStation() == false ? nextStationPLAN : getNextStation(); PLANStation.stations.forEach((station) => { if (station.nom == nextStationPLAN.name) { if (padX + station.x < 0) { padX = -Math.max( 0, (PLANStation.stations.indexOf(station) + 1) * (PLANStation.arc.width + PLANStation.rect.width) - 1024 ); } else if (padX + station.x > 1024) { padX = -1024; } } station.render(); }); }; PLANStation.canvas = document.getElementById("canvasPlan"); PLANStation.ctx = PLANStation.canvas.getContext("2d"); PLANStation.loadingImg().then(() => { fetch( "https://raw.githubusercontent.com/PieroLB/pmd-tools-assets/main/plan/data.json" ) .then((resp) => resp.json()) .then((resp) => { let line = new URLSearchParams(location.search).get("line"); if (resp) { PLANStation.colorLine = resp[line].color; resp[line].stations.forEach((station) => { let stationInPMD = zoneStations.find( (s) => s.name == station.nom || s.name == station.nom + " v1" || s.name == station.nom + " v2" ); new PLANStation( station.nom, station.lieuTouristique, station.accessible, station.correspondances, stationInPMD ); }); } for (let station of zoneStations) { let stationPLAN = PLANStation.stations.find( (s) => s.nom == station.name || s.nom == station.name + " v1" || s.nom == station.name + " v2" ); if (stationPLAN) { padX = -Math.max( 0, (PLANStation.stations.indexOf(stationPLAN) + 1) * (PLANStation.arc.width + PLANStation.rect.width) - 1024 ); break; } } PLANStation.canvas.addEventListener("click", function (event) { PLANStation.stations.forEach((station) => { let arc = { x: station.x + padX, y: PLANStation.y }; if ( event.clientY - this.getBoundingClientRect().y >= arc.y && event.clientY - this.getBoundingClientRect().y <= arc.y + PLANStation.arc.width && event.clientX >= arc.x && event.clientX <= arc.x + PLANStation.arc.width ) { station.closed = !station.closed; if (station.stationInPMD != null) station.stationInPMD.closed = station.closed; return; } }); }); let clignote = true; const intervalle = 500; setInterval(() => { PLANStation.stations.forEach((station) => { if ( station.nom == nextStationPLAN.name || station.nom + " v1" == nextStationPLAN.name || station.nom + " v2" == nextStationPLAN.name ) { station.clignote = clignote; clignote = !clignote; } else if ( zoneStations .slice(0, zoneStations.indexOf(nextStationPLAN) + 1) .find( (s) => s.name == station.nom || s.name == station.nom + " v1" || s.name == station.nom + " v2" ) ) { station.clignote = false; } else { station.clignote = true; } }); }, intervalle); update(); }); }); }; const settings = () => { var toolsStatus = { timer: { nom: "le timer", elementID: "time-box", status: true }, auto: { nom: "le mode auto", elementID: "auto", status: true }, plan: { nom: "le plan", elementID: "canvasPlan", status: true }, }; const styleId = "dynamic-important-style"; if (!document.getElementById(styleId)) { const style = document.createElement("style"); style.id = styleId; style.textContent = ` .hidden-important { display: none !important; } .flex-important { display: flex !important; } `; document.head.appendChild(style); } if (localStorage.getItem("toolsStatus")) { let storage = JSON.parse(localStorage.getItem("toolsStatus")); Object.keys(toolsStatus).forEach((tool) => { toolsStatus[tool].status = storage[tool] == null ? true : storage[tool]; }); } else { let storage = {}; Object.keys(toolsStatus).forEach((tool) => { storage[tool] = toolsStatus[tool].status; }); localStorage.setItem("toolsStatus", JSON.stringify(storage)); } Object.keys(toolsStatus).forEach((tool) => { if (document.getElementById(toolsStatus[tool].elementID)) { if (toolsStatus[tool].status) { document .getElementById(toolsStatus[tool].elementID) .classList.remove("hidden-important"); document .getElementById(toolsStatus[tool].elementID) .classList.add("flex-important"); } else { document .getElementById(toolsStatus[tool].elementID) .classList.remove("flex-important"); document .getElementById(toolsStatus[tool].elementID) .classList.add("hidden-important"); } } if (tool == "plan") { if (toolsStatus[tool].status) { document.getElementById("plan").classList.remove("flex-important"); document.getElementById("plan").classList.add("hidden-important"); } else { document.getElementById("plan").classList.remove("hidden-important"); document.getElementById("plan").classList.add("flex-important"); } } }); let loop = setInterval(() => { if (document.querySelectorAll("#extra").length == 2) { clearInterval(loop); let params = document.querySelectorAll("#extra")[1]; let lastParam = params.querySelectorAll(".menubtn.parambtn")[ params.querySelectorAll(".menubtn.parambtn").length - 1 ]; let paramPMDTools = document.createElement("div"); paramPMDTools.className = "menubtn parambtn"; paramPMDTools.textContent = "Paramètres PMD+"; lastParam.after(paramPMDTools); paramPMDTools.addEventListener("click", () => { let extra = document.createElement("div"); extra.id = "extra"; extra.style.opacity = "1"; document.body.appendChild(extra); let popup = document.createElement("div"); popup.id = "popup"; extra.appendChild(popup); let menuButtonList = document.createElement("div"); menuButtonList.id = "menuButtonList"; menuButtonList.className = "scrollbar-invisible"; popup.appendChild(menuButtonList); Object.keys(toolsStatus).forEach((tool) => { let button = document.createElement("div"); button.className = "menubtn parambtn"; button.textContent = `Afficher ${toolsStatus[tool].nom} : ${ toolsStatus[tool].status ? "Oui" : "Non" }`; menuButtonList.appendChild(button); button.addEventListener("click", () => { toolsStatus[tool].status = !toolsStatus[tool].status; let storage = JSON.parse(localStorage.getItem("toolsStatus")); storage[tool] = toolsStatus[tool].status; localStorage.setItem("toolsStatus", JSON.stringify(storage)); button.textContent = `Afficher ${toolsStatus[tool].nom} : ${ toolsStatus[tool].status ? "Oui" : "Non" }`; if (toolsStatus[tool].status) { document .getElementById(toolsStatus[tool].elementID) .classList.remove("hidden-important"); document .getElementById(toolsStatus[tool].elementID) .classList.add("flex-important"); } else { document .getElementById(toolsStatus[tool].elementID) .classList.remove("flex-important"); document .getElementById(toolsStatus[tool].elementID) .classList.add("hidden-important"); } if (tool == "plan") { if (toolsStatus[tool].status) { document .getElementById("plan") .classList.remove("flex-important"); document .getElementById("plan") .classList.add("hidden-important"); } else { document .getElementById("plan") .classList.remove("hidden-important"); document.getElementById("plan").classList.add("flex-important"); } } }); }); let fermer = document.createElement("div"); fermer.className = "menubtn parambtn"; fermer.textContent = "Fermer"; menuButtonList.appendChild(fermer); fermer.addEventListener("click", () => extra.remove()); }); } }); }; const timer = () => { const moduleTime = UTILS.getModule("Time"); let loopWaitingStart = setInterval(() => { if (moduleTime.lastTimeDelay + moduleTime.timeDelay > 0) { clearInterval(loopWaitingStart); var avtStation = zoneStations[0]; var station = false; var tempsMax; var nextStation; setInterval(() => { if ( zoneStations.find( (a) => -globalTranslate > a.start && -globalTranslate < a.end ) != undefined && zoneStations.indexOf( zoneStations.find( (a) => -globalTranslate > a.start && -globalTranslate < a.end ) ) != zoneStations.length - 1 ) { // SI DANS STATION if (station == false) { // SI ON ETAIT PAS DANS STATION AVT tempsMax = moduleTime.lastTimeDelay + moduleTime.timeDelay; console.log( tempsMax, moduleTime.lastTimeDelay, moduleTime.timeDelay ); } nextStation = zoneStations[ zoneStations.indexOf( zoneStations.find( (a) => -globalTranslate > a.start && -globalTranslate < a.end ) ) + 1 ]; avtStation = nextStation; station = true; } else { station = false; nextStation = avtStation; } timeBeforeArriving = moduleTime.lastTimeDelay + moduleTime.timeDelay; document.getElementById("time").textContent = timeBeforeArriving; document.getElementById("nextStation").textContent = nextStation.name; let pourcentage = (timeBeforeArriving / tempsMax) * 100; if (pourcentage >= 0) { const angle = 360 * (pourcentage / 100); const radius = 30; const x = 30 + radius * Math.cos(-Math.PI / 2 + (angle * Math.PI) / 180); const y = 30 + radius * Math.sin(-Math.PI / 2 + (angle * Math.PI) / 180); const largeArcFlag = angle <= 180 ? "0" : "1"; const pathData = "M 30,30 L 30,0 A 30,30 0 " + largeArcFlag + ",1 " + x + "," + y + " Z"; document.getElementById("sector").setAttribute("d", pathData); } let rouge = 255 - (pourcentage * 255) / 100; let vert = (pourcentage * 255) / 100; let bleu = 0; document .getElementById("sector") .setAttribute("fill", "rgb(" + rouge + "," + vert + "," + bleu + ")"); let distance = (nextStation.start - -globalTranslate) / 75; // en mètres document.getElementById("distance").textContent = Math.round(distance) + "m"; }); } }); }; const displayUI = () => { // Create time-box div let timeBox = document.createElement("div"); timeBox.id = "time-box"; timeBox.style.cssText = "position: absolute; right: 0px; bottom: 0px; height:100%; width:134px; background-color: black;"; document.getElementById("pupitre").appendChild(timeBox); // Create time-boxClosed div let timeBoxClosed = document.createElement("div"); timeBoxClosed.id = "time-boxClosed"; timeBoxClosed.style.cssText = "z-index:3; position: absolute; left: 0px; top: 0px; height:100%; width:19px; background-color: #3E3C44; border-top-right-radius:10px;"; timeBox.appendChild(timeBoxClosed); // Create the SVG arrow button inside time-boxClosed let arrowButton = document.createElement("div"); arrowButton.style.cssText = "background-color: #929497; border-radius:100%; display:flex; align-items:center; justify-content:center; cursor:pointer"; arrowButton.onclick = () => { document.getElementById("time-boxOpened").style.display = ""; document.getElementById("time-boxClosed").style.display = "none"; }; timeBoxClosed.appendChild(arrowButton); let arrowSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); arrowSvg.setAttribute("width", "19"); arrowSvg.setAttribute("height", "19"); arrowSvg.setAttribute("viewBox", "0 0 19 19"); arrowSvg.setAttribute("fill", "none"); let arrowPath = document.createElementNS( "http://www.w3.org/2000/svg", "path" ); arrowPath.setAttribute( "d", "M6 13.7075L10.3266 9.5L6 5.2925L7.33198 4L13 9.5L7.33198 15L6 13.7075Z" ); arrowPath.setAttribute("fill", "black"); arrowSvg.appendChild(arrowPath); arrowButton.appendChild(arrowSvg); // Create time-boxOpened div let timeBoxOpened = document.createElement("div"); timeBoxOpened.id = "time-boxOpened"; timeBoxOpened.style.cssText = "z-index:2; position: absolute; left: 0px; top: 0px; height:100%; width:250px; background-color: #3E3C44; border-top-right-radius:10px; display:none"; timeBox.appendChild(timeBoxOpened); // Create the SVG circle in time-boxOpened let circleContainer = document.createElement("div"); circleContainer.style.cssText = "position:absolute; top:0px; left:0px; width:100%; height:70px; display:flex; align-items:center; justify-content:center"; timeBoxOpened.appendChild(circleContainer); let circleSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); circleSvg.id = "circle"; circleSvg.setAttribute("width", "60"); circleSvg.setAttribute("height", "60"); circleSvg.setAttribute("viewBox", "0 0 60 60"); circleSvg.setAttribute("fill", "none"); let sectorPath = document.createElementNS( "http://www.w3.org/2000/svg", "path" ); sectorPath.id = "sector"; sectorPath.setAttribute("d", "M30,30 L30,0 A30,30 0 0,1 30,0 Z"); sectorPath.setAttribute("fill", "green"); circleSvg.appendChild(sectorPath); circleContainer.appendChild(circleSvg); // Create time display text let timeTextContainer = document.createElement("div"); timeTextContainer.className = "text-time"; timeTextContainer.style.cssText = "position:absolute; top:70px; left:0px; width: 100%; height:20px; display:flex; align-items:center; justify-content:center; font-size: 20px; color:#929497; text-align:center"; let timeText = document.createElement("div"); timeText.innerHTML = '<strong id="time">--</strong> secondes'; timeTextContainer.appendChild(timeText); timeBoxOpened.appendChild(timeTextContainer); // Create next station display let nextStationContainer = document.createElement("div"); nextStationContainer.className = "text-time"; nextStationContainer.style.cssText = "position:absolute; top:80px; left:0px; width:100%; height:63px; display:flex; align-items:center; justify-content:center; font-size: 15px; color:#929497; text-align:center"; let nextStationText = document.createElement("div"); nextStationText.innerHTML = 'Prochaine station :<br><strong id="nextStation">---</strong>'; nextStationContainer.appendChild(nextStationText); timeBoxOpened.appendChild(nextStationContainer); // Create distance display let distanceContainer = document.createElement("div"); distanceContainer.className = "text-time"; distanceContainer.style.cssText = "position:absolute; top:108px; left:0px; width:100%; height:63px; display:flex; align-items:center; justify-content:center; font-size: 15px; color:#929497; text-align:center"; let distanceText = document.createElement("div"); distanceText.innerHTML = 'Distance : <strong id="distance">--m</strong>'; distanceContainer.appendChild(distanceText); timeBoxOpened.appendChild(distanceContainer); // Create close button in time-boxOpened let closeButton = document.createElement("div"); closeButton.style.cssText = "position:absolute; top:0px; right:0px; width:19px; height:19px; background-color: #929497; border-radius:100%; display:flex; align-items:center; justify-content:center; cursor:pointer"; closeButton.onclick = () => { document.getElementById("time-boxClosed").style.display = ""; document.getElementById("time-boxOpened").style.display = "none"; }; timeBoxOpened.appendChild(closeButton); let closeSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); closeSvg.setAttribute("width", "19"); closeSvg.setAttribute("height", "19"); closeSvg.setAttribute("viewBox", "0 0 19 19"); closeSvg.setAttribute("fill", "none"); let line1 = document.createElementNS("http://www.w3.org/2000/svg", "line"); line1.setAttribute("x1", "5.35355"); line1.setAttribute("y1", "5.64645"); line1.setAttribute("x2", "13.35"); line1.setAttribute("y2", "13.6429"); line1.setAttribute("stroke", "#B81111"); let line2 = document.createElementNS("http://www.w3.org/2000/svg", "line"); line2.setAttribute("x1", "5.17959"); line2.setAttribute("y1", "13.6464"); line2.setAttribute("x2", "13.1761"); line2.setAttribute("y2", "5.64996"); line2.setAttribute("stroke", "#B81111"); closeSvg.appendChild(line1); closeSvg.appendChild(line2); closeButton.appendChild(closeSvg); // Create auto button div let autoButton = document.createElement("div"); autoButton.id = "auto"; const styles = getComputedStyle(document.getElementById("emergencyStop")); for (const prop of styles) { autoButton.style.setProperty(prop, styles.getPropertyValue(prop)); } autoButton.style.marginTop = `${ document.getElementById("emergencyStop").offsetHeight + 10 }px`; autoButton.innerHTML = '<span class="center">AUTO</span>'; autoButton.onmouseover = function () { this.style.border = "solid #EE5757 3px"; }; autoButton.onmouseout = function () { this.style.border = "solid transparent 3px"; }; document.getElementById("pupitre").appendChild(autoButton); // Create canvas element let canvasPlan = document.createElement("canvas"); canvasPlan.id = "canvasPlan"; canvasPlan.style.cssText = `position:absolute; top:0px; left: ${ document.getElementById("display").offsetWidth }px;`; document.body.appendChild(canvasPlan); if ( document.getElementById("mf01_bfdg") || document.getElementById("mp89_kfu") ) { document.getElementById("time-box").style.left = "1023px"; if (document.getElementById("mf01_bfdg")) { document.getElementById("auto").style.left = "953px"; document.getElementById("auto").style.bottom = "20px"; document.getElementById("time-box").style.height = "152px"; document.getElementById("time-boxClosed").style.backgroundColor = document.getElementById("time-boxOpened").style.backgroundColor = "#00398E"; } else if (document.getElementById("mp89_kfu")) { document.getElementById("auto").style.left = "830px"; document.getElementById("auto").style.bottom = "95px"; document.getElementById("time-boxClosed").style.backgroundColor = document.getElementById("time-boxOpened").style.backgroundColor = "#61777B"; Object.values(document.getElementsByClassName("text-time")).forEach( (element) => { element.style.color = "#B0B2B4"; } ); } } }; (function () { "use strict"; if (location.pathname === "/game") { const orignialLoad = _load; _load = () => { orignialLoad(); displayUI(); settings(); plan(); timer(); auto(); }; } })();