#include "monster_annie" #include "monster_bear" #include "monster_bigminer" #include "monster_chicken" #include "monster_cowboy" #include "monster_crispen" #include "monster_dyndave" #include "monster_eagle" // Precache #include "monster_horse" #include "monster_hoss" #include "monster_kaiewi" #include "monster_masala" #include "monster_mexbandit" #include "monster_nagatow" #include "monster_puma" #include "monster_ramone" #include "monster_smallminer" #include "monster_snake" #include "monster_tied_colonel" #include "monster_townmex" #include "monster_townwes" void HLWanted_MonstersRegister() { @g_TalkMonster = @CTalkMonster(); HLWanted_Annie::Register(); HLWanted_Bear::Register(); HLWanted_BigMiner::Register(); HLWanted_Chicken::Register(); HLWanted_ColonelTied::Register(); HLWanted_Cowboy::Register(); HLWanted_Crispen::Register(); HLWanted_DynDave::Register(); HLWanted_Eagle::Precache(); HLWanted_Horse::Register(); HLWanted_Hoss::Register(); HLWanted_Kaiewi::Register(); HLWanted_Masala::Register(); HLWanted_MexBandit::Register(); HLWanted_Nagatow::Register(); HLWanted_Ramone::Register(); HLWanted_Puma::Register(); HLWanted_SmallMiner::Register(); HLWanted_Snake::Register(); HLWanted_TownMex::Register(); HLWanted_TownWes::Register(); } // Make ally npcs that restart the level when killed unkillable - Outerbeast void AddNpcGodmode() { array P_ENTITIES( g_EngineFuncs.NumberOfEntities() ); if( g_EntityFuncs.Instance( 0 ).FindMonstersInWorld( @P_ENTITIES, FL_MONSTER ) < 1 ) return; for( uint i = 0; i < P_ENTITIES.length(); i++ ) { if( P_ENTITIES[i] is null || !P_ENTITIES[i].IsMonster() || !P_ENTITIES[i].IsAlive() ) continue; CBaseMonster@ pMonster = P_ENTITIES[i].MyMonsterPointer(); // This guy is scripted to die, so don't add godmode here if( pMonster is null || pMonster.GetTargetname() == "poorbarn" ) continue; if( pMonster.m_iTriggerCondition == 4 && pMonster.m_iszTriggerTarget != "" ) { CBaseEntity@ pRestartEntity; while( ( @pRestartEntity = g_EntityFuncs.FindEntityByTargetname( pRestartEntity, pMonster.m_iszTriggerTarget ) ) !is null ) { if( pRestartEntity is null || pRestartEntity.GetClassname() != "player_loadsaved" ) continue; pMonster.pev.takedamage = DAMAGE_NO; break; } } } P_ENTITIES.resize( 0 ); } // NOT USED /* void NpcHealthBalance(CBaseEntity@ pActivator, CBaseEntity@ pCaller, USE_TYPE useType, float flValue) { array P_ENTITIES( g_EngineFuncs.NumberOfEntities() ); if( g_EntityFuncs.Instance( 0 ).FindMonstersInWorld( @P_ENTITIES, FL_MONSTER ) <= 0 ) return; for( uint i = 0; i < P_ENTITIES.length(); i++ ) { if( P_ENTITIES[i] is null || P_ENTITIES[i].pev.deadflag != DEAD_NO || P_ENTITIES[i].GetClassname() != "monster_bear" ) continue; P_ENTITIES[i].pev.health = CalcNewHealth( int( P_ENTITIES[i].pev.health ), 500 ); } } // Apply full health for every even player count and half on odd player count int CalcNewHealth(int iBaseHealth, int iPerPlayerInc, bool bEvenOddNum = false) { int iNumPlayers = 0, iCalcNewHealth = 0; for( int iPlayer = 1; iPlayer <= g_Engine.maxClients; ++iPlayer ) { CBasePlayer@ pPlayer = g_PlayerFuncs.FindPlayerByIndex( iPlayer ); if( pPlayer is null || !pPlayer.IsConnected() ) continue; if( g_SurvivalMode.MapSupportEnabled() && g_SurvivalMode.IsActive() ) { if( !pPlayer.IsAlive() ) continue; } if( ++iNumPlayers == 1 ) continue; if( bEvenOddNum ) iCalcNewHealth += iNumPlayers % 2 == 0 ? iPerPlayerInc : iPerPlayerInc / 2; else iCalcNewHealth += iPerPlayerInc; } return iBaseHealth + iCalcNewHealth; } */ CTalkMonster@ g_TalkMonster; final class CTalkMonster { int g_fMinerQuestion = 0; // true if an idle miner asked a question. Cleared when someone answers. float g_talkWaitTime = g_Engine.time; } class CBaseCustomMonster : ScriptBaseMonsterEntity { int SF_MONSTER_GAG = 2; int SF_MONSTER_FADECORPSE = 512; Vector VecCheckToss( edict_t@& in pEdict, const Vector& in vecSpot1, Vector vecSpot2, const float flGravityAdj = 1.0 ) { TraceResult tr; Vector vecMidPoint;// halfway point between Spot1 and Spot2 Vector vecApex;// highest point Vector vecScale; Vector vecGrenadeVel; Vector vecTemp; //float flGravity = g_EngineFuncs.CVarGetFloat( "sv_gravity" ) * flGravityAdj; float flGravity = 800.0f * flGravityAdj; if( vecSpot2.z - vecSpot1.z > 500 ) return g_vecZero; // to high, fail g_EngineFuncs.MakeVectors(pev.angles); // toss a little bit to the left or right, not right down on the enemy's bean (head). vecSpot2 = vecSpot2 + g_Engine.v_right * ( Math.RandomFloat(-8,8) + Math.RandomFloat(-16,16) ); vecSpot2 = vecSpot2 + g_Engine.v_forward * ( Math.RandomFloat(-8,8) + Math.RandomFloat(-16,16) ); // calculate the midpoint and apex of the 'triangle' // UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT // How much time does it take to get there? // get a rough idea of how high it can be thrown vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; g_Utility.TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,500), ignore_monsters, self.edict(), tr); vecMidPoint = tr.vecEndPos; // (subtract 15 so the grenade doesn't hit the ceiling) vecMidPoint.z -= 15; if( vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z ) return g_vecZero; // to not enough space, fail // How high should the grenade travel to reach the apex float distance1 = (vecMidPoint.z - vecSpot1.z); float distance2 = (vecMidPoint.z - vecSpot2.z); // How long will it take for the grenade to travel this distance float time1 = sqrt( distance1 / (0.5 * flGravity) ); float time2 = sqrt( distance2 / (0.5 * flGravity) ); if( time1 < 0.1 ) return g_vecZero; // too close // how hard to throw sideways to get there in time. vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2); // how hard upwards to reach the apex at the right time. vecGrenadeVel.z = flGravity * time1; // find the apex vecApex = vecSpot1 + vecGrenadeVel * time1; vecApex.z = vecMidPoint.z; g_Utility.TraceLine(vecSpot1, vecApex, dont_ignore_monsters, self.edict(), tr); if (tr.flFraction != 1.0) return g_vecZero; // fail! // UNDONE: either ignore monsters or change it to not care if we hit our enemy g_Utility.TraceLine(vecSpot2, vecApex, ignore_monsters, self.edict(), tr); if (tr.flFraction != 1.0) return g_vecZero; // fail! return vecGrenadeVel; } Vector VecCheckThrow( edict_t@& in pEdict, const Vector& in vecSpot1, Vector vecSpot2, const float flSpeed, const float flGravityAdj = 1.0 ) { //float flGravity = g_EngineFuncs.CVarGetFloat( "sv_gravity" ) * flGravityAdj; float flGravity = 800.0f * flGravityAdj; Vector vecGrenadeVel = (vecSpot2 - vecSpot1); // throw at a constant time float time = vecGrenadeVel.Length( ) / flSpeed; vecGrenadeVel = vecGrenadeVel * (1.0 / time); // adjust upward toss to compensate for gravity loss vecGrenadeVel.z += flGravity * time * 0.5; Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5); TraceResult tr; g_Utility.TraceLine(vecSpot1, vecApex, dont_ignore_monsters, pEdict, tr); if (tr.flFraction != 1.0) return g_vecZero; // fail! g_Utility.TraceLine(vecSpot2, vecApex, ignore_monsters, pEdict, tr); if (tr.flFraction != 1.0) return g_vecZero; // fail! return vecGrenadeVel; } }