Rev 23 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | unit Game; |
2 | |||
3 | interface |
||
4 | |||
5 | uses |
||
6 | SysUtils, Classes, Forms, GameBinStruct; |
||
7 | |||
8 | type |
||
9 | TPictureType = (ptDia, ptDecision); |
||
10 | |||
11 | THotspotIndex = 0..2; |
||
12 | |||
13 | TGame = class; |
||
14 | PHotspot = ^THotspot; |
||
15 | THotspot = record |
||
16 | game: TGame; |
||
17 | lpAction: PActionDef; |
||
18 | cHotspotTopLeft: TCoord; |
||
19 | cHotspotBottomRight: TCoord; |
||
20 | end; |
||
21 | |||
22 | TShowPictureCallback = procedure(Game: TGame; AFilename: string; AType: TPictureType) of object; |
||
23 | TPlaySoundCallback = procedure(Game: TGame; AFilename: string) of object; |
||
24 | TSimpleCallback = procedure(Game: TGame) of object; |
||
24 | daniel-mar | 25 | TWaitCallback = function(Game: TGame; AMilliseconds: Cardinal): boolean of object; |
2 | daniel-mar | 26 | TSetHotspotCallback = procedure(Game: TGame; AIndex: THotspotIndex; AHotspot: THotspot) of object; |
27 | TClearHotspotsCallback = procedure(Game: TGame) of object; |
||
28 | |||
29 | TGame = class(TObject) |
||
30 | private |
||
31 | FPictureShowCallback: TShowPictureCallback; |
||
32 | FAsyncSoundCallback: TPlaySoundCallback; |
||
33 | FExitCallback: TSimpleCallback; |
||
34 | FWaitCallback: TWaitCallback; |
||
35 | FSetHotspotCallback: TSetHotspotCallback; |
||
36 | FClearHotspotsCallback: TClearHotspotsCallback; |
||
37 | FDirectory: string; |
||
38 | FScore: integer; |
||
21 | daniel-mar | 39 | FCurDecisionScene: PSceneDef; |
40 | FPrevDecisionScene: PSceneDef; |
||
2 | daniel-mar | 41 | procedure TryExit; |
42 | procedure PrevDecisionScene; |
||
43 | protected |
||
44 | GameData: TGameBinFile; |
||
19 | daniel-mar | 45 | function Wait(AMilliseconds: integer): boolean; |
2 | daniel-mar | 46 | procedure PlayScene(scene: PSceneDef; goToDecision: boolean); |
23 | daniel-mar | 47 | function WavePrefix: string; |
2 | daniel-mar | 48 | public |
49 | procedure PerformAction(action: PActionDef); |
||
50 | property PictureShowCallback: TShowPictureCallback read FPictureShowCallback write FPictureShowCallback; |
||
51 | property AsyncSoundCallback: TPlaySoundCallback read FAsyncSoundCallback write FAsyncSoundCallback; |
||
52 | property ExitCallback: TSimpleCallback read FExitCallback write FExitCallback; |
||
53 | property WaitCallback: TWaitCallback read FWaitCallback write FWaitCallback; |
||
54 | property SetHotspotCallback: TSetHotspotCallback read FSetHotspotCallback write FSetHotspotCallback; |
||
55 | property ClearHotspotsCallback: TClearHotspotsCallback read FClearHotspotsCallback write FClearHotspotsCallback; |
||
56 | property Directory: string read FDirectory; |
||
57 | property Score: integer read FScore; |
||
58 | constructor Create(ADirectory: string); |
||
59 | procedure Run; |
||
60 | end; |
||
61 | |||
62 | implementation |
||
63 | |||
23 | daniel-mar | 64 | uses |
65 | MMSystem, Windows; |
||
66 | |||
67 | function Supports16BitWaveout: boolean; |
||
68 | var |
||
69 | caps: TWaveOutCaps; |
||
70 | begin |
||
71 | ZeroMemory(@caps, sizeof(caps)); |
||
72 | waveOutGetDevCaps(0, @caps, sizeof(caps)); |
||
73 | result := caps.dwFormats and $CCCCCCCC <> 0; // Note: Original SHOWTIME.EXE only checked $0CCC |
||
74 | end; |
||
75 | |||
2 | daniel-mar | 76 | { TGame } |
77 | |||
78 | constructor TGame.Create(ADirectory: string); |
||
79 | var |
||
80 | fs: TFileStream; |
||
81 | gameBinFilename: string; |
||
82 | begin |
||
83 | FDirectory := ADirectory; |
||
84 | |||
85 | gameBinFilename := IncludeTrailingPathDelimiter(ADirectory) + 'GAME.BIN'; |
||
86 | if not FileExists(gameBinFilename) then |
||
87 | begin |
||
88 | raise Exception.Create('Cannot find GAME.BIN'); |
||
89 | end; |
||
90 | |||
91 | fs := TFileStream.Create(gameBinFilename, fmOpenRead); |
||
92 | try |
||
93 | fs.ReadBuffer(GameData, SizeOf(GameData)); |
||
94 | finally |
||
95 | FreeAndNil(fs); |
||
96 | end; |
||
97 | end; |
||
98 | |||
99 | procedure TGame.TryExit; |
||
100 | begin |
||
101 | if Assigned(ExitCallback) then ExitCallback(Self); |
||
102 | end; |
||
103 | |||
104 | procedure TGame.PrevDecisionScene; |
||
105 | begin |
||
21 | daniel-mar | 106 | if Assigned(FPrevDecisionScene) then PlayScene(FPrevDecisionScene, true) |
2 | daniel-mar | 107 | end; |
108 | |||
109 | procedure TGame.PerformAction(action: PActionDef); |
||
110 | var |
||
111 | nextScene: PSceneDef; |
||
112 | begin |
||
113 | Inc(FScore, action^.scoreDelta); |
||
114 | if action^.nextSceneID = SCENEID_PREVDECISION then |
||
115 | PrevDecisionScene |
||
116 | else if action^.nextSceneID = SCENEID_ENDGAME then |
||
117 | TryExit |
||
118 | else |
||
119 | begin |
||
12 | daniel-mar | 120 | nextScene := GameData.FindScene(action^.nextSceneID); |
2 | daniel-mar | 121 | if Assigned(nextScene) then |
12 | daniel-mar | 122 | PlayScene(nextScene, action^.sceneSegment=SEGMENT_DECISION) |
2 | daniel-mar | 123 | (* |
124 | else |
||
125 | raise Exception.CreateFmt('Scene %d was not found in GAME.BIN', [action^.nextSceneID]); |
||
126 | *) |
||
127 | end; |
||
128 | end; |
||
129 | |||
19 | daniel-mar | 130 | function TGame.Wait(AMilliseconds: integer): boolean; |
2 | daniel-mar | 131 | begin |
132 | if Assigned(WaitCallback) then |
||
19 | daniel-mar | 133 | begin |
134 | result := WaitCallback(Self, AMilliseconds) |
||
135 | end |
||
2 | daniel-mar | 136 | else |
19 | daniel-mar | 137 | begin |
2 | daniel-mar | 138 | Sleep(AMilliseconds); |
19 | daniel-mar | 139 | result := false; // don't cancel |
140 | end; |
||
2 | daniel-mar | 141 | end; |
142 | |||
23 | daniel-mar | 143 | function TGame.WavePrefix: string; |
144 | begin |
||
145 | if Supports16BitWaveout then |
||
146 | result := '' |
||
147 | else |
||
148 | result := 'E'; |
||
149 | end; |
||
150 | |||
2 | daniel-mar | 151 | procedure TGame.PlayScene(scene: PSceneDef; goToDecision: boolean); |
152 | var |
||
153 | i: integer; |
||
154 | hotspot: THotspot; |
||
155 | begin |
||
156 | if Assigned(ClearHotspotsCallback) then |
||
157 | begin |
||
158 | ClearHotspotsCallback(Self); |
||
159 | end; |
||
160 | if not goToDecision then |
||
161 | begin |
||
162 | if Assigned(AsyncSoundCallback) then |
||
163 | begin |
||
164 | AsyncSoundCallback(Self, IncludeTrailingPathDelimiter(FDirectory) + |
||
23 | daniel-mar | 165 | scene^.szSceneFolder + PathDelim + WavePrefix + scene^.szDialogWav); |
2 | daniel-mar | 166 | end; |
167 | for i := scene^.pictureIndex to scene^.pictureIndex + scene^.numPics - 1 do |
||
168 | begin |
||
169 | if Assigned(PictureShowCallback) then |
||
170 | begin |
||
171 | PictureShowCallback(Self, IncludeTrailingPathDelimiter(FDirectory) + |
||
172 | scene^.szSceneFolder + PathDelim + GameData.pictures[i].szBitmapFile, ptDia); |
||
173 | end; |
||
19 | daniel-mar | 174 | if Wait(GameData.pictures[i].duration * 100) then |
175 | begin |
||
21 | daniel-mar | 176 | // Wait was cancelled by VK_RETURN |
19 | daniel-mar | 177 | AsyncSoundCallback(Self, ''); |
178 | break; |
||
179 | end; |
||
2 | daniel-mar | 180 | if Application.Terminated then Abort; |
181 | end; |
||
182 | end; |
||
183 | if scene^.szDecisionBmp <> '' then |
||
184 | begin |
||
21 | daniel-mar | 185 | FPrevDecisionScene := FCurDecisionScene; |
186 | FCurDecisionScene := scene; |
||
2 | daniel-mar | 187 | if Assigned(PictureShowCallback) then |
188 | begin |
||
189 | PictureShowCallback(Self, IncludeTrailingPathDelimiter(FDirectory) + |
||
190 | scene^.szSceneFolder + PathDelim + scene^.szDecisionBmp, ptDecision); |
||
191 | end; |
||
192 | if Assigned(SetHotspotCallback) then |
||
193 | begin |
||
194 | for i := 0 to scene^.numActions - 1 do |
||
195 | begin |
||
196 | hotspot.Game := Self; |
||
197 | hotspot.lpAction := @scene^.actions[i]; |
||
198 | hotspot.cHotspotTopLeft.X := scene^.actions[i].cHotspotTopLeft.X; |
||
199 | hotspot.cHotspotTopLeft.Y := scene^.actions[i].cHotspotTopLeft.Y; |
||
200 | hotspot.cHotspotBottomRight.X := scene^.actions[i].cHotspotBottomRight.X; |
||
201 | hotspot.cHotspotBottomRight.Y := scene^.actions[i].cHotspotBottomRight.Y; |
||
202 | SetHotspotCallback(Self, i, hotspot); |
||
203 | end; |
||
204 | end; |
||
205 | end |
||
206 | else |
||
207 | begin |
||
208 | if scene^.numActions > 0 then PerformAction(@scene^.actions[0]); |
||
209 | end; |
||
210 | end; |
||
211 | |||
212 | procedure TGame.Run; |
||
213 | begin |
||
214 | if GameData.numScenes = 0 then exit; |
||
215 | PlayScene(@GameData.Scenes[0], false); |
||
216 | end; |
||
217 | |||
218 | end. |