Subversion Repositories spacemission

Compare Revisions

Regard whitespace Rev 79 → Rev 78

/GamMain.pas
1230,8 → 1230,6
{ TMainForm }
 
procedure TMainForm.FormCreate(Sender: TObject);
resourcestring
SAppTitle = 'SpaceMission %s';
begin
Randomize;
 
1294,7 → 1292,7
 
{ Ende VCL-Ersatz }
 
Application.Title := Format(SAppTitle, [ProgramVersion]);
Application.Title := 'SpaceMission '+ProgramVersion;
LoadOptions;
DXInit;
SoundInit;
1353,11 → 1351,9
end;
 
procedure TMainForm.DXInit;
const
DxgFile = 'DirectX\Graphics.dxg'; // do not localize
begin
try
Imagelist.Items.LoadFromFile(OwnDirectory+DxgFile);
Imagelist.Items.LoadFromFile(OwnDirectory+'DirectX\Graphics.dxg');
ImageList.Items.MakeColorTable;
DXDraw.ColorTable := ImageList.Items.ColorTable;
DXDraw.DefColorTable := ImageList.Items.ColorTable;
1374,7 → 1370,7
 
procedure TMainForm.CheckUpdatesClick(Sender: TObject);
begin
CheckForUpdates('spacemission', ProgramVersion); // do not localize
CheckForUpdates('spacemission', ProgramVersion);
end;
 
procedure TMainForm.BeendenClick(Sender: TObject);
1390,10 → 1386,8
end;
 
procedure TMainForm.SoundInit;
const
DxwFile = 'DirectX\Sound.dxw'; // do not localize
begin
if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+DxwFile) then
if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+'DirectX\Sound.dxw') then
begin
OptionSound.Checked := false;
OptionSound.Enabled := False;
1406,7 → 1400,7
begin
try
DXSound.Initialize;
WaveList.Items.LoadFromFile(OwnDirectory+DxwFile);
WaveList.Items.LoadFromFile(OwnDirectory+'DirectX\Sound.dxw');
except
OptionSound.enabled := False;
WaveList.items.clear;
1417,12 → 1411,10
end;
 
procedure TMainForm.MusicInit;
const
DxmFile = 'DirectX\Music.dxm'; // do not localize
var
i: integer;
begin
if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+DxmFile) then
if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+'DirectX\Music.dxm') then
begin
optionmusic.Checked := false;
optionmusic.Enabled := False;
1430,7 → 1422,7
end;
 
try
dxmusic.Midis.LoadFromFile(OwnDirectory+DxmFile);
dxmusic.Midis.LoadFromFile(OwnDirectory+'DirectX\Music.dxm');
for i := 0 to dxmusic.Midis.Count-1 do
begin
if not dxmusic.Midis.Items[i].IsInitialized then
1484,11 → 1476,9
end;
 
procedure TMainForm.DXTimerDeactivate(Sender: TObject);
resourcestring
SPauseTitle = '%s [Pause]';
begin
TDxTimer(Sender).Tag := TDxTimer(Sender).Tag + 1;
Caption := Format(SPauseTitle, [Application.Title]);
Caption := Application.Title + ' [Pause]';
PauseMusic(FMusic);
end;
 
1541,9 → 1531,9
Reg.RootKey := HKEY_CURRENT_USER;
if Reg.OpenKey(RegistrySettingsKey, true) then
begin
Reg.WriteBool(MusicSettingKey, OptionMusic.checked);
Reg.WriteBool(SoundSettingKey, OptionSound.checked);
Reg.WriteInteger(SpeedSettingKey, Ord(FInterval)); // TODO : maybe it would be better to let the user change the real speed, so they can set their own custom one!
Reg.WriteBool('Music', OptionMusic.checked);
Reg.WriteBool('Sound', OptionSound.checked);
Reg.WriteInteger('Speed', Ord(FInterval));
Reg.CloseKey;
end;
finally
1560,18 → 1550,18
Reg.RootKey := HKEY_CURRENT_USER;
if Reg.OpenKey(RegistrySettingsKey, true) then
begin
if Reg.ValueExists(MusicSettingKey) then
optionmusic.checked := Reg.ReadBool(MusicSettingKey)
if Reg.ValueExists('Music') then
optionmusic.checked := Reg.ReadBool('Music')
else
optionmusic.checked := true; // default
 
if Reg.ValueExists(SoundSettingKey) then
optionsound.checked := Reg.ReadBool(SoundSettingKey)
if Reg.ValueExists('Sound') then
optionsound.checked := Reg.ReadBool('Sound')
else
optionsound.checked := true; // default
 
if Reg.ValueExists(SpeedSettingKey) then
FInterval := TGameInterval(Reg.ReadInteger(SpeedSettingKey))
if Reg.ValueExists('Speed') then
FInterval := TGameInterval(Reg.ReadInteger('Speed'))
else
FInterval := giMittel; // default
 
1856,7 → 1846,7
 
procedure TMainForm.NewLevel(lev: integer);
resourcestring
SLevelInvalid = 'Das Level Nr. %d ist ungültig!'+#13#10+'Das Programm wird beendet.';
LNG_LEVEL_INVALID = 'Das Level Nr. %d ist ungültig!'+#13#10+'Das Programm wird beendet.';
const
RandomLevelMaxEnemyLives = 10;
var
1983,7 → 1973,7
LevelData.RasterErzwingen := false;
LevelData.LoadFromFile(levFile.fileLocation);
except
showmessage(Format(SLevelInvalid, [lev]));
showmessage(Format(LNG_LEVEL_INVALID, [lev]));
ResetLevelData;
end;
end;
2108,7 → 2098,7
FLevel := 1;
if FGameMode = gmEditor then
begin
ShellExecute(0, 'open', PChar(OwnDirectory+LevEditExe), '', PChar(OwnDirectory), SW_NORMAL); // do not localize
ShellExecute(0, 'open', PChar(OwnDirectory+'LevEdit.exe'), '', PChar(OwnDirectory), SW_NORMAL);
Close;
exit;
end;
2126,15 → 2116,6
end;
 
procedure TMainForm.SceneMain;
resourcestring
SMissionSucsessful = 'Mission erfolgreich!';
SMissionFailed = 'Mission gescheitert!';
SPunkte = 'Punkte: %s'; // TODO: Is %f or FloatToStrF() better for internationalization?
SLevel = 'Level: %d';
SLifes = 'Leben: %d';
SInfLifes = '';
SBossLifes = 'Boss: %d';
SEinheiten = 'Einheiten: %d';
var
Enemy: TSprite;
spriteClass: TClass;
2197,16 → 2178,16
begin
{$REGION 'Anzeige Punkte'}
DXDraw.Surface.Canvas.Font.Color := clOlive;
DXDraw.Surface.Canvas.Textout(9, 9, Format(SPunkte, [FloatToStrF(FScore,ffNumber,14,0)]));
DXDraw.Surface.Canvas.Textout(9, 9, 'Punkte: ' + FloatToStrF(FScore,ffNumber,14,0));
DXDraw.Surface.Canvas.Font.Color := clYellow;
DXDraw.Surface.Canvas.Textout(10, 10, Format(SPunkte, [FloatToStrF(FScore,ffNumber,14,0)]));
DXDraw.Surface.Canvas.Textout(10, 10, 'Punkte: ' + FloatToStrF(FScore,ffNumber,14,0));
{$ENDREGION}
 
{$REGION 'Anzeige Level'}
DXDraw.Surface.Canvas.Font.Color := clMaroon;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-141, 9, Format(SLevel, [flevel]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-141, 9, 'Level: ' + IntToStr(flevel));
DXDraw.Surface.Canvas.Font.Color := clRed;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-140, 10, Format(SLevel, [flevel]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-140, 10, 'Level: ' + IntToStr(flevel));
{$ENDREGION}
 
{$REGION 'Lebensanzeige'}
2214,9 → 2195,9
if FCheat then
begin
DXDraw.Surface.Canvas.Font.Color := clPurple;
DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, SInfLifes);
DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, 'Leben: ?');
DXDraw.Surface.Canvas.Font.Color := clFuchsia;
DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, SInfLifes);
DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, 'Leben: ?');
end
else
begin
2223,9 → 2204,9
if ((Flife = 1) and ((FBlink div 300) mod 2=0)) or (Flife <> 1) then
begin
DXDraw.Surface.Canvas.Font.Color := clPurple;
DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, Format(SLifes, [flife]));
DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, 'Leben: ' + IntToStr(flife));
DXDraw.Surface.Canvas.Font.Color := clFuchsia;
DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, Format(SLifes, [flife]));
DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, 'Leben: ' + IntToStr(flife));
end;
if Flife = 1 then BlinkUpdate;
end;
2241,26 → 2222,26
if (tmpEnemyAnzeige>0) then
begin
DXDraw.Surface.Canvas.Font.Color := clGreen;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-81, Format(SBossLifes, [FBossLife]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, Format(SEinheiten, [tmpEnemyAnzeige]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-81, 'Boss: ' + IntToStr(FBossLife));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
DXDraw.Surface.Canvas.Font.Color := clLime;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-80, Format(SBossLifes, [FBossLife]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, Format(SEinheiten, [tmpEnemyAnzeige]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-80, 'Boss: ' + IntToStr(FBossLife));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
end
else
begin
DXDraw.Surface.Canvas.Font.Color := clGreen;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, Format(SBossLifes, [FBossLife]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, 'Boss: ' + IntToStr(FBossLife));
DXDraw.Surface.Canvas.Font.Color := clLime;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, Format(SBossLifes, [FBossLife]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, 'Boss: ' + IntToStr(FBossLife));
end;
end
else if (FBossLife<=0) and (tmpEnemyAnzeige>0) then
begin
DXDraw.Surface.Canvas.Font.Color := clGreen;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, Format(SEinheiten, [tmpEnemyAnzeige]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
DXDraw.Surface.Canvas.Font.Color := clLime;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, Format(SEinheiten, [tmpEnemyAnzeige]));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
end;
{$ENDREGION}
 
2268,9 → 2249,9
if (EnemyCounter=0) and (FRestEnemies=0) and ((FBossImLevel and (FBossLife=0)) or not FBossImLevel) then
begin
DXDraw.Surface.Canvas.Font.Color := clGreen;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, SMissionSucsessful);
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, 'Mission erfolgreich!');
DXDraw.Surface.Canvas.Font.Color := clLime;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, SMissionSucsessful);
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, 'Mission erfolgreich!');
DXDraw.Surface.Canvas.Release;
Sleep(1);
inc(FCounter);
2281,9 → 2262,9
else
begin
DXDraw.Surface.Canvas.Font.Color := clMaroon;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, SMissionFailed);
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, 'Mission gescheitert!');
DXDraw.Surface.Canvas.Font.Color := clRed;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, SMissionFailed);
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, 'Mission gescheitert!');
end;
DXDraw.Surface.Canvas.Release;
end;
/ComHilfe.pas
34,7 → 34,7
DOC: Variant;
begin
if not Assigned(WebBrowser1.Document) then
WebBrowser1.Navigate('about:blank'); // do not localize
WebBrowser1.Navigate('about:blank');
 
DOC := WebBrowser1.Document;
DOC.Clear;
53,7 → 53,7
slCss := TStringList.Create();
try
slHtml.LoadFromFile(AMarkDownFile);
cssFile := IncludeTrailingPathDelimiter(FDirectory) + 'Style.css'; // do not localize
cssFile := IncludeTrailingPathDelimiter(FDirectory) + 'Style.css';
if FileExists(cssFile) then
slCss.LoadFromFile(cssFile);
md := TMarkdownProcessor.CreateDialect(mdCommonMark);
60,15 → 60,15
try
//md.AllowUnsafe := true;
ShowHTMLHelp(
'<html>'+ // do not localize
'<head>'+ // do not localize
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'+ // do not localize
'<style>'+slCss.Text+'</style>'+ // do not localize
'</head>'+ // do not localize
'<body>'+ // do not localize
'<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'+
'<style>'+slCss.Text+'</style>'+
'</head>'+
'<body>'+
md.process(UTF8ToString(RawByteString(slHtml.Text)))+
'</body>'+ // do not localize
'</html>'); // do not localize
'</body>'+
'</html>');
finally
FreeAndNil(md);
end;
82,17 → 82,17
const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
Headers: OleVariant; var Cancel: WordBool);
begin
if SameText(Copy(URL,1,7),'http://') or // do not localize
SameText(Copy(URL,1,8),'https://') or // do not localize
SameText(Copy(URL,1,7),'mailto:') then // do not localize
if SameText(Copy(URL,1,7),'http://') or
SameText(Copy(URL,1,8),'https://') or
SameText(Copy(URL,1,7),'mailto:') then
begin
// Links in default Browser anzeigen
ShellExecute(handle, 'open', PChar(string(URL)), '', '', SW_NORMAL); // do not localize
ShellExecute(handle, 'open', PChar(string(URL)), '', '', SW_NORMAL);
Cancel := true;
end
else if SameText(ExtractFileExt(URL), '.md') then // do not localize
else if SameText(ExtractFileExt(URL), '.md') then
begin
if SameText(Copy(URL,1,6), 'about:') then // do not localize
if SameText(Copy(URL,1,6), 'about:') then
ShowMarkDownHelp(IncludeTrailingPathDelimiter(FDirectory) + Copy(URL,7,Length(URL)))
else
ShowMarkDownHelp(URL);
/Global.pas
3,15 → 3,12
interface
 
const
ProgramVersion = '1.2.1';
LevEditRasterW = 48;
LevEditRasterH = 32;
ProgramVersion = '1.2';
RasterW = 48;
RasterH = 32;
MaxPossibleEnemyLives = 999;
MaxPossibleLevels = 999;
RegistrySettingsKey = 'SOFTWARE\ViaThinkSoft\SpaceMission\Settings'; // do not localize
MusicSettingKey = 'Music'; // do not localize
SoundSettingKey = 'Sound'; // do not localize
SpeedSettingKey = 'Speed'; // do not localize
RegistrySettingsKey = 'SOFTWARE\ViaThinkSoft\SpaceMission\Settings';
DefaultLevelLength = 1200;
StartLives = 6;
conleicht = 650 div 60; // 10
19,11 → 16,7
conschwer = 1350 div 60; // 22
conmaster = 2000 div 60; // 33
DEFAULT_ANIMSPEED = 15/1000;
ADDITIONAL_ENEMIES_PER_LEVEL = 75; // Zufalls-Level
BossWidth = 4;
BossHeight = 2;
SpaceMissionExe = 'SpaceMission.exe'; // do not localize
LevEditExe = 'LevEdit.exe'; // do not localize
ADDITIONAL_ENEMIES_PER_LEVEL = 75;
 
type
// DirectX\Music.dxm
75,7 → 68,7
function OwnDirectory: string;
 
const
FOLDERID_SavedGames: TGuid = '{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}'; // do not localize
FOLDERID_SavedGames: TGuid = '{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}';
 
// Useful functions
function GetKnownFolderPath(const rfid: TGUID): string;
85,8 → 78,7
implementation
 
uses
Windows, SysUtils, Dialogs, ActiveX, ShlObj, TlHelp32, wininet, Forms, ShellAPI,
System.UITypes;
Windows, SysUtils, ActiveX, ShlObj, TlHelp32, wininet, Forms, ShellAPI;
 
function GetKnownFolderPath(const rfid: TGUID): string;
var
156,14 → 148,14
Str : pansichar; // SIC! pansichar
begin
ResStr:='';
if (system.pos('http://',lowercase(AUrl))=0) and // do not localize
(system.pos('https://',lowercase(AUrl))=0) then // do not localize
AUrl:='http://'+AUrl; // do not localize
if (system.pos('http://',lowercase(AUrl))=0) and
(system.pos('https://',lowercase(AUrl))=0) then
AUrl:='http://'+AUrl;
 
// Hinzugefügt
if Assigned(Application) then Application.ProcessMessages;
 
hSession:=InternetOpen('InetURL:/1.0', // do not localize
hSession:=InternetOpen('InetURL:/1.0',
INTERNET_OPEN_TYPE_PRECONFIG,
nil,
nil,
193,7 → 185,7
dwIndex);
res := pchar(@dwcode);
dwNumber := sizeof(databuffer)-1;
if (res ='200') or (res = '302') then // do not localize
if (res ='200') or (res = '302') then
begin
while (InternetReadfile(hfile,
@databuffer,
212,7 → 204,7
end;
end
else
ResStr := 'Status:'+AnsiString(res); // do not localize
ResStr := 'Status:'+AnsiString(res);
if assigned(hfile) then
InternetCloseHandle(hfile);
end;
225,28 → 217,24
end;
 
procedure CheckForUpdates(ViaThinkSoftProjectName: string; AVersion: string);
resourcestring
SDownloadError = 'Ein Fehler ist aufgetreten. Wahrscheinlich ist keine Internetverbindung aufgebaut, oder der der ViaThinkSoft-Server vorübergehend offline.';
SNewProgramVersionAvailable = 'Eine neue Programmversion ist vorhanden. Möchten Sie diese jetzt herunterladen?';
SNoUpdateAvailable = 'Es ist keine neue Programmversion vorhanden.';
var
cont: RawByteString;
begin
cont := GetHTML('https://www.viathinksoft.de/update/?id='+ViaThinkSoftProjectName); // do not localize
cont := GetHTML('https://www.viathinksoft.de/update/?id='+ViaThinkSoftProjectName);
if copy(cont, 0, 7) = 'Status:' then
begin
MessageDlg(SDownloadError, mtError, [mbOk], 0);
Application.MessageBox('Ein Fehler ist aufgetreten. Wahrscheinlich ist keine Internetverbindung aufgebaut, oder der der ViaThinkSoft-Server vorübergehend offline.', 'Fehler', MB_OK + MB_ICONERROR)
end
else
begin
if string(cont) <> AVersion then
begin
if MessageDlg(SNewProgramVersionAvailable, mtConfirmation, mbYesNoCancel, 0) = mrYes then
shellexecute(application.handle, 'open', pchar('https://www.viathinksoft.de/update/?id=@'+ViaThinkSoftProjectName), '', '', sw_normal); // do not localize
if Application.MessageBox('Eine neue Programmversion ist vorhanden. Möchten Sie diese jetzt herunterladen?', 'Information', MB_YESNO + MB_ICONASTERISK) = ID_YES then
shellexecute(application.handle, 'open', pchar('https://www.viathinksoft.de/update/?id=@'+ViaThinkSoftProjectName), '', '', sw_normal);
end
else
begin
MessageDlg(SNoUpdateAvailable, mtInformation, [mbOk], 0);
Application.MessageBox('Es ist keine neue Programmversion vorhanden.', 'Information', MB_OK + MB_ICONASTERISK);
end;
end;
end;
/LevMain.pas
128,7 → 128,7
procedure DoMove(MoveCount: Integer); override;
end;
 
TEnemyOrItem = class(TImageSprite)
TEnemy = class(TImageSprite)
strict private
FLives: integer;
FEnemyType: TEnemyType;
144,23 → 144,23
 
procedure TBackground.DoMove(MoveCount: Integer);
begin
X := -(MainForm.ScrollP * LevEditRasterW);
X := -(MainForm.ScrollP * RasterW);
end;
 
{ TEnemy }
 
procedure TEnemyOrItem.DoMove(MoveCount: Integer);
procedure TEnemy.DoMove(MoveCount: Integer);
begin
if not FCorInit then
begin
FXCor := trunc(x) + (MainForm.ScrollP * LevEditRasterW);
FXCor := trunc(x) + (MainForm.ScrollP * RasterW);
FCorInit := true;
end;
if MainForm.LevData.IndexOfEnemy(FXCor, integer(round(Y)), FEnemyType, FLives) = -1 then dead;
X := FXCor - (MainForm.ScrollP * LevEditRasterW);
X := FXCor - (MainForm.ScrollP * RasterW);
end;
 
constructor TEnemyOrItem.Create(AParent: TSprite; AEnemyType: TEnemyType; ALives: Integer);
constructor TEnemy.Create(AParent: TSprite; AEnemyType: TEnemyType; ALives: Integer);
begin
inherited Create(AParent);
if AEnemyType = etEnemyAttacker then Image := MainForm.GetSpriteGraphic(smgEnemyAttacker);
186,7 → 186,7
 
procedure TMainForm.DXInit;
begin
Imagelist.Items.LoadFromFile(OwnDirectory+'DirectX\Graphics.dxg'); // do not localize
Imagelist.Items.LoadFromFile(OwnDirectory+'DirectX\Graphics.dxg');
ImageList.Items.MakeColorTable;
DXDraw.ColorTable := ImageList.Items.ColorTable;
DXDraw.DefColorTable := ImageList.Items.ColorTable;
197,7 → 197,6
procedure TMainForm.FormCreate(Sender: TObject);
resourcestring
SFileError = 'Die Datei kann von SpaceMission nicht geöffnet werden!';
SCaption = 'SpaceMission %s - Leveleditor';
begin
{ VCL-Ersatz start }
dxtimer := tdxtimer.create(self);
249,8 → 248,8
// Leeres Level am Anfang braucht keine Beenden-Bestätigung.
// LevChanged := true;
 
//Application.Title := Format(SCaption, [ProgramVersion]);
Caption := Format(SCaption, [ProgramVersion]);
//Application.Title := 'SpaceMission '+ProgramVersion+' - Leveleditor';
Caption := 'SpaceMission '+ProgramVersion+' - Leveleditor';
DXInit;
LevData := TLevelData.create;
ProgramInit;
482,7 → 481,7
sav: TSaveData;
tmp: string;
begin
KillTask(SpaceMissionExe);
KillTask('SpaceMission.exe');
 
sav := TSaveData.Create;
try
497,7 → 496,7
sav.LevelData.Assign(LevData);
tmp := GetTestlevelFilename;
sav.SaveToFile(tmp);
ShellExecute(Handle, 'open', PChar(OwnDirectory+SpaceMissionExe), PChar('"'+tmp+'"'), PChar(OwnDirectory), SW_NORMAL); // do not localize
ShellExecute(Handle, 'open', PChar(OwnDirectory+'SpaceMission.exe'), PChar('"'+tmp+'"'), PChar(OwnDirectory), SW_NORMAL);
finally
FreeAndNil(sav);
end;
526,7 → 525,7
 
function TMainForm.GetTestlevelFilename: string;
begin
result := IncludeTrailingPathDelimiter(TPath.GetTempPath) + 'SpaceMissionTest.sav'; // do not localize
result := IncludeTrailingPathDelimiter(TPath.GetTempPath) + 'SpaceMissionTest.sav';
end;
 
procedure TMainForm.HilfeTopicClick(Sender: TObject);
568,8 → 567,8
j, k, l, ex, ey: integer;
ok, breaked: boolean;
begin
ex := trunc(x/LevEditRasterW) * LevEditRasterW;
ey := trunc(y/LevEditRasterH) * LevEditRasterH;
ex := trunc(x/RasterW) * RasterW;
ey := trunc(y/RasterH) * RasterH;
EnemyCreateSprite(ex, ey, SelectedEnemyType, LivesEdit.Value);
breaked := false;
{ Setzen }
586,11 → 585,11
begin
if boss then
begin
for k := 0 to BossWidth-1 do
for k := 0 to 3 do
begin
for l := 0 to BossHeight-2 do
for l := 0 to 1 do
begin
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), etEnemyBoss, j) <> -1 then
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * RasterW), ey - (RasterH * l), etEnemyBoss, j) <> -1 then
begin
ok := false;
break;
600,7 → 599,7
end;
if not ok then break;
end;
if LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1 then
if LevData.IndexOfEnemy(ex + (ScrollP * RasterW), ey, i, j) <> -1 then
begin
ok := false;
break;
612,9 → 611,9
if ok then
begin
if EnemyTypeHasLives(SelectedEnemyType) then
LevData.AddEnemy(ex + (ScrollP * LevEditRasterW), ey, SelectedEnemyType, LivesEdit.Value)
LevData.AddEnemy(ex + (ScrollP * RasterW), ey, SelectedEnemyType, LivesEdit.Value)
else
LevData.AddEnemy(ex + (ScrollP * LevEditRasterW), ey, SelectedEnemyType, 0);
LevData.AddEnemy(ex + (ScrollP * RasterW), ey, SelectedEnemyType, 0);
inc(NumEnemys);
if SelectedEnemyType = etEnemyBoss then boss := true;
end
629,13 → 628,13
begin
if boss and (i = etEnemyBoss) then
begin
for k := 0 to BossWidth - 1 do
for k := 0 to 3 do
begin
for l := 0 to BossHeight - 1 do
for l := 0 to 1 do
begin
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j) <> -1 then
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * RasterW), ey - (RasterH * l), i, j) <> -1 then
begin
LevData.DeleteEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j);
LevData.DeleteEnemy(ex + ((ScrollP - k) * RasterW), ey - (RasterH * l), i, j);
Boss := false;
dec(NumEnemys);
breaked := true;
645,9 → 644,9
if breaked then break;
end;
end;
if LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1 then
if LevData.IndexOfEnemy(ex + (ScrollP * RasterW), ey, i, j) <> -1 then
begin
LevData.DeleteEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j);
LevData.DeleteEnemy(ex + (ScrollP * RasterW), ey, i, j);
if i = etEnemyBoss then Boss := false;
dec(NumEnemys);
breaked := true;
675,7 → 674,7
var
Enemy: TSprite;
begin
Enemy := TEnemyOrItem.Create(SpriteEngine.Engine, AEnemyType, ALives);
Enemy := TEnemy.Create(SpriteEngine.Engine, AEnemyType, ALives);
Enemy.x := x;
Enemy.y := y;
end;
712,37 → 711,32
end;
 
procedure TMainForm.AnzeigeAct;
resourcestring
SYes = 'Ja';
SNo = 'Nein';
begin
SLabel1b.Caption := inttostr(NumEnemys);
if Boss then SLabel2b.Caption := SYes else SLabel2b.Caption := SNo;
if Boss then SLabel2b.Caption := 'Ja' else SLabel2b.Caption := 'Nein';
SLabel3b.Caption := inttostr(ScrollBar.Max);
if LevChanged then
begin
SLabel4a.Font.Color := $00000096;
SLabel4b.Font.Color := $00000096;
SLabel4b.Caption := SNo;
SLabel4b.Caption := 'Nein';
end
else
begin
SLabel4a.Font.Color := $00009600;
SLabel4b.Font.Color := $00009600;
SLabel4b.Caption := SYes;
SLabel4b.Caption := 'Ja';
end;
end;
 
procedure TMainForm.AufUpdatesprfen1Click(Sender: TObject);
begin
CheckForUpdates('spacemission', ProgramVersion); // do not localize
CheckForUpdates('spacemission', ProgramVersion);
end;
 
procedure TMainForm.NeuClick(Sender: TObject);
resourcestring
SReallyDeleteLevel = 'Level wirklich löschen?';
begin
if MessageDlg(SReallyDeleteLevel, mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg('Level wirklich löschen?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
DestroyLevel;
end;
 
752,7 → 746,6
status_info = 'Zeigen Sie mit dem Mauszeiger auf eine Einheit, um deren Eigenschaften anzuzeigen...';
status_lives = 'Leben: ';
status_nolives = 'Einheit hat keine Lebensangabe';
SUnknownEnemyType = '???';
var
i: TEnemyType;
ex, ey, j, k, l: integer;
766,8 → 759,8
StatusBar.SimpleText := ' ' + status_info;
exit;
end;
ex := trunc(x/LevEditRasterW) * LevEditRasterW;
ey := trunc(y/LevEditRasterH) * LevEditRasterH;
ex := trunc(x/RasterW) * RasterW;
ey := trunc(y/RasterH) * RasterH;
lifes := -1;
enemyType := etUnknown;
breaked := false;
777,11 → 770,11
begin
if boss and (i = etEnemyBoss) then
begin
for k := 0 to BossWidth - 1 do
for k := 0 to 3 do
begin
for l := 0 to BossHeight - 1 do
for l := 0 to 1 do
begin
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j) <> -1 then
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * RasterW), ey - (RasterH * l), i, j) <> -1 then
begin
lifes := j;
breaked := true;
791,7 → 784,7
if breaked then break;
end;
end;
if (breaked = false) and (LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1) then
if (breaked = false) and (LevData.IndexOfEnemy(ex + (ScrollP * RasterW), ey, i, j) <> -1) then
begin
lifes := j;
enemyType := i;
811,7 → 804,7
else if Ord(enemyType) = 6 then enemyName := Enemy6.Caption
else if Ord(enemyType) = 7 then enemyName := Enemy7.Caption
else if Ord(enemyType) = 8 then enemyName := Enemy8.Caption
else enemyName := SUnknownEnemyType;
else enemyName := '???';
if lifes > 0 then
StatusBar.SimpleText := ' ' + enemyName + ' - ' + status_lives + inttostr(lifes)
else
822,11 → 815,9
end;
 
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
resourcestring
SExitWithoutSave = 'Beenden ohne abspeichern?';
begin
if Assigned(LevData) and LevChanged and (LevData.CountEnemies>0) then
CanClose := MessageDlg(SExitWithoutSave, mtConfirmation, mbYesNoCancel, 0) = mrYes;
CanClose := MessageDlg('Beenden ohne abspeichern?', mtConfirmation, mbYesNoCancel, 0) = mrYes;
end;
 
procedure TMainForm.Spielfelderweitern1Click(Sender: TObject);
/LevSpeicherung.pas
59,7 → 59,6
resourcestring
SLevelListBox = 'Level %d';
SSelbsterstellt = 'Selbsterstellt';
SLevelFileNotFound = 'Leveldatei nicht gefunden';
 
procedure TSpeicherungForm.SearchLevels;
var
93,14 → 92,12
end;
 
procedure TSpeicherungForm.LoeschenBtnClick(Sender: TObject);
resourcestring
SReallyDeleteLevel = 'Dieses Level wirklich löschen?';
var
fil: TLevelFile;
begin
if LevelListBox.ItemIndex = -1 then exit;
 
if MessageDlg(SReallyDeleteLevel, mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg('Dieses Level wirklich löschen?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
begin
li1a.visible := false;
li2a.visible := false;
114,7 → 111,7
LadenBtn.enabled := false;
LoeschenBtn.enabled := false;
fil := GetLevelFileName(GetListBoxSelectedLevelNumber,false);
if not fil.found then raise Exception.Create(SLevelFileNotFound);
if not fil.found then raise Exception.Create('Leveldatei nicht gefunden');
deletefile(fil.fileLocation);
SearchLevels;
end;
121,8 → 118,6
end;
 
procedure TSpeicherungForm.LadenBtnClick(Sender: TObject);
resourcestring
SLoadNewLevelAndDiscardChanges = 'Neues Level laden und Änderungen verwerfen?';
var
fil: TLevelFile;
begin
130,7 → 125,7
 
if MainForm.LevChanged and (MainForm.LevData.CountEnemies>0) then
begin
if MessageDlg(SLoadNewLevelAndDiscardChanges, mtConfirmation, mbYesNoCancel, 0) <> mrYes then exit;
if MessageDlg('Neues Level laden und Änderungen verwerfen?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then exit;
end;
 
// Da Button bei ungültigen Level deaktiviert wird, ist das nicht mehr nötig.
140,7 → 135,7
MainForm.DestroyLevel;
MainForm.LevData.RasterErzwingen := true;
fil := GetLevelFileName(GetListBoxSelectedLevelNumber,false);
if not fil.found then raise Exception.Create(SLevelFileNotFound);
if not fil.found then raise Exception.Create('Leveldatei nicht gefunden');
MainForm.LevData.LoadFromFile(fil.fileLocation);
MainForm.RefreshFromLevData;
MainForm.LevChanged := false;
149,14 → 144,10
end;
 
procedure TSpeicherungForm.SpeichernBtnClick(Sender: TObject);
resourcestring
SLevelIsEmpty = 'Das Level ist leer!';
SLevelAlreadyExists = 'Level ist bereits vorhanden. Ersetzen?';
SNoValidLevelName = 'Dies ist kein gültiger Levelname!';
begin
if MainForm.LevData.CountEnemies = 0 then
begin
MessageDlg(SLevelIsEmpty, mtError, [mbOK], 0);
MessageDlg('Das Level ist leer!', mtError, [mbOK], 0);
LevelNumber.SetFocus;
exit;
end;
172,7 → 163,7
(copy(LevelName.text, i, 1) = '>') or
(copy(LevelName.text, i, 1) = '|') then
begin
MessageDlg(SNoValidLevelName, mtError, [mbOK], 0);
MessageDlg('Dies ist kein gültiger Levelname!', mtError, [mbOK], 0);
LevelName.SetFocus;
exit;
end;
180,7 → 171,7
if (LevelListBox.items.IndexOf(Format(SLevelListBox, [LevelNumber.Value])) > -1) or
(LevelListBox.items.IndexOf(Format(SLevelListBox, [LevelNumber.Value])+' ('+SSelbsterstellt+')') > -1) then
begin
if MessageDlg(SLevelAlreadyExists, mtConfirmation, mbYesNoCancel, 0) <> mrYes then
if MessageDlg('Level ist bereits vorhanden. Ersetzen?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then
exit;
end;
 
195,11 → 186,6
end;
 
procedure TSpeicherungForm.LevelListBoxClick(Sender: TObject);
resourcestring
SYes = 'Ja';
SNo = 'Nein';
SFields = '%d Felder';
SXbyY = '%s von %s';
var
LevelData: TLevelData;
boss: boolean;
231,7 → 217,7
LevelData.RasterErzwingen := true;
 
fil := GetLevelFileName(GetListBoxSelectedLevelNumber,false);
if not fil.found then raise Exception.Create(SLevelFileNotFound);
if not fil.found then raise Exception.Create('Leveldatei nicht gefunden');
LevelData.LoadFromFile(fil.fileLocation);
 
boss := false;
255,11 → 241,11
LoeschenBtn.enabled := true;
li1b.caption := inttostr(anzahlEinheiten);
if boss then
li2b.caption := SYes
li2b.caption := 'Ja'
else
li2b.caption := SNo;
li3b.caption := Format(SFields, [LevelData.LevelEditorLength]);
li4.Caption := Trim(Format(SXbyY, [LevelData.LevelName, LevelData.LevelAuthor]));
li2b.caption := 'Nein';
li3b.caption := IntToStr(LevelData.LevelEditorLength) + ' Felder';
li4.Caption := Trim(LevelData.LevelName + ' von ' + LevelData.LevelAuthor);
finally
FreeAndNil(LevelData);
end;
/ComLevelReader.pas
11,7 → 11,7
// - GamMain.pas : TMainForm.SceneMain
// - LevMain.pas : * GUI
// * TMainForm.SelectedEnemyType
// * TEnemyOrItem.Create
// * TEnemy.Create
// * TMainForm.DXDrawMouseMove
// * TMainForm.DXDrawMouseDown
TEnemyType = (
96,19 → 96,14
const
// { iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) 37476 products(2) spacemission(8) file-format(1) lev-sav-v12(1) }
// https://hosted.oidplus.com/viathinksoft/?goto=oid%3A1.3.6.1.4.1.37476.2.8.1.1
OID_LEVSAV_VER12 = '1.3.6.1.4.1.37476.2.8.1.1'; // do not localize
OID_LEVSAV_VER12 = '1.3.6.1.4.1.37476.2.8.1.1';
 
resourcestring
SLevelFileFolder = 'Levels';
SLevelFileSubFolder = 'SpaceMission';
SExtraContentAfterLine = 'Zeile %d ist ungültig (Zusatzinfo am Ende)';
 
function GetLevelFileName(lev: integer; forceuserdir: boolean): TLevelFile;
 
function _GetLevelVerzeichnisSystem: string;
begin
// Für die Auslieferungs-Levels
result := OwnDirectory + SLevelFileFolder;
result := OwnDirectory + 'Levels';
end;
 
function _GetLevelVerzeichnisUser: string;
121,12 → 116,12
if result = '' then
begin
// Pre Vista
result := OwnDirectory + SLevelFileFolder;
result := OwnDirectory + 'Levels';
end
else
begin
result := IncludeTrailingPathDelimiter(result);
result := result + SLevelFileSubFolder;
result := result + 'SpaceMission';
end;
result := IncludeTrailingPathDelimiter(result);
ForceDirectories(result);
136,8 → 131,8
var
old, new: string;
begin
new := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisUser)+'Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files // do not localize
old := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisUser)+'Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files // do not localize
new := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisUser)+'Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files
old := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisUser)+'Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files
if fileexists(new) then exit(new);
if fileexists(old) then exit(old);
exit(new);
147,8 → 142,8
var
old, new: string;
begin
new := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisSystem)+'Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files // do not localize
old := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisSystem)+'Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files // do not localize
new := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisSystem)+'Level '+inttostr(lev)+'.lev'; // Version 0.3+ Level Files
old := IncludeTrailingPathDelimiter(_GetLevelVerzeichnisSystem)+'Lev'+inttostr(lev)+'A1.lev'; // Version 0.2 Level Files
if fileexists(new) then exit(new);
if fileexists(old) then exit(old);
exit(new);
287,9 → 282,6
end;
 
procedure TLevelData.AddEnemy(x,y:integer;enemyType:TEnemyType;lifes:integer);
resourcestring
SInvalidXCoord = 'X-Koordinate muss ohne Rest durch %d teilbar sein';
SInvalidYCoord = 'Y-Koordinate muss ohne Rest durch %d teilbar sein';
begin
SetLength(EnemyAdventTable, Length(EnemyAdventTable)+1);
 
296,8 → 288,8
if enemyType = etEnemyMeteor then lifes := 0;
if RasterErzwingen then
begin
if x mod LevEditRasterW <> 0 then raise Exception.CreateFmt(SInvalidXCoord, [LevEditRasterW]);
if y mod LevEditRasterH <> 0 then raise Exception.CreateFmt(SInvalidYCoord, [LevEditRasterH]);
if x mod RasterW <> 0 then raise Exception.CreateFmt('X-Koordinate muss ohne Rest durch %d teilbar sein', [RasterW]);
if y mod RasterH <> 0 then raise Exception.CreateFmt('Y-Koordinate muss ohne Rest durch %d teilbar sein', [RasterH]);
end;
if lifes > MaxPossibleEnemyLives then lifes := MaxPossibleEnemyLives;
 
327,9 → 319,6
end;
 
procedure TLevelData.LoadFromStrings(sl: TStrings);
resourcestring
SInvalidLevelFile = 'Level-Format nicht unterstützt oder Datei ist beschädigt';
SEnemyTypeNotImplemented = 'Enemy Type %d not implemented';
var
curline: integer;
z, act: integer;
339,7 → 328,6
ergebnis: string;
ary: TStringDynArray;
sLine: string;
iEnemy: Integer;
begin
Clear;
 
369,8 → 357,8
if z > 2 then inc(act);
if act = 5 then act := 1;
ergebnis := sl.Strings[z-1];
if ergebnis = '; SpaceMission 0.4' then // do not localize
sl2.Add('; SpaceMission 1.0') // do not localize
if ergebnis = '; SpaceMission 0.4' then
sl2.Add('; SpaceMission 1.0')
else
begin
if (ergebnis = '30000') and (z = 3) then
403,10 → 391,7
curline := 3;
while curline < sl.Count do
begin
iEnemy := strtoint(sl.Strings[curline]);
if TEnemyType(iEnemy) = etUnknown then // <-- for some reason, etUnknown will also be set if iEnemy is too large. This is actually good!
raise Exception.CreateFmt(SEnemyTypeNotImplemented, [iEnemy]);
tmpEnemy := TEnemyType(iEnemy);
tmpEnemy := TEnemyType(strtoint(sl.Strings[curline]));
Inc(curline);
tmpX := strtoint(sl.Strings[curline]);
Inc(curline);
430,7 → 415,7
begin
LevelEditorLength := StrToInt(ary[1]);
if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
end
else if SameText(ary[0], 'Name') then // do not localize
begin
442,15 → 427,12
end
else if SameText(ary[0], 'Enemy') then // do not localize
begin
iEnemy := strtoint(ary[1]);
if TEnemyType(iEnemy) = etUnknown then // <-- for some reason, etUnknown will also be set if iEnemy is too large. This is actually good!
raise Exception.CreateFmt(SEnemyTypeNotImplemented, [iEnemy]);
tmpEnemy := TEnemyType(iEnemy);
tmpEnemy := TEnemyType(strtoint(ary[1]));
tmpX := strtoint(ary[2]);
tmpY := strtoint(ary[3]);
tmpLifes := strtoint(ary[4]);
if (Length(ary) > 5) and (Copy(ary[5], 1, 1) <> ';') then
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes);
end;
end;
458,7 → 440,7
end
else
begin
raise Exception.Create(SInvalidLevelFile);
raise Exception.Create('Level-Format nicht unterstützt oder Datei ist beschädigt');
end;
 
SortEnemies; // Sortierung nach X-Koordinate ist sehr wichtig für das Spiel!
540,8 → 522,6
end;
 
procedure TLevelData.SaveToStrings(sl: TStrings);
resourcestring
SLevelEnemyLineComment = '; Type XCoord YCoord Lives';
var
i: integer;
begin
551,7 → 531,7
if LevelAuthor <> '' then sl.Add('Author ' + LevelAuthor); // do not localize
sl.Add('Width ' + IntToStr(LevelEditorLength)); // do not localize
SortEnemies;
sl.Add(SLevelEnemyLineComment);
sl.Add('; Type XCoord YCoord Lives');
for i := 0 to Length(EnemyAdventTable)-1 do
begin
sl.Add(Trim(
665,8 → 645,6
end;
 
procedure TSaveData.LoadFromStrings(sl: TStrings);
resourcestring
SInvalidFile = 'Spielstand-Format nicht unterstützt oder Datei beschädigt';
var
curline: Integer;
ary: TStringDynArray;
696,25 → 674,25
begin
Score := StrToInt(ary[1]);
if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
end
else if SameText(ary[0], 'Lives') then // do not localize
begin
Life := StrToInt(ary[1]);
if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
end
else if SameText(ary[0], 'Level') then // do not localize
begin
Level := StrToInt(ary[1]);
if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
end
else if SameText(ary[0], 'Mode') then // do not localize
begin
GameMode := TGameMode(StrToInt(ary[1]));
if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
end;
end;
if Assigned(LevelData) then FreeAndNil(LevelData);
724,7 → 702,7
end
else
begin
raise Exception.Create(SInvalidFile);
raise Exception.Create('Spielstand-Format nicht unterstützt oder Datei beschädigt');
end;
end;
 
/LevEdit.dproj
90,8 → 90,7
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_MinorVer>2</VerInfo_MinorVer>
<VerInfo_Keys>CompanyName=ViaThinkSoft;FileDescription=SpaceMission LevelEditor;FileVersion=1.2.1.0;InternalName=SpaceMission LevEdit;LegalCopyright=(C) 2001-2024 Daniel Marschall, ViaThinkSoft;LegalTrademarks=;OriginalFilename=LevEdit.exe;ProductName=SpaceMission;ProductVersion=1.2.1;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
<VerInfo_Release>1</VerInfo_Release>
<VerInfo_Keys>CompanyName=ViaThinkSoft;FileDescription=SpaceMission LevelEditor;FileVersion=1.2.0.0;InternalName=SpaceMission LevEdit;LegalCopyright=(C) 2001-2024 Daniel Marschall, ViaThinkSoft;LegalTrademarks=;OriginalFilename=LevEdit.exe;ProductName=SpaceMission;ProductVersion=1.2;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Version>7.0</Version>
/TODO.md
1,15 → 1,11
 
# SpaceMission TODO
 
## Geplant für 1.2.1
 
- Registry individual Speed Setting
 
## Geplant für 1.3
 
- Neue Einheit: Ufo, das im Kreis fliegt und nicht weggeht
- Bei Pause => Entweder alles grau werden lassen, oder vielleicht ganz groß Pause in die Bildschirmmitte schreiben
- Auf Englisch übersetzen
- Vorbereitung auf Multilingualität (all strings in resourcestrings), ggf. sogar schon auf Englisch übersetzen
- SplashScreens: als BMP
 
## Kleinigkeiten
26,15 → 22,14
 
## Ideen
 
- Neues Item: 10 Sekunden unverwundbarkeit item
- Neues Item: Geld Geschenk item
- Neue Einheit: 10 Sekunden unverwundbarkeit item
- Neue Einheit: Geld Geschenk item
- Boss schwieriger machen: Er soll auch nach links und rechts gehen?
- Spiellogik: Wenn man gegen einen gegner fliegt, soll er schaden haben!
- Cooldown für Laser? Limitierung der Schüsse (Kanone wird heiß).
- Highscore Liste
- "Throwback" nach einem hit. Nach Treffer, zurückgeschleudert werden
- Anderer Soundeffekt, wenn man selbst getroffen ist
- Leveleditor: "unsaubere" levels akzeptieren! komet mit 1+ leben, einheiten, die nicht auf der linie sind.
- "unsaubere" levels akzeptieren! komet mit 1+ leben, einheiten, die nicht auf der linie sind.
- Netzwerkspiel?
- Leveleditor: Ober - / Unterfelder? (was meinte ich damit?)
- Leveleditor: Höchstens 9999 enemies?
43,14 → 38,17
- Verschiedene Dinge bei schnelligkeit anders?! z.B. Boss-Explore, Schießende Einheiten (Tamas)
- Tama 1 must damage PL. Sprite!
- Tama 2 must damage EN. Sprite!
- Tama 1 und Tama 2 könnten sich gegenseitig kaputt machen?
- Tama 1 und Tama 2 müssten sich gegenseitig kaputt machen?
- Speicherung: Umbenennen - Button?
 
## Repro, Unklar, Fragen
 
- Was ist wenn man mission erfolgreich hatte und dann doch stirbt?
- Kartengröße bleibt bei "Neu"
- Que: Gibt es eine neuere Version des Shoot-Samples (nicht mehr vorhanden in aktueller DelphiX)
- Leveleditor performance oder deadlock probleme? bei vielen einheiten wird das sehr langsam? algo verbessern?
- Tastenspeere bei runter+links+shot
- "Beenden ohne Speichern?" bei leerem Level
- Leveleditor performance oder deadlock probleme?
- Leveleditor Probleme mit Schiebebildchen... (was meinte ich damit?)
- Leveleditor Wenn Level gelöscht, dass gerade geladen ist, dann LevChanged = true!
- Leveleditor Boss überschneidet Einheiten ?
64,8 → 62,10
- Dec(live) bei attacker1 manchmal kein Ton?
- Sequences (was meinte ich damit?)
- Rnd: Soll Boss-Live auch RND?
- leicht, mittel, schwer: falsche fps bei langsameren grafikkarten?
- leicht, mittel, schwer: falsche fps bei langsameren karten
- auch mit einer symbolleiste mit ordnersymbol bei lev (oder sm)?
- lev: überall ok = focus!
- lev: bei vielen einheiten wird das arsch-langsam? algo verbessern?
- systemmodus auswählen (move rechnungen ausführen?) oder ein rechenlabel mit dem status anzeigen
- SM: Soll bei Verwaltung lieber statt dem ersten satz bei status was anderes hin? Levelart: Normales Level.
Wenn es bleiben soll, dann den satz verbessern. Das Level ist ein Zufallslevel
/GamSpeicherung.pas
58,12 → 58,6
 
{$R *.DFM}
 
resourcestring
SSaveGameFileNotFound = 'Spielstandsdatei nicht gefunden';
SNa = 'n/a';
SSaveGameFolder = 'Spielstände';
SSaveGameSubFolder = 'SpaceMission';
 
{ TSpeicherungForm }
 
procedure TSpeicherungForm.SearchSaves;
82,10 → 76,10
li4b.visible := false;
liu.visible := false;
liw.visible := true;
li1.caption := SNa;
li2b.caption := SNa;
li3b.caption := SNa;
li4b.caption := SNa;
li1.caption := 'n/a';
li2b.caption := 'n/a';
li3b.caption := 'n/a';
li4b.caption := 'n/a';
LadenBtn.enabled := false;
LoeschenBtn.enabled := false;
res := FindFirst(IncludeTrailingPathDelimiter(GetSpielstandVerzeichnisSystem)+'*.sav', 0, sr);
115,14 → 109,12
end;
 
procedure TSpeicherungForm.LoeschenBtnClick(Sender: TObject);
resourcestring
SDeleteSaveGame = 'Diesen Spielstand wirklich löschen?';
var
fil: string;
begin
if LevelListBox.ItemIndex = -1 then exit;
 
if MessageDlg(SDeleteSaveGame, mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg('Diesen Spielstand wirklich löschen?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
begin
li1.visible := false;
li2a.visible := false;
133,14 → 125,14
li4b.visible := false;
liu.visible := false;
liw.visible := false;
li1.caption := SNa;
li2b.caption := SNa;
li3b.caption := SNa;
li4b.caption := SNa;
li1.caption := 'n/a';
li2b.caption := 'n/a';
li3b.caption := 'n/a';
li4b.caption := 'n/a';
LadenBtn.enabled := false;
LoeschenBtn.enabled := false;
fil := GetSaveGameFileName(LevelListBox.Items.strings[LevelListBox.itemindex], false);
if not fileexists(fil) then raise Exception.Create(SSaveGameFileNotFound);
if not fileexists(fil) then raise Exception.Create('Spielstandsdatei nicht gefunden');
deletefile(fil);
searchsaves;
end;
150,8 → 142,8
var
usr, sys: string;
begin
usr := IncludeTrailingPathDelimiter(GetSpielstandVerzeichnisUser) + SpielstandName + '.sav'; // ab SpaceMission 1.2+ // do not localize
sys := IncludeTrailingPathDelimiter(GetSpielstandVerzeichnisSystem) + SpielstandName + '.sav'; // alte Versionen von SpaceMission <1.2 // do not localize
usr := IncludeTrailingPathDelimiter(GetSpielstandVerzeichnisUser) + SpielstandName + '.sav'; // ab SpaceMission 1.2+
sys := IncludeTrailingPathDelimiter(GetSpielstandVerzeichnisSystem) + SpielstandName + '.sav'; // alte Versionen von SpaceMission <1.2
if fileexists(usr) or forceuserdir then exit(usr);
if fileexists(sys) then exit(sys);
exit(usr);
175,10 → 167,10
li4b.visible := false;
liu.visible := false;
liw.visible := false;
li1.caption := SNa;
li2b.caption := SNa;
li3b.caption := SNa;
li4b.caption := SNa;
li1.caption := 'n/a';
li2b.caption := 'n/a';
li3b.caption := 'n/a';
li4b.caption := 'n/a';
LadenBtn.enabled := false;
LoeschenBtn.enabled := false;
end;
187,7 → 179,7
SavGame := TSaveData.Create;
try
fil := GetSaveGameFileName(LevelListBox.Items.strings[LevelListBox.itemindex], false);
if not fileexists(fil) then raise Exception.Create(SSaveGameFileNotFound);
if not fileexists(fil) then raise Exception.Create('Spielstandsdatei nicht gefunden');
SavGame.LoadFromFile(fil);
mainform.FScore := SavGame.Score;
mainform.FLife := SavGame.Life;
208,10 → 200,6
end;
 
procedure TSpeicherungForm.SpeichernBtnClick(Sender: TObject);
resourcestring
SNoValidSaveGameName = 'Dies ist kein gültiger Spielstandname!';
SEmptySaveGameName = 'Bitte geben Sie einen Namen für den Spielstand ein';
SReplaceSaveGame = 'Spielstand ist bereits vorhanden. Ersetzen?';
var
SavGame: TSaveData;
i: integer;
218,7 → 206,7
begin
if Levelname.text = '' then
begin
MessageDlg(SEmptySaveGameName, mtError, [mbOK], 0);
MessageDlg('Dies ist kein gültiger Spielstandname!', mtError, [mbOK], 0);
LevelName.setfocus;
exit;
end;
234,7 → 222,7
(copy(LevelName.text, i, 1) = '>') or
(copy(LevelName.text, i, 1) = '|') then
begin
MessageDlg(SNoValidSaveGameName, mtError, [mbOK], 0);
MessageDlg('Dies ist kein gültiger Spielstandname!', mtError, [mbOK], 0);
LevelName.setfocus;
exit;
end;
241,7 → 229,7
end;
if LevelListBox.items.IndexOf(LevelName.text) > -1 then
begin
if MessageDlg(SReplaceSaveGame, mtConfirmation, mbYesNoCancel, 0) <> mrYes then
if MessageDlg('Spielstand ist bereits vorhanden. Ersetzen?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then
exit;
end;
 
262,11 → 250,6
end;
 
procedure TSpeicherungForm.LevelListBoxClick(Sender: TObject);
resourcestring
SNoNA = 'n/a';
SIsNormalLevel = 'Das Level ist ein norm. Level';
SIsRandomLevel = 'Das Level ist ein Zufallslevel';
SHasAttachedLevel = '%s mit Karte';
var
SavGame: TSaveData;
Punkte, Leben, Level: integer;
285,10 → 268,10
li4b.visible := false;
liu.visible := false;
liw.visible := false;
li1.caption := SNoNA;
li2b.caption := SNoNA;
li3b.caption := SNoNA;
li4b.caption := SNoNA;
li1.caption := 'n/a';
li2b.caption := 'n/a';
li3b.caption := 'n/a';
li4b.caption := 'n/a';
if (LevelListBox.items.count=0) or (LevelListBox.itemindex = -1) then
begin
ladenbtn.enabled := false;
302,7 → 285,7
try
try
fil := GetSaveGameFileName(LevelListBox.Items.strings[LevelListBox.itemindex], false);
if not fileexists(fil) then raise Exception.Create(SSaveGameFileNotFound);
if not fileexists(fil) then raise Exception.Create('Spielstandsdatei nicht gefunden');
SavGame.LoadFromFile(fil);
Punkte := SavGame.Score;
Leben := SavGame.Life;
325,11 → 308,11
li4a.visible := true;
li4b.visible := true;
if Art = gmLevels then
li1.caption := SIsNormalLevel
li1.caption := 'Das Level ist ein norm. Level'
else
li1.caption := SIsRandomLevel;
li1.caption := 'Das Level ist ein Zufallslevel';
if BeinhaltetLevelDaten then
li1.Caption := Format(SHasAttachedLevel, [li1.Caption]);
li1.Caption := li1.Caption + ' mit Karte';
li3b.caption := inttostr(Level);
li4b.caption := inttostr(Leben);
li2b.caption := inttostr(Punkte);
367,7 → 350,7
function TSpeicherungForm.GetSpielstandVerzeichnisSystem: string;
begin
// nicht mehr verwendet seit version 1.2
result := OwnDirectory + SSaveGameFolder;
result := OwnDirectory + 'Spielstände';
end;
 
function TSpeicherungForm.GetSpielstandVerzeichnisUser: string;
380,12 → 363,12
if result = '' then
begin
// Pre Vista
result := OwnDirectory + SSaveGameFolder;
result := OwnDirectory + 'Spielstände';
end
else
begin
result := IncludeTrailingPathDelimiter(result);
result := result + SSaveGameSubFolder;
result := result + 'SpaceMission';
end;
result := IncludeTrailingPathDelimiter(result);
ForceDirectories(result);
/SpaceMission.dproj
90,8 → 90,7
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_MinorVer>2</VerInfo_MinorVer>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_Keys>CompanyName=ViaThinkSoft;FileDescription=SpaceMission;FileVersion=1.2.1.0;InternalName=SpaceMission;LegalCopyright=(C) 2001-2024 Daniel Marschall, ViaThinkSoft;LegalTrademarks=;OriginalFilename=SpaceMission.exe;ProductName=SpaceMission;ProductVersion=1.2.1;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
<VerInfo_Release>1</VerInfo_Release>
<VerInfo_Keys>CompanyName=ViaThinkSoft;FileDescription=SpaceMission;FileVersion=1.2.0.0;InternalName=SpaceMission;LegalCopyright=(C) 2001-2024 Daniel Marschall, ViaThinkSoft;LegalTrademarks=;OriginalFilename=SpaceMission.exe;ProductName=SpaceMission;ProductVersion=1.2;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Version>7.0</Version>
/SpaceMission.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/LevOptions.dfm
69,7 → 69,6
Width = 329
Height = 57
Color = clInfoBk
ParentBackground = False
TabOrder = 0
object ElLabel1: TLabel
Left = 8
93,13 → 92,11
'Die Spielfeldgr'#246#223'e wird nur von dem Leveleditor '#13#10'ben'#246'tigt. Das ' +
#196'ndern dieser Gr'#246#223'e wirkt sich '#13#10'nicht auf die Gr'#246#223'e der Levels ' +
'aus.'
Color = clInfoBk
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
ParentColor = False
ParentFont = False
end
end
/GamCheat.dfm
35,7 → 35,6
Font.Name = 'MS Sans Serif'
Font.Style = [fsUnderline]
ParentFont = False
Visible = False
OnClick = Label3Click
end
object CheatEdit: TEdit
/GamCheat.pas
40,8 → 40,6
const
// Cheat1 = 'Kmkjk'+#39+'Khyc'; {Johnny Cash}
Cheat1 = #75+#109+#107+#106+#107+#127+#39+#75+#104+#121+#99;
 
resourcestring
Cheat1Text = 'Unendlich Leben!';
 
procedure TCheatForm.AbbBtnClick(Sender: TObject);
56,10 → 54,6
end;
 
procedure TCheatForm.OKBtnClick(Sender: TObject);
resourcestring
SCheatUnlocked = 'Dieser Cheat wurde freigeschaltet!';
SCheckAlreadyUnlocked = 'Dieser Cheat wurde bereits freigeschaltet!';
SNoCheat = 'Dies ist kein offizieller Cheat!';
var
temp: string;
i, j: integer;
74,10 → 68,10
if lowercase(temp) = lowercase(Cheat1) then
begin
if mainform.FCheat then
showmessage(SCheckAlreadyUnlocked)
showmessage('Dieser Cheat wurde bereits freigeschaltet!')
else
begin
showmessage(SCheatUnlocked);
showmessage('Dieser Cheat wurde freigeschaltet!');
mainform.FCheat := true;
SearchCheats;
end;
85,7 → 79,7
end
else
begin
showmessage(SNoCheat);
showmessage('Dies ist kein offizieller Cheat!');
CheatEdit.text := '';
CheatEdit.setfocus;
end;
114,18 → 108,15
end;
 
procedure TCheatForm.Label2Click(Sender: TObject);
resourcestring
SDisableCheat = 'Diesen Cheat wirklich deaktivieren?';
SCheatDisabled = 'Dieser Cheat wurde deakiviert!';
begin
if not CheatBox.items.IndexOf(Cheat1Text) = -1 then
begin
if CheatBox.Selected[CheatBox.items.IndexOf(Cheat1Text)] then
begin
if MessageDlg(SDisableCheat, mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg('Diesen Cheat wirklich deaktivieren?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
begin
mainform.FCheat := false;
showmessage(SCheatDisabled);
showmessage('Dieser Cheat wurde deakiviert!');
SearchCheats;
end;
end;
134,7 → 125,7
 
procedure TCheatForm.Label3Click(Sender: TObject);
begin
shellexecute(handle, 'open', pchar('mailto:daniel-marschall@viathinksoft.de?subject=Cheats für SpaceMission '+ProgramVersion), '', '', 1); // do not localize
shellexecute(handle, 'open', pchar('mailto:daniel-marschall@viathinksoft.de?subject=Cheats für SpaceMission '+ProgramVersion), '', '', 1);
end;
 
end.
/ComInfo.pas
42,20 → 42,18
end;
 
procedure TInfoForm.FormCreate(Sender: TObject);
resourcestring
SVersion = 'Version %s';
begin
VersionLbl.caption := Format(SVersion, [ProgramVersion]);
VersionLbl.caption := 'Version ' + ProgramVersion;
end;
 
procedure TInfoForm.WebsiteClick(Sender: TObject);
begin
ShellExecute(application.Handle, 'open', pchar('https://'+url2.caption+'/'), nil, nil, SW_SHOW); // do not localize
ShellExecute(application.Handle, 'open', pchar('https://'+url2.caption+'/'), nil, nil, SW_SHOW);
end;
 
procedure TInfoForm.EMailClick(Sender: TObject);
begin
ShellExecute(application.Handle, 'open', pchar('mailto:'+url1.Caption+'?subject=SpaceMission ' + ProgramVersion), nil, nil, SW_SHOW); // do not localize
ShellExecute(application.Handle, 'open', pchar('mailto:'+url1.Caption+'?subject=SpaceMission ' + ProgramVersion), nil, nil, SW_SHOW);
end;
 
end.