Subversion Repositories spacemission

Compare Revisions

Regard whitespace Rev 78 → Rev 79

/ComHilfe.pas
34,7 → 34,7
DOC: Variant;
begin
if not Assigned(WebBrowser1.Document) then
WebBrowser1.Navigate('about:blank');
WebBrowser1.Navigate('about:blank'); // do not localize
 
DOC := WebBrowser1.Document;
DOC.Clear;
53,7 → 53,7
slCss := TStringList.Create();
try
slHtml.LoadFromFile(AMarkDownFile);
cssFile := IncludeTrailingPathDelimiter(FDirectory) + 'Style.css';
cssFile := IncludeTrailingPathDelimiter(FDirectory) + 'Style.css'; // do not localize
if FileExists(cssFile) then
slCss.LoadFromFile(cssFile);
md := TMarkdownProcessor.CreateDialect(mdCommonMark);
60,15 → 60,15
try
//md.AllowUnsafe := true;
ShowHTMLHelp(
'<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'+
'<style>'+slCss.Text+'</style>'+
'</head>'+
'<body>'+
'<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
md.process(UTF8ToString(RawByteString(slHtml.Text)))+
'</body>'+
'</html>');
'</body>'+ // do not localize
'</html>'); // do not localize
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
SameText(Copy(URL,1,8),'https://') or
SameText(Copy(URL,1,7),'mailto:') then
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
begin
// Links in default Browser anzeigen
ShellExecute(handle, 'open', PChar(string(URL)), '', '', SW_NORMAL);
ShellExecute(handle, 'open', PChar(string(URL)), '', '', SW_NORMAL); // do not localize
Cancel := true;
end
else if SameText(ExtractFileExt(URL), '.md') then
else if SameText(ExtractFileExt(URL), '.md') then // do not localize
begin
if SameText(Copy(URL,1,6), 'about:') then
if SameText(Copy(URL,1,6), 'about:') then // do not localize
ShowMarkDownHelp(IncludeTrailingPathDelimiter(FDirectory) + Copy(URL,7,Length(URL)))
else
ShowMarkDownHelp(URL);
/ComInfo.pas
42,18 → 42,20
end;
 
procedure TInfoForm.FormCreate(Sender: TObject);
resourcestring
SVersion = 'Version %s';
begin
VersionLbl.caption := 'Version ' + ProgramVersion;
VersionLbl.caption := Format(SVersion, [ProgramVersion]);
end;
 
procedure TInfoForm.WebsiteClick(Sender: TObject);
begin
ShellExecute(application.Handle, 'open', pchar('https://'+url2.caption+'/'), nil, nil, SW_SHOW);
ShellExecute(application.Handle, 'open', pchar('https://'+url2.caption+'/'), nil, nil, SW_SHOW); // do not localize
end;
 
procedure TInfoForm.EMailClick(Sender: TObject);
begin
ShellExecute(application.Handle, 'open', pchar('mailto:'+url1.Caption+'?subject=SpaceMission ' + ProgramVersion), nil, nil, SW_SHOW);
ShellExecute(application.Handle, 'open', pchar('mailto:'+url1.Caption+'?subject=SpaceMission ' + ProgramVersion), nil, nil, SW_SHOW); // do not localize
end;
 
end.
/ComLevelReader.pas
11,7 → 11,7
// - GamMain.pas : TMainForm.SceneMain
// - LevMain.pas : * GUI
// * TMainForm.SelectedEnemyType
// * TEnemy.Create
// * TEnemyOrItem.Create
// * TMainForm.DXDrawMouseMove
// * TMainForm.DXDrawMouseDown
TEnemyType = (
96,14 → 96,19
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';
OID_LEVSAV_VER12 = '1.3.6.1.4.1.37476.2.8.1.1'; // do not localize
 
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 + 'Levels';
result := OwnDirectory + SLevelFileFolder;
end;
 
function _GetLevelVerzeichnisUser: string;
116,12 → 121,12
if result = '' then
begin
// Pre Vista
result := OwnDirectory + 'Levels';
result := OwnDirectory + SLevelFileFolder;
end
else
begin
result := IncludeTrailingPathDelimiter(result);
result := result + 'SpaceMission';
result := result + SLevelFileSubFolder;
end;
result := IncludeTrailingPathDelimiter(result);
ForceDirectories(result);
131,8 → 136,8
var
old, new: string;
begin
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
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
if fileexists(new) then exit(new);
if fileexists(old) then exit(old);
exit(new);
142,8 → 147,8
var
old, new: string;
begin
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
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
if fileexists(new) then exit(new);
if fileexists(old) then exit(old);
exit(new);
282,6 → 287,9
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);
 
288,8 → 296,8
if enemyType = etEnemyMeteor then lifes := 0;
if RasterErzwingen then
begin
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]);
if x mod LevEditRasterW <> 0 then raise Exception.CreateFmt(SInvalidXCoord, [LevEditRasterW]);
if y mod LevEditRasterH <> 0 then raise Exception.CreateFmt(SInvalidYCoord, [LevEditRasterH]);
end;
if lifes > MaxPossibleEnemyLives then lifes := MaxPossibleEnemyLives;
 
319,6 → 327,9
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;
328,6 → 339,7
ergebnis: string;
ary: TStringDynArray;
sLine: string;
iEnemy: Integer;
begin
Clear;
 
357,8 → 369,8
if z > 2 then inc(act);
if act = 5 then act := 1;
ergebnis := sl.Strings[z-1];
if ergebnis = '; SpaceMission 0.4' then
sl2.Add('; SpaceMission 1.0')
if ergebnis = '; SpaceMission 0.4' then // do not localize
sl2.Add('; SpaceMission 1.0') // do not localize
else
begin
if (ergebnis = '30000') and (z = 3) then
391,7 → 403,10
curline := 3;
while curline < sl.Count do
begin
tmpEnemy := TEnemyType(strtoint(sl.Strings[curline]));
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);
Inc(curline);
tmpX := strtoint(sl.Strings[curline]);
Inc(curline);
415,7 → 430,7
begin
LevelEditorLength := StrToInt(ary[1]);
if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then
raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
end
else if SameText(ary[0], 'Name') then // do not localize
begin
427,12 → 442,15
end
else if SameText(ary[0], 'Enemy') then // do not localize
begin
tmpEnemy := TEnemyType(strtoint(ary[1]));
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);
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('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
AddEnemy(tmpX, tmpY, tmpEnemy, tmpLifes);
end;
end;
440,7 → 458,7
end
else
begin
raise Exception.Create('Level-Format nicht unterstützt oder Datei ist beschädigt');
raise Exception.Create(SInvalidLevelFile);
end;
 
SortEnemies; // Sortierung nach X-Koordinate ist sehr wichtig für das Spiel!
522,6 → 540,8
end;
 
procedure TLevelData.SaveToStrings(sl: TStrings);
resourcestring
SLevelEnemyLineComment = '; Type XCoord YCoord Lives';
var
i: integer;
begin
531,7 → 551,7
if LevelAuthor <> '' then sl.Add('Author ' + LevelAuthor); // do not localize
sl.Add('Width ' + IntToStr(LevelEditorLength)); // do not localize
SortEnemies;
sl.Add('; Type XCoord YCoord Lives');
sl.Add(SLevelEnemyLineComment);
for i := 0 to Length(EnemyAdventTable)-1 do
begin
sl.Add(Trim(
645,6 → 665,8
end;
 
procedure TSaveData.LoadFromStrings(sl: TStrings);
resourcestring
SInvalidFile = 'Spielstand-Format nicht unterstützt oder Datei beschädigt';
var
curline: Integer;
ary: TStringDynArray;
674,25 → 696,25
begin
Score := StrToInt(ary[1]);
if (Length(ary) > 2) and (Copy(ary[2], 1, 1) <> ';') then
raise Exception.CreateFmt('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
raise Exception.CreateFmt(SExtraContentAfterLine, [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('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
raise Exception.CreateFmt(SExtraContentAfterLine, [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('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
raise Exception.CreateFmt(SExtraContentAfterLine, [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('Zeile %d ist ungültig (Zusatzinfo am Ende)', [curline+1]);
raise Exception.CreateFmt(SExtraContentAfterLine, [curline+1]);
end;
end;
if Assigned(LevelData) then FreeAndNil(LevelData);
702,7 → 724,7
end
else
begin
raise Exception.Create('Spielstand-Format nicht unterstützt oder Datei beschädigt');
raise Exception.Create(SInvalidFile);
end;
end;
 
/GamCheat.dfm
35,6 → 35,7
Font.Name = 'MS Sans Serif'
Font.Style = [fsUnderline]
ParentFont = False
Visible = False
OnClick = Label3Click
end
object CheatEdit: TEdit
/GamCheat.pas
40,6 → 40,8
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);
54,6 → 56,10
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;
68,10 → 74,10
if lowercase(temp) = lowercase(Cheat1) then
begin
if mainform.FCheat then
showmessage('Dieser Cheat wurde bereits freigeschaltet!')
showmessage(SCheckAlreadyUnlocked)
else
begin
showmessage('Dieser Cheat wurde freigeschaltet!');
showmessage(SCheatUnlocked);
mainform.FCheat := true;
SearchCheats;
end;
79,7 → 85,7
end
else
begin
showmessage('Dies ist kein offizieller Cheat!');
showmessage(SNoCheat);
CheatEdit.text := '';
CheatEdit.setfocus;
end;
108,15 → 114,18
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('Diesen Cheat wirklich deaktivieren?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg(SDisableCheat, mtConfirmation, mbYesNoCancel, 0) = mrYes then
begin
mainform.FCheat := false;
showmessage('Dieser Cheat wurde deakiviert!');
showmessage(SCheatDisabled);
SearchCheats;
end;
end;
125,7 → 134,7
 
procedure TCheatForm.Label3Click(Sender: TObject);
begin
shellexecute(handle, 'open', pchar('mailto:daniel-marschall@viathinksoft.de?subject=Cheats für SpaceMission '+ProgramVersion), '', '', 1);
shellexecute(handle, 'open', pchar('mailto:daniel-marschall@viathinksoft.de?subject=Cheats für SpaceMission '+ProgramVersion), '', '', 1); // do not localize
end;
 
end.
/GamMain.pas
1230,6 → 1230,8
{ TMainForm }
 
procedure TMainForm.FormCreate(Sender: TObject);
resourcestring
SAppTitle = 'SpaceMission %s';
begin
Randomize;
 
1292,7 → 1294,7
 
{ Ende VCL-Ersatz }
 
Application.Title := 'SpaceMission '+ProgramVersion;
Application.Title := Format(SAppTitle, [ProgramVersion]);
LoadOptions;
DXInit;
SoundInit;
1351,9 → 1353,11
end;
 
procedure TMainForm.DXInit;
const
DxgFile = 'DirectX\Graphics.dxg'; // do not localize
begin
try
Imagelist.Items.LoadFromFile(OwnDirectory+'DirectX\Graphics.dxg');
Imagelist.Items.LoadFromFile(OwnDirectory+DxgFile);
ImageList.Items.MakeColorTable;
DXDraw.ColorTable := ImageList.Items.ColorTable;
DXDraw.DefColorTable := ImageList.Items.ColorTable;
1370,7 → 1374,7
 
procedure TMainForm.CheckUpdatesClick(Sender: TObject);
begin
CheckForUpdates('spacemission', ProgramVersion);
CheckForUpdates('spacemission', ProgramVersion); // do not localize
end;
 
procedure TMainForm.BeendenClick(Sender: TObject);
1386,8 → 1390,10
end;
 
procedure TMainForm.SoundInit;
const
DxwFile = 'DirectX\Sound.dxw'; // do not localize
begin
if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+'DirectX\Sound.dxw') then
if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+DxwFile) then
begin
OptionSound.Checked := false;
OptionSound.Enabled := False;
1400,7 → 1406,7
begin
try
DXSound.Initialize;
WaveList.Items.LoadFromFile(OwnDirectory+'DirectX\Sound.dxw');
WaveList.Items.LoadFromFile(OwnDirectory+DxwFile);
except
OptionSound.enabled := False;
WaveList.items.clear;
1411,10 → 1417,12
end;
 
procedure TMainForm.MusicInit;
const
DxmFile = 'DirectX\Music.dxm'; // do not localize
var
i: integer;
begin
if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+'DirectX\Music.dxm') then
if (WaveOutGetNumDevs < 1) or not FileExists(OwnDirectory+DxmFile) then
begin
optionmusic.Checked := false;
optionmusic.Enabled := False;
1422,7 → 1430,7
end;
 
try
dxmusic.Midis.LoadFromFile(OwnDirectory+'DirectX\Music.dxm');
dxmusic.Midis.LoadFromFile(OwnDirectory+DxmFile);
for i := 0 to dxmusic.Midis.Count-1 do
begin
if not dxmusic.Midis.Items[i].IsInitialized then
1476,9 → 1484,11
end;
 
procedure TMainForm.DXTimerDeactivate(Sender: TObject);
resourcestring
SPauseTitle = '%s [Pause]';
begin
TDxTimer(Sender).Tag := TDxTimer(Sender).Tag + 1;
Caption := Application.Title + ' [Pause]';
Caption := Format(SPauseTitle, [Application.Title]);
PauseMusic(FMusic);
end;
 
1531,9 → 1541,9
Reg.RootKey := HKEY_CURRENT_USER;
if Reg.OpenKey(RegistrySettingsKey, true) then
begin
Reg.WriteBool('Music', OptionMusic.checked);
Reg.WriteBool('Sound', OptionSound.checked);
Reg.WriteInteger('Speed', Ord(FInterval));
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.CloseKey;
end;
finally
1550,18 → 1560,18
Reg.RootKey := HKEY_CURRENT_USER;
if Reg.OpenKey(RegistrySettingsKey, true) then
begin
if Reg.ValueExists('Music') then
optionmusic.checked := Reg.ReadBool('Music')
if Reg.ValueExists(MusicSettingKey) then
optionmusic.checked := Reg.ReadBool(MusicSettingKey)
else
optionmusic.checked := true; // default
 
if Reg.ValueExists('Sound') then
optionsound.checked := Reg.ReadBool('Sound')
if Reg.ValueExists(SoundSettingKey) then
optionsound.checked := Reg.ReadBool(SoundSettingKey)
else
optionsound.checked := true; // default
 
if Reg.ValueExists('Speed') then
FInterval := TGameInterval(Reg.ReadInteger('Speed'))
if Reg.ValueExists(SpeedSettingKey) then
FInterval := TGameInterval(Reg.ReadInteger(SpeedSettingKey))
else
FInterval := giMittel; // default
 
1846,7 → 1856,7
 
procedure TMainForm.NewLevel(lev: integer);
resourcestring
LNG_LEVEL_INVALID = 'Das Level Nr. %d ist ungültig!'+#13#10+'Das Programm wird beendet.';
SLevelInvalid = 'Das Level Nr. %d ist ungültig!'+#13#10+'Das Programm wird beendet.';
const
RandomLevelMaxEnemyLives = 10;
var
1973,7 → 1983,7
LevelData.RasterErzwingen := false;
LevelData.LoadFromFile(levFile.fileLocation);
except
showmessage(Format(LNG_LEVEL_INVALID, [lev]));
showmessage(Format(SLevelInvalid, [lev]));
ResetLevelData;
end;
end;
2098,7 → 2108,7
FLevel := 1;
if FGameMode = gmEditor then
begin
ShellExecute(0, 'open', PChar(OwnDirectory+'LevEdit.exe'), '', PChar(OwnDirectory), SW_NORMAL);
ShellExecute(0, 'open', PChar(OwnDirectory+LevEditExe), '', PChar(OwnDirectory), SW_NORMAL); // do not localize
Close;
exit;
end;
2116,6 → 2126,15
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;
2178,16 → 2197,16
begin
{$REGION 'Anzeige Punkte'}
DXDraw.Surface.Canvas.Font.Color := clOlive;
DXDraw.Surface.Canvas.Textout(9, 9, 'Punkte: ' + FloatToStrF(FScore,ffNumber,14,0));
DXDraw.Surface.Canvas.Textout(9, 9, Format(SPunkte, [FloatToStrF(FScore,ffNumber,14,0)]));
DXDraw.Surface.Canvas.Font.Color := clYellow;
DXDraw.Surface.Canvas.Textout(10, 10, 'Punkte: ' + FloatToStrF(FScore,ffNumber,14,0));
DXDraw.Surface.Canvas.Textout(10, 10, Format(SPunkte, [FloatToStrF(FScore,ffNumber,14,0)]));
{$ENDREGION}
 
{$REGION 'Anzeige Level'}
DXDraw.Surface.Canvas.Font.Color := clMaroon;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-141, 9, 'Level: ' + IntToStr(flevel));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-141, 9, Format(SLevel, [flevel]));
DXDraw.Surface.Canvas.Font.Color := clRed;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-140, 10, 'Level: ' + IntToStr(flevel));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-140, 10, Format(SLevel, [flevel]));
{$ENDREGION}
 
{$REGION 'Lebensanzeige'}
2195,9 → 2214,9
if FCheat then
begin
DXDraw.Surface.Canvas.Font.Color := clPurple;
DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, 'Leben: ?');
DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, SInfLifes);
DXDraw.Surface.Canvas.Font.Color := clFuchsia;
DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, 'Leben: ?');
DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, SInfLifes);
end
else
begin
2204,9 → 2223,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, 'Leben: ' + IntToStr(flife));
DXDraw.Surface.Canvas.Textout(9, dxdraw.surfaceheight-41, Format(SLifes, [flife]));
DXDraw.Surface.Canvas.Font.Color := clFuchsia;
DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, 'Leben: ' + IntToStr(flife));
DXDraw.Surface.Canvas.Textout(10, dxdraw.surfaceheight-40, Format(SLifes, [flife]));
end;
if Flife = 1 then BlinkUpdate;
end;
2222,26 → 2241,26
if (tmpEnemyAnzeige>0) then
begin
DXDraw.Surface.Canvas.Font.Color := clGreen;
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.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.Font.Color := clLime;
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));
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]));
end
else
begin
DXDraw.Surface.Canvas.Font.Color := clGreen;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, 'Boss: ' + IntToStr(FBossLife));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, Format(SBossLifes, [FBossLife]));
DXDraw.Surface.Canvas.Font.Color := clLime;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, 'Boss: ' + IntToStr(FBossLife));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, Format(SBossLifes, [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, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-191, dxdraw.surfaceheight-41, Format(SEinheiten, [tmpEnemyAnzeige]));
DXDraw.Surface.Canvas.Font.Color := clLime;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, 'Einheiten: ' + IntToStr(tmpEnemyAnzeige));
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-190, dxdraw.surfaceheight-40, Format(SEinheiten, [tmpEnemyAnzeige]));
end;
{$ENDREGION}
 
2249,9 → 2268,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, 'Mission erfolgreich!');
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, SMissionSucsessful);
DXDraw.Surface.Canvas.Font.Color := clLime;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, 'Mission erfolgreich!');
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, SMissionSucsessful);
DXDraw.Surface.Canvas.Release;
Sleep(1);
inc(FCounter);
2262,9 → 2281,9
else
begin
DXDraw.Surface.Canvas.Font.Color := clMaroon;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, 'Mission gescheitert!');
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-251, dxdraw.surfaceheight-41, SMissionFailed);
DXDraw.Surface.Canvas.Font.Color := clRed;
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, 'Mission gescheitert!');
DXDraw.Surface.Canvas.Textout(dxdraw.surfacewidth-250, dxdraw.surfaceheight-40, SMissionFailed);
end;
DXDraw.Surface.Canvas.Release;
end;
/GamSpeicherung.pas
58,6 → 58,12
 
{$R *.DFM}
 
resourcestring
SSaveGameFileNotFound = 'Spielstandsdatei nicht gefunden';
SNa = 'n/a';
SSaveGameFolder = 'Spielstände';
SSaveGameSubFolder = 'SpaceMission';
 
{ TSpeicherungForm }
 
procedure TSpeicherungForm.SearchSaves;
76,10 → 82,10
li4b.visible := false;
liu.visible := false;
liw.visible := true;
li1.caption := 'n/a';
li2b.caption := 'n/a';
li3b.caption := 'n/a';
li4b.caption := 'n/a';
li1.caption := SNa;
li2b.caption := SNa;
li3b.caption := SNa;
li4b.caption := SNa;
LadenBtn.enabled := false;
LoeschenBtn.enabled := false;
res := FindFirst(IncludeTrailingPathDelimiter(GetSpielstandVerzeichnisSystem)+'*.sav', 0, sr);
109,12 → 115,14
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('Diesen Spielstand wirklich löschen?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg(SDeleteSaveGame, mtConfirmation, mbYesNoCancel, 0) = mrYes then
begin
li1.visible := false;
li2a.visible := false;
125,14 → 133,14
li4b.visible := false;
liu.visible := false;
liw.visible := false;
li1.caption := 'n/a';
li2b.caption := 'n/a';
li3b.caption := 'n/a';
li4b.caption := 'n/a';
li1.caption := SNa;
li2b.caption := SNa;
li3b.caption := SNa;
li4b.caption := SNa;
LadenBtn.enabled := false;
LoeschenBtn.enabled := false;
fil := GetSaveGameFileName(LevelListBox.Items.strings[LevelListBox.itemindex], false);
if not fileexists(fil) then raise Exception.Create('Spielstandsdatei nicht gefunden');
if not fileexists(fil) then raise Exception.Create(SSaveGameFileNotFound);
deletefile(fil);
searchsaves;
end;
142,8 → 150,8
var
usr, sys: string;
begin
usr := IncludeTrailingPathDelimiter(GetSpielstandVerzeichnisUser) + SpielstandName + '.sav'; // ab SpaceMission 1.2+
sys := IncludeTrailingPathDelimiter(GetSpielstandVerzeichnisSystem) + SpielstandName + '.sav'; // alte Versionen von SpaceMission <1.2
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
if fileexists(usr) or forceuserdir then exit(usr);
if fileexists(sys) then exit(sys);
exit(usr);
167,10 → 175,10
li4b.visible := false;
liu.visible := false;
liw.visible := false;
li1.caption := 'n/a';
li2b.caption := 'n/a';
li3b.caption := 'n/a';
li4b.caption := 'n/a';
li1.caption := SNa;
li2b.caption := SNa;
li3b.caption := SNa;
li4b.caption := SNa;
LadenBtn.enabled := false;
LoeschenBtn.enabled := false;
end;
179,7 → 187,7
SavGame := TSaveData.Create;
try
fil := GetSaveGameFileName(LevelListBox.Items.strings[LevelListBox.itemindex], false);
if not fileexists(fil) then raise Exception.Create('Spielstandsdatei nicht gefunden');
if not fileexists(fil) then raise Exception.Create(SSaveGameFileNotFound);
SavGame.LoadFromFile(fil);
mainform.FScore := SavGame.Score;
mainform.FLife := SavGame.Life;
200,6 → 208,10
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;
206,7 → 218,7
begin
if Levelname.text = '' then
begin
MessageDlg('Dies ist kein gültiger Spielstandname!', mtError, [mbOK], 0);
MessageDlg(SEmptySaveGameName, mtError, [mbOK], 0);
LevelName.setfocus;
exit;
end;
222,7 → 234,7
(copy(LevelName.text, i, 1) = '>') or
(copy(LevelName.text, i, 1) = '|') then
begin
MessageDlg('Dies ist kein gültiger Spielstandname!', mtError, [mbOK], 0);
MessageDlg(SNoValidSaveGameName, mtError, [mbOK], 0);
LevelName.setfocus;
exit;
end;
229,7 → 241,7
end;
if LevelListBox.items.IndexOf(LevelName.text) > -1 then
begin
if MessageDlg('Spielstand ist bereits vorhanden. Ersetzen?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then
if MessageDlg(SReplaceSaveGame, mtConfirmation, mbYesNoCancel, 0) <> mrYes then
exit;
end;
 
250,6 → 262,11
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;
268,10 → 285,10
li4b.visible := false;
liu.visible := false;
liw.visible := false;
li1.caption := 'n/a';
li2b.caption := 'n/a';
li3b.caption := 'n/a';
li4b.caption := 'n/a';
li1.caption := SNoNA;
li2b.caption := SNoNA;
li3b.caption := SNoNA;
li4b.caption := SNoNA;
if (LevelListBox.items.count=0) or (LevelListBox.itemindex = -1) then
begin
ladenbtn.enabled := false;
285,7 → 302,7
try
try
fil := GetSaveGameFileName(LevelListBox.Items.strings[LevelListBox.itemindex], false);
if not fileexists(fil) then raise Exception.Create('Spielstandsdatei nicht gefunden');
if not fileexists(fil) then raise Exception.Create(SSaveGameFileNotFound);
SavGame.LoadFromFile(fil);
Punkte := SavGame.Score;
Leben := SavGame.Life;
308,11 → 325,11
li4a.visible := true;
li4b.visible := true;
if Art = gmLevels then
li1.caption := 'Das Level ist ein norm. Level'
li1.caption := SIsNormalLevel
else
li1.caption := 'Das Level ist ein Zufallslevel';
li1.caption := SIsRandomLevel;
if BeinhaltetLevelDaten then
li1.Caption := li1.Caption + ' mit Karte';
li1.Caption := Format(SHasAttachedLevel, [li1.Caption]);
li3b.caption := inttostr(Level);
li4b.caption := inttostr(Leben);
li2b.caption := inttostr(Punkte);
350,7 → 367,7
function TSpeicherungForm.GetSpielstandVerzeichnisSystem: string;
begin
// nicht mehr verwendet seit version 1.2
result := OwnDirectory + 'Spielstände';
result := OwnDirectory + SSaveGameFolder;
end;
 
function TSpeicherungForm.GetSpielstandVerzeichnisUser: string;
363,12 → 380,12
if result = '' then
begin
// Pre Vista
result := OwnDirectory + 'Spielstände';
result := OwnDirectory + SSaveGameFolder;
end
else
begin
result := IncludeTrailingPathDelimiter(result);
result := result + 'SpaceMission';
result := result + SSaveGameSubFolder;
end;
result := IncludeTrailingPathDelimiter(result);
ForceDirectories(result);
/Global.pas
3,12 → 3,15
interface
 
const
ProgramVersion = '1.2';
RasterW = 48;
RasterH = 32;
ProgramVersion = '1.2.1';
LevEditRasterW = 48;
LevEditRasterH = 32;
MaxPossibleEnemyLives = 999;
MaxPossibleLevels = 999;
RegistrySettingsKey = 'SOFTWARE\ViaThinkSoft\SpaceMission\Settings';
RegistrySettingsKey = 'SOFTWARE\ViaThinkSoft\SpaceMission\Settings'; // do not localize
MusicSettingKey = 'Music'; // do not localize
SoundSettingKey = 'Sound'; // do not localize
SpeedSettingKey = 'Speed'; // do not localize
DefaultLevelLength = 1200;
StartLives = 6;
conleicht = 650 div 60; // 10
16,7 → 19,11
conschwer = 1350 div 60; // 22
conmaster = 2000 div 60; // 33
DEFAULT_ANIMSPEED = 15/1000;
ADDITIONAL_ENEMIES_PER_LEVEL = 75;
ADDITIONAL_ENEMIES_PER_LEVEL = 75; // Zufalls-Level
BossWidth = 4;
BossHeight = 2;
SpaceMissionExe = 'SpaceMission.exe'; // do not localize
LevEditExe = 'LevEdit.exe'; // do not localize
 
type
// DirectX\Music.dxm
68,7 → 75,7
function OwnDirectory: string;
 
const
FOLDERID_SavedGames: TGuid = '{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}';
FOLDERID_SavedGames: TGuid = '{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}'; // do not localize
 
// Useful functions
function GetKnownFolderPath(const rfid: TGUID): string;
78,7 → 85,8
implementation
 
uses
Windows, SysUtils, ActiveX, ShlObj, TlHelp32, wininet, Forms, ShellAPI;
Windows, SysUtils, Dialogs, ActiveX, ShlObj, TlHelp32, wininet, Forms, ShellAPI,
System.UITypes;
 
function GetKnownFolderPath(const rfid: TGUID): string;
var
148,14 → 156,14
Str : pansichar; // SIC! pansichar
begin
ResStr:='';
if (system.pos('http://',lowercase(AUrl))=0) and
(system.pos('https://',lowercase(AUrl))=0) then
AUrl:='http://'+AUrl;
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
 
// Hinzugefügt
if Assigned(Application) then Application.ProcessMessages;
 
hSession:=InternetOpen('InetURL:/1.0',
hSession:=InternetOpen('InetURL:/1.0', // do not localize
INTERNET_OPEN_TYPE_PRECONFIG,
nil,
nil,
185,7 → 193,7
dwIndex);
res := pchar(@dwcode);
dwNumber := sizeof(databuffer)-1;
if (res ='200') or (res = '302') then
if (res ='200') or (res = '302') then // do not localize
begin
while (InternetReadfile(hfile,
@databuffer,
204,7 → 212,7
end;
end
else
ResStr := 'Status:'+AnsiString(res);
ResStr := 'Status:'+AnsiString(res); // do not localize
if assigned(hfile) then
InternetCloseHandle(hfile);
end;
217,24 → 225,28
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);
cont := GetHTML('https://www.viathinksoft.de/update/?id='+ViaThinkSoftProjectName); // do not localize
if copy(cont, 0, 7) = 'Status:' then
begin
Application.MessageBox('Ein Fehler ist aufgetreten. Wahrscheinlich ist keine Internetverbindung aufgebaut, oder der der ViaThinkSoft-Server vorübergehend offline.', 'Fehler', MB_OK + MB_ICONERROR)
MessageDlg(SDownloadError, mtError, [mbOk], 0);
end
else
begin
if string(cont) <> AVersion then
begin
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);
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
end
else
begin
Application.MessageBox('Es ist keine neue Programmversion vorhanden.', 'Information', MB_OK + MB_ICONASTERISK);
MessageDlg(SNoUpdateAvailable, mtInformation, [mbOk], 0);
end;
end;
end;
/LevEdit.dproj
90,7 → 90,8
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_MinorVer>2</VerInfo_MinorVer>
<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>
<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>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Version>7.0</Version>
/LevMain.pas
128,7 → 128,7
procedure DoMove(MoveCount: Integer); override;
end;
 
TEnemy = class(TImageSprite)
TEnemyOrItem = class(TImageSprite)
strict private
FLives: integer;
FEnemyType: TEnemyType;
144,23 → 144,23
 
procedure TBackground.DoMove(MoveCount: Integer);
begin
X := -(MainForm.ScrollP * RasterW);
X := -(MainForm.ScrollP * LevEditRasterW);
end;
 
{ TEnemy }
 
procedure TEnemy.DoMove(MoveCount: Integer);
procedure TEnemyOrItem.DoMove(MoveCount: Integer);
begin
if not FCorInit then
begin
FXCor := trunc(x) + (MainForm.ScrollP * RasterW);
FXCor := trunc(x) + (MainForm.ScrollP * LevEditRasterW);
FCorInit := true;
end;
if MainForm.LevData.IndexOfEnemy(FXCor, integer(round(Y)), FEnemyType, FLives) = -1 then dead;
X := FXCor - (MainForm.ScrollP * RasterW);
X := FXCor - (MainForm.ScrollP * LevEditRasterW);
end;
 
constructor TEnemy.Create(AParent: TSprite; AEnemyType: TEnemyType; ALives: Integer);
constructor TEnemyOrItem.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');
Imagelist.Items.LoadFromFile(OwnDirectory+'DirectX\Graphics.dxg'); // do not localize
ImageList.Items.MakeColorTable;
DXDraw.ColorTable := ImageList.Items.ColorTable;
DXDraw.DefColorTable := ImageList.Items.ColorTable;
197,6 → 197,7
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);
248,8 → 249,8
// Leeres Level am Anfang braucht keine Beenden-Bestätigung.
// LevChanged := true;
 
//Application.Title := 'SpaceMission '+ProgramVersion+' - Leveleditor';
Caption := 'SpaceMission '+ProgramVersion+' - Leveleditor';
//Application.Title := Format(SCaption, [ProgramVersion]);
Caption := Format(SCaption, [ProgramVersion]);
DXInit;
LevData := TLevelData.create;
ProgramInit;
481,7 → 482,7
sav: TSaveData;
tmp: string;
begin
KillTask('SpaceMission.exe');
KillTask(SpaceMissionExe);
 
sav := TSaveData.Create;
try
496,7 → 497,7
sav.LevelData.Assign(LevData);
tmp := GetTestlevelFilename;
sav.SaveToFile(tmp);
ShellExecute(Handle, 'open', PChar(OwnDirectory+'SpaceMission.exe'), PChar('"'+tmp+'"'), PChar(OwnDirectory), SW_NORMAL);
ShellExecute(Handle, 'open', PChar(OwnDirectory+SpaceMissionExe), PChar('"'+tmp+'"'), PChar(OwnDirectory), SW_NORMAL); // do not localize
finally
FreeAndNil(sav);
end;
525,7 → 526,7
 
function TMainForm.GetTestlevelFilename: string;
begin
result := IncludeTrailingPathDelimiter(TPath.GetTempPath) + 'SpaceMissionTest.sav';
result := IncludeTrailingPathDelimiter(TPath.GetTempPath) + 'SpaceMissionTest.sav'; // do not localize
end;
 
procedure TMainForm.HilfeTopicClick(Sender: TObject);
567,8 → 568,8
j, k, l, ex, ey: integer;
ok, breaked: boolean;
begin
ex := trunc(x/RasterW) * RasterW;
ey := trunc(y/RasterH) * RasterH;
ex := trunc(x/LevEditRasterW) * LevEditRasterW;
ey := trunc(y/LevEditRasterH) * LevEditRasterH;
EnemyCreateSprite(ex, ey, SelectedEnemyType, LivesEdit.Value);
breaked := false;
{ Setzen }
585,11 → 586,11
begin
if boss then
begin
for k := 0 to 3 do
for k := 0 to BossWidth-1 do
begin
for l := 0 to 1 do
for l := 0 to BossHeight-2 do
begin
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * RasterW), ey - (RasterH * l), etEnemyBoss, j) <> -1 then
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), etEnemyBoss, j) <> -1 then
begin
ok := false;
break;
599,7 → 600,7
end;
if not ok then break;
end;
if LevData.IndexOfEnemy(ex + (ScrollP * RasterW), ey, i, j) <> -1 then
if LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1 then
begin
ok := false;
break;
611,9 → 612,9
if ok then
begin
if EnemyTypeHasLives(SelectedEnemyType) then
LevData.AddEnemy(ex + (ScrollP * RasterW), ey, SelectedEnemyType, LivesEdit.Value)
LevData.AddEnemy(ex + (ScrollP * LevEditRasterW), ey, SelectedEnemyType, LivesEdit.Value)
else
LevData.AddEnemy(ex + (ScrollP * RasterW), ey, SelectedEnemyType, 0);
LevData.AddEnemy(ex + (ScrollP * LevEditRasterW), ey, SelectedEnemyType, 0);
inc(NumEnemys);
if SelectedEnemyType = etEnemyBoss then boss := true;
end
628,13 → 629,13
begin
if boss and (i = etEnemyBoss) then
begin
for k := 0 to 3 do
for k := 0 to BossWidth - 1 do
begin
for l := 0 to 1 do
for l := 0 to BossHeight - 1 do
begin
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * RasterW), ey - (RasterH * l), i, j) <> -1 then
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j) <> -1 then
begin
LevData.DeleteEnemy(ex + ((ScrollP - k) * RasterW), ey - (RasterH * l), i, j);
LevData.DeleteEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j);
Boss := false;
dec(NumEnemys);
breaked := true;
644,9 → 645,9
if breaked then break;
end;
end;
if LevData.IndexOfEnemy(ex + (ScrollP * RasterW), ey, i, j) <> -1 then
if LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1 then
begin
LevData.DeleteEnemy(ex + (ScrollP * RasterW), ey, i, j);
LevData.DeleteEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j);
if i = etEnemyBoss then Boss := false;
dec(NumEnemys);
breaked := true;
674,7 → 675,7
var
Enemy: TSprite;
begin
Enemy := TEnemy.Create(SpriteEngine.Engine, AEnemyType, ALives);
Enemy := TEnemyOrItem.Create(SpriteEngine.Engine, AEnemyType, ALives);
Enemy.x := x;
Enemy.y := y;
end;
711,32 → 712,37
end;
 
procedure TMainForm.AnzeigeAct;
resourcestring
SYes = 'Ja';
SNo = 'Nein';
begin
SLabel1b.Caption := inttostr(NumEnemys);
if Boss then SLabel2b.Caption := 'Ja' else SLabel2b.Caption := 'Nein';
if Boss then SLabel2b.Caption := SYes else SLabel2b.Caption := SNo;
SLabel3b.Caption := inttostr(ScrollBar.Max);
if LevChanged then
begin
SLabel4a.Font.Color := $00000096;
SLabel4b.Font.Color := $00000096;
SLabel4b.Caption := 'Nein';
SLabel4b.Caption := SNo;
end
else
begin
SLabel4a.Font.Color := $00009600;
SLabel4b.Font.Color := $00009600;
SLabel4b.Caption := 'Ja';
SLabel4b.Caption := SYes;
end;
end;
 
procedure TMainForm.AufUpdatesprfen1Click(Sender: TObject);
begin
CheckForUpdates('spacemission', ProgramVersion);
CheckForUpdates('spacemission', ProgramVersion); // do not localize
end;
 
procedure TMainForm.NeuClick(Sender: TObject);
resourcestring
SReallyDeleteLevel = 'Level wirklich löschen?';
begin
if MessageDlg('Level wirklich löschen?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg(SReallyDeleteLevel, mtConfirmation, mbYesNoCancel, 0) = mrYes then
DestroyLevel;
end;
 
746,6 → 752,7
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;
759,8 → 766,8
StatusBar.SimpleText := ' ' + status_info;
exit;
end;
ex := trunc(x/RasterW) * RasterW;
ey := trunc(y/RasterH) * RasterH;
ex := trunc(x/LevEditRasterW) * LevEditRasterW;
ey := trunc(y/LevEditRasterH) * LevEditRasterH;
lifes := -1;
enemyType := etUnknown;
breaked := false;
770,11 → 777,11
begin
if boss and (i = etEnemyBoss) then
begin
for k := 0 to 3 do
for k := 0 to BossWidth - 1 do
begin
for l := 0 to 1 do
for l := 0 to BossHeight - 1 do
begin
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * RasterW), ey - (RasterH * l), i, j) <> -1 then
if LevData.IndexOfEnemy(ex + ((ScrollP - k) * LevEditRasterW), ey - (LevEditRasterH * l), i, j) <> -1 then
begin
lifes := j;
breaked := true;
784,7 → 791,7
if breaked then break;
end;
end;
if (breaked = false) and (LevData.IndexOfEnemy(ex + (ScrollP * RasterW), ey, i, j) <> -1) then
if (breaked = false) and (LevData.IndexOfEnemy(ex + (ScrollP * LevEditRasterW), ey, i, j) <> -1) then
begin
lifes := j;
enemyType := i;
804,7 → 811,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 := '???';
else enemyName := SUnknownEnemyType;
if lifes > 0 then
StatusBar.SimpleText := ' ' + enemyName + ' - ' + status_lives + inttostr(lifes)
else
815,9 → 822,11
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('Beenden ohne abspeichern?', mtConfirmation, mbYesNoCancel, 0) = mrYes;
CanClose := MessageDlg(SExitWithoutSave, mtConfirmation, mbYesNoCancel, 0) = mrYes;
end;
 
procedure TMainForm.Spielfelderweitern1Click(Sender: TObject);
/LevOptions.dfm
69,6 → 69,7
Width = 329
Height = 57
Color = clInfoBk
ParentBackground = False
TabOrder = 0
object ElLabel1: TLabel
Left = 8
92,11 → 93,13
'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
/LevSpeicherung.pas
59,6 → 59,7
resourcestring
SLevelListBox = 'Level %d';
SSelbsterstellt = 'Selbsterstellt';
SLevelFileNotFound = 'Leveldatei nicht gefunden';
 
procedure TSpeicherungForm.SearchLevels;
var
92,12 → 93,14
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('Dieses Level wirklich löschen?', mtConfirmation, mbYesNoCancel, 0) = mrYes then
if MessageDlg(SReallyDeleteLevel, mtConfirmation, mbYesNoCancel, 0) = mrYes then
begin
li1a.visible := false;
li2a.visible := false;
111,7 → 114,7
LadenBtn.enabled := false;
LoeschenBtn.enabled := false;
fil := GetLevelFileName(GetListBoxSelectedLevelNumber,false);
if not fil.found then raise Exception.Create('Leveldatei nicht gefunden');
if not fil.found then raise Exception.Create(SLevelFileNotFound);
deletefile(fil.fileLocation);
SearchLevels;
end;
118,6 → 121,8
end;
 
procedure TSpeicherungForm.LadenBtnClick(Sender: TObject);
resourcestring
SLoadNewLevelAndDiscardChanges = 'Neues Level laden und Änderungen verwerfen?';
var
fil: TLevelFile;
begin
125,7 → 130,7
 
if MainForm.LevChanged and (MainForm.LevData.CountEnemies>0) then
begin
if MessageDlg('Neues Level laden und Änderungen verwerfen?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then exit;
if MessageDlg(SLoadNewLevelAndDiscardChanges, mtConfirmation, mbYesNoCancel, 0) <> mrYes then exit;
end;
 
// Da Button bei ungültigen Level deaktiviert wird, ist das nicht mehr nötig.
135,7 → 140,7
MainForm.DestroyLevel;
MainForm.LevData.RasterErzwingen := true;
fil := GetLevelFileName(GetListBoxSelectedLevelNumber,false);
if not fil.found then raise Exception.Create('Leveldatei nicht gefunden');
if not fil.found then raise Exception.Create(SLevelFileNotFound);
MainForm.LevData.LoadFromFile(fil.fileLocation);
MainForm.RefreshFromLevData;
MainForm.LevChanged := false;
144,10 → 149,14
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('Das Level ist leer!', mtError, [mbOK], 0);
MessageDlg(SLevelIsEmpty, mtError, [mbOK], 0);
LevelNumber.SetFocus;
exit;
end;
163,7 → 172,7
(copy(LevelName.text, i, 1) = '>') or
(copy(LevelName.text, i, 1) = '|') then
begin
MessageDlg('Dies ist kein gültiger Levelname!', mtError, [mbOK], 0);
MessageDlg(SNoValidLevelName, mtError, [mbOK], 0);
LevelName.SetFocus;
exit;
end;
171,7 → 180,7
if (LevelListBox.items.IndexOf(Format(SLevelListBox, [LevelNumber.Value])) > -1) or
(LevelListBox.items.IndexOf(Format(SLevelListBox, [LevelNumber.Value])+' ('+SSelbsterstellt+')') > -1) then
begin
if MessageDlg('Level ist bereits vorhanden. Ersetzen?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then
if MessageDlg(SLevelAlreadyExists, mtConfirmation, mbYesNoCancel, 0) <> mrYes then
exit;
end;
 
186,6 → 195,11
end;
 
procedure TSpeicherungForm.LevelListBoxClick(Sender: TObject);
resourcestring
SYes = 'Ja';
SNo = 'Nein';
SFields = '%d Felder';
SXbyY = '%s von %s';
var
LevelData: TLevelData;
boss: boolean;
217,7 → 231,7
LevelData.RasterErzwingen := true;
 
fil := GetLevelFileName(GetListBoxSelectedLevelNumber,false);
if not fil.found then raise Exception.Create('Leveldatei nicht gefunden');
if not fil.found then raise Exception.Create(SLevelFileNotFound);
LevelData.LoadFromFile(fil.fileLocation);
 
boss := false;
241,11 → 255,11
LoeschenBtn.enabled := true;
li1b.caption := inttostr(anzahlEinheiten);
if boss then
li2b.caption := 'Ja'
li2b.caption := SYes
else
li2b.caption := 'Nein';
li3b.caption := IntToStr(LevelData.LevelEditorLength) + ' Felder';
li4.Caption := Trim(LevelData.LevelName + ' von ' + LevelData.LevelAuthor);
li2b.caption := SNo;
li3b.caption := Format(SFields, [LevelData.LevelEditorLength]);
li4.Caption := Trim(Format(SXbyY, [LevelData.LevelName, LevelData.LevelAuthor]));
finally
FreeAndNil(LevelData);
end;
/SpaceMission.dproj
90,7 → 90,8
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_MinorVer>2</VerInfo_MinorVer>
<VerInfo_Locale>1033</VerInfo_Locale>
<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>
<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>
</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
/TODO.md
1,11 → 1,15
 
# 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
- Vorbereitung auf Multilingualität (all strings in resourcestrings), ggf. sogar schon auf Englisch übersetzen
- Auf Englisch übersetzen
- SplashScreens: als BMP
 
## Kleinigkeiten
22,14 → 26,15
 
## Ideen
 
- Neue Einheit: 10 Sekunden unverwundbarkeit item
- Neue Einheit: Geld Geschenk item
- Neues Item: 10 Sekunden unverwundbarkeit item
- Neues Item: 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
- "unsaubere" levels akzeptieren! komet mit 1+ leben, einheiten, die nicht auf der linie sind.
- Anderer Soundeffekt, wenn man selbst getroffen ist
- Leveleditor: "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?
38,17 → 43,14
- 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 müssten sich gegenseitig kaputt machen?
- Tama 1 und Tama 2 könnten 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)
- Tastenspeere bei runter+links+shot
- "Beenden ohne Speichern?" bei leerem Level
- Leveleditor performance oder deadlock probleme?
- Leveleditor performance oder deadlock probleme? bei vielen einheiten wird das sehr langsam? algo verbessern?
- Leveleditor Probleme mit Schiebebildchen... (was meinte ich damit?)
- Leveleditor Wenn Level gelöscht, dass gerade geladen ist, dann LevChanged = true!
- Leveleditor Boss überschneidet Einheiten ?
62,10 → 64,8
- 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 karten
- auch mit einer symbolleiste mit ordnersymbol bei lev (oder sm)?
- leicht, mittel, schwer: falsche fps bei langsameren grafikkarten?
- 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