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