OverPy is a high-level language for the workshop: a custom built language that compiles to the workshop language.
OverPy allows you to manage your gamemodes much more easily, thanks to its ability to code with modern development practices: multiple files, switches, dictionaries, macros, function macros, enums, built-in JS preprocessing…
It contains built-in optimizations, allowing you to focus on making the source code clearer.
OverPy also includes a decompiler, to not have to recode your entire gamemode, and to get started as fast as possible.
All in-game languages are supported, meaning you do not need to switch your in-game language to English to use it.
The VS Code extension includes syntax highlighting, autocompletion, and documentation.
Big thanks to arxenix who parsed the workshop documentation: https://github.com/arxenix/owws-documentation/blob/master/workshop.json
As well as the Overtool team for allowing me to datamine translations from the game.
Installation
Please refer to the wiki: https://github.com/Zezombye/overpy/wiki/General-usage
Optimization
Even if you prefer the workshop UI to coding in a text file, OverPy can serve as a tool to save elements and improve run time.
It can be done very easily by decompiling then compiling (OverPy guarantees that your gamemode will have the same effective behavior).
Some examples of saved elements:
Loot Quest - Regular Maps (4QV99) by Delwion : 19998 -> 18750 (-1248)
OverHammer (KYGBP) by Kinkku : 19865 -> 17664 (-2201)
Among Us (6C777) by Momaker: 19909 -> 17575 (-2334)
Preprocessing
Thanks to macros, you can declare constants and additional variables.
As such, instead of using “magic numbers”, you can do :
#!define PLAYER_SPEED 5.5
This will replace PLAYER_SPEED
with 5.5, and save a variable slot while still retaining comprehension.
To declare an enum, you can use the enum keyword:
enum GameStatus:
GAME_NOT_STARTED = 1,
GAME_IN_PROGRESS,
GAME_FINISHED
If you find yourself running out of variables, you can replace some of them by an array lookup much more easily:
#!define somevar array[3]
Moreover, inline functions allow you to use complex values while not duplicating the code:
#!define knockbackMult 1.3
#!define knockbackScalar 0.2
#!define kbMultScalar (knockbackMult * (1-knockbackScalar))
#!define kbRatioMult (knockbackMult * knockbackScalar)
Another example is for color reevaluation, to display an HUD Text with the color in a variable. Here, I use a macro to dynamically replace color
with the color I specify, and minimise the code duplication instead of copy-pasting the whole hudHeader
function 4 times.
enum ColorVar:
BLUE,
RED,
YELLOW,
ORANGE
globalvar currentColor = ColorVar.BLUE
#!define coloredText(str, color) hudHeader(getAllPlayers() if currentColor == ColorVar.(color) else [], str, HudPosition.LEFT, 0, Color.(color), HudReeval.VISIBILITY_SORT_ORDER_AND_STRING)
rule "Initialize the colored texts":
coloredText("some text", BLUE)
coloredText("some text", RED)
coloredText("some text", YELLOW)
coloredText("some text", ORANGE)
JavaScript macros
To give even more power to preprocessing, OverPy allows you to use JavaScript macros. This allows for example an easy way to loop the creation of rules:
var result = "";
for (var i = 1; i <= 6; i++) {
result += `
rule "destroy barricade ${i} if hp is 0":
@Event global
@Condition barricade${i}hp <= 0
barricade${i} = vect(0,-1000,0)`
}
result;
Or even to declare your gamemode data in dictionaries, where the JS macro will iterate on the dictionary and populate the arrays:
var result = "";
result += "playerSpawns = ["+zoneData.map(x => x.playerSpawn).join(", ")+"]\n";
result += "zonesUnlockLocation = ["+zoneData.map(x => x.unlockLocation).join(", ")+"]\n";
result += "zonesUnlockMoney = ["+zoneData.map(x => x.unlockMoney).join(", ")+"]\n";
for (var i = 0; i < zoneData.length; i++) {
result += "meiSpawns["+i+"] = ["+zoneData[i].meiSpawns.join(", ")+"]\n";
}
result;
generateZoneVariables([{
playerSpawn: vect(-42.63, 17.03, 83.12),
meiSpawns: [
vect(-22.44, 28, 51.66),
vect(-45.60, 11, 48.22),
],
unlockLocation: vect(-57.10, 16.2, 56.74),
unlockMoney: 500,
},{
playerSpawn: vect(-48.86, 19, 51.64),
meiSpawns: [
vect(-73.12, 13, 35.11),
],
unlockLocation: vect(-53.81, 10.87, 36.71),
unlockMoney: 700,
},
])
Switches
To replace long if-elif-else chains that test the same variable for a specific value, OverPy allows you to use switches:
switch eventPlayer.enemyHero:
case Hero.ANA:
eventPlayer.resistance = 2
break
case Hero.ASHE:
eventPlayer.resistance = 3
break
default:
eventPlayer.resistance = 4
This allows for both a size and runtime optimization, as the value of eventPlayer.enemyHero is not recalculated each time.
Inline dictionaries
The above switch can be replaced by an inline dictionary, as the same action is ran every time:
eventPlayer.resistance = {
0: 4,
Hero.ANA: 2,
Hero.ASHE: 3,
}[eventPlayer.enemyHero]
Quality of life
Automatic string splitting: you can use strings with more than 128 chars, and more than 3 formatters.
Workshop settings sort: you can specify a sort order for workshop settings.
Built-in math functions: log(), lineIntersectsSphere(), math.pi, math.e
Help & Feedback
Want to know more? Join the discord for help and feedback: https://discord.gg/EEMjjFB