From 4cc19614caf4828f09b55b239940ea8b6eaa4007 Mon Sep 17 00:00:00 2001 From: bw Date: Thu, 1 Nov 2007 12:36:59 +0000 Subject: [PATCH] Lode Runner Live game git-svn-id: svn://kolibrios.org@670 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/games/lrl/LRL.pp | 83 ++ programs/games/lrl/LRLEditor.pp | 304 +++++++ programs/games/lrl/LRLHighScores.pp | 234 +++++ programs/games/lrl/LRLIntroduction.pp | 135 +++ programs/games/lrl/LRLLevels.pp | 1194 +++++++++++++++++++++++++ programs/games/lrl/LRLMainMenu.pp | 116 +++ programs/games/lrl/LRLRoutines.pp | 499 +++++++++++ programs/games/lrl/LRLSprites.pp | 255 ++++++ programs/games/lrl/bin/lrl.img | Bin 0 -> 153049 bytes programs/games/lrl/bin/lrl.lev | Bin 0 -> 72825 bytes programs/games/lrl/build.bat | 30 + programs/games/lrl/readme-ru.txt | 10 + 12 files changed, 2860 insertions(+) create mode 100644 programs/games/lrl/LRL.pp create mode 100644 programs/games/lrl/LRLEditor.pp create mode 100644 programs/games/lrl/LRLHighScores.pp create mode 100644 programs/games/lrl/LRLIntroduction.pp create mode 100644 programs/games/lrl/LRLLevels.pp create mode 100644 programs/games/lrl/LRLMainMenu.pp create mode 100644 programs/games/lrl/LRLRoutines.pp create mode 100644 programs/games/lrl/LRLSprites.pp create mode 100644 programs/games/lrl/bin/lrl.img create mode 100644 programs/games/lrl/bin/lrl.lev create mode 100644 programs/games/lrl/build.bat create mode 100644 programs/games/lrl/readme-ru.txt diff --git a/programs/games/lrl/LRL.pp b/programs/games/lrl/LRL.pp new file mode 100644 index 0000000000..e82bbb0c0b --- /dev/null +++ b/programs/games/lrl/LRL.pp @@ -0,0 +1,83 @@ +program LodeRunnerLive; + +{$apptype gui} + + +uses + LRLRoutines, + LRLSprites, + LRLLevels, + LRLMainMenu, + {LRLHighScores, + LRLEditor,} + LRLIntroduction; + +const + Version: array [1..34] of char = 'Lode Runner LIVE. Version 1.0'#13#10#13#10'$'; + + +procedure LRLInitialize; +begin + kos_setkeyboardmode(0); + ImagesInitialize; +end; + + +procedure LRLDeinitialize; +begin + ImagesDeinitialize; +end; + + +procedure LRLGameStart; +var + cl: Integer; +begin + Palette256Set(LRLPalette^); + + ShowLives := True; + ShowScore := True; + ShowLevel := True; + LRLLives := 5; + LRLScore := 0; + + cl := 1; + repeat + LRLPlayLevel(cl); + KeyboardFlush; + if GameResult = 10 then + begin + Inc(LRLLives); + LRLScore := LRLScore + 10000 * longint(cl); + Inc(cl); + end else + Dec(LRLLives); + until (LRLLives = 0) or (GameResult = 100); + + {(GameResult <> 100) and LRLBestScore(LRLScore) then + begin + LRLInsertScore(LRLEnterName, LRLScore); + LRLShowHighScores; + end;} +end; + +procedure LRLShell; +var + MenuSelection: word; +begin + MenuSelection := 1; + repeat + LRLSelectItem(MenuSelection); + if MenuSelection = 1 then LRLGameStart; + {if MenuSelection = 2 then LRLEditLevels; + if MenuSelection = 3 then LRLShowHighScores;} + until MenuSelection = 4; +end; + + +begin + LRLInitialize; + LRLIntro; + LRLShell; + LRLDeinitialize; +end. diff --git a/programs/games/lrl/LRLEditor.pp b/programs/games/lrl/LRLEditor.pp new file mode 100644 index 0000000000..237ded35b4 --- /dev/null +++ b/programs/games/lrl/LRLEditor.pp @@ -0,0 +1,304 @@ +unit LRLEditor; + +interface + +uses DOSFileAccess, LRLRoutines, LRLSprites, LRLLevels; + +procedure LRLEditLevels; + +implementation + +var + CurrentLevel: word; + CurrentTool: word; + TotalLevels: word; + MouseX, MouseY: integer; + TimeToRefresh: boolean; + RefreshDelay: word; + RefreshRemain: word; + OldTimer: POINTER; + +procedure LRLRedrawLevel; +var + i, j: integer; +begin + ImageClear(LRLScreen^); + for i := 1 to 16 do + for j := 1 to 30 do + with LRLLevel.Field[j, i] do + ImagePut(LRLScreen^, LRLEnvironment[Image].Image[Count].Data^, j * 10, i * 10, 0, 0, 319, 199); + for i := 1 to 10 do + with LRLLevel.Player[i] do + begin + if Controller <> 0 then + ImagePutTransparent(LRLScreen^, LRLFigure[Colour, SpriteData].Image[Sprite].Data^, + Position.x * 10 + Position.xoffs, Position.y * 10 + Position.yoffs, 0, 0, 319, 199); + end; + ImageFill(LRLFontBuffer^, 12, 12, 252); + ImagePut(LRLScreen^, LRLFontBuffer^, 10, 184, 0, 0, 319, 199); + for i := 1 to 13 do + begin + if i > 9 then + ImagePut(LRLScreen^, LRLFigure[i - 9, 1].Image[1].Data^, i * 15 - 4, 185, 0, 0, 319, 199) + else + ImagePut(LRLScreen^, LRLEnvironment[i].Image[1].Data^, i * 15 - 4, 185, 0, 0, 319, 199); + end; + for i := 1 to 6 do + begin + if LRLEditorButton[i].Lit then + ImagePut(LRLScreen^, LRLEditorButton[i].LightIcon^, LRLEditorButton[i].x1, + LRLEditorButton[i].y1, 0, 0, 319, 199) + else + ImagePut(LRLScreen^, LRLEditorButton[i].DarkIcon^, LRLEditorButton[i].x1, + LRLEditorButton[i].y1, 0, 0, 319, 199); + end; + LRLDrawOrnamental(0, 0, 31, 17, 1); +end; + +procedure RefreshRunner; +{INTERRUPT; +ASSEMBLER;} +asm + DEC RefreshRemain + JNZ @DoTimer + + MOV AX,RefreshDelay + MOV RefreshRemain,AX + MOV TimeToRefresh,-1 + + @DoTimer: + PUSHF + CALL OldTimer +end; + +procedure LRLMoveMouse; +var + s, s2: string[20]; +begin + MSMouseGetXY(Mousex, Mousey); + if not MSMouseInArea(200, 180, 325, 205) then + begin + if CurrentTool < 10 then + ImagePut(LRLScreen^, LRLEnvironment[CurrentTool].Image[1].Data^, + Mousex - 5, Mousey - 5, 0, 0, 319, 199) + else + ImagePut(LRLScreen^, LRLFigure[CurrentTool - 9, 1].Image[1].Data^, + Mousex - 5, Mousey - 5, 0, 0, 319, 199); + end; + if not MSMouseInArea(-2, -2, 55, 20) then + begin + ImageFill(LRLFontBuffer^, 50, 15, 0); + ImagePut(LRLScreen^, LRLFontBuffer^, 0, 0, 0, 0, 319, 199); + STR(CurrentLevel, s); + STR(TotalLevels, s2); + ImageStringGet(s + '/' + s2, LRLFont^, LRLFontBuffer^, 251); + ImagePut(LRLScreen^, LRLFontBuffer^, 25 - ImageSizex(LRLFontBuffer^) div 2, 0, 0, 0, 319, 199); + end; + ImagePutTransparent(LRLScreen^, LRLMousePointer^, Mousex, Mousey, 0, 0, 319, 199); +end; + +procedure RePress; +var + x, y: integer; +begin + MSMouseButtonWasPressed(1, x, y); + MSMouseButtonWasReleased(1, x, y); + MSMouseButtonWasPressed(4, x, y); + MSMouseButtonWasReleased(4, x, y); +end; + +procedure LRLEditLevels; +var + Keypress: word; + NeedToFade: boolean; + DrawNow: boolean; + i, j: integer; + x, y: integer; + Cmd: word; +begin + if not MSMouseDriverExist then Exit; + Repress; + ShowLives := False; + ShowScore := False; + Palette256Set(LRLPalette^); + OldTimer := SetInterrupt($8, @RefreshRunner); + Keypress := 0; + RefreshDelay := 1; + RefreshRemain := 1; + CurrentLevel := 1; + CurrentTool := 2; + TotalLevels := LRLLevelCount; + TimeToRefresh := True; + DrawNow := False; + MSMouseSetXY(160, 100); + LRLLoadLevel(CurrentLevel); + repeat + if TimeToRefresh then + begin + LRLRedrawLevel; + LRLMoveMouse; + ScreenApply(LRLScreen^); + TimeToRefresh := False; + end; + if Keypressed then + begin + Keypress := Readkey; + end; + if MSMouseButtonWasReleased(1, x, y) then + begin + LRLScore := 0; + FadeClear; + ImageClear(LRLScreen^); + ScreenApply(LRLScreen^); + Palette256Set(LRLPalette^); + LRLPlayLevel(CurrentLevel); + FadeClear; + ImageClear(LRLScreen^); + ScreenApply(LRLScreen^); + Palette256Set(LRLPalette^); + LRLLoadLevel(CurrentLevel); + Repress; + end; + if MSMouseButtonWasPressed(0, x, y) then + begin + DrawNow := True; + end; + if MSMouseButtonWasReleased(0, x, y) then + begin + DrawNow := False; + Cmd := 0; + for i := 1 to 6 do + LRLEditorButton[i].Lit := False; + for i := 1 to 6 do + begin + if MSMouseInArea(LRLEditorButton[i].x1, LRLEditorButton[i].y1, + LRLEditorButton[i].x2, LRLEditorButton[i].y2) then + begin + Cmd := LRLEditorButton[i].Command; + BREAK; + end; + end; + if (Cmd = 1) then + LRLSaveLevel(CurrentLevel); + Repress; + if (Cmd = 2) then + begin + LRLInsertLevel(CurrentLevel); + Inc(CurrentLevel); + TotalLevels := LRLLevelCount; + LRLLoadLevel(CurrentLevel); + Repress; + end; + if (Cmd = 3) and (CurrentLevel < TotalLevels) then + begin + Inc(CurrentLevel); + LRLLoadLevel(CurrentLevel); + Repress; + end; + if (Cmd = 4) then + begin + for i := 1 to 16 do + for j := 1 to 30 do + LRLLevel.Field[j, i].Image := 1; + for i := 1 to 10 do + LRLLevel.Player[i].Controller := 0; + Repress; + end; + if (Cmd = 5) and (TotalLevels > 1) then + begin + LRLDeleteLevel(CurrentLevel); + TotalLevels := LRLLevelCount; + if CurrentLevel > TotalLevels then + CurrentLevel := TotalLevels; + LRLLoadLevel(CurrentLevel); + Repress; + end; + if (Cmd = 6) and (CurrentLevel > 1) then + begin + Dec(CurrentLevel); + LRLLoadLevel(CurrentLevel); + Repress; + end; + MSMouseGetXY(Mousex, Mousey); + if (Mousey > 180) then + begin + for i := 1 to 13 do + begin + if (Mousey > 184) and (Mousey < 195) and (Mousex > i * 15 - 5) and (Mousex < i * 15 + 6) then + begin + CurrentTool := i; + BREAK; + end; + end; + end; + end; + if DrawNow then + begin + for i := 1 to 6 do + LRLEditorButton[i].Lit := False; + for i := 1 to 6 do + begin + if MSMouseInArea(LRLEditorButton[i].x1, LRLEditorButton[i].y1, + LRLEditorButton[i].x2, LRLEditorButton[i].y2) then + begin + LRLEditorButton[i].Lit := True; + BREAK; + end; + end; + MSMouseGetXY(Mousex, Mousey); + x := (Mousex) div 10; + y := (Mousey) div 10; + if (x > 0) and (x < 31) and (y > 0) and (y < 17) then + begin + for i := 1 to 10 do + begin + if (LRLLevel.Player[i].Controller <> 0) and (LRLLevel.Player[i].Position.x = x) and + (LRLLevel.Player[i].Position.y = y) then + begin + if (CurrentTool <> 2) and (CurrentTool <> 3) and (CurrentTool <> 4) and + (CurrentTool <> 7) then + begin + LRLLevel.Player[i].Controller := 0; + BREAK; + end; + end; + end; + if CurrentTool < 10 then + LRLLevel.Field[x, y].Image := CurrentTool + else + begin + if (LRLLevel.Field[x, y].Image = 2) or (LRLLevel.Field[x, y].Image = 3) or + (LRLLevel.Field[x, y].Image = 4) or (LRLLevel.Field[x, y].Image = 1) then + begin + if CurrentTool = 10 then + begin + LRLLevel.Player[1].Controller := 1; + LRLLevel.Player[1].Position.x := x; + LRLLevel.Player[1].Position.y := y; + LRLLevel.Player[1].Colour := 1; + end + else + begin + j := 2; + for i := 2 to 10 do + begin + if LRLLevel.Player[i].Controller = 0 then + begin + j := i; + BREAK; + end; + end; + LRLLevel.Player[j].Controller := 2; + LRLLevel.Player[j].Position.x := x; + LRLLevel.Player[j].Position.y := y; + LRLLevel.Player[j].Colour := CurrentTool - 9; + end; + end; + end; + end; + end; + until (LO(Keypress) = 27); + SetInterrupt($8, OldTimer); +end; + +end. diff --git a/programs/games/lrl/LRLHighScores.pp b/programs/games/lrl/LRLHighScores.pp new file mode 100644 index 0000000000..46ca0f68ce --- /dev/null +++ b/programs/games/lrl/LRLHighScores.pp @@ -0,0 +1,234 @@ +unit LRLHighScores; + + +interface + + +uses + LRLRoutines, LRLSprites, StrUnit; + + +procedure LRLLoadHighScores; +procedure LRLShowHighScores; +function LRLBestScore(Score: longint): boolean; +procedure LRLInsertScore(Name: string; Score: longint); +procedure LRLSaveHighScores; +function LRLEnterName: string; + + +implementation + + +const + HighsFileName = 'LRL.HSR'; + HighsFileHeader: string[29] = 'Lode Runner Live High Scores'#26; + +type + TSupers = packed record + Name: string[20]; + Score: longint; + end; + +var + MainScreen: POINTER; + HighFrame: POINTER; + HighTable: array[1..5] of TSupers; + +procedure LoadData; +var + j: word; +begin + GETMEM(MainScreen, 64004); + GETMEM(HighFrame, 45000); + DFAFilePositionSet(ImageFile, LRLImagesFilePosition, DFASeekFromStart); + DFAFileRead(ImageFile, MainScreen^, 7940, j); + DecompressRepByte(MainScreen^, HighFrame^, 7940, j); + DFAFileRead(ImageFile, MainScreen^, 64004, j); +end; + +procedure DisposeData; +begin + FREEMEM(MainScreen, 64004); + FREEMEM(HighFrame, 45000); +end; + +procedure LRLShowHighScores; +var + p: POINTER; + i: integer; + s: string; +begin + LRLLoadHighScores; + GETMEM(p, 768); + DataFill(p^, 768, 0, 0); + Palette256Set(p^); + FREEMEM(p, 768); + LoadData; + ImagePut(LRLScreen^, MainScreen^, 0, 0, 0, 0, 319, 199); + ImagePut(LRLScreen^, HighFrame^, 6, 50, 0, 0, 319, 199); + for i := 1 to 5 do + begin + ImageStringGet(CHR(i + 48) + '. ' + HighTable[i].Name, LRLFont^, LRLFontBuffer^, 110); + ImagePut(LRLScreen^, LRLFontBuffer^, 55, 85 + i * 17, 8, 0, 319, 199); + STR(HighTable[i].Score, s); + ImageStringGet(s, LRLFont^, LRLFontBuffer^, 46); + ImagePut(LRLScreen^, LRLFontBuffer^, 260 - ImageSizex(LRLFontBuffer^), 85 + i * 17, 8, 0, 319, 199); + end; + ScreenApply(LRLScreen^); + FadeTo(LRLMenuPalette); + READKEY; + FadeClear; + ImageClear(LRLScreen^); + ScreenApply(LRLScreen^); + DisposeData; +end; + +procedure LRLLoadHighScores; +var + InFile: TDFAFileHandle; + i, j: word; + high: TSupers; + dummy: string[30]; +begin + high.Name := 'Lode Runner'; + DFAFileOpen(InFile, HighsFileName, DFAAccessReadWrite); + if DFALastResult(InFile) <> 0 then + begin + DFAFileCreate(InFile, HighsFileName, DFAAttributeArchive); + DFAFileWrite(InFile, HighsFileHeader[1], 29, i); + for i := 1 to 5 do + begin + high.score := 60000 - i * 10000; + DFAFileWrite(InFile, high, SIZEOF(high), j); + end; + end; + DFAFilePositionSet(InFile, 0, DFASeekFromStart); + DFAFileRead(InFile, dummy[1], 29, j); + if (DFALastResult(InFile) <> 0) or + (not DataIdentical(dummy[1], HighsFileHeader[1], 29, 0, 0)) then + begin + WRITELN('Error: Invalid file with high scores! (try to remove LRL.HSR file)'); + WRITELN('Ошибка: Неверный файл с рекордами! (попробуйте удалить файл LRL.HSR)'); + Halt(1); + end; + DFAFileRead(InFile, HighTable, SIZEOF(TSupers) * 5, j); + DFAFileClose(InFile); +end; + +procedure LRLSaveHighScores; +var + InFile: TDFAFileHandle; + i, j: word; +begin + DFAFileOpen(InFile, HighsFileName, DFAAccessReadWrite); + DFAFilePositionSet(InFile, 29, DFASeekFromStart); + DFAFileWrite(InFile, HighTable, SIZEOF(TSupers) * 5, j); + DFAFileClose(InFile); +end; + +function LRLBestScore(Score: longint): boolean; +var + i: integer; +begin + LRLBestScore := True; + LRLLoadHighScores; + i := 1; + while True do + begin + if Score >= HighTable[i].Score then + EXIT; + Inc(i); + if i > 5 then + begin + LRLBestScore := False; + EXIT; + end; + end; +end; + +procedure LRLInsertScore(Name: string; Score: longint); +var + i, j: word; +begin + LRLLoadHighScores; + i := 1; + while True do + begin + if Score >= HighTable[i].Score then + begin + for j := 4 downto i do + begin + HighTable[j + 1].Name := HighTable[j].Name; + HighTable[j + 1].Score := HighTable[j].Score; + end; + HighTable[i].Name := Name; + HighTable[i].Score := Score; + LRLSaveHighScores; + EXIT; + end; + Inc(i); + if i > 5 then + begin + EXIT; + end; + end; +end; + +function LRLEnterName: string; +var + p: POINTER; + i: integer; + RedrawName: boolean; + Keypress: word; + Name: string; +begin + Name := ''; + GETMEM(p, 768); + DataFill(p^, 768, 0, 0); + Palette256Set(p^); + FREEMEM(p, 768); + ImageClear(LRLScreen^); + ImagePut(LRLScreen^, LRLLogo^, 3, 3, 0, 0, 319, 199); + ImageStringGet('Congratulations! You are in Top-Five!', LRLFont^, LRLFontBuffer^, 110); + ImagePut(LRLScreen^, LRLFontBuffer^, 160 - ImageSizex(LRLFontBuffer^) shr 1, 85, 0, 0, 319, 199); + ImageStringGet('Enter your name below, Champ', LRLFont^, LRLFontBuffer^, 111); + ImagePut(LRLScreen^, LRLFontBuffer^, 160 - ImageSizex(LRLFontBuffer^) shr + 1, 110, 0, 0, 319, 199); + ImageStringGet('---------------------------', LRLFont^, LRLFontBuffer^, 100); + ImagePut(LRLScreen^, LRLFontBuffer^, 160 - ImageSizex(LRLFontBuffer^) shr + 1, 155, 0, 0, 319, 199); + ScreenApply(LRLScreen^); + FadeTo(LRLMenuPalette); + RedrawName := True; + repeat + if RedrawName = True then + begin + ImageFill(LRLFontBuffer^, 320, 20, 0); + ImagePut(LRLScreen^, LRLFontBuffer^, 0, 140, 0, 0, 319, 199); + ImageStringGet(Name, LRLFont^, LRLFontBuffer^, 100); + ImagePut(LRLScreen^, LRLFontBuffer^, 160 - ImageSizex(LRLFontBuffer^) shr + 1, 140, 0, 0, 319, 199); + ScreenApply(LRLScreen^); + RedrawName := False; + end; + Keypress := READKEY; + if (LO(Keypress) = 8) and (LENGTH(Name) > 0) then + begin + Name[0] := char(Ord(Name[0]) - 1); + RedrawName := True; + end; + if (LO(Keypress) > 31) and (LENGTH(Name) < 20) then + begin + Name := Name + char(LO(Keypress)); + RedrawName := True; + end; + until LO(Keypress) = 13; + FadeClear; + Name := StringTrimAll(Name, ' '); + if LENGTH(Name) = 0 then + Name := 'Anonymous'; + LRLEnterName := Name; +end; + + +end. diff --git a/programs/games/lrl/LRLIntroduction.pp b/programs/games/lrl/LRLIntroduction.pp new file mode 100644 index 0000000000..80fab06d31 --- /dev/null +++ b/programs/games/lrl/LRLIntroduction.pp @@ -0,0 +1,135 @@ +unit LRLIntroduction; + + +interface + + +uses + SysUtils, + LRLRoutines, LRLSprites; + + +procedure LRLIntro; + + +implementation + + +const + IntroText: array[1..14] of String = ( + 'Lode Runner LIVE. FREEWARE Version 1.0', + 'KolibriOS port by bw (Vladimir V. Byrgazov)', + 'Copyright (c) 1995 Aleksey V. Vaneev', + 'Copyright (c) 2007 bw', + '', + 'Send comments to Aleksey V. Vaneev', + '2:5003/15@FidoNet', + 'ikomi@glas.apc.org', + '', + 'Send comments to bw', + 'bw@handsdriver.net', + '', + '', + '' + ); + + SPACE40 = ' '; + + +var + RefreshDelay: Word; + RefreshRemain: Word; + TimeToRefresh: Boolean; + OldTimer: Pointer; + + +procedure LRLIntro; +var + i, j, l: Integer; + Count: Word; + k: Word; + MainScreen: Pointer; +begin + RefreshDelay := 1; + RefreshRemain := 1; + GetMem(MainScreen, 64004); + + Seek(ImageFile, LRLImagesFilePosition + 7940); + BlockRead(ImageFile, MainScreen^, 64004, k); + Palette256Set(LRLMenuPalette^); + ImageFill(LRLFontBuffer^, 320, 55, 0); + ImageClear(LRLScreen^); + + for i := -50 to 4 do + begin + ImagePut(LRLScreen^, LRLFontBuffer^, 0, 0, 0, 0, 319, 199); + ImagePut(LRLScreen^, LRLLogo^, 3, i, 0, 0, 319, 199); + ScreenApply(LRLScreen^); + if Keypressed then + begin + ReadKey; + FreeMem(MainScreen, 64004); + Exit; + end; + Sleep(10); + end; + + ImageFill(LRLFontBuffer^, 320, 55, 0); + for i := 0 to 10 do + begin + for k := 0 to 20 do + for j := 0 to 16 do + ImagePutTransparent(LRLScreen^, MainScreen^, 0, 0, + j * 20 - 10 - i, k * 20 - 10 - i, + j * 20 - 10 + i, k * 20 - 10 + i); + + Sleep(50); + + ImagePut(LRLScreen^, LRLFontBuffer^, 0, 182, 0, 0, 319, 199); + ScreenApply(LRLScreen^); + if Keypressed then + begin + ReadKey; + FreeMem(MainScreen, 64004); + Exit; + end; + end; + + Count := 1; + k := 1; + repeat + if TimeToRefresh then + begin + Inc(Count); + TimeToRefresh := False; + end; + + if Count >= 2 then + begin + ImageStringGet(SPACE40 + IntroText[k] + SPACE40, LRLFont^, LRLFontBuffer^, 110); + for l := 200 downto 184 do + begin + ImagePut(LRLScreen^, LRLFontBuffer^, 160 - ImageSizeX(LRLFontBuffer^) div 2, l, 0, 0, 319, 199); + ScreenApply(LRLScreen^); + Sleep(20); + end; + Inc(k); + if k > Length(IntroText) then k := 1; + Count := 0; + end; + + for I := 1 to 8 do + if Keypressed then + Break else + Sleep(250); + + TimeToRefresh := True; + until KeyPressed; + + ReadKey; + FadeClear; + FreeMem(MainScreen, 64004); +end; + + +end. diff --git a/programs/games/lrl/LRLLevels.pp b/programs/games/lrl/LRLLevels.pp new file mode 100644 index 0000000000..ed811a13a3 --- /dev/null +++ b/programs/games/lrl/LRLLevels.pp @@ -0,0 +1,1194 @@ +unit LRLLevels; + +{$mode objfpc} + + +interface + + +uses + SysUtils, + LRLRoutines, LRLSprites; + + +type + TLRLPlayerPosition = packed record + x, y: Byte; + xoffs, yoffs: ShortInt; + end; + + TLRLPlayer = packed record + Command: Byte; + { pictures: + 1 - running left <- + 2 - running right -> + 3 - climbing up ^ + 4 - climbing down v + 5 - falling + 6 - ~~~~~ left <- + 7 - ~~~~~ right -> + 8 - firing left <- + 9 - firing right -> + } + NewCommandWas: Boolean; + NewCommand: Byte; + Position: TLRLPlayerPosition; + Sprite: Byte; + SpriteData: Byte; + Controller: Byte; + { + controllers: + 0 - not playing + 1 - human/keyboard + 2 - computer + } + Prizes: Byte; + { + max 1 if computer player + a) computer player leaves prize if falling into hole + b) takes prize if he has no prizes + } + Colour: Byte; + end; + + TLRLBrick = packed record + Image: Byte; + Count: Byte; + Flags: Byte; + { flags: + bit 0 - needed to animate this brick 5 sprites then pause + and then finnally 5 sprites + bit 1 - set if fatal brick + bit 2 - set if allowable to jump + bit 3 - allowable to walk thru + bit 4 - hidden + bit 5 - background + bit 6 - wait now + bit 7 - not draw it + } + IdleCount: Byte; + end; + + TLRLLevel = packed record + Field: array[1..30, 1..16] of TLRLBrick; + Player: array[1..20] of TLRLPlayer; + end; + + +const + BrickFlags: array[1..20] of Byte = ( + 48, 4 + 8 + 32 + 128, + 49, 8 + 32, + 50, 4 + 8 + 32, + 51, 4 + 8 + 32, + 52, 2, + 53, 4, + 54, 4 + 8, + 55, 2, + 56, 2, + 65, 4 + 8 + 16 + 32); + + +const + KeyboardControls: array[1..21] of Word = ( + $00B0, 1, 1, + $00B3, 1, 2, + $00B2, 1, 3, + $00B1, 1, 4, + $00B5, 1, 6, + $00B7, 1, 7, + $0037, 1, 5); + ControlNumber = 7; + + +var + ShowLives: Boolean; + ShowScore: Boolean; + ShowLevel: Boolean; + LRLLevel: TLRLLevel; + LRLLives: Integer; + LRLScore: Longint; + LRLCLevel: Word; + ComputerTurn: Word; + ComputerReaction: Word; + TimeToRefresh: Boolean; + OldTimer: Pointer; + TotalPrizes: Integer; + GameStarted: Boolean; + EndOfGame: Boolean; + GameResult: Word; + Paused: Boolean; + + +procedure LRLLoadLevel(Number: Byte); +procedure LRLUpdatePlayers; +procedure LRLDrawOrnamental(x1, y1, x2, y2, ornament: Byte); +function LRLPlayLevel(Number: Byte): Word; +function LRLLevelCount: Word; +procedure LRLDeleteLevel(Count: Word); +procedure LRLInsertLevel(After: Word); +procedure LRLSaveLevel(Count: Word); + + +implementation + + +const + LevelFileName = 'LRL.LEV'; + LevelFileHeader: String = 'Lode Runner Live Levels'#26; + + ERR_OPENFILE = 'Невозможно открыть файл уровней'; + ERR_BADFILE = 'Неверный или поврежденный файл уровней'; + + +function LRLLevelCount: Word; +var + LevelFile: File; + c, k: Word; +begin + c := 0; + AssignFile(LevelFile, LevelFileName); + Reset(LevelFile, 1); + Seek(LevelFile, 24); + BlockRead(LevelFile, c, 1, k); + LRLLevelCount := c; + Close(LevelFile); +end; + + +procedure LRLSaveLevel(Count: Word); +var + LevelFile: File; + i, j: Integer; + k: Word; + b: Pointer; +begin + GetMem(b, 480); + if (Count = 0) or (Count > LRLLevelCount) then + Exit; + AssignFile(LevelFile, LevelFileName); + Reset(LevelFile, 1); + Seek(LevelFile, Longint(25 + 520 * (Longint(Count) - 1))); + for i := 1 to 10 do + begin + DataBytePut(b^, (i - 1) * 4, LRLLevel.Player[i].Position.x); + DataBytePut(b^, (i - 1) * 4 + 1, LRLLevel.Player[i].Position.y); + DataBytePut(b^, (i - 1) * 4 + 2, LRLLevel.Player[i].Colour); + DataBytePut(b^, (i - 1) * 4 + 3, LRLLevel.Player[i].Controller); + end; + BlockWrite(LevelFile, b^, 40, k); + for i := 1 to 16 do + for j := 1 to 30 do + DataBytePut(b^, (i - 1) * 30 + j - 1, LRLLevel.Field[j, i].Image + 47); + BlockWrite(LevelFile, b^, 480, k); + Close(LevelFile); + FreeMem(b, 480); +end; + + +procedure LRLDeleteLevel(Count: Word); +var + Buffer: Pointer; + LevelFile: File; + i, j: Integer; + l: Longint; + k: Word; +begin + GetMem(Buffer, 1000); + j := LRLLevelCount; + if (j < Count) or (j < 2) or (Count = 0) then + Exit; + AssignFile(LevelFile, LevelFileName); + Reset(LevelFile, 1); + for l := Count + 1 to j do + begin + Seek(LevelFile, Longint(25 + 520 * (Longint(l) - 1))); + BlockRead(LevelFile, Buffer^, 520, k); + Seek(LevelFile, Longint(25 + 520 * (Longint(l - 1) - 1))); + BlockWrite(LevelFile, Buffer^, 520, k); + end; + Seek(LevelFile, 24); + Dec(j); + BlockWrite(LevelFile, j, 1, k); + Seek(LevelFile, FileSize(LevelFile) - 520); + Truncate(LevelFile); + Close(LevelFile); + FreeMem(Buffer, 1000); +end; + + +procedure LRLInsertLevel(After: Word); +var + Buffer: Pointer; + LevelFile: File; + i, j: Integer; + l: Longint; + k: Word; +begin + GetMem(Buffer, 1000); + j := LRLLevelCount; + if (After > j) or (After = 0) then + Exit; + AssignFile(LevelFile, LevelFileName); + Reset(LevelFile, 1); + for l := j downto After + 1 do + begin + Seek(LevelFile, Longint(25 + 520 * (Longint(l) - 1))); + BlockRead(LevelFile, Buffer^, 520, k); + Seek(LevelFile, Longint(25 + 520 * (Longint(l + 1) - 1))); + BlockWrite(LevelFile, Buffer^, 520, k); + end; + Seek(LevelFile, 24); + Inc(j); + BlockWrite(LevelFile, j, 1, k); + Seek(LevelFile, Longint(25 + 520 * (Longint(After + 1) - 1))); + DataFill(Buffer^, 40, 0, 0); + DataFill(Buffer^, 480, 48, 40); + BlockWrite(LevelFile, Buffer^, 520, k); + Close(LevelFile); + FreeMem(Buffer, 1000); +end; + + +procedure LRLLoadLevel(Number: Byte); +var + LevelFile: File; + InBuffer: Pointer; + i, j, k, l, x, y: Word; + a, b, c: Byte; +begin + TotalPrizes := 0; + GetMem(InBuffer, $FFF0); + + AssignFile(LevelFile, LevelFileName); + Reset(LevelFile, 1); + if IOResult <> 0 then + raise Exception.Create(ERR_OPENFILE); + + BlockRead(LevelFile, InBuffer^, 24, k); + BlockRead(LevelFile, c, 1, k); + if (c = 0) or (IOResult <> 0) or (not DataIdentical(InBuffer^, LevelFileHeader[1], 24, 0, 0)) then + raise Exception.Create(ERR_BADFILE); + + if (Number = 0) or (Number > c) then Number := 1; + Seek(LevelFile, Longint(25 + 520 * (Longint(Number) - 1))); + BlockRead(LevelFile, InBuffer^, 40, k); + + for i := 1 to 10 do + with LRLLevel.Player[i] do + begin + Command := 10; + NewCommandWas := False; + NewCommand := 10; + Position.x := DataByteGet(InBuffer^, (i - 1) * 4 + 0); + Position.y := DataByteGet(InBuffer^, (i - 1) * 4 + 1); + Position.xoffs := 0; + Position.yoffs := 0; + Sprite := 1; + SpriteData := 1; + Controller := DataByteGet(InBuffer^, (i - 1) * 4 + 3); + Prizes := 0; + Colour := DataByteGet(InBuffer^, (i - 1) * 4 + 2); + end; + + BlockRead(LevelFile, InBuffer^, 480, k); + for i := 1 to 16 do for j := 1 to 30 do + with LRLLevel.Field[j, i] do + begin + a := DataByteGet(InBuffer^, (i - 1) * 30 + (j - 1)); + for b := 1 to 10 do + if BrickFlags[b * 2 - 1] = a then + Flags := BrickFlags[b * 2]; + Count := 1; + if a < 64 then + a := a - 47 else + a := a - 63; + Image := a; + IdleCount := 0; + if Image = 4 then Inc(TotalPrizes); + end; + + BlockRead(LevelFile, InBuffer^, 480, k); + Close(LevelFile); + LRLCLevel := Number; + FreeMem(InBuffer, $FFF0); +end; + + +procedure LRLDrawOrnamental(x1, y1, x2, y2, ornament: Byte); +var + i: Integer; +begin + ImagePut(LRLScreen^, LRLDecoration[ornament].Image[6].Data^, x1 * 10, y1 * 10, 0, 0, 319, 199); + ImagePut(LRLScreen^, LRLDecoration[ornament].Image[7].Data^, x2 * 10, y1 * 10, 0, 0, 319, 199); + ImagePut(LRLScreen^, LRLDecoration[ornament].Image[5].Data^, x1 * 10, y2 * 10, 0, 0, 319, 199); + ImagePut(LRLScreen^, LRLDecoration[ornament].Image[8].Data^, x2 * 10, y2 * 10, 0, 0, 319, 199); + for i := x1 + 1 to x2 - 1 do + begin + ImagePut(LRLScreen^, LRLDecoration[ornament].Image[3].Data^, i * 10, y1 * 10, 0, 0, 319, 199); + ImagePut(LRLScreen^, LRLDecoration[ornament].Image[4].Data^, i * 10, y2 * 10, 0, 0, 319, 199); + end; + for i := y1 + 1 to y2 - 1 do + begin + ImagePut(LRLScreen^, LRLDecoration[ornament].Image[2].Data^, x1 * 10, i * 10, 0, 0, 319, 199); + ImagePut(LRLScreen^, LRLDecoration[ornament].Image[1].Data^, x2 * 10, i * 10, 0, 0, 319, 199); + end; +end; + + +procedure LRLRedrawLevel; +var + i, j: Integer; + s: string; +begin + ImageClear(LRLScreen^); + for i := 1 to 16 do for j := 1 to 30 do + with LRLLevel.Field[j, i] do + if ((Flags and 128) = 0) and ((Flags and 32) <> 0) and ((Flags and 16) = 0) then + ImagePut(LRLScreen^, LRLEnvironment[Image].Image[Count].Data^,j * 10, i * 10, 0, 0, 319, 199); + + for i := 1 to 10 do + with LRLLevel.Player[i] do + if Controller <> 0 then + ImagePutTransparent(LRLScreen^, LRLFigure[Colour, SpriteData].Image[Sprite].Data^,Position.x * 10 + Position.xoffs, Position.y * 10 + Position.yoffs, 0, 0, 319, 199); + + for i := 1 to 16 do for j := 1 to 30 do + with LRLLevel.Field[j, i] do + if ((Flags and 128) = 0) and ((Flags and 32) = 0) and ((Flags and 16) = 0) then + ImagePutTransparent(LRLScreen^, LRLEnvironment[Image].Image[LRLLevel.Field[j, i].Count].Data^, j * 10, i * 10, 0, 0, 319, 199); + + if not Paused then + begin + if ShowScore then + begin + STR(LRLScore, s); + ImageStringGet(s, LRLFont^, LRLFontBuffer^, 222); + ImagePut(LRLScreen^, LRLFontBuffer^, 56, 185, 0, 0, 319, 199); + ImageStringGet('Score: ', LRLFont^, LRLFontBuffer^, 254); + ImagePut(LRLScreen^, LRLFontBuffer^, 10, 185, 0, 0, 319, 199); + end; + if ShowLives then + begin + STR(LRLLives, s); + ImageStringGet(s, LRLFont^, LRLFontBuffer^, 222); + ImagePut(LRLScreen^, LRLFontBuffer^, 177, 185, 0, 0, 319, 199); + ImageStringGet('Lives: ', LRLFont^, LRLFontBuffer^, 254); + ImagePut(LRLScreen^, LRLFontBuffer^, 135, 185, 0, 0, 319, 199); + end; + if ShowLevel then + begin + Str(LRLCLevel, s); + ImageStringGet(s, LRLFont^, LRLFontBuffer^, 222); + ImagePut(LRLScreen^, LRLFontBuffer^, 292, 185, 0, 0, 319, 199); + ImageStringGet('Level: ', LRLFont^, LRLFontBuffer^, 254); + ImagePut(LRLScreen^, LRLFontBuffer^, 250, 185, 0, 0, 319, 199); + end; + end + else + begin + ImageStringGet('Game now paused', LRLFont^, LRLFontBuffer^, 254); + ImagePut(LRLScreen^, LRLFontBuffer^, 160 - ImageSizex(LRLFontBuffer^) div + 2, 185, 0, 0, 319, 199); + end; + LRLDrawOrnamental(0, 0, 31, 17, 1); +end; + + +procedure LRLStartSequence; +var + tmpScreen1: Pointer; + tmpScreen2: Pointer; + i: Integer; +begin + GetMem(tmpScreen1, 64000); + GetMem(tmpScreen2, 49000); + ImageFill(tmpScreen2^, 300, 160, 0); + LRLRedrawLevel; + i := 0; + while i < 100 do + begin + DataMove(LRLScreen^, tmpScreen1^, 64000, 0, 0); + ImagePut(tmpScreen1^, tmpScreen2^, 10, 10, 0, i, 319, 199 - i); + ScreenApply(tmpScreen1^); + Sleep(20); + i := i + 4; + end; + ScreenApply(LRLScreen^); + FreeMem(tmpScreen1, 64000); + FreeMem(tmpScreen2, 49000); +end; + + +procedure LRLEndSequence; +var + tmpScreen1: Pointer; + tmpScreen2: Pointer; + i: Integer; +begin + GetMem(tmpScreen1, 64000); + GetMem(tmpScreen2, 49000); + ImageFill(tmpScreen2^, 300, 160, 0); + LRLRedrawLevel; + i := 100; + while i > 0 do + begin + DataMove(LRLScreen^, tmpScreen1^, 64000, 0, 0); + ImagePut(tmpScreen1^, tmpScreen2^, 10, 10, 0, i, 319, 199 - i); + ScreenApply(tmpScreen1^); + Sleep(20); + i := i - 4; + end; + ImagePut(LRLScreen^, tmpScreen2^, 10, 10, 0, 0, 319, 199); + ScreenApply(LRLScreen^); + FreeMem(tmpScreen1, 64000); + FreeMem(tmpScreen2, 49000); +end; + + +{ +game result: +1 - zamurovali +2 - poimali +10 - vse zdelano +50 - no more levels +60 - no human players +100 - esc was pressed +} +procedure LRLUpdatePlayers; +var + i, j, k: Integer; + spd: Word; +begin + for i := 1 to 10 do + begin + with LRLLevel.Player[i] do + begin + if Controller <> 0 then + begin + if (LRLLevel.Field[Position.x, Position.y].Flags and 2 <> 0) then + begin + if i = 1 then + begin + EndOfGame := True; + GameResult := 1; + Exit; + end; + if Prizes <> 0 then + begin + Prizes := 0; + LRLLevel.Field[Position.x, Position.y - 1].Image := 4; + LRLLevel.Field[Position.x, Position.y - 1].Flags := BrickFlags[8]; + end; + repeat + Position.y := Random(2) + 1; + Position.x := Random(30) + 1; + until (LRLLevel.Field[Position.x, Position.y].Image = 1) or + (LRLLevel.Field[Position.x, Position.y].Image = 2) or + (LRLLevel.Field[Position.x, Position.y].Image = 3) or + (LRLLevel.Field[Position.x, Position.y].Image = 4); + Command := 10; + Continue; + end; + + if LRLLevel.Field[Position.x, Position.y].Image = 4 then + if Controller = 2 then + if Prizes = 0 then + begin + Inc(Prizes); + LRLLevel.Field[Position.x, Position.y].Image := 1; + LRLLevel.Field[Position.x, Position.y].Flags := BrickFlags[2]; + end else else + begin + Dec(TotalPrizes); + LRLScore := LRLScore + 100 * Longint(LRLCLevel); + LRLLevel.Field[Position.x, Position.y].Image := 1; + LRLLevel.Field[Position.x, Position.y].Flags := BrickFlags[2]; + end; + + if (i = 1) then + begin + if (TotalPrizes = 0) and (Position.y = 1) and + (LRLLevel.Field[Position.x, Position.y].Image = 2) then + begin + EndOfGame := True; + GameResult := 10; + Exit; + end; + for k := 2 to 10 do + if (LRLLevel.Player[k].Controller <> 0) then + if (LRLLevel.Player[k].Position.x = Position.x) and + (LRLLevel.Player[k].Position.y = Position.y) then + begin + EndOfGame := True; + GameResult := 2; + Exit; + end; + end; + if (LRLLevel.Field[Position.x, Position.y].Flags and 1 <> 0) then + begin + if (Controller = 2) then + begin + if Prizes <> 0 then + begin + Prizes := 0; + LRLLevel.Field[Position.x, Position.y - 1].Image := 4; + LRLLevel.Field[Position.x, Position.y - 1].Flags := BrickFlags[8]; + end; + end; + end; + if Controller = 2 then + spd := 2 + else + spd := 3; + + if (LRLLevel.Field[Position.x, Position.y + 1].Flags and 4 <> 0) and + (LRLLevel.Field[Position.x, Position.y].Image <> 3) and + ((LRLLevel.Field[Position.x, Position.y].Image <> 2) or + (LRLLevel.Field[Position.x, Position.y].Flags and 16 <> 0)) and + (Position.y < 16) then + begin + k := 2; + while k <= 10 do + if (k <> i) and (LRLLevel.Player[k].Controller <> 0) and + (LRLLevel.Player[k].Position.x = Position.x) and + (LRLLevel.Player[k].Position.y = Position.y + 1) and + (Position.y < 16) then + begin + k := 100; + Break; + end else + Inc(k); + + if k <> 100 then + begin + NewCommand := 5; + NewCommandWas := True; + end; + end; + + if NewCommandWas then + begin + if (NewCommand <> Command) and (Command <> 5) then + begin + Command := NewCommand; + Sprite := 1; + end; + NewCommandWas := False; + end; + + if (Command = 1) then + begin + if (LRLLevel.Field[Position.x, Position.y].Image = 3) then + begin + if Position.xoffs < 1 then + begin + if ((LRLLevel.Field[Position.x - 1, Position.y].Flags and 8 = 0) and + (LRLLevel.Field[Position.x - 1, Position.y].Image <> 3)) or + (LRLLevel.Field[Position.x, Position.y].Image <> 3) or (Position.x = 1) then + begin + Command := 10; + Position.xoffs := 0; + end; + end; + if (Command <> 10) and (SpriteData <> 6) then + begin + SpriteData := 6; + Sprite := 1; + end; + end else + begin + if Position.xoffs < 1 then + begin + if (LRLLevel.Field[Position.x - 1, Position.y].Flags and 8 = 0) or (Position.x = 1) then + begin + Command := 10; + Position.xoffs := 0; + end; + end; + if (Command <> 10) and (SpriteData <> 1) then SpriteData := 1; + end; + + if Command <> 10 then + begin + k := 1; + while (k > 0) do + begin + Inc(k); + if k = 11 then + begin + if (SpriteData = 6) then + begin + if (Sprite = 2) then Dec(Position.xoffs, 5) else + if (Sprite = 3) then Dec(Position.xoffs, 1); + end else + Dec(Position.xoffs, spd); + Break; + end; + if (k <> i) and (i <> 1) and + (LRLLevel.Player[k].Controller <> 0) and + (LRLLevel.Player[k].Position.x = Position.x - 1) and + (LRLLevel.Player[k].Position.y = Position.y) then + begin + Command := 10; + Break; + end; + end; + end; + end; + + if (Command = 2) then + begin + if (LRLLevel.Field[Position.x, Position.y].Image = 3) then + begin + if Position.xoffs > -1 then + begin + if ((LRLLevel.Field[Position.x + 1, Position.y].Flags and 8 = 0) and + (LRLLevel.Field[Position.x + 1, Position.y].Image <> 3)) or + (LRLLevel.Field[Position.x, Position.y].Image <> 3) or (Position.x = 30) then + begin + Command := 10; + Position.xoffs := 0; + end; + end; + if (Command <> 10) and (SpriteData <> 7) then + begin + SpriteData := 7; + Sprite := 1; + end; + end + else + begin + if Position.xoffs > -1 then + begin + if (LRLLevel.Field[Position.x + 1, Position.y].Flags and 8 = 0) or (Position.x = 30) then + begin + Command := 10; + Position.xoffs := 0; + end; + end; + if (Command <> 10) and (SpriteData <> 2) then + SpriteData := 2; + end; + if Command <> 10 then + begin + k := 1; + while (k > 0) do + begin + Inc(k); + if k = 11 then + begin + if (SpriteData = 7) then + begin + if (Sprite = 2) then + Inc(Position.xoffs, 5); + if (Sprite = 3) then + Inc(Position.xoffs, 1); + end + else + Inc(Position.xoffs, spd); + Break; + end; + if (k <> i) and (i <> 1) and (LRLLevel.Player[k].Controller <> 0) then + if (LRLLevel.Player[k].Position.x = Position.x + 1) and + (LRLLevel.Player[k].Position.y = Position.y) then + begin + Command := 10; + Break; + end; + end; + end; + end; + + if (Command = 3) then + begin + if Position.yoffs < 1 then + begin + if ((LRLLevel.Field[Position.x, Position.y].Image <> 2) or + (LRLLevel.Field[Position.x, Position.y].Flags and 16 <> 0)) or + ((LRLLevel.Field[Position.x, Position.y - 1].Flags and 4 = 0) and + ((LRLLevel.Field[Position.x, Position.y - 1].Image <> 2) or + (LRLLevel.Field[Position.x, Position.y - 1].Flags and 16 <> 0))) or + (Position.y < 2) then + begin + Command := 10; + Position.yoffs := 0; + end; + end; + if (Command <> 10) and (SpriteData <> 3) then + SpriteData := 3; + if Command <> 10 then + begin + k := 1; + while (k > 0) do + begin + Inc(k); + if k = 11 then + begin + Dec(Position.yoffs, spd); + Break; + end; + if (k <> i) and (i <> 1) and (LRLLevel.Player[k].Controller <> 0) then + if (LRLLevel.Player[k].Position.y = Position.y - 1) and + (LRLLevel.Player[k].Position.x = Position.x) then + begin + Command := 10; + Break; + end; + end; + end; + end; + + if (Command = 4) then + begin + if (LRLLevel.Field[Position.x, Position.y].Image = 3) and + ((LRLLevel.Field[Position.x, Position.y + 1].Image <> 2) or + (LRLLevel.Field[Position.x, Position.y + 1].Flags and 16 <> 0)) and + (Position.y < 16) then + begin + Command := 5; + Sprite := 1; + if (LRLLevel.Field[Position.x, Position.y + 1].Flags and 4 <> 0) then + Inc(Position.yoffs); + end + else + begin + if Position.yoffs > -1 then + begin + if (((LRLLevel.Field[Position.x, Position.y + 1].Image <> 2) or + (LRLLevel.Field[Position.x, Position.y + 1].Flags and 16 <> 0)) and + (LRLLevel.Field[Position.x, Position.y + 1].Flags and 4 = 0)) or + (Position.y = 16) then + begin + Command := 10; + Position.yoffs := 0; + end; + end; + if (Command <> 10) and (SpriteData <> 4) then + SpriteData := 4; + if Command <> 10 then + begin + k := 1; + while (k > 0) do + begin + Inc(k); + if k = 11 then + begin + Inc(Position.yoffs, spd); + Break; + end; + if (k <> i) and (i <> 1) and (LRLLevel.Player[k].Controller <> 0) then + if (LRLLevel.Player[k].Position.y = Position.y + 1) and + (LRLLevel.Player[k].Position.x = Position.x) then + begin + Command := 10; + Break; + end; + end; + end; + end; + end; + + if (Command = 5) then + begin + if Position.yoffs < 1 then + begin + if (LRLLevel.Field[Position.x, Position.y + 1].Flags and 4 = 0) or + (Position.y = 16) or (LRLLevel.Field[Position.x, Position.y].Image = 3) or + ((LRLLevel.Field[Position.x, Position.y].Flags and 1 <> 0) and (i <> 1)) then + begin + Command := 10; + if (LRLLevel.Field[Position.x, Position.y].Image = 3) then + SpriteData := 5; + Position.yoffs := 0; + Position.xoffs := 0; + end; + for k := 2 to 10 do + if (k <> i) and (LRLLevel.Player[k].Controller <> 0) then + if (LRLLevel.Player[k].Position.x = Position.x) and + (LRLLevel.Player[k].Position.y = Position.y + 1) and + (LRLLevel.Field[Position.x, Position.y + 1].Flags and 1 <> 0) and + (Position.y < 16) then + begin + Command := 10; + Position.yoffs := 0; + Break; + end; + end; + if (Command <> 10) and (SpriteData <> 5) then + begin + SpriteData := 5; + Sprite := 1; + end; + if Command <> 10 then + begin + Inc(Position.yoffs, 2); + end; + end; + + if (Command = 6) then + begin + if (Position.y < 16) and (Position.x > 1) and + (LRLLevel.Field[Position.x - 1, Position.y + 1].Image = 9) and + (LRLLevel.Field[Position.x - 1, Position.y + 1].Flags and 1 = 0) and + (((LRLLevel.Field[Position.x - 1, Position.y].Image = 1) or + (LRLLevel.Field[Position.x - 1, Position.y].Flags and 1 <> 0)) or + (LRLLevel.Field[Position.x - 1, Position.y].Flags and 16 <> 0)) then + begin + NewCommandWas := True; + for k := 2 to 10 do + if (k <> i) and (LRLLevel.Player[k].Controller <> 0) then + if (LRLLevel.Player[k].Position.x = Position.x - 1) and + (LRLLevel.Player[k].Position.y = Position.y) then + begin + NewCommandWas := False; + Break; + end; + if NewCommandWas then + begin + LRLLevel.Field[Position.x - 1, Position.y + 1].Flags := + LRLLevel.Field[Position.x - 1, Position.y + 1].Flags or 1; + Position.xoffs := 0; + SpriteData := 8; + NewCommandWas := False; + end; + end; + Command := 10; + end; + + if (Command = 7) then + begin + if (Position.y < 16) and (Position.x < 30) and + (LRLLevel.Field[Position.x + 1, Position.y + 1].Image = 9) and + (LRLLevel.Field[Position.x + 1, Position.y + 1].Flags and 1 = 0) and + (((LRLLevel.Field[Position.x + 1, Position.y].Image = 1) or + (LRLLevel.Field[Position.x + 1, Position.y].Flags and 1 <> 0)) or + (LRLLevel.Field[Position.x + 1, Position.y].Flags and 16 <> 0)) then + begin + NewCommandWas := True; + for k := 2 to 10 do + if (k <> i) and (LRLLevel.Player[k].Controller <> 0) then + if (LRLLevel.Player[k].Position.x = Position.x + 1) and + (LRLLevel.Player[k].Position.y = Position.y) then + begin + NewCommandWas := False; + Break; + end; + if NewCommandWas then + begin + LRLLevel.Field[Position.x + 1, Position.y + 1].Flags := + LRLLevel.Field[Position.x + 1, Position.y + 1].Flags or 1; + Position.xoffs := 0; + SpriteData := 9; + NewCommandWas := False; + end; + end; + Command := 10; + end; + + if (Command = 1) or (Command = 2) then + if Position.yoffs < 0 then Inc(Position.yoffs) else + if Position.yoffs > 0 then Dec(Position.yoffs); + + if (Command = 3) or (Command = 4) or (Command = 5) then + if Position.xoffs < 0 then Inc(Position.xoffs) else + if Position.xoffs > 0 then Dec(Position.xoffs); + + if Command < 6 then + begin + Inc(Sprite); + if Sprite > LRLFigure[Colour, SpriteData].ImageCount then Sprite := 1; + if Position.xoffs < -4 then + begin + Dec(Position.x); + Position.xoffs := 10 + Position.xoffs; + end; + if Position.xoffs > 5 then + begin + Inc(Position.x); + Position.xoffs := Position.xoffs - 10; + end; + if Position.yoffs < -4 then + begin + Dec(Position.y); + Position.yoffs := 10 + Position.yoffs; + end; + if Position.yoffs > 5 then + begin + Inc(Position.y); + Position.yoffs := Position.yoffs - 10; + end; + end; + end; + end; + end; +end; + + +procedure LRLUpdateBricks; +var + i, j, k: Integer; +begin + for i := 1 to 16 do + for j := 1 to 30 do + begin + if LRLLevel.Field[j, i].Flags and 1 <> 0 then + begin + if LRLLevel.Field[j, i].Count = 1 then + begin + LRLLevel.Field[j, i].Flags := LRLLevel.Field[j, i].Flags and $FF - 2; + LRLLevel.Field[j, i].Flags := LRLLevel.Field[j, i].Flags or 4 + 8; + end; + if LRLLevel.Field[j, i].IdleCount = 0 then + begin + Inc(LRLLevel.Field[j, i].Count); + if LRLLevel.Field[j, i].Count < 6 then + begin + for k := 2 to 10 do + if (LRLLevel.Player[k].Controller <> 0) then + if (LRLLevel.Player[k].Position.x = j) and + (LRLLevel.Player[k].Position.y = i - 1) then + begin + LRLLevel.Field[j, i].Count := 13 - LRLLevel.Field[j, i].Count; + LRLLevel.Field[j, i].Flags := LRLLevel.Field[j, i].Flags or 2; + LRLLevel.Field[j, i].Flags := LRLLevel.Field[j, i].Flags and $FE - 4 - 8; + LRLLevel.Field[j, i].Count := 1; + Break; + end; + end; + if LRLLevel.Field[j, i].Count = 6 then + begin + LRLLevel.Field[j, i].IdleCount := 100; + end; + end + else + Dec(LRLLevel.Field[j, i].IdleCount); + if LRLLevel.Field[j, i].Count = 12 then + begin + LRLLevel.Field[j, i].Flags := LRLLevel.Field[j, i].Flags or 2; + LRLLevel.Field[j, i].Flags := LRLLevel.Field[j, i].Flags and $FE - 4 - 8; + LRLLevel.Field[j, i].Count := 1; + end; + end; + end; +end; + + +procedure LRLComputerPlayer; +var + k, l, m, f1, f2, i, j: Integer; +begin + if ComputerTurn >= ComputerReaction then + begin + ComputerTurn := 0; + for k := 1 to 10 do + begin + with LRLLevel.Player[k] do + begin + if Controller = 2 then + begin + NewCommandWas := True; + NewCommand := 10; + if (Position.y > LRLLevel.Player[1].Position.y) then + begin + if ((LRLLevel.Field[Position.x, Position.y].Image = 2) and + (LRLLevel.Field[Position.x, Position.y].Flags and 16 = 0) and + ((LRLLevel.Field[Position.x, Position.y - 1].Image = 2) or + (LRLLevel.Field[Position.x, Position.y - 1].Flags and 4 <> 0)) and + (Position.y > 1)) then + begin + NewCommand := 3; + end + else + begin + m := 1; + l := Position.x; + i := 1; + while i <> 0 do + begin + l := l + i; + if ((LRLLevel.Field[l, Position.y].Image = 2) and + (LRLLevel.Field[l, Position.y].Flags and 16 = 0)) and + ((LRLLevel.Field[l, Position.y - 1].Image = 2) and + (LRLLevel.Field[l, Position.y - 1].Flags and 16 = 0)) and (Position.y <> 1) then + begin + if m = 0 then + begin + f2 := Position.x - l; + Break; + end; + m := 0; + i := not i + 1; + f1 := l - Position.x; + l := Position.x; + end + else + if (LRLLevel.Field[l, Position.y].Flags and 8 = 0) or (l > 30) or (l < 1) then + begin + if m = 0 then + begin + f2 := 100; + Break; + end; + m := 0; + i := not i + 1; + l := Position.x; + f1 := 100; + end; + end; + if (f1 = 100) and (f2 = 100) then + NewCommand := 10 + else + begin + if f1 > f2 then + NewCommand := 1 + else + NewCommand := 2; + end; + end; + end + else + if (Position.y < LRLLevel.Player[1].Position.y) then + begin + if (((LRLLevel.Field[Position.x, Position.y + 1].Image = 2) and + (LRLLevel.Field[Position.x, Position.y + 1].Flags and 16 = 0)) or + (LRLLevel.Field[Position.x, Position.y + 1].Flags and 4 <> 0)) and + (Position.y < 16) and (LRLLevel.Field[Position.x, Position.y + 1].Flags and 1 = 0) then + begin + NewCommand := 4; + end + else + begin + m := 1; + l := Position.x; + i := 1; + while i <> 0 do + begin + l := l + i; + if ((LRLLevel.Field[l, Position.y + 1].Image = 2) and + (LRLLevel.Field[l, Position.y + 1].Flags and 16 = 0)) or + ((LRLLevel.Field[l, Position.y + 1].Flags and 4 <> 0) and + (LRLLevel.Field[l, Position.y + 1].Flags and 1 = 0)) then + begin + if m = 0 then + begin + f2 := Position.x - l; + Break; + end; + m := 0; + i := not i + 1; + f1 := l - Position.x; + l := Position.x; + end + else + if (LRLLevel.Field[l, Position.y].Flags and 8 = 0) or (l > 30) or (l < 1) then + begin + if m = 0 then + begin + f2 := 100; + Break; + end; + m := 0; + i := not i + 1; + l := Position.x; + f1 := 100; + end; + end; + if (f1 = 100) and (f2 = 100) then + NewCommand := 10 + else + begin + if f1 > f2 then + NewCommand := 1 + else + NewCommand := 2; + end; + end; + end + else + begin + if (Position.x > LRLLevel.Player[1].Position.x) then + NewCommand := 1; + if (Position.x < LRLLevel.Player[1].Position.x) then + NewCommand := 2; + end; + end; + end; + end; + end + else + Inc(ComputerTurn); +end; + + +function LRLPlayLevel(Number: Byte): Word; +var + Keypress: Word; + i: Word; + L, C: Longword; +begin + Randomize; + ComputerReaction := 1; + LRLLoadLevel(Number); + + if LRLCLevel <> Number then + begin + GameResult := 50; + Exit; + end; + if LRLLevel.Player[1].Controller <> 1 then + begin + GameResult := 60; + Exit; + end; + + TimeToRefresh := True; + GameStarted := False; + GameResult := 0; + Paused := False; + EndOfGame := False; + + LRLStartSequence; + + Keypress := 0; + L := 0; + + repeat + C := LastDosTick(); + if L <> C then + begin + L := C; + if GameStarted and not Paused then + begin + LRLComputerPlayer; + LRLUpdatePlayers; + LRLUpdateBricks; + end; + LRLRedrawLevel; + ScreenApply(LRLScreen^); + end else + Sleep(20); + + if Keypressed then + begin + Keypress := ReadKey; + GameStarted := True; + Paused := False; + + for i := 0 to ControlNumber - 1 do + if KeyboardControls[i * 3 + 1] = Keypress then + begin + LRLLevel.Player[KeyboardControls[i * 3 + 2]].NewCommand := KeyboardControls[i * 3 + 3]; + LRLLevel.Player[KeyboardControls[i * 3 + 2]].NewCommandWas := True; + end; + + if (Keypress = $50) or (Keypress = $70) then + Paused := True; + end; + until (Keypress = $1B) or EndOfGame; + + if EndOfGame then + LRLEndSequence else + GameResult := 100; +end; + +end. diff --git a/programs/games/lrl/LRLMainMenu.pp b/programs/games/lrl/LRLMainMenu.pp new file mode 100644 index 0000000000..ff24e4aa13 --- /dev/null +++ b/programs/games/lrl/LRLMainMenu.pp @@ -0,0 +1,116 @@ +unit LRLMainMenu; + + +interface + + +uses + LRLRoutines, LRLSprites; + + +procedure LRLSelectItem(var Item: Word); + + +implementation + + +var + MainScreen: Pointer; + Selection: array[1..4] of Pointer; + SelectionDark: array[1..4] of Pointer; + SelectionSize: array[1..4] of Word; + SelectionDarkSize: array[1..4] of Word; + + +procedure LoadData; +var + size, j: Word; + i: Integer; +begin + GetMem(MainScreen, 64004); + Seek(ImageFile, LRLImagesFilePosition + 7940); + BlockRead(ImageFile, MainScreen^, 64004, j); + for i := 1 to 4 do + begin + BlockRead(ImageFile, SelectionSize[i], 2, j); + GetMem(Selection[i], SelectionSize[i]); + BlockRead(ImageFile, Selection[i]^, SelectionSize[i], j); + BlockRead(ImageFile, SelectionDarkSize[i], 2, j); + GetMem(SelectionDark[i], SelectionDarkSize[i]); + BlockRead(ImageFile, SelectionDark[i]^, SelectionDarkSize[i], j); + end; +end; + + +procedure DisposeData; +var + i: Integer; +begin + FreeMem(MainScreen, 64004); + for i := 1 to 4 do + begin + FreeMem(Selection[i], SelectionSize[i]); + FreeMem(SelectionDark[i], SelectionDarkSize[i]); + end; +end; + + +procedure LRLSelectItem(var Item: Word); +var + Keypress: Word; + RedrawAll: Boolean; + NeedToFade: Boolean; + p: Pointer; + i: Integer; +begin + GetMem(p, 768); + DataFill(p^, 768, 0, 0); + Palette256Set(p^); + FreeMem(p, 768); + LoadData; + NeedToFade := True; + ImagePut(LRLScreen^, MainScreen^, 0, 0, 0, 0, 319, 199); + RedrawAll := True; + KeyboardFlush; + + repeat + if RedrawAll then + begin + for i := 1 to 4 do + if i = Item then + ImagePutTransparent(LRLScreen^, Selection[i]^, 63, 66 + (i - 1) * 30, 0, 0, 319, 199) else + ImagePutTransparent(LRLScreen^, SelectionDark[i]^, 63, 66 + (i - 1) * 30, 0, 0, 319, 199); + + ScreenApply(LRLScreen^); + + if NeedToFade then + begin + FadeTo(LRLMenuPalette); + NeedToFade := False; + end; + + RedrawAll := False; + end; + + Keypress := ReadKey; + + if (Keypress = $B1) and (Item < 4) then + begin + Inc(Item); + RedrawAll := True; + end; + if (Keypress = $B2) and (Item > 1) then + begin + Dec(Item); + RedrawAll := True; + end; + until Keypress = $0D; + + FadeClear; + ImageClear(LRLScreen^); + ScreenApply(LRLScreen^); + DisposeData; +end; + + +end. diff --git a/programs/games/lrl/LRLRoutines.pp b/programs/games/lrl/LRLRoutines.pp new file mode 100644 index 0000000000..92c513fe74 --- /dev/null +++ b/programs/games/lrl/LRLRoutines.pp @@ -0,0 +1,499 @@ +unit LRLRoutines; + +{$mode objfpc} +{$asmmode intel} + + +interface + + +procedure ImagePut(var Screen, ImageBuffer; X, Y: Integer; Winx1, Winy1, Winx2, Winy2: Word); +procedure ImagePutTransparent(var Screen, ImageBuffer; X, Y: Integer; Winx1, Winy1, Winx2, Winy2: Word); +procedure ImageFill(var ImageBuffer; SizeX, SizeY: Word; Value: Byte); +function ImageSizeX(var ImageBuffer): Word; +function ImageSizeY(var ImageBuffer): Word; +procedure ImageStringGet(Source: String; var FontData, Buffer; ColorOffs: Byte); +procedure ScreenApply(var Buffer); +procedure ImageClear(var Buffer); + +procedure Palette256Set(var Palette256); +procedure Palette256Get(var Palette256); +procedure Palette256Grayscale(var Palette256; StartElement, EndElement: Byte); +procedure Palette256Darken(var Palette256; StartElement, EndElement, Decrement, MinValue: Byte); +procedure Palette256Transform(var SourcePalette, DestinationPalette); +function DataByteGet(var Buffer; BufferOffset: Word): Byte; +procedure DataBytePut(var Buffer; BufferOffset: Word; Value: Byte); +function DataWordGet(var Buffer; BufferOffset: Word): Word; +procedure DataWordPut(var Buffer; BufferOffset: Word; Value: Word); +procedure DataMove(var Source, Destination; Count: Word; SourceOffset, DestinationOffset: Word); +procedure DataAdd(var Buffer; Count: Word; Amount: Byte; BufferOffset: Word); +procedure DataFill(var Buffer; Count: Word; Value: Byte; BufferOffset: Word); +function DataIdentical(var Array1, Array2; Count: Word; Array1Offset, Array2Offset: Word): Boolean; +function ReadKey: Word; +function Keypressed: Boolean; +function SetInterrupt(Int: Byte; NewAddress: Pointer): Pointer; +procedure FadeClear; +procedure FadeTo(pal: Pointer); +procedure DecompressRepByte(var InArray, OutArray; InArraySize: Word; var OutArraySize: Word); +function MSMouseInArea(x1, y1, x2, y2: Integer): Boolean; +function MSMouseDriverExist: Boolean; +procedure MSMouseGetXY(var x, y: Integer); +function MSMouseButtonStatusGet: Word; +function MSMouseButtonWasPressed(Button: Word; var x, y: Integer): Boolean; +function MSMouseButtonWasReleased(Button: Word; var x, y: Integer): Boolean; +procedure MSMouseSetXY(x, y: Integer); +procedure KeyboardFlush; +function GetInterrupt(Int: Byte): Pointer; + +procedure AssignFile(var AFile: File; AFileName: String); +function LastDosTick(): Longword; + + +implementation + + +uses + SysUtils; + + +const + SCREEN_WIDTH = 320; + SCREEN_HEIGHT = 200; + +type + PRGBColor = ^TRGBColor; + TRGBColor = packed record + R, G, B: Byte; + end; + + PRGBPalette = ^TRGBPalette; + TRGBPalette = array[Byte] of TRGBColor; + +var + ScreenRGBPalette: TRGBPalette; + ScreenRGBBuffer : array[0..SCREEN_HEIGHT - 1, 0..SCREEN_WIDTH - 1] of TRGBColor; + ScreenBuffer : array[0..SCREEN_WIDTH * SCREEN_HEIGHT - 1] of Byte; + + AlreadyKeyPressed: Boolean = False; + + +procedure Paint; +begin + kos_begindraw(); + kos_definewindow(500, 100, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, $01000000); + kos_drawimage24(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, @ScreenRGBBuffer); + kos_enddraw(); +end; + +procedure UpdateRGBBuffer; +var + I, J: Longint; + B: PByte; +begin + B := @ScreenBuffer; + for I := 0 to SCREEN_HEIGHT - 1 do + for J := 0 to SCREEN_WIDTH - 1 do + begin + ScreenRGBBuffer[I, J] := ScreenRGBPalette[B^]; + Inc(B); + end; + Paint; +end; + + +procedure ImagePut(var Screen, ImageBuffer; X, Y: Integer; WinX1, WinY1, WinX2, WinY2: Word); +var + Width, Height: Word; + I, J, K: Integer; + P: Pointer; +begin + Width := PWord(@ImageBuffer)[0]; + Height := PWord(@ImageBuffer)[1]; + + P := @ImageBuffer + 4; + for I := Y to Y + Height - 1 do + begin + if (I >= 0) and (I < SCREEN_HEIGHT) and (I >= WinY1) and (I <= WinY2) then + begin + if X < WinX1 then + J := WinX1 - X else + J := 0; + K := Width - J; + if WinX1 + K - 1 > WinX2 then + K := WinX2 - WinX1 + 1; + Move((P + J)^, (@Screen + I * SCREEN_WIDTH + X + J)^, K); + end; + Inc(P, Width); + end; +end; + +procedure ImagePutTransparent(var Screen, ImageBuffer; X, Y: Integer; Winx1, Winy1, Winx2, Winy2: Word); +begin + ImagePut(Screen, ImageBuffer, X, Y, Winx1, Winy1, Winx2, Winy2); +end; + +procedure ImageFill(var ImageBuffer; SizeX, SizeY: Word; Value: Byte); +begin + PWord(@ImageBuffer)^ := SizeX; + PWord(@ImageBuffer + 2)^ := SizeY; + FillChar((@ImageBuffer + 4)^, SizeX * SizeY, Value); +end; + +function ImageSizeX(var ImageBuffer): Word; +begin + Result := PWord(@ImageBuffer)^; +end; + +function ImageSizeY(var ImageBuffer): Word; +begin + Result := PWord(@ImageBuffer + 2)^; +end; + +procedure ImageStringGet(Source: String; var FontData, Buffer; ColorOffs: Byte); +var + Width, Height: Word; + Table: PWord; + P, B: PByte; + X, I, J, K, C: Word; +begin + Height := PWord(@FontData + 2)^; + Table := PWord(@FontData + 4); + + { расчет длины строки } + Width := 0; + for I := 1 to Length(Source) do + begin + P := @Table[Ord(Source[I])]; + Inc(Width, PWord(P + PWord(P)^)^); + end; + + PWord(@Buffer)^ := Width; + PWord(@Buffer + 2)^ := Height; + + { вывод строки } + X := 0; + for I := 1 to Length(Source) do + begin + P := @Table[Ord(Source[I])]; + B := PByte(P + PWord(P)^); + C := PWord(B)^; + Inc(B, 2); + + P := PByte(@Buffer + 4 + X); + for K := 0 to Height - 1 do + begin + for J := 0 to C - 1 do + begin + if B^ = 0 then + P^ := 0 else + P^ := B^ + ColorOffs; + Inc(P); + Inc(B); + end; + Inc(P, Width - C); + end; + + Inc(X, C); + end; +end; + +procedure ScreenApply(var Buffer); +begin + Move(Buffer, ScreenBuffer, SizeOf(ScreenBuffer)); + UpdateRGBBuffer; +end; + + +procedure ImageClear(var Buffer); +begin + FillChar(Buffer, SCREEN_WIDTH * SCREEN_HEIGHT, 0); +end; + + +procedure Palette256Set(var Palette256); +var + I: Longint; + P: PRGBColor; +begin + P := @Palette256; + for I := 0 to 255 do + with ScreenRGBPalette[I] do + begin + R := Round(P^.B / 63 * 255); + G := Round(P^.G / 63 * 255); + B := Round(P^.R / 63 * 255); + Inc(P); + end; + UpdateRGBBuffer; +end; + +procedure Palette256Get(var Palette256); +var + I: Longint; + P: PRGBColor; +begin + P := @Palette256; + for I := 0 to 255 do + with ScreenRGBPalette[I] do + begin + P^.R := Round(B / 255 * 63); + P^.G := Round(G / 255 * 63); + P^.B := Round(R / 255 * 63); + Inc(P); + end; +end; + +procedure Palette256Grayscale(var Palette256; StartElement, EndElement: Byte); +begin +end; + +procedure Palette256Darken(var Palette256; StartElement, EndElement, Decrement, MinValue: Byte); +begin +end; + +procedure Palette256Transform(var SourcePalette, DestinationPalette); +var + I: Longint; + S, D: PByte; +begin + S := @SourcePalette; + D := @DestinationPalette; + for I := 0 to 767 do + begin + if S^ < D^ then Inc(S^) else + if S^ > D^ then Dec(S^); + Inc(S); + Inc(D); + end; +end; + +function DataByteGet(var Buffer; BufferOffset: Word): Byte; +begin + Result := PByte(@Buffer + BufferOffset)^; +end; + +procedure DataBytePut(var Buffer; BufferOffset: Word; Value: Byte); +begin + PByte(@Buffer + BufferOffset)^ := Value; +end; + +function DataWordGet(var Buffer; BufferOffset: Word): Word; +begin + Result := PWord(@Buffer + BufferOffset)^; +end; + +procedure DataWordPut(var Buffer; BufferOffset: Word; Value: Word); +begin + PWord(@Buffer + BufferOffset)^ := Value; +end; + +procedure DataMove(var Source, Destination; Count: Word; SourceOffset, DestinationOffset: Word); +begin + Move((@Source + SourceOffset)^, (@Destination + DestinationOffset)^, Count); +end; + +procedure DataFill(var Buffer; Count: Word; Value: Byte; BufferOffset: Word); +begin + FillChar((@Buffer + BufferOffset)^, Count, Value); +end; + +function DataIdentical(var Array1, Array2; Count: Word; Array1Offset, Array2Offset: Word): Boolean; +begin + Result := CompareByte((@Array1 + Array1Offset)^, (@Array2 + Array2Offset)^, Count) = 0; +end; + +procedure DataAdd(var Buffer; Count: Word; Amount: Byte; BufferOffset: Word); +var + I: Word; +begin + for I := 0 to Count do + Inc(PByte(@Buffer + BufferOffset + I)^, Amount); + {if >0 then += amount} +end; + +function ReadKey: Word; +var + Event: Word; +begin + if not AlreadyKeyPressed then + begin + kos_maskevents(ME_PAINT or ME_KEYBOARD); + repeat + Event := kos_getevent(); + if Event = SE_PAINT then Paint; + until Event = SE_KEYBOARD; + end; + Result := kos_getkey() shr 8; + AlreadyKeyPressed := False; + {WriteLn('ReadKey -> ', IntToHex(Result, 2));} +end; + +function Keypressed: Boolean; +begin + if AlreadyKeyPressed then + Result := True else + begin + kos_maskevents(ME_KEYBOARD); + Result := kos_getevent(False) = SE_KEYBOARD; + AlreadyKeyPressed := Result; + end; +end; + +procedure KeyboardFlush; +var + Event: Word; +begin + kos_maskevents(ME_KEYBOARD); + repeat + Event := kos_getevent(False); + if Event = SE_KEYBOARD then kos_getkey(); + until Event = 0; + AlreadyKeyPressed := False; +end; + +function SetInterrupt(Int: Byte; NewAddress: Pointer): Pointer; +begin + Result := nil; +end; + +procedure FadeClear; +var + Pal1, Pal2: Pointer; + i: Integer; +begin + GetMem(Pal1, 768); + GetMem(Pal2, 768); + Palette256Get(Pal1^); + for i := 0 to 32 do + begin + DataMove(Pal1^, Pal2^, 768, 0, 0); + Palette256Darken(Pal2^, 0, 255, i * 2, 0); + Palette256Set(Pal2^); + end; + FreeMem(Pal1, 768); + FreeMem(Pal2, 768); +end; + +procedure FadeTo(Pal: Pointer); +var + Pal1: Pointer; + I: Integer; +begin + GetMem(Pal1, 768); + Palette256Get(Pal1^); + for I := 0 to 63 do + begin + Palette256Transform(Pal1^, Pal^); + Palette256Set(Pal1^); + kos_delay(1); + end; + FreeMem(Pal1, 768); +end; + +procedure DecompressRepByte(var InArray, OutArray; InArraySize: Word; var OutArraySize: Word); +begin +{asm + PUSH DS + + xor DX,DX + xor AX,AX + + LDS SI,InArray + LES DI,OutArray + + MOV CX,InArraySize + JCXZ @Done + + @Loop1: + LODSB + CMP AL,0 + JE @VsePonyatno + CMP AL,4 + JB @MensheTreh + + INC DX + STOSB + JMP @DoLoop + + @MensheTreh: + SUB CX,1 + MOV BX,CX + + MOV CX,AX + ADD DX,AX + LODSB + REP STOSB + + MOV CX,BX + JMP @DoLoop + + @VsePonyatno: + LODSB + SUB CX,2 + MOV BX,CX + MOV CX,AX + ADD DX,AX + LODSB + REP STOSB + MOV CX,BX + + @DoLoop: + JCXZ @Done + LOOP @Loop1 + + @Done: + LES DI,OutArraySize + MOV[ES:DI],DX + POP DS} +end; + +function MSMouseInArea(x1, y1, x2, y2: Integer): Boolean; +begin + Result := False; +end; + +function MSMouseDriverExist: Boolean; +begin + Result := True; +end; + +procedure MSMouseGetXY(var x, y: Integer); +begin +end; + +function MSMouseButtonStatusGet: Word; +begin + Result := 0; +end; + +function MSMouseButtonWasPressed(Button: Word; var x, y: Integer): Boolean; +begin + Result := False; +end; + +function MSMouseButtonWasReleased(Button: Word; var x, y: Integer): Boolean; +begin + Result := False; +end; + +procedure MSMouseSetXY(x, y: Integer); +begin +end; + +function GetInterrupt(Int: Byte): Pointer; +begin + Result := nil; +end; + +procedure AssignFile(var AFile: File; AFileName: String); +begin + Assign(AFile, IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + AFileName); +end; + +function LastDosTick(): Longword; +begin + Result := Round(kos_timecounter() * 0.182); +end; + + +end. diff --git a/programs/games/lrl/LRLSprites.pp b/programs/games/lrl/LRLSprites.pp new file mode 100644 index 0000000000..706935e529 --- /dev/null +++ b/programs/games/lrl/LRLSprites.pp @@ -0,0 +1,255 @@ +unit LRLSprites; + +{$mode objfpc} +{$i-} + + +interface + + +uses + SysUtils, + LRLRoutines; + +{ + all coordinates in standard style: + 0 + + 0 +----------> x + | + | + | + | + + v + + y +} + +type + TLRLImage = packed record + Data: Pointer; { standard 256-colour image data } + Size: Word; { size of image (for destruction) } + end; + + PLRLSprite = ^TLRLSprite; + + TLRLSprite = packed record + Image: array[1..12] of TLRLImage; { moving image } + ImageCount: Byte; { how many images there } + end; + + +type + TButton = packed record + Lit: Boolean; + DarkIcon: Pointer; + LightIcon: Pointer; + DarkIconSize: Word; + LightIconSize: Word; + x1, y1: Integer; + x2, y2: Integer; + Command: Word; + end; + + +var + ImageFile: File; + LRLEnvironment: array[1..20] of TLRLSprite; + LRLFigure: array[1..4, 1..9] of TLRLSprite; + LRLDecoration: array[1..1] of TLRLSprite; + LRLPalette: Pointer; + LRLScreen: Pointer; + LRLMenuPalette: Pointer; + LRLLogo: Pointer; + LRLFont: Pointer; + LRLFontBuffer: Pointer; + LRLMousePointer: Pointer; + LRLImagesFilePosition: longint; + LRLEditorButton: array[1..6] of TButton; + + +procedure ImagesInitialize; +procedure ImagesDeinitialize; + + +implementation + + +const + ImageFileName = 'LRL.IMG'; + ImageFileHeader: ShortString = 'Lode Runner Live Images'#26; + + ERR_OPENFILE = 'Невозможно открыть файл картинок'; + ERR_BADFILE = 'Неверный или поврежденный файл картинок'; + + +procedure LoadImages; +var + InBuffer: Pointer; + i, j, k, l, x, y: Word; + a, b, c: Byte; +begin + GetMem(InBuffer, $FFF0); + + AssignFile(ImageFile, ImageFileName); + Reset(ImageFile, 1); + if IOResult <> 0 then + raise Exception.Create(ERR_OPENFILE); + + BlockRead(ImageFile, InBuffer^, 24, k); + if (IOResult <> 0) or not DataIdentical(InBuffer^, ImageFileHeader[1], 24, 0, 0) then + raise Exception.Create(ERR_BADFILE); + + { load palette } + GetMem(LRLPalette, 768); + BlockRead(ImageFile, LRLPalette^, 768, k); + + { figures loading loop } + for i := 1 to 9 do + begin + BlockRead(ImageFile, a, 1, k); + LRLFigure[1, i].ImageCount := a; + for j := 1 to a do + begin + GetMem(LRLFigure[1, i].Image[j].Data, 104); + BlockRead(ImageFile, LRLFigure[1, i].Image[j].Data^, 104, k); + x := DataWordGet(LRLFigure[1, i].Image[j].Data^, 0); + y := DataWordGet(LRLFigure[1, i].Image[j].Data^, 2); + LRLFigure[1, i].Image[j].Size := x * y + 4; + for l := 2 to 4 do + begin + LRLFigure[l, i].Image[j].Size := LRLFigure[1, i].Image[j].Size; + LRLFigure[l, i].ImageCount := a; + GetMem(LRLFigure[l, i].Image[j].Data, LRLFigure[l, i].Image[j].Size); + DataMove(LRLFigure[1, i].Image[j].Data^, LRLFigure[l, i].Image[j].Data^, LRLFigure[l, i].Image[j].Size, 0, 0); + DataAdd(LRLFigure[l, i].Image[j].Data^, LRLFigure[l, i].Image[j].Size, (l - 1) shl 5, 4); + end; + end; + end; + + { decoration loading loop } + for i := 1 to 1 do + begin + BlockRead(ImageFile, a, 1, k); + LRLDecoration[i].ImageCount := a; + for j := 1 to a do + begin + GetMem(LRLDecoration[i].Image[j].Data, 104); + BlockRead(ImageFile, LRLDecoration[i].Image[j].Data^, 104, k); + x := DataWordGet(LRLDecoration[i].Image[j].Data^, 0); + y := DataWordGet(LRLDecoration[i].Image[j].Data^, 2); + LRLDecoration[i].Image[j].Size := x * y + 4; + end; + end; + + { environment loading loop } + for i := 1 to 9 do + begin + BlockRead(ImageFile, a, 1, k); + LRLEnvironment[i].ImageCount := a; + for j := 1 to a do + begin + GetMem(LRLEnvironment[i].Image[j].Data, 104); + BlockRead(ImageFile, LRLEnvironment[i].Image[j].Data^, 104, k); + x := DataWordGet(LRLEnvironment[i].Image[j].Data^, 0); + y := DataWordGet(LRLEnvironment[i].Image[j].Data^, 2); + LRLEnvironment[i].Image[j].Size := x * y + 4; + end; + end; + + y := 181; + x := 212; + + for i := 1 to 6 do + begin + if i = 4 then + begin + y := 191; + x := 212; + end; + + LRLEditorButton[i].x1 := x; + LRLEditorButton[i].y1 := y; + LRLEditorButton[i].x2 := x + 32; + LRLEditorButton[i].y2 := y + 9; + LRLEditorButton[i].Lit := False; + LRLEditorButton[i].Command := i; + LRLEditorButton[i].DarkIconSize := 292; + LRLEditorButton[i].LightIconSize := 292; + + GetMem(LRLEditorButton[i].DarkIcon, LRLEditorButton[i].DarkIconSize); + GetMem(LRLEditorButton[i].LightIcon, LRLEditorButton[i].LightIconSize); + BlockRead(ImageFile, LRLEditorButton[i].LightIcon^, 292, l); + BlockRead(ImageFile, LRLEditorButton[i].DarkIcon^, 292, l); + + Inc(x, 33); + end; + + { load font } + GetMem(LRLFont, 20455); + BlockRead(ImageFile, LRLFont^, 20455, k); + + { load Pointer } + GetMem(LRLMousePointer, 174); + BlockRead(ImageFile, LRLMousePointer^, 174, k); + + { load palette } + GetMem(LRLMenuPalette, 768); + BlockRead(ImageFile, LRLMenuPalette^, 768, k); + + { load logo } + GetMem(LRLLogo, 12524); + BlockRead(ImageFile, LRLLogo^, 12524, k); + + LRLImagesFilePosition := FilePos(ImageFile); + FreeMem(InBuffer, $FFF0); +end; + + +procedure ImagesInitialize; +begin + LoadImages; + GetMem(LRLScreen, 64000); + GetMem(LRLFontBuffer, 32000); +end; + + +procedure ImagesDeinitialize; +var + i, j, l: Integer; +begin + FreeMem(LRLPalette, 768); + + for i := 1 to 9 do + for j := 1 to LRLFigure[1, i].ImageCount do + begin + FreeMem(LRLFigure[1, i].Image[j].Data, 104); + for l := 2 to 4 do + FreeMem(LRLFigure[l, i].Image[j].Data, LRLFigure[l, i].Image[j].Size); + end; + + for i := 1 to 1 do + for j := 1 to LRLDecoration[i].ImageCount do + FreeMem(LRLDecoration[i].Image[j].Data, 104); + + for i := 1 to 9 do + for j := 1 to LRLEnvironment[i].ImageCount do + FreeMem(LRLEnvironment[i].Image[j].Data, 104); + + for i := 1 to 6 do + begin + FreeMem(LRLEditorButton[i].DarkIcon, LRLEditorButton[i].DarkIconSize); + FreeMem(LRLEditorButton[i].LightIcon, LRLEditorButton[i].LightIconSize); + end; + + FreeMem(LRLFont, 20455); + FreeMem(LRLMousePointer, 174); + FreeMem(LRLMenuPalette, 768); + FreeMem(LRLLogo, 12524); + FreeMem(LRLScreen, 64000); + FreeMem(LRLFontBuffer, 32000); + + Close(ImageFile); +end; + + +end. diff --git a/programs/games/lrl/bin/lrl.img b/programs/games/lrl/bin/lrl.img new file mode 100644 index 0000000000000000000000000000000000000000..79430f21e28b608b6483db35cae9898ef70d594a GIT binary patch literal 153049 zcmeFaX^drOdf#`ts;1doW}3sH=;GYcy*14iMNuT1VpF%fy4YPKuUbX~dQychstF@@ zq8PHeT_qOH#6}VXL1M;$k$A*W=pi+v69l#sBZ(|aHV|lm13M0cz=4)52soU;c0L68 zkVJuzO-p{i|MQ-6Z&g=S7kfAZ1JSv4&w0>AA93RSAXF4ANvzOy7$@cu1%C zzHn~5`tSqa@oi`CY`tsEocJ&}tou`4_d?f=yY7j@TJKi(@R@G);qJn6x3LODybo?0 z-`#C|Z}+{Q>(;)bTYR8 zm8t9dcU@mPj!(~#&P|N{9A*BNoQs%DT0iTWkaV!$aeR7x2BFZP(Ukm5ouY}3U6KDu zNA{XjsR2j*Vc0>g#G(*UrJuUDrzbwuL zQYUnCveP3swr^l27Xc2Kf3 zEohUJd`gWd)}VAEn(fKGFYejEa8N&lPZ5$26b&kNFTj`>;B50_^FcG{sfT?A#^AmcjGUlv6>zHe zt#qIu*&ImTBLB@W>~EE$els2DR1BdkJ4QU<24=x+Us$7VF5Fbvs8o>a{D+mCgybN6 zj^u5ZxN0j&G{ayhPrJ*!Vx_LzcxEPTh0P#|lv>Y}N}=Yd@WJsiBL11u%qioa{op1< zSReG%8Iz&ZLflWyxDOIH*`s4ohk0W&r;a+_ol#5P5c?9m&?RIKKqo0S)td#Hlp+{Ioe4k;qk+#r z9ezC@+2|(SyYEC>bfZvpUsj&t^X1T#&%0mgsn1H?yJrI3*FWgK_Q3}qLi}s(Smz(e z&tlrT?&}})Wk!6xx>|DhhaT(z84et!*E;p-`@;`D_*(bD*F)Cw*HZeROFdt9D&E0qA{ z)Ya{4RDX>|HtIvN*C!`bRjb{GL8S-`A?avXe(<&E7q;Dp01;7|SP?Oz7KbK&KR=DF zB0|~5Agv-PlxDE`S`)E!aTwg0z?#difAAsGl1)+D{{js z9KlqyL`PcAMAWDIhnyj;>St?w8W$vJfPMhw5(iP4ic}YN8HZZbLOuepEBH#B4+Bb5 zhwe}s^l@Sp2|+%zhmw^&D?Y8xxz&+H`@rDX0JNm|09{M6^oTTRPigSfzW$qa45MG@ zx32reUvm4!U+Vg*U$9Q@?5Y2Vt&XU%Vf2f`_6xuKOTYZfzx+$T@XOHuc(;3n?ze0E z-LCuX-^%toln$x;-QTILqUl%r?ftL*RNLPBcuMcT*Kg6N=kwKljK2DQn8Na_@6DH} zr|x~~sBZ$zO4QE@c{HOY!29og^}U*-uii`P{U-W*hcL43eKb<~$kz%#^?qOY>U*eI zCr!)wem~v!`)T_9wEZZ+NLIcd(qZKvAp%`AKXe!Qvis;GiqE_6zAHERkg?x=CosSB zF0YhGs_*{PPerhI-g*C>_ujilKJUN%t}pn!_x3yQy#4mu&db~HzVptzDZTs7SHAMj zI{@-tmE`lzJMU2UE|R_XE<@i{9tOYrE(Z)H_>^Q3@4X6iZ`1Sbx4Z7E9O?V++wXmq z!dGS`Y0Bp-Y?QwGek&o_yB6P7GKajA5@aBvWKxD)<8xdDKs~zJBcs0ph+U+R{*@*bhM;?W%Nj@GIMzQ8u>2SN&Lmd=9r8C}YJh-D|DCj!( z_voi#(fEYL;k$1n?yPqA*Y!Xy3J%?IWpwQJlW8~QefU=GK78w~-}*2)kkVUer;W`$ zEyF%^hw&K>mDV0w{rDPPEk(j|wxU1Bx$#i|`xO1w`H;g;zV(yGZ(?+OkDvVTCqF!P z`%>C}lkH0%*6vFme)yYTvVxiqKTLZ{)TU+Fhwd;w!x__hwc$11o_$LdisC>&y=$aB zdAkk#!|Cwdmp=T`@!Q8{M@(J}DK=tx|2#W?u>y8wDZ`8o^PG09$S$+tGdrku+G0Vq zhe|(wj{iLSp?zR@pzy7;qf8u@5F5!PI)`p$ClqRS?UVUU;~nj^(b`NPUG|T+EtCfu zeS5}O3xz|+_Y4mlPh>|wcl`D@f9`J{yZx-~zx6kKJAdrw$~09wmDQ5YcFCBbol!M@ z){;*Bc!nQ8{viMT^x<>V_OpNUXOG|Xwc~sI?BDp=zj6F#`)_u>oj>+-Wk;r+%4$hx zyJXDJ&ZrtcYe}bmJj0J4e~|xv`trHgO^kly`0dw!<#y^ODs#XtLqF!1jMI&l2ew}18c?c>dBm61q1Ed?cm40$IhuO%hA z^oeO`XXGzd`l9}f7US&K}SIdMH zTHfnN4ph>2Xm4Yr*z#SU<_7v{G5eJmeZREJ@rdnPm)Dp*Q%}FI98{TUF7H*wGj+90 zXsPmEKXRawzC(K(BgK~QhBVjHPm9^F#OV9oH80EKxNYHg&UOn6pI%s9xUg_-;fEJq zUHI{ZKfCbf7yi=1UtRcH3x99nHx~ZU!f!5|T6}nMviRKM)x|F?-dy~Xi+^VE-&%Zo z@vkiY{NmqT{Po3uxcJi2k1hS&(zk!&&wb)|KJjm!{yV3C`}Ep<|Neasp7|qZe&)>A z&ivu~|I_>bm-{y#_{9gFeDL3S@c(-7k3IA&4_*A^Kl{m_{^X;d`d2>nPd@cW&;GY( zHy-|L4}bd8fA-V==+j?#?^{;)`|NLEFeEL_OzWCk$*>^wj%wKrspFHzNpZ)vKKL6ZT zo?E!^;}?G8!qw;h%JXNx=imLF-~FC{@rD2Kg+Foew=e!1FaFkxKl;7@;Cr{Gzcig* zdjHay%Rh1Xf4KYy)_!H};+4OC<%#vbu>Mch|L9A9|E1@ze&y<4yZX1U{ufvOo2&o$ z>i=j;gH#h#|#-G{vw>IA1_$wPfzwviBetqK~Zv5{X-RIAKe*F1oKmXF_f9Uf+ z^7$Y8{I7j}{rmod@B8HM|MKtu?ce{W|GZ@Bcr)|N0O7t3UA9f8fy{{0l$$-~Hg{f9OB_p_jk#kH2v3hkxUT`5>-t zip=)ES24rF(*Mu#IK3Z@kM(S^J9X;FKcU}`{U@l%fPVLl2y>t0!=MiCJ+1w5hjhH7 z=P|Ot3VL?P(8Fo>wf*rBIcoGkOo9iuGY${8`C~Efg`i6fYsWiJ501_GK~@LO?~it= zgkaGe3cXS^&$u1v<0*{V*gETJ&gu_vJ>+z$c=Uu0>2X|Djh=BIh(++@>g}*p>K)hZ zh&HRWleT%vmV?UIsD9rc15etjXB*IH9Cw&w)w+e%KpA&IJRO+Er5DRpV`4~oYkQp z>(Jx2-u`FI9Dn5d0IB5928JE z45g}!^ch;}%~YDN9B3aX3|bvGSVj$;qq@y?Ily5!-DgzP9ziOsY~y|Cf!a27AbqgV zv?`ff=Q`ZEKT3|!yc?s$(2~clybnDzkq>Qam95J`P3F({0eCE{Lllo-P%C!skK5)# z)1h4tR2~Sq2U_R&IcKKS%zaz zZ;r{KMQ2i4p;V-$F{`MvbU9erkC_{AD34aTFJvCVqmk={nWK7;ak?DOiqZCRB-_0n z8kOT&6{qlM9PjO*yvJ@sbUt34(79`u<9U62td7;l#^z>sn=4U17UL7n)geYJR`bN~ z%Bl@GPPJpNm>aXX@%!+WJlkCkO^E%6fG|h*kfN;i>)W4Iy?eumB?ZJahqDD)1d^0%ApIi8p%Ts$Fpkk3{(%r@zBc1$ha`|zP7G*Gv{!xeH_??VZ6aOTKqnXL7WTsC; zq7Fyx_xGBe4OEU|Hr#6NIfcW$>=;uJ^^|7ElDe0wKklz>XNNc5S=;1p@MQ2k?E+9O z;)SU2l2R{^wIAaqtB+$-P`2Yp)jir7D#!J`v+XW|7WW3!afd*9tekh4O;c+)M9<@R z3~hHoWZ#|VJ5@d~{R98>oI5Lat>Q2;sVe~IhEY3r_VEIEq!c#Ds(5p3#jx*#ZC}}X z9!D%%l^R7hW5c9zN@Mld*S1gle!yK>9o^w@t-@u{vDZ2P%y`a8S5yuLuDK2wmGS$j z9(Q)M(0tXoH5Lo@cmB-}|HS-Bk0*5*ezM&RsJp4zgD2e@N`KQjTQRdfq!LIUN!p4rM&_ zgq?%#IGjMMxgc~XkD}b9x`V-t>+!7Gcm=M%{%{mUbvbG~o>gX`w1PkrFqK7bCh|$E`u`@5ZWEM6+N!YG0g+)lrIt74!x& zjoP7yc}6|k;aH7_jj)WN)G2WW8S=3#%^oo7cgs#}+h&H)~cPUG=0u{w%}^{VGV zafdUd=-;i_*BqnP38Ppj@27g`*)g0*A;XXe?T(rw4tM2vLRQDoY5b4tlD6YnMT6=W zb?!=TfMLF8qjEf}0jv3uhmt!%!<*pv66hdGfO!8;F4-lIA3K}XRU7!|vt_Cse#Hg+c~93w(C z%{lnI&S7Ye;#LY-E(wo39LKMo7-~d9_!}=PShJsl$2n1sP_nTf4g;-5>bS!k^?k)- z6FLOHvA?L>^xeny&XWgbtiGwG5^0dBVTL@j(mvq?s5RYLm>V?=4+BY9liFhoJ@I`^ z4?AfOutBURdi1emD87AMIP5scdKkl@uFR3sFg)@QO^Ro)`@yrjDl4m@(~<0EeU9of z>oI6?u+S{OL>vVDxC+tZAj`wg_a!Iz4 z+nVpA&P%SrosOj3Cbk(b-6ZH%$3Y#>8?QqTG}ee3eb~P6EYgS3=#l$)SRE!oUw2Te zl6=@xX!4y{t9_tlbm z&`G#P&l7S!9^S@{LzQ~Uiro|&+J+f8O4s9A^#qGvv1?opKODuz`r}y*#G^t3>fj;j zw4NUWt9fz*tNoQZyLVP?LI&jyA>OMKy^rH`R{%rd1gv_F$1rQ2I_vR!6*DX>{T?2_ zhsPWOcZ+SfW$U%unc_LHAK zyBn*c1E>6Ww?p(l47O@_f3j6n5gKS0hr8~FQRpVGY)2J7iq0V{wIWu?Tjt#k#q99? zN!Bt&yC-({V?X_aP`z;bMEEF5Hl86|;8`=H-_G{YpF26(#6skr{^q2b<9TS&e<^jc zZIEOp(?=+kNWGcG4vOs&K%EqzHeB+dHx!)VR%uh3=L)Uq?y8^692*kh)3XYHPKxXN zF)epxeRp$&M3~JTqE~Tjj5(z8IDU6yH4vC%HzPZ%oYfu4?W7YMu~lqP<|KvI|48n0 z4ae);P#bs_#JzrVQqggMe~$XT;t{MuZO$c%YK`3AwvXDeCwH<^KDHbNs`HhN-q6<0 z?|K;S9v1DM#~sJwb?3fka015l(=|;hxQ%;Xw4O8?e~Pu9Us<&blA3%2e$C+ zb6U@|uTFgvG&kHThDfrv)#to`@6IEPtM-IarTk!>?4!2k8GSBb!SJDv!ji(=ex7# zCuh%ZoPD-C`|RZGvm0lp-P!5n>~!PoMt62&a&`k+-K3j9adLk*xqmXbe`E4UH+f_- zd1PZU>L#PfWVA6k-%ZX>Cg(RM&vuh%CzEG4Cev;*olK_umR~p7m`pY{_;0osy2*uZ zG`zptxPP*7|HcOY8TXON#v>aWqi$m~*%)nXobNWyPd3hP zY&_d-JUiKVc4K4OZA>Q{Q^%uI$Q0BE_b;7!^z=iIU4HDb)1Q6p^7+S3Klj+>%a1*> zusmK^etKc~(TA2-A6kCqq2)&&TOL2Q{PbhXkFGASt}Z{bx_tWl@*__#kDp$C`swA% z&n-Xt;_~W?%g?;HeERb8BiEM4*Os5Yw)|rE*=ya(nT3_<11sGlE7w+5u3cN{&Ws=W z)cD%N;};$scPrzER>m)m$Jd@5zwp$!dwTrP^W$qTj$gPk?yilOyVdjE>SrHVee!`- z7@vQ1^|RyEC&#M~J-NF4)av=CRzLf~>XR?5b}z0zbY*qsqXyc zh4arpbpG_C=Py5Z{>+&tA9?7>%a1(y@MBLt^VpMDR-QaPe)5skC!bq=@|mZfJpIg* zk39F}b1y!5`SO#`AjiT}*B*Fk^`WQ6k3F@z`qcR8r&eEl>h$!fM=n1#zV_5p-P7Ht zo}NDWba(CP7rJMzbJku>d)180jAqYJ4%(ZLJblr0gEIjw(1J6D1splSg z{<-DnpL_B7=bn1uxfiZH_vA~@J#g*0%PY?>UwM9|dtvR=Q<;+K+O1)`j&;>_7YvC6wDljRo3eFNg$yCNqYIbv?Nb~bNs?rb6UNk`q;@1E(*58T|H3A2MZ|1{g&=+-So z^nL5b^*aGMam_rPk1_#s0`!7J80YdEk>|vM-($xqKH=-uCgOerGd!B7v-J^#nF$an z+74m(+x!T0zSUi)JGXXk?cBa~mv6PtryV(3~@Y=@sAp)t7 zLg(H^zqgUs%iQ$Tom(u#?`<1tH~bONrSnmu`kVlekO&kof8y>x)p=D-F*oGAwR!s> zYSZa;b(w9~r!#M!Zxk+leJ9{;R;T$6A#vE!Y*eGzBgF3JbUYQZ!mm7FZlx!IQ7=-H zWv;nj`$g)W+1=XJ`4CA}fu&O08nF;wi*|-4U4xXmdxvLCug@>6QtoAg*<7P=sVr~& zb?0_0ce)7{`(KBcBE4kp8~5B{r0WwV;Wj`P9WkxfCN?;xv0fz$-TP)ntc|+y%hleP z-K|~R=2V%djT^Po%^BgA37FrKQ;R#`VRIK1^vNa`WlsAViB8yBtVVZDQr*{~jXuPQ zBY?|YDDPzIMwH6pN}dtU%*Ld!t#z7cHe@jdj^-HY;iVBh8ne5#cinYG-oHtEJTq>I z?Ytbh@P_~}6|i2Ef&^i*=`-}*B4TTmo0tIRr0i_-jgkm&`O{;^WQdjDxYe)Apkl~U zxcxjzYRA>v))5$)Bs8yVQ*xJ=5;ydXuG6v=3v$W2(?P&6sAvJdp4r{n0p3~P8l>HX zUk#oP)$o!!%gp8n=%;@n6~gSx4He$ZazP_U@IigFnQxSdDRqrX%Fl&*7oq<7MSqP>|#L!-S@Bo!6W_M}FmBE-n zbBgMrYB3uszf4x|G;!jLft6wm8@9OPyg{}9Q#DTLGS`S5I{$WJ!=$yz@pTSbi9;Ea zzYIRGG^^zw1MRxy)RCYCeFr0L6UlOyY20mW48siHP6u|8 zZh!m8_y*;HMq~!a%^hTEL!}sK=~W&lq-?qY@oxalLdz%!9T&xU7%X$7=`))e6$PgV zUg1g*Kvy}5q5}n%w~_2X=1xR%96kA48;xBM(o?!k9%3|B8Ag(}p9appMGY{%g{y_T zoa{hzTL+SUcCfw-adP&zo1ENWkY#90pTGnS>?4eg;D!#naZMOM(EkC3CPdo@ob%Y` zK|RNLOT0E6*3n>k_GO9o#H$-8&H1r~fh}tT{fL7jNpnM=(ONIzZ_Qw6}YRtals*ZXG zmt{&MCTmSg`z_Ek(`M4h@v_o+nIX1JqJo8t)ulM4Xe0~Tf<6KZa|6TnXn?cWMM>$W zFuc)|MhMeZVTPgovO1zB=Mv%zv9@m^PH3j1k(mxb@@AUEDP^i`EzJWIJK~Ttk5NWs z`d?&#+AwC{>?Caol0E6)Q$Wevx30IY#wdoS&D@YJrd7FtmQ0+;tRYIe(wm7^m&%Mp zK`Bhjk>UVMk*!XZwgi|+>XbL^r#5nu8Y`zW*$HH^zl@6*J$SSbL)5jc_eyXHjY7~V zl4ONSCy}#lWnfL=$_qgxd%NZ_Cu-X>s3Qv{BYSO9aH2Tav-ecO37Ehc8jw~fdwG2( zkxCZQ=RF!X8T5mSr?rfuRXmtuFEc_;*KoAFWZf)IGT8{Hut}@5>vE`x@BBE|8vh_@ z+A?!m=}zIyOb`U3Qpu_uC{&@c%s_XMkGUa=M5c&@NmXLoH#<;DtGC_^1kFieVg2ei zL9JTILn@8D03Uxq*$$9CAlO}Wf#Z{i!BEXQ+NwO&3rR8 z*@>_QAUQPAD6+p@SJLU@YBB`r1B{-e)2$oPB{3!Ql)EX7gwj;fHH=qtt`;+aw3)Zf z4KA@F0}x=?2D5Ct=m}{}O2^)BR>>M*QP#5$QpZG@3b2|+N$UlzvKqeV0dF?VpdYYB zZU|6ns4dWop?V1C1#||v%MwO9LQ@eMvIOQ?zp`e9xuNfI3}>ezWJ0;-4C?eo6npcI zMoM51g8|Zpnv#nU?NQ3rSUi|6bYvvjA%P_;WU&t&hcU=zN`p2QVg{t|owi_YGecJh z#0+;T-5^j*PBIIgEMwixd60ww9x14xUQb6eS6H%Xt&x%n83iksYs?WK>v!cXy*N3x z>m4;CTJ39s7Xr}$0XI=XAjCB{C^l`-uh!mOBE7kR7RtIqK^LoDd%5hh#<Z^Hs3qTP7ql#G0V=#8quwwy@*tM#xnqor%32%$EO!% zfyxYX-4JnTsYx0HPeQ8sJb2vzLC_!OJ`n44LS>$k8NwCXreIN`o!VSCWZ`D`pkgkK z53H+T3L+EBD$pd4bHzXJ(k*C2ze;prjSQKF%3?~ksWjJ(J8H@+!g;+GH0T17*OSD( zs*73I6o)xATl*yi^Mn^cpM?%3FQS>xS@w@g{T1BiZW+l~+lfR@69sr_UIko2oUke| z%fTGW5blts5NrF$&6wB&Nq|Dm`lMqw*ZWQj?C?FaiQ&mH2|L%Z5Y$WHKs$xhWE8ix zYfTED6}4rPGRGaljIJWmwT9o1TQUHhb4{_|SFXdcWMJ&R=ohf1Sk)uWtD{imazn3W zZLDgv(r9NlbAxim@)7gEWI15ipu{l!Sn5;haPG~P!B-^)6{aOOdIC{`#*GRSvaHpK zbDxM-vL^Nuj~(5#OzwaVr)*nj+*U#ML4*BfQlJbD*h)%T-Q`!*2 z9~9isO}7vW@A5*;6Dn%Yy+*GabXuoXN1VILlJflK;;_vJ{dY#*lbNp)!?J{g z4hh|$m=Q2Y2uqZZJJK=9E~sgWd(?FUgIyW9&UO`;TdVe_W5U1G9InLsF&Jf-_1M6? z*i4UeYm0=NosOp0F)G>FpT=BLk@}*O(})cSi7?&fGK9r=mK>0=6Vt9MCzMFqtwQpGEZV1N>QfDd`nv4@?D4+@(;s`Gt zqg}gQV7!gjfEY-mwFwqwX%`ztCNt(5svP77?M!h&C4;ar1+)3Q4^t+Rbm-Ulz2p!@ z?m{IF;UEMcIA}#e5v43gHTcWTCLu~K`lw6}rbRe9NyrhbB$vJsKDzYmvod$I(@Hlj zD4$qq4xH2EO3%rwk1$JyP_rs@u&juwddB_=J+Y_+R0UB^sU(p5!W_-D8~KWibJROXY4WWCVv#!df0j8ev`G{Lb_WF43pl!e1G zv~q`JOEG4cdGeYh9Aj^pLc2H#GD+KkH7@9cpjwrw6^AX&G)?N91(Jes!k?-Krp%K% z&{NPoM(3EMoh9!4Q{R(6U~oxsk%3;ju^@a^&q{2`v>Q%B9g?{pUP7`Dv1zWJNMYNri*X}9R5SKIZ(sb~d(S|$qu zA|=&;xMpS`@*oAJcue2K5vzT7?WGpsi-m?>Z@JN9p=tC89(9fNT zln$h(3YIli%dCZddt5`Vao#L#LQ4_koD*or;?}H-MR7Er+a+9UmcU)Pz=OgFi-U0B zsVgNuz8A%kz{<)I$qM|&e@tOhGKT{It2)TfmsZes>ax{S`OH!(%*W|!_2sHkG zQRO_5eN80oEp{-I5|LaqopE=*8Auzf9a+=LL}Ox-+BT_9uMb9ci-?qzqi#3q7AhvA za&9^l3q$FNRb6}38gnqC_(D+RGCMJqo{8&9tT0^Pu|-S$n`WgMu49_`2;2}balr#X)?Y4T0M+^mv(6du@Iw9)Faq1_$0IRnnOV+EvjcsVGdLEVGO zb+E)xbacI+9x7@9tPRx!$G?m|GSnGD&os@<#FnTqaIpzbTR>x2MuvWV#j!^~L(Lq7 z^!${!CmEt7{GICI4x&#-A%w6h2Wre|KD`dCG+duHGtoy1rA%ZuX6~IySi1t=**AJ7 zf{zKgl9RzaXNL8pyXhK?c3W#sVj_KiOj0ONJnQ8O6MD%oBI+SYDyExdRmA_&XS^2w z4zlSv+%s&?hZ)+}_6NC(r%wGv{%88iXlbyhLUpl~({>nLoL-zRTwGr4mKR1BN6UVb z>(r@*4na6lUSu!(Ub+mGhb+Q|#wJb#kyHg8@l}ubKi-YkwqELfkUMt^eBtYp-E@mk_~U5S@n92AuU;9S zT3l?U#cniSn2xWE=r{i2=GNXe-x?e*PN`VRvHMIn;&fr!JZ^!tOSa zj&H6mUb?Zc%Uz;J2$7f8rdQZ6tX-P&V^pItCs)>{sB@_az3?Vtd~tJO>qp+$TI?3L zZtTACxrJ`LwY_y??`HQPk1lTA*xFf8jxR23Z*G4cc3TVEH+I*czqPo%vwan6XS(U` z_U?_{t?^>FwhQ|mPPSRuJkYHzc)m65J_Y;jZfSRCkKJqA-RW+8bzygJ5lZV_#Mp$@ z?i*JZxl-QR+VQrxsfx<0hf*|s4Zd1Q@MR*V%oPY3IuKzDV16dv|Mx&kmWY z?H!5>Tid%7wzt$~cL$kwf)RL+x4KU#7NXohs`1s`Jzip@@dc;r@O(|21Z?k(vGa8+ z^K~C3vi0p7TbROww39|(5-256r0cNV62lSl>}+3W?l7$2G(xpaXKsw8U_=y!YlnNK z4|Wrv+P$#_8ZT{KzoH&jHmP}StGlK{tig)ODVY?Gxtng?Sa9x`XHmjFr&#scE+!Tu z+C=Lse5Vyews&{GEd?^5p0O+&` z;gf4j*7oLZ&6{pBi9DV=NNC*+PepF1M{uYubVU zPP@#~TF|*dY3B+;(P?{xe5V#Cw-97giLPo#o88s!h11QhH@9QgfV3UE=F>ya!4ZI5 zS@)oEmRY)SdwYY*FW!Lg=cu96?u|<^HTZC2<~|UC^Cdb>ad-;%b<4OI7Bcd%g9I4n z7~?{(n3Lu+?q2H75L}(9@O$H>SkLY4H?ZjO78XOO!QL(H?v1gOtGBdN>NdA;Z|@1s z7DB~fHJ7!_30>CcGSOZQFqjP@>|8m8eeCS+E$oh}ay!r<&dLq#h%YstTIiwK-8S-I zJ~#H>nCkK|8zLbSv861ZR)iZjb$D#&#_knE3Bd3Kq&Bk%lQVcb04d8<5K1~Ummm|l zw{sOiMoi%Dp0J!+93c_KtKDhBbVR|I2!7(Sy?Og)q7N~LSu&(;-PqatJQ0tX*^c?* zTJl2@JOq)5fP1^!uNerY=nWc6-8s1R_M%Gz^{GX10f95R)E*WLD3jgS_Ha||WueR$ z;y6=K!8T&Pxb*JcO7jN7RI7-eIF`XXQ6^+WP)@MMVY2>gOr42Y(qd>+1cJZCo0Hx z^NWbGo%tqy%PqFD0E^~CwC$}SN&@dxQ6{)pM42GUYkOA-FE5;q*=}wV9)bzsHPbWQ zlG}|1eU`!%1i{aCD!Sk$=zF$9p`C5#eo?LubXRcA$gw8#L>A=PMT*gtz1;B*Zgxq%$hy|4`+ zWhLYArwQBG!xAD227$N&0v;%Um0a3hbW&f^Vw>|2Rd_?hsgHASm*s&!q)Gzk)2wS6-tHGZ|f>icX?3Szv&6!txF? zdJV8%>ZYd_rsY3OLSile?d$~@EQSmKFyuEf!K2I%!!%jq<^qOtmY52kEy%-X2WJNu z)HK6zfj(kJv#*nN(F=dBi zL2}8uhJx$PH35kMQ4xgFgJ}HPqI!-o*(9ye7tMwrO% zYj0qJSo&+3B}d0QN)6GD`68z@q)$fB_;-oSuAWgUfI05_0kvhjJ@qI zzO?nyE;PMt7$b@pzO(>;8DHTTl!DemcV+u(-1C9Gm$;z7s<*Zmh;bOz?!p$=Dw|uH z{lZ%5j*w^cw2Q_%mIcCgb4M>i!fn7{0u^lUH6jQa!u2IW0m9rMwRfM9^=G-PF-_sn>9? z?Va)p+}b(Aq4tDid!SJ@v6if+es42Bw zgc_YADTDB3V$tg8&F;nIWdamJA(pEltk-}tpS`_otl-#3=hEeK;q&8wR}a#wNYCWPfvHCb0^2PA#TRyhg#sscXoc?v?|L_p|D~ z;D!EVYNFmmuIZT`9KDQ@2Bih3&FON9JHCmS`bz{`kSB--`YQ;wy^uL@<+H6o1R;WW z(7O84R=P0@wJ<^%7p(>e*C)iM`|)WP4hvi{iydL$^s0Ai)<`4@;&f@X*!Lw|0xSt} zx;?ZqVHOf0Yg#^Cvtdvt2q4e)L}@KWCidzPc(_dHaS}RR8J~JiQrlA`vr5CM%m7EC`cQ#dvJO z*|{~%=p_=a@Zg~xH*d(epvg59g^AWoyyU8v%X2-eS@TV!-;Kq+n`5of)d7NXc`Jf9 zSzdA3(179Ul}txHL`f?Pdp|-D14S+;nIzURtkjsXe1ZALq^k*HGWz zO|Nd>T-bhT-2F=miLK|Z+L_feORcy*HGHLZ{mc|CQe2GzR_&@Qn-m{hSRIBX6t`ik zeTVhcY2RV>%zDpleXcJax7f3LaFAzp-7ArzwlGjzopo4WUGF=rt~>R8-%%5IVOG1k z?qs9`#a=mv%_s~kpxYCp@2tbXg4(_VeS2aHb1W7H3hS%fAs!gd4daGnFV1{z(*k0B z?dtl2eQ}Q4oI81!5mB%9M>4u|!HImW{%={9-S<7K_*Jv#eqdvTb; zUU}#qKFM?DHHgN<_2cHGT;FGZJ?#5zYBmh#>jlPm+6hw&{PG9RMeCAxMX9gs)@NKd!%)D!Q=J_7X)zfEs?M|=e z;Qpxf;{8>xVME3%$ew%}dO~NOPvT3bH1vAd(2uzP z)WZEsZ?2qXiq@xk%Iefo{#K_b560b+^#q2~m__@e3Gi3Jj3bjuH%6|mtviw;5Ek~V1AsEzN55i`xFR!lCjrp{ffBkEyfJ3peB?^V7YLyI@ z&Ok&Sh}vpbT43p}T= z#JC8N*3b?1XQlvp#*k)>?4x*{Q7*RPN6T6}71DK4D^(waHi$c(QfQ%CPl9?C(qA zbwB|Uu*g6Wc+f@#nXaFv`9WdP_z-j&bf&g7d?;pM4(X$q7$if|qIPu_$=#*JY0k^m zDl*WMn)h^S#8d7e>Blvp7)wh4X?!3SG7c!gDKx~-6k;_ynny1NowctpDQVDl;mq?w z#xil?^QZpH`W(OgP-sq$E8E6@?FMXLe3<(9BA=PAEUxfj9QzeNPIuq_I80VJVds&Z zhdOJezM*xik(1eYD02eU;s8(L>I&R_ldb$yCjZ*5ir=z5K#GXVZgB=Cv zrxZn+cHg`*z`?5~Pt(&QY9C1slo2kLH`rbtf5A9b07_@|9qrMZqnfwZfdi-QuRjL1 zs&mZTSO_r%kk%-9Hy|ri#QI~CTH+GM*x}*q5#1;Qf-2G6>tio#;&SmpAs^r3Av+#h za=v)i!F{AyW}a)Nl@}XKv~w5hn5VRb0?9m{;;D_5vJTK=L(4+)V=OmpST6F^Y@XiD z<7U%vELYGZoylc)nx8M`I$2`0w5T;;9NGxcjc30^&&S<3@H56`O9iA@wTfAFDkm!$ zn1|39D-EA{Yfq)MK?QXfjf+gVJ2fqgh^EPm(9HDuq>Xcql4`&%C5m-a`ERhyPxC_< z(u?_eHZn&Ap3~Hg8~ymR6{AFIr`do`+yOBXXI#s;g&vdkJhbZbBw(+y2n^V@ld2kO z+d$EC3y78>#580~fi53k*rCzUBh1NIaR+7+Ym7}|hxrSbJUmpYHhsm=3J%}Mp5Zk& zeDy0v!}F6IgI$jyNCKS`>1qX$gf4sCrj$UD@+-gpC3K~_L8~cGk6C%Zv#%w2h#b#f z`bg&upSb3EMkiCB9s+@Q_4L}YhqIcPOlEP69U>sp+*{)ka(Bz_&^Jo!%$9QIzj(Np za*YD0d_4kz>&aoBs)4#QjnQ;val0=lOSa4t?jX_Tj((nc#MhRVh=LEai zDf=t6t5d@uhrT{Xzrxp2PoDR!5QtFPqVtd~7&ahVxv_535|KcX7i$6%n;^1_%NTil z8V-eUDBeL%*fb%)VBgGz!wKpOJbSjsp+ONF^r^Sd3A$}fWAb&eRbIiu*uTN_5{gg} zIzB?J72e*w4#Gidm5#jYq}6?UPW$Q=p1JqSA&mAB^jM*;o0{v+gOKzjS~2vfiDuc&GiXu zS<3uD87hQykU%Gfk*@< z0W$%<3_`3KrR$;=X1OMs_$zU=slbivQxSB{#8*zeQ^|r%b*J?peJRSmJ@cO@_C2L@ zFsXrK;0=7BNU90d)eU|PTm3sTvT#GMZxbQ7f7norrv2=@u^T zk`UGc=Wj6ZXQC$|pkKCD8s{4$jRoHsT3JaXfHoMlU%k4%XdovJX-PX4J{m4GV>xfXWhugR=;Ikpe!;{bu@SjgSA#cwM|ac<$9Lgi)#v+ufws249Y^Cr(+$e@xls;UhXLXll}=pr}+L3L#5|8 z!ToH~N&_mNqS1iH*rrC5H3rnMWrF&Ojj=g~(kce^jXlqAp|)x$u7Yx?KT5p|$I(F1 zZ-x0~n>Ya`F&WjjL4}azpD@RQ8ja1BCFUjH8#L4F-+p;3X0MRNNHOK=`mqcU;rvrm z8(d`4XX+Zq@xix=nyH{CPt)Y$LjBxa5FluNWHYNEQN+d!eR1G?;Z75bX&T)c_%MV9 z{p#y)WHG-?CQU2+A&)Y2&v`hN%MXOs9C#t8)0-DVv?*=RT@Kh*gx3rBW*dMov;_;) zvnPN;%t^##SZGEac69Sfm<70C_+=!v#wum6gR(#`c$70@yHH3By-qm9PoRa=L#S2~ z-dv33cO?uYg8@UAMY85qF))HP!kbAwqN*9XFjUgKozU9&ZlXFy+re}DZ&SBUYb#^N zf@)^R62r=tXG?1nCD>$xlD#&`PX0Kbpra5e(>_K#zhx|y=@Ra(deItpFA@q#tqUP# z;Eg}g34Du%2n0pHt6yIrvm2?I^rPpv(T2o`4u3}Dh#pjh3QSMN`Szkl=7unAJ-B{L zu?&;;Qt$ ze&>}zu;jN(w6ErXncHxTv=HT&eHdPmI8!2ePNGaQYilb@{a2qsrtC;5>4VY42Mx_a zuZn6&2G@UMYNTHnW_BFp7X^ovO}j56O<6{|Tb#%q!Qf^$kd*^Jh5HKV~l6JFJw_arosB40>h7Z;KXPerv!UzzcCm;CmsW zu3@XUPgb}>Q2uPGkG)fJol5o=N!``}qqc@S5xc&q585r-$5J@UBE$1=|u;HaLhuCTu9HkDfBWM2Dp4z8dw)kEwc}@>f=w%`ioLw1nte~;tD#4 zjmP}{4`;zHKPF*}f|oy_<;-%uVjPaCYBJ`8{x!$$_q1&l}^s$HJ7bDgI0Z319^*{m2%1w2Y1A}?-c$UnA~ODy9dKTMY=-*1IjP`f)&O}#mLO$Y^n=8o?&$Z9150QA4bvS z0KTkV*Uf3J@CPk^e$~Fr3nY+{HP^B~2k1a1=6a%8Y@nzh--sAR5C4!P0@E2uP~bZE zI6;rK3;tVot)mXjx)@x5ibHZMpK0*XW`#)9Kt*&)t36on8%xbDwFcPPVm*`CrOwET zBXAw0AnDGMc*WJDfMvl8{vZ&3PF-YGUiuKm0oSr;hR8ABg9Vy^SRu||46 zTxU(Veh54nRKmJk;}qjHH@oaZbFXbB#!Cj9uo{05$Fq|S_JW<0jREN zFB&`BTzK`nSm;@WC(vwq(BYT_-Mf7nfL%~eq?z0Y^)%|%7;HqNh7p^r&mGK}o7u4a zo)2Ta6ta&kY9l({-U>W*pNpTfDKnxUOR!j9%#%LRmU@2Jbn$WSQ?zx4bQiO_^I{+( znhyLyBy|udmK|Qaxj6y8>E|@x_WqIHJG`*12v|z=nqUC*bM0r2&H@)XHH4`*7aZek za(AEm6se$wbMt9MBq1S&d9TvY;1)B1QvUfc5Z+r`Hvgb9I}=_5MGYLmNx+{DN_34lUu zY~0oG6HjUv>G>fIZ^9b;xWn$!E!Sdn6m};dnkW=@D$4#>D{ znm){;Ot&QC;OWA>ZRRChwsxkudmkr?Bs-^+p)Ac{C?GgZrU@(IZ?xo1iFA(XvHmfZ zExF6ur9IUVu(P~Y?`A#O_MhEEtWP=Dl;ILDXqaj~3iBGIH&en%4%1!ex+3CR%uRK7w; z#6(FKzsx#IlR(XbHL)D&Q%FdU7^;@r3u_EgO$i|lB??j8XefT6$Y`Zyy_p+EVM8Pm zZieut*KH>{V)85$aR#p{1Zij4+-DBmm<=bbn^27B#>0*uw9)5r8d&aWlRDI`v7h~! zK9E2YpDvy1f1e7O5rGIF7juLdn?7KSLm6if3#YB?SZ_Nwx8$lmwne+W%Kz%W4OHS` z@thC%YBG%d)RR8Mr{d)1ZIt!uLoGw+)|h*T&IjIMgiCs6K$b+h1nI*=2B@)cb1Hw= zFG|W3E2W}NB&AiL$}O@es8#%

VpvG84`~{VYG#qV@P9nL9HELVj|o$Jz^~7={9P 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ℜDGO}E3KN%UliVdSuY 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 literal 0 HcmV?d00001 diff --git a/programs/games/lrl/build.bat b/programs/games/lrl/build.bat new file mode 100644 index 0000000000..2eee86df89 --- /dev/null +++ b/programs/games/lrl/build.bat @@ -0,0 +1,30 @@ +@echo off + +rem Для сборки игры необходимо в переменной UNITS (определена ниже) +rem указать расположение папки, в которой находятся откомпилированные модули +rem RTL для KolibriOS. Например, если исходники RTL находятся в папке my/rtl, +rem то собранные модули RTL - скорее всего в my/units. Может оказаться +rem достаточным просто перенести эту папку (lrl) в директорию my. + +rem Так же, для сборки, вам понадобится утилита exe2kos.exe и FreePascal 2.2.0. + + +set NAME=lrl +set NAMEEXE=%NAME%.exe +set NAMEKEX=%NAME%.kex + +set BUILD=-FUbuild +set UNITS=-Fu../units + +fpc %NAME%.pp -n -Twin32 -Se5 -XXs -Sg -O3pPENTIUM3 -CfSSE -WB0 %BUILD% %UNITS% +if errorlevel 1 goto error + +exe2kos.exe %NAMEEXE% %NAMEKEX% +del %NAMEEXE% +move %NAMEKEX% bin +goto end + +:error +echo An error occured while building %NAME% + +:end diff --git a/programs/games/lrl/readme-ru.txt b/programs/games/lrl/readme-ru.txt new file mode 100644 index 0000000000..0491b25f4b --- /dev/null +++ b/programs/games/lrl/readme-ru.txt @@ -0,0 +1,10 @@ + +Lode Runner Live 1.0 +==================== + +Проект по переносу игры Lode Runner Live 1.0 с платформы DOS в KolibriOS. + +Читайте комментарии по компиляции в build.bat. + +На данный момент тестировалась кроскомпиляция только из Windows 2000 SP4 +на 32х разрядной машине.