diff options
Diffstat (limited to 'game/code/sound/dialog/dialogline.cpp')
-rw-r--r-- | game/code/sound/dialog/dialogline.cpp | 1018 |
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 |