Rev 12 | Go to most recent revision | Details | 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; |
||
25 | TWaitCallback = procedure(Game: TGame; AMilliseconds: integer) of object; |
||
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; |
||
39 | CurDecisionScene, LastDecisionScene: PSceneDef; |
||
40 | procedure TryExit; |
||
41 | procedure PrevDecisionScene; |
||
42 | protected |
||
43 | GameData: TGameBinFile; |
||
44 | function FindScene(ASceneID: integer): PSceneDef; |
||
45 | procedure Wait(AMilliseconds: integer); |
||
46 | procedure PlayScene(scene: PSceneDef; goToDecision: boolean); |
||
47 | public |
||
48 | procedure PerformAction(action: PActionDef); |
||
49 | property PictureShowCallback: TShowPictureCallback read FPictureShowCallback write FPictureShowCallback; |
||
50 | property AsyncSoundCallback: TPlaySoundCallback read FAsyncSoundCallback write FAsyncSoundCallback; |
||
51 | property ExitCallback: TSimpleCallback read FExitCallback write FExitCallback; |
||
52 | property WaitCallback: TWaitCallback read FWaitCallback write FWaitCallback; |
||
53 | property SetHotspotCallback: TSetHotspotCallback read FSetHotspotCallback write FSetHotspotCallback; |
||
54 | property ClearHotspotsCallback: TClearHotspotsCallback read FClearHotspotsCallback write FClearHotspotsCallback; |
||
55 | property Directory: string read FDirectory; |
||
56 | property Score: integer read FScore; |
||
57 | constructor Create(ADirectory: string); |
||
58 | procedure Run; |
||
59 | end; |
||
60 | |||
61 | implementation |
||
62 | |||
63 | { TGame } |
||
64 | |||
65 | constructor TGame.Create(ADirectory: string); |
||
66 | var |
||
67 | fs: TFileStream; |
||
68 | gameBinFilename: string; |
||
69 | begin |
||
70 | FDirectory := ADirectory; |
||
71 | |||
72 | gameBinFilename := IncludeTrailingPathDelimiter(ADirectory) + 'GAME.BIN'; |
||
73 | if not FileExists(gameBinFilename) then |
||
74 | begin |
||
75 | raise Exception.Create('Cannot find GAME.BIN'); |
||
76 | end; |
||
77 | |||
78 | fs := TFileStream.Create(gameBinFilename, fmOpenRead); |
||
79 | try |
||
80 | fs.ReadBuffer(GameData, SizeOf(GameData)); |
||
81 | finally |
||
82 | FreeAndNil(fs); |
||
83 | end; |
||
84 | end; |
||
85 | |||
86 | function TGame.FindScene(ASceneID: integer): PSceneDef; |
||
87 | var |
||
88 | i: integer; |
||
89 | begin |
||
90 | for i := 0 to GameData.numScenes - 1 do |
||
91 | begin |
||
92 | if GameData.scenes[i].szSceneFolder = Format('SC%.2d', [ASceneID]) then |
||
93 | begin |
||
94 | result := @GameData.scenes[i]; |
||
95 | exit; |
||
96 | end; |
||
97 | end; |
||
98 | result := nil; |
||
99 | end; |
||
100 | |||
101 | procedure TGame.TryExit; |
||
102 | begin |
||
103 | if Assigned(ExitCallback) then ExitCallback(Self); |
||
104 | end; |
||
105 | |||
106 | procedure TGame.PrevDecisionScene; |
||
107 | begin |
||
108 | if Assigned(LastDecisionScene) then PlayScene(LastDecisionScene, true) |
||
109 | end; |
||
110 | |||
111 | procedure TGame.PerformAction(action: PActionDef); |
||
112 | var |
||
113 | nextScene: PSceneDef; |
||
114 | begin |
||
115 | Inc(FScore, action^.scoreDelta); |
||
116 | if action^.nextSceneID = SCENEID_PREVDECISION then |
||
117 | PrevDecisionScene |
||
118 | else if action^.nextSceneID = SCENEID_ENDGAME then |
||
119 | TryExit |
||
120 | else |
||
121 | begin |
||
122 | nextScene := FindScene(action^.nextSceneID); |
||
123 | if Assigned(nextScene) then |
||
124 | PlayScene(nextScene, action^.sceneSegment=1) |
||
125 | (* |
||
126 | else |
||
127 | raise Exception.CreateFmt('Scene %d was not found in GAME.BIN', [action^.nextSceneID]); |
||
128 | *) |
||
129 | end; |
||
130 | end; |
||
131 | |||
132 | procedure TGame.Wait(AMilliseconds: integer); |
||
133 | begin |
||
134 | if Assigned(WaitCallback) then |
||
135 | WaitCallback(Self, AMilliseconds) |
||
136 | else |
||
137 | Sleep(AMilliseconds); |
||
138 | end; |
||
139 | |||
140 | procedure TGame.PlayScene(scene: PSceneDef; goToDecision: boolean); |
||
141 | var |
||
142 | i: integer; |
||
143 | hotspot: THotspot; |
||
144 | begin |
||
145 | if Assigned(ClearHotspotsCallback) then |
||
146 | begin |
||
147 | ClearHotspotsCallback(Self); |
||
148 | end; |
||
149 | if not goToDecision then |
||
150 | begin |
||
151 | if Assigned(AsyncSoundCallback) then |
||
152 | begin |
||
153 | AsyncSoundCallback(Self, IncludeTrailingPathDelimiter(FDirectory) + |
||
154 | scene^.szSceneFolder + PathDelim + scene^.szDialogWav); |
||
155 | end; |
||
156 | for i := scene^.pictureIndex to scene^.pictureIndex + scene^.numPics - 1 do |
||
157 | begin |
||
158 | if Assigned(PictureShowCallback) then |
||
159 | begin |
||
160 | PictureShowCallback(Self, IncludeTrailingPathDelimiter(FDirectory) + |
||
161 | scene^.szSceneFolder + PathDelim + GameData.pictures[i].szBitmapFile, ptDia); |
||
162 | end; |
||
163 | Wait(GameData.pictures[i].duration * 100); |
||
164 | if Application.Terminated then Abort; |
||
165 | end; |
||
166 | end; |
||
167 | if scene^.szDecisionBmp <> '' then |
||
168 | begin |
||
169 | LastDecisionScene := CurDecisionScene; |
||
170 | CurDecisionScene := scene; |
||
171 | if Assigned(PictureShowCallback) then |
||
172 | begin |
||
173 | PictureShowCallback(Self, IncludeTrailingPathDelimiter(FDirectory) + |
||
174 | scene^.szSceneFolder + PathDelim + scene^.szDecisionBmp, ptDecision); |
||
175 | end; |
||
176 | if Assigned(SetHotspotCallback) then |
||
177 | begin |
||
178 | for i := 0 to scene^.numActions - 1 do |
||
179 | begin |
||
180 | hotspot.Game := Self; |
||
181 | hotspot.lpAction := @scene^.actions[i]; |
||
182 | hotspot.cHotspotTopLeft.X := scene^.actions[i].cHotspotTopLeft.X; |
||
183 | hotspot.cHotspotTopLeft.Y := scene^.actions[i].cHotspotTopLeft.Y; |
||
184 | hotspot.cHotspotBottomRight.X := scene^.actions[i].cHotspotBottomRight.X; |
||
185 | hotspot.cHotspotBottomRight.Y := scene^.actions[i].cHotspotBottomRight.Y; |
||
186 | SetHotspotCallback(Self, i, hotspot); |
||
187 | end; |
||
188 | end; |
||
189 | end |
||
190 | else |
||
191 | begin |
||
192 | if scene^.numActions > 0 then PerformAction(@scene^.actions[0]); |
||
193 | end; |
||
194 | end; |
||
195 | |||
196 | procedure TGame.Run; |
||
197 | begin |
||
198 | if GameData.numScenes = 0 then exit; |
||
199 | PlayScene(@GameData.Scenes[0], false); |
||
200 | end; |
||
201 | |||
202 | end. |