// ----------------------------------------------------------------------- // // // ROUTINE: CLTDialogueWnd::ShowDecisions // // PURPOSE: Shows the decisions // // ----------------------------------------------------------------------- // BOOL CLTDialogueWnd::ShowDecisions() { // If we have decisions to make, do them now m_bDecisions = FALSE; if(!m_csDecisions.IsEmpty()) { ILTCommon* pCommon = g_pLTClient->Common(); if (!pCommon) { return FALSE; } ConParse parse; parse.Init((char *)(LPCSTR)m_csDecisions); m_collDialogueIDs.RemoveAll(); CStringArray collDecisions; DWORD dwID; while (pCommon->Parse(&parse) == LT_OK) { if (parse.m_nArgs > 0 && parse.m_Args[0]) { dwID = atoi(parse.m_Args[0]); DWORD dwTranslatedID = dwID; HSTRING hString=g_pLTClient->FormatString(dwTranslatedID); if(!hString) { return FALSE; } m_collDialogueIDs.Add(dwID); collDecisions.Add(g_pLTClient->GetStringData(hString)); g_pLTClient->FreeString(hString); } } if(collDecisions.GetSize() <= 0) { return FALSE; } if(m_DecisionWnd.DisplayText(&collDecisions,this,TRUE)) { // If we immediatelly displayed the decisions, let the server // finish talking... if (!m_bImmediateDecisions) { // Tell the server to stop speaking HMESSAGEWRITE hMessage; hMessage = g_pLTClient->StartMessage(CSM_DIALOGUE_STOP); g_pLTClient->EndMessage(hMessage); } m_bEnabled = FALSE; m_bDecisions = TRUE; return TRUE; } } return FALSE; }
void CinematicTrigger::SendReplyMessage(int nReply) { if (m_nCurMessage >= MAX_CT_MESSAGES) return; ILTCommon* pCommon = g_pLTServer->Common(); if (!pCommon) return; CString csTarget; CString csMsg; ConParse parse; char* pMsg = g_pLTServer->GetStringData(m_hstrRepliesTarget[m_nCurMessage]); if(!pMsg) return; parse.Init(pMsg); int i; for(i=0;i<nReply;i++) { if(pCommon->Parse(&parse) == LT_OK) { if(i == (nReply - 1)) { if (parse.m_nArgs > 0 && parse.m_Args[0]) { csTarget = parse.m_Args[0]; } break; } } } pMsg = g_pLTServer->GetStringData(m_hstrRepliesMsg[m_nCurMessage]); if(!pMsg) return; parse.Init(pMsg); for(i=0;i<nReply;i++) { if(pCommon->Parse(&parse) == LT_OK) { if(i == (nReply - 1)) { if (parse.m_nArgs > 0 && parse.m_Args[0]) { csMsg = parse.m_Args[0]; } break; } } } if (!csTarget.IsEmpty() && !csMsg.IsEmpty()) { SendTriggerMsgToObjects(this, (char *)(LPCSTR)csTarget, (char *)(LPCSTR)csMsg); } }
void DisplayMeter::TriggerMsg(HOBJECT hSender, const char *szMsg) { ILTCommon* pCommon = g_pLTServer->Common(); if (!pCommon) return; // ConParse does not destroy szMsg, so this is safe ConParse parse; parse.Init((char*)szMsg); while (pCommon->Parse(&parse) == LT_OK) { if (parse.m_nArgs > 0 && parse.m_Args[0]) { if ((_stricmp(parse.m_Args[0], "show") == 0)) { if (parse.m_nArgs > 1) { HandleShow((uint8)atoi(parse.m_Args[1])); } else HandleShow(100); } else if (_stricmp(parse.m_Args[0], "plus") == 0) { if (parse.m_nArgs > 1) { HandlePlus((uint8)atoi(parse.m_Args[1])); } } else if (_stricmp(parse.m_Args[0], "minus") == 0) { if (parse.m_nArgs > 1) { HandleMinus((uint8)atoi(parse.m_Args[1])); } } else if (_stricmp(parse.m_Args[0], "set") == 0) { if (parse.m_nArgs > 1) { HandleSet((uint8)atoi(parse.m_Args[1])); } } else if (_stricmp(parse.m_Args[0], "hide") == 0) { HandleEnd(); } } } }
bool CLightningFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps) { LTVector vSave = pBaseData->m_vPos; // Perform base class initialisation if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) return false; ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); ocs.m_ObjectType = OT_NORMAL; ocs.m_Flags = pBaseData->m_dwObjectFlags | FLAG_NOLIGHT; ocs.m_Flags2 |= pBaseData->m_dwObjectFlags2; ocs.m_Pos = m_vCreatePos; m_hObject = m_pLTClient->CreateObject(&ocs); if( !m_hObject ) return false; // Are we rendering really close? m_bReallyClose = !!(pBaseData->m_dwObjectFlags & FLAG_REALLYCLOSE); // Create the max number of bolts CLightningBolt *pBolt = LTNULL; PT_TRAIL_SECTION ts; for( uint32 nBolts = 0; nBolts < GetProps()->m_nMaxNumBolts; ++nBolts ) { pBolt = debug_new( CLightningBolt ); pBolt->m_nNumSegments = GetRandom( (int)GetProps()->m_nMinSegmentsPerBolt, (int)GetProps()->m_nMaxSegmentsPerBolt ); // Add all the trail sections now since we don't need to constantly create and delete them... for( uint32 nSegs = 0; nSegs < pBolt->m_nNumSegments; ++nSegs ) { ts.m_vPos = m_vCreatePos; pBolt->m_collPathPts.AddTail( ts ); } m_lstBolts.push_back( pBolt ); } // Setup the target data so we now where the lightning is going... if( pBaseData->m_bUseTargetData ) { if( pBaseData->m_hTarget ) { m_hTarget = pBaseData->m_hTarget; } else if( m_hParent ) { m_hTarget = m_hParent; } else { m_hTarget = LTNULL; } m_vTargetPos = pBaseData->m_vTargetPos; } else { // Use our parent as the target if we have one otherwise just use ourselves... m_hTarget = (m_hParent ? m_hParent : m_hObject); m_vTargetPos = m_vCreatePos; } // Load the texture if one was specified... if( !m_hTexture && GetProps()->m_szTexture[0] ) { m_pLTClient->GetTexInterface()->CreateTextureFromName( m_hTexture, GetProps()->m_szTexture ); } // Create a list of attractor nodes if( m_hTarget ) { ILTModel *pModelLT = m_pLTClient->GetModelLT(); ILTCommon *pCommonLT = m_pLTClient->Common(); HMODELNODE hNode = -1; HMODELSOCKET hSocket = -1; HATTRACTOR hAttractor = INVALID_ATTRACTOR; CAttractor cAttractor; // Add any nodes to our attractor list... if( GetProps()->m_szNodeAttractors[0] ) { ConParse parse( GetProps()->m_szNodeAttractors ); while( pCommonLT->Parse( &parse ) == LT_OK ) { if( parse.m_nArgs > 0 && parse.m_Args[0] ) { if( pModelLT->GetNode( m_hTarget, parse.m_Args[0], hAttractor ) == LT_OK ) { cAttractor.m_hModel = m_hTarget; cAttractor.m_hAttractor = hAttractor; cAttractor.m_eType = CAttractor::eNode; m_lstAttractors.push_back( cAttractor ); } } } } // Add any sockets to our attractor list... if( GetProps()->m_szSocketAttractors[0] ) { ConParse parse( GetProps()->m_szSocketAttractors ); while( pCommonLT->Parse( &parse ) == LT_OK ) { if( parse.m_nArgs > 0 && parse.m_Args[0] ) { if( pModelLT->GetSocket( m_hTarget, parse.m_Args[0], hAttractor ) == LT_OK ) { cAttractor.m_hModel = m_hTarget; cAttractor.m_hAttractor = hAttractor; cAttractor.m_eType = CAttractor::eSocket; m_lstAttractors.push_back( cAttractor ); } } } } } m_tmElapsedEmission = 0.0f; m_fDelay = 0.0f; return true; }
void CinematicTrigger::TriggerMsg(HOBJECT hSender, const char *pMsg) { if (!pMsg) return; ILTCommon* pCommon = g_pLTServer->Common(); if (!pCommon) return; // ConParse does not destroy szMsg, so this is safe ConParse parse; parse.Init((char*)pMsg); while (pCommon->Parse(&parse) == LT_OK) { if (parse.m_nArgs > 0 && parse.m_Args[0]) { if (_stricmp(parse.m_Args[0], "ON") == 0) { HandleOn(); } else if (_stricmp(parse.m_Args[0], "OFF") == 0) { HandleOff(); } else if (_stricmp(parse.m_Args[0], "SKIP") == 0) { if (m_bCanSkip) { HandleOff(); } } else if (_stricmp(parse.m_Args[0], "CAMERA") == 0) { if (m_hCamera && parse.m_nArgs > 1 && parse.m_Args[1]) { // Copy all arguments to g_tokenspace... sprintf(g_tokenSpace, "%s", parse.m_Args[1]); for (int i=2; i < parse.m_nArgs && parse.m_Args[i]; i++) { strcat(g_tokenSpace, " "); strcat(g_tokenSpace, parse.m_Args[i]); } // Send camera the message... SendTriggerMsgToObject(this, m_hCamera, FALSE, g_tokenSpace); } } else if (_stricmp(parse.m_Args[0], "KEYFRAMER") == 0) { if (m_hKeyFramer && parse.m_nArgs > 1 && parse.m_Args[1]) { // Copy all arguments to g_tokenspace... sprintf(g_tokenSpace, "%s", parse.m_Args[1]); for (int i=2; i < parse.m_nArgs && parse.m_Args[i]; i++) { strcat(g_tokenSpace, " "); strcat(g_tokenSpace, parse.m_Args[i]); } // Send keyframer the message... SendTriggerMsgToObject(this, m_hKeyFramer, FALSE, g_tokenSpace); } } } } }
LTBOOL CinematicTrigger::StartDialogue(int nDecision) { if(m_nCurMessage >= MAX_CT_MESSAGES) return LTFALSE; CString csDialogue; CString csTarget; CString csChar; uint8 byMood = 0; if(nDecision) { char* pMsg = g_pLTServer->GetStringData(m_hstrReplies[m_nCurMessage]); if(!pMsg) return FALSE; ILTCommon* pCommon = g_pLTServer->Common(); if (!pCommon) return FALSE; ConParse parse; parse.Init(pMsg); for(int i=0;i<nDecision;i++) { if(pCommon->Parse(&parse) == LT_OK) { if (parse.m_nArgs < 2) { if (parse.m_nArgs < 1 || stricmp(parse.m_Args[0], "NONE") != 0) { g_pLTServer->CPrint("Cinematic Trigger - ERROR - Not enough replies for the amount of decisions!"); TRACE("Cinematic Trigger - ERROR - Not enough replies for the amount of decisions!\n"); return FALSE; } } else if(i == (nDecision - 1)) { csTarget = parse.m_Args[0]; if(csTarget.Compare("Cinematic") == 0) { //HandleOff(); - Should be done by reply message? // Force the dialogue to be done... m_nCurMessage = MAX_CT_MESSAGES; // We have another cinematic to play, turn it on... SendTriggerMsgToObjects(this, parse.m_Args[1], "ON"); return FALSE; } else { // Look at the second argument to determine if we have a // character override if((parse.m_Args[1][0] < '0') && (parse.m_Args[1][0] > '9')) { // We have a character override csChar = parse.m_Args[1]; csDialogue = parse.m_Args[2]; // Check for a mood if(parse.m_nArgs == 4) { // char charoverride id mood byMood = atoi(parse.m_Args[3]); } } else { // We don't have a character override csDialogue = parse.m_Args[1]; // check for a mood if(parse.m_nArgs == 3) { // char id mood byMood = atoi(parse.m_Args[2]); } } } } } } } else { // Send the message here SendMessage(); // Check for an initial message if (m_nCurMessage == 0) { if (m_hstrDialogueStartTarget && m_hstrDialogueStartMsg) { SendTriggerMsgToObjects(this, g_pLTServer->GetStringData(m_hstrDialogueStartTarget), g_pLTServer->GetStringData(m_hstrDialogueStartMsg)); } } csDialogue = g_pLTServer->GetStringData(m_hstrDialogue[m_nCurMessage]); csTarget = g_pLTServer->GetStringData(m_hstrWhoPlaysDialogue[m_nCurMessage]); } if (csDialogue.IsEmpty()) { // Make sure the reply messages are sent, even if we aren't going to // do any dialogue... if (nDecision) { SendReplyMessage(nDecision); } return LTFALSE; } const char *szCharOverride = NULL; if(csChar.IsEmpty()) { int nSpace = csTarget.Find(' '); if(nSpace != -1) { // There is a space in the name, therefore we have a character override csChar = csTarget.Right(csTarget.GetLength()-nSpace-1); csTarget = csTarget.Left(nSpace); if(!csChar.IsEmpty()) szCharOverride = csChar; } } else { szCharOverride = csChar; } HOBJECT hObj = !csTarget.IsEmpty() ? PlayedBy((char *)(LPCSTR)csTarget) : LTNULL; if (hObj) { CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hObj); if (pChar) { char *szDecisions = NULL; if (!nDecision && m_hstrDecisions[m_nCurMessage]) { szDecisions = g_pLTServer->GetStringData(m_hstrDecisions[m_nCurMessage]); } // See if there's a windowed message next int nNext = m_nCurMessage + 1; //BOOL bStayOpen = (szDecisions || ((nNext < MAX_CT_MESSAGES) && m_hstrDialogue[nNext] && m_bWindow[nNext] && (m_fDelay[nNext] == 0.0f))); //BOOL bWindow = m_bWindow[m_nCurMessage]; BOOL bStayOpen = LTFALSE; BOOL bWindow = (BOOL)szDecisions; pChar->PlayDialogue((char *)(LPCSTR)csDialogue,this,bWindow,bStayOpen,szCharOverride,szDecisions,byMood); SetupLinks(hObj); return LTTRUE; } } return LTFALSE; }
void CMusic::ProcessMusicMessage(char* pMessage) { // Make sure mgrs are initialized if (!pMessage || !pMessage[0]) return; if (!IsInitialized()) return; if (!IsLevelInitialized()) return; if (m_pMusicMgr == NULL) return; ILTCommon* pCommon = g_pLTClient->Common(); ConParse parse; parse.Init(pMessage); while (pCommon->Parse(&parse) == LT_OK) { if (parse.m_nArgs > 1) { if (parse.m_Args[1] != NULL) { // change intensity command if ((_stricmp(parse.m_Args[1], "intensity") == 0) || (_stricmp(parse.m_Args[1], "i") == 0)) { if (parse.m_nArgs > 2) { if (parse.m_Args[2] != NULL) { // convert intensity value to an int int nIntensity = atoi(parse.m_Args[2]); // figure out the enact time (optional parameter) LTDMEnactTypes nEnact = LTDMEnactDefault; if (parse.m_nArgs > 3) nEnact = StringToEnactType(parse.m_Args[3]); // change the music intensity ChangeIntensity(nIntensity, nEnact); } } } // play secondary segment command if ((_stricmp(parse.m_Args[1], "secondary") == 0) || (_stricmp(parse.m_Args[1], "ps") == 0)) { if (parse.m_nArgs > 2) { if (parse.m_Args[2] != NULL) { strcpy(m_State.szSecondary, parse.m_Args[2]); // figure out the enact time (optional parameter) m_State.nSecondaryEnact = LTDMEnactDefault; if (parse.m_nArgs > 3) m_State.nSecondaryEnact = StringToEnactType(parse.m_Args[3]); // play a secondary segment m_pMusicMgr->PlaySecondary(m_State.szSecondary, m_State.nSecondaryEnact); } } } // play motif command if ((_stricmp(parse.m_Args[1], "motif") == 0) || (_stricmp(parse.m_Args[1], "pm") == 0)) { if (parse.m_nArgs > 3) { if ((parse.m_Args[2] != NULL) && (parse.m_Args[3] != NULL)) { strcpy(m_State.szMotifStyle, parse.m_Args[2]); strcpy(m_State.szMotifName, parse.m_Args[3]); // figure out the enact time (optional parameter) m_State.nMotifEnact = LTDMEnactDefault; if (parse.m_nArgs > 4) { m_State.nMotifEnact = StringToEnactType(parse.m_Args[4]); } // play a motif if ((stricmp(m_State.szMotifStyle,"*") == 0)) { m_pMusicMgr->PlayMotif(NULL, m_State.szMotifName, m_State.nMotifEnact); } else { m_pMusicMgr->PlayMotif(m_State.szMotifStyle, m_State.szMotifName, m_State.nMotifEnact); } } } } // set volume command if ((_stricmp(parse.m_Args[1], "volume") == 0) || (_stricmp(parse.m_Args[1], "v") == 0)) { if (parse.m_nArgs > 2) { if (parse.m_Args[2] != NULL) { // set the new volume SetTriggerVolume(atol(parse.m_Args[2])); } } } // stop secondary segment command if ((_stricmp(parse.m_Args[1], "stopsecondary") == 0) || (_stricmp(parse.m_Args[1], "ss") == 0)) { if (parse.m_nArgs > 2) { if (parse.m_Args[2] != NULL) { // No secondary... m_State.szSecondary[0] = '\0'; // figure out the enact time (optional parameter) LTDMEnactTypes nEnact = LTDMEnactDefault; if (parse.m_nArgs > 3) nEnact = StringToEnactType(parse.m_Args[3]); // stop a secondary segment if name is * stop all if ((stricmp(parse.m_Args[2],"*") == 0)) m_pMusicMgr->StopSecondary(NULL, nEnact); else m_pMusicMgr->StopSecondary(parse.m_Args[2], nEnact); } } } // stop motif command if ((_stricmp(parse.m_Args[1], "stopmotif") == 0) || (_stricmp(parse.m_Args[1], "sm") == 0)) { if (parse.m_nArgs > 3) { if ((parse.m_Args[2] != NULL) && (parse.m_Args[3] != NULL)) { // No motifs... m_State.szMotifStyle[0] = '\0'; m_State.szMotifName[0] = '\0'; // figure out the enact time (optional parameter) LTDMEnactTypes nEnact = LTDMEnactDefault; if (parse.m_nArgs > 4) nEnact = StringToEnactType(parse.m_Args[4]); // if name or style are * pass in NULL for all/any if ((stricmp(parse.m_Args[2],"*") == 0)) { if ((stricmp(parse.m_Args[3],"*") == 0)) m_pMusicMgr->StopMotif(NULL, NULL, nEnact); else m_pMusicMgr->StopMotif(NULL, parse.m_Args[3], nEnact); } else { if ((stricmp(parse.m_Args[3],"*") == 0)) m_pMusicMgr->StopMotif(parse.m_Args[2], NULL, nEnact); else m_pMusicMgr->StopMotif(parse.m_Args[2], parse.m_Args[3], nEnact); } } } } // play command if ((_stricmp(parse.m_Args[1], "play") == 0) || (_stricmp(parse.m_Args[1], "p") == 0)) { // begin playing music Play(); } // stop command if ((_stricmp(parse.m_Args[1], "stop") == 0) || (_stricmp(parse.m_Args[1], "s") == 0)) { // enact time to stop at LTDMEnactTypes nEnact = LTDMEnactDefault; // see if there is another parameter for the enact time if (parse.m_nArgs > 2) { if (parse.m_Args[2] != NULL) { // figure out the enact time (optional parameter) if (parse.m_nArgs > 3) nEnact = StringToEnactType(parse.m_Args[3]); } } // stop music from playing Stop(nEnact); } } } } }
uint32 Lock::ObjectMessageFn(HOBJECT hSender, uint32 messageID, HMESSAGEREAD hRead) { if (!g_pLTServer) return 0; switch(messageID) { case MID_TRIGGER: { ILTCommon* pCommon = g_pLTServer->Common(); if (!pCommon) return 0; const char *szMsg = (const char*)g_pLTServer->ReadFromMessageDWord(hRead); // ConParse does not destroy szMsg, so this is safe ConParse parse; parse.Init((char*)szMsg); while (pCommon->Parse(&parse) == LT_OK) { if (parse.m_nArgs > 0 && parse.m_Args[0]) { if (_stricmp(parse.m_Args[0], s_szGadget) == 0) { HandleGadgetMsg(hSender, parse); } } } } break; case MID_DAMAGE: { if (m_bUnlocked) break; uint32 dwRet = 0; DamageStruct damage; damage.InitFromMessage(hRead); LTBOOL bProcessDamage = m_bShootable; if (!bProcessDamage) { if (m_bWeldable) { bProcessDamage = (damage.eType == DT_GADGET_WELDER); } else if (m_bLightable) { bProcessDamage = (damage.eType == DT_GADGET_LIGHTER); } else { bProcessDamage = (damage.eType == DT_GADGET_LOCK_PICK); } } if (bProcessDamage) { dwRet = Prop::ObjectMessageFn(hSender, messageID, hRead); if (m_damage.IsDead()) { SetupUnlockState(); } } return dwRet; } break; default : break; } return Prop::ObjectMessageFn(hSender, messageID, hRead); }
void GameBase::TriggerMsg(HOBJECT hSender, const char* szMsg) { if (!szMsg) return; ILTCommon* pCommon = g_pLTServer->Common(); if (!pCommon) return; // ConParse does not destroy szMsg, so this is safe ConParse parse; parse.Init((char*)szMsg); while (pCommon->Parse(&parse) == LT_OK) { if (parse.m_nArgs > 0 && parse.m_Args[0]) { uint32 dwFlags = g_pLTServer->GetObjectFlags(m_hObject); if (!m_dwOriginalFlags) { m_dwOriginalFlags = dwFlags; } if (_stricmp(parse.m_Args[0], "VISIBLE") == 0) { if (parse.m_nArgs > 1 && parse.m_Args[1]) { if ((_stricmp(parse.m_Args[1], "1") == 0) || (_stricmp(parse.m_Args[1], "TRUE") == 0)) { dwFlags |= FLAG_VISIBLE; } else { if ((_stricmp(parse.m_Args[1], "0") == 0) || (_stricmp(parse.m_Args[1], "FALSE") == 0)) { dwFlags &= ~FLAG_VISIBLE; } } } } else if (_stricmp(parse.m_Args[0], "SOLID") == 0) { if (parse.m_nArgs > 1 && parse.m_Args[1]) { if ((_stricmp(parse.m_Args[1], "1") == 0) || (_stricmp(parse.m_Args[1], "TRUE") == 0)) { dwFlags |= FLAG_SOLID; if (m_dwOriginalFlags & FLAG_RAYHIT) { dwFlags |= FLAG_RAYHIT; } } else { if ((_stricmp(parse.m_Args[1], "0") == 0) || (_stricmp(parse.m_Args[1], "FALSE") == 0)) { dwFlags &= ~FLAG_SOLID; dwFlags &= ~FLAG_RAYHIT; } } } } g_pLTServer->SetObjectFlags(m_hObject, dwFlags); } } }
uint32 SecurityCamera::ObjectMessageFn(HOBJECT hSender, uint32 messageID, HMESSAGEREAD hRead) { if (!g_pLTServer) return 0; switch(messageID) { case MID_TRIGGER: { ILTCommon* pCommon = g_pLTServer->Common(); if (!pCommon) return 0; const char *szMsg = (const char*)g_pLTServer->ReadFromMessageDWord(hRead); // ConParse does not destroy szMsg, so this is safe ConParse parse; parse.Init((char*)szMsg); while (pCommon->Parse(&parse) == LT_OK) { if (parse.m_nArgs > 0 && parse.m_Args[0]) { if (_stricmp(parse.m_Args[0], s_szOff) == 0) { SetState(eStateOff); } else if (_stricmp(parse.m_Args[0], s_szReset) == 0) { SetState(eStateReset); } else if (_stricmp(parse.m_Args[0], s_szGadget) == 0) { HandleGadgetMsg(parse); } else if (_stricmp(parse.m_Args[0], s_szTripped) == 0) { m_bTripped = LTTRUE; // Make sure the camera is set to use the red light... char buf[128]; g_pServerButeMgr->GetSecurityCameraString( "RedLight", buf, ARRAY_LEN(buf)); g_pLTServer->SetObjectFilenames(m_hLight, buf, ""); SetState(eStateOff); } } } } break; case MID_DAMAGE: { // Let our damage aggregate process the message first... uint32 dwRet = CScanner::ObjectMessageFn(hSender, messageID, hRead); // Check to see if we have been destroyed if (m_damage.IsDead()) { SetState(eStateDestroyed); } return dwRet; } break; default : break; } return CScanner::ObjectMessageFn(hSender, messageID, hRead); }