summaryrefslogtreecommitdiffstats
path: root/game/code/sound/dialog/dialogline.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/code/sound/dialog/dialogline.cpp')
-rw-r--r--game/code/sound/dialog/dialogline.cpp1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/game/code/sound/dialog/dialogline.cpp b/game/code/sound/dialog/dialogline.cpp
new file mode 100644
index 0000000..d23c3f2
--- /dev/null
+++ b/game/code/sound/dialog/dialogline.cpp
@@ -0,0 +1,1018 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogline.cpp
+//
+// Description: Atomic unit of dialog. A DialogLine object represents a
+// complete line of dialog spoken by a single character.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radkey.hpp>
+#include <radnamespace.hpp>
+#include <p3d/anim/skeleton.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/dialogline.h>
+
+#include <sound/dialog/dialogselectiongroup.h>
+
+#include <sound/simpsonssoundplayer.h>
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+
+#include <mission/gameplaymanager.h>
+#include <worldsim/character/character.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+EventTableEntry eventTable[] =
+{
+ { "GIC", 0, EVENT_GETINTOVEHICLE_START, 2500 },
+ { "GOC", 0, EVENT_GETOUTOFVEHICLE_START, 2500 },
+ { "convinit", 0, EVENT_CONVERSATION_INIT_DIALOG, 2500 },
+ { "noboxconv", 0, EVENT_IN_GAMEPLAY_CONVERSATION, 2500 },
+ { "tutorial", 0, EVENT_TUTORIAL_DIALOG_PLAY, 2500 },
+ { "Mcrash", 0, EVENT_MINOR_VEHICLE_CRASH, 2500 },
+ { "Bcrash", 0, EVENT_BIG_VEHICLE_CRASH, 2500 },
+ { "Arrive", 0, EVENT_DESTINATION_REACHED, 2500 },
+ { "Air", 0, EVENT_BIG_AIR, 2500 },
+ { "Burn", 0, EVENT_BURNOUT, 2500 },
+ { "ObjectW", 0, EVENT_COLLECT_OBJECT, 2500 },
+ { "Break", 0, EVENT_HIT_BREAKABLE, 2500 },
+ { "Mfail", 0, EVENT_MISSION_FAILURE, 4000 },
+ { "Mvic", 0, EVENT_MISSION_SUCCESS_DIALOG, 4000 },
+ { "Tail", 0, EVENT_TAIL_LOST_DIALOG, 2500 },
+ { "NewAI", 0, EVENT_CHASE_VEHICLE_PROXIMITY, 2500 },
+ { "Time", 0, EVENT_TIME_RUNNING_OUT, 2500 },
+ { "Pass", 0, EVENT_RACE_PASSED_AI, 2500 },
+ { "Passed", 0, EVENT_RACE_GOT_PASSED_BY_AI, 2500 },
+ { "Activate", 0, EVENT_BIG_RED_SWITCH_PRESSED, 250 }, // Make this quite short
+ { "Fall", 0, EVENT_DEATH_VOLUME_SOUND, 2500 },
+ { "Char", 0, EVENT_PEDESTRIAN_SMACKDOWN, 2500 },
+ { "HitByW", 0, EVENT_KICK_NPC_SOUND, 2500 },
+ { "BreakCa", 0, EVENT_BREAK_CAMERA_OR_BOX, 2500 },
+ { "Turbo", 0, EVENT_CHARACTER_TIRED_NOW, 2500 },
+ { "Springboard", 0, static_cast<EventEnum>(EVENT_LOCATOR + LocatorEvent::BOUNCEPAD), 2500 },
+ { "NHitByC", 0, EVENT_PEDESTRIAN_DODGE, 2500 },
+ { "HitByC", 0, EVENT_PLAYER_CAR_HIT_NPC, 2500 },
+ { "HitP", 0, EVENT_PLAYER_MAKES_LIGHT_OF_CAR_HITTING_NPC, 2500 },
+ { "Damage", 0, EVENT_BIG_CRASH, 2500 },
+ { "Door", 0, EVENT_WRONG_SIDE_DUMBASS, 2500 },
+ { "CarWay", 0, EVENT_TRAFFIC_IMPEDED, 2500 },
+ { "Doorbell", 0, EVENT_DING_DONG, 2500 },
+ { "Askride", 0, EVENT_PHONE_BOOTH_RIDE_REQUEST, 0 },
+ { "Ridereply", 0, EVENT_PHONE_BOOTH_NEW_VEHICLE_SELECTED, 0 },
+ { "Answer", 0, EVENT_PHONE_BOOTH_OLD_VEHICLE_RESELECTED, 0 },
+ { "HitCar", 0, EVENT_VILLAIN_CAR_HIT_PLAYER, 2500 },
+ { "Greeting", 0, EVENT_AMBIENT_GREETING, 2500 },
+ { "Idlereply", 0, EVENT_AMBIENT_RESPONSE, 0 },
+ { "Askfood", 0, EVENT_AMBIENT_ASKFOOD, 2500 },
+ { "Foodreply", 0, EVENT_AMBIENT_FOODREPLY, 0 },
+ { "CarBuy", 0, EVENT_HAGGLING_WITH_GIL, 2500 },
+ { "Dcar", 0, EVENT_BIG_BOOM_SOUND, 5000 },
+ { "Card", 0, EVENT_CARD_COLLECTED, 2500 },
+ { "Mstart", 0, EVENT_MISSION_BRIEFING_ACCEPTED, 0 }
+};
+
+static unsigned int eventTableLength = sizeof( eventTable ) / sizeof( EventTableEntry );
+
+CharacterTableEntry characterTable[] =
+{
+ { 0, "Hom", 0, "homer" },
+ { 0, "Mrg", 0, "marge" },
+ { 0, "Brt", 0, "bart" },
+ { 0, "Lis", 0, "lisa" },
+ { 0, "Apu", 0, "apu" },
+ { 0, "Agn", 0, "askinner" },
+ { 0, "Brn", 0, "barney" },
+ { 0, "Bee", 0, "beeman" },
+ { 0, "Crl", 0, "carl" },
+ { 0, "Cbg", 0, "cbg" },
+ { 0, "Clt", 0, "cletus" },
+ { 0, "Dol", 0, "dolph" },
+ { 0, "Nic", 0, "nriviera" },
+ { 0, "Frk", 0, "frink" },
+ { 0, "Fla", 0, "ned" },
+ { 0, "By1", 0, "boy1" },
+ { 0, "By2", 0, "boy2" },
+ { 0, "Fm1", 0, "fem1" },
+ { 0, "Fm2", 0, "fem2" },
+ { 0, "Gil", 0, "gil" },
+ { 0, "Gr1", 0, "girl1" },
+ { 0, "Gr2", 0, "girl2" },
+ { 0, "Kan", 0, "kang" },
+ { 0, "Kod", 0, "kodos" },
+ { 0, "Mn1", 0, "male1" },
+ { 0, "Mn2", 0, "male2" },
+ { 0, "Grp", 0, "grandpa" },
+ { 0, "Mol", 0, "moleman" },
+ { 0, "Jas", 0, "jasper" },
+ { 0, "Jim", 0, "jimbo" },
+ { 0, "Kea", 0, "kearney" },
+ { 0, "Kru", 0, "krusty" },
+ { 0, "Len", 0, "lenny" },
+ { 0, "Loe", 0, "lou" },
+ { 0, "Lou", 0, "louie" },
+ { 0, "Mil", 0, "milhouse" },
+ { 0, "Moe", 0, "moe" },
+ { 0, "Nel", 0, "nelson" },
+ { 0, "Oto", 0, "otto" },
+ { 0, "Pat", 0, "patty" },
+ { 0, "Qim", 0, "quimby" },
+ { 0, "Ral", 0, "ralph" },
+ { 0, "Sea", 0, "captain" },
+ { 0, "Sel", 0, "selma" },
+ { 0, "Skn", 0, "skinner" },
+ { 0, "Smi", 0, "smithers" },
+ { 0, "Snk", 0, "snake" },
+ { 0, "Svt", 0, "teen" },
+ { 0, "Wig", 0, "wiggum" },
+ { 0, "Wil", 0, "willie" },
+ { 0, "Zom", 0, "zombie" },
+ { 0, "Zm1", 0, "zombie1" },
+ { 0, "Zm2", 0, "zombie2" },
+ { 0, "Zm3", 0, "zombie3" },
+ { 0, "Zm4", 0, "zombie4" },
+ { 0, "Hib", 0, "hibbert" },
+ { 0, "Bur", 0, "burns" },
+ { 0, "Rod", 0, "rod" },
+ { 0, "Todd", 0, "todd" },
+ { 0, "Bkm", 0, "brockman" },
+ { 0, "Hbn", 0, "homerbrain" },
+ { 0, "Vm1", 0, "traffic1" },
+ { 0, "Vm2", 0, "traffic2" },
+ { 0, "Vm3", 0, "traffic3" },
+ { 0, "Vm4", 0, "traffic4" }
+};
+
+static unsigned int characterTableLength = sizeof( characterTable ) / sizeof( CharacterTableEntry );
+
+//
+// The food guys
+//
+static unsigned int APU_INDEX = 4;
+static unsigned int TEEN_INDEX = 47;
+
+//
+// Arbitrary number, used in field name buffers
+//
+static const int FIELD_BUFFER_LEN = 64;
+static const int MY_FILENAME_BUFFER_LEN = 150;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// DialogLine::DialogLine
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogLine::DialogLine( IDaSoundResource* resource )
+{
+ m_resource = resource;
+ m_characterIndex = -1;
+ m_role = ROLE_NONE;
+ m_conversationPosition = NOT_CONVERSATION_LINE;
+ m_ConversationName = 0;
+
+ static bool tablesInitialized = false;
+
+ if( !tablesInitialized )
+ {
+ initializeTables();
+ tablesInitialized = true;
+ }
+
+ parseResourceFilename();
+}
+
+//==============================================================================
+// DialogLine::~DialogLine
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogLine::~DialogLine()
+{
+}
+
+//==============================================================================
+// DialogLine::PlayLine
+//==============================================================================
+// Description: Play the dialog line
+//
+// Parameters: lineIndex - ignored, only used for other SelectableDialog subclasses
+// player - what we use for the playing
+// callback - who we call when we're done
+//
+// Return: N/A.
+//
+//==============================================================================
+void DialogLine::PlayLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ player.PlayResource( m_resource, callback );
+}
+
+//=============================================================================
+// DialogLine::QueueLine
+//=============================================================================
+// Description: Buffer a line of dialog for playback
+//
+// Parameters: lineIndex - ignored, only used for other SelectableDialog subclasses
+// player - what we use for the queueing
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::QueueLine( unsigned int lineIndex, SimpsonsSoundPlayer& player )
+{
+ player.QueueSound( m_resource );
+}
+
+//=============================================================================
+// DialogLine::PlayQueuedLine
+//=============================================================================
+// Description: Play the sound we queued with QueueLine
+//
+// Parameters: player - what we use for the playing
+// callback - if non-NULL, object to notify when playback done
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::PlayQueuedLine( SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ player.PlayQueuedSound( callback );
+}
+
+//=============================================================================
+// DialogLine::StripDirectoryCrud
+//=============================================================================
+// Description: Utility function for stripping directory prefix from filenames
+//
+// Parameters: filename - filename to strip
+// buffer - holds stripped filename
+// bufferLen - length of buffer
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::StripDirectoryCrud( const char* filename, char* buffer, int bufferLen )
+{
+ const char* charPtr;
+ int i, j;
+ int strippedLength = 0;
+
+ i = strlen( filename );
+ charPtr = &(filename[i]);
+ while( i > 0 )
+ {
+ if( ( *charPtr == '/' ) || ( *charPtr == '\\' ) )
+ {
+ break;
+ }
+ else
+ {
+ ++strippedLength;
+ --i;
+ --charPtr;
+ }
+ }
+
+ //
+ // Copy stripped filename to buffer
+ //
+ if( i > 0 )
+ {
+ ++charPtr;
+ }
+
+ if( strippedLength > bufferLen )
+ {
+ strippedLength = bufferLen;
+ }
+
+ for( j = 0; j < strippedLength; j++ )
+ {
+ buffer[j] = *charPtr++;
+ }
+}
+
+//=============================================================================
+// DialogLine::GetEventTableEntry
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( unsigned int index )
+//
+// Return: EventTableEntry
+//
+//=============================================================================
+const EventTableEntry* DialogLine::GetEventTableEntry( unsigned int index )
+{
+ if( index >= eventTableLength )
+ {
+ return( NULL );
+ }
+ else
+ {
+ return( &(eventTable[index]) );
+ }
+}
+
+//=============================================================================
+// DialogLine::GetEventTableSize
+//=============================================================================
+// Description: Return the number of entries in the event table
+//
+// Parameters: None
+//
+// Return: table size
+//
+//=============================================================================
+unsigned int DialogLine::GetEventTableSize()
+{
+ return( eventTableLength );
+}
+
+//=============================================================================
+// DialogLine::GetCharacterTableEntry
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( unsigned int index )
+//
+// Return: CharacterTableEntry
+//
+//=============================================================================
+const CharacterTableEntry* DialogLine::GetCharacterTableEntry( unsigned int index )
+{
+ if( index >= characterTableLength )
+ {
+ return( NULL );
+ }
+ else
+ {
+ return( &(characterTable[index]) );
+ }
+}
+
+//=============================================================================
+// DialogLine::GetCharacterTableSize
+//=============================================================================
+// Description: Return the number of entries in the character table
+//
+// Parameters: None
+//
+// Return: table size
+//
+//=============================================================================
+unsigned int DialogLine::GetCharacterTableSize()
+{
+ return( characterTableLength );
+}
+
+//=============================================================================
+// DialogLine::UsesCharacter
+//=============================================================================
+// Description: Indicate whether this dialog line comes from
+// the character given
+//
+// Parameters: characterObj - character to match
+//
+// Return: true if character matches this line, false otherwise
+//
+//=============================================================================
+bool DialogLine::UsesCharacter( tUID characterUID )
+{
+ return( characterUID == GetCharacterUID( ) );
+}
+
+//=============================================================================
+// DialogLine::AddMatchingDialog
+//=============================================================================
+// Description: Request to a SelectableDialog object (this one) to add a new
+// DialogLine or such with the same characteristics. Since this
+// object represents a single line, we need to create a
+// DialogSelectionGroup and add self and the new dialog line to it,
+// and put it in our spot in the list.
+//
+// Parameters: newDialog - dialogLine that matches this one
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::AddMatchingDialog( SelectableDialog& newDialog, SelectableDialogList& list )
+{
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ DialogSelectionGroup* group = new DialogSelectionGroup( *this, newDialog );
+
+ rAssert( group != NULL );
+
+ list.remove( this );
+ list.push_back( group );
+
+ HeapMgr()->PopHeap( GMA_AUDIO_PERSISTENT );
+}
+
+//=============================================================================
+// DialogLine::GetConversationName
+//=============================================================================
+// Description: Returns the name of the conversation this line belongs to,
+// if this is a conversation line. We'll calculate it on the
+// fly, no sense in wasting more space than we already are.
+//
+// Parameters: None
+//
+// Return: radKey32 representation of conversation name field, or 0
+// if this isn't a conversation line
+//
+//=============================================================================
+
+void DialogLine::parseConversationName( )
+{
+ bool fieldFound;
+ char fieldBuffer[FIELD_BUFFER_LEN];
+ char filenameBuffer[MY_FILENAME_BUFFER_LEN];
+ char tempBuffer[MY_FILENAME_BUFFER_LEN];
+
+ //
+ // Strip the directory crud
+ //
+ m_resource->GetFileNameAt( 0, tempBuffer, MY_FILENAME_BUFFER_LEN );
+ StripDirectoryCrud( tempBuffer, filenameBuffer, MY_FILENAME_BUFFER_LEN );
+
+ fieldFound = getNameField( filenameBuffer, 0, fieldBuffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ if( ( fieldBuffer[0] == 'C') && ( fieldBuffer[1] == '\0' ) )
+ {
+ //
+ // Conversation line
+ //
+ fieldFound = getNameField( filenameBuffer, 1, fieldBuffer, FIELD_BUFFER_LEN );
+ m_ConversationName = radMakeKey32( fieldBuffer );
+ }
+ else
+ {
+ //
+ // Not conversation line
+ //
+ rTuneAssert( false );
+ }
+}
+
+//=============================================================================
+// DialogLine::IsFoodCharacter
+//=============================================================================
+// Description: Determine whether this character gets Askfood lines or
+// Idlereply
+//
+// Parameters: theGuy - ambient character being talked to
+//
+// Return: true for Askfood, false for Idlereply
+//
+//=============================================================================
+bool DialogLine::IsFoodCharacter( Character* theGuy )
+{
+ tUID UID1;
+ bool retVal = false;
+
+ choreo::Puppet* puppet = theGuy->GetPuppet();
+ if( puppet != NULL )
+ {
+ UID1 = puppet->GetPose()->GetSkeleton()->GetUID();
+
+ //
+ // Hard-coded hack
+ //
+ rAssert( strcmp( "Apu", characterTable[APU_INDEX].characterString ) == 0 );
+ rAssert( strcmp( "Svt", characterTable[TEEN_INDEX].characterString ) == 0 );
+
+ if( ( UID1 == static_cast< tUID >( characterTable[APU_INDEX].realCharacterUID ) )
+ || ( UID1 == static_cast< tUID >( characterTable[TEEN_INDEX].realCharacterUID ) ) )
+ {
+ retVal = true;
+ }
+ }
+
+ return( retVal );
+}
+
+//=============================================================================
+// DialogLine::GetLifeInMsecsForEvent
+//=============================================================================
+// Description: Given an event, return the number of milliseconds that the
+// dialog for that event should be allowed to live in the queue
+//
+// Parameters: eventID - ID for event
+//
+// Return: lifetime in msecs, 0 for infinite lifetime
+//
+//=============================================================================
+unsigned int DialogLine::GetLifeInMsecsForEvent( EventEnum eventID )
+{
+ unsigned int i;
+ unsigned int lifetime = 2500; // 2.5 sec. default
+
+ for( i = 0; i < eventTableLength; i++ )
+ {
+ if( eventTable[i].event == eventID )
+ {
+ lifetime = eventTable[i].lifeInMsecs;
+ break;
+ }
+ }
+
+ return( lifetime );
+}
+
+//=============================================================================
+// DialogLine::FillCharacterName
+//=============================================================================
+// Description: Fill the given buffer with the text name of the character
+// matching the given UID
+//
+// Parameters: buffer - buffer to write name to
+// bufferSize - length of buffer
+// characterUID - UID of character to find name for
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::FillCharacterName( char* buffer, unsigned int bufferSize, tUID characterUID )
+{
+ unsigned int i;
+ unsigned int tableSize;
+ const CharacterTableEntry* charTableLine;
+
+ tableSize = GetCharacterTableSize();
+
+ for( i = 0; i < tableSize; i++ )
+ {
+ charTableLine = GetCharacterTableEntry( i );
+ if( charTableLine->realCharacterUID == characterUID )
+ {
+ break;
+ }
+ }
+
+ if( i < tableSize )
+ {
+ rAssert( strlen( charTableLine->characterString ) < bufferSize );
+ strcpy( buffer, charTableLine->characterString );
+ }
+ else
+ {
+ rAssert( bufferSize >= 4 );
+ strcpy( buffer, "???" );
+ }
+}
+
+//=============================================================================
+// DialogLine::FillEventName
+//=============================================================================
+// Description: Fill the given buffer with the text name of the event
+// matching the given ID
+//
+// Parameters: buffer - buffer to write name to
+// bufferSize - length of buffer
+// eventID - ID of event to find name for
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::FillEventName( char* buffer, unsigned int bufferSize, EventEnum eventID )
+{
+ unsigned int i;
+ unsigned int tableSize;
+ const EventTableEntry* eventTableLine;
+
+ tableSize = GetEventTableSize();
+
+ for( i = 0; i < tableSize; i++ )
+ {
+ eventTableLine = GetEventTableEntry( i );
+ if( eventTableLine->event == eventID )
+ {
+ break;
+ }
+ }
+
+ if( i < tableSize )
+ {
+ rAssert( strlen( eventTableLine->eventString ) < bufferSize );
+ strcpy( buffer, eventTableLine->eventString );
+ }
+ else
+ {
+ rAssert( bufferSize >= 4 );
+ strcpy( buffer, "???" );
+ }
+}
+
+//=============================================================================
+// DialogLine::PrintResourceName
+//=============================================================================
+// Description: Dump out the name of the sound resource. For debugging.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::PrintResourceName()
+{
+#ifndef RAD_RELEASE
+ char buffer[256];
+
+ rAssert( m_resource != NULL );
+
+ m_resource->GetFileNameAt( 0, buffer, 256 );
+ rDebugPrintf( "DialogLine - %s\n", buffer );
+#endif
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// DialogLine::parseResourceFilename
+//=============================================================================
+// Description: Look at the resource filename and fill out the dialog line
+// attributes based on what we find
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::parseResourceFilename()
+{
+ bool fieldFound;
+ char fieldBuffer[FIELD_BUFFER_LEN];
+ char filenameBuffer[MY_FILENAME_BUFFER_LEN];
+ char tempBuffer[MY_FILENAME_BUFFER_LEN];
+
+ //
+ // Strip the directory crud
+ //
+ m_resource->GetFileNameAt( 0, tempBuffer, MY_FILENAME_BUFFER_LEN );
+ StripDirectoryCrud( tempBuffer, filenameBuffer, MY_FILENAME_BUFFER_LEN );
+
+ fieldFound = getNameField( filenameBuffer, 0, fieldBuffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ if( ( fieldBuffer[0] == 'C') && ( fieldBuffer[1] == '\0' ) )
+ {
+ //
+ // Conversation line
+ //
+ parseConversationName( );
+ matchOrderField( filenameBuffer, 2 );
+ matchEventField( filenameBuffer, 3 );
+ matchCharacterField( filenameBuffer, 4 );
+ matchLevelField( filenameBuffer, 5 );
+ }
+ else
+ {
+ //
+ // One-liner
+ //
+ matchRoleField( filenameBuffer, 0 );
+ matchEventField( filenameBuffer, 1 );
+ matchCharacterField( filenameBuffer, 2 );
+ matchLevelField( filenameBuffer, 3 );
+ }
+}
+
+void DialogLine::matchRoleField( const char* filename, int field )
+{
+ char buffer[FIELD_BUFFER_LEN];
+ bool fieldFound;
+
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ switch( buffer[0] )
+ {
+ case 'W':
+ m_role = ROLE_WALKER;
+ break;
+ case 'D':
+ m_role = ROLE_DRIVER;
+ break;
+ case 'P':
+ m_role = ROLE_PEDESTRIAN;
+ break;
+ case 'V':
+ m_role = ROLE_VILLAIN;
+ break;
+ default:
+ rAssertMsg( false, "Unknown role field in dialog file\n" );
+ break;
+ }
+}
+
+//=============================================================================
+// DialogLine::matchEventField
+//=============================================================================
+// Description: Parse the field at the given position and store the eventEnum
+// that matches it
+//
+// Parameters: field - number of field to parse
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::matchEventField( const char* filename, int field )
+{
+ unsigned int i;
+ char buffer[FIELD_BUFFER_LEN];
+ radKey32 fieldKey;
+ bool fieldFound;
+
+ //
+ // Event name. Use a lookup table to translate to the event
+ // enumeration.
+ //
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ fieldKey = ::radMakeCaseInsensitiveKey32( buffer );
+ for( i = 0; i < eventTableLength; i++ )
+ {
+ if( fieldKey == eventTable[i].eventKey )
+ {
+ m_event = eventTable[i].event;
+ break;
+ }
+ }
+}
+
+//=============================================================================
+// DialogLine::matchOrderField
+//=============================================================================
+// Description: Parse the field at the given position and store it as the value
+// for the conversation position
+//
+// Parameters: field - number of field to parse
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::matchOrderField( const char* filename, int field )
+{
+ char buffer[FIELD_BUFFER_LEN];
+ bool fieldFound;
+
+ //
+ // Event name. Use a lookup table to translate to the event
+ // enumeration.
+ //
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ rAssert( buffer[0] >= '0' );
+ rAssert( buffer[0] <= '9' );
+
+ m_conversationPosition = buffer[0] - '0';
+}
+
+//=============================================================================
+// DialogLine::matchCharacterField
+//=============================================================================
+// Description: Parse the field at the given position and store the characterEnum
+// that matches it
+//
+// Parameters: field - number of field to parse
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::matchCharacterField( const char* filename, int field )
+{
+ unsigned int i;
+ char buffer[FIELD_BUFFER_LEN];
+ radKey32 fieldKey;
+ bool fieldFound;
+
+ //
+ // Character. Use another lookup table.
+ //
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ fieldKey = ::radMakeCaseInsensitiveKey32( buffer );
+ for( i = 0; i < characterTableLength; i++ )
+ {
+ if( fieldKey == characterTable[i].characterKey )
+ {
+ m_characterIndex = i;
+ break;
+ }
+ }
+
+ rAssert( ( i < characterTableLength )
+ || ( filename[0] != 'C' ) );
+}
+
+//=============================================================================
+// DialogLine::matchLevelField
+//=============================================================================
+// Description: Parse the field at the given position and store the level
+// and mission numbers that match it
+//
+// Parameters: field - number of field to parse
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::matchLevelField( const char* filename, int field )
+{
+ char buffer[FIELD_BUFFER_LEN];
+ bool fieldFound;
+
+ //
+ // Level/Mission.
+ //
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+
+ if( fieldFound )
+ {
+ if( ( buffer[0] == 'L' )
+ && ( buffer[1] >= '0' )
+ && ( buffer[1] <= '9' ) )
+ {
+ //
+ // Level number, start to string is "Lx"
+ //
+ m_levelNum = buffer[1] - '0';
+ rAssert( m_levelNum > 0 );
+ rAssert( m_levelNum < GameplayManager::MAX_LEVELS );
+
+ if( strlen( buffer ) >= 4 )
+ {
+ //
+ // Level and mission, expected string is "LxMy"
+ //
+ rAssert( ( buffer[2] == 'M' ) || ( buffer[2] == 'B' ) || ( buffer[2] == 'R' ) || ( buffer[2] == 'T' ) );
+ m_missionNum = buffer[3] - '0';
+ rAssert( m_missionNum >= 1 );
+ rAssert( m_missionNum <= 7 );
+
+ //
+ // Bonus == 8
+ // Races == 9-11
+ // Tutorial == 12
+ //
+ if( buffer[2] == 'B' )
+ {
+ rAssert( m_missionNum == 1 );
+ m_missionNum = BONUS_MISSION_NUMBER;
+ }
+ else if( buffer[2] == 'R' )
+ {
+ rAssert( m_missionNum >= 1 );
+ rAssert( m_missionNum <= 3 );
+ m_missionNum += FIRST_RACE_MISSION_NUMBER - 1;
+ }
+ else if( buffer[2] == 'T' )
+ {
+ rAssert( m_missionNum == 1 );
+ m_missionNum = TUTORIAL_MISSION_NUMBER;
+ }
+ }
+ else
+ {
+ m_missionNum = NO_MISSION;
+ }
+ }
+ }
+}
+
+//=============================================================================
+// DialogLine::getNameField
+//=============================================================================
+// Description: Parse the filename for a particular field, and return it in
+// the given buffer
+//
+// Parameters: filename -- name of file to parse
+// field -- number of field to find (counting from 0)
+// buffer -- buffer to copy field into
+// bufferLen -- length of buffer
+//
+// Return: true if requested field exists, false otherwise
+//
+//=============================================================================
+bool DialogLine::getNameField( const char* filename, int field, char* buffer, int bufferLen )
+{
+ const char* currentChar;
+ int i;
+ int fieldCount = field;
+ bool fieldFound = false;
+
+ currentChar = filename;
+ while( ( fieldCount > 0 ) && ( *currentChar != '\0' ) && ( *currentChar != '.' ) )
+ {
+ if( *currentChar == '_' )
+ {
+ --fieldCount;
+ }
+
+ ++currentChar;
+ }
+
+ if( ( *currentChar != '\0' ) && ( *currentChar != '.' ) )
+ {
+ //
+ // Field found, copy to buffer. Since GC has no string functions (argh),
+ // use hand-rolled strncpy
+ //
+ for( i = 0;
+ ( (i < bufferLen-1) && (currentChar[i] != '\0') && (currentChar[i] != '_') && (currentChar[i] != '.') );
+ i++ )
+ {
+ buffer[i] = currentChar[i];
+ }
+ buffer[i] = '\0';
+
+ fieldFound = true;
+ }
+
+ return( fieldFound );
+}
+
+//=============================================================================
+// DialogLine::initializeTables
+//=============================================================================
+// Description: Fill out the radKey32 entries in the event table.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::initializeTables()
+{
+ unsigned int i;
+
+ for( i = 0; i < eventTableLength; i++ )
+ {
+ eventTable[i].eventKey = ::radMakeCaseInsensitiveKey32( eventTable[i].eventString );
+ }
+
+ for( i = 0; i < characterTableLength; i++ )
+ {
+ characterTable[i].characterKey = ::radMakeCaseInsensitiveKey32( characterTable[i].characterString );
+ characterTable[i].realCharacterUID = tEntity::MakeUID( characterTable[i].realCharacterName );
+ }
+}
+
+tUID DialogLine::GetCharacterUID( void )
+{
+ if ( -1 == m_characterIndex )
+ {
+ return 0;
+ }
+
+ tUID uid = characterTable[ m_characterIndex ].realCharacterUID;
+ return uid;
+}
+
+tUID DialogLine::GetDialogLineCharacterUID( unsigned int lineNum )
+{
+ return GetCharacterUID( );
+}
+ \ No newline at end of file