SDLPoP scripting/modding (concept, ideas, discussion)
Posted: March 20th, 2016, 9:44 pm
Hi all,
I have been thinking about possible modding features for SDLPoP, and I have been working on some prototypes for this.
Of course, some customization of the game is already possible (though not yet as extensive as with CusPoP). Currently it is relatively easy to change the way SDLPoP behaves by editing a configuration file (SDLPoP.ini), and the number of available options can of course be expanded in the future.
But this has some limitations, and we can try to do even better!
Problem: Need to have separate installations of SDLPoP for each mod you want to play.
(This can be circumvented somewhat by running from the command prompt while in a different working directory, but this takes a lot of setting up and may not be an ideal solution for most people. Also, it is not straightforward for mods to override user options specified in SDLPoP.ini - e.g. whether bugfixes should be enabled)
Possible solution:
We could organize mods in a dedicated "mods/" folder, and provide an SDLPoP.ini option that tells SDLPoP from which directory custom files should be loaded:
So basically you add a mod folder to the "mods/" directory and put the modified files in that (unmodified files can just be loaded from the normal data files).
This way, the mod never interferes with the original game data. If you want to play the original game again, you simply change the "levelset" option back to "original" in SDLPoP.ini and you're done.
To make mods override gameplay configuration options, you could add an INI file into the mod directory itself (e.g. "mod.ini"). For example, this short configuration file will turn off all gameplay fixes only for this mod:
Problem: It is very difficult to add custom features in a mod without changing the SDLPoP source code.
It would of course be possible to add anything as an option to SDLPoP.ini... but this has its limits. And new features that modders might want for their own mods (such as custom potions or new special events) may not always be suitable as core SDLPoP features.
Possible solution:
We could add a scripting system for creating SDLPoP add-ons!
It turns out that implementing such a system is actually quite doable. The most suitable framework that I could find for this purpose was libtcc; this is an embeddable part of the open source Tiny C Compiler, a fast and lightweight compiler for C code.
The libtcc library can be invoked as a single fairly small dll (about 130 kB) - so SDLPoP will not become much bigger when we decide to add libtcc as the basis of a scripting system.
So the basic idea is this:
- Modders can write add-on scripts for SDLPoP in the C language, and distribute a script together with their mod.
- SDLPoP compiles and starts the script upon launch.
- Custom features should then "just work" in-game.
I have been working on experimental SDLPoP support for the mod organization and scripting features. To try everything out for yourself, you can download the test build for Windows (as usual with source code included) in the attachment below (SDLPoP_v1.17b2.zip).
(N.B. this is NOT something like an official beta, just an experimental build!)
I put together some "example" mods in a separate ZIP file (SDLPoP Mods.zip).
Usage: extract the contents of the ZIP file into the "mods/" folder of SDLPoP, then open SDLPoP.ini and change the "levelset" option to any of the mod folder names.
In this ZIP file, I added the first three mods from popot.org (http://www.popot.org/custom_levels.php?sort=id). Each mod has its own folder. Some have modified graphics, but I found that some data files (specifically, customized VDUNGEON.DAT and KID.DAT) caused SDLPoP to crash so I left those out.
I also added an (unfinished) "pure-script" version of my own mod, Secrets of the Citadel. So you can take a look at how I rewrote some of the mod's features as an SDLPoP script (the Readme.txt in that folder contains some additional explanation).
The scripting system (concept)
In the test build, SDLPoP looks for a plain text file called "mod.scr" and tries to compile that as C code.
The "mod.scr" file should always be in a mod directory (it will not work in the main folder of SDLPoP). (The reasoning for this is that scripts are always part of a mod anyway, and having some random script sitting in the main folder by accident could lead to unexpected behavior.)
About the script file extension:
I initially thought about giving scripts a .P1S extension (for Prince of Persia 1 Script), but perhaps this is not the best option. The other PoP1 files all have extensions like .SAV, .DAT, so perhaps the best way to not break the pattern is to use an extension like .SCR (for SCRIPT). (so, incidentally, perhaps replay files should be called .REC instead of .P1R?)
How to write a script:
SDLPoP tries to find specific functions as entry points for the script. These functions then get called at specific times:
At the top of the script, you should include the header that contains declarations for types, variables and functions that you can use:
The file "pop_script" is located in "data/script/". This is what it looks like currently:
This is far from complete, many things are missing, but you can already do some interesting things.
You can also use some C library functions (such as printf).
The work ahead is somewhat daunting still, if we decide to go ahead with this...
At the very least I had fun coming this far!
This is only a proposal, so please discuss!
GitHub branch: https://github.com/Falcury/SDLPoP/tree/script
GitHub PR: https://github.com/NagyD/SDLPoP/pull/57
I have been thinking about possible modding features for SDLPoP, and I have been working on some prototypes for this.
Of course, some customization of the game is already possible (though not yet as extensive as with CusPoP). Currently it is relatively easy to change the way SDLPoP behaves by editing a configuration file (SDLPoP.ini), and the number of available options can of course be expanded in the future.
But this has some limitations, and we can try to do even better!
Problem: Need to have separate installations of SDLPoP for each mod you want to play.
(This can be circumvented somewhat by running from the command prompt while in a different working directory, but this takes a lot of setting up and may not be an ideal solution for most people. Also, it is not straightforward for mods to override user options specified in SDLPoP.ini - e.g. whether bugfixes should be enabled)
Possible solution:
We could organize mods in a dedicated "mods/" folder, and provide an SDLPoP.ini option that tells SDLPoP from which directory custom files should be loaded:
Code: Select all
; You can choose which levels to play using the 'levelset' option:
; 'original' --> play the original levels (Default)
; 'Your Mod Name' --> play a custom levelset (the custom files must be in a directory "mods/Your Mod Name/")
levelset = The Great Escape
This way, the mod never interferes with the original game data. If you want to play the original game again, you simply change the "levelset" option back to "original" in SDLPoP.ini and you're done.
To make mods override gameplay configuration options, you could add an INI file into the mod directory itself (e.g. "mod.ini"). For example, this short configuration file will turn off all gameplay fixes only for this mod:
Code: Select all
[Enhancements]
use_fixes_and_enhancements = false
It would of course be possible to add anything as an option to SDLPoP.ini... but this has its limits. And new features that modders might want for their own mods (such as custom potions or new special events) may not always be suitable as core SDLPoP features.
Possible solution:
We could add a scripting system for creating SDLPoP add-ons!
It turns out that implementing such a system is actually quite doable. The most suitable framework that I could find for this purpose was libtcc; this is an embeddable part of the open source Tiny C Compiler, a fast and lightweight compiler for C code.
The libtcc library can be invoked as a single fairly small dll (about 130 kB) - so SDLPoP will not become much bigger when we decide to add libtcc as the basis of a scripting system.
So the basic idea is this:
- Modders can write add-on scripts for SDLPoP in the C language, and distribute a script together with their mod.
- SDLPoP compiles and starts the script upon launch.
- Custom features should then "just work" in-game.
I have been working on experimental SDLPoP support for the mod organization and scripting features. To try everything out for yourself, you can download the test build for Windows (as usual with source code included) in the attachment below (SDLPoP_v1.17b2.zip).
(N.B. this is NOT something like an official beta, just an experimental build!)
I put together some "example" mods in a separate ZIP file (SDLPoP Mods.zip).
Usage: extract the contents of the ZIP file into the "mods/" folder of SDLPoP, then open SDLPoP.ini and change the "levelset" option to any of the mod folder names.
In this ZIP file, I added the first three mods from popot.org (http://www.popot.org/custom_levels.php?sort=id). Each mod has its own folder. Some have modified graphics, but I found that some data files (specifically, customized VDUNGEON.DAT and KID.DAT) caused SDLPoP to crash so I left those out.
I also added an (unfinished) "pure-script" version of my own mod, Secrets of the Citadel. So you can take a look at how I rewrote some of the mod's features as an SDLPoP script (the Readme.txt in that folder contains some additional explanation).
The scripting system (concept)
In the test build, SDLPoP looks for a plain text file called "mod.scr" and tries to compile that as C code.
The "mod.scr" file should always be in a mod directory (it will not work in the main folder of SDLPoP). (The reasoning for this is that scripts are always part of a mod anyway, and having some random script sitting in the main folder by accident could lead to unexpected behavior.)
About the script file extension:
I initially thought about giving scripts a .P1S extension (for Prince of Persia 1 Script), but perhaps this is not the best option. The other PoP1 files all have extensions like .SAV, .DAT, so perhaps the best way to not break the pattern is to use an extension like .SCR (for SCRIPT). (so, incidentally, perhaps replay files should be called .REC instead of .P1R?)
How to write a script:
SDLPoP tries to find specific functions as entry points for the script. These functions then get called at specific times:
Code: Select all
// Called immediately after the script has been compiled and loaded correctly.
void on_init() { /* your code here */ }
// Called every time you begin a new game.
void on_start_game() { /* your code here */ }
// Called right after a level has been loaded (or reloaded again after restarting).
void on_load_level(int level_number) { /* your code here */ }
// Called when a level ends, just before a cutscene or the next level is loaded.
void on_end_level(int level_number) { /* your code here */ }
// Called when a potion is drunk.
void on_drink_potion(int potion_id) { /* your code here */ }
// Called just before the game draws a potion. Bubble color and pot size can be changed here.
void custom_potion_anim(int potion_id) { /* your code here */ }
// Called every game tick.
void custom_timers() { /* your code here */ }
Code: Select all
#include <pop_script.h>
Spoiler: show
You can also use some C library functions (such as printf).
The work ahead is somewhat daunting still, if we decide to go ahead with this...
At the very least I had fun coming this far!
This is only a proposal, so please discuss!
GitHub branch: https://github.com/Falcury/SDLPoP/tree/script
GitHub PR: https://github.com/NagyD/SDLPoP/pull/57