//========================================================= // StartMonster //========================================================= void CSquadMonster :: StartMonster( void ) { CBaseMonster :: StartMonster(); if ( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() ) { if ( HasNetName() ) { // if I have a groupname, I can only recruit if I'm flagged as leader if ( !GetSpawnFlags().Any( SF_SQUADMONSTER_LEADER ) ) { return; } } // try to form squads now. int iSquadSize = SquadRecruit( 1024, 4 ); if ( iSquadSize ) { ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, GetClassname() ); } if ( IsLeader() && ClassnameIs( "monster_human_grunt" ) ) { SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack SetSkin( 0 ); } } }
// // The door has reached the "down" position. Back to quiescence. // void CBaseDoor::DoorHitBottom( void ) { if( !GetSpawnFlags().Any( SF_DOOR_SILENT ) ) { STOP_SOUND( this, CHAN_STATIC, ( char* ) STRING( pev->noiseMoving ) ); EMIT_SOUND( this, CHAN_STATIC, ( char* ) STRING( pev->noiseArrived ), 1, ATTN_NORM ); } ASSERT( m_toggle_state == TS_GOING_DOWN ); m_toggle_state = TS_AT_BOTTOM; // Re-instate touch method, cycle is complete if( GetSpawnFlags().Any( SF_DOOR_USE_ONLY ) ) {// use only door SetTouch( NULL ); } else // touchable door SetTouch( &CBaseDoor::DoorTouch ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target if( HasNetName() && !GetSpawnFlags().Any( SF_DOOR_START_OPEN ) ) FireTargets( GetNetName(), m_hActivator, this, USE_TOGGLE, 0 ); }
// // The door has reached the "up" position. Either go back down, or wait for another activation. // void CBaseDoor::DoorHitTop( void ) { if( !GetSpawnFlags().Any( SF_DOOR_SILENT ) ) { STOP_SOUND( this, CHAN_STATIC, ( char* ) STRING( pev->noiseMoving ) ); EMIT_SOUND( this, CHAN_STATIC, ( char* ) STRING( pev->noiseArrived ), 1, ATTN_NORM ); } ASSERT( m_toggle_state == TS_GOING_UP ); m_toggle_state = TS_AT_TOP; // toggle-doors don't come down automatically, they wait for refire. if( GetSpawnFlags().Any( SF_DOOR_NO_AUTO_RETURN ) ) { // Re-instate touch method, movement is complete if( !GetSpawnFlags().Any( SF_DOOR_USE_ONLY ) ) SetTouch( &CBaseDoor::DoorTouch ); } else { // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open SetNextThink( GetLastThink() + m_flWait ); SetThink( &CBaseDoor::DoorGoDown ); if( m_flWait == -1 ) { SetNextThink( -1 ); } } // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target if( HasNetName() && GetSpawnFlags().Any( SF_DOOR_START_OPEN ) ) FireTargets( GetNetName(), m_hActivator, this, USE_TOGGLE, 0 ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished }
//========================================================= // // SquadRecruit(), get some monsters of my classification and // link them as a group. returns the group size // //========================================================= int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) { int squadCount; EntityClassification_t iMyClass = Classify();// cache this monster's class // Don't recruit if I'm already in a group if ( InSquad() ) return 0; if ( maxMembers < 2 ) return 0; // I am my own leader m_hSquadLeader = this; squadCount = 1; CBaseEntity *pEntity = NULL; if ( HasNetName() ) { // I have a netname, so unconditionally recruit everyone else with that name. pEntity = UTIL_FindEntityByString( pEntity, "netname", GetNetName() ); while ( pEntity ) { CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer(); if ( pRecruit ) { if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && pRecruit != this ) { // minimum protection here against user error.in worldcraft. if (!SquadAdd( pRecruit )) break; squadCount++; } } pEntity = UTIL_FindEntityByString( pEntity, "netname", GetNetName() ); } } else { while ((pEntity = UTIL_FindEntityInSphere( pEntity, GetAbsOrigin(), searchRadius )) != NULL) { CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer( ); if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) { // Can we recruit this guy? if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && ( (iMyClass != EntityClassifications().GetClassificationId( classify::ALIEN_MONSTER )) || FStrEq( GetClassname(), pRecruit->GetClassname() )) && !pRecruit->HasNetName() ) { TraceResult tr; UTIL_TraceLine( GetAbsOrigin() + GetViewOffset(), pRecruit->GetAbsOrigin() + GetViewOffset(), ignore_monsters, pRecruit->edict(), &tr );// try to hit recruit with a traceline. if ( tr.flFraction == 1.0 ) { if (!SquadAdd( pRecruit )) break; squadCount++; } } } } } // no single member squads if (squadCount == 1) { m_hSquadLeader = NULL; } return squadCount; }
//========================================================= // MakeMonster- this is the code that drops the monster //========================================================= void CMonsterMaker::MakeMonster( void ) { if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) {// not allowed to make a new one yet. Too many live ones out right now. return; } if ( !m_flGround ) { // set altitude. Now that I'm activated, any breakables, etc should be out from under me. TraceResult tr; UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr ); m_flGround = tr.vecEndPos.z; } Vector mins = GetAbsOrigin() - Vector( 34, 34, 0 ); Vector maxs = GetAbsOrigin() + Vector( 34, 34, 0 ); maxs.z = GetAbsOrigin().z; mins.z = m_flGround; CBaseEntity *pList[2]; int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER ); if ( count ) { // don't build a stack of monsters! return; } CBaseEntity* pEntity = CBaseEntity::Create( STRING( m_iszMonsterClassname ), GetAbsOrigin(), GetAbsAngles(), nullptr, false ); if( !pEntity ) { ALERT( at_console, "NULL Ent in MonsterMaker!\n" ); return; } // If I have a target, fire! if ( HasTarget() ) { // delay already overloaded for this entity, so can't call SUB_UseTargets() FireTargets( GetTarget(), this, this, USE_TOGGLE, 0 ); } pEntity->SetAbsOrigin( GetAbsOrigin() ); pEntity->SetAbsAngles( GetAbsAngles() ); pEntity->GetSpawnFlags() |= SF_MONSTER_FALL_TO_GROUND; // Children hit monsterclip brushes if ( GetSpawnFlags().Any(SF_MONSTERMAKER_MONSTERCLIP ) ) pEntity->GetSpawnFlags() |= SF_MONSTER_HITMONSTERCLIP; DispatchSpawn( pEntity->edict() ); pEntity->SetOwner( this ); if ( HasNetName() ) { // if I have a netname (overloaded), give the child monster that name as a targetname pEntity->SetTargetname( GetNetName() ); } m_cLiveChildren++;// count this monster m_cNumMonsters--; if ( m_cNumMonsters == 0 ) { // Disable this forever. Don't kill it because it still gets death notices SetThink( NULL ); SetUse( NULL ); } }