From db18b55fc324bfc9c69ba633b69aafbd8295b8d5 Mon Sep 17 00:00:00 2001 From: Lwmte Date: Sat, 23 May 2015 07:49:50 +0300 Subject: [PATCH] Updated animation speed/accel data types and flyby camera trigger type. By finding out EXTREMELY PERVERSE data type which was used by original programmers to store speed and accel values for animations, we have finally fixed almost all animation speeds, and made Lara movement even more genuine! Also, another important discovery is an extra bitu16 field after flyby camera trigger function operand, which contains some important flyby properties. Along the way, taking it into account fixes wrong trigger parsing in TR4-5. --- scripts/entity/entity_functions.lua | 22 +++++++++++++ scripts/entity/entity_properties.lua | 2 +- scripts/trigger/trigger_functions.lua | 4 +-- src/anim_state_control.cpp | 46 ++++++++++----------------- src/character_controller.cpp | 10 +++--- src/character_controller.h | 5 +-- src/engine.cpp | 2 +- src/engine.h | 7 ++-- src/entity.cpp | 39 ++++++++++++++++------- src/game.cpp | 16 +++++----- src/main_SDL.cpp | 2 +- src/mesh.h | 22 ++++++------- src/resource.cpp | 27 +++++++++------- src/vt/l_common.cpp | 21 ++++++++++++ src/vt/l_main.h | 1 + src/vt/l_tr1.cpp | 6 ++-- src/vt/l_tr4.cpp | 13 +++----- src/vt/tr_types.h | 14 +++----- 18 files changed, 151 insertions(+), 108 deletions(-) diff --git a/scripts/entity/entity_functions.lua b/scripts/entity/entity_functions.lua index 3039ab4a4..d56af99b5 100644 --- a/scripts/entity/entity_functions.lua +++ b/scripts/entity/entity_functions.lua @@ -148,6 +148,28 @@ function venicebird_init(id) -- Venice singing birds (TR2) prepareEntity(id); end +function drips_init(id) -- Maria Doria drips (TR2) + + setEntityTypeFlag(id, ENTITY_TYPE_GENERIC); + + entity_funcs[id].onActivate = function(object_id, activator_id) + setEntityActivity(object_id, 1); + end + + entity_funcs[id].onDeactivate = function(object_id, activator_id) + setEntityActivity(object_id, 0); + end + + entity_funcs[id].onLoop = function(object_id) + if(tickEntity(object_id) == TICK_STOPPED) then setEntityActivity(object_id, 0) end; + if(getEntityDistance(player, object_id) < 8192.0) then + if(math.random(100000) > 99500) then playSound(329, object_id) end; + end; + end + + prepareEntity(id); +end + function doorbell_init(id) -- Lara's Home doorbell (TR2) setEntityTypeFlag(id, ENTITY_TYPE_GENERIC); diff --git a/scripts/entity/entity_properties.lua b/scripts/entity/entity_properties.lua index 5ad8d59c3..f8d86a8e6 100644 --- a/scripts/entity/entity_properties.lua +++ b/scripts/entity/entity_properties.lua @@ -379,7 +379,7 @@ tr2_entity_tbl[209] = {coll = 0x00}; -- Dragon explosion effect (e tr2_entity_tbl[210] = {coll = 0x00}; -- Dragon explosion effect (expanding netted bubble) tr2_entity_tbl[211] = {coll = 0x00}; -- Dragon explosion effect (expanding solid bubble) tr2_entity_tbl[212] = {coll = 0x00, func = "alarm_TR2"}; -- Alarm -tr2_entity_tbl[213] = {coll = 0x00, hide = 0x01}; -- Placeholder +tr2_entity_tbl[213] = {coll = 0x00, hide = 0x01, func = "drips"}; -- Dripping water tr2_entity_tbl[214] = {coll = 0x02}; -- Tyrannosaur tr2_entity_tbl[215] = {coll = 0x00, hide = 0x01, func = "venicebird"}; -- Singing birds tr2_entity_tbl[216] = {coll = 0x00, hide = 0x01}; -- Placeholder diff --git a/scripts/trigger/trigger_functions.lua b/scripts/trigger/trigger_functions.lua index e28a22a45..be6c8dfa7 100644 --- a/scripts/trigger/trigger_functions.lua +++ b/scripts/trigger/trigger_functions.lua @@ -172,9 +172,9 @@ end -- Plays specified flyby. Only valid in TR4-5. -function playFlyby(flyby_index) +function playFlyby(flyby_index, once) if(getLevelVersion() < TR_IV) then return 0 end; - print("FLYBY: index = " .. flyby_index); + print("FLYBY: index = " .. flyby_index .. " once = " .. once); end diff --git a/src/anim_state_control.cpp b/src/anim_state_control.cpp index 707c46cc8..75feb0ae4 100644 --- a/src/anim_state_control.cpp +++ b/src/anim_state_control.cpp @@ -250,7 +250,14 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) * Base onfloor animations */ case TR_STATE_LARA_STOP: - ent->dir_flag = ENT_STAY; + + // Reset directional flag only on intermediate animation! + + if(ss_anim->current_animation == TR_ANIMATION_LARA_STAY_SOLID) + { + ent->dir_flag = ENT_STAY; + } + cmd->rot[0] = 0; cmd->crouch |= low_vertical_space; Character_Lean(ent, cmd, 0.0); @@ -674,10 +681,6 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) case TR_STATE_LARA_RUN_BACK: ent->dir_flag = ENT_MOVE_BACKWARD; - if(ss_anim->current_animation == TR_ANIMATION_LARA_RUN_BACK_BEGIN) - { - ent->current_speed = 16.0; ///@FIXME: magick! - } if(ent->move_type == MOVE_FREE_FALLING) { @@ -1069,8 +1072,7 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) if(ent->character->height_info.quicksand) { - ent->current_speed = 8.0; - Entity_UpdateCurrentSpeed(ent, 0); + ent->current_speed *= 0.5; } if(cmd->move[0] == 1) @@ -1142,17 +1144,16 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) case TR_STATE_LARA_WALK_BACK: cmd->rot[0] *= 0.4; - vec3_mul_scalar(global_offset, ent->transform + 4, -WALK_BACK_OFFSET); - global_offset[2] += ent->bf.bb_max[2]; - i = Character_CheckNextStep(ent, global_offset, &next_fc); - //ent->dir_flag = ENT_MOVE_BACKWARD; + ent->dir_flag = ENT_MOVE_BACKWARD; if(ent->character->height_info.quicksand) { - ent->current_speed = 4.0; - Entity_UpdateCurrentSpeed(ent, 0); + ent->current_speed *= 0.5; } - + + vec3_mul_scalar(global_offset, ent->transform + 4, -WALK_BACK_OFFSET); + global_offset[2] += ent->bf.bb_max[2]; + i = Character_CheckNextStep(ent, global_offset, &next_fc); if(ent->move_type == MOVE_FREE_FALLING) { Entity_SetAnimation(ent, TR_ANIMATION_LARA_START_FREE_FALL, 0); @@ -1961,7 +1962,6 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) case TR_STATE_LARA_LADDER_LEFT: //ent->character->complex_collision = 0x01; ent->dir_flag = ENT_MOVE_LEFT; - ent->current_speed = 5.0; if((cmd->action == 0) || (ent->character->climb.wall_hit == 0)) { ss_anim->next_state = TR_STATE_LARA_HANG; @@ -1975,7 +1975,6 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) case TR_STATE_LARA_LADDER_RIGHT: //ent->character->complex_collision = 0x01; ent->dir_flag = ENT_MOVE_RIGHT; - ent->current_speed = 5.0; if((cmd->action == 0) || (ent->character->climb.wall_hit == 0)) { ss_anim->next_state = TR_STATE_LARA_HANG; @@ -2040,7 +2039,6 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) break; case TR_STATE_LARA_SHIMMY_LEFT: - ent->current_speed = 5.0; cmd->rot[0] = 0.0; ent->dir_flag = ENT_MOVE_LEFT; if(cmd->action == 0) @@ -2100,7 +2098,6 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) break; case TR_STATE_LARA_SHIMMY_RIGHT: - ent->current_speed = 5.0; cmd->rot[0] = 0.0; ent->dir_flag = ENT_MOVE_RIGHT; if(cmd->action == 0) @@ -2823,7 +2820,7 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) break; case TR_STATE_LARA_CRAWL_BACK: - ent->dir_flag = ENT_MOVE_BACKWARD; + ent->dir_flag = ENT_MOVE_FORWARD; // Absurd? No, Core Design. ent->character->no_fix_body_parts = BODY_PART_HANDS_2 | BODY_PART_HANDS_3 | BODY_PART_LEGS_3; cmd->rot[0] = cmd->rot[0] * 0.5; vec3_mul_scalar(move, ent->transform + 4, -PENETRATION_TEST_OFFSET); @@ -2843,17 +2840,6 @@ int State_Control_Lara(struct entity_s *ent, struct ss_animation_s *ss_anim) ent->dir_flag = ENT_STAY; Entity_SetAnimation(ent, TR_ANIMATION_LARA_CRAWL_IDLE, 0); } - else - { - if(ss_anim->current_animation == TR_ANIMATION_LARA_CRAWL_BACKWARD) - { - ent->current_speed = 16.0; ///@FIXME: magick! - } - else - { - ent->current_speed = 6.0; - } - } break; case TR_STATE_LARA_CRAWL_TURN_LEFT: diff --git a/src/character_controller.cpp b/src/character_controller.cpp index b402992a3..c6ebb39d8 100644 --- a/src/character_controller.cpp +++ b/src/character_controller.cpp @@ -1576,24 +1576,24 @@ int Character_MoveOnFloor(struct entity_s *ent) { ent->character->resp.slide = CHARACTER_SLIDE_FRONT; ent->angles[0] = ang + 180.0; - // front forward sly down + // front forward slide down } else { ent->character->resp.slide = CHARACTER_SLIDE_BACK; ent->angles[0] = ang; - // back forward sly down + // back forward slide down } Entity_UpdateRotation(ent); ent->character->resp.vertical_collide |= 0x01; } - else // no slide - free to walk + else // no slide - free to walk { t = ent->current_speed * ent->character->speed_mult; - t = (t < 0.0)?(0.0):(t); /// stick or feature: that is a serious question! ent->character->resp.vertical_collide |= 0x01; ent->angles[0] += ent->character->cmd.rot[0]; - Entity_UpdateRotation(ent); // apply rotations + + Entity_UpdateRotation(ent); // apply rotations if(ent->dir_flag & ENT_MOVE_FORWARD) { diff --git a/src/character_controller.h b/src/character_controller.h index 7d289fbf0..339fb3a7a 100644 --- a/src/character_controller.h +++ b/src/character_controller.h @@ -159,8 +159,8 @@ enum CharParameters #define PARAM_ABSOLUTE_MAX (-1) -#define LARA_PARAM_HEALTH_MAX (1000.0) // 30 secs of air -#define LARA_PARAM_AIR_MAX (1800.0) // 30 secs of air +#define LARA_PARAM_HEALTH_MAX (1000.0) // 1000 HP +#define LARA_PARAM_AIR_MAX (3600.0) // 60 secs of air #define LARA_PARAM_STAMINA_MAX (120.0) // 4 secs of sprint #define LARA_PARAM_WARMTH_MAX (240.0) // 8 secs of freeze @@ -280,6 +280,7 @@ typedef struct character_s struct entity_s *ent; // actor entity struct character_command_s cmd; // character control commands struct character_response_s resp; // character response info (collides, slide, next steps, drops, e.t.c.) + struct inventory_node_s *inventory; struct character_param_s parameters; struct character_stats_s statistics; diff --git a/src/engine.cpp b/src/engine.cpp index a559835d7..90d587f3a 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -245,7 +245,7 @@ void Engine_BTInit() bt_engine_dynamicsWorld->setInternalTickCallback(Engine_InternalTickCallback); bt_engine_dynamicsWorld->setGravity(btVector3(0, 0, -4500.0)); - debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe); + debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawConstraints); bt_engine_dynamicsWorld->setDebugDrawer(&debugDrawer); //bt_engine_dynamicsWorld->getPairCache()->setInternalGhostPairCallback(bt_engine_filterCallback); } diff --git a/src/engine.h b/src/engine.h index 254ca729d..1d5fa7e63 100644 --- a/src/engine.h +++ b/src/engine.h @@ -16,12 +16,15 @@ #define OBJECT_STATIC_MESH (0x0001) #define OBJECT_ROOM_BASE (0x0002) #define OBJECT_ENTITY (0x0003) -#define OBJECT_BULLET_MISC (0x0004) +#define OBJECT_HAIR (0x0004) +#define OBJECT_BULLET_MISC (0x7FFF) +#define COLLISION_MASK_NONE (0x0000) #define COLLISION_MASK_ALL (0xFFFF) + #define COLLISION_GROUP_ALL (0xFFFF) #define COLLISION_GROUP_STATIC (0x0001) // room mesh, statics -#define COLLISION_GROUP_CINEMATIC (0x0002) // doors, blocks, static animated entityes +#define COLLISION_GROUP_KINEMATIC (0x0002) // doors, blocks, static animated entityes #define COLLISION_GROUP_CHARACTERS (0x0004) // Lara, enemies, friends, creatures #define COLLISION_GROUP_BULLETS (0x0008) // bullets, rockets, grenades, arrows... #define COLLISION_GROUP_DYNAMICS (0x0010) // test balls, warious diff --git a/src/entity.cpp b/src/entity.cpp index 9c7fc00c3..dd8621f1a 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -250,13 +250,16 @@ void BT_GenEntityRigidBody(entity_p ent) { ent->bt_body[i] = NULL; cshape = BT_CSfromMesh(ent->bf.animations.model->mesh_tree[i].mesh_base, true, true, ent->self->collide_flag, false); + cshape->calculateLocalInertia(0.0, localInertia); + if(cshape) { Mat4_Mat4_mul(tr, ent->transform, ent->bf.bone_tags[i].full_transform); startTransform.setFromOpenGLMatrix(tr); btDefaultMotionState* motionState = new btDefaultMotionState(startTransform); ent->bt_body[i] = new btRigidBody(0.0, motionState, cshape, localInertia); - bt_engine_dynamicsWorld->addRigidBody(ent->bt_body[i], COLLISION_GROUP_CINEMATIC, COLLISION_MASK_ALL); + ent->bt_body[i]->setCollisionFlags(ent->bt_body[i]->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + bt_engine_dynamicsWorld->addRigidBody(ent->bt_body[i], COLLISION_GROUP_KINEMATIC, COLLISION_MASK_ALL); ent->bt_body[i]->setUserPointer(ent->self); } } @@ -977,7 +980,7 @@ void Entity_SetAnimation(entity_p entity, int animation, int frame, int another_ entity->bf.animations.last_state = anim->state_id; entity->bf.animations.next_state = anim->state_id; - entity->current_speed = anim->speed; + entity->current_speed = anim->speed_x; entity->bf.animations.current_animation = animation; entity->bf.animations.current_frame = frame; entity->bf.animations.next_animation = animation; @@ -1213,7 +1216,6 @@ int Entity_Frame(entity_p entity, btScalar time) ret = 0x01; Entity_DoAnimCommands(entity, &entity->bf.animations, ret); Entity_DoAnimMove(entity); - entity->bf.animations.current_frame = frame; } af = entity->bf.animations.model->animations + entity->bf.animations.current_animation; @@ -1225,14 +1227,29 @@ int Entity_Frame(entity_p entity, btScalar time) entity->bf.animations.lerp = (entity->smooth_anim)?(dt / entity->bf.animations.period):(0.0); Entity_GetNextFrame(&entity->bf, entity->bf.animations.period, stc, &entity->bf.animations.next_frame, &entity->bf.animations.next_animation, ss_anim->anim_flags); - Character_DoWeaponFrame(entity, time); - /* - * Update acceleration - */ - if(entity->character) - { - entity->current_speed += time * entity->character->speed_mult * (btScalar)af->accel_hi; + // Update acceleration. + // With variable framerate, we don't know when we'll reach final + // frame for sure, so we use native frame number check to increase acceleration. + + if((entity->character) && (ss_anim->current_frame != frame)) + { + + // NB!!! For Lara, we update ONLY X-axis speed/accel. + + if(af->accel_x == 0) + { + entity->current_speed = af->speed_x; + } + else + { + entity->current_speed += af->accel_x; + } } + + entity->bf.animations.current_frame = frame; + + + Character_DoWeaponFrame(entity, time); Entity_UpdateCurrentBoneFrame(&entity->bf, entity->transform); if(entity->bf.animations.onFrame != NULL) @@ -1726,4 +1743,4 @@ void Character_DoWeaponFrame(struct entity_s *entity, btScalar time) Entity_DoAnimCommands(entity, ss_anim, 0); } } -} \ No newline at end of file +} diff --git a/src/game.cpp b/src/game.cpp index c6a733e8e..c4dc173dc 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -752,13 +752,12 @@ void Game_UpdateCharacters() } } - __inline btScalar Game_Tick(btScalar *game_logic_time) { - int t; - t = *game_logic_time / GAME_LOGIC_REFRESH_INTERVAL; - *game_logic_time -= (btScalar)t * GAME_LOGIC_REFRESH_INTERVAL; - return *game_logic_time; + int t = *game_logic_time / GAME_LOGIC_REFRESH_INTERVAL; + btScalar dt = (btScalar)t * GAME_LOGIC_REFRESH_INTERVAL; + *game_logic_time -= dt; + return dt; } @@ -801,14 +800,14 @@ void Game_Frame(btScalar time) return; } + // We're going to update main logic with a fixed step. // This allows to conserve CPU resources and keep everything in sync! if(game_logic_time >= GAME_LOGIC_REFRESH_INTERVAL) { - int32_t t = game_logic_time / GAME_LOGIC_REFRESH_INTERVAL; - btScalar dt = (btScalar)t * GAME_LOGIC_REFRESH_INTERVAL; - game_logic_time -= dt; + btScalar dt = Game_Tick(&game_logic_time); + bt_engine_dynamicsWorld->stepSimulation(dt, 8); lua_DoTasks(engine_lua, dt); Game_UpdateAI(); @@ -822,6 +821,7 @@ void Game_Frame(btScalar time) if(is_entitytree) Game_LoopEntities(engine_world.entity_tree->root); } + // This must be called EVERY frame to max out smoothness. // Includes animations, camera movement, and so on. diff --git a/src/main_SDL.cpp b/src/main_SDL.cpp index 58d725883..9e65279a6 100644 --- a/src/main_SDL.cpp +++ b/src/main_SDL.cpp @@ -182,7 +182,7 @@ void SkeletalModelTestDraw() Gui_OutTextXY(screen_info.w-632, 120, "sprite ID = %d; mesh ID = %d", bsprite->id, mesh); Gui_OutTextXY(screen_info.w-632, 96, "model ID = %d, anim = %d of %d, rate = %d, frame = %d of %d", smodel->id, anim, smodel->animation_count, smodel->animations[anim].original_frame_rate, frame, smodel->animations[anim].frames_count); Gui_OutTextXY(screen_info.w-632, 72, "next anim = %d, next frame = %d, num_state_changes = %d", (af->next_anim)?(af->next_anim->id):-1, af->next_frame, af->state_change_count); - Gui_OutTextXY(screen_info.w-632, 48, "v1 = %d, v2 = %d, al1 = %d, ah1 = %d, al2 = %d, ah2 = %d", af->speed, af->speed2, af->accel_lo, af->accel_hi, af->accel_lo2, af->accel_hi2); + Gui_OutTextXY(screen_info.w-632, 48, "vx = %f, vy = %f, ax = %f, ay = %f", af->speed_x, af->speed_y, af->accel_x, af->accel_y); Gui_OutTextXY(screen_info.w-632, 24, "bb_min(%d, %d, %d), bb_max(%d, %d, %d)", (int)bframe->bb_min[0], (int)bframe->bb_min[1], (int)bframe->bb_min[2], (int)bframe->bb_max[0], (int)bframe->bb_max[1], (int)bframe->bb_max[2]); Gui_OutTextXY(screen_info.w-632, 4, "x0 = %d, y0 = %d, z0 = %d", (int)bframe->pos[0], (int)bframe->pos[1], (int)bframe->pos[2]); diff --git a/src/mesh.h b/src/mesh.h index c8207642b..1b29b15b0 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -299,25 +299,23 @@ typedef struct animation_frame_s { uint32_t id; uint8_t original_frame_rate; - int accel_hi; - int accel_hi2; - int accel_lo; - int accel_lo2; - int speed; - int speed2; + btScalar speed_x; // Forward-backward speed + btScalar accel_x; // Forward-backward accel + btScalar speed_y; // Left-right speed + btScalar accel_y; // Left-right accel uint32_t anim_command; uint32_t num_anim_commands; uint16_t state_id; int16_t unknown; int16_t unknown2; - uint16_t frames_count; // number of frames - struct bone_frame_s *frames; // frames data + uint16_t frames_count; // Number of frames + struct bone_frame_s *frames; // Frame data - uint16_t state_change_count; // number of animation statechanges - struct state_change_s *state_change; // animation statechanges data + uint16_t state_change_count; // Number of animation statechanges + struct state_change_s *state_change; // Animation statechanges data - struct animation_frame_s *next_anim; // next default animation - int next_frame; // next default frame + struct animation_frame_s *next_anim; // Next default animation + int next_frame; // Next default frame }animation_frame_t, *animation_frame_p; /* diff --git a/src/resource.cpp b/src/resource.cpp index d13d5d253..4a69896d0 100644 --- a/src/resource.cpp +++ b/src/resource.cpp @@ -1087,8 +1087,14 @@ int TR_Sector_TranslateFloorData(room_sector_p sector, class VT_Level *tr) break; case TR_FD_TRIGFUNC_FLYBY: - snprintf(buf, 128, " playFlyby(%d); \n", operands); - strcat(cont_events, buf); + { + entry++; + uint8_t flyby_once = ((*entry) & 0x0100) >> 8; + cont_bit = ((*entry) & 0x8000) >> 15; + + snprintf(buf, 128, " playFlyby(%d, %d); \n", operands, flyby_once); + strcat(cont_events, buf); + } break; case TR_FD_TRIGFUNC_CUTSCENE: @@ -3437,21 +3443,20 @@ void TR_GenSkeletalModel(struct world_s *world, size_t model_num, struct skeleta } frame_step = tr_animation->frame_size; - //Sys_DebugLog(LOG_FILENAME, "frame_step = %d", frame_step); anim->id = i; anim->original_frame_rate = tr_animation->frame_rate; - anim->accel_hi = tr_animation->accel_hi; - anim->accel_hi2 = tr_animation->accel_hi2; - anim->accel_lo = tr_animation->accel_lo; - anim->accel_lo2 = tr_animation->accel_lo2; - anim->speed = tr_animation->speed; - anim->speed2 = tr_animation->speed2; + + anim->speed_x = tr_animation->speed; + anim->accel_x = tr_animation->accel; + anim->speed_y = tr_animation->accel_lateral; + anim->accel_y = tr_animation->speed_lateral; + anim->anim_command = tr_animation->anim_command; anim->num_anim_commands = tr_animation->num_anim_commands; anim->state_id = tr_animation->state_id; - anim->unknown = tr_animation->unknown; - anim->unknown2 = tr_animation->unknown2; + anim->frames_count = TR_GetNumFramesForAnimation(tr, tr_moveable->animation_index+i); + //Sys_DebugLog(LOG_FILENAME, "Anim[%d], %d", tr_moveable->animation_index, TR_GetNumFramesForAnimation(tr, tr_moveable->animation_index)); // Parse AnimCommands diff --git a/src/vt/l_common.cpp b/src/vt/l_common.cpp index 3b7c97821..f46ed225e 100644 --- a/src/vt/l_common.cpp +++ b/src/vt/l_common.cpp @@ -155,3 +155,24 @@ float TR_Level::read_float(SDL_RWops * const src) return data; } + +/** \brief reads mixed TR-specific float value (used in animation speed/accel fields). + * + * uses current position from src. does endian correction. throws TR_ReadError when not successful. + */ +float TR_Level::read_mixfloat(SDL_RWops * const src) +{ + int16_t base_int; + uint16_t sign_int; + + if (src == NULL) + Sys_extError("read_mixfloat: src == NULL"); + + if ((SDL_RWread(src, &sign_int, 2, 1) < 1) || (SDL_RWread(src, &base_int, 2, 1) < 1)) + Sys_extError("read_mixfloat"); + + base_int = SDL_SwapLE32(base_int); + sign_int = SDL_SwapLE32(sign_int); + + return ((float)base_int + ((float)sign_int / 65535.0)); +} diff --git a/src/vt/l_main.h b/src/vt/l_main.h index 9bc79172c..d5728e3e9 100644 --- a/src/vt/l_main.h +++ b/src/vt/l_main.h @@ -545,6 +545,7 @@ class TR_Level { int32_t read_bit32(SDL_RWops * const src); uint32_t read_bitu32(SDL_RWops * const src); float read_float(SDL_RWops * const src); + float read_mixfloat(SDL_RWops * const src); void read_mesh_data(SDL_RWops * const src); void read_frame_moveable_data(SDL_RWops * const src); diff --git a/src/vt/l_tr1.cpp b/src/vt/l_tr1.cpp index 91ca8aa89..288e51789 100644 --- a/src/vt/l_tr1.cpp +++ b/src/vt/l_tr1.cpp @@ -499,10 +499,8 @@ void TR_Level::read_tr_animation(SDL_RWops * const src, tr_animation_t & animati animation.frame_size = read_bitu8(src); animation.state_id = read_bitu16(src); - animation.unknown = read_bit16(src); - animation.speed = read_bit16(src); - animation.accel_lo = read_bit16(src); - animation.accel_hi = read_bit16(src); + animation.speed = read_mixfloat(src); + animation.accel = read_mixfloat(src); animation.frame_start = read_bitu16(src); animation.frame_end = read_bitu16(src); diff --git a/src/vt/l_tr4.cpp b/src/vt/l_tr4.cpp index 1116c1b2a..4054c85bf 100644 --- a/src/vt/l_tr4.cpp +++ b/src/vt/l_tr4.cpp @@ -326,15 +326,10 @@ void TR_Level::read_tr4_animation(SDL_RWops * const src, tr_animation_t & animat animation.frame_size = read_bitu8(src); animation.state_id = read_bitu16(src); - animation.unknown = read_bit16(src); - animation.speed = read_bit16(src); - animation.accel_lo = read_bit16(src); - animation.accel_hi = read_bit16(src); - - animation.unknown2 = read_bit16(src); - animation.speed2 = read_bit16(src); - animation.accel_lo2 = read_bit16(src); - animation.accel_hi2 = read_bit16(src); + animation.speed = read_mixfloat(src); + animation.accel = read_mixfloat(src); + animation.speed_lateral = read_mixfloat(src); + animation.accel_lateral = read_mixfloat(src); animation.frame_start = read_bitu16(src); animation.frame_end = read_bitu16(src); diff --git a/src/vt/tr_types.h b/src/vt/tr_types.h index 56406f2ad..b5d9aa54a 100644 --- a/src/vt/tr_types.h +++ b/src/vt/tr_types.h @@ -430,15 +430,11 @@ typedef struct { // 32 bytes TR1/2/3 40 bytes TR4 uint8_t frame_size; // number of bit16's in Frames[] used by this animation uint16_t state_id; - int16_t unknown; - int16_t speed; - int16_t accel_lo; - int16_t accel_hi; - - int16_t unknown2; // new in TR4 --> - int16_t speed2; // not really sure what these mean. - int16_t accel_lo2; - int16_t accel_hi2; // <-- TR4 + float speed; + float accel; + + float speed_lateral; // new in TR4 --> + float accel_lateral; // lateral speed and acceleration. uint16_t frame_start; // first frame in this animation uint16_t frame_end; // last frame in this animation (numframes = (End - Start) + 1)