Hey guys,
Me and @kimono are working on a split screen feature to expand the mods possibilities. This is in a very experimental step and needs a lot of improvements yet, so you can find bugs but it's working.
Basically, most native engine functions related to screen scrolling are simulated with scripts on the updated.c event and many codes are the same as the "zoom" script. The "core" functions in this case are the "drawspriteq/drawscreen".
Currently I'm doing some experiments to understand better how it works once we don't have much info about. Technically, the drawspriteq draws all sprites to the screen and moves his offset depending on the player movement. In this case the native "xpos" variant is totally disabled by creating a "wait" in the "at 0" otherwise it can cause some undesired effects like screen shaking or wrong panel positions.
In fact the player is moving on the level but once the "xpos" stays on the "at 0" forever, the "subject_to_screen" property need to be disabled on all entities. Most things will need to be replicated with scripts or alternative functions in this prototype version, but I'm working to improve it and turn the level design easier.
Note that in the video I'm using a resolution of 640x480, so this way the game looks better than a resized 320x240 to 160x120 resolution. The advantage on using a doubled resolution is because you can rescale the 640x480 to look as a native 320x240 simply using drawmethod in case you have only 1 player in-game.
Any tips and suggestions are always welcome, we hope it can be useful for new mods in the future.
How to use it:
1) You will need the file "data/script.txt", set your "alwaysupdate" function to 1
2) You will need the file "data/scripts/updated.c", copy and paste the entire script on it
3) Create an "wait" with "at 0" inside your level file, same as the example below
Level design example:
Updated.c file content:
Me and @kimono are working on a split screen feature to expand the mods possibilities. This is in a very experimental step and needs a lot of improvements yet, so you can find bugs but it's working.
Basically, most native engine functions related to screen scrolling are simulated with scripts on the updated.c event and many codes are the same as the "zoom" script. The "core" functions in this case are the "drawspriteq/drawscreen".
Currently I'm doing some experiments to understand better how it works once we don't have much info about. Technically, the drawspriteq draws all sprites to the screen and moves his offset depending on the player movement. In this case the native "xpos" variant is totally disabled by creating a "wait" in the "at 0" otherwise it can cause some undesired effects like screen shaking or wrong panel positions.
In fact the player is moving on the level but once the "xpos" stays on the "at 0" forever, the "subject_to_screen" property need to be disabled on all entities. Most things will need to be replicated with scripts or alternative functions in this prototype version, but I'm working to improve it and turn the level design easier.
Note that in the video I'm using a resolution of 640x480, so this way the game looks better than a resized 320x240 to 160x120 resolution. The advantage on using a doubled resolution is because you can rescale the 640x480 to look as a native 320x240 simply using drawmethod in case you have only 1 player in-game.
Any tips and suggestions are always welcome, we hope it can be useful for new mods in the future.
How to use it:
1) You will need the file "data/script.txt", set your "alwaysupdate" function to 1
2) You will need the file "data/scripts/updated.c", copy and paste the entire script on it
3) Create an "wait" with "at 0" inside your level file, same as the example below
Level design example:
group 100 100
at 0
wait
at 0
spawn Ralf
health 1000000
aggression -10000
coords 600 230
at 0
Updated.c file content:
C:
void main()
{
if(openborvariant("in_titlescreen")){
clearglobalvar();
clearlocalvar();
}
if(openborvariant("in_level")){
if(!openborvariant("pause")){
splitScreen(0);
splitScreen(1);
clearspriteq();
}
}
}
void splitScreen(int player)
{//Simulates a "split screen" feature (Kratus 02-2022)
//Don't forget to set a "wait" in "at 0" on every level to lock the "xpos" scrolling to avoid screen "shaking"
//Most things on the game will need to be scripted, once most native functions will not work in the level design
void ent = getplayerproperty(player, "entity");
if(ent){
void vScreen = openborvariant("vscreen");
float x = getentityproperty(ent, "x");
float hRes = openborvariant("hresolution");
float vRes = openborvariant("vresolution");
float xPos = openborvariant("xpos");
float minZ = openborvariant("PLAYER_MIN_Z");
float maxZ = openborvariant("PLAYER_MAX_Z");
float screenDif = (vRes/2)*player;
float scaleX = 256;
float scaleY = 256;
float zAdd = 500;
float xVel = 1;
//START AND DEFINE VARIABLES
if(getglobalvar("screenP"+player) == NULL()){
changeopenborvariant("viewportx", 0);
changeopenborvariant("viewporty", 0);
changeopenborvariant("viewportw", openborvariant("levelwidth"));
changeopenborvariant("viewporth", openborvariant("levelheight"));
changeentityproperty(ent, "position", xPos+(hRes/6), minZ+(screenDif/8));
setglobalvar("xOffset"+player, 0);
setglobalvar("screenP"+player, allocscreen(openborvariant("levelwidth"), vRes));
}
//READJUST SCREENS FOR 1 OR TWO PLAYERS IN REAL TIME
//DISABLED BECAUSE NEED IMPROVEMENTS
if(openborvariant("count_players") <= 1){
// scaleX = 512;
// scaleY = 512;
// hRes = hRes/2;
// screenDif = 0;
}
//CLEAR SCREEN
clearscreen(getglobalvar("screenP"+player));
//ADJUST LEVEL OFFSET AS A "FAKE" XPOS FOR EACH SCREEN IN REAL TIME
//USED WHEN THE CHARACTER IS MOVED TO RIGHT DIRECTION IN REAL TIME
if(x + getglobalvar("xOffset"+player) > (hRes/2)){
if(getglobalvar("xOffset"+player) > (hRes-openborvariant("levelwidth"))){
setglobalvar("xOffset"+player, getglobalvar("xOffset"+player)-xVel);
changeentityproperty(ent, "subject_to_screen", 0);
//changelevelproperty("wall", 0, "x", x-(hRes/2)); //TESTED TO REPLACE THE NATIVE BLOCKADE FEATURE
}
}
//USED WHEN THE CHARACTER IS MOVED TO LEFT DIRECTION IN REAL TIME
//DISABLED TO WORK ONLY FOR THE RIGHT DIRECTION, BUT THE LEFT DIRECTION WORKS CORRETLY TOO
if(x + getglobalvar("xOffset"+player) < (hRes/2)){
if(getglobalvar("xOffset"+player) < 0){
//setglobalvar("xOffset"+player, getglobalvar("xOffset"+player)+xVel);
changeentityproperty(ent, "subject_to_screen", 0);
}
else
{
changeentityproperty(ent, "subject_to_screen", 1);
}
}
//DEBUG INFO
drawstring(getglobalvar("xOffset"+player)/10000, 50+screenDif, 0, openborvariant("levelwidth"), openborconstant("MAX_INT")/100000);
drawstring(getglobalvar("xOffset"+player)/10000, 60+screenDif, 0, getglobalvar("xOffset"+player), openborconstant("MAX_INT")/100000);
drawstring(getglobalvar("xOffset"+player)/10000, 70+screenDif, 0, x, openborconstant("MAX_INT")/100000);
//DRAW EVERYTHING IN REAL TIME
drawspriteq(getglobalvar("screenP"+player), 0, openborconstant("MIN_INT"), maxZ+zAdd, getglobalvar("xOffset"+player), 0);
changedrawmethod(NULL(),"reset", 1);
changedrawmethod(NULL(),"enabled", 1);
changedrawmethod(NULL(),"scalex", scaleX);
changedrawmethod(NULL(),"scaley", scaleY);
drawscreen(getglobalvar("screenP"+player), 0, screenDif, (maxZ*9)+player);
drawspriteq(vScreen, 0, maxZ+zAdd+1, openborconstant("MAX_INT"), 0, 0);
}
else
{
if(getglobalvar("screenP"+player) != NULL()){setglobalvar("screenP"+player, NULL());}
}
}
Last edited: