re: the sound-cue table, and cutscene dialogue's speaker/portrait/timing
dat/tables.pak holds a 5798-entry SOUNDS record (cue name -> sound id) and a 5135-entry FILES record (.slb bank paths). Cue names are the join key, so a script message id now resolves all the way to the bank that voices it: MSG_VOICE_D_257 -> VOICE_D_257 -> 6945 -> jpn\etc\VOICE_D_257.slb. The prefix rule is MSG_ -> VOICE_, not strip-MSG_. My first rule was the latter; it left 88 names unresolved and I was about to write those families up as text-only announcements, until VOICE_TCAF_592.slb turned up in FILES and refuted it. Corrected rule resolves 1326 of 1338, and SOUNDS and FILES agree on exactly the same 12 absentees. Separately, MSG_DEMO_* is driven by its own IDXD tables in the language packs, which carry speaker, portrait, on-screen seconds and audio cue per page. Field count is 9*PageCount+2 for all 7 distinct PageCounts; 1252/1252 caption-key slots match <ID>_<page>_<line>; the 78 multi-page records equal the 78 counted independently from the caption side; 138 ids close exactly against the caption table both ways. Does not settle the known VOICE_D_452 wrong-recording case -- every cue id is distinct, so bank sharing is not happening at this layer.
This commit is contained in:
320
docs/re/data/cutscene-message-table.txt
Normal file
320
docs/re/data/cutscene-message-table.txt
Normal file
@@ -0,0 +1,320 @@
|
||||
# Cutscene message table — dat/GP_MAIN_GAME_E.pak, IDXD objects
|
||||
#
|
||||
# One line per page. A page is one subtitle box; successive pages are
|
||||
# successive utterances, which is why the speaker changes mid-message.
|
||||
# Columns: id, page, speaker, portrait, on-screen seconds, audio cue,
|
||||
# then the caption text.
|
||||
|
||||
MSG_DEMO_000 p0 CRICHTON CRICHTON_02 2s DEMO_000 ACROPOLIS to Rhino Leader. Permission granted to return fire.
|
||||
p1 CRICHTON CRICHTON_07 2.3s DEMO_001 We're sending Bird Flight to back you up.
|
||||
p2 CRICHTON CRICHTON_02 2.2s DEMO_002 Raymond, take care of the cadets.
|
||||
p3 RAYMOND RAYMOND_01 2s DEMO_003 Don't worry. I'll make sure we get out of this.
|
||||
p4 RAYMOND RAYMOND_06 5.2s DEMO_004 Ellen, Katana, engage the enemy together!
|
||||
MSG_DEMO_005 p0 ELLEN ELLEN_04 1.1s DEMO_005 Rhino 3, roger that!
|
||||
p1 KATANA KATANA_04 1.8s DEMO_006 Rhino 2, roger that!
|
||||
MSG_DEMO_007 p0 RAYMOND RAYMOND_01 2.9s DEMO_007 Okay, it looks like we can escape now.
|
||||
p1 KATANA KATANA_06 3.2s DEMO_008 Rhino Leader, a jump-out signal has appeared on the radar!
|
||||
MSG_DEMO_009 p0 ELLEN ELLEN_05 1.6s DEMO_009 No way! There's more of them?
|
||||
p1 RAYMOND RAYMOND_03 3.6s DEMO_010 Rhino Leader to ACROPOLIS! There's a whole fleet of them now!
|
||||
p2 CRICHTON CRICHTON_07 1.4s DEMO_011 What? Is there any way you can get out of there?
|
||||
p3 RAYMOND RAYMOND_07 2.8s DEMO_012 If we get rid of those fighters, we can cut our way out of here.
|
||||
MSG_DEMO_013 p0 SANDRA SANDRA_06 2.8s DEMO_013 This is Bird Leader! Do you copy, Raymond?
|
||||
MSG_DEMO_014 p0 RAYMOND RAYMOND_06 3.6s DEMO_014 We did it! Okay, all pilots follow my lead!
|
||||
MSG_DEMO_015 p0 RAYMOND RAYMOND_01 4.8s DEMO_015 Rhino Leader to ACROPOLIS. We made it through and we're coming home.
|
||||
p1 CRICHTON CRICHTON_01 3.1s DEMO_016 Roger. It's good to see you're all safe.
|
||||
MSG_DEMO_017 p0 KATANA KATANA_07 2.1s DEMO_017 Yeah, but Brandon ...
|
||||
p1 ANTONIUS ANTONIUS_03 5.4s DEMO_018 Damn. There's only seven of us.
|
||||
p2 ELLEN ELLEN_11 3.6s DEMO_019 Brandon ... How could this happen?
|
||||
p3 KATANA KATANA_08 2.1s DEMO_020 Ellen ...
|
||||
MSG_DEMO_021 p0 RAYMOND RAYMOND_02 2.5s DEMO_021 It's over … for now.
|
||||
MSG_DEMO_022 p0 RAYMOND RAYMOND_04 4.2s DEMO_022 This is Rhino Leader. Enemy destroyed. I think Katana here deserves a medal.
|
||||
p1 CRICHTON CRICHTON_03 3.6s DEMO_023 Understood. I'll have some hot coffee for you when you get back.
|
||||
MSG_DEMO_024 p0 RAYMOND RAYMOND_04 4s DEMO_024 Katana, I didn't know you could fly like that.
|
||||
p1 KATANA KATANA_07 2.3s DEMO_025 Yeah, but Brandon ...
|
||||
p2 RAYMOND RAYMOND_01 2.3s DEMO_026 It wasn't your fault.
|
||||
p3 RAYMOND RAYMOND_02 2.1s DEMO_027 We're going home, Katana.
|
||||
p4 KATANA KATANA_07 2s DEMO_028 Right.
|
||||
MSG_DEMO_029 p0 VIEIRA VIEIRA_02 4.2s DEMO_029 TCAF CALIBAN to Schlos Base. Haven't you been able to get a signal yet?
|
||||
p1 HIGGINS HIGGINS_02 4.3s DEMO_030 Admiral Vieira, we are under attack right now! Please give up on contacting headquarters!
|
||||
MSG_DEMO_031 p0 RAYMOND RAYMOND_01 2.4s DEMO_031 Katana, Ellen, stick together and you'll be okay.
|
||||
p1 RAYMOND RAYMOND_05 2.9s DEMO_032 Gene, you're behind me. Now, don't screw up!
|
||||
p2 GENE GENE_01 1.5s DEMO_033 Yes sir.
|
||||
p3 RAYMOND RAYMOND_06 3.7s DEMO_034 Don't be afraid! Show them what our Delta Sabers can do!
|
||||
MSG_DEMO_035 p0 VIEIRA VIEIRA_02 4.1s DEMO_035 TCAF CALIBAN to ACROPOLIS.
|
||||
p1 VIEIRA VIEIRA_01 3.8s DEMO_036 We are withdrawing temporarily to reorganize the front. I need you to escort us.
|
||||
p2 CRICHTON CRICHTON_04 2.3s DEMO_037 Admiral, what do you mean? We're currently engaged in ...
|
||||
p3 VIEIRA VIEIRA_02 4.6s DEMO_038 No backtalk! My ship must be protected at all costs!
|
||||
p4 CRICHTON CRICHTON_06 1.3s DEMO_039 Understood.
|
||||
MSG_DEMO_040 p0 CRICHTON CRICHTON_02 2.5s DEMO_040 ACROPOLIS to Rhino Leader. I need you to provide an escort for the flagship CALIBAN.
|
||||
p1 NATALIE NATALIE_01 1.8s DEMO_041 I've sent the coordinates of Admiral Vieira's ship.
|
||||
p2 RAYMOND RAYMOND_01 2s DEMO_042 Rhino Leader, roger that.
|
||||
MSG_DEMO_043 p0 TCAFBASEOP TCAFBASEOP_02 2.7s DEMO_043 Incoming interstellar cruise missile!
|
||||
p1 HIGGINS HIGGINS_02 1.3s DEMO_044
|
||||
MSG_DEMO_045 p0 HIGGINS HIGGINS_01 2.5s DEMO_045 At this rate the base won't last long! Your orders, sir?
|
||||
p1 VIEIRA VIEIRA_02 3.6s DEMO_046 We've sustained severe damage as well, Higgins! I'm turning over command to you!
|
||||
p2 HIGGINS HIGGINS_02 2.5s DEMO_047 Admiral?
|
||||
p3 VIEIRA VIEIRA_01 3s DEMO_048 I .. uh … I have to bring word of the invasion to our other fleets!
|
||||
p4 VIEIRA VIEIRA_02 4s DEMO_049 Set a course for Hargenteen in the Ingres System. Commence jump!
|
||||
MSG_DEMO_050 p0 KATANA KATANA_04 1s DEMO_050 The Admiral's ship ...
|
||||
p1 ELLEN ELLEN_05 1.5s DEMO_051 Did he just run away?
|
||||
MSG_DEMO_052 p0 IAN IAN_03 3s DEMO_052 More cruise missiles have jumped out! Their target is Schlos Base!
|
||||
p1 CRICHTON CRICHTON_04 2s DEMO_053 All Flights! Shoot down those missiles!
|
||||
p2 RAYMOND RAYMOND_06 1.2s DEMO_054 Roger that!
|
||||
MSG_DEMO_055 p0 CRICHTON CRICHTON_04 3.4s DEMO_055 This is the TCAF ACROPOLIS. Schlos Base, can you read me?
|
||||
MSG_DEMO_056 p0 HIGGINS HIGGINS_02 3.3s DEMO_056 This is Schlos Base. We're still here, barely.
|
||||
p1 HIGGINS HIGGINS_01 3.8s DEMO_057 But it appears the ADAN forces are retreating. Good work everyone.
|
||||
MSG_DEMO_058 p0 ELLEN ELLEN_02 2s DEMO_058 We did it, Katana!
|
||||
MSG_DEMO_059 p0 KATANA KATANA_08 2.1s DEMO_059 We tried to destroy all the missiles, but ...
|
||||
p1 RAYMOND RAYMOND_04 2.8s DEMO_060 No, you did fine. It's those fools' fault for turning chicken.
|
||||
p2 GENE GENE_01 2s DEMO_061 I bet we're going to get medals for this!
|
||||
MSG_DEMO_062 p0 CRICHTON CRICHTON_02 2.4s DEMO_062 Let's help the others. Pilots, return to the carrier.
|
||||
p1 RAYMOND RAYMOND_05 1.5s DEMO_063 Roger.
|
||||
MSG_DEMO_064 p0 CRICHTON CRICHTON_07 3.3s DEMO_064 This is the ACROPOLIS! Come in, Headquarters! We are suffering heavy losses!
|
||||
MSG_DEMO_065 p0 HIGGINS HIGGINS_01 3.7s DEMO_065 This is acting Admiral Higgins. Our fleet is also engaged in combat. We can't spare anyone to assist you.
|
||||
p1 HIGGINS HIGGINS_02 2.2s DEMO_066 You're going to have to complete your mission with the units you have.
|
||||
MSG_DEMO_067 p0 CRICHTON CRICHTON_05 1.6s DEMO_067A Understood.
|
||||
MSG_DEMO_069 p0 CRICHTON CRICHTON_02 2.9s DEMO_068 Our first priority is the safety of the transit platforms. Pilots, get rid of the nearby enemies.
|
||||
MSG_DEMO_070 p0 IAN IAN_02 2.7s DEMO_069 The enemy squadron has been destroyed! The area is now secure.
|
||||
p1 CRICHTON CRICHTON_01 1.2s DEMO_070 Good.
|
||||
MSG_DEMO_072 p0 CRICHTON CRICHTON_02 4.7s DEMO_071 ACROPOLIS to the cargoships. You can now take off. Evacuate as soon as you are ready.
|
||||
p1 SHIPLADY1 SHIPLADY1_02 3.7s DEMO_072 Roger that! We three are going first. Keep us covered!
|
||||
p2 CRICHTON CRICHTON_02 2.6s DEMO_073 Rhino Flight, Bird Flight, escort the cargoships.
|
||||
MSG_DEMO_075 p0 SHIPLADY1 SHIPLADY1_01 4.5s DEMO_074 This is LADY 1. We are preparing to exit the atmosphere. Take care of yourselves!
|
||||
MSG_DEMO_076 p0 NATALIE NATALIE_02 2.3s DEMO_075 All cargoships successfully evacuated.
|
||||
p1 CRICHTON CRICHTON_07 1.2s DEMO_076 Who's next?
|
||||
p2 NATALIE NATALIE_02 1.5s DEMO_077 The next group of four ships is the last.
|
||||
p3 CRICHTON CRICHTON_02 2s DEMO_078 Good, then we're going along with them.
|
||||
p4 CRICHTON CRICHTON_07 1.6s DEMO_079 Natalie, call back the squadron to escort us.
|
||||
p5 NATALIE NATALIE_01 0.8s DEMO_080 Roger.
|
||||
MSG_DEMO_082 p0 IAN IAN_03 3.3s DEMO_081 Captain! A new group of enemies is approaching at high speed! It's the same black squadron!
|
||||
MSG_DEMO_083 p0 MARGRAS2 MARGRAS2_05 2s DEMO_082 Night Ravens, attack!
|
||||
MSG_DEMO_084 p0 MARGRAS2 MARGRAS2_01 2.9s DEMO_083 That's enough. All units, retreat.
|
||||
MSG_DEMO_085 p0 TASKENT TASKENT_03 4.5s DEMO_084 Damn it! I'll make them pay the next time I see them!
|
||||
p1 MARGRAS2 MARGRAS2_02 2.8s DEMO_085 Yeah, I didn't expect resistance like that, either.
|
||||
MSG_DEMO_087 p0 RAYMOND RAYMOND_01 1.8s DEMO_086 Who knew ADAN had pilots that skilled?
|
||||
p1 KATANA KATANA_03 3.3s DEMO_087 I was surprised, too. Their leader was especially tough.
|
||||
p2 ELLEN ELLEN_09 2.7s DEMO_088 They can try, but it won't get them anywhere!
|
||||
p3 RAYMOND RAYMOND_02 2.7s DEMO_089 Personally, I hope they don't come back.
|
||||
p4 RAYMOND RAYMOND_04 4.2s DEMO_090 We're lucky we had you, Katana. Your technique just keeps getting better!
|
||||
p5 KATANA KATANA_02 1.5s DEMO_091 Thank you, sir.
|
||||
MSG_DEMO_093 p0 NATALIE NATALIE_02 2.9s DEMO_092 Beginning atmosphere exit sequence. All units return to the carrier.
|
||||
p1 RAYMOND RAYMOND_01 2.6s DEMO_093 Roger that. Say goodbye to Lebendorf.
|
||||
MSG_DEMO_095 p0 KATANA KATANA_04 2.2s DEMO_094 Rhino Leader, they're here!
|
||||
MSG_DEMO_096 p0 ELLEN ELLEN_03 2.4s DEMO_095 They haven't noticed us yet.
|
||||
p1 RAYMOND RAYMOND_01 3.3s DEMO_096 All units, start your engines. Let's do this!
|
||||
p2 RAYMOND RAYMOND_06 4.2s DEMO_097 Whether the rest of the fleet escapes or not depends on us. Everybody stay focused!
|
||||
MSG_DEMO_099 p0 IAN IAN_04 3.5s DEMO_098 Captain! Enemies approaching from 2 o'clock! It's a mixed group of ships and fighters!
|
||||
MSG_DEMO_100 p0 IAN IAN_03 2.3s DEMO_099 They're fast! It's that black squadron!
|
||||
MSG_DEMO_101 p0 ELLEN ELLEN_04 2.5s DEMO_100 The black squadron ... Katana ... it couldn't be.
|
||||
p1 KATANA KATANA_05 2.2s DEMO_101 Could it really be Margras?
|
||||
MSG_DEMO_103 p0 RAYMOND RAYMOND_06 3s DEMO_102 Don't let any of them get near the ACROPOLIS!
|
||||
p1 RAYMOND RAYMOND_01 2.4s DEMO_103 And Katana, don't go chasing after any more enemies!
|
||||
p2 GENE GENE_01 1.9s DEMO_104 Yeah, you heard Rhino Leader.
|
||||
p3 ELLEN ELLEN_04 1.8s DEMO_105 But Katana had a reason for going after that one!
|
||||
p4 KATANA KATANA_08 2.3s DEMO_106 It's okay, Ellen.
|
||||
p5 KATANA KATANA_03 1.7s DEMO_107 I'll be more careful from now on, Leader.
|
||||
p6 RAYMOND RAYMOND_05 1.8s DEMO_108 All right. Now get out there and do your best!
|
||||
p7 KATANA KATANA_02 1.3s DEMO_109 Yes, sir!
|
||||
MSG_DEMO_111 p0 IAN IAN_03 1.7s DEMO_110 Two more enemy ships have jumped out! They're close!
|
||||
p1 CRICHTON CRICHTON_05 1.4s DEMO_111
|
||||
MSG_DEMO_113 p0 NATALIE NATALIE_04 1s DEMO_112 Deck 3 has been hit!
|
||||
p1 IAN IAN_04 1.2s DEMO_113 Captain, at this rate we're goners!
|
||||
p2 CRICHTON CRICHTON_02 3.3s DEMO_114 Rhino Flight, attack the destroyers around the ACROPOLIS! Bird Flight, check the destroyers farther out!
|
||||
p3 CRICHTON CRICHTON_06 1.6s DEMO_115 Russell, how much longer will those engine repairs take?
|
||||
p4 RUSSELL RUSSELL_02 0.8s DEMO_116 At least ten minutes.
|
||||
p5 CRICHTON CRICHTON_02 1.4s DEMO_117 Do it in five!
|
||||
MSG_DEMO_119 p0 CRICHTON CRICHTON_04 2s DEMO_118 We mustn't give in! Show some spirit!
|
||||
MSG_DEMO_120 p0 RUSSELL RUSSELL_02 3.2s DEMO_119 Captain, the engine is back online! We can go any time!
|
||||
p1 IAN IAN_02 2.5s DEMO_120 Enemy reinforcements! They're headed this way!
|
||||
p2 CRICHTON CRICHTON_02 2.5s DEMO_121 Let's cut our way through them and jump. Pilots, return to the carrier!
|
||||
p3 RAYMOND RAYMOND_06 2.2s DEMO_122 Roger that. Katana, let's go!
|
||||
MSG_DEMO_124 p0 ELLEN ELLEN_06 2.9s DEMO_123 This is just too much! Why do they keep following us wherever we go?
|
||||
p1 GENE GENE_03 1.9s DEMO_124 I thought we were finally gonna be able to relax once we reached Hargenteen.
|
||||
p2 KATANA KATANA_01 1.4s DEMO_125 There's nothing we can do about it, so let's just get it over with.
|
||||
p3 RAYMOND RAYMOND_05 1.4s DEMO_126 That's right. This is no time to slack off.
|
||||
p4 RAYMOND RAYMOND_01 3.5s DEMO_127 We'll be making contact with the enemy soon, so save your complaints for them!
|
||||
MSG_DEMO_129 p0 ADANB ADANB_01 2.8s DEMO_128 All ships, commence attack on the TCAF squadron.
|
||||
MSG_DEMO_130 p0 ELLEN ELLEN_09 2.7s DEMO_129 Reinforcements? I thought we'd seen the last of them.
|
||||
p1 RAYMOND RAYMOND_03 3.6s DEMO_130 Well, you were wrong. Everybody be careful!
|
||||
p2 KATANA KATANA_03 1.1s DEMO_131 Roger that!
|
||||
MSG_DEMO_133 p0 TCAFMIRANDA TCAFMIRANDA_01 4.5s DEMO_132 This is the TCAF MIRANDA. Glad to see you're still with us, ACROPOLIS.
|
||||
p1 TCAFMIRANDA TCAFMIRANDA_02 3.2s DEMO_133 We're about to begin our ambush, so we'll need all the help we can get from you and your squadron.
|
||||
MSG_DEMO_135 p0 IAN IAN_03 2.7s DEMO_134 Something is jumping out in front of us! It's big!
|
||||
MSG_DEMO_136 p0 ADANETERNAL ADANETERNAL_02 3.5s DEMO_135 Ready … Aim … Fire!
|
||||
MSG_DEMO_137 p0 CRICHTON CRICHTON_07 3.1s DEMO_136 This is bad. Pilots, take out that battleship!
|
||||
p1 ELLEN ELLEN_08 3s DEMO_137 You want me to stop them? Easy for you to say!
|
||||
MSG_DEMO_139 p0 IAN IAN_01 1.5s DEMO_138 Enemy battleship destroyed!
|
||||
p1 CRICHTON CRICHTON_01 2.4s DEMO_139 Looks like we've driven them off for now.
|
||||
MSG_DEMO_141 p0 KATANA KATANA_10 1.8s DEMO_140 Rhino Leader! Are you all right?
|
||||
p1 RAYMOND RAYMOND_07 2s DEMO_141 I'm fine.
|
||||
MSG_DEMO_143 p0 VIEIRA VIEIRA_03 4s DEMO_142 It's time to show the enemy what the 17th Independent Squadron is made of! Give it your all!
|
||||
MSG_DEMO_144 p0 ANTONIUS ANTONIUS_01 2.9s DEMO_143 Like I need him to tell me that! They should leave everything up to us White Griffons!
|
||||
p1 SANDRA SANDRA_06 1.7s DEMO_144 All right everybody, time to do this!
|
||||
MSG_DEMO_146 p0 ELLEN ELLEN_01 1.2s DEMO_145 Everyone's really pumped up!
|
||||
p1 KATANA KATANA_02 1.6s DEMO_146 Yeah, let's do it!
|
||||
p2 YOJI YOJI_03 2.3s DEMO_147 It's an honor to serve under your command, Rhino Leader. I'm lookin' forward to it.
|
||||
MSG_DEMO_149 p0 RAYMOND RAYMOND_11 3.3s DEMO_148 ACROPOLIS to White Griffon Squadron. Your first priority ... get rid of the enemy's Flight units.
|
||||
p1 RAYMOND RAYMOND_14 2.8s DEMO_149 Katana, go in there full-force. I know you can handle it.
|
||||
MSG_DEMO_151 p0 KATANA KATANA_03 1.2s DEMO_150 Yes sir!
|
||||
MSG_DEMO_152 p0 TCAFCALIBANOP TCAFCALIBANOP_01 1.9s DEMO_151 Sir, the enemy forces are driven off and our course is secured!
|
||||
p1 VIEIRA VIEIRA_02 4.2s DEMO_152 Good. We're going to charge the enemy! All ships, full speed ahead!
|
||||
p2 VIEIRA VIEIRA_01 2.2s DEMO_153 ACROPOLIS, make an opening for us!
|
||||
p3 CRICHTON CRICHTON_06 1.4s DEMO_154 Are you telling us to take the lead again?
|
||||
p4 VIEIRA VIEIRA_02 2.3s DEMO_155 Do I need to repeat myself?
|
||||
p5 CRICHTON CRICHTON_02 2.1s DEMO_156 Understood. Commencing charge.
|
||||
MSG_DEMO_158 p0 RAYMOND RAYMOND_14 3.5s DEMO_157 We're all through here, Katana. Good job.
|
||||
p1 KATANA KATANA_02 1s DEMO_158 Thank you, sir.
|
||||
p2 VIEIRA VIEIRA_03 3.5s DEMO_159 We are heading into enemy territory! All ships, finish preparations and commence jump!
|
||||
MSG_DEMO_161 p0 VIEIRA VIEIRA_02 2.8s DEMO_160 What? What happened?
|
||||
p1 TCAFCALIBANOP TCAFCALIBANOP_02 3s DEMO_161 It was a mine! There's a mine field around the enemy base!
|
||||
p2 VIEIRA VIEIRA_02 1.2s DEMO_162 What?
|
||||
MSG_DEMO_164 p0 CRICHTON CRICHTON_07 1.3s DEMO_163 We've got to do something to help the others.
|
||||
p1 RAYMOND RAYMOND_16 2s DEMO_164 Katana, destroy the mines around the fleet!
|
||||
MSG_DEMO_166 p0 ADANOPB ADANOPB_02 1.7s DEMO_165 They've destroyed the mines!
|
||||
p1 ADANBASE ADANBASE_01 2.5s DEMO_166 Send out the defense force to intercept them.
|
||||
MSG_DEMO_168 p0 VIEIRA VIEIRA_03 3.3s DEMO_167 Well done! All my pilots are aces!
|
||||
p1 VIEIRA VIEIRA_02 3s DEMO_168 We're attacking the enemy base. All ships, follow my lead!
|
||||
MSG_DEMO_170 p0 TCAFCALIBANOP TCAFCALIBANOP_01 1.6s DEMO_169 The enemy base has been destroyed!
|
||||
p1 VIEIRA VIEIRA_03 4.6s DEMO_170 Good. Now maybe those ADAN scum know how foolish they were to challenge us.
|
||||
p2 VIEIRA VIEIRA_01 2.5s DEMO_171 Call in the fighters and set a course for the next target!
|
||||
MSG_DEMO_173 p0 VIEIRA VIEIRA_03 3.3s DEMO_172 Heh, is this all they have? We'll scatter them like ants!
|
||||
p1 VIEIRA VIEIRA_01 2s DEMO_173 Destroyers and fighters, attack!
|
||||
MSG_DEMO_175 p0 ELLEN ELLEN_08 2.8s DEMO_174 Hey, Katana, could this be the same Acheron ... ?
|
||||
p1 KATANA KATANA_04 3.1s DEMO_175 Yeah, this should be Margras' home planet.
|
||||
p2 ELLEN ELLEN_04 2.5s DEMO_176 But I thought he said it was a green planet?
|
||||
MSG_DEMO_178 p0 KATANA KATANA_08 1.8s DEMO_177 What happened here?
|
||||
MSG_DEMO_179 p0 TCAFCALIBANOP TCAFCALIBANOP_01 2.7s DEMO_178 The enemy force is moving away from the targeted facility. They could be trying to escape.
|
||||
p1 VIEIRA VIEIRA_01 2.2s DEMO_179 So they're running in fear. Chase them down!
|
||||
MSG_DEMO_181 p0 CRICHTON CRICHTON_06 1.8s DEMO_180 Admiral Vieira, what about investigating the other wreckage?
|
||||
p1 VIEIRA VIEIRA_03 4.2s DEMO_181 What? Well, the ACROPOLIS should be able to handle that on its own. I leave it up to you.
|
||||
p2 VIEIRA VIEIRA_01 1.6s DEMO_182 But I want the White Griffons sent after the enemy.
|
||||
p3 CRICHTON CRICHTON_07 2.2s DEMO_183 But if we do that then we won't have enough cover.
|
||||
p4 VIEIRA VIEIRA_03 2.6s DEMO_184 There aren't any enemies in those other ruins.
|
||||
p5 CRICHTON CRICHTON_02 2.3s DEMO_185 Understood. I'll send Rhino Flight over your way.
|
||||
MSG_DEMO_187 p0 CRICHTON CRICHTON_02 1.7s DEMO_186 Bird Flight stays with the ACROPOLIS.
|
||||
MSG_DEMO_188 p0 ADANPLD ADANPLD_02 2.6s DEMO_187 Those idiots have fallen right into our trap. Attack!
|
||||
MSG_DEMO_189 p0 VIEIRA VIEIRA_02 3.1s DEMO_188 Warships? Where were they hiding those?
|
||||
p1 VIEIRA VIEIRA_01 2.3s DEMO_189 Retreat! Retreat!
|
||||
p2 VIEIRA VIEIRA_02 2.6s DEMO_190A White Griffon Squadron! Protect my ship!
|
||||
p3 ELLEN ELLEN_05 2s DEMO_190B The black squadron? Katana!
|
||||
p4 KATANA KATANA_06 2s DEMO_190C What are they doing here?
|
||||
MSG_DEMO_192 p0 TCAFCALIBANOP TCAFCALIBANOP_02 2.1s DEMO_191 Enemy reinforcements are heading this way!
|
||||
p1 VIEIRA VIEIRA_02 2.5s DEMO_192 More of them? We've got no choice. Commence jump!
|
||||
MSG_DEMO_194 p0 TASKENT TASKENT_02 2.5s DEMO_193 Damn, the big fish got away.
|
||||
MSG_DEMO_195 p0 TASKENT TASKENT_04 2.5s DEMO_194 Oh well, I'll just go and hit that carrier over there!
|
||||
p1 RAYMOND RAYMOND_13 2.8s DEMO_195 Katana, return to the ACROPOLIS now! Sandra and the others are in trouble!
|
||||
p2 ELLEN ELLEN_09 1.5s DEMO_196 We've got troubles of our own!
|
||||
p3 KATANA KATANA_11 1.3s DEMO_197 Ellen, you and the others go! I'll handle things here!
|
||||
MSG_DEMO_199 p0 TASKENT TASKENT_04 1s DEMO_198 You little punk!
|
||||
MSG_DEMO_200 p0 TASKENT TASKENT_03 1s DEMO_199
|
||||
MSG_DEMO_201 p0 KATANA KATANA_09 3.7s DEMO_200 Aaaaah! Margras!
|
||||
MSG_DEMO_202 p0 MARGRAS MARGRAS_06 2.6s DEMO_201 This isn't good!
|
||||
MSG_DEMO_203 p0 KATANA KATANA_09 1.6s DEMO_202 Wait, Margras!
|
||||
MSG_DEMO_204 p0 RUSSELL RUSSELL_01 2.8s DEMO_203 Engineering report: there's no problem with the atmospheric composition, so we should be able to use it as fuel.
|
||||
p1 CRICHTON CRICHTON_03 2.1s DEMO_204 Understood. Looks like we're going to make it back to Hargenteen after all.
|
||||
MSG_DEMO_206 p0 IAN IAN_02 2.4s DEMO_205 Incoming enemy fighters! They're heading straight for the ACROPOLIS!
|
||||
p1 CRICHTON CRICHTON_06 2s DEMO_206 Why can't they just leave us alone?
|
||||
p2 CRICHTON CRICHTON_02 3.1s DEMO_207 Bird Flight, protect ACROPOLIS. Rhino Flight, move to intercept the enemy.
|
||||
p3 CRICHTON CRICHTON_07 1.8s DEMO_208 We'll continue resupplying as we take evasive action.
|
||||
p4 KATANA KATANA_03 1.8s DEMO_209 Roger that! Moving to intercept.
|
||||
p5 SANDRA SANDRA_04 1.7s DEMO_210 We're counting on you, Rhino Leader!
|
||||
MSG_DEMO_212 p0 ADANA ADANA_02 2.4s DEMO_211 There they are! Attack!
|
||||
MSG_DEMO_213 p0 CRICHTON CRICHTON_05 2.3s DEMO_212
|
||||
p1 CRICHTON CRICHTON_07 2s DEMO_213 White Griffons, attack the enemy fleet!
|
||||
MSG_DEMO_215 p0 CRICHTON CRICHTON_02 3s DEMO_214 Now! All engines full power! We're leaving!
|
||||
p1 RUSSELL RUSSELL_01 2.5s DEMO_215 Understood! Hold on tight!
|
||||
MSG_DEMO_217 p0 RUSSELL RUSSELL_02 2.3s DEMO_216A Here we go!
|
||||
MSG_DEMO_218 p0 HIGGINS HIGGINS_01 3.2s DEMO_219 TCAF VINSON to ACROPOLIS.
|
||||
p1 HIGGINS HIGGINS_03 4.2s DEMO_220 It's been a while since Lebendorf. I'm proud to be fighting alongside you again.
|
||||
p2 CRICHTON CRICHTON_03 2.2s DEMO_221 The feeling is mutual, Commodore Higgins. Let's give it everything we've got!
|
||||
MSG_DEMO_221 p0 TCAFOPA TCAFOPA_02 3s DEMO_217 The vanguard of the enemy fleet is speeding up. They're charging!
|
||||
MSG_DEMO_222 p0 TCAFOLYMPUS TCAFOLYMPUS_02 2s DEMO_218 All ships, prepare for combat!
|
||||
MSG_DEMO_223 p0 CRICHTON CRICHTON_04 1.9s DEMO_222 Why have they spread out?
|
||||
p1 IAN IAN_02 2s DEMO_223 Something is jumping out in front of us. Mass reading is ...
|
||||
p2 IAN IAN_03 3s DEMO_224 Impossible! It has a mass reading of almost thirty trillion tons!
|
||||
MSG_DEMO_226 p0 CRICHTON CRICHTON_01 3.1s DEMO_225 The enemy's main force has been destroyed. We've gained a firm advantage in the battle.
|
||||
p1 NATALIE NATALIE_03 1.9s DEMO_226 Way to go, White Griffons!
|
||||
p2 IAN IAN_02 2.1s DEMO_227 Something is jumping out in front of us. Mass reading is ...
|
||||
p3 IAN IAN_03 3s DEMO_228 Impossible! It has a mass reading of almost thirty trillion tons!
|
||||
MSG_DEMO_230 p0 SANDRA SANDRA_06 2.2s DEMO_245 Damn it. All of them lost, in an instant!
|
||||
p1 ELLEN ELLEN_04 3.2s DEMO_246 Huh, what the … what is that thing?
|
||||
MSG_DEMO_232 p0 CRICHTON CRICHTON_04 2.2s DEMO_247 Back into formation! We have to help the fleet and get out ourselves!
|
||||
MSG_DEMO_233 p0 KATANA KATANA_10 1.8s DEMO_248 That's right. Don't give up!
|
||||
MSG_DEMO_234 p0 RUSSELL RUSSELL_01 2.2s DEMO_249 Captain, I think we should get moving, too.
|
||||
p1 CRICHTON CRICHTON_02 2.8s DEMO_250 I agree. Call back the White Griffons!
|
||||
MSG_DEMO_236 p0 IAN IAN_02 1.6s DEMO_255 We destroyed all the enemy forces in the area!
|
||||
p1 CRICHTON CRICHTON_06 1.2s DEMO_256 Commodore Higgins, now's our chance!
|
||||
MSG_DEMO_238 p0 HIGGINS HIGGINS_02 3.3s DEMO_257 Very well. Commence jump! Set a course for Earth!
|
||||
p1 HIGGINS HIGGINS_03 4s DEMO_258 We never would have gotten out without the White Griffons. Once we get back, I'm giving you all medals.
|
||||
MSG_DEMO_240 p0 IAN IAN_02 4s DEMO_259 It's definitely the Night Raven Squadron. However, we don't have any information regarding one of the fighters. It's most likely a prototype.
|
||||
MSG_DEMO_241 p0 ELLEN ELLEN_04 1.2s DEMO_260 Katana ...
|
||||
p1 KATANA KATANA_11 1.3s DEMO_261 I know.
|
||||
MSG_DEMO_243 p0 MARGRAS MARGRAS_04 2.9s DEMO_262 Katana, can you hear me? Katana!
|
||||
p1 KATANA KATANA_05 1.5s DEMO_263 Margras!
|
||||
p2 MARGRAS MARGRAS_02 2.4s DEMO_264 So you're the one they sent after us ... Good.
|
||||
p3 KATANA KATANA_04 0.3s DEMO_265 Wait, there's something I have to ask you.
|
||||
p4 MARGRAS MARGRAS_05 2.5s DEMO_266 Fight me. Let's end this here!
|
||||
MSG_DEMO_248 p0 ADANPLE ADANPLE_02 2.4s DEMO_267 Sir, we've lost contact with Raven 5!
|
||||
p1 MARGRAS MARGRAS_01 2.6s DEMO_268 Katana, you've gotten better.
|
||||
MSG_DEMO_250 p0 MARGRAS MARGRAS_06 1.5s DEMO_269 Stay back, all of you.
|
||||
MSG_DEMO_251 p0 KATANA KATANA_06 1.5s DEMO_270 Ellen, below you!
|
||||
p1 ELLEN ELLEN_10 1s DEMO_271
|
||||
MSG_DEMO_253 p0 ELLEN ELLEN_05 1.7s DEMO_272 Katana! Margras!
|
||||
MSG_DEMO_254 p0 MARGRAS MARGRAS_05 2.3s DEMO_273 Come on, Katana! It's one-on-one now!
|
||||
MSG_DEMO_255 p0 KATANA KATANA_03 2.2s DEMO_274 All right, have it your way.
|
||||
MSG_DEMO_256 p0 MARGRAS MARGRAS_06 2.3s DEMO_275 Damn! Move!
|
||||
MSG_DEMO_257 p0 MARGRAS MARGRAS_05 2.4s DEMO_276 Katana! Why aren't you firing?
|
||||
p1 KATANA KATANA_04 3s DEMO_277 Because this fight is over. Just let it end.
|
||||
p2 MARGRAS MARGRAS_04 1.7s DEMO_278A
|
||||
MSG_DEMO_260 p0 MARGRAS MARGRAS_07 3s DEMO_278B
|
||||
MSG_DEMO_261 p0 HIGGINS HIGGINS_01 5s DEMO_279 I'm going to need all your strength to protect Earth and put an end to this war!
|
||||
p1 HIGGINS HIGGINS_02 4s DEMO_280 First we have to break through the enemy forces in front of us. Good luck everyone!
|
||||
MSG_DEMO_263 p0 KATANA KATANA_03 3.4s DEMO_281 It's time, everybody. White Griffons, attack!
|
||||
p1 MARGRAS3 MARGRAS3_05 1.7s DEMO_282 Night Ravens, follow me!
|
||||
MSG_DEMO_265 p0 HIGGINS HIGGINS_02 3.2s DEMO_283 Nicely done! Now let's head for the Prometheus Driver!
|
||||
MSG_DEMO_266 p0 SANDRA SANDRA_02 3.4s DEMO_284 More of them! Guess they aren't gonna let us waltz right up to their front door!
|
||||
MSG_DEMO_267 p0 ELLEN ELLEN_05 2.5s DEMO_285 What is this? There are so many of them!
|
||||
p1 MARGRAS3 MARGRAS3_04 1.6s DEMO_286 Phantoms!
|
||||
p2 HIGGINS HIGGINS_02 3.6s DEMO_287 All ships, clear out the enemy and support the fighters! We need as many of them as possible to reach the Driver!
|
||||
MSG_DEMO_270 p0 CRICHTON CRICHTON_02 1.6s DEMO_288 Now, all units charge!
|
||||
p1 KATANA KATANA_09 2s DEMO_289 Roger that!
|
||||
p2 SANDRA SANDRA_05 3.1s DEMO_290 Damn, there's no end to them!
|
||||
p3 ELLEN ELLEN_03 2.1s DEMO_291 Katana, you go on! We'll take care of things here!
|
||||
p4 KATANA KATANA_03 1.7s DEMO_292 All right! Take care of yourself, Ellen!
|
||||
MSG_DEMO_275 p0 MARGRAS3 MARGRAS3_01 1.5s DEMO_293 Katana!
|
||||
MSG_DEMO_276 p0 KATANA KATANA_04 1.6s DEMO_294 Are we the only ones that made it through?
|
||||
p1 MARGRAS3 MARGRAS3_02 1.9s DEMO_295 Don't worry. The two of us is all it'll take.
|
||||
p2 KATANA KATANA_01 1.5s DEMO_296 You got that right. Let's go!
|
||||
MSG_DEMO_279 p0 NATALIE NATALIE_02 3.9s DEMO_297 Rhino Leader, continue your current course. The firing mechanism is directly ahead.
|
||||
p1 NATALIE NATALIE_04 2.6s DEMO_298 Hurry, we don't have much more time. The energy reading from inside the Driver is increasing.
|
||||
MSG_DEMO_281 p0 KATANA KATANA_08 3s DEMO_299 ACROPOLIS? ACROPOLIS, do you read me?
|
||||
MSG_DEMO_282 p0 KATANA KATANA_11 2.7s DEMO_300 Get out of my way!
|
||||
MSG_DEMO_283 p0 KATANA KATANA_04 1.1s DEMO_301 This must be the firing mechanism!
|
||||
MSG_DEMO_284 p0 NATALIE NATALIE_04 1.7s DEMO_302 Rhino Leader! Rhino Leader, come in!
|
||||
p1 KATANA KATANA_03 1.3s DEMO_303 This is Rhino Leader!
|
||||
p2 NATALIE NATALIE_03 2.8s DEMO_304 Oh, thank goodness you're safe!
|
||||
p3 CRICHTON CRICHTON_02 2.5s DEMO_305 They should almost be finished charging.
|
||||
p4 CRICHTON CRICHTON_07 1.5s DEMO_306 Destroy the firing mechanism now!
|
||||
p5 KATANA KATANA_04 1.3s DEMO_307 Understood!
|
||||
MSG_DEMO_290 p0 KATANA KATANA_11 1.8s DEMO_308
|
||||
MSG_DEMO_291 p0 KATANA KATANA_06 1.7s DEMO_309 Watch this, Margras.
|
||||
MSG_DEMO_292 p0 KATANA KATANA_04 1s DEMO_310 What the?
|
||||
MSG_DEMO_400 p0 NATALIE NATALIE_03 2s DEMO_216B We did it!
|
||||
MSG_DEMO_401 p0 CRICHTON CRICHTON_01 3s DEMO_216C White Griffons, return to the ACROPOLIS! We're heading home to Hargenteen!
|
||||
MSG_DEMO_500 p0 KATANA KATANA_07 2s
|
||||
MSG_DEMO_600 p0 NATALIE NATALIE_01 1.9s Rhino 3 has landed. Commencing resupply.
|
||||
MSG_DEMO_600 p0 NATALIE NATALIE_01 1.9s Rhino 3 has landed. Commencing resupply.
|
||||
MSG_DEMO_600 p0 NATALIE NATALIE_01 1.9s Rhino 3 has landed. Commencing resupply.
|
||||
MSG_DEMO_601 p0 NATALIE NATALIE_01 2.2s Rhino Leader has landed. Commencing resupply.
|
||||
MSG_DEMO_601 p0 NATALIE NATALIE_01 2.2s Rhino Leader has landed. Commencing resupply.
|
||||
MSG_DEMO_601 p0 NATALIE NATALIE_01 2.2s Rhino Leader has landed. Commencing resupply.
|
||||
MSG_DEMO_602 p0 NATALIE NATALIE_02 1.7s Resupply complete. You are cleared for take-off!
|
||||
MSG_DEMO_602 p0 NATALIE NATALIE_02 1.7s Resupply complete. You are cleared for take-off!
|
||||
MSG_DEMO_602 p0 NATALIE NATALIE_02 1.7s Resupply complete. You are cleared for take-off!
|
||||
MSG_DEMO_602 p0 NATALIE NATALIE_02 1.7s Resupply complete. You are cleared for take-off!
|
||||
MSG_DEMO_603 p0 TCAFSUPPLY TCAFSUPPLY_01 1.6s All right, beginning resupply.
|
||||
MSG_DEMO_603 p0 TCAFSUPPLY TCAFSUPPLY_01 1.6s All right, beginning resupply.
|
||||
MSG_DEMO_603 p0 TCAFSUPPLY TCAFSUPPLY_01 1.6s All right, beginning resupply.
|
||||
MSG_DEMO_603 p0 TCAFSUPPLY TCAFSUPPLY_01 1.6s All right, beginning resupply.
|
||||
MSG_DEMO_604 p0 TCAFSUPPLY TCAFSUPPLY_03 1.6s Resupply complete. Switching to take-off sequence.
|
||||
MSG_DEMO_604 p0 TCAFSUPPLY TCAFSUPPLY_03 1.6s Resupply complete. Switching to take-off sequence.
|
||||
89
docs/re/structures/cutscene-message-table.md
Normal file
89
docs/re/structures/cutscene-message-table.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# The cutscene message table — speaker, portrait, timing and audio cue
|
||||
|
||||
**✅ Settled 2026-08-26.** The `MSG_DEMO_*` family is not called from any stage
|
||||
script; it is driven by its own IDXD tables in the language packs. Those tables
|
||||
carry, per line of cutscene dialogue: **who says it, which portrait is shown,
|
||||
how long it stays on screen, and which audio cue plays**.
|
||||
|
||||
This answers the question left open by
|
||||
[isl-message-dialogue-link.md](isl-message-dialogue-link.md) — what drives
|
||||
cutscene dialogue, given that built-in 64 never mentions it.
|
||||
|
||||
## Where it lives
|
||||
|
||||
32 IDXD objects per language pack (`dat/GP_MAIN_GAME_<lang>.pak`). Each holds a
|
||||
`Generic` record with a `Count`, plus some number of `Message_NNN` records —
|
||||
**149 in total** across the English pack, covering **138 distinct ids**.
|
||||
|
||||
## Record layout
|
||||
|
||||
A `Message_NNN` record has two named fields, `ID` and `PageCount`, and then
|
||||
**9 positional fields per page**:
|
||||
|
||||
| slot | content | example |
|
||||
|---|---|---|
|
||||
| 0 | speaker | `CharacterNATALIE` |
|
||||
| 1 | portrait | `FaceNATALIE_01` |
|
||||
| 2 | constant `None` at all 149 records | `None` |
|
||||
| 3 | on-screen seconds, 1.00 – 5.00 (mean 2.48) | `1.9` |
|
||||
| 4 | audio cue, or empty | `DEMO_017` |
|
||||
| 5–8 | the four caption keys of that page | `MSG_DEMO_600_000_00` … `_03` |
|
||||
|
||||
The field count is exactly **9 · PageCount + 2**, and that identity holds for
|
||||
every one of the 7 distinct PageCount values present (1→11, 2→20, 3→29, 4→38,
|
||||
5→47, 6→56, 8→74). That is what pins the per-page grouping.
|
||||
|
||||
## Evidence
|
||||
|
||||
* **1 252 of 1 252** caption-key slots equal `<ID>_<page>_<line>` exactly, with
|
||||
**zero** mismatches. The grouping is not a guess about which slot is which.
|
||||
* **78** records span more than one page — which independently equals the 78
|
||||
multi-page `MSG_DEMO` ids counted from the *caption* side, by a different
|
||||
method. Two measurements, same number.
|
||||
* In **68 of those 78** the speaker changes between pages, confirming from the
|
||||
data that successive pages are successive utterances rather than one long
|
||||
speech.
|
||||
* The id sets close exactly: **138 ids in the caption table, 138 in the message
|
||||
table, none on either side without the other.**
|
||||
* 28 distinct speakers, 98 distinct portraits.
|
||||
|
||||
## The audio cue (slot 4)
|
||||
|
||||
296 of 313 pages carry a cue, and there are **296 distinct values** — one per
|
||||
page, never reused. It joins to the `SOUNDS` table described in
|
||||
[sound-cue-table.md](sound-cue-table.md):
|
||||
|
||||
DEMO_017 -> sound id 8017
|
||||
|
||||
The numbering rule is `DEMO_nnn` → `8000 + nnn`, which holds for **286 of 286**
|
||||
plain-numeric cues. The 9 remaining cues carry a letter suffix
|
||||
(`DEMO_067A`, `DEMO_190A`–`C`, `DEMO_216A`–`C`, `DEMO_278A`–`B`) and are
|
||||
assigned 8400–8408 in order. There is no unexplained residue.
|
||||
|
||||
Within a message, **77 of the 78** multi-page records number their cues
|
||||
consecutively; one does not.
|
||||
|
||||
**A guess I had and dropped:** slot 4 looked at first like a movie reference,
|
||||
since the values resemble the `DEMO_nnn` naming of a clip. It is not — there
|
||||
are 97 `.wmv` files on the disc and their names look nothing like this
|
||||
(`ADV.wmv`, `RT01A.wmv`), and the values are unique *per page*, which no movie
|
||||
reference would be.
|
||||
|
||||
## What this does not settle
|
||||
|
||||
* **17 pages have no cue** (slot 4 empty). Silent, or voiced by another route,
|
||||
is unmeasured.
|
||||
* **Slot 2 is `None` at all 149 records**, so what it would hold otherwise is
|
||||
unknown — a constant with no observed variation carries no information.
|
||||
* **5 ids have more than one record** (`MSG_DEMO_600`–`604`), accounting for
|
||||
the 11 extra records over 138 ids. Whether these are context variants or
|
||||
duplicates was not investigated.
|
||||
* **Nothing here was run.** This is a static read of the tables; the playback
|
||||
order, and whether slot 3 is really the on-screen duration rather than an
|
||||
audio length or a delay, has not been checked against the running game.
|
||||
|
||||
## Artifact
|
||||
|
||||
[`../data/cutscene-message-table.txt`](../data/cutscene-message-table.txt) —
|
||||
all 313 pages with speaker, portrait, seconds, cue and text.
|
||||
Regenerate with `tools/re-capture/sound_cues.py demo`.
|
||||
94
docs/re/structures/sound-cue-table.md
Normal file
94
docs/re/structures/sound-cue-table.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# The sound-cue table, and how dialogue binds to a recording
|
||||
|
||||
**✅ Settled 2026-08-26.** `dat/tables.pak` carries the game's cue index. It
|
||||
closes the join from a message id to the `.slb` bank that voices it — the
|
||||
missing link between the script/caption side and the audio side.
|
||||
|
||||
## The table
|
||||
|
||||
One IDXD object in `dat/tables.pak` (373 680 bytes, 5 records, 10 937 fields)
|
||||
holds:
|
||||
|
||||
| record | shape | content |
|
||||
|---|---|---|
|
||||
| `SETTINGS` | 3 fields | `PATH` = `game:\dat\sound.pak+`, `PARAM` = `Pj_Silph.xgs`, and a positional `BANK_SE` |
|
||||
| `BANK_SE` | 1 positional | `Static.slb` |
|
||||
| `FILES` | 5 135 positional | bank paths — `jpn\Voice\VOICE_TCAF_592.slb`, `BGM_001.slb`, … |
|
||||
| `STAGES` | **0 fields** | present but empty |
|
||||
| `SOUNDS` | 5 798 **named** | cue name → numeric sound id |
|
||||
|
||||
`SOUNDS` is the only record on the disc found so far that is entirely named
|
||||
fields, and the names are the join key.
|
||||
|
||||
Cue families and their id ranges — the id space is partitioned by family, with
|
||||
no overlap:
|
||||
|
||||
VOICE n=5044 1500 .. 7331
|
||||
SE n= 322 1 .. 901
|
||||
DEMO n= 295 8000 .. 8408
|
||||
BR n= 101 8500 .. 8600
|
||||
BGM n= 32 1001 .. 1109
|
||||
JNGL n= 3 1201 .. 1203
|
||||
|
||||
5 797 of the 5 798 values are numeric and **all 5 797 are distinct** — the ids
|
||||
are unique, so the id is not how banks get shared. One cue's value is
|
||||
non-numeric.
|
||||
|
||||
The id is **not** an index into `FILES`: ids run to 8 600 and `FILES` has only
|
||||
5 135 entries. `FILES` is reached by *name*, not by id.
|
||||
|
||||
## The join: a message id to a recording
|
||||
|
||||
MSG_VOICE_D_257 (built-in 64's operand, see isl-message-dialogue-link.md)
|
||||
-> cue VOICE_D_257 `MSG_` becomes `VOICE_`
|
||||
-> id 6945 SOUNDS
|
||||
-> bank jpn\etc\VOICE_D_257.slb FILES, matched on stem
|
||||
|
||||
The prefix rule has one wrinkle, and getting it wrong is easy:
|
||||
|
||||
* **`MSG_` is replaced by `VOICE_`** — it is not simply stripped.
|
||||
* A name that already carries `VOICE_` keeps the one it has rather than
|
||||
doubling it: `MSG_VOICE_D_257` → `VOICE_D_257`, but `MSG_TCAF_592` →
|
||||
`VOICE_TCAF_592` (not `TCAF_592`).
|
||||
|
||||
**I got this wrong first.** Stripping `MSG_` resolved 1 250 of 1 338 script
|
||||
message names and left 88 unresolved, and the 88 were exactly the four-letter
|
||||
ship families (`ADAN` 32, `ADPL` 27, `TCAF` 12, `ACRO` 3, `RHIN` 2) — which I
|
||||
was ready to write up as "text-only announcements with no recording". Seeing
|
||||
`jpn\Voice\VOICE_TCAF_592.slb` in `FILES` refuted that: the recordings exist,
|
||||
my rule was wrong. Under the corrected rule the count is **1 326 of 1 338**.
|
||||
|
||||
`SOUNDS` and `FILES` agree exactly — the same 12 names are absent from both,
|
||||
and **every one of the 5 135 bank files has a cue** (zero orphans). 663 cues
|
||||
have no bank file; those are `SE`/`BGM`-family cues living in other banks.
|
||||
|
||||
## The 12 script lines with no recording
|
||||
|
||||
MSG_VOICE_A_273 MSG_VOICE_D_183
|
||||
MSG_VOICE_D_600 … MSG_VOICE_D_608 MSG_VOICE_D_611
|
||||
|
||||
All twelve are in the `VOICE` family, have caption text, are called from the
|
||||
stage scripts, and have neither a cue nor a bank. Ten of them form the near
|
||||
contiguous block `D_600`–`D_611`. Whether they are subtitle-only by design or
|
||||
a late cut is **not settled** — the shape (a contiguous high block) suggests
|
||||
lines added after the recording sessions, but that is a guess, not a
|
||||
measurement.
|
||||
|
||||
## What this does *not* settle
|
||||
|
||||
* **The known wrong-recording case is not explained by this table.**
|
||||
`VOICE_D_452` — the generic "Resupply complete" line documented in
|
||||
[voice-bank-leading-region.md](../voice-bank-leading-region.md) — has its own
|
||||
unique id (7140) and its own bank. Since every id is distinct, bank sharing
|
||||
is **not** happening at the cue level, so that symptom still has to be
|
||||
explained inside the bank/`sound.pak` layer.
|
||||
* **`STAGES` is empty**, and what would have populated it is unknown.
|
||||
* **`SOUNDS`' one non-numeric value** was not chased down.
|
||||
* Only the English pack and the `jpn\` bank paths were examined. Every path in
|
||||
`FILES` begins with `jpn\`, which is consistent with the already-recorded
|
||||
finding that the voice set is Japanese, but the other language packs'
|
||||
tables were not diffed against this one.
|
||||
|
||||
## Tool
|
||||
|
||||
tools/re-capture/sound_cues.py summary | resolve <MSG_id> | demo | unbound
|
||||
203
tools/re-capture/sound_cues.py
Normal file
203
tools/re-capture/sound_cues.py
Normal file
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env python3
|
||||
"""The sound-cue table in `dat/tables.pak`, and what a message id binds to.
|
||||
|
||||
sound_cues.py summary # table shape and cue families
|
||||
sound_cues.py resolve MSG_VOICE_D_257 # message id -> cue -> id + bank file
|
||||
sound_cues.py demo # the cutscene message table
|
||||
sound_cues.py unbound # script message ids with no recording
|
||||
|
||||
One IDXD object in `dat/tables.pak` carries five records: `SETTINGS`,
|
||||
`BANK_SE`, `FILES` (5 135 `.slb` bank paths), `STAGES` (empty) and `SOUNDS`
|
||||
(5 798 named fields, cue name -> numeric sound id). Cue names are the join key:
|
||||
a script message `MSG_<X>` plays the cue `VOICE_<X>`, and the bank file is
|
||||
`jpn\\Voice\\VOICE_<X>.slb`. See docs/re/structures/sound-cue-table.md.
|
||||
"""
|
||||
import collections
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
import zlib
|
||||
|
||||
TABLES = '/work/sylph_extract/dat/tables.pak'
|
||||
|
||||
|
||||
def be32(b, o):
|
||||
return struct.unpack_from('>I', b, o)[0]
|
||||
|
||||
|
||||
def cstr(b, pool, off):
|
||||
base = pool + off
|
||||
return b[base:b.index(b'\0', base)].decode('latin1')
|
||||
|
||||
|
||||
def pak_entries(path):
|
||||
d = open(path, 'rb').read()
|
||||
segs, base, i = b'', path[:-4], 0
|
||||
while os.path.exists('%s.p%02d' % (base, i)):
|
||||
segs += open('%s.p%02d' % (base, i), 'rb').read()
|
||||
i += 1
|
||||
out = {}
|
||||
for k in range(be32(d, 4)):
|
||||
h, off, cs = struct.unpack_from('>III', d, 0x10 + 12 * k)
|
||||
raw = segs[off:off + cs]
|
||||
if raw[:2] == b'Z1':
|
||||
try:
|
||||
raw = zlib.decompress(raw[10:])
|
||||
except Exception:
|
||||
pass
|
||||
out[h] = raw
|
||||
return out
|
||||
|
||||
|
||||
def records(b):
|
||||
"""IDXD -> {record name: [(field name or None, value)]}."""
|
||||
n = be32(b, 4)
|
||||
o = 8 + 16 * n
|
||||
recs = [struct.unpack_from('>IIII', b, 8 + 16 * i) for i in range(n)]
|
||||
m = be32(b, o)
|
||||
o += 4
|
||||
fl = [struct.unpack_from('>III', b, o + 12 * i) for i in range(m)]
|
||||
o += 12 * m
|
||||
pool = o + 4
|
||||
out = {}
|
||||
for (_nh, no, fb, fe) in recs:
|
||||
name = cstr(b, pool, no) if no != 0xFFFFFFFF else None
|
||||
out[name] = [(cstr(b, pool, fno) if fno != 0xFFFFFFFF else None,
|
||||
cstr(b, pool, fvo)) for (_k, fno, fvo) in fl[fb:fe]]
|
||||
return out
|
||||
|
||||
|
||||
def sound_table():
|
||||
obj = [v for v in pak_entries(TABLES).values()
|
||||
if v[:4] == b'IDXD' and b'DEMO_017' in v][0]
|
||||
r = records(obj)
|
||||
sounds = {k: v for k, v in r['SOUNDS']}
|
||||
files = [v for _, v in r['FILES']]
|
||||
return sounds, files, r
|
||||
|
||||
|
||||
def cue_for(message_id):
|
||||
"""`MSG_VOICE_D_257` -> `VOICE_D_257`; `MSG_TCAF_592` -> `VOICE_TCAF_592`.
|
||||
|
||||
The `MSG_` prefix becomes `VOICE_`, except that a name already carrying
|
||||
`VOICE_` keeps the one it has rather than doubling it.
|
||||
"""
|
||||
x = message_id[4:] if message_id.startswith('MSG_') else message_id
|
||||
return x if x.startswith('VOICE_') else 'VOICE_' + x
|
||||
|
||||
|
||||
def wstr(b, pool, off):
|
||||
base = pool + 2 * off
|
||||
e = base
|
||||
while b[e:e + 2] != b'\0\0':
|
||||
e += 2
|
||||
return ''.join(chr(c) for c in
|
||||
struct.unpack('>%dH' % ((e - base) // 2), b[base:e]))
|
||||
|
||||
|
||||
def captions(lang='E'):
|
||||
"""`MSG_*_<page>_<line>` -> text, from the pack's IXUD field tables."""
|
||||
pak = '/work/sylph_extract/dat/GP_MAIN_GAME_%s.pak' % lang
|
||||
out = {}
|
||||
for b in pak_entries(pak).values():
|
||||
if b[:4] != b'IXUD':
|
||||
continue
|
||||
n = be32(b, 4)
|
||||
o = 8 + 16 * n
|
||||
m = be32(b, o)
|
||||
o += 4
|
||||
fl = [struct.unpack_from('>III', b, o + 12 * i) for i in range(m)]
|
||||
o += 12 * m
|
||||
pool = o + 4
|
||||
for (_k, no, vo) in fl:
|
||||
if no == 0xFFFFFFFF:
|
||||
continue
|
||||
try:
|
||||
key, val = wstr(b, pool, no), wstr(b, pool, vo)
|
||||
except Exception:
|
||||
continue
|
||||
if key.startswith('MSG_') and val.strip():
|
||||
out.setdefault(key, val)
|
||||
return out
|
||||
|
||||
|
||||
def demo_messages(lang='E'):
|
||||
"""The cutscene message table: id -> per-page (speaker, face, dur, cue)."""
|
||||
pak = '/work/sylph_extract/dat/GP_MAIN_GAME_%s.pak' % lang
|
||||
out = {}
|
||||
for b in pak_entries(pak).values():
|
||||
if b[:4] != b'IDXD' or b'MSG_DEMO' not in b:
|
||||
continue
|
||||
for name, fs in records(b).items():
|
||||
if not name or not name.startswith('Message_'):
|
||||
continue
|
||||
named = {k: v for k, v in fs if k}
|
||||
pos = [v for k, v in fs if k is None]
|
||||
pc = int(named['PageCount'])
|
||||
out.setdefault(named['ID'], []).append(
|
||||
[tuple(pos[9 * p:9 * p + 9]) for p in range(pc)])
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
what = sys.argv[1] if len(sys.argv) > 1 else 'summary'
|
||||
sounds, files, recs = sound_table()
|
||||
stems = {os.path.basename(f.replace('\\', '/'))[:-4]
|
||||
for f in files if f.lower().endswith('.slb')}
|
||||
|
||||
if what == 'resolve':
|
||||
mid = sys.argv[2]
|
||||
c = cue_for(mid)
|
||||
print('message %s' % mid)
|
||||
print(' cue %s' % c)
|
||||
print(' sound id %s' % sounds.get(c, '<not in SOUNDS>'))
|
||||
hit = [f for f in files
|
||||
if os.path.basename(f.replace('\\', '/'))[:-4] == c]
|
||||
print(' bank file %s' % (hit[0] if hit else '<no bank>'))
|
||||
return
|
||||
|
||||
if what == 'demo':
|
||||
cap = captions()
|
||||
print('# Cutscene message table — dat/GP_MAIN_GAME_E.pak, IDXD objects')
|
||||
print('#')
|
||||
print('# One line per page. A page is one subtitle box; successive pages are')
|
||||
print('# successive utterances, which is why the speaker changes mid-message.')
|
||||
print('# Columns: id, page, speaker, portrait, on-screen seconds, audio cue,')
|
||||
print('# then the caption text.')
|
||||
print()
|
||||
for mid, variants in sorted(demo_messages().items()):
|
||||
for pages in variants:
|
||||
for i, g in enumerate(pages):
|
||||
text = ' '.join(cap.get('%s_%03d_%02d' % (mid, i, l), '')
|
||||
for l in range(4)).strip()
|
||||
print('%-16s p%d %-14s %-18s %5ss %-11s %s'
|
||||
% (mid if i == 0 else '', i,
|
||||
g[0].replace('Character', ''),
|
||||
g[1].replace('Face', ''), g[3], g[4], text))
|
||||
return
|
||||
|
||||
if what == 'unbound':
|
||||
for c in sorted(set(sounds) - stems):
|
||||
print('%-24s id=%s (cue with no bank file)' % (c, sounds[c]))
|
||||
return
|
||||
|
||||
print('records : %s' % ', '.join(str(k) for k in recs))
|
||||
print('SOUNDS cues : %d' % len(sounds))
|
||||
print('FILES bank paths : %d (distinct stems %d)' % (len(files), len(stems)))
|
||||
print('cues with no file : %d' % len(set(sounds) - stems))
|
||||
print('files with no cue : %d' % len(stems - set(sounds)))
|
||||
fam = collections.Counter(re.match(r'[A-Za-z]+', k).group(0) for k in sounds)
|
||||
print('\ncue families and their sound-id ranges:')
|
||||
rng = collections.defaultdict(list)
|
||||
for k, v in sounds.items():
|
||||
if v.lstrip('-').isdigit():
|
||||
rng[re.match(r'[A-Za-z]+', k).group(0)].append(int(v))
|
||||
for p, _ in fam.most_common():
|
||||
v = rng.get(p, [])
|
||||
if v:
|
||||
print(' %-8s n=%-5d %6d .. %6d' % (p, len(v), min(v), max(v)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user