// Pick a sequence for the given activity. If the current sequence is appropriate for the // current activity, and its stored weight is negative (whatever that means), always select // it. Otherwise perform a weighted selection -- imagine a large roulette wheel, with each // sequence having a number of spaces corresponding to its weight. int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence ) { if (!ValidateAgainst(pstudiohdr)) { AssertMsg1(false, "CStudioHdr %s has changed its vmodel pointer without reinitializing its activity mapping! Now performing emergency reinitialization.", pstudiohdr->pszName()); ExecuteOnce(DebuggerBreakIfDebugging()); Reinitialize(pstudiohdr); } // a null m_pSequenceTuples just means that this studio header has no activities. if (!m_pSequenceTuples) return ACTIVITY_NOT_AVAILABLE; // is the current sequence appropriate? if (curSequence >= 0) { mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( curSequence ); if (seqdesc.activity == activity && seqdesc.actweight < 0) return curSequence; } // get the data for the given activity HashValueType dummy( activity, 0, 0, 0 ); UtlHashHandle_t handle = m_ActToSeqHash.Find(dummy); if (!m_ActToSeqHash.IsValidHandle(handle)) { return ACTIVITY_NOT_AVAILABLE; } const HashValueType * __restrict actData = &m_ActToSeqHash[handle]; int weighttotal = actData->totalWeight; // generate a random number from 0 to the total weight int randomValue; if ( IsInPrediction() ) { randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1 ); } else { randomValue = RandomInt( 0, weighttotal - 1 ); } // chug through the entries in the list (they are sequential therefore cache-coherent) // until we run out of random juice SequenceTuple * __restrict sequenceInfo = m_pSequenceTuples + actData->startingIdx; const SequenceTuple *const stopHere = sequenceInfo + actData->count; // this is a backup // in case the weights are somehow miscalculated -- we don't read or write through // it (because it aliases the restricted pointer above); it's only here for // the comparison. while (randomValue >= sequenceInfo->weight && sequenceInfo < stopHere) { randomValue -= sequenceInfo->weight; ++sequenceInfo; } return sequenceInfo->seqnum; }
int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequenceFromModifiers( CStudioHdr *pstudiohdr, int activity, CUtlSymbol *pActivityModifiers, int iModifierCount ) { if ( !pstudiohdr->SequencesAvailable() ) { return ACTIVITY_NOT_AVAILABLE; } VerifySequenceIndex( pstudiohdr ); if ( pstudiohdr->GetNumSeq() == 1 ) { return ( ::GetSequenceActivity( pstudiohdr, 0, NULL ) == activity ) ? 0 : ACTIVITY_NOT_AVAILABLE; } if (!ValidateAgainst(pstudiohdr)) { AssertMsg1(false, "CStudioHdr %s has changed its vmodel pointer without reinitializing its activity mapping! Now performing emergency reinitialization.", pstudiohdr->pszName()); ExecuteOnce(DebuggerBreakIfDebugging()); Reinitialize(pstudiohdr); } // a null m_pSequenceTuples just means that this studio header has no activities. if (!m_pSequenceTuples) return ACTIVITY_NOT_AVAILABLE; // get the data for the given activity HashValueType dummy( activity, 0, 0, 0 ); UtlHashHandle_t handle = m_ActToSeqHash.Find(dummy); if (!m_ActToSeqHash.IsValidHandle(handle)) { return ACTIVITY_NOT_AVAILABLE; } const HashValueType * __restrict actData = &m_ActToSeqHash[handle]; // go through each sequence and give it a score int top_score = -1; CUtlVector<int> topScoring( actData->count, actData->count ); for ( int i = 0; i < actData->count; i++ ) { SequenceTuple * __restrict sequenceInfo = m_pSequenceTuples + actData->startingIdx + i; int score = 0; // count matching activity modifiers for ( int m = 0; m < iModifierCount; m++ ) { int num_modifiers = sequenceInfo->iNumActivityModifiers; for ( int k = 0; k < num_modifiers; k++ ) { if ( sequenceInfo->pActivityModifiers[ k ] == pActivityModifiers[ m ] ) { score++; break; } } } if ( score > top_score ) { topScoring.RemoveAll(); topScoring.AddToTail( sequenceInfo->seqnum ); top_score = score; } } // randomly pick between the highest scoring sequences ( NOTE: this method of selecting a sequence ignores activity weights ) if ( IsInPrediction() ) { return topScoring[ SharedRandomInt( "SelectWeightedSequence", 0, topScoring.Count() - 1 ) ]; } return topScoring[ RandomInt( 0, topScoring.Count() - 1 ) ]; }