Subversion Repositories spacemission

Rev

Rev 94 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit Global;
  2.  
  3. interface
  4.  
  5. const
  6.   ProgramVersion = '1.2.2';
  7.   LevEditRasterW = 48;
  8.   LevEditRasterH = 32;
  9.   LevEditRows = 15; // Attention: if you change this, you also need to change the LevEditor GUI!
  10.   LevEditCols = 13; // Attention: if you change this, you also need to change the LevEditor GUI!
  11.   MaxPossibleEnemyLives = 999;
  12.   MaxPossibleLevels = 999;
  13.   RegistrySettingsKey = 'SOFTWARE\ViaThinkSoft\SpaceMission\Settings'; // do not localize
  14.   MusicSettingKey = 'Music'; // do not localize
  15.   SoundSettingKey = 'Sound'; // do not localize
  16.   SpeedSettingKey = 'GameSpeed'; // do not localize
  17.   DefaultLevelLength = 1200;
  18.   StartLives = 6;
  19.   SpeedEasy = 650 div 60; // 10
  20.   SpeedMedium = 1000 div 60; // 16
  21.   SpeedHard = 1350 div 60; // 22
  22.   SpeedMaster = 2000 div 60; // 33
  23.   DEFAULT_ANIMSPEED = 15/1000;
  24.   BossWidth = 4;
  25.   BossHeight = 2;
  26.   SpaceMissionExe = 'SpaceMission.exe'; // do not localize
  27.   LevEditExe = 'LevEdit.exe'; // do not localize
  28.   DxgFile = 'DirectX\Graphics.dxg'; // do not localize
  29.   DxwFile = 'DirectX\Sound.dxw'; // do not localize
  30.   DxmFile = 'DirectX\Music.dxm'; // do not localize
  31.   RandomLevelMaxEnemyLives = 10;
  32.   RandomLevelMedikitEveryX = 250;
  33.   RandomLevelAdditionalEnemiesPerLevel = 75; // Zufalls-Level
  34.  
  35. const
  36.   // Cheat1 = 'Kmkjk'+#39+'Khyc';
  37.   Cheat1 = #75+#109+#107+#106+#107+#127+#39+#75+#104+#121+#99; {Johnny Cash}
  38.  
  39. resourcestring
  40.   Cheat1Text = 'Unendlich Leben!';
  41.  
  42. type
  43.   TCheat = (ctUnknown, ctInfiniteLives);
  44.   TCheatSet = set of TCheat;
  45.  
  46.   // DirectX\Music.dxm
  47.   TSpaceMissionMusicTrack = (
  48.     smmNone,
  49.     smmBoss,   // dxmusic.Midis[0]
  50.     smmGame,   // dxmusic.Midis[1]
  51.     smmScene,  // dxmusic.Midis[2]
  52.     smmTitle   // dxmusic.Midis[3]
  53.   );
  54.  
  55.   // DirectX\Graphics.dxg
  56.   TSpaceMissionGraphicSprite = (
  57.     smgNone,
  58.     smgEnemyDisk,         // ImageList.Items.Item[0]
  59.     smgEnemyAttacker,     // ImageList.Items.Item[1]
  60.     smgEnemyBoss,         // ImageList.Items.Item[2]
  61.     smgBounce,            // ImageList.Items.Item[3]
  62.     smgMachine,           // ImageList.Items.Item[4]
  63.     smgEnemyAttacker2,    // ImageList.Items.Item[5]
  64.     smgEnemyAttacker3,    // ImageList.Items.Item[6]
  65.     smgEnemyMeteor,       // ImageList.Items.Item[7]
  66.     smgBounce2,           // ImageList.Items.Item[8]
  67.     smgEnemyDisk2,        // ImageList.Items.Item[9]
  68.     smgLogo,              // ImageList.Items.Item[10]
  69.     smgExplosion,         // ImageList.Items.Item[11]
  70.     smgBackgroundPlanet1, // ImageList.Items.Item[12]
  71.     smgMatrix,            // ImageList.Items.Item[13]
  72.     smgStar1,             // ImageList.Items.Item[14]
  73.     smgStar2,             // ImageList.Items.Item[15]
  74.     smgStar3,             // ImageList.Items.Item[16]
  75.     smgBackgroundBlue,    // ImageList.Items.Item[17]
  76.     smgBackgroundRed,     // ImageList.Items.Item[18]
  77.     smgBackgroundYellow,  // ImageList.Items.Item[19]
  78.     smgHintergrundRot,    // ImageList.Items.Item[20]
  79.     smgItemMedikit        // ImageList.Items.Item[21]
  80.   );
  81.  
  82.   // DirectX\Sound.dxw
  83.   TSpaceMissionSound = (
  84.     smsNone,
  85.     smsSceneMov,      // WaveList.Items.Item[0]
  86.     smsExplosion,     // WaveList.Items.Item[1]
  87.     smsHit,           // WaveList.Items.Item[2]
  88.     smsShoot,         // WaveList.Items.Item[3]
  89.     smsItemCollected  // WaveList.Items.Item[4]
  90.   );
  91.  
  92. function OwnDirectory: string;
  93.  
  94. const
  95.   FOLDERID_SavedGames: TGuid = '{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}'; // do not localize
  96.  
  97. // Useful functions
  98. procedure SpaceMission_SwitchLanguage;
  99. function GetKnownFolderPath(const rfid: TGUID): string;
  100. function KillTask(ExeFileName: string): Integer;
  101. procedure CheckForUpdates(ViaThinkSoftProjectName: string; AVersion: string);
  102.  
  103. implementation
  104.  
  105. uses
  106.   Windows, SysUtils, Dialogs, ActiveX, ShlObj, TlHelp32, wininet, Forms, ShellAPI,
  107.   System.UITypes;
  108.  
  109. procedure SwitchLanguage(newLang: string);
  110. var
  111.   oldHInst: hInst;
  112.   newHInst: hInst;
  113.   bakOverride: string;
  114.   FileName: array [0..MAX_PATH] of Char;
  115.   Module: PLibModule;
  116. begin
  117.   Module := LibModuleList;
  118.   GetModuleFileName(Module.Instance, FileName, Length(FileName));
  119.  
  120.   bakOverride := GetLocaleOverride('');
  121.   try
  122.     SetLocaleOverride(newLang);
  123.  
  124.     // Note: SetLocaleOverride() alone does not work, because LibModuleList.ResInstance
  125.     // is already set and won't be re-set by the FindResourceHInstance()!
  126.     newHInst := LoadResourceModule(FileName);
  127.     if newHInst = 0 then newHInst := Module.Instance;
  128.  
  129.     oldHInst := Module.ResInstance;
  130.     Module.ResInstance := newHInst;
  131.     FreeLibrary(oldHInst);
  132.   except
  133.     SetLocaleOverride(bakOverride);
  134.   end;
  135. end;
  136.  
  137. function GetUserDefaultUILanguage: LANGID; stdcall; external 'kernel32';
  138.  
  139. procedure SpaceMission_SwitchLanguage;
  140. const
  141.   BaseLanguage = LANG_GERMAN;
  142.   DesiredFallbackLanguage = 'ENU'; // English USA
  143. begin
  144.   // We need this because of a tricky problem...
  145.   // Our base language is German (DE), and we have a translation for English USA (ENU)
  146.   // If the system locale is not exactly ENU (even ENG is not accepted), then the base language (German) will be used.
  147.   // But much more people are speaking English than German. So we need to force the system to use ENU instead of DE.
  148.   // This decision if we choose DE or ENU is done by the language selected during setup.
  149.   if (GetLocaleOverride('') = '') and
  150.      ((GetUserDefaultUILanguage and $FF) <> BaseLanguage) then
  151.   begin
  152.     SwitchLanguage(DesiredFallbackLanguage);
  153.   end;
  154. end;
  155.  
  156. function GetKnownFolderPath(const rfid: TGUID): string;
  157. var
  158.   OutPath: PWideChar;
  159. begin
  160.   // https://www.delphipraxis.net/135471-unit-zur-verwendung-von-shgetknownfolderpath.html
  161.   if ShGetKnownFolderPath(rfid, 0, 0, OutPath) {>= 0} = S_OK then
  162.   begin
  163.     Result := OutPath;
  164.     // From MSDN
  165.     // ppszPath [out]
  166.     // Type: PWSTR*
  167.     // When this method returns, contains the address of a pointer to a null-terminated Unicode string that specifies the path of the known folder
  168.     // The calling process is responsible for freeing this resource once it is no longer needed by calling CoTaskMemFree.
  169.     // The returned path does not include a trailing backslash. For example, "C:\Users" is returned rather than "C:\Users\".
  170.     CoTaskMemFree(OutPath);
  171.   end
  172.   else
  173.   begin
  174.     Result := '';
  175.   end;
  176. end;
  177.  
  178. // https://stackoverflow.com/questions/43774320/how-to-kill-a-process-by-name
  179. function KillTask(ExeFileName: string): Integer;
  180. const
  181.   PROCESS_TERMINATE = $0001;
  182. var
  183.   ContinueLoop: BOOL;
  184.   FSnapshotHandle: THandle;
  185.   FProcessEntry32: TProcessEntry32;
  186. begin
  187.   Result := 0;
  188.   FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  189.   FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  190.   ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
  191.  
  192.   while Integer(ContinueLoop) <> 0 do
  193.   begin
  194.     if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
  195.       UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
  196.       UpperCase(ExeFileName))) then
  197.       Result := Integer(TerminateProcess(
  198.                         OpenProcess(PROCESS_TERMINATE,
  199.                                     BOOL(0),
  200.                                     FProcessEntry32.th32ProcessID),
  201.                                     0));
  202.      ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  203.   end;
  204.   CloseHandle(FSnapshotHandle);
  205. end;
  206.  
  207. function OwnDirectory: string;
  208. begin
  209.   result := extractfilepath(paramstr(0));
  210. end;
  211.  
  212. // https://www.delphipraxis.net/post43515.html , fixed , works for Delphi 12 Athens
  213. function GetHTML(AUrl: string): RawByteString;
  214. var
  215.   databuffer : array[0..4095] of ansichar; // SIC! ansichar!
  216.   ResStr : ansistring; // SIC! ansistring
  217.   hSession, hfile: hInternet;
  218.   dwindex,dwcodelen,dwread,dwNumber: cardinal;
  219.   dwcode : array[1..20] of char;
  220.   res    : pchar;
  221.   Str    : pansichar; // SIC! pansichar
  222. begin
  223.   ResStr:='';
  224.   if (system.pos('http://',lowercase(AUrl))=0) and // do not localize
  225.      (system.pos('https://',lowercase(AUrl))=0) then // do not localize
  226.      AUrl:='http://'+AUrl; // do not localize
  227.  
  228.   // Hinzugefügt
  229.   if Assigned(Application) then Application.ProcessMessages;
  230.  
  231.   hSession:=InternetOpen('InetURL:/1.0', // do not localize
  232.                          INTERNET_OPEN_TYPE_PRECONFIG,
  233.                          nil,
  234.                          nil,
  235.                          0);
  236.   if assigned(hsession) then
  237.   begin
  238.     // Hinzugefügt
  239.     if Assigned(Application) then application.ProcessMessages;
  240.  
  241.     hfile:=InternetOpenUrl(
  242.            hsession,
  243.            pchar(AUrl),
  244.            nil,
  245.            0,
  246.            INTERNET_FLAG_RELOAD,
  247.            0);
  248.     dwIndex  := 0;
  249.     dwCodeLen := 10;
  250.  
  251.     // Hinzugefügt
  252.     if Assigned(Application) then application.ProcessMessages;
  253.  
  254.     HttpQueryInfo(hfile,
  255.                   HTTP_QUERY_STATUS_CODE,
  256.                   @dwcode,
  257.                   dwcodeLen,
  258.                   dwIndex);
  259.     res := pchar(@dwcode);
  260.     dwNumber := sizeof(databuffer)-1;
  261.     if (res ='200') or (res = '302') then // do not localize
  262.     begin
  263.       while (InternetReadfile(hfile,
  264.                               @databuffer,
  265.                               dwNumber,
  266.                               DwRead)) do
  267.       begin
  268.  
  269.         // Hinzugefügt
  270.         if Assigned(Application) then application.ProcessMessages;
  271.  
  272.         if dwRead =0 then
  273.           break;
  274.         databuffer[dwread]:=#0;
  275.         Str := pansichar(@databuffer);
  276.         resStr := resStr + Str;
  277.       end;
  278.     end
  279.     else
  280.       ResStr := 'Status:'+AnsiString(res); // do not localize
  281.     if assigned(hfile) then
  282.       InternetCloseHandle(hfile);
  283.   end;
  284.  
  285.   // Hinzugefügt
  286.   if Assigned(Application) then application.ProcessMessages;
  287.  
  288.   InternetCloseHandle(hsession);
  289.   Result := resStr;
  290. end;
  291.  
  292. procedure CheckForUpdates(ViaThinkSoftProjectName: string; AVersion: string);
  293. resourcestring
  294.   SDownloadError = 'Ein Fehler ist aufgetreten. Wahrscheinlich ist keine Internetverbindung aufgebaut, oder der der ViaThinkSoft-Server vorübergehend offline.';
  295.   SNewProgramVersionAvailable = 'Eine neue Programmversion ist vorhanden. Möchten Sie diese jetzt herunterladen?';
  296.   SNoUpdateAvailable = 'Es ist keine neue Programmversion vorhanden.';
  297. var
  298.   cont: RawByteString;
  299. begin
  300.   cont := GetHTML('https://www.viathinksoft.de/update/?id='+ViaThinkSoftProjectName); // do not localize
  301.   if copy(cont, 0, 7) = 'Status:' then
  302.   begin
  303.     MessageDlg(SDownloadError, mtError, [mbOk], 0);
  304.   end
  305.   else
  306.   begin
  307.     if string(cont) <> AVersion then
  308.     begin
  309.       if MessageDlg(SNewProgramVersionAvailable, mtConfirmation, mbYesNoCancel, 0) = mrYes then
  310.         shellexecute(application.handle, 'open', pchar('https://www.viathinksoft.de/update/?id=@'+ViaThinkSoftProjectName), '', '', sw_normal); // do not localize
  311.     end
  312.     else
  313.     begin
  314.       MessageDlg(SNoUpdateAvailable, mtInformation, [mbOk], 0);
  315.     end;
  316.   end;
  317. end;
  318.  
  319. end.
  320.