Skip to content

Commit

Permalink
Fix for issue #3140.
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.thedarkmod.com/svn/darkmod_src/trunk@5722 49c82d7f-2e2a-0410-a16f-ae8f201b507f
  • Loading branch information
grayman committed Mar 25, 2013
1 parent 7617b54 commit b386c68
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 65 deletions.
31 changes: 23 additions & 8 deletions game/SndProp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,8 @@ void CsndProp::Propagate

if ( cv_spr_debug.GetBool() )
{
gameLocal.Printf("Found %d ents with valid type for propagation\n", validTypeEnts.Num() );
DM_LOG(LC_SOUND, LT_DEBUG)LOGSTRING("Found %d ents with valid type for propagation\r", validTypeEnts.Num() );
gameLocal.Printf("Found %d valid AIs to propagate to\n", validTypeEnts.Num() );
DM_LOG(LC_SOUND, LT_DEBUG)LOGSTRING("Found %d valid AIs to propagate to\r", validTypeEnts.Num() );
timer_Prop.Stop(); // grayman - only time things if the debug cvar is set
DM_LOG(LC_SOUND, LT_INFO)LOGSTRING("Timer: Finished finding all AI entities, comptime = %lf [ms]\r", timer_Prop.Milliseconds() );
timer_Prop.Start();
Expand Down Expand Up @@ -587,8 +587,17 @@ void CsndProp::Propagate
DM_LOG(LC_SOUND, LT_DEBUG)LOGSTRING("Sound was propagated from inanimate object: Alerts all teams\r" );
}
}
else if ( testAI == maker ) // grayman #3140 - makers don't ping themselves
{
// do nothing, bValidTeam is false at this point
}
else
{
// grayman - tmask holds flags that describe which team
// relationships should receive the propagated sound.
// When one or more of the flags matches the relationship
// flags between the maker and the listener (testAI), then
// the listener should respond to the sound.
compMask.m_bits.same = ( testAI->team == mteam );
compMask.m_bits.friendly = testAI->IsFriend(maker);
compMask.m_bits.neutral = testAI->IsNeutral(maker);
Expand All @@ -607,8 +616,7 @@ void CsndProp::Propagate

// TODO : Add another else if for the case of Listeners

// don't alert the AI that caused the sound
if ( bValidTeam && ( testAI != maker ) )
if ( bValidTeam /* && ( testAI != maker ) */ ) // grayman #3140 - maker test moved up
{
if ( cv_spr_debug.GetBool() )
{
Expand All @@ -620,7 +628,7 @@ void CsndProp::Propagate

if ( cv_spr_debug.GetBool() )
{
DM_LOG(LC_SOUND, LT_DEBUG)LOGSTRING("AI %s does not have a valid team for propagation\r", testAI->name.c_str() );
DM_LOG(LC_SOUND, LT_DEBUG)LOGSTRING("AI %s either doesn't have a valid team for propagation, or is the maker\r", testAI->name.c_str() );
}
}

Expand Down Expand Up @@ -650,6 +658,13 @@ void CsndProp::Propagate
// Don't bother propagation if no one is in range
if ( validEnts.Num() == 0 )
{
// grayman #3140 - We're done propagating, clear the message list of the issuing AI, if appropriate
if ( maker->IsType(idAI::Type) )
{
idAI* makerAI = static_cast<idAI*>(maker);
makerAI->ClearMessages();
}

return;
}

Expand Down Expand Up @@ -750,7 +765,7 @@ void CsndProp::SetupParms( const idDict *parms, SSprParms *propParms, USprFlags

DM_LOG(LC_SOUND,LT_DEBUG)LOGSTRING("Parsing team alert and propagation flags from propagated_sounds.def\r");

// note: by default, if the key is not found, GetBool returns false
// note: by default, if the key is not found, GetBool returns 'false' for the first 3, and 'true' for prop_to_enemy
tempflags.m_bits.same = parms->GetBool("prop_to_same");
tempflags.m_bits.friendly = parms->GetBool("prop_to_friend");
tempflags.m_bits.neutral = parms->GetBool("prop_to_neutral");
Expand Down Expand Up @@ -1207,10 +1222,10 @@ void CsndProp::ProcessAI(idAI* ai, idVec3 origin, SSprParms *propParms)
// check AI hearing, get environmental noise, etc
if ( cv_spr_debug.GetBool() )
{
gameLocal.Printf("Propagated sound %s to AI %s, from origin %s : Propagated volume %f, Apparent origin of sound: %s \r",
gameLocal.Printf("Propagated sound %s to AI %s, from origin %s : Propagated volume %f, Apparent origin of sound: %s\n",
propParms->name.c_str(), ai->name.c_str(), origin.ToString(), propParms->propVol, propParms->direction.ToString() );

DM_LOG(LC_SOUND, LT_DEBUG)LOGSTRING("Propagated sound %s to AI %s, from origin %s : Propagated volume %f, Apparent origin of sound: %s \r",
DM_LOG(LC_SOUND, LT_DEBUG)LOGSTRING("Propagated sound %s to AI %s, from origin %s : Propagated volume %f, Apparent origin of sound: %s\r",
propParms->name.c_str(), ai->name.c_str(), origin.ToString(), propParms->propVol, propParms->direction.ToString() );
}

Expand Down
35 changes: 31 additions & 4 deletions game/ai/AI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6152,10 +6152,36 @@ bool idAI::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVe
ChangeEntityRelation(attacker, -10);

// Switch to pain state if idle
if ( ( AI_AlertIndex == ai::ERelaxed ) &&
if ( /*( AI_AlertIndex == ai::ERelaxed ) && */ // grayman #3140 - go to PainState at any alert level
( damage > 0 ) &&
( ( damageDef == NULL ) || !damageDef->GetBool("no_pain_anim", "0")))
{
// grayman #3140 - note what caused the damage, in case PainState needs to do something special.
// Start with the basic causes (arrow, melee, moveable) and expand to the others as needed.
ai::Memory& memory = GetMemory();
memory.causeOfPain = ai::EPC_None;
if ( inflictor )
{
if ( inflictor->IsType(idProjectile::Type) )
{
memory.causeOfPain = ai::EPC_Projectile;
}
else if ( inflictor->IsType(CMeleeWeapon::Type) )
{
memory.causeOfPain = ai::EPC_Melee;
}
else if ( inflictor->IsType(idMoveable::Type) )
{
memory.causeOfPain = ai::EPC_Moveable;
}
}
else
{
if ( damageDef->GetBool( "no_air" ) )
{
memory.causeOfPain = ai::EPC_Drown;
}
}
GetMind()->PushState(ai::StatePtr(new ai::PainState));
}
}
Expand Down Expand Up @@ -6406,7 +6432,7 @@ void idAI::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir,
return;
}

if (inflictor != NULL && inflictor->IsType(idProjectile::Type))
if ( ( inflictor != NULL ) && inflictor->IsType(idProjectile::Type))
{
int damageTaken = preHitHealth - health;

Expand Down Expand Up @@ -8969,7 +8995,7 @@ void idAI::HearSound(SSprParms *propParms, float noise, const idVec3& origin)
// Retrieve the messages from the other AI, if there are any
if (propParms->makerAI != NULL)
{
for (int i = 0; i < propParms->makerAI->m_Messages.Num(); i++)
for ( int i = 0 ; i < propParms->makerAI->m_Messages.Num() ; i++ )
{
mind->GetState()->OnAICommMessage(*propParms->makerAI->m_Messages[i], psychLoud);
}
Expand Down Expand Up @@ -12136,7 +12162,8 @@ bool idAI::CanGreet() // grayman #3338
if ( ( greetingState == ECannotGreet ) || // can never greet
( greetingState == ECannotGreetYet ) || // not allowed to greet yet
( AI_AlertIndex >= ai::EObservant) || // too alert
( GetAttackFlag(COMBAT_MELEE) && !spawnArgs.GetBool("unarmed_melee","0") ) || // visible melee weapon drawn
( mind->GetState()->GetName() == "Flee" ) || // grayman #3140 - no greeting if fleeing
( GetAttackFlag(COMBAT_MELEE) && !spawnArgs.GetBool("unarmed_melee","0") ) || // visible melee weapon drawn
( GetAttackFlag(COMBAT_RANGED) && !spawnArgs.GetBool("unarmed_ranged","0") ) ) // visible ranged weapon drawn
{
return false;
Expand Down
4 changes: 4 additions & 0 deletions game/ai/Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ void Memory::Save(idSaveGame* savefile) const
savefile->WriteBool(stopHandlingElevator); // grayman #2816
savefile->WriteInt(nextTime2GenRandomSpot); // grayman #2422
savefile->WriteInt(static_cast<int>(alertClass));
savefile->WriteInt(static_cast<int>(causeOfPain)); // grayman #3140
savefile->WriteInt(static_cast<int>(alertType));
savefile->WriteFloat(alertRadius);
savefile->WriteBool(stimulusLocationItselfShouldBeSearched);
Expand Down Expand Up @@ -264,6 +265,9 @@ void Memory::Restore(idRestoreGame* savefile)
savefile->ReadInt(temp);
alertClass = static_cast<EAlertClass>(temp);

savefile->ReadInt(temp);
causeOfPain = static_cast<EPainCause>(temp); // grayman #3140

savefile->ReadInt(temp);
alertType = static_cast<EAlertType>(temp);

Expand Down
16 changes: 16 additions & 0 deletions game/ai/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ enum EAlertState
EAlertStateNum
};

// grayman #3140 - what caused my pain?
enum EPainCause
{
EPC_None = 0,
EPC_Projectile,
EPC_Melee,
EPC_Drown,
EPC_KO,
EPC_Fall,
EPC_Moveable,
EPC_Num
};

const char* const AlertStateNames[EAlertStateNum] =
{
"Relaxed",
Expand Down Expand Up @@ -264,6 +277,9 @@ class Memory
idVec3 posMissingItem;
idVec3 posEvidenceIntruders;

// grayman #3140 - cause of pain
EPainCause causeOfPain;

// grayman #3331 - force a hiding spot search (don't rely just on the alert index changing)
bool mandatory;

Expand Down
15 changes: 4 additions & 11 deletions game/ai/States/CombatState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,18 +340,11 @@ void CombatState::Think(idAI* owner)

_criticalHealth = owner->spawnArgs.GetInt("health_critical", "0");

// greebo: Check for weapons and flee if we are unarmed.
if (!_meleePossible && !_rangedPossible)
// greebo: Check for weapons and flee if ...
if ( ( !_meleePossible && !_rangedPossible ) || // ... I'm unarmed
( owner->spawnArgs.GetBool("is_civilian", "0")) || // ... I'm a civilian, and don't fight
( owner->health < _criticalHealth ) ) // grayman #3140 ... I'm very damaged and can't afford to engage in combat
{
DM_LOG(LC_AI, LT_INFO)LOGSTRING("I'm unarmed, I'm afraid!\r");
owner->GetMind()->SwitchState(STATE_FLEE);
return;
}

// greebo: Check for civilian AI, which will always flee in face of a combat (this is a temporary query)
if (owner->spawnArgs.GetBool("is_civilian", "0"))
{
DM_LOG(LC_AI, LT_INFO)LOGSTRING("I'm a civilian. I'm afraid.\r");
owner->GetMind()->SwitchState(STATE_FLEE);
return;
}
Expand Down
11 changes: 8 additions & 3 deletions game/ai/States/FleeState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,14 @@ void FleeState::Init(idAI* owner)
singleBark = "snd_to_flee_event";
}

owner->commSubsystem->AddCommTask(
CommunicationTaskPtr(new SingleBarkTask(singleBark,message))
);
// grayman #3140 - if hit by an arrow, issue a different bark
if ( memory.causeOfPain == EPC_Projectile )
{
singleBark = "snd_taking_fire";
memory.causeOfPain = EPC_None;
}

owner->commSubsystem->AddCommTask(CommunicationTaskPtr(new SingleBarkTask(singleBark,message)));

owner->commSubsystem->AddSilence(3000);

Expand Down
87 changes: 66 additions & 21 deletions game/ai/States/PainState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,24 @@ void PainState::Init(idAI* owner)
// Set end time
_stateEndTime = gameLocal.time + 5000;

memory.alertPos = owner->GetPhysics()->GetOrigin();

// Do a single bark and assemble an AI message
CommMessagePtr message = CommMessagePtr(new CommMessage(
CommMessage::DetectedEnemy_CommType,
owner, NULL, // from this AI to anyone
NULL,
memory.alertPos
));

owner->commSubsystem->AddCommTask(
CommunicationTaskPtr(new SingleBarkTask("snd_pain_large", message))
);
// grayman #3140 - if drowning, skip issuing a message. The drowning
// sound effect is handled in idActor::Damage().
if ( memory.causeOfPain != EPC_Drown )
{
memory.alertPos = owner->GetPhysics()->GetOrigin();

// Do a single bark and assemble an AI message
CommMessagePtr message = CommMessagePtr(new CommMessage(
CommMessage::DetectedEnemy_CommType,
owner, NULL, // from this AI to anyone
NULL,
memory.alertPos
));

owner->commSubsystem->AddCommTask(
CommunicationTaskPtr(new SingleBarkTask("snd_pain_large", message))
);
}
}

// Gets called each time the mind is thinking
Expand All @@ -79,18 +84,58 @@ void PainState::Think(idAI* owner)
if ( ( gameLocal.time >= _stateEndTime ) ||
( idStr(owner->WaitState(ANIMCHANNEL_TORSO)) != "pain" ) )
{
// grayman #3331 - civilians and unarmed AI should flee
if ( ( ( owner->GetNumMeleeWeapons() == 0 ) && ( owner->GetNumRangedWeapons() == 0 ) ) ||
owner->spawnArgs.GetBool("is_civilian", "0") )
bool willBark = ( owner->AI_AlertLevel < owner->thresh_5 ); // don't bark a response if in combat

bool willFlee = ( ( ( owner->GetNumMeleeWeapons() == 0 ) && ( owner->GetNumRangedWeapons() == 0 ) ) ||
owner->spawnArgs.GetBool("is_civilian", "0") );

// grayman #3140 - what caused this pain?

Memory& memory = owner->GetMemory();
if ( memory.causeOfPain == EPC_Drown )
{
owner->fleeingEvent = true; // I'm fleeing the scene, not fleeing an enemy
owner->GetMind()->SwitchState(STATE_FLEE);
// no bark and no fleeing if drowning
willBark = false;
willFlee = false;
}
else if ( memory.causeOfPain == EPC_Projectile )
{
// If fleeing, snd_taking_fire will be played at the start of the flee state,
// so there's no reason to play it here.

// If not fleeing, play snd_taking_fire here.

willBark = !willFlee;
memory.timeEnemySeen = gameLocal.time;
memory.posEnemySeen = owner->GetPhysics()->GetOrigin();
}

if ( willBark )
{
// grayman #3140 - Emit the snd_taking_fire bark

// This will hold the message to be delivered with the bark
CommMessagePtr message;

message = CommMessagePtr(new CommMessage(
CommMessage::RequestForHelp_CommType,
owner, NULL, // from this AI to anyone
NULL,
owner->GetPhysics()->GetOrigin()
));

owner->commSubsystem->AddCommTask(CommunicationTaskPtr(new SingleBarkTask("snd_taking_fire", message)));
}
else

if ( willFlee ) // grayman #3331 - civilians and unarmed AI should flee
{
// End this state
owner->GetMind()->EndState();
owner->fleeingEvent = true; // I'm fleeing the scene, not fleeing an enemy
owner->GetMind()->SwitchState(STATE_FLEE);
return;
}

// End this state
owner->GetMind()->EndState();
}
}

Expand Down
Loading

0 comments on commit b386c68

Please sign in to comment.