// ==UserScript==
// @name GeoFS Mod Menu -cool-
// @namespace http://tampermonkey.net/
// @version 1.3
// @description Mod Menu for GeoFS flight model variables using console-modifiable input fields
// @author Jasp
// @match https://www.geo-fs.com/*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// Preset values
const presets = {
"Default": {
maxRPM: 2500,
enginePower: 100000,
fuelFlow: 0.3,
dragFactor: 0.05,
liftFactor: 1.0
},
"High Power": {
maxRPM: 4000,
enginePower: 200000,
fuelFlow: 0.8,
dragFactor: 0.03,
liftFactor: 1.2
},
"Glider": {
maxRPM: 0,
enginePower: 0,
fuelFlow: 0,
dragFactor: 0.01,
liftFactor: 1.5
},
"Heavy Jet": {
maxRPM: 3200,
enginePower: 150000,
fuelFlow: 0.6,
dragFactor: 0.07,
liftFactor: 0.9
},
"Light Sport": {
maxRPM: 2800,
enginePower: 75000,
fuelFlow: 0.4,
dragFactor: 0.04,
liftFactor: 1.3
}
};
const variableSettings = {
maxRPM: { min: 1000, max: 4000 },
minRPM: { min: 500, max: 1500 },
starterRPM: { min: 300, max: 1000 },
idleThrottle: { min: 0.01, max: 0.2 },
fuelFlow: { min: 0.1, max: 1.0 },
enginePower: { min: 50000, max: 200000 },
brakeRPM: { min: 100, max: 1000 },
wingArea: { min: 5, max: 150 },
dragFactor: { min: 0.01, max: 0.2 },
liftFactor: { min: 0.5, max: 2.0 },
CD0: { min: 0.01, max: 0.1 },
CLmax: { min: 0.5, max: 2.0 },
elevatorFactor: { min: 0.1, max: 2.0 },
rudderFactor: { min: 0.1, max: 2.0 },
aileronFactor: { min: 0.1, max: 2.0 },
mass: { min: 500, max: 50000 },
emptyWeight: { min: 500, max: 30000 },
maxWeight: { min: 1000, max: 100000 },
inertia: { min: 100, max: 50000 },
pitchMoment: { min: 10, max: 5000 },
yawMoment: { min: 10, max: 5000 },
rollMoment: { min: 10, max: 5000 },
gearDrag: { min: 0.01, max: 0.5 },
gearCompression: { min: 0.01, max: 1.0 },
gearLength: { min: 0.5, max: 5.0 }
};
const categories = {
"Engine": ["maxRPM", "minRPM", "starterRPM", "idleThrottle", "fuelFlow", "enginePower", "brakeRPM"],
"Aerodynamics": ["wingArea", "dragFactor", "liftFactor", "CD0", "CLmax", "elevatorFactor", "rudderFactor", "aileronFactor"],
"Flight Model": ["mass", "emptyWeight", "maxWeight", "inertia", "pitchMoment", "yawMoment", "rollMoment"],
"Landing Gear": ["gearDrag", "gearCompression", "gearLength"]
};
const menuStyle = `
#geofsModMenu {
position: fixed;
top: 50px;
right: 20px;
background: rgba(0,0,0,0.85);
color: white;
padding: 15px;
border-radius: 10px;
z-index: 9999;
max-height: 90vh;
overflow-y: auto;
font-family: sans-serif;
font-size: 14px;
display: none;
width: 300px;
}
#geofsModMenu h2 {
font-size: 16px;
margin-top: 10px;
border-bottom: 1px solid #ccc;
}
#geofsModMenu input[type="number"] {
width: 80px;
margin: 2px 0;
background: #222;
color: white;
border: 1px solid #555;
padding: 3px;
}
#geofsModMenu input[type="range"] {
width: 100%;
margin-bottom: 10px;
}
.preset-button {
background: #444;
color: white;
padding: 4px 10px;
margin: 2px;
border: 1px solid #777;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
}
.preset-button:hover {
background: #666;
}
`;
const styleTag = document.createElement("style");
styleTag.innerHTML = menuStyle;
document.head.appendChild(styleTag);
const menu = document.createElement("div");
menu.id = "geofsModMenu";
const inputsMap = {}; // For syncing preset updates
// Add preset buttons
const presetHeader = document.createElement("h2");
presetHeader.textContent = "Presets";
menu.appendChild(presetHeader);
for (const [name, values] of Object.entries(presets)) {
const btn = document.createElement("button");
btn.textContent = name;
btn.className = "preset-button";
btn.onclick = () => {
for (const [key, val] of Object.entries(values)) {
const input = inputsMap[key]?.input;
const slider = inputsMap[key]?.slider;
if (input && slider) {
input.value = val;
slider.value = val;
updateModel(key, val);
}
}
};
menu.appendChild(btn);
}
// Add all variable controls
for (const [category, vars] of Object.entries(categories)) {
const header = document.createElement("h2");
header.textContent = category;
menu.appendChild(header);
vars.forEach(variable => {
const setting = variableSettings[variable] || { min: 0, max: 100 };
const label = document.createElement("label");
label.textContent = variable + ": ";
const input = document.createElement("input");
input.type = "number";
input.step = "any";
input.value = setting.min;
const slider = document.createElement("input");
slider.type = "range";
slider.min = setting.min;
slider.max = setting.max;
slider.step = (setting.max - setting.min) / 100;
slider.value = setting.min;
input.oninput = () => {
slider.value = input.value;
updateModel(variable, input.value);
};
slider.oninput = () => {
input.value = slider.value;
updateModel(variable, slider.value);
};
inputsMap[variable] = { input, slider };
label.appendChild(input);
menu.appendChild(label);
menu.appendChild(slider);
menu.appendChild(document.createElement("br"));
});
}
document.body.appendChild(menu);
function updateModel(variable, value) {
try {
if (geofs?.aircraft?.instance?.flightModel) {
const model = geofs.aircraft.instance.flightModel;
if (variable in model) {
model[variable] = parseFloat(value);
console.log(`[MOD MENU] Set ${variable} to ${value}`);
}
}
} catch (err) {
console.error("GeoFS mod menu error:", err);
}
}
// Toggle menu with '#'
document.addEventListener("keydown", function (e) {
if (e.key === "#") {
menu.style.display = (menu.style.display === "none") ? "block" : "none";
}
});
console.log("[GeoFS Mod Menu] Loaded. Press '#' to toggle.");
})();