1 extern "C" {
2 #include <lua.h>
3 #include <lualib.h>
4 #include <lauxlib.h>
5 }
6
7 #include "core/gl_text.h"
8 #include "core/console.h"
9 #include "script/script.h"
10 #include "gui/gui.h"
11 #include "audio/audio.h"
12 #include "engine.h"
13 #include "gameflow.h"
14 #include "game.h"
15 #include "world.h"
16
17 #include <assert.h>
18 #include <string.h>
19 #include <vector>
20
21 typedef struct gameflow_action_s
22 {
23 int16_t m_opcode;
24 uint16_t m_operand;
25 } gameflow_action_t;
26
27 struct gameflow_s
28 {
29 int m_currentGameID;
30 int m_currentLevelID;
31
32 int m_nextGameID;
33 int m_nextLevelID;
34
35 char m_currentLevelName[LEVEL_NAME_MAX_LEN];
36 char m_currentLevelPath[MAX_ENGINE_PATH];
37 char m_secretsTriggerMap[GF_MAX_SECRETS];
38
39 std::vector<gameflow_action_t> m_actions;
40 } global_gameflow;
41
42 typedef struct level_info_s
43 {
44 int num_levels = 0;
45 char name[LEVEL_NAME_MAX_LEN];
46 char path[MAX_ENGINE_PATH];
47 char pic[MAX_ENGINE_PATH];
48 }level_info_t, *level_info_p;
49
50
51 bool Gameflow_GetLevelInfo(level_info_p info, int game_id, int level_id);
52 bool Gameflow_GetFMVPath(level_info_p info, int fmv_id);
53 bool Gameflow_SetGameInternal(int game_id, int level_id);
54
55
Gameflow_Init()56 void Gameflow_Init()
57 {
58 global_gameflow.m_nextGameID = -1;
59 global_gameflow.m_nextLevelID = -1;
60 memset(global_gameflow.m_currentLevelName, 0, sizeof(global_gameflow.m_currentLevelName));
61 memset(global_gameflow.m_currentLevelPath, 0, sizeof(global_gameflow.m_currentLevelPath));
62 memset(global_gameflow.m_secretsTriggerMap, 0, sizeof(global_gameflow.m_secretsTriggerMap));
63 global_gameflow.m_actions.clear();
64 }
65
66
Gameflow_Send(int opcode,int operand)67 bool Gameflow_Send(int opcode, int operand)
68 {
69 gameflow_action_t act;
70
71 act.m_opcode = opcode;
72 act.m_operand = operand;
73 global_gameflow.m_actions.push_back(act);
74
75 return true;
76 }
77
78
Gameflow_ProcessCommands()79 void Gameflow_ProcessCommands()
80 {
81 level_info_t info;
82 for(; !Engine_IsVideoPlayed() && !global_gameflow.m_actions.empty(); global_gameflow.m_actions.pop_back())
83 {
84 gameflow_action_t &it = global_gameflow.m_actions.back();
85 switch(it.m_opcode)
86 {
87 case GF_OP_LEVELCOMPLETE:
88 if(World_GetPlayer())
89 {
90 luaL_dostring(engine_lua, "saved_inventory = getItems(player);");
91 }
92 if(Gameflow_SetGameInternal(global_gameflow.m_currentGameID, global_gameflow.m_currentLevelID + 1) && World_GetPlayer())
93 {
94 luaL_dostring(engine_lua, "if(saved_inventory ~= nil) then\n"
95 "removeAllItems(player);\n"
96 "for k, v in pairs(saved_inventory) do\n"
97 "addItem(player, k, v);\n"
98 "end;\n"
99 "saved_inventory = nil;\n"
100 "end;");
101 }
102 break;
103
104 case GF_OP_SETTRACK:
105 Audio_StreamPlay(it.m_operand);
106 break;
107
108 case GF_OP_STARTFMV:
109 if(Gameflow_GetFMVPath(&info, it.m_operand))
110 {
111 Engine_PlayVideo(info.path);
112 }
113 break;
114
115 case GF_NOENTRY:
116 continue;
117
118 default:
119 //Con_Printf("Unimplemented gameflow opcode: %i", global_gameflow.m_actions[i].m_opcode);
120 break;
121 }; // end switch(gameflow_manager.Operand)
122 }
123
124 if(global_gameflow.m_nextGameID >= 0)
125 {
126 Gameflow_SetGameInternal(global_gameflow.m_nextGameID, global_gameflow.m_nextLevelID);
127 global_gameflow.m_nextGameID = -1;
128 global_gameflow.m_nextLevelID = -1;
129 }
130 }
131
132
Gameflow_SetMap(const char * filePath,int game_id,int level_id)133 bool Gameflow_SetMap(const char* filePath, int game_id, int level_id)
134 {
135 level_info_t info;
136 if(Gameflow_GetLevelInfo(&info, game_id, level_id))
137 {
138 level_id = (level_id <= info.num_levels) ? (level_id) : (1);
139 if(!Gui_LoadScreenAssignPic(info.pic))
140 {
141 Gui_LoadScreenAssignPic("resource/graphics/legal");
142 }
143 }
144
145 strncpy(global_gameflow.m_currentLevelPath, filePath, MAX_ENGINE_PATH);
146 global_gameflow.m_currentGameID = game_id;
147 global_gameflow.m_currentLevelID = level_id;
148
149 return Engine_LoadMap(filePath);
150 }
151
152
Gameflow_SetGame(int game_id,int level_id)153 bool Gameflow_SetGame(int game_id, int level_id)
154 {
155 global_gameflow.m_nextGameID = game_id;
156 global_gameflow.m_nextLevelID = level_id;
157 return true;
158 }
159
160
Gameflow_GetLevelInfo(level_info_p info,int game_id,int level_id)161 bool Gameflow_GetLevelInfo(level_info_p info, int game_id, int level_id)
162 {
163 int top = lua_gettop(engine_lua);
164
165 lua_getglobal(engine_lua, "gameflow_params");
166 if(!lua_istable(engine_lua, -1))
167 {
168 lua_settop(engine_lua, top);
169 return false;
170 }
171
172 lua_rawgeti(engine_lua, -1, game_id);
173 if(!lua_istable(engine_lua, -1))
174 {
175 lua_settop(engine_lua, top);
176 return false;
177 }
178
179 lua_getfield(engine_lua, -1, "title");
180 strncpy(info->pic, lua_tostring(engine_lua, -1), MAX_ENGINE_PATH);
181 lua_pop(engine_lua, 1);
182
183 lua_getfield(engine_lua, -1, "numlevels");
184 info->num_levels = lua_tointeger(engine_lua, -1);
185 lua_pop(engine_lua, 1);
186
187 lua_getfield(engine_lua, -1, "levels");
188 if(!lua_istable(engine_lua, -1))
189 {
190 lua_settop(engine_lua, top);
191 return false;
192 }
193
194 level_id = (level_id <= info->num_levels) ? (level_id) : (1);
195 lua_rawgeti(engine_lua, -1, level_id);
196 if(!lua_istable(engine_lua, -1))
197 {
198 lua_settop(engine_lua, top);
199 return false;
200 }
201
202 lua_getfield(engine_lua, -1, "name");
203 strncpy(info->name, lua_tostring(engine_lua, -1), LEVEL_NAME_MAX_LEN);
204 lua_pop(engine_lua, 1);
205
206 lua_getfield(engine_lua, -1, "filepath");
207 strncpy(info->path, lua_tostring(engine_lua, -1), MAX_ENGINE_PATH);
208 lua_pop(engine_lua, 1);
209
210 lua_getfield(engine_lua, -1, "picpath");
211 strncpy(info->pic, lua_tostring(engine_lua, -1), MAX_ENGINE_PATH);
212 lua_pop(engine_lua, 1);
213
214 lua_pop(engine_lua, 1); // level_id
215 lua_pop(engine_lua, 1); // levels
216
217 lua_pop(engine_lua, 1); // game_id
218 lua_settop(engine_lua, top);
219
220 return true;
221 }
222
223
Gameflow_GetFMVPath(level_info_p info,int fmv_id)224 bool Gameflow_GetFMVPath(level_info_p info, int fmv_id)
225 {
226 int top = lua_gettop(engine_lua);
227
228 lua_getglobal(engine_lua, "gameflow_params");
229 if(!lua_istable(engine_lua, -1))
230 {
231 lua_settop(engine_lua, top);
232 return false;
233 }
234
235 lua_rawgeti(engine_lua, -1, global_gameflow.m_currentGameID);
236 if(!lua_istable(engine_lua, -1))
237 {
238 lua_settop(engine_lua, top);
239 return false;
240 }
241
242 lua_getfield(engine_lua, -1, "fmv");
243 if(!lua_istable(engine_lua, -1))
244 {
245 lua_settop(engine_lua, top);
246 return false;
247 }
248
249 lua_rawgeti(engine_lua, -1, fmv_id);
250 if(!lua_istable(engine_lua, -1))
251 {
252 lua_settop(engine_lua, top);
253 return false;
254 }
255
256 lua_getfield(engine_lua, -1, "name");
257 strncpy(info->name, lua_tostring(engine_lua, -1), LEVEL_NAME_MAX_LEN);
258 lua_pop(engine_lua, 1);
259
260 lua_getfield(engine_lua, -1, "filepath");
261 strncpy(info->path, lua_tostring(engine_lua, -1), MAX_ENGINE_PATH);
262 lua_pop(engine_lua, 1);
263
264 lua_pop(engine_lua, 1); // fmv_id
265 lua_pop(engine_lua, 1); // fmv
266
267 lua_pop(engine_lua, 1); // game_id
268 lua_settop(engine_lua, top);
269
270 return true;
271 }
272
273
Gameflow_SetGameInternal(int game_id,int level_id)274 bool Gameflow_SetGameInternal(int game_id, int level_id)
275 {
276 level_info_t info;
277 if(Gameflow_GetLevelInfo(&info, game_id, level_id))
278 {
279 level_id = (level_id <= info.num_levels) ? (level_id) : (1);
280 if(!Gui_LoadScreenAssignPic(info.pic))
281 {
282 Gui_LoadScreenAssignPic("resource/graphics/legal");
283 }
284
285 global_gameflow.m_currentGameID = game_id;
286 global_gameflow.m_currentLevelID = level_id;
287 strncpy(global_gameflow.m_currentLevelName, info.name, LEVEL_NAME_MAX_LEN);
288 strncpy(global_gameflow.m_currentLevelPath, info.path, MAX_ENGINE_PATH);
289 return Engine_LoadMap(info.path);
290 }
291
292 return false;
293 }
294
295
Gameflow_GetCurrentLevelPathLocal()296 const char *Gameflow_GetCurrentLevelPathLocal()
297 {
298 return global_gameflow.m_currentLevelPath + strlen(Engine_GetBasePath());
299 }
300
301
Gameflow_GetCurrentGameID()302 uint8_t Gameflow_GetCurrentGameID()
303 {
304 return global_gameflow.m_currentGameID;
305 }
306
307
Gameflow_GetCurrentLevelID()308 uint8_t Gameflow_GetCurrentLevelID()
309 {
310 return global_gameflow.m_currentLevelID;
311 }
312
313
Gameflow_ResetSecrets()314 void Gameflow_ResetSecrets()
315 {
316 memset(global_gameflow.m_secretsTriggerMap, 0, GF_MAX_SECRETS * sizeof(*global_gameflow.m_secretsTriggerMap));
317 }
318
319
Gameflow_SetSecretStateAtIndex(int index,int value)320 void Gameflow_SetSecretStateAtIndex(int index, int value)
321 {
322 assert((index >= 0) && index <= (GF_MAX_SECRETS));
323 global_gameflow.m_secretsTriggerMap[index] = (char)value; ///@FIXME should not cast.
324 }
325
326
Gameflow_GetSecretStateAtIndex(int index)327 int Gameflow_GetSecretStateAtIndex(int index)
328 {
329 assert((index >= 0) && index <= (GF_MAX_SECRETS));
330 return global_gameflow.m_secretsTriggerMap[index];
331 }