List of commits:
Subject Hash Author Date (UTC)
Animation command: ANIM <loop|play> <bg|fg> <fps> <directory> 6066e2cae1dc29043902d46549f443c7b683fd88 mse 2021-09-06 06:42:13
Switch to C++17 489987b1b2749f37e0ac76594308635affbd24f2 mse 2021-09-05 10:51:02
Fix stats synchronization bug 3b6195c3321a6f10af43839cc00d24f301eddb3e mse 2021-09-05 04:45:58
Add top-level command: STRLEN, scriptable player name$ ec7a623cdc98b9832f35f0beb3e45179e6094436 mse 2021-09-05 03:17:47
Start work on animation system d2aafd6f46c719342054e3f256f972f4917f2231 mse 2021-09-05 02:41:28
Add string scripting with $ operator 20034a2b658ee8ad4f2082c44301c231b0323fc7 mse 2021-09-03 10:20:55
Enhance console /set command to support operators 61032844fcb833f04e2f6d1e123f8f0f89333107 mse 2021-09-02 11:06:00
Add scriptable bribing & remove hard-coded karma increment 41b4d79da6331b4b1ffd96f36ae1b032a869b482 mse 2021-08-31 17:51:29
Add floor operator (_) 819304b561d474e962afa7397ef68ffae83e8649 mse 2021-08-31 13:49:57
Switch inventories and stats to floating-point c6e4142e664648ca8f4aa913b48526093c985987 mse 2021-08-31 13:35:20
Switch scripting to floating-point & code comments eb067496f4edb4420c05a09dc034ad0a25ad1e56 mse 2021-08-31 11:06:01
Add top-level command: GOSUB 62e9520aec0471fe023ead290595f735a30eb806 mse 2021-08-26 09:31:27
Add persistent VN stats 2d1ffc35afd8ae0f477cbd5aac0559fc02571600 mse 2021-08-23 10:44:16
Bribes increase karma 643f0fc6da65316aa799bbe00cea2030e2c1ccd6 mse 2021-08-17 08:16:36
Add command: #RUMBLE <intensity> <milliseconds> 02964b2ecc57a48192522ef369e33c4912d2f0d2 mse 2021-08-16 07:17:40
Reset position in non-mouse menu selection c21eb6a9d238fa1909dbbbc49907ad09bfca52c8 mse 2021-08-16 03:30:49
Add haptic rumble for combat 65ff172308b0ba26b8930e8e83eb41bd36c6b008 mse 2021-08-15 06:11:25
Reduce joystick sensitivity 3804492a52d36c40cd51d42a971fe92f4fdd52ba mse 2021-08-14 22:37:19
Set audio buffer 1024 to reduce latency b1733b33b3342b32f08e1bafb5baf63ed7db419e mse 2021-07-11 02:56:22
Update readme, deps, bump to v0.5.0 2f96bc1fe9af48874750f2ba507eda5d704313b0 mse 2021-07-05 12:14:52
Commit 6066e2cae1dc29043902d46549f443c7b683fd88 - Animation command: ANIM <loop|play> <bg|fg> <fps> <directory>
Author: mse
Author date (UTC): 2021-09-06 06:42
Committer name: mse
Committer date (UTC): 2021-09-06 06:42
Parent(s): 489987b1b2749f37e0ac76594308635affbd24f2
Signing key:
Tree: 64d4a526ab1e49838a63c37e252bd60ecd6a192f
File Lines added Lines deleted
confec.cpp 132 12
File confec.cpp changed (mode: 100644) (index 471d7a3..75ed14f)
... ... FILE *FileOpen( const char* filename, const char* modes );
115 115 #include <ctime> #include <ctime>
116 116
117 117 #include <algorithm> #include <algorithm>
118 #include <exception>
119 #include <filesystem>
118 120 #include <limits> #include <limits>
119 121 #include <map> #include <map>
120 122 #include <random> #include <random>
 
... ... fgl::Texture shadeBox, button_n, button_p;
186 188 // VN variables. // VN variables.
187 189 long long health = 0, day = 0, money = 0, multiplayer = 0, mainmenu = 0; long long health = 0, day = 0, money = 0, multiplayer = 0, mainmenu = 0;
188 190
191 // Animation variables.
192 bool animation_loop = false;
193 int animation_layer = 0;
194 double animation_fps = 0.0;
195
196 // Image subsystem variables.
197 int bgIndex = -1, fgIndex = -1, choiceIndex = -1;
198
189 199 struct Image { struct Image {
190 200 std::string imgName; std::string imgName;
191 201 fgl::Texture imgTexture; fgl::Texture imgTexture;
 
... ... struct Image {
194 204 std::vector<Image> backgrounds; std::vector<Image> backgrounds;
195 205 std::vector<Image> foregrounds; std::vector<Image> foregrounds;
196 206
197 int bgIndex = -1, fgIndex = -1, choiceIndex = -1;
198
199 207 // Get the index to the specified background image, or -1 if failure. // Get the index to the specified background image, or -1 if failure.
200 208 int findBackground( std::string imgName ){ int findBackground( std::string imgName ){
201 209 if( imgName.length() > 0 ){ if( imgName.length() > 0 ){
 
... ... int main( int argc, char* argv[] ){
1186 1194 return -2.0; return -2.0;
1187 1195 } }
1188 1196 if( param.length() >= 16 if( param.length() >= 16
1189 && param.substr( 0, 9 ) == "ANIMATION" ){
1197 && param.substr( 0, 4 ) == "ANIM" ){
1198 // Half of conservative VRAM = 64 MB = 24 frames at 1280x533
1199 // Looping.
1200 bool is_loop;
1201 if( param.substr( 5, 4 ) == "loop" ){
1202 is_loop = true;
1203 }else if( param.substr( 5, 4 ) == "play" ){
1204 is_loop = false;
1205 }else{
1206 return 0.0;
1207 }
1190 1208 // Layer. // Layer.
1191 1209 bool is_foreground; bool is_foreground;
1192 1210 if( param.substr( 10, 2 ) == "fg" ){ if( param.substr( 10, 2 ) == "fg" ){
 
... ... int main( int argc, char* argv[] ){
1196 1214 }else{ }else{
1197 1215 return 0.0; return 0.0;
1198 1216 } }
1199 size_t space_at = param.find_first_of( 14, ' ' );
1217 size_t space_at = param.find_first_of( ' ', 14 );
1200 1218 if( space_at == std::string::npos if( space_at == std::string::npos
1201 1219 || space_at == param.length() - 1 ){ || space_at == param.length() - 1 ){
1202 1220 return 0.0; return 0.0;
 
... ... int main( int argc, char* argv[] ){
1204 1222 // Frames per second. // Frames per second.
1205 1223 double f = double f =
1206 1224 world.safeStold( param.substr( 13, space_at - 13 ) ); world.safeStold( param.substr( 13, space_at - 13 ) );
1207 f = std::min( std::max( f, 0.1 ), 30.0 );
1225 f = std::min( std::max( f, 0.01 ), 30.0 );
1208 1226 // Directory containing frame sequence. // Directory containing frame sequence.
1209 1227 std::string dir_name = param.substr( space_at + 1 ); std::string dir_name = param.substr( space_at + 1 );
1210 std::string dir_check =
1211 data_path + ( is_foreground ? "/fg/" : "/bg/" ) + dir_name;
1212 // TODO: Check directory for files, load files.
1213 // Half of conservative VRAM = 64 MB = 24 frames at 1280x533
1214 // https://stackoverflow.com/questions/8149569/scan-a-directory-to-find-files-in-c
1215 //freeImages();
1216 // Load stuff here.
1228 // data_path should technically be first in the vector, but
1229 // in this case the order doesn't matter.
1230 std::vector<std::string> search_paths = mod_paths;
1231 search_paths.push_back( data_path );
1232 // Check directories for image files.
1233 std::map<std::string,bool> frame_files;
1234 for( std::string &path : search_paths ){
1235 std::string dir_check =
1236 path + ( is_foreground ? "/fg/" : "/bg/" ) + dir_name;
1237 std::filesystem::path fspath{ dir_check };
1238 try{
1239 for( const auto &entry : std::filesystem::directory_iterator{ fspath } ){
1240 if( entry.is_regular_file() ){
1241 auto ext = entry.path().extension();
1242 if( ext == ".png" || ext == ".PNG"
1243 || ext == ".jpg" || ext == ".JPG"
1244 || ext == ".jpeg" || ext == ".JPEG" ){
1245 frame_files[entry.path().filename()] = true;
1246 }
1247 }
1248 }
1249 }catch( std::exception &e ){
1250 // Bad file or directory. Moving on.
1251 }
1252 }
1253 if( frame_files.empty() ) return 0.0;
1254 // Confirmed for loading the animation. Free VRAM.
1255 freeImages();
1256 // Load the frames.
1257 for( auto &frame : frame_files ){
1258 std::string img_name = dir_name + "/" + frame.first;
1259 if( is_foreground ){
1260 foregrounds.push_back( {
1261 img_name,
1262 loadImage( data_path + "/fg/" + img_name, true, true )
1263 } );
1264 }else{
1265 backgrounds.push_back( {
1266 img_name,
1267 loadImage( data_path + "/bg/" + img_name, true, true )
1268 } );
1269 }
1270 }
1271 // Set frame and globals.
1272 if( is_foreground ){
1273 convo.screen.fg = foregrounds[0].imgName;
1274 }else{
1275 convo.screen.bg = backgrounds[0].imgName;
1276 }
1277 animation_loop = is_loop;
1278 animation_layer = is_foreground ? 2 : 1;
1279 animation_fps = f;
1217 1280 return 0.0; return 0.0;
1218 1281 } }
1219 1282 if( param.length() >= 9 if( param.length() >= 9
 
... ... void Render(){
4304 4367 UpdateInventoryService(); UpdateInventoryService();
4305 4368 } }
4306 4369
4370 // Image animations.
4371 static double animation_timer;
4372 if( animation_layer > 0 ){
4373 animation_timer += d;
4374 if( animation_timer >= 1.0 / animation_fps ){
4375 animation_timer =
4376 std::fmod( animation_timer, 1.0 / animation_fps );
4377 std::string img_name =
4378 animation_layer == 1 ? convo.screen.bg : convo.screen.fg;
4379 size_t slash_at = img_name.find_first_of( '/' );
4380 if( slash_at == std::string::npos ){
4381 // Animations are enabled but no frame sequence
4382 // directory is specified.
4383 animation_layer = 0;
4384 animation_timer = 0.0;
4385 }else{
4386 // Make sure the next image is in the same directory.
4387 std::string img_dir = img_name.substr( 0, slash_at + 1 );
4388 if( animation_layer == 1 ){
4389 if( bgIndex + 1 < (int)backgrounds.size()
4390 && backgrounds[bgIndex + 1].imgName.substr( 0, slash_at + 1 )
4391 == img_dir ){
4392 // Go to the next frame.
4393 bgIndex++;
4394 convo.screen.bg = backgrounds[bgIndex].imgName;
4395 }else if( backgrounds.size() > 0 && animation_loop ){
4396 // Go to the first frame.
4397 bgIndex = 0;
4398 convo.screen.bg = backgrounds[bgIndex].imgName;
4399 }else{
4400 // The backgrounds failed to load or no loop.
4401 animation_layer = 0;
4402 animation_timer = 0.0;
4403 }
4404 }else{
4405 if( fgIndex + 1 < (int)foregrounds.size()
4406 && foregrounds[fgIndex + 1].imgName.substr( 0, slash_at + 1 )
4407 == img_dir ){
4408 // Go to the next frame.
4409 fgIndex++;
4410 convo.screen.fg = foregrounds[fgIndex].imgName;
4411 }else if( foregrounds.size() > 0 && animation_loop ){
4412 // Go to the first frame.
4413 fgIndex = 0;
4414 convo.screen.fg = foregrounds[fgIndex].imgName;
4415 }else{
4416 // The foregrounds failed to load or no loop.
4417 animation_layer = 0;
4418 animation_timer = 0.0;
4419 }
4420 }
4421 }
4422 }
4423 }else{
4424 animation_timer = 0.0;
4425 }
4426
4307 4427 // Calculate time of day and ambient light color. // Calculate time of day and ambient light color.
4308 4428 if( world.followEntity >= 0 && world.entities.size() >= 1 ){ if( world.followEntity >= 0 && world.entities.size() >= 1 ){
4309 4429 auto &player = world.entities[world.followEntity]; auto &player = world.entities[world.followEntity];
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/mse/ConfectionerEngine

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/mse/ConfectionerEngine

Clone this repository using git:
git clone git://git.rocketgit.com/user/mse/ConfectionerEngine

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main