//========================================================= // GetSchedule - Decides which type of schedule best suits // the monster's current state and conditions. Then calls // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= Schedule_t *CBaseMonster :: GetSchedule ( void ) { switch ( m_MonsterState ) { case MONSTERSTATE_PRONE: { return GetScheduleOfType( SCHED_BARNACLE_VICTIM_GRAB ); break; } case MONSTERSTATE_NONE: { ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); break; } case MONSTERSTATE_IDLE: { if ( HasConditions ( bits_COND_HEAR_SOUND ) ) { return GetScheduleOfType( SCHED_ALERT_FACE ); } else if ( FRouteClear() ) { // no valid route! return GetScheduleOfType( SCHED_IDLE_STAND ); } else { // valid route. Get moving return GetScheduleOfType( SCHED_IDLE_WALK ); } break; } case MONSTERSTATE_ALERT: { if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) { return GetScheduleOfType ( SCHED_VICTORY_DANCE ); } if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) { if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction { return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); } else { return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); } } else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) { return GetScheduleOfType( SCHED_ALERT_FACE ); } else { return GetScheduleOfType( SCHED_ALERT_STAND ); } break; } case MONSTERSTATE_COMBAT: { if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // clear the current (dead) enemy and try to find another. m_hEnemy = NULL; if ( GetEnemy() ) { ClearConditions( bits_COND_ENEMY_DEAD ); return GetSchedule(); } else { SetState( MONSTERSTATE_ALERT ); return GetSchedule(); } } if ( HasConditions(bits_COND_NEW_ENEMY) ) { return GetScheduleOfType ( SCHED_WAKE_ANGRY ); } else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) { return GetScheduleOfType( SCHED_SMALL_FLINCH ); } else if ( !HasConditions(bits_COND_SEE_ENEMY) ) { // we can't see the enemy if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) { // enemy is unseen, but not occluded! // turn to face enemy return GetScheduleOfType( SCHED_COMBAT_FACE ); } else { // chase! return GetScheduleOfType( SCHED_CHASE_ENEMY ); } } else { // we can see the enemy if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) { return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); } if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) { return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); } if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) { return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); } if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) { return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); } if ( !HasConditions(bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1) ) { // if we can see enemy but can't use either attack type, we must need to get closer to enemy return GetScheduleOfType( SCHED_CHASE_ENEMY ); } else if ( !FacingIdeal() ) { //turn return GetScheduleOfType( SCHED_COMBAT_FACE ); } else { ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); } } break; } case MONSTERSTATE_DEAD: { return GetScheduleOfType( SCHED_DIE ); break; } case MONSTERSTATE_SCRIPT: { ASSERT( m_pCine != NULL ); if ( !m_pCine ) { ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); // ALERT( at_console, "Script failed for %s\n", STRING(pev->classname) ); CineCleanup(); return GetScheduleOfType( SCHED_IDLE_STAND ); } return GetScheduleOfType( SCHED_AISCRIPT ); } default: { ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); break; } } return &slError[ 0 ]; }
//========================================================= // GetScheduleOfType - returns a pointer to one of the // monster's available schedules of the indicated type. //========================================================= Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) { // ALERT ( at_console, "Sched Type:%d\n", Type ); switch ( Type ) { // This is the schedule for scripted sequences AND scripted AI case SCHED_AISCRIPT: { ASSERT( m_pCine != NULL ); if ( !m_pCine ) { ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); CineCleanup(); return GetScheduleOfType( SCHED_IDLE_STAND ); } // else // ALERT( at_aiconsole, "Starting script %s for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); switch ( m_pCine->m_fMoveTo ) { case 0: case 4: return slWaitScript; case 1: return slWalkToScript; case 2: return slRunToScript; case 5: return slFaceScript; } break; } case SCHED_IDLE_STAND: { if ( RANDOM_LONG(0,14) == 0 && FCanActiveIdle() ) { return &slActiveIdle[ 0 ]; } return &slIdleStand[ 0 ]; } case SCHED_IDLE_WALK: { return &slIdleWalk[ 0 ]; } case SCHED_WAIT_TRIGGER: { return &slIdleTrigger[ 0 ]; } case SCHED_WAKE_ANGRY: { return &slWakeAngry[ 0 ]; } case SCHED_ALERT_FACE: { return &slAlertFace[ 0 ]; } case SCHED_ALERT_STAND: { return &slAlertStand[ 0 ]; } case SCHED_COMBAT_STAND: { return &slCombatStand[ 0 ]; } case SCHED_COMBAT_FACE: { return &slCombatFace[ 0 ]; } case SCHED_CHASE_ENEMY: { return &slChaseEnemy[ 0 ]; } case SCHED_CHASE_ENEMY_FAILED: { return &slFail[ 0 ]; } case SCHED_SMALL_FLINCH: { return &slSmallFlinch[ 0 ]; } case SCHED_ALERT_SMALL_FLINCH: { return &slAlertSmallFlinch[ 0 ]; } case SCHED_RELOAD: { return &slReload[ 0 ]; } case SCHED_ARM_WEAPON: { return &slArmWeapon[ 0 ]; } case SCHED_STANDOFF: { return &slStandoff[ 0 ]; } case SCHED_RANGE_ATTACK1: { return &slRangeAttack1[ 0 ]; } case SCHED_RANGE_ATTACK2: { return &slRangeAttack2[ 0 ]; } case SCHED_MELEE_ATTACK1: { return &slPrimaryMeleeAttack[ 0 ]; } case SCHED_MELEE_ATTACK2: { return &slSecondaryMeleeAttack[ 0 ]; } case SCHED_SPECIAL_ATTACK1: { return &slSpecialAttack1[ 0 ]; } case SCHED_SPECIAL_ATTACK2: { return &slSpecialAttack2[ 0 ]; } case SCHED_TAKE_COVER_FROM_BEST_SOUND: { return &slTakeCoverFromBestSound[ 0 ]; } case SCHED_TAKE_COVER_FROM_ENEMY: { return &slTakeCoverFromEnemy[ 0 ]; } case SCHED_COWER: { return &slCower[ 0 ]; } case SCHED_AMBUSH: { return &slAmbush[ 0 ]; } case SCHED_BARNACLE_VICTIM_GRAB: { return &slBarnacleVictimGrab[ 0 ]; } case SCHED_BARNACLE_VICTIM_CHOMP: { return &slBarnacleVictimChomp[ 0 ]; } case SCHED_INVESTIGATE_SOUND: { return &slInvestigateSound[ 0 ]; } case SCHED_DIE: { return &slDie[ 0 ]; } case SCHED_TAKE_COVER_FROM_ORIGIN: { return &slTakeCoverFromOrigin[ 0 ]; } case SCHED_VICTORY_DANCE: { return &slVictoryDance[ 0 ]; } case SCHED_FAIL: { return slFail; } default: { ALERT ( at_console, "GetScheduleOfType()\nNo CASE for Schedule Type %d!\n", Type ); return &slIdleStand[ 0 ]; break; } } return NULL; }