/**
* @class
*/
function Cheat(input)
{
if (input.player < 0)
return;
const cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
const playerEnt = cmpPlayerManager.GetPlayerByID(input.player);
if (playerEnt == INVALID_ENTITY)
return;
const cmpPlayer = Engine.QueryInterface(playerEnt, IID_Player);
if (!cmpPlayer?.GetCheatsEnabled())
return;
const cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
switch(input.action)
{
case "addresource":
if (isNaN(input.parameter))
return;
cmpPlayer.AddResource(input.text, input.parameter);
return;
case "revealmap":
Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).SetLosRevealAll(-1, true);
return;
case "maxpopulation":
cmpPlayer.SetPopulationBonuses((cmpPlayerManager.GetMaxWorldPopulation() || cmpPlayer.GetMaxPopulation()) + 500);
return;
case "changemaxpopulation":
{
Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager).AddModifiers("cheat/maxpopulation", {
"Player/MaxPopulation": [{ "affects": ["Player"], "add": 500 }],
}, playerEnt);
return;
}
case "convertunit":
if (isNaN(input.parameter))
return;
const playerID = (input.parameter > -1 && QueryPlayerIDInterface(input.parameter) || cmpPlayer).GetPlayerID();
for (const ent of input.selected)
Engine.QueryInterface(ent, IID_Ownership)?.SetOwner(playerID);
return;
case "killunits":
for (const ent of input.selected)
{
const cmpHealth = Engine.QueryInterface(ent, IID_Health);
if (cmpHealth)
cmpHealth.Kill();
else
Engine.DestroyEntity(ent);
}
return;
case "defeatplayer":
if (isNaN(input.parameter))
return;
QueryPlayerIDInterface(input.parameter)?.SetState("defeated",
markForTranslation("%(player)s has been defeated (cheat).")
);
return;
case "createunits":
{
if (isNaN(input.player) || isNaN(input.parameter))
return;
const cmpTrainer = input.selected.length && Engine.QueryInterface(input.selected[0], IID_Trainer);
if (!cmpTrainer)
{
cmpGuiInterface.PushNotification({
"type": "text",
"players": [input.player],
"message": markForTranslation("You need to select a building that trains units."),
"translateMessage": true
});
return;
}
let owner = input.player;
const cmpOwnership = Engine.QueryInterface(input.selected[0], IID_Ownership);
if (cmpOwnership)
owner = cmpOwnership.GetOwner();
for (let i = 0; i < Math.min(input.parameter, cmpPlayer.GetMaxPopulation() - cmpPlayer.GetPopulationCount()); ++i)
{
const batch = new cmpTrainer.Item(input.templates[i % input.templates.length], 1, input.selected[0], null);
batch.player = owner;
batch.Finish();
// ToDo: If not able to spawn, cancel the batch.
}
return;
}
case "fastactions":
{
const cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
if (cmpModifiersManager.HasAnyModifier("cheat/fastactions", playerEnt))
cmpModifiersManager.RemoveAllModifiers("cheat/fastactions", playerEnt);
else
cmpModifiersManager.AddModifiers("cheat/fastactions", {
"Cost/BuildTime": [{ "affects": [["Structure"], ["Unit"]], "multiply": 0.01 }],
"ResourceGatherer/BaseSpeed": [{ "affects": [["Structure"], ["Unit"]], "multiply": 1000 }],
"Pack/Time": [{ "affects": [["Structure"], ["Unit"]], "multiply": 0.01 }],
"Upgrade/Time": [{ "affects": [["Structure"], ["Unit"]], "multiply": 0.01 }],
"Researcher/TechCostMultiplier/time": [{ "affects": [["Structure"], ["Unit"]], "multiply": 0.01 }]
}, playerEnt);
return;
}
case "changephase":
{
const cmpTechnologyManager = Engine.QueryInterface(playerEnt, IID_TechnologyManager);
if (!cmpTechnologyManager)
return;
// store the phase we want in the next input parameter
let parameter;
if (!cmpTechnologyManager.IsTechnologyResearched("phase_town"))
parameter = "phase_town";
else if (!cmpTechnologyManager.IsTechnologyResearched("phase_city"))
parameter = "phase_city";
else
return;
if (TechnologyTemplates.Has(parameter + "_" + cmpPlayer.civ))
parameter += "_" + cmpPlayer.civ;
else
parameter += "_generic";
Cheat({
"player": input.player,
"action": "researchTechnology",
"parameter": parameter,
"selected": input.selected
});
return;
}
case "researchTechnology":
{
if (!input.parameter.length)
return;
let techname = input.parameter;
const cmpTechnologyManager = Engine.QueryInterface(playerEnt, IID_TechnologyManager);
if (!cmpTechnologyManager)
return;
// check, if building is selected
if (input.selected[0])
{
const cmpResearcher = Engine.QueryInterface(input.selected[0], IID_Researcher);
if (cmpResearcher)
{
// try to spilt the input
const tmp = input.parameter.split(/\s+/);
const number = +tmp[0];
const pair = tmp.length > 1 && (tmp[1] == "top" || tmp[1] == "bottom") ? tmp[1] : "top"; // use top as default value
// check, if valid number was parsed.
if (!isNaN(number))
{
// get name of tech
const techs = cmpResearcher.GetTechnologiesList();
if (number > 0 && number <= techs.length)
{
const tech = techs[number-1];
if (!tech)
return;
// get name of tech
if (tech.pair)
techname = tech[pair];
else
techname = tech;
}
else
return;
}
}
}
if (TechnologyTemplates.Has(techname))
cmpTechnologyManager.ResearchTechnology(techname);
return;
}
case "metaCheat":
for (const resource of Resources.GetCodes())
Cheat({ "player": input.player, "action": "addresource", "text": resource, "parameter": input.parameter });
Cheat({ "player": input.player, "action": "maxpopulation" });
Cheat({ "player": input.player, "action": "changemaxpopulation" });
Cheat({ "player": input.player, "action": "fastactions" });
for (let i = 0; i < 2; ++i)
Cheat({ "player": input.player, "action": "changephase", "selected": input.selected });
return;
case "playRetro":
const play = input.parameter.toLowerCase() != "off";
cmpGuiInterface.PushNotification({
"type": "play-tracks",
"tracks": play && input.parameter.split(" "),
"lock": play,
"players": [input.player]
});
return;
default:
warn("Cheat '" + input.action + "' is not implemented");
return;
}
}
Engine.RegisterGlobal("Cheat", Cheat);