Subversion Repositories Games.Carmageddon

Rev

Rev 14 | Rev 20 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "harness.h"
  2. #include "ascii_tables.h"
  3. #include "brender_emu/renderer_impl.h"
  4. #include "include/harness/config.h"
  5. #include "include/harness/hooks.h"
  6. #include "include/harness/os.h"
  7. #include "platforms/null.h"
  8. #include "sound/sound.h"
  9. //#include "version.h" // Pierre-Marie Baty -- our port doesn't need that (though it's actually based on dethrace-0.7.1)
  10.  
  11. #include <errno.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <sys/stat.h>
  15.  
  16. br_pixelmap* palette;
  17. uint32_t* screen_buffer;
  18. harness_br_renderer* renderer_state;
  19.  
  20. br_pixelmap* last_dst = NULL;
  21. br_pixelmap* last_src = NULL;
  22.  
  23. unsigned int last_frame_time = 0;
  24. int force_null_platform = 0;
  25.  
  26. extern unsigned int GetTotalTime(void);
  27.  
  28. extern br_v1db_state v1db;
  29. extern uint32_t gI_am_cheating;
  30.  
  31. // SplatPack or Carmageddon. This is where we represent the code differences between the two. For example, the intro smack file.
  32. tHarness_game_info harness_game_info;
  33.  
  34. // Configuration options
  35. tHarness_game_config harness_game_config;
  36.  
  37. // Platform hooks
  38. tHarness_platform gHarness_platform;
  39.  
  40. extern void Harness_Platform_Init(tHarness_platform* platform);
  41.  
  42. int Harness_ProcessCommandLine(int* argc, char* argv[]);
  43.  
  44. static void Harness_DetectGameMode(void) {
  45.     if (access("DATA/RACES/CASTLE.TXT", F_OK) != -1) {
  46.         // All splatpack edition have the castle track
  47.         if (access("DATA/RACES/CASTLE2.TXT", F_OK) != -1) {
  48.             // Only the full splat release has the castle2 track
  49.             harness_game_info.defines.INTRO_SMK_FILE = "SPLINTRO.SMK";
  50.             harness_game_info.defines.GERMAN_LOADSCRN = "LOADSCRN.PIX";
  51.             harness_game_info.mode = eGame_splatpack;
  52.             printf("Game mode: Splat Pack\n");
  53.         } else if (access("DATA/RACES/TINSEL.TXT", F_OK) != -1) {
  54.             // Only the the splat x-mas demo has the tinsel track
  55.             harness_game_info.defines.INTRO_SMK_FILE = "MIX_INTR.SMK";
  56.             harness_game_info.defines.GERMAN_LOADSCRN = "";
  57.             harness_game_info.mode = eGame_splatpack_xmas_demo;
  58.             printf("Game mode: Splat Pack X-mas demo\n");
  59.         } else {
  60.             // Assume we're using the splatpack demo
  61.             harness_game_info.defines.INTRO_SMK_FILE = "MIX_INTR.SMK";
  62.             harness_game_info.defines.GERMAN_LOADSCRN = "";
  63.             harness_game_info.mode = eGame_splatpack_demo;
  64.             printf("Game mode: Splat Pack demo\n");
  65.         }
  66.     } else if (access("DATA/RACES/CITYB3.TXT", F_OK) != -1) {
  67.         // All non-splatpack edition have the cityb3 track
  68.         if (access("DATA/RACES/CITYA1.TXT", F_OK) == -1) {
  69.             // The demo does not have the citya1 track
  70.             harness_game_info.defines.INTRO_SMK_FILE = "";
  71.             harness_game_info.defines.GERMAN_LOADSCRN = "COWLESS.PIX";
  72.             harness_game_info.mode = eGame_carmageddon_demo;
  73.             printf("Game mode: Carmageddon demo\n");
  74.         } else {
  75.             goto carmageddon;
  76.         }
  77.     } else {
  78.     carmageddon:
  79.         if (access("DATA/CUTSCENE/Mix_intr.smk", F_OK) == -1) {
  80.             harness_game_info.defines.INTRO_SMK_FILE = "Mix_intr.smk";
  81.         } else {
  82.             harness_game_info.defines.INTRO_SMK_FILE = "MIX_INTR.SMK";
  83.         }
  84.         harness_game_info.defines.GERMAN_LOADSCRN = "LOADSCRN.PIX";
  85.         harness_game_info.mode = eGame_carmageddon;
  86.         printf("Game mode: Carmageddon\n");
  87.     }
  88.  
  89.     harness_game_info.localization = eGameLocalization_none;
  90.     if (access("DATA/TRNSLATE.TXT", F_OK) != -1) {
  91.         FILE* f = fopen("DATA/TRNSLATE.TXT", "rb");
  92.         fseek(f, 0, SEEK_END);
  93.         int filesize = ftell(f);
  94.         fseek(f, 0, SEEK_SET);
  95.         char* buffer = malloc(filesize + 1);
  96.         int nb = fread(buffer, 1, filesize, f);
  97.         if (nb != filesize) {
  98.             LOG_PANIC("Unable to read DATA/TRNSLATE.TXT");
  99.         }
  100.         buffer[filesize] = '\0';
  101.         fclose(f);
  102.         if (strstr(buffer, "NEUES SPIEL") != NULL) {
  103.             harness_game_info.localization = eGameLocalization_german;
  104.             LOG_INFO("Language: \"%s\"", "German");
  105.         } else {
  106.             LOG_INFO("Language: unrecognized");
  107.         }
  108.         free(buffer);
  109.     }
  110.  
  111.     switch (harness_game_info.mode) {
  112.     case eGame_carmageddon:
  113.         switch (harness_game_info.localization) {
  114.         case eGameLocalization_german:
  115.             harness_game_info.defines.requires_ascii_table = 1;
  116.             harness_game_info.defines.ascii_table = carmageddon_german_ascii_tables.ascii;
  117.             harness_game_info.defines.ascii_shift_table = carmageddon_german_ascii_tables.ascii_shift;
  118.             break;
  119.         default:
  120.             harness_game_info.defines.ascii_table = carmageddon_ascii_tables.ascii;
  121.             harness_game_info.defines.ascii_shift_table = carmageddon_ascii_tables.ascii_shift;
  122.             break;
  123.         }
  124.         break;
  125.     case eGame_carmageddon_demo:
  126.         harness_game_info.defines.ascii_table = demo_ascii_tables.ascii;
  127.         harness_game_info.defines.ascii_shift_table = demo_ascii_tables.ascii_shift;
  128.         break;
  129.     case eGame_splatpack_demo:
  130.     case eGame_splatpack_xmas_demo:
  131.         harness_game_info.defines.ascii_table = xmas_ascii_tables.ascii;
  132.         harness_game_info.defines.ascii_shift_table = xmas_ascii_tables.ascii_shift;
  133.         break;
  134.     default:
  135.         break;
  136.     }
  137. }
  138.  
  139. #ifdef __APPLE__
  140. #include <pwd.h> // for struct passwd and getpwuid()
  141. #endif /* __APPLE__ */
  142. void Harness_Init(int* argc, char* argv[]) {
  143.     int result;
  144. #ifndef DETHRACE_VERSION
  145. #define DETHRACE_VERSION "0.7.1-pmbaty" // Pierre-Marie Baty -- CMake fix
  146. #endif // !DETHRACE_VERSION
  147.     printf("Dethrace version: %s\n", DETHRACE_VERSION);
  148.  
  149.     memset(&harness_game_info, 0, sizeof(harness_game_info));
  150.  
  151.     // disable the original CD check code
  152.     harness_game_config.enable_cd_check = 0;
  153.     // original physics time step. Lower values seem to work better at 30+ fps
  154.     harness_game_config.physics_step_time = 40;
  155.     // do not limit fps by default
  156.     harness_game_config.fps = 0;
  157.     // do not freeze timer
  158.     harness_game_config.freeze_timer = 0;
  159.     // default demo time out is 240s
  160.     harness_game_config.demo_timeout = 240000;
  161.     // disable developer diagnostics by default
  162.     harness_game_config.enable_diagnostics = 0;
  163.     // no volume multiplier
  164.     harness_game_config.volume_multiplier = 1.0f;
  165.     // start window in windowed mode
  166.     harness_game_config.start_full_screen = 0;
  167.     // Disable gore check emulation
  168.     harness_game_config.gore_check = 0;
  169.     // Enable Sound Options menu
  170.     harness_game_config.sound_options = 1; // Pierre-Marie Baty -- invert option default value
  171.     // Skip binding socket to allow local network testing
  172.     harness_game_config.no_bind = 0;
  173.     // Disable verbose logging
  174.     harness_game_config.verbose = 0;
  175.  
  176.     // install signal handler by default
  177.     harness_game_config.install_signalhandler = 1;
  178.  
  179.     Harness_ProcessCommandLine(argc, argv);
  180.  
  181.     if (harness_game_config.install_signalhandler) {
  182.         OS_InstallSignalHandler(argv[0]);
  183.     }
  184.  
  185.     char* root_dir = getenv("DETHRACE_ROOT_DIR");
  186.     if (root_dir != NULL) {
  187.         LOG_INFO("DETHRACE_ROOT_DIR is set to '%s'", root_dir);
  188.     } else {
  189.         root_dir = OS_Dirname(argv[0]);
  190. #ifdef __APPLE__
  191.         // Pierre-Marie Baty -- macOS .app fix
  192.         // peek in ~/Library/Application Support/<DOTTED BUNDLE ID>
  193.         // if the directory doesn't exist, create it and copy all the contents of root_dir in it
  194.         // this is necessary to have a read/write copy of the game data to not invalidate the app bundle's code signature
  195.         // disk space
  196.         {
  197.            extern int CFStringGetCString (void *theString, char *buffer, int bufferSize, uint32_t encoding); // avoid importing the whole Cocoa stuff
  198.            extern void *CFBundleGetIdentifier (void *bundle); // avoid importing the whole Cocoa stuff
  199.            extern void *CFBundleGetMainBundle (void); // avoid importing the whole Cocoa stuff
  200.            static char data_path[1024] = "";
  201.            char bundle_id[256];
  202.            char *homedir = getenv ("HOME");
  203.            if (homedir == NULL)
  204.               homedir = getpwuid (getuid ())->pw_dir;
  205.            CFStringGetCString (CFBundleGetIdentifier (CFBundleGetMainBundle ()), bundle_id, sizeof (bundle_id), 0x08000100 /*kCFStringEncodingUTF8*/);
  206.            sprintf (data_path, "%s/Library/Application Support/%s", homedir, bundle_id);
  207.            if (access (data_path, 0) != 0)
  208.            {
  209.               mkdir (data_path, 0755);
  210.               {
  211.                  char cp_cmd[2048];
  212.                  sprintf (cp_cmd, "cp -LR \"%s/../Resources/DATA\" \"%s\"", root_dir, data_path);
  213.                  system (cp_cmd);
  214.               }
  215.            }
  216.            root_dir = data_path;
  217.         }
  218. #endif /* __APPLE__ */
  219.         if (root_dir[0] == 0)
  220.             strcpy(root_dir, "."); // Pierre-Marie Baty -- consistency check
  221.     }
  222.         printf("Using root directory: %s\n", root_dir);
  223.         result = chdir(root_dir);
  224.         if (result != 0) {
  225.             LOG_PANIC("Failed to chdir. Error is %s", strerror(errno));
  226.     }
  227.  
  228.     if (harness_game_info.mode == eGame_none) {
  229.         Harness_DetectGameMode();
  230.     }
  231.  
  232.     if (force_null_platform) {
  233.         Null_Platform_Init(&gHarness_platform);
  234.     } else {
  235.         Harness_Platform_Init(&gHarness_platform);
  236.     }
  237. }
  238.  
  239. // used by unit tests
  240. void Harness_ForceNullPlatform(void) {
  241.     force_null_platform = 1;
  242. }
  243.  
  244. int Harness_ProcessCommandLine(int* argc, char* argv[]) {
  245.     for (int i = 1; i < *argc; i++) {
  246.         int handled = 0;
  247.  
  248.         if (strcasecmp(argv[i], "--cdcheck") == 0) {
  249.             harness_game_config.enable_cd_check = 1;
  250.             handled = 1;
  251.         } else if (strstr(argv[i], "--debug=") != NULL) {
  252.             char* s = strstr(argv[i], "=");
  253.             harness_debug_level = atoi(s + 1);
  254.             LOG_INFO("debug level set to %d", harness_debug_level);
  255.             handled = 1;
  256.         } else if (strstr(argv[i], "--physics-step-time=") != NULL) {
  257.             char* s = strstr(argv[i], "=");
  258.             harness_game_config.physics_step_time = atoi(s + 1);
  259.             LOG_INFO("Physics step time set to %d", harness_game_config.physics_step_time);
  260.             handled = 1;
  261.         } else if (strstr(argv[i], "--fps=") != NULL) {
  262.             char* s = strstr(argv[i], "=");
  263.             harness_game_config.fps = atoi(s + 1);
  264.             LOG_INFO("FPS limiter set to %f", harness_game_config.fps);
  265.             handled = 1;
  266.         } else if (strcasecmp(argv[i], "--freeze-timer") == 0) {
  267.             LOG_INFO("Timer frozen");
  268.             harness_game_config.freeze_timer = 1;
  269.             handled = 1;
  270.         } else if (strcasecmp(argv[i], "--no-signal-handler") == 0) {
  271.             LOG_INFO("Don't install the signal handler");
  272.             harness_game_config.install_signalhandler = 0;
  273.             handled = 1;
  274.         } else if (strstr(argv[i], "--demo-timeout=") != NULL) {
  275.             char* s = strstr(argv[i], "=");
  276.             harness_game_config.demo_timeout = atoi(s + 1) * 1000;
  277.             LOG_INFO("Demo timeout set to %d milliseconds", harness_game_config.demo_timeout);
  278.             handled = 1;
  279.         } else if (strcasecmp(argv[i], "--i-am-cheating") == 0) {
  280.             gI_am_cheating = 0xa11ee75d;
  281.             handled = 1;
  282.         } else if (strcasecmp(argv[i], "--enable-diagnostics") == 0) {
  283.             harness_game_config.enable_diagnostics = 1;
  284.             handled = 1;
  285.         } else if (strstr(argv[i], "--volume-multiplier=") != NULL) {
  286.             char* s = strstr(argv[i], "=");
  287.             harness_game_config.volume_multiplier = atof(s + 1);
  288.             LOG_INFO("Volume multiplier set to %f", harness_game_config.volume_multiplier);
  289.             handled = 1;
  290.         } else if (strcasecmp(argv[i], "--full-screen") == 0) {
  291.             harness_game_config.start_full_screen = 1;
  292.             handled = 1;
  293.         } else if (strcasecmp(argv[i], "--gore-check") == 0) {
  294.             harness_game_config.gore_check = 1;
  295.             handled = 1;
  296.         } else if (strcasecmp(argv[i], "--no-sound-options") == 0) { // Pierre-Marie Baty -- invert option default value
  297.             harness_game_config.sound_options = 0; // Pierre-Marie Baty -- invert option default value
  298.             handled = 1;
  299.         } else if (strcasecmp(argv[i], "--no-bind") == 0) {
  300.             harness_game_config.no_bind = 1;
  301.             handled = 1;
  302.         }
  303.  
  304.         if (handled) {
  305.             // shift args downwards
  306.             for (int j = i; j < *argc - 1; j++) {
  307.                 argv[j] = argv[j + 1];
  308.             }
  309.             (*argc)--;
  310.             i--;
  311.         }
  312.     }
  313.  
  314.     return 0;
  315. }
  316.  
  317. // Filesystem hooks
  318. FILE* Harness_Hook_fopen(const char* pathname, const char* mode) {
  319.     return OS_fopen(pathname, mode);
  320. }
  321.