I am writing a tool that analyzes factory chains and corrects faulty ones.
There it build new factories if some are missing.
The tool normally is invoked by the player and attempts to build the factories using the public authority's player number. Unfortunately, command_x(tool_build_factory) ignores the specified player number and builds using the active player, quickly driving the player into bankruptcy.
The script can change the player number using command_x(tool_switch_player). Unfortunately, the script does not know to which player was switched afterwards, and there is no way for the script to find this out.
What is missing is: world.get_active_player_nr() {welt->get_active_player_nr()}
Of course, this would be even nicer: welt->switch_active_player(player-nr)
[DE]ich schreibe an einem Tool das die Fabrikketten analysiert und fehlerhafte Ketten korrigiert.
Dazu baut es eventuell fehlende Fabriken neu.
Das Tool wird vom Spieler aufgerufen und versucht unter der Spielernummer der Öffentlichen Hand die Fabriken zu bauen. Leider ignoriert command_x(tool_build_factory) die angegebene Spielernummer und baut unter dem aktiven Spieler, was diesen schnell in die Pleite treibt.
Mann kann mit command_x(tool_switch_player) die Spielernummer ändern. Leider weiß das Script nachher nicht auf welchen Spieler gewechselt wurde und es gibt für das Script auch keine Möglichkeit das heraus zu bekommen.
Was fehlt ist: world.get_active_player_nr() {welt->get_active_player_nr()}
Schöner noch wäre natürlich: welt->switch_active_player(player-nr)
The script will fail if the public player is locked ...
But a quick check showed that this worked:
function build_factory(pos, ignore_climates, rotation, base_prod, name)
{
local public_pl = player_x(1)
local factory_builder = command_x(tool_build_factory)
return factory_builder.work(public_pl, pos, "" + ignore_climates.tointeger() + rotation + base_prod + "," + name)
}
And you can find out if the player is the public player, if pl.get_name() == player_x(1).get_name() then you are the public player.
Or you can use the trick of the testcode, and restore the budget after each build ...
pl.book_cash(amount - pl.get_current_net_wealth())
Yes this work (I do it so) but:
local [b]public_pl = player_x(1)[/b]
local factory_builder = command_x(tool_build_factory)
return factory_builder.work([b]public_pl[/b], pos, "" + ignore_climates.tointeger() + rotation + base_prod + "," + name)public_pl is ignored
Have you check who pay the factory? It is the player!
Quote from: prissi on June 30, 2026, 08:35:40 AMOr you can use the trick of the testcode, and restore the budget after each build ...
pl.book_cash(amount - pl.get_current_net_wealth())
Ok this trick is a solution i think. 8)
Mea culpa. I trusted the documentation without testing it myself.
Quotelocal werkzeug = command_x(tool_switch_player)
local is_ok = werkzeug.work(publicPlayer,p1,"")
command_x(
tool_switch_player) doesn't work at all
(https://makie.de/tool_switch_player.png)
Quote from: prissi on June 30, 2026, 08:35:40 AMOr you can use the trick of the testcode, and restore the budget after each build ...
pl.book_cash(amount - pl.get_current_net_wealth())
No, doesn't work ::(
api_player.cc
Quoteif (scenario) {
/**
* Change bank account of player by given amount @p delta.
* @param delta
* @ingroup scen_only
*/
register_method(vm, player_book_account, "book_cash", true);
}
Ah, yes, this works only in the scenario modus. In normal game mode, the tools (and AIs) can only use the same tools as the player, so no cheating in multiplayer games. That was a design decision.
For what you want to achieve, the easiest way is probaly so have an error message if the player's name is not player_x(1).get_name() in the script, to only run it when the player is the public player.
function work(pl, pos) {
if(pl.get_name()!=player_x(1).get_name()) {
return "This tool must be run as public player"
}
...
}
Most player play in single mode and the simplest method to cheat is to play without bankruptcy.
I'd like to see that player who delves into the depths of the Squirrel-API and write a script just to cheat in a multiplayer simutrans game. We are not at Counter-Strike.
Okay, I'll add a check that stops the script if there isn't enough money, with a note to rerun as a public player.
Quote from: makie on June 30, 2026, 02:06:15 PMMost player play in single mode and the simplest method to cheat is to play without bankruptcy.
I'd like to see that player who delves into the depths of the Squirrel-API and write a script just to cheat in a multiplayer simutrans game. We are not at Counter-Strike.
...
It can certainly be considered cheating when many paths (especially roads) are made public in order to drastically reduce maintenance costs. After all, the toll revenue depends on usage rather than being a fixed fee for every field.
Of course, designating them as public roads entails some cost. However, once the standard 60-month period has passed, the costs associated with the paths are significantly lower.
If the program officially allows you to make roads public, then in my view, that isn't cheating.
My original approach was to switch to public service in the script, as it is normally permitted for players, at least in pak128.german. Only the command just isn't working. This command can be disabled, for the player in the GUI, as it is the case in various scenarios—but in pak128.german, it is normally permitted for the player. There is no cheating. The script do as the player can do. If the command is forbidden the script can handle this, if the second problem see below is solved.
The second problem: After the tool_switch_player there is no way to check witch player is active. There is a lake of get_active_player_nr(), a internal routine that is only not exported to Squirrel. No cheating at all.
Cheating the building cost is a idea form prissi, not mine.
command_x(tool_switch_player) isn't working because there is no coding for executing this command in the program from Squirrel.
The squirrel virtual machine VM is tied to a player. So switching players would require to restart the VM as that player. However, r12053 will allow players to run commands as other players IF that player is not locked. Just like a normal player could do. I.e. the above script can build the factory as player_x(1).
Thank you very much, I can manage with that now. :thumbsup: :thumbsup: :thumbsup:
Small question:
Is there any other way to detect a locked public player than by trying it and catching the exception with "try" and "catch"?
Another question:
Is there any other way to detect the Version of Simutrans as trying a new call and catching the exception with "try" and "catch"?
My solution: try get_target_cities() -> no? then old program version! --> check if player has enough money else hint for use public player
try with public player --> get a catch --> ok it is locked! --> try as aktiv player if has enough money
Quote from: makie on July 01, 2026, 08:38:48 AM...
Another question:
Is there any other way to detect the Version of Simutrans as trying a new call and catching the exception with "try" and "catch"?
...
get_version_number()
(https://doc.simutrans-germany.com/Simutrans-Squirrel-API/api__world_8cc.html#ad7396ae9539fe844bda5f8f39ec75078)
Quote from: Andarix on July 01, 2026, 09:35:59 AMget_version_number()
(https://doc.simutrans-germany.com/Simutrans-Squirrel-API/api__world_8cc.html#ad7396ae9539fe844bda5f8f39ec75078)
Thank you very much, that is helpful.
I search for it but couldn't find it.