1 
2 #include <stdlib.h>
3 #include <stdio.h>
4 
5 extern "C" {
6 #include <lua.h>
7 #include <lualib.h>
8 #include <lauxlib.h>
9 }
10 
11 #include "core/system.h"
12 #include "core/console.h"
13 #include "core/vmath.h"
14 #include "core/polygon.h"
15 #include "core/obb.h"
16 #include "render/camera.h"
17 #include "render/frustum.h"
18 #include "render/render.h"
19 #include "gui/gui_inventory.h"
20 #include "script/script.h"
21 #include "vt/tr_versions.h"
22 #include "audio/audio.h"
23 #include "engine.h"
24 #include "controls.h"
25 #include "room.h"
26 #include "world.h"
27 #include "game.h"
28 #include "skeletal_model.h"
29 #include "entity.h"
30 #include "trigger.h"
31 #include "character_controller.h"
32 #include "gameflow.h"
33 #include "inventory.h"
34 
35 extern lua_State *engine_lua;
36 
37 int Save_Entity(entity_p ent, void *data);
38 
lua_mlook(lua_State * lua)39 int lua_mlook(lua_State * lua)
40 {
41     if(lua_gettop(lua) == 0)
42     {
43         control_states.mouse_look = !control_states.mouse_look;
44         Con_Printf("mlook = %d", control_states.mouse_look);
45         return 0;
46     }
47 
48     control_states.mouse_look = lua_tointeger(lua, 1);
49     Con_Printf("mlook = %d", control_states.mouse_look);
50     return 0;
51 }
52 
53 
lua_freelook(lua_State * lua)54 int lua_freelook(lua_State * lua)
55 {
56     if(lua_gettop(lua) == 0)
57     {
58         control_states.free_look = !control_states.free_look;
59         Con_Printf("free_look = %d", control_states.free_look);
60         return 0;
61     }
62 
63     control_states.free_look = lua_tointeger(lua, 1);
64     Con_Printf("free_look = %d", control_states.free_look);
65     return 0;
66 }
67 
68 
lua_cam_distance(lua_State * lua)69 int lua_cam_distance(lua_State * lua)
70 {
71     if(lua_gettop(lua) == 0)
72     {
73         Con_Printf("cam_distance = %.2f", control_states.cam_distance);
74         return 0;
75     }
76 
77     control_states.cam_distance = lua_tonumber(lua, 1);
78     Con_Printf("cam_distance = %.2f", control_states.cam_distance);
79     return 0;
80 }
81 
82 
lua_noclip(lua_State * lua)83 int lua_noclip(lua_State * lua)
84 {
85     if(lua_gettop(lua) == 0)
86     {
87         control_states.noclip = !control_states.noclip;
88     }
89     else
90     {
91         control_states.noclip = lua_tointeger(lua, 1);
92     }
93 
94     Con_Printf("noclip = %d", control_states.noclip);
95     return 0;
96 }
97 
98 
Game_InitGlobals()99 void Game_InitGlobals()
100 {
101     control_states.free_look_speed = 3000.0;
102     control_states.mouse_look = 1;
103     control_states.free_look = 0;
104     control_states.noclip = 0;
105     control_states.cam_distance = 800.0;
106 }
107 
108 
Game_RegisterLuaFunctions(struct lua_State * lua)109 void Game_RegisterLuaFunctions(struct lua_State *lua)
110 {
111     if(lua != NULL)
112     {
113         lua_register(lua, "mlook", lua_mlook);
114         lua_register(lua, "freelook", lua_freelook);
115         lua_register(lua, "cam_distance", lua_cam_distance);
116         lua_register(lua, "noclip", lua_noclip);
117     }
118 }
119 
120 
121 /**
122  * Load game state
123  */
Game_Load(const char * name)124 int Game_Load(const char* name)
125 {
126     FILE *f;
127     char *ch, local;
128 
129     local = 1;
130     for(ch = (char*)name; *ch; ch++)
131     {
132         if((*ch == '\\') || (*ch == '/'))
133         {
134             local = 0;
135             break;
136         }
137     }
138 
139     if(local)
140     {
141         char save_path[1024];
142         size_t save_path_base_len = sizeof(save_path) - 1;
143         strncpy(save_path, Engine_GetBasePath(), save_path_base_len);
144         save_path[save_path_base_len] = 0;
145         strncat(save_path, "save/", save_path_base_len - strlen(save_path));
146         strncat(save_path, name, save_path_base_len - strlen(save_path));
147         if(!Sys_FileFound(save_path, 0))
148         {
149             Sys_extWarn("Can not read file \"%s\"", save_path);
150             return 0;
151         }
152         Script_LuaClearTasks();
153         luaL_dofile(engine_lua, save_path);
154     }
155     else
156     {
157         f = fopen(name, "rb");
158         if(f == NULL)
159         {
160             Sys_extWarn("Can not read file \"%s\"", name);
161             return 0;
162         }
163         fclose(f);
164         Script_LuaClearTasks();
165         luaL_dofile(engine_lua, name);
166     }
167 
168     return 1;
169 }
170 
171 /**
172  * Entity save function, based on engine lua scripts;
173  */
Save_Entity(entity_p ent,void * data)174 int Save_Entity(entity_p ent, void *data)
175 {
176     if(ent)
177     {
178         FILE **f = (FILE**)data;
179         if(ent->type_flags & ENTITY_TYPE_SPAWNED)
180         {
181             uint32_t room_id = (ent->self->room) ? (ent->self->room->id) : (0xFFFFFFFF);
182             fprintf(*f, "\nspawnEntity(%d, 0x%X, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d);", ent->bf->animations.model->id, room_id,
183                     ent->transform.M4x4[12 + 0], ent->transform.M4x4[12 + 1], ent->transform.M4x4[12 + 2],
184                     ent->transform.angles[0], ent->transform.angles[1], ent->transform.angles[2], ent->id);
185         }
186         else
187         {
188             fprintf(*f, "\nsetEntityPos(%d, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f);", ent->id,
189                     ent->transform.M4x4[12 + 0], ent->transform.M4x4[12 + 1], ent->transform.M4x4[12 + 2],
190                     ent->transform.angles[0], ent->transform.angles[1], ent->transform.angles[2]);
191         }
192 
193         if(ent->self->room)
194         {
195             fprintf(*f, "\nsetEntityRoomMove(%d, %d, %d, %d);", ent->id, ent->self->room->id, ent->move_type, ent->dir_flag);
196         }
197         else
198         {
199             fprintf(*f, "\nsetEntityRoomMove(%d, nil, %d, %d);", ent->id, ent->move_type, ent->dir_flag);
200         }
201 
202         if(ent->bf->animations.model && ent->character)
203         {
204             fprintf(*f, "\nsetEntityBaseAnimModel(%d, %d);", ent->id, ent->bf->animations.model->id);
205         }
206 
207         if(ent->activation_point)
208         {
209             activation_point_p ap = ent->activation_point;
210             fprintf(*f, "\nsetEntityActivationOffset(%d, %.4f, %.4f, %.4f, %.4f);", ent->id, ap->offset[0], ap->offset[1], ap->offset[2], ap->offset[3]);
211             fprintf(*f, "\nsetEntityActivationDirection(%d, %.4f, %.4f, %.4f, %.4f);", ent->id, ap->direction[0], ap->direction[1], ap->direction[2], ap->direction[3]);
212         }
213 
214         for(uint16_t i = 0; i < ent->bf->bone_tag_count; ++i)
215         {
216             ss_bone_tag_p b_tag = ent->bf->bone_tags + i;
217             if(b_tag->is_hidden)
218             {
219                 fprintf(*f, "\nsetEntityBoneVisibility(%d, %d, false);", ent->id, i);
220             }
221             if(ent->character)
222             {
223                 if(b_tag->is_targeted)
224                 {
225                     fprintf(*f, "\nentitySSAnimSetTarget(%d, %d, %.2f, %.2f, %.2f, %.6f, %.6f, %.6f);", ent->id, i,
226                         b_tag->mod.target[0], b_tag->mod.target[1], b_tag->mod.target[2],
227                         b_tag->mod.direction[0], b_tag->mod.direction[1], b_tag->mod.direction[2]);
228                 }
229                 if(b_tag->is_axis_modded)
230                 {
231                     fprintf(*f, "\nentitySSAnimSetAxisMod(%d, %d, %.6f, %.6f, %.6f);", ent->id, i,
232                         b_tag->mod.axis_mod[0], b_tag->mod.axis_mod[1], b_tag->mod.axis_mod[2]);
233                 }
234                 fprintf(*f, "\nentitySSAnimSetTargetingLimit(%d, %d, %.6f, %.6f, %.6f, %.6f);", ent->id, i,
235                     b_tag->mod.limit[0], b_tag->mod.limit[1], b_tag->mod.limit[2], b_tag->mod.limit[3]);
236                 fprintf(*f, "\nentitySSAnimSetCurrentRotation(%d, %d, %.6f, %.6f, %.6f, %.6f);", ent->id, i,
237                     b_tag->mod.current[0], b_tag->mod.current[1], b_tag->mod.current[2], b_tag->mod.current[3]);
238             }
239         }
240 
241         char save_buff[32768] = {0};
242         if(Script_GetEntitySaveData(engine_lua, ent->id, save_buff, sizeof(save_buff)) > 0)
243         {
244             fprintf(*f, "\n%s", save_buff);
245         }
246 
247         ss_animation_p ss_anim = &ent->bf->animations;
248         for(; ss_anim->next; ss_anim = ss_anim->next);
249 
250         for(; ss_anim; ss_anim = ss_anim->prev)
251         {
252             if(ss_anim->type != ANIM_TYPE_BASE)
253             {
254                 if(ss_anim->model)
255                 {
256                     fprintf(*f, "\nentitySSAnimEnsureExists(%d, %d, %d);", ent->id, ss_anim->type, ss_anim->model->id);
257                 }
258                 else
259                 {
260                     fprintf(*f, "\nentitySSAnimEnsureExists(%d, %d, nil);", ent->id, ss_anim->type);
261                 }
262             }
263         }
264 
265         fprintf(*f, "\nremoveAllItems(%d);", ent->id);
266         for(inventory_node_p i = ent->inventory; i; i = i->next)
267         {
268             fprintf(*f, "\naddItem(%d, %d, %d);", ent->id, i->id, i->count);
269         }
270 
271         if(ent->character)
272         {
273             fprintf(*f, "\nsetCharacterClimbPoint(%d, %.2f, %.2f, %.2f);", ent->id,
274                     ent->character->climb.point[0], ent->character->climb.point[1], ent->character->climb.point[2]);
275             if(ent->character->target_id != ENTITY_ID_NONE)
276             {
277                 fprintf(*f, "\nsetCharacterTarget(%d, %d);", ent->id, ent->character->target_id);
278             }
279             else
280             {
281                 fprintf(*f, "\nsetCharacterTarget(%d);", ent->id);
282             }
283 
284             fprintf(*f, "\nsetCharacterWeaponModel(%d, %d, %d);", ent->id, ent->character->weapon_id, ent->character->weapon_state);
285             for(int i = 0; i < PARAM_LASTINDEX; i++)
286             {
287                 fprintf(*f, "\nsetCharacterParam(%d, %d, %.2f, %.2f);", ent->id, i, ent->character->parameters.param[i], ent->character->parameters.maximum[i]);
288             }
289         }
290 
291         fprintf(*f, "\nsetEntityLinearSpeed(%d, %.2f);", ent->id, ent->linear_speed);
292         fprintf(*f, "\nsetEntitySpeed(%d, %.2f, %.2f, %.2f);", ent->id, ent->speed[0], ent->speed[1], ent->speed[2]);
293 
294         fprintf(*f, "\nsetEntityFlags(%d, 0x%.4X, 0x%.4X, 0x%.8X);", ent->id, ent->state_flags, ent->type_flags, ent->callback_flags);
295         fprintf(*f, "\nsetEntityCollisionFlags(%d, %d, %d, %d);", ent->id, ent->self->collision_group, ent->self->collision_shape, ent->self->collision_mask);
296         fprintf(*f, "\nsetEntityTriggerLayout(%d, 0x%.2X);", ent->id, ent->trigger_layout);
297         fprintf(*f, "\nsetEntityTimer(%d, %.3f);", ent->id, ent->timer);
298 
299         for(ss_anim = &ent->bf->animations; ss_anim; ss_anim = ss_anim->next)
300         {
301             if(ss_anim->model)
302             {
303                 fprintf(*f, "\nsetEntityAnim(%d, %d, %d, %d, %d, %d);", ent->id, ss_anim->type, ss_anim->next_animation, ss_anim->next_frame, ss_anim->current_animation, ss_anim->current_frame);
304                 fprintf(*f, "\nsetEntityAnimStateHeavy(%d, %d, %d);", ent->id, ss_anim->type, ss_anim->next_state_heavy);
305                 fprintf(*f, "\nsetEntityAnimState(%d, %d, %d);", ent->id, ss_anim->type, ss_anim->next_state);
306                 fprintf(*f, "\nentitySSAnimSetExtFlags(%d, %d, %d, %d);", ent->id, ss_anim->type, ss_anim->enabled, ss_anim->anim_ext_flags);
307                 fprintf(*f, "\nentitySSAnimSetEnable(%d, %d, %d);", ent->id, ss_anim->type, ss_anim->enabled);
308             }
309         }
310 
311         if(ent->no_fix_all)
312         {
313             fprintf(*f, "\nnoFixEntityCollision(%d, true);", ent->id);
314         }
315         if(ent->no_move)
316         {
317             fprintf(*f, "\nnoEntityMove(%d, true);", ent->id);
318         }
319     }
320 
321     return 0;
322 }
323 
324 /**
325  * Save current game state
326  */
Game_Save(const char * name)327 int Game_Save(const char* name)
328 {
329     FILE *f;
330     char local;
331 
332     local = 1;
333     for(const char *ch = name; *ch; ch++)
334     {
335         if((*ch == '\\') || (*ch == '/'))
336         {
337             local = 0;
338             break;
339         }
340     }
341 
342     if(local)
343     {
344         char save_path[1024];
345         size_t save_path_base_len = sizeof(save_path) - 1;
346         strncpy(save_path, Engine_GetBasePath(), save_path_base_len);
347         save_path[save_path_base_len] = 0;
348         strncat(save_path, "save/", save_path_base_len - strlen(save_path));
349         strncat(save_path, name, save_path_base_len - strlen(save_path));
350         f = fopen(save_path, "wb");
351     }
352     else
353     {
354         f = fopen(name, "wb");
355     }
356 
357     if(!f)
358     {
359         Sys_extWarn("Can not create file \"%s\"", name);
360         return 0;
361     }
362 
363     fprintf(f, "loadMap(\"%s\", %d, %d);\n", Gameflow_GetCurrentLevelPathLocal(), Gameflow_GetCurrentGameID(), Gameflow_GetCurrentLevelID());
364 
365     // Save flipmap and flipped room states.
366     uint8_t *flip_map;
367     uint8_t *flip_state;
368     uint32_t flip_count;
369     World_GetFlipInfo(&flip_map, &flip_state, &flip_count);
370     for(uint32_t i = 0; i < flip_count; i++)
371     {
372         fprintf(f, "setFlipMap(%d, 0x%02X, 0);\n", i, flip_map[i]);
373         fprintf(f, "setFlipState(%d, %d);\n", i, flip_state[i]);
374     }
375     if(World_GetVersion() < TR_IV)
376     {
377         fprintf(f, "setGlobalFlipState(%d);\n", (int)World_GetGlobalFlipState());
378     }
379 
380     int id = 0;
381     room_p r = World_GetRoomByID(id);
382     while(r)
383     {
384         if(r->alternate_room_next || r->alternate_room_prev)
385         {
386             fprintf(f, "setRoomActiveContent(%d, %d);\n", id, r->content->original_room_id);
387         }
388         r = World_GetRoomByID(++id);
389     }
390 
391     char save_buffer[32768] = {0};
392     if(Script_GetFlipEffectsSaveData(engine_lua, save_buffer, sizeof(save_buffer)) > 0)
393     {
394         fprintf(f, "\n%s\n", save_buffer);
395     }
396 
397     World_IterateAllEntities(&Save_Entity, &f);
398 
399     fclose(f);
400 
401     return 1;
402 }
403 
404 
Game_ApplyControls(struct entity_s * ent)405 void Game_ApplyControls(struct entity_s *ent)
406 {
407     int8_t move_logic[3];
408     int8_t look_logic[3];
409 
410     // Keyboard move logic
411 
412     move_logic[0] = control_states.move_forward - control_states.move_backward;
413     move_logic[1] = control_states.move_right - control_states.move_left;
414     move_logic[2] = control_states.move_up - control_states.move_down;
415 
416     // Keyboard look logic
417 
418     look_logic[0] = control_states.look_left - control_states.look_right;
419     look_logic[1] = control_states.look_down - control_states.look_up;
420     look_logic[2] = control_states.look_roll_right - control_states.look_roll_left;
421 
422     // APPLY CONTROLS
423 
424     control_states.cam_angles[0] += 2.2 * engine_frame_time * look_logic[0];
425     control_states.cam_angles[1] += 2.2 * engine_frame_time * look_logic[1];
426     control_states.cam_angles[2] += 2.2 * engine_frame_time * look_logic[2];
427 
428     if(!World_GetRoomByID(0))
429     {
430         if(control_mapper.use_joy)
431         {
432             if(control_mapper.joy_look_x != 0)
433             {
434                 control_states.cam_angles[0] -=0.015 * engine_frame_time * control_mapper.joy_look_x;
435 
436             }
437             if(control_mapper.joy_look_y != 0)
438             {
439                 control_states.cam_angles[1] -=0.015 * engine_frame_time * control_mapper.joy_look_y;
440             }
441         }
442 
443         if(control_states.mouse_look != 0)
444         {
445             control_states.cam_angles[0] -= 0.015 * control_states.look_axis_x;
446             control_states.cam_angles[1] -= 0.015 * control_states.look_axis_y;
447             control_states.look_axis_x = 0.0;
448             control_states.look_axis_y = 0.0;
449         }
450 
451         Cam_SetRotation(&engine_camera, control_states.cam_angles);
452         float dist = (control_states.state_walk) ? (control_states.free_look_speed * engine_frame_time * 0.3f) : (control_states.free_look_speed * engine_frame_time);
453         Cam_MoveAlong(&engine_camera, dist * move_logic[0]);
454         Cam_MoveStrafe(&engine_camera, dist * move_logic[1]);
455         Cam_MoveVertical(&engine_camera, dist * move_logic[2]);
456 
457         return;
458     }
459 
460     if(control_mapper.use_joy)
461     {
462         if(control_mapper.joy_look_x != 0)
463         {
464             control_states.cam_angles[0] -=engine_frame_time * control_mapper.joy_look_x;
465         }
466         if(control_mapper.joy_look_y != 0)
467         {
468             control_states.cam_angles[1] -=engine_frame_time * control_mapper.joy_look_y;
469         }
470     }
471 
472     if(control_states.mouse_look != 0)
473     {
474         control_states.cam_angles[0] -= 0.015 * control_states.look_axis_x;
475         control_states.cam_angles[1] -= 0.015 * control_states.look_axis_y;
476         control_states.look_axis_x = 0.0;
477         control_states.look_axis_y = 0.0;
478     }
479 
480     if(control_states.free_look || !ent || !ent->character)
481     {
482         float dist = (control_states.state_walk) ? (control_states.free_look_speed * engine_frame_time * 0.3f) : (control_states.free_look_speed * engine_frame_time);
483         Cam_SetRotation(&engine_camera, control_states.cam_angles);
484         Cam_MoveAlong(&engine_camera, dist * move_logic[0]);
485         Cam_MoveStrafe(&engine_camera, dist * move_logic[1]);
486         Cam_MoveVertical(&engine_camera, dist * move_logic[2]);
487         engine_camera.current_room = World_FindRoomByPosCogerrence(engine_camera.transform.M4x4 + 12, engine_camera.current_room);
488     }
489     else if(control_states.noclip)
490     {
491         float pos[3];
492         float dist = (control_states.state_walk) ? (control_states.free_look_speed * engine_frame_time * 0.3f) : (control_states.free_look_speed * engine_frame_time);
493         Cam_SetRotation(&engine_camera, control_states.cam_angles);
494         Cam_MoveAlong(&engine_camera, dist * move_logic[0]);
495         Cam_MoveStrafe(&engine_camera, dist * move_logic[1]);
496         Cam_MoveVertical(&engine_camera, dist * move_logic[2]);
497         engine_camera.current_room = World_FindRoomByPosCogerrence(engine_camera.transform.M4x4 + 12, engine_camera.current_room);
498 
499         ent->transform.angles[0] = 180.0 * control_states.cam_angles[0] / M_PI;
500         pos[0] = engine_camera.transform.M4x4[12 + 0] + engine_camera.transform.M4x4[8 + 0] * control_states.cam_distance;
501         pos[1] = engine_camera.transform.M4x4[12 + 1] + engine_camera.transform.M4x4[8 + 1] * control_states.cam_distance;
502         pos[2] = engine_camera.transform.M4x4[12 + 2] + engine_camera.transform.M4x4[8 + 2] * control_states.cam_distance - 512.0f;
503         vec3_copy(ent->transform.M4x4 + 12, pos);
504         Entity_UpdateTransform(ent);
505         Entity_UpdateRoomPos(ent);
506         Entity_UpdateRigidBody(ent, 1);
507         Entity_GhostUpdate(ent);
508         Entity_FixPenetrations(ent, NULL, NULL, COLLISION_FILTER_CHARACTER);
509     }
510     else
511     {
512         // Apply controls to Lara
513         ent->character->cmd.action = control_states.state_action;
514         ent->character->cmd.ready_weapon = control_states.do_draw_weapon;
515         ent->character->cmd.jump = control_states.do_jump;
516         ent->character->cmd.shift = control_states.state_walk;
517 
518         ent->character->cmd.roll = ((control_states.move_forward && control_states.move_backward) || control_states.do_roll);
519 
520         // New commands only for TR3 and above
521         ent->character->cmd.sprint = control_states.state_sprint;
522         ent->character->cmd.crouch = control_states.state_crouch;
523 
524         if(control_states.use_small_medi)
525         {
526             Script_UseItem(engine_lua, ITEM_SMALL_MEDIPACK, ent->id);
527             control_states.use_small_medi = 0;
528         }
529 
530         if(control_states.use_big_medi)
531         {
532             Script_UseItem(engine_lua, ITEM_LARGE_MEDIPACK, ent->id);
533             control_states.use_big_medi = 0;
534         }
535 
536         if((control_mapper.use_joy == 1) && (control_mapper.joy_move_x != 0))
537         {
538             ent->character->cmd.rot[0] = (control_mapper.joy_move_x > 0) ? (-1) : (1);
539         }
540         else
541         {
542             ent->character->cmd.rot[0] = -move_logic[1];
543         }
544 
545         if( (control_mapper.use_joy == 1) && (control_mapper.joy_move_y != 0 ) )
546         {
547             ent->character->cmd.rot[1] = (control_mapper.joy_move_y > 0) ? (-1) : (1);
548         }
549         else
550         {
551             ent->character->cmd.rot[1] = move_logic[0];
552         }
553 
554         vec3_copy(ent->character->cmd.move, move_logic);
555     }
556 }
557 
558 
Game_UpdateEntity(entity_p ent,void * data)559 int Game_UpdateEntity(entity_p ent, void *data)
560 {
561     if(ent && (ent != World_GetPlayer()) && (!ent->self->room || (ent->self->room == ent->self->room->real_room)))
562     {
563         if(ent->character)
564         {
565             Character_Update(ent);
566         }
567         if(ent->state_flags & ENTITY_STATE_ENABLED)
568         {
569             Entity_ProcessSector(ent);
570             Script_LoopEntity(engine_lua, ent);
571         }
572         Entity_Frame(ent, engine_frame_time);
573         Entity_UpdateRigidBody(ent, ent->character != NULL);
574         Entity_UpdateRoomPos(ent);
575     }
576 
577     return 0;
578 }
579 
580 
Game_Frame(float time)581 void Game_Frame(float time)
582 {
583     entity_p player = World_GetPlayer();
584 
585     // GUI and controls should be updated at all times!
586     if(!Con_IsShown() && control_states.gui_inventory && main_inventory_manager)
587     {
588         if(player &&
589           (main_inventory_manager->getCurrentState() == gui_InventoryManager::INVENTORY_DISABLED))
590         {
591             main_inventory_manager->setInventory(&player->inventory, player->id);
592             main_inventory_manager->send(gui_InventoryManager::INVENTORY_OPEN);
593         }
594         if(main_inventory_manager->getCurrentState() == gui_InventoryManager::INVENTORY_IDLE)
595         {
596             main_inventory_manager->send(gui_InventoryManager::INVENTORY_CLOSE);
597         }
598     }
599 
600     // If console or inventory is active, only thing to update is audio.
601     if(Con_IsShown() || main_inventory_manager->getCurrentState() != gui_InventoryManager::INVENTORY_DISABLED)
602     {
603         return;
604     }
605 
606     // In game mode
607     Script_DoTasks(engine_lua, time);
608 
609     // This must be called EVERY frame to max out smoothness.
610     // Includes animations, camera movement, and so on.
611     if(player && player->character)
612     {
613         if(engine_camera_state.state != CAMERA_STATE_FLYBY)
614         {
615             Game_ApplyControls(player);
616         }
617         else
618         {
619             memset(&player->character->cmd, 0x00, sizeof(player->character->cmd));
620         }
621 
622         if(!control_states.noclip)
623         {
624             Character_Update(player);
625             Script_LoopEntity(engine_lua, player);   ///@TODO: fix that hack (refactoring)
626             if(player->character->target_id == ENTITY_ID_NONE)
627             {
628                 entity_p target = Character_FindTarget(player);
629                 if(target)
630                 {
631                     player->character->target_id = target->id;
632                 }
633             }
634             else if(player->character->weapon_state != WEAPON_STATE_HIDE)
635             {
636                 entity_p target = World_GetEntityByID(player->character->target_id);
637                 if(!target || !Character_IsTargetAccessible(player, target))
638                 {
639                     player->character->target_id = ENTITY_ID_NONE;
640                 }
641             }
642         }
643         Entity_Frame(player, time);
644         Entity_UpdateRigidBody(player, 1);
645         Entity_UpdateRoomPos(player);
646     }
647     else if(control_states.free_look)
648     {
649         Game_ApplyControls(NULL);
650     }
651 
652     if(control_states.look)
653     {
654         if(engine_camera_state.state == CAMERA_STATE_FLYBY)
655         {
656             engine_camera_state.state = CAMERA_STATE_NORMAL;
657             Cam_SetFovAspect(&engine_camera, screen_info.fov, engine_camera.aspect);
658         }
659         engine_camera_state.time = 0.0f;
660     }
661 
662     if(!control_states.noclip && !control_states.free_look)
663     {
664         entity_p target = World_GetEntityByID(engine_camera_state.target_id);
665         target = (target) ? (target) : (player);
666         if(engine_camera_state.state == CAMERA_STATE_FLYBY)
667         {
668             Cam_PlayFlyBy(&engine_camera_state, time);
669         }
670         else
671         {
672             if(engine_camera_state.sink)
673             {
674                 if(engine_camera_state.move)
675                 {
676                     Cam_MoveTo(&engine_camera, engine_camera_state.sink->pos, engine_frame_time * TR_METERING_SECTORSIZE * (float)engine_camera_state.move);
677                 }
678                 else
679                 {
680                     vec3_copy(engine_camera.transform.M4x4 + 12, engine_camera_state.sink->pos);
681                 }
682 
683                 if(target)
684                 {
685                     float pos[3];
686                     if(target->character)
687                     {
688                         Mat4_vec3_mul(pos, target->transform.M4x4, target->bf->bone_tags[target->character->bone_head].full_transform + 12);
689                     }
690                     else
691                     {
692                         vec3_copy(pos, target->transform.M4x4 + 12);
693                     }
694                     Cam_LookTo(&engine_camera, pos);
695                 }
696             }
697             else if(player)
698             {
699                 engine_camera_state.entity_offset_x = 16.0f;
700                 engine_camera_state.entity_offset_z = 128.0f;
701                 Cam_FollowEntity(&engine_camera, &engine_camera_state, player);
702                 if(!control_states.look && target && (engine_camera_state.state == CAMERA_STATE_LOOK_AT))
703                 {
704                     Character_LookAt(player, target->transform.M4x4 + 12);
705                     Cam_LookTo(&engine_camera, target->transform.M4x4 + 12);
706                 }
707                 else
708                 {
709                     Character_ClearLookAt(player);
710                 }
711             }
712 
713             engine_camera_state.time -= engine_frame_time;
714             if(engine_camera_state.time < 0.0f)
715             {
716                 if(target && (engine_camera_state.state == CAMERA_STATE_LOOK_AT))
717                 {
718                     target->state_flags |= ENTITY_STATE_NO_CAM_TARGETABLE;
719                 }
720                 engine_camera_state.state = CAMERA_STATE_NORMAL;
721                 engine_camera_state.time = 0.0f;
722                 engine_camera_state.move = 0;
723                 engine_camera_state.sink = NULL;
724                 engine_camera_state.target_id = ENTITY_ID_NONE;
725                 Cam_SetFovAspect(&engine_camera, screen_info.fov, engine_camera.aspect);
726             }
727         }
728     }
729 
730     World_IterateAllEntities(Game_UpdateEntity, NULL);
731 
732     Physics_StepSimulation(time);
733 
734     Controls_RefreshStates();
735     renderer.UpdateAnimTextures();
736 }
737 
738 
Game_Prepare()739 void Game_Prepare()
740 {
741     entity_p player = World_GetPlayer();
742     if(player && player->character)
743     {
744         // Set character values to default.
745 
746         Character_SetParamMaximum(player, PARAM_HEALTH , LARA_PARAM_HEALTH_MAX );
747         Character_SetParam       (player, PARAM_HEALTH , LARA_PARAM_HEALTH_MAX );
748         Character_SetParamMaximum(player, PARAM_AIR    , LARA_PARAM_AIR_MAX    );
749         Character_SetParam       (player, PARAM_AIR    , LARA_PARAM_AIR_MAX    );
750         Character_SetParamMaximum(player, PARAM_STAMINA, LARA_PARAM_STAMINA_MAX);
751         Character_SetParam       (player, PARAM_STAMINA, LARA_PARAM_STAMINA_MAX);
752         Character_SetParamMaximum(player, PARAM_WARMTH,  LARA_PARAM_WARMTH_MAX );
753         Character_SetParam       (player, PARAM_WARMTH , LARA_PARAM_WARMTH_MAX );
754 
755         // Set character statistics to default.
756 
757         player->character->statistics.distance       = 0.0;
758         player->character->statistics.ammo_used      = 0;
759         player->character->statistics.hits           = 0;
760         player->character->statistics.kills          = 0;
761         player->character->statistics.medipacks_used = 0;
762         player->character->statistics.saves_used     = 0;
763         player->character->statistics.secrets_game   = 0;
764         player->character->statistics.secrets_level  = 0;
765 
766         vec3_copy(engine_camera.transform.M4x4 + 12, player->transform.M4x4 + 12);
767         engine_camera.transform.M4x4[12 + 2] += player->character->height;
768         engine_camera.transform.angles[0] = player->transform.angles[0] + 180.0f;
769         engine_camera.current_room = player->self->room;
770     }
771     else
772     {
773         // If there is no character present, move default camera position to
774         // the first room (useful for TR1-3 cutscene levels).
775         room_p room = World_GetRoomByID(0);
776         if(room)
777         {
778             engine_camera.transform.M4x4[12 + 0] = room->bb_max[0];
779             engine_camera.transform.M4x4[12 + 1] = room->bb_max[1];
780             engine_camera.transform.M4x4[12 + 2] = room->bb_max[2];
781         }
782     }
783 
784     // Set gameflow parameters to default.
785     // Reset secret trigger map.
786     Gameflow_ResetSecrets();///@UNIMPLEMENTED We should save the secrets to a save file prior to resetting!
787 }
788 
789 
Game_PlayFlyBy(uint32_t sequence_id,int once)790 void Game_PlayFlyBy(uint32_t sequence_id, int once)
791 {
792     if(engine_camera_state.state != CAMERA_STATE_FLYBY)
793     {
794         for(flyby_camera_sequence_p s = World_GetFlyBySequences(); s; s = s->next)
795         {
796             if((s->start->sequence == (int)sequence_id) && (!once || !s->locked))
797             {
798                 engine_camera_state.state = CAMERA_STATE_FLYBY;
799                 engine_camera_state.flyby = s;
800                 s->locked = (once != 0x00);
801                 engine_camera_state.time = 0.0f;
802                 break;
803             }
804         }
805     }
806 }
807 
808 
Game_SetCameraTarget(uint32_t entity_id)809 void Game_SetCameraTarget(uint32_t entity_id)
810 {
811     entity_p ent = World_GetEntityByID(entity_id);
812     engine_camera_state.move = 0;
813     engine_camera_state.target_id = entity_id;
814     if(ent && !engine_camera_state.sink && !(ent->state_flags & ENTITY_STATE_NO_CAM_TARGETABLE))
815     {
816         engine_camera_state.state = CAMERA_STATE_LOOK_AT;
817         engine_camera_state.time = 1.0f;
818     }
819 }
820 
821 
Game_SetCamera(uint32_t camera_id,int once,int move,float timer)822 void Game_SetCamera(uint32_t camera_id, int once, int move, float timer)
823 {
824     static_camera_sink_p sink = World_GetStaticCameraSink(camera_id);
825     if(sink && !sink->locked)
826     {
827         engine_camera_state.move = move;
828         engine_camera_state.time = timer;
829         engine_camera_state.sink = sink;
830         sink->locked |= 0x01 & once;
831         engine_camera_state.state = CAMERA_STATE_FIXED;
832         if(engine_camera_state.target_id == ENTITY_ID_NONE)
833         {
834             engine_camera_state.move = 4;
835         }
836     }
837 }
838 
839 
Game_StopFlyBy()840 void Game_StopFlyBy()
841 {
842     engine_camera_state.state = CAMERA_STATE_NORMAL;
843     engine_camera_state.flyby = NULL;
844     Cam_SetFovAspect(&engine_camera, screen_info.fov, engine_camera.aspect);
845 }
846