//========================================================= // RunAI //========================================================= void CBaseMonster :: RunAI ( void ) { // to test model's eye height //UTIL_ParticleEffect ( pev->origin + pev->view_ofs, g_vecZero, 255, 10 ); // IDLE sound permitted in ALERT state is because monsters were silent in ALERT state. Only play IDLE sound in IDLE state // once we have sounds for that state. if ( ( m_MonsterState == MONSTERSTATE_IDLE || m_MonsterState == MONSTERSTATE_ALERT ) && RANDOM_LONG(0,99) == 0 && !(pev->flags & SF_MONSTER_GAG) ) { IdleSound(); } if ( m_MonsterState != MONSTERSTATE_NONE && m_MonsterState != MONSTERSTATE_PRONE && m_MonsterState != MONSTERSTATE_DEAD )// don't bother with this crap if monster is prone. { // collect some sensory Condition information. // don't let monsters outside of the player's PVS act up, or most of the interesting // things will happen before the player gets there! // UPDATE: We now let COMBAT state monsters think and act fully outside of player PVS. This allows the player to leave // an area where monsters are fighting, and the fight will continue. if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) ) { Look( m_flDistLook ); Listen();// check for audible sounds. // now filter conditions. ClearConditions( IgnoreConditions() ); GetEnemy(); } // do these calculations if monster has an enemy. if ( m_hEnemy != NULL ) { CheckEnemy( m_hEnemy ); } CheckAmmo(); } FCheckAITrigger(); PrescheduleThink(); MaintainSchedule(); // if the monster didn't use these conditions during the above call to MaintainSchedule() or CheckAITrigger() // we throw them out cause we don't want them sitting around through the lifespan of a schedule // that doesn't use them. m_afConditions &= ~( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ); }
void CBaseMonster::CallGibMonster() { BOOL fade = FALSE; if (HasHumanGibs()) { if (CVAR_GET_FLOAT("violence_hgibs") == 0) fade = TRUE; } else if (HasAlienGibs()) { if (CVAR_GET_FLOAT("violence_agibs") == 0) fade = TRUE; } // do something with the body. while monster blows up pev->solid = SOLID_NOT; pev->takedamage = DAMAGE_NO; if (fade) { FadeMonster(); } else { // make the model invisible. pev->effects = EF_NODRAW; GibMonster(); } pev->deadflag = DEAD_DEAD; FCheckAITrigger(); // don't let the status bar glitch for players.with <0 health. if (pev->health < -99.0f) { pev->health = 0; } if (ShouldFadeOnDeath() && !fade) UTIL_Remove(this); }
BOOL CBaseMonster::CineCleanup() { CCineMonster *pOldCine = m_pCine; // am I linked to a cinematic? if(m_pCine) { // okay, reset me to what it thought I was before m_pCine->m_hTargetEnt = NULL; pev->movetype = m_pCine->m_saved_movetype; pev->solid = m_pCine->m_saved_solid; pev->effects = m_pCine->m_saved_effects; } else { // arg, punt pev->movetype = MOVETYPE_STEP; // this is evil pev->solid = SOLID_SLIDEBOX; } m_pCine = NULL; m_hTargetEnt = NULL; m_pGoalEnt = NULL; if(pev->deadflag == DEAD_DYING) { // last frame of death animation? pev->health = 0; pev->framerate = 0.0; pev->solid = SOLID_NOT; SetState(MONSTERSTATE_DEAD); pev->deadflag = DEAD_DEAD; UTIL_SetSize(pev, pev->mins, Vector(pev->maxs.x, pev->maxs.y, pev->mins.z + 2)); if(pOldCine && FBitSet(pOldCine->pev->spawnflags, SF_SCRIPT_LEAVECORPSE)) { SetUse(NULL); // BUGBUG -- This doesn't call Killed() SetThink(NULL); // This will probably break some stuff SetTouch(NULL); } else SUB_StartFadeOut(); // SetThink( SUB_DoNothing ); // This turns off animation & physics in case their origin ends up stuck in the world or something StopAnimation(); pev->movetype = MOVETYPE_NONE; pev->effects |= EF_NOINTERP; // Don't interpolate either, assume the corpse is positioned in its final resting place return FALSE; } // If we actually played a sequence if(pOldCine && pOldCine->m_iszPlay) { if(!(pOldCine->pev->spawnflags & SF_SCRIPT_NOSCRIPTMOVEMENT)) { // reset position Vector new_origin, new_angle; GetBonePosition(0, new_origin, new_angle); // Figure out how far they have moved // We can't really solve this problem because we can't query the movement of the origin relative // to the sequence. We can get the root bone's position as we do here, but there are // cases where the root bone is in a different relative position to the entity's origin // before/after the sequence plays. So we are stuck doing this: // !!!HACKHACK: Float the origin up and drop to floor because some sequences have // irregular motion that can't be properly accounted for. // UNDONE: THIS SHOULD ONLY HAPPEN IF WE ACTUALLY PLAYED THE SEQUENCE. Vector oldOrigin = pev->origin; // UNDONE: ugly hack. Don't move monster if they don't "seem" to move // this really needs to be done with the AX,AY,etc. flags, but that aren't consistantly // being set, so animations that really do move won't be caught. if((oldOrigin - new_origin).Length2D() < 8.0) new_origin = oldOrigin; pev->origin.x = new_origin.x; pev->origin.y = new_origin.y; pev->origin.z += 1; pev->flags |= FL_ONGROUND; int drop = DROP_TO_FLOOR(ENT(pev)); // Origin in solid? Set to org at the end of the sequence if(drop < 0) pev->origin = oldOrigin; else if(drop == 0) // Hanging in air? { pev->origin.z = new_origin.z; pev->flags &= ~FL_ONGROUND; } // else entity hit floor, leave there // pEntity->pev->origin.z = new_origin.z + 5.0; // damn, got to fix this UTIL_SetOrigin(pev, pev->origin); pev->effects |= EF_NOINTERP; } // We should have some animation to put these guys in, but for now it's idle. // Due to NOINTERP above, there won't be any blending between this anim & the sequence m_Activity = ACT_RESET; } // set them back into a normal state pev->enemy = NULL; if(pev->health > 0) m_IdealMonsterState = MONSTERSTATE_IDLE; // m_previousState; else { // Dropping out because he got killed // Can't call killed() no attacker and weirdness (late gibbing) may result m_IdealMonsterState = MONSTERSTATE_DEAD; SetConditions(bits_COND_LIGHT_DAMAGE); pev->deadflag = DEAD_DYING; FCheckAITrigger(); pev->deadflag = DEAD_NO; } // SetAnimation( m_MonsterState ); ClearBits(pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT); return TRUE; }
void CApache :: DyingThink( void ) { StudioFrameAdvance( ); pev->nextthink = gpGlobals->time + 0.1; pev->avelocity = pev->avelocity * 1.02; // still falling? if (m_flNextRocket > gpGlobals->time ) { // random explosions MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); WRITE_SHORT( g_sModelIndexFireball ); WRITE_BYTE( RANDOM_LONG(0,29) + 30 ); // scale * 10 WRITE_BYTE( 12 ); // framerate WRITE_BYTE( TE_EXPLFLAG_NONE ); MESSAGE_END(); // lots of smoke MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_SMOKE ); WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); WRITE_SHORT( g_sModelIndexSmoke ); WRITE_BYTE( 100 ); // scale * 10 WRITE_BYTE( 10 ); // framerate MESSAGE_END(); Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); WRITE_BYTE( TE_BREAKMODEL); // position WRITE_COORD( vecSpot.x ); WRITE_COORD( vecSpot.y ); WRITE_COORD( vecSpot.z ); // size WRITE_COORD( 400 ); WRITE_COORD( 400 ); WRITE_COORD( 132 ); // velocity WRITE_COORD( pev->velocity.x ); WRITE_COORD( pev->velocity.y ); WRITE_COORD( pev->velocity.z ); // randomization WRITE_BYTE( 50 ); // Model WRITE_SHORT( m_iBodyGibs ); //model id# // # of shards WRITE_BYTE( 4 ); // let client decide // duration WRITE_BYTE( 30 );// 3.0 seconds // flags WRITE_BYTE( BREAK_METAL ); MESSAGE_END(); // don't stop it we touch a entity pev->flags &= ~FL_ONGROUND; pev->nextthink = gpGlobals->time + 0.2; return; } else { Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; /* MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now WRITE_COORD( vecSpot.x ); WRITE_COORD( vecSpot.y ); WRITE_COORD( vecSpot.z + 300 ); WRITE_SHORT( g_sModelIndexFireball ); WRITE_BYTE( 250 ); // scale * 10 WRITE_BYTE( 8 ); // framerate MESSAGE_END(); */ // fireball MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); WRITE_BYTE( TE_SPRITE ); WRITE_COORD( vecSpot.x ); WRITE_COORD( vecSpot.y ); WRITE_COORD( vecSpot.z + 256 ); WRITE_SHORT( m_iExplode ); WRITE_BYTE( 120 ); // scale * 10 WRITE_BYTE( 255 ); // brightness MESSAGE_END(); // big smoke MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); WRITE_BYTE( TE_SMOKE ); WRITE_COORD( vecSpot.x ); WRITE_COORD( vecSpot.y ); WRITE_COORD( vecSpot.z + 512 ); WRITE_SHORT( g_sModelIndexSmoke ); WRITE_BYTE( 250 ); // scale * 10 WRITE_BYTE( 5 ); // framerate MESSAGE_END(); // blast circle MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_BEAMCYLINDER ); WRITE_COORD( pev->origin.x); WRITE_COORD( pev->origin.y); WRITE_COORD( pev->origin.z); WRITE_COORD( pev->origin.x); WRITE_COORD( pev->origin.y); WRITE_COORD( pev->origin.z + 2000 ); // reach damage radius over .2 seconds WRITE_SHORT( m_iSpriteTexture ); WRITE_BYTE( 0 ); // startframe WRITE_BYTE( 0 ); // framerate WRITE_BYTE( 4 ); // life WRITE_BYTE( 32 ); // width WRITE_BYTE( 0 ); // noise WRITE_BYTE( 255 ); // r, g, b WRITE_BYTE( 255 ); // r, g, b WRITE_BYTE( 192 ); // r, g, b WRITE_BYTE( 128 ); // brightness WRITE_BYTE( 0 ); // speed MESSAGE_END(); EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); RadiusDamage( pev->origin, pev, pev, 300, CLASS_NONE, DMG_BLAST ); if (/*!(pev->spawnflags & SF_NOWRECKAGE) && */(pev->flags & FL_ONGROUND)) { CBaseEntity *pWreckage = Create( "cycler_wreckage", pev->origin, pev->angles ); // SET_MODEL( ENT(pWreckage->pev), STRING(pev->model) ); UTIL_SetSize( pWreckage->pev, Vector( -200, -200, -128 ), Vector( 200, 200, -32 ) ); pWreckage->pev->frame = pev->frame; pWreckage->pev->sequence = pev->sequence; pWreckage->pev->framerate = 0; pWreckage->pev->dmgtime = gpGlobals->time + 5; } // gibs vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); WRITE_BYTE( TE_BREAKMODEL); // position WRITE_COORD( vecSpot.x ); WRITE_COORD( vecSpot.y ); WRITE_COORD( vecSpot.z + 64); // size WRITE_COORD( 400 ); WRITE_COORD( 400 ); WRITE_COORD( 128 ); // velocity WRITE_COORD( 0 ); WRITE_COORD( 0 ); WRITE_COORD( 200 ); // randomization WRITE_BYTE( 30 ); // Model WRITE_SHORT( m_iBodyGibs ); //model id# // # of shards WRITE_BYTE( 200 ); // duration WRITE_BYTE( 200 );// 10.0 seconds // flags WRITE_BYTE( BREAK_METAL ); MESSAGE_END(); //modif de jULIEN pev->deadflag = DEAD_DEAD; FCheckAITrigger(); //========= SetThink( SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; } }