CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) { CBaseEntity *pEntity; CBaseMonster *pGrunt; TraceResult tr; UTIL_TraceLine( vecSrc, vecSrc + Vector( 0, 0, -4096.0), dont_ignore_monsters, ENT(pev), &tr); if ( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP) return NULL; for (int i = 0; i < m_iUnits; i++) { if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive()) { if (m_hGrunt[i] != NULL && m_hGrunt[i]->pev->rendermode == kRenderNormal) { m_hGrunt[i]->SUB_StartFadeOut( ); } pEntity = Create( "monster_human_grunt", vecSrc, GetAbsAngles() ); pGrunt = pEntity->MyMonsterPointer( ); pGrunt->pev->movetype = MOVETYPE_FLY; pGrunt->SetAbsVelocity( Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) )); pGrunt->SetActivity( ACT_GLIDE ); CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); pBeam->PointEntInit( vecSrc + Vector(0,0,112), pGrunt->entindex() ); pBeam->SetFlags( BEAM_FSOLID ); pBeam->SetColor( 255, 255, 255 ); pBeam->SetThink( SUB_Remove ); pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->GetAbsVelocity().z + 0.5; // ALERT( at_console, "%d at %.0f %.0f %.0f\n", i, m_vecOrigin[i].x, m_vecOrigin[i].y, m_vecOrigin[i].z ); pGrunt->m_vecLastPosition = m_vecOrigin[i]; m_hGrunt[i] = pGrunt; return pGrunt; } } // ALERT( at_console, "none dead\n"); return NULL; }
// make the entity carry out the scripted sequence instructions, but without // destroying the monster's state. void CCineAI::PossessEntity( void ) { Schedule_t *pNewSchedule; CBaseEntity *pEntity = m_hTargetEnt; CBaseMonster *pTarget = NULL; if( pEntity ) pTarget = pEntity->MyMonsterPointer(); if( pTarget ) { if( !pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_AI ) ) { ALERT( at_aiconsole, "(AI)Can't possess entity %s\n", pTarget->GetClassname() ); return; } pTarget->m_hGoalEnt = this; pTarget->m_pCine = this; pTarget->m_hTargetEnt = this; m_saved_movetype = pTarget->GetMoveType(); m_saved_solid = pTarget->GetSolidType(); m_saved_effects = pTarget->GetEffects(); pTarget->GetEffects() |= GetEffects(); switch( m_fMoveTo ) { case 0: case 5: pTarget->m_scriptState = SCRIPT_WAIT; break; case 1: pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; break; case 2: pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; break; case 4: { // zap the monster instantly to the site of the script entity. pTarget->SetAbsOrigin( GetAbsOrigin() ); pTarget->SetIdealYaw( GetAbsAngles().y ); pTarget->SetAngularVelocity( g_vecZero ); pTarget->SetAbsVelocity( Vector( 0, 0, 0 ) ); pTarget->GetEffects() |= EF_NOINTERP; Vector vecAngles = pTarget->GetAbsAngles(); vecAngles.y = GetAbsAngles().y; pTarget->SetAbsAngles( vecAngles ); pTarget->m_scriptState = SCRIPT_WAIT; m_startTime = gpGlobals->time + 1E6; // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters pTarget->GetFlags().ClearFlags( FL_ONGROUND ); break; } default: ALERT( at_aiconsole, "aiscript: invalid Move To Position value!" ); break; } ALERT( at_aiconsole, "\"%s\" found and used\n", pTarget->GetTargetname() ); pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; /* if (m_iszIdle) { StartSequence( pTarget, m_iszIdle, false ); if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) { pTarget->SetFrameRate( 0 ); } } */ // Already in a scripted state? if( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) { pNewSchedule = pTarget->GetScheduleOfType( SCHED_AISCRIPT ); pTarget->ChangeSchedule( pNewSchedule ); } } }
void CController :: HandleAnimEvent( AnimEvent_t& event ) { switch( event.event ) { case CONTROLLER_AE_HEAD_OPEN: { Vector vecStart, angleGun; GetAttachment( 0, vecStart, angleGun ); MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment WRITE_COORD( vecStart.x ); // origin WRITE_COORD( vecStart.y ); WRITE_COORD( vecStart.z ); WRITE_COORD( 1 ); // radius WRITE_BYTE( 255 ); // R WRITE_BYTE( 192 ); // G WRITE_BYTE( 64 ); // B WRITE_BYTE( 20 ); // life * 10 WRITE_COORD( -32 ); // decay MESSAGE_END(); m_iBall[0] = 192; m_iBallTime[0] = gpGlobals->time + atoi( event.options ) / 15.0; m_iBall[1] = 255; m_iBallTime[1] = gpGlobals->time + atoi( event.options ) / 15.0; } break; case CONTROLLER_AE_BALL_SHOOT: { Vector vecStart, angleGun; GetAttachment( 0, vecStart, angleGun ); MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment WRITE_COORD( 0 ); // origin WRITE_COORD( 0 ); WRITE_COORD( 0 ); WRITE_COORD( 32 ); // radius WRITE_BYTE( 255 ); // R WRITE_BYTE( 192 ); // G WRITE_BYTE( 64 ); // B WRITE_BYTE( 10 ); // life * 10 WRITE_COORD( 32 ); // decay MESSAGE_END(); CBaseMonster *pBall = (CBaseMonster*)Create( "controller_head_ball", vecStart, GetAbsAngles(), edict() ); pBall->SetAbsVelocity( Vector( 0, 0, 32 ) ); pBall->m_hEnemy = m_hEnemy; m_iBall[0] = 0; m_iBall[1] = 0; } break; case CONTROLLER_AE_SMALL_SHOOT: { AttackSound( ); m_flShootTime = gpGlobals->time; m_flShootEnd = m_flShootTime + atoi( event.options ) / 15.0; } break; case CONTROLLER_AE_POWERUP_FULL: { m_iBall[0] = 255; m_iBallTime[0] = gpGlobals->time + atoi( event.options ) / 15.0; m_iBall[1] = 255; m_iBallTime[1] = gpGlobals->time + atoi( event.options ) / 15.0; } break; case CONTROLLER_AE_POWERUP_HALF: { m_iBall[0] = 192; m_iBallTime[0] = gpGlobals->time + atoi( event.options ) / 15.0; m_iBall[1] = 192; m_iBallTime[1] = gpGlobals->time + atoi( event.options ) / 15.0; } break; default: CBaseMonster::HandleAnimEvent( event ); break; } }
void CController :: RunTask ( const Task_t& task ) { if (m_flShootEnd > gpGlobals->time) { Vector vecHand, vecAngle; GetAttachment( 2, vecHand, vecAngle ); while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) { Vector vecSrc = vecHand + GetAbsVelocity() * (m_flShootTime - gpGlobals->time); Vector vecDir; if (m_hEnemy != NULL) { if (HasConditions( bits_COND_SEE_ENEMY )) { m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->GetAbsVelocity() * 0.5; } else { m_vecEstVelocity = m_vecEstVelocity * 0.8; } vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( GetAbsOrigin() ), m_vecEstVelocity, gSkillData.GetControllerSpeedBall() ); float delta = 0.03490; // +-2 degree vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.GetControllerSpeedBall(); vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, GetAbsAngles(), edict() ); pBall->SetAbsVelocity( vecDir ); } m_flShootTime += 0.2; } if (m_flShootTime > m_flShootEnd) { m_iBall[0] = 64; m_iBallTime[0] = m_flShootEnd; m_iBall[1] = 64; m_iBallTime[1] = m_flShootEnd; m_fInCombat = false; } } switch ( task.iTask ) { case TASK_WAIT_FOR_MOVEMENT: case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: case TASK_WAIT_PVS: MakeIdealYaw( m_vecEnemyLKP ); ChangeYaw( GetYawSpeed() ); if (m_fSequenceFinished) { m_fInCombat = false; } CSquadMonster :: RunTask ( task ); if (!m_fInCombat) { if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 )) { SetSequence( LookupActivity( ACT_RANGE_ATTACK1 ) ); SetFrame( 0 ); ResetSequenceInfo( ); m_fInCombat = true; } else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 )) { SetSequence( LookupActivity( ACT_RANGE_ATTACK2 ) ); SetFrame( 0 ); ResetSequenceInfo( ); m_fInCombat = true; } else { int iFloat = LookupFloat( ); if (m_fSequenceFinished || iFloat != GetSequence() ) { SetSequence( iFloat ); SetFrame( 0 ); ResetSequenceInfo( ); } } } break; default: CSquadMonster :: RunTask ( task ); break; } }
// make the entity enter a scripted sequence void CCineMonster::PossessEntity( void ) { CBaseEntity *pEntity = m_hTargetEnt; CBaseMonster *pTarget = NULL; if( pEntity ) pTarget = pEntity->MyMonsterPointer(); if( pTarget ) { // FindEntity() just checked this! #if 0 if( !pTarget->CanPlaySequence( FCanOverrideState() ) ) { ALERT( at_aiconsole, "Can't possess entity %s\n", pTarget->GetClassname() ); return; } #endif pTarget->m_hGoalEnt = this; pTarget->m_pCine = this; pTarget->m_hTargetEnt = this; m_saved_movetype = pTarget->GetMoveType(); m_saved_solid = pTarget->GetSolidType(); m_saved_effects = pTarget->GetEffects(); pTarget->GetEffects() |= GetEffects(); switch( m_fMoveTo ) { case 0: pTarget->m_scriptState = SCRIPT_WAIT; break; case 1: pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; DelayStart( true ); break; case 2: pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; DelayStart( true ); break; case 4: pTarget->SetAbsOrigin( GetAbsOrigin() ); pTarget->SetIdealYaw( GetAbsAngles().y ); pTarget->SetAngularVelocity( g_vecZero ); pTarget->SetAbsVelocity( Vector( 0, 0, 0 ) ); pTarget->GetEffects() |= EF_NOINTERP; Vector vecAngles = pTarget->GetAbsAngles(); vecAngles.y = GetAbsAngles().y; pTarget->SetAbsAngles( vecAngles ); pTarget->m_scriptState = SCRIPT_WAIT; m_startTime = gpGlobals->time + 1E6; // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters // pTarget->GetFlags().ClearFlags( FL_ONGROUND ); break; } // ALERT( at_aiconsole, "\"%s\" found and used (INT: %s)\n", pTarget->GetTargetname(), GetSpawnFlags().Any( SF_SCRIPT_NOINTERRUPT ) ?"No":"Yes" ); pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; if( m_iszIdle ) { StartSequence( pTarget, m_iszIdle, false ); if( FStrEq( STRING( m_iszIdle ), STRING( m_iszPlay ) ) ) { pTarget->SetFrameRate( 0 ); } } } }