1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-13 16:44:50 +02:00

TR4 remap soundtracks, fix triggers parser, fix ponytails for young Lara,

This commit is contained in:
XProger
2019-07-22 05:18:43 +03:00
parent 4ae25e37a6
commit e3757d5c43
5 changed files with 323 additions and 143 deletions

View File

@@ -748,7 +748,7 @@ namespace Debug {
const char *ent = (cmd.action == TR::Action::ACTIVATE || cmd.action == TR::Action::CAMERA_TARGET) ? getEntityName(level, level.entities[cmd.args]) : ""; const char *ent = (cmd.action == TR::Action::ACTIVATE || cmd.action == TR::Action::CAMERA_TARGET) ? getEntityName(level, level.entities[cmd.args]) : "";
sprintf(buf, "%s -> %s (%d)", getTriggerAction(level, cmd.action), ent, cmd.args); sprintf(buf, "%s -> %s (%d)", getTriggerAction(level, cmd.action), ent, cmd.args);
if (cmd.action == TR::Action::CAMERA_SWITCH) { if (cmd.action == TR::Action::CAMERA_SWITCH || cmd.action == TR::Action::FLYBY || cmd.action == TR::Action::CUTSCENE) {
i++; i++;
sprintf(buf, "%s delay: %d speed: %d", buf, int(info.trigCmd[i].timer), int(info.trigCmd[i].speed)); sprintf(buf, "%s delay: %d speed: %d", buf, int(info.trigCmd[i].timer), int(info.trigCmd[i].speed));
} }

View File

@@ -1555,6 +1555,9 @@ namespace TR {
SOUNDTRACK , // play soundtrack SOUNDTRACK , // play soundtrack
EFFECT , // special effect trigger EFFECT , // special effect trigger
SECRET , // secret found SECRET , // secret found
CLEAR_BODIES , // clear all dead bodies
FLYBY , // play flyby camera sequence
CUTSCENE , // play cutscene
}; };
}; };
@@ -1982,8 +1985,9 @@ namespace TR {
int D = (SQR(dx) + SQR(dy) + SQR(dz)) >> 12; int D = (SQR(dx) + SQR(dy) + SQR(dz)) >> 12;
int R = SQR(light.radius >> 1) >> 12; int R = SQR(light.radius >> 1) >> 12;
int M = max(1, D + R); // TODO TR4
int value = min(0x1FFF, (light.intensity * R) / (D + R) + ambientInv); int value = min(0x1FFF, (light.intensity * R) / M + ambientInv);
if (maxValue < value) { if (maxValue < value) {
if (nearLight) { if (nearLight) {
@@ -3229,6 +3233,7 @@ namespace TR {
case VER_TR5_PC : loadTR5_PC (stream); break; case VER_TR5_PC : loadTR5_PC (stream); break;
case VER_TR5_PSX : loadTR5_PSX (stream); break; case VER_TR5_PSX : loadTR5_PSX (stream); break;
case VER_TR5_SDC : loadTR5_SDC (stream); break; case VER_TR5_SDC : loadTR5_SDC (stream); break;
default : ASSERT(false);
} }
prepare(); prepare();

View File

@@ -141,7 +141,44 @@ namespace TR {
LVL_TR3_CHAMBER, LVL_TR3_CHAMBER,
LVL_TR3_STPAUL, LVL_TR3_STPAUL,
// TR4 // TR4
LVL_TR4_TITLE,
LVL_TR4_ANGKOR1, LVL_TR4_ANGKOR1,
LVL_TR4_ANG_RACE,
LVL_TR4_SETTOMB1,
LVL_TR4_SETTOMB2,
LVL_TR4_JEEPCHAS,
LVL_TR4_JEEPCHS2,
LVL_TR4_KARNAK1,
LVL_TR4_HALL,
LVL_TR4_LAKE,
LVL_TR4_SEMER,
LVL_TR4_SEMER2,
LVL_TR4_TRAIN,
LVL_TR4_ALEXHUB,
LVL_TR4_ALEXHUB2,
LVL_TR4_PALACES,
LVL_TR4_PALACES2,
LVL_TR4_CSPLIT1,
LVL_TR4_CSPLIT2,
LVL_TR4_LIBRARY,
LVL_TR4_LIBEND,
LVL_TR4_BIKEBIT,
LVL_TR4_NUTRENCH,
LVL_TR4_CORTYARD,
LVL_TR4_LOWSTRT,
LVL_TR4_HIGHSTRT,
LVL_TR4_CITNEW,
LVL_TR4_JOBY1A,
LVL_TR4_JOBY1B,
LVL_TR4_JOBY2,
LVL_TR4_JOBY3A,
LVL_TR4_JOBY3B,
LVL_TR4_JOBY4A,
LVL_TR4_JOBY4B,
LVL_TR4_JOBY4C,
LVL_TR4_JOBY5A,
LVL_TR4_JOBY5B,
LVL_TR4_JOBY5C,
LVL_MAX, LVL_MAX,
}; };
@@ -202,7 +239,17 @@ namespace TR {
TRACK_TR3_CUT_11 = 71, TRACK_TR3_CUT_11 = 71,
TRACK_TR3_CUT_12 = 66, TRACK_TR3_CUT_12 = 66,
// TR4 // TR4
TRACK_TR4_OUT_DAY = 106, TRACK_TR4_BOSS = 97,
TRACK_TR4_JEEP = 98,
TRACK_TR4_BATTLE = 102,
TRACK_TR4_TITLE = 104,
TRACK_TR4_COASTAL = 105,
TRACK_TR4_TRAIN = 106,
TRACK_TR4_IN_DARK = 107,
TRACK_TR4_IN_DRIPS = 108,
TRACK_TR4_WEIRD1 = 109,
TRACK_TR4_OUT_DAY = 110,
TRACK_TR4_OUT_NIGHT = 111,
}; };
// #define LEVEL (version,name,track) { #name, STR_##version##_##name, TRACK_##version##track }, // #define LEVEL (version,name,track) { #name, STR_##version##_##name, TRACK_##version##track },
@@ -300,122 +347,159 @@ namespace TR {
{ "CHAMBER" , STR_TR3_CHAMBER , TRACK_TR3_ANTARC_3 }, { "CHAMBER" , STR_TR3_CHAMBER , TRACK_TR3_ANTARC_3 },
{ "STPAUL" , STR_TR3_STPAUL , TRACK_TR3_CAVES }, { "STPAUL" , STR_TR3_STPAUL , TRACK_TR3_CAVES },
// TR4 // TR4
{ "ANGKOR1" , STR_UNKNOWN , TRACK_TR4_OUT_DAY }, { "title" , STR_UNKNOWN , TRACK_TR4_TITLE },
{ "angkor1" , STR_UNKNOWN , TRACK_TR4_OUT_DAY },
{ "ang_race" , STR_UNKNOWN , TRACK_TR4_OUT_DAY },
{ "settomb1" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "settomb2" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "jeepchas" , STR_UNKNOWN , TRACK_TR4_OUT_DAY },
{ "jeepchs2" , STR_UNKNOWN , TRACK_TR4_JEEP },
{ "karnak1" , STR_UNKNOWN , TRACK_TR4_OUT_DAY },
{ "hall" , STR_UNKNOWN , TRACK_TR4_OUT_DAY },
{ "lake" , STR_UNKNOWN , TRACK_TR4_OUT_DAY },
{ "semer" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "semer2" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "train" , STR_UNKNOWN , TRACK_TR4_TRAIN },
{ "alexhub" , STR_UNKNOWN , TRACK_TR4_OUT_DAY },
{ "alexhub2" , STR_UNKNOWN , TRACK_TR4_COASTAL },
{ "palaces" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "palaces2" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "csplit1" , STR_UNKNOWN , TRACK_TR4_IN_DRIPS },
{ "csplit2" , STR_UNKNOWN , TRACK_TR4_IN_DRIPS },
{ "library" , STR_UNKNOWN , TRACK_TR4_IN_DRIPS },
{ "libend" , STR_UNKNOWN , TRACK_TR4_WEIRD1 },
{ "bikebit" , STR_UNKNOWN , TRACK_TR4_BATTLE },
{ "nutrench" , STR_UNKNOWN , TRACK_TR4_BATTLE },
{ "cortyard" , STR_UNKNOWN , TRACK_TR4_BATTLE },
{ "lowstrt" , STR_UNKNOWN , TRACK_TR4_BATTLE },
{ "highstrt" , STR_UNKNOWN , TRACK_TR4_BATTLE },
{ "citnew" , STR_UNKNOWN , TRACK_TR4_BATTLE },
{ "joby1a" , STR_UNKNOWN , TRACK_TR4_OUT_NIGHT },
{ "joby1b" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "joby2" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "joby3a" , STR_UNKNOWN , TRACK_TR4_OUT_NIGHT },
{ "joby3b" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "joby4a" , STR_UNKNOWN , TRACK_TR4_OUT_NIGHT },
{ "joby4b" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "joby4c" , STR_UNKNOWN , TRACK_TR4_OUT_NIGHT },
{ "joby5a" , STR_UNKNOWN , TRACK_TR4_IN_DARK },
{ "joby5b" , STR_UNKNOWN , TRACK_TR4_BOSS },
{ "joby5c" , STR_UNKNOWN , TRACK_TR4_IN_DRIPS },
}; };
static const char* TRACK_LIST_TR4[] = { static const char* TRACK_LIST_TR4[] = {
"VonCroy2", "044_Attack_part_i"
"VonCroy3", , "008_VonCroy9a"
"VonCroy4", , "100_Attack_part_ii"
"VonCroy5", , "010_VonCroy10"
"VonCroy6_Lara2", , "015_VonCroy14"
"VonCroy7", , "073_Secret"
"VonCroy8", , "109_Lyre_01"
"VonCroy9a", , "042_Action_Part_iv"
"VonCroy9b_Lara3", , "043_Action_Part_v"
"VonCroy10", , "030_VonCroy30"
"VonCroy11a", , "012_VonCroy11b"
"VonCroy11b", , "011_VonCroy11a"
"VonCroy12_13a_Lara4", , "063_Misc_Inc_01"
"VonCroy13b", , "014_VonCroy13b"
"VonCroy14", , "111_charmer"
"VonCroy15", , "025_VonCroy24b"
"VonCroy16_lara5", , "023_VonCroy23"
"VonCroy17", , "006_VonCroy7"
"Lara6_VonCroy18", , "024_VonCroy24a"
"VonCroy19", , "110_Lyre_02"
"VC20_L7_VC21_L8_VC22a", , "020_VonCroy19"
"VonCroy22b", , "034_VonCroy34"
"VonCroy23", , "054_General_Part_ii"
"VonCroy24a", , "036_VonCroy36"
"VonCroy24b", , "004_VonCroy5"
"VC25_L9_VC26_L10", , "035_VonCroy35"
"VonCroy27", , "027_VonCroy27"
"VonCroy28_L11", , "053_General_Part_i"
"VonCroy29", , "022_VonCroy22b"
"VonCroy30", , "028_VonCroy28_L11"
"VonCroy31_L12", , "003_VonCroy4"
"VonCroy32_L13", , "001_VonCroy2"
"VonCroy33", , "041_Action_Part_iii"
"VonCroy34", , "057_General_Part_v"
"VonCroy35", , "018_VonCroy17"
"VonCroy36", , "064_Misc_Inc_02"
"VC37_L15_VC38", , "033_VonCroy33"
"A_Short_01", , "031_VonCroy31_L12"
"TR4_Title_Q10", , "032_VonCroy32_L13"
"Action_Part_ii", , "016_VonCroy15"
"Action_Part_iii", , "065_Misc_Inc_03"
"Action_Part_iv", , "040_Action_Part_ii"
"Action_Part_v", , "112_Gods_part_iv"
"Attack_part_i", , "029_VonCroy29"
"Authentic_TR", , "007_VonCroy8"
"Boss_01", , "013_VonCroy12_13a_Lara4"
"Boss_02", , "009_VonCroy9b_Lara3"
"Close_to_the_End", , "081_dig"
"Close_to_the_End_part_ii", , "085_intro"
"Underwater_Find_part_i", , "071_Ominous_Part_i"
"Egyptian_Mood_Part_i", , "095_phildoor"
"Egyptian_Mood_Part_ii", , "061_In_The_Pyramid_Part_i"
"General_Part_i", , "050_Underwater_Find_part_i"
"General_Part_ii", , "058_Gods_Part_i"
"General_Part_iii", , "005_VonCroy6_Lara2"
"General_Part_iv", , "045_Authentic_TR"
"General_Part_v", , "060_Gods_Part_iii"
"Gods_Part_i", , "055_General_Part_iii"
"Gods_Part_ii", , "059_Gods_Part_ii"
"Gods_Part_iii", , "068_Mystery_Part_ii"
"In_The_Pyramid_Part_i", , "076_captain2"
"Jeep_Thrills_max", , "019_Lara6_VonCroy18"
"Misc_Inc_01", , "002_VonCroy3"
"Misc_Inc_02", , "066_Misc_Inc_04"
"Misc_Inc_03", , "067_Mystery_Part_i"
"Misc_Inc_04", , "038_A_Short_01"
"Mystery_Part_i", , "088_key"
"Mystery_Part_ii", , "017_VonCroy16_lara5"
"Mystery_Part_iii", , "026_VC25_L9_VC26_L10"
"Mystery_Part_iv", , "056_General_Part_iv"
"Ominous_Part_i", , "021_VC20_L7_VC21_L8_VC22a"
"Puzzle_part_i", , "096_sarcoph"
"Secret", , "087_jeepB"
"backpack", , "091_minilib1"
"captain1", , "086_jeepA"
"captain2", , "051_Egyptian_Mood_Part_i"
"crocgod", , "078_croywon"
"croywon", , "092_minilib2"
"crypt1", , "083_horus"
"crypt2", , "049_Close_to_the_End_part_ii"
"dig", , "037_VC37_L15_VC38"
"finale", , "097_scorpion"
"horus", , "089_larawon"
"inscrip", , "094_minilib4"
"intro", , "098_throne"
"jeepA", , "048_Close_to_the_End"
"jeepB", , "070_Mystery_Part_iv"
"key", , "093_minilib3"
"larawon", , "072_Puzzle_part_i"
"libend", , "074_backpack"
"minilib1", , "069_Mystery_Part_iii"
"minilib2", , "052_Egyptian_Mood_Part_ii"
"minilib3", , "084_inscrip"
"minilib4", , "099_whouse"
"phildoor", , "047_Boss_02"
"sarcoph", , "080_crypt2"
"scorpion", , "090_libend"
"throne", , "046_Boss_01"
"whouse", , "062_Jeep_Thrills_max"
"Attack_part_ii", , "079_crypt1"
"A1_In_Dark", , "082_finale"
"A2_In_Drips", , "075_captain1"
"A3_Out_Night", , "105_A5_Battle"
"A4_Weird1", , "077_crocgod"
"A5_Battle", , "039_TR4_Title_Q10"
"A6_Out_Day", , "108_A8_Coastal"
"A7_Train+", , "107_A7_Train+"
"A8_Coastal", , "101_A1_In_Dark"
"Lyre_01", , "102_A2_In_Drips"
"Lyre_02", , "104_A4_Weird1"
"charmer", , "106_A6_Out_Day"
"Gods_part_iv" , "103_A3_Out_Night"
}; };
Version getGameVersionByLevel(LevelID id) { Version getGameVersionByLevel(LevelID id) {
@@ -425,7 +509,7 @@ namespace TR {
return VER_TR2; return VER_TR2;
if (id >= LVL_TR3_TITLE && id <= LVL_TR3_STPAUL) if (id >= LVL_TR3_TITLE && id <= LVL_TR3_STPAUL)
return VER_TR3; return VER_TR3;
if (id >= LVL_TR4_ANGKOR1 && id < LVL_MAX) if (id >= LVL_TR4_TITLE && id <= LVL_TR4_JOBY5C)
return VER_TR4; return VER_TR4;
return VER_UNKNOWN; return VER_UNKNOWN;
} }
@@ -813,7 +897,44 @@ namespace TR {
case 1080046 : case 1080046 :
case 2321393 : return LVL_TR3_CUT_12; case 2321393 : return LVL_TR3_CUT_12;
// TR4 // TR4
case 3007155 : return LVL_TR4_TITLE;
case 4034313 : return LVL_TR4_ANGKOR1; case 4034313 : return LVL_TR4_ANGKOR1;
case 4343019 : return LVL_TR4_ANG_RACE;
case 3715110 : return LVL_TR4_SETTOMB1;
case 3868566 : return LVL_TR4_SETTOMB2;
case 3600478 : return LVL_TR4_JEEPCHAS;
case 4826055 : return LVL_TR4_JEEPCHS2;
case 4773596 : return LVL_TR4_KARNAK1;
case 4882065 : return LVL_TR4_HALL;
case 5021843 : return LVL_TR4_LAKE;
case 4409367 : return LVL_TR4_SEMER;
case 4294398 : return LVL_TR4_SEMER2;
case 3246177 : return LVL_TR4_TRAIN;
case 4007946 : return LVL_TR4_ALEXHUB;
case 4735043 : return LVL_TR4_ALEXHUB2;
case 4549992 : return LVL_TR4_PALACES;
case 4779709 : return LVL_TR4_PALACES2;
case 4570232 : return LVL_TR4_CSPLIT1;
case 4838007 : return LVL_TR4_CSPLIT2;
case 4606099 : return LVL_TR4_LIBRARY;
case 3240517 : return LVL_TR4_LIBEND;
case 5013974 : return LVL_TR4_BIKEBIT;
case 4260336 : return LVL_TR4_NUTRENCH;
case 4989001 : return LVL_TR4_CORTYARD;
case 3970465 : return LVL_TR4_LOWSTRT;
case 4725022 : return LVL_TR4_HIGHSTRT;
case 4776907 : return LVL_TR4_CITNEW;
case 5011064 : return LVL_TR4_JOBY1A;
case 4544163 : return LVL_TR4_JOBY1B;
case 4839409 : return LVL_TR4_JOBY2;
case 4433722 : return LVL_TR4_JOBY3A;
case 5141026 : return LVL_TR4_JOBY3B;
case 4786641 : return LVL_TR4_JOBY4A;
case 4401690 : return LVL_TR4_JOBY4B;
case 4999677 : return LVL_TR4_JOBY4C;
case 3741579 : return LVL_TR4_JOBY5A;
case 4623726 : return LVL_TR4_JOBY5B;
case 4398142 : return LVL_TR4_JOBY5C;
} }
if (name) { if (name) {
@@ -861,6 +982,7 @@ namespace TR {
case VER_TR1 : return LVL_TR1_TITLE; case VER_TR1 : return LVL_TR1_TITLE;
case VER_TR2 : return LVL_TR2_TITLE; case VER_TR2 : return LVL_TR2_TITLE;
case VER_TR3 : return LVL_TR3_TITLE; case VER_TR3 : return LVL_TR3_TITLE;
case VER_TR4 : return LVL_TR4_TITLE;
} }
return LVL_TR1_TITLE; return LVL_TR1_TITLE;
ASSERT(false); ASSERT(false);
@@ -882,6 +1004,7 @@ namespace TR {
case VER_TR1 : return LVL_TR1_1; case VER_TR1 : return LVL_TR1_1;
case VER_TR2 : return LVL_TR2_WALL; case VER_TR2 : return LVL_TR2_WALL;
case VER_TR3 : return LVL_TR3_JUNGLE; case VER_TR3 : return LVL_TR3_JUNGLE;
case VER_TR4 : return LVL_TR4_ANGKOR1;
} }
ASSERT(false); ASSERT(false);
return LVL_MAX; return LVL_MAX;
@@ -892,6 +1015,7 @@ namespace TR {
case VER_TR1 : return LVL_TR1_10C; case VER_TR1 : return LVL_TR1_10C;
case VER_TR2 : return LVL_TR2_HOUSE; case VER_TR2 : return LVL_TR2_HOUSE;
case VER_TR3 : return LVL_TR3_CHAMBER; case VER_TR3 : return LVL_TR3_CHAMBER;
case VER_TR4 : return LVL_TR4_JOBY5C;
} }
ASSERT(false); ASSERT(false);
return LVL_MAX; return LVL_MAX;
@@ -906,7 +1030,10 @@ namespace TR {
} }
bool isTitleLevel(LevelID id) { bool isTitleLevel(LevelID id) {
return id == LVL_TR1_TITLE || id == LVL_TR2_TITLE || id == LVL_TR3_TITLE; return id == LVL_TR1_TITLE ||
id == LVL_TR2_TITLE ||
id == LVL_TR3_TITLE ||
id == LVL_TR4_TITLE;
} }
bool isEmptyLevel(LevelID id) { bool isEmptyLevel(LevelID id) {
@@ -974,6 +1101,7 @@ namespace TR {
case VER_TR2_PSX : sprintf(dst, "DATA/%s.PSX", LEVEL_INFO[id].name); break; case VER_TR2_PSX : sprintf(dst, "DATA/%s.PSX", LEVEL_INFO[id].name); break;
case VER_TR3_PC : sprintf(dst, isCutsceneLevel(id) ? "cuts/%s.TR2" : "data/%s.TR2", LEVEL_INFO[id].name); break; case VER_TR3_PC : sprintf(dst, isCutsceneLevel(id) ? "cuts/%s.TR2" : "data/%s.TR2", LEVEL_INFO[id].name); break;
case VER_TR3_PSX : sprintf(dst, isCutsceneLevel(id) ? "CUTS/%s.PSX" : "DATA/%s.PSX", LEVEL_INFO[id].name); break; case VER_TR3_PSX : sprintf(dst, isCutsceneLevel(id) ? "CUTS/%s.PSX" : "DATA/%s.PSX", LEVEL_INFO[id].name); break;
case VER_TR4_PC : sprintf(dst, "DATA/%s.tr4", LEVEL_INFO[id].name); break;
default : ASSERT(false); default : ASSERT(false);
} }
} else { } else {
@@ -1185,8 +1313,8 @@ namespace TR {
callback(Sound::openCDAudioWAD("audio/cdaudio.wad", track), userData); callback(Sound::openCDAudioWAD("audio/cdaudio.wad", track), userData);
return; return;
case VER_TR4_PC : case VER_TR4_PC :
sprintf(title, "audio/%03d_%s", track, TRACK_LIST_TR4[track - 1]); strcpy(title, TRACK_LIST_TR4[track]);
if (!checkTrack("", title)) { if (!checkTrack("audio/", title)) {
callback(NULL, userData); callback(NULL, userData);
} }
break; break;

View File

@@ -498,11 +498,13 @@ struct Lara : Character {
mesh->renderModel(lara->level->extra.braid); mesh->renderModel(lara->level->extra.braid);
} }
} *braid; } *braid[2];
Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), wpnCurrent(TR::Entity::NONE), wpnNext(TR::Entity::NONE), braid(NULL) { Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), wpnCurrent(TR::Entity::NONE), wpnNext(TR::Entity::NONE) {
camera = new Camera(game, this); camera = new Camera(game, this);
braid[0] = braid[1] = NULL;
itemHolster = TR::Entity::NONE; itemHolster = TR::Entity::NONE;
hitTimer = 0.0f; hitTimer = 0.0f;
networkInput = -1; networkInput = -1;
@@ -547,8 +549,26 @@ struct Lara : Character {
arms[i].rotAbs = quat(0, 0, 0, 1); arms[i].rotAbs = quat(0, 0, 0, 1);
} }
if (level->extra.braid > -1) if (level->extra.braid > -1) {
braid = new Braid(this, (level->version & (TR::VER_TR2 | TR::VER_TR3)) ? vec3(-2.0f, -16.0f, -48.0f) : vec3(-4.0f, 24.0f, -48.0f)); vec3 offset(0.0f);
switch (level->version & TR::VER_VERSION) {
case TR::VER_TR1 :
braid[0] = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
break;
case TR::VER_TR2 :
case TR::VER_TR3 :
braid[0] = new Braid(this, vec3(-2.0f, -16.0f, -48.0f));
break;
case TR::VER_TR4 :
if (isYoung()) {
braid[0] = new Braid(this, vec3(-32.0f, -48.0f, -32.0f));
braid[1] = new Braid(this, vec3( 32.0f, -48.0f, -32.0f));
} else {
braid[0] = new Braid(this, vec3(-2.0f, -16.0f, -48.0f));
}
break;
}
}
// TR1 // TR1
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, STAND_ONWATER); // gym (pool) //reset(14, vec3(40448, 3584, 60928), PI * 0.5f, STAND_ONWATER); // gym (pool)
@@ -626,10 +646,15 @@ struct Lara : Character {
virtual ~Lara() { virtual ~Lara() {
delete camera; delete camera;
delete braid; delete braid[0];
delete braid[1];
delete environment; delete environment;
} }
bool isYoung() {
return level->id == TR::LVL_TR4_ANGKOR1 || level->id == TR::LVL_TR4_ANG_RACE;
}
bool canSaveGame() { bool canSaveGame() {
return health > 0.0f && !burn return health > 0.0f && !burn
&& state != STATE_USE_KEY && state != STATE_USE_KEY
@@ -1546,6 +1571,9 @@ struct Lara : Character {
} }
void doBubbles() { void doBubbles() {
if ((level->version & TR::VER_VERSION) > TR::VER_TR2) {
return; // TODO
}
int count = rand() % 3; int count = rand() % 3;
if (!count) return; if (!count) return;
game->playSound(TR::SND_BUBBLE, pos, Sound::PAN); game->playSound(TR::SND_BUBBLE, pos, Sound::PAN);
@@ -2224,6 +2252,14 @@ struct Lara : Character {
game->playTrack(TR::TRACK_TR1_SECRET, true); game->playTrack(TR::TRACK_TR1_SECRET, true);
} }
break; break;
case TR::Action::CLEAR_BODIES :
break;
case TR::Action::FLYBY :
cmdIndex++; // TODO
break;
case TR::Action::CUTSCENE :
cmdIndex++; // TODO
break;
} }
} }
@@ -3202,8 +3238,13 @@ struct Lara : Character {
updateLights(); updateLights();
if (fixRoomIndex() && braid) if (fixRoomIndex()) {
braid->update(); for (int i = 0; i < COUNT(braid); i++) {
if (braid[i]) {
braid[i]->update();
}
}
}
} else { } else {
switch (usedItem) { switch (usedItem) {
case TR::Entity::INV_MEDIKIT_SMALL : case TR::Entity::INV_MEDIKIT_SMALL :
@@ -3219,8 +3260,11 @@ struct Lara : Character {
} }
Character::update(); Character::update();
if (braid) for (int i = 0; i < COUNT(braid); i++) {
braid->update(); if (braid[i]) {
braid[i]->update();
}
}
} }
camera->update(); camera->update();
@@ -3791,8 +3835,11 @@ struct Lara : Character {
visibleMask = visMask; visibleMask = visMask;
if (braid) for (int i = 0; i < COUNT(braid); i++) {
braid->render(mesh); if (braid[i]) {
braid[i]->render(mesh);
}
}
if (state == STATE_MIDAS_DEATH /* && Core::pass == Core::passCompose */) { if (state == STATE_MIDAS_DEATH /* && Core::pass == Core::passCompose */) {
game->setRoomParams(getRoomIndex(), Shader::MIRROR, 1.2f, 1.0f, 0.2f, 1.0f, false); game->setRoomParams(getRoomIndex(), Shader::MIRROR, 1.2f, 1.0f, 0.2f, 1.0f, false);

View File

@@ -448,7 +448,8 @@ struct MeshBuilder {
} }
} }
weldSkinJoints(vertices + vStartModel); weldSkinJoints(vertices + vStartModel, level->extra.laraSkin, level->extra.laraJoints);
weldSkinJoints(vertices + vStartModel, level->extra.braid, level->extra.braid);
ASSERT(vCount - vStartModel <= 0xFFFF); ASSERT(vCount - vStartModel <= 0xFFFF);
@@ -696,15 +697,15 @@ struct MeshBuilder {
return false; return false;
} }
void weldSkinJoints(Vertex *vertices) { void weldSkinJoints(Vertex *vertices, int16 skinIndex, int16 jointsIndex) {
if (level->extra.laraSkin == -1 || level->extra.laraJoints == -1) { if (skinIndex == -1 || jointsIndex == -1) {
return; return;
} }
int t = Core::getTime();
ASSERT(level->models[level->extra.laraSkin].mCount == level->models[level->extra.laraJoints].mCount);
const TR::Model *model = level->models + level->extra.laraSkin; ASSERT(level->models[skinIndex].mCount == level->models[jointsIndex].mCount);
const TR::Node *node = (TR::Node*)level->nodesData + model->node;
const TR::Model *model = level->models + skinIndex;
const TR::Node *node = (TR::Node*)&level->nodesData[model->node];//(TR::Node*)level->nodesData + model->node;
int sIndex = 0; int sIndex = 0;
short4 stack[16]; short4 stack[16];
@@ -723,8 +724,8 @@ struct MeshBuilder {
jointsPos[i] = pos; jointsPos[i] = pos;
} }
const ModelRange &rangeSkin = models[level->extra.laraSkin]; const ModelRange &rangeSkin = models[skinIndex];
const ModelRange &rangeJoints = models[level->extra.laraJoints]; const ModelRange &rangeJoints = models[jointsIndex];
#define COORD_FILL(VAR,RANGE)\ #define COORD_FILL(VAR,RANGE)\
short4 *VAR = new short4[RANGE.vCount];\ short4 *VAR = new short4[RANGE.vCount];\
@@ -741,7 +742,8 @@ struct MeshBuilder {
// bruteforce :( // bruteforce :(
for (int j = 0; j < rangeJoints.vCount; j++) { for (int j = 0; j < rangeJoints.vCount; j++) {
for (int i = 0; i < rangeSkin.vCount; i++) { for (int i = 0; i < rangeSkin.vCount; i++) {
if (abs(vSkin[i].x - vJoints[j].x) <= 1 && if (//vSkin[i].w < vJoints[j].w &&
abs(vSkin[i].x - vJoints[j].x) <= 1 &&
abs(vSkin[i].y - vJoints[j].y) <= 1 && abs(vSkin[i].y - vJoints[j].y) <= 1 &&
abs(vSkin[i].z - vJoints[j].z) <= 1) { // compare position abs(vSkin[i].z - vJoints[j].z) <= 1) { // compare position
vertices[rangeJoints.vStart + j].coord = vertices[rangeSkin.vStart + i].coord; // set bone index vertices[rangeJoints.vStart + j].coord = vertices[rangeSkin.vStart + i].coord; // set bone index
@@ -755,8 +757,6 @@ struct MeshBuilder {
delete[] vJoints; delete[] vJoints;
#undef COORD_FILL #undef COORD_FILL
LOG("remap joints: %d\n", Core::getTime() - t);
} }
int calcWaterLevel(int16 roomIndex, bool flip) { int calcWaterLevel(int16 roomIndex, bool flip) {