Make custom lobbies persistent, add bot count and spawn selection options
Update v0.6.6.8main
parent
9b85d5d9b4
commit
8a85790caf
1
build.js
1
build.js
|
@ -145,6 +145,7 @@ const rawCodeSegments = [
|
||||||
"[0]=__L(),@strs[1]=@game.@gIsSingleplayer?__L():__L(),",
|
"[0]=__L(),@strs[1]=@game.@gIsSingleplayer?__L():__L(),",
|
||||||
"?(this.gB=Math.floor(.066*aK.fw),g5=aK.g5-4*@uiSizes.@gap-this.gB):",
|
"?(this.gB=Math.floor(.066*aK.fw),g5=aK.g5-4*@uiSizes.@gap-this.gB):",
|
||||||
`for(a0L=new Array(@game.@gMaxPlayers),a0A.font=a07,@i=game.gMaxPlayers-1;0<=i;i--)a0L[i]=i+1+".",@playerData.@playerNames[i]=aY.qW.tm(playerData.@rawPlayerNames[i],a07,a0W),a0K[i]=Math.floor(a0A.measureText(playerData.playerNames[i]).width);`,
|
`for(a0L=new Array(@game.@gMaxPlayers),a0A.font=a07,@i=game.gMaxPlayers-1;0<=i;i--)a0L[i]=i+1+".",@playerData.@playerNames[i]=aY.qW.tm(playerData.@rawPlayerNames[i],a07,a0W),a0K[i]=Math.floor(a0A.measureText(playerData.playerNames[i]).width);`,
|
||||||
|
`var dt=@MenuManager.@getState();if(6===dt){if(4211===d)`
|
||||||
]
|
]
|
||||||
|
|
||||||
rawCodeSegments.forEach(code => {
|
rawCodeSegments.forEach(code => {
|
||||||
|
|
21
patches.js
21
patches.js
|
@ -318,11 +318,16 @@ canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6
|
||||||
replaceRawCode("this.xY=function(){this.wg(),Sockets.kt.wf(3240),aN.setState(0),i___.j(5,5)}",
|
replaceRawCode("this.xY=function(){this.wg(),Sockets.kt.wf(3240),aN.setState(0),i___.j(5,5)}",
|
||||||
`this.xY=function(){this.wg(),Sockets.kt.wf(3240),__fx.customLobby.setActive(false),aN.setState(0),i___.j(5,5)},
|
`this.xY=function(){this.wg(),Sockets.kt.wf(3240),__fx.customLobby.setActive(false),aN.setState(0),i___.j(5,5)},
|
||||||
__fx.customLobby.setLeaveFunction(() => this.xY())`)
|
__fx.customLobby.setLeaveFunction(() => this.xY())`)
|
||||||
|
// when a socket error occurs on the custom lobby socket
|
||||||
replaceRawCode("this.wQ=function(wR,d){if(8===i.pz&&0===wR)if(4211===d)wS(d);",
|
replaceRawCode("this.wQ=function(wR,d){if(8===i.pz&&0===wR)if(4211===d)wS(d);",
|
||||||
"this.wQ=function(wR,d){ wR===1&&__fx.customLobby.isActive()&&__fx.customLobby.setActive(false); if(8===i.pz&&0===wR)if(4211===d)wS(d);")
|
`this.wQ=function(wR,d){
|
||||||
|
wR===1 && __fx.customLobby.isActive() && ${dict.MenuManager}.${dict.getState}() !== 6 && __fx.customLobby.setActive(false);
|
||||||
|
if(8===i.pz&&0===wR)if(4211===d)wS(d);`)
|
||||||
// when leaving a game
|
// when leaving a game
|
||||||
replaceRawCode("this.wl=function(zs){ap.ky.zt(),this.vH=0,bU.zu(),m.n.setState(0),zs||bJ.df.show(),aN.setState(0),i.j(5,5)}",
|
replaceRawCode("this.wl=function(zs){ap.ky.zt(),this.vH=0,bU.zu(),m.n.setState(0),zs||bJ.df.show(),aN.setState(0),i.j(5,5)}",
|
||||||
"this.wl=function(zs){__fx.customLobby.setActive(false); ap.ky.zt(),this.vH=0,bU.zu(),m.n.setState(0),zs||bJ.df.show(),aN.setState(0),i.j(5,5)}")
|
`this.wl=function(zs){ __fx.customLobby.isActive() === false && ap.ky.zt(),
|
||||||
|
this.vH=0,bU.zu(),m.n.setState(0),zs||bJ.df.show(),aN.setState(0);
|
||||||
|
if (__fx.customLobby.isActive()) __fx.customLobby.rejoinLobby(); else i.j(5,5)}`)
|
||||||
// if the server is unreachable
|
// if the server is unreachable
|
||||||
replaceRawCode("0===a7Q?g.wc(3249):", "0===a7Q?g.wc(3249):1===a7Q&&__fx.customLobby.isActive()?(g.wc(3249),__fx.customLobby.setActive(false)):")
|
replaceRawCode("0===a7Q?g.wc(3249):", "0===a7Q?g.wc(3249):1===a7Q&&__fx.customLobby.isActive()?(g.wc(3249),__fx.customLobby.setActive(false)):")
|
||||||
// error descriptions
|
// error descriptions
|
||||||
|
@ -332,11 +337,23 @@ canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6
|
||||||
// map info (for the map selection menu)
|
// map info (for the map selection menu)
|
||||||
replaceRawCode("this.info=new Array(Maps.totalMapCount+1),this.info[0]={name:__L(),",
|
replaceRawCode("this.info=new Array(Maps.totalMapCount+1),this.info[0]={name:__L(),",
|
||||||
"this.info=new Array(Maps.totalMapCount+1),__fx.customLobby.setMapInfo(this.info),this.info[0]={name:__L(),")
|
"this.info=new Array(Maps.totalMapCount+1),__fx.customLobby.setMapInfo(this.info),this.info[0]={name:__L(),")
|
||||||
|
// to not set custom lobby games as singleplayer
|
||||||
|
replaceRawCode(",a.b(c,d),1===players.length&&SingleplayerMenu.a9H(type),",
|
||||||
|
",a.b(c,d),1===players.length&&!__fx.customLobby.isActive()&&SingleplayerMenu.a9H(type),");
|
||||||
|
replaceRawCode(",this.vK=this.jS=players.length,this.gameIsSingleplayer=1===this.vK,",
|
||||||
|
",this.vK=this.jS=players.length,this.gameIsSingleplayer=1===this.vK&&!__fx.customLobby.isActive(),")
|
||||||
// custom difficulty
|
// custom difficulty
|
||||||
replaceRawCode("if(ax.jm){if(ax.jn.jo)for(i=game.jp-1;0<=i;i--)this.strength[i+jl]=ax.jn.jo[i+1]}else if(9===game.jq)this.jr();",
|
replaceRawCode("if(ax.jm){if(ax.jn.jo)for(i=game.jp-1;0<=i;i--)this.strength[i+jl]=ax.jn.jo[i+1]}else if(9===game.jq)this.jr();",
|
||||||
`if(ax.jm){if(ax.jn.jo)for(i=game.jp-1;0<=i;i--)this.strength[i+jl]=ax.jn.jo[i+1]}else if(9===game.jq)this.jr();
|
`if(ax.jm){if(ax.jn.jo)for(i=game.jp-1;0<=i;i--)this.strength[i+jl]=ax.jn.jo[i+1]}else if(9===game.jq)this.jr();
|
||||||
else if (__fx.customLobby.isActive()) for(i=game.jp-1;0<=i;i--) this.strength[i+jl] = __fx.customLobby.gameInfo.difficulty;`
|
else if (__fx.customLobby.isActive()) for(i=game.jp-1;0<=i;i--) this.strength[i+jl] = __fx.customLobby.gameInfo.difficulty;`
|
||||||
)
|
)
|
||||||
|
// spawn selection
|
||||||
|
replaceRawCode(",ax.jm&&!ax.jn.zi?this.zZ=this.gh=!1:this.zZ=this.gh=this.iS||this.jS<100,",
|
||||||
|
",ax.jm&&!ax.jn.zi?this.zZ=this.gh=!1 : __fx.customLobby.isActive() ? this.zZ=this.gh=__fx.customLobby.gameInfo.spawnSelection : this.zZ=this.gh=this.iS||this.jS<100,")
|
||||||
|
// bot count
|
||||||
|
replaceRawCode(",this.js?this.t1=aO.zj():this.t1=this.maxPlayers,this.jp=this.t1-this.jS,",
|
||||||
|
`,__fx.customLobby.isActive() ? this.t1 = Math.max(Math.min(__fx.customLobby.gameInfo.botCount, this.maxPlayers), this.jS)
|
||||||
|
: this.js?this.t1=aO.zj():this.t1=this.maxPlayers,this.jp=this.t1-this.jS,`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid hostname detection avoidance
|
// Invalid hostname detection avoidance
|
||||||
|
|
|
@ -34,6 +34,7 @@ const playerList = document.createElement("div");
|
||||||
playerListContainer.append(playerCount, playerList);
|
playerListContainer.append(playerCount, playerList);
|
||||||
|
|
||||||
const optionsContainer = document.createElement("div");
|
const optionsContainer = document.createElement("div");
|
||||||
|
optionsContainer.className = "text-align-left";
|
||||||
|
|
||||||
const optionsStructure = {
|
const optionsStructure = {
|
||||||
mode: {
|
mode: {
|
||||||
|
@ -51,26 +52,32 @@ const optionsStructure = {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
map: { label: "Map:", type: "selectMenu" },
|
map: { label: "Map:", type: "selectMenu" },
|
||||||
difficulty: { label: "Difficulty", type: "selectMenu", options: [
|
difficulty: { label: "Difficulty:", type: "selectMenu", options: [
|
||||||
{ value: 0, label: "Very Easy (Default)" },
|
{ value: 0, label: "Very Easy (Default)" },
|
||||||
{ value: 1, label: "Easy (1v1)" },
|
{ value: 1, label: "Easy (1v1)" },
|
||||||
{ value: 2, label: "Normal" },
|
{ value: 2, label: "Normal" },
|
||||||
{ value: 3, label: "Hard" },
|
{ value: 3, label: "Hard" },
|
||||||
{ value: 4, label: "Very Hard" },
|
{ value: 4, label: "Very Hard" },
|
||||||
{ value: 5, label: "Impossible" }
|
{ value: 5, label: "Impossible" }
|
||||||
]}
|
]},
|
||||||
|
spawnSelection: { label: "Spawn selection", type: "checkbox" },
|
||||||
|
botCount: { label: "Bot & player count:", type: "numberInput", attributes: { min: "1", max: "512" } }
|
||||||
}
|
}
|
||||||
const optionsElements = {};
|
const optionsElements = {};
|
||||||
const optionsValues = {};
|
const optionsValues = {};
|
||||||
|
|
||||||
function updateOption(option, value) {
|
function updateOption(option, value) {
|
||||||
value = value.toString();
|
if (optionsStructure[option].type === "checkbox")
|
||||||
optionsElements[option].value = value.toString();
|
optionsElements[option].checked = (value === 0 ? false : true);
|
||||||
|
else optionsElements[option].value = value.toString();
|
||||||
optionsValues[option] = value;
|
optionsValues[option] = value;
|
||||||
}
|
}
|
||||||
function inputUpdateHandler(key, e) {
|
function inputUpdateHandler(key, e) {
|
||||||
sendMessage("options", [key, parseInt(e.target.value)])
|
sendMessage("options", [key, parseInt(e.target.value)])
|
||||||
}
|
}
|
||||||
|
function checkboxUpdateHandler(key, e) {
|
||||||
|
sendMessage("options", [key, e.target.checked ? 1 : 0])
|
||||||
|
}
|
||||||
Object.entries(optionsStructure).forEach(([key, item]) => {
|
Object.entries(optionsStructure).forEach(([key, item]) => {
|
||||||
const label = document.createElement("label");
|
const label = document.createElement("label");
|
||||||
if (item.tooltip) label.title = item.tooltip;
|
if (item.tooltip) label.title = item.tooltip;
|
||||||
|
@ -82,6 +89,7 @@ Object.entries(optionsStructure).forEach(([key, item]) => {
|
||||||
);
|
);
|
||||||
optionsElements[key] = element;
|
optionsElements[key] = element;
|
||||||
if (item.type === "textInput") element.type = "text";
|
if (item.type === "textInput") element.type = "text";
|
||||||
|
if (item.type === "numberInput") element.type = "number";
|
||||||
if (item.placeholder) element.placeholder = item.placeholder;
|
if (item.placeholder) element.placeholder = item.placeholder;
|
||||||
if (isValueInput || item.type === "selectMenu")
|
if (isValueInput || item.type === "selectMenu")
|
||||||
element.addEventListener("change", inputUpdateHandler.bind(undefined, key))
|
element.addEventListener("change", inputUpdateHandler.bind(undefined, key))
|
||||||
|
@ -94,6 +102,9 @@ Object.entries(optionsStructure).forEach(([key, item]) => {
|
||||||
label.append(document.createElement("br"), note);
|
label.append(document.createElement("br"), note);
|
||||||
}
|
}
|
||||||
if (item.options) setSelectMenuOptions(item.options, element);
|
if (item.options) setSelectMenuOptions(item.options, element);
|
||||||
|
if (item.attributes) Object.entries(item.attributes).forEach(
|
||||||
|
([name, value]) => element.setAttribute(name, value)
|
||||||
|
);
|
||||||
label.append(element);
|
label.append(element);
|
||||||
if (item.type === "checkbox") {
|
if (item.type === "checkbox") {
|
||||||
element.type = "checkbox";
|
element.type = "checkbox";
|
||||||
|
@ -102,18 +113,14 @@ Object.entries(optionsStructure).forEach(([key, item]) => {
|
||||||
label.className = "checkbox";
|
label.className = "checkbox";
|
||||||
label.append(checkmark);
|
label.append(checkmark);
|
||||||
//checkboxFields[item.for] = element;
|
//checkboxFields[item.for] = element;
|
||||||
}// else label.append(document.createElement("br"));
|
element.addEventListener("change", checkboxUpdateHandler.bind(undefined, key))
|
||||||
optionsContainer.append(label, document.createElement("br"));
|
} else label.append(document.createElement("br"));
|
||||||
|
optionsContainer.append(label/*, document.createElement("br")*/);
|
||||||
});
|
});
|
||||||
|
|
||||||
function setMapInfo(maps) {
|
function setMapInfo(maps) {
|
||||||
setTimeout(() => setSelectMenuOptions(maps.map((info, index) => ({ value: index.toString(), label: info.name })), optionsElements["map"]), 0);
|
setTimeout(() => setSelectMenuOptions(maps.map((info, index) => ({ value: index.toString(), label: info.name })), optionsElements["map"]), 0);
|
||||||
}
|
}
|
||||||
/*const botCountInput = document.createElement("input");
|
|
||||||
botCountInput.setAttribute("type", "number");
|
|
||||||
botCountInput.setAttribute("min", "0");
|
|
||||||
botCountInput.setAttribute("max", "512");
|
|
||||||
botCountInput.value = "512";*/
|
|
||||||
|
|
||||||
main.append(playerListContainer, optionsContainer);
|
main.append(playerListContainer, optionsContainer);
|
||||||
|
|
||||||
|
@ -183,7 +190,8 @@ function isCustomMessage(raw) {
|
||||||
currentCode = data.code;
|
currentCode = data.code;
|
||||||
playerIsHost = data.isHost;
|
playerIsHost = data.isHost;
|
||||||
startButton.disabled = !playerIsHost;
|
startButton.disabled = !playerIsHost;
|
||||||
optionsContainer.className = playerIsHost ? "" : "disabled";
|
if (playerIsHost) optionsContainer.classList.remove("disabled");
|
||||||
|
else optionsContainer.classList.add("disabled");
|
||||||
Object.entries(data.options).forEach(([option, value]) => updateOption(option, value));
|
Object.entries(data.options).forEach(([option, value]) => updateOption(option, value));
|
||||||
displayPlayers(data.players);
|
displayPlayers(data.players);
|
||||||
} else if (type === "addPlayer") {
|
} else if (type === "addPlayer") {
|
||||||
|
@ -194,8 +202,10 @@ function isCustomMessage(raw) {
|
||||||
playerElements[index].element.remove();
|
playerElements[index].element.remove();
|
||||||
playerElements.splice(index, 1);
|
playerElements.splice(index, 1);
|
||||||
updatePlayerCount();
|
updatePlayerCount();
|
||||||
|
} else if (type === "inLobby") {
|
||||||
|
const index = data;
|
||||||
|
playerElements[index].inGameBadge.className = "d-none";
|
||||||
} else if (type === "options") {
|
} else if (type === "options") {
|
||||||
console.log(data);
|
|
||||||
const [option, value] = data;
|
const [option, value] = data;
|
||||||
updateOption(option, value);
|
updateOption(option, value);
|
||||||
} else if (type === "setHost") {
|
} else if (type === "setHost") {
|
||||||
|
@ -205,14 +215,21 @@ function isCustomMessage(raw) {
|
||||||
} else if (type === "host") {
|
} else if (type === "host") {
|
||||||
playerIsHost = true;
|
playerIsHost = true;
|
||||||
startButton.disabled = false;
|
startButton.disabled = false;
|
||||||
optionsContainer.className = "";
|
optionsContainer.classList.remove("disabled");
|
||||||
playerElements.forEach(p => { if (!p.isHost) p.kickButton.className = "" });
|
playerElements.forEach(p => { if (!p.isHost) p.kickButton.className = "" });
|
||||||
} else if (type === "serverMessage") alert(data);
|
} else if (type === "serverMessage") alert(data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/** @type {{ element: HTMLDivElement, hostBadge: HTMLSpanElement, kickButton: HTMLButtonElement, isHost: boolean }[]} */
|
/** @type {{ element: HTMLDivElement, hostBadge: HTMLSpanElement, inGameBadge: HTMLSpanElement, kickButton: HTMLButtonElement, isHost: boolean }[]} */
|
||||||
let playerElements = [];
|
let playerElements = [];
|
||||||
/** @param {{ name: string, isHost: boolean }} player */
|
function createBadge(text, visible) {
|
||||||
|
const badge = document.createElement("span");
|
||||||
|
badge.textContent = text;
|
||||||
|
badge.className = visible ? "" : "d-none";
|
||||||
|
return badge;
|
||||||
|
}
|
||||||
|
/** @typedef {{ name: string, isHost?: boolean, inGame?: boolean }} PlayerInfo */
|
||||||
|
/** @param {PlayerInfo} player */
|
||||||
function addPlayer(player) {
|
function addPlayer(player) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.className = "lobby-player";
|
div.className = "lobby-player";
|
||||||
|
@ -221,12 +238,11 @@ function addPlayer(player) {
|
||||||
kickButton.textContent = "Kick";
|
kickButton.textContent = "Kick";
|
||||||
kickButton.className = playerIsHost && !player.isHost ? "" : "d-none";
|
kickButton.className = playerIsHost && !player.isHost ? "" : "d-none";
|
||||||
kickButton.addEventListener("click", kickButtonHandler);
|
kickButton.addEventListener("click", kickButtonHandler);
|
||||||
const badge = document.createElement("span");
|
const hostBadge = createBadge("Host", player.isHost);
|
||||||
badge.textContent = "Host";
|
const inGameBadge = createBadge("In Game", player.inGame);
|
||||||
badge.className = player.isHost ? "" : "d-none";
|
div.append(hostBadge, inGameBadge, kickButton);
|
||||||
div.append(badge, kickButton);
|
|
||||||
playerList.append(div);
|
playerList.append(div);
|
||||||
playerElements.push({ element: div, hostBadge: badge, kickButton, isHost: player.isHost });
|
playerElements.push({ element: div, hostBadge, inGameBadge, kickButton, isHost: player.isHost });
|
||||||
}
|
}
|
||||||
function kickButtonHandler(event) {
|
function kickButtonHandler(event) {
|
||||||
const button = event.target;
|
const button = event.target;
|
||||||
|
@ -237,7 +253,7 @@ function kickButtonHandler(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** @param {{ name: string, isHost: boolean }[]} players */
|
/** @param {PlayerInfo[]} players */
|
||||||
function displayPlayers(players) {
|
function displayPlayers(players) {
|
||||||
playerElements = [];
|
playerElements = [];
|
||||||
playerList.innerHTML = "";
|
playerList.innerHTML = "";
|
||||||
|
@ -255,7 +271,9 @@ function startGame() {
|
||||||
WindowManager.closeWindow("customLobby");
|
WindowManager.closeWindow("customLobby");
|
||||||
sendMessage("startGame");
|
sendMessage("startGame");
|
||||||
}
|
}
|
||||||
|
function rejoinLobby() {
|
||||||
|
joinLobby();
|
||||||
|
}
|
||||||
|
|
||||||
function setJoinFunction(f) { joinLobby = f; }
|
function setJoinFunction(f) { joinLobby = f; }
|
||||||
function setLeaveFunction(f) { leaveLobby = f; }
|
function setLeaveFunction(f) { leaveLobby = f; }
|
||||||
|
@ -267,7 +285,7 @@ function setActive(active) {
|
||||||
function hideWindow() {
|
function hideWindow() {
|
||||||
WindowManager.closeWindow("customLobby");
|
WindowManager.closeWindow("customLobby");
|
||||||
}
|
}
|
||||||
const gameInterface = { gameInfo: optionsValues, showJoinPrompt, isCustomMessage, getSocketURL, setJoinFunction, setLeaveFunction, setSendFunction, setMapInfo, hideWindow, isActive: () => isActive, setActive }
|
const gameInterface = { gameInfo: optionsValues, showJoinPrompt, isCustomMessage, getSocketURL, setJoinFunction, setLeaveFunction, setSendFunction, setMapInfo, rejoinLobby, hideWindow, isActive: () => isActive, setActive }
|
||||||
|
|
||||||
const customLobby = gameInterface
|
const customLobby = gameInterface
|
||||||
export default customLobby
|
export default customLobby
|
|
@ -1,5 +1,5 @@
|
||||||
const fx_version = '0.6.6.7'; // FX Client Version
|
const fx_version = '0.6.6.8'; // FX Client Version
|
||||||
const fx_update = 'Nov 25'; // FX Client Last Updated
|
const fx_update = 'Dec 8'; // FX Client Last Updated
|
||||||
|
|
||||||
import settingsManager from './settings.js';
|
import settingsManager from './settings.js';
|
||||||
import { clanFilter, leaderboardFilter } from "./clanFilters.js";
|
import { clanFilter, leaderboardFilter } from "./clanFilters.js";
|
||||||
|
|
|
@ -110,6 +110,9 @@
|
||||||
.text-align-center {
|
.text-align-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.text-align-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
Loading…
Reference in New Issue