int p_p2(value v1, type t1, value v2, type t2) { char *result; value new_v2; type new_t2; /* first check the arguments */ Check_Integer(t2); Check_Output_Atom(t1); /* take note of new resatisfaction */ new_v2.nint = v2.nint + 1; new_t2.kernel = TINT; Remember(2, new_v2, new_t2); /* get the string that corresponds to the value of v2 */ switch(v2.nint) { case 1: result = "a"; break; case 2: result = "b"; break; case 3: result = "c"; break; default: Fail; } Return_Unify_Atom(v1, t1, Did(result, 0)); }
void CNPC_BigMomma::NodeReach( void ) { CInfoBM *pTarget = (CInfoBM*)GetTarget(); Forget( bits_MEMORY_ADVANCE_NODE ); if ( !pTarget ) return; if ( pTarget->m_iHealth >= 1 ) m_iMaxHealth = m_iHealth = pTarget->m_iHealth * sk_bigmomma_health_factor.GetFloat(); if ( !HasMemory( bits_MEMORY_FIRED_NODE ) ) { if ( pTarget ) { pTarget->m_OnAnimationEvent.FireOutput( this, this ); } } Forget( bits_MEMORY_FIRED_NODE ); m_iszTarget = pTarget->m_target; if ( pTarget->m_iHealth == 0 ) Remember( bits_MEMORY_ADVANCE_NODE ); // Move on if no health at this node else { GetNavigator()->ClearGoal(); } }
int p_member(value velt, type telt, value vlist, type tlist) { pword *p; /* we require a list or nil */ Check_List(tlist); /* if the list is empty, we fail */ if(IsNil(tlist)) { Fail; } /* the tail of the list */ p = vlist.ptr + 1; /* must be dereferenced! */ Dereference(p); /* * on backtracking we will get the tail of the list * instead of the list itself */ Remember(2, p->val, p->tag); /* * and we behave as the unification * of the element and the head */ Return_Unify_Pw(velt, telt, vlist.ptr->val, vlist.ptr->tag); }
void CNPC_BigMomma::LayHeadcrab( void ) { CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, GetAbsOrigin(), GetAbsAngles(), this ); pChild->AddSpawnFlags( SF_NPC_FALL_TO_GROUND ); pChild->SetOwnerEntity( this ); // Is this the second crab in a pair? if ( HasMemory( bits_MEMORY_CHILDPAIR ) ) { m_crabTime = gpGlobals->curtime + RandomFloat( 5, 10 ); Forget( bits_MEMORY_CHILDPAIR ); } else { m_crabTime = gpGlobals->curtime + RandomFloat( 0.5, 2.5 ); Remember( bits_MEMORY_CHILDPAIR ); } trace_t tr; UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,100), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); UTIL_DecalTrace( &tr, "Splash" ); CPASAttenuationFilter filter( this ); EmitSound( filter, entindex(), "BigMomma.LayHeadcrab" ); m_crabCount++; }
void CBigMomma :: LayHeadcrab( void ) { CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, pev->origin, pev->angles, edict() ); pChild->pev->spawnflags |= SF_MONSTER_FALL_TO_GROUND; // Is this the second crab in a pair? if ( HasMemory( bits_MEMORY_CHILDPAIR ) ) { m_crabTime = gpGlobals->time + RANDOM_FLOAT( 5, 10 ); Forget( bits_MEMORY_CHILDPAIR ); } else { m_crabTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 2.5 ); Remember( bits_MEMORY_CHILDPAIR ); } TraceResult tr; UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,100), ignore_monsters, edict(), &tr); UTIL_DecalTrace( &tr, DECAL_MOMMABIRTH ); EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBirthSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); m_crabCount++; }
void CBigMomma::Activate( void ) { if ( m_hTargetEnt == 0 ) Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up CBaseMonster::Activate(); }
void CNPC_BigMomma::Activate( void ) { if ( GetTarget() == NULL ) Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up BaseClass::Activate(); }
int COtis :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) { int ret; // make sure friends talk about it if player hurts talkmonsters... if ( !m_fHostile ) ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); else ret = CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); if ( !IsAlive() || pev->deadflag == DEAD_DYING || m_fHostile ) return ret; if ( !m_fHostile ) { if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) ) { m_flPlayerDamage += flDamage; // This is a heurstic to determine if the player intended to harm me // If I have an enemy, we can't establish intent (may just be crossfire) if ( m_hEnemy == NULL ) { // If the player was facing directly at me, or I'm already suspicious, get mad if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) ) { // Alright, now I'm pissed! PlaySentence( "OT_MAD", 4, VOL_NORM, ATTN_NORM ); Remember( bits_MEMORY_PROVOKED ); StopFollowing( TRUE ); } else { // Hey, be careful with that PlaySentence( "OT_SHOT", 4, VOL_NORM, ATTN_NORM ); Remember( bits_MEMORY_SUSPICIOUS ); } } else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) PlaySentence( "OT_SHOT", 4, VOL_NORM, ATTN_NORM ); } } return ret; }
/* ============ Killed ============ */ void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) { unsigned int cCount = 0; BOOL fDone = FALSE; CBaseEntity* theBaseEntity = CBaseEntity::Instance(pevAttacker->owner); if(!theBaseEntity) { theBaseEntity = CBaseEntity::Instance(pevAttacker); } ASSERT(theBaseEntity); theBaseEntity->AwardKill(this->pev); if ( HasMemory( bits_MEMORY_KILLED ) ) { if ( ShouldGibMonster( iGib ) ) CallGibMonster(); return; } Remember( bits_MEMORY_KILLED ); // clear the deceased's sound channels.(may have been firing or reloading when killed) EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/null.wav", 1, ATTN_NORM); m_IdealMonsterState = MONSTERSTATE_DEAD; // Make sure this condition is fired too (TakeDamage breaks out before this happens on death) SetConditions( bits_COND_LIGHT_DAMAGE ); // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); if ( pOwner ) { pOwner->DeathNotice( pev ); } if ( ShouldGibMonster( iGib ) ) { CallGibMonster(); return; } else if ( pev->flags & FL_MONSTER ) { SetTouch( NULL ); BecomeDead(); } // don't let the status bar glitch for players.with <0 health. if (pev->health < -99) { pev->health = 0; } //pev->enemy = ENT( pevAttacker );//why? (sjb) m_IdealMonsterState = MONSTERSTATE_DEAD; }
int CNPC_Vortigaunt::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ) { // don't slash one of your own if ( ( inputInfo.GetDamageType() & DMG_SLASH ) && inputInfo.GetAttacker() && IRelationType( inputInfo.GetAttacker() ) == D_NU ) return 0; Remember( bits_MEMORY_PROVOKED ); return BaseClass::OnTakeDamage_Alive( inputInfo ); }
int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { if ( pevInflictor && pevInflictor->flags & FL_CLIENT ) { Remember( bits_MEMORY_PROVOKED ); StopFollowing( TRUE ); } // make sure friends talk about it if player hurts scientist... return CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); }
int CNPC_HL1Barney::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ) { // make sure friends talk about it if player hurts talkmonsters... int ret = BaseClass::OnTakeDamage_Alive( inputInfo ); if ( !IsAlive() || m_lifeState == LIFE_DYING ) return ret; if ( m_NPCState != NPC_STATE_PRONE && ( inputInfo.GetAttacker()->GetFlags() & FL_CLIENT ) ) { // This is a heurstic to determine if the player intended to harm me // If I have an enemy, we can't establish intent (may just be crossfire) if ( GetEnemy() == NULL ) { // If the player was facing directly at me, or I'm already suspicious, get mad if ( HasMemory( bits_MEMORY_SUSPICIOUS ) || IsFacing( inputInfo.GetAttacker(), GetAbsOrigin() ) ) { // Alright, now I'm pissed! Speak( BA_MAD ); Remember( bits_MEMORY_PROVOKED ); StopFollowing(); } else { // Hey, be careful with that Speak( BA_SHOT ); Remember( bits_MEMORY_SUSPICIOUS ); } } else if ( !(GetEnemy()->IsPlayer()) && m_lifeState == LIFE_ALIVE ) { Speak( BA_SHOT ); } } return ret; }
void CBigMomma::NodeStart(int iszNextNode) { pev->netname = iszNextNode; CBaseEntity *pTarget = NULL; if(pev->netname) { edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->netname)); if(!FNullEnt(pentTarget)) pTarget = Instance(pentTarget); } if(!pTarget) { ALERT(at_aiconsole, "BM: Finished the path!!\n"); Remember(bits_MEMORY_PATH_FINISHED); return; } Remember(bits_MEMORY_ON_PATH); m_hTargetEnt = pTarget; }
int CBigMomma :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { // Don't take any acid damage -- BigMomma's mortar is acid if ( bitsDamageType & DMG_ACID ) flDamage = 0; if ( !HasMemory(bits_MEMORY_PATH_FINISHED) ) { if ( pev->health <= flDamage ) { pev->health = flDamage + 1; Remember( bits_MEMORY_ADVANCE_NODE | bits_MEMORY_COMPLETED_NODE ); ALERT( at_aiconsole, "BM: Finished node health!!!\n" ); } } return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); }
int CNPC_BigMomma::OnTakeDamage( const CTakeDamageInfo &info ) { CTakeDamageInfo newInfo = info; // Don't take any acid damage -- BigMomma's mortar is acid if ( newInfo.GetDamageType() & DMG_ACID ) { newInfo.SetDamage( 0 ); } // never die from damage, just advance to the next node if ( ( GetHealth() - newInfo.GetDamage() ) < 1 ) { newInfo.SetDamage( 0 ); Remember( bits_MEMORY_ADVANCE_NODE ); DevMsg( 2, "BM: Finished node health!!!\n" ); } DevMsg( 2, "BM Health: %f\n", GetHealth() - newInfo.GetDamage() ); return BaseClass::OnTakeDamage( newInfo ); }
void CBigMomma::NodeReach( void ) { CBaseEntity *pTarget = m_hTargetEnt; Forget( bits_MEMORY_ADVANCE_NODE ); if ( !pTarget ) return; if ( pTarget->pev->health ) pev->max_health = pev->health = pTarget->pev->health * gSkillData.bigmommaHealthFactor; if ( !HasMemory( bits_MEMORY_FIRED_NODE ) ) { if ( pTarget->pev->message ) FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); } Forget( bits_MEMORY_FIRED_NODE ); pev->netname = pTarget->pev->target; if ( pTarget->pev->health == 0 ) Remember( bits_MEMORY_ADVANCE_NODE ); // Move on if no health at this node }
void CBigMomma::Activate( void ) { if ( m_hTargetEnt == NULL ) Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CBigMomma :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: case BIG_AE_MELEE_ATTACKBL: case BIG_AE_MELEE_ATTACK1: { Vector forward, right; UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); Vector center = pev->origin + forward * 128; Vector mins = center - Vector( 64, 64, 0 ); Vector maxs = center + Vector( 64, 64, 64 ); CBaseEntity *pList[8]; int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER|FL_CLIENT ); CBaseEntity *pHurt = NULL; for ( int i = 0; i < count && !pHurt; i++ ) { if ( pList[i] != this ) { if ( pList[i]->pev->owner != edict() ) pHurt = pList[i]; } } if ( pHurt ) { pHurt->TakeDamage( pev, pev, gSkillData.bigmommaDmgSlash, DMG_CRUSH | DMG_SLASH ); pHurt->pev->punchangle.x = 15; switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) - (right * 200); break; case BIG_AE_MELEE_ATTACKBL: pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) + (right * 200); break; case BIG_AE_MELEE_ATTACK1: pHurt->pev->velocity = pHurt->pev->velocity + (forward * 220) + Vector(0,0,200); break; } pHurt->pev->flags &= ~FL_ONGROUND; EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); } } break; case BIG_AE_SCREAM: EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); break; case BIG_AE_PAIN_SOUND: EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); break; case BIG_AE_ATTACK_SOUND: EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackSounds ); break; case BIG_AE_BIRTH_SOUND: EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pBirthSounds ); break; case BIG_AE_SACK: if ( RANDOM_LONG(0,100) < 30 ) EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pSackSounds ); break; case BIG_AE_DEATHSOUND: EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); break; case BIG_AE_STEP1: // Footstep left case BIG_AE_STEP3: // Footstep back left EMIT_SOUND_ARRAY_DYN( CHAN_ITEM, pFootSounds ); break; case BIG_AE_STEP4: // Footstep back right case BIG_AE_STEP2: // Footstep right EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pFootSounds ); break; case BIG_AE_MORTAR_ATTACK1: LaunchMortar(); break; case BIG_AE_LAY_CRAB: LayHeadcrab(); break; case BIG_AE_JUMP_FORWARD: ClearBits( pev->flags, FL_ONGROUND ); UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground UTIL_MakeVectors ( pev->angles ); pev->velocity = (gpGlobals->v_forward * 200) + gpGlobals->v_up * 500; break; case BIG_AE_EARLY_TARGET: { CBaseEntity *pTarget = m_hTargetEnt; if ( pTarget && pTarget->pev->message ) FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); Remember( bits_MEMORY_FIRED_NODE ); } break; default: CBaseMonster::HandleAnimEvent( pEvent ); break; } }
//========================================================= // Start task - selects the correct activity and performs // any necessary calculations to start the next task on the // schedule. //========================================================= void CBaseMonster :: StartTask ( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_TURN_RIGHT: { float flCurrentYaw; flCurrentYaw = UTIL_AngleMod( pev->angles.y ); pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); SetTurnActivity(); break; } case TASK_TURN_LEFT: { float flCurrentYaw; flCurrentYaw = UTIL_AngleMod( pev->angles.y ); pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); SetTurnActivity(); break; } case TASK_REMEMBER: { Remember ( (int)pTask->flData ); TaskComplete(); break; } case TASK_FORGET: { Forget ( (int)pTask->flData ); TaskComplete(); break; } case TASK_FIND_HINTNODE: { m_iHintNode = FindHintNode(); if ( m_iHintNode != NO_NODE ) { TaskComplete(); } else { TaskFail(); } break; } case TASK_STORE_LASTPOSITION: { m_vecLastPosition = pev->origin; TaskComplete(); break; } case TASK_CLEAR_LASTPOSITION: { m_vecLastPosition = g_vecZero; TaskComplete(); break; } case TASK_CLEAR_HINTNODE: { m_iHintNode = NO_NODE; TaskComplete(); break; } case TASK_STOP_MOVING: { if ( m_IdealActivity == m_movementActivity ) { m_IdealActivity = GetStoppedActivity(); } RouteClear(); TaskComplete(); break; } case TASK_PLAY_SEQUENCE_FACE_ENEMY: case TASK_PLAY_SEQUENCE_FACE_TARGET: case TASK_PLAY_SEQUENCE: { m_IdealActivity = ( Activity )( int )pTask->flData; break; } case TASK_PLAY_ACTIVE_IDLE: { // monsters verify that they have a sequence for the node's activity BEFORE // moving towards the node, so it's ok to just set the activity without checking here. m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; break; } case TASK_SET_SCHEDULE: { Schedule_t *pNewSchedule; pNewSchedule = GetScheduleOfType( (int)pTask->flData ); if ( pNewSchedule ) { ChangeSchedule( pNewSchedule ); } else { TaskFail(); } break; } case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_COVER_FROM_ENEMY: { entvars_t *pevCover; if ( m_hEnemy == NULL ) { // Find cover from self if no enemy available pevCover = pev; // TaskFail(); // return; } else pevCover = m_hEnemy->pev; if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) { // try lateral first m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_COVER_FROM_ORIGIN: { if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no cover! TaskFail(); } } break; case TASK_FIND_COVER_FROM_BEST_SOUND: { CSound *pBestSound; pBestSound = PBestSound(); ASSERT( pBestSound != NULL ); /* if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) { // try lateral first m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } */ if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no coverwhatsoever. or no sound in list TaskFail(); } break; } case TASK_FACE_HINTNODE: { pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; SetTurnActivity(); break; } case TASK_FACE_LASTPOSITION: MakeIdealYaw ( m_vecLastPosition ); SetTurnActivity(); break; case TASK_FACE_TARGET: if ( m_hTargetEnt != NULL ) { MakeIdealYaw ( m_hTargetEnt->pev->origin ); SetTurnActivity(); } else TaskFail(); break; case TASK_FACE_ENEMY: { MakeIdealYaw ( m_vecEnemyLKP ); SetTurnActivity(); break; } case TASK_FACE_IDEAL: { SetTurnActivity(); break; } case TASK_FACE_ROUTE: { if (FRouteClear()) { ALERT(at_aiconsole, "No route to face!\n"); TaskFail(); } else { MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); SetTurnActivity(); } break; } case TASK_WAIT_PVS: case TASK_WAIT_INDEFINITE: { // don't do anything. break; } case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: {// set a future time that tells us when the wait is over. m_flWaitFinished = gpGlobals->time + pTask->flData; break; } case TASK_WAIT_RANDOM: {// set a future time that tells us when the wait is over. m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); break; } case TASK_MOVE_TO_TARGET_RANGE: { if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) TaskComplete(); else { m_vecMoveGoal = m_hTargetEnt->pev->origin; if ( !MoveToTarget( ACT_WALK, 2 ) ) TaskFail(); } break; } case TASK_RUN_TO_SCRIPT: case TASK_WALK_TO_SCRIPT: { Activity newActivity; if ( !m_pGoalEnt || (m_pGoalEnt->pev->origin - pev->origin).Length() < 1 ) TaskComplete(); else { if ( pTask->iTask == TASK_WALK_TO_SCRIPT ) newActivity = ACT_WALK; else newActivity = ACT_RUN; // This monster can't do this! if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) TaskComplete(); else { if ( m_pGoalEnt != NULL ) { Vector vecDest; vecDest = m_pGoalEnt->pev->origin; if ( !MoveToLocation( newActivity, 2, vecDest ) ) { TaskFail(); ALERT( at_aiconsole, "%s Failed to reach script!!!\n", STRING(pev->classname) ); RouteClear(); } } else { TaskFail(); ALERT( at_aiconsole, "%s: MoveTarget is missing!?!\n", STRING(pev->classname) ); RouteClear(); } } } TaskComplete(); break; } case TASK_CLEAR_MOVE_WAIT: { m_flMoveWaitFinished = gpGlobals->time; TaskComplete(); break; } case TASK_MELEE_ATTACK1_NOTURN: case TASK_MELEE_ATTACK1: { m_IdealActivity = ACT_MELEE_ATTACK1; break; } case TASK_MELEE_ATTACK2_NOTURN: case TASK_MELEE_ATTACK2: { m_IdealActivity = ACT_MELEE_ATTACK2; break; } case TASK_RANGE_ATTACK1_NOTURN: case TASK_RANGE_ATTACK1: { m_IdealActivity = ACT_RANGE_ATTACK1; break; } case TASK_RANGE_ATTACK2_NOTURN: case TASK_RANGE_ATTACK2: { m_IdealActivity = ACT_RANGE_ATTACK2; break; } case TASK_RELOAD_NOTURN: case TASK_RELOAD: { m_IdealActivity = ACT_RELOAD; break; } case TASK_SPECIAL_ATTACK1: { m_IdealActivity = ACT_SPECIAL_ATTACK1; break; } case TASK_SPECIAL_ATTACK2: { m_IdealActivity = ACT_SPECIAL_ATTACK2; break; } case TASK_SET_ACTIVITY: { m_IdealActivity = (Activity)(int)pTask->flData; TaskComplete(); break; } case TASK_GET_PATH_TO_ENEMY_LKP: { if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_ENEMY: { CBaseEntity *pEnemy = m_hEnemy; if ( pEnemy == NULL ) { TaskFail(); return; } if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) { TaskComplete(); } else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_ENEMY_CORPSE: { UTIL_MakeVectors( pev->angles ); if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } else { ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); TaskFail(); } } break; case TASK_GET_PATH_TO_SPOT: { CBaseEntity *pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_TARGET: { RouteClear(); if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_SCRIPT: { RouteClear(); if ( m_pCine != NULL && MoveToLocation( m_movementActivity, 1, m_pCine->pev->origin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_HINTNODE:// for active idles! { if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_LASTPOSITION: { m_vecMoveGoal = m_vecLastPosition; if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_BESTSOUND: { CSound *pSound; pSound = PBestSound(); if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_BESTSCENT: { CSound *pScent; pScent = PBestScent(); if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); TaskFail(); } break; } case TASK_RUN_PATH: { // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) { m_movementActivity = ACT_RUN; } else { m_movementActivity = ACT_WALK; } TaskComplete(); break; } case TASK_WALK_PATH: { if ( pev->movetype == MOVETYPE_FLY ) { m_movementActivity = ACT_FLY; } if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) { m_movementActivity = ACT_WALK; } else { m_movementActivity = ACT_RUN; } TaskComplete(); break; } case TASK_STRAFE_PATH: { Vector2D vec2DirToPoint; Vector2D vec2RightSide; // to start strafing, we have to first figure out if the target is on the left side or right side UTIL_MakeVectors ( pev->angles ); vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) { // strafe right m_movementActivity = ACT_STRAFE_RIGHT; } else { // strafe left m_movementActivity = ACT_STRAFE_LEFT; } TaskComplete(); break; } case TASK_WAIT_FOR_MOVEMENT: { if (FRouteClear()) { TaskComplete(); } break; } case TASK_EAT: { Eat( pTask->flData ); TaskComplete(); break; } case TASK_SMALL_FLINCH: { m_IdealActivity = GetSmallFlinchActivity(); break; } case TASK_DIE: { RouteClear(); m_IdealActivity = GetDeathActivity(); pev->deadflag = DEAD_DYING; break; } case TASK_SOUND_WAKE: { AlertSound(); TaskComplete(); break; } case TASK_SOUND_DIE: { DeathSound(); TaskComplete(); break; } case TASK_SOUND_IDLE: { IdleSound(); TaskComplete(); break; } case TASK_SOUND_PAIN: { PainSound(); TaskComplete(); break; } case TASK_SOUND_DEATH: { DeathSound(); TaskComplete(); break; } case TASK_SOUND_ANGRY: { // sounds are complete as soon as we get here, cause we've already played them. ALERT ( at_aiconsole, "SOUND\n" ); TaskComplete(); break; } case TASK_WAIT_FOR_SCRIPT: { if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) { TaskComplete(); //LRC - start playing immediately } else if (!m_pCine->IsAction() && m_pCine->m_iszIdle) { m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) { pev->framerate = 0; } } else m_IdealActivity = ACT_IDLE; break; } case TASK_PLAY_SCRIPT: { if (m_pCine->IsAction()) { //ALERT(at_console,"PlayScript: setting idealactivity %d\n",m_pCine->m_fAction); switch(m_pCine->m_fAction) { case 0: m_IdealActivity = ACT_RANGE_ATTACK1; break; case 1: m_IdealActivity = ACT_RANGE_ATTACK2; break; case 2: m_IdealActivity = ACT_MELEE_ATTACK1; break; case 3: m_IdealActivity = ACT_MELEE_ATTACK2; break; case 4: m_IdealActivity = ACT_SPECIAL_ATTACK1; break; case 5: m_IdealActivity = ACT_SPECIAL_ATTACK2; break; case 6: m_IdealActivity = ACT_RELOAD; break; case 7: m_IdealActivity = ACT_HOP; break; } pev->framerate = 1.0; // shouldn't be needed, but just in case pev->movetype = MOVETYPE_FLY; ClearBits(pev->flags, FL_ONGROUND); } else { m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); if ( m_fSequenceFinished ) ClearSchedule(); pev->framerate = 1.0; //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); } m_scriptState = SCRIPT_PLAYING; break; } case TASK_ENABLE_SCRIPT: { m_pCine->DelayStart( 0 ); TaskComplete(); break; } //LRC case TASK_END_SCRIPT: { m_pCine->SequenceDone( this ); TaskComplete(); break; } case TASK_PLANT_ON_SCRIPT: { if ( m_pCine != NULL ) { // Plant on script // LRC - if it's a teleport script, do the turn too if (m_pCine->m_fMoveTo == 4 || m_pCine->m_fMoveTo == 6) { if (m_pCine->m_fTurnType == 0) //LRC pev->angles.y = m_hTargetEnt->pev->angles.y; else if (m_pCine->m_fTurnType == 1) pev->angles.y = UTIL_VecToYaw(m_hTargetEnt->pev->origin - pev->origin); pev->ideal_yaw = pev->angles.y; pev->avelocity = Vector( 0, 0, 0 ); pev->velocity = Vector( 0, 0, 0 ); pev->effects |= EF_NOINTERP; } if (m_pCine->m_fMoveTo != 6) pev->origin = m_pGoalEnt->pev->origin; } TaskComplete(); break; } case TASK_FACE_SCRIPT: { if ( m_pCine != NULL && m_pCine->m_fMoveTo != 0) // movetype "no move" makes us ignore turntype { switch (m_pCine->m_fTurnType) { case 0: pev->ideal_yaw = UTIL_AngleMod( m_pCine->pev->angles.y ); break; case 1: // yes, this is inconsistent- turn to face uses the "target" and turn to angle uses the "cine". if (m_hTargetEnt) MakeIdealYaw ( m_hTargetEnt->pev->origin ); else MakeIdealYaw ( m_pCine->pev->origin ); break; // default: don't turn } } TaskComplete(); m_IdealActivity = ACT_IDLE; RouteClear(); break; } case TASK_SUGGEST_STATE: { m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; TaskComplete(); break; } case TASK_SET_FAIL_SCHEDULE: m_failSchedule = (int)pTask->flData; TaskComplete(); break; case TASK_CLEAR_FAIL_SCHEDULE: m_failSchedule = SCHED_NONE; TaskComplete(); break; default: { ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); break; } } }
int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) { // make sure friends talk about it if player hurts talkmonsters... int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); if ( !IsAlive() || pev->deadflag == DEAD_DYING ) return ret; // LRC - if my reaction to the player has been overridden, don't do this stuff if (m_iPlayerReact) return ret; if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) ) { m_flPlayerDamage += flDamage; // This is a heurstic to determine if the player intended to harm me // If I have an enemy, we can't establish intent (may just be crossfire) if ( m_hEnemy == NULL ) { // If the player was facing directly at me, or I'm already suspicious, get mad if( (m_afMemory & bits_MEMORY_SUSPICIOUS) || UTIL_IsFacing( pevAttacker, GetAbsOrigin() )) { // Alright, now I'm pissed! if (m_iszSpeakAs) { char szBuf[32]; strcpy(szBuf,STRING(m_iszSpeakAs)); strcat(szBuf,"_MAD"); PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); } else { PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM ); } Remember( bits_MEMORY_PROVOKED ); StopFollowing( TRUE ); } else { // Hey, be careful with that if (m_iszSpeakAs) { char szBuf[32]; strcpy(szBuf,STRING(m_iszSpeakAs)); strcat(szBuf,"_SHOT"); PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); } else { PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); } Remember( bits_MEMORY_SUSPICIOUS ); } } else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) { if (m_iszSpeakAs) { char szBuf[32]; strcpy(szBuf,STRING(m_iszSpeakAs)); strcat(szBuf,"_SHOT"); PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); } else { PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); } } } return ret; }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CNPC_BigMomma::HandleAnimEvent( animevent_t *pEvent ) { CPASAttenuationFilter filter( this ); Vector vecFwd, vecRight, vecUp; QAngle angles; angles = GetAbsAngles(); AngleVectors( angles, &vecFwd, &vecRight, &vecUp ); switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: case BIG_AE_MELEE_ATTACKBL: case BIG_AE_MELEE_ATTACK1: { Vector center = GetAbsOrigin() + vecFwd * 128; Vector mins = center - Vector( 64, 64, 0 ); Vector maxs = center + Vector( 64, 64, 64 ); CBaseEntity *pList[8]; int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_NPC | FL_CLIENT ); CBaseEntity *pHurt = NULL; for ( int i = 0; i < count && !pHurt; i++ ) { if ( pList[i] != this ) { if ( pList[i]->GetOwnerEntity() != this ) { pHurt = pList[i]; } } } if ( pHurt ) { CTakeDamageInfo info( this, this, 15, DMG_CLUB | DMG_SLASH ); CalculateMeleeDamageForce( &info, (pHurt->GetAbsOrigin() - GetAbsOrigin()), pHurt->GetAbsOrigin() ); pHurt->TakeDamage( info ); QAngle newAngles = angles; newAngles.x = 15; if ( pHurt->IsPlayer() ) { ((CBasePlayer *)pHurt)->SetPunchAngle( newAngles ); } switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: // pHurt->pev->velocity = pHurt->pev->velocity + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200) ); break; case BIG_AE_MELEE_ATTACKBL: pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) + (vecRight * 200) ); break; case BIG_AE_MELEE_ATTACK1: pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 220) + Vector(0,0,200) ); break; } pHurt->SetGroundEntity( NULL ); EmitSound( filter, entindex(), "BigMomma.AttackHit" ); } } break; case BIG_AE_SCREAM: EmitSound( filter, entindex(), "BigMomma.Alert" ); break; case BIG_AE_PAIN_SOUND: EmitSound( filter, entindex(), "BigMomma.Pain" ); break; case BIG_AE_ATTACK_SOUND: EmitSound( filter, entindex(), "BigMomma.Attack" ); break; case BIG_AE_BIRTH_SOUND: EmitSound( filter, entindex(), "BigMomma.Birth" ); break; case BIG_AE_SACK: if ( RandomInt(0,100) < 30 ) { EmitSound( filter, entindex(), "BigMomma.Sack" ); } break; case BIG_AE_DEATHSOUND: EmitSound( filter, entindex(), "BigMomma.Die" ); break; case BIG_AE_STEP1: // Footstep left case BIG_AE_STEP3: // Footstep back left EmitSound( filter, entindex(), "BigMomma.FootstepLeft" ); break; case BIG_AE_STEP4: // Footstep back right case BIG_AE_STEP2: // Footstep right EmitSound( filter, entindex(), "BigMomma.FootstepRight" ); break; case BIG_AE_MORTAR_ATTACK1: LaunchMortar(); break; case BIG_AE_LAY_CRAB: LayHeadcrab(); break; case BIG_AE_JUMP_FORWARD: SetGroundEntity( NULL ); SetAbsOrigin(GetAbsOrigin() + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground SetAbsVelocity(vecFwd * 200 + vecUp * 500 ); break; case BIG_AE_EARLY_TARGET: { CInfoBM *pTarget = (CInfoBM*) GetTarget(); if ( pTarget ) { pTarget->m_OnAnimationEvent.FireOutput( this, this ); } Remember( bits_MEMORY_FIRED_NODE ); } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
bool CAI_BlendedMotor::AddTurnGesture( float flYD ) { // some funky bug with human turn gestures, disable for now return false; // try using a turn gesture Activity activity = ACT_INVALID; float weight = 1.0; float turnCompletion = 1.0; if (m_flNextTurnGesture > gpGlobals->curtime) { /* if ( GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT ) { Msg( "%.1f : [ %.2f ]\n", flYD, m_flNextTurnAct - gpGlobals->curtime ); } */ return false; } if ( GetOuter()->IsMoving() || GetOuter()->IsCrouching() ) { return false; } if (fabs( flYD ) < 15) { return false; } else if (flYD < -45) { activity = ACT_GESTURE_TURN_RIGHT90; weight = flYD / -90; turnCompletion = 0.36; } else if (flYD < 0) { activity = ACT_GESTURE_TURN_RIGHT45; weight = flYD / -45; turnCompletion = 0.4; } else if (flYD <= 45) { activity = ACT_GESTURE_TURN_LEFT45; weight = flYD / 45; turnCompletion = 0.4; } else { activity = ACT_GESTURE_TURN_LEFT90; weight = flYD / 90; turnCompletion = 0.36; } int seq = SelectWeightedSequence( activity ); if (scene_flatturn->GetBool() && GetOuter()->IsCurSchedule( SCHED_SCENE_GENERIC )) { Activity flatactivity = activity; if (activity == ACT_GESTURE_TURN_RIGHT90) { flatactivity = ACT_GESTURE_TURN_RIGHT90_FLAT; } else if (activity == ACT_GESTURE_TURN_RIGHT45) { flatactivity = ACT_GESTURE_TURN_RIGHT45_FLAT; } else if (activity == ACT_GESTURE_TURN_LEFT90) { flatactivity = ACT_GESTURE_TURN_LEFT90_FLAT; } else if (activity == ACT_GESTURE_TURN_LEFT45) { flatactivity = ACT_GESTURE_TURN_LEFT45_FLAT; } if (flatactivity != activity) { int newseq = SelectWeightedSequence( flatactivity ); if (newseq != ACTIVITY_NOT_AVAILABLE) { seq = newseq; } } } if (seq != ACTIVITY_NOT_AVAILABLE) { int iLayer = GetOuter()->AddGestureSequence( seq ); if (iLayer != -1) { GetOuter()->SetLayerPriority( iLayer, 100 ); // vary the playback a bit SetLayerPlaybackRate( iLayer, 1.0 ); float actualDuration = GetOuter()->GetLayerDuration( iLayer ); float rate = enginerandom->RandomFloat( 0.5, 1.1 ); float diff = fabs( flYD ); float speed = (diff / (turnCompletion * actualDuration / rate)) * 0.1; speed = clamp( speed, 15, 35 ); speed = min( speed, diff ); actualDuration = (diff / (turnCompletion * speed)) * 0.1 ; GetOuter()->SetLayerDuration( iLayer, actualDuration ); SetLayerWeight( iLayer, weight ); SetYawSpeed( speed ); Remember( bits_MEMORY_TURNING ); // don't overlap the turn portion of the gestures, and don't play them too often m_flNextTurnGesture = gpGlobals->curtime + max( turnCompletion * actualDuration, 0.3 ); /* if ( GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT ) { Msg( "%.1f : %.2f %.2f : %.2f (%.2f)\n", flYD, weight, speed, actualDuration, turnCompletion * actualDuration ); } */ return true; } else { return false; } } return false; }
static void GetFullFontList(Widget w) { Widget b; int i, j, nfonts, ii, nogood, ac; char **list, *p, *q; char field[14][64]; /* ??? FIX ME */ struct xlfd_fields **fields; Arg al[2]; /* * Use userdata field to pass the FC widget id. * * We need this because we might get called from a tearoff, * and in a tearoff we cannot walk up the widget tree to find * the FontChooser. */ ac = 0; XtSetArg(al[ac], XmNuserData, (XtPointer)w); ac++; for (i=0; i<14; i++) { XtAddCallback(FC_Menus(w)[i], XmNentryCallback, FCFilter, (XtPointer)i); b = XmCreatePushButtonGadget(FC_Menus(w)[i], "*", al, ac); XtManageChild(b); XtVaSetValues(FC_Menus(w)[i], XmNmenuHistory, b, NULL); FC_Setting(w)[i] = XtNewString("*"); } list = XListFonts(XtDisplay(w), FC_Pattern(w), 4096, &nfonts); fields = (struct xlfd_fields **)XtCalloc(14, sizeof(struct xlfd_fields *)); for (i=0; i<nfonts; i++) { /* sscanf doesn't cope well with empty fields, so do this ourselves. */ nogood = 0; for (j=0, p=list[i]; j<14; j++) { /* Scan for a dash and a string starting at p, store it in field */ if (*p != '-') { fprintf(stderr, "%s: Can't scan font name '%s'\n", XtName(w), list[i]); nogood = 1; break; } p++; for (q=p, ii=0; *q && *q != '-' && ii < 64; q++, ii++) field[j][ii] = *q; field[j][ii] = '\0'; if (*q) p = q; else break; } for (j=0; j<14; j++) { Remember(fields, j, field[j]); } } /* Create buttons */ for (i=0; i<14; i++) { /* * Sort according to criteria from resource. */ if (FC_SortCriteria(w) && strlen(FC_SortCriteria(w)) > 13) { size_t s, n; s = sizeof(char *); n = fields[i]->num; if (FC_SortCriteria(w)[i] == 'n' || FC_SortCriteria(w)[i] == 'N') { qsort(fields[i]->names, n, s, qsort_helper_num); } else if (FC_SortCriteria(w)[i] == 'a' || FC_SortCriteria(w)[i] == 'A') { qsort(fields[i]->names, n, s, qsort_helper_alpha); } else { ; /* don't sort, silently */ } } for (j=0; j<fields[i]->num; j++) { b = XmCreatePushButtonGadget(FC_Menus(w)[i], fields[i]->names[j], al, ac); XtManageChild(b); XtFree(fields[i]->names[j]); } XtFree((XtPointer)fields[i]->names); XtFree((XtPointer)fields[i]); } XtFree((XtPointer)fields); XFreeFontNames(list); ShowCount(w, nfonts); }
/* ============ TakeDamage The damage is coming from inflictor, but get mad at attacker This should be the only function that ever reduces health. bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK Time-based damage: only occurs while the monster is within the trigger_hurt. When a monster is poisoned via an arrow etc it takes all the poison damage at once. GLOBALS ASSUMED SET: g_iSkillLevel ============ */ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { float flTake; Vector vecDir; if (!pev->takedamage) return 0; if ( !IsAlive() ) { return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } if ( pev->deadflag == DEAD_NO ) { // no pain sound during death animation. PainSound();// "Ouch!" } //!!!LATER - make armor consideration here! flTake = flDamage; // set damage type sustained m_bitsDamageType |= bitsDamageType; // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). vecDir = Vector( 0, 0, 0 ); if (!FNullEnt( pevInflictor )) { CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); if (pInflictor) { vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize(); } } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // todo: remove after combining shotgun blasts? if ( IsPlayer() ) { if ( pevInflictor ) pev->dmg_inflictor = ENT(pevInflictor); pev->dmg_take += flTake; // check for godmode or invincibility if ( pev->flags & FL_GODMODE ) { return 0; } } // if this is a player, move him around! if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) ) { pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); } // do the damage pev->health -= flTake; // HACKHACK Don't kill monsters in a script. Let them break their scripts first if ( m_MonsterState == MONSTERSTATE_SCRIPT ) { SetConditions( bits_COND_LIGHT_DAMAGE ); return 0; } if ( pev->health <= 0 ) { g_pevLastInflictor = pevInflictor; if ( bitsDamageType & DMG_ALWAYSGIB ) { Killed( pevAttacker, GIB_ALWAYS ); } else if ( bitsDamageType & DMG_NEVERGIB ) { Killed( pevAttacker, GIB_NEVER ); } else { Killed( pevAttacker, GIB_NORMAL ); } g_pevLastInflictor = NULL; return 0; } // react to the damage (get mad) if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) { //LRC - new behaviours, for m_iPlayerReact. if (pevAttacker->flags & FL_CLIENT) { if (m_iPlayerReact == 2) { // just get angry. Remember( bits_MEMORY_PROVOKED ); } else if (m_iPlayerReact == 3) { // try to decide whether it was deliberate... if I have an enemy, assume it was just crossfire. if ( m_hEnemy == 0 ) { if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || UTIL_IsFacing( pevAttacker, pev->origin ) ) Remember( bits_MEMORY_PROVOKED ); else Remember( bits_MEMORY_SUSPICIOUS ); } } } if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) {// only if the attack was a monster or client! // enemy's last known position is somewhere down the vector that the attack came from. if (pevInflictor) { if (m_hEnemy == 0 || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) { m_vecEnemyLKP = pevInflictor->origin; } } else { m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); } MakeIdealYaw( m_vecEnemyLKP ); // add pain to the conditions // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and // heavy damage per monster class? if ( flDamage > 0 ) { SetConditions(bits_COND_LIGHT_DAMAGE); } if ( flDamage >= 20 ) { SetConditions(bits_COND_HEAVY_DAMAGE); } } } return 1; }