Custom lobby difficulty option, hide bot names setting
Custom lobby options are now automatically generated from a specified structure, similar to the settings menu Update v0.6.6.7main
parent
407716b11b
commit
9b85d5d9b4
27
patches.js
27
patches.js
|
@ -140,7 +140,7 @@ canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6
|
|||
`, ${dict.game}.${dict.gIsTeamGame} && __fx.donationsTracker.displayHistory($2, ${rawPlayerNames}, ${gIsSingleplayer}), $1 && !isEmptySpace $3`);
|
||||
|
||||
// Reset donation history and leaderboard filter when a new game is started
|
||||
replaceOne(new RegExp(`,this\\.${dictionary.playerBalances}.fill\\(0\\),`, "g"), "$& __fx.donationsTracker.reset(), __fx.leaderboardFilter.reset(), __fx.customLobby.isActive() && __fx.customLobby.setActive(false), ");
|
||||
replaceOne(new RegExp(`,this\\.${dictionary.playerBalances}.fill\\(0\\),`, "g"), "$& __fx.donationsTracker.reset(), __fx.leaderboardFilter.reset(), __fx.customLobby.isActive() && __fx.customLobby.hideWindow(), ");
|
||||
|
||||
{ // Player list and leaderboard filter tabs
|
||||
// Draw player list button
|
||||
|
@ -164,19 +164,24 @@ canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6
|
|||
)) return; $4`);
|
||||
}
|
||||
|
||||
{ // Display density of other players
|
||||
{ // Name rendering patches - Display density of other players & Hide bot names features
|
||||
const r = matchRawCode(`bD.dO.data[7].value?a9W(i,jm,jk,jl,ctx):a9V(ctx,i,jm,jk,jl,a9S)))`);
|
||||
const settingsSwitchNameAndBalance = `${r.bD}.${r.dO}.${r.data}[7].${r.value}`;
|
||||
//console.log(settingsSwitchNameAndBalance);
|
||||
// Applies when the "Reverse Name/Balance" setting is off
|
||||
// Balance rendering; Renders density when the "Reverse Name/Balance" setting is off
|
||||
replaceRawCode("function a9V(ctx,i,fontSize,x,y,a9S){i=ac.jv.formatNumber(playerData.playerBalances[i]);a9S>>1&1?(ctx.lineWidth=.05*fontSize,ctx.strokeStyle=a9U(fontSize,a9S%2),ctx.strokeText(i,x,y)):(1<a9S&&(ctx.lineWidth=.12*fontSize,ctx.strokeStyle=a9U(fontSize,a9S),ctx.strokeText(i,x,y)),ctx.fillText(i,x,y))}",
|
||||
`function a9V(ctx,i,fontSize,x,y,a9S){
|
||||
var ___id = i;
|
||||
i=ac.jv.formatNumber(playerData.playerBalances[i]);a9S>>1&1?(ctx.lineWidth=.05*fontSize,ctx.strokeStyle=a9U(fontSize,a9S%2),ctx.strokeText(i,x,y)):(1<a9S&&(ctx.lineWidth=.12*fontSize,ctx.strokeStyle=a9U(fontSize,a9S),ctx.strokeText(i,x,y)),ctx.fillText(i,x,y));
|
||||
${settingsSwitchNameAndBalance} || __fx.settings.showPlayerDensity && (__fx.settings.coloredDensity && (ctx.fillStyle = __fx.utils.textStyleBasedOnDensity(___id)), ctx.fillText(__fx.utils.getDensity(___id), x, y + fontSize))}`)
|
||||
// Applies when the "Reverse Name/Balance" setting is on (default)
|
||||
replaceOne(/(function \w+\((\w+),(?<fontSize>\w+),(?<x>\w+),(?<y>\w+),(?<canvas>\w+)\){)(\6\.fillText\((?<playerData>\w+)\.(?<playerNames>\w+)\[\2\],\4,\5\)),(\2<(?<game>\w+)\.(?<gHumans>\w+)&&2!==\8\.(?<playerStates>\w+)\[[^}]+)}/g,
|
||||
`$1 var ___id = $2; $7, $10; ${settingsSwitchNameAndBalance} && __fx.settings.showPlayerDensity && (__fx.settings.coloredDensity && ($<canvas>.fillStyle = __fx.utils.textStyleBasedOnDensity(___id)), $<canvas>.fillText(__fx.utils.getDensity(___id), $<x>, $<y> + $<fontSize>)); }`);
|
||||
// Name rendering; Renders density when the "Reverse Name/Balance" setting is on (default)
|
||||
replaceOne(/(function \w+\((?<i>\w+),(?<fontSize>\w+),(?<x>\w+),(?<y>\w+),(?<canvas>\w+)\){)(\6\.fillText\((?<playerData>\w+)\.(?<playerNames>\w+)\[\2\],\4,\5\)),(\2<(?<game>\w+)\.(?<gHumans>\w+)&&2!==\8\.(?<playerStates>\w+)\[[^}]+)}/g,
|
||||
`$1 var ___id = $2;
|
||||
var showName = $<i> < $<game>.$<gHumans> || !__fx.settings.hideBotNames;
|
||||
if (showName) $7, $10;
|
||||
${settingsSwitchNameAndBalance} && __fx.settings.showPlayerDensity && (
|
||||
__fx.settings.coloredDensity && ($<canvas>.fillStyle = __fx.utils.textStyleBasedOnDensity(___id)),
|
||||
$<canvas>.fillText(__fx.utils.getDensity(___id), $<x>, showName ? $<y> + $<fontSize> : $<y>)
|
||||
); }`);
|
||||
}
|
||||
|
||||
{ // Leaderboard filter
|
||||
|
@ -315,6 +320,9 @@ canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6
|
|||
__fx.customLobby.setLeaveFunction(() => this.xY())`)
|
||||
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);")
|
||||
// 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)}",
|
||||
"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)}")
|
||||
// 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)):")
|
||||
// error descriptions
|
||||
|
@ -324,6 +332,11 @@ canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6
|
|||
// map info (for the map selection menu)
|
||||
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(),")
|
||||
// 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();",
|
||||
`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;`
|
||||
)
|
||||
}
|
||||
|
||||
// Invalid hostname detection avoidance
|
||||
|
|
|
@ -10,9 +10,6 @@ let leaveLobby = () => { };
|
|||
let sendRaw = (socketId, data) => { };
|
||||
const textEncoder = new TextEncoder();
|
||||
const textDecoder = new TextDecoder();
|
||||
/*const gameInfo = {
|
||||
botCount: 512
|
||||
}*/
|
||||
|
||||
WindowManager.add({
|
||||
name: "lobbyJoinMenu",
|
||||
|
@ -36,38 +33,87 @@ playerCount.textContent = "0 Players";
|
|||
const playerList = document.createElement("div");
|
||||
playerListContainer.append(playerCount, playerList);
|
||||
|
||||
// todo: convert the options into something similar to the automatic settings generator
|
||||
const optionsContainer = document.createElement("div");
|
||||
const gameModeSelectMenu = document.createElement("select");
|
||||
setSelectMenuOptions([
|
||||
{ value: 0, label: "2 Teams" },
|
||||
{ value: 1, label: "3 Teams" },
|
||||
{ value: 2, label: "4 Teams" },
|
||||
{ value: 3, label: "5 Teams" },
|
||||
{ value: 4, label: "6 Teams" },
|
||||
{ value: 5, label: "7 Teams" },
|
||||
{ value: 6, label: "8 Teams" },
|
||||
{ value: 7, label: "Battle Royale" },
|
||||
{ value: 10, label: "No Fullsend Battle Royale" },
|
||||
{ value: 9, label: "Zombie mode" }
|
||||
], gameModeSelectMenu);
|
||||
gameModeSelectMenu.value = "7";
|
||||
const mapSelectMenu = document.createElement("select");
|
||||
function setMapInfo(maps) {
|
||||
setTimeout(() => setSelectMenuOptions(maps.map((info, index) => ({ value: index.toString(), label: info.name })), mapSelectMenu), 0);
|
||||
|
||||
const optionsStructure = {
|
||||
mode: {
|
||||
label: "Mode:", type: "selectMenu", options: [
|
||||
{ value: 0, label: "2 Teams" },
|
||||
{ value: 1, label: "3 Teams" },
|
||||
{ value: 2, label: "4 Teams" },
|
||||
{ value: 3, label: "5 Teams" },
|
||||
{ value: 4, label: "6 Teams" },
|
||||
{ value: 5, label: "7 Teams" },
|
||||
{ value: 6, label: "8 Teams" },
|
||||
{ value: 7, label: "Battle Royale" },
|
||||
{ value: 10, label: "No Fullsend Battle Royale" },
|
||||
{ value: 9, label: "Zombie mode" }
|
||||
]
|
||||
},
|
||||
map: { label: "Map:", type: "selectMenu" },
|
||||
difficulty: { label: "Difficulty", type: "selectMenu", options: [
|
||||
{ value: 0, label: "Very Easy (Default)" },
|
||||
{ value: 1, label: "Easy (1v1)" },
|
||||
{ value: 2, label: "Normal" },
|
||||
{ value: 3, label: "Hard" },
|
||||
{ value: 4, label: "Very Hard" },
|
||||
{ value: 5, label: "Impossible" }
|
||||
]}
|
||||
}
|
||||
const optionsElements = {};
|
||||
const optionsValues = {};
|
||||
|
||||
function updateOption(option, value) {
|
||||
value = value.toString();
|
||||
optionsElements[option].value = value.toString();
|
||||
optionsValues[option] = value;
|
||||
}
|
||||
function inputUpdateHandler(key, e) {
|
||||
sendMessage("options", [key, parseInt(e.target.value)])
|
||||
}
|
||||
Object.entries(optionsStructure).forEach(([key, item]) => {
|
||||
const label = document.createElement("label");
|
||||
if (item.tooltip) label.title = item.tooltip;
|
||||
const isValueInput = item.type.endsWith("Input");
|
||||
const element = document.createElement(
|
||||
isValueInput || item.type === "checkbox" ? "input"
|
||||
: item.type === "selectMenu" ? "select"
|
||||
: "button"
|
||||
);
|
||||
optionsElements[key] = element;
|
||||
if (item.type === "textInput") element.type = "text";
|
||||
if (item.placeholder) element.placeholder = item.placeholder;
|
||||
if (isValueInput || item.type === "selectMenu")
|
||||
element.addEventListener("change", inputUpdateHandler.bind(undefined, key))
|
||||
if (item.text) element.innerText = item.text;
|
||||
if (item.action) element.addEventListener("click", item.action);
|
||||
if (item.label) label.append(item.label + " ");
|
||||
if (item.note) {
|
||||
const note = document.createElement("small");
|
||||
note.innerText = item.note;
|
||||
label.append(document.createElement("br"), note);
|
||||
}
|
||||
if (item.options) setSelectMenuOptions(item.options, element);
|
||||
label.append(element);
|
||||
if (item.type === "checkbox") {
|
||||
element.type = "checkbox";
|
||||
const checkmark = document.createElement("span");
|
||||
checkmark.className = "checkmark";
|
||||
label.className = "checkbox";
|
||||
label.append(checkmark);
|
||||
//checkboxFields[item.for] = element;
|
||||
}// else label.append(document.createElement("br"));
|
||||
optionsContainer.append(label, document.createElement("br"));
|
||||
});
|
||||
|
||||
function setMapInfo(maps) {
|
||||
setTimeout(() => setSelectMenuOptions(maps.map((info, index) => ({ value: index.toString(), label: info.name })), optionsElements["map"]), 0);
|
||||
}
|
||||
gameModeSelectMenu.addEventListener("change", e => sendMessage("options", ["mode", parseInt(e.target.value)]));
|
||||
mapSelectMenu.addEventListener("change", e => sendMessage("options", ["map", parseInt(e.target.value)]));
|
||||
/*const botCountInput = document.createElement("input");
|
||||
botCountInput.setAttribute("type", "number");
|
||||
botCountInput.setAttribute("min", "0");
|
||||
botCountInput.setAttribute("max", "512");
|
||||
botCountInput.value = "512";*/
|
||||
optionsContainer.append(
|
||||
"Mode: ", gameModeSelectMenu, document.createElement("br"),
|
||||
"Map: ", mapSelectMenu, document.createElement("br"),
|
||||
//"Bot count: "
|
||||
);
|
||||
|
||||
main.append(playerListContainer, optionsContainer);
|
||||
|
||||
|
@ -138,8 +184,7 @@ function isCustomMessage(raw) {
|
|||
playerIsHost = data.isHost;
|
||||
startButton.disabled = !playerIsHost;
|
||||
optionsContainer.className = playerIsHost ? "" : "disabled";
|
||||
gameModeSelectMenu.value = data.options.mode.toString();
|
||||
mapSelectMenu.value = data.options.map.toString();
|
||||
Object.entries(data.options).forEach(([option, value]) => updateOption(option, value));
|
||||
displayPlayers(data.players);
|
||||
} else if (type === "addPlayer") {
|
||||
addPlayer(data);
|
||||
|
@ -152,8 +197,7 @@ function isCustomMessage(raw) {
|
|||
} else if (type === "options") {
|
||||
console.log(data);
|
||||
const [option, value] = data;
|
||||
if (option === "mode") gameModeSelectMenu.value = value.toString();
|
||||
else if (option === "map") mapSelectMenu.value = value.toString();
|
||||
updateOption(option, value);
|
||||
} else if (type === "setHost") {
|
||||
const index = data;
|
||||
playerElements[index].isHost = true;
|
||||
|
@ -163,7 +207,7 @@ function isCustomMessage(raw) {
|
|||
startButton.disabled = false;
|
||||
optionsContainer.className = "";
|
||||
playerElements.forEach(p => { if (!p.isHost) p.kickButton.className = "" });
|
||||
}
|
||||
} else if (type === "serverMessage") alert(data);
|
||||
return true;
|
||||
}
|
||||
/** @type {{ element: HTMLDivElement, hostBadge: HTMLSpanElement, kickButton: HTMLButtonElement, isHost: boolean }[]} */
|
||||
|
@ -187,7 +231,10 @@ function addPlayer(player) {
|
|||
function kickButtonHandler(event) {
|
||||
const button = event.target;
|
||||
for (let index = 0; index < playerElements.length; index++) {
|
||||
if (playerElements[index].kickButton === button) sendMessage("kick", index);
|
||||
if (playerElements[index].kickButton === button) {
|
||||
sendMessage("kick", index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @param {{ name: string, isHost: boolean }[]} players */
|
||||
|
@ -206,7 +253,7 @@ function getSocketURL() {
|
|||
}
|
||||
function startGame() {
|
||||
WindowManager.closeWindow("customLobby");
|
||||
sendMessage("startGame" /*{ mode: gameModeSelectMenu.value, map: mapSelectMenu.value }*/);
|
||||
sendMessage("startGame");
|
||||
}
|
||||
|
||||
|
||||
|
@ -217,7 +264,10 @@ function setActive(active) {
|
|||
isActive = active;
|
||||
if (active === false) WindowManager.closeWindow("customLobby");
|
||||
}
|
||||
const gameInterface = { showJoinPrompt, isCustomMessage, getSocketURL, setJoinFunction, setLeaveFunction, setSendFunction, setMapInfo, isActive: () => isActive, setActive }
|
||||
function hideWindow() {
|
||||
WindowManager.closeWindow("customLobby");
|
||||
}
|
||||
const gameInterface = { gameInfo: optionsValues, showJoinPrompt, isCustomMessage, getSocketURL, setJoinFunction, setLeaveFunction, setSendFunction, setMapInfo, hideWindow, isActive: () => isActive, setActive }
|
||||
|
||||
const customLobby = gameInterface
|
||||
export default customLobby
|
|
@ -1,5 +1,5 @@
|
|||
const fx_version = '0.6.6.6'; // FX Client Version
|
||||
const fx_update = 'Nov 14'; // FX Client Last Updated
|
||||
const fx_version = '0.6.6.7'; // FX Client Version
|
||||
const fx_update = 'Nov 25'; // FX Client Last Updated
|
||||
|
||||
import settingsManager from './settings.js';
|
||||
import { clanFilter, leaderboardFilter } from "./clanFilters.js";
|
||||
|
|
|
@ -16,6 +16,7 @@ var settings = {
|
|||
showPlayerDensity: true,
|
||||
coloredDensity: true,
|
||||
densityDisplayStyle: "percentage",
|
||||
hideBotNames: false,
|
||||
highlightClanSpawns: false,
|
||||
//"customMapFileBtn": true
|
||||
customBackgroundUrl: "",
|
||||
|
@ -79,6 +80,7 @@ const settingsManager = new (function () {
|
|||
},
|
||||
],
|
||||
},
|
||||
{ for: "hideBotNames", type: "checkbox", label: "Hide bot names" },
|
||||
{
|
||||
for: "highlightClanSpawns",
|
||||
type: "checkbox",
|
||||
|
|
Loading…
Reference in New Issue