From d20abd0465de0341b2234c2bf2fd5ed55a6fbe0c Mon Sep 17 00:00:00 2001 From: Night Owl Date: Fri, 7 Dec 2018 16:59:27 +0500 Subject: [PATCH] Remove useless files. --- dlls/AI_BaseNPC_Schedule.cpp | 1514 -------------------- dlls/Wxdebug.cpp | 395 ------ dlls/aflock.cpp | 918 ------------ dlls/agrunt.cpp | 1178 ---------------- dlls/apache.cpp | 1027 -------------- dlls/barnacle.cpp | 459 ------ dlls/barney.cpp | 826 ----------- dlls/bigmomma.cpp | 1186 ---------------- dlls/bloater.cpp | 212 --- dlls/bullsquid.cpp | 1265 ----------------- dlls/controller.cpp | 1378 ------------------ dlls/crossbow.cpp | 561 -------- dlls/egon.cpp | 544 ------- dlls/flyingmonster.cpp | 268 ---- dlls/flyingmonster.h | 49 - dlls/gargantua.cpp | 1332 ------------------ dlls/gauss.cpp | 633 --------- dlls/genericmonster.cpp | 139 -- dlls/glock.cpp | 261 ---- dlls/gman.cpp | 236 ---- dlls/hassassin.cpp | 992 ------------- dlls/headcrab.cpp | 552 -------- dlls/hgrunt.cpp | 2487 --------------------------------- dlls/hornet.cpp | 435 ------ dlls/hornetgun.cpp | 285 ---- dlls/houndeye.cpp | 1295 ----------------- dlls/ichthyosaur.cpp | 1093 --------------- dlls/islave.cpp | 842 ----------- dlls/leech.cpp | 685 --------- dlls/maprules.cpp | 875 ------------ dlls/maprules.h | 19 - dlls/monstermaker.cpp | 289 ---- dlls/mp5.cpp | 358 ----- dlls/nihilanth.cpp | 1818 ------------------------ dlls/osprey.cpp | 776 ---------- dlls/python.cpp | 309 ---- dlls/rat.cpp | 99 -- dlls/roach.cpp | 459 ------ dlls/satchel.cpp | 480 ------- dlls/scientist.cpp | 1431 ------------------- dlls/shotgun.cpp | 392 ------ dlls/singleplay_gamerules.cpp | 326 ----- dlls/squeakgrenade.cpp | 585 -------- dlls/stats.cpp | 151 -- dlls/tentacle.cpp | 1023 -------------- dlls/tripmine.cpp | 518 ------- dlls/wxdebug.h | 137 -- dlls/zombie.cpp | 338 ----- 48 files changed, 33430 deletions(-) delete mode 100644 dlls/AI_BaseNPC_Schedule.cpp delete mode 100644 dlls/Wxdebug.cpp delete mode 100644 dlls/aflock.cpp delete mode 100644 dlls/agrunt.cpp delete mode 100644 dlls/apache.cpp delete mode 100644 dlls/barnacle.cpp delete mode 100644 dlls/barney.cpp delete mode 100644 dlls/bigmomma.cpp delete mode 100644 dlls/bloater.cpp delete mode 100644 dlls/bullsquid.cpp delete mode 100644 dlls/controller.cpp delete mode 100644 dlls/crossbow.cpp delete mode 100644 dlls/egon.cpp delete mode 100644 dlls/flyingmonster.cpp delete mode 100644 dlls/flyingmonster.h delete mode 100644 dlls/gargantua.cpp delete mode 100644 dlls/gauss.cpp delete mode 100644 dlls/genericmonster.cpp delete mode 100644 dlls/glock.cpp delete mode 100644 dlls/gman.cpp delete mode 100644 dlls/hassassin.cpp delete mode 100644 dlls/headcrab.cpp delete mode 100644 dlls/hgrunt.cpp delete mode 100644 dlls/hornet.cpp delete mode 100644 dlls/hornetgun.cpp delete mode 100644 dlls/houndeye.cpp delete mode 100644 dlls/ichthyosaur.cpp delete mode 100644 dlls/islave.cpp delete mode 100644 dlls/leech.cpp delete mode 100644 dlls/maprules.cpp delete mode 100644 dlls/maprules.h delete mode 100644 dlls/monstermaker.cpp delete mode 100644 dlls/mp5.cpp delete mode 100644 dlls/nihilanth.cpp delete mode 100644 dlls/osprey.cpp delete mode 100644 dlls/python.cpp delete mode 100644 dlls/rat.cpp delete mode 100644 dlls/roach.cpp delete mode 100644 dlls/satchel.cpp delete mode 100644 dlls/scientist.cpp delete mode 100644 dlls/shotgun.cpp delete mode 100644 dlls/singleplay_gamerules.cpp delete mode 100644 dlls/squeakgrenade.cpp delete mode 100644 dlls/stats.cpp delete mode 100644 dlls/tentacle.cpp delete mode 100644 dlls/tripmine.cpp delete mode 100644 dlls/wxdebug.h delete mode 100644 dlls/zombie.cpp diff --git a/dlls/AI_BaseNPC_Schedule.cpp b/dlls/AI_BaseNPC_Schedule.cpp deleted file mode 100644 index 468bb358..00000000 --- a/dlls/AI_BaseNPC_Schedule.cpp +++ /dev/null @@ -1,1514 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// schedule.cpp - functions and data pertaining to the -// monsters' AI scheduling system. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "animation.h" -#include "scripted.h" -#include "nodes.h" -#include "defaultai.h" -#include "soundent.h" - -extern CGraph WorldGraph; - -//========================================================= -// FHaveSchedule - Returns TRUE if monster's m_pSchedule -// is anything other than NULL. -//========================================================= -BOOL CBaseMonster :: FHaveSchedule( void ) -{ - if ( m_pSchedule == NULL ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -// ClearSchedule - blanks out the caller's schedule pointer -// and index. -//========================================================= -void CBaseMonster :: ClearSchedule( void ) -{ - m_iTaskStatus = TASKSTATUS_NEW; - m_pSchedule = NULL; - m_iScheduleIndex = 0; -} - -//========================================================= -// FScheduleDone - Returns TRUE if the caller is on the -// last task in the schedule -//========================================================= -BOOL CBaseMonster :: FScheduleDone ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - if ( m_iScheduleIndex == m_pSchedule->cTasks ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// ChangeSchedule - replaces the monster's schedule pointer -// with the passed pointer, and sets the ScheduleIndex back -// to 0 -//========================================================= -void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) -{ - ASSERT( pNewSchedule != NULL ); - - m_pSchedule = pNewSchedule; - m_iScheduleIndex = 0; - m_iTaskStatus = TASKSTATUS_NEW; - m_afConditions = 0;// clear all of the conditions - m_failSchedule = SCHED_NONE; - - if ( m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND && !(m_pSchedule->iSoundMask) ) - { - ALERT ( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); - } - else if ( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) - { - ALERT ( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); - } - -#if _DEBUG - if ( !ScheduleFromName( pNewSchedule->pName ) ) - { - ALERT( at_console, "Schedule %s not in table!!!\n", pNewSchedule->pName ); - } -#endif - -// this is very useful code if you can isolate a test case in a level with a single monster. It will notify -// you of every schedule selection the monster makes. -#if 0 - if ( FClassnameIs( pev, "monster_human_grunt" ) ) - { - Task_t *pTask = GetTask(); - - if ( pTask ) - { - const char *pName = NULL; - - if ( m_pSchedule ) - { - pName = m_pSchedule->pName; - } - else - { - pName = "No Schedule"; - } - - if ( !pName ) - { - pName = "Unknown"; - } - - ALERT( at_aiconsole, "%s: picked schedule %s\n", STRING( pev->classname ), pName ); - } - } -#endif// 0 - -} - -//========================================================= -// NextScheduledTask - increments the ScheduleIndex -//========================================================= -void CBaseMonster :: NextScheduledTask ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - m_iTaskStatus = TASKSTATUS_NEW; - m_iScheduleIndex++; - - if ( FScheduleDone() ) - { - // just completed last task in schedule, so make it invalid by clearing it. - SetConditions( bits_COND_SCHEDULE_DONE ); - //ClearSchedule(); - } -} - -//========================================================= -// IScheduleFlags - returns an integer with all Conditions -// bits that are currently set and also set in the current -// schedule's Interrupt mask. -//========================================================= -int CBaseMonster :: IScheduleFlags ( void ) -{ - if( !m_pSchedule ) - { - return 0; - } - - // strip off all bits excepts the ones capable of breaking this schedule. - return m_afConditions & m_pSchedule->iInterruptMask; -} - -//========================================================= -// FScheduleValid - returns TRUE as long as the current -// schedule is still the proper schedule to be executing, -// taking into account all conditions -//========================================================= -BOOL CBaseMonster :: FScheduleValid ( void ) -{ - if ( m_pSchedule == NULL ) - { - // schedule is empty, and therefore not valid. - return FALSE; - } - - if ( HasConditions( m_pSchedule->iInterruptMask | bits_COND_SCHEDULE_DONE | bits_COND_TASK_FAILED ) ) - { -#ifdef DEBUG - if ( HasConditions ( bits_COND_TASK_FAILED ) && m_failSchedule == SCHED_NONE ) - { - // fail! Send a visual indicator. - ALERT ( at_aiconsole, "Schedule: %s Failed\n", m_pSchedule->pName ); - - Vector tmp = pev->origin; - tmp.z = pev->absmax.z + 16; - UTIL_Sparks( tmp ); - } -#endif // DEBUG - - // some condition has interrupted the schedule, or the schedule is done - return FALSE; - } - - return TRUE; -} - -//========================================================= -// MaintainSchedule - does all the per-think schedule maintenance. -// ensures that the monster leaves this function with a valid -// schedule! -//========================================================= -void CBaseMonster :: MaintainSchedule ( void ) -{ - Schedule_t *pNewSchedule; - int i; - - // UNDONE: Tune/fix this 10... This is just here so infinite loops are impossible - for ( i = 0; i < 10; i++ ) - { - if ( m_pSchedule != NULL && TaskIsComplete() ) - { - NextScheduledTask(); - } - - // validate existing schedule - if ( !FScheduleValid() || m_MonsterState != m_IdealMonsterState ) - { - // if we come into this block of code, the schedule is going to have to be changed. - // if the previous schedule was interrupted by a condition, GetIdealState will be - // called. Else, a schedule finished normally. - - // Notify the monster that his schedule is changing - ScheduleChange(); - - // Call GetIdealState if we're not dead and one or more of the following... - // - in COMBAT state with no enemy (it died?) - // - conditions bits (excluding SCHEDULE_DONE) indicate interruption, - // - schedule is done but schedule indicates it wants GetIdealState called - // after successful completion (by setting bits_COND_SCHEDULE_DONE in iInterruptMask) - // DEAD & SCRIPT are not suggestions, they are commands! - if ( m_IdealMonsterState != MONSTERSTATE_DEAD && - (m_IdealMonsterState != MONSTERSTATE_SCRIPT || m_IdealMonsterState == m_MonsterState) ) - { - if ( (m_afConditions && !HasConditions(bits_COND_SCHEDULE_DONE)) || - (m_pSchedule && (m_pSchedule->iInterruptMask & bits_COND_SCHEDULE_DONE)) || - ((m_MonsterState == MONSTERSTATE_COMBAT) && (m_hEnemy == NULL)) ) - { - GetIdealState(); - } - } - if ( HasConditions( bits_COND_TASK_FAILED ) && m_MonsterState == m_IdealMonsterState ) - { - if ( m_failSchedule != SCHED_NONE ) - pNewSchedule = GetScheduleOfType( m_failSchedule ); - else - pNewSchedule = GetScheduleOfType( SCHED_FAIL ); - // schedule was invalid because the current task failed to start or complete - ALERT ( at_aiconsole, "Schedule Failed at %d!\n", m_iScheduleIndex ); - ChangeSchedule( pNewSchedule ); - } - else - { - SetState( m_IdealMonsterState ); - if ( m_MonsterState == MONSTERSTATE_SCRIPT || m_MonsterState == MONSTERSTATE_DEAD ) - pNewSchedule = CBaseMonster::GetSchedule(); - else - pNewSchedule = GetSchedule(); - ChangeSchedule( pNewSchedule ); - } - } - - if ( m_iTaskStatus == TASKSTATUS_NEW ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - TaskBegin(); - StartTask( pTask ); - } - - // UNDONE: Twice?!!! - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } - - if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) - break; - } - - if ( TaskIsRunning() ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - RunTask( pTask ); - } - - // UNDONE: We have to do this so that we have an animation set to blend to if RunTask changes the animation - // RunTask() will always change animations at the end of a script! - // Don't do this twice - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } -} - -//========================================================= -// RunTask -//========================================================= -void CBaseMonster :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - case TASK_TURN_LEFT: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - { - CBaseEntity *pTarget; - - if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) - pTarget = m_hTargetEnt; - else - pTarget = m_hEnemy; - if ( pTarget ) - { - pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); - ChangeYaw( pev->yaw_speed ); - } - if ( m_fSequenceFinished ) - TaskComplete(); - } - break; - - case TASK_PLAY_SEQUENCE: - case TASK_PLAY_ACTIVE_IDLE: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - - - case TASK_FACE_ENEMY: - { - MakeIdealYaw( m_vecEnemyLKP ); - - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_FACE_HINTNODE: - case TASK_FACE_LASTPOSITION: - case TASK_FACE_TARGET: - case TASK_FACE_IDEAL: - case TASK_FACE_ROUTE: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_PVS: - { - if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_RANDOM: - { - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - float distance; - - if ( m_hTargetEnt == NULL ) - TaskFail(); - else - { - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Re-evaluate when you think your finished, or the target has moved too far - if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - FRefreshRoute(); - } - - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( distance < pTask->flData ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - else if ( distance < 190 && m_movementActivity != ACT_WALK ) - m_movementActivity = ACT_WALK; - else if ( distance >= 270 && m_movementActivity != ACT_RUN ) - m_movementActivity = ACT_RUN; - } - - break; - } - case TASK_WAIT_FOR_MOVEMENT: - { - if (MovementIsComplete()) - { - TaskComplete(); - RouteClear(); // Stop moving - } - break; - } - case TASK_DIE: - { - if ( m_fSequenceFinished && pev->frame >= 255 ) - { - pev->deadflag = DEAD_DEAD; - - SetThink( NULL ); - StopAnimation(); - - if ( !BBoxFlat() ) - { - // a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will - // block the player on a slope or stairs, the corpse is made nonsolid. -// pev->solid = SOLID_NOT; - UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); - } - else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem - UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) ); - - if ( ShouldFadeOnDeath() ) - { - // this monster was created by a monstermaker... fade the corpse out. - SUB_StartFadeOut(); - } - else - { - // body is gonna be around for a while, so have it stink for a bit. - CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 ); - } - } - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RELOAD_NOTURN: - { - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_RANGE_ATTACK1: - case TASK_MELEE_ATTACK1: - case TASK_MELEE_ATTACK2: - case TASK_RANGE_ATTACK2: - case TASK_SPECIAL_ATTACK1: - case TASK_SPECIAL_ATTACK2: - case TASK_RELOAD: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_SMALL_FLINCH: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - } - break; - case TASK_WAIT_FOR_SCRIPT: - { - if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) - { - TaskComplete(); - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); - if ( m_fSequenceFinished ) - ClearSchedule(); - pev->framerate = 1.0; - //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); - } - break; - } - case TASK_PLAY_SCRIPT: - { - if (m_fSequenceFinished) - { - m_pCine->SequenceDone( this ); - } - break; - } - } -} - -//========================================================= -// SetTurnActivity - measures the difference between the way -// the monster is facing and determines whether or not to -// select one of the 180 turn animations. -//========================================================= -void CBaseMonster :: SetTurnActivity ( void ) -{ - float flYD; - flYD = FlYawDiff(); - - if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) - {// big right turn - m_IdealActivity = ACT_TURN_RIGHT; - } - else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) - {// big left turn - m_IdealActivity = ACT_TURN_LEFT; - } -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. -//========================================================= -void CBaseMonster :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_TURN_LEFT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_REMEMBER: - { - Remember ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FORGET: - { - Forget ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FIND_HINTNODE: - { - m_iHintNode = FindHintNode(); - - if ( m_iHintNode != NO_NODE ) - { - TaskComplete(); - } - else - { - TaskFail(); - } - break; - } - case TASK_STORE_LASTPOSITION: - { - m_vecLastPosition = pev->origin; - TaskComplete(); - break; - } - case TASK_CLEAR_LASTPOSITION: - { - m_vecLastPosition = g_vecZero; - TaskComplete(); - break; - } - case TASK_CLEAR_HINTNODE: - { - m_iHintNode = NO_NODE; - TaskComplete(); - break; - } - case TASK_STOP_MOVING: - { - if ( m_IdealActivity == m_movementActivity ) - { - m_IdealActivity = GetStoppedActivity(); - } - - RouteClear(); - TaskComplete(); - break; - } - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - case TASK_PLAY_SEQUENCE: - { - m_IdealActivity = ( Activity )( int )pTask->flData; - break; - } - case TASK_PLAY_ACTIVE_IDLE: - { - // monsters verify that they have a sequence for the node's activity BEFORE - // moving towards the node, so it's ok to just set the activity without checking here. - m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; - break; - } - case TASK_SET_SCHEDULE: - { - Schedule_t *pNewSchedule; - - pNewSchedule = GetScheduleOfType( (int)pTask->flData ); - - if ( pNewSchedule ) - { - ChangeSchedule( pNewSchedule ); - } - else - { - TaskFail(); - } - - break; - } - case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ENEMY: - { - entvars_t *pevCover; - - if ( m_hEnemy == NULL ) - { - // Find cover from self if no enemy available - pevCover = pev; -// TaskFail(); -// return; - } - else - pevCover = m_hEnemy->pev; - - if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ORIGIN: - { - if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no cover! - TaskFail(); - } - } - break; - case TASK_FIND_COVER_FROM_BEST_SOUND: - { - CSound *pBestSound; - - pBestSound = PBestSound(); - - ASSERT( pBestSound != NULL ); - /* - if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - */ - - if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. or no sound in list - TaskFail(); - } - break; - } - case TASK_FACE_HINTNODE: - { - pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; - SetTurnActivity(); - break; - } - - case TASK_FACE_LASTPOSITION: - MakeIdealYaw ( m_vecLastPosition ); - SetTurnActivity(); - break; - - case TASK_FACE_TARGET: - if ( m_hTargetEnt != NULL ) - { - MakeIdealYaw ( m_hTargetEnt->pev->origin ); - SetTurnActivity(); - } - else - TaskFail(); - break; - case TASK_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - SetTurnActivity(); - break; - } - case TASK_FACE_IDEAL: - { - SetTurnActivity(); - break; - } - case TASK_FACE_ROUTE: - { - if (FRouteClear()) - { - ALERT(at_aiconsole, "No route to face!\n"); - TaskFail(); - } - else - { - MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); - SetTurnActivity(); - } - break; - } - case TASK_WAIT_PVS: - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_FACE_ENEMY: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + pTask->flData; - break; - } - case TASK_WAIT_RANDOM: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK, 2 ) ) - TaskFail(); - } - break; - } - case TASK_RUN_TO_TARGET: - case TASK_WALK_TO_TARGET: - { - Activity newActivity; - - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - if ( pTask->iTask == TASK_WALK_TO_TARGET ) - newActivity = ACT_WALK; - else - newActivity = ACT_RUN; - // This monster can't do this! - if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) - TaskComplete(); - else - { - if ( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) - { - TaskFail(); - ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING(pev->classname) ); - RouteClear(); - } - } - } - TaskComplete(); - break; - } - case TASK_CLEAR_MOVE_WAIT: - { - m_flMoveWaitFinished = gpGlobals->time; - TaskComplete(); - break; - } - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1: - { - m_IdealActivity = ACT_MELEE_ATTACK1; - break; - } - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_MELEE_ATTACK2: - { - m_IdealActivity = ACT_MELEE_ATTACK2; - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_RANGE_ATTACK1: - { - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2: - { - m_IdealActivity = ACT_RANGE_ATTACK2; - break; - } - case TASK_RELOAD_NOTURN: - case TASK_RELOAD: - { - m_IdealActivity = ACT_RELOAD; - break; - } - case TASK_SPECIAL_ATTACK1: - { - m_IdealActivity = ACT_SPECIAL_ATTACK1; - break; - } - case TASK_SPECIAL_ATTACK2: - { - m_IdealActivity = ACT_SPECIAL_ATTACK2; - break; - } - case TASK_SET_ACTIVITY: - { - m_IdealActivity = (Activity)(int)pTask->flData; - TaskComplete(); - break; - } - case TASK_GET_PATH_TO_ENEMY_LKP: - { - if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY_CORPSE: - { - UTIL_MakeVectors( pev->angles ); - if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else - { - ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); - TaskFail(); - } - } - break; - case TASK_GET_PATH_TO_SPOT: - { - CBaseEntity *pPlayer = CBaseEntity::Instance( FIND_ENTITY_BY_CLASSNAME( NULL, "player" ) ); - if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - - case TASK_GET_PATH_TO_TARGET: - { - RouteClear(); - if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_HINTNODE:// for active idles! - { - if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_LASTPOSITION: - { - m_vecMoveGoal = m_vecLastPosition; - - if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_BESTSOUND: - { - CSound *pSound; - - pSound = PBestSound(); - - if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); - TaskFail(); - } - break; - } -case TASK_GET_PATH_TO_BESTSCENT: - { - CSound *pScent; - - pScent = PBestScent(); - - if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); - - TaskFail(); - } - break; - } - case TASK_RUN_PATH: - { - // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? - if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_RUN; - } - else - { - m_movementActivity = ACT_WALK; - } - TaskComplete(); - break; - } - case TASK_WALK_PATH: - { - if ( pev->movetype == MOVETYPE_FLY ) - { - m_movementActivity = ACT_FLY; - } - if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_WALK; - } - else - { - m_movementActivity = ACT_RUN; - } - TaskComplete(); - break; - } - case TASK_STRAFE_PATH: - { - Vector2D vec2DirToPoint; - Vector2D vec2RightSide; - - // to start strafing, we have to first figure out if the target is on the left side or right side - UTIL_MakeVectors ( pev->angles ); - - vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); - vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); - - if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) - { - // strafe right - m_movementActivity = ACT_STRAFE_RIGHT; - } - else - { - // strafe left - m_movementActivity = ACT_STRAFE_LEFT; - } - TaskComplete(); - break; - } - - - case TASK_WAIT_FOR_MOVEMENT: - { - if (FRouteClear()) - { - TaskComplete(); - } - break; - } - - case TASK_EAT: - { - Eat( pTask->flData ); - TaskComplete(); - break; - } - case TASK_SMALL_FLINCH: - { - m_IdealActivity = GetSmallFlinchActivity(); - break; - } - case TASK_DIE: - { - RouteClear(); - - m_IdealActivity = GetDeathActivity(); - - pev->deadflag = DEAD_DYING; - break; - } - case TASK_SOUND_WAKE: - { - AlertSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DIE: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_IDLE: - { - IdleSound(); - TaskComplete(); - break; - } - case TASK_SOUND_PAIN: - { - PainSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DEATH: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_ANGRY: - { - // sounds are complete as soon as we get here, cause we've already played them. - ALERT ( at_aiconsole, "SOUND\n" ); - TaskComplete(); - break; - } - case TASK_WAIT_FOR_SCRIPT: - { - if (m_pCine->m_iszIdle) - { - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); - if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) - { - pev->framerate = 0; - } - } - else - m_IdealActivity = ACT_IDLE; - - break; - } - case TASK_PLAY_SCRIPT: - { - pev->movetype = MOVETYPE_FLY; - ClearBits(pev->flags, FL_ONGROUND); - m_scriptState = SCRIPT_PLAYING; - break; - } - case TASK_ENABLE_SCRIPT: - { - m_pCine->DelayStart( 0 ); - TaskComplete(); - break; - } - case TASK_PLANT_ON_SCRIPT: - { - if ( m_hTargetEnt != NULL ) - { - pev->origin = m_hTargetEnt->pev->origin; // Plant on target - } - - TaskComplete(); - break; - } - case TASK_FACE_SCRIPT: - { - if ( m_hTargetEnt != NULL ) - { - pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); - } - - TaskComplete(); - m_IdealActivity = ACT_IDLE; - RouteClear(); - break; - } - - case TASK_SUGGEST_STATE: - { - m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; - TaskComplete(); - break; - } - - case TASK_SET_FAIL_SCHEDULE: - m_failSchedule = (int)pTask->flData; - TaskComplete(); - break; - - case TASK_CLEAR_FAIL_SCHEDULE: - m_failSchedule = SCHED_NONE; - TaskComplete(); - break; - - default: - { - ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); - break; - } - } -} - -//========================================================= -// GetTask - returns a pointer to the current -// scheduled task. NULL if there's a problem. -//========================================================= -Task_t *CBaseMonster :: GetTask ( void ) -{ - if ( m_iScheduleIndex < 0 || m_iScheduleIndex >= m_pSchedule->cTasks ) - { - // m_iScheduleIndex is not within valid range for the monster's current schedule. - return NULL; - } - else - { - return &m_pSchedule->pTasklist[ m_iScheduleIndex ]; - } -} - -//========================================================= -// 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) ); - CineCleanup(); - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - - return GetScheduleOfType( SCHED_AISCRIPT ); - } - default: - { - ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); - break; - } - } - - return &slError[ 0 ]; -} diff --git a/dlls/Wxdebug.cpp b/dlls/Wxdebug.cpp deleted file mode 100644 index 26d0d381..00000000 --- a/dlls/Wxdebug.cpp +++ /dev/null @@ -1,395 +0,0 @@ -//==========================================================================; -// -// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY -// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR -// PURPOSE. -// -// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. -// -//--------------------------------------------------------------------------; - - -// For every module and executable we store a debugging level and flags -// for the types of output that are desired. Constants for the types are -// defined in WXDEBUG.H and more can be added. -// The keys are stored in the registry under the -// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\Type and -// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\Level key values -// -// There are also global values under SOFTWARE\Debug\Global which are loaded -// after the module-specific values. The Types specified there are OR'ed with -// the module specific types and m_dwLevel is set to the greater of the global -// and the module specific settings. - -#include -#include - -#include "extdll.h" -#include "util.h" -#include "wxdebug.h" - -#include - -#ifdef _DEBUG - -void WINAPI DbgInitModuleName(void); -void WINAPI DbgInitModuleSettings(void); -void WINAPI DbgInitGlobalSettings(void); -void WINAPI DbgInitLogTo(HKEY hKey); -void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel); - - - -const INT iDEBUGINFO = 512; // Used to format strings - -HINSTANCE m_hInst; // Module instance handle -TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name -//CRITICAL_SECTION m_CSDebug; // Controls access to list -BOOL m_bInit = FALSE; // Have we been initialised -HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here -DWORD m_dwTypes = 0; -DWORD m_dwLevel = 0; - -const TCHAR *m_pBaseKey = TEXT("SOFTWARE\\Debug"); -const TCHAR *m_pGlobalKey = TEXT("GLOBAL"); -TCHAR *pKeyNames[] = -{ - TEXT("Types"), - TEXT("Level") -}; - - -// DbgInitialize -// This sets the instance handle that the debug library uses to find -// the module's file name from the Win32 GetModuleFileName function -void WINAPI DbgInitialise(HINSTANCE hInst) -{ - if (!m_bInit) - { - //InitializeCriticalSection(&m_CSDebug); - m_bInit = TRUE; - m_hInst = hInst; - DbgInitModuleName(); - DbgInitModuleSettings(); - DbgInitGlobalSettings(); - } -} - - -// DbgTerminate -// This is called to clear up any resources the debug library uses - at the -// moment we delete our critical section and the handle of the output file. -void WINAPI DbgTerminate() -{ - if (m_bInit) - { - if (m_hOutput != INVALID_HANDLE_VALUE) - { - DBGASSERTEXECUTE(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - //DeleteCriticalSection(&m_CSDebug); - m_bInit = FALSE; - } -} - - -// DbgInitModuleName -// Initialise the module file name -void WINAPI DbgInitModuleName() -{ - TCHAR FullName[iDEBUGINFO]; // Load the full path and module name - TCHAR *pName; // Searches from the end for a backslash - - GetModuleFileName(m_hInst,FullName,iDEBUGINFO); - pName = _tcsrchr(FullName,'\\'); - if (pName == NULL) - { - pName = FullName; - } - else - { - pName++; - } - lstrcpy(m_ModuleName,pName); -} - - -// DbgInitModuleSettings -// Retrieve the module-specific settings -void WINAPI DbgInitModuleSettings() -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hModuleKey; // Module key handle - - // Construct the base key name - wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_ModuleName); - - // Create or open the key for this module - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD)0, // Reserved value - NULL, // Address of class name - (DWORD)0, // Special options flags - KEY_ALL_ACCESS, // Desired security access - NULL, // Key security descriptor - &hModuleKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access module key")); - return; - } - - DbgInitLogTo(hModuleKey); - DbgInitKeyLevels(hModuleKey, &m_dwTypes, &m_dwLevel); - RegCloseKey(hModuleKey); -} - - -// DbgInitGlobalSettings -// This is called by DbgInitialize to read the global debug settings for -// Level and Type from the registry. The Types are OR'ed together and m_dwLevel -// is set to the greater of the global and module-specific values. -void WINAPI DbgInitGlobalSettings() -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hGlobalKey; // Global override key - DWORD dwTypes = 0; - DWORD dwLevel = 0; - - // Construct the global base key name - wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_pGlobalKey); - - // Create or open the key for this module - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD)0, // Reserved value - NULL, // Address of class name - (DWORD)0, // Special options flags - KEY_ALL_ACCESS, // Desired security access - NULL, // Key security descriptor - &hGlobalKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access GLOBAL module key")); - return; - } - - DbgInitKeyLevels(hGlobalKey, &dwTypes, &dwLevel); - RegCloseKey(hGlobalKey); - - m_dwTypes |= dwTypes; - if (dwLevel > m_dwLevel) - m_dwLevel = dwLevel; -} - - -// DbgInitLogTo -// Called by DbgInitModuleSettings to setup alternate logging destinations -void WINAPI DbgInitLogTo(HKEY hKey) -{ - LONG lReturn; - DWORD dwKeyType; - DWORD dwKeySize; - TCHAR szFile[MAX_PATH] = {0}; - static const TCHAR cszKey[] = TEXT("LogToFile"); - - dwKeySize = MAX_PATH; - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - cszKey, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) szFile, // Returns the field's value - &dwKeySize); // Number of bytes transferred - - // create an empty key if it does not already exist - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) - { - dwKeySize = 1; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - cszKey, // Address of subkey name - (DWORD) 0, // Reserved field - REG_SZ, // Type of the key field - (PBYTE)szFile, // Value for the field - dwKeySize); // Size of the field buffer - } - - // if an output-to was specified. try to open it. - if (m_hOutput != INVALID_HANDLE_VALUE) - { - DBGASSERTEXECUTE(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - if (szFile[0] != 0) - { - if (!lstrcmpi(szFile, TEXT("Console"))) - { - m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - if (m_hOutput == INVALID_HANDLE_VALUE) - { - AllocConsole(); - m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - } - SetConsoleTitle (TEXT("Valve Debug Output")); - } else if (szFile[0] && - lstrcmpi(szFile, TEXT("Debug")) && - lstrcmpi(szFile, TEXT("Debugger")) && - lstrcmpi(szFile, TEXT("Deb"))) - { - m_hOutput = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE != m_hOutput) - { - static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); - SetFilePointer (m_hOutput, 0, NULL, FILE_END); - DbgOutString (cszBar); - } - } - } -} - - -// DbgInitKeyLevels -// This is called by DbgInitModuleSettings and DbgInitGlobalSettings to read -// settings for Types and Level from the registry -void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel) -{ - LONG lReturn; // Create key return value - DWORD dwKeySize; // Size of the key value - DWORD dwKeyType; // Receives it's type - - // Get the Types value - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[0], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE)pdwTypes, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - // If either the key was not available or it was not a DWORD value - // then we ensure only the high priority debug logging is output - // but we try and update the field to a zero filled DWORD value - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) - { - *pdwTypes = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[0], // Address of subkey name - (DWORD)0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE)pdwTypes, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[0]); - *pdwTypes = 0; - } - } - - // Get the Level value - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[1], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE)pdwLevel, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - // If either the key was not available or it was not a DWORD value - // then we ensure only the high priority debug logging is output - // but we try and update the field to a zero filled DWORD value - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) - { - *pdwLevel = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[1], // Address of subkey name - (DWORD)0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE)pdwLevel, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[1]); - *pdwLevel = 0; - } - } -} - - -// DbgOutString -void WINAPI DbgOutString(LPCTSTR psz) -{ - if (!m_bInit) - return; - if (m_hOutput != INVALID_HANDLE_VALUE) { - UINT cb = lstrlen(psz); - DWORD dw; - WriteFile (m_hOutput, psz, cb, &dw, NULL); - } else { - OutputDebugString (psz); - } -} - - -// DbgLogInfo -// Print a formatted string to the debugger prefixed with this module's name -// Because the debug code is linked statically every module loaded will -// have its own copy of this code. It therefore helps if the module name is -// included on the output so that the offending code can be easily found -void WINAPI DbgLogInfo(DWORD Type, DWORD Level, const TCHAR *pFormat,...) -{ - if (!m_bInit) - return; - // Check the current level for this type combination */ - if (((Type & m_dwTypes) == 0) || (m_dwLevel < Level)) - return; - - TCHAR szInfo[2000]; - - // Format the variable length parameter list - - va_list va; - va_start(va, pFormat); - - //lstrcpy(szInfo, m_ModuleName); - //lstrcat(szInfo, TEXT(": ")); - wvsprintf(szInfo /* + lstrlen(szInfo) */, pFormat, va); - //lstrcat(szInfo, TEXT("\r\n")); - DbgOutString(szInfo); - - va_end(va); -} - - -// DbgKernelAssert -// If we are executing as a pure kernel filter we cannot display message -// boxes to the user, this provides an alternative which puts the error -// condition on the debugger output with a suitable eye catching message -void WINAPI DbgKernelAssert(const TCHAR *pCondition, const TCHAR *pFileName, INT iLine) -{ - if (!m_bInit) - return; - DbgLogInfo(LOG_ERROR, 0, TEXT(m_ModuleName)); - DbgLogInfo(LOG_ERROR, 0, TEXT(": Assertion FAILED (%s) at line %d in file %s\r\n"), pCondition, iLine, pFileName); - DebugBreak(); -} - -#endif // _DEBUG - - diff --git a/dlls/aflock.cpp b/dlls/aflock.cpp deleted file mode 100644 index d50a8165..00000000 --- a/dlls/aflock.cpp +++ /dev/null @@ -1,918 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "squadmonster.h" - -#define AFLOCK_MAX_RECRUIT_RADIUS 1024 -#define AFLOCK_FLY_SPEED 125 -#define AFLOCK_TURN_RATE 75 -#define AFLOCK_ACCELERATE 10 -#define AFLOCK_CHECK_DIST 192 -#define AFLOCK_TOO_CLOSE 100 -#define AFLOCK_TOO_FAR 256 - -//========================================================= -//========================================================= -class CFlockingFlyerFlock : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void SpawnFlock( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - // Sounds are shared by the flock - static void PrecacheFlockSounds( void ); - - int m_cFlockSize; - float m_flFlockRadius; -}; - -TYPEDESCRIPTION CFlockingFlyerFlock::m_SaveData[] = -{ - DEFINE_FIELD( CFlockingFlyerFlock, m_cFlockSize, FIELD_INTEGER ), - DEFINE_FIELD( CFlockingFlyerFlock, m_flFlockRadius, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CFlockingFlyerFlock, CBaseMonster ) - -//========================================================= -//========================================================= -class CFlockingFlyer : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SpawnCommonCode( void ); - void EXPORT IdleThink( void ); - void BoidAdvanceFrame( void ); - void EXPORT FormFlock( void ); - void EXPORT Start( void ); - void EXPORT FlockLeaderThink( void ); - void EXPORT FlockFollowerThink( void ); - void EXPORT FallHack( void ); - void MakeSound( void ); - void AlertFlock( void ); - void SpreadFlock( void ); - void SpreadFlock2( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - void Poop ( void ); - BOOL FPathBlocked( void ); - //void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int IsLeader( void ) { return m_pSquadLeader == this; } - int InSquad( void ) { return m_pSquadLeader != NULL; } - int SquadCount( void ); - void SquadRemove( CFlockingFlyer *pRemove ); - void SquadUnlink( void ); - void SquadAdd( CFlockingFlyer *pAdd ); - void SquadDisband( void ); - - CFlockingFlyer *m_pSquadLeader; - CFlockingFlyer *m_pSquadNext; - BOOL m_fTurning;// is this boid turning? - BOOL m_fCourseAdjust;// followers set this flag TRUE to override flocking while they avoid something - BOOL m_fPathBlocked;// TRUE if there is an obstacle ahead - Vector m_vecReferencePoint;// last place we saw leader - Vector m_vecAdjustedVelocity;// adjusted velocity (used when fCourseAdjust is TRUE) - float m_flGoalSpeed; - float m_flLastBlockedTime; - float m_flFakeBlockedTime; - float m_flAlertTime; - float m_flFlockNextSoundTime; -}; - -LINK_ENTITY_TO_CLASS( monster_flyer, CFlockingFlyer ) -LINK_ENTITY_TO_CLASS( monster_flyer_flock, CFlockingFlyerFlock ) - -TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] = -{ - DEFINE_FIELD( CFlockingFlyer, m_pSquadLeader, FIELD_CLASSPTR ), - DEFINE_FIELD( CFlockingFlyer, m_pSquadNext, FIELD_CLASSPTR ), - DEFINE_FIELD( CFlockingFlyer, m_fTurning, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_fCourseAdjust, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_fPathBlocked, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_vecReferencePoint, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CFlockingFlyer, m_vecAdjustedVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CFlockingFlyer, m_flGoalSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CFlockingFlyer, m_flLastBlockedTime, FIELD_TIME ), - DEFINE_FIELD( CFlockingFlyer, m_flFakeBlockedTime, FIELD_TIME ), - DEFINE_FIELD( CFlockingFlyer, m_flAlertTime, FIELD_TIME ), - //DEFINE_FIELD( CFlockingFlyer, m_flFlockNextSoundTime, FIELD_TIME ), // don't need to save -}; - -IMPLEMENT_SAVERESTORE( CFlockingFlyer, CBaseMonster ) - -//========================================================= -//========================================================= -void CFlockingFlyerFlock::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "iFlockSize" ) ) - { - m_cFlockSize = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "flFlockRadius" ) ) - { - m_flFlockRadius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock::Spawn() -{ - Precache(); - SpawnFlock(); - - REMOVE_ENTITY( ENT( pev ) ); // dump the spawn ent -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock::Precache() -{ - //PRECACHE_MODEL( "models/aflock.mdl" ); - PRECACHE_MODEL( "models/boid.mdl" ); - - PrecacheFlockSounds(); -} - -void CFlockingFlyerFlock::PrecacheFlockSounds( void ) -{ - PRECACHE_SOUND( "boid/boid_alert1.wav" ); - PRECACHE_SOUND( "boid/boid_alert2.wav" ); - - PRECACHE_SOUND( "boid/boid_idle1.wav" ); - PRECACHE_SOUND( "boid/boid_idle2.wav" ); -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock::SpawnFlock( void ) -{ - float R = m_flFlockRadius; - int iCount; - Vector vecSpot; - CFlockingFlyer *pBoid, *pLeader; - - pLeader = pBoid = NULL; - - for( iCount = 0; iCount < m_cFlockSize; iCount++ ) - { - pBoid = GetClassPtr( (CFlockingFlyer *)NULL ); - - if( !pLeader ) - { - // make this guy the leader. - pLeader = pBoid; - - pLeader->m_pSquadLeader = pLeader; - pLeader->m_pSquadNext = NULL; - } - - vecSpot.x = RANDOM_FLOAT( -R, R ); - vecSpot.y = RANDOM_FLOAT( -R, R ); - vecSpot.z = RANDOM_FLOAT( 0, 16 ); - vecSpot = pev->origin + vecSpot; - - UTIL_SetOrigin( pBoid->pev, vecSpot ); - pBoid->pev->movetype = MOVETYPE_FLY; - pBoid->SpawnCommonCode(); - pBoid->pev->flags &= ~FL_ONGROUND; - pBoid->pev->velocity = g_vecZero; - pBoid->pev->angles = pev->angles; - - pBoid->pev->frame = 0; - pBoid->pev->nextthink = gpGlobals->time + 0.2; - pBoid->SetThink( &CFlockingFlyer::IdleThink ); - - if( pBoid != pLeader ) - { - pLeader->SquadAdd( pBoid ); - } - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer::Spawn() -{ - Precache(); - SpawnCommonCode(); - - pev->frame = 0; - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CFlockingFlyer::IdleThink ); -} - -//========================================================= -//========================================================= -void CFlockingFlyer::Precache() -{ - //PRECACHE_MODEL( "models/aflock.mdl" ); - PRECACHE_MODEL( "models/boid.mdl" ); - CFlockingFlyerFlock::PrecacheFlockSounds(); -} - -//========================================================= -//========================================================= -void CFlockingFlyer::MakeSound( void ) -{ - if( m_flAlertTime > gpGlobals->time ) - { - // make agitated sounds - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "boid/boid_alert1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "boid/boid_alert2.wav", 1, ATTN_NORM ); - break; - } - - return; - } - - // make normal sound - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_idle1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_idle2.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer::Killed( entvars_t *pevAttacker, int iGib ) -{ - CFlockingFlyer *pSquad; - - pSquad = (CFlockingFlyer *)m_pSquadLeader; - - while( pSquad ) - { - pSquad->m_flAlertTime = gpGlobals->time + 15; - pSquad = (CFlockingFlyer *)pSquad->m_pSquadNext; - } - - if( m_pSquadLeader ) - { - m_pSquadLeader->SquadRemove( this ); - } - - pev->deadflag = DEAD_DEAD; - - pev->framerate = 0; - pev->effects = EF_NOINTERP; - - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - pev->movetype = MOVETYPE_TOSS; - - SetThink( &CFlockingFlyer::FallHack ); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CFlockingFlyer::FallHack( void ) -{ - if( pev->flags & FL_ONGROUND ) - { - if( !FClassnameIs ( pev->groundentity, "worldspawn" ) ) - { - pev->flags &= ~FL_ONGROUND; - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - pev->velocity = g_vecZero; - SetThink( NULL ); - } - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer::SpawnCommonCode() -{ - pev->deadflag = DEAD_NO; - pev->classname = MAKE_STRING( "monster_flyer" ); - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->takedamage = DAMAGE_NO; - pev->health = 1; - - m_fPathBlocked = FALSE;// obstacles will be detected - m_flFieldOfView = 0.2; - - //SET_MODEL( ENT( pev ), "models/aflock.mdl" ); - SET_MODEL( ENT( pev ), "models/boid.mdl" ); - - //UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - UTIL_SetSize( pev, Vector( -5, -5, 0 ), Vector( 5, 5, 2 ) ); -} - -//========================================================= -//========================================================= -void CFlockingFlyer::BoidAdvanceFrame() -{ - float flapspeed = ( pev->speed - pev->armorvalue ) / AFLOCK_ACCELERATE; - pev->armorvalue = pev->armorvalue * .8 + pev->speed * .2; - - if( flapspeed < 0 ) - flapspeed = -flapspeed; - if( flapspeed < 0.25 ) - flapspeed = 0.25; - if( flapspeed > 1.9 ) - flapspeed = 1.9; - - pev->framerate = flapspeed; - - // lean - pev->avelocity.x = -( pev->angles.x + flapspeed * 5 ); - - // bank - pev->avelocity.z = -( pev->angles.z + pev->avelocity.y ); - - // pev->framerate = flapspeed; - StudioFrameAdvance( 0.1 ); -} - -//========================================================= -//========================================================= -void CFlockingFlyer::IdleThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.2; - - // see if there's a client in the same pvs as the monster - if( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - SetThink( &CFlockingFlyer::Start ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - -//========================================================= -// Start - player enters the pvs, so get things going. -//========================================================= -void CFlockingFlyer::Start( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if( IsLeader() ) - { - SetThink( &CFlockingFlyer::FlockLeaderThink ); - } - else - { - SetThink( &CFlockingFlyer::FlockFollowerThink ); - } -/* - Vector vecTakeOff; - vecTakeOff = Vector( 0, 0, 0 ); - - vecTakeOff.z = 50 + RANDOM_FLOAT( 0, 100 ); - vecTakeOff.x = 20 - RANDOM_FLOAT( 0, 40 ); - vecTakeOff.y = 20 - RANDOM_FLOAT( 0, 40 ); - - pev->velocity = vecTakeOff; - - pev->speed = pev->velocity.Length(); - pev->sequence = 0; -*/ - SetActivity( ACT_FLY ); - ResetSequenceInfo(); - BoidAdvanceFrame(); - - pev->speed = AFLOCK_FLY_SPEED;// no delay! -} - -//========================================================= -// Leader boid calls this to form a flock from surrounding boids -//========================================================= -void CFlockingFlyer::FormFlock( void ) -{ - if( !InSquad() ) - { - // I am my own leader - m_pSquadLeader = this; - m_pSquadNext = NULL; - int squadCount = 1; - - CBaseEntity *pEntity = NULL; - - while( ( pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, AFLOCK_MAX_RECRUIT_RADIUS ) ) != NULL ) - { - CBaseMonster *pRecruit = pEntity->MyMonsterPointer(); - - if( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) - { - // Can we recruit this guy? - if( FClassnameIs ( pRecruit->pev, "monster_flyer" ) ) - { - squadCount++; - SquadAdd( (CFlockingFlyer *)pRecruit ); - } - } - } - } - - SetThink( &CFlockingFlyer::IdleThink );// now that flock is formed, go to idle and wait for a player to come along. - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// Searches for boids that are too close and pushes them away -//========================================================= -void CFlockingFlyer::SpreadFlock() -{ - Vector vecDir; - float flSpeed;// holds vector magnitude while we fiddle with the direction - - CFlockingFlyer *pList = m_pSquadLeader; - while( pList ) - { - if( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) - { - // push the other away - vecDir = pList->pev->origin - pev->origin; - vecDir = vecDir.Normalize(); - - // store the magnitude of the other boid's velocity, and normalize it so we - // can average in a course that points away from the leader. - flSpeed = pList->pev->velocity.Length(); - pList->pev->velocity = pList->pev->velocity.Normalize(); - pList->pev->velocity = ( pList->pev->velocity + vecDir ) * 0.5; - pList->pev->velocity = pList->pev->velocity * flSpeed; - } - - pList = pList->m_pSquadNext; - } -} - -//========================================================= -// Alters the caller's course if he's too close to others -// -// This function should **ONLY** be called when Caller's velocity is normalized!! -//========================================================= -void CFlockingFlyer::SpreadFlock2() -{ - Vector vecDir; - - CFlockingFlyer *pList = m_pSquadLeader; - while( pList ) - { - if( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) - { - vecDir = pev->origin - pList->pev->origin; - vecDir = vecDir.Normalize(); - - pev->velocity = pev->velocity + vecDir; - } - - pList = pList->m_pSquadNext; - } -} - -//========================================================= -// FBoidPathBlocked - returns TRUE if there is an obstacle ahead -//========================================================= -BOOL CFlockingFlyer::FPathBlocked() -{ - TraceResult tr; - Vector vecDist;// used for general measurements - Vector vecDir;// used for general measurements - BOOL fBlocked; - - if( m_flFakeBlockedTime > gpGlobals->time ) - { - m_flLastBlockedTime = gpGlobals->time; - return TRUE; - } - - // use VELOCITY, not angles, not all boids point the direction they are flying - //vecDir = UTIL_VecToAngles( pevBoid->velocity ); - UTIL_MakeVectors ( pev->angles ); - - fBlocked = FALSE;// assume the way ahead is clear - - // check for obstacle ahead - UTIL_TraceLine( pev->origin, pev->origin + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction != 1.0 ) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - // extra wide checks - UTIL_TraceLine( pev->origin + gpGlobals->v_right * 12, pev->origin + gpGlobals->v_right * 12 + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction != 1.0 ) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - UTIL_TraceLine( pev->origin - gpGlobals->v_right * 12, pev->origin - gpGlobals->v_right * 12 + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction != 1.0 ) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - if( !fBlocked && gpGlobals->time - m_flLastBlockedTime > 6 ) - { - // not blocked, and it's been a few seconds since we've actually been blocked. - m_flFakeBlockedTime = gpGlobals->time + RANDOM_LONG( 1, 3 ); - } - - return fBlocked; -} - -//========================================================= -// Leader boids use this think every tenth -//========================================================= -void CFlockingFlyer::FlockLeaderThink( void ) -{ - TraceResult tr; - Vector vecDist;// used for general measurements - Vector vecDir;// used for general measurements - float flLeftSide; - float flRightSide; - - pev->nextthink = gpGlobals->time + 0.1; - - UTIL_MakeVectors( pev->angles ); - - // is the way ahead clear? - if( !FPathBlocked () ) - { - // if the boid is turning, stop the trend. - if( m_fTurning ) - { - m_fTurning = FALSE; - pev->avelocity.y = 0; - } - - m_fPathBlocked = FALSE; - - if( pev->speed <= AFLOCK_FLY_SPEED ) - pev->speed += 5; - - pev->velocity = gpGlobals->v_forward * pev->speed; - - BoidAdvanceFrame(); - - return; - } - - // IF we get this far in the function, the leader's path is blocked! - m_fPathBlocked = TRUE; - - if( !m_fTurning )// something in the way and boid is not already turning to avoid - { - // measure clearance on left and right to pick the best dir to turn - UTIL_TraceLine( pev->origin, pev->origin + gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT( pev ), &tr ); - vecDist = ( tr.vecEndPos - pev->origin ); - flRightSide = vecDist.Length(); - - UTIL_TraceLine( pev->origin, pev->origin - gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT( pev ), &tr ); - vecDist = tr.vecEndPos - pev->origin; - flLeftSide = vecDist.Length(); - - // turn right if more clearance on right side - if( flRightSide > flLeftSide ) - { - pev->avelocity.y = -AFLOCK_TURN_RATE; - m_fTurning = TRUE; - } - // default to left turn :) - else if( flLeftSide > flRightSide ) - { - pev->avelocity.y = AFLOCK_TURN_RATE; - m_fTurning = TRUE; - } - else - { - // equidistant. Pick randomly between left and right. - m_fTurning = TRUE; - - if( RANDOM_LONG( 0, 1 ) == 0 ) - { - pev->avelocity.y = AFLOCK_TURN_RATE; - } - else - { - pev->avelocity.y = -AFLOCK_TURN_RATE; - } - } - } - SpreadFlock(); - - pev->velocity = gpGlobals->v_forward * pev->speed; - - // check and make sure we aren't about to plow into the ground, don't let it happen - UTIL_TraceLine( pev->origin, pev->origin - gpGlobals->v_up * 16, ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction != 1.0 && pev->velocity.z < 0 ) - pev->velocity.z = 0; - - // maybe it did, though. - if( FBitSet( pev->flags, FL_ONGROUND ) ) - { - UTIL_SetOrigin( pev, pev->origin + Vector( 0, 0, 1 ) ); - pev->velocity.z = 0; - } - - if( m_flFlockNextSoundTime < gpGlobals->time ) - { - MakeSound(); - m_flFlockNextSoundTime = gpGlobals->time + RANDOM_FLOAT( 1, 3 ); - } - - BoidAdvanceFrame( ); - - return; -} - -//========================================================= -// follower boids execute this code when flocking -//========================================================= -void CFlockingFlyer::FlockFollowerThink( void ) -{ - TraceResult tr; - Vector vecDist; - Vector vecDir; - Vector vecDirToLeader; - float flDistToLeader; - - pev->nextthink = gpGlobals->time + 0.1; - - if( IsLeader() || !InSquad() ) - { - // the leader has been killed and this flyer suddenly finds himself the leader. - SetThink( &CFlockingFlyer::FlockLeaderThink ); - return; - } - - vecDirToLeader = ( m_pSquadLeader->pev->origin - pev->origin ); - flDistToLeader = vecDirToLeader.Length(); - - // match heading with leader - pev->angles = m_pSquadLeader->pev->angles; - - // - // We can see the leader, so try to catch up to it - // - if( FInViewCone ( m_pSquadLeader ) ) - { - // if we're too far away, speed up - if( flDistToLeader > AFLOCK_TOO_FAR ) - { - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 1.5; - } - - // if we're too close, slow down - else if( flDistToLeader < AFLOCK_TOO_CLOSE ) - { - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; - } - } - else - { - // wait up! the leader isn't out in front, so we slow down to let him pass - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; - } - - SpreadFlock2(); - - pev->speed = pev->velocity.Length(); - pev->velocity = pev->velocity.Normalize(); - - // if we are too far from leader, average a vector towards it into our current velocity - if( flDistToLeader > AFLOCK_TOO_FAR ) - { - vecDirToLeader = vecDirToLeader.Normalize(); - pev->velocity = (pev->velocity + vecDirToLeader) * 0.5; - } - - // clamp speeds and handle acceleration - if( m_flGoalSpeed > AFLOCK_FLY_SPEED * 2 ) - { - m_flGoalSpeed = AFLOCK_FLY_SPEED * 2; - } - - if( pev->speed < m_flGoalSpeed ) - { - pev->speed += AFLOCK_ACCELERATE; - } - else if( pev->speed > m_flGoalSpeed ) - { - pev->speed -= AFLOCK_ACCELERATE; - } - - pev->velocity = pev->velocity * pev->speed; - - BoidAdvanceFrame( ); -} - -/* - // Is this boid's course blocked? - if( FBoidPathBlocked( pev ) ) - { - // course is still blocked from last time. Just keep flying along adjusted - // velocity - if( m_fCourseAdjust ) - { - pev->velocity = m_vecAdjustedVelocity * pev->speed; - return; - } - else // set course adjust flag and calculate adjusted velocity - { - m_fCourseAdjust = TRUE; - - // use VELOCITY, not angles, not all boids point the direction they are flying - //vecDir = UTIL_VecToAngles( pev->velocity ); - //UTIL_MakeVectors( vecDir ); - - UTIL_MakeVectors( pev->angles ); - - // measure clearance on left and right to pick the best dir to turn - UTIL_TraceLine( pev->origin, pev->origin + gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT( pev ), &tr ); - vecDist = tr.vecEndPos - pev->origin; - flRightSide = vecDist.Length(); - - UTIL_TraceLine( pev->origin, pev->origin - gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT( pev ), &tr ); - vecDist = tr.vecEndPos - pev->origin; - flLeftSide = vecDist.Length(); - - // slide right if more clearance on right side - if( flRightSide > flLeftSide ) - { - m_vecAdjustedVelocity = gpGlobals->v_right; - } - // else slide left - else - { - m_vecAdjustedVelocity = gpGlobals->v_right * -1; - } - } - return; - } - - // if we make it this far, boids path is CLEAR! - m_fCourseAdjust = FALSE; -*/ - -//========================================================= -// -// SquadUnlink(), Unlink the squad pointers. -// -//========================================================= -void CFlockingFlyer::SquadUnlink( void ) -{ - m_pSquadLeader = NULL; - m_pSquadNext = NULL; -} - -//========================================================= -// -// SquadAdd(), add pAdd to my squad -// -//========================================================= -void CFlockingFlyer::SquadAdd( CFlockingFlyer *pAdd ) -{ - ASSERT( pAdd != NULL ); - ASSERT( !pAdd->InSquad() ); - ASSERT( this->IsLeader() ); - - pAdd->m_pSquadNext = m_pSquadNext; - m_pSquadNext = pAdd; - pAdd->m_pSquadLeader = this; -} - -//========================================================= -// -// SquadRemove(), remove pRemove from my squad. -// If I am pRemove, promote m_pSquadNext to leader -// -//========================================================= -void CFlockingFlyer::SquadRemove( CFlockingFlyer *pRemove ) -{ - ASSERT( pRemove != NULL ); - ASSERT( this->IsLeader() ); - ASSERT( pRemove->m_pSquadLeader == this ); - - if( SquadCount() > 2 ) - { - // Removing the leader, promote m_pSquadNext to leader - if( pRemove == this ) - { - CFlockingFlyer *pLeader = m_pSquadNext; - - if( pLeader ) - { - // copy the enemy LKP to the new leader - pLeader->m_vecEnemyLKP = m_vecEnemyLKP; - - CFlockingFlyer *pList = pLeader; - - while( pList ) - { - pList->m_pSquadLeader = pLeader; - pList = pList->m_pSquadNext; - } - - } - SquadUnlink(); - } - else // removing a node - { - CFlockingFlyer *pList = this; - - // Find the node before pRemove - while( pList->m_pSquadNext != pRemove ) - { - // assert to test valid list construction - ASSERT( pList->m_pSquadNext != NULL ); - pList = pList->m_pSquadNext; - } - // List validity - ASSERT( pList->m_pSquadNext == pRemove ); - - // Relink without pRemove - pList->m_pSquadNext = pRemove->m_pSquadNext; - - // Unlink pRemove - pRemove->SquadUnlink(); - } - } - else - SquadDisband(); -} - -//========================================================= -// -// SquadCount(), return the number of members of this squad -// callable from leaders & followers -// -//========================================================= -int CFlockingFlyer::SquadCount( void ) -{ - CFlockingFlyer *pList = m_pSquadLeader; - int squadCount = 0; - while( pList ) - { - squadCount++; - pList = pList->m_pSquadNext; - } - - return squadCount; -} - -//========================================================= -// -// SquadDisband(), Unlink all squad members -// -//========================================================= -void CFlockingFlyer::SquadDisband( void ) -{ - CFlockingFlyer *pList = m_pSquadLeader; - CFlockingFlyer *pNext; - - while( pList ) - { - pNext = pList->m_pSquadNext; - pList->SquadUnlink(); - pList = pNext; - } -} diff --git a/dlls/agrunt.cpp b/dlls/agrunt.cpp deleted file mode 100644 index cb47ac65..00000000 --- a/dlls/agrunt.cpp +++ /dev/null @@ -1,1178 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Agrunt - Dominant, warlike alien grunt monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "squadmonster.h" -#include "weapons.h" -#include "soundent.h" -#include "hornet.h" - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_AGRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, - SCHED_AGRUNT_THREAT_DISPLAY -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_AGRUNT_SETUP_HIDE_ATTACK = LAST_COMMON_TASK + 1, - TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE -}; - -int iAgruntMuzzleFlash; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define AGRUNT_AE_HORNET1 ( 1 ) -#define AGRUNT_AE_HORNET2 ( 2 ) -#define AGRUNT_AE_HORNET3 ( 3 ) -#define AGRUNT_AE_HORNET4 ( 4 ) -#define AGRUNT_AE_HORNET5 ( 5 ) -// some events are set up in the QC file that aren't recognized by the code yet. -#define AGRUNT_AE_PUNCH ( 6 ) -#define AGRUNT_AE_BITE ( 7 ) - -#define AGRUNT_AE_LEFT_FOOT ( 10 ) -#define AGRUNT_AE_RIGHT_FOOT ( 11 ) - -#define AGRUNT_AE_LEFT_PUNCH ( 12 ) -#define AGRUNT_AE_RIGHT_PUNCH ( 13 ) - -#define AGRUNT_MELEE_DIST 100 - -class CAGrunt : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - int ISoundMask( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -32, -32, 0 ); - pev->absmax = pev->origin + Vector( 32, 32, 85 ); - } - - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - BOOL FCanCheckAttacks( void ); - BOOL CheckMeleeAttack1( float flDot, float flDist ); - BOOL CheckRangeAttack1( float flDot, float flDist ); - void StartTask( Task_t *pTask ); - void AlertSound( void ); - void DeathSound( void ); - void PainSound( void ); - void AttackSound( void ); - void PrescheduleThink( void ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - int IRelationship( CBaseEntity *pTarget ); - void StopTalking( void ); - BOOL ShouldSpeak( void ); - CUSTOM_SCHEDULES - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - static const char *pAttackSounds[]; - static const char *pDieSounds[]; - static const char *pPainSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - - BOOL m_fCanHornetAttack; - float m_flNextHornetAttackCheck; - - float m_flNextPainTime; - - // three hacky fields for speech stuff. These don't really need to be saved. - float m_flNextSpeakTime; - float m_flNextWordTime; - int m_iLastWord; -}; - -LINK_ENTITY_TO_CLASS( monster_alien_grunt, CAGrunt ) - -TYPEDESCRIPTION CAGrunt::m_SaveData[] = -{ - DEFINE_FIELD( CAGrunt, m_fCanHornetAttack, FIELD_BOOLEAN ), - DEFINE_FIELD( CAGrunt, m_flNextHornetAttackCheck, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextPainTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextSpeakTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextWordTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_iLastWord, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CAGrunt, CSquadMonster ) - -const char *CAGrunt::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CAGrunt::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CAGrunt::pAttackSounds[] = -{ - "agrunt/ag_attack1.wav", - "agrunt/ag_attack2.wav", - "agrunt/ag_attack3.wav", -}; - -const char *CAGrunt::pDieSounds[] = -{ - "agrunt/ag_die1.wav", - "agrunt/ag_die4.wav", - "agrunt/ag_die5.wav", -}; - -const char *CAGrunt::pPainSounds[] = -{ - "agrunt/ag_pain1.wav", - "agrunt/ag_pain2.wav", - "agrunt/ag_pain3.wav", - "agrunt/ag_pain4.wav", - "agrunt/ag_pain5.wav", -}; - -const char *CAGrunt::pIdleSounds[] = -{ - "agrunt/ag_idle1.wav", - "agrunt/ag_idle2.wav", - "agrunt/ag_idle3.wav", - "agrunt/ag_idle4.wav", -}; - -const char *CAGrunt::pAlertSounds[] = -{ - "agrunt/ag_alert1.wav", - "agrunt/ag_alert3.wav", - "agrunt/ag_alert4.wav", - "agrunt/ag_alert5.wav", -}; - -//========================================================= -// IRelationship - overridden because Human Grunts are -// Alien Grunt's nemesis. -//========================================================= -int CAGrunt::IRelationship( CBaseEntity *pTarget ) -{ - if( FClassnameIs( pTarget->pev, "monster_human_grunt" ) ) - { - return R_NM; - } - - return CSquadMonster::IRelationship( pTarget ); -} - -//========================================================= -// ISoundMask -//========================================================= -int CAGrunt::ISoundMask( void ) -{ - return ( bits_SOUND_WORLD | bits_SOUND_COMBAT | bits_SOUND_PLAYER | bits_SOUND_DANGER ); -} - -//========================================================= -// TraceAttack -//========================================================= -void CAGrunt::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if( ptr->iHitgroup == 10 && ( bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_CLUB ) ) ) - { - // hit armor - if( pev->dmgtime != gpGlobals->time || ( RANDOM_LONG( 0, 10 ) < 1 ) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2 ) ); - pev->dmgtime = gpGlobals->time; - } - - if( RANDOM_LONG( 0, 1 ) == 0 ) - { - Vector vecTracerDir = vecDir; - - vecTracerDir.x += RANDOM_FLOAT( -0.3, 0.3 ); - vecTracerDir.y += RANDOM_FLOAT( -0.3, 0.3 ); - vecTracerDir.z += RANDOM_FLOAT( -0.3, 0.3 ); - - vecTracerDir = vecTracerDir * -512; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, ptr->vecEndPos ); - WRITE_BYTE( TE_TRACER ); - WRITE_COORD( ptr->vecEndPos.x ); - WRITE_COORD( ptr->vecEndPos.y ); - WRITE_COORD( ptr->vecEndPos.z ); - - WRITE_COORD( vecTracerDir.x ); - WRITE_COORD( vecTracerDir.y ); - WRITE_COORD( vecTracerDir.z ); - MESSAGE_END(); - } - - flDamage -= 20; - if( flDamage <= 0 ) - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - else - { - SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage );// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - } - - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -//========================================================= -// StopTalking - won't speak again for 10-20 seconds. -//========================================================= -void CAGrunt::StopTalking( void ) -{ - m_flNextWordTime = m_flNextSpeakTime = gpGlobals->time + 10 + RANDOM_LONG( 0, 10 ); -} - -//========================================================= -// ShouldSpeak - Should this agrunt be talking? -//========================================================= -BOOL CAGrunt::ShouldSpeak( void ) -{ - if( m_flNextSpeakTime > gpGlobals->time ) - { - // my time to talk is still in the future. - return FALSE; - } - - if( pev->spawnflags & SF_MONSTER_GAG ) - { - if( m_MonsterState != MONSTERSTATE_COMBAT ) - { - // if gagged, don't talk outside of combat. - // if not going to talk because of this, put the talk time - // into the future a bit, so we don't talk immediately after - // going into combat - m_flNextSpeakTime = gpGlobals->time + 3; - return FALSE; - } - } - - return TRUE; -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CAGrunt::PrescheduleThink( void ) -{ - if( ShouldSpeak() ) - { - if( m_flNextWordTime < gpGlobals->time ) - { - int num = -1; - - do - { - num = RANDOM_LONG( 0, ARRAYSIZE( pIdleSounds ) - 1 ); - } while( num == m_iLastWord ); - - m_iLastWord = num; - - // play a new sound - EMIT_SOUND( ENT( pev ), CHAN_VOICE, pIdleSounds[num], 1.0, ATTN_NORM ); - - // is this word our last? - if( RANDOM_LONG( 1, 10 ) <= 1 ) - { - // stop talking. - StopTalking(); - } - else - { - m_flNextWordTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 1 ); - } - } - } -} - -//========================================================= -// DieSound -//========================================================= -void CAGrunt::DeathSound( void ) -{ - StopTalking(); - - EMIT_SOUND( ENT( pev ), CHAN_VOICE, pDieSounds[RANDOM_LONG( 0, ARRAYSIZE( pDieSounds ) - 1 )], 1.0, ATTN_NORM ); -} - -//========================================================= -// AlertSound -//========================================================= -void CAGrunt::AlertSound( void ) -{ - StopTalking(); - - EMIT_SOUND( ENT( pev ), CHAN_VOICE, pAlertSounds[RANDOM_LONG( 0, ARRAYSIZE( pAlertSounds ) - 1 )], 1.0, ATTN_NORM ); -} - -//========================================================= -// AttackSound -//========================================================= -void CAGrunt::AttackSound( void ) -{ - StopTalking(); - - EMIT_SOUND( ENT( pev ), CHAN_VOICE, pAttackSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackSounds ) - 1 )], 1.0, ATTN_NORM ); -} - -//========================================================= -// PainSound -//========================================================= -void CAGrunt::PainSound( void ) -{ - if( m_flNextPainTime > gpGlobals->time ) - { - return; - } - - m_flNextPainTime = gpGlobals->time + 0.6; - - StopTalking(); - - EMIT_SOUND( ENT( pev ), CHAN_VOICE, pPainSounds[RANDOM_LONG( 0, ARRAYSIZE( pPainSounds ) - 1 )], 1.0, ATTN_NORM ); -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CAGrunt::Classify( void ) -{ - return CLASS_ALIEN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CAGrunt::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 110; - break; - default: - ys = 100; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CAGrunt::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case AGRUNT_AE_HORNET1: - case AGRUNT_AE_HORNET2: - case AGRUNT_AE_HORNET3: - case AGRUNT_AE_HORNET4: - case AGRUNT_AE_HORNET5: - { - // m_vecEnemyLKP should be center of enemy body - Vector vecArmPos, vecArmDir; - Vector vecDirToEnemy; - Vector angDir; - - if( HasConditions( bits_COND_SEE_ENEMY ) ) - { - vecDirToEnemy = ( ( m_vecEnemyLKP ) - pev->origin ); - angDir = UTIL_VecToAngles( vecDirToEnemy ); - vecDirToEnemy = vecDirToEnemy.Normalize(); - } - else - { - angDir = pev->angles; - UTIL_MakeAimVectors( angDir ); - vecDirToEnemy = gpGlobals->v_forward; - } - - pev->effects = EF_MUZZLEFLASH; - - // make angles +-180 - if( angDir.x > 180 ) - { - angDir.x = angDir.x - 360; - } - - SetBlending( 0, angDir.x ); - GetAttachment( 0, vecArmPos, vecArmDir ); - - vecArmPos = vecArmPos + vecDirToEnemy * 32; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecArmPos ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( vecArmPos.x ); // pos - WRITE_COORD( vecArmPos.y ); - WRITE_COORD( vecArmPos.z ); - WRITE_SHORT( iAgruntMuzzleFlash ); // model - WRITE_BYTE( 6 ); // size * 10 - WRITE_BYTE( 128 ); // brightness - MESSAGE_END(); - - CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, UTIL_VecToAngles( vecDirToEnemy ), edict() ); - UTIL_MakeVectors ( pHornet->pev->angles ); - pHornet->pev->velocity = gpGlobals->v_forward * 300; - - switch( RANDOM_LONG ( 0 , 2 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "agrunt/ag_fire1.wav", 1.0, ATTN_NORM, 0, 100 ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "agrunt/ag_fire2.wav", 1.0, ATTN_NORM, 0, 100 ); - break; - case 2: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "agrunt/ag_fire3.wav", 1.0, ATTN_NORM, 0, 100 ); - break; - } - - CBaseMonster *pHornetMonster = pHornet->MyMonsterPointer(); - - if( pHornetMonster ) - { - pHornetMonster->m_hEnemy = m_hEnemy; - } - } - break; - case AGRUNT_AE_LEFT_FOOT: - switch( RANDOM_LONG( 0, 1 ) ) - { - // left foot - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_BODY, "player/pl_ladder2.wav", 1, ATTN_NORM, 0, 70 ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_BODY, "player/pl_ladder4.wav", 1, ATTN_NORM, 0, 70 ); - break; - } - break; - case AGRUNT_AE_RIGHT_FOOT: - // right foot - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_BODY, "player/pl_ladder1.wav", 1, ATTN_NORM, 0, 70 ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_BODY, "player/pl_ladder3.wav", 1, ATTN_NORM, 0 ,70); - break; - } - break; - - case AGRUNT_AE_LEFT_PUNCH: - { - CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); - - if( pHurt ) - { - pHurt->pev->punchangle.y = -25; - pHurt->pev->punchangle.x = 8; - - // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. - if( pHurt->IsPlayer() ) - { - // this is a player. Knock him around. - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 250; - } - - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - - Vector vecArmPos, vecArmAng; - GetAttachment( 0, vecArmPos, vecArmAng ); - SpawnBlood( vecArmPos, pHurt->BloodColor(), 25 );// a little surface blood. - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - } - } - break; - case AGRUNT_AE_RIGHT_PUNCH: - { - CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); - - if( pHurt ) - { - pHurt->pev->punchangle.y = 25; - pHurt->pev->punchangle.x = 8; - - // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. - if( pHurt->IsPlayer() ) - { - // this is a player. Knock him around. - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * -250; - } - - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - - Vector vecArmPos, vecArmAng; - GetAttachment( 0, vecArmPos, vecArmAng ); - SpawnBlood( vecArmPos, pHurt->BloodColor(), 25 );// a little surface blood. - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - } - } - break; - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CAGrunt::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/agrunt.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.agruntHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = 0; - m_afCapability |= bits_CAP_SQUAD; - - m_HackedGunPos = Vector( 24, 64, 48 ); - - m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG( 0, 10 ); - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CAGrunt::Precache() -{ - size_t i; - - PRECACHE_MODEL( "models/agrunt.mdl" ); - - for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND( pAttackHitSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND( pAttackMissSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND( pIdleSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pDieSounds ); i++ ) - PRECACHE_SOUND( pDieSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND( pPainSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND( pAttackSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND( pAlertSounds[i] ); - - PRECACHE_SOUND( "hassault/hw_shoot1.wav" ); - - iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" ); - - UTIL_PrecacheOther( "hornet" ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// Fail Schedule -//========================================================= -Task_t tlAGruntFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slAGruntFail[] = -{ - { - tlAGruntFail, - ARRAYSIZE( tlAGruntFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AGrunt Fail" - }, -}; - -//========================================================= -// Combat Fail Schedule -//========================================================= -Task_t tlAGruntCombatFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slAGruntCombatFail[] = -{ - { - tlAGruntCombatFail, - ARRAYSIZE( tlAGruntCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AGrunt Combat Fail" - }, -}; - -//========================================================= -// Standoff schedule. Used in combat when a monster is -// hiding in cover or the enemy has moved out of sight. -// Should we look around in this schedule? -//========================================================= -Task_t tlAGruntStandoff[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, -}; - -Schedule_t slAGruntStandoff[] = -{ - { - tlAGruntStandoff, - ARRAYSIZE( tlAGruntStandoff ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "Agrunt Standoff" - } -}; - -//========================================================= -// Suppress -//========================================================= -Task_t tlAGruntSuppressHornet[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slAGruntSuppress[] = -{ - { - tlAGruntSuppressHornet, - ARRAYSIZE( tlAGruntSuppressHornet ), - 0, - 0, - "AGrunt Suppress Hornet", - }, -}; - -//========================================================= -// primary range attacks -//========================================================= -Task_t tlAGruntRangeAttack1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slAGruntRangeAttack1[] = -{ - { - tlAGruntRangeAttack1, - ARRAYSIZE( tlAGruntRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE, - 0, - "AGrunt Range Attack1" - }, -}; - -Task_t tlAGruntHiddenRangeAttack1[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_STANDOFF }, - { TASK_AGRUNT_SETUP_HIDE_ATTACK, 0 }, - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, 0 }, - { TASK_RANGE_ATTACK1_NOTURN, (float)0 }, -}; - -Schedule_t slAGruntHiddenRangeAttack[] = -{ - { - tlAGruntHiddenRangeAttack1, - ARRAYSIZE ( tlAGruntHiddenRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "AGrunt Hidden Range Attack1" - }, -}; - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAGruntTakeCoverFromEnemy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAGruntTakeCoverFromEnemy[] = -{ - { - tlAGruntTakeCoverFromEnemy, - ARRAYSIZE( tlAGruntTakeCoverFromEnemy ), - bits_COND_NEW_ENEMY, - 0, - "AGruntTakeCoverFromEnemy" - }, -}; - -//========================================================= -// Victory dance! -//========================================================= -Task_t tlAGruntVictoryDance[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_AGRUNT_THREAT_DISPLAY }, - { TASK_WAIT, (float)0.2 }, - { TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, - { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, -}; - -Schedule_t slAGruntVictoryDance[] = -{ - { - tlAGruntVictoryDance, - ARRAYSIZE( tlAGruntVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "AGruntVictoryDance" - }, -}; - -//========================================================= -//========================================================= -Task_t tlAGruntThreatDisplay[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, -}; - -Schedule_t slAGruntThreatDisplay[] = -{ - { - tlAGruntThreatDisplay, - ARRAYSIZE( tlAGruntThreatDisplay ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - bits_SOUND_PLAYER | - bits_SOUND_COMBAT | - bits_SOUND_WORLD, - "AGruntThreatDisplay" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CAGrunt ) -{ - slAGruntFail, - slAGruntCombatFail, - slAGruntStandoff, - slAGruntSuppress, - slAGruntRangeAttack1, - slAGruntHiddenRangeAttack, - slAGruntTakeCoverFromEnemy, - slAGruntVictoryDance, - slAGruntThreatDisplay, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CAGrunt, CSquadMonster ) - -//========================================================= -// FCanCheckAttacks - this is overridden for alien grunts -// because they can use their smart weapons against unseen -// enemies. Base class doesn't attack anyone it can't see. -//========================================================= -BOOL CAGrunt::FCanCheckAttacks( void ) -{ - if( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// CheckMeleeAttack1 - alien grunts zap the crap out of -// any enemy that gets too close. -//========================================================= -BOOL CAGrunt::CheckMeleeAttack1( float flDot, float flDist ) -{ - if( HasConditions( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != 0 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 -// -// !!!LATER - we may want to load balance this. Several -// tracelines are done, so we may not want to do this every -// server frame. Definitely not while firing. -//========================================================= -BOOL CAGrunt::CheckRangeAttack1( float flDot, float flDist ) -{ - if( gpGlobals->time < m_flNextHornetAttackCheck ) - { - return m_fCanHornetAttack; - } - - if( HasConditions( bits_COND_SEE_ENEMY ) && flDist >= AGRUNT_MELEE_DIST && flDist <= 1024 && flDot >= 0.5 && NoFriendlyFire() ) - { - TraceResult tr; - Vector vecArmPos, vecArmDir; - - // verify that a shot fired from the gun will hit the enemy before the world. - // !!!LATER - we may wish to do something different for projectile weapons as opposed to instant-hit - UTIL_MakeVectors( pev->angles ); - GetAttachment( 0, vecArmPos, vecArmDir ); - //UTIL_TraceLine( vecArmPos, vecArmPos + gpGlobals->v_forward * 256, ignore_monsters, ENT( pev ), &tr ); - UTIL_TraceLine( vecArmPos, m_hEnemy->BodyTarget( vecArmPos ), dont_ignore_monsters, ENT( pev ), &tr ); - - if( tr.flFraction == 1.0 || tr.pHit == m_hEnemy->edict() ) - { - m_flNextHornetAttackCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); - m_fCanHornetAttack = TRUE; - return m_fCanHornetAttack; - } - } - - m_flNextHornetAttackCheck = gpGlobals->time + 0.2;// don't check for half second if this check wasn't successful - m_fCanHornetAttack = FALSE; - return m_fCanHornetAttack; -} - -//========================================================= -// StartTask -//========================================================= -void CAGrunt::StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE: - { - UTIL_MakeVectors( pev->angles ); - if( BuildRoute( m_vecEnemyLKP - gpGlobals->v_forward * 50, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else - { - ALERT( at_aiconsole, "AGruntGetPathToEnemyCorpse failed!!\n" ); - TaskFail(); - } - } - break; - case TASK_AGRUNT_SETUP_HIDE_ATTACK: - // alien grunt shoots hornets back out into the open from a concealed location. - // try to find a spot to throw that gives the smart weapon a good chance of finding the enemy. - // ideally, this spot is along a line that is perpendicular to a line drawn from the agrunt to the enemy. - CBaseMonster *pEnemyMonsterPtr; - - pEnemyMonsterPtr = m_hEnemy->MyMonsterPointer(); - - if( pEnemyMonsterPtr ) - { - Vector vecCenter; - TraceResult tr; - BOOL fSkip; - - fSkip = FALSE; - vecCenter = Center(); - - UTIL_VecToAngles( m_vecEnemyLKP - pev->origin ); - - UTIL_TraceLine( Center() + gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction == 1.0 ) - { - MakeIdealYaw( pev->origin + gpGlobals->v_right * 128 ); - fSkip = TRUE; - TaskComplete(); - } - - if( !fSkip ) - { - UTIL_TraceLine( Center() - gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction == 1.0 ) - { - MakeIdealYaw( pev->origin - gpGlobals->v_right * 128 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if( !fSkip ) - { - UTIL_TraceLine( Center() + gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction == 1.0 ) - { - MakeIdealYaw( pev->origin + gpGlobals->v_right * 256 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if( !fSkip ) - { - UTIL_TraceLine( Center() - gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction == 1.0 ) - { - MakeIdealYaw( pev->origin - gpGlobals->v_right * 256 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if( !fSkip ) - { - TaskFail(); - } - } - else - { - ALERT( at_aiconsole, "AGRunt - no enemy monster ptr!!!\n" ); - TaskFail(); - } - break; - default: - CSquadMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// 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 *CAGrunt::GetSchedule( void ) -{ - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if( pSound && ( pSound->m_iType & bits_SOUND_DANGER ) ) - { - // dangerous sound nearby! - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - } - - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { - // dead enemy - if( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster::GetSchedule(); - } - - if( HasConditions( bits_COND_NEW_ENEMY ) ) - { - return GetScheduleOfType( SCHED_WAKE_ANGRY ); - } - - // zap player! - if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - AttackSound();// this is a total hack. Should be parto f the schedule - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - - if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - // can attack - if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot ( bits_SLOTS_AGRUNT_HORNET ) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - if( OccupySlot ( bits_SLOT_AGRUNT_CHASE ) ) - { - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - - return GetScheduleOfType( SCHED_STANDOFF ); - } - break; - default: - break; - } - - return CSquadMonster::GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t *CAGrunt::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - return &slAGruntTakeCoverFromEnemy[0]; - break; - case SCHED_RANGE_ATTACK1: - if( HasConditions( bits_COND_SEE_ENEMY ) ) - { - //normal attack - return &slAGruntRangeAttack1[0]; - } - else - { - // attack an unseen enemy - // return &slAGruntHiddenRangeAttack[0]; - return &slAGruntRangeAttack1[0]; - } - break; - case SCHED_AGRUNT_THREAT_DISPLAY: - return &slAGruntThreatDisplay[0]; - break; - case SCHED_AGRUNT_SUPPRESS: - return &slAGruntSuppress[0]; - break; - case SCHED_STANDOFF: - return &slAGruntStandoff[0]; - break; - case SCHED_VICTORY_DANCE: - return &slAGruntVictoryDance[0]; - break; - case SCHED_FAIL: - // no fail schedule specified, so pick a good generic one. - { - if( m_hEnemy != 0 ) - { - // I have an enemy - // !!!LATER - what if this enemy is really far away and i'm chasing him? - // this schedule will make me stop, face his last known position for 2 - // seconds, and then try to move again - return &slAGruntCombatFail[0]; - } - - return &slAGruntFail[0]; - } - break; - } - - return CSquadMonster::GetScheduleOfType( Type ); -} diff --git a/dlls/apache.cpp b/dlls/apache.cpp deleted file mode 100644 index b3cfcf87..00000000 --- a/dlls/apache.cpp +++ /dev/null @@ -1,1027 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef OEM_BUILD - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -#define SF_WAITFORTRIGGER (0x04 | 0x40) // UNDONE: Fix! -#define SF_NOWRECKAGE 0x08 - -class CApache : public CBaseMonster -{ - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - int Classify( void ) { return CLASS_HUMAN_MILITARY; }; - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -300, -300, -172 ); - pev->absmax = pev->origin + Vector( 300, 300, 8 ); - } - - void EXPORT HuntThink( void ); - void EXPORT FlyTouch( CBaseEntity *pOther ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT NullThink( void ); - - void ShowDamage( void ); - void Flight( void ); - void FireRocket( void ); - BOOL FireGun( void ); - - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - - int m_iRockets; - float m_flForce; - float m_flNextRocket; - - Vector m_vecTarget; - Vector m_posTarget; - - Vector m_vecDesired; - Vector m_posDesired; - - Vector m_vecGoal; - - Vector m_angGun; - float m_flLastSeen; - float m_flPrevSeen; - - int m_iSoundState; // don't save this - - int m_iSpriteTexture; - int m_iExplode; - int m_iBodyGibs; - - float m_flGoalSpeed; - - int m_iDoSmokePuff; - CBeam *m_pBeam; -}; - -LINK_ENTITY_TO_CLASS( monster_apache, CApache ) - -TYPEDESCRIPTION CApache::m_SaveData[] = -{ - DEFINE_FIELD( CApache, m_iRockets, FIELD_INTEGER ), - DEFINE_FIELD( CApache, m_flForce, FIELD_FLOAT ), - DEFINE_FIELD( CApache, m_flNextRocket, FIELD_TIME ), - DEFINE_FIELD( CApache, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_posTarget, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CApache, m_vecDesired, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_posDesired, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CApache, m_vecGoal, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_angGun, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_flLastSeen, FIELD_TIME ), - DEFINE_FIELD( CApache, m_flPrevSeen, FIELD_TIME ), - //DEFINE_FIELD( CApache, m_iSoundState, FIELD_INTEGER ), // Don't save, precached - //DEFINE_FIELD( CApache, m_iSpriteTexture, FIELD_INTEGER ), - //DEFINE_FIELD( CApache, m_iExplode, FIELD_INTEGER ), - //DEFINE_FIELD( CApache, m_iBodyGibs, FIELD_INTEGER ), - DEFINE_FIELD( CApache, m_pBeam, FIELD_CLASSPTR ), - DEFINE_FIELD( CApache, m_flGoalSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CApache, m_iDoSmokePuff, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CApache, CBaseMonster ) - -void CApache::Spawn( void ) -{ - Precache(); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL( ENT( pev ), "models/apache.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.apacheHealth; - - m_flFieldOfView = -0.707; // 270 degrees - - pev->sequence = 0; - ResetSequenceInfo(); - pev->frame = RANDOM_LONG( 0, 0xFF ); - - InitBoneControllers(); - - if( pev->spawnflags & SF_WAITFORTRIGGER ) - { - SetUse( &CApache::StartupUse ); - } - else - { - SetThink( &CApache::HuntThink ); - SetTouch( &CApache::FlyTouch ); - pev->nextthink = gpGlobals->time + 1.0; - } - - m_iRockets = 10; -} - -void CApache::Precache( void ) -{ - PRECACHE_MODEL( "models/apache.mdl" ); - - PRECACHE_SOUND( "apache/ap_rotor1.wav" ); - PRECACHE_SOUND( "apache/ap_rotor2.wav" ); - PRECACHE_SOUND( "apache/ap_rotor3.wav" ); - PRECACHE_SOUND( "apache/ap_whine1.wav" ); - - PRECACHE_SOUND( "weapons/mortarhit.wav" ); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/white.spr" ); - - PRECACHE_SOUND( "turret/tu_fire1.wav" ); - - PRECACHE_MODEL( "sprites/lgtning.spr" ); - - m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); - m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" ); - - UTIL_PrecacheOther( "hvr_rocket" ); -} - -void CApache::NullThink( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.5; -} - -void CApache::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CApache::HuntThink ); - SetTouch( &CApache::FlyTouch ); - pev->nextthink = gpGlobals->time + 0.1; - SetUse( NULL ); -} - -void CApache::Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->gravity = 0.3; - - STOP_SOUND( ENT( pev ), CHAN_STATIC, "apache/ap_rotor2.wav" ); - - UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) ); - SetThink( &CApache::DyingThink ); - SetTouch( &CApache::CrashTouch ); - pev->nextthink = gpGlobals->time + 0.1; - pev->health = 0; - pev->takedamage = DAMAGE_NO; - - if( pev->spawnflags & SF_NOWRECKAGE ) - { - m_flNextRocket = gpGlobals->time + 4.0; - } - else - { - m_flNextRocket = gpGlobals->time + 15.0; - } -} - -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(); - - SetThink( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - -void CApache::FlyTouch( CBaseEntity *pOther ) -{ - // bounce if we hit something solid - if( pOther->pev->solid == SOLID_BSP ) - { - TraceResult tr = UTIL_GetGlobalTrace(); - - // UNDONE, do a real bounce - pev->velocity = pev->velocity + tr.vecPlaneNormal * ( pev->velocity.Length() + 200 ); - } -} - -void CApache::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if( pOther->pev->solid == SOLID_BSP ) - { - SetTouch( NULL ); - m_flNextRocket = gpGlobals->time; - pev->nextthink = gpGlobals->time; - } -} - -void CApache::GibMonster( void ) -{ - // EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200 ); -} - -void CApache::HuntThink( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - ShowDamage(); - - if( m_pGoalEnt == NULL && !FStringNull( pev->target ) )// this monster has a target - { - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) ); - if( m_pGoalEnt ) - { - m_posDesired = m_pGoalEnt->pev->origin; - UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); - m_vecGoal = gpGlobals->v_forward; - } - } - - // if( m_hEnemy == NULL ) - { - Look( 4092 ); - m_hEnemy = BestVisibleEnemy(); - } - - // generic speed up - if( m_flGoalSpeed < 800 ) - m_flGoalSpeed += 5; - - if( m_hEnemy != 0 ) - { - // ALERT( at_console, "%s\n", STRING( m_hEnemy->pev->classname ) ); - if( FVisible( m_hEnemy ) ) - { - if( m_flLastSeen < gpGlobals->time - 5 ) - m_flPrevSeen = gpGlobals->time; - m_flLastSeen = gpGlobals->time; - m_posTarget = m_hEnemy->Center(); - } - else - { - m_hEnemy = NULL; - } - } - - m_vecTarget = ( m_posTarget - pev->origin ).Normalize(); - - float flLength = ( pev->origin - m_posDesired ).Length(); - - if( m_pGoalEnt ) - { - // ALERT( at_console, "%.0f\n", flLength ); - - if( flLength < 128 ) - { - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_pGoalEnt->pev->target ) ); - if( m_pGoalEnt ) - { - m_posDesired = m_pGoalEnt->pev->origin; - UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); - m_vecGoal = gpGlobals->v_forward; - flLength = ( pev->origin - m_posDesired ).Length(); - } - } - } - else - { - m_posDesired = pev->origin; - } - - if( flLength > 250 ) // 500 - { - // float flLength2 = ( m_posTarget - pev->origin ).Length() * ( 1.5 - DotProduct( ( m_posTarget - pev->origin ).Normalize(), pev->velocity.Normalize() ) ); - // if( flLength2 < flLength ) - if( m_flLastSeen + 90 > gpGlobals->time && DotProduct( ( m_posTarget - pev->origin ).Normalize(), ( m_posDesired - pev->origin ).Normalize() ) > 0.25 ) - { - m_vecDesired = ( m_posTarget - pev->origin ).Normalize(); - } - else - { - m_vecDesired = ( m_posDesired - pev->origin ).Normalize(); - } - } - else - { - m_vecDesired = m_vecGoal; - } - - Flight(); - - // ALERT( at_console, "%.0f %.0f %.0f\n", gpGlobals->time, m_flLastSeen, m_flPrevSeen ); - if( ( m_flLastSeen + 1 > gpGlobals->time ) && ( m_flPrevSeen + 2 < gpGlobals->time ) ) - { - if( FireGun() ) - { - // slow down if we're fireing - if( m_flGoalSpeed > 400 ) - m_flGoalSpeed = 400; - } - - // don't fire rockets and gun on easy mode - if( g_iSkillLevel == SKILL_EASY ) - m_flNextRocket = gpGlobals->time + 10.0; - } - - UTIL_MakeAimVectors( pev->angles ); - Vector vecEst = ( gpGlobals->v_forward * 800 + pev->velocity ).Normalize(); - // ALERT( at_console, "%d %d %d %4.2f\n", pev->angles.x < 0, DotProduct( pev->velocity, gpGlobals->v_forward ) > -100, m_flNextRocket < gpGlobals->time, DotProduct( m_vecTarget, vecEst ) ); - - if( ( m_iRockets % 2 ) == 1 ) - { - FireRocket(); - m_flNextRocket = gpGlobals->time + 0.5; - if( m_iRockets <= 0 ) - { - m_flNextRocket = gpGlobals->time + 10; - m_iRockets = 10; - } - } - else if( pev->angles.x < 0 && DotProduct( pev->velocity, gpGlobals->v_forward ) > -100 && m_flNextRocket < gpGlobals->time ) - { - if( m_flLastSeen + 60 > gpGlobals->time ) - { - if( m_hEnemy != 0 ) - { - // make sure it's a good shot - if( DotProduct( m_vecTarget, vecEst ) > .965 ) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, ignore_monsters, edict(), &tr ); - if( (tr.vecEndPos - m_posTarget ).Length() < 512 ) - FireRocket(); - } - } - else - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, dont_ignore_monsters, edict(), &tr ); - // just fire when close - if( ( tr.vecEndPos - m_posTarget ).Length() < 512 ) - FireRocket(); - } - } - } -} - -void CApache::Flight( void ) -{ - // tilt model 5 degrees - Vector vecAdj = Vector( 5.0, 0, 0 ); - - // estimate where I'll be facing in one seconds - UTIL_MakeAimVectors( pev->angles + pev->avelocity * 2 + vecAdj ); - // Vector vecEst1 = pev->origin + pev->velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 ); - // float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right ); - - float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); - - if( flSide < 0 ) - { - if( pev->avelocity.y < 60 ) - { - pev->avelocity.y += 8; // 9 * ( 3.0 / 2.0 ); - } - } - else - { - if( pev->avelocity.y > -60 ) - { - pev->avelocity.y -= 8; // 9 * ( 3.0 / 2.0 ); - } - } - pev->avelocity.y *= 0.98; - - // estimate where I'll be in two seconds - UTIL_MakeAimVectors( pev->angles + pev->avelocity * 1 + vecAdj ); - Vector vecEst = pev->origin + pev->velocity * 2.0 + gpGlobals->v_up * m_flForce * 20 - Vector( 0, 0, 384 * 2 ); - - // add immediate force - UTIL_MakeAimVectors( pev->angles + vecAdj ); - pev->velocity.x += gpGlobals->v_up.x * m_flForce; - pev->velocity.y += gpGlobals->v_up.y * m_flForce; - pev->velocity.z += gpGlobals->v_up.z * m_flForce; - // add gravity - pev->velocity.z -= 38.4; // 32ft/sec - - - float flSpeed = pev->velocity.Length(); - float flDir = DotProduct( Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, 0 ), Vector( pev->velocity.x, pev->velocity.y, 0 ) ); - if( flDir < 0 ) - flSpeed = -flSpeed; - - float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); - - // float flSlip = DotProduct( pev->velocity, gpGlobals->v_right ); - float flSlip = -DotProduct( m_posDesired - vecEst, gpGlobals->v_right ); - - // fly sideways - if( flSlip > 0 ) - { - if( pev->angles.z > -30 && pev->avelocity.z > -15 ) - pev->avelocity.z -= 4; - else - pev->avelocity.z += 2; - } - else - { - if( pev->angles.z < 30 && pev->avelocity.z < 15 ) - pev->avelocity.z += 4; - else - pev->avelocity.z -= 2; - } - - // sideways drag - pev->velocity.x = pev->velocity.x * ( 1.0 - fabs( gpGlobals->v_right.x ) * 0.05 ); - pev->velocity.y = pev->velocity.y * ( 1.0 - fabs( gpGlobals->v_right.y ) * 0.05 ); - pev->velocity.z = pev->velocity.z * ( 1.0 - fabs( gpGlobals->v_right.z ) * 0.05 ); - - // general drag - pev->velocity = pev->velocity * 0.995; - - // apply power to stay correct height - if( m_flForce < 80 && vecEst.z < m_posDesired.z ) - { - m_flForce += 12; - } - else if( m_flForce > 30 ) - { - if( vecEst.z > m_posDesired.z ) - m_flForce -= 8; - } - - // pitch forward or back to get to target - if( flDist > 0 && flSpeed < m_flGoalSpeed /* && flSpeed < flDist */ && pev->angles.x + pev->avelocity.x > -40 ) - { - // ALERT( at_console, "F " ); - // lean forward - pev->avelocity.x -= 12.0; - } - else if( flDist < 0 && flSpeed > -50 && pev->angles.x + pev->avelocity.x < 20 ) - { - // ALERT( at_console, "B " ); - // lean backward - pev->avelocity.x += 12.0; - } - else if( pev->angles.x + pev->avelocity.x > 0 ) - { - // ALERT( at_console, "f " ); - pev->avelocity.x -= 4.0; - } - else if( pev->angles.x + pev->avelocity.x < 0 ) - { - // ALERT( at_console, "b " ); - pev->avelocity.x += 4.0; - } - - // ALERT( at_console, "%.0f %.0f : %.0f %.0f : %.0f %.0f : %.0f\n", pev->origin.x, pev->velocity.x, flDist, flSpeed, pev->angles.x, pev->avelocity.x, m_flForce ); - // ALERT( at_console, "%.0f %.0f : %.0f %0.f : %.0f\n", pev->origin.z, pev->velocity.z, vecEst.z, m_posDesired.z, m_flForce ); - - // make rotor, engine sounds - if( m_iSoundState == 0 ) - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_rotor2.wav", 1.0, 0.3, 0, 110 ); - // EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - } - else - { - CBaseEntity *pPlayer = NULL; - - pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - // UNDONE: this needs to send different sounds to every player for multiplayer. - if( pPlayer ) - { - float pitch = DotProduct( pev->velocity - pPlayer->pev->velocity, ( pPlayer->pev->origin - pev->origin ).Normalize() ); - - pitch = (int)( 100 + pitch / 50.0 ); - - if( pitch > 250 ) - pitch = 250; - if( pitch < 50 ) - pitch = 50; - if( pitch == 100 ) - pitch = 101; - - float flVol = ( m_flForce / 100.0 ) + .1; - if( flVol > 1.0 ) - flVol = 1.0; - - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_rotor2.wav", 1.0, 0.3, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch ); - } - // EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch ); - - // ALERT( at_console, "%.0f %.2f\n", pitch, flVol ); - } -} - -void CApache::FireRocket( void ) -{ - static float side = 1.0; - - if( m_iRockets <= 0 ) - return; - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + 1.5 * ( gpGlobals->v_forward * 21 + gpGlobals->v_right * 70 * side + gpGlobals->v_up * -79 ); - - switch( m_iRockets % 5 ) - { - case 0: - vecSrc = vecSrc + gpGlobals->v_right * 10; - break; - case 1: - vecSrc = vecSrc - gpGlobals->v_right * 10; - break; - case 2: - vecSrc = vecSrc + gpGlobals->v_up * 10; - break; - case 3: - vecSrc = vecSrc - gpGlobals->v_up * 10; - break; - case 4: - break; - } - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - - CBaseEntity *pRocket = CBaseEntity::Create( "hvr_rocket", vecSrc, pev->angles, edict() ); - if( pRocket ) - pRocket->pev->velocity = pev->velocity + gpGlobals->v_forward * 100; - - m_iRockets--; - - side = - side; -} - -BOOL CApache::FireGun() -{ - UTIL_MakeAimVectors( pev->angles ); - - Vector posGun, angGun; - GetAttachment( 1, posGun, angGun ); - - Vector vecTarget = ( m_posTarget - posGun ).Normalize(); - - Vector vecOut; - - vecOut.x = DotProduct( gpGlobals->v_forward, vecTarget ); - vecOut.y = -DotProduct( gpGlobals->v_right, vecTarget ); - vecOut.z = DotProduct( gpGlobals->v_up, vecTarget ); - - Vector angles = UTIL_VecToAngles( vecOut ); - - angles.x = -angles.x; - if( angles.y > 180 ) - angles.y = angles.y - 360; - if( angles.y < -180 ) - angles.y = angles.y + 360; - if( angles.x > 180 ) - angles.x = angles.x - 360; - if( angles.x < -180 ) - angles.x = angles.x + 360; - - if( angles.x > m_angGun.x ) - m_angGun.x = Q_min( angles.x, m_angGun.x + 12 ); - if( angles.x < m_angGun.x ) - m_angGun.x = Q_max( angles.x, m_angGun.x - 12 ); - if( angles.y > m_angGun.y ) - m_angGun.y = Q_min( angles.y, m_angGun.y + 12 ); - if( angles.y < m_angGun.y ) - m_angGun.y = Q_max( angles.y, m_angGun.y - 12 ); - - m_angGun.y = SetBoneController( 0, m_angGun.y ); - m_angGun.x = SetBoneController( 1, m_angGun.x ); - - Vector posBarrel, angBarrel; - GetAttachment( 0, posBarrel, angBarrel ); - Vector vecGun = ( posBarrel - posGun ).Normalize(); - - if( DotProduct( vecGun, vecTarget ) > 0.98 ) - { -#if 1 - FireBullets( 1, posGun, vecGun, VECTOR_CONE_4DEGREES, 8192, BULLET_MONSTER_12MM, 1 ); - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.3 ); -#else - static float flNext; - TraceResult tr; - UTIL_TraceLine( posGun, posGun + vecGun * 8192, dont_ignore_monsters, ENT( pev ), &tr ); - - if( !m_pBeam ) - { - m_pBeam = CBeam::BeamCreate( "sprites/lgtning.spr", 80 ); - m_pBeam->PointEntInit( pev->origin, entindex() ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->SetColor( 255, 180, 96 ); - m_pBeam->SetBrightness( 192 ); - } - - if( flNext < gpGlobals->time ) - { - flNext = gpGlobals->time + 0.5; - m_pBeam->SetStartPos( tr.vecEndPos ); - } -#endif - return TRUE; - } - else - { - if( m_pBeam ) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } - } - return FALSE; -} - -void CApache::ShowDamage( void ) -{ - if( m_iDoSmokePuff > 0 || RANDOM_LONG( 0, 99 ) > pev->health ) - { - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z - 32 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG( 0, 9 ) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - } - if( m_iDoSmokePuff > 0 ) - m_iDoSmokePuff--; -} - -int CApache::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if( pevInflictor->owner == edict() ) - return 0; - - if( bitsDamageType & DMG_BLAST ) - { - flDamage *= 2; - } - - /* - if( ( bitsDamageType & DMG_BULLET ) && flDamage > 50 ) - { - // clip bullet damage at 50 - flDamage = 50; - } - */ - - // ALERT( at_console, "%.0f\n", flDamage ); - return CBaseEntity::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CApache::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); - - // ignore blades - if( ptr->iHitgroup == 6 && ( bitsDamageType & ( DMG_ENERGYBEAM | DMG_BULLET | DMG_CLUB ) ) ) - return; - - // hit hard, hits cockpit, hits engines - if( flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2 ) - { - // ALERT( at_console, "%.0f\n", flDamage ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - m_iDoSmokePuff = 3 + ( flDamage / 5.0 ); - } - else - { - // do half damage in the body - // AddMultiDamage( pevAttacker, this, flDamage / 2.0, bitsDamageType ); - UTIL_Ricochet( ptr->vecEndPos, 2.0 ); - } -} - -class CApacheHVR : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void EXPORT IgniteThink( void ); - void EXPORT AccelerateThink( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_iTrail; - Vector m_vecForward; -}; - -LINK_ENTITY_TO_CLASS( hvr_rocket, CApacheHVR ) - -TYPEDESCRIPTION CApacheHVR::m_SaveData[] = -{ - //DEFINE_FIELD( CApacheHVR, m_iTrail, FIELD_INTEGER ), // Dont' save, precache - DEFINE_FIELD( CApacheHVR, m_vecForward, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CApacheHVR, CGrenade ) - -void CApacheHVR::Spawn( void ) -{ - Precache(); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL( ENT( pev ), "models/HVR.mdl" ); - UTIL_SetSize( pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CApacheHVR::IgniteThink ); - SetTouch( &CGrenade::ExplodeTouch ); - - UTIL_MakeAimVectors( pev->angles ); - m_vecForward = gpGlobals->v_forward; - pev->gravity = 0.5; - - pev->nextthink = gpGlobals->time + 0.1; - - pev->dmg = 150; -} - -void CApacheHVR::Precache( void ) -{ - PRECACHE_MODEL( "models/HVR.mdl" ); - m_iTrail = PRECACHE_MODEL( "sprites/smoke.spr" ); - PRECACHE_SOUND("weapons/rocket1.wav"); -} - -void CApacheHVR::IgniteThink( void ) -{ - // pev->movetype = MOVETYPE_TOSS; - - // pev->movetype = MOVETYPE_FLY; - pev->effects |= EF_LIGHT; - - // make rocket sound - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); - - // rocket trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT( entindex() ); // entity - WRITE_SHORT( m_iTrail ); // model - WRITE_BYTE( 15 ); // life - WRITE_BYTE( 5 ); // width - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) - - // set to accelerate - SetThink( &CApacheHVR::AccelerateThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CApacheHVR::AccelerateThink( void ) -{ - // check world boundaries - if( pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096 ) - { - UTIL_Remove( this ); - return; - } - - // accelerate - float flSpeed = pev->velocity.Length(); - if( flSpeed < 1800 ) - { - pev->velocity = pev->velocity + m_vecForward * 200; - } - - // re-aim - pev->angles = UTIL_VecToAngles( pev->velocity ); - - pev->nextthink = gpGlobals->time + 0.1; -} -#endif diff --git a/dlls/barnacle.cpp b/dlls/barnacle.cpp deleted file mode 100644 index ecc1f5d4..00000000 --- a/dlls/barnacle.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// barnacle - stationary ceiling mounted 'fishing' monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -#define BARNACLE_BODY_HEIGHT 44 // how 'tall' the barnacle's model is. -#define BARNACLE_PULL_SPEED 8 -#define BARNACLE_KILL_VICTIM_DELAY 5 // how many seconds after pulling prey in to gib them. - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BARNACLE_AE_PUKEGIB 2 - -class CBarnacle : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - CBaseEntity *TongueTouchEnt( float *pflLength ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void EXPORT BarnacleThink( void ); - void EXPORT WaitTillDead( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flAltitude; - float m_flCachedLength; // tongue cached length - float m_flKillVictimTime; - int m_cGibs; // barnacle loads up on gibs each time it kills something. - BOOL m_fTongueExtended; - BOOL m_fLiftingPrey; - float m_flTongueAdj; - - // FIXME: need a custom barnacle model with non-generic hitgroup - // otherwise we can apply to damage to tongue instead of body -#ifdef BARNACLE_FIX_VISIBILITY - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -16, -16, -m_flCachedLength ); - pev->absmax = pev->origin + Vector( 16, 16, 0 ); - } -#endif -}; - -LINK_ENTITY_TO_CLASS( monster_barnacle, CBarnacle ) - -TYPEDESCRIPTION CBarnacle::m_SaveData[] = -{ - DEFINE_FIELD( CBarnacle, m_flAltitude, FIELD_FLOAT ), - DEFINE_FIELD( CBarnacle, m_flKillVictimTime, FIELD_TIME ), - DEFINE_FIELD( CBarnacle, m_cGibs, FIELD_INTEGER ),// barnacle loads up on gibs each time it kills something. - DEFINE_FIELD( CBarnacle, m_fTongueExtended, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarnacle, m_fLiftingPrey, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarnacle, m_flTongueAdj, FIELD_FLOAT ), - DEFINE_FIELD( CBarnacle, m_flCachedLength, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBarnacle, CBaseMonster ) - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBarnacle::Classify( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBarnacle::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BARNACLE_AE_PUKEGIB: - CGib::SpawnRandomGibs( pev, 1, 1 ); - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CBarnacle::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/barnacle.mdl" ); - UTIL_SetSize( pev, Vector( -16, -16, -32 ), Vector( 16, 16, 0 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_AIM; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = EF_INVLIGHT; // take light from the ceiling - pev->health = 25; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_flKillVictimTime = 0; - m_flCachedLength = 32; // mins.z - m_cGibs = 0; - m_fLiftingPrey = FALSE; - m_flTongueAdj = -100; - - InitBoneControllers(); - - SetActivity( ACT_IDLE ); - - SetThink( &CBarnacle::BarnacleThink ); - pev->nextthink = gpGlobals->time + 0.5; - - UTIL_SetOrigin( pev, pev->origin ); -} - -int CBarnacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if( bitsDamageType & DMG_CLUB ) - { - flDamage = pev->health; - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -//========================================================= -void CBarnacle::BarnacleThink( void ) -{ - CBaseEntity *pTouchEnt; - CBaseMonster *pVictim; - float flLength; -#ifdef BARNACLE_FIX_VISIBILITY - if( m_flCachedLength != ( m_flAltitude + m_flTongueAdj ) || ( pev->absmin.z != pev->origin.z + -m_flCachedLength ) ) - { - // recalc collision box here to avoid barnacle disappears bug - m_flCachedLength = m_flAltitude + m_flTongueAdj; - UTIL_SetOrigin( pev, pev->origin ); - } -#endif - pev->nextthink = gpGlobals->time + 0.1; - - if( m_hEnemy != 0 ) - { - // barnacle has prey. - if( !m_hEnemy->IsAlive() ) - { - // someone (maybe even the barnacle) killed the prey. Reset barnacle. - m_fLiftingPrey = FALSE;// indicate that we're not lifting prey. - m_hEnemy = NULL; - return; - } - - if( m_fLiftingPrey ) - { - if( m_hEnemy != 0 && m_hEnemy->pev->deadflag != DEAD_NO ) - { - // crap, someone killed the prey on the way up. - m_hEnemy = NULL; - m_fLiftingPrey = FALSE; - return; - } - - // still pulling prey. - Vector vecNewEnemyOrigin = m_hEnemy->pev->origin; - vecNewEnemyOrigin.x = pev->origin.x; - vecNewEnemyOrigin.y = pev->origin.y; - - // guess as to where their neck is - vecNewEnemyOrigin.x -= 6 * cos( m_hEnemy->pev->angles.y * M_PI / 180.0 ); - vecNewEnemyOrigin.y -= 6 * sin( m_hEnemy->pev->angles.y * M_PI / 180.0 ); - - m_flAltitude -= BARNACLE_PULL_SPEED; - vecNewEnemyOrigin.z += BARNACLE_PULL_SPEED; - - if( fabs( pev->origin.z - ( vecNewEnemyOrigin.z + m_hEnemy->pev->view_ofs.z - 8 ) ) < BARNACLE_BODY_HEIGHT ) - { - // prey has just been lifted into position ( if the victim origin + eye height + 8 is higher than the bottom of the barnacle, it is assumed that the head is within barnacle's body ) - m_fLiftingPrey = FALSE; - - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_bite3.wav", 1, ATTN_NORM ); - - pVictim = m_hEnemy->MyMonsterPointer(); - - m_flKillVictimTime = gpGlobals->time + 10;// now that the victim is in place, the killing bite will be administered in 10 seconds. - - if( pVictim ) - { - pVictim->BarnacleVictimBitten( pev ); - SetActivity( ACT_EAT ); - } - } - - UTIL_SetOrigin( m_hEnemy->pev, vecNewEnemyOrigin ); - } - else - { - // prey is lifted fully into feeding position and is dangling there. - pVictim = m_hEnemy->MyMonsterPointer(); - - if( m_flKillVictimTime != -1 && gpGlobals->time > m_flKillVictimTime ) - { - // kill! - if( pVictim ) - { - pVictim->TakeDamage( pev, pev, pVictim->pev->health, DMG_SLASH | DMG_ALWAYSGIB ); - m_cGibs = 3; - } - - return; - } - - // bite prey every once in a while - if( pVictim && ( RANDOM_LONG( 0, 49 ) == 0 ) ) - { - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); - break; - } - - pVictim->BarnacleVictimBitten( pev ); - } - } - } - else - { - // barnacle has no prey right now, so just idle and check to see if anything is touching the tongue. - // If idle and no nearby client, don't think so often - if( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 1, 1.5 ); // Stagger a bit to keep barnacles from thinking on the same frame - - if( m_fSequenceFinished ) - { - // this is done so barnacle will fidget. - SetActivity ( ACT_IDLE ); - m_flTongueAdj = -100; - } - - if( m_cGibs && RANDOM_LONG( 0, 99 ) == 1 ) - { - // cough up a gib. - CGib::SpawnRandomGibs( pev, 1, 1 ); - m_cGibs--; - - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); - break; - } - } - - pTouchEnt = TongueTouchEnt( &flLength ); - - if( pTouchEnt != NULL && m_fTongueExtended ) - { - // tongue is fully extended, and is touching someone. - if( pTouchEnt->FBecomeProne() ) - { - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_alert2.wav", 1, ATTN_NORM ); - - SetSequenceByName( "attack1" ); - m_flTongueAdj = -20; - - m_hEnemy = pTouchEnt; - - pTouchEnt->pev->movetype = MOVETYPE_FLY; - pTouchEnt->pev->velocity = g_vecZero; - pTouchEnt->pev->basevelocity = g_vecZero; - pTouchEnt->pev->origin.x = pev->origin.x; - pTouchEnt->pev->origin.y = pev->origin.y; - - m_fLiftingPrey = TRUE;// indicate that we should be lifting prey. - m_flKillVictimTime = -1;// set this to a bogus time while the victim is lifted. - - m_flAltitude = pev->origin.z - pTouchEnt->EyePosition().z; - } - } - else - { - // calculate a new length for the tongue to be clear of anything else that moves under it. - if( m_flAltitude < flLength ) - { - // if tongue is higher than is should be, lower it kind of slowly. - m_flAltitude += BARNACLE_PULL_SPEED; - m_fTongueExtended = FALSE; - } - else - { - m_flAltitude = flLength; - m_fTongueExtended = TRUE; - } - } - } - - // ALERT( at_console, "tounge %f\n", m_flAltitude + m_flTongueAdj ); - SetBoneController( 0, -( m_flAltitude + m_flTongueAdj ) ); - StudioFrameAdvance( 0.1 ); -} - -//========================================================= -// Killed. -//========================================================= -void CBarnacle::Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster *pVictim; - - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - - if( m_hEnemy != 0 ) - { - pVictim = m_hEnemy->MyMonsterPointer(); - - if( pVictim ) - { - pVictim->BarnacleVictimReleased(); - } - } - - //CGib::SpawnRandomGibs( pev, 4, 1 ); - - switch( RANDOM_LONG ( 0, 1 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_die1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "barnacle/bcl_die3.wav", 1, ATTN_NORM ); - break; - } - - SetActivity( ACT_DIESIMPLE ); - SetBoneController( 0, 0 ); - - StudioFrameAdvance( 0.1 ); - - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CBarnacle::WaitTillDead ); -} - -//========================================================= -//========================================================= -void CBarnacle::WaitTillDead( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - float flInterval = StudioFrameAdvance( 0.1 ); - DispatchAnimEvents( flInterval ); - - if( m_fSequenceFinished ) - { - // death anim finished. - StopAnimation(); - SetThink( NULL ); - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBarnacle::Precache() -{ - PRECACHE_MODEL( "models/barnacle.mdl" ); - - PRECACHE_SOUND( "barnacle/bcl_alert2.wav" );//happy, lifting food up - PRECACHE_SOUND( "barnacle/bcl_bite3.wav" );//just got food to mouth - PRECACHE_SOUND( "barnacle/bcl_chew1.wav" ); - PRECACHE_SOUND( "barnacle/bcl_chew2.wav" ); - PRECACHE_SOUND( "barnacle/bcl_chew3.wav" ); - PRECACHE_SOUND( "barnacle/bcl_die1.wav" ); - PRECACHE_SOUND( "barnacle/bcl_die3.wav" ); -} - -//========================================================= -// TongueTouchEnt - does a trace along the barnacle's tongue -// to see if any entity is touching it. Also stores the length -// of the trace in the int pointer provided. -//========================================================= -#define BARNACLE_CHECK_SPACING 8 -CBaseEntity *CBarnacle::TongueTouchEnt( float *pflLength ) -{ - TraceResult tr; - float length; - - // trace once to hit architecture and see if the tongue needs to change position. - UTIL_TraceLine( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT( pev ), &tr ); - length = fabs( pev->origin.z - tr.vecEndPos.z ); - if( pflLength ) - { - *pflLength = length; - } - - Vector delta = Vector( BARNACLE_CHECK_SPACING, BARNACLE_CHECK_SPACING, 0 ); - Vector mins = pev->origin - delta; - Vector maxs = pev->origin + delta; - maxs.z = pev->origin.z; - mins.z -= length; - - CBaseEntity *pList[10]; - int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, ( FL_CLIENT | FL_MONSTER ) ); - if( count ) - { - for( int i = 0; i < count; i++ ) - { - // only clients and monsters - if( pList[i] != this && IRelationship( pList[i] ) > R_NO && pList[ i ]->pev->deadflag == DEAD_NO ) // this ent is one of our enemies. Barnacle tries to eat it. - { - return pList[i]; - } - } - } - - return NULL; -} diff --git a/dlls/barney.cpp b/dlls/barney.cpp deleted file mode 100644 index 3fc5aef0..00000000 --- a/dlls/barney.cpp +++ /dev/null @@ -1,826 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// monster template -//========================================================= -// UNDONE: Holster weapon? - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "talkmonster.h" -#include "schedule.h" -#include "defaultai.h" -#include "scripted.h" -#include "weapons.h" -#include "soundent.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -// first flag is barney dying for scripted sequences? -#define BARNEY_AE_DRAW ( 2 ) -#define BARNEY_AE_SHOOT ( 3 ) -#define BARNEY_AE_HOLSTER ( 4 ) - -#define BARNEY_BODY_GUNHOLSTERED 0 -#define BARNEY_BODY_GUNDRAWN 1 -#define BARNEY_BODY_GUNGONE 2 - -class CBarney : public CTalkMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - void BarneyFirePistol( void ); - void AlertSound( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; } - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - BOOL CheckRangeAttack1( float flDot, float flDist ); - - void DeclineFollowing( void ); - - // Override these to set behavior - Schedule_t *GetScheduleOfType( int Type ); - Schedule_t *GetSchedule( void ); - MONSTERSTATE GetIdealState( void ); - - void DeathSound( void ); - void PainSound( void ); - - void TalkInit( void ); - - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - void Killed( entvars_t *pevAttacker, int iGib ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BOOL m_fGunDrawn; - float m_painTime; - float m_checkAttackTime; - BOOL m_lastAttackCheck; - - // UNDONE: What is this for? It isn't used? - float m_flPlayerDamage;// how much pain has the player inflicted on me? - - CUSTOM_SCHEDULES -}; - -LINK_ENTITY_TO_CLASS( monster_barney, CBarney ) - -TYPEDESCRIPTION CBarney::m_SaveData[] = -{ - DEFINE_FIELD( CBarney, m_fGunDrawn, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarney, m_painTime, FIELD_TIME ), - DEFINE_FIELD( CBarney, m_checkAttackTime, FIELD_TIME ), - DEFINE_FIELD( CBarney, m_lastAttackCheck, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarney, m_flPlayerDamage, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBarney, CTalkMonster ) - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlBaFollow[] = -{ - { TASK_MOVE_TO_TARGET_RANGE, (float)128 }, // Move within 128 of target ent (client) - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slBaFollow[] = -{ - { - tlBaFollow, - ARRAYSIZE( tlBaFollow ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - bits_SOUND_DANGER, - "Follow" - }, -}; - -//========================================================= -// BarneyDraw - much better looking draw schedule for when -// barney knows who he's gonna attack. -//========================================================= -Task_t tlBarneyEnemyDraw[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, 0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM }, -}; - -Schedule_t slBarneyEnemyDraw[] = -{ - { - tlBarneyEnemyDraw, - ARRAYSIZE( tlBarneyEnemyDraw ), - 0, - 0, - "Barney Enemy Draw" - } -}; - -Task_t tlBaFaceTarget[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE }, -}; - -Schedule_t slBaFaceTarget[] = -{ - { - tlBaFaceTarget, - ARRAYSIZE( tlBaFaceTarget ), - bits_COND_CLIENT_PUSH | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - bits_SOUND_DANGER, - "FaceTarget" - }, -}; - -Task_t tlIdleBaStand[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds. - { TASK_TLK_HEADRESET, (float)0 }, // reset head position -}; - -Schedule_t slIdleBaStand[] = -{ - { - tlIdleBaStand, - ARRAYSIZE( tlIdleBaStand ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_PROVOKED, - bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "IdleStand" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CBarney ) -{ - slBaFollow, - slBarneyEnemyDraw, - slBaFaceTarget, - slIdleBaStand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster ) - -void CBarney::StartTask( Task_t *pTask ) -{ - CTalkMonster::StartTask( pTask ); -} - -void CBarney::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - if( m_hEnemy != 0 && ( m_hEnemy->IsPlayer() ) ) - { - pev->framerate = 1.5; - } - CTalkMonster::RunTask( pTask ); - break; - default: - CTalkMonster::RunTask( pTask ); - break; - } -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CBarney::ISoundMask( void) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_CARCASS | - bits_SOUND_MEAT | - bits_SOUND_GARBAGE | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBarney::Classify( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// ALertSound - barney says "Freeze!" -//========================================================= -void CBarney::AlertSound( void ) -{ - if( m_hEnemy != 0 ) - { - if( FOkToSpeak() ) - { - PlaySentence( "BA_ATTACK", RANDOM_FLOAT( 2.8, 3.2 ), VOL_NORM, ATTN_IDLE ); - } - } -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBarney::SetYawSpeed( void ) -{ - int ys; - - ys = 0; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 70; - break; - case ACT_WALK: - ys = 70; - break; - case ACT_RUN: - ys = 90; - break; - default: - ys = 70; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CBarney::CheckRangeAttack1( float flDot, float flDist ) -{ - if( flDist <= 1024 && flDot >= 0.5 ) - { - if( gpGlobals->time > m_checkAttackTime ) - { - TraceResult tr; - - Vector shootOrigin = pev->origin + Vector( 0, 0, 55 ); - CBaseEntity *pEnemy = m_hEnemy; - Vector shootTarget = ( ( pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin ) + m_vecEnemyLKP ); - UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT( pev ), &tr ); - m_checkAttackTime = gpGlobals->time + 1; - if( tr.flFraction == 1.0 || ( tr.pHit != NULL && CBaseEntity::Instance( tr.pHit ) == pEnemy ) ) - m_lastAttackCheck = TRUE; - else - m_lastAttackCheck = FALSE; - m_checkAttackTime = gpGlobals->time + 1.5; - } - return m_lastAttackCheck; - } - return FALSE; -} - -//========================================================= -// BarneyFirePistol - shoots one round from the pistol at -// the enemy barney is facing. -//========================================================= -void CBarney::BarneyFirePistol( void ) -{ - Vector vecShootOrigin; - - UTIL_MakeVectors( pev->angles ); - vecShootOrigin = pev->origin + Vector( 0, 0, 55 ); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); - pev->effects = EF_MUZZLEFLASH; - - FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM ); - - int pitchShift = RANDOM_LONG( 0, 20 ); - - // Only shift about half the time - if( pitchShift > 10 ) - pitchShift = 0; - else - pitchShift -= 5; - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "barney/ba_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift ); - - CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); - - // UNDONE: Reload? - m_cAmmoLoaded--;// take away a bullet! -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBarney::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BARNEY_AE_SHOOT: - BarneyFirePistol(); - break; - case BARNEY_AE_DRAW: - // barney's bodygroup switches here so he can pull gun from holster - pev->body = BARNEY_BODY_GUNDRAWN; - m_fGunDrawn = TRUE; - break; - case BARNEY_AE_HOLSTER: - // change bodygroup to replace gun in holster - pev->body = BARNEY_BODY_GUNHOLSTERED; - m_fGunDrawn = FALSE; - break; - default: - CTalkMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CBarney::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/barney.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = gSkillData.barneyHealth; - pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - - pev->body = 0; // gun in holster - m_fGunDrawn = FALSE; - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; - - MonsterInit(); - SetUse( &CTalkMonster::FollowerUse ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBarney::Precache() -{ - PRECACHE_MODEL( "models/barney.mdl" ); - - PRECACHE_SOUND( "barney/ba_attack1.wav" ); - PRECACHE_SOUND( "barney/ba_attack2.wav" ); - - PRECACHE_SOUND( "barney/ba_pain1.wav" ); - PRECACHE_SOUND( "barney/ba_pain2.wav" ); - PRECACHE_SOUND( "barney/ba_pain3.wav" ); - - PRECACHE_SOUND( "barney/ba_die1.wav" ); - PRECACHE_SOUND( "barney/ba_die2.wav" ); - PRECACHE_SOUND( "barney/ba_die3.wav" ); - - // every new barney must call this, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - TalkInit(); - CTalkMonster::Precache(); -} - -// Init talk data -void CBarney::TalkInit() -{ - CTalkMonster::TalkInit(); - - // scientists speach group names (group names are in sentences.txt) - m_szGrp[TLK_ANSWER] = "BA_ANSWER"; - m_szGrp[TLK_QUESTION] = "BA_QUESTION"; - m_szGrp[TLK_IDLE] = "BA_IDLE"; - m_szGrp[TLK_STARE] = "BA_STARE"; - m_szGrp[TLK_USE] = "BA_OK"; - m_szGrp[TLK_UNUSE] = "BA_WAIT"; - m_szGrp[TLK_STOP] = "BA_STOP"; - - m_szGrp[TLK_NOSHOOT] = "BA_SCARED"; - m_szGrp[TLK_HELLO] = "BA_HELLO"; - - m_szGrp[TLK_PLHURT1] = "!BA_CUREA"; - m_szGrp[TLK_PLHURT2] = "!BA_CUREB"; - m_szGrp[TLK_PLHURT3] = "!BA_CUREC"; - - m_szGrp[TLK_PHELLO] = NULL; //"BA_PHELLO"; // UNDONE - m_szGrp[TLK_PIDLE] = NULL; //"BA_PIDLE"; // UNDONE - m_szGrp[TLK_PQUESTION] = "BA_PQUEST"; // UNDONE - - m_szGrp[TLK_SMELL] = "BA_SMELL"; - - m_szGrp[TLK_WOUND] = "BA_WOUND"; - m_szGrp[TLK_MORTAL] = "BA_MORTAL"; - - // get voice for head - just one barney voice for now - m_voicePitch = 100; -} - -static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) -{ - Vector vecDir = reference - pevTest->origin; - vecDir.z = 0; - vecDir = vecDir.Normalize(); - Vector forward, angle; - angle = pevTest->v_angle; - angle.x = 0; - UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL ); - - // He's facing me, he meant it - if( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so - { - return TRUE; - } - return FALSE; -} - -int CBarney::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // make sure friends talk about it if player hurts talkmonsters... - int ret = CTalkMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); - if( !IsAlive() || pev->deadflag == DEAD_DYING ) - return ret; - - if( m_MonsterState != MONSTERSTATE_PRONE && ( pevAttacker->flags & FL_CLIENT ) ) - { - m_flPlayerDamage += flDamage; - - // This is a heurstic to determine if the player intended to harm me - // If I have an enemy, we can't establish intent (may just be crossfire) - if( m_hEnemy == 0 ) - { - // If the player was facing directly at me, or I'm already suspicious, get mad - if( ( m_afMemory & bits_MEMORY_SUSPICIOUS ) || IsFacing( pevAttacker, pev->origin ) ) - { - // Alright, now I'm pissed! - PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM ); - - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); - } - else - { - // Hey, be careful with that - PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); - Remember( bits_MEMORY_SUSPICIOUS ); - } - } - else if( !( m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) - { - PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); - } - } - - return ret; -} - -//========================================================= -// PainSound -//========================================================= -void CBarney::PainSound( void ) -{ - if( gpGlobals->time < m_painTime ) - return; - - m_painTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 0.75 ); - - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "barney/ba_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "barney/ba_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - case 2: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "barney/ba_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CBarney::DeathSound( void ) -{ - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "barney/ba_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "barney/ba_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - case 2: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "barney/ba_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - } -} - -void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - switch( ptr->iHitgroup ) - { - case HITGROUP_CHEST: - case HITGROUP_STOMACH: - if (bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_BLAST ) ) - { - flDamage = flDamage / 2; - } - break; - case 10: - if( bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_CLUB ) ) - { - flDamage -= 20; - if( flDamage <= 0 ) - { - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - flDamage = 0.01; - } - } - - // always a head shot - ptr->iHitgroup = HITGROUP_HEAD; - break; - } - - CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -void CBarney::Killed( entvars_t *pevAttacker, int iGib ) -{ - if( pev->body < BARNEY_BODY_GUNGONE ) - { - // drop the gun! - Vector vecGunPos; - Vector vecGunAngles; - - pev->body = BARNEY_BODY_GUNGONE; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); - } - - SetUse( NULL ); - CTalkMonster::Killed( pevAttacker, iGib ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Schedule_t *CBarney::GetScheduleOfType( int Type ) -{ - Schedule_t *psched; - - switch( Type ) - { - case SCHED_ARM_WEAPON: - if( m_hEnemy != 0 ) - { - // face enemy, then draw. - return slBarneyEnemyDraw; - } - break; - // Hook these to make a looping schedule - case SCHED_TARGET_FACE: - // call base class default so that barney will talk - // when 'used' - psched = CTalkMonster::GetScheduleOfType( Type ); - - if( psched == slIdleStand ) - return slBaFaceTarget; // override this for different target face behavior - else - return psched; - case SCHED_TARGET_CHASE: - return slBaFollow; - case SCHED_IDLE_STAND: - // call base class default so that scientist will talk - // when standing during idle - psched = CTalkMonster::GetScheduleOfType( Type ); - - if( psched == slIdleStand ) - { - // just look straight ahead. - return slIdleBaStand; - } - else - return psched; - } - - return CTalkMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// 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 *CBarney::GetSchedule( void ) -{ - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - if( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() ) - { - PlaySentence( "BA_KILL", 4, VOL_NORM, ATTN_NORM ); - } - - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { - // dead enemy - if( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster::GetSchedule(); - } - - // always act surprized with a new enemy - if( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE ) ) - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - - // wait for one schedule to draw gun - if( !m_fGunDrawn ) - return GetScheduleOfType( SCHED_ARM_WEAPON ); - - if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - break; - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - // flinch if hurt - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - if( m_hEnemy == 0 && IsFollowing() ) - { - if( !m_hTargetEnt->IsAlive() ) - { - // UNDONE: Comment about the recently dead player here? - StopFollowing( FALSE ); - break; - } - else - { - if( HasConditions( bits_COND_CLIENT_PUSH ) ) - { - return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); - } - return GetScheduleOfType( SCHED_TARGET_FACE ); - } - } - - if( HasConditions( bits_COND_CLIENT_PUSH ) ) - { - return GetScheduleOfType( SCHED_MOVE_AWAY ); - } - - // try to say something about smells - TrySmellTalk(); - break; - default: - break; - } - - return CTalkMonster::GetSchedule(); -} - -MONSTERSTATE CBarney::GetIdealState( void ) -{ - return CTalkMonster::GetIdealState(); -} - -void CBarney::DeclineFollowing( void ) -{ - PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM ); -} - -//========================================================= -// DEAD BARNEY PROP -// -// Designer selects a pose in worldcraft, 0 through num_poses-1 -// this value is added to what is selected as the 'first dead pose' -// among the monster's normal animations. All dead poses must -// appear sequentially in the model file. Be sure and set -// the m_iFirstPose properly! -// -//========================================================= -class CDeadBarney : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify( void ) { return CLASS_PLAYER_ALLY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static const char *m_szPoses[3]; -}; - -const char *CDeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" }; - -void CDeadBarney::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "pose" ) ) - { - m_iPose = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney ) - -//========================================================= -// ********** DeadBarney SPAWN ********** -//========================================================= -void CDeadBarney::Spawn() -{ - PRECACHE_MODEL( "models/barney.mdl" ); - SET_MODEL( ENT( pev ), "models/barney.mdl" ); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - if( pev->sequence == -1 ) - { - ALERT( at_console, "Dead barney with bad pose\n" ); - } - // Corpses have less health - pev->health = 8;//gSkillData.barneyHealth; - - MonsterInitDead(); -} diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp deleted file mode 100644 index 434d6134..00000000 --- a/dlls/bigmomma.cpp +++ /dev/null @@ -1,1186 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// monster template -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "decals.h" -#include "weapons.h" -#include "game.h" - -#define SF_INFOBM_RUN 0x0001 -#define SF_INFOBM_WAIT 0x0002 - -// AI Nodes for Big Momma -class CInfoBM : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData* pkvd ); - - // name in pev->targetname - // next in pev->target - // radius in pev->scale - // health in pev->health - // Reach target in pev->message - // Reach delay in pev->speed - // Reach sequence in pev->netname - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - string_t m_preSequence; -}; - -LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM ) - -TYPEDESCRIPTION CInfoBM::m_SaveData[] = -{ - DEFINE_FIELD( CInfoBM, m_preSequence, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CInfoBM, CPointEntity ) - -void CInfoBM::Spawn( void ) -{ -} - -void CInfoBM::KeyValue( KeyValueData* pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "radius" ) ) - { - pev->scale = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "reachdelay" ) ) - { - pev->speed = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "reachtarget" ) ) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "reachsequence" ) ) - { - pev->netname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "presequence" ) ) - { - m_preSequence = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -//========================================================= -// Mortar shot entity -//========================================================= -class CBMortar : public CBaseEntity -{ -public: - void Spawn( void ); - - static CBMortar *Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity ); - void Touch( CBaseEntity *pOther ); - void EXPORT Animate( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( bmortar, CBMortar ) - -TYPEDESCRIPTION CBMortar::m_SaveData[] = -{ - DEFINE_FIELD( CBMortar, m_maxFrame, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBMortar, CBaseEntity ) - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BIG_AE_STEP1 1 // Footstep left -#define BIG_AE_STEP2 2 // Footstep right -#define BIG_AE_STEP3 3 // Footstep back left -#define BIG_AE_STEP4 4 // Footstep back right -#define BIG_AE_SACK 5 // Sack slosh -#define BIG_AE_DEATHSOUND 6 // Death sound - -#define BIG_AE_MELEE_ATTACKBR 8 // Leg attack -#define BIG_AE_MELEE_ATTACKBL 9 // Leg attack -#define BIG_AE_MELEE_ATTACK1 10 // Leg attack -#define BIG_AE_MORTAR_ATTACK1 11 // Launch a mortar -#define BIG_AE_LAY_CRAB 12 // Lay a headcrab -#define BIG_AE_JUMP_FORWARD 13 // Jump up and forward -#define BIG_AE_SCREAM 14 // alert sound -#define BIG_AE_PAIN_SOUND 15 // pain sound -#define BIG_AE_ATTACK_SOUND 16 // attack sound -#define BIG_AE_BIRTH_SOUND 17 // birth sound -#define BIG_AE_EARLY_TARGET 50 // Fire target early - -// User defined conditions -#define bits_COND_NODE_SEQUENCE ( bits_COND_SPECIAL1 ) // pev->netname contains the name of a sequence to play - -// Attack distance constants -#define BIG_ATTACKDIST 170 -#define BIG_MORTARDIST 800 -#define BIG_MAXCHILDREN 20 // Max # of live headcrab children - -#define bits_MEMORY_CHILDPAIR ( bits_MEMORY_CUSTOM1 ) -#define bits_MEMORY_ADVANCE_NODE ( bits_MEMORY_CUSTOM2 ) -#define bits_MEMORY_COMPLETED_NODE ( bits_MEMORY_CUSTOM3 ) -#define bits_MEMORY_FIRED_NODE ( bits_MEMORY_CUSTOM4 ) - -int gSpitSprite, gSpitDebrisSprite; -Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ); -void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count ); - -// UNDONE: -// -#define BIG_CHILDCLASS "monster_babycrab" - -class CBigMomma : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - - void NodeStart( int iszNextNode ); - void NodeReach( void ); - BOOL ShouldGoToNode( void ); - - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void LayHeadcrab( void ); - - int GetNodeSequence( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if( pTarget ) - { - return pTarget->pev->netname; // netname holds node sequence - } - return 0; - } - - int GetNodePresequence( void ) - { - CInfoBM *pTarget = (CInfoBM *)(CBaseEntity *)m_hTargetEnt; - if( pTarget ) - { - return pTarget->m_preSequence; - } - return 0; - } - - float GetNodeDelay( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if( pTarget ) - { - return pTarget->pev->speed; // Speed holds node delay - } - return 0; - } - - float GetNodeRange( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if( pTarget ) - { - return pTarget->pev->scale; // Scale holds node delay - } - return 1e6; - } - - float GetNodeYaw( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if( pTarget ) - { - if( pTarget->pev->angles.y != 0 ) - return pTarget->pev->angles.y; - } - return pev->angles.y; - } - - // Restart the crab count on each new level - void OverrideReset( void ) - { - m_crabCount = 0; - } - - void DeathNotice( entvars_t *pevChild ); - - BOOL CanLayCrab( void ) - { - if( m_crabTime < gpGlobals->time && m_crabCount < BIG_MAXCHILDREN ) - { - // Don't spawn crabs inside each other - Vector mins = pev->origin - Vector( 32, 32, 0 ); - Vector maxs = pev->origin + Vector( 32, 32, 0 ); - - CBaseEntity *pList[2]; - int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_MONSTER ); - for( int i = 0; i < count; i++ ) - { - if( pList[i] != this ) // Don't hurt yourself! - return FALSE; - } - return TRUE; - } - - return FALSE; - } - - void LaunchMortar( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -95, -95, 0 ); - pev->absmax = pev->origin + Vector( 95, 95, 190 ); - } - - BOOL CheckMeleeAttack1( float flDot, float flDist ); // Slash - BOOL CheckMeleeAttack2( float flDot, float flDist ); // Lay a crab - BOOL CheckRangeAttack1( float flDot, float flDist ); // Mortar launch - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pChildDieSounds[]; - static const char *pSackSounds[]; - static const char *pDeathSounds[]; - static const char *pAttackSounds[]; - static const char *pAttackHitSounds[]; - static const char *pBirthSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pFootSounds[]; - - CUSTOM_SCHEDULES - -private: - float m_nodeTime; - float m_crabTime; - float m_mortarTime; - float m_painSoundTime; - int m_crabCount; -}; - -LINK_ENTITY_TO_CLASS( monster_bigmomma, CBigMomma ) - -TYPEDESCRIPTION CBigMomma::m_SaveData[] = -{ - DEFINE_FIELD( CBigMomma, m_nodeTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_crabTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_mortarTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_painSoundTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_crabCount, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBigMomma, CBaseMonster ) - -const char *CBigMomma::pChildDieSounds[] = -{ - "gonarch/gon_childdie1.wav", - "gonarch/gon_childdie2.wav", - "gonarch/gon_childdie3.wav", -}; - -const char *CBigMomma::pSackSounds[] = -{ - "gonarch/gon_sack1.wav", - "gonarch/gon_sack2.wav", - "gonarch/gon_sack3.wav", -}; - -const char *CBigMomma::pDeathSounds[] = -{ - "gonarch/gon_die1.wav", -}; - -const char *CBigMomma::pAttackSounds[] = -{ - "gonarch/gon_attack1.wav", - "gonarch/gon_attack2.wav", - "gonarch/gon_attack3.wav", -}; - -const char *CBigMomma::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CBigMomma::pBirthSounds[] = -{ - "gonarch/gon_birth1.wav", - "gonarch/gon_birth2.wav", - "gonarch/gon_birth3.wav", -}; - -const char *CBigMomma::pAlertSounds[] = -{ - "gonarch/gon_alert1.wav", - "gonarch/gon_alert2.wav", - "gonarch/gon_alert3.wav", -}; - -const char *CBigMomma::pPainSounds[] = -{ - "gonarch/gon_pain2.wav", - "gonarch/gon_pain4.wav", - "gonarch/gon_pain5.wav", -}; - -const char *CBigMomma::pFootSounds[] = -{ - "gonarch/gon_step1.wav", - "gonarch/gon_step2.wav", - "gonarch/gon_step3.wav", -}; - -void CBigMomma::KeyValue( KeyValueData *pkvd ) -{ -#if 0 - if( FStrEq( pkvd->szKeyName, "volume" ) ) - { - m_volume = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else -#endif - CBaseMonster::KeyValue( pkvd ); -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBigMomma::Classify( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBigMomma::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_IDLE: - ys = 100; - break; - default: - ys = 90; - } - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBigMomma::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BIG_AE_MELEE_ATTACKBR: - case BIG_AE_MELEE_ATTACKBL: - case BIG_AE_MELEE_ATTACK1: - { - Vector forward, right; - - UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); - - Vector center = pev->origin + forward * 128; - Vector mins = center - Vector( 64, 64, 0 ); - Vector maxs = center + Vector( 64, 64, 64 ); - - CBaseEntity *pList[8]; - int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER | FL_CLIENT ); - CBaseEntity *pHurt = NULL; - - for( int i = 0; i < count && !pHurt; i++ ) - { - if( pList[i] != this ) - { - if( pList[i]->pev->owner != edict() ) - pHurt = pList[i]; - } - } - - if( pHurt ) - { - pHurt->TakeDamage( pev, pev, gSkillData.bigmommaDmgSlash, DMG_CRUSH | DMG_SLASH ); - pHurt->pev->punchangle.x = 15; - switch( pEvent->event ) - { - case BIG_AE_MELEE_ATTACKBR: - pHurt->pev->velocity = pHurt->pev->velocity + ( forward * 150 ) + Vector( 0, 0, 250 ) - ( right * 200 ); - break; - case BIG_AE_MELEE_ATTACKBL: - pHurt->pev->velocity = pHurt->pev->velocity + ( forward * 150 ) + Vector( 0, 0, 250 ) + ( right * 200 ); - break; - case BIG_AE_MELEE_ATTACK1: - pHurt->pev->velocity = pHurt->pev->velocity + ( forward * 220 ) + Vector( 0, 0, 200 ); - break; - } - - pHurt->pev->flags &= ~FL_ONGROUND; - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pAttackHitSounds ), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - } - } - break; - case BIG_AE_SCREAM: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); - break; - case BIG_AE_PAIN_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); - break; - case BIG_AE_ATTACK_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackSounds ); - break; - case BIG_AE_BIRTH_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pBirthSounds ); - break; - case BIG_AE_SACK: - if( RANDOM_LONG( 0, 100 ) < 30 ) - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pSackSounds ); - break; - case BIG_AE_DEATHSOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); - break; - case BIG_AE_STEP1: // Footstep left - case BIG_AE_STEP3: // Footstep back left - EMIT_SOUND_ARRAY_DYN( CHAN_ITEM, pFootSounds ); - break; - case BIG_AE_STEP4: // Footstep back right - case BIG_AE_STEP2: // Footstep right - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pFootSounds ); - break; - case BIG_AE_MORTAR_ATTACK1: - LaunchMortar(); - break; - case BIG_AE_LAY_CRAB: - LayHeadcrab(); - break; - case BIG_AE_JUMP_FORWARD: - ClearBits( pev->flags, FL_ONGROUND ); - - UTIL_SetOrigin( pev, pev->origin + Vector( 0, 0, 1) );// take him off ground so engine doesn't instantly reset onground - UTIL_MakeVectors( pev->angles ); - - pev->velocity = gpGlobals->v_forward * 200 + gpGlobals->v_up * 500; - break; - case BIG_AE_EARLY_TARGET: - { - CBaseEntity *pTarget = m_hTargetEnt; - if( pTarget && pTarget->pev->message ) - FireTargets( STRING( pTarget->pev->message ), this, this, USE_TOGGLE, 0 ); - Remember( bits_MEMORY_FIRED_NODE ); - } - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -void CBigMomma::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if( ptr->iHitgroup != 1 ) - { - // didn't hit the sack? - if( pev->dmgtime != gpGlobals->time || ( RANDOM_LONG( 0, 10 ) < 1 ) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - else if( gpGlobals->time > m_painSoundTime ) - { - m_painSoundTime = gpGlobals->time + RANDOM_LONG( 1, 3 ); - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); - } - - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -int CBigMomma::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Don't take any acid damage -- BigMomma's mortar is acid - if( bitsDamageType & DMG_ACID ) - flDamage = 0; - - if( !HasMemory( bits_MEMORY_PATH_FINISHED ) ) - { - if( pev->health <= flDamage ) - { - pev->health = flDamage + 1; - Remember( bits_MEMORY_ADVANCE_NODE | bits_MEMORY_COMPLETED_NODE ); - ALERT( at_aiconsole, "BM: Finished node health!!!\n" ); - } - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CBigMomma::LayHeadcrab( void ) -{ - CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, pev->origin, pev->angles, edict() ); - - pChild->pev->spawnflags |= SF_MONSTER_FALL_TO_GROUND; - - // Is this the second crab in a pair? - if( HasMemory( bits_MEMORY_CHILDPAIR ) ) - { - m_crabTime = gpGlobals->time + RANDOM_FLOAT( 5, 10 ); - Forget( bits_MEMORY_CHILDPAIR ); - } - else - { - m_crabTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 2.5 ); - Remember( bits_MEMORY_CHILDPAIR ); - } - - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin - Vector( 0, 0, 100 ), ignore_monsters, edict(), &tr ); - UTIL_DecalTrace( &tr, DECAL_MOMMABIRTH ); - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBirthSounds ), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - m_crabCount++; -} - -void CBigMomma::DeathNotice( entvars_t *pevChild ) -{ - if( m_crabCount > 0 ) // Some babies may cross a transition, but we reset the count then - m_crabCount--; - if( IsAlive() ) - { - // Make the "my baby's dead" noise! - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pChildDieSounds ); - } -} - -void CBigMomma::LaunchMortar( void ) -{ - m_mortarTime = gpGlobals->time + RANDOM_FLOAT( 2, 15 ); - - Vector startPos = pev->origin; - startPos.z += 180; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pSackSounds ), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - CBMortar *pBomb = CBMortar::Shoot( edict(), startPos, pev->movedir ); - pBomb->pev->gravity = 1.0; - MortarSpray( startPos, Vector( 0, 0, 1 ), gSpitSprite, 24 ); -} - -//========================================================= -// Spawn -//========================================================= -void CBigMomma::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/big_mom.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = 150 * gSkillData.bigmommaHealthFactor; - pev->view_ofs = Vector( 0, 0, 128 );// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBigMomma::Precache() -{ - PRECACHE_MODEL( "models/big_mom.mdl" ); - - PRECACHE_SOUND_ARRAY( pChildDieSounds ); - PRECACHE_SOUND_ARRAY( pSackSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pAttackHitSounds ); - PRECACHE_SOUND_ARRAY( pBirthSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pFootSounds ); - - UTIL_PrecacheOther( BIG_CHILDCLASS ); - - // TEMP: Squid - PRECACHE_MODEL( "sprites/mommaspit.spr" );// spit projectile. - gSpitSprite = PRECACHE_MODEL( "sprites/mommaspout.spr" );// client side spittle. - gSpitDebrisSprite = PRECACHE_MODEL( "sprites/mommablob.spr" ); - - PRECACHE_SOUND( "bullchicken/bc_acid1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_spithit2.wav" ); -} - -void CBigMomma::Activate( void ) -{ - if( m_hTargetEnt == 0 ) - Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up -} - -void CBigMomma::NodeStart( int iszNextNode ) -{ - pev->netname = iszNextNode; - - CBaseEntity *pTarget = NULL; - - if( pev->netname ) - { - edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->netname ) ); - - if( !FNullEnt( pentTarget ) ) - pTarget = Instance( pentTarget ); - } - - if( !pTarget ) - { - ALERT( at_aiconsole, "BM: Finished the path!!\n" ); - Remember( bits_MEMORY_PATH_FINISHED ); - return; - } - Remember( bits_MEMORY_ON_PATH ); - m_hTargetEnt = pTarget; -} - -void CBigMomma::NodeReach( void ) -{ - CBaseEntity *pTarget = m_hTargetEnt; - - Forget( bits_MEMORY_ADVANCE_NODE ); - - if( !pTarget ) - return; - - if( pTarget->pev->health ) - pev->max_health = pev->health = pTarget->pev->health * gSkillData.bigmommaHealthFactor; - - if( !HasMemory( bits_MEMORY_FIRED_NODE ) ) - { - if( pTarget->pev->message ) - FireTargets( STRING( pTarget->pev->message ), this, this, USE_TOGGLE, 0 ); - } - Forget( bits_MEMORY_FIRED_NODE ); - - pev->netname = pTarget->pev->target; - if( pTarget->pev->health == 0 ) - Remember( bits_MEMORY_ADVANCE_NODE ); // Move on if no health at this node -} - -// Slash -BOOL CBigMomma::CheckMeleeAttack1( float flDot, float flDist ) -{ - if( flDot >= 0.7 ) - { - if( flDist <= BIG_ATTACKDIST ) - return TRUE; - } - return FALSE; -} - -// Lay a crab -BOOL CBigMomma::CheckMeleeAttack2( float flDot, float flDist ) -{ - return CanLayCrab(); -} - -// Mortar launch -BOOL CBigMomma::CheckRangeAttack1( float flDot, float flDist ) -{ - if( flDist <= BIG_MORTARDIST && m_mortarTime < gpGlobals->time ) - { - CBaseEntity *pEnemy = m_hEnemy; - - if( pEnemy ) - { - Vector startPos = pev->origin; - startPos.z += 180; - pev->movedir = VecCheckSplatToss( pev, startPos, pEnemy->BodyTarget( pev->origin ), RANDOM_FLOAT( 150, 500 ) ); - if( pev->movedir != g_vecZero ) - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -enum -{ - SCHED_BIG_NODE = LAST_COMMON_SCHEDULE + 1, - SCHED_NODE_FAIL -}; - -enum -{ - TASK_MOVE_TO_NODE_RANGE = LAST_COMMON_TASK + 1, // Move within node range - TASK_FIND_NODE, // Find my next node - TASK_PLAY_NODE_PRESEQUENCE, // Play node pre-script - TASK_PLAY_NODE_SEQUENCE, // Play node script - TASK_PROCESS_NODE, // Fire targets, etc. - TASK_WAIT_NODE, // Wait at the node - TASK_NODE_DELAY, // Delay walking toward node for a bit. You've failed to get there - TASK_NODE_YAW // Get the best facing direction for this node -}; - -Task_t tlBigNode[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_NODE_FAIL }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_NODE, (float)0 }, // Find my next node - { TASK_PLAY_NODE_PRESEQUENCE, (float)0 }, // Play the pre-approach sequence if any - { TASK_MOVE_TO_NODE_RANGE, (float)0 }, // Move within node range - { TASK_STOP_MOVING, (float)0 }, - { TASK_NODE_YAW, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WAIT_NODE, (float)0 }, // Wait for node delay - { TASK_PLAY_NODE_SEQUENCE, (float)0 }, // Play the sequence if one exists - { TASK_PROCESS_NODE, (float)0 }, // Fire targets, etc. - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slBigNode[] = -{ - { - tlBigNode, - ARRAYSIZE( tlBigNode ), - 0, - 0, - "Big Node" - }, -}; - -Task_t tlNodeFail[] = -{ - { TASK_NODE_DELAY, (float)10 }, // Try to do something else for 10 seconds - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slNodeFail[] = -{ - { - tlNodeFail, - ARRAYSIZE( tlNodeFail ), - 0, - 0, - "NodeFail" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CBigMomma ) -{ - slBigNode, - slNodeFail, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CBigMomma, CBaseMonster ) - -Schedule_t *CBigMomma::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_BIG_NODE: - return slBigNode; - break; - case SCHED_NODE_FAIL: - return slNodeFail; - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - -BOOL CBigMomma::ShouldGoToNode( void ) -{ - if( HasMemory( bits_MEMORY_ADVANCE_NODE ) ) - { - if( m_nodeTime < gpGlobals->time ) - return TRUE; - } - return FALSE; -} - -Schedule_t *CBigMomma::GetSchedule( void ) -{ - if( ShouldGoToNode() ) - { - return GetScheduleOfType( SCHED_BIG_NODE ); - } - - return CBaseMonster::GetSchedule(); -} - -void CBigMomma::StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_FIND_NODE: - { - CBaseEntity *pTarget = m_hTargetEnt; - if( !HasMemory( bits_MEMORY_ADVANCE_NODE ) ) - { - if( pTarget ) - pev->netname = m_hTargetEnt->pev->target; - } - NodeStart( pev->netname ); - TaskComplete(); - ALERT( at_aiconsole, "BM: Found node %s\n", STRING( pev->netname ) ); - } - break; - case TASK_NODE_DELAY: - m_nodeTime = gpGlobals->time + pTask->flData; - TaskComplete(); - ALERT( at_aiconsole, "BM: FAIL! Delay %.2f\n", pTask->flData ); - break; - case TASK_PROCESS_NODE: - ALERT( at_aiconsole, "BM: Reached node %s\n", STRING( pev->netname ) ); - NodeReach(); - TaskComplete(); - break; - case TASK_PLAY_NODE_PRESEQUENCE: - case TASK_PLAY_NODE_SEQUENCE: - { - int sequence; - if( pTask->iTask == TASK_PLAY_NODE_SEQUENCE ) - sequence = GetNodeSequence(); - else - sequence = GetNodePresequence(); - - ALERT( at_aiconsole, "BM: Playing node sequence %s\n", STRING( sequence ) ); - if( sequence ) - { - sequence = LookupSequence( STRING( sequence ) ); - if( sequence != -1 ) - { - pev->sequence = sequence; - pev->frame = 0; - ResetSequenceInfo(); - ALERT( at_aiconsole, "BM: Sequence %s\n", STRING( GetNodeSequence() ) ); - return; - } - } - TaskComplete(); - } - break; - case TASK_NODE_YAW: - pev->ideal_yaw = GetNodeYaw(); - TaskComplete(); - break; - case TASK_WAIT_NODE: - m_flWait = gpGlobals->time + GetNodeDelay(); - if( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) - ALERT( at_aiconsole, "BM: Wait at node %s forever\n", STRING( pev->netname ) ); - else - ALERT( at_aiconsole, "BM: Wait at node %s for %.2f\n", STRING( pev->netname ), GetNodeDelay() ); - break; - - - case TASK_MOVE_TO_NODE_RANGE: - { - CBaseEntity *pTarget = m_hTargetEnt; - if( !pTarget ) - TaskFail(); - else - { - if( ( pTarget->pev->origin - pev->origin ).Length() < GetNodeRange() ) - TaskComplete(); - else - { - Activity act = ACT_WALK; - if( pTarget->pev->spawnflags & SF_INFOBM_RUN ) - act = ACT_RUN; - - m_vecMoveGoal = pTarget->pev->origin; - if( !MoveToTarget( act, 2 ) ) - { - TaskFail(); - } - } - } - } - ALERT( at_aiconsole, "BM: Moving to node %s\n", STRING( pev->netname ) ); - break; - case TASK_MELEE_ATTACK1: - // Play an attack sound here - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, ATTN_NORM, 0, PITCH_NORM ); - CBaseMonster::StartTask( pTask ); - break; - default: - CBaseMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CBigMomma::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_MOVE_TO_NODE_RANGE: - { - float distance; - - if( m_hTargetEnt == 0 ) - TaskFail(); - else - { - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if( (distance < GetNodeRange() ) || MovementIsComplete() ) - { - ALERT( at_aiconsole, "BM: Reached node!\n" ); - TaskComplete(); - RouteClear(); // Stop moving - } - } - } - break; - case TASK_WAIT_NODE: - if( m_hTargetEnt != 0 && ( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) ) - return; - - if( gpGlobals->time > m_flWaitFinished ) - TaskComplete(); - ALERT( at_aiconsole, "BM: The WAIT is over!\n" ); - break; - case TASK_PLAY_NODE_PRESEQUENCE: - case TASK_PLAY_NODE_SEQUENCE: - if( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - default: - CBaseMonster::RunTask( pTask ); - break; - } -} - -Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ) -{ - TraceResult tr; - Vector vecMidPoint;// halfway point between Spot1 and Spot2 - Vector vecApex;// highest point - Vector vecScale; - Vector vecGrenadeVel; - Vector vecTemp; - float flGravity = g_psv_gravity->value; - - // calculate the midpoint and apex of the 'triangle' - vecMidPoint = vecSpot1 + ( vecSpot2 - vecSpot1 ) * 0.5; - UTIL_TraceLine( vecMidPoint, vecMidPoint + Vector( 0, 0, maxHeight ), ignore_monsters, ENT( pev ), &tr ); - vecApex = tr.vecEndPos; - - UTIL_TraceLine( vecSpot1, vecApex, dont_ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction != 1.0 ) - { - // fail! - return g_vecZero; - } - - // Don't worry about actually hitting the target, this won't hurt us! - - // How high should the grenade travel (subtract 15 so the grenade doesn't hit the ceiling)? - float height = vecApex.z - vecSpot1.z - 15; - // How fast does the grenade need to travel to reach that height given gravity? - float speed = sqrt( 2 * flGravity * height ); - - // How much time does it take to get there? - float time = speed / flGravity; - vecGrenadeVel = vecSpot2 - vecSpot1; - vecGrenadeVel.z = 0; - - // Travel half the distance to the target in that time (apex is at the midpoint) - vecGrenadeVel = vecGrenadeVel * ( 0.5 / time ); - // Speed to offset gravity at the desired height - vecGrenadeVel.z = speed; - - return vecGrenadeVel; -} - -// --------------------------------- -// -// Mortar -// -// --------------------------------- -void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( position.x ); // pos - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - WRITE_COORD( direction.x ); // dir - WRITE_COORD( direction.y ); - WRITE_COORD( direction.z ); - WRITE_SHORT( spriteModel ); // model - WRITE_BYTE ( count ); // count - WRITE_BYTE ( 130 ); // speed - WRITE_BYTE ( 80 ); // noise ( client will divide by 100 ) - MESSAGE_END(); -} - -// UNDONE: right now this is pretty much a copy of the squid spit with minor changes to the way it does damage -void CBMortar::Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->classname = MAKE_STRING( "bmortar" ); - - pev->solid = SOLID_BBOX; - pev->rendermode = kRenderTransAlpha; - pev->renderamt = 255; - - SET_MODEL( ENT( pev ), "sprites/mommaspit.spr" ); - pev->frame = 0; - pev->scale = 0.5; - - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - pev->dmgtime = gpGlobals->time + 0.4; -} - -void CBMortar::Animate( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if( gpGlobals->time > pev->dmgtime ) - { - pev->dmgtime = gpGlobals->time + 0.2; - MortarSpray( pev->origin, -pev->velocity.Normalize(), gSpitSprite, 3 ); - } - if( pev->frame++ ) - { - if ( pev->frame > m_maxFrame ) - { - pev->frame = 0; - } - } -} - -CBMortar *CBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity ) -{ - CBMortar *pSpit = GetClassPtr( (CBMortar *)NULL ); - pSpit->Spawn(); - - UTIL_SetOrigin( pSpit->pev, vecStart ); - pSpit->pev->velocity = vecVelocity; - pSpit->pev->owner = pOwner; - pSpit->pev->scale = 2.5; - pSpit->SetThink( &CBMortar::Animate ); - pSpit->pev->nextthink = gpGlobals->time + 0.1; - - return pSpit; -} - -void CBMortar::Touch( CBaseEntity *pOther ) -{ - TraceResult tr; - int iPitch; - - // splat sound - iPitch = RANDOM_FLOAT( 90, 110 ); - - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); - - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - if( pOther->IsBSPModel() ) - { - - // make a splat on the wall - UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); - UTIL_DecalTrace( &tr, DECAL_MOMMASPLAT ); - } - else - { - tr.vecEndPos = pev->origin; - tr.vecPlaneNormal = -1 * pev->velocity.Normalize(); - } - - // make some flecks - MortarSpray( tr.vecEndPos, tr.vecPlaneNormal, gSpitSprite, 24 ); - - entvars_t *pevOwner = NULL; - if( pev->owner ) - pevOwner = VARS(pev->owner); - - RadiusDamage( pev->origin, pev, pevOwner, gSkillData.bigmommaDmgBlast, gSkillData.bigmommaRadiusBlast, CLASS_NONE, DMG_ACID ); - UTIL_Remove( this ); -} -#endif diff --git a/dlls/bloater.cpp b/dlls/bloater.cpp deleted file mode 100644 index 537c68ad..00000000 --- a/dlls/bloater.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Bloater -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BLOATER_AE_ATTACK_MELEE1 0x01 - -class CBloater : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSnd( void ); - - // No range attacks - BOOL CheckRangeAttack1( float flDot, float flDist ) { return FALSE; } - BOOL CheckRangeAttack2( float flDot, float flDist ) { return FALSE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); -}; - -LINK_ENTITY_TO_CLASS( monster_bloater, CBloater ) - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBloater::Classify( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBloater::SetYawSpeed( void ) -{ - int ys; - - ys = 120; -#if 0 - switch( m_Activity ) - { - } -#endif - pev->yaw_speed = ys; -} - -int CBloater::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CBloater::PainSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG( 0, 9 ); - - switch( RANDOM_LONG( 0, 5 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_pain1.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_pain2.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - default: - break; - } -#endif -} - -void CBloater::AlertSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG( 0, 9 ); - - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_alert10.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_alert20.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - case 2: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_alert30.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - } -#endif -} - -void CBloater::IdleSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG( 0, 9 ); - - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_idle1.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_idle2.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - case 2: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_idle3.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - } -#endif -} - -void CBloater::AttackSnd( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG( 0, 9 ); - - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_attack1.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "zombie/zo_attack2.wav", 1.0, ATTN_NORM, 0, pitch ); - break; - } -#endif -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CBloater::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BLOATER_AE_ATTACK_MELEE1: - { - // do stuff for this event. - AttackSnd(); - } - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CBloater::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/floater.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->spawnflags |= FL_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = 40; - pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBloater::Precache() -{ - PRECACHE_MODEL( "models/floater.mdl" ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= diff --git a/dlls/bullsquid.cpp b/dlls/bullsquid.cpp deleted file mode 100644 index af3ab88a..00000000 --- a/dlls/bullsquid.cpp +++ /dev/null @@ -1,1265 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// bullsquid - big, spotty tentacle-mouthed meanie. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "nodes.h" -#include "effects.h" -#include "decals.h" -#include "soundent.h" -#include "game.h" - -#define SQUID_SPRINT_DIST 256 // how close the squid has to get before starting to sprint and refusing to swerve - -int iSquidSpitSprite; - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_SQUID_HURTHOP = LAST_COMMON_SCHEDULE + 1, - SCHED_SQUID_SMELLFOOD, - SCHED_SQUID_SEECRAB, - SCHED_SQUID_EAT, - SCHED_SQUID_SNIFF_AND_EAT, - SCHED_SQUID_WALLOW -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_SQUID_HOPTURN = LAST_COMMON_TASK + 1 -}; - -//========================================================= -// Bullsquid's spit projectile -//========================================================= -class CSquidSpit : public CBaseEntity -{ -public: - void Spawn( void ); - - static void Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - void Touch( CBaseEntity *pOther ); - void EXPORT Animate( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( squidspit, CSquidSpit ) - -TYPEDESCRIPTION CSquidSpit::m_SaveData[] = -{ - DEFINE_FIELD( CSquidSpit, m_maxFrame, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CSquidSpit, CBaseEntity ) - -void CSquidSpit::Spawn( void ) -{ - pev->movetype = MOVETYPE_FLY; - pev->classname = MAKE_STRING( "squidspit" ); - - pev->solid = SOLID_BBOX; - pev->rendermode = kRenderTransAlpha; - pev->renderamt = 255; - - SET_MODEL( ENT( pev ), "sprites/bigspit.spr" ); - pev->frame = 0; - pev->scale = 0.5; - - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - - m_maxFrame = (float)MODEL_FRAMES( pev->modelindex ) - 1; -} - -void CSquidSpit::Animate( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if( pev->frame++ ) - { - if( pev->frame > m_maxFrame ) - { - pev->frame = 0; - } - } -} - -void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CSquidSpit *pSpit = GetClassPtr( (CSquidSpit *)NULL ); - pSpit->Spawn(); - - UTIL_SetOrigin( pSpit->pev, vecStart ); - pSpit->pev->velocity = vecVelocity; - pSpit->pev->owner = ENT( pevOwner ); - - pSpit->SetThink( &CSquidSpit::Animate ); - pSpit->pev->nextthink = gpGlobals->time + 0.1; -} - -void CSquidSpit::Touch( CBaseEntity *pOther ) -{ - TraceResult tr; - int iPitch; - - // splat sound - iPitch = RANDOM_FLOAT( 90, 110 ); - - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); - - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - if( !pOther->pev->takedamage ) - { - // make a splat on the wall - UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); - UTIL_DecalTrace( &tr, DECAL_SPIT1 + RANDOM_LONG( 0, 1 ) ); - - // make some flecks - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( tr.vecEndPos.x ); // pos - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_COORD( tr.vecPlaneNormal.x ); // dir - WRITE_COORD( tr.vecPlaneNormal.y ); - WRITE_COORD( tr.vecPlaneNormal.z ); - WRITE_SHORT( iSquidSpitSprite ); // model - WRITE_BYTE( 5 ); // count - WRITE_BYTE( 30 ); // speed - WRITE_BYTE( 80 ); // noise ( client will divide by 100 ) - MESSAGE_END(); - } - else - { - pOther->TakeDamage( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC ); - } - - SetThink( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BSQUID_AE_SPIT ( 1 ) -#define BSQUID_AE_BITE ( 2 ) -#define BSQUID_AE_BLINK ( 3 ) -#define BSQUID_AE_TAILWHIP ( 4 ) -#define BSQUID_AE_HOP ( 5 ) -#define BSQUID_AE_THROW ( 6 ) - -class CBullsquid : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void IdleSound( void ); - void PainSound( void ); - void DeathSound( void ); - void AlertSound( void ); - void AttackSound( void ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - BOOL CheckMeleeAttack1( float flDot, float flDist ); - BOOL CheckMeleeAttack2( float flDot, float flDist ); - BOOL CheckRangeAttack1( float flDot, float flDist ); - void RunAI( void ); - BOOL FValidateHintType( short sHint ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - int IRelationship( CBaseEntity *pTarget ); - int IgnoreConditions( void ); - MONSTERSTATE GetIdealState( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CUSTOM_SCHEDULES - static TYPEDESCRIPTION m_SaveData[]; - - BOOL m_fCanThreatDisplay;// this is so the squid only does the "I see a headcrab!" dance one time. - - float m_flLastHurtTime;// we keep track of this, because if something hurts a squid, it will forget about its love of headcrabs for a while. - float m_flNextSpitTime;// last time the bullsquid used the spit attack. -}; - -LINK_ENTITY_TO_CLASS( monster_bullchicken, CBullsquid ) - -TYPEDESCRIPTION CBullsquid::m_SaveData[] = -{ - DEFINE_FIELD( CBullsquid, m_fCanThreatDisplay, FIELD_BOOLEAN ), - DEFINE_FIELD( CBullsquid, m_flLastHurtTime, FIELD_TIME ), - DEFINE_FIELD( CBullsquid, m_flNextSpitTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CBullsquid, CBaseMonster ) - -//========================================================= -// IgnoreConditions -//========================================================= -int CBullsquid::IgnoreConditions( void ) -{ - int iIgnore = CBaseMonster::IgnoreConditions(); - - if( gpGlobals->time - m_flLastHurtTime <= 20 ) - { - // haven't been hurt in 20 seconds, so let the squid care about stink. - iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; - } - - if( m_hEnemy != 0 ) - { - if( FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) - { - // (Unless after a tasty headcrab) - iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; - } - } - - return iIgnore; -} - -//========================================================= -// IRelationship - overridden for bullsquid so that it can -// be made to ignore its love of headcrabs for a while. -//========================================================= -int CBullsquid::IRelationship( CBaseEntity *pTarget ) -{ - if( gpGlobals->time - m_flLastHurtTime < 5 && FClassnameIs( pTarget->pev, "monster_headcrab" ) ) - { - // if squid has been hurt in the last 5 seconds, and is getting relationship for a headcrab, - // tell squid to disregard crab. - return R_NO; - } - - return CBaseMonster::IRelationship( pTarget ); -} - -//========================================================= -// TakeDamage - overridden for bullsquid so we can keep track -// of how much time has passed since it was last injured -//========================================================= -int CBullsquid::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - float flDist; - Vector vecApex; - - // if the squid is running, has an enemy, was hurt by the enemy, hasn't been hurt in the last 3 seconds, and isn't too close to the enemy, - // it will swerve. (whew). - if( m_hEnemy != 0 && IsMoving() && pevAttacker == m_hEnemy->pev && gpGlobals->time - m_flLastHurtTime > 3 ) - { - flDist = ( pev->origin - m_hEnemy->pev->origin ).Length2D(); - - if( flDist > SQUID_SPRINT_DIST ) - { - flDist = ( pev->origin - m_Route[m_iRouteIndex].vecLocation ).Length2D();// reusing flDist. - - if( FTriangulate( pev->origin, m_Route[m_iRouteIndex].vecLocation, flDist * 0.5, m_hEnemy, &vecApex ) ) - { - InsertWaypoint( vecApex, bits_MF_TO_DETOUR | bits_MF_DONT_SIMPLIFY ); - } - } - } - - if( !FClassnameIs( pevAttacker, "monster_headcrab" ) ) - { - // don't forget about headcrabs if it was a headcrab that hurt the squid. - m_flLastHurtTime = gpGlobals->time; - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CBullsquid::CheckRangeAttack1( float flDot, float flDist ) -{ - if( IsMoving() && flDist >= 512 ) - { - // squid will far too far behind if he stops running to spit at this distance from the enemy. - return FALSE; - } - - if( flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextSpitTime ) - { - if( m_hEnemy != 0 ) - { - if( fabs( pev->origin.z - m_hEnemy->pev->origin.z ) > 256 ) - { - // don't try to spit at someone up really high or down really low. - return FALSE; - } - } - - if( IsMoving() ) - { - // don't spit again for a long time, resume chasing enemy. - m_flNextSpitTime = gpGlobals->time + 5; - } - else - { - // not moving, so spit again pretty soon. - m_flNextSpitTime = gpGlobals->time + 0.5; - } - - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CheckMeleeAttack1 - bullsquid is a big guy, so has a longer -// melee range than most monsters. This is the tailwhip attack -//========================================================= -BOOL CBullsquid::CheckMeleeAttack1( float flDot, float flDist ) -{ - if( m_hEnemy->pev->health <= gSkillData.bullsquidDmgWhip && flDist <= 85 && flDot >= 0.7 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckMeleeAttack2 - bullsquid is a big guy, so has a longer -// melee range than most monsters. This is the bite attack. -// this attack will not be performed if the tailwhip attack -// is valid. -//========================================================= -BOOL CBullsquid::CheckMeleeAttack2( float flDot, float flDist ) -{ - if( flDist <= 85 && flDot >= 0.7 && !HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) // The player & bullsquid can be as much as their bboxes - { // apart (48 * sqrt(3)) and he can still attack (85 is a little more than 48*sqrt(3)) - return TRUE; - } - return FALSE; -} - -//========================================================= -// FValidateHintType -//========================================================= -BOOL CBullsquid::FValidateHintType( short sHint ) -{ - size_t i; - - static short sSquidHints[] = - { - HINT_WORLD_HUMAN_BLOOD, - }; - - for( i = 0; i < ARRAYSIZE( sSquidHints ); i++ ) - { - if( sSquidHints[i] == sHint ) - { - return TRUE; - } - } - - ALERT( at_aiconsole, "Couldn't validate hint type" ); - return FALSE; -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CBullsquid::ISoundMask( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_CARCASS | - bits_SOUND_MEAT | - bits_SOUND_GARBAGE | - bits_SOUND_PLAYER; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBullsquid::Classify( void ) -{ - return CLASS_ALIEN_PREDATOR; -} - -//========================================================= -// IdleSound -//========================================================= -#define SQUID_ATTN_IDLE (float)1.5 -void CBullsquid::IdleSound( void ) -{ - switch( RANDOM_LONG( 0, 4 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, SQUID_ATTN_IDLE ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, SQUID_ATTN_IDLE ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle3.wav", 1, SQUID_ATTN_IDLE ); - break; - case 3: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle4.wav", 1, SQUID_ATTN_IDLE ); - break; - case 4: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle5.wav", 1, SQUID_ATTN_IDLE ); - break; - } -} - -//========================================================= -// PainSound -//========================================================= -void CBullsquid::PainSound( void ) -{ - int iPitch = RANDOM_LONG( 85, 120 ); - - switch( RANDOM_LONG( 0, 3 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_pain1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_pain2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 2: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_pain3.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 3: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_pain4.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } -} - -//========================================================= -// AlertSound -//========================================================= -void CBullsquid::AlertSound( void ) -{ - int iPitch = RANDOM_LONG( 140, 160 ); - - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBullsquid::SetYawSpeed( void ) -{ - int ys; - - ys = 0; - - switch ( m_Activity ) - { - case ACT_WALK: - ys = 90; - break; - case ACT_RUN: - ys = 90; - break; - case ACT_IDLE: - ys = 90; - break; - case ACT_RANGE_ATTACK1: - ys = 90; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CBullsquid::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BSQUID_AE_SPIT: - { - Vector vecSpitOffset; - Vector vecSpitDir; - - UTIL_MakeVectors( pev->angles ); - - // !!!HACKHACK - the spot at which the spit originates (in front of the mouth) was measured in 3ds and hardcoded here. - // we should be able to read the position of bones at runtime for this info. - vecSpitOffset = ( gpGlobals->v_right * 8 + gpGlobals->v_forward * 37 + gpGlobals->v_up * 23 ); - vecSpitOffset = ( pev->origin + vecSpitOffset ); - vecSpitDir = ( ( m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs ) - vecSpitOffset ).Normalize(); - - vecSpitDir.x += RANDOM_FLOAT( -0.05, 0.05 ); - vecSpitDir.y += RANDOM_FLOAT( -0.05, 0.05 ); - vecSpitDir.z += RANDOM_FLOAT( -0.05, 0 ); - - // do stuff for this event. - AttackSound(); - - // spew the spittle temporary ents. - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpitOffset ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( vecSpitOffset.x ); // pos - WRITE_COORD( vecSpitOffset.y ); - WRITE_COORD( vecSpitOffset.z ); - WRITE_COORD( vecSpitDir.x ); // dir - WRITE_COORD( vecSpitDir.y ); - WRITE_COORD( vecSpitDir.z ); - WRITE_SHORT( iSquidSpitSprite ); // model - WRITE_BYTE( 15 ); // count - WRITE_BYTE( 210 ); // speed - WRITE_BYTE( 25 ); // noise ( client will divide by 100 ) - MESSAGE_END(); - - CSquidSpit::Shoot( pev, vecSpitOffset, vecSpitDir * 900 ); - } - break; - case BSQUID_AE_BITE: - { - // SOUND HERE! - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgBite, DMG_SLASH ); - - if( pHurt ) - { - //pHurt->pev->punchangle.z = -15; - //pHurt->pev->punchangle.x = -45; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 100; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; - } - } - break; - case BSQUID_AE_TAILWHIP: - { - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgWhip, DMG_CLUB | DMG_ALWAYSGIB ); - - if( pHurt ) - { - pHurt->pev->punchangle.z = -20; - pHurt->pev->punchangle.x = 20; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 200; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; - } - } - break; - case BSQUID_AE_BLINK: - { - // close eye. - pev->skin = 1; - } - break; - case BSQUID_AE_HOP: - { - float flGravity = g_psv_gravity->value; - - // throw the squid up into the air on this frame. - if( FBitSet( pev->flags, FL_ONGROUND ) ) - { - pev->flags -= FL_ONGROUND; - } - - // jump into air for 0.8 (24/30) seconds - //pev->velocity.z += ( 0.875 * flGravity ) * 0.5; - pev->velocity.z += ( 0.625 * flGravity ) * 0.5; - } - break; - case BSQUID_AE_THROW: - { - int iPitch; - - // squid throws its prey IF the prey is a client. - CBaseEntity *pHurt = CheckTraceHullAttack( 70, 0, 0 ); - - if( pHurt ) - { - // croonchy bite sound - iPitch = RANDOM_FLOAT( 90, 110 ); - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_bite2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_bite3.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - //pHurt->pev->punchangle.x = RANDOM_LONG( 0, 34 ) - 5; - //pHurt->pev->punchangle.z = RANDOM_LONG( 0, 49 ) - 25; - //pHurt->pev->punchangle.y = RANDOM_LONG( 0, 89 ) - 45; - - // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. - UTIL_ScreenShake( pHurt->pev->origin, 25.0, 1.5, 0.7, 2 ); - - if( pHurt->IsPlayer() ) - { - UTIL_MakeVectors( pev->angles ); - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 300 + gpGlobals->v_up * 300; - } - } - } - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CBullsquid::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/bullsquid.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.bullsquidHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - m_fCanThreatDisplay = TRUE; - m_flNextSpitTime = gpGlobals->time; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBullsquid::Precache() -{ - PRECACHE_MODEL( "models/bullsquid.mdl" ); - - PRECACHE_MODEL( "sprites/bigspit.spr" );// spit projectile. - - iSquidSpitSprite = PRECACHE_MODEL( "sprites/tinyspit.spr" );// client side spittle. - - PRECACHE_SOUND( "zombie/claw_miss2.wav" );// because we use the basemonster SWIPE animation event - - PRECACHE_SOUND( "bullchicken/bc_attack2.wav" ); - PRECACHE_SOUND( "bullchicken/bc_attack3.wav" ); - - PRECACHE_SOUND( "bullchicken/bc_die1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_die2.wav" ); - PRECACHE_SOUND( "bullchicken/bc_die3.wav" ); - - PRECACHE_SOUND( "bullchicken/bc_idle1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_idle2.wav" ); - PRECACHE_SOUND( "bullchicken/bc_idle3.wav" ); - PRECACHE_SOUND( "bullchicken/bc_idle4.wav" ); - PRECACHE_SOUND( "bullchicken/bc_idle5.wav" ); - - PRECACHE_SOUND( "bullchicken/bc_pain1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_pain2.wav" ); - PRECACHE_SOUND( "bullchicken/bc_pain3.wav" ); - PRECACHE_SOUND( "bullchicken/bc_pain4.wav" ); - - PRECACHE_SOUND( "bullchicken/bc_attackgrowl.wav" ); - PRECACHE_SOUND( "bullchicken/bc_attackgrowl2.wav" ); - PRECACHE_SOUND( "bullchicken/bc_attackgrowl3.wav" ); - - PRECACHE_SOUND( "bullchicken/bc_acid1.wav" ); - - PRECACHE_SOUND( "bullchicken/bc_bite2.wav" ); - PRECACHE_SOUND( "bullchicken/bc_bite3.wav" ); - - PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_spithit2.wav" ); -} - -//========================================================= -// DeathSound -//========================================================= -void CBullsquid::DeathSound( void ) -{ - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_die1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_die2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_die3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// AttackSound -//========================================================= -void CBullsquid::AttackSound( void ) -{ - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_attack2.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_attack3.wav", 1, ATTN_NORM ); - break; - } -} - -//======================================================== -// RunAI - overridden for bullsquid because there are things -// that need to be checked every think. -//======================================================== -void CBullsquid::RunAI( void ) -{ - // first, do base class stuff - CBaseMonster::RunAI(); - - if( pev->skin != 0 ) - { - // close eye if it was open. - pev->skin = 0; - } - - if( RANDOM_LONG( 0, 39 ) == 0 ) - { - pev->skin = 1; - } - - if( m_hEnemy != 0 && m_Activity == ACT_RUN ) - { - // chasing enemy. Sprint for last bit - if( ( pev->origin - m_hEnemy->pev->origin).Length2D() < SQUID_SPRINT_DIST ) - { - pev->framerate = 1.25; - } - } -} - -//======================================================== -// AI Schedules Specific to this monster -//========================================================= - -// primary range attack -Task_t tlSquidRangeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slSquidRangeAttack1[] = -{ - { - tlSquidRangeAttack1, - ARRAYSIZE( tlSquidRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "Squid Range Attack1" - }, -}; - -// Chase enemy schedule -Task_t tlSquidChaseEnemy1[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 },// !!!OEM - this will stop nasty squid oscillation. - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slSquidChaseEnemy[] = -{ - { - tlSquidChaseEnemy1, - ARRAYSIZE( tlSquidChaseEnemy1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_SMELL_FOOD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_TASK_FAILED | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER | - bits_SOUND_MEAT, - "Squid Chase Enemy" - }, -}; - -Task_t tlSquidHurtHop[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_SQUID_HOPTURN, (float)0 }, - { TASK_FACE_ENEMY, (float)0 },// in case squid didn't turn all the way in the air. -}; - -Schedule_t slSquidHurtHop[] = -{ - { - tlSquidHurtHop, - ARRAYSIZE( tlSquidHurtHop ), - 0, - 0, - "SquidHurtHop" - } -}; - -Task_t tlSquidSeeCrab[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EXCITED }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slSquidSeeCrab[] = -{ - { - tlSquidSeeCrab, - ARRAYSIZE( tlSquidSeeCrab ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "SquidSeeCrab" - } -}; - -// squid walks to something tasty and eats it. -Task_t tlSquidEat[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the food - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_EAT, (float)50 }, - { TASK_GET_PATH_TO_LASTPOSITION, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidEat[] = -{ - { - tlSquidEat, - ARRAYSIZE( tlSquidEat ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY, - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_MEAT | - bits_SOUND_CARCASS, - "SquidEat" - } -}; - -// this is a bit different than just Eat. We use this schedule when the food is far away, occluded, or behind -// the squid. This schedule plays a sniff animation before going to the source of food. -Task_t tlSquidSniffAndEat[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the food - { TASK_PLAY_SEQUENCE, (float)ACT_DETECT_SCENT }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_EAT, (float)50 }, - { TASK_GET_PATH_TO_LASTPOSITION, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidSniffAndEat[] = -{ - { - tlSquidSniffAndEat, - ARRAYSIZE( tlSquidSniffAndEat ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY, - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_MEAT | - bits_SOUND_CARCASS, - "SquidSniffAndEat" - } -}; - -// squid does this to stinky things. -Task_t tlSquidWallow[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the stinkiness - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_INSPECT_FLOOR }, - { TASK_EAT, (float)50 },// keeps squid from eating or sniffing anything else for a while. - { TASK_GET_PATH_TO_LASTPOSITION, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidWallow[] = -{ - { - tlSquidWallow, - ARRAYSIZE( tlSquidWallow ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY, - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_GARBAGE, - "SquidWallow" - } -}; - -DEFINE_CUSTOM_SCHEDULES( CBullsquid ) -{ - slSquidRangeAttack1, - slSquidChaseEnemy, - slSquidHurtHop, - slSquidSeeCrab, - slSquidEat, - slSquidSniffAndEat, - slSquidWallow -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CBullsquid, CBaseMonster ) - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t *CBullsquid::GetSchedule( void ) -{ - switch( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - { - if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - return GetScheduleOfType( SCHED_SQUID_HURTHOP ); - } - - if( HasConditions( bits_COND_SMELL_FOOD ) ) - { - CSound *pSound; - - pSound = PBestScent(); - - if( pSound && ( !FInViewCone( &pSound->m_vecOrigin ) || !FVisible( pSound->m_vecOrigin ) ) ) - { - // scent is behind or occluded - return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); - } - - // food is right out in the open. Just go get it. - return GetScheduleOfType( SCHED_SQUID_EAT ); - } - - if( HasConditions( bits_COND_SMELL ) ) - { - // there's something stinky. - CSound *pSound; - - pSound = PBestScent(); - if( pSound ) - return GetScheduleOfType( SCHED_SQUID_WALLOW ); - } - break; - } - case MONSTERSTATE_COMBAT: - { - // dead enemy - if( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster::GetSchedule(); - } - - if( HasConditions( bits_COND_NEW_ENEMY ) ) - { - if( m_fCanThreatDisplay && IRelationship( m_hEnemy ) == R_HT ) - { - // this means squid sees a headcrab! - m_fCanThreatDisplay = FALSE;// only do the headcrab dance once per lifetime. - return GetScheduleOfType( SCHED_SQUID_SEECRAB ); - } - else - { - return GetScheduleOfType( SCHED_WAKE_ANGRY ); - } - } - - if( HasConditions( bits_COND_SMELL_FOOD ) ) - { - CSound *pSound; - - pSound = PBestScent(); - - if( pSound && ( !FInViewCone( &pSound->m_vecOrigin ) || !FVisible( pSound->m_vecOrigin ) ) ) - { - // scent is behind or occluded - return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); - } - - // food is right out in the open. Just go get it. - return GetScheduleOfType( SCHED_SQUID_EAT ); - } - - if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - - if( HasConditions( bits_COND_CAN_MELEE_ATTACK2 ) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); - } - - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - break; - } - default: - break; - } - - return CBaseMonster::GetSchedule(); -} - -//========================================================= -// GetScheduleOfType -//========================================================= -Schedule_t *CBullsquid::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_RANGE_ATTACK1: - return &slSquidRangeAttack1[0]; - break; - case SCHED_SQUID_HURTHOP: - return &slSquidHurtHop[0]; - break; - case SCHED_SQUID_SEECRAB: - return &slSquidSeeCrab[0]; - break; - case SCHED_SQUID_EAT: - return &slSquidEat[0]; - break; - case SCHED_SQUID_SNIFF_AND_EAT: - return &slSquidSniffAndEat[0]; - break; - case SCHED_SQUID_WALLOW: - return &slSquidWallow[0]; - break; - case SCHED_CHASE_ENEMY: - return &slSquidChaseEnemy[0]; - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. OVERRIDDEN for bullsquid because it needs to -// know explicitly when the last attempt to chase the enemy -// failed, since that impacts its attack choices. -//========================================================= -void CBullsquid::StartTask( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch( pTask->iTask ) - { - case TASK_MELEE_ATTACK2: - { - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_attackgrowl.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_attackgrowl2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "bullchicken/bc_attackgrowl3.wav", 1, ATTN_NORM ); - break; - } - - CBaseMonster::StartTask( pTask ); - break; - } - case TASK_SQUID_HOPTURN: - { - SetActivity( ACT_HOP ); - MakeIdealYaw( m_vecEnemyLKP ); - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - if( BuildRoute( m_hEnemy->pev->origin, bits_MF_TO_ENEMY, m_hEnemy ) ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - else - { - ALERT( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - default: - { - CBaseMonster::StartTask( pTask ); - break; - } - } -} - -//========================================================= -// RunTask -//========================================================= -void CBullsquid::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_SQUID_HOPTURN: - { - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if( m_fSequenceFinished ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - break; - } - default: - { - CBaseMonster::RunTask( pTask ); - break; - } - } -} - -//========================================================= -// GetIdealState - Overridden for Bullsquid to deal with -// the feature that makes it lose interest in headcrabs for -// a while if something injures it. -//========================================================= -MONSTERSTATE CBullsquid::GetIdealState( void ) -{ - int iConditions; - - iConditions = IScheduleFlags(); - - // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - /* - COMBAT goes to ALERT upon death of enemy - */ - { - if( m_hEnemy != 0 && ( iConditions & bits_COND_LIGHT_DAMAGE || iConditions & bits_COND_HEAVY_DAMAGE ) && FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) - { - // if the squid has a headcrab enemy and something hurts it, it's going to forget about the crab for a while. - m_hEnemy = NULL; - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - break; - } - default: - break; - } - - m_IdealMonsterState = CBaseMonster::GetIdealState(); - - return m_IdealMonsterState; -} diff --git a/dlls/controller.cpp b/dlls/controller.cpp deleted file mode 100644 index e1d57517..00000000 --- a/dlls/controller.cpp +++ /dev/null @@ -1,1378 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// CONTROLLER -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "effects.h" -#include "schedule.h" -#include "weapons.h" -#include "squadmonster.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define CONTROLLER_AE_HEAD_OPEN 1 -#define CONTROLLER_AE_BALL_SHOOT 2 -#define CONTROLLER_AE_SMALL_SHOOT 3 -#define CONTROLLER_AE_POWERUP_FULL 4 -#define CONTROLLER_AE_POWERUP_HALF 5 - -#define CONTROLLER_FLINCH_DELAY 2 // at most one flinch every n secs - -class CController : public CSquadMonster -{ -public: - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - void UpdateOnRemove(); - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void RunAI( void ); - BOOL CheckRangeAttack1( float flDot, float flDist ); // balls - BOOL CheckRangeAttack2( float flDot, float flDist ); // head - BOOL CheckMeleeAttack1( float flDot, float flDist ); // block, throw - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - CUSTOM_SCHEDULES - - void Stop( void ); - void Move( float flInterval ); - int CheckLocalMove( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void SetActivity( Activity NewActivity ); - BOOL ShouldAdvanceRoute( float flWaypointDist ); - int LookupFloat(); - - float m_flNextFlinch; - - float m_flShootTime; - float m_flShootEnd; - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSound( void ); - void DeathSound( void ); - - static const char *pAttackSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pDeathSounds[]; - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - CSprite *m_pBall[2]; // hand balls - int m_iBall[2]; // how bright it should be - float m_iBallTime[2]; // when it should be that color - int m_iBallCurrent[2]; // current brightness - - Vector m_vecEstVelocity; - - Vector m_velocity; - int m_fInCombat; -}; - -LINK_ENTITY_TO_CLASS( monster_alien_controller, CController ) - -TYPEDESCRIPTION CController::m_SaveData[] = -{ - DEFINE_ARRAY( CController, m_pBall, FIELD_CLASSPTR, 2 ), - DEFINE_ARRAY( CController, m_iBall, FIELD_INTEGER, 2 ), - DEFINE_ARRAY( CController, m_iBallTime, FIELD_TIME, 2 ), - DEFINE_ARRAY( CController, m_iBallCurrent, FIELD_INTEGER, 2 ), - DEFINE_FIELD( CController, m_vecEstVelocity, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CController, CSquadMonster ) - -const char *CController::pAttackSounds[] = -{ - "controller/con_attack1.wav", - "controller/con_attack2.wav", - "controller/con_attack3.wav", -}; - -const char *CController::pIdleSounds[] = -{ - "controller/con_idle1.wav", - "controller/con_idle2.wav", - "controller/con_idle3.wav", - "controller/con_idle4.wav", - "controller/con_idle5.wav", -}; - -const char *CController::pAlertSounds[] = -{ - "controller/con_alert1.wav", - "controller/con_alert2.wav", - "controller/con_alert3.wav", -}; - -const char *CController::pPainSounds[] = -{ - "controller/con_pain1.wav", - "controller/con_pain2.wav", - "controller/con_pain3.wav", -}; - -const char *CController::pDeathSounds[] = -{ - "controller/con_die1.wav", - "controller/con_die2.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CController::Classify( void ) -{ - return CLASS_ALIEN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CController::SetYawSpeed( void ) -{ - int ys; - - ys = 120; -#if 0 - switch ( m_Activity ) - { - } -#endif - pev->yaw_speed = ys; -} - -int CController::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // HACK HACK -- until we fix this. - if( IsAlive() ) - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CController::Killed( entvars_t *pevAttacker, int iGib ) -{ - // shut off balls - /* - m_iBall[0] = 0; - m_iBallTime[0] = gpGlobals->time + 4.0; - m_iBall[1] = 0; - m_iBallTime[1] = gpGlobals->time + 4.0; - */ - - // fade balls - if( m_pBall[0] ) - { - m_pBall[0]->SUB_StartFadeOut(); - m_pBall[0] = NULL; - } - if( m_pBall[1] ) - { - m_pBall[1]->SUB_StartFadeOut(); - m_pBall[1] = NULL; - } - - CSquadMonster::Killed( pevAttacker, iGib ); -} - -void CController::GibMonster( void ) -{ - // delete balls - if( m_pBall[0] ) - { - UTIL_Remove( m_pBall[0] ); - m_pBall[0] = NULL; - } - if( m_pBall[1] ) - { - UTIL_Remove( m_pBall[1] ); - m_pBall[1] = NULL; - } - CSquadMonster::GibMonster(); -} - -void CController::PainSound( void ) -{ - if( RANDOM_LONG( 0, 5 ) < 2 ) - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); -} - -void CController::AlertSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); -} - -void CController::IdleSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pIdleSounds ); -} - -void CController::AttackSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAttackSounds ); -} - -void CController::DeathSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CController::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->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( pEvent->options ) / 15.0; - m_iBall[1] = 255; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->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, pev->angles, edict() ); - - pBall->pev->velocity = 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( pEvent->options ) / 15.0; - } - break; - case CONTROLLER_AE_POWERUP_FULL: - { - m_iBall[0] = 255; - m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - m_iBall[1] = 255; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - } - break; - case CONTROLLER_AE_POWERUP_HALF: - { - m_iBall[0] = 192; - m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - m_iBall[1] = 192; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - } - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CController::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/controller.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->flags |= FL_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.controllerHealth; - pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CController::Precache() -{ - PRECACHE_MODEL( "models/controller.mdl" ); - - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pIdleSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - - PRECACHE_MODEL( "sprites/xspark4.spr" ); - - UTIL_PrecacheOther( "controller_energy_ball" ); - UTIL_PrecacheOther( "controller_head_ball" ); -} - -void CController::UpdateOnRemove() -{ - CBaseEntity::UpdateOnRemove(); - - if( m_pBall[0] ) - { - UTIL_Remove( m_pBall[0] ); - m_pBall[0] = 0; - } - - if( m_pBall[1] ) - { - UTIL_Remove( m_pBall[1] ); - m_pBall[1] = 0; - } -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -// Chase enemy schedule -Task_t tlControllerChaseEnemy[] = -{ - { TASK_GET_PATH_TO_ENEMY, (float)128 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slControllerChaseEnemy[] = -{ - { - tlControllerChaseEnemy, - ARRAYSIZE( tlControllerChaseEnemy ), - bits_COND_NEW_ENEMY | - bits_COND_TASK_FAILED, - 0, - "ControllerChaseEnemy" - }, -}; - -Task_t tlControllerStrafe[] = -{ - { TASK_WAIT, (float)0.2 }, - { TASK_GET_PATH_TO_ENEMY, (float)128 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slControllerStrafe[] = -{ - { - tlControllerStrafe, - ARRAYSIZE( tlControllerStrafe ), - bits_COND_NEW_ENEMY, - 0, - "ControllerStrafe" - }, -}; - -Task_t tlControllerTakeCover[] = -{ - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slControllerTakeCover[] = -{ - { - tlControllerTakeCover, - ARRAYSIZE( tlControllerTakeCover ), - bits_COND_NEW_ENEMY, - 0, - "ControllerTakeCover" - }, -}; - -Task_t tlControllerFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slControllerFail[] = -{ - { - tlControllerFail, - ARRAYSIZE( tlControllerFail ), - 0, - 0, - "ControllerFail" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CController ) -{ - slControllerChaseEnemy, - slControllerStrafe, - slControllerTakeCover, - slControllerFail, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CController, CSquadMonster ) - -//========================================================= -// StartTask -//========================================================= -void CController::StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - CSquadMonster::StartTask( pTask ); - break; - case TASK_GET_PATH_TO_ENEMY_LKP: - { - if( BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, pTask->flData, (m_vecEnemyLKP - pev->origin).Length() + 1024 ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - CBaseEntity *pEnemy = m_hEnemy; - - if( pEnemy == NULL ) - { - TaskFail(); - return; - } - - if( BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, pTask->flData, ( pEnemy->pev->origin - pev->origin).Length() + 1024 ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - default: - CSquadMonster::StartTask( pTask ); - break; - } -} - -Vector Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ) -{ - Vector vecTo = vecDst - vecSrc; - - float a = DotProduct( vecMove, vecMove ) - flSpeed * flSpeed; - float b = 0 * DotProduct( vecTo, vecMove ); // why does this work? - float c = DotProduct( vecTo, vecTo ); - float t; - - if( a == 0 ) - { - t = c / ( flSpeed * flSpeed ); - } - else - { - t = b * b - 4 * a * c; - t = sqrt( t ) / ( 2.0 * a ); - float t1 = -b +t; - float t2 = -b -t; - - if( t1 < 0 || t2 < t1 ) - t = t2; - else - t = t1; - } - - // ALERT( at_console, "Intersect %f\n", t ); - - if( t < 0.1 ) - t = 0.1; - if( t > 10.0 ) - t = 10.0; - - Vector vecHit = vecTo + vecMove * t; - return vecHit.Normalize() * flSpeed; -} - -int CController::LookupFloat() -{ - if( m_velocity.Length() < 32.0 ) - { - return LookupSequence( "up" ); - } - - UTIL_MakeAimVectors( pev->angles ); - float x = DotProduct( gpGlobals->v_forward, m_velocity ); - float y = DotProduct( gpGlobals->v_right, m_velocity ); - float z = DotProduct( gpGlobals->v_up, m_velocity ); - - if( fabs( x ) > fabs( y ) && fabs( x ) > fabs( z ) ) - { - if( x > 0 ) - return LookupSequence( "forward" ); - else - return LookupSequence( "backward" ); - } - else if( fabs( y ) > fabs( z ) ) - { - if( y > 0 ) - return LookupSequence( "right" ); - else - return LookupSequence( "left" ); - } - else - { - if( z > 0 ) - return LookupSequence( "up" ); - else - return LookupSequence( "down" ); - } -} - -//========================================================= -// RunTask -//========================================================= -void CController::RunTask( Task_t *pTask ) -{ - if( m_flShootEnd > gpGlobals->time ) - { - Vector vecHand, vecAngle; - - GetAttachment( 2, vecHand, vecAngle ); - - while( m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time ) - { - Vector vecSrc = vecHand + pev->velocity * ( m_flShootTime - gpGlobals->time ); - Vector vecDir; - - if( m_hEnemy != 0 ) - { - if( HasConditions( bits_COND_SEE_ENEMY ) ) - { - m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->pev->velocity * 0.5; - } - else - { - m_vecEstVelocity = m_vecEstVelocity * 0.8; - } - vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( pev->origin ), m_vecEstVelocity, gSkillData.controllerSpeedBall ); - float delta = 0.03490; // +-2 degree - vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.controllerSpeedBall; - - vecSrc = vecSrc + vecDir * ( gpGlobals->time - m_flShootTime ); - CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, pev->angles, edict() ); - pBall->pev->velocity = 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( pTask->iTask ) - { - case TASK_WAIT_FOR_MOVEMENT: - case TASK_WAIT: - case TASK_WAIT_FACE_ENEMY: - case TASK_WAIT_PVS: - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if( m_fSequenceFinished ) - { - m_fInCombat = FALSE; - } - - CSquadMonster::RunTask( pTask ); - - if( !m_fInCombat ) - { - if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - pev->sequence = LookupActivity( ACT_RANGE_ATTACK1 ); - pev->frame = 0; - ResetSequenceInfo(); - m_fInCombat = TRUE; - } - else if( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) ) - { - pev->sequence = LookupActivity( ACT_RANGE_ATTACK2 ); - pev->frame = 0; - ResetSequenceInfo(); - m_fInCombat = TRUE; - } - else - { - int iFloat = LookupFloat(); - if( m_fSequenceFinished || iFloat != pev->sequence ) - { - pev->sequence = iFloat; - pev->frame = 0; - ResetSequenceInfo(); - } - } - } - break; - default: - CSquadMonster::RunTask( pTask ); - break; - } -} - -//========================================================= -// 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 *CController::GetSchedule( void ) -{ - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { - // Vector vecTmp = Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0 ); - - // dead enemy - if( HasConditions( bits_COND_LIGHT_DAMAGE ) ) - { - // m_iFrustration++; - } - if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - { - // m_iFrustration++; - } - } - break; - case MONSTERSTATE_IDLE: - case MONSTERSTATE_ALERT: - break; - default: - break; - } - - return CSquadMonster::GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t *CController::GetScheduleOfType( int Type ) -{ - // ALERT( at_console, "%d\n", m_iFrustration ); - switch( Type ) - { - case SCHED_CHASE_ENEMY: - return slControllerChaseEnemy; - case SCHED_RANGE_ATTACK1: - return slControllerStrafe; - case SCHED_RANGE_ATTACK2: - case SCHED_MELEE_ATTACK1: - case SCHED_MELEE_ATTACK2: - case SCHED_TAKE_COVER_FROM_ENEMY: - return slControllerTakeCover; - case SCHED_FAIL: - return slControllerFail; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// CheckRangeAttack1 - shoot a bigass energy ball out of their head -// -//========================================================= -BOOL CController::CheckRangeAttack1( float flDot, float flDist ) -{ - if( flDot > 0.5 && flDist > 256 && flDist <= 2048 ) - { - return TRUE; - } - return FALSE; -} - -BOOL CController::CheckRangeAttack2( float flDot, float flDist ) -{ - if( flDot > 0.5 && flDist > 64 && flDist <= 2048 ) - { - return TRUE; - } - return FALSE; -} - -BOOL CController::CheckMeleeAttack1( float flDot, float flDist ) -{ - return FALSE; -} - -void CController::SetActivity( Activity NewActivity ) -{ - CBaseMonster::SetActivity( NewActivity ); - - switch( m_Activity ) - { - case ACT_WALK: - m_flGroundSpeed = 100; - break; - default: - m_flGroundSpeed = 100; - break; - } -} - -//========================================================= -// RunAI -//========================================================= -void CController::RunAI( void ) -{ - CBaseMonster::RunAI(); - Vector vecStart, angleGun; - - if( HasMemory( bits_MEMORY_KILLED ) ) - return; - - for( int i = 0; i < 2; i++ ) - { - if( m_pBall[i] == NULL ) - { - m_pBall[i] = CSprite::SpriteCreate( "sprites/xspark4.spr", pev->origin, TRUE ); - m_pBall[i]->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pBall[i]->SetAttachment( edict(), ( i + 3 ) ); - m_pBall[i]->SetScale( 1.0 ); - } - - float t = m_iBallTime[i] - gpGlobals->time; - if( t > 0.1 ) - t = 0.1 / t; - else - t = 1.0; - - m_iBallCurrent[i] += ( m_iBall[i] - m_iBallCurrent[i] ) * t; - - m_pBall[i]->SetBrightness( m_iBallCurrent[i] ); - - GetAttachment( i + 2, vecStart, angleGun ); - UTIL_SetOrigin( m_pBall[i]->pev, vecStart ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() + 0x1000 * ( i + 3 ) ); // entity, attachment - WRITE_COORD( vecStart.x ); // origin - WRITE_COORD( vecStart.y ); - WRITE_COORD( vecStart.z ); - WRITE_COORD( m_iBallCurrent[i] / 8 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 5 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } -} - -extern void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ); - -void CController::Stop( void ) -{ - m_IdealActivity = GetStoppedActivity(); -} - -#define DIST_TO_CHECK 200 - -void CController::Move( float flInterval ) -{ - float flWaypointDist; - float flCheckDist; - float flDist;// how far the lookahead check got before hitting an object. - float flMoveDist; - Vector vecDir; - Vector vecApex; - CBaseEntity *pTargetEnt; - - // Don't move if no valid route - if( FRouteClear() ) - { - ALERT( at_aiconsole, "Tried to move with no route!\n" ); - TaskFail(); - return; - } - - if( m_flMoveWaitFinished > gpGlobals->time ) - return; - -// Debug, test movement code -#if 0 -// if( CVAR_GET_FLOAT( "stopmove" ) != 0 ) - { - if( m_movementGoal == MOVEGOAL_ENEMY ) - RouteSimplify( m_hEnemy ); - else - RouteSimplify( m_hTargetEnt ); - FRefreshRoute(); - return; - } -#else -// Debug, draw the route -// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); -#endif - // if the monster is moving directly towards an entity (enemy for instance), we'll set this pointer - // to that entity for the CheckLocalMove and Triangulate functions. - pTargetEnt = NULL; - - if( m_flGroundSpeed == 0 ) - { - m_flGroundSpeed = 100; - // TaskFail(); - // return; - } - - flMoveDist = m_flGroundSpeed * flInterval; - - do - { - // local move to waypoint. - vecDir = ( m_Route[m_iRouteIndex].vecLocation - pev->origin ).Normalize(); - flWaypointDist = ( m_Route[m_iRouteIndex].vecLocation - pev->origin ).Length(); - - // MakeIdealYaw( m_Route[m_iRouteIndex].vecLocation ); - // ChangeYaw( pev->yaw_speed ); - - // if the waypoint is closer than CheckDist, CheckDist is the dist to waypoint - if( flWaypointDist < DIST_TO_CHECK ) - { - flCheckDist = flWaypointDist; - } - else - { - flCheckDist = DIST_TO_CHECK; - } - - if( ( m_Route[m_iRouteIndex].iType & ( ~bits_MF_NOT_TO_MASK ) ) == bits_MF_TO_ENEMY ) - { - // only on a PURE move to enemy ( i.e., ONLY MF_TO_ENEMY set, not MF_TO_ENEMY and DETOUR ) - pTargetEnt = m_hEnemy; - } - else if( ( m_Route[m_iRouteIndex].iType & ~bits_MF_NOT_TO_MASK ) == bits_MF_TO_TARGETENT ) - { - pTargetEnt = m_hTargetEnt; - } - - // !!!BUGBUG - CheckDist should be derived from ground speed. - // If this fails, it should be because of some dynamic entity blocking this guy. - // We've already checked this path, so we should wait and time out if the entity doesn't move - flDist = 0; - if( CheckLocalMove( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) - { - CBaseEntity *pBlocker; - - // Can't move, stop - Stop(); - // Blocking entity is in global trace_ent - pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); - if( pBlocker ) - { - DispatchBlocked( edict(), pBlocker->edict() ); - } - if( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) - { - // Can we still move toward our target? - if( flDist < m_flGroundSpeed ) - { - // Wait for a second - m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; - //ALERT( at_aiconsole, "Move %s!!!\n", STRING( pBlocker->pev->classname ) ); - return; - } - } - else - { - // try to triangulate around whatever is in the way. - if( FTriangulate( pev->origin, m_Route[m_iRouteIndex].vecLocation, flDist, pTargetEnt, &vecApex ) ) - { - InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); - RouteSimplify( pTargetEnt ); - } - else - { - ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); - Stop(); - if( m_moveWaitTime > 0 ) - { - FRefreshRoute(); - m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime * 0.5; - } - else - { - TaskFail(); - ALERT( at_aiconsole, "Failed to move!\n" ); - //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, ( pev->origin + ( vecDir * flCheckDist ) ).z, m_Route[m_iRouteIndex].vecLocation.z ); - } - return; - } - } - } - - // UNDONE: this is a hack to quit moving farther than it has looked ahead. - if( flCheckDist < flMoveDist ) - { - MoveExecute( pTargetEnt, vecDir, flCheckDist / m_flGroundSpeed ); - - // ALERT( at_console, "%.02f\n", flInterval ); - AdvanceRoute( flWaypointDist ); - flMoveDist -= flCheckDist; - } - else - { - MoveExecute( pTargetEnt, vecDir, flMoveDist / m_flGroundSpeed ); - - if( ShouldAdvanceRoute( flWaypointDist - flMoveDist ) ) - { - AdvanceRoute( flWaypointDist ); - } - flMoveDist = 0; - } - - if( MovementIsComplete() ) - { - Stop(); - RouteClear(); - } - } while( flMoveDist > 0 && flCheckDist > 0 ); - - // cut corner? - if( flWaypointDist < 128 ) - { - if( m_movementGoal == MOVEGOAL_ENEMY ) - RouteSimplify( m_hEnemy ); - else - RouteSimplify( m_hTargetEnt ); - FRefreshRoute(); - - if( m_flGroundSpeed > 100 ) - m_flGroundSpeed -= 40; - } - else - { - if( m_flGroundSpeed < 400 ) - m_flGroundSpeed += 10; - } -} - -BOOL CController::ShouldAdvanceRoute( float flWaypointDist ) -{ - if( flWaypointDist <= 32 ) - { - return TRUE; - } - - return FALSE; -} - -int CController::CheckLocalMove( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) -{ - TraceResult tr; - - UTIL_TraceHull( vecStart + Vector( 0, 0, 32 ), vecEnd + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, edict(), &tr ); - - // ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z ); - // ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z ); - - if( pflDist ) - { - *pflDist = ( ( tr.vecEndPos - Vector( 0, 0, 32 ) ) - vecStart ).Length();// get the distance. - } - - // ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction ); - if( tr.fStartSolid || tr.flFraction < 1.0 ) - { - if( pTarget && pTarget->edict() == gpGlobals->trace_ent ) - return LOCALMOVE_VALID; - return LOCALMOVE_INVALID; - } - - return LOCALMOVE_VALID; -} - -void CController::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - if( m_IdealActivity != m_movementActivity ) - m_IdealActivity = m_movementActivity; - - // ALERT( at_console, "move %.4f %.4f %.4f : %f\n", vecDir.x, vecDir.y, vecDir.z, flInterval ); - - // float flTotal = m_flGroundSpeed * pev->framerate * flInterval; - // UTIL_MoveToOrigin ( ENT( pev ), m_Route[m_iRouteIndex].vecLocation, flTotal, MOVE_STRAFE ); - - m_velocity = m_velocity * 0.8 + m_flGroundSpeed * vecDir * 0.2; - - UTIL_MoveToOrigin( ENT( pev ), pev->origin + m_velocity, m_velocity.Length() * flInterval, MOVE_STRAFE ); -} - -//========================================================= -// Controller bouncy ball attack -//========================================================= -class CControllerHeadBall : public CBaseMonster -{ - void Spawn( void ); - void Precache( void ); - void EXPORT HuntThink( void ); - void EXPORT DieThink( void ); - void EXPORT BounceTouch( CBaseEntity *pOther ); - void MovetoTarget( Vector vecTarget ); - void Crawl( void ); - int m_flNextAttack; - Vector m_vecIdeal; - EHANDLE m_hOwner; -}; - -LINK_ENTITY_TO_CLASS( controller_head_ball, CControllerHeadBall ) - -void CControllerHeadBall::Spawn( void ) -{ - Precache(); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT( pev ), "sprites/xspark4.spr" ); - pev->rendermode = kRenderTransAdd; - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->renderamt = 255; - pev->scale = 2.0; - - UTIL_SetSize(pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CControllerHeadBall::HuntThink ); - SetTouch( &CControllerHeadBall::BounceTouch ); - - m_vecIdeal = Vector( 0, 0, 0 ); - - pev->nextthink = gpGlobals->time + 0.1; - - m_hOwner = Instance( pev->owner ); - pev->dmgtime = gpGlobals->time; -} - -void CControllerHeadBall::Precache( void ) -{ - PRECACHE_MODEL( "sprites/xspark1.spr" ); - PRECACHE_SOUND( "debris/zap4.wav" ); - PRECACHE_SOUND( "weapons/electro4.wav" ); -} - -void CControllerHeadBall::HuntThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - pev->renderamt -= 5; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( pev->renderamt / 16 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - - // check world boundaries - if( gpGlobals->time - pev->dmgtime > 5 || pev->renderamt < 64 || m_hEnemy == 0 || m_hOwner == 0 || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096 ) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - MovetoTarget( m_hEnemy->Center() ); - - if( ( m_hEnemy->Center() - pev->origin ).Length() < 64 ) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, ENT( pev ), &tr ); - - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if( pEntity != NULL && pEntity->pev->takedamage ) - { - ClearMultiDamage(); - pEntity->TraceAttack( m_hOwner->pev, gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK ); - ApplyMultiDamage( pev, m_hOwner->pev ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - UTIL_EmitAmbientSound( ENT( pev ), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); - - m_flNextAttack = gpGlobals->time + 3.0; - - SetThink( &CControllerHeadBall::DieThink ); - pev->nextthink = gpGlobals->time + 0.3; - } - - //Crawl(); -} - -void CControllerHeadBall::DieThink( void ) -{ - UTIL_Remove( this ); -} - -void CControllerHeadBall::MovetoTarget( Vector vecTarget ) -{ - // accelerate - float flSpeed = m_vecIdeal.Length(); - if( flSpeed == 0 ) - { - m_vecIdeal = pev->velocity; - flSpeed = m_vecIdeal.Length(); - } - - if( flSpeed > 400 ) - { - m_vecIdeal = m_vecIdeal.Normalize() * 400; - } - m_vecIdeal = m_vecIdeal + ( vecTarget - pev->origin ).Normalize() * 100; - pev->velocity = m_vecIdeal; -} - -void CControllerHeadBall::Crawl( void ) -{ - Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize(); - Vector vecPnt = pev->origin + pev->velocity * 0.3 + vecAim * 64; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( vecPnt.x); - WRITE_COORD( vecPnt.y); - WRITE_COORD( vecPnt.z); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); -} - -void CControllerHeadBall::BounceTouch( CBaseEntity *pOther ) -{ - Vector vecDir = m_vecIdeal.Normalize(); - - TraceResult tr = UTIL_GetGlobalTrace(); - - float n = -DotProduct( tr.vecPlaneNormal, vecDir ); - - vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; - - m_vecIdeal = vecDir * m_vecIdeal.Length(); -} - -class CControllerZapBall : public CBaseMonster -{ - void Spawn( void ); - void Precache( void ); - void EXPORT AnimateThink( void ); - void EXPORT ExplodeTouch( CBaseEntity *pOther ); - - EHANDLE m_hOwner; -}; - -LINK_ENTITY_TO_CLASS( controller_energy_ball, CControllerZapBall ) - -void CControllerZapBall::Spawn( void ) -{ - Precache(); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL( ENT( pev ), "sprites/xspark4.spr" ); - pev->rendermode = kRenderTransAdd; - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->renderamt = 255; - pev->scale = 0.5; - - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CControllerZapBall::AnimateThink ); - SetTouch( &CControllerZapBall::ExplodeTouch ); - - m_hOwner = Instance( pev->owner ); - pev->dmgtime = gpGlobals->time; // keep track of when ball spawned - pev->nextthink = gpGlobals->time + 0.1; -} - -void CControllerZapBall::Precache( void ) -{ - PRECACHE_MODEL( "sprites/xspark4.spr" ); - // PRECACHE_SOUND( "debris/zap4.wav" ); - // PRECACHE_SOUND( "weapons/electro4.wav" ); -} - -void CControllerZapBall::AnimateThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - pev->frame = ( (int)pev->frame + 1 ) % 11; - - if( gpGlobals->time - pev->dmgtime > 5 || pev->velocity.Length() < 10 ) - { - SetTouch( NULL ); - UTIL_Remove( this ); - } -} - -void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) -{ - if( pOther->pev->takedamage ) - { - TraceResult tr = UTIL_GetGlobalTrace(); - - entvars_t *pevOwner; - - if( m_hOwner != 0 ) - { - pevOwner = m_hOwner->pev; - } - else - { - pevOwner = pev; - } - - ClearMultiDamage(); - pOther->TraceAttack(pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM ); - ApplyMultiDamage( pevOwner, pevOwner ); - - UTIL_EmitAmbientSound( ENT( pev ), tr.vecEndPos, "weapons/electro4.wav", 0.3, ATTN_NORM, 0, RANDOM_LONG( 90, 99 ) ); - } - - UTIL_Remove( this ); -} -#endif //!OEM && !HLDEMO diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp deleted file mode 100644 index 12d0ff8c..00000000 --- a/dlls/crossbow.cpp +++ /dev/null @@ -1,561 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - -#ifndef CLIENT_DLL -#define BOLT_AIR_VELOCITY 2000 -#define BOLT_WATER_VELOCITY 1000 - -extern BOOL gPhysicsInterfaceInitialized; - -// UNDONE: Save/restore this? Don't forget to set classname and LINK_ENTITY_TO_CLASS() -// -// OVERLOADS SOME ENTVARS: -// -// speed - the ideal magnitude of my velocity -class CCrossbowBolt : public CBaseEntity -{ - void Spawn( void ); - void Precache( void ); - int Classify( void ); - void EXPORT BubbleThink( void ); - void EXPORT BoltTouch( CBaseEntity *pOther ); - void EXPORT ExplodeThink( void ); - - int m_iTrail; - -public: - static CCrossbowBolt *BoltCreate( void ); -}; - -LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt ) - -CCrossbowBolt *CCrossbowBolt::BoltCreate( void ) -{ - // Create a new entity with CCrossbowBolt private data - CCrossbowBolt *pBolt = GetClassPtr( (CCrossbowBolt *)NULL ); - pBolt->pev->classname = MAKE_STRING( "crossbow_bolt" ); // g-cont. enable save\restore - pBolt->Spawn(); - - return pBolt; -} - -void CCrossbowBolt::Spawn() -{ - Precache(); - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->gravity = 0.5; - - SET_MODEL( ENT( pev ), "models/crossbow_bolt.mdl" ); - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - - SetTouch( &CCrossbowBolt::BoltTouch ); - SetThink( &CCrossbowBolt::BubbleThink ); - pev->nextthink = gpGlobals->time + 0.2; -} - -void CCrossbowBolt::Precache() -{ - PRECACHE_MODEL( "models/crossbow_bolt.mdl" ); - PRECACHE_SOUND( "weapons/xbow_hitbod1.wav" ); - PRECACHE_SOUND( "weapons/xbow_hitbod2.wav" ); - PRECACHE_SOUND( "weapons/xbow_fly1.wav" ); - PRECACHE_SOUND( "weapons/xbow_hit1.wav" ); - PRECACHE_SOUND( "fvox/beep.wav" ); - m_iTrail = PRECACHE_MODEL( "sprites/streak.spr" ); -} - -int CCrossbowBolt::Classify( void ) -{ - return CLASS_NONE; -} - -void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) -{ - SetTouch( NULL ); - SetThink( NULL ); - - if( pOther->pev->takedamage ) - { - TraceResult tr = UTIL_GetGlobalTrace(); - entvars_t *pevOwner; - - pevOwner = VARS( pev->owner ); - - // UNDONE: this needs to call TraceAttack instead - ClearMultiDamage(); - - if( pOther->IsPlayer() ) - { - pOther->TraceAttack( pevOwner, gSkillData.plrDmgCrossbowClient, pev->velocity.Normalize(), &tr, DMG_NEVERGIB ); - } - else - { - pOther->TraceAttack( pevOwner, gSkillData.plrDmgCrossbowMonster, pev->velocity.Normalize(), &tr, DMG_BULLET | DMG_NEVERGIB ); - } - - ApplyMultiDamage( pev, pevOwner ); - - pev->velocity = Vector( 0, 0, 0 ); - // play body "thwack" sound - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM ); - break; - } - - if( !g_pGameRules->IsMultiplayer() ) - { - Killed( pev, GIB_NEVER ); - } - } - else - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_BODY, "weapons/xbow_hit1.wav", RANDOM_FLOAT( 0.95, 1.0 ), ATTN_NORM, 0, 98 + RANDOM_LONG( 0, 7 ) ); - - SetThink( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit. - - if( FClassnameIs( pOther->pev, "worldspawn" ) ) - { - // if what we hit is static architecture, can stay around for a while. - Vector vecDir = pev->velocity.Normalize(); - UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); - pev->angles = UTIL_VecToAngles( vecDir ); - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_FLY; - pev->velocity = Vector( 0, 0, 0 ); - pev->avelocity.z = 0; - pev->angles.z = RANDOM_LONG( 0, 360 ); - pev->nextthink = gpGlobals->time + 10.0; - } - else if( pOther->pev->movetype == MOVETYPE_PUSH || pOther->pev->movetype == MOVETYPE_PUSHSTEP ) - { - Vector vecDir = pev->velocity.Normalize(); - UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); - pev->angles = UTIL_VecToAngles( vecDir ); - pev->solid = SOLID_NOT; - pev->velocity = Vector( 0, 0, 0 ); - pev->avelocity.z = 0; - pev->angles.z = RANDOM_LONG( 0, 360 ); - pev->nextthink = gpGlobals->time + 10.0; - - if (gPhysicsInterfaceInitialized) { - // g-cont. Setup movewith feature - pev->movetype = MOVETYPE_COMPOUND; // set movewith type - pev->aiment = ENT( pOther->pev ); // set parent - } - } - - if( UTIL_PointContents( pev->origin ) != CONTENTS_WATER ) - { - UTIL_Sparks( pev->origin ); - } - } - - if( g_pGameRules->IsMultiplayer() ) - { - SetThink( &CCrossbowBolt::ExplodeThink ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - -void CCrossbowBolt::BubbleThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if( pev->waterlevel == 0 ) - return; - - UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 1 ); -} - -void CCrossbowBolt::ExplodeThink( void ) -{ - int iContents = UTIL_PointContents( pev->origin ); - int iScale; - - pev->dmg = 40; - iScale = 10; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - if( iContents != CONTENTS_WATER ) - { - WRITE_SHORT( g_sModelIndexFireball ); - } - else - { - WRITE_SHORT( g_sModelIndexWExplosion ); - } - WRITE_BYTE( iScale ); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - entvars_t *pevOwner; - - if( pev->owner ) - pevOwner = VARS( pev->owner ); - else - pevOwner = NULL; - - pev->owner = NULL; // can't traceline attack owner if this is set - - ::RadiusDamage( pev->origin, pev, pevOwner, pev->dmg, 128, CLASS_NONE, DMG_BLAST | DMG_ALWAYSGIB ); - - UTIL_Remove( this ); -} -#endif - -enum crossbow_e -{ - CROSSBOW_IDLE1 = 0, // full - CROSSBOW_IDLE2, // empty - CROSSBOW_FIDGET1, // full - CROSSBOW_FIDGET2, // empty - CROSSBOW_FIRE1, // full - CROSSBOW_FIRE2, // reload - CROSSBOW_FIRE3, // empty - CROSSBOW_RELOAD, // from empty - CROSSBOW_DRAW1, // full - CROSSBOW_DRAW2, // empty - CROSSBOW_HOLSTER1, // full - CROSSBOW_HOLSTER2 // empty -}; - -LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow ) - -void CCrossbow::Spawn() -{ - Precache(); - m_iId = WEAPON_CROSSBOW; - SET_MODEL( ENT( pev ), "models/w_crossbow.mdl" ); - - m_iDefaultAmmo = CROSSBOW_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -int CCrossbow::AddToPlayer( CBasePlayer *pPlayer ) -{ - if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -void CCrossbow::Precache( void ) -{ - PRECACHE_MODEL( "models/w_crossbow.mdl" ); - PRECACHE_MODEL( "models/v_crossbow.mdl" ); - PRECACHE_MODEL( "models/p_crossbow.mdl" ); - - PRECACHE_SOUND( "weapons/xbow_fire1.wav" ); - PRECACHE_SOUND( "weapons/xbow_reload1.wav" ); - - UTIL_PrecacheOther( "crossbow_bolt" ); - - m_usCrossbow = PRECACHE_EVENT( 1, "events/crossbow1.sc" ); - m_usCrossbow2 = PRECACHE_EVENT( 1, "events/crossbow2.sc" ); -} - -int CCrossbow::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "bolts"; - p->iMaxAmmo1 = BOLT_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = CROSSBOW_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 2; - p->iId = WEAPON_CROSSBOW; - p->iFlags = 0; - p->iWeight = CROSSBOW_WEIGHT; - return 1; -} - -BOOL CCrossbow::Deploy() -{ - if( m_iClip ) - return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW1, "bow" ); - return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW2, "bow" ); -} - -void CCrossbow::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - if( m_fInZoom ) - { - SecondaryAttack(); - } - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - if( m_iClip ) - SendWeaponAnim( CROSSBOW_HOLSTER1 ); - else - SendWeaponAnim( CROSSBOW_HOLSTER2 ); -} - -void CCrossbow::PrimaryAttack( void ) -{ -#ifdef CLIENT_DLL - if( m_fInZoom && bIsMultiplayer() ) -#else - if( m_fInZoom && g_pGameRules->IsMultiplayer() ) -#endif - { - FireSniperBolt(); - return; - } - - FireBolt(); -} - -// this function only gets called in multiplayer -void CCrossbow::FireSniperBolt() -{ - m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); - - if( m_iClip == 0 ) - { - PlayEmptySound(); - return; - } - - TraceResult tr; - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_iClip--; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - UTIL_MakeVectors( anglesAim ); - Vector vecSrc = m_pPlayer->GetGunPosition() - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; - - UTIL_TraceLine( vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, m_pPlayer->edict(), &tr ); - -#ifndef CLIENT_DLL - if( tr.pHit->v.takedamage ) - { - ClearMultiDamage(); - CBaseEntity::Instance( tr.pHit )->TraceAttack( m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); - ApplyMultiDamage( pev, m_pPlayer->pev ); - } -#endif -} - -void CCrossbow::FireBolt() -{ - TraceResult tr; - - if( m_iClip == 0 ) - { - PlayEmptySound(); - return; - } - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - m_iClip--; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - UTIL_MakeVectors( anglesAim ); - - anglesAim.x = -anglesAim.x; - -#ifndef CLIENT_DLL - Vector vecSrc = m_pPlayer->GetGunPosition() - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; - - CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate(); - pBolt->pev->origin = vecSrc; - pBolt->pev->angles = anglesAim; - pBolt->pev->owner = m_pPlayer->edict(); - - if( m_pPlayer->pev->waterlevel == 3 ) - { - pBolt->pev->velocity = vecDir * BOLT_WATER_VELOCITY; - pBolt->pev->speed = BOLT_WATER_VELOCITY; - } - else - { - pBolt->pev->velocity = vecDir * BOLT_AIR_VELOCITY; - pBolt->pev->speed = BOLT_AIR_VELOCITY; - } - pBolt->pev->avelocity.z = 10; -#endif - - if( !m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - - m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); - - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - - if( m_iClip != 0 ) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; - else - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; -} - -void CCrossbow::SecondaryAttack() -{ - if( m_pPlayer->pev->fov != 0 ) - { - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - m_fInZoom = 0; - } - else if( m_pPlayer->pev->fov != 20 ) - { - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 20; - m_fInZoom = 1; - } - - pev->nextthink = UTIL_WeaponTimeBase() + 0.1; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; -} - -void CCrossbow::Reload( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == CROSSBOW_MAX_CLIP ) - return; - - if( m_pPlayer->pev->fov != 0 ) - { - SecondaryAttack(); - } - - if( DefaultReload( CROSSBOW_MAX_CLIP, CROSSBOW_RELOAD, 4.5 ) ) - { - EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT( 0.95, 1.0 ), ATTN_NORM, 0, 93 + RANDOM_LONG( 0, 0xF ) ); - } -} - -void CCrossbow::WeaponIdle( void ) -{ - m_pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES ); // get the autoaim vector but ignore it; used for autoaim crosshair in DM - - ResetEmptySound(); - - if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) - { - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if( flRand <= 0.75 ) - { - if( m_iClip ) - { - SendWeaponAnim( CROSSBOW_IDLE1 ); - } - else - { - SendWeaponAnim( CROSSBOW_IDLE2 ); - } - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - if( m_iClip ) - { - SendWeaponAnim( CROSSBOW_FIDGET1 ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; - } - else - { - SendWeaponAnim( CROSSBOW_FIDGET2 ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 30.0; - } - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - } -} - -class CCrossbowAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT( pev ), "models/w_crossbow_clip.mdl" ); - CBasePlayerAmmo::Spawn(); - } - void Precache( void ) - { - PRECACHE_MODEL( "models/w_crossbow_clip.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if( pOther->GiveAmmo( AMMO_CROSSBOWCLIP_GIVE, "bolts", BOLT_MAX_CARRY ) != -1 ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ) -#endif diff --git a/dlls/egon.cpp b/dlls/egon.cpp deleted file mode 100644 index b83c9086..00000000 --- a/dlls/egon.cpp +++ /dev/null @@ -1,544 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" -#include "customentity.h" -#include "gamerules.h" - -#define EGON_PRIMARY_VOLUME 450 -#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" -#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" -#define EGON_SOUND_OFF "weapons/egon_off1.wav" -#define EGON_SOUND_RUN "weapons/egon_run3.wav" -#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" - -#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes -#define EGON_SWITCH_WIDE_TIME 1.5 - -enum egon_e { - EGON_IDLE1 = 0, - EGON_FIDGET1, - EGON_ALTFIREON, - EGON_ALTFIRECYCLE, - EGON_ALTFIREOFF, - EGON_FIRE1, - EGON_FIRE2, - EGON_FIRE3, - EGON_FIRE4, - EGON_DRAW, - EGON_HOLSTER -}; - -LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ) - -void CEgon::Spawn() -{ - Precache(); - m_iId = WEAPON_EGON; - SET_MODEL( ENT( pev ), "models/w_egon.mdl" ); - - m_iDefaultAmmo = EGON_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -void CEgon::Precache( void ) -{ - PRECACHE_MODEL( "models/w_egon.mdl" ); - PRECACHE_MODEL( "models/v_egon.mdl" ); - PRECACHE_MODEL( "models/p_egon.mdl" ); - - PRECACHE_MODEL( "models/w_9mmclip.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - - PRECACHE_SOUND( EGON_SOUND_OFF ); - PRECACHE_SOUND( EGON_SOUND_RUN ); - PRECACHE_SOUND( EGON_SOUND_STARTUP ); - - PRECACHE_MODEL( EGON_BEAM_SPRITE ); - PRECACHE_MODEL( EGON_FLARE_SPRITE ); - - PRECACHE_SOUND( "weapons/357_cock1.wav" ); - - m_usEgonFire = PRECACHE_EVENT( 1, "events/egon_fire.sc" ); - m_usEgonStop = PRECACHE_EVENT( 1, "events/egon_stop.sc" ); -} - -BOOL CEgon::Deploy( void ) -{ - m_deployed = FALSE; - m_fireState = FIRE_OFF; - return DefaultDeploy( "models/v_egon.mdl", "models/p_egon.mdl", EGON_DRAW, "egon" ); -} - -int CEgon::AddToPlayer( CBasePlayer *pPlayer ) -{ - if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -void CEgon::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( EGON_HOLSTER ); - - EndAttack(); -} - -int CEgon::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "uranium"; - p->iMaxAmmo1 = URANIUM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 2; - p->iId = m_iId = WEAPON_EGON; - p->iFlags = 0; - p->iWeight = EGON_WEIGHT; - - return 1; -} - -#define EGON_PULSE_INTERVAL 0.1 -#define EGON_DISCHARGE_INTERVAL 0.1 - -float CEgon::GetPulseInterval( void ) -{ - return EGON_PULSE_INTERVAL; -} - -float CEgon::GetDischargeInterval( void ) -{ - return EGON_DISCHARGE_INTERVAL; -} - -BOOL CEgon::HasAmmo( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - return FALSE; - - return TRUE; -} - -void CEgon::UseAmmo( int count ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count ) - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count; - else - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0; -} - -void CEgon::Attack( void ) -{ - // don't fire underwater - if( m_pPlayer->pev->waterlevel == 3 ) - { - if( m_fireState != FIRE_OFF || m_pBeam ) - { - EndAttack(); - } - else - { - PlayEmptySound(); - } - return; - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition(); - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - switch( m_fireState ) - { - case FIRE_OFF: - { - if( !HasAmmo() ) - { - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; - PlayEmptySound( ); - return; - } - - m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP. - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 1, 0 ); - - m_shakeTime = 0; - - m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - pev->fuser1 = UTIL_WeaponTimeBase() + 2; - - pev->dmgtime = gpGlobals->time + GetPulseInterval(); - m_fireState = FIRE_CHARGE; - break; - } - case FIRE_CHARGE: - { - Fire( vecSrc, vecAiming ); - m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - - if( pev->fuser1 <= UTIL_WeaponTimeBase() ) - { - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 0, 0 ); - pev->fuser1 = 1000; - } - - if( !HasAmmo() ) - { - EndAttack(); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; - } - break; - } - } -} - -void CEgon::PrimaryAttack( void ) -{ - m_fireMode = FIRE_WIDE; - Attack(); -} - -void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) -{ - Vector vecDest = vecOrigSrc + vecDir * 2048; - edict_t *pentIgnore; - TraceResult tr; - - pentIgnore = m_pPlayer->edict(); - Vector tmpSrc = vecOrigSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3; - - // ALERT( at_console, "." ); - - UTIL_TraceLine( vecOrigSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); - - if( tr.fAllSolid ) - return; - -#ifndef CLIENT_DLL - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if( pEntity == NULL ) - return; - - if( g_pGameRules->IsMultiplayer() ) - { - if( m_pSprite && pEntity->pev->takedamage ) - { - m_pSprite->pev->effects &= ~EF_NODRAW; - } - else if( m_pSprite ) - { - m_pSprite->pev->effects |= EF_NODRAW; - } - } -#endif - float timedist = 0.0f; - - switch( m_fireMode ) - { - case FIRE_NARROW: -#ifndef CLIENT_DLL - if( pev->dmgtime < gpGlobals->time ) - { - // Narrow mode only does damage to the entity it hits - ClearMultiDamage(); - if( pEntity->pev->takedamage ) - { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonNarrow, vecDir, &tr, DMG_ENERGYBEAM ); - } - ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - - if( g_pGameRules->IsMultiplayer() ) - { - // multiplayer uses 1 ammo every 1/10th second - if( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.1; - } - } - else - { - // single player, use 3 ammo/second - if( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.166; - } - } - - pev->dmgtime = gpGlobals->time + GetPulseInterval(); - } -#endif - timedist = ( pev->dmgtime - gpGlobals->time ) / GetPulseInterval(); - break; - case FIRE_WIDE: -#ifndef CLIENT_DLL - if( pev->dmgtime < gpGlobals->time ) - { - // wide mode does damage to the ent, and radius damage - ClearMultiDamage(); - if( pEntity->pev->takedamage ) - { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonWide, vecDir, &tr, DMG_ENERGYBEAM | DMG_ALWAYSGIB ); - } - ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - - if( g_pGameRules->IsMultiplayer() ) - { - // radius damage a little more potent in multiplayer. - ::RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, gSkillData.plrDmgEgonWide/4, 128, CLASS_NONE, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ); - } - - if( !m_pPlayer->IsAlive() ) - return; - - if( g_pGameRules->IsMultiplayer() ) - { - //multiplayer uses 5 ammo/second - if( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.2; - } - } - else - { - // Wide mode uses 10 charges per second in single player - if( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.1; - } - } - - pev->dmgtime = gpGlobals->time + GetDischargeInterval(); - if( m_shakeTime < gpGlobals->time ) - { - UTIL_ScreenShake( tr.vecEndPos, 5.0, 150.0, 0.75, 250.0 ); - m_shakeTime = gpGlobals->time + 1.5; - } - } -#endif - timedist = ( pev->dmgtime - gpGlobals->time ) / GetDischargeInterval(); - break; - } - - if( timedist < 0 ) - timedist = 0; - else if( timedist > 1 ) - timedist = 1; - timedist = 1 - timedist; - - UpdateEffect( tmpSrc, tr.vecEndPos, timedist ); -} - -void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ) -{ -#ifndef CLIENT_DLL - if( !m_pBeam ) - { - CreateEffect(); - } - - m_pBeam->SetStartPos( endPoint ); - m_pBeam->SetBrightness( (int)( 255 - ( timeBlend * 180 )) ); - m_pBeam->SetWidth( (int)( 40 - ( timeBlend * 20 ) ) ); - - if( m_fireMode == FIRE_WIDE ) - m_pBeam->SetColor( (int)( 30 + ( 25 * timeBlend ) ), (int)( 30 + ( 30 * timeBlend ) ), (int)( 64 + 80 * fabs( sin( gpGlobals->time * 10 ) ) ) ); - else - m_pBeam->SetColor( (int)( 60 + ( 25 * timeBlend ) ), (int)( 120 + ( 30 * timeBlend ) ), (int)( 64 + 80 * fabs( sin( gpGlobals->time *10 ) ) ) ); - - UTIL_SetOrigin( m_pSprite->pev, endPoint ); - m_pSprite->pev->frame += 8 * gpGlobals->frametime; - if( m_pSprite->pev->frame > m_pSprite->Frames() ) - m_pSprite->pev->frame = 0; - - m_pNoise->SetStartPos( endPoint ); -#endif -} - -void CEgon::CreateEffect( void ) -{ -#ifndef CLIENT_DLL - DestroyEffect(); - - m_pBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 40 ); - m_pBeam->PointEntInit( pev->origin, m_pPlayer->entindex() ); - m_pBeam->SetFlags( BEAM_FSINE ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition - m_pBeam->pev->flags |= FL_SKIPLOCALHOST; - m_pBeam->pev->owner = m_pPlayer->edict(); - - m_pNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 55 ); - m_pNoise->PointEntInit( pev->origin, m_pPlayer->entindex() ); - m_pNoise->SetScrollRate( 25 ); - m_pNoise->SetBrightness( 100 ); - m_pNoise->SetEndAttachment( 1 ); - m_pNoise->pev->spawnflags |= SF_BEAM_TEMPORARY; - m_pNoise->pev->flags |= FL_SKIPLOCALHOST; - m_pNoise->pev->owner = m_pPlayer->edict(); - - m_pSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, pev->origin, FALSE ); - m_pSprite->pev->scale = 1.0; - m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY; - m_pSprite->pev->flags |= FL_SKIPLOCALHOST; - m_pSprite->pev->owner = m_pPlayer->edict(); - - if( m_fireMode == FIRE_WIDE ) - { - m_pBeam->SetScrollRate( 50 ); - m_pBeam->SetNoise( 20 ); - m_pNoise->SetColor( 50, 50, 255 ); - m_pNoise->SetNoise( 8 ); - } - else - { - m_pBeam->SetScrollRate( 110 ); - m_pBeam->SetNoise( 5 ); - m_pNoise->SetColor( 80, 120, 255 ); - m_pNoise->SetNoise( 2 ); - } -#endif -} - -void CEgon::DestroyEffect( void ) -{ -#ifndef CLIENT_DLL - if( m_pBeam ) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } - - if( m_pNoise ) - { - UTIL_Remove( m_pNoise ); - m_pNoise = NULL; - } - if( m_pSprite ) - { - if( m_fireMode == FIRE_WIDE ) - m_pSprite->Expand( 10, 500 ); - else - UTIL_Remove( m_pSprite ); - m_pSprite = NULL; - } -#endif -} - -void CEgon::WeaponIdle( void ) -{ - ResetEmptySound(); - - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if( m_fireState != FIRE_OFF ) - EndAttack(); - - int iAnim; - - float flRand = RANDOM_FLOAT( 0, 1 ); - - if( flRand <= 0.5 ) - { - iAnim = EGON_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - iAnim = EGON_FIDGET1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - } - - SendWeaponAnim( iAnim ); - m_deployed = TRUE; -} - -void CEgon::EndAttack( void ) -{ - bool bMakeNoise = false; - - if( m_fireState != FIRE_OFF ) //Checking the button just in case!. - bMakeNoise = true; - - PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, m_pPlayer->edict(), m_usEgonStop, 0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, bMakeNoise, 0, 0, 0 ); - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - - m_fireState = FIRE_OFF; - - DestroyEffect(); -} - -class CEgonAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT( pev ), "models/w_chainammo.mdl" ); - CBasePlayerAmmo::Spawn(); - } - - void Precache( void ) - { - PRECACHE_MODEL( "models/w_chainammo.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - - BOOL AddAmmo( CBaseEntity *pOther ) - { - if( pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1 ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ) -#endif diff --git a/dlls/flyingmonster.cpp b/dlls/flyingmonster.cpp deleted file mode 100644 index c9822898..00000000 --- a/dlls/flyingmonster.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "flyingmonster.h" - -#define FLYING_AE_FLAP (8) -#define FLYING_AE_FLAPSOUND (9) - -extern DLL_GLOBAL edict_t *g_pBodyQueueHead; - -int CFlyingMonster::CheckLocalMove( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) -{ - // UNDONE: need to check more than the endpoint - if( FBitSet( pev->flags, FL_SWIM ) && ( UTIL_PointContents( vecEnd ) != CONTENTS_WATER ) ) - { - // ALERT( at_aiconsole, "can't swim out of water\n" ); - return FALSE; - } - - TraceResult tr; - - UTIL_TraceHull( vecStart + Vector( 0, 0, 32 ), vecEnd + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, edict(), &tr ); - - // ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z ); - // ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z ); - - if( pflDist ) - { - *pflDist = ( ( tr.vecEndPos - Vector( 0, 0, 32 ) ) - vecStart ).Length();// get the distance. - } - - // ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction ); - if( tr.fStartSolid || tr.flFraction < 1.0 ) - { - if( pTarget && pTarget->edict() == gpGlobals->trace_ent ) - return LOCALMOVE_VALID; - return LOCALMOVE_INVALID; - } - - return LOCALMOVE_VALID; -} - -BOOL CFlyingMonster::FTriangulate( const Vector &vecStart, const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) -{ - return CBaseMonster::FTriangulate( vecStart, vecEnd, flDist, pTargetEnt, pApex ); -} - -Activity CFlyingMonster::GetStoppedActivity( void ) -{ - if( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else - return ACT_IDLE; - - return ACT_HOVER; -} - -void CFlyingMonster::Stop( void ) -{ - Activity stopped = GetStoppedActivity(); - if( m_IdealActivity != stopped ) - { - m_flightSpeed = 0; - m_IdealActivity = stopped; - } - pev->angles.z = 0; - pev->angles.x = 0; - m_vecTravel = g_vecZero; -} - -float CFlyingMonster::ChangeYaw( int speed ) -{ - if( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlYawDiff(); - float target = 0; - - if( m_IdealActivity != GetStoppedActivity() ) - { - if( diff < -20 ) - target = 90; - else if( diff > 20 ) - target = -90; - } - pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * gpGlobals->frametime ); - } - return CBaseMonster::ChangeYaw( speed ); -} - -void CFlyingMonster::Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_STEP; - ClearBits( pev->flags, FL_ONGROUND ); - pev->angles.z = 0; - pev->angles.x = 0; - CBaseMonster::Killed( pevAttacker, iGib ); -} - -void CFlyingMonster::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case FLYING_AE_FLAP: - m_flightSpeed = 400; - break; - case FLYING_AE_FLAPSOUND: - if( m_pFlapSound ) - EMIT_SOUND( edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM ); - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -void CFlyingMonster::Move( float flInterval ) -{ - if( pev->movetype == MOVETYPE_FLY ) - m_flGroundSpeed = m_flightSpeed; - CBaseMonster::Move( flInterval ); -} - -BOOL CFlyingMonster::ShouldAdvanceRoute( float flWaypointDist ) -{ - // Get true 3D distance to the goal so we actually reach the correct height - if( m_Route[m_iRouteIndex].iType & bits_MF_IS_GOAL ) - flWaypointDist = ( m_Route[m_iRouteIndex].vecLocation - pev->origin ).Length(); - - if( flWaypointDist <= 64 + ( m_flGroundSpeed * gpGlobals->frametime ) ) - return TRUE; - - return FALSE; -} - -void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - if( pev->movetype == MOVETYPE_FLY ) - { - if( gpGlobals->time - m_stopTime > 1.0 ) - { - if( m_IdealActivity != m_movementActivity ) - { - m_IdealActivity = m_movementActivity; - m_flGroundSpeed = m_flightSpeed = 200; - } - } - Vector vecMove = pev->origin + ( ( vecDir + ( m_vecTravel * m_momentum ) ).Normalize() * (m_flGroundSpeed * flInterval ) ); - - if( m_IdealActivity != m_movementActivity ) - { - m_flightSpeed = UTIL_Approach( 100, m_flightSpeed, 75 * gpGlobals->frametime ); - if( m_flightSpeed < 100 ) - m_stopTime = gpGlobals->time; - } - else - m_flightSpeed = UTIL_Approach( 20, m_flightSpeed, 300 * gpGlobals->frametime ); - - if( CheckLocalMove( pev->origin, vecMove, pTargetEnt, NULL ) ) - { - m_vecTravel = vecMove - pev->origin; - m_vecTravel = m_vecTravel.Normalize(); - UTIL_MoveToOrigin( ENT( pev ), vecMove, ( m_flGroundSpeed * flInterval ), MOVE_STRAFE ); - } - else - { - m_IdealActivity = GetStoppedActivity(); - m_stopTime = gpGlobals->time; - m_vecTravel = g_vecZero; - } - } - else - CBaseMonster::MoveExecute( pTargetEnt, vecDir, flInterval ); -} - -float CFlyingMonster::CeilingZ( const Vector &position ) -{ - TraceResult tr; - - Vector minUp = position; - Vector maxUp = position; - maxUp.z += 4096.0; - - UTIL_TraceLine( position, maxUp, ignore_monsters, NULL, &tr ); - if( tr.flFraction != 1.0 ) - maxUp.z = tr.vecEndPos.z; - - if( ( pev->flags ) & FL_SWIM ) - { - return UTIL_WaterLevel( position, minUp.z, maxUp.z ); - } - return maxUp.z; -} - -BOOL CFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float *pFraction ) -{ - int conPosition = UTIL_PointContents( position ); - if( ( ( ( pev->flags ) & FL_SWIM ) == FL_SWIM ) ^ ( conPosition == CONTENTS_WATER ) ) - { - // SWIMING & !WATER - // or FLYING & WATER - // - *pFraction = 0.0; - return TRUE; // We hit a water boundary because we are where we don't belong. - } - int conProbe = UTIL_PointContents( probe ); - if( conProbe == conPosition ) - { - // The probe is either entirely inside the water (for fish) or entirely - // outside the water (for birds). - // - *pFraction = 1.0; - return FALSE; - } - - Vector ProbeUnit = ( probe - position ).Normalize(); - float ProbeLength = ( probe - position ).Length(); - float maxProbeLength = ProbeLength; - float minProbeLength = 0; - - float diff = maxProbeLength - minProbeLength; - while( diff > 1.0 ) - { - float midProbeLength = minProbeLength + diff / 2.0; - Vector midProbeVec = midProbeLength * ProbeUnit; - if( UTIL_PointContents( position + midProbeVec ) == conPosition ) - { - minProbeLength = midProbeLength; - } - else - { - maxProbeLength = midProbeLength; - } - diff = maxProbeLength - minProbeLength; - } - *pFraction = minProbeLength/ProbeLength; - - return TRUE; -} - -float CFlyingMonster::FloorZ( const Vector &position ) -{ - TraceResult tr; - - Vector down = position; - down.z -= 2048; - - UTIL_TraceLine( position, down, ignore_monsters, NULL, &tr ); - - if( tr.flFraction != 1.0 ) - return tr.vecEndPos.z; - - return down.z; -} diff --git a/dlls/flyingmonster.h b/dlls/flyingmonster.h deleted file mode 100644 index 31ff4e33..00000000 --- a/dlls/flyingmonster.h +++ /dev/null @@ -1,49 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -// Base class for flying monsters. This overrides the movement test & execution code from CBaseMonster -#pragma once -#ifndef FLYINGMONSTER_H -#define FLYINGMONSTER_H - -class CFlyingMonster : public CBaseMonster -{ -public: - int CheckLocalMove( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist );// check validity of a straight move through space - BOOL FTriangulate( const Vector &vecStart, const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ); - Activity GetStoppedActivity( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - void Stop( void ); - float ChangeYaw( int speed ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void Move( float flInterval = 0.1 ); - BOOL ShouldAdvanceRoute( float flWaypointDist ); - - inline void SetFlyingMomentum( float momentum ) { m_momentum = momentum; } - inline void SetFlyingFlapSound( const char *pFlapSound ) { m_pFlapSound = pFlapSound; } - inline void SetFlyingSpeed( float speed ) { m_flightSpeed = speed; } - float CeilingZ( const Vector &position ); - float FloorZ( const Vector &position ); - BOOL ProbeZ( const Vector &position, const Vector &probe, float *pFraction ); - - // UNDONE: Save/restore this stuff!!! -protected: - Vector m_vecTravel; // Current direction - float m_flightSpeed; // Current flight speed (decays when not flapping or gliding) - float m_stopTime; // Last time we stopped (to avoid switching states too soon) - float m_momentum; // Weight for desired vs. momentum velocity - const char *m_pFlapSound; -}; -#endif //FLYINGMONSTER_H diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp deleted file mode 100644 index f3155d7f..00000000 --- a/dlls/gargantua.cpp +++ /dev/null @@ -1,1332 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef OEM_BUILD - -//========================================================= -// Gargantua -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "schedule.h" -#include "customentity.h" -#include "weapons.h" -#include "effects.h" -#include "soundent.h" -#include "decals.h" -#include "explode.h" -#include "func_break.h" - -//========================================================= -// Gargantua Monster -//========================================================= -const float GARG_ATTACKDIST = 80.0; - -// Garg animation events -#define GARG_AE_SLASH_LEFT 1 -//#define GARG_AE_BEAM_ATTACK_RIGHT 2 // No longer used -#define GARG_AE_LEFT_FOOT 3 -#define GARG_AE_RIGHT_FOOT 4 -#define GARG_AE_STOMP 5 -#define GARG_AE_BREATHE 6 -#define STOMP_FRAMETIME 0.015 // gpGlobals->frametime - -// Gargantua is immune to any damage but this -#define GARG_DAMAGE (DMG_ENERGYBEAM|DMG_CRUSH|DMG_MORTAR|DMG_BLAST) -#define GARG_EYE_SPRITE_NAME "sprites/gargeye1.spr" -#define GARG_BEAM_SPRITE_NAME "sprites/xbeam3.spr" -#define GARG_BEAM_SPRITE2 "sprites/xbeam3.spr" -#define GARG_STOMP_SPRITE_NAME "sprites/gargeye1.spr" -#define GARG_STOMP_BUZZ_SOUND "weapons/mine_charge.wav" -#define GARG_FLAME_LENGTH 330 -#define GARG_GIB_MODEL "models/metalplategibs.mdl" - -#define ATTN_GARG (ATTN_NORM) - -#define STOMP_SPRITE_COUNT 10 - -int gStompSprite = 0, gGargGibModel = 0; -void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ); - -class CSmoker; - -// Spiral Effect -class CSpiral : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } - static CSpiral *Create( const Vector &origin, float height, float radius, float duration ); -}; - -LINK_ENTITY_TO_CLASS( streak_spiral, CSpiral ) - -class CStomp : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); - static CStomp *StompCreate( const Vector &origin, const Vector &end, float speed ); - -private: -// UNDONE: re-use this sprite list instead of creating new ones all the time -// CSprite *m_pSprites[STOMP_SPRITE_COUNT]; -}; - -LINK_ENTITY_TO_CLASS( garg_stomp, CStomp ) - -CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float speed ) -{ - CStomp *pStomp = GetClassPtr( (CStomp *)NULL ); - - pStomp->pev->origin = origin; - Vector dir = end - origin; - pStomp->pev->scale = dir.Length(); - pStomp->pev->movedir = dir.Normalize(); - pStomp->pev->speed = speed; - pStomp->Spawn(); - - return pStomp; -} - -void CStomp::Spawn( void ) -{ - pev->nextthink = gpGlobals->time; - pev->classname = MAKE_STRING( "garg_stomp" ); - pev->dmgtime = gpGlobals->time; - - pev->framerate = 30; - pev->model = MAKE_STRING( GARG_STOMP_SPRITE_NAME ); - pev->rendermode = kRenderTransTexture; - pev->renderamt = 0; - EMIT_SOUND_DYN( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND, 1, ATTN_NORM, 0, PITCH_NORM * 0.55 ); -} - -#define STOMP_INTERVAL 0.025 - -void CStomp::Think( void ) -{ - TraceResult tr; - - pev->nextthink = gpGlobals->time + 0.1; - - // Do damage for this frame - Vector vecStart = pev->origin; - vecStart.z += 30; - Vector vecEnd = vecStart + ( pev->movedir * pev->speed * STOMP_FRAMETIME ); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if( tr.pHit && tr.pHit != pev->owner ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - entvars_t *pevOwner = pev; - if( pev->owner ) - pevOwner = VARS( pev->owner ); - - if( pEntity ) - pEntity->TakeDamage( pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC ); - } - - // Accelerate the effect - pev->speed = pev->speed + ( STOMP_FRAMETIME ) * pev->framerate; - pev->framerate = pev->framerate + ( STOMP_FRAMETIME ) * 1500; - - // Move and spawn trails - while( gpGlobals->time - pev->dmgtime > STOMP_INTERVAL ) - { - pev->origin = pev->origin + pev->movedir * pev->speed * STOMP_INTERVAL; - for( int i = 0; i < 2; i++ ) - { - CSprite *pSprite = CSprite::SpriteCreate( GARG_STOMP_SPRITE_NAME, pev->origin, TRUE ); - if( pSprite ) - { - UTIL_TraceLine( pev->origin, pev->origin - Vector( 0, 0, 500 ), ignore_monsters, edict(), &tr ); - pSprite->pev->origin = tr.vecEndPos; - pSprite->pev->velocity = Vector( RANDOM_FLOAT( -200, 200 ), RANDOM_FLOAT( -200, 200 ), 175 ); - // pSprite->AnimateAndDie( RANDOM_FLOAT( 8.0, 12.0 ) ); - pSprite->pev->nextthink = gpGlobals->time + 0.3; - pSprite->SetThink( &CBaseEntity::SUB_Remove ); - pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxFadeFast ); - } - } - pev->dmgtime += STOMP_INTERVAL; - - // Scale has the "life" of this effect - pev->scale -= STOMP_INTERVAL * pev->speed; - if( pev->scale <= 0 ) - { - // Life has run out - UTIL_Remove( this ); - STOP_SOUND( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND ); - } - } -} - -void StreakSplash( const Vector &origin, const Vector &direction, int color, int count, int speed, int velocityRange ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_STREAK_SPLASH ); - WRITE_COORD( origin.x ); // origin - WRITE_COORD( origin.y ); - WRITE_COORD( origin.z ); - WRITE_COORD( direction.x ); // direction - WRITE_COORD( direction.y ); - WRITE_COORD( direction.z ); - WRITE_BYTE( color ); // Streak color 6 - WRITE_SHORT( count ); // count - WRITE_SHORT( speed ); - WRITE_SHORT( velocityRange ); // Random velocity modifier - MESSAGE_END(); -} - -class CGargantua : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void UpdateOnRemove(); - void SetYawSpeed( void ); - int Classify( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - BOOL CheckMeleeAttack1( float flDot, float flDist ); // Swipe - BOOL CheckMeleeAttack2( float flDot, float flDist ); // Flames - BOOL CheckRangeAttack1( float flDot, float flDist ); // Stomp attack - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -80, -80, 0 ); - pev->absmax = pev->origin + Vector( 80, 80, 214 ); - } - - Schedule_t *GetScheduleOfType( int Type ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - - void PrescheduleThink( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - void DeathEffect( void ); - - void EyeOff( void ); - void EyeOn( int level ); - void EyeUpdate( void ); - void Leap( void ); - void StompAttack( void ); - void FlameCreate( void ); - void FlameUpdate( void ); - void FlameControls( float angleX, float angleY ); - void FlameDestroy( void ); - inline BOOL FlameIsOn( void ) { return m_pFlame[0] != NULL; } - - void FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CUSTOM_SCHEDULES - -private: - static const char *pAttackHitSounds[]; - static const char *pBeamAttackSounds[]; - static const char *pAttackMissSounds[]; - static const char *pRicSounds[]; - static const char *pFootSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackSounds[]; - static const char *pStompSounds[]; - static const char *pBreatheSounds[]; - - CBaseEntity* GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType); - - CSprite *m_pEyeGlow; // Glow around the eyes - CBeam *m_pFlame[4]; // Flame beams - - int m_eyeBrightness; // Brightness target - float m_seeTime; // Time to attack (when I see the enemy, I set this) - float m_flameTime; // Time of next flame attack - float m_painSoundTime; // Time of next pain sound - float m_streakTime; // streak timer (don't send too many) - float m_flameX; // Flame thrower aim - float m_flameY; -}; - -LINK_ENTITY_TO_CLASS( monster_gargantua, CGargantua ) - -TYPEDESCRIPTION CGargantua::m_SaveData[] = -{ - DEFINE_FIELD( CGargantua, m_pEyeGlow, FIELD_CLASSPTR ), - DEFINE_FIELD( CGargantua, m_eyeBrightness, FIELD_INTEGER ), - DEFINE_FIELD( CGargantua, m_seeTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_flameTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_streakTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_painSoundTime, FIELD_TIME ), - DEFINE_ARRAY( CGargantua, m_pFlame, FIELD_CLASSPTR, 4 ), - DEFINE_FIELD( CGargantua, m_flameX, FIELD_FLOAT ), - DEFINE_FIELD( CGargantua, m_flameY, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGargantua, CBaseMonster ) - -const char *CGargantua::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CGargantua::pBeamAttackSounds[] = -{ - "garg/gar_flameoff1.wav", - "garg/gar_flameon1.wav", - "garg/gar_flamerun1.wav", -}; - -const char *CGargantua::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CGargantua::pRicSounds[] = -{ -#if 0 - "weapons/ric1.wav", - "weapons/ric2.wav", - "weapons/ric3.wav", - "weapons/ric4.wav", - "weapons/ric5.wav", -#else - "debris/metal4.wav", - "debris/metal6.wav", - "weapons/ric4.wav", - "weapons/ric5.wav", -#endif -}; - -const char *CGargantua::pFootSounds[] = -{ - "garg/gar_step1.wav", - "garg/gar_step2.wav", -}; - -const char *CGargantua::pIdleSounds[] = -{ - "garg/gar_idle1.wav", - "garg/gar_idle2.wav", - "garg/gar_idle3.wav", - "garg/gar_idle4.wav", - "garg/gar_idle5.wav", -}; - -const char *CGargantua::pAttackSounds[] = -{ - "garg/gar_attack1.wav", - "garg/gar_attack2.wav", - "garg/gar_attack3.wav", -}; - -const char *CGargantua::pAlertSounds[] = -{ - "garg/gar_alert1.wav", - "garg/gar_alert2.wav", - "garg/gar_alert3.wav", -}; - -const char *CGargantua::pPainSounds[] = -{ - "garg/gar_pain1.wav", - "garg/gar_pain2.wav", - "garg/gar_pain3.wav", -}; - -const char *CGargantua::pStompSounds[] = -{ - "garg/gar_stomp1.wav", -}; - -const char *CGargantua::pBreatheSounds[] = -{ - "garg/gar_breathe1.wav", - "garg/gar_breathe2.wav", - "garg/gar_breathe3.wav", -}; -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -#if 0 -enum -{ - SCHED_ = LAST_COMMON_SCHEDULE + 1 -}; -#endif - -enum -{ - TASK_SOUND_ATTACK = LAST_COMMON_TASK + 1, - TASK_FLAME_SWEEP -}; - -Task_t tlGargFlame[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SOUND_ATTACK, (float)0 }, - // { TASK_PLAY_SEQUENCE, (float)ACT_SIGNAL1 }, - { TASK_SET_ACTIVITY, (float)ACT_MELEE_ATTACK2 }, - { TASK_FLAME_SWEEP, (float)4.5 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slGargFlame[] = -{ - { - tlGargFlame, - ARRAYSIZE( tlGargFlame ), - 0, - 0, - "GargFlame" - }, -}; - -// primary melee attack -Task_t tlGargSwipe[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK1, (float)0 }, -}; - -Schedule_t slGargSwipe[] = -{ - { - tlGargSwipe, - ARRAYSIZE( tlGargSwipe ), - bits_COND_CAN_MELEE_ATTACK2, - 0, - "GargSwipe" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CGargantua ) -{ - slGargFlame, - slGargSwipe, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CGargantua, CBaseMonster ) - -void CGargantua::EyeOn( int level ) -{ - m_eyeBrightness = level; -} - -void CGargantua::EyeOff( void ) -{ - m_eyeBrightness = 0; -} - -void CGargantua::EyeUpdate( void ) -{ - if( m_pEyeGlow ) - { - m_pEyeGlow->pev->renderamt = UTIL_Approach( m_eyeBrightness, m_pEyeGlow->pev->renderamt, 26 ); - if( m_pEyeGlow->pev->renderamt == 0 ) - m_pEyeGlow->pev->effects |= EF_NODRAW; - else - m_pEyeGlow->pev->effects &= ~EF_NODRAW; - UTIL_SetOrigin( m_pEyeGlow->pev, pev->origin ); - } -} - -void CGargantua::StompAttack( void ) -{ - TraceResult trace; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin + Vector(0,0,60) + 35 * gpGlobals->v_forward; - Vector vecAim = ShootAtEnemy( vecStart ); - Vector vecEnd = (vecAim * 1024) + vecStart; - - UTIL_TraceLine( vecStart, vecEnd, ignore_monsters, edict(), &trace ); - CStomp::StompCreate( vecStart, trace.vecEndPos, 0 ); - UTIL_ScreenShake( pev->origin, 12.0, 100.0, 2.0, 1000 ); - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pStompSounds[RANDOM_LONG( 0, ARRAYSIZE( pStompSounds ) - 1 )], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG( -10, 10 ) ); - - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,20), ignore_monsters, edict(), &trace ); - if( trace.flFraction < 1.0 ) - UTIL_DecalTrace( &trace, DECAL_GARGSTOMP1 ); -} - -void CGargantua::FlameCreate( void ) -{ - int i; - Vector posGun, angleGun; - TraceResult trace; - - UTIL_MakeVectors( pev->angles ); - - for( i = 0; i < 4; i++ ) - { - if( i < 2 ) - m_pFlame[i] = CBeam::BeamCreate( GARG_BEAM_SPRITE_NAME, 240 ); - else - m_pFlame[i] = CBeam::BeamCreate( GARG_BEAM_SPRITE2, 140 ); - if( m_pFlame[i] ) - { - int attach = i%2; - // attachment is 0 based in GetAttachment - GetAttachment( attach + 1, posGun, angleGun ); - - Vector vecEnd = ( gpGlobals->v_forward * GARG_FLAME_LENGTH ) + posGun; - UTIL_TraceLine( posGun, vecEnd, dont_ignore_monsters, edict(), &trace ); - - m_pFlame[i]->PointEntInit( trace.vecEndPos, entindex() ); - if( i < 2 ) - m_pFlame[i]->SetColor( 255, 130, 90 ); - else - m_pFlame[i]->SetColor( 0, 120, 255 ); - m_pFlame[i]->SetBrightness( 190 ); - m_pFlame[i]->SetFlags( BEAM_FSHADEIN ); - m_pFlame[i]->SetScrollRate( 20 ); - // attachment is 1 based in SetEndAttachment - m_pFlame[i]->SetEndAttachment( attach + 2 ); - CSoundEnt::InsertSound( bits_SOUND_COMBAT, posGun, 384, 0.3 ); - } - } - EMIT_SOUND_DYN( edict(), CHAN_BODY, pBeamAttackSounds[1], 1.0, ATTN_NORM, 0, PITCH_NORM ); - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pBeamAttackSounds[2], 1.0, ATTN_NORM, 0, PITCH_NORM ); -} - -void CGargantua::FlameControls( float angleX, float angleY ) -{ - if( angleY < -180 ) - angleY += 360; - else if( angleY > 180 ) - angleY -= 360; - - if( angleY < -45 ) - angleY = -45; - else if( angleY > 45 ) - angleY = 45; - - m_flameX = UTIL_ApproachAngle( angleX, m_flameX, 4 ); - m_flameY = UTIL_ApproachAngle( angleY, m_flameY, 8 ); - SetBoneController( 0, m_flameY ); - SetBoneController( 1, m_flameX ); -} - -void CGargantua::FlameUpdate( void ) -{ - int i; - TraceResult trace; - Vector vecStart, angleGun; - BOOL streaks = FALSE; - - for( i = 0; i < 2; i++ ) - { - if( m_pFlame[i] ) - { - Vector vecAim = pev->angles; - vecAim.x += m_flameX; - vecAim.y += m_flameY; - - UTIL_MakeVectors( vecAim ); - - GetAttachment( i + 1, vecStart, angleGun ); - Vector vecEnd = vecStart + ( gpGlobals->v_forward * GARG_FLAME_LENGTH ); // - offset[i] * gpGlobals->v_right; - - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &trace ); - - m_pFlame[i]->SetStartPos( trace.vecEndPos ); - m_pFlame[i+2]->SetStartPos( ( vecStart * 0.6 ) + ( trace.vecEndPos * 0.4 ) ); - - if( trace.flFraction != 1.0 && gpGlobals->time > m_streakTime ) - { - StreakSplash( trace.vecEndPos, trace.vecPlaneNormal, 6, 20, 50, 400 ); - streaks = TRUE; - UTIL_DecalTrace( &trace, DECAL_SMALLSCORCH1 + RANDOM_LONG( 0, 2 ) ); - } - - // RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); - FlameDamage( vecStart, trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() + 0x1000 * ( i + 2 ) ); // entity, attachment - WRITE_COORD( vecStart.x ); // origin - WRITE_COORD( vecStart.y ); - WRITE_COORD( vecStart.z ); - WRITE_COORD( RANDOM_FLOAT( 32, 48 ) ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } - } - if( streaks ) - m_streakTime = gpGlobals->time; -} - -void CGargantua::FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - CBaseEntity *pEntity = NULL; - TraceResult tr; - float flAdjustedDamage; - Vector vecSpot; - - Vector vecMid = ( vecStart + vecEnd ) * 0.5; - - float searchRadius = ( vecStart - vecMid).Length(); - - Vector vecAim = ( vecEnd - vecStart ).Normalize(); - - // iterate on all entities in the vicinity. - while( ( pEntity = UTIL_FindEntityInSphere( pEntity, vecMid, searchRadius ) ) != NULL ) - { - if( pEntity->pev->takedamage != DAMAGE_NO ) - { - // UNDONE: this should check a damage mask, not an ignore - if( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) - { - // houndeyes don't hurt other houndeyes with their attack - continue; - } - - vecSpot = pEntity->BodyTarget( vecMid ); - - float dist = DotProduct( vecAim, vecSpot - vecMid ); - if( dist > searchRadius ) - dist = searchRadius; - else if( dist < -searchRadius ) - dist = searchRadius; - - Vector vecSrc = vecMid + dist * vecAim; - - UTIL_TraceLine( vecSrc, vecSpot, dont_ignore_monsters, ENT( pev ), &tr ); - - if( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) - { - // the explosion can 'see' this entity, so hurt them! - // decrease damage for an ent that's farther from the flame. - dist = ( vecSrc - tr.vecEndPos ).Length(); - - if( dist > 64 ) - { - flAdjustedDamage = flDamage - ( dist - 64 ) * 0.4; - if( flAdjustedDamage <= 0 ) - continue; - } - else - { - flAdjustedDamage = flDamage; - } - - // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); - if( tr.flFraction != 1.0 ) - { - ClearMultiDamage(); - pEntity->TraceAttack( pevInflictor, flAdjustedDamage, ( tr.vecEndPos - vecSrc ).Normalize(), &tr, bitsDamageType ); - ApplyMultiDamage( pevInflictor, pevAttacker ); - } - else - { - pEntity->TakeDamage( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); - } - } - } - } -} - -void CGargantua::FlameDestroy( void ) -{ - int i; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pBeamAttackSounds[0], 1.0, ATTN_NORM, 0, PITCH_NORM ); - for( i = 0; i < 4; i++ ) - { - if( m_pFlame[i] ) - { - UTIL_Remove( m_pFlame[i] ); - m_pFlame[i] = NULL; - } - } -} - -void CGargantua::PrescheduleThink( void ) -{ - if( !HasConditions( bits_COND_SEE_ENEMY ) ) - { - m_seeTime = gpGlobals->time + 5; - EyeOff(); - } - else - EyeOn( 200 ); - - EyeUpdate(); -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGargantua::Classify( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGargantua::SetYawSpeed( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 60; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 180; - break; - case ACT_WALK: - case ACT_RUN: - ys = 60; - break; - default: - ys = 60; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// Spawn -//========================================================= -void CGargantua::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/garg.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.gargantuaHealth; - //pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file - m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); - - m_pEyeGlow = CSprite::SpriteCreate( GARG_EYE_SPRITE_NAME, pev->origin, FALSE ); - m_pEyeGlow->SetTransparency( kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation ); - m_pEyeGlow->SetAttachment( edict(), 1 ); - EyeOff(); - m_seeTime = gpGlobals->time + 5; - m_flameTime = gpGlobals->time + 2; -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGargantua::Precache() -{ - size_t i; - - PRECACHE_MODEL( "models/garg.mdl" ); - PRECACHE_MODEL( GARG_EYE_SPRITE_NAME ); - PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME ); - PRECACHE_MODEL( GARG_BEAM_SPRITE2 ); - gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME ); - gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL ); - PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND ); - - for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND( pAttackHitSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ ) - PRECACHE_SOUND( pBeamAttackSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND( pAttackMissSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pRicSounds ); i++ ) - PRECACHE_SOUND( pRicSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pFootSounds ); i++ ) - PRECACHE_SOUND( pFootSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND( pIdleSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND( pAlertSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND( pPainSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND( pAttackSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pStompSounds ); i++ ) - PRECACHE_SOUND( pStompSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ ) - PRECACHE_SOUND( pBreatheSounds[i] ); -} - -void CGargantua::UpdateOnRemove() -{ - CBaseEntity::UpdateOnRemove(); - - if( m_pEyeGlow ) - { - UTIL_Remove( m_pEyeGlow ); - m_pEyeGlow = 0; - } - - FlameDestroy(); -} - -void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - ALERT( at_aiconsole, "CGargantua::TraceAttack\n" ); - - if( !IsAlive() ) - { - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); - return; - } - - // UNDONE: Hit group specific damage? - if( bitsDamageType & ( GARG_DAMAGE | DMG_BLAST ) ) - { - if( m_painSoundTime < gpGlobals->time ) - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pPainSounds[RANDOM_LONG( 0, ARRAYSIZE( pPainSounds ) - 1 )], 1.0, ATTN_GARG, 0, PITCH_NORM ); - m_painSoundTime = gpGlobals->time + RANDOM_FLOAT( 2.5, 4 ); - } - } - - bitsDamageType &= GARG_DAMAGE; - - if( bitsDamageType == 0 ) - { - if( pev->dmgtime != gpGlobals->time || (RANDOM_LONG( 0, 100 ) < 20 ) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 0.5 ,1.5 ) ); - pev->dmgtime = gpGlobals->time; - //if ( RANDOM_LONG( 0, 100 ) < 25 ) - // EMIT_SOUND_DYN( ENT( pev ), CHAN_BODY, pRicSounds[RANDOM_LONG( 0, ARRAYSIZE( pRicSounds ) - 1 )], 1.0, ATTN_NORM, 0, PITCH_NORM ); - } - flDamage = 0; - } - - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -int CGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - ALERT( at_aiconsole, "CGargantua::TakeDamage\n" ); - - if( IsAlive() ) - { - if( !( bitsDamageType & GARG_DAMAGE ) ) - flDamage *= 0.01; - if( bitsDamageType & DMG_BLAST ) - SetConditions( bits_COND_LIGHT_DAMAGE ); - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CGargantua::DeathEffect( void ) -{ - int i; - UTIL_MakeVectors( pev->angles ); - Vector deathPos = pev->origin + gpGlobals->v_forward * 100; - - // Create a spiral of streaks - CSpiral::Create( deathPos, ( pev->absmax.z - pev->absmin.z ) * 0.6, 125, 1.5 ); - - Vector position = pev->origin; - position.z += 32; - for( i = 0; i < 7; i+=2 ) - { - SpawnExplosion( position, 70, ( i * 0.3 ), 60 + ( i * 20 ) ); - position.z += 15; - } - - CBaseEntity *pSmoker = CBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL ); - pSmoker->pev->health = 1; // 1 smoke balls - pSmoker->pev->scale = 46; // 4.6X normal size - pSmoker->pev->dmg = 0; // 0 radial distribution - pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds -} - -void CGargantua::Killed( entvars_t *pevAttacker, int iGib ) -{ - EyeOff(); - UTIL_Remove( m_pEyeGlow ); - m_pEyeGlow = NULL; - CBaseMonster::Killed( pevAttacker, GIB_NEVER ); -} - -//========================================================= -// CheckMeleeAttack1 -// Garg swipe attack -// -//========================================================= -BOOL CGargantua::CheckMeleeAttack1( float flDot, float flDist ) -{ - //ALERT( at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist ); - - if( flDot >= 0.7 ) - { - if( flDist <= GARG_ATTACKDIST ) - return TRUE; - } - return FALSE; -} - -// Flame thrower madness! -BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) -{ - //ALERT( at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist ); - - if( gpGlobals->time > m_flameTime ) - { - if( flDot >= 0.8 && flDist > GARG_ATTACKDIST ) - { - if ( flDist <= GARG_FLAME_LENGTH ) - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 -// flDot is the cos of the angle of the cone within which -// the attack can occur. -//========================================================= -// -// Stomp attack -// -//========================================================= -BOOL CGargantua::CheckRangeAttack1( float flDot, float flDist ) -{ - if( gpGlobals->time > m_seeTime ) - { - if( flDot >= 0.7 && flDist > GARG_ATTACKDIST ) - { - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGargantua::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case GARG_AE_SLASH_LEFT: - { - // HACKHACK!!! - CBaseEntity *pHurt = GargantuaCheckTraceHullAttack( GARG_ATTACKDIST + 10.0, gSkillData.gargantuaDmgSlash, DMG_SLASH ); - if( pHurt ) - { - if( pHurt->pev->flags & ( FL_MONSTER | FL_CLIENT ) ) - { - pHurt->pev->punchangle.x = -30; // pitch - pHurt->pev->punchangle.y = -30; // yaw - pHurt->pev->punchangle.z = 30; // roll - //UTIL_MakeVectors( pev->angles ); // called by CheckTraceHullAttack - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; - } - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG( 0, 15 ) ); - } - else // Play a random attack miss sound - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG( 0, 15 ) ); - - Vector forward; - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - } - break; - case GARG_AE_RIGHT_FOOT: - case GARG_AE_LEFT_FOOT: - UTIL_ScreenShake( pev->origin, 4.0, 3.0, 1.0, 750 ); - EMIT_SOUND_DYN( edict(), CHAN_BODY, pFootSounds[RANDOM_LONG( 0, ARRAYSIZE( pFootSounds ) - 1 )], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG( -10, 10 ) ); - break; - case GARG_AE_STOMP: - StompAttack(); - m_seeTime = gpGlobals->time + 12; - break; - case GARG_AE_BREATHE: - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pBreatheSounds[RANDOM_LONG( 0, ARRAYSIZE( pBreatheSounds ) - 1 )], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG( -10, 10 ) ); - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// CheckTraceHullAttack - expects a length to trace, amount -// of damage to do, and damage type. Returns a pointer to -// the damaged entity in case the monster wishes to do -// other stuff to the victim (punchangle, etc) -// Used for many contact-range melee attacks. Bites, claws, etc. - -// Overridden for Gargantua because his swing starts lower as -// a percentage of his height (otherwise he swings over the -// players head) -//========================================================= -CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType) -{ - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin; - vecStart.z += 64; - Vector vecEnd = vecStart + ( gpGlobals->v_forward * flDist ) - ( gpGlobals->v_up * flDist * 0.3 ); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); - - if( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if( iDamage > 0 ) - { - pEntity->TakeDamage( pev, pev, iDamage, iDmgType ); - } - - return pEntity; - } - - return NULL; -} - -Schedule_t *CGargantua::GetScheduleOfType( int Type ) -{ - // HACKHACK - turn off the flames if they are on and garg goes scripted / dead - if( FlameIsOn() ) - FlameDestroy(); - - switch( Type ) - { - case SCHED_MELEE_ATTACK2: - return slGargFlame; - case SCHED_MELEE_ATTACK1: - return slGargSwipe; - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - -void CGargantua::StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_FLAME_SWEEP: - FlameCreate(); - m_flWaitFinished = gpGlobals->time + pTask->flData; - m_flameTime = gpGlobals->time + 6; - m_flameX = 0; - m_flameY = 0; - break; - case TASK_SOUND_ATTACK: - if( RANDOM_LONG( 0, 100 ) < 30 ) - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAttackSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackSounds ) - 1 )], 1.0, ATTN_GARG, 0, PITCH_NORM ); - TaskComplete(); - break; - case TASK_DIE: - m_flWaitFinished = gpGlobals->time + 1.6; - DeathEffect(); - // FALL THROUGH - default: - CBaseMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CGargantua::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_DIE: - if( gpGlobals->time > m_flWaitFinished ) - { - pev->renderfx = kRenderFxExplode; - pev->rendercolor.x = 255; - pev->rendercolor.y = 0; - pev->rendercolor.z = 0; - StopAnimation(); - pev->nextthink = gpGlobals->time + 0.15; - SetThink( &CBaseEntity::SUB_Remove ); - int i; - int parts = MODEL_FRAMES( gGargGibModel ); - for( i = 0; i < 10; i++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( GARG_GIB_MODEL ); - - int bodyPart = 0; - if( parts > 1 ) - bodyPart = RANDOM_LONG( 0, pev->body - 1 ); - - pGib->pev->body = bodyPart; - pGib->m_bloodColor = BLOOD_COLOR_YELLOW; - pGib->m_material = matNone; - pGib->pev->origin = pev->origin; - pGib->pev->velocity = UTIL_RandomBloodVector() * RANDOM_FLOAT( 300, 500 ); - pGib->pev->nextthink = gpGlobals->time + 1.25; - pGib->SetThink( &CBaseEntity::SUB_FadeOut ); - } - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BREAKMODEL ); - - // position - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - - // size - WRITE_COORD( 200 ); - WRITE_COORD( 200 ); - WRITE_COORD( 128 ); - - // velocity - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - - // randomization - WRITE_BYTE( 200 ); - - // Model - WRITE_SHORT( gGargGibModel ); //model id# - - // # of shards - WRITE_BYTE( 50 ); - - // duration - WRITE_BYTE( 20 );// 3.0 seconds - - // flags - - WRITE_BYTE( BREAK_FLESH ); - MESSAGE_END(); - - return; - } - else - CBaseMonster::RunTask( pTask ); - break; - case TASK_FLAME_SWEEP: - if( gpGlobals->time > m_flWaitFinished ) - { - FlameDestroy(); - TaskComplete(); - FlameControls( 0, 0 ); - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - } - else - { - BOOL cancel = FALSE; - - Vector angles = g_vecZero; - - FlameUpdate(); - CBaseEntity *pEnemy = m_hEnemy; - if( pEnemy ) - { - Vector org = pev->origin; - org.z += 64; - Vector dir = pEnemy->BodyTarget( org ) - org; - angles = UTIL_VecToAngles( dir ); - angles.x = -angles.x; - angles.y -= pev->angles.y; - if( dir.Length() > 400 ) - cancel = TRUE; - } - if( fabs(angles.y) > 60 ) - cancel = TRUE; - - if( cancel ) - { - m_flWaitFinished -= 0.5; - m_flameTime -= 0.5; - } - // FlameControls( angles.x + 2 * sin( gpGlobals->time * 8 ), angles.y + 28 * sin( gpGlobals->time * 8.5 ) ); - FlameControls( angles.x, angles.y ); - } - break; - default: - CBaseMonster::RunTask( pTask ); - break; - } -} - -class CSmoker : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); -}; - -LINK_ENTITY_TO_CLASS( env_smoker, CSmoker ) - -void CSmoker::Spawn( void ) -{ - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time; - pev->solid = SOLID_NOT; - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->angles = g_vecZero; -} - -void CSmoker::Think( void ) -{ - // lots of smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -pev->dmg, pev->dmg ) ); - WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -pev->dmg, pev->dmg ) ); - WRITE_COORD( pev->origin.z); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(pev->scale, pev->scale * 1.1 ) ); - WRITE_BYTE( RANDOM_LONG( 8, 14 ) ); // framerate - MESSAGE_END(); - - pev->health--; - if( pev->health > 0 ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.2 ); - else - UTIL_Remove( this ); -} - -void CSpiral::Spawn( void ) -{ - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time; - pev->solid = SOLID_NOT; - UTIL_SetSize( pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->angles = g_vecZero; -} - -CSpiral *CSpiral::Create( const Vector &origin, float height, float radius, float duration ) -{ - if( duration <= 0 ) - return NULL; - - CSpiral *pSpiral = GetClassPtr( (CSpiral *)NULL ); - pSpiral->Spawn(); - pSpiral->pev->dmgtime = pSpiral->pev->nextthink; - pSpiral->pev->origin = origin; - pSpiral->pev->scale = radius; - pSpiral->pev->dmg = height; - pSpiral->pev->speed = duration; - pSpiral->pev->health = 0; - pSpiral->pev->angles = g_vecZero; - - return pSpiral; -} - -#define SPIRAL_INTERVAL 0.1 //025 - -void CSpiral::Think( void ) -{ - float time = gpGlobals->time - pev->dmgtime; - - while( time > SPIRAL_INTERVAL ) - { - Vector position = pev->origin; - Vector direction = Vector(0,0,1); - - float fraction = 1.0 / pev->speed; - - float radius = ( pev->scale * pev->health ) * fraction; - - position.z += ( pev->health * pev->dmg ) * fraction; - pev->angles.y = ( pev->health * 360 * 8 ) * fraction; - UTIL_MakeVectors( pev->angles ); - position = position + gpGlobals->v_forward * radius; - direction = ( direction + gpGlobals->v_forward ).Normalize(); - - StreakSplash( position, Vector( 0, 0, 1 ), RANDOM_LONG( 8, 11 ), 20, RANDOM_LONG( 50, 150 ), 400 ); - - // Jeez, how many counters should this take ? :) - pev->dmgtime += SPIRAL_INTERVAL; - pev->health += SPIRAL_INTERVAL; - time -= SPIRAL_INTERVAL; - } - - pev->nextthink = gpGlobals->time; - - if( pev->health >= pev->speed ) - UTIL_Remove( this ); -} - -// HACKHACK Cut and pasted from explode.cpp -void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ) -{ - KeyValueData kvd; - char buf[128]; - - center.x += RANDOM_FLOAT( -randomRange, randomRange ); - center.y += RANDOM_FLOAT( -randomRange, randomRange ); - - CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, g_vecZero, NULL ); - sprintf( buf, "%3d", magnitude ); - kvd.szKeyName = "iMagnitude"; - kvd.szValue = buf; - pExplosion->KeyValue( &kvd ); - pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; - - pExplosion->Spawn(); - pExplosion->SetThink( &CBaseEntity::SUB_CallUseToggle ); - pExplosion->pev->nextthink = gpGlobals->time + time; -} -#endif diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp deleted file mode 100644 index 62af08e1..00000000 --- a/dlls/gauss.cpp +++ /dev/null @@ -1,633 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "shake.h" -#include "gamerules.h" -#include "game.h" - -#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging -#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged - -enum gauss_e -{ - GAUSS_IDLE = 0, - GAUSS_IDLE2, - GAUSS_FIDGET, - GAUSS_SPINUP, - GAUSS_SPIN, - GAUSS_FIRE, - GAUSS_FIRE2, - GAUSS_HOLSTER, - GAUSS_DRAW -}; - -LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ) - -float CGauss::GetFullChargeTime( void ) -{ -#ifdef CLIENT_DLL - if( bIsMultiplayer() ) -#else - if( g_pGameRules->IsMultiplayer() ) -#endif - { - return 1.5; - } - - return 4; -} - -#ifdef CLIENT_DLL -extern int g_irunninggausspred; -#endif - -void CGauss::Spawn() -{ - Precache(); - m_iId = WEAPON_GAUSS; - SET_MODEL( ENT( pev ), "models/w_gauss.mdl" ); - - m_iDefaultAmmo = GAUSS_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -void CGauss::Precache( void ) -{ - PRECACHE_MODEL( "models/w_gauss.mdl" ); - PRECACHE_MODEL( "models/v_gauss.mdl" ); - PRECACHE_MODEL( "models/p_gauss.mdl" ); - - PRECACHE_SOUND( "items/9mmclip1.wav" ); - - PRECACHE_SOUND( "weapons/gauss2.wav" ); - PRECACHE_SOUND( "weapons/electro4.wav" ); - PRECACHE_SOUND( "weapons/electro5.wav" ); - PRECACHE_SOUND( "weapons/electro6.wav" ); - PRECACHE_SOUND( "ambience/pulsemachine.wav" ); - - m_iGlow = PRECACHE_MODEL( "sprites/hotglow.spr" ); - m_iBalls = PRECACHE_MODEL( "sprites/hotglow.spr" ); - m_iBeam = PRECACHE_MODEL( "sprites/smoke.spr" ); - - m_usGaussFire = PRECACHE_EVENT( 1, "events/gauss.sc" ); - m_usGaussSpin = PRECACHE_EVENT( 1, "events/gaussspin.sc" ); -} - -int CGauss::AddToPlayer( CBasePlayer *pPlayer ) -{ - if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -int CGauss::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "uranium"; - p->iMaxAmmo1 = URANIUM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 1; - p->iId = m_iId = WEAPON_GAUSS; - p->iFlags = 0; - p->iWeight = GAUSS_WEIGHT; - - return 1; -} - -BOOL CGauss::IsUseable() -{ - // Currently charging, allow the player to fire it first. - Solokiller - return CBasePlayerWeapon::IsUseable() || m_fInAttack != 0; -} - -BOOL CGauss::Deploy() -{ - m_pPlayer->m_flPlayAftershock = 0.0; - return DefaultDeploy( "models/v_gauss.mdl", "models/p_gauss.mdl", GAUSS_DRAW, "gauss" ); -} - -void CGauss::Holster( int skiplocal /* = 0 */ ) -{ - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_GLOBAL, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - SendWeaponAnim( GAUSS_HOLSTER ); - m_fInAttack = 0; -} - -void CGauss::PrimaryAttack() -{ - // don't fire underwater - if( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound(); - m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); - return; - } - - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 2 ) - { - PlayEmptySound(); - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - m_fPrimaryFire = TRUE; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 2; - - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.2; -} - -void CGauss::SecondaryAttack() -{ - // don't fire underwater - if( m_pPlayer->pev->waterlevel == 3 ) - { - if( m_fInAttack != 0 ) - { - EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG( 0, 0x3f ) ); - SendWeaponAnim( GAUSS_IDLE ); - m_fInAttack = 0; - } - else - { - PlayEmptySound(); - } - - m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); - return; - } - - if( m_fInAttack == 0 ) - { - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM ); - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - m_fPrimaryFire = FALSE; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;// take one ammo just to start the spin - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase(); - - // spin up - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - - SendWeaponAnim( GAUSS_SPINUP ); - m_fInAttack = 1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - m_pPlayer->m_flStartCharge = gpGlobals->time; - m_pPlayer->m_flAmmoStartCharge = UTIL_WeaponTimeBase() + GetFullChargeTime(); - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); - - m_iSoundState = SND_CHANGE_PITCH; - } - else if( m_fInAttack == 1 ) - { - if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) - { - SendWeaponAnim( GAUSS_SPIN ); - m_fInAttack = 2; - } - } - else - { - // Moved to before the ammo burn. - // Because we drained 1 when m_InAttack == 0, then 1 again now before checking if we're out of ammo, - // this resuled in the player having -1 ammo, which in turn caused CanDeploy to think it could be deployed. - // This will need to be fixed further down the line by preventing negative ammo unless explicitly required (infinite ammo?), - // But this check will prevent the problem for now. - Solokiller - // TODO: investigate further. - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - // out of ammo! force the gun to fire - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; - return; - } - - // during the charging process, eat one bit of ammo every once in a while - if( UTIL_WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) - { -#ifdef CLIENT_DLL - if( bIsMultiplayer() ) -#else - if( g_pGameRules->IsMultiplayer() ) -#endif - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.1; - } - else - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.3; - } - } - - if( UTIL_WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) - { - // don't eat any more ammo after gun is fully charged. - m_pPlayer->m_flNextAmmoBurn = 1000; - } - - int pitch = (int)( ( gpGlobals->time - m_pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100 ); - if( pitch > 250 ) - pitch = 250; - - // ALERT( at_console, "%d %d %d\n", m_fInAttack, m_iSoundState, pitch ); - - if( m_iSoundState == 0 ) - ALERT( at_console, "sound state %d\n", m_iSoundState ); - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - - // m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - if( m_pPlayer->m_flStartCharge < gpGlobals->time - 10 ) - { - // Player charged up too long. Zap him. - EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG( 0, 0x3f ) ); - EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/electro6.wav", 1.0, ATTN_NORM, 0, 75 + RANDOM_LONG( 0, 0x3f ) ); - - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; -#ifndef CLIENT_DLL - m_pPlayer->TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), 50, DMG_SHOCK ); - UTIL_ScreenFade( m_pPlayer, Vector( 255, 128, 0 ), 2, 0.5, 128, FFADE_IN ); -#endif - SendWeaponAnim( GAUSS_IDLE ); - - // Player may have been killed and this weapon dropped, don't execute any more code after this! - return; - } - } -} - -//========================================================= -// StartFire- since all of this code has to run and then -// call Fire(), it was easier at this point to rip it out -// of weaponidle() and make its own function then to try to -// merge this into Fire(), which has some identical variable names -//========================================================= -void CGauss::StartFire( void ) -{ - float flDamage; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition(); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8; - - if( gpGlobals->time - m_pPlayer->m_flStartCharge > GetFullChargeTime() ) - { - flDamage = 200; - } - else - { - flDamage = 200 * ( ( gpGlobals->time - m_pPlayer->m_flStartCharge ) / GetFullChargeTime() ); - } - - if( m_fPrimaryFire ) - { - // fixed damage on primary attack -#ifdef CLIENT_DLL - flDamage = 20; -#else - flDamage = gSkillData.plrDmgGauss; -#endif - } - - if( m_fInAttack != 3 ) - { - //ALERT( at_console, "Time:%f Damage:%f\n", gpGlobals->time - m_pPlayer->m_flStartCharge, flDamage ); -#ifndef CLIENT_DLL - float flZVel = m_pPlayer->pev->velocity.z; - - if( !m_fPrimaryFire ) - { - m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * flDamage * 5; - } - - if( !g_pGameRules->IsMultiplayer() ) - { - // in deathmatch, gauss can pop you up into the air. Not in single play. - m_pPlayer->pev->velocity.z = flZVel; - } -#endif - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - } - - // time until aftershock 'static discharge' sound - m_pPlayer->m_flPlayAftershock = gpGlobals->time + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.3, 0.8 ); - - Fire( vecSrc, vecAiming, flDamage ); -} - -void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) -{ - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - TraceResult tr, beam_tr; -#ifndef CLIENT_DLL - Vector vecSrc = vecOrigSrc; - Vector vecDest = vecSrc + vecDir * 8192; - edict_t *pentIgnore; - float flMaxFrac = 1.0; - int nTotal = 0; - int fHasPunched = 0; - int fFirstBeam = 1; - int nMaxHits = 10; - - pentIgnore = ENT( m_pPlayer->pev ); -#else - if( m_fPrimaryFire == false ) - g_irunninggausspred = true; -#endif - // The main firing event is sent unreliably so it won't be delayed. - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); - - // This reliable event is used to stop the spinning sound - // It's delayed by a fraction of second to make sure it is delayed by 1 frame on the client - // It's sent reliably anyway, which could lead to other delays - - PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - - /*ALERT( at_console, "%f %f %f\n%f %f %f\n", - vecSrc.x, vecSrc.y, vecSrc.z, - vecDest.x, vecDest.y, vecDest.z );*/ - - //ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); - -#ifndef CLIENT_DLL - while( flDamage > 10 && nMaxHits > 0 ) - { - nMaxHits--; - - // ALERT( at_console, "." ); - UTIL_TraceLine( vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); - - if( tr.fAllSolid ) - break; - - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if( pEntity == NULL ) - break; - - if( fFirstBeam ) - { - m_pPlayer->pev->effects |= EF_MUZZLEFLASH; - fFirstBeam = 0; - - nTotal += 26; - } - - if( pEntity->pev->takedamage ) - { - ClearMultiDamage(); - pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); - ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - } - - if( pEntity->ReflectGauss() ) - { - float n; - - pentIgnore = NULL; - - n = -DotProduct( tr.vecPlaneNormal, vecDir ); - - if( n < 0.5 ) // 60 degrees - { - // ALERT( at_console, "reflect %f\n", n ); - // reflect - Vector r; - - r = 2.0 * tr.vecPlaneNormal * n + vecDir; - flMaxFrac = flMaxFrac - tr.flFraction; - vecDir = r; - vecSrc = tr.vecEndPos + vecDir * 8; - vecDest = vecSrc + vecDir * 8192; - - // explode a bit - m_pPlayer->RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, flDamage * n, CLASS_NONE, DMG_BLAST ); - - nTotal += 34; - - // lose energy - if( n == 0 ) n = 0.1; - flDamage = flDamage * ( 1 - n ); - } - else - { - nTotal += 13; - - // limit it to one hole punch - if( fHasPunched ) - break; - fHasPunched = 1; - - // try punching through wall if secondary attack (primary is incapable of breaking through) - if( !m_fPrimaryFire ) - { - UTIL_TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, &beam_tr ); - if( !beam_tr.fAllSolid ) - { - // trace backwards to find exit point - UTIL_TraceLine( beam_tr.vecEndPos, tr.vecEndPos, dont_ignore_monsters, pentIgnore, &beam_tr ); - - n = ( beam_tr.vecEndPos - tr.vecEndPos ).Length(); - - if( n < flDamage ) - { - if( n == 0 ) - n = 1; - flDamage -= n; - - // ALERT( at_console, "punch %f\n", n ); - nTotal += 21; - - // exit blast damage - //m_pPlayer->RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, CLASS_NONE, DMG_BLAST ); - float damage_radius; - - if( g_pGameRules->IsMultiplayer() ) - { - damage_radius = flDamage * 1.75; // Old code == 2.5 - } - else - { - damage_radius = flDamage * 2.5; - } - - ::RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, damage_radius, CLASS_NONE, DMG_BLAST ); - - CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - - nTotal += 53; - - vecSrc = beam_tr.vecEndPos + vecDir; - } - else if( !selfgauss.value ) - { - flDamage = 0; - } - } - else - { - //ALERT( at_console, "blocked %f\n", n ); - flDamage = 0; - } - } - else - { - //ALERT( at_console, "blocked solid\n" ); - - flDamage = 0; - } - - } - } - else - { - vecSrc = tr.vecEndPos + vecDir; - pentIgnore = ENT( pEntity->pev ); - } - } -#endif - // ALERT( at_console, "%d bytes\n", nTotal ); -} - -void CGauss::WeaponIdle( void ) -{ - ResetEmptySound(); - - // play aftershock static discharge - if( m_pPlayer->m_flPlayAftershock && m_pPlayer->m_flPlayAftershock < gpGlobals->time ) - { - switch( RANDOM_LONG( 0, 3 ) ) - { - case 0: - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/electro4.wav", RANDOM_FLOAT( 0.7, 0.8 ), ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/electro5.wav", RANDOM_FLOAT( 0.7, 0.8 ), ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/electro6.wav", RANDOM_FLOAT( 0.7, 0.8 ), ATTN_NORM ); - break; - case 3: - break; // no sound - } - m_pPlayer->m_flPlayAftershock = 0.0; - } - - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if( m_fInAttack != 0 ) - { - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; - - // Need to set m_flNextPrimaryAttack so the weapon gets a chance to complete its secondary fire animation. - Solokiller - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; - } - else - { - int iAnim; - float flRand = RANDOM_FLOAT( 0, 1 ); - if( flRand <= 0.5 ) - { - iAnim = GAUSS_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else if( flRand <= 0.75 ) - { - iAnim = GAUSS_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - iAnim = GAUSS_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - } -#ifndef CLIENT_DLL - SendWeaponAnim( iAnim ); -#endif - } -} - -class CGaussAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT( pev ), "models/w_gaussammo.mdl" ); - CBasePlayerAmmo::Spawn(); - } - void Precache( void ) - { - PRECACHE_MODEL( "models/w_gaussammo.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if( pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1 ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ) -#endif diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp deleted file mode 100644 index 3cc0acc6..00000000 --- a/dlls/genericmonster.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Generic Monster - purely for scripted sequence work. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -// For holograms, make them not solid so the player can walk through them -#define SF_GENERICMONSTER_NOTSOLID 4 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CGenericMonster : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask( void ); -}; - -LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ) - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGenericMonster::Classify( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGenericMonster::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGenericMonster::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// ISoundMask - generic monster can't hear. -//========================================================= -int CGenericMonster::ISoundMask( void ) -{ - return 0; -} - -//========================================================= -// Spawn -//========================================================= -void CGenericMonster::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), STRING( pev->model ) ); -/* - if( FStrEq( STRING( pev->model ), "models/player.mdl" ) ) - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - else - UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX); -*/ - if( FStrEq( STRING( pev->model ), "models/player.mdl" ) || FStrEq( STRING( pev->model ), "models/holo.mdl" ) ) - UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX ); - else - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = 8; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); - - if( pev->spawnflags & SF_GENERICMONSTER_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGenericMonster::Precache() -{ - PRECACHE_MODEL( STRING( pev->model ) ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= diff --git a/dlls/glock.cpp b/dlls/glock.cpp deleted file mode 100644 index 1150d8b9..00000000 --- a/dlls/glock.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - -enum glock_e -{ - GLOCK_IDLE1 = 0, - GLOCK_IDLE2, - GLOCK_IDLE3, - GLOCK_SHOOT, - GLOCK_SHOOT_EMPTY, - GLOCK_RELOAD, - GLOCK_RELOAD_NOT_EMPTY, - GLOCK_DRAW, - GLOCK_HOLSTER, - GLOCK_ADD_SILENCER -}; - -LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ) -LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ) - -void CGlock::Spawn() -{ - pev->classname = MAKE_STRING( "weapon_9mmhandgun" ); // hack to allow for old names - Precache(); - m_iId = WEAPON_GLOCK; - SET_MODEL( ENT( pev ), "models/w_9mmhandgun.mdl" ); - - m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -void CGlock::Precache( void ) -{ - PRECACHE_MODEL( "models/v_9mmhandgun.mdl" ); - PRECACHE_MODEL( "models/w_9mmhandgun.mdl" ); - PRECACHE_MODEL( "models/p_9mmhandgun.mdl" ); - - m_iShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shell - - PRECACHE_SOUND( "items/9mmclip1.wav" ); - PRECACHE_SOUND( "items/9mmclip2.wav" ); - - PRECACHE_SOUND( "weapons/pl_gun1.wav" );//silenced handgun - PRECACHE_SOUND( "weapons/pl_gun2.wav" );//silenced handgun - PRECACHE_SOUND( "weapons/pl_gun3.wav" );//handgun - - m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); - m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); -} - -int CGlock::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = GLOCK_MAX_CLIP; - p->iSlot = 1; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_GLOCK; - p->iWeight = GLOCK_WEIGHT; - - return 1; -} - -int CGlock::AddToPlayer( CBasePlayer *pPlayer ) -{ - if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -BOOL CGlock::Deploy() -{ - // pev->body = 1; - return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 ); -} - -void CGlock::SecondaryAttack( void ) -{ - GlockFire( 0.1, 0.2, FALSE ); -} - -void CGlock::PrimaryAttack( void ) -{ - GlockFire( 0.01, 0.3, TRUE ); -} - -void CGlock::GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ) -{ - if( m_iClip <= 0 ) - { - if( m_fFireOnEmpty ) - { - PlayEmptySound(); - m_flNextPrimaryAttack = GetNextAttackDelay( 0.2 ); - } - - return; - } - - m_iClip--; - - m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - // silenced - if( pev->body == 1 ) - { - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - } - else - { - // non-silenced - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - } - - Vector vecSrc = m_pPlayer->GetGunPosition(); - Vector vecAiming; - - if( fUseAutoAim ) - { - vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - } - else - { - vecAiming = gpGlobals->v_forward; - } - - Vector vecDir; - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = GetNextAttackDelay( flCycleTime ); - - if( !m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - -void CGlock::Reload( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == GLOCK_MAX_CLIP ) - return; - - int iResult; - - if( m_iClip == 0 ) - iResult = DefaultReload( GLOCK_MAX_CLIP, GLOCK_RELOAD, 1.5 ); - else - iResult = DefaultReload( GLOCK_MAX_CLIP, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); - - if( iResult ) - { - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } -} - -void CGlock::WeaponIdle( void ) -{ - ResetEmptySound(); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - // only idle if the slid isn't back - if( m_iClip != 0 ) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 ); - - if( flRand <= 0.3 + 0 * 0.75 ) - { - iAnim = GLOCK_IDLE3; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 49.0 / 16; - } - else if( flRand <= 0.6 + 0 * 0.875 ) - { - iAnim = GLOCK_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0; - } - else - { - iAnim = GLOCK_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; - } - SendWeaponAnim( iAnim, 1 ); - } -} - -class CGlockAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT( pev ), "models/w_9mmclip.mdl" ); - CBasePlayerAmmo::Spawn(); - } - - void Precache( void ) - { - PRECACHE_MODEL( "models/w_9mmclip.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - - BOOL AddAmmo( CBaseEntity *pOther ) - { - if( pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1 ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ) -LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ) diff --git a/dlls/gman.cpp b/dlls/gman.cpp deleted file mode 100644 index 377755f6..00000000 --- a/dlls/gman.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// GMan - misunderstood servant of the people -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "weapons.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CGMan : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); - - EHANDLE m_hPlayer; - EHANDLE m_hTalkTarget; - float m_flTalkTime; -}; - -LINK_ENTITY_TO_CLASS( monster_gman, CGMan ) - -TYPEDESCRIPTION CGMan::m_SaveData[] = -{ - DEFINE_FIELD( CGMan, m_hTalkTarget, FIELD_EHANDLE ), - DEFINE_FIELD( CGMan, m_flTalkTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CGMan, CBaseMonster ) - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGMan::Classify( void ) -{ - return CLASS_NONE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGMan::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGMan::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// ISoundMask - generic monster can't hear. -//========================================================= -int CGMan::ISoundMask( void ) -{ - return 0; -} - -//========================================================= -// Spawn -//========================================================= -void CGMan::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/gman.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = DONT_BLEED; - pev->health = 100; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGMan::Precache() -{ - PRECACHE_MODEL( "models/gman.mdl" ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -void CGMan::StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_WAIT: - if( m_hPlayer == 0 ) - { - m_hPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - } - break; - } - CBaseMonster::StartTask( pTask ); -} - -void CGMan::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_WAIT: - // look at who I'm talking to - if( m_flTalkTime > gpGlobals->time && m_hTalkTarget != 0 ) - { - float yaw = VecToYaw( m_hTalkTarget->pev->origin - pev->origin ) - pev->angles.y; - - if( yaw > 180 ) - yaw -= 360; - if( yaw < -180 ) - yaw += 360; - - // turn towards vector - SetBoneController( 0, yaw ); - } - // look at player, but only if playing a "safe" idle animation - else if( m_hPlayer != 0 && pev->sequence == 0 ) - { - float yaw = VecToYaw( m_hPlayer->pev->origin - pev->origin ) - pev->angles.y; - - if( yaw > 180 ) - yaw -= 360; - if( yaw < -180 ) - yaw += 360; - - // turn towards vector - SetBoneController( 0, yaw ); - } - else - { - SetBoneController( 0, 0 ); - } - CBaseMonster::RunTask( pTask ); - break; - default: - SetBoneController( 0, 0 ); - CBaseMonster::RunTask( pTask ); - break; - } -} - -//========================================================= -// Override all damage -//========================================================= -int CGMan::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - pev->health = pev->max_health / 2; // always trigger the 50% damage aitrigger - - if( flDamage > 0 ) - { - SetConditions( bits_COND_LIGHT_DAMAGE ); - } - - if( flDamage >= 20 ) - { - SetConditions( bits_COND_HEAVY_DAMAGE ); - } - return TRUE; -} - -void CGMan::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -void CGMan::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) -{ - CBaseMonster::PlayScriptedSentence( pszSentence, duration, volume, attenuation, bConcurrent, pListener ); - - m_flTalkTime = gpGlobals->time + duration; - m_hTalkTarget = pListener; -} diff --git a/dlls/hassassin.cpp b/dlls/hassassin.cpp deleted file mode 100644 index f51ed4cb..00000000 --- a/dlls/hassassin.cpp +++ /dev/null @@ -1,992 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// hassassin - Human assassin, fast and stealthy -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "squadmonster.h" -#include "weapons.h" -#include "soundent.h" -#include "game.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_ASSASSIN_EXPOSED = LAST_COMMON_SCHEDULE + 1,// cover was blown. - SCHED_ASSASSIN_JUMP, // fly through the air - SCHED_ASSASSIN_JUMP_ATTACK, // fly through the air and shoot - SCHED_ASSASSIN_JUMP_LAND // hit and run away -}; - -//========================================================= -// monster-specific tasks -//========================================================= - -enum -{ - TASK_ASSASSIN_FALL_TO_GROUND = LAST_COMMON_TASK + 1 // falling and waiting to hit ground -}; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ASSASSIN_AE_SHOOT1 1 -#define ASSASSIN_AE_TOSS1 2 -#define ASSASSIN_AE_JUMP 3 - -#define bits_MEMORY_BADJUMP ( bits_MEMORY_CUSTOM1 ) - -class CHAssassin : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - int Classify( void ); - int ISoundMask( void); - void Shoot( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - BOOL CheckMeleeAttack1( float flDot, float flDist ); // jump - // BOOL CheckMeleeAttack2( float flDot, float flDist ); - BOOL CheckRangeAttack1( float flDot, float flDist ); // shoot - BOOL CheckRangeAttack2( float flDot, float flDist ); // throw grenade - void StartTask( Task_t *pTask ); - void RunAI( void ); - void RunTask( Task_t *pTask ); - void DeathSound( void ); - void IdleSound( void ); - CUSTOM_SCHEDULES - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flLastShot; - float m_flDiviation; - - float m_flNextJump; - Vector m_vecJumpVelocity; - - float m_flNextGrenadeCheck; - Vector m_vecTossVelocity; - BOOL m_fThrowGrenade; - - int m_iTargetRanderamt; - - int m_iFrustration; - - int m_iShell; -}; - -LINK_ENTITY_TO_CLASS( monster_human_assassin, CHAssassin ) - -TYPEDESCRIPTION CHAssassin::m_SaveData[] = -{ - DEFINE_FIELD( CHAssassin, m_flLastShot, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_flDiviation, FIELD_FLOAT ), - - DEFINE_FIELD( CHAssassin, m_flNextJump, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_vecJumpVelocity, FIELD_VECTOR ), - - DEFINE_FIELD( CHAssassin, m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CHAssassin, m_fThrowGrenade, FIELD_BOOLEAN ), - - DEFINE_FIELD( CHAssassin, m_iTargetRanderamt, FIELD_INTEGER ), - DEFINE_FIELD( CHAssassin, m_iFrustration, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CHAssassin, CBaseMonster ) - -//========================================================= -// DieSound -//========================================================= -void CHAssassin::DeathSound( void ) -{ -} - -//========================================================= -// IdleSound -//========================================================= -void CHAssassin::IdleSound( void ) -{ -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CHAssassin::ISoundMask( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHAssassin::Classify( void ) -{ - return CLASS_HUMAN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHAssassin::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 360; - break; - default: - ys = 360; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// Shoot -//========================================================= -void CHAssassin::Shoot( void ) -{ - if( m_hEnemy == 0 ) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - if( m_flLastShot + 2 < gpGlobals->time ) - { - m_flDiviation = 0.10; - } - else - { - m_flDiviation -= 0.01; - if( m_flDiviation < 0.02 ) - m_flDiviation = 0.02; - } - m_flLastShot = gpGlobals->time; - - UTIL_MakeVectors( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT( 40, 90 ) + gpGlobals->v_up * RANDOM_FLOAT( 75, 200 ) + gpGlobals->v_forward * RANDOM_FLOAT( -40, 40 ); - EjectBrass( pev->origin + gpGlobals->v_up * 32 + gpGlobals->v_forward * 12, vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL ); - FireBullets( 1, vecShootOrigin, vecShootDir, Vector( m_flDiviation, m_flDiviation, m_flDiviation ), 2048, BULLET_MONSTER_9MM ); // shoot +-8 degrees - - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT( 0.6, 0.8 ), ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT( 0.6, 0.8 ), ATTN_NORM ); - break; - } - - pev->effects |= EF_MUZZLEFLASH; - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); - - m_cAmmoLoaded--; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CHAssassin::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case ASSASSIN_AE_SHOOT1: - Shoot(); - break; - case ASSASSIN_AE_TOSS1: - { - UTIL_MakeVectors( pev->angles ); - CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector( 0, 0, 32 ), m_vecTossVelocity, 2.0 ); - - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - m_fThrowGrenade = FALSE; - // !!!LATER - when in a group, only try to throw grenade if ordered. - } - break; - case ASSASSIN_AE_JUMP: - { - // ALERT( at_console, "jumping"); - UTIL_MakeAimVectors( pev->angles ); - pev->movetype = MOVETYPE_TOSS; - pev->flags &= ~FL_ONGROUND; - pev->velocity = m_vecJumpVelocity; - m_flNextJump = gpGlobals->time + 3.0; - } - return; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHAssassin::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/hassassin.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = 0; - pev->health = gSkillData.hassassinHealth; - m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP; - pev->friction = 1; - - m_HackedGunPos = Vector( 0, 24, 48 ); - - m_iTargetRanderamt = 20; - pev->renderamt = 20; - pev->rendermode = kRenderTransTexture; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHAssassin::Precache() -{ - PRECACHE_MODEL( "models/hassassin.mdl" ); - - PRECACHE_SOUND( "weapons/pl_gun1.wav" ); - PRECACHE_SOUND( "weapons/pl_gun2.wav" ); - - PRECACHE_SOUND( "debris/beamstart1.wav" ); - - m_iShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shell -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// Fail Schedule -//========================================================= -Task_t tlAssassinFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - // { TASK_WAIT_PVS, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, -}; - -Schedule_t slAssassinFail[] = -{ - { - tlAssassinFail, - ARRAYSIZE( tlAssassinFail ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER | - bits_SOUND_PLAYER, - "AssassinFail" - }, -}; - -//========================================================= -// Enemy exposed Agrunt's cover -//========================================================= -Task_t tlAssassinExposed[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_JUMP }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slAssassinExposed[] = -{ - { - tlAssassinExposed, - ARRAYSIZE( tlAssassinExposed ), - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AssassinExposed", - }, -}; - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAssassinTakeCoverFromEnemy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAssassinTakeCoverFromEnemy[] = -{ - { - tlAssassinTakeCoverFromEnemy, - ARRAYSIZE( tlAssassinTakeCoverFromEnemy ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "AssassinTakeCoverFromEnemy" - }, -}; - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAssassinTakeCoverFromEnemy2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK2 }, - { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAssassinTakeCoverFromEnemy2[] = -{ - { - tlAssassinTakeCoverFromEnemy2, - ARRAYSIZE( tlAssassinTakeCoverFromEnemy2 ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "AssassinTakeCoverFromEnemy2" - }, -}; - -//========================================================= -// hide from the loudest sound source -//========================================================= -Task_t tlAssassinTakeCoverFromBestSound[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MELEE_ATTACK1 }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slAssassinTakeCoverFromBestSound[] = -{ - { - tlAssassinTakeCoverFromBestSound, - ARRAYSIZE( tlAssassinTakeCoverFromBestSound ), - bits_COND_NEW_ENEMY, - 0, - "AssassinTakeCoverFromBestSound" - }, -}; - -//========================================================= -// AlertIdle Schedules -//========================================================= -Task_t tlAssassinHide[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, -}; - -Schedule_t slAssassinHide[] = -{ - { - tlAssassinHide, - ARRAYSIZE( tlAssassinHide ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "AssassinHide" - }, -}; - -//========================================================= -// HUNT Schedules -//========================================================= -Task_t tlAssassinHunt[] = -{ - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slAssassinHunt[] = -{ - { - tlAssassinHunt, - ARRAYSIZE( tlAssassinHunt ), - bits_COND_NEW_ENEMY | - // bits_COND_SEE_ENEMY | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "AssassinHunt" - }, -}; - -//========================================================= -// Jumping Schedules -//========================================================= -Task_t tlAssassinJump[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, - { TASK_SET_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_ATTACK }, -}; - -Schedule_t slAssassinJump[] = -{ - { - tlAssassinJump, - ARRAYSIZE( tlAssassinJump ), - 0, - 0, - "AssassinJump" - }, -}; - -//========================================================= -// repel -//========================================================= -Task_t tlAssassinJumpAttack[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_LAND }, - // { TASK_SET_ACTIVITY, (float)ACT_FLY }, - { TASK_ASSASSIN_FALL_TO_GROUND, (float)0 }, -}; - -Schedule_t slAssassinJumpAttack[] = -{ - { - tlAssassinJumpAttack, - ARRAYSIZE( tlAssassinJumpAttack ), - 0, - 0, - "AssassinJumpAttack" - }, -}; - -//========================================================= -// repel -//========================================================= -Task_t tlAssassinJumpLand[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_EXPOSED }, - // { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MELEE_ATTACK1 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_REMEMBER, (float)bits_MEMORY_BADJUMP }, - { TASK_FIND_NODE_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_FORGET, (float)bits_MEMORY_BADJUMP }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 }, -}; - -Schedule_t slAssassinJumpLand[] = -{ - { - tlAssassinJumpLand, - ARRAYSIZE( tlAssassinJumpLand ), - 0, - 0, - "AssassinJumpLand" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CHAssassin ) -{ - slAssassinFail, - slAssassinExposed, - slAssassinTakeCoverFromEnemy, - slAssassinTakeCoverFromEnemy2, - slAssassinTakeCoverFromBestSound, - slAssassinHide, - slAssassinHunt, - slAssassinJump, - slAssassinJumpAttack, - slAssassinJumpLand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHAssassin, CBaseMonster ) - -//========================================================= -// CheckMeleeAttack1 - jump like crazy if the enemy gets too close. -//========================================================= -BOOL CHAssassin::CheckMeleeAttack1( float flDot, float flDist ) -{ - if( m_flNextJump < gpGlobals->time && ( flDist <= 128 || HasMemory( bits_MEMORY_BADJUMP ) ) && m_hEnemy != 0 ) - { - TraceResult tr; - - Vector vecDest = pev->origin + Vector( RANDOM_FLOAT( -64, 64), RANDOM_FLOAT( -64, 64 ), 160 ); - - UTIL_TraceHull( pev->origin + Vector( 0, 0, 36 ), vecDest + Vector( 0, 0, 36 ), dont_ignore_monsters, human_hull, ENT( pev ), &tr ); - - if( tr.fStartSolid || tr.flFraction < 1.0 ) - { - return FALSE; - } - - float flGravity = g_psv_gravity->value; - - float time = sqrt( 160 / ( 0.5 * flGravity ) ); - float speed = flGravity * time / 160; - m_vecJumpVelocity = ( vecDest - pev->origin ) * speed; - - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 - drop a cap in their ass -// -//========================================================= -BOOL CHAssassin::CheckRangeAttack1( float flDot, float flDist ) -{ - if( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist > 64 && flDist <= 2048 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) - { - TraceResult tr; - - Vector vecSrc = GetGunPosition(); - - // verify that a bullet fired from the gun will hit the enemy before the world. - UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget( vecSrc ), dont_ignore_monsters, ENT( pev ), &tr ); - - if( tr.flFraction == 1 || tr.pHit == m_hEnemy->edict() ) - { - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 - toss grenade is enemy gets in the way and is too close. -//========================================================= -BOOL CHAssassin::CheckRangeAttack2( float flDot, float flDist ) -{ - m_fThrowGrenade = FALSE; - if( !FBitSet( m_hEnemy->pev->flags, FL_ONGROUND ) ) - { - // don't throw grenades at anything that isn't on the ground! - return FALSE; - } - - // don't get grenade happy unless the player starts to piss you off - if( m_iFrustration <= 2 ) - return FALSE; - - if( m_flNextGrenadeCheck < gpGlobals->time && !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 512 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) - { - Vector vecToss = VecCheckThrow( pev, GetGunPosition(), m_hEnemy->Center(), flDist, 0.5 ); // use dist as speed to get there in 1 second - - if( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - - return TRUE; - } - } - - return FALSE; -} - -//========================================================= -// RunAI -//========================================================= -void CHAssassin::RunAI( void ) -{ - CBaseMonster::RunAI(); - - // always visible if moving - // always visible is not on hard - if( g_iSkillLevel != SKILL_HARD || m_hEnemy == 0 || pev->deadflag != DEAD_NO || m_Activity == ACT_RUN || m_Activity == ACT_WALK || !( pev->flags & FL_ONGROUND ) ) - m_iTargetRanderamt = 255; - else - m_iTargetRanderamt = 20; - - if( pev->renderamt > m_iTargetRanderamt ) - { - if( pev->renderamt == 255 ) - { - EMIT_SOUND( ENT( pev ), CHAN_BODY, "debris/beamstart1.wav", 0.2, ATTN_NORM ); - } - - pev->renderamt = Q_max( pev->renderamt - 50, m_iTargetRanderamt ); - pev->rendermode = kRenderTransTexture; - } - else if( pev->renderamt < m_iTargetRanderamt ) - { - pev->renderamt = Q_min( pev->renderamt + 50, m_iTargetRanderamt ); - if( pev->renderamt == 255 ) - pev->rendermode = kRenderNormal; - } - - if( m_Activity == ACT_RUN || m_Activity == ACT_WALK ) - { - static int iStep = 0; - iStep = !iStep; - if( iStep ) - { - switch( RANDOM_LONG( 0, 3 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_BODY, "player/pl_step1.wav", 0.5, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_BODY, "player/pl_step3.wav", 0.5, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_BODY, "player/pl_step2.wav", 0.5, ATTN_NORM ); - break; - case 3: - EMIT_SOUND( ENT( pev ), CHAN_BODY, "player/pl_step4.wav", 0.5, ATTN_NORM ); - break; - } - } - } -} - -//========================================================= -// StartTask -//========================================================= -void CHAssassin::StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_RANGE_ATTACK2: - if( !m_fThrowGrenade ) - { - TaskComplete(); - } - else - { - CBaseMonster::StartTask( pTask ); - } - break; - case TASK_ASSASSIN_FALL_TO_GROUND: - break; - default: - CBaseMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CHAssassin::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_ASSASSIN_FALL_TO_GROUND: - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if( m_fSequenceFinished ) - { - if( pev->velocity.z > 0 ) - { - pev->sequence = LookupSequence( "fly_up" ); - } - else if( HasConditions( bits_COND_SEE_ENEMY ) ) - { - pev->sequence = LookupSequence( "fly_attack" ); - pev->frame = 0; - } - else - { - pev->sequence = LookupSequence( "fly_down" ); - pev->frame = 0; - } - - ResetSequenceInfo(); - SetYawSpeed(); - } - if( pev->flags & FL_ONGROUND ) - { - // ALERT( at_console, "on ground\n" ); - TaskComplete(); - } - break; - default: - CBaseMonster::RunTask( pTask ); - break; - } -} - -//========================================================= -// 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 *CHAssassin::GetSchedule( void ) -{ - switch( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - case MONSTERSTATE_ALERT: - { - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if( pSound &&( pSound->m_iType & bits_SOUND_DANGER ) ) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - if( pSound &&( pSound->m_iType & bits_SOUND_COMBAT ) ) - { - return GetScheduleOfType( SCHED_INVESTIGATE_SOUND ); - } - } - } - break; - case MONSTERSTATE_COMBAT: - { - // dead enemy - if( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster::GetSchedule(); - } - - // flying? - if( pev->movetype == MOVETYPE_TOSS ) - { - if( pev->flags & FL_ONGROUND ) - { - // ALERT( at_console, "landed\n" ); - // just landed - pev->movetype = MOVETYPE_STEP; - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_LAND ); - } - else - { - // ALERT( at_console, "jump\n" ); - // jump or jump/shoot - if( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType( SCHED_ASSASSIN_JUMP ); - else - return GetScheduleOfType( SCHED_ASSASSIN_JUMP_ATTACK ); - } - } - - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if( pSound && ( pSound->m_iType & bits_SOUND_DANGER ) ) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - } - - if( HasConditions( bits_COND_LIGHT_DAMAGE ) ) - { - m_iFrustration++; - } - if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - { - m_iFrustration++; - } - - // jump player! - if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - // ALERT( at_console, "melee attack 1\n" ); - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - - // throw grenade - if( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) ) - { - // ALERT( at_console, "range attack 2\n"); - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - - // spotted - if( HasConditions( bits_COND_SEE_ENEMY ) && HasConditions( bits_COND_ENEMY_FACING_ME ) ) - { - // ALERT( at_console, "exposed\n" ); - m_iFrustration++; - return GetScheduleOfType( SCHED_ASSASSIN_EXPOSED ); - } - - // can attack - if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - // ALERT( at_console, "range attack 1\n" ); - m_iFrustration = 0; - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - if( HasConditions( bits_COND_SEE_ENEMY ) ) - { - // ALERT( at_console, "face\n" ); - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - - // new enemy - if( HasConditions( bits_COND_NEW_ENEMY ) ) - { - // ALERT( at_console, "take cover\n" ); - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - - // ALERT( at_console, "stand\n" ); - return GetScheduleOfType( SCHED_ALERT_STAND ); - } - break; - default: - break; - } - - return CBaseMonster::GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t *CHAssassin::GetScheduleOfType( int Type ) -{ - // ALERT( at_console, "%d\n", m_iFrustration ); - switch( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - if( pev->health > 30 ) - return slAssassinTakeCoverFromEnemy; - else - return slAssassinTakeCoverFromEnemy2; - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - return slAssassinTakeCoverFromBestSound; - case SCHED_ASSASSIN_EXPOSED: - return slAssassinExposed; - case SCHED_FAIL: - if( m_MonsterState == MONSTERSTATE_COMBAT ) - return slAssassinFail; - break; - case SCHED_ALERT_STAND: - if( m_MonsterState == MONSTERSTATE_COMBAT ) - return slAssassinHide; - break; - case SCHED_CHASE_ENEMY: - return slAssassinHunt; - case SCHED_MELEE_ATTACK1: - if( pev->flags & FL_ONGROUND ) - { - if( m_flNextJump > gpGlobals->time ) - { - // can't jump yet, go ahead and fail - return slAssassinFail; - } - else - { - return slAssassinJump; - } - } - else - { - return slAssassinJumpAttack; - } - case SCHED_ASSASSIN_JUMP: - case SCHED_ASSASSIN_JUMP_ATTACK: - return slAssassinJumpAttack; - case SCHED_ASSASSIN_JUMP_LAND: - return slAssassinJumpLand; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} -#endif diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp deleted file mode 100644 index 60e03c10..00000000 --- a/dlls/headcrab.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// headcrab.cpp - tiny, jumpy alien parasite -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "game.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HC_AE_JUMPATTACK ( 2 ) - -Task_t tlHCRangeAttack1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WAIT_RANDOM, (float)0.5 }, -}; - -Schedule_t slHCRangeAttack1[] = -{ - { - tlHCRangeAttack1, - ARRAYSIZE( tlHCRangeAttack1 ), - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "HCRangeAttack1" - }, -}; - -Task_t tlHCRangeAttack1Fast[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slHCRangeAttack1Fast[] = -{ - { - tlHCRangeAttack1Fast, - ARRAYSIZE( tlHCRangeAttack1Fast ), - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "HCRAFast" - }, -}; - -class CHeadCrab : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void RunTask ( Task_t *pTask ); - void StartTask ( Task_t *pTask ); - void SetYawSpeed ( void ); - void EXPORT LeapTouch ( CBaseEntity *pOther ); - Vector Center( void ); - Vector BodyTarget( const Vector &posSrc ); - void PainSound( void ); - void DeathSound( void ); - void IdleSound( void ); - void AlertSound( void ); - void PrescheduleThink( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack2 ( float flDot, float flDist ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; } - virtual int GetVoicePitch( void ) { return 100; } - virtual float GetSoundVolue( void ) { return 1.0; } - Schedule_t* GetScheduleOfType ( int Type ); - - CUSTOM_SCHEDULES - - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackSounds[]; - static const char *pDeathSounds[]; - static const char *pBiteSounds[]; -}; - -LINK_ENTITY_TO_CLASS( monster_headcrab, CHeadCrab ) - -DEFINE_CUSTOM_SCHEDULES( CHeadCrab ) -{ - slHCRangeAttack1, - slHCRangeAttack1Fast, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHeadCrab, CBaseMonster ) - -const char *CHeadCrab::pIdleSounds[] = -{ - "headcrab/hc_idle1.wav", - "headcrab/hc_idle2.wav", - "headcrab/hc_idle3.wav", -}; - -const char *CHeadCrab::pAlertSounds[] = -{ - "headcrab/hc_alert1.wav", -}; - -const char *CHeadCrab::pPainSounds[] = -{ - "headcrab/hc_pain1.wav", - "headcrab/hc_pain2.wav", - "headcrab/hc_pain3.wav", -}; - -const char *CHeadCrab::pAttackSounds[] = -{ - "headcrab/hc_attack1.wav", - "headcrab/hc_attack2.wav", - "headcrab/hc_attack3.wav", -}; - -const char *CHeadCrab::pDeathSounds[] = -{ - "headcrab/hc_die1.wav", - "headcrab/hc_die2.wav", -}; - -const char *CHeadCrab::pBiteSounds[] = -{ - "headcrab/hc_headbite.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHeadCrab::Classify( void ) -{ - return CLASS_ALIEN_PREY; -} - -//========================================================= -// Center - returns the real center of the headcrab. The -// bounding box is much larger than the actual creature so -// this is needed for targeting -//========================================================= -Vector CHeadCrab::Center( void ) -{ - return Vector( pev->origin.x, pev->origin.y, pev->origin.z + 6 ); -} - -Vector CHeadCrab::BodyTarget( const Vector &posSrc ) -{ - return Center(); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHeadCrab::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_IDLE: - ys = 30; - break; - case ACT_RUN: - case ACT_WALK: - ys = 20; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 60; - break; - case ACT_RANGE_ATTACK1: - ys = 30; - break; - default: - ys = 30; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHeadCrab::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case HC_AE_JUMPATTACK: - { - ClearBits( pev->flags, FL_ONGROUND ); - - UTIL_SetOrigin( pev, pev->origin + Vector( 0, 0, 1 ) );// take him off ground so engine doesn't instantly reset onground - UTIL_MakeVectors( pev->angles ); - - Vector vecJumpDir; - if( m_hEnemy != 0 ) - { - float gravity = g_psv_gravity->value; - if( gravity <= 1 ) - gravity = 1; - - // How fast does the headcrab need to travel to reach that height given gravity? - float height = m_hEnemy->pev->origin.z + m_hEnemy->pev->view_ofs.z - pev->origin.z; - if( height < 16 ) - height = 16; - float speed = sqrt( 2 * gravity * height ); - float time = speed / gravity; - - // Scale the sideways velocity to get there at the right time - vecJumpDir = m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs - pev->origin; - vecJumpDir = vecJumpDir * ( 1.0 / time ); - - // Speed to offset gravity at the desired height - vecJumpDir.z = speed; - - // Don't jump too far/fast - float distance = vecJumpDir.Length(); - - if( distance > 650 ) - { - vecJumpDir = vecJumpDir * ( 650.0 / distance ); - } - } - else - { - // jump hop, don't care where - vecJumpDir = Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_up.z ) * 350; - } - - int iSound = RANDOM_LONG(0,2); - if( iSound != 0 ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[iSound], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - - pev->velocity = vecJumpDir; - m_flNextAttack = gpGlobals->time + 2; - } - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHeadCrab::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/headcrab.mdl" ); - UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.headcrabHealth; - pev->view_ofs = Vector( 0, 0, 20 );// position of the eyes relative to monster's origin. - pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHeadCrab::Precache() -{ - PRECACHE_SOUND_ARRAY( pIdleSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_SOUND_ARRAY( pBiteSounds ); - - PRECACHE_MODEL( "models/headcrab.mdl" ); -} - -//========================================================= -// RunTask -//========================================================= -void CHeadCrab::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - case TASK_RANGE_ATTACK2: - { - if( m_fSequenceFinished ) - { - TaskComplete(); - SetTouch( NULL ); - m_IdealActivity = ACT_IDLE; - } - break; - } - default: - { - CBaseMonster::RunTask( pTask ); - } - } -} - -//========================================================= -// LeapTouch - this is the headcrab's touch function when it -// is in the air -//========================================================= -void CHeadCrab::LeapTouch( CBaseEntity *pOther ) -{ - if( !pOther->pev->takedamage ) - { - return; - } - - if( pOther->Classify() == Classify() ) - { - return; - } - - // Don't hit if back on ground - if( !FBitSet( pev->flags, FL_ONGROUND ) ) - { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBiteSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - - pOther->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH ); - } - - SetTouch( NULL ); -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CHeadCrab::PrescheduleThink( void ) -{ - // make the crab coo a little bit in combat state - if( m_MonsterState == MONSTERSTATE_COMBAT && RANDOM_FLOAT( 0, 5 ) < 0.1 ) - { - IdleSound(); - } -} - -void CHeadCrab::StartTask( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - m_IdealActivity = ACT_RANGE_ATTACK1; - SetTouch( &CHeadCrab::LeapTouch ); - break; - } - default: - { - CBaseMonster::StartTask( pTask ); - } - } -} - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CHeadCrab::CheckRangeAttack1( float flDot, float flDist ) -{ - if( FBitSet( pev->flags, FL_ONGROUND ) && flDist <= 256 && flDot >= 0.65 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 -//========================================================= -BOOL CHeadCrab::CheckRangeAttack2( float flDot, float flDist ) -{ - return FALSE; - // BUGBUG: Why is this code here? There is no ACT_RANGE_ATTACK2 animation. I've disabled it for now. -#if 0 - if( FBitSet( pev->flags, FL_ONGROUND ) && flDist > 64 && flDist <= 256 && flDot >= 0.5 ) - { - return TRUE; - } - return FALSE; -#endif -} - -int CHeadCrab::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Don't take any acid damage -- BigMomma's mortar is acid - if( bitsDamageType & DMG_ACID ) - flDamage = 0; - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -#define CRAB_ATTN_IDLE (float)1.5 - -//========================================================= -// IdleSound -//========================================================= -void CHeadCrab::IdleSound( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pIdleSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// AlertSound -//========================================================= -void CHeadCrab::AlertSound( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAlertSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// AlertSound -//========================================================= -void CHeadCrab::PainSound( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// DeathSound -//========================================================= -void CHeadCrab::DeathSound( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -Schedule_t *CHeadCrab::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_RANGE_ATTACK1: - { - return &slHCRangeAttack1[0]; - } - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - -class CBabyCrab : public CHeadCrab -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite * 0.3; } - BOOL CheckRangeAttack1( float flDot, float flDist ); - Schedule_t *GetScheduleOfType ( int Type ); - virtual int GetVoicePitch( void ) { return PITCH_NORM + RANDOM_LONG( 40, 50 ); } - virtual float GetSoundVolue( void ) { return 0.8; } -}; - -LINK_ENTITY_TO_CLASS( monster_babycrab, CBabyCrab ) - -void CBabyCrab::Spawn( void ) -{ - CHeadCrab::Spawn(); - SET_MODEL( ENT( pev ), "models/baby_headcrab.mdl" ); - pev->rendermode = kRenderTransTexture; - pev->renderamt = 192; - UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) ); - - pev->health = gSkillData.headcrabHealth * 0.25; // less health than full grown -} - -void CBabyCrab::Precache( void ) -{ - PRECACHE_MODEL( "models/baby_headcrab.mdl" ); - CHeadCrab::Precache(); -} - -void CBabyCrab::SetYawSpeed( void ) -{ - pev->yaw_speed = 120; -} - -BOOL CBabyCrab::CheckRangeAttack1( float flDot, float flDist ) -{ - if( pev->flags & FL_ONGROUND ) - { - if( pev->groundentity && ( pev->groundentity->v.flags & ( FL_CLIENT | FL_MONSTER ) ) ) - return TRUE; - - // A little less accurate, but jump from closer - if( flDist <= 180 && flDot >= 0.55 ) - return TRUE; - } - - return FALSE; -} - -Schedule_t *CBabyCrab::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_FAIL: // If you fail, try to jump! - if( m_hEnemy != 0 ) - return slHCRangeAttack1Fast; - break; - case SCHED_RANGE_ATTACK1: - { - return slHCRangeAttack1Fast; - } - break; - } - - return CHeadCrab::GetScheduleOfType( Type ); -} diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp deleted file mode 100644 index 62c947f1..00000000 --- a/dlls/hgrunt.cpp +++ /dev/null @@ -1,2487 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// hgrunt -//========================================================= - -//========================================================= -// Hit groups! -//========================================================= -/* - - 1 - Head - 2 - Stomach - 3 - Gun - -*/ - -#include "extdll.h" -#include "plane.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "animation.h" -#include "squadmonster.h" -#include "weapons.h" -#include "talkmonster.h" -#include "soundent.h" -#include "effects.h" -#include "customentity.h" - -int g_fGruntQuestion; // true if an idle grunt asked a question. Cleared when someone answers. - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// monster-specific DEFINE's -//========================================================= -#define GRUNT_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x! -#define GRUNT_VOL 0.35 // volume of grunt sounds -#define GRUNT_ATTN ATTN_NORM // attenutation of grunt sentences -#define HGRUNT_LIMP_HEALTH 20 -#define HGRUNT_DMG_HEADSHOT ( DMG_BULLET | DMG_CLUB ) // damage types that can kill a grunt with a single headshot. -#define HGRUNT_NUM_HEADS 2 // how many grunt heads are there? -#define HGRUNT_MINIMUM_HEADSHOT_DAMAGE 15 // must do at least this much damage in one shot to head to score a headshot kill -#define HGRUNT_SENTENCE_VOLUME (float)0.35 // volume of grunt sentences - -#define HGRUNT_9MMAR ( 1 << 0) -#define HGRUNT_HANDGRENADE ( 1 << 1) -#define HGRUNT_GRENADELAUNCHER ( 1 << 2) -#define HGRUNT_SHOTGUN ( 1 << 3) - -#define HEAD_GROUP 1 -#define HEAD_GRUNT 0 -#define HEAD_COMMANDER 1 -#define HEAD_SHOTGUN 2 -#define HEAD_M203 3 -#define GUN_GROUP 2 -#define GUN_MP5 0 -#define GUN_SHOTGUN 1 -#define GUN_NONE 2 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HGRUNT_AE_RELOAD ( 2 ) -#define HGRUNT_AE_KICK ( 3 ) -#define HGRUNT_AE_BURST1 ( 4 ) -#define HGRUNT_AE_BURST2 ( 5 ) -#define HGRUNT_AE_BURST3 ( 6 ) -#define HGRUNT_AE_GREN_TOSS ( 7 ) -#define HGRUNT_AE_GREN_LAUNCH ( 8 ) -#define HGRUNT_AE_GREN_DROP ( 9 ) -#define HGRUNT_AE_CAUGHT_ENEMY ( 10 ) // grunt established sight with an enemy (player only) that had previously eluded the squad. -#define HGRUNT_AE_DROP_GUN ( 11 ) // grunt (probably dead) is dropping his mp5. - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_GRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, - SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE,// move to a location to set up an attack against the enemy. (usually when a friendly is in the way). - SCHED_GRUNT_COVER_AND_RELOAD, - SCHED_GRUNT_SWEEP, - SCHED_GRUNT_FOUND_ENEMY, - SCHED_GRUNT_REPEL, - SCHED_GRUNT_REPEL_ATTACK, - SCHED_GRUNT_REPEL_LAND, - SCHED_GRUNT_WAIT_FACE_ENEMY, - SCHED_GRUNT_TAKECOVER_FAILED,// special schedule type that forces analysis of conditions and picks the best possible schedule to recover from this type of failure. - SCHED_GRUNT_ELOF_FAIL -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_GRUNT_FACE_TOSS_DIR = LAST_COMMON_TASK + 1, - TASK_GRUNT_SPEAK_SENTENCE, - TASK_GRUNT_CHECK_FIRE -}; - -//========================================================= -// monster-specific conditions -//========================================================= -#define bits_COND_GRUNT_NOFIRE ( bits_COND_SPECIAL1 ) - -class CHGrunt : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - int ISoundMask( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL FCanCheckAttacks( void ); - BOOL CheckMeleeAttack1( float flDot, float flDist ); - BOOL CheckRangeAttack1( float flDot, float flDist ); - BOOL CheckRangeAttack2( float flDot, float flDist ); - void CheckAmmo( void ); - void SetActivity( Activity NewActivity ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - void DeathSound( void ); - void PainSound( void ); - void IdleSound( void ); - Vector GetGunPosition( void ); - void Shoot( void ); - void Shotgun( void ); - void PrescheduleThink( void ); - void GibMonster( void ); - void SpeakSentence( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CBaseEntity *Kick( void ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - int IRelationship( CBaseEntity *pTarget ); - - BOOL FOkToSpeak( void ); - void JustSpoke( void ); - - CUSTOM_SCHEDULES - static TYPEDESCRIPTION m_SaveData[]; - - // checking the feasibility of a grenade toss is kind of costly, so we do it every couple of seconds, - // not every server frame. - float m_flNextGrenadeCheck; - float m_flNextPainTime; - float m_flLastEnemySightTime; - - Vector m_vecTossVelocity; - - BOOL m_fThrowGrenade; - BOOL m_fStanding; - BOOL m_fFirstEncounter;// only put on the handsign show in the squad's first encounter. - int m_cClipSize; - - int m_voicePitch; - - int m_iBrassShell; - int m_iShotgunShell; - - int m_iSentence; - - static const char *pGruntSentences[]; -}; - -LINK_ENTITY_TO_CLASS( monster_human_grunt, CHGrunt ) - -TYPEDESCRIPTION CHGrunt::m_SaveData[] = -{ - DEFINE_FIELD( CHGrunt, m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( CHGrunt, m_flNextPainTime, FIELD_TIME ), - //DEFINE_FIELD( CHGrunt, m_flLastEnemySightTime, FIELD_TIME ), // don't save, go to zero - DEFINE_FIELD( CHGrunt, m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CHGrunt, m_fThrowGrenade, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_fStanding, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_fFirstEncounter, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_cClipSize, FIELD_INTEGER ), - DEFINE_FIELD( CHGrunt, m_voicePitch, FIELD_INTEGER ), - //DEFINE_FIELD( CShotgun, m_iBrassShell, FIELD_INTEGER ), - //DEFINE_FIELD( CShotgun, m_iShotgunShell, FIELD_INTEGER ), - DEFINE_FIELD( CHGrunt, m_iSentence, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CHGrunt, CSquadMonster ) - -const char *CHGrunt::pGruntSentences[] = -{ - "HG_GREN", // grenade scared grunt - "HG_ALERT", // sees player - "HG_MONSTER", // sees monster - "HG_COVER", // running to cover - "HG_THROW", // about to throw grenade - "HG_CHARGE", // running out to get the enemy - "HG_TAUNT", // say rude things -}; - -typedef enum -{ - HGRUNT_SENT_NONE = -1, - HGRUNT_SENT_GREN = 0, - HGRUNT_SENT_ALERT, - HGRUNT_SENT_MONSTER, - HGRUNT_SENT_COVER, - HGRUNT_SENT_THROW, - HGRUNT_SENT_CHARGE, - HGRUNT_SENT_TAUNT -} HGRUNT_SENTENCE_TYPES; - -//========================================================= -// Speak Sentence - say your cued up sentence. -// -// Some grunt sentences (take cover and charge) rely on actually -// being able to execute the intended action. It's really lame -// when a grunt says 'COVER ME' and then doesn't move. The problem -// is that the sentences were played when the decision to TRY -// to move to cover was made. Now the sentence is played after -// we know for sure that there is a valid path. The schedule -// may still fail but in most cases, well after the grunt has -// started moving. -//========================================================= -void CHGrunt::SpeakSentence( void ) -{ - if( m_iSentence == HGRUNT_SENT_NONE ) - { - // no sentence cued up. - return; - } - - if( FOkToSpeak() ) - { - SENTENCEG_PlayRndSz( ENT( pev ), pGruntSentences[m_iSentence], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - JustSpoke(); - } -} - -//========================================================= -// IRelationship - overridden because Alien Grunts are -// Human Grunt's nemesis. -//========================================================= -int CHGrunt::IRelationship( CBaseEntity *pTarget ) -{ - if( FClassnameIs( pTarget->pev, "monster_alien_grunt" ) || ( FClassnameIs( pTarget->pev, "monster_gargantua" ) ) ) - { - return R_NM; - } - - return CSquadMonster::IRelationship( pTarget ); -} - -//========================================================= -// GibMonster - make gun fly through the air. -//========================================================= -void CHGrunt::GibMonster( void ) -{ - Vector vecGunPos; - Vector vecGunAngles; - - if( GetBodygroup( 2 ) != 2 ) - { - // throw a gun if the grunt has one - GetAttachment( 0, vecGunPos, vecGunAngles ); - - CBaseEntity *pGun; - - if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) ) - { - pGun = DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); - } - else - { - pGun = DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); - } - - if( pGun ) - { - pGun->pev->velocity = Vector( RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( 200, 300 ) ); - pGun->pev->avelocity = Vector( 0, RANDOM_FLOAT( 200, 400 ), 0 ); - } - - if( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER ) ) - { - pGun = DropItem( "ammo_ARgrenades", vecGunPos, vecGunAngles ); - if ( pGun ) - { - pGun->pev->velocity = Vector( RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( 200, 300 ) ); - pGun->pev->avelocity = Vector( 0, RANDOM_FLOAT( 200, 400 ), 0 ); - } - } - } - - CBaseMonster::GibMonster(); -} - -//========================================================= -// ISoundMask - Overidden for human grunts because they -// hear the DANGER sound that is made by hand grenades and -// other dangerous items. -//========================================================= -int CHGrunt::ISoundMask( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_DANGER; -} - -//========================================================= -// someone else is talking - don't speak -//========================================================= -BOOL CHGrunt::FOkToSpeak( void ) -{ - // if someone else is talking, don't speak - if( gpGlobals->time <= CTalkMonster::g_talkWaitTime ) - return FALSE; - - if( pev->spawnflags & SF_MONSTER_GAG ) - { - if( m_MonsterState != MONSTERSTATE_COMBAT ) - { - // no talking outside of combat if gagged. - return FALSE; - } - } - - // if player is not in pvs, don't speak - //if( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - // return FALSE; - - return TRUE; -} - -//========================================================= -//========================================================= -void CHGrunt::JustSpoke( void ) -{ - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT( 1.5, 2.0 ); - m_iSentence = HGRUNT_SENT_NONE; -} - -//========================================================= -// PrescheduleThink - this function runs after conditions -// are collected and before scheduling code is run. -//========================================================= -void CHGrunt::PrescheduleThink( void ) -{ - if( InSquad() && m_hEnemy != 0 ) - { - if( HasConditions( bits_COND_SEE_ENEMY ) ) - { - // update the squad's last enemy sighting time. - MySquadLeader()->m_flLastEnemySightTime = gpGlobals->time; - } - else - { - if( gpGlobals->time - MySquadLeader()->m_flLastEnemySightTime > 5 ) - { - // been a while since we've seen the enemy - MySquadLeader()->m_fEnemyEluded = TRUE; - } - } - } -} - -//========================================================= -// FCanCheckAttacks - this is overridden for human grunts -// because they can throw/shoot grenades when they can't see their -// target and the base class doesn't check attacks if the monster -// cannot see its enemy. -// -// !!!BUGBUG - this gets called before a 3-round burst is fired -// which means that a friendly can still be hit with up to 2 rounds. -// ALSO, grenades will not be tossed if there is a friendly in front, -// this is a bad bug. Friendly machine gun fire avoidance -// will unecessarily prevent the throwing of a grenade as well. -//========================================================= -BOOL CHGrunt::FCanCheckAttacks( void ) -{ - if( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CHGrunt::CheckMeleeAttack1( float flDot, float flDist ) -{ - CBaseMonster *pEnemy = 0; - - if( m_hEnemy != 0 ) - { - pEnemy = m_hEnemy->MyMonsterPointer(); - - if( !pEnemy ) - { - return FALSE; - } - } - - if( flDist <= 64 && flDot >= 0.7 && - pEnemy->Classify() != CLASS_ALIEN_BIOWEAPON && - pEnemy->Classify() != CLASS_PLAYER_BIOWEAPON ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 - overridden for HGrunt, cause -// FCanCheckAttacks() doesn't disqualify all attacks based -// on whether or not the enemy is occluded because unlike -// the base class, the HGrunt can attack when the enemy is -// occluded (throw grenade over wall, etc). We must -// disqualify the machine gun attack if the enemy is occluded. -//========================================================= -BOOL CHGrunt::CheckRangeAttack1( float flDot, float flDist ) -{ - if( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) - { - TraceResult tr; - - if( !m_hEnemy->IsPlayer() && flDist <= 64 ) - { - // kick nonclients, but don't shoot at them. - return FALSE; - } - - Vector vecSrc = GetGunPosition(); - - // verify that a bullet fired from the gun will hit the enemy before the world. - UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget( vecSrc ), ignore_monsters, ignore_glass, ENT( pev ), &tr ); - - if( tr.flFraction == 1.0 ) - { - return TRUE; - } - } - - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 - this checks the Grunt's grenade -// attack. -//========================================================= -BOOL CHGrunt::CheckRangeAttack2( float flDot, float flDist ) -{ - if( !FBitSet( pev->weapons, ( HGRUNT_HANDGRENADE | HGRUNT_GRENADELAUNCHER ) ) ) - { - return FALSE; - } - - // if the grunt isn't moving, it's ok to check. - if( m_flGroundSpeed != 0 ) - { - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - // assume things haven't changed too much since last time - if( gpGlobals->time < m_flNextGrenadeCheck ) - { - return m_fThrowGrenade; - } - - if( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) && m_hEnemy->pev->waterlevel == 0 && m_vecEnemyLKP.z > pev->absmax.z ) - { - //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to - // be grenaded. - // don't throw grenades at anything that isn't on the ground! - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - Vector vecTarget; - - if( FBitSet( pev->weapons, HGRUNT_HANDGRENADE ) ) - { - // find feet - if( RANDOM_LONG( 0, 1 ) ) - { - // magically know where they are - vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmin.z ); - } - else - { - // toss it to where you last saw them - vecTarget = m_vecEnemyLKP; - } - // vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - // vecTarget = vecTarget + m_hEnemy->pev->velocity * 2; - } - else - { - // find target - // vecTarget = m_hEnemy->BodyTarget( pev->origin ); - vecTarget = m_vecEnemyLKP + ( m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin ); - // estimate position - if( HasConditions( bits_COND_SEE_ENEMY ) ) - vecTarget = vecTarget + ( ( vecTarget - pev->origin).Length() / gSkillData.hgruntGrenadeSpeed ) * m_hEnemy->pev->velocity; - } - - // are any of my squad members near the intended grenade impact area? - if( InSquad() ) - { - if( SquadMemberInRange( vecTarget, 256 ) ) - { - // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - } - } - - if( ( vecTarget - pev->origin ).Length2D() <= 256 ) - { - // crap, I don't want to blow myself up - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - if( FBitSet( pev->weapons, HGRUNT_HANDGRENADE ) ) - { - Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 ); - - if( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - else - { - Vector vecToss = VecCheckThrow( pev, GetGunPosition(), vecTarget, gSkillData.hgruntGrenadeSpeed, 0.5 ); - - if( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 0.3; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - - return m_fThrowGrenade; -} - -//========================================================= -// TraceAttack - make sure we're not taking it in the helmet -//========================================================= -void CHGrunt::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - // check for helmet shot - if( ptr->iHitgroup == 11 ) - { - // make sure we're wearing one - if( GetBodygroup( 1 ) == HEAD_GRUNT && ( bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB ) ) ) - { - // absorb damage - flDamage -= 20; - if( flDamage <= 0 ) - { - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - flDamage = 0.01; - } - } - // it's head shot anyways - ptr->iHitgroup = HITGROUP_HEAD; - } - CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -//========================================================= -// TakeDamage - overridden for the grunt because the grunt -// needs to forget that he is in cover if he's hurt. (Obviously -// not in a safe place anymore). -//========================================================= -int CHGrunt::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - Forget( bits_MEMORY_INCOVER ); - - return CSquadMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHGrunt::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_IDLE: - ys = 150; - break; - case ACT_RUN: - ys = 150; - break; - case ACT_WALK: - ys = 180; - break; - case ACT_RANGE_ATTACK1: - ys = 120; - break; - case ACT_RANGE_ATTACK2: - ys = 120; - break; - case ACT_MELEE_ATTACK1: - ys = 120; - break; - case ACT_MELEE_ATTACK2: - ys = 120; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 180; - break; - case ACT_GLIDE: - case ACT_FLY: - ys = 30; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -void CHGrunt::IdleSound( void ) -{ - if( FOkToSpeak() && ( g_fGruntQuestion || RANDOM_LONG( 0, 1 ) ) ) - { - if( !g_fGruntQuestion ) - { - // ask question or make statement - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - // check in - SENTENCEG_PlayRndSz( ENT( pev ), "HG_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch ); - g_fGruntQuestion = 1; - break; - case 1: - // question - SENTENCEG_PlayRndSz( ENT( pev ), "HG_QUEST", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch ); - g_fGruntQuestion = 2; - break; - case 2: - // statement - SENTENCEG_PlayRndSz( ENT( pev ), "HG_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch ); - break; - } - } - else - { - switch( g_fGruntQuestion ) - { - case 1: - // check in - SENTENCEG_PlayRndSz( ENT( pev ), "HG_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch ); - break; - case 2: - // question - SENTENCEG_PlayRndSz( ENT( pev ), "HG_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch ); - break; - } - g_fGruntQuestion = 0; - } - JustSpoke(); - } -} - -//========================================================= -// CheckAmmo - overridden for the grunt because he actually -// uses ammo! (base class doesn't) -//========================================================= -void CHGrunt::CheckAmmo( void ) -{ - if( m_cAmmoLoaded <= 0 ) - { - SetConditions( bits_COND_NO_AMMO_LOADED ); - } -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHGrunt::Classify( void ) -{ - return CLASS_HUMAN_MILITARY; -} - -//========================================================= -//========================================================= -CBaseEntity *CHGrunt::Kick( void ) -{ - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin; - vecStart.z += pev->size.z * 0.5; - Vector vecEnd = vecStart + ( gpGlobals->v_forward * 70 ); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); - - if( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - return pEntity; - } - - return NULL; -} - -//========================================================= -// GetGunPosition return the end of the barrel -//========================================================= - -Vector CHGrunt::GetGunPosition() -{ - if( m_fStanding ) - { - return pev->origin + Vector( 0, 0, 60 ); - } - else - { - return pev->origin + Vector( 0, 0, 48 ); - } -} - -//========================================================= -// Shoot -//========================================================= -void CHGrunt::Shoot( void ) -{ - if( m_hEnemy == 0 ) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - UTIL_MakeVectors( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT( 40, 90 ) + gpGlobals->v_up * RANDOM_FLOAT( 75, 200 ) + gpGlobals->v_forward * RANDOM_FLOAT( -40, 40 ); - EjectBrass( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL ); - FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_MONSTER_MP5 ); // shoot +-5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - -//========================================================= -// Shoot -//========================================================= -void CHGrunt::Shotgun( void ) -{ - if( m_hEnemy == 0 ) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - UTIL_MakeVectors( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT( 40, 90 ) + gpGlobals->v_up * RANDOM_FLOAT( 75, 200 ) + gpGlobals->v_forward * RANDOM_FLOAT( -40, 40 ); - EjectBrass( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iShotgunShell, TE_BOUNCE_SHOTSHELL ); - FireBullets( gSkillData.hgruntShotgunPellets, vecShootOrigin, vecShootDir, VECTOR_CONE_15DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); // shoot +-7.5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHGrunt::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - Vector vecShootDir; - Vector vecShootOrigin; - - switch( pEvent->event ) - { - case HGRUNT_AE_DROP_GUN: - { - Vector vecGunPos; - Vector vecGunAngles; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - // switch to body group with no gun. - SetBodygroup( GUN_GROUP, GUN_NONE ); - - // now spawn a gun. - if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) ) - { - DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); - } - else - { - DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); - } - - if( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER ) ) - { - DropItem( "ammo_ARgrenades", BodyTarget( pev->origin ), vecGunAngles ); - } - } - break; - case HGRUNT_AE_RELOAD: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "hgrunt/gr_reload1.wav", 1, ATTN_NORM ); - m_cAmmoLoaded = m_cClipSize; - ClearConditions( bits_COND_NO_AMMO_LOADED ); - break; - case HGRUNT_AE_GREN_TOSS: - { - UTIL_MakeVectors( pev->angles ); - // CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector( 0, 0, 32 ), m_vecTossVelocity, 3.5 ); - CGrenade::ShootTimed( pev, GetGunPosition(), m_vecTossVelocity, 3.5 ); - - m_fThrowGrenade = FALSE; - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - // !!!LATER - when in a group, only try to throw grenade if ordered. - } - break; - case HGRUNT_AE_GREN_LAUNCH: - { - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/glauncher.wav", 0.8, ATTN_NORM ); - CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity ); - m_fThrowGrenade = FALSE; - if( g_iSkillLevel == SKILL_HARD ) - m_flNextGrenadeCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 );// wait a random amount of time before shooting again - else - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - } - break; - case HGRUNT_AE_GREN_DROP: - { - UTIL_MakeVectors( pev->angles ); - CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 17 - gpGlobals->v_right * 27 + gpGlobals->v_up * 6, g_vecZero, 3 ); - } - break; - case HGRUNT_AE_BURST1: - { - if( FBitSet( pev->weapons, HGRUNT_9MMAR ) ) - { - Shoot(); - - // the first round of the three round burst plays the sound and puts a sound in the world sound list. - if( RANDOM_LONG( 0, 1 ) ) - { - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "hgrunt/gr_mgun1.wav", 1, ATTN_NORM ); - } - else - { - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "hgrunt/gr_mgun2.wav", 1, ATTN_NORM ); - } - } - else - { - Shotgun(); - - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM ); - } - - CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); - } - break; - case HGRUNT_AE_BURST2: - case HGRUNT_AE_BURST3: - Shoot(); - break; - case HGRUNT_AE_KICK: - { - CBaseEntity *pHurt = Kick(); - - if( pHurt ) - { - // SOUND HERE! - UTIL_MakeVectors( pev->angles ); - pHurt->pev->punchangle.x = 15; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50; - pHurt->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB ); - } - } - break; - case HGRUNT_AE_CAUGHT_ENEMY: - { - if( FOkToSpeak() ) - { - SENTENCEG_PlayRndSz( ENT( pev ), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - JustSpoke(); - } - - } - break; - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHGrunt::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/hgrunt.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = 0; - pev->health = gSkillData.hgruntHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_flNextGrenadeCheck = gpGlobals->time + 1; - m_flNextPainTime = gpGlobals->time; - m_iSentence = HGRUNT_SENT_NONE; - - m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; - - m_fEnemyEluded = FALSE; - m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet. - - m_HackedGunPos = Vector( 0, 0, 55 ); - - if( pev->weapons == 0 ) - { - // initialize to original values - pev->weapons = HGRUNT_9MMAR | HGRUNT_HANDGRENADE; - // pev->weapons = HGRUNT_SHOTGUN; - // pev->weapons = HGRUNT_9MMAR | HGRUNT_GRENADELAUNCHER; - } - - if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) ) - { - SetBodygroup( GUN_GROUP, GUN_SHOTGUN ); - m_cClipSize = 8; - } - else - { - m_cClipSize = GRUNT_CLIP_SIZE; - } - m_cAmmoLoaded = m_cClipSize; - - if( RANDOM_LONG( 0, 99 ) < 80 ) - pev->skin = 0; // light skin - else - pev->skin = 1; // dark skin - - if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) ) - { - SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN ); - } - else if( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER ) ) - { - SetBodygroup( HEAD_GROUP, HEAD_M203 ); - pev->skin = 1; // alway dark skin - } - - CTalkMonster::g_talkWaitTime = 0; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHGrunt::Precache() -{ - PRECACHE_MODEL( "models/hgrunt.mdl" ); - - PRECACHE_SOUND( "hgrunt/gr_mgun1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_mgun2.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_die1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_die2.wav" ); - PRECACHE_SOUND( "hgrunt/gr_die3.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_pain1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain2.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain3.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain4.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain5.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_reload1.wav" ); - - PRECACHE_SOUND( "weapons/glauncher.wav" ); - - PRECACHE_SOUND( "weapons/sbarrel1.wav" ); - - PRECACHE_SOUND( "zombie/claw_miss2.wav" );// because we use the basemonster SWIPE animation event - - // get voice pitch - if( RANDOM_LONG( 0, 1 ) ) - m_voicePitch = 109 + RANDOM_LONG( 0, 7 ); - else - m_voicePitch = 100; - - m_iBrassShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shell - m_iShotgunShell = PRECACHE_MODEL( "models/shotgunshell.mdl" ); -} - -//========================================================= -// start task -//========================================================= -void CHGrunt::StartTask( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch( pTask->iTask ) - { - case TASK_GRUNT_CHECK_FIRE: - if( !NoFriendlyFire() ) - { - SetConditions( bits_COND_GRUNT_NOFIRE ); - } - TaskComplete(); - break; - case TASK_GRUNT_SPEAK_SENTENCE: - SpeakSentence(); - TaskComplete(); - break; - case TASK_WALK_PATH: - case TASK_RUN_PATH: - // grunt no longer assumes he is covered if he moves - Forget( bits_MEMORY_INCOVER ); - CSquadMonster::StartTask( pTask ); - break; - case TASK_RELOAD: - m_IdealActivity = ACT_RELOAD; - break; - case TASK_GRUNT_FACE_TOSS_DIR: - break; - case TASK_FACE_IDEAL: - case TASK_FACE_ENEMY: - CSquadMonster::StartTask( pTask ); - if( pev->movetype == MOVETYPE_FLY ) - { - m_IdealActivity = ACT_GLIDE; - } - break; - default: - CSquadMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CHGrunt::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_GRUNT_FACE_TOSS_DIR: - { - // project a point along the toss vector and turn to face that point. - MakeIdealYaw( pev->origin + m_vecTossVelocity * 64 ); - ChangeYaw( pev->yaw_speed ); - - if( FacingIdeal() ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - break; - } - default: - { - CSquadMonster::RunTask( pTask ); - break; - } - } -} - -//========================================================= -// PainSound -//========================================================= -void CHGrunt::PainSound( void ) -{ - if( gpGlobals->time > m_flNextPainTime ) - { -#if 0 - if( RANDOM_LONG( 0, 99 ) < 5 ) - { - // pain sentences are rare - if( FOkToSpeak() ) - { - SENTENCEG_PlayRndSz( ENT( pev ), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM ); - JustSpoke(); - return; - } - } -#endif - switch( RANDOM_LONG( 0, 6 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_pain3.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_pain4.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_pain5.wav", 1, ATTN_NORM ); - break; - case 3: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_pain1.wav", 1, ATTN_NORM ); - break; - case 4: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_pain2.wav", 1, ATTN_NORM ); - break; - } - - m_flNextPainTime = gpGlobals->time + 1; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CHGrunt::DeathSound( void ) -{ - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_die1.wav", 1, ATTN_IDLE ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_die2.wav", 1, ATTN_IDLE ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hgrunt/gr_die3.wav", 1, ATTN_IDLE ); - break; - } -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// GruntFail -//========================================================= -Task_t tlGruntFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slGruntFail[] = -{ - { - tlGruntFail, - ARRAYSIZE( tlGruntFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - 0, - "Grunt Fail" - }, -}; - -//========================================================= -// Grunt Combat Fail -//========================================================= -Task_t tlGruntCombatFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slGruntCombatFail[] = -{ - { - tlGruntCombatFail, - ARRAYSIZE( tlGruntCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Grunt Combat Fail" - }, -}; - -//========================================================= -// Victory dance! -//========================================================= -Task_t tlGruntVictoryDance[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, -}; - -Schedule_t slGruntVictoryDance[] = -{ - { - tlGruntVictoryDance, - ARRAYSIZE( tlGruntVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "GruntVictoryDance" - }, -}; - -//========================================================= -// Establish line of fire - move to a position that allows -// the grunt to attack. -//========================================================= -Task_t tlGruntEstablishLineOfFire[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_GRUNT_ELOF_FAIL }, - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_GRUNT_SPEAK_SENTENCE,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slGruntEstablishLineOfFire[] = -{ - { - tlGruntEstablishLineOfFire, - ARRAYSIZE( tlGruntEstablishLineOfFire ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "GruntEstablishLineOfFire" - }, -}; - -//========================================================= -// GruntFoundEnemy - grunt established sight with an enemy -// that was hiding from the squad. -//========================================================= -Task_t tlGruntFoundEnemy[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_SIGNAL1 }, -}; - -Schedule_t slGruntFoundEnemy[] = -{ - { - tlGruntFoundEnemy, - ARRAYSIZE( tlGruntFoundEnemy ), - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "GruntFoundEnemy" - }, -}; - -//========================================================= -// GruntCombatFace Schedule -//========================================================= -Task_t tlGruntCombatFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_SWEEP }, -}; - -Schedule_t slGruntCombatFace[] = -{ - { - tlGruntCombatFace1, - ARRAYSIZE( tlGruntCombatFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Combat Face" - }, -}; - -//========================================================= -// Suppressing fire - don't stop shooting until the clip is -// empty or grunt gets hurt. -//========================================================= -Task_t tlGruntSignalSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_SIGNAL2 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0}, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntSignalSuppress[] = -{ - { - tlGruntSignalSuppress, - ARRAYSIZE( tlGruntSignalSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - bits_SOUND_DANGER, - "SignalSuppress" - }, -}; - -Task_t tlGruntSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntSuppress[] = -{ - { - tlGruntSuppress, - ARRAYSIZE( tlGruntSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - bits_SOUND_DANGER, - "Suppress" - }, -}; - -//========================================================= -// grunt wait in cover - we don't allow danger or the ability -// to attack to break a grunt's run to cover schedule, but -// when a grunt is in cover, we do want them to attack if they can. -//========================================================= -Task_t tlGruntWaitInCover[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, -}; - -Schedule_t slGruntWaitInCover[] = -{ - { - tlGruntWaitInCover, - ARRAYSIZE( tlGruntWaitInCover ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - bits_SOUND_DANGER, - "GruntWaitInCover" - }, -}; - -//========================================================= -// run to cover. -// !!!BUGBUG - set a decent fail schedule here. -//========================================================= -Task_t tlGruntTakeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_GRUNT_TAKECOVER_FAILED }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_GRUNT_SPEAK_SENTENCE, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY }, -}; - -Schedule_t slGruntTakeCover[] = -{ - { - tlGruntTakeCover1, - ARRAYSIZE ( tlGruntTakeCover1 ), - 0, - 0, - "TakeCover" - }, -}; - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlGruntGrenadeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)99 }, - { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, - { TASK_PLAY_SEQUENCE, (float)ACT_SPECIAL_ATTACK1 }, - { TASK_CLEAR_MOVE_WAIT, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY }, -}; - -Schedule_t slGruntGrenadeCover[] = -{ - { - tlGruntGrenadeCover1, - ARRAYSIZE( tlGruntGrenadeCover1 ), - 0, - 0, - "GrenadeCover" - }, -}; - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlGruntTossGrenadeCover1[] = -{ - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slGruntTossGrenadeCover[] = -{ - { - tlGruntTossGrenadeCover1, - ARRAYSIZE( tlGruntTossGrenadeCover1 ), - 0, - 0, - "TossGrenadeCover" - }, -}; - -//========================================================= -// hide from the loudest sound source (to run from grenade) -//========================================================= -Task_t tlGruntTakeCoverFromBestSound[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_COWER },// duck and cover if cannot move from explosion - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slGruntTakeCoverFromBestSound[] = -{ - { - tlGruntTakeCoverFromBestSound, - ARRAYSIZE( tlGruntTakeCoverFromBestSound ), - 0, - 0, - "GruntTakeCoverFromBestSound" - }, -}; - -//========================================================= -// Grunt reload schedule -//========================================================= -Task_t tlGruntHideReload[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RELOAD }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RELOAD }, -}; - -Schedule_t slGruntHideReload[] = -{ - { - tlGruntHideReload, - ARRAYSIZE( tlGruntHideReload ), - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "GruntHideReload" - } -}; - -//========================================================= -// Do a turning sweep of the area -//========================================================= -Task_t tlGruntSweep[] = -{ - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slGruntSweep[] = -{ - { - tlGruntSweep, - ARRAYSIZE( tlGruntSweep ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_HEAR_SOUND, - bits_SOUND_WORLD |// sound flags - bits_SOUND_DANGER | - bits_SOUND_PLAYER, - "Grunt Sweep" - }, -}; - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack1A[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntRangeAttack1A[] = -{ - { - tlGruntRangeAttack1A, - ARRAYSIZE( tlGruntRangeAttack1A ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - bits_SOUND_DANGER, - "Range Attack1A" - }, -}; - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack1B[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_IDLE_ANGRY }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntRangeAttack1B[] = -{ - { - tlGruntRangeAttack1B, - ARRAYSIZE( tlGruntRangeAttack1B ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_GRUNT_NOFIRE | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER, - "Range Attack1B" - }, -}; - -//========================================================= -// secondary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_GRUNT_FACE_TOSS_DIR, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RANGE_ATTACK2 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY },// don't run immediately after throwing grenade. -}; - -Schedule_t slGruntRangeAttack2[] = -{ - { - tlGruntRangeAttack2, - ARRAYSIZE( tlGruntRangeAttack2 ), - 0, - 0, - "RangeAttack2" - }, -}; - -//========================================================= -// repel -//========================================================= -Task_t tlGruntRepel[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_GLIDE }, -}; - -Schedule_t slGruntRepel[] = -{ - { - tlGruntRepel, - ARRAYSIZE( tlGruntRepel ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel" - }, -}; - -//========================================================= -// repel -//========================================================= -Task_t tlGruntRepelAttack[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_FLY }, -}; - -Schedule_t slGruntRepelAttack[] = -{ - { - tlGruntRepelAttack, - ARRAYSIZE( tlGruntRepelAttack ), - bits_COND_ENEMY_OCCLUDED, - 0, - "Repel Attack" - }, -}; - -//========================================================= -// repel land -//========================================================= -Task_t tlGruntRepelLand[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_LAND }, - { TASK_GET_PATH_TO_LASTPOSITION, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slGruntRepelLand[] = -{ - { - tlGruntRepelLand, - ARRAYSIZE( tlGruntRepelLand ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel Land" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CHGrunt ) -{ - slGruntFail, - slGruntCombatFail, - slGruntVictoryDance, - slGruntEstablishLineOfFire, - slGruntFoundEnemy, - slGruntCombatFace, - slGruntSignalSuppress, - slGruntSuppress, - slGruntWaitInCover, - slGruntTakeCover, - slGruntGrenadeCover, - slGruntTossGrenadeCover, - slGruntTakeCoverFromBestSound, - slGruntHideReload, - slGruntSweep, - slGruntRangeAttack1A, - slGruntRangeAttack1B, - slGruntRangeAttack2, - slGruntRepel, - slGruntRepelAttack, - slGruntRepelLand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster ) - -//========================================================= -// SetActivity -//========================================================= -void CHGrunt::SetActivity( Activity NewActivity ) -{ - int iSequence = ACTIVITY_NOT_AVAILABLE; - //void *pmodel = GET_MODEL_PTR( ENT( pev ) ); - - switch( NewActivity ) - { - case ACT_RANGE_ATTACK1: - // grunt is either shooting standing or shooting crouched - if( FBitSet( pev->weapons, HGRUNT_9MMAR ) ) - { - if( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_mp5" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_mp5" ); - } - } - else - { - if( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_shotgun" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_shotgun" ); - } - } - break; - case ACT_RANGE_ATTACK2: - // grunt is going to a secondary long range attack. This may be a thrown - // grenade or fired grenade, we must determine which and pick proper sequence - if( pev->weapons & HGRUNT_HANDGRENADE ) - { - // get toss anim - iSequence = LookupSequence( "throwgrenade" ); - } - else - { - // get launch anim - iSequence = LookupSequence( "launchgrenade" ); - } - break; - case ACT_RUN: - if( pev->health <= HGRUNT_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity( ACT_RUN_HURT ); - } - else - { - iSequence = LookupActivity( NewActivity ); - } - break; - case ACT_WALK: - if( pev->health <= HGRUNT_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity( ACT_WALK_HURT ); - } - else - { - iSequence = LookupActivity( NewActivity ); - } - break; - case ACT_IDLE: - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - NewActivity = ACT_IDLE_ANGRY; - } - iSequence = LookupActivity( NewActivity ); - break; - default: - iSequence = LookupActivity( NewActivity ); - break; - } - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // Set to the desired anim, or default anim if the desired is not present - if( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if( pev->sequence != iSequence || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo(); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT( at_console, "%s has no sequence for act:%d\n", STRING( pev->classname ), NewActivity ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } -} - -//========================================================= -// Get Schedule! -//========================================================= -Schedule_t *CHGrunt::GetSchedule( void ) -{ - - // clear old sentence - m_iSentence = HGRUNT_SENT_NONE; - - // flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling. - if( pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE ) - { - if( pev->flags & FL_ONGROUND ) - { - // just landed - pev->movetype = MOVETYPE_STEP; - return GetScheduleOfType( SCHED_GRUNT_REPEL_LAND ); - } - else - { - // repel down a rope, - if( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType( SCHED_GRUNT_REPEL_ATTACK ); - else - return GetScheduleOfType( SCHED_GRUNT_REPEL ); - } - } - - // grunts place HIGH priority on running away from danger sounds. - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if( pSound ) - { - if( pSound->m_iType & bits_SOUND_DANGER ) - { - // dangerous sound nearby! - - //!!!KELLY - currently, this is the grunt's signal that a grenade has landed nearby, - // and the grunt should find cover from the blast - // good place for "SHIT!" or some other colorful verbal indicator of dismay. - // It's not safe to play a verbal order here "Scatter", etc cause - // this may only affect a single individual in a squad. - if( FOkToSpeak() ) - { - SENTENCEG_PlayRndSz( ENT( pev ), "HG_GREN", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - JustSpoke(); - } - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - /* - if( !HasConditions( bits_COND_SEE_ENEMY ) && ( pSound->m_iType & ( bits_SOUND_PLAYER | bits_SOUND_COMBAT ) ) ) - { - MakeIdealYaw( pSound->m_vecOrigin ); - } - */ - } - } - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { - // dead enemy - if( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster::GetSchedule(); - } - - // new enemy - if( HasConditions( bits_COND_NEW_ENEMY ) ) - { - if( InSquad() ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - - if( !IsLeader() ) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else - { - //!!!KELLY - the leader of a squad of grunts has just seen the player or a - // monster and has made it the squad's enemy. You - // can check pev->flags for FL_CLIENT to determine whether this is the player - // or a monster. He's going to immediately start - // firing, though. If you'd like, we can make an alternate "first sight" - // schedule where the leader plays a handsign anim - // that gives us enough time to hear a short sentence or spoken command - // before he starts pluggin away. - if( FOkToSpeak() )// && RANDOM_LONG( 0, 1 ) ) - { - if( ( m_hEnemy != 0 ) && m_hEnemy->IsPlayer() ) - // player - SENTENCEG_PlayRndSz( ENT( pev ), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - else if( ( m_hEnemy != 0 ) && - ( m_hEnemy->Classify() != CLASS_PLAYER_ALLY ) && - ( m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE ) && - ( m_hEnemy->Classify() != CLASS_MACHINE ) ) - // monster - SENTENCEG_PlayRndSz( ENT( pev ), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - - JustSpoke(); - } - - if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_GRUNT_SUPPRESS ); - } - else - { - return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - } - } - } - // no ammo - else if( HasConditions( bits_COND_NO_AMMO_LOADED ) ) - { - //!!!KELLY - this individual just realized he's out of bullet ammo. - // He's going to try to find cover to run to and reload, but rarely, if - // none is available, he'll drop and reload in the open here. - return GetScheduleOfType( SCHED_GRUNT_COVER_AND_RELOAD ); - } - // damaged just a little - else if( HasConditions( bits_COND_LIGHT_DAMAGE ) ) - { - // if hurt: - // 90% chance of taking cover - // 10% chance of flinch. - int iPercent = RANDOM_LONG( 0, 99 ); - - if( iPercent <= 90 && m_hEnemy != 0 ) - { - // only try to take cover if we actually have an enemy! - - //!!!KELLY - this grunt was hit and is going to run to cover. - if( FOkToSpeak() ) // && RANDOM_LONG( 0, 1 ) ) - { - //SENTENCEG_PlayRndSz( ENT( pev ), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - m_iSentence = HGRUNT_SENT_COVER; - //JustSpoke(); - } - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - } - // can kick - else if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - // can grenade launch - else if( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER) && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - // shoot a grenade if you can - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - // can shoot - else if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - if( InSquad() ) - { - // if the enemy has eluded the squad and a squad member has just located the enemy - // and the enemy does not see the squad member, issue a call to the squad to waste a - // little time and give the player a chance to turn. - if( MySquadLeader()->m_fEnemyEluded && !HasConditions( bits_COND_ENEMY_FACING_ME ) ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - return GetScheduleOfType( SCHED_GRUNT_FOUND_ENEMY ); - } - } - - if( OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - // try to take an available ENGAGE slot - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - else if( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - // throw a grenade if can and no engage slots are available - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - else - { - // hide! - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - } - // can't see enemy - else if( HasConditions( bits_COND_ENEMY_OCCLUDED ) ) - { - if( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - //!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc - if( FOkToSpeak() ) - { - SENTENCEG_PlayRndSz( ENT( pev ), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - JustSpoke(); - } - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - else if( OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - //!!!KELLY - grunt cannot see the enemy and has just decided to - // charge the enemy's position. - if( FOkToSpeak() )// && RANDOM_LONG( 0, 1 ) ) - { - //SENTENCEG_PlayRndSz( ENT( pev ), "HG_CHARGE", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - m_iSentence = HGRUNT_SENT_CHARGE; - //JustSpoke(); - } - - return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - else - { - //!!!KELLY - grunt is going to stay put for a couple seconds to see if - // the enemy wanders back out into the open, or approaches the - // grunt's covered position. Good place for a taunt, I guess? - if( FOkToSpeak() && RANDOM_LONG( 0, 1 ) ) - { - SENTENCEG_PlayRndSz( ENT( pev ), "HG_TAUNT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - JustSpoke(); - } - return GetScheduleOfType( SCHED_STANDOFF ); - } - } - - if( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - } - break; - default: - break; - } - - // no special cases here, call the base class - return CSquadMonster::GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t *CHGrunt::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - { - if( InSquad() ) - { - if( g_iSkillLevel == SKILL_HARD && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - if( FOkToSpeak() ) - { - SENTENCEG_PlayRndSz( ENT( pev ), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch ); - JustSpoke(); - } - return slGruntTossGrenadeCover; - } - else - { - return &slGruntTakeCover[0]; - } - } - else - { - if( RANDOM_LONG( 0, 1 ) ) - { - return &slGruntTakeCover[0]; - } - else - { - return &slGruntGrenadeCover[0]; - } - } - } - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - { - return &slGruntTakeCoverFromBestSound[0]; - } - case SCHED_GRUNT_TAKECOVER_FAILED: - { - if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - return GetScheduleOfType( SCHED_FAIL ); - } - break; - case SCHED_GRUNT_ELOF_FAIL: - { - // human grunt is unable to move to a position that allows him to attack the enemy. - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - break; - case SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE: - { - return &slGruntEstablishLineOfFire[0]; - } - break; - case SCHED_RANGE_ATTACK1: - { - // randomly stand or crouch - if( RANDOM_LONG( 0, 9 ) == 0 ) - m_fStanding = RANDOM_LONG( 0, 1 ); - - if( m_fStanding ) - return &slGruntRangeAttack1B[0]; - else - return &slGruntRangeAttack1A[0]; - } - case SCHED_RANGE_ATTACK2: - { - return &slGruntRangeAttack2[0]; - } - case SCHED_COMBAT_FACE: - { - return &slGruntCombatFace[0]; - } - case SCHED_GRUNT_WAIT_FACE_ENEMY: - { - return &slGruntWaitInCover[0]; - } - case SCHED_GRUNT_SWEEP: - { - return &slGruntSweep[0]; - } - case SCHED_GRUNT_COVER_AND_RELOAD: - { - return &slGruntHideReload[0]; - } - case SCHED_GRUNT_FOUND_ENEMY: - { - return &slGruntFoundEnemy[0]; - } - case SCHED_VICTORY_DANCE: - { - if( InSquad() ) - { - if( !IsLeader() ) - { - return &slGruntFail[0]; - } - } - - return &slGruntVictoryDance[0]; - } - case SCHED_GRUNT_SUPPRESS: - { - if( m_hEnemy->IsPlayer() && m_fFirstEncounter ) - { - m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy - return &slGruntSignalSuppress[0]; - } - else - { - return &slGruntSuppress[0]; - } - } - case SCHED_FAIL: - { - if( m_hEnemy != 0 ) - { - // grunt has an enemy, so pick a different default fail schedule most likely to help recover. - return &slGruntCombatFail[0]; - } - - return &slGruntFail[0]; - } - case SCHED_GRUNT_REPEL: - { - if( pev->velocity.z > -128 ) - pev->velocity.z -= 32; - return &slGruntRepel[0]; - } - case SCHED_GRUNT_REPEL_ATTACK: - { - if( pev->velocity.z > -128 ) - pev->velocity.z -= 32; - return &slGruntRepelAttack[0]; - } - case SCHED_GRUNT_REPEL_LAND: - { - return &slGruntRepelLand[0]; - } - default: - { - return CSquadMonster::GetScheduleOfType( Type ); - } - } -} - -//========================================================= -// CHGruntRepel - when triggered, spawns a monster_human_grunt -// repelling down a line. -//========================================================= - -class CHGruntRepel : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int m_iSpriteTexture; // Don't save, precache -}; - -LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel ) - -void CHGruntRepel::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - - SetUse( &CHGruntRepel::RepelUse ); -} - -void CHGruntRepel::Precache( void ) -{ - UTIL_PrecacheOther( "monster_human_grunt" ); - m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); -} - -void CHGruntRepel::RepelUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -4096.0 ), dont_ignore_monsters, ENT( pev ), &tr ); - /* - if( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP ) - return NULL; - */ - - CBaseEntity *pEntity = Create( "monster_human_grunt", pev->origin, pev->angles ); - CBaseMonster *pGrunt = pEntity->MyMonsterPointer(); - pGrunt->pev->movetype = MOVETYPE_FLY; - pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) ); - pGrunt->SetActivity( ACT_GLIDE ); - // UNDONE: position? - pGrunt->m_vecLastPosition = tr.vecEndPos; - - CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); - pBeam->PointEntInit( pev->origin + Vector( 0, 0, 112 ), pGrunt->entindex() ); - pBeam->SetFlags( BEAM_FSOLID ); - pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( &CBaseEntity::SUB_Remove ); - pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; - - UTIL_Remove( this ); -} - -//========================================================= -// DEAD HGRUNT PROP -//========================================================= -class CDeadHGrunt : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify( void ) { return CLASS_HUMAN_MILITARY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static const char *m_szPoses[3]; -}; - -const char *CDeadHGrunt::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; - -void CDeadHGrunt::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "pose" ) ) - { - m_iPose = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CDeadHGrunt ) - -//========================================================= -// ********** DeadHGrunt SPAWN ********** -//========================================================= -void CDeadHGrunt::Spawn( void ) -{ - PRECACHE_MODEL( "models/hgrunt.mdl" ); - SET_MODEL( ENT( pev ), "models/hgrunt.mdl" ); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - - if( pev->sequence == -1 ) - { - ALERT( at_console, "Dead hgrunt with bad pose\n" ); - } - - // Corpses have less health - pev->health = 8; - - // map old bodies onto new bodies - switch( pev->body ) - { - case 0: - // Grunt with Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); - SetBodygroup( GUN_GROUP, GUN_MP5 ); - break; - case 1: - // Commander with Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); - SetBodygroup( GUN_GROUP, GUN_MP5 ); - break; - case 2: - // Grunt no Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); - SetBodygroup( GUN_GROUP, GUN_NONE ); - break; - case 3: - // Commander no Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); - SetBodygroup( GUN_GROUP, GUN_NONE ); - break; - } - - MonsterInitDead(); -} diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp deleted file mode 100644 index 758ba7e9..00000000 --- a/dlls/hornet.cpp +++ /dev/null @@ -1,435 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Hornets -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "soundent.h" -#include "hornet.h" -#include "gamerules.h" - -int iHornetTrail; -int iHornetPuff; - -LINK_ENTITY_TO_CLASS( hornet, CHornet ) - -//========================================================= -// Save/Restore -//========================================================= -TYPEDESCRIPTION CHornet::m_SaveData[] = -{ - DEFINE_FIELD( CHornet, m_flStopAttack, FIELD_TIME ), - DEFINE_FIELD( CHornet, m_iHornetType, FIELD_INTEGER ), - DEFINE_FIELD( CHornet, m_flFlySpeed, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CHornet, CBaseMonster ) - -//========================================================= -// don't let hornets gib, ever. -//========================================================= -int CHornet::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // filter these bits a little. - bitsDamageType &= ~( DMG_ALWAYSGIB ); - bitsDamageType |= DMG_NEVERGIB; - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -//========================================================= -void CHornet::Spawn( void ) -{ - Precache(); - - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - pev->takedamage = DAMAGE_YES; - pev->flags |= FL_MONSTER; - pev->health = 1;// weak! - - if( g_pGameRules->IsMultiplayer() ) - { - // hornets don't live as long in multiplayer - m_flStopAttack = gpGlobals->time + 3.5; - } - else - { - m_flStopAttack = gpGlobals->time + 5.0; - } - - m_flFieldOfView = 0.9; // +- 25 degrees - - if( RANDOM_LONG( 1, 5 ) <= 2 ) - { - m_iHornetType = HORNET_TYPE_RED; - m_flFlySpeed = HORNET_RED_SPEED; - } - else - { - m_iHornetType = HORNET_TYPE_ORANGE; - m_flFlySpeed = HORNET_ORANGE_SPEED; - } - - SET_MODEL( ENT( pev ), "models/hornet.mdl" ); - UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) ); - - SetTouch( &CHornet::DieTouch ); - SetThink( &CHornet::StartTrack ); - - edict_t *pSoundEnt = pev->owner; - if( !pSoundEnt ) - pSoundEnt = edict(); - - if( !FNullEnt( pev->owner ) && ( pev->owner->v.flags & FL_CLIENT ) ) - { - pev->dmg = gSkillData.plrDmgHornet; - } - else - { - // no real owner, or owner isn't a client. - pev->dmg = gSkillData.monDmgHornet; - } - - pev->nextthink = gpGlobals->time + 0.1; - ResetSequenceInfo(); -} - -void CHornet::Precache() -{ - PRECACHE_MODEL( "models/hornet.mdl" ); - - PRECACHE_SOUND( "agrunt/ag_fire1.wav" ); - PRECACHE_SOUND( "agrunt/ag_fire2.wav" ); - PRECACHE_SOUND( "agrunt/ag_fire3.wav" ); - - PRECACHE_SOUND( "hornet/ag_buzz1.wav" ); - PRECACHE_SOUND( "hornet/ag_buzz2.wav" ); - PRECACHE_SOUND( "hornet/ag_buzz3.wav" ); - - PRECACHE_SOUND( "hornet/ag_hornethit1.wav" ); - PRECACHE_SOUND( "hornet/ag_hornethit2.wav" ); - PRECACHE_SOUND( "hornet/ag_hornethit3.wav" ); - - iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" ); - iHornetTrail = PRECACHE_MODEL( "sprites/laserbeam.spr" ); -} - -//========================================================= -// hornets will never get mad at each other, no matter who the owner is. -//========================================================= -int CHornet::IRelationship( CBaseEntity *pTarget ) -{ - if( pTarget->pev->modelindex == pev->modelindex ) - { - return R_NO; - } - - return CBaseMonster::IRelationship( pTarget ); -} - -//========================================================= -// ID's Hornet as their owner -//========================================================= -int CHornet::Classify( void ) -{ - if( pev->owner && pev->owner->v.flags & FL_CLIENT ) - { - return CLASS_PLAYER_BIOWEAPON; - } - - return CLASS_ALIEN_BIOWEAPON; -} - -//========================================================= -// StartTrack - starts a hornet out tracking its target -//========================================================= -void CHornet::StartTrack( void ) -{ - IgniteTrail(); - - SetTouch( &CHornet::TrackTouch ); - SetThink( &CHornet::TrackTarget ); - - pev->nextthink = gpGlobals->time + 0.1; -} - -//========================================================= -// StartDart - starts a hornet out just flying straight. -//========================================================= -void CHornet::StartDart( void ) -{ - IgniteTrail(); - - SetTouch( &CHornet::DartTouch ); - - SetThink( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 4; -} - -void CHornet::IgniteTrail( void ) -{ -/* - - ted's suggested trail colors: - -r161 -g25 -b97 - -r173 -g39 -b14 - -old colors - case HORNET_TYPE_RED: - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 0 ); // r, g, b - break; - case HORNET_TYPE_ORANGE: - WRITE_BYTE( 0 ); // r, g, b - WRITE_BYTE( 100 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - break; - -*/ - // trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT( entindex() ); // entity - WRITE_SHORT( iHornetTrail ); // model - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 2 ); // width - - switch( m_iHornetType ) - { - case HORNET_TYPE_RED: - WRITE_BYTE( 179 ); // r, g, b - WRITE_BYTE( 39 ); // r, g, b - WRITE_BYTE( 14 ); // r, g, b - break; - case HORNET_TYPE_ORANGE: - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 0 ); // r, g, b - break; - } - - WRITE_BYTE( 128 ); // brightness - MESSAGE_END(); -} - -//========================================================= -// Hornet is flying, gently tracking target -//========================================================= -void CHornet::TrackTarget( void ) -{ - Vector vecFlightDir; - Vector vecDirToEnemy; - float flDelta; - - StudioFrameAdvance(); - - if( gpGlobals->time > m_flStopAttack ) - { - SetTouch( NULL ); - SetThink( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - return; - } - - // UNDONE: The player pointer should come back after returning from another level - if( m_hEnemy == 0 ) - { - // enemy is dead. - Look( 512 ); - m_hEnemy = BestVisibleEnemy(); - } - - if( m_hEnemy != 0 && FVisible( m_hEnemy ) ) - { - m_vecEnemyLKP = m_hEnemy->BodyTarget( pev->origin ); - } - else - { - m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1; - } - - vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize(); - - if( pev->velocity.Length() < 0.1 ) - vecFlightDir = vecDirToEnemy; - else - vecFlightDir = pev->velocity.Normalize(); - - // measure how far the turn is, the wider the turn, the slow we'll go this time. - flDelta = DotProduct( vecFlightDir, vecDirToEnemy ); - - if( flDelta < 0.5 ) - { - // hafta turn wide again. play sound - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); - break; - } - } - - if( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED ) - { - // no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far. - flDelta = 0.25; - } - - pev->velocity = ( vecFlightDir + vecDirToEnemy ).Normalize(); - - if( pev->owner && ( pev->owner->v.flags & FL_MONSTER ) ) - { - // random pattern only applies to hornets fired by monsters, not players. - pev->velocity.x += RANDOM_FLOAT( -0.10, 0.10 );// scramble the flight dir a bit. - pev->velocity.y += RANDOM_FLOAT( -0.10, 0.10 ); - pev->velocity.z += RANDOM_FLOAT( -0.10, 0.10 ); - } - - switch( m_iHornetType ) - { - case HORNET_TYPE_RED: - pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); - break; - case HORNET_TYPE_ORANGE: - pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn. - pev->nextthink = gpGlobals->time + 0.1;// fixed think time - break; - } - - pev->angles = UTIL_VecToAngles( pev->velocity ); - - pev->solid = SOLID_BBOX; - - // if hornet is close to the enemy, jet in a straight line for a half second. - // (only in the single player game) - if( m_hEnemy != 0 && !g_pGameRules->IsMultiplayer() ) - { - if( flDelta >= 0.4 && ( pev->origin - m_vecEnemyLKP ).Length() <= 300 ) - { - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( pev->origin.x ); // pos - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( iHornetPuff ); // model - // WRITE_BYTE( 0 ); // life * 10 - WRITE_BYTE( 2 ); // size * 10 - WRITE_BYTE( 128 ); // brightness - MESSAGE_END(); - - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); - break; - } - pev->velocity = pev->velocity * 2; - pev->nextthink = gpGlobals->time + 1.0; - // don't attack again - m_flStopAttack = gpGlobals->time; - } - } -} - -//========================================================= -// Tracking Hornet hit something -//========================================================= -void CHornet::TrackTouch( CBaseEntity *pOther ) -{ - if( pOther->edict() == pev->owner || pOther->pev->modelindex == pev->modelindex ) - { - // bumped into the guy that shot it. - pev->solid = SOLID_NOT; - return; - } - - if( IRelationship( pOther ) <= R_NO ) - { - // hit something we don't want to hurt, so turn around. - - pev->velocity = pev->velocity.Normalize(); - - pev->velocity.x *= -1; - pev->velocity.y *= -1; - - pev->origin = pev->origin + pev->velocity * 4; // bounce the hornet off a bit. - pev->velocity = pev->velocity * m_flFlySpeed; - - return; - } - - DieTouch( pOther ); -} - -void CHornet::DartTouch( CBaseEntity *pOther ) -{ - DieTouch( pOther ); -} - -void CHornet::DieTouch( CBaseEntity *pOther ) -{ - if( pOther && pOther->pev->takedamage && pev->owner ) - { - // do the damage - switch( RANDOM_LONG( 0, 2 ) ) - { - // buzz when you plug someone - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_hornethit1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_hornethit2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "hornet/ag_hornethit3.wav", 1, ATTN_NORM ); - break; - } - - pOther->TakeDamage( pev, VARS( pev->owner ), pev->dmg, DMG_BULLET ); - } - - pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid - pev->solid = SOLID_NOT; - - SetThink( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! -} diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp deleted file mode 100644 index cc63d6db..00000000 --- a/dlls/hornetgun.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "hornet.h" -#include "gamerules.h" - -enum hgun_e -{ - HGUN_IDLE1 = 0, - HGUN_FIDGETSWAY, - HGUN_FIDGETSHAKE, - HGUN_DOWN, - HGUN_UP, - HGUN_SHOOT -}; - -enum firemode_e -{ - FIREMODE_TRACK = 0, - FIREMODE_FAST -}; - -LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun ) - -BOOL CHgun::IsUseable( void ) -{ - return TRUE; -} - -void CHgun::Spawn() -{ - Precache(); - m_iId = WEAPON_HORNETGUN; - SET_MODEL( ENT( pev ), "models/w_hgun.mdl" ); - - m_iDefaultAmmo = HIVEHAND_DEFAULT_GIVE; - m_iFirePhase = 0; - - FallInit();// get ready to fall down. -} - -void CHgun::Precache( void ) -{ - PRECACHE_MODEL( "models/v_hgun.mdl" ); - PRECACHE_MODEL( "models/w_hgun.mdl" ); - PRECACHE_MODEL( "models/p_hgun.mdl" ); - - m_usHornetFire = PRECACHE_EVENT( 1, "events/firehornet.sc" ); - - UTIL_PrecacheOther( "hornet" ); -} - -int CHgun::AddToPlayer( CBasePlayer *pPlayer ) -{ - if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { -#ifndef CLIENT_DLL - if( g_pGameRules->IsMultiplayer() ) - { - // in multiplayer, all hivehands come full. - pPlayer->m_rgAmmo[PrimaryAmmoIndex()] = HORNET_MAX_CARRY; - } -#endif - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -int CHgun::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "Hornets"; - p->iMaxAmmo1 = HORNET_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 3; - p->iId = m_iId = WEAPON_HORNETGUN; - p->iFlags = ITEM_FLAG_NOAUTOSWITCHEMPTY | ITEM_FLAG_NOAUTORELOAD; - p->iWeight = HORNETGUN_WEIGHT; - - return 1; -} - -BOOL CHgun::Deploy() -{ - return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" ); -} - -void CHgun::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( HGUN_DOWN ); - - //!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either. - if( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) - { - m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] = 1; - } -} - -void CHgun::PrimaryAttack() -{ - Reload(); - - if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - { - return; - } -#ifndef CLIENT_DLL - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - - CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pHornet->pev->velocity = gpGlobals->v_forward * 300; - - m_flRechargeTime = gpGlobals->time + 0.5; -#endif - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_TRACK, 0, 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.25; - - if( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) - { - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; - } - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - -void CHgun::SecondaryAttack( void ) -{ - Reload(); - - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - return; - } - - //Wouldn't be a bad idea to completely predict these, since they fly so fast... -#ifndef CLIENT_DLL - CBaseEntity *pHornet; - Vector vecSrc; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - - vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12; - - m_iFirePhase++; - switch( m_iFirePhase ) - { - case 1: - vecSrc = vecSrc + gpGlobals->v_up * 8; - break; - case 2: - vecSrc = vecSrc + gpGlobals->v_up * 8; - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 3: - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 4: - vecSrc = vecSrc + gpGlobals->v_up * -8; - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 5: - vecSrc = vecSrc + gpGlobals->v_up * -8; - break; - case 6: - vecSrc = vecSrc + gpGlobals->v_up * -8; - vecSrc = vecSrc + gpGlobals->v_right * -8; - break; - case 7: - vecSrc = vecSrc + gpGlobals->v_right * -8; - break; - case 8: - vecSrc = vecSrc + gpGlobals->v_up * 8; - vecSrc = vecSrc + gpGlobals->v_right * -8; - m_iFirePhase = 0; - break; - } - - pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pHornet->pev->velocity = gpGlobals->v_forward * 1200; - pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity ); - - pHornet->SetThink( &CHornet::StartDart ); - - m_flRechargeTime = gpGlobals->time + 0.5; -#endif - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 ); - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - -void CHgun::Reload( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= HORNET_MAX_CARRY ) - return; - - while( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < HORNET_MAX_CARRY && m_flRechargeTime < gpGlobals->time ) - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]++; - m_flRechargeTime += 0.5; - } -} - -void CHgun::WeaponIdle( void ) -{ - Reload(); - - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if( flRand <= 0.75 ) - { - iAnim = HGUN_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * ( 2 ); - } - else if( flRand <= 0.875 ) - { - iAnim = HGUN_FIDGETSWAY; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; - } - else - { - iAnim = HGUN_FIDGETSHAKE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 35.0 / 16.0; - } - SendWeaponAnim( iAnim ); -} -#endif diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp deleted file mode 100644 index cedee258..00000000 --- a/dlls/houndeye.cpp +++ /dev/null @@ -1,1295 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Houndeye - spooky sonic dog. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "animation.h" -#include "nodes.h" -#include "squadmonster.h" -#include "soundent.h" -#include "game.h" - -extern CGraph WorldGraph; - -// houndeye does 20 points of damage spread over a sphere 384 units in diameter, and each additional -// squad member increases the BASE damage by 110%, per the spec. -#define HOUNDEYE_MAX_SQUAD_SIZE 4 -#define HOUNDEYE_MAX_ATTACK_RADIUS 384 -#define HOUNDEYE_SQUAD_BONUS (float)1.1 - -#define HOUNDEYE_EYE_FRAMES 4 // how many different switchable maps for the eye - -#define HOUNDEYE_SOUND_STARTLE_VOLUME 128 // how loud a sound has to be to badly scare a sleeping houndeye - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_HOUND_CLOSE_EYE = LAST_COMMON_TASK + 1, - TASK_HOUND_OPEN_EYE, - TASK_HOUND_THREAT_DISPLAY, - TASK_HOUND_FALL_ASLEEP, - TASK_HOUND_WAKE_UP, - TASK_HOUND_HOP_BACK -}; - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_HOUND_AGITATED = LAST_COMMON_SCHEDULE + 1, - SCHED_HOUND_HOP_RETREAT, - SCHED_HOUND_FAIL -}; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HOUND_AE_WARN 1 -#define HOUND_AE_STARTATTACK 2 -#define HOUND_AE_THUMP 3 -#define HOUND_AE_ANGERSOUND1 4 -#define HOUND_AE_ANGERSOUND2 5 -#define HOUND_AE_HOPBACK 6 -#define HOUND_AE_CLOSE_EYE 7 - -class CHoundeye : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void SetYawSpeed( void ); - void WarmUpSound( void ); - void AlertSound( void ); - void DeathSound( void ); - void WarnSound( void ); - void PainSound( void ); - void IdleSound( void ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - void SonicAttack( void ); - void PrescheduleThink( void ); - void SetActivity( Activity NewActivity ); - void WriteBeamColor( void ); - BOOL CheckRangeAttack1( float flDot, float flDist ); - BOOL FValidateHintType( short sHint ); - BOOL FCanActiveIdle( void ); - Schedule_t *GetScheduleOfType( int Type ); - Schedule_t *GetSchedule( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CUSTOM_SCHEDULES - static TYPEDESCRIPTION m_SaveData[]; - - int m_iSpriteTexture; - BOOL m_fAsleep;// some houndeyes sleep in idle mode if this is set, the houndeye is lying down - BOOL m_fDontBlink;// don't try to open/close eye if this bit is set! - Vector m_vecPackCenter; // the center of the pack. The leader maintains this by averaging the origins of all pack members. -}; - -LINK_ENTITY_TO_CLASS( monster_houndeye, CHoundeye ) - -TYPEDESCRIPTION CHoundeye::m_SaveData[] = -{ - DEFINE_FIELD( CHoundeye, m_iSpriteTexture, FIELD_INTEGER ), - DEFINE_FIELD( CHoundeye, m_fAsleep, FIELD_BOOLEAN ), - DEFINE_FIELD( CHoundeye, m_fDontBlink, FIELD_BOOLEAN ), - DEFINE_FIELD( CHoundeye, m_vecPackCenter, FIELD_POSITION_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CHoundeye, CSquadMonster ) - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHoundeye::Classify( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// FValidateHintType -//========================================================= -BOOL CHoundeye::FValidateHintType( short sHint ) -{ - size_t i; - - static short sHoundHints[] = - { - HINT_WORLD_MACHINERY, - HINT_WORLD_BLINKING_LIGHT, - HINT_WORLD_HUMAN_BLOOD, - HINT_WORLD_ALIEN_BLOOD, - }; - - for( i = 0; i < ARRAYSIZE( sHoundHints ); i++ ) - { - if( sHoundHints[i] == sHint ) - { - return TRUE; - } - } - - ALERT( at_aiconsole, "Couldn't validate hint type" ); - return FALSE; -} - -//========================================================= -// FCanActiveIdle -//========================================================= -BOOL CHoundeye::FCanActiveIdle( void ) -{ - if( InSquad() ) - { - CSquadMonster *pSquadLeader = MySquadLeader(); - - for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember( i ); - - if( pMember != NULL && pMember != this && pMember->m_iHintNode != NO_NODE ) - { - // someone else in the group is active idling right now! - return FALSE; - } - } - - return TRUE; - } - - return TRUE; -} - -//========================================================= -// CheckRangeAttack1 - overridden for houndeyes so that they -// try to get within half of their max attack radius before -// attacking, so as to increase their chances of doing damage. -//========================================================= -BOOL CHoundeye::CheckRangeAttack1( float flDot, float flDist ) -{ - if( flDist <= ( HOUNDEYE_MAX_ATTACK_RADIUS * 0.5 ) && flDot >= 0.3 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHoundeye::SetYawSpeed( void ) -{ - int ys; - - ys = 90; - - switch( m_Activity ) - { - case ACT_CROUCHIDLE://sleeping! - ys = 0; - break; - case ACT_IDLE: - ys = 60; - break; - case ACT_WALK: - case ACT_RUN: - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - break; - default: - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// SetActivity -//========================================================= -void CHoundeye::SetActivity( Activity NewActivity ) -{ - int iSequence; - - if( NewActivity == m_Activity ) - return; - - if( m_MonsterState == MONSTERSTATE_COMBAT && NewActivity == ACT_IDLE && RANDOM_LONG( 0, 1 ) ) - { - // play pissed idle. - iSequence = LookupSequence( "madidle" ); - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // In case someone calls this with something other than the ideal activity - m_IdealActivity = m_Activity; - - // Set to the desired anim, or default anim if the desired is not present - if( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - pev->sequence = iSequence; // Set to the reset anim (if it's there) - pev->frame = 0; // FIX: frame counter shouldn't be reset when its the same activity as before - ResetSequenceInfo(); - SetYawSpeed(); - } - } - else - { - CSquadMonster::SetActivity( NewActivity ); - } -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHoundeye::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case HOUND_AE_WARN: - // do stuff for this event. - WarnSound(); - break; - case HOUND_AE_STARTATTACK: - WarmUpSound(); - break; - case HOUND_AE_HOPBACK: - { - float flGravity = g_psv_gravity->value; - - pev->flags &= ~FL_ONGROUND; - - pev->velocity = gpGlobals->v_forward * -200; - pev->velocity.z += ( 0.6 * flGravity ) * 0.5; - break; - } - case HOUND_AE_THUMP: - // emit the shockwaves - SonicAttack(); - break; - case HOUND_AE_ANGERSOUND1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM ); - break; - case HOUND_AE_ANGERSOUND2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_pain1.wav", 1, ATTN_NORM ); - break; - case HOUND_AE_CLOSE_EYE: - if( !m_fDontBlink ) - { - pev->skin = HOUNDEYE_EYE_FRAMES - 1; - } - break; - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHoundeye::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/houndeye.mdl" ); - UTIL_SetSize( pev, Vector( -16, -16, 0 ), Vector( 16, 16, 36 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_YELLOW; - pev->effects = 0; - pev->health = gSkillData.houndeyeHealth; - pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_fAsleep = FALSE; // everyone spawns awake - m_fDontBlink = FALSE; - m_afCapability |= bits_CAP_SQUAD; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHoundeye::Precache() -{ - PRECACHE_MODEL( "models/houndeye.mdl" ); - - PRECACHE_SOUND( "houndeye/he_alert1.wav" ); - PRECACHE_SOUND( "houndeye/he_alert2.wav" ); - PRECACHE_SOUND( "houndeye/he_alert3.wav" ); - - PRECACHE_SOUND( "houndeye/he_die1.wav" ); - PRECACHE_SOUND( "houndeye/he_die2.wav" ); - PRECACHE_SOUND( "houndeye/he_die3.wav" ); - - PRECACHE_SOUND( "houndeye/he_idle1.wav" ); - PRECACHE_SOUND( "houndeye/he_idle2.wav" ); - PRECACHE_SOUND( "houndeye/he_idle3.wav" ); - - PRECACHE_SOUND( "houndeye/he_hunt1.wav" ); - PRECACHE_SOUND( "houndeye/he_hunt2.wav" ); - PRECACHE_SOUND( "houndeye/he_hunt3.wav" ); - - PRECACHE_SOUND( "houndeye/he_pain1.wav" ); - PRECACHE_SOUND( "houndeye/he_pain3.wav" ); - PRECACHE_SOUND( "houndeye/he_pain4.wav" ); - PRECACHE_SOUND( "houndeye/he_pain5.wav" ); - - PRECACHE_SOUND( "houndeye/he_attack1.wav" ); - PRECACHE_SOUND( "houndeye/he_attack3.wav" ); - - PRECACHE_SOUND( "houndeye/he_blast1.wav" ); - PRECACHE_SOUND( "houndeye/he_blast2.wav" ); - PRECACHE_SOUND( "houndeye/he_blast3.wav" ); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/shockwave.spr" ); -} - -//========================================================= -// IdleSound -//========================================================= -void CHoundeye::IdleSound( void ) -{ - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_idle1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_idle2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_idle3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// IdleSound -//========================================================= -void CHoundeye::WarmUpSound( void ) -{ - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "houndeye/he_attack1.wav", 0.7, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "houndeye/he_attack3.wav", 0.7, ATTN_NORM ); - break; - } -} - -//========================================================= -// WarnSound -//========================================================= -void CHoundeye::WarnSound( void ) -{ - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_hunt1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_hunt2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_hunt3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// AlertSound -//========================================================= -void CHoundeye::AlertSound( void ) -{ - if( InSquad() && !IsLeader() ) - { - return; // only leader makes ALERT sound. - } - - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_alert1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_alert2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_alert3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CHoundeye::DeathSound( void ) -{ - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_die1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_die2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_die3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// PainSound -//========================================================= -void CHoundeye::PainSound( void ) -{ - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_pain4.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "houndeye/he_pain5.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// WriteBeamColor - writes a color vector to the network -// based on the size of the group. -//========================================================= -void CHoundeye::WriteBeamColor( void ) -{ - BYTE bRed, bGreen, bBlue; - - if( InSquad() ) - { - switch( SquadCount() ) - { - case 2: - // no case for 0 or 1, cause those are impossible for monsters in Squads. - bRed = 101; - bGreen = 133; - bBlue = 221; - break; - case 3: - bRed = 67; - bGreen = 85; - bBlue = 255; - break; - case 4: - bRed = 62; - bGreen = 33; - bBlue = 211; - break; - default: - ALERT( at_aiconsole, "Unsupported Houndeye SquadSize!\n" ); - bRed = 188; - bGreen = 220; - bBlue = 255; - break; - } - } - else - { - // solo houndeye - weakest beam - bRed = 188; - bGreen = 220; - bBlue = 255; - } - - WRITE_BYTE( bRed ); - WRITE_BYTE( bGreen ); - WRITE_BYTE( bBlue ); -} - -//========================================================= -// SonicAttack -//========================================================= -void CHoundeye::SonicAttack( void ) -{ - float flAdjustedDamage; - float flDist; - - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "houndeye/he_blast1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "houndeye/he_blast2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "houndeye/he_blast3.wav", 1, ATTN_NORM ); - break; - } - - // blast circles - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z + 16 ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z + 16 + HOUNDEYE_MAX_ATTACK_RADIUS / .2 ); // reach damage radius over .3 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 2 ); // life - WRITE_BYTE( 16 ); // width - WRITE_BYTE( 0 ); // noise - - WriteBeamColor(); - - WRITE_BYTE( 255 ); //brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z + 16 ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z + 16 + ( HOUNDEYE_MAX_ATTACK_RADIUS / 2 ) / .2 ); // reach damage radius over .3 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 2 ); // life - WRITE_BYTE( 16 ); // width - WRITE_BYTE( 0 ); // noise - - WriteBeamColor(); - - WRITE_BYTE( 255 ); //brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - CBaseEntity *pEntity = NULL; - // iterate on all entities in the vicinity. - while( ( pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, HOUNDEYE_MAX_ATTACK_RADIUS ) ) != NULL ) - { - if( pEntity->pev->takedamage != DAMAGE_NO ) - { - if( !FClassnameIs( pEntity->pev, "monster_houndeye" ) ) - { - // houndeyes don't hurt other houndeyes with their attack - // houndeyes do FULL damage if the ent in question is visible. Half damage otherwise. - // This means that you must get out of the houndeye's attack range entirely to avoid damage. - // Calculate full damage first - - if( SquadCount() > 1 ) - { - // squad gets attack bonus. - flAdjustedDamage = gSkillData.houndeyeDmgBlast + gSkillData.houndeyeDmgBlast * ( HOUNDEYE_SQUAD_BONUS * ( SquadCount() - 1 ) ); - } - else - { - // solo - flAdjustedDamage = gSkillData.houndeyeDmgBlast; - } - - flDist = ( pEntity->Center() - pev->origin ).Length(); - - flAdjustedDamage -= ( flDist / HOUNDEYE_MAX_ATTACK_RADIUS ) * flAdjustedDamage; - - if( !FVisible( pEntity ) ) - { - if( pEntity->IsPlayer() ) - { - // if this entity is a client, and is not in full view, inflict half damage. We do this so that players still - // take the residual damage if they don't totally leave the houndeye's effective radius. We restrict it to clients - // so that monsters in other parts of the level don't take the damage and get pissed. - flAdjustedDamage *= 0.5; - } - else if( !FClassnameIs( pEntity->pev, "func_breakable" ) && !FClassnameIs( pEntity->pev, "func_pushable" ) ) - { - // do not hurt nonclients through walls, but allow damage to be done to breakables - flAdjustedDamage = 0; - } - } - - //ALERT ( at_aiconsole, "Damage: %f\n", flAdjustedDamage ); - - if( flAdjustedDamage > 0 ) - { - pEntity->TakeDamage( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB ); - } - } - } - } -} - -//========================================================= -// start task -//========================================================= -void CHoundeye::StartTask( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch( pTask->iTask ) - { - case TASK_HOUND_FALL_ASLEEP: - { - m_fAsleep = TRUE; // signal that hound is lying down (must stand again before doing anything else!) - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_WAKE_UP: - { - m_fAsleep = FALSE; // signal that hound is standing again - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_OPEN_EYE: - { - m_fDontBlink = FALSE; // turn blinking back on and that code will automatically open the eye - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_CLOSE_EYE: - { - pev->skin = 0; - m_fDontBlink = TRUE; // tell blink code to leave the eye alone. - break; - } - case TASK_HOUND_THREAT_DISPLAY: - { - m_IdealActivity = ACT_IDLE_ANGRY; - break; - } - case TASK_HOUND_HOP_BACK: - { - m_IdealActivity = ACT_LEAP; - break; - } - case TASK_RANGE_ATTACK1: - { - m_IdealActivity = ACT_RANGE_ATTACK1; - -/* - if( InSquad() ) - { - // see if there is a battery to connect to. - CSquadMonster *pSquad = m_pSquadLeader; - - while( pSquad ) - { - if( pSquad->m_iMySlot == bits_SLOT_HOUND_BATTERY ) - { - // draw a beam. - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( ENTINDEX( this->edict() ) ); - WRITE_SHORT( ENTINDEX( pSquad->edict() ) ); - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 40 ); // width - WRITE_BYTE( 10 ); // noise - WRITE_BYTE( 0 ); // r, g, b - WRITE_BYTE( 50 ); // r, g, b - WRITE_BYTE( 250); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); - break; - } - - pSquad = pSquad->m_pSquadNext; - } - } -*/ - break; - } - case TASK_SPECIAL_ATTACK1: - { - m_IdealActivity = ACT_SPECIAL_ATTACK1; - break; - } - case TASK_GUARD: - { - m_IdealActivity = ACT_GUARD; - break; - } - default: - { - CSquadMonster::StartTask( pTask ); - break; - } - } -} - -//========================================================= -// RunTask -//========================================================= -void CHoundeye::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_HOUND_THREAT_DISPLAY: - { - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - case TASK_HOUND_CLOSE_EYE: - { - if( pev->skin < HOUNDEYE_EYE_FRAMES - 1 ) - { - pev->skin++; - } - break; - } - case TASK_HOUND_HOP_BACK: - { - if( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - case TASK_SPECIAL_ATTACK1: - { - pev->skin = RANDOM_LONG( 0, HOUNDEYE_EYE_FRAMES - 1 ); - - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - float life; - life = ( ( 255 - pev->frame ) / ( pev->framerate * m_flFrameRate ) ); - if( life < 0.1 ) - life = 0.1; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_IMPLOSION ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z + 16 ); - WRITE_BYTE( 50 * life + 100 ); // radius - WRITE_BYTE( pev->frame / 25.0 ); // count - WRITE_BYTE( life * 10 ); // life - MESSAGE_END(); - - if( m_fSequenceFinished ) - { - SonicAttack(); - TaskComplete(); - } - break; - } - default: - { - CSquadMonster::RunTask( pTask ); - break; - } - } -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CHoundeye::PrescheduleThink( void ) -{ - // if the hound is mad and is running, make hunt noises. - if( m_MonsterState == MONSTERSTATE_COMBAT && m_Activity == ACT_RUN && RANDOM_FLOAT( 0, 1 ) < 0.2 ) - { - WarnSound(); - } - - // at random, initiate a blink if not already blinking or sleeping - if( !m_fDontBlink ) - { - if( ( pev->skin == 0 ) && RANDOM_LONG( 0, 0x7F ) == 0 ) - { - // start blinking! - pev->skin = HOUNDEYE_EYE_FRAMES - 1; - } - else if( pev->skin != 0 ) - { - // already blinking - pev->skin--; - } - } - - // if you are the leader, average the origins of each pack member to get an approximate center. - if( IsLeader() ) - { - CSquadMonster *pSquadMember; - int iSquadCount = 0; - - for( int i = 0; i < MAX_SQUAD_MEMBERS; i++ ) - { - pSquadMember = MySquadMember( i ); - - if( pSquadMember ) - { - iSquadCount++; - m_vecPackCenter = m_vecPackCenter + pSquadMember->pev->origin; - } - } - - m_vecPackCenter = m_vecPackCenter / iSquadCount; - } -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlHoundGuardPack[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_GUARD, (float)0 }, -}; - -Schedule_t slHoundGuardPack[] = -{ - { - tlHoundGuardPack, - ARRAYSIZE ( tlHoundGuardPack ), - bits_COND_SEE_HATE | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_HEAR_SOUND, - - bits_SOUND_COMBAT |// sound flags - bits_SOUND_WORLD | - bits_SOUND_MEAT | - bits_SOUND_PLAYER, - "GuardPack" - }, -}; - -// primary range attack -Task_t tlHoundYell1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_HOUND_AGITATED }, -}; - -Task_t tlHoundYell2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slHoundRangeAttack[] = -{ - { - tlHoundYell1, - ARRAYSIZE ( tlHoundYell1 ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundRangeAttack1" - }, - { - tlHoundYell2, - ARRAYSIZE ( tlHoundYell2 ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundRangeAttack2" - }, -}; - -// lie down and fall asleep -Task_t tlHoundSleep[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_RANDOM, (float)5 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, - { TASK_HOUND_FALL_ASLEEP, (float)0 }, - { TASK_WAIT_RANDOM, (float)25 }, - { TASK_HOUND_CLOSE_EYE, (float)0 }, - //{ TASK_WAIT, (float)10 }, - //{ TASK_WAIT_RANDOM, (float)10 }, -}; - -Schedule_t slHoundSleep[] = -{ - { - tlHoundSleep, - ARRAYSIZE ( tlHoundSleep ), - bits_COND_HEAR_SOUND | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY, - - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_WORLD, - "Hound Sleep" - }, -}; - -// wake and stand up lazily -Task_t tlHoundWakeLazy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_HOUND_OPEN_EYE, (float)0 }, - { TASK_WAIT_RANDOM, (float)2.5 }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, - { TASK_HOUND_WAKE_UP, (float)0 }, -}; - -Schedule_t slHoundWakeLazy[] = -{ - { - tlHoundWakeLazy, - ARRAYSIZE ( tlHoundWakeLazy ), - 0, - 0, - "WakeLazy" - }, -}; - -// wake and stand up with great urgency! -Task_t tlHoundWakeUrgent[] = -{ - { TASK_HOUND_OPEN_EYE, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_HOUND_WAKE_UP, (float)0 }, -}; - -Schedule_t slHoundWakeUrgent[] = -{ - { - tlHoundWakeUrgent, - ARRAYSIZE ( tlHoundWakeUrgent ), - 0, - 0, - "WakeUrgent" - }, -}; - -Task_t tlHoundSpecialAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SPECIAL_ATTACK1, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_IDLE_ANGRY }, -}; - -Schedule_t slHoundSpecialAttack1[] = -{ - { - tlHoundSpecialAttack1, - ARRAYSIZE ( tlHoundSpecialAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED, - - 0, - "Hound Special Attack1" - }, -}; - -Task_t tlHoundAgitated[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, -}; - -Schedule_t slHoundAgitated[] = -{ - { - tlHoundAgitated, - ARRAYSIZE ( tlHoundAgitated ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Hound Agitated" - }, -}; - -Task_t tlHoundHopRetreat[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_HOP_BACK, 0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slHoundHopRetreat[] = -{ - { - tlHoundHopRetreat, - ARRAYSIZE ( tlHoundHopRetreat ), - 0, - 0, - "Hound Hop Retreat" - }, -}; - -// hound fails in combat with client in the PVS -Task_t tlHoundCombatFailPVS[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, -}; - -Schedule_t slHoundCombatFailPVS[] = -{ - { - tlHoundCombatFailPVS, - ARRAYSIZE ( tlHoundCombatFailPVS ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundCombatFailPVS" - }, -}; - -// hound fails in combat with no client in the PVS. Don't keep peeping! -Task_t tlHoundCombatFailNoPVS[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_PVS, 0 }, -}; - -Schedule_t slHoundCombatFailNoPVS[] = -{ - { - tlHoundCombatFailNoPVS, - ARRAYSIZE ( tlHoundCombatFailNoPVS ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundCombatFailNoPVS" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CHoundeye ) -{ - slHoundGuardPack, - slHoundRangeAttack, - &slHoundRangeAttack[ 1 ], - slHoundSleep, - slHoundWakeLazy, - slHoundWakeUrgent, - slHoundSpecialAttack1, - slHoundAgitated, - slHoundHopRetreat, - slHoundCombatFailPVS, - slHoundCombatFailNoPVS, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHoundeye, CSquadMonster ) - -//========================================================= -// GetScheduleOfType -//========================================================= -Schedule_t *CHoundeye::GetScheduleOfType( int Type ) -{ - if( m_fAsleep ) - { - // if the hound is sleeping, must wake and stand! - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pWakeSound; - - pWakeSound = PBestSound(); - ASSERT( pWakeSound != NULL ); - if( pWakeSound ) - { - MakeIdealYaw( pWakeSound->m_vecOrigin ); - - if( FLSoundVolume( pWakeSound ) >= HOUNDEYE_SOUND_STARTLE_VOLUME ) - { - // awakened by a loud sound - return &slHoundWakeUrgent[0]; - } - } - // sound was not loud enough to scare the bejesus out of houndeye - return &slHoundWakeLazy[0]; - } - else if( HasConditions( bits_COND_NEW_ENEMY ) ) - { - // get up fast, to fight. - return &slHoundWakeUrgent[0]; - } - else - { - // hound is waking up on its own - return &slHoundWakeLazy[0]; - } - } - switch( Type ) - { - case SCHED_IDLE_STAND: - { - // we may want to sleep instead of stand! - if( InSquad() && !IsLeader() && !m_fAsleep && RANDOM_LONG( 0, 29 ) < 1 ) - { - return &slHoundSleep[0]; - } - else - { - return CSquadMonster::GetScheduleOfType( Type ); - } - } - case SCHED_RANGE_ATTACK1: - { - return &slHoundRangeAttack[0]; -/* - if( InSquad() ) - { - return &slHoundRangeAttack[RANDOM_LONG( 0, 1 )]; - } - - return &slHoundRangeAttack[1]; -*/ - } - case SCHED_SPECIAL_ATTACK1: - { - return &slHoundSpecialAttack1[0]; - } - case SCHED_GUARD: - { - return &slHoundGuardPack[0]; - } - case SCHED_HOUND_AGITATED: - { - return &slHoundAgitated[0]; - } - case SCHED_HOUND_HOP_RETREAT: - { - return &slHoundHopRetreat[0]; - } - case SCHED_FAIL: - { - if( m_MonsterState == MONSTERSTATE_COMBAT ) - { - if( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - // client in PVS - return &slHoundCombatFailPVS[0]; - } - else - { - // client has taken off! - return &slHoundCombatFailNoPVS[0]; - } - } - else - { - return CSquadMonster::GetScheduleOfType( Type ); - } - } - default: - { - return CSquadMonster::GetScheduleOfType( Type ); - } - } -} - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t *CHoundeye::GetSchedule( void ) -{ - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { - // dead enemy - if( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster::GetSchedule(); - } - - if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - if( RANDOM_FLOAT( 0, 1 ) <= 0.4 ) - { - TraceResult tr; - UTIL_MakeVectors( pev->angles ); - UTIL_TraceHull( pev->origin, pev->origin + gpGlobals->v_forward * -128, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); - - if( tr.flFraction == 1.0 ) - { - // it's clear behind, so the hound will jump - return GetScheduleOfType( SCHED_HOUND_HOP_RETREAT ); - } - } - - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - - if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - if( OccupySlot( bits_SLOTS_HOUND_ATTACK ) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - return GetScheduleOfType( SCHED_HOUND_AGITATED ); - } - break; - } - default: - break; - } - - return CSquadMonster::GetSchedule(); -} diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp deleted file mode 100644 index 53f57a27..00000000 --- a/dlls/ichthyosaur.cpp +++ /dev/null @@ -1,1093 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// icthyosaur - evin, satan fish monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "flyingmonster.h" -#include "nodes.h" -#include "soundent.h" -#include "animation.h" -#include "effects.h" -#include "weapons.h" - -#define SEARCH_RETRY 16 - -#define ICHTHYOSAUR_SPEED 150 - -extern CGraph WorldGraph; - -#define EYE_MAD 0 -#define EYE_BASE 1 -#define EYE_CLOSED 2 -#define EYE_BACK 3 -#define EYE_LOOK 4 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -// UNDONE: Save/restore here -class CIchthyosaur : public CFlyingMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - CUSTOM_SCHEDULES - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - - void Killed( entvars_t *pevAttacker, int iGib ); - void BecomeDead( void ); - - void EXPORT CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT BiteTouch( CBaseEntity *pOther ); - - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - - BOOL CheckMeleeAttack1( float flDot, float flDist ); - BOOL CheckRangeAttack1( float flDot, float flDist ); - - float ChangeYaw( int speed ); - Activity GetStoppedActivity( void ); - - void Move( float flInterval ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void MonsterThink( void ); - void Stop( void ); - void Swim( void ); - Vector DoProbe(const Vector &Probe ); - - float VectorToPitch( const Vector &vec ); - float FlPitchDiff( void ); - float ChangePitch( int speed ); - - Vector m_SaveVelocity; - float m_idealDist; - - float m_flBlink; - - float m_flEnemyTouched; - BOOL m_bOnAttack; - - float m_flMaxSpeed; - float m_flMinSpeed; - float m_flMaxDist; - - CBeam *m_pBeam; - - float m_flNextAlert; - - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pAttackSounds[]; - static const char *pBiteSounds[]; - static const char *pDieSounds[]; - static const char *pPainSounds[]; - - void IdleSound( void ); - void AlertSound( void ); - void AttackSound( void ); - void BiteSound( void ); - void DeathSound( void ); - void PainSound( void ); -}; - -LINK_ENTITY_TO_CLASS( monster_ichthyosaur, CIchthyosaur ) - -TYPEDESCRIPTION CIchthyosaur::m_SaveData[] = -{ - DEFINE_FIELD( CIchthyosaur, m_SaveVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CIchthyosaur, m_idealDist, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flBlink, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flEnemyTouched, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_bOnAttack, FIELD_BOOLEAN ), - DEFINE_FIELD( CIchthyosaur, m_flMaxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flMinSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flMaxDist, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flNextAlert, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CIchthyosaur, CFlyingMonster ) - -const char *CIchthyosaur::pIdleSounds[] = -{ - "ichy/ichy_idle1.wav", - "ichy/ichy_idle2.wav", - "ichy/ichy_idle3.wav", - "ichy/ichy_idle4.wav", -}; - -const char *CIchthyosaur::pAlertSounds[] = -{ - "ichy/ichy_alert2.wav", - "ichy/ichy_alert3.wav", -}; - -const char *CIchthyosaur::pAttackSounds[] = -{ - "ichy/ichy_attack1.wav", - "ichy/ichy_attack2.wav", -}; - -const char *CIchthyosaur::pBiteSounds[] = -{ - "ichy/ichy_bite1.wav", - "ichy/ichy_bite2.wav", -}; - -const char *CIchthyosaur::pPainSounds[] = -{ - "ichy/ichy_pain2.wav", - "ichy/ichy_pain3.wav", - "ichy/ichy_pain5.wav", -}; - -const char *CIchthyosaur::pDieSounds[] = -{ - "ichy/ichy_die2.wav", - "ichy/ichy_die4.wav", -}; - -#define EMIT_ICKY_SOUND( chan, array ) \ - EMIT_SOUND_DYN( ENT( pev ), chan , array[RANDOM_LONG( 0, ARRAYSIZE( array ) - 1 )], 1.0, 0.6, 0, RANDOM_LONG( 95, 105 ) ); - -void CIchthyosaur::IdleSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pIdleSounds ); -} - -void CIchthyosaur::AlertSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pAlertSounds ); -} - -void CIchthyosaur::AttackSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pAttackSounds ); -} - -void CIchthyosaur::BiteSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_WEAPON, pBiteSounds ); -} - -void CIchthyosaur::DeathSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pDieSounds ); -} - -void CIchthyosaur::PainSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pPainSounds ); -} - -//========================================================= -// monster-specific tasks and states -//========================================================= -enum -{ - TASK_ICHTHYOSAUR_CIRCLE_ENEMY = LAST_COMMON_TASK + 1, - TASK_ICHTHYOSAUR_SWIM, - TASK_ICHTHYOSAUR_FLOAT -}; - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -static Task_t tlSwimAround[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_WALK }, - { TASK_ICHTHYOSAUR_SWIM, 0.0 }, -}; - -static Schedule_t slSwimAround[] = -{ - { - tlSwimAround, - ARRAYSIZE(tlSwimAround), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - bits_SOUND_PLAYER | - bits_SOUND_COMBAT, - "SwimAround" - }, -}; - -static Task_t tlSwimAgitated[] = -{ - { TASK_STOP_MOVING, (float) 0 }, - { TASK_SET_ACTIVITY, (float)ACT_RUN }, - { TASK_WAIT, (float)2.0 }, -}; - -static Schedule_t slSwimAgitated[] = -{ - { - tlSwimAgitated, - ARRAYSIZE(tlSwimAgitated), - 0, - 0, - "SwimAgitated" - }, -}; - -static Task_t tlCircleEnemy[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_WALK }, - { TASK_ICHTHYOSAUR_CIRCLE_ENEMY, 0.0 }, -}; - -static Schedule_t slCircleEnemy[] = -{ - { - tlCircleEnemy, - ARRAYSIZE(tlCircleEnemy), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK1, - 0, - "CircleEnemy" - }, -}; - -Task_t tlTwitchDie[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SOUND_DIE, (float)0 }, - { TASK_DIE, (float)0 }, - { TASK_ICHTHYOSAUR_FLOAT, (float)0 }, -}; - -Schedule_t slTwitchDie[] = -{ - { - tlTwitchDie, - ARRAYSIZE( tlTwitchDie ), - 0, - 0, - "Die" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CIchthyosaur ) -{ - slSwimAround, - slSwimAgitated, - slCircleEnemy, - slTwitchDie, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CIchthyosaur, CFlyingMonster ) - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CIchthyosaur::Classify( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CIchthyosaur::CheckMeleeAttack1( float flDot, float flDist ) -{ - if( flDot >= 0.7 && m_flEnemyTouched > gpGlobals->time - 0.2 ) - { - return TRUE; - } - return FALSE; -} - -void CIchthyosaur::BiteTouch( CBaseEntity *pOther ) -{ - // bite if we hit who we want to eat - if( pOther == m_hEnemy ) - { - m_flEnemyTouched = gpGlobals->time; - m_bOnAttack = TRUE; - } -} - -void CIchthyosaur::CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !ShouldToggle( useType, m_bOnAttack ) ) - return; - - if( m_bOnAttack ) - { - m_bOnAttack = 0; - } - else - { - m_bOnAttack = 1; - } -} - -//========================================================= -// CheckRangeAttack1 - swim in for a chomp -// -//========================================================= -BOOL CIchthyosaur::CheckRangeAttack1( float flDot, float flDist ) -{ - if( flDot > -0.7 && (m_bOnAttack || ( flDist <= 192 && m_idealDist <= 192 ) ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CIchthyosaur::SetYawSpeed( void ) -{ - pev->yaw_speed = 100; -} - -//========================================================= -// Killed - overrides CFlyingMonster. -// -void CIchthyosaur::Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster::Killed( pevAttacker, iGib ); - pev->velocity = Vector( 0, 0, 0 ); -} - -void CIchthyosaur::BecomeDead( void ) -{ - pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. - - // give the corpse half of the monster's original maximum health. - pev->health = pev->max_health / 2; - pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. -} - -#define ICHTHYOSAUR_AE_SHAKE_RIGHT 1 -#define ICHTHYOSAUR_AE_SHAKE_LEFT 2 - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CIchthyosaur::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - int bDidAttack = FALSE; - switch( pEvent->event ) - { - case ICHTHYOSAUR_AE_SHAKE_RIGHT: - case ICHTHYOSAUR_AE_SHAKE_LEFT: - { - if( m_hEnemy != 0 && FVisible( m_hEnemy ) ) - { - CBaseEntity *pHurt = m_hEnemy; - - if( m_flEnemyTouched < gpGlobals->time - 0.2 && ( m_hEnemy->BodyTarget( pev->origin ) - pev->origin).Length() > ( 32 + 16 + 32 ) ) - break; - - Vector vecShootDir = ShootAtEnemy( pev->origin ); - UTIL_MakeAimVectors( pev->angles ); - - if( DotProduct( vecShootDir, gpGlobals->v_forward ) > 0.707 ) - { - m_bOnAttack = TRUE; - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 300; - if( pHurt->IsPlayer() ) - { - pHurt->pev->angles.x += RANDOM_FLOAT( -35, 35 ); - pHurt->pev->angles.y += RANDOM_FLOAT( -90, 90 ); - pHurt->pev->angles.z = 0; - pHurt->pev->fixangle = TRUE; - } - pHurt->TakeDamage( pev, pev, gSkillData.ichthyosaurDmgShake, DMG_SLASH ); - } - } - BiteSound(); - - bDidAttack = TRUE; - } - break; - default: - CFlyingMonster::HandleAnimEvent( pEvent ); - break; - } - - if( bDidAttack ) - { - Vector vecSrc = pev->origin + gpGlobals->v_forward * 32; - UTIL_Bubbles( vecSrc - Vector( 8, 8, 8 ), vecSrc + Vector( 8, 8, 8 ), 16 ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CIchthyosaur::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/icky.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, -32 ), Vector( 32, 32, 32 ) ); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.ichthyosaurHealth; - pev->view_ofs = Vector( 0, 0, 16 ); - m_flFieldOfView = VIEW_FIELD_WIDE; - m_MonsterState = MONSTERSTATE_NONE; - SetBits(pev->flags, FL_SWIM); - SetFlyingSpeed( ICHTHYOSAUR_SPEED ); - SetFlyingMomentum( 2.5 ); // Set momentum constant - - m_afCapability = bits_CAP_RANGE_ATTACK1 | bits_CAP_SWIM; - - MonsterInit(); - - SetTouch( &CIchthyosaur::BiteTouch ); - SetUse( &CIchthyosaur::CombatUse ); - - m_idealDist = 384; - m_flMinSpeed = 80; - m_flMaxSpeed = 300; - m_flMaxDist = 384; - - Vector Forward; - UTIL_MakeVectorsPrivate( pev->angles, Forward, 0, 0 ); - pev->velocity = m_flightSpeed * Forward.Normalize(); - m_SaveVelocity = pev->velocity; -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CIchthyosaur::Precache() -{ - PRECACHE_MODEL( "models/icky.mdl" ); - - PRECACHE_SOUND_ARRAY( pIdleSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pBiteSounds ); - PRECACHE_SOUND_ARRAY( pDieSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); -} - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t* CIchthyosaur::GetSchedule() -{ - // ALERT( at_console, "GetSchedule( )\n" ); - switch( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - m_flightSpeed = 80; - return GetScheduleOfType( SCHED_IDLE_WALK ); - break; - case MONSTERSTATE_ALERT: - m_flightSpeed = 150; - return GetScheduleOfType( SCHED_IDLE_WALK ); - break; - case MONSTERSTATE_COMBAT: - m_flMaxSpeed = 400; - // eat them - if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - - // chase them down and eat them - if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - { - m_bOnAttack = TRUE; - } - if( pev->health < pev->max_health - 20 ) - { - m_bOnAttack = TRUE; - } - - return GetScheduleOfType( SCHED_STANDOFF ); - break; - default: - break; - } - - return CFlyingMonster::GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t *CIchthyosaur::GetScheduleOfType( int Type ) -{ - // ALERT( at_console, "GetScheduleOfType( %d ) %d\n", Type, m_bOnAttack ); - switch( Type ) - { - case SCHED_IDLE_WALK: - return slSwimAround; - case SCHED_STANDOFF: - return slCircleEnemy; - case SCHED_FAIL: - return slSwimAgitated; - case SCHED_DIE: - return slTwitchDie; - case SCHED_CHASE_ENEMY: - AttackSound(); - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. -//========================================================= -void CIchthyosaur::StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: - break; - case TASK_ICHTHYOSAUR_SWIM: - break; - case TASK_SMALL_FLINCH: - if( m_idealDist > 128 ) - { - m_flMaxDist = 512; - m_idealDist = 512; - } - else - { - m_bOnAttack = TRUE; - } - CFlyingMonster::StartTask( pTask ); - break; - case TASK_ICHTHYOSAUR_FLOAT: - pev->skin = EYE_BASE; - SetSequenceByName( "bellyup" ); - break; - default: - CFlyingMonster::StartTask( pTask ); - break; - } -} - -void CIchthyosaur::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: - if( m_hEnemy == 0 ) - { - TaskComplete(); - } - else if( FVisible( m_hEnemy ) ) - { - Vector vecFrom = m_hEnemy->EyePosition(); - - Vector vecDelta = ( pev->origin - vecFrom ).Normalize(); - Vector vecSwim = CrossProduct( vecDelta, Vector( 0, 0, 1 ) ).Normalize(); - - if( DotProduct( vecSwim, m_SaveVelocity ) < 0 ) - vecSwim = vecSwim * -1.0; - - Vector vecPos = vecFrom + vecDelta * m_idealDist + vecSwim * 32; - - // ALERT( at_console, "vecPos %.0f %.0f %.0f\n", vecPos.x, vecPos.y, vecPos.z ); - - TraceResult tr; - - UTIL_TraceHull( vecFrom, vecPos, ignore_monsters, large_hull, m_hEnemy->edict(), &tr ); - - if( tr.flFraction > 0.5 ) - vecPos = tr.vecEndPos; - - m_SaveVelocity = m_SaveVelocity * 0.8 + 0.2 * ( vecPos - pev->origin ).Normalize() * m_flightSpeed; - - // ALERT( at_console, "m_SaveVelocity %.2f %.2f %.2f\n", m_SaveVelocity.x, m_SaveVelocity.y, m_SaveVelocity.z ); - - if( HasConditions( bits_COND_ENEMY_FACING_ME ) && m_hEnemy->FVisible( this ) ) - { - m_flNextAlert -= 0.1; - - if( m_idealDist < m_flMaxDist ) - { - m_idealDist += 4; - } - - if( m_flightSpeed > m_flMinSpeed ) - { - m_flightSpeed -= 2; - } - else if( m_flightSpeed < m_flMinSpeed ) - { - m_flightSpeed += 2; - } - if( m_flMinSpeed < m_flMaxSpeed ) - { - m_flMinSpeed += 0.5; - } - } - else - { - m_flNextAlert += 0.1; - - if( m_idealDist > 128 ) - { - m_idealDist -= 4; - } - if( m_flightSpeed < m_flMaxSpeed ) - { - m_flightSpeed += 4; - } - } - // ALERT( at_console, "%.0f\n", m_idealDist ); - } - else - { - m_flNextAlert = gpGlobals->time + 0.2; - } - - if( m_flNextAlert < gpGlobals->time ) - { - // ALERT( at_console, "AlertSound()\n" ); - AlertSound(); - m_flNextAlert = gpGlobals->time + RANDOM_FLOAT( 3, 5 ); - } - break; - case TASK_ICHTHYOSAUR_SWIM: - if( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - case TASK_DIE: - if( m_fSequenceFinished ) - { - pev->deadflag = DEAD_DEAD; - - TaskComplete(); - } - break; - case TASK_ICHTHYOSAUR_FLOAT: - pev->angles.x = UTIL_ApproachAngle( 0, pev->angles.x, 20 ); - pev->velocity = pev->velocity * 0.8; - if( pev->waterlevel > 1 && pev->velocity.z < 64 ) - { - pev->velocity.z += 8; - } - else - { - pev->velocity.z -= 8; - } - // ALERT( at_console, "%f\n", pev->velocity.z ); - break; - default: - CFlyingMonster::RunTask( pTask ); - break; - } -} - -float CIchthyosaur::VectorToPitch( const Vector &vec ) -{ - float pitch; - if( vec.z == 0 && vec.x == 0 ) - pitch = 0; - else - { - pitch = (int) ( atan2( vec.z, sqrt( vec.x * vec.x + vec.y * vec.y ) ) * 180 / M_PI ); - if( pitch < 0 ) - pitch += 360; - } - return pitch; -} - -//========================================================= -void CIchthyosaur::Move( float flInterval ) -{ - CFlyingMonster::Move( flInterval ); -} - -float CIchthyosaur::FlPitchDiff( void ) -{ - float flPitchDiff; - float flCurrentPitch; - - flCurrentPitch = UTIL_AngleMod( pev->angles.z ); - - if( flCurrentPitch == pev->idealpitch ) - { - return 0; - } - - flPitchDiff = pev->idealpitch - flCurrentPitch; - - if( pev->idealpitch > flCurrentPitch ) - { - if( flPitchDiff >= 180 ) - flPitchDiff = flPitchDiff - 360; - } - else - { - if( flPitchDiff <= -180 ) - flPitchDiff = flPitchDiff + 360; - } - return flPitchDiff; -} - -float CIchthyosaur::ChangePitch( int speed ) -{ - if( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlPitchDiff(); - float target = 0; - if( m_IdealActivity != GetStoppedActivity() ) - { - if( diff < -20 ) - target = 45; - else if( diff > 20 ) - target = -45; - } - pev->angles.x = UTIL_Approach(target, pev->angles.x, 220.0 * 0.1 ); - } - return 0; -} - -float CIchthyosaur::ChangeYaw( int speed ) -{ - if( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlYawDiff(); - float target = 0; - - if( m_IdealActivity != GetStoppedActivity() ) - { - if( diff < -20 ) - target = 20; - else if( diff > 20 ) - target = -20; - } - pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * 0.1 ); - } - return CFlyingMonster::ChangeYaw( speed ); -} - -Activity CIchthyosaur::GetStoppedActivity( void ) -{ - if( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else - return ACT_IDLE; - return ACT_WALK; -} - -void CIchthyosaur::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - m_SaveVelocity = vecDir * m_flightSpeed; -} - -void CIchthyosaur::MonsterThink( void ) -{ - CFlyingMonster::MonsterThink(); - - if( pev->deadflag == DEAD_NO ) - { - if( m_MonsterState != MONSTERSTATE_SCRIPT ) - { - Swim(); - - // blink the eye - if( m_flBlink < gpGlobals->time ) - { - pev->skin = EYE_CLOSED; - if( m_flBlink + 0.2 < gpGlobals->time ) - { - m_flBlink = gpGlobals->time + RANDOM_FLOAT( 3, 4 ); - if( m_bOnAttack ) - pev->skin = EYE_MAD; - else - pev->skin = EYE_BASE; - } - } - } - } -} - -void CIchthyosaur::Stop( void ) -{ - if( !m_bOnAttack ) - m_flightSpeed = 80.0; -} - -void CIchthyosaur::Swim() -{ - //int retValue = 0; - - Vector start = pev->origin; - - Vector Angles; - Vector Forward, Right, Up; - - if( FBitSet( pev->flags, FL_ONGROUND ) ) - { - pev->angles.x = 0; - pev->angles.y += RANDOM_FLOAT( -45, 45 ); - ClearBits( pev->flags, FL_ONGROUND ); - - Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_MakeVectorsPrivate( Angles, Forward, Right, Up ); - - pev->velocity = Forward * 200 + Up * 200; - - return; - } - - if( m_bOnAttack && m_flightSpeed < m_flMaxSpeed ) - { - m_flightSpeed += 40; - } - if( m_flightSpeed < 180 ) - { - if( m_IdealActivity == ACT_RUN ) - SetActivity( ACT_WALK ); - if( m_IdealActivity == ACT_WALK ) - pev->framerate = m_flightSpeed / 150.0; - // ALERT( at_console, "walk %.2f\n", pev->framerate ); - } - else - { - if( m_IdealActivity == ACT_WALK ) - SetActivity( ACT_RUN ); - if( m_IdealActivity == ACT_RUN) - pev->framerate = m_flightSpeed / 150.0; - // ALERT( at_console, "run %.2f\n", pev->framerate ); - } -/* - if( !m_pBeam ) - { - m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 80 ); - m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex() ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->SetColor( 255, 180, 96 ); - m_pBeam->SetBrightness( 192 ); - } -*/ -#define PROBE_LENGTH 150 - Angles = UTIL_VecToAngles( m_SaveVelocity ); - Angles.x = -Angles.x; - UTIL_MakeVectorsPrivate( Angles, Forward, Right, Up ); - - Vector f, u, l, r, d; - f = DoProbe( start + PROBE_LENGTH * Forward ); - r = DoProbe( start + PROBE_LENGTH / 3 * Forward + Right ); - l = DoProbe( start + PROBE_LENGTH / 3 * Forward - Right ); - u = DoProbe( start + PROBE_LENGTH / 3 * Forward + Up ); - d = DoProbe( start + PROBE_LENGTH / 3 * Forward - Up ); - - Vector SteeringVector = f + r + l + u + d; - m_SaveVelocity = ( m_SaveVelocity + SteeringVector / 2 ).Normalize(); - - Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_MakeVectorsPrivate( Angles, Forward, Right, Up ); - // ALERT( at_console, "%f : %f\n", Angles.x, Forward.z ); - - float flDot = DotProduct( Forward, m_SaveVelocity ); - if( flDot > 0.5 ) - pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed; - else if( flDot > 0 ) - pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed * ( flDot + 0.5 ); - else - pev->velocity = m_SaveVelocity = m_SaveVelocity * 80; - - // ALERT( at_console, "%.0f %.0f\n", m_flightSpeed, pev->velocity.Length() ); - - // ALERT( at_console, "Steer %f %f %f\n", SteeringVector.x, SteeringVector.y, SteeringVector.z ); -/* - m_pBeam->SetStartPos( pev->origin + pev->velocity ); - m_pBeam->RelinkBeam(); -*/ - // ALERT( at_console, "speed %f\n", m_flightSpeed ); - - Angles = UTIL_VecToAngles( m_SaveVelocity ); - - // Smooth Pitch - // - if( Angles.x > 180 ) - Angles.x = Angles.x - 360; - pev->angles.x = UTIL_Approach( Angles.x, pev->angles.x, 50 * 0.1 ); - if( pev->angles.x < -80 ) - pev->angles.x = -80; - if( pev->angles.x > 80 ) - pev->angles.x = 80; - - // Smooth Yaw and generate Roll - // - float turn = 360; - // ALERT( at_console, "Y %.0f %.0f\n", Angles.y, pev->angles.y ); - - if( fabs( Angles.y - pev->angles.y ) < fabs( turn ) ) - { - turn = Angles.y - pev->angles.y; - } - if( fabs( Angles.y - pev->angles.y + 360 ) < fabs( turn ) ) - { - turn = Angles.y - pev->angles.y + 360; - } - if( fabs( Angles.y - pev->angles.y - 360 ) < fabs( turn ) ) - { - turn = Angles.y - pev->angles.y - 360; - } - - float speed = m_flightSpeed * 0.1; - - // ALERT( at_console, "speed %.0f %f\n", turn, speed ); - if( fabs( turn ) > speed ) - { - if( turn < 0.0 ) - { - turn = -speed; - } - else - { - turn = speed; - } - } - pev->angles.y += turn; - pev->angles.z -= turn; - pev->angles.y = fmod( ( pev->angles.y + 360.0 ), 360.0 ); - - static float yaw_adj; - - yaw_adj = yaw_adj * 0.8 + turn; - - // ALERT( at_console, "yaw %f : %f\n", turn, yaw_adj ); - - SetBoneController( 0, -yaw_adj / 4.0 ); - - // Roll Smoothing - // - turn = 360; - if( fabs( Angles.z - pev->angles.z ) < fabs( turn ) ) - { - turn = Angles.z - pev->angles.z; - } - if( fabs( Angles.z - pev->angles.z + 360 ) < fabs( turn ) ) - { - turn = Angles.z - pev->angles.z + 360; - } - if( fabs( Angles.z - pev->angles.z - 360 ) < fabs( turn ) ) - { - turn = Angles.z - pev->angles.z - 360; - } - speed = m_flightSpeed / 2 * 0.1; - - if( fabs( turn ) < speed ) - { - pev->angles.z += turn; - } - else - { - if( turn < 0.0 ) - { - pev->angles.z -= speed; - } - else - { - pev->angles.z += speed; - } - } - - if( pev->angles.z < -20 ) - pev->angles.z = -20; - if( pev->angles.z > 20 ) - pev->angles.z = 20; - - UTIL_MakeVectorsPrivate( Vector( -Angles.x, Angles.y, Angles.z ), Forward, Right, Up ); - - // UTIL_MoveToOrigin ( ENT( pev ), pev->origin + Forward * speed, speed, MOVE_STRAFE ); -} - -Vector CIchthyosaur::DoProbe( const Vector &Probe ) -{ - Vector WallNormal = Vector( 0, 0, -1 ); // WATER normal is Straight Down for fish. - float frac; - BOOL bBumpedSomething = ProbeZ( pev->origin, Probe, &frac ); - - TraceResult tr; - TRACE_MONSTER_HULL( edict(), pev->origin, Probe, dont_ignore_monsters, edict(), &tr ); - if( tr.fAllSolid || tr.flFraction < 0.99 ) - { - if( tr.flFraction < 0.0 ) - tr.flFraction = 0.0; - if( tr.flFraction > 1.0 ) - tr.flFraction = 1.0; - if( tr.flFraction < frac ) - { - frac = tr.flFraction; - bBumpedSomething = TRUE; - WallNormal = tr.vecPlaneNormal; - } - } - - if( bBumpedSomething && ( m_hEnemy == 0 || tr.pHit != m_hEnemy->edict() ) ) - { - Vector ProbeDir = Probe - pev->origin; - - Vector NormalToProbeAndWallNormal = CrossProduct( ProbeDir, WallNormal ); - Vector SteeringVector = CrossProduct( NormalToProbeAndWallNormal, ProbeDir ); - - float SteeringForce = m_flightSpeed * ( 1 -frac ) * ( DotProduct( WallNormal.Normalize(), m_SaveVelocity.Normalize() ) ); - if( SteeringForce < 0.0 ) - { - SteeringForce = -SteeringForce; - } - SteeringVector = SteeringForce * SteeringVector.Normalize(); - - return SteeringVector; - } - return Vector( 0, 0, 0 ); -} -#endif diff --git a/dlls/islave.cpp b/dlls/islave.cpp deleted file mode 100644 index b516c09b..00000000 --- a/dlls/islave.cpp +++ /dev/null @@ -1,842 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Alien slave monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "squadmonster.h" -#include "schedule.h" -#include "effects.h" -#include "weapons.h" -#include "soundent.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ISLAVE_AE_CLAW ( 1 ) -#define ISLAVE_AE_CLAWRAKE ( 2 ) -#define ISLAVE_AE_ZAP_POWERUP ( 3 ) -#define ISLAVE_AE_ZAP_SHOOT ( 4 ) -#define ISLAVE_AE_ZAP_DONE ( 5 ) - -#define ISLAVE_MAX_BEAMS 8 - -class CISlave : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void UpdateOnRemove(); - void SetYawSpeed( void ); - int ISoundMask( void ); - int Classify( void ); - int IRelationship( CBaseEntity *pTarget ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL CheckRangeAttack1( float flDot, float flDist ); - BOOL CheckRangeAttack2( float flDot, float flDist ); - void CallForHelp( const char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - - void DeathSound( void ); - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - - void StartTask( Task_t *pTask ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - CUSTOM_SCHEDULES - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void ClearBeams(); - void ArmBeam( int side ); - void WackBeam( int side, CBaseEntity *pEntity ); - void ZapBeam( int side ); - void BeamGlow( void ); - - int m_iBravery; - - CBeam *m_pBeam[ISLAVE_MAX_BEAMS]; - - int m_iBeams; - float m_flNextAttack; - - int m_voicePitch; - - EHANDLE m_hDead; - - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - static const char *pPainSounds[]; - static const char *pDeathSounds[]; -}; - -LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave ) -LINK_ENTITY_TO_CLASS( monster_vortigaunt, CISlave ) - -TYPEDESCRIPTION CISlave::m_SaveData[] = -{ - DEFINE_FIELD( CISlave, m_iBravery, FIELD_INTEGER ), - - DEFINE_ARRAY( CISlave, m_pBeam, FIELD_CLASSPTR, ISLAVE_MAX_BEAMS ), - DEFINE_FIELD( CISlave, m_iBeams, FIELD_INTEGER ), - DEFINE_FIELD( CISlave, m_flNextAttack, FIELD_TIME ), - - DEFINE_FIELD( CISlave, m_voicePitch, FIELD_INTEGER ), - - DEFINE_FIELD( CISlave, m_hDead, FIELD_EHANDLE ), - -}; - -IMPLEMENT_SAVERESTORE( CISlave, CSquadMonster ) - -const char *CISlave::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CISlave::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CISlave::pPainSounds[] = -{ - "aslave/slv_pain1.wav", - "aslave/slv_pain2.wav", -}; - -const char *CISlave::pDeathSounds[] = -{ - "aslave/slv_die1.wav", - "aslave/slv_die2.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CISlave::Classify( void ) -{ - return CLASS_ALIEN_MILITARY; -} - -int CISlave::IRelationship( CBaseEntity *pTarget ) -{ - if( ( pTarget->IsPlayer() ) ) - if( ( pev->spawnflags & SF_MONSTER_WAIT_UNTIL_PROVOKED ) && ! ( m_afMemory & bits_MEMORY_PROVOKED ) ) - return R_NO; - return CBaseMonster::IRelationship( pTarget ); -} - -void CISlave::CallForHelp( const char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) -{ - // ALERT( at_aiconsole, "help " ); - - // skip ones not on my netname - if( FStringNull( pev->netname ) ) - return; - - CBaseEntity *pEntity = NULL; - - while( ( pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ) ) != NULL) - { - float d = ( pev->origin - pEntity->pev->origin ).Length(); - if( d < flDist ) - { - CBaseMonster *pMonster = pEntity->MyMonsterPointer(); - if( pMonster ) - { - pMonster->m_afMemory |= bits_MEMORY_PROVOKED; - pMonster->PushEnemy( hEnemy, vecLocation ); - } - } - } -} - -//========================================================= -// ALertSound - scream -//========================================================= -void CISlave::AlertSound( void ) -{ - if( m_hEnemy != 0 ) - { - SENTENCEG_PlayRndSz( ENT( pev ), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch ); - - CallForHelp( "monster_alien_slave", 512, m_hEnemy, m_vecEnemyLKP ); - } -} - -//========================================================= -// IdleSound -//========================================================= -void CISlave::IdleSound( void ) -{ - if( RANDOM_LONG( 0, 2 ) == 0 ) - { - SENTENCEG_PlayRndSz( ENT( pev ), "SLV_IDLE", 0.85, ATTN_NORM, 0, m_voicePitch ); - } -#if 0 - int side = RANDOM_LONG( 0, 1 ) * 2 - 1; - - ClearBeams(); - ArmBeam( side ); - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + gpGlobals->v_right * 2 * side; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_DLIGHT ); - WRITE_COORD( vecSrc.x ); // X - WRITE_COORD( vecSrc.y ); // Y - WRITE_COORD( vecSrc.z ); // Z - WRITE_BYTE( 8 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 96 ); // b - WRITE_BYTE( 10 ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END(); - - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "debris/zap1.wav", 1, ATTN_NORM, 0, 100 ); -#endif -} - -//========================================================= -// PainSound -//========================================================= -void CISlave::PainSound( void ) -{ - if( RANDOM_LONG( 0, 2 ) == 0 ) - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pPainSounds[RANDOM_LONG( 0, ARRAYSIZE( pPainSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch ); - } -} - -//========================================================= -// DieSound -//========================================================= -void CISlave::DeathSound( void ) -{ - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pDeathSounds[RANDOM_LONG( 0, ARRAYSIZE( pDeathSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch ); -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CISlave::ISoundMask( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - -void CISlave::Killed( entvars_t *pevAttacker, int iGib ) -{ - ClearBeams(); - CSquadMonster::Killed( pevAttacker, iGib ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CISlave::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_WALK: - ys = 50; - break; - case ACT_RUN: - ys = 70; - break; - case ACT_IDLE: - ys = 50; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CISlave::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - // ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame ); - switch( pEvent->event ) - { - case ISLAVE_AE_CLAW: - { - // SOUND HERE! - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClaw, DMG_SLASH ); - if( pHurt ) - { - if( pHurt->pev->flags & ( FL_MONSTER | FL_CLIENT ) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - } - // Play a random attack hit sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - } - break; - case ISLAVE_AE_CLAWRAKE: - { - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClawrake, DMG_SLASH ); - if( pHurt ) - { - if( pHurt->pev->flags & ( FL_MONSTER | FL_CLIENT ) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - } - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - else - { - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - } - break; - case ISLAVE_AE_ZAP_POWERUP: - { - // speed up attack when on hard - if( g_iSkillLevel == SKILL_HARD ) - pev->framerate = 1.5; - - UTIL_MakeAimVectors( pev->angles ); - - if( m_iBeams == 0 ) - { - Vector vecSrc = pev->origin + gpGlobals->v_forward * 2; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_DLIGHT ); - WRITE_COORD( vecSrc.x ); // X - WRITE_COORD( vecSrc.y ); // Y - WRITE_COORD( vecSrc.z ); // Z - WRITE_BYTE( 12 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 96 ); // b - WRITE_BYTE( 20 / pev->framerate ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END(); - } - if( m_hDead != 0 ) - { - WackBeam( -1, m_hDead ); - WackBeam( 1, m_hDead ); - } - else - { - ArmBeam( -1 ); - ArmBeam( 1 ); - BeamGlow(); - } - - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); - pev->skin = m_iBeams / 2; - } - break; - case ISLAVE_AE_ZAP_SHOOT: - { - ClearBeams(); - - if( m_hDead != 0 ) - { - Vector vecDest = m_hDead->pev->origin + Vector( 0, 0, 38 ); - TraceResult trace; - UTIL_TraceHull( vecDest, vecDest, dont_ignore_monsters, human_hull, m_hDead->edict(), &trace ); - - if( !trace.fStartSolid ) - { - CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->pev->origin, m_hDead->pev->angles ); - //CBaseMonster *pNewMonster = pNew->MyMonsterPointer(); - pNew->pev->spawnflags |= 1; - WackBeam( -1, pNew ); - WackBeam( 1, pNew ); - UTIL_Remove( m_hDead ); - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); - /* - CBaseEntity *pEffect = Create( "test_effect", pNew->Center(), pev->angles ); - pEffect->Use( this, this, USE_ON, 1 ); - */ - break; - } - } - ClearMultiDamage(); - - UTIL_MakeAimVectors( pev->angles ); - - ZapBeam( -1 ); - ZapBeam( 1 ); - - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); - // STOP_SOUND( ENT( pev ), CHAN_WEAPON, "debris/zap4.wav" ); - ApplyMultiDamage( pev, pev ); - - m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 ); - } - break; - case ISLAVE_AE_ZAP_DONE: - { - ClearBeams(); - } - break; - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// CheckRangeAttack1 - normal beam attack -//========================================================= -BOOL CISlave::CheckRangeAttack1( float flDot, float flDist ) -{ - if( m_flNextAttack > gpGlobals->time ) - { - return FALSE; - } - - return CSquadMonster::CheckRangeAttack1( flDot, flDist ); -} - -//========================================================= -// CheckRangeAttack2 - check bravery and try to resurect dead comrades -//========================================================= -BOOL CISlave::CheckRangeAttack2( float flDot, float flDist ) -{ - return FALSE; - - if( m_flNextAttack > gpGlobals->time ) - { - return FALSE; - } - - m_hDead = NULL; - m_iBravery = 0; - - CBaseEntity *pEntity = NULL; - while( ( pEntity = UTIL_FindEntityByClassname( pEntity, "monster_alien_slave" ) ) != NULL ) - { - TraceResult tr; - - UTIL_TraceLine( EyePosition(), pEntity->EyePosition(), ignore_monsters, ENT( pev ), &tr ); - if( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) - { - if( pEntity->pev->deadflag == DEAD_DEAD ) - { - float d = ( pev->origin - pEntity->pev->origin ).Length(); - if( d < flDist ) - { - m_hDead = pEntity; - flDist = d; - } - m_iBravery--; - } - else - { - m_iBravery++; - } - } - } - if( m_hDead != 0 ) - return TRUE; - else - return FALSE; -} - -//========================================================= -// StartTask -//========================================================= -void CISlave::StartTask( Task_t *pTask ) -{ - ClearBeams(); - - CSquadMonster::StartTask( pTask ); -} - -//========================================================= -// Spawn -//========================================================= -void CISlave::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/islave.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.slaveHealth; - pev->view_ofs = Vector( 0, 0, 64 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_RANGE_ATTACK2 | bits_CAP_DOORS_GROUP; - - m_voicePitch = RANDOM_LONG( 85, 110 ); - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CISlave::Precache() -{ - size_t i; - - PRECACHE_MODEL( "models/islave.mdl" ); - PRECACHE_MODEL( "sprites/lgtning.spr" ); - PRECACHE_SOUND( "debris/zap1.wav" ); - PRECACHE_SOUND( "debris/zap4.wav" ); - PRECACHE_SOUND( "weapons/electro4.wav" ); - PRECACHE_SOUND( "hassault/hw_shoot1.wav" ); - PRECACHE_SOUND( "zombie/zo_pain2.wav" ); - PRECACHE_SOUND( "headcrab/hc_headbite.wav" ); - PRECACHE_SOUND( "weapons/cbar_miss1.wav" ); - - for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND( pAttackHitSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND( pAttackMissSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND( pPainSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ ) - PRECACHE_SOUND( pDeathSounds[i] ); - - UTIL_PrecacheOther( "test_effect" ); -} - -void CISlave::UpdateOnRemove() -{ - CBaseEntity::UpdateOnRemove(); - - ClearBeams(); -} - -//========================================================= -// TakeDamage - get provoked when injured -//========================================================= - -int CISlave::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // don't slash one of your own - if( ( bitsDamageType & DMG_SLASH ) && pevAttacker && IRelationship( Instance( pevAttacker ) ) < R_DL ) - return 0; - - m_afMemory |= bits_MEMORY_PROVOKED; - return CSquadMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CISlave::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if( bitsDamageType & DMG_SHOCK ) - return; - - CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -// primary range attack -Task_t tlSlaveAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slSlaveAttack1[] = -{ - { - tlSlaveAttack1, - ARRAYSIZE ( tlSlaveAttack1 ), - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND | - bits_COND_HEAVY_DAMAGE, - - bits_SOUND_DANGER, - "Slave Range Attack1" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CISlave ) -{ - slSlaveAttack1, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CISlave, CSquadMonster ) - -//========================================================= -//========================================================= -Schedule_t *CISlave::GetSchedule( void ) -{ - ClearBeams(); -/* - if( pev->spawnflags ) - { - pev->spawnflags = 0; - return GetScheduleOfType( SCHED_RELOAD ); - } -*/ - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - - if( pSound && ( pSound->m_iType & bits_SOUND_DANGER ) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - if( pSound->m_iType & bits_SOUND_COMBAT ) - m_afMemory |= bits_MEMORY_PROVOKED; - } - - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - // dead enemy - if( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster::GetSchedule(); - } - - if( pev->health < 20 || m_iBravery < 0 ) - { - if( !HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - m_failSchedule = SCHED_CHASE_ENEMY; - if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - if( HasConditions( bits_COND_SEE_ENEMY ) && HasConditions( bits_COND_ENEMY_FACING_ME ) ) - { - // ALERT( at_console, "exposed\n"); - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - } - } - break; - default: - break; - } - return CSquadMonster::GetSchedule(); -} - -Schedule_t *CISlave::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_FAIL: - if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return CSquadMonster::GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - break; - case SCHED_RANGE_ATTACK1: - return slSlaveAttack1; - case SCHED_RANGE_ATTACK2: - return slSlaveAttack1; - } - return CSquadMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// ArmBeam - small beam from arm to nearby geometry -//========================================================= -void CISlave::ArmBeam( int side ) -{ - TraceResult tr; - float flDist = 1.0; - - if( m_iBeams >= ISLAVE_MAX_BEAMS ) - return; - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + gpGlobals->v_up * 36 + gpGlobals->v_right * side * 16 + gpGlobals->v_forward * 32; - - for( int i = 0; i < 3; i++ ) - { - Vector vecAim = gpGlobals->v_right * side * RANDOM_FLOAT( 0, 1 ) + gpGlobals->v_up * RANDOM_FLOAT( -1, 1 ); - TraceResult tr1; - UTIL_TraceLine( vecSrc, vecSrc + vecAim * 512, dont_ignore_monsters, ENT( pev ), &tr1 ); - if( flDist > tr1.flFraction ) - { - tr = tr1; - flDist = tr.flFraction; - } - } - - // Couldn't find anything close enough - if( flDist == 1.0 ) - return; - - DecalGunshot( &tr, BULLET_PLAYER_CROWBAR ); - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); - if( !m_pBeam[m_iBeams] ) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex() ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - // m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetColor( 96, 128, 16 ); - m_pBeam[m_iBeams]->SetBrightness( 64 ); - m_pBeam[m_iBeams]->SetNoise( 80 ); - m_iBeams++; -} - -//========================================================= -// BeamGlow - brighten all beams -//========================================================= -void CISlave::BeamGlow() -{ - int b = m_iBeams * 32; - if( b > 255 ) - b = 255; - - for( int i = 0; i < m_iBeams; i++ ) - { - if( m_pBeam[i]->GetBrightness() != 255 ) - { - m_pBeam[i]->SetBrightness( b ); - } - } -} - -//========================================================= -// WackBeam - regenerate dead colleagues -//========================================================= -void CISlave::WackBeam( int side, CBaseEntity *pEntity ) -{ - //Vector vecDest; - //float flDist = 1.0; - - if( m_iBeams >= ISLAVE_MAX_BEAMS ) - return; - - if( pEntity == NULL ) - return; - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); - if( !m_pBeam[m_iBeams] ) - return; - - m_pBeam[m_iBeams]->PointEntInit( pEntity->Center(), entindex() ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 80 ); - m_iBeams++; -} - -//========================================================= -// ZapBeam - heavy damage directly forward -//========================================================= -void CISlave::ZapBeam( int side ) -{ - Vector vecSrc, vecAim; - TraceResult tr; - CBaseEntity *pEntity; - - if( m_iBeams >= ISLAVE_MAX_BEAMS ) - return; - - vecSrc = pev->origin + gpGlobals->v_up * 36; - vecAim = ShootAtEnemy( vecSrc ); - float deflection = 0.01; - vecAim = vecAim + side * gpGlobals->v_right * RANDOM_FLOAT( 0, deflection ) + gpGlobals->v_up * RANDOM_FLOAT( -deflection, deflection ); - UTIL_TraceLine( vecSrc, vecSrc + vecAim * 1024, dont_ignore_monsters, ENT( pev ), &tr ); - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 50 ); - if( !m_pBeam[m_iBeams] ) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex() ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 20 ); - m_iBeams++; - - pEntity = CBaseEntity::Instance( tr.pHit ); - if( pEntity != NULL && pEntity->pev->takedamage ) - { - pEntity->TraceAttack( pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK ); - } - UTIL_EmitAmbientSound( ENT( pev ), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); -} - -//========================================================= -// ClearBeams - remove all beams -//========================================================= -void CISlave::ClearBeams() -{ - for( int i = 0; i < ISLAVE_MAX_BEAMS; i++ ) - { - if( m_pBeam[i] ) - { - UTIL_Remove( m_pBeam[i] ); - m_pBeam[i] = NULL; - } - } - m_iBeams = 0; - pev->skin = 0; - - STOP_SOUND( ENT( pev ), CHAN_WEAPON, "debris/zap4.wav" ); -} diff --git a/dlls/leech.cpp b/dlls/leech.cpp deleted file mode 100644 index 1d64eae1..00000000 --- a/dlls/leech.cpp +++ /dev/null @@ -1,685 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// leech - basic little swimming monster -//========================================================= -// -// UNDONE: -// DONE:Steering force model for attack -// DONE:Attack animation control / damage -// DONE:Establish range of up/down motion and steer around vertical obstacles -// DONE:Re-evaluate height periodically -// DONE:Fall (MOVETYPE_TOSS) and play different anim if out of water -// Test in complex room (c2a3?) -// DONE:Sounds? - Kelly will fix -// Blood cloud? Hurt effect? -// Group behavior? -// DONE:Save/restore -// Flop animation - just bind to ACT_TWITCH -// Fix fatal push into wall case -// -// Try this on a bird -// Try this on a model with hulls/tracehull? -// - -#include "float.h" -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" - -// Animation events -#define LEECH_AE_ATTACK 1 -#define LEECH_AE_FLOP 2 - -// Movement constants - -#define LEECH_ACCELERATE 10 -#define LEECH_CHECK_DIST 45 -#define LEECH_SWIM_SPEED 50 -#define LEECH_SWIM_ACCEL 80 -#define LEECH_SWIM_DECEL 10 -#define LEECH_TURN_RATE 90 -#define LEECH_SIZEX 10 -#define LEECH_FRAMETIME 0.1 - -#define DEBUG_BEAMS 0 - -#if DEBUG_BEAMS -#include "effects.h" -#endif - -class CLeech : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT SwimThink( void ); - void EXPORT DeadThink( void ); - void Touch( CBaseEntity *pOther ) - { - if( pOther->IsPlayer() ) - { - // If the client is pushing me, give me some base velocity - if( gpGlobals->trace_ent && gpGlobals->trace_ent == edict() ) - { - pev->basevelocity = pOther->pev->velocity; - pev->flags |= FL_BASEVELOCITY; - } - } - } - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -8, -8, 0 ); - pev->absmax = pev->origin + Vector( 8, 8, 2 ); - } - - void AttackSound( void ); - void AlertSound( void ); - void UpdateMotion( void ); - float ObstacleDistance( CBaseEntity *pTarget ); - void MakeVectors( void ); - void RecalculateWaterlevel( void ); - void SwitchLeechState( void ); - - // Base entity functions - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - void Activate( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - int Classify( void ) { return CLASS_INSECT; } - int IRelationship( CBaseEntity *pTarget ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pAttackSounds[]; - static const char *pAlertSounds[]; - -private: - // UNDONE: Remove unused boid vars, do group behavior - float m_flTurning;// is this boid turning? - BOOL m_fPathBlocked;// TRUE if there is an obstacle ahead - float m_flAccelerate; - float m_obstacle; - float m_top; - float m_bottom; - float m_height; - float m_waterTime; - float m_sideTime; // Timer to randomly check clearance on sides - float m_zTime; - float m_stateTime; - float m_attackSoundTime; - -#if DEBUG_BEAMS - CBeam *m_pb; - CBeam *m_pt; -#endif -}; - -LINK_ENTITY_TO_CLASS( monster_leech, CLeech ) - -TYPEDESCRIPTION CLeech::m_SaveData[] = -{ - DEFINE_FIELD( CLeech, m_flTurning, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_fPathBlocked, FIELD_BOOLEAN ), - DEFINE_FIELD( CLeech, m_flAccelerate, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_obstacle, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_top, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_bottom, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_height, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_waterTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_sideTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_zTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_stateTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_attackSoundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CLeech, CBaseMonster ) - -const char *CLeech::pAttackSounds[] = -{ - "leech/leech_bite1.wav", - "leech/leech_bite2.wav", - "leech/leech_bite3.wav", -}; - -const char *CLeech::pAlertSounds[] = -{ - "leech/leech_alert1.wav", - "leech/leech_alert2.wav", -}; - -void CLeech::Spawn( void ) -{ - Precache(); - SET_MODEL( ENT( pev ), "models/leech.mdl" ); - // Just for fun - // SET_MODEL( ENT( pev ), "models/icky.mdl" ); - - //UTIL_SetSize( pev, g_vecZero, g_vecZero ); - UTIL_SetSize( pev, Vector( -1, -1, 0 ), Vector( 1, 1, 2 ) ); - // Don't push the minz down too much or the water check will fail because this entity is really point-sized - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - SetBits( pev->flags, FL_SWIM ); - pev->health = gSkillData.leechHealth; - - m_flFieldOfView = -0.5; // 180 degree FOV - m_flDistLook = 750; - MonsterInit(); - SetThink( &CLeech::SwimThink ); - SetUse( NULL ); - SetTouch( NULL ); - pev->view_ofs = g_vecZero; - - m_flTurning = 0; - m_fPathBlocked = FALSE; - SetActivity( ACT_SWIM ); - SetState( MONSTERSTATE_IDLE ); - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 1, 5 ); -} - -void CLeech::Activate( void ) -{ - RecalculateWaterlevel(); -} - -void CLeech::RecalculateWaterlevel( void ) -{ - // Calculate boundaries - Vector vecTest = pev->origin - Vector( 0, 0, 400 ); - - TraceResult tr; - - UTIL_TraceLine( pev->origin, vecTest, missile, edict(), &tr ); - if( tr.flFraction != 1.0 ) - m_bottom = tr.vecEndPos.z + 1; - else - m_bottom = vecTest.z; - - m_top = UTIL_WaterLevel( pev->origin, pev->origin.z, pev->origin.z + 400 ) - 1; - - // Chop off 20% of the outside range - float newBottom = m_bottom * 0.8 + m_top * 0.2; - m_top = m_bottom * 0.2 + m_top * 0.8; - m_bottom = newBottom; - m_height = RANDOM_FLOAT( m_bottom, m_top ); - m_waterTime = gpGlobals->time + RANDOM_FLOAT( 5, 7 ); -} - -void CLeech::SwitchLeechState( void ) -{ - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 3, 6 ); - if( m_MonsterState == MONSTERSTATE_COMBAT ) - { - m_hEnemy = NULL; - SetState( MONSTERSTATE_IDLE ); - // We may be up against the player, so redo the side checks - m_sideTime = 0; - } - else - { - Look( m_flDistLook ); - CBaseEntity *pEnemy = BestVisibleEnemy(); - if( pEnemy && pEnemy->pev->waterlevel != 0 ) - { - m_hEnemy = pEnemy; - SetState( MONSTERSTATE_COMBAT ); - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 18, 25 ); - AlertSound(); - } - } -} - -int CLeech::IRelationship( CBaseEntity *pTarget ) -{ - if( pTarget->IsPlayer() ) - return R_DL; - return CBaseMonster::IRelationship( pTarget ); -} - -void CLeech::AttackSound( void ) -{ - if( gpGlobals->time > m_attackSoundTime ) - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAttackSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackSounds ) - 1 )], 1.0, ATTN_NORM, 0, PITCH_NORM ); - m_attackSoundTime = gpGlobals->time + 0.5; - } -} - -void CLeech::AlertSound( void ) -{ - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAlertSounds[RANDOM_LONG( 0, ARRAYSIZE( pAlertSounds ) - 1 )], 1.0, ATTN_NORM * 0.5, 0, PITCH_NORM ); -} - -void CLeech::Precache( void ) -{ - size_t i; - - //PRECACHE_MODEL( "models/icky.mdl" ); - PRECACHE_MODEL( "models/leech.mdl" ); - - for( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND( pAttackSounds[i] ); - for( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND( pAlertSounds[i] ); -} - -int CLeech::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - pev->velocity = g_vecZero; - - // Nudge the leech away from the damage - if( pevInflictor ) - { - pev->velocity = ( pev->origin - pevInflictor->origin ).Normalize() * 25; - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CLeech::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case LEECH_AE_ATTACK: - AttackSound(); - CBaseEntity *pEnemy; - - pEnemy = m_hEnemy; - if( pEnemy != NULL ) - { - Vector dir, face; - - UTIL_MakeVectorsPrivate( pev->angles, face, NULL, NULL ); - face.z = 0; - dir = (pEnemy->pev->origin - pev->origin); - dir.z = 0; - dir = dir.Normalize(); - face = face.Normalize(); - - if( DotProduct( dir, face ) > 0.9 ) // Only take damage if the leech is facing the prey - pEnemy->TakeDamage( pev, pev, gSkillData.leechDmgBite, DMG_SLASH ); - } - m_stateTime -= 2; - break; - case LEECH_AE_FLOP: - // Play flop sound - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -void CLeech::MakeVectors( void ) -{ - Vector tmp = pev->angles; - tmp.x = -tmp.x; - UTIL_MakeVectors( tmp ); -} - -// -// ObstacleDistance - returns normalized distance to obstacle -// -float CLeech::ObstacleDistance( CBaseEntity *pTarget ) -{ - TraceResult tr; - Vector vecTest; - - // use VELOCITY, not angles, not all boids point the direction they are flying - //Vector vecDir = UTIL_VecToAngles( pev->velocity ); - MakeVectors(); - - // check for obstacle ahead - vecTest = pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine( pev->origin, vecTest, missile, edict(), &tr ); - - if( tr.fStartSolid ) - { - pev->speed = -LEECH_SWIM_SPEED * 0.5; - //ALERT( at_console, "Stuck from (%f %f %f) to (%f %f %f)\n", pev->oldorigin.x, pev->oldorigin.y, pev->oldorigin.z, pev->origin.x, pev->origin.y, pev->origin.z ); - //UTIL_SetOrigin( pev, pev->oldorigin ); - } - - if( tr.flFraction != 1.0 ) - { - if( ( pTarget == NULL || tr.pHit != pTarget->edict() ) ) - { - return tr.flFraction; - } - else - { - if( fabs( m_height - pev->origin.z ) > 10 ) - return tr.flFraction; - } - } - - if( m_sideTime < gpGlobals->time ) - { - // extra wide checks - vecTest = pev->origin + gpGlobals->v_right * LEECH_SIZEX * 2 + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine( pev->origin, vecTest, missile, edict(), &tr ); - if( tr.flFraction != 1.0 ) - return tr.flFraction; - - vecTest = pev->origin - gpGlobals->v_right * LEECH_SIZEX * 2 + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine( pev->origin, vecTest, missile, edict(), &tr ); - if( tr.flFraction != 1.0 ) - return tr.flFraction; - - // Didn't hit either side, so stop testing for another 0.5 - 1 seconds - m_sideTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 1 ); - } - return 1.0; -} - -void CLeech::DeadThink( void ) -{ - if( m_fSequenceFinished ) - { - if( m_Activity == ACT_DIEFORWARD ) - { - SetThink( NULL ); - StopAnimation(); - return; - } - else if( pev->flags & FL_ONGROUND ) - { - pev->solid = SOLID_NOT; - SetActivity(ACT_DIEFORWARD); - } - } - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - // Apply damage velocity, but keep out of the walls - if( pev->velocity.x != 0 || pev->velocity.y != 0 ) - { - TraceResult tr; - - // Look 0.5 seconds ahead - UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 0.5, missile, edict(), &tr ); - if( tr.flFraction != 1.0 ) - { - pev->velocity.x = 0; - pev->velocity.y = 0; - } - } -} - -void CLeech::UpdateMotion( void ) -{ - float flapspeed = ( pev->speed - m_flAccelerate ) / LEECH_ACCELERATE; - m_flAccelerate = m_flAccelerate * 0.8 + pev->speed * 0.2; - - if( flapspeed < 0 ) - flapspeed = -flapspeed; - flapspeed += 1.0; - if( flapspeed < 0.5 ) - flapspeed = 0.5; - if( flapspeed > 1.9 ) - flapspeed = 1.9; - - pev->framerate = flapspeed; - - if( !m_fPathBlocked ) - pev->avelocity.y = pev->ideal_yaw; - else - pev->avelocity.y = pev->ideal_yaw * m_obstacle; - - if( pev->avelocity.y > 150 ) - m_IdealActivity = ACT_TURN_LEFT; - else if( pev->avelocity.y < -150 ) - m_IdealActivity = ACT_TURN_RIGHT; - else - m_IdealActivity = ACT_SWIM; - - // lean - float targetPitch, delta; - delta = m_height - pev->origin.z; - - if( delta < -10 ) - targetPitch = -30; - else if( delta > 10 ) - targetPitch = 30; - else - targetPitch = 0; - - pev->angles.x = UTIL_Approach( targetPitch, pev->angles.x, 60 * LEECH_FRAMETIME ); - - // bank - pev->avelocity.z = -( pev->angles.z + ( pev->avelocity.y * 0.25 ) ); - - if( m_MonsterState == MONSTERSTATE_COMBAT && HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - m_IdealActivity = ACT_MELEE_ATTACK1; - - // Out of water check - if( !pev->waterlevel ) - { - pev->movetype = MOVETYPE_TOSS; - m_IdealActivity = ACT_TWITCH; - pev->velocity = g_vecZero; - - // Animation will intersect the floor if either of these is non-zero - pev->angles.z = 0; - pev->angles.x = 0; - - if( pev->framerate < 1.0 ) - pev->framerate = 1.0; - } - else if( pev->movetype == MOVETYPE_TOSS ) - { - pev->movetype = MOVETYPE_FLY; - pev->flags &= ~FL_ONGROUND; - RecalculateWaterlevel(); - m_waterTime = gpGlobals->time + 2; // Recalc again soon, water may be rising - } - - if( m_Activity != m_IdealActivity ) - { - SetActivity( m_IdealActivity ); - } - float flInterval = StudioFrameAdvance(); - DispatchAnimEvents( flInterval ); -#if DEBUG_BEAMS - if( !m_pb ) - m_pb = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); - if( !m_pt ) - m_pt = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); - m_pb->PointsInit( pev->origin, pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST ); - m_pt->PointsInit( pev->origin, pev->origin - gpGlobals->v_right * ( pev->avelocity.y * 0.25 ) ); - if( m_fPathBlocked ) - { - float color = m_obstacle * 30; - if( m_obstacle == 1.0 ) - color = 0; - if( color > 255 ) - color = 255; - m_pb->SetColor( 255, (int)color, (int)color ); - } - else - m_pb->SetColor( 255, 255, 0 ); - m_pt->SetColor( 0, 0, 255 ); -#endif -} - -void CLeech::SwimThink( void ) -{ - TraceResult tr; - float flLeftSide; - float flRightSide; - float targetSpeed; - float targetYaw = 0; - CBaseEntity *pTarget; - - if( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 1, 1.5 ); - pev->velocity = g_vecZero; - return; - } - else - pev->nextthink = gpGlobals->time + 0.1; - - targetSpeed = LEECH_SWIM_SPEED; - - if( m_waterTime < gpGlobals->time ) - RecalculateWaterlevel(); - - if( m_stateTime < gpGlobals->time ) - SwitchLeechState(); - - ClearConditions( bits_COND_CAN_MELEE_ATTACK1 ); - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - pTarget = m_hEnemy; - if( !pTarget ) - SwitchLeechState(); - else - { - // Chase the enemy's eyes - m_height = pTarget->pev->origin.z + pTarget->pev->view_ofs.z - 5; - // Clip to viable water area - if( m_height < m_bottom ) - m_height = m_bottom; - else if( m_height > m_top ) - m_height = m_top; - Vector location = pTarget->pev->origin - pev->origin; - location.z += (pTarget->pev->view_ofs.z); - if( location.Length() < 40 ) - SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); - // Turn towards target ent - targetYaw = UTIL_VecToYaw( location ); - - targetYaw = UTIL_AngleDiff( targetYaw, UTIL_AngleMod( pev->angles.y ) ); - - if( targetYaw < ( -LEECH_TURN_RATE * 0.75 ) ) - targetYaw = ( -LEECH_TURN_RATE * 0.75 ); - else if( targetYaw > ( LEECH_TURN_RATE * 0.75 ) ) - targetYaw = ( LEECH_TURN_RATE * 0.75 ); - else - targetSpeed *= 2; - } - break; - default: - if( m_zTime < gpGlobals->time ) - { - float newHeight = RANDOM_FLOAT( m_bottom, m_top ); - m_height = 0.5 * m_height + 0.5 * newHeight; - m_zTime = gpGlobals->time + RANDOM_FLOAT( 1, 4 ); - } - if( RANDOM_LONG( 0, 100 ) < 10 ) - targetYaw = RANDOM_LONG( -30, 30 ); - pTarget = NULL; - - // oldorigin test - if( ( pev->origin - pev->oldorigin ).Length() < 1 ) - { - // If leech didn't move, there must be something blocking it, so try to turn - m_sideTime = 0; - } - break; - } - - m_obstacle = ObstacleDistance( pTarget ); - pev->oldorigin = pev->origin; - if( m_obstacle < 0.1 ) - m_obstacle = 0.1; - - // is the way ahead clear? - if( m_obstacle == 1.0 ) - { - // if the leech is turning, stop the trend. - if( m_flTurning != 0 ) - { - m_flTurning = 0; - } - - m_fPathBlocked = FALSE; - pev->speed = UTIL_Approach( targetSpeed, pev->speed, LEECH_SWIM_ACCEL * LEECH_FRAMETIME ); - pev->velocity = gpGlobals->v_forward * pev->speed; - - } - else - { - m_obstacle = 1.0 / m_obstacle; - // IF we get this far in the function, the leader's path is blocked! - m_fPathBlocked = TRUE; - - if( m_flTurning == 0 )// something in the way and leech is not already turning to avoid - { - Vector vecTest; - // measure clearance on left and right to pick the best dir to turn - vecTest = pev->origin + ( gpGlobals->v_right * LEECH_SIZEX ) + ( gpGlobals->v_forward * LEECH_CHECK_DIST ); - UTIL_TraceLine( pev->origin, vecTest, missile, edict(), &tr ); - flRightSide = tr.flFraction; - - vecTest = pev->origin + ( gpGlobals->v_right * -LEECH_SIZEX ) + ( gpGlobals->v_forward * LEECH_CHECK_DIST ); - UTIL_TraceLine( pev->origin, vecTest, missile, edict(), &tr ); - flLeftSide = tr.flFraction; - - // turn left, right or random depending on clearance ratio - float delta = ( flRightSide - flLeftSide ); - if( delta > 0.1 || ( delta > -0.1 && RANDOM_LONG( 0, 100 ) < 50 ) ) - m_flTurning = -LEECH_TURN_RATE; - else - m_flTurning = LEECH_TURN_RATE; - } - pev->speed = UTIL_Approach( -( LEECH_SWIM_SPEED * 0.5 ), pev->speed, LEECH_SWIM_DECEL * LEECH_FRAMETIME * m_obstacle ); - pev->velocity = gpGlobals->v_forward * pev->speed; - } - pev->ideal_yaw = m_flTurning + targetYaw; - UpdateMotion(); -} - -void CLeech::Killed( entvars_t *pevAttacker, int iGib ) -{ - Vector vecSplatDir; - TraceResult tr; - - //ALERT(at_aiconsole, "Leech: killed\n"); - // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. - CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); - if( pOwner ) - pOwner->DeathNotice( pev ); - - // When we hit the ground, play the "death_end" activity - if( pev->waterlevel ) - { - pev->angles.z = 0; - pev->angles.x = 0; - pev->origin.z += 1; - pev->avelocity = g_vecZero; - if( RANDOM_LONG( 0, 99 ) < 70 ) - pev->avelocity.y = RANDOM_LONG( -720, 720 ); - - pev->gravity = 0.02; - ClearBits( pev->flags, FL_ONGROUND ); - SetActivity( ACT_DIESIMPLE ); - } - else - SetActivity( ACT_DIEFORWARD ); - - pev->movetype = MOVETYPE_TOSS; - pev->takedamage = DAMAGE_NO; - SetThink( &CLeech::DeadThink ); -} diff --git a/dlls/maprules.cpp b/dlls/maprules.cpp deleted file mode 100644 index 519f7d2a..00000000 --- a/dlls/maprules.cpp +++ /dev/null @@ -1,875 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -// ------------------------------------------- -// -// maprules.cpp -// -// This module contains entities for implementing/changing game -// rules dynamically within each map (.BSP) -// -// ------------------------------------------- - -#include "extdll.h" -#include "eiface.h" -#include "util.h" -#include "gamerules.h" -//#include "maprules.h" //empty file -#include "cbase.h" -#include "player.h" - -class CRuleEntity : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void SetMaster( int iszMaster ) { m_iszMaster = iszMaster; } - -protected: - BOOL CanFireForActivator( CBaseEntity *pActivator ); - -private: - string_t m_iszMaster; -}; - -TYPEDESCRIPTION CRuleEntity::m_SaveData[] = -{ - DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING), -}; - -IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ) - -void CRuleEntity::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = EF_NODRAW; -} - -void CRuleEntity::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq(pkvd->szKeyName, "master" ) ) - { - SetMaster( ALLOC_STRING( pkvd->szValue ) ); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator ) -{ - if( m_iszMaster ) - { - if( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) - return TRUE; - else - return FALSE; - } - - return TRUE; -} - -// -// CRulePointEntity -- base class for all rule "point" entities (not brushes) -// -class CRulePointEntity : public CRuleEntity -{ -public: - void Spawn( void ); -}; - -void CRulePointEntity::Spawn( void ) -{ - CRuleEntity::Spawn(); - pev->frame = 0; - pev->model = 0; -} - -// -// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes) -// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing -// -class CRuleBrushEntity : public CRuleEntity -{ -public: - void Spawn( void ); - -private: -}; - -void CRuleBrushEntity::Spawn( void ) -{ - SET_MODEL( edict(), STRING(pev->model) ); - CRuleEntity::Spawn(); -} - -// CGameScore / game_score -- award points to player / team -// Points +/- total -// Flag: Allow negative scores SF_SCORE_NEGATIVE -// Flag: Award points to team in teamplay SF_SCORE_TEAM - -#define SF_SCORE_NEGATIVE 0x0001 -#define SF_SCORE_TEAM 0x0002 - -class CGameScore : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline int Points( void ) { return (int)pev->frags; } - inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; } - inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; } - - inline void SetPoints( int points ) { pev->frags = points; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_score, CGameScore ) - -void CGameScore::Spawn( void ) -{ - CRulePointEntity::Spawn(); -} - -void CGameScore::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "points" ) ) - { - SetPoints( atoi( pkvd->szValue ) ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - -void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - // Only players can use this - if( pActivator->IsPlayer() ) - { - if( AwardToTeam() ) - { - pActivator->AddPointsToTeam( Points(), AllowNegativeScore() ); - } - else - { - pActivator->AddPoints( Points(), AllowNegativeScore() ); - } - } -} - -// CGameEnd / game_end -- Ends the game in MP - -class CGameEnd : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -private: -}; - -LINK_ENTITY_TO_CLASS( game_end, CGameEnd ) - -void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - g_pGameRules->EndMultiplayerGame(); -} - -// -// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message) -// Flag: All players SF_ENVTEXT_ALLPLAYERS -// - -#define SF_ENVTEXT_ALLPLAYERS 0x0001 - -class CGameText : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline BOOL MessageToAll( void ) { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS); } - inline void MessageSet( const char *pMessage ) { pev->message = ALLOC_STRING(pMessage); } - inline const char *MessageGet( void ) { return STRING(pev->message); } - -private: - - hudtextparms_t m_textParms; -}; - -LINK_ENTITY_TO_CLASS( game_text, CGameText ) - -// Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so -// it can't impact saved Half-Life games. -TYPEDESCRIPTION CGameText::m_SaveData[] = -{ - DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ), -}; - -IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ) - -void CGameText::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "channel" ) ) - { - m_textParms.channel = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "x" ) ) - { - m_textParms.x = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq(pkvd->szKeyName, "y" ) ) - { - m_textParms.y = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "effect" ) ) - { - m_textParms.effect = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "color" ) ) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r1 = color[0]; - m_textParms.g1 = color[1]; - m_textParms.b1 = color[2]; - m_textParms.a1 = color[3]; - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "color2" ) ) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r2 = color[0]; - m_textParms.g2 = color[1]; - m_textParms.b2 = color[2]; - m_textParms.a2 = color[3]; - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "fadein" ) ) - { - m_textParms.fadeinTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "fadeout" ) ) - { - m_textParms.fadeoutTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "holdtime" ) ) - { - m_textParms.holdTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq(pkvd->szKeyName, "fxtime" ) ) - { - m_textParms.fxTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - -void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - if( MessageToAll() ) - { - UTIL_HudMessageAll( m_textParms, MessageGet() ); - } - else - { - if( pActivator->IsNetClient() ) - { - UTIL_HudMessage( pActivator, m_textParms, MessageGet() ); - } - } -} - -// -// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator -// Only allows mastered entity to fire if the team matches my team -// -// team index (pulled from server team list "mp_teamlist" -// Flag: Remove on Fire -// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it) -// - -#define SF_TEAMMASTER_FIREONCE 0x0001 -#define SF_TEAMMASTER_ANYTEAM 0x0002 - -class CGameTeamMaster : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int ObjectCaps( void ) { return CRulePointEntity:: ObjectCaps() | FCAP_MASTER; } - - BOOL IsTriggered( CBaseEntity *pActivator ); - const char *TeamID( void ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) ? TRUE : FALSE; } - inline BOOL AnyTeam( void ) { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) ? TRUE : FALSE; } - -private: - BOOL TeamMatch( CBaseEntity *pActivator ); - - int m_teamIndex; - USE_TYPE triggerType; -}; - -LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ) - -void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "teamindex" ) ) - { - m_teamIndex = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "triggerstate" ) ) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - -void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - if( useType == USE_SET ) - { - if( value < 0 ) - { - m_teamIndex = -1; - } - else - { - m_teamIndex = g_pGameRules->GetTeamIndex( pActivator->TeamID() ); - } - return; - } - - if( TeamMatch( pActivator ) ) - { - SUB_UseTargets( pActivator, triggerType, value ); - if( RemoveOnFire() ) - UTIL_Remove( this ); - } -} - -BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) -{ - return TeamMatch( pActivator ); -} - -const char *CGameTeamMaster::TeamID( void ) -{ - if( m_teamIndex < 0 ) // Currently set to "no team" - return ""; - - return g_pGameRules->GetIndexedTeamName( m_teamIndex ); // UNDONE: Fill this in with the team from the "teamlist" -} - -BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) -{ - if( m_teamIndex < 0 && AnyTeam() ) - return TRUE; - - if( !pActivator ) - return FALSE; - - return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() ); -} - -// -// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team -// Flag: Fire once -// Flag: Clear team -- Sets the team to "NONE" instead of activator - -#define SF_TEAMSET_FIREONCE 0x0001 -#define SF_TEAMSET_CLEARTEAM 0x0002 - -class CGameTeamSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMSET_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldClearTeam( void ) { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ) - -void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - if( ShouldClearTeam() ) - { - SUB_UseTargets( pActivator, USE_SET, -1 ); - } - else - { - SUB_UseTargets( pActivator, USE_SET, 0 ); - } - - if( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - -// -// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired -// -// Needs master? -class CGamePlayerZone : public CRuleBrushEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - string_t m_iszInTarget; - string_t m_iszOutTarget; - string_t m_iszInCount; - string_t m_iszOutCount; -}; - -LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone ) -TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = -{ - DEFINE_FIELD( CGamePlayerZone, m_iszInTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszInCount, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ) - -void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq(pkvd->szKeyName, "intarget" ) ) - { - m_iszInTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "outtarget" ) ) - { - m_iszOutTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "incount" ) ) - { - m_iszInCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "outcount" ) ) - { - m_iszOutCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRuleBrushEntity::KeyValue( pkvd ); -} - -void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int playersInCount = 0; - int playersOutCount = 0; - - if( !CanFireForActivator( pActivator ) ) - return; - - CBaseEntity *pPlayer = NULL; - - for( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - { - TraceResult trace; - int hullNumber; - - hullNumber = human_hull; - if( pPlayer->pev->flags & FL_DUCKING ) - { - hullNumber = head_hull; - } - - UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace ); - - if( trace.fStartSolid ) - { - playersInCount++; - if( m_iszInTarget ) - { - FireTargets( STRING( m_iszInTarget ), pPlayer, pActivator, useType, value ); - } - } - else - { - playersOutCount++; - if( m_iszOutTarget ) - { - FireTargets( STRING( m_iszOutTarget ), pPlayer, pActivator, useType, value ); - } - } - } - } - - if( m_iszInCount ) - { - FireTargets( STRING( m_iszInCount ), pActivator, this, USE_SET, playersInCount ); - } - - if( m_iszOutCount ) - { - FireTargets( STRING( m_iszOutCount ), pActivator, this, USE_SET, playersOutCount ); - } -} - -// -// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it -// Flag: Fire once - -#define SF_PKILL_FIREONCE 0x0001 - -class CGamePlayerHurt : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PKILL_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ) - -void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - if( pActivator->IsPlayer() ) - { - if( pev->dmg < 0 ) - pActivator->TakeHealth( -pev->dmg, DMG_GENERIC ); - else - pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); - } - - SUB_UseTargets( pActivator, useType, value ); - - if( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - -// -// CGameCounter / game_counter -- Counts events and fires target -// Flag: Fire once -// Flag: Reset on Fire - -#define SF_GAMECOUNT_FIREONCE 0x0001 -#define SF_GAMECOUNT_RESET 0x0002 - -class CGameCounter : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) ? TRUE : FALSE; } - inline BOOL ResetOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_RESET) ? TRUE : FALSE; } - - inline void CountUp( void ) { pev->frags++; } - inline void CountDown( void ) { pev->frags--; } - inline void ResetCount( void ) { pev->frags = pev->dmg; } - inline int CountValue( void ) { return (int)pev->frags; } - inline int LimitValue( void ) { return (int)pev->health; } - - inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } - -private: - - inline void SetCountValue( int value ) { pev->frags = value; } - inline void SetInitialValue( int value ) { pev->dmg = value; } -}; - -LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ) - -void CGameCounter::Spawn( void ) -{ - // Save off the initial count - SetInitialValue( CountValue() ); - CRulePointEntity::Spawn(); -} - -void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - switch( useType ) - { - case USE_ON: - case USE_TOGGLE: - CountUp(); - break; - case USE_OFF: - CountDown(); - break; - case USE_SET: - SetCountValue( (int)value ); - break; - } - - if( HitLimit() ) - { - SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); - if( RemoveOnFire() ) - { - UTIL_Remove( this ); - } - - if( ResetOnFire() ) - { - ResetCount(); - } - } -} - -// -// CGameCounterSet / game_counter_set -- Sets the counter's value -// Flag: Fire once - -#define SF_GAMECOUNTSET_FIREONCE 0x0001 - -class CGameCounterSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ) - -void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - SUB_UseTargets( pActivator, USE_SET, pev->frags ); - - if( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - -// -// CGamePlayerEquip / game_playerequip -- Sets the default player equipment -// Flag: USE Only - -#define SF_PLAYEREQUIP_USEONLY 0x0001 -#define MAX_EQUIP 32 - -class CGamePlayerEquip : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - inline BOOL UseOnly( void ) { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) ? TRUE : FALSE; } - -private: - void EquipPlayer( CBaseEntity *pPlayer ); - - string_t m_weaponNames[MAX_EQUIP]; - int m_weaponCount[MAX_EQUIP]; -}; - -LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip ) - -void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) -{ - CRulePointEntity::KeyValue( pkvd ); - - if( !pkvd->fHandled ) - { - for( int i = 0; i < MAX_EQUIP; i++ ) - { - if( !m_weaponNames[i] ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - - m_weaponNames[i] = ALLOC_STRING( tmp ); - m_weaponCount[i] = atoi( pkvd->szValue ); - m_weaponCount[i] = Q_max( 1, m_weaponCount[i] ); - pkvd->fHandled = TRUE; - break; - } - } - } -} - -void CGamePlayerEquip::Touch( CBaseEntity *pOther ) -{ - if( !CanFireForActivator( pOther ) ) - return; - - if( UseOnly() ) - return; - - EquipPlayer( pOther ); -} - -void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) -{ - CBasePlayer *pPlayer = NULL; - - if( pEntity->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pEntity; - } - - if( !pPlayer ) - return; - - for( int i = 0; i < MAX_EQUIP; i++ ) - { - if( !m_weaponNames[i] ) - break; - for( int j = 0; j < m_weaponCount[i]; j++ ) - { - pPlayer->GiveNamedItem( STRING( m_weaponNames[i] ) ); - } - } -} - -void CGamePlayerEquip::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - EquipPlayer( pActivator ); -} - -// -// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it -// Flag: Fire once -// Flag: Kill Player -// Flag: Gib Player - -#define SF_PTEAM_FIREONCE 0x0001 -#define SF_PTEAM_KILL 0x0002 -#define SF_PTEAM_GIB 0x0004 - -class CGamePlayerTeam : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -private: - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PTEAM_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldKillPlayer( void ) { return (pev->spawnflags & SF_PTEAM_KILL) ? TRUE : FALSE; } - inline BOOL ShouldGibPlayer( void ) { return (pev->spawnflags & SF_PTEAM_GIB) ? TRUE : FALSE; } - - const char *TargetTeamName( const char *pszTargetName ); -}; - -LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ) - -const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) -{ - CBaseEntity *pTeamEntity = NULL; - - while( ( pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName ) ) != NULL ) - { - if( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) - return pTeamEntity->TeamID(); - } - - return NULL; -} - -void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !CanFireForActivator( pActivator ) ) - return; - - if( pActivator->IsPlayer() ) - { - const char *pszTargetTeam = TargetTeamName( STRING(pev->target) ); - if ( pszTargetTeam ) - { - CBasePlayer *pPlayer = (CBasePlayer *)pActivator; - g_pGameRules->ChangePlayerTeam( pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer() ); - } - } - - if( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} diff --git a/dlls/maprules.h b/dlls/maprules.h deleted file mode 100644 index 70a88fb5..00000000 --- a/dlls/maprules.h +++ /dev/null @@ -1,19 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef MAPRULES_H -#define MAPRULES_H -#endif //MAPRULES_H - diff --git a/dlls/monstermaker.cpp b/dlls/monstermaker.cpp deleted file mode 100644 index 38173d41..00000000 --- a/dlls/monstermaker.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Monster Maker - this is an entity that creates monsters -// in the game. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "saverestore.h" - -// Monstermaker spawnflags -#define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname ) -#define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired. -#define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip - -//========================================================= -// MonsterMaker - this ent creates monsters during the game. -//========================================================= -class CMonsterMaker : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT CyclicUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT MakerThink( void ); - void DeathNotice( entvars_t *pevChild );// monster maker children use this to tell the monster maker that they have died. - void MakeMonster( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - string_t m_iszMonsterClassname;// classname of the monster(s) that will be created. - - int m_cNumMonsters;// max number of monsters this ent can create - - int m_cLiveChildren;// how many monsters made by this monster maker that are currently alive - int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time. - - float m_flGround; // z coord of the ground under me, used to make sure no monsters are under the maker when it drops a new child - - BOOL m_fActive; - BOOL m_fFadeChildren;// should we make the children fadeout? -}; - -LINK_ENTITY_TO_CLASS( monstermaker, CMonsterMaker ) - -TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = -{ - DEFINE_FIELD( CMonsterMaker, m_iszMonsterClassname, FIELD_STRING ), - DEFINE_FIELD( CMonsterMaker, m_cNumMonsters, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_cLiveChildren, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_flGround, FIELD_FLOAT ), - DEFINE_FIELD( CMonsterMaker, m_iMaxLiveChildren, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_fActive, FIELD_BOOLEAN ), - DEFINE_FIELD( CMonsterMaker, m_fFadeChildren, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster ) - -void CMonsterMaker::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "monstercount" ) ) - { - m_cNumMonsters = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "m_imaxlivechildren" ) ) - { - m_iMaxLiveChildren = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "monstertype" ) ) - { - m_iszMonsterClassname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -void CMonsterMaker::Spawn() -{ - pev->solid = SOLID_NOT; - - m_cLiveChildren = 0; - Precache(); - if( !FStringNull( pev->targetname ) ) - { - if( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) - { - SetUse( &CMonsterMaker::CyclicUse );// drop one monster each time we fire - } - else - { - SetUse( &CMonsterMaker::ToggleUse );// so can be turned on/off - } - - if( FBitSet( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) - { - // start making monsters as soon as monstermaker spawns - m_fActive = TRUE; - SetThink( &CMonsterMaker::MakerThink ); - } - else - { - // wait to be activated. - m_fActive = FALSE; - SetThink( &CBaseEntity::SUB_DoNothing ); - } - } - else - { - // no targetname, just start. - pev->nextthink = gpGlobals->time + m_flDelay; - m_fActive = TRUE; - SetThink( &CMonsterMaker::MakerThink ); - } - - if( m_cNumMonsters == 1 ) - { - m_fFadeChildren = FALSE; - } - else - { - m_fFadeChildren = TRUE; - } - - m_flGround = 0; -} - -void CMonsterMaker::Precache( void ) -{ - CBaseMonster::Precache(); - - UTIL_PrecacheOther( STRING( m_iszMonsterClassname ) ); -} - -//========================================================= -// MakeMonster- this is the code that drops the monster -//========================================================= -void CMonsterMaker::MakeMonster( void ) -{ - edict_t *pent; - entvars_t *pevCreate; - - 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( pev->origin, pev->origin - Vector( 0, 0, 2048 ), ignore_monsters, ENT( pev ), &tr ); - m_flGround = tr.vecEndPos.z; - } - - Vector mins = pev->origin - Vector( 34, 34, 0 ); - Vector maxs = pev->origin + Vector( 34, 34, 0 ); - maxs.z = pev->origin.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; - } - - pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname ); - - if( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in MonsterMaker!\n" ); - return; - } - - // If I have a target, fire! - if( !FStringNull( pev->target ) ) - { - // delay already overloaded for this entity, so can't call SUB_UseTargets() - FireTargets( STRING( pev->target ), this, this, USE_TOGGLE, 0 ); - } - - pevCreate = VARS( pent ); - pevCreate->origin = pev->origin; - pevCreate->angles = pev->angles; - SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND ); - - // Children hit monsterclip brushes - if( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) - SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP ); - - DispatchSpawn( ENT( pevCreate ) ); - pevCreate->owner = edict(); - - if( !FStringNull( pev->netname ) ) - { - // if I have a netname (overloaded), give the child monster that name as a targetname - pevCreate->targetname = pev->netname; - } - - 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 ); - } -} - -//========================================================= -// CyclicUse - drops one monster from the monstermaker -// each time we call this. -//========================================================= -void CMonsterMaker::CyclicUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - MakeMonster(); -} - -//========================================================= -// ToggleUse - activates/deactivates the monster maker -//========================================================= -void CMonsterMaker::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if( !ShouldToggle( useType, m_fActive ) ) - return; - - if( m_fActive ) - { - m_fActive = FALSE; - SetThink( NULL ); - } - else - { - m_fActive = TRUE; - SetThink( &CMonsterMaker::MakerThink ); - } - - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// MakerThink - creates a new monster every so often -//========================================================= -void CMonsterMaker::MakerThink( void ) -{ - pev->nextthink = gpGlobals->time + m_flDelay; - - MakeMonster(); -} - -//========================================================= -//========================================================= -void CMonsterMaker::DeathNotice( entvars_t *pevChild ) -{ - // ok, we've gotten the deathnotice from our child, now clear out its owner if we don't want it to fade. - m_cLiveChildren--; - - if( !m_fFadeChildren ) - { - pevChild->owner = NULL; - } -} diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp deleted file mode 100644 index 403efa04..00000000 --- a/dlls/mp5.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "gamerules.h" - -enum mp5_e -{ - MP5_LONGIDLE = 0, - MP5_IDLE1, - MP5_LAUNCH, - MP5_RELOAD, - MP5_DEPLOY, - MP5_FIRE1, - MP5_FIRE2, - MP5_FIRE3 -}; - -LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 ) -LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ) - -//========================================================= -//========================================================= -int CMP5::SecondaryAmmoIndex( void ) -{ - return m_iSecondaryAmmoType; -} - -void CMP5::Spawn() -{ - pev->classname = MAKE_STRING( "weapon_9mmAR" ); // hack to allow for old names - Precache(); - SET_MODEL( ENT( pev ), "models/w_9mmAR.mdl" ); - m_iId = WEAPON_MP5; - - m_iDefaultAmmo = MP5_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -void CMP5::Precache( void ) -{ - PRECACHE_MODEL( "models/v_9mmAR.mdl" ); - PRECACHE_MODEL( "models/w_9mmAR.mdl" ); - PRECACHE_MODEL( "models/p_9mmAR.mdl" ); - - m_iShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shellTE_MODEL - - PRECACHE_MODEL( "models/grenade.mdl" ); // grenade - - PRECACHE_MODEL( "models/w_9mmARclip.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - - PRECACHE_SOUND( "items/clipinsert1.wav" ); - PRECACHE_SOUND( "items/cliprelease1.wav" ); - - PRECACHE_SOUND( "weapons/hks1.wav" );// H to the K - PRECACHE_SOUND( "weapons/hks2.wav" );// H to the K - PRECACHE_SOUND( "weapons/hks3.wav" );// H to the K - - PRECACHE_SOUND( "weapons/glauncher.wav" ); - PRECACHE_SOUND( "weapons/glauncher2.wav" ); - - PRECACHE_SOUND( "weapons/357_cock1.wav" ); - - m_usMP5 = PRECACHE_EVENT( 1, "events/mp5.sc" ); - m_usMP52 = PRECACHE_EVENT( 1, "events/mp52.sc" ); -} - -int CMP5::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = "ARgrenades"; - p->iMaxAmmo2 = M203_GRENADE_MAX_CARRY; - p->iMaxClip = MP5_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_MP5; - p->iWeight = MP5_WEIGHT; - - return 1; -} - -int CMP5::AddToPlayer( CBasePlayer *pPlayer ) -{ - if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -BOOL CMP5::Deploy() -{ - return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" ); -} - -void CMP5::PrimaryAttack() -{ - // don't fire underwater - if( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound(); - m_flNextPrimaryAttack = 0.15; - return; - } - - if( m_iClip <= 0 ) - { - PlayEmptySound(); - m_flNextPrimaryAttack = 0.15; - return; - } - - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip--; - - m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector vecSrc = m_pPlayer->GetGunPosition(); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - Vector vecDir; -#ifdef CLIENT_DLL - if( !bIsMultiplayer() ) -#else - if( !g_pGameRules->IsMultiplayer() ) -#endif - { - // optimized multiplayer. Widened to make it easier to hit a moving player - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // single player spread - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usMP5, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if( !m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - - m_flNextPrimaryAttack = GetNextAttackDelay( 0.1 ); - - if( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - -void CMP5::SecondaryAttack( void ) -{ - // don't fire underwater - if( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = 0.15; - return; - } - - if( m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] == 0 ) - { - PlayEmptySound(); - return; - } - - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - - m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER; - m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2; - - m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - // we don't add in player velocity anymore. - CGrenade::ShootContact( m_pPlayer->pev, - m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16, - gpGlobals->v_forward * 800 ); - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); - - m_flNextPrimaryAttack = GetNextAttackDelay( 1 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting. - - if( !m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] ) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); -} - -void CMP5::Reload( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == MP5_MAX_CLIP ) - return; - - DefaultReload( MP5_MAX_CLIP, MP5_RELOAD, 1.5 ); -} - -void CMP5::WeaponIdle( void ) -{ - ResetEmptySound(); - - m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - int iAnim; - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - iAnim = MP5_LONGIDLE; - break; - default: - case 1: - iAnim = MP5_IDLE1; - break; - } - - SendWeaponAnim( iAnim ); - - m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. -} - -BOOL CMP5::IsUseable() -{ - //Can be used if the player has AR grenades. - Solokiller - return CBasePlayerWeapon::IsUseable() || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] > 0; -} - -class CMP5AmmoClip : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT( pev ), "models/w_9mmARclip.mdl" ); - CBasePlayerAmmo::Spawn(); - } - void Precache( void ) - { - PRECACHE_MODEL( "models/w_9mmARclip.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = ( pOther->GiveAmmo( AMMO_MP5CLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1 ); - if( bResult ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - } - return bResult; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip ) -LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip ) - -class CMP5Chainammo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT( pev ), "models/w_chainammo.mdl" ); - CBasePlayerAmmo::Spawn(); - } - void Precache( void ) - { - PRECACHE_MODEL( "models/w_chainammo.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = ( pOther->GiveAmmo( AMMO_CHAINBOX_GIVE, "9mm", _9MM_MAX_CARRY ) != -1 ); - if( bResult ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - } - return bResult; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_9mmbox, CMP5Chainammo ) - -class CMP5AmmoGrenade : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT( pev ), "models/w_ARgrenade.mdl" ); - CBasePlayerAmmo::Spawn(); - } - void Precache( void ) - { - PRECACHE_MODEL( "models/w_ARgrenade.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = ( pOther->GiveAmmo( AMMO_M203BOX_GIVE, "ARgrenades", M203_GRENADE_MAX_CARRY ) != -1 ); - - if( bResult ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - } - return bResult; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_mp5grenades, CMP5AmmoGrenade ) -LINK_ENTITY_TO_CLASS( ammo_ARgrenades, CMP5AmmoGrenade ) diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp deleted file mode 100644 index 1d072db4..00000000 --- a/dlls/nihilanth.cpp +++ /dev/null @@ -1,1818 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" - -#define N_SCALE 15 -#define N_SPHERES 20 - -class CNihilanth : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - void UpdateOnRemove(); - int Classify( void ) { return CLASS_ALIEN_MILITARY; }; - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -16 * N_SCALE, -16 * N_SCALE, -48 * N_SCALE ); - pev->absmax = pev->origin + Vector( 16 * N_SCALE, 16 * N_SCALE, 28 * N_SCALE ); - } - - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void EXPORT StartupThink( void ); - void EXPORT HuntThink( void ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT NullThink( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void FloatSequence( void ); - void NextActivity( void ); - - void Flight( void ); - - BOOL AbsorbSphere( void ); - BOOL EmitSphere( void ); - void TargetSphere( USE_TYPE useType, float value ); - CBaseEntity *RandomTargetname( const char *szName ); - void ShootBalls( void ); - void MakeFriend( Vector vecPos ); - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - - void PainSound( void ); - void DeathSound( void ); - - static const char *pAttackSounds[]; // vocalization: play sometimes when he launches an attack - static const char *pBallSounds[]; // the sound of the lightening ball launch - static const char *pShootSounds[]; // grunting vocalization: play sometimes when he launches an attack - static const char *pRechargeSounds[]; // vocalization: play when he recharges - static const char *pLaughSounds[]; // vocalization: play sometimes when hit and still has lots of health - static const char *pPainSounds[]; // vocalization: play sometimes when hit and has much less health and no more chargers - static const char *pDeathSounds[]; // vocalization: play as he dies - - // x_teleattack1.wav the looping sound of the teleport attack ball. - - float m_flForce; - - float m_flNextPainSound; - - Vector m_velocity; - Vector m_avelocity; - - Vector m_vecTarget; - Vector m_posTarget; - - Vector m_vecDesired; - Vector m_posDesired; - - float m_flMinZ; - float m_flMaxZ; - - Vector m_vecGoal; - - float m_flLastSeen; - float m_flPrevSeen; - - int m_irritation; - - int m_iLevel; - int m_iTeleport; - - EHANDLE m_hRecharger; - - EHANDLE m_hSphere[N_SPHERES]; - int m_iActiveSpheres; - - float m_flAdj; - - CSprite *m_pBall; - - char m_szRechargerTarget[64]; - char m_szDrawUse[64]; - char m_szTeleportUse[64]; - char m_szTeleportTouch[64]; - char m_szDeadUse[64]; - char m_szDeadTouch[64]; - - float m_flShootEnd; - float m_flShootTime; - - EHANDLE m_hFriend[3]; -}; - -LINK_ENTITY_TO_CLASS( monster_nihilanth, CNihilanth ) - -TYPEDESCRIPTION CNihilanth::m_SaveData[] = -{ - DEFINE_FIELD( CNihilanth, m_flForce, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_flNextPainSound, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_velocity, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_avelocity, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_posTarget, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CNihilanth, m_vecDesired, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_posDesired, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CNihilanth, m_flMinZ, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_flMaxZ, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_vecGoal, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_flLastSeen, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_flPrevSeen, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_irritation, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_iLevel, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_iTeleport, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_hRecharger, FIELD_EHANDLE ), - DEFINE_ARRAY( CNihilanth, m_hSphere, FIELD_EHANDLE, N_SPHERES ), - DEFINE_FIELD( CNihilanth, m_iActiveSpheres, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_flAdj, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_pBall, FIELD_CLASSPTR ), - DEFINE_ARRAY( CNihilanth, m_szRechargerTarget, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDrawUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szTeleportUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szTeleportTouch, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDeadUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDeadTouch, FIELD_CHARACTER, 64 ), - DEFINE_FIELD( CNihilanth, m_flShootEnd, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_flShootTime, FIELD_TIME ), - DEFINE_ARRAY( CNihilanth, m_hFriend, FIELD_EHANDLE, 3 ), -}; - -IMPLEMENT_SAVERESTORE( CNihilanth, CBaseMonster ) - -class CNihilanthHVR : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - - void CircleInit( CBaseEntity *pTarget ); - void AbsorbInit( void ); - void TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ); - void GreenBallInit( void ); - void ZapInit( CBaseEntity *pEnemy ); - - void EXPORT HoverThink( void ); - BOOL CircleTarget( Vector vecTarget ); - void EXPORT DissipateThink( void ); - - void EXPORT ZapThink( void ); - void EXPORT TeleportThink( void ); - void EXPORT TeleportTouch( CBaseEntity *pOther ); - - void EXPORT RemoveTouch( CBaseEntity *pOther ); - void EXPORT BounceTouch( CBaseEntity *pOther ); - void EXPORT ZapTouch( CBaseEntity *pOther ); - - CBaseEntity *RandomClassname( const char *szName ); - - // void EXPORT SphereUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void MovetoTarget( Vector vecTarget ); - virtual void Crawl( void ); - - void Zap( void ); - void Teleport( void ); - - float m_flIdealVel; - Vector m_vecIdeal; - CNihilanth *m_pNihilanth; - EHANDLE m_hTouch; - int m_nFrames; -}; - -LINK_ENTITY_TO_CLASS( nihilanth_energy_ball, CNihilanthHVR ) - -TYPEDESCRIPTION CNihilanthHVR::m_SaveData[] = -{ - DEFINE_FIELD( CNihilanthHVR, m_flIdealVel, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanthHVR, m_vecIdeal, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanthHVR, m_pNihilanth, FIELD_CLASSPTR ), - DEFINE_FIELD( CNihilanthHVR, m_hTouch, FIELD_EHANDLE ), - DEFINE_FIELD( CNihilanthHVR, m_nFrames, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CNihilanthHVR, CBaseMonster ) - -//========================================================= -// Nihilanth, final Boss monster -//========================================================= - -const char *CNihilanth::pAttackSounds[] = -{ - "X/x_attack1.wav", - "X/x_attack2.wav", - "X/x_attack3.wav", -}; - -const char *CNihilanth::pBallSounds[] = -{ - "X/x_ballattack1.wav", -}; - -const char *CNihilanth::pShootSounds[] = -{ - "X/x_shoot1.wav", -}; - -const char *CNihilanth::pRechargeSounds[] = -{ - "X/x_recharge1.wav", - "X/x_recharge2.wav", - "X/x_recharge3.wav", -}; - -const char *CNihilanth::pLaughSounds[] = -{ - "X/x_laugh1.wav", - "X/x_laugh2.wav", -}; - -const char *CNihilanth::pPainSounds[] = -{ - "X/x_pain1.wav", - "X/x_pain2.wav", -}; - -const char *CNihilanth::pDeathSounds[] = -{ - "X/x_die1.wav", -}; - -void CNihilanth::Spawn( void ) -{ - Precache(); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL( edict(), "models/nihilanth.mdl" ); - // UTIL_SetSize(pev, Vector( -300, -300, 0), Vector(300, 300, 512)); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.nihilanthHealth; - pev->view_ofs = Vector( 0, 0, 300 ); - - m_flFieldOfView = -1; // 360 degrees - - pev->sequence = 0; - ResetSequenceInfo(); - - InitBoneControllers(); - - SetThink( &CNihilanth::StartupThink ); - pev->nextthink = gpGlobals->time + 0.1; - - m_vecDesired = Vector( 1, 0, 0 ); - m_posDesired = Vector( pev->origin.x, pev->origin.y, 512 ); - - m_iLevel = 1; - m_iTeleport = 1; - - if( m_szRechargerTarget[0] == '\0' ) - strcpy( m_szRechargerTarget, "n_recharger" ); - if( m_szDrawUse[0] == '\0' ) - strcpy( m_szDrawUse, "n_draw" ); - if( m_szTeleportUse[0] == '\0' ) - strcpy( m_szTeleportUse, "n_leaving" ); - if( m_szTeleportTouch[0] == '\0' ) - strcpy( m_szTeleportTouch, "n_teleport" ); - if( m_szDeadUse[0] == '\0' ) - strcpy( m_szDeadUse, "n_dead" ); - if( m_szDeadTouch[0] == '\0' ) - strcpy( m_szDeadTouch, "n_ending" ); - - // near death - /* - m_iTeleport = 10; - m_iLevel = 10; - m_irritation = 2; - pev->health = 100; - */ -} - -void CNihilanth::Precache( void ) -{ - PRECACHE_MODEL( "models/nihilanth.mdl" ); - PRECACHE_MODEL( "sprites/lgtning.spr" ); - UTIL_PrecacheOther( "nihilanth_energy_ball" ); - UTIL_PrecacheOther( "monster_alien_controller" ); - UTIL_PrecacheOther( "monster_alien_slave" ); - - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pBallSounds ); - PRECACHE_SOUND_ARRAY( pShootSounds ); - PRECACHE_SOUND_ARRAY( pRechargeSounds ); - PRECACHE_SOUND_ARRAY( pLaughSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_SOUND( "debris/beamstart7.wav" ); -} - -void CNihilanth::UpdateOnRemove() -{ - CBaseEntity::UpdateOnRemove(); - - if( m_pBall ) - { - UTIL_Remove( m_pBall ); - m_pBall = 0; - } - - for( int i = 0; i < N_SPHERES; i++ ) - { - if( CBaseEntity* pSphere = (CBaseEntity *)m_hSphere[i] ) - { - UTIL_Remove( pSphere ); - m_hSphere[i] = 0; - } - } -} - -void CNihilanth::PainSound( void ) -{ - if( m_flNextPainSound > gpGlobals->time ) - return; - - m_flNextPainSound = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); - - if( pev->health > gSkillData.nihilanthHealth / 2 ) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pLaughSounds ), 1.0, 0.2 ); - } - else if( m_irritation >= 2 ) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1.0, 0.2 ); - } -} - -void CNihilanth::DeathSound( void ) -{ - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), 1.0, 0.1 ); -} - -void CNihilanth::NullThink( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.5; -} - -void CNihilanth::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CNihilanth::HuntThink ); - pev->nextthink = gpGlobals->time + 0.1; - SetUse( &CNihilanth::CommandUse ); -} - -void CNihilanth::StartupThink( void ) -{ - m_irritation = 0; - m_flAdj = 512; - - CBaseEntity *pEntity; - - pEntity = UTIL_FindEntityByTargetname( NULL, "n_min" ); - if( pEntity ) - m_flMinZ = pEntity->pev->origin.z; - else - m_flMinZ = -4096; - - pEntity = UTIL_FindEntityByTargetname( NULL, "n_max" ); - if( pEntity ) - m_flMaxZ = pEntity->pev->origin.z; - else - m_flMaxZ = 4096; - - m_hRecharger = this; - for( int i = 0; i < N_SPHERES; i++ ) - { - EmitSphere(); - } - m_hRecharger = NULL; - - SetThink( &CNihilanth::HuntThink ); - SetUse( &CNihilanth::CommandUse ); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CNihilanth::Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster::Killed( pevAttacker, iGib ); -} - -void CNihilanth::DyingThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents(); - StudioFrameAdvance(); - - if( pev->deadflag == DEAD_NO ) - { - DeathSound(); - pev->deadflag = DEAD_DYING; - - m_posDesired.z = m_flMaxZ; - } - - if( pev->deadflag == DEAD_DYING ) - { - Flight(); - - if( fabs( pev->origin.z - m_flMaxZ ) < 16 ) - { - pev->velocity = Vector( 0, 0, 0 ); - FireTargets( m_szDeadUse, this, this, USE_ON, 1.0 ); - pev->deadflag = DEAD_DEAD; - } - } - - if( m_fSequenceFinished ) - { - pev->avelocity.y += RANDOM_FLOAT( -100, 100 ); - if( pev->avelocity.y < -100 ) - pev->avelocity.y = -100; - if( pev->avelocity.y > 100 ) - pev->avelocity.y = 100; - - pev->sequence = LookupSequence( "die1" ); - } - - if( m_pBall ) - { - if( m_pBall->pev->renderamt > 0 ) - { - m_pBall->pev->renderamt = Q_max( 0, m_pBall->pev->renderamt - 2 ); - } - else - { - UTIL_Remove( m_pBall ); - m_pBall = NULL; - } - } - - Vector vecDir, vecSrc, vecAngles; - - UTIL_MakeAimVectors( pev->angles ); - int iAttachment = RANDOM_LONG( 1, 4 ); - - do { - vecDir = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ); - } while( DotProduct( vecDir, vecDir ) > 1.0 ); - - switch( RANDOM_LONG( 1, 4 ) ) - { - case 1: - // head - vecDir.z = fabs( vecDir.z ) * 0.5; - vecDir = vecDir + 2 * gpGlobals->v_up; - break; - case 2: - // eyes - if( DotProduct( vecDir, gpGlobals->v_forward ) < 0 ) - vecDir = vecDir * -1; - - vecDir = vecDir + 2 * gpGlobals->v_forward; - break; - case 3: - // left hand - if( DotProduct( vecDir, gpGlobals->v_right ) > 0 ) - vecDir = vecDir * -1; - vecDir = vecDir - 2 * gpGlobals->v_right; - break; - case 4: - // right hand - if( DotProduct( vecDir, gpGlobals->v_right ) < 0 ) - vecDir = vecDir * -1; - vecDir = vecDir + 2 * gpGlobals->v_right; - break; - } - - GetAttachment( iAttachment - 1, vecSrc, vecAngles ); - - TraceResult tr; - - UTIL_TraceLine( vecSrc, vecSrc + vecDir * 4096, ignore_monsters, ENT( pev ), &tr ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() + 0x1000 * iAttachment ); - WRITE_COORD( tr.vecEndPos.x); - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 5 ); // life - WRITE_BYTE( 100 ); // width - WRITE_BYTE( 120 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - GetAttachment( 0, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = Vector( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; - pEntity->GreenBallInit(); - - return; -} - -void CNihilanth::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if( pOther->pev->solid == SOLID_BSP ) - { - SetTouch( NULL ); - pev->nextthink = gpGlobals->time; - } -} - -void CNihilanth::GibMonster( void ) -{ - // EMIT_SOUND_DYN( edict(), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200 ); -} - -void CNihilanth::FloatSequence( void ) -{ - if( m_irritation >= 2 ) - { - pev->sequence = LookupSequence( "float_open" ); - } - else if( m_avelocity.y > 30 ) - { - pev->sequence = LookupSequence( "walk_r" ); - } - else if( m_avelocity.y < -30 ) - { - pev->sequence = LookupSequence( "walk_l" ); - } - else if( m_velocity.z > 30 ) - { - pev->sequence = LookupSequence( "walk_u" ); - } - else if( m_velocity.z < -30 ) - { - pev->sequence = LookupSequence( "walk_d" ); - } - else - { - pev->sequence = LookupSequence( "float" ); - } -} - -void CNihilanth::ShootBalls( void ) -{ - if( m_flShootEnd > gpGlobals->time ) - { - Vector vecHand, vecAngle; - - while( m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time ) - { - if( m_hEnemy != 0 ) - { - Vector vecSrc, vecDir; - CNihilanthHVR *pEntity; - - GetAttachment( 2, vecHand, vecAngle ); - vecSrc = vecHand + pev->velocity * ( m_flShootTime - gpGlobals->time ); - // vecDir = ( m_posTarget - vecSrc ).Normalize(); - vecDir = ( m_posTarget - pev->origin ).Normalize(); - vecSrc = vecSrc + vecDir * ( gpGlobals->time - m_flShootTime ); - pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = vecDir * 200.0; - pEntity->ZapInit( m_hEnemy ); - - GetAttachment( 3, vecHand, vecAngle ); - vecSrc = vecHand + pev->velocity * ( m_flShootTime - gpGlobals->time ); - // vecDir = ( m_posTarget - vecSrc ).Normalize(); - vecDir = ( m_posTarget - pev->origin ).Normalize(); - vecSrc = vecSrc + vecDir * ( gpGlobals->time - m_flShootTime ); - pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = vecDir * 200.0; - pEntity->ZapInit( m_hEnemy ); - } - m_flShootTime += 0.2; - } - } -} - -void CNihilanth::MakeFriend( Vector vecStart ) -{ - int i; - - for( i = 0; i < 3; i++ ) - { - if( m_hFriend[i] != 0 && !m_hFriend[i]->IsAlive() ) - { - if( pev->rendermode == kRenderNormal ) // don't do it if they are already fading - m_hFriend[i]->MyMonsterPointer()->FadeMonster(); - m_hFriend[i] = NULL; - } - - if( m_hFriend[i] == 0 ) - { - if( RANDOM_LONG( 0, 1 ) == 0 ) - { - int iNode = WorldGraph.FindNearestNode( vecStart, bits_NODE_AIR ); - if( iNode != NO_NODE ) - { - CNode &node = WorldGraph.Node( iNode ); - TraceResult tr; - UTIL_TraceHull( node.m_vecOrigin + Vector( 0, 0, 32 ), node.m_vecOrigin + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, NULL, &tr ); - if( tr.fStartSolid == 0 ) - m_hFriend[i] = Create( "monster_alien_controller", node.m_vecOrigin, pev->angles ); - } - } - else - { - int iNode = WorldGraph.FindNearestNode( vecStart, bits_NODE_LAND | bits_NODE_WATER ); - if( iNode != NO_NODE ) - { - CNode &node = WorldGraph.Node( iNode ); - TraceResult tr; - UTIL_TraceHull( node.m_vecOrigin + Vector( 0, 0, 36 ), node.m_vecOrigin + Vector( 0, 0, 36 ), dont_ignore_monsters, human_hull, NULL, &tr ); - if( tr.fStartSolid == 0 ) - m_hFriend[i] = Create( "monster_alien_slave", node.m_vecOrigin, pev->angles ); - } - } - if( m_hFriend[i] != 0 ) - { - EMIT_SOUND( m_hFriend[i]->edict(), CHAN_WEAPON, "debris/beamstart7.wav", 1.0, ATTN_NORM ); - } - - return; - } - } -} - -void CNihilanth::NextActivity() -{ - UTIL_MakeAimVectors( pev->angles ); - - if( m_irritation >= 2 ) - { - if( m_pBall == NULL ) - { - m_pBall = CSprite::SpriteCreate( "sprites/tele1.spr", pev->origin, TRUE ); - if( m_pBall ) - { - m_pBall->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pBall->SetAttachment( edict(), 1 ); - m_pBall->SetScale( 4.0 ); - m_pBall->pev->framerate = 10.0; - m_pBall->TurnOn(); - } - } - - if( m_pBall ) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() + 0x1000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 200 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } - } - - if( ( pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2 ) && m_hRecharger == 0 && m_iLevel <= 9 ) - { - char szName[64]; - - CBaseEntity *pEnt = NULL; - CBaseEntity *pRecharger = NULL; - float flDist = 8192; - - sprintf( szName, "%s%d", m_szRechargerTarget, m_iLevel ); - - while( ( pEnt = UTIL_FindEntityByTargetname( pEnt, szName ) ) != NULL ) - { - float flLocal = (pEnt->pev->origin - pev->origin ).Length(); - if( flLocal < flDist ) - { - flDist = flLocal; - pRecharger = pEnt; - } - } - - if( pRecharger ) - { - m_hRecharger = pRecharger; - m_posDesired = Vector( pev->origin.x, pev->origin.y, pRecharger->pev->origin.z ); - m_vecDesired = ( pRecharger->pev->origin - m_posDesired ).Normalize(); - m_vecDesired.z = 0; - m_vecDesired = m_vecDesired.Normalize(); - } - else - { - m_hRecharger = NULL; - ALERT( at_aiconsole, "nihilanth can't find %s\n", szName ); - m_iLevel++; - if( m_iLevel > 9 ) - m_irritation = 2; - } - } - - float flDist = ( m_posDesired - pev->origin ).Length(); - float flDot = DotProduct( m_vecDesired, gpGlobals->v_forward ); - - if( m_hRecharger != 0 ) - { - // at we at power up yet? - if( flDist < 128.0 ) - { - int iseq = LookupSequence( "recharge" ); - - if( iseq != pev->sequence ) - { - char szText[64]; - - sprintf( szText, "%s%d", m_szDrawUse, m_iLevel ); - FireTargets( szText, this, this, USE_ON, 1.0 ); - - ALERT( at_console, "fireing %s\n", szText ); - } - pev->sequence = LookupSequence( "recharge" ); - } - else - { - FloatSequence(); - } - return; - } - - if( m_hEnemy != 0 && !m_hEnemy->IsAlive() ) - { - m_hEnemy = 0; - } - - if( m_flLastSeen + 15 < gpGlobals->time ) - { - m_hEnemy = 0; - } - - if( m_hEnemy == 0 ) - { - Look( 4096 ); - m_hEnemy = BestVisibleEnemy(); - } - - if( m_hEnemy != 0 && m_irritation != 0 ) - { - if( m_flLastSeen + 5 > gpGlobals->time && flDist < 256 && flDot > 0 ) - { - if( m_irritation >= 2 && pev->health < gSkillData.nihilanthHealth / 2.0 ) - { - pev->sequence = LookupSequence( "attack1_open" ); - } - else - { - if( RANDOM_LONG( 0, 1 ) == 0 ) - { - pev->sequence = LookupSequence( "attack1" ); // zap - } - else - { - char szText[64]; - - sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); - - sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); - CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); - - if( pTrigger != NULL || pTouch != NULL ) - { - pev->sequence = LookupSequence( "attack2" ); // teleport - } - else - { - m_iTeleport++; - pev->sequence = LookupSequence( "attack1" ); // zap - } - } - } - return; - } - } - - FloatSequence(); -} - -void CNihilanth::HuntThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents(); - StudioFrameAdvance(); - - ShootBalls(); - - // if dead, force cancelation of current animation - if( pev->health <= 0 ) - { - SetThink( &CNihilanth::DyingThink ); - m_fSequenceFinished = TRUE; - return; - } - - // ALERT( at_console, "health %.0f\n", pev->health ); - - // if damaged, try to abosorb some spheres - if( pev->health < gSkillData.nihilanthHealth && AbsorbSphere() ) - { - pev->health += gSkillData.nihilanthHealth / N_SPHERES; - } - - // get new sequence - if( m_fSequenceFinished ) - { - // if ( !m_fSequenceLoops ) - pev->frame = 0; - NextActivity(); - ResetSequenceInfo(); - pev->framerate = 2.0 - 1.0 * ( pev->health / gSkillData.nihilanthHealth ); - } - - // look for current enemy - if( m_hEnemy != 0 && m_hRecharger == 0 ) - { - if( FVisible( m_hEnemy ) ) - { - if( m_flLastSeen < gpGlobals->time - 5 ) - m_flPrevSeen = gpGlobals->time; - m_flLastSeen = gpGlobals->time; - m_posTarget = m_hEnemy->pev->origin; - m_vecTarget = ( m_posTarget - pev->origin ).Normalize(); - m_vecDesired = m_vecTarget; - m_posDesired = Vector( pev->origin.x, pev->origin.y, m_posTarget.z + m_flAdj ); - } - else - { - m_flAdj = Q_min( m_flAdj + 10, 1000 ); - } - } - - // don't go too high - if( m_posDesired.z > m_flMaxZ ) - m_posDesired.z = m_flMaxZ; - - // don't go too low - if( m_posDesired.z < m_flMinZ ) - m_posDesired.z = m_flMinZ; - - Flight(); -} - -void CNihilanth::Flight( void ) -{ - // estimate where I'll be facing in one seconds - UTIL_MakeAimVectors( pev->angles + m_avelocity ); - // Vector vecEst1 = pev->origin + m_velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 ); - // float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right ); - - float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); - - if( flSide < 0 ) - { - if( m_avelocity.y < 180 ) - { - m_avelocity.y += 6; // 9 * ( 3.0 / 2.0 ); - } - } - else - { - if( m_avelocity.y > -180 ) - { - m_avelocity.y -= 6; // 9 * ( 3.0 / 2.0 ); - } - } - m_avelocity.y *= 0.98; - - // estimate where I'll be in two seconds - Vector vecEst = pev->origin + m_velocity * 2.0 + gpGlobals->v_up * m_flForce * 20; - - // add immediate force - UTIL_MakeAimVectors( pev->angles ); - m_velocity.x += gpGlobals->v_up.x * m_flForce; - m_velocity.y += gpGlobals->v_up.y * m_flForce; - m_velocity.z += gpGlobals->v_up.z * m_flForce; - - float flSpeed = m_velocity.Length(); - float flDir = DotProduct( Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, 0 ), Vector( m_velocity.x, m_velocity.y, 0 ) ); - if( flDir < 0 ) - flSpeed = -flSpeed; - - //float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); - - // sideways drag - m_velocity.x = m_velocity.x * ( 1.0 - fabs( gpGlobals->v_right.x ) * 0.05 ); - m_velocity.y = m_velocity.y * ( 1.0 - fabs( gpGlobals->v_right.y ) * 0.05 ); - m_velocity.z = m_velocity.z * ( 1.0 - fabs( gpGlobals->v_right.z ) * 0.05 ); - - // general drag - m_velocity = m_velocity * 0.995; - - // apply power to stay correct height - if( m_flForce < 100 && vecEst.z < m_posDesired.z ) - { - m_flForce += 10; - } - else if( m_flForce > -100 && vecEst.z > m_posDesired.z ) - { - if( vecEst.z > m_posDesired.z ) - m_flForce -= 10; - } - - UTIL_SetOrigin( pev, pev->origin + m_velocity * 0.1 ); - pev->angles = pev->angles + m_avelocity * 0.1; - - // ALERT( at_console, "%5.0f %5.0f : %4.0f : %3.0f : %2.0f\n", m_posDesired.z, pev->origin.z, m_velocity.z, m_avelocity.y, m_flForce ); -} - -BOOL CNihilanth::AbsorbSphere( void ) -{ - for( int i = 0; i < N_SPHERES; i++ ) - { - if( m_hSphere[i] != 0 ) - { - CNihilanthHVR *pSphere = (CNihilanthHVR *)( (CBaseEntity *)m_hSphere[i] ); - pSphere->AbsorbInit(); - m_hSphere[i] = NULL; - m_iActiveSpheres--; - return TRUE; - } - } - return FALSE; -} - -BOOL CNihilanth::EmitSphere( void ) -{ - m_iActiveSpheres = 0; - int empty = 0; - - for( int i = 0; i < N_SPHERES; i++ ) - { - if( m_hSphere[i] != 0 ) - { - m_iActiveSpheres++; - } - else - { - empty = i; - } - } - - if( m_iActiveSpheres >= N_SPHERES ) - return FALSE; - - Vector vecSrc = m_hRecharger->pev->origin; - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->CircleInit( this ); - - m_hSphere[empty] = pEntity; - return TRUE; -} - -void CNihilanth::TargetSphere( USE_TYPE useType, float value ) -{ - int i; - CBaseMonster *pSphere; - - for( i = 0; i < N_SPHERES; i++ ) - { - if( m_hSphere[i] != 0 ) - { - pSphere = m_hSphere[i]->MyMonsterPointer(); - if( pSphere->m_hEnemy == 0 ) - break; - } - } - - if( i == N_SPHERES ) - { - return; - } - - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - UTIL_SetOrigin( pSphere->pev, vecSrc ); - pSphere->Use( this, this, useType, value ); - pSphere->pev->velocity = m_vecDesired * RANDOM_FLOAT( 50, 100 ) + Vector( RANDOM_FLOAT( -50, 50 ), RANDOM_FLOAT( -50, 50 ), RANDOM_FLOAT( -50, 50 ) ); -} - -void CNihilanth::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 1: - // shoot - break; - case 2: - // zen - if( m_hEnemy != 0 ) - { - if( RANDOM_LONG( 0, 4 ) == 0 ) - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); - - EMIT_SOUND( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBallSounds ), 1.0, 0.2 ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() + 0x3000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() + 0x4000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - m_flShootTime = gpGlobals->time; - m_flShootEnd = gpGlobals->time + 1.0; - } - break; - case 3: - // prayer - if( m_hEnemy != 0 ) - { - char szText[32]; - - sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); - - sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); - CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); - - if( pTrigger != NULL || pTouch != NULL ) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); - - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->TeleportInit( this, m_hEnemy, pTrigger, pTouch ); - } - else - { - m_iTeleport++; // unexpected failure - - EMIT_SOUND( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBallSounds ), 1.0, 0.2 ); - - ALERT( at_aiconsole, "nihilanth can't target %s\n", szText ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() + 0x3000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() + 0x4000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - m_flShootTime = gpGlobals->time; - m_flShootEnd = gpGlobals->time + 1.0; - } - } - break; - case 4: - // get a sphere - { - if( m_hRecharger != 0 ) - { - if( !EmitSphere() ) - { - m_hRecharger = NULL; - } - } - } - break; - case 5: - // start up sphere machine - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pRechargeSounds ), 1.0, 0.2 ); - } - break; - case 6: - if( m_hEnemy != 0 ) - { - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->ZapInit( m_hEnemy ); - } - break; - case 7: - /* - Vector vecSrc, vecAngles; - GetAttachment( 0, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = Vector( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; - pEntity->GreenBallInit(); - */ - break; - } -} - -void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - switch( useType ) - { - case USE_OFF: - { - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); - if( pTouch ) - { - if( m_hEnemy != 0 ) - { - pTouch->Touch( m_hEnemy ); - } - // if the player is using "notarget", the ending sequence won't fire unless we catch it here - else - { - CBaseEntity *pEntity = UTIL_FindEntityByClassname( NULL, "player" ); - if( pEntity != NULL && pEntity->IsAlive() ) - { - pTouch->Touch( pEntity ); - } - } - } - } - break; - case USE_ON: - if( m_irritation == 0 ) - { - m_irritation = 1; - } - break; - case USE_SET: - break; - case USE_TOGGLE: - break; - } -} - -int CNihilanth::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if( pevInflictor->owner == edict() ) - return 0; - - if( flDamage >= pev->health ) - { - pev->health = 1; - if( m_irritation != 3 ) - return 0; - } - - PainSound(); - - pev->health -= flDamage; - return 0; -} - -void CNihilanth::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if( m_irritation == 3 ) - m_irritation = 2; - - if( m_irritation == 2 && ptr->iHitgroup == 2 && flDamage > 2 ) - m_irritation = 3; - - if( m_irritation != 3 ) - { - Vector vecBlood = ( ptr->vecEndPos - pev->origin ).Normalize(); - - UTIL_BloodStream( ptr->vecEndPos, vecBlood, BloodColor(), flDamage + ( 100 - 100 * ( pev->health / gSkillData.nihilanthHealth ) ) ); - } - - // SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage * 5.0 );// a little surface blood. - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -CBaseEntity *CNihilanth::RandomTargetname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while( ( pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName ) ) != NULL ) - { - total++; - if( RANDOM_LONG( 0, total - 1 ) < 1 ) - pEntity = pNewEntity; - } - return pEntity; -} - -//========================================================= -// Controller bouncy ball attack -//========================================================= - -void CNihilanthHVR::Spawn( void ) -{ - Precache(); - - pev->rendermode = kRenderTransAdd; - pev->renderamt = 255; - pev->scale = 3.0; -} - -void CNihilanthHVR::Precache( void ) -{ - PRECACHE_MODEL( "sprites/flare6.spr" ); - PRECACHE_MODEL( "sprites/nhth1.spr" ); - PRECACHE_MODEL( "sprites/exit1.spr" ); - PRECACHE_MODEL( "sprites/tele1.spr" ); - PRECACHE_MODEL( "sprites/animglow01.spr" ); - PRECACHE_MODEL( "sprites/xspark4.spr" ); - PRECACHE_MODEL( "sprites/muzzleflash3.spr" ); - PRECACHE_SOUND( "debris/zap4.wav" ); - PRECACHE_SOUND( "weapons/electro4.wav" ); - PRECACHE_SOUND( "x/x_teleattack1.wav" ); -} - -void CNihilanthHVR::CircleInit( CBaseEntity *pTarget ) -{ - pev->movetype = MOVETYPE_NOCLIP; - pev->solid = SOLID_NOT; - - // SET_MODEL( edict(), "sprites/flare6.spr" ); - // pev->scale = 3.0; - // SET_MODEL( edict(), "sprites/xspark4.spr" ); - SET_MODEL( edict(), "sprites/muzzleflash3.spr" ); - pev->rendercolor.x = 255; - pev->rendercolor.y = 224; - pev->rendercolor.z = 192; - pev->scale = 2.0; - m_nFrames = 1; - pev->renderamt = 255; - - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CNihilanthHVR::HoverThink ); - SetTouch( &CNihilanthHVR::BounceTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - m_hTargetEnt = pTarget; -} - -CBaseEntity *CNihilanthHVR::RandomClassname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while( ( pNewEntity = UTIL_FindEntityByClassname( pNewEntity, szName ) ) != NULL ) - { - total++; - if( RANDOM_LONG( 0, total - 1 ) < 1 ) - pEntity = pNewEntity; - } - return pEntity; -} - -void CNihilanthHVR::HoverThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if( m_hTargetEnt != 0 ) - { - CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 16 * N_SCALE ) ); - } - else - { - UTIL_Remove( this ); - } - - if( RANDOM_LONG( 0, 99 ) < 5 ) - { -/* - CBaseEntity *pOther = RandomClassname( STRING( pev->classname ) ); - - if( pOther && pOther != this ) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( pOther->entindex() ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); - } -*/ -/* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( m_hTargetEnt->entindex() + 0x1000 ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); -*/ - } - - pev->frame = ( (int)pev->frame + 1 ) % m_nFrames; -} - -void CNihilanthHVR::ZapInit( CBaseEntity *pEnemy ) -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL( edict(), "sprites/nhth1.spr" ); - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->scale = 2.0; - - pev->velocity = ( pEnemy->pev->origin - pev->origin ).Normalize() * 200; - - m_hEnemy = pEnemy; - SetThink( &CNihilanthHVR::ZapThink ); - SetTouch( &CNihilanthHVR::ZapTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 ); -} - -void CNihilanthHVR::ZapThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.05; - - // check world boundaries - if( m_hEnemy == 0 || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096 ) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - if( pev->velocity.Length() < 2000 ) - { - pev->velocity = pev->velocity * 1.2; - } - - // MovetoTarget( m_hEnemy->Center() ); - - if( ( m_hEnemy->Center() - pev->origin ).Length() < 256 ) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, edict(), &tr ); - - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if( pEntity != NULL && pEntity->pev->takedamage ) - { - ClearMultiDamage(); - pEntity->TraceAttack( pev, gSkillData.nihilanthZap, pev->velocity, &tr, DMG_SHOCK ); - ApplyMultiDamage( pev, pev ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 20 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 196 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - UTIL_EmitAmbientSound( edict(), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); - - SetTouch( NULL ); - UTIL_Remove( this ); - pev->nextthink = gpGlobals->time + 0.2; - return; - } - - pev->frame = (int)( pev->frame + 1 ) % 11; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 128 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - // Crawl(); -} - -void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) -{ - UTIL_EmitAmbientSound( edict(), pev->origin, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, RANDOM_LONG( 90, 95 ) ); - - RadiusDamage( pev, pev, 50, CLASS_NONE, DMG_SHOCK ); - pev->velocity = pev->velocity * 0; - - /* - for( int i = 0; i < 10; i++ ) - { - Crawl(); - } - */ - - SetTouch( NULL ); - UTIL_Remove( this ); - pev->nextthink = gpGlobals->time + 0.2; -} - -void CNihilanthHVR::TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ) -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->velocity.z *= 0.2; - - SET_MODEL( edict(), "sprites/exit1.spr" ); - - m_pNihilanth = pOwner; - m_hEnemy = pEnemy; - m_hTargetEnt = pTarget; - m_hTouch = pTouch; - - SetThink( &CNihilanthHVR::TeleportThink ); - SetTouch( &CNihilanthHVR::TeleportTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "x/x_teleattack1.wav", 1, 0.2, 0, 100 ); -} - -void CNihilanthHVR::GreenBallInit() -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->scale = 1.0; - - SET_MODEL( edict(), "sprites/exit1.spr" ); - - SetTouch( &CNihilanthHVR::RemoveTouch ); -} - -void CNihilanthHVR::TeleportThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - // check world boundaries - if( m_hEnemy == 0 || !m_hEnemy->IsAlive() || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096 ) - { - STOP_SOUND( edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); - return; - } - - if( ( m_hEnemy->Center() - pev->origin).Length() < 128 ) - { - STOP_SOUND( edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); - - if( m_hTargetEnt != 0 ) - m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); - - if( m_hTouch != 0 && m_hEnemy != 0 ) - m_hTouch->Touch( m_hEnemy ); - } - else - { - MovetoTarget( m_hEnemy->Center() ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 0 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 0 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 256 ); // decay - MESSAGE_END(); - - pev->frame = (int)( pev->frame + 1 ) % 20; -} - -void CNihilanthHVR::AbsorbInit( void ) -{ - SetThink( &CNihilanthHVR::DissipateThink ); - pev->renderamt = 255; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( m_hTargetEnt->entindex() + 0x1000 ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 50 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); -} - -void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) -{ - CBaseEntity *pEnemy = m_hEnemy; - - if( pOther == pEnemy ) - { - if( m_hTargetEnt != 0 ) - m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); - - if( m_hTouch != 0 && pEnemy != NULL ) - m_hTouch->Touch( pEnemy ); - } - else - { - m_pNihilanth->MakeFriend( pev->origin ); - } - - SetTouch( NULL ); - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); -} - -void CNihilanthHVR::DissipateThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if( pev->scale > 5.0 ) - UTIL_Remove( this ); - - pev->renderamt -= 2; - pev->scale += 0.1; - - if( m_hTargetEnt != 0 ) - { - CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 4096 ) ); - } - else - { - UTIL_Remove( this ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex() ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( pev->renderamt ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); -} - -BOOL CNihilanthHVR::CircleTarget( Vector vecTarget ) -{ - BOOL fClose = FALSE; - - Vector vecDest = vecTarget; - Vector vecEst = pev->origin + pev->velocity * 0.5; - Vector vecSrc = pev->origin; - vecDest.z = 0; - vecEst.z = 0; - vecSrc.z = 0; - float d1 = ( vecDest - vecSrc ).Length() - 24 * N_SCALE; - float d2 = ( vecDest - vecEst ).Length() - 24 * N_SCALE; - - if( m_vecIdeal == Vector( 0, 0, 0 ) ) - { - m_vecIdeal = pev->velocity; - } - - if( d1 < 0 && d2 <= d1 ) - { - // ALERT( at_console, "too close\n" ); - m_vecIdeal = m_vecIdeal - ( vecDest - vecSrc ).Normalize() * 50; - } - else if( d1 > 0 && d2 >= d1 ) - { - // ALERT( at_console, "too far\n" ); - m_vecIdeal = m_vecIdeal + ( vecDest - vecSrc ).Normalize() * 50; - } - pev->avelocity.z = d1 * 20; - - if( d1 < 32 ) - { - fClose = TRUE; - } - - m_vecIdeal = m_vecIdeal + Vector( RANDOM_FLOAT( -2, 2 ), RANDOM_FLOAT( -2, 2 ), RANDOM_FLOAT( -2, 2 )); - m_vecIdeal = Vector( m_vecIdeal.x, m_vecIdeal.y, 0 ).Normalize() * 200 - /* + Vector( -m_vecIdeal.y, m_vecIdeal.x, 0 ).Normalize() * 32 */ - + Vector( 0, 0, m_vecIdeal.z ); - // m_vecIdeal = m_vecIdeal + Vector( -m_vecIdeal.y, m_vecIdeal.x, 0 ).Normalize() * 2; - - // move up/down - d1 = vecTarget.z - pev->origin.z; - if( d1 > 0 && m_vecIdeal.z < 200 ) - m_vecIdeal.z += 20; - else if( d1 < 0 && m_vecIdeal.z > -200 ) - m_vecIdeal.z -= 20; - - pev->velocity = m_vecIdeal; - - // ALERT( at_console, "%.0f %.0f %.0f\n", m_vecIdeal.x, m_vecIdeal.y, m_vecIdeal.z ); - return fClose; -} - -void CNihilanthHVR::MovetoTarget( Vector vecTarget ) -{ - if( m_vecIdeal == Vector( 0, 0, 0 ) ) - { - m_vecIdeal = pev->velocity; - } - - // accelerate - float flSpeed = m_vecIdeal.Length(); - if( flSpeed > 300 ) - { - m_vecIdeal = m_vecIdeal.Normalize() * 300; - } - m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 300; - pev->velocity = m_vecIdeal; -} - -void CNihilanthHVR::Crawl( void ) -{ - Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize(); - Vector vecPnt = pev->origin + pev->velocity * 0.2 + vecAim * 128; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( vecPnt.x ); - WRITE_COORD( vecPnt.y ); - WRITE_COORD( vecPnt.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); -} - -void CNihilanthHVR::RemoveTouch( CBaseEntity *pOther ) -{ - STOP_SOUND( edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); -} - -void CNihilanthHVR::BounceTouch( CBaseEntity *pOther ) -{ - Vector vecDir = m_vecIdeal.Normalize(); - - TraceResult tr = UTIL_GetGlobalTrace(); - - float n = -DotProduct( tr.vecPlaneNormal, vecDir ); - - vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; - - m_vecIdeal = vecDir * m_vecIdeal.Length(); -} -#endif diff --git a/dlls/osprey.cpp b/dlls/osprey.cpp deleted file mode 100644 index 6a421645..00000000 --- a/dlls/osprey.cpp +++ /dev/null @@ -1,776 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "effects.h" -#include "customentity.h" - -typedef struct -{ - int isValid; - EHANDLE hGrunt; - Vector vecOrigin; - Vector vecAngles; -} t_ospreygrunt; - -#define SF_WAITFORTRIGGER 0x40 - -#define MAX_CARRY 24 - -class COsprey : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - int ObjectCaps( void ) { return CBaseMonster::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - void Spawn( void ); - void Precache( void ); - int Classify( void ) { return CLASS_MACHINE; }; - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - - void UpdateGoal( void ); - BOOL HasDead( void ); - void EXPORT FlyThink( void ); - void EXPORT DeployThink( void ); - void Flight( void ); - void EXPORT HitTouch( CBaseEntity *pOther ); - void EXPORT FindAllThink( void ); - void EXPORT HoverThink( void ); - CBaseMonster *MakeGrunt( Vector vecSrc ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - // int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - void ShowDamage( void ); - - CBaseEntity *m_pGoalEnt; - Vector m_vel1; - Vector m_vel2; - Vector m_pos1; - Vector m_pos2; - Vector m_ang1; - Vector m_ang2; - float m_startTime; - float m_dTime; - - Vector m_velocity; - - float m_flIdealtilt; - float m_flRotortilt; - - float m_flRightHealth; - float m_flLeftHealth; - - int m_iUnits; - EHANDLE m_hGrunt[MAX_CARRY]; - Vector m_vecOrigin[MAX_CARRY]; - EHANDLE m_hRepel[4]; - - int m_iSoundState; - int m_iSpriteTexture; - - int m_iPitch; - - int m_iExplode; - int m_iTailGibs; - int m_iBodyGibs; - int m_iEngineGibs; - - int m_iDoLeftSmokePuff; - int m_iDoRightSmokePuff; -}; - -LINK_ENTITY_TO_CLASS( monster_osprey, COsprey ) - -TYPEDESCRIPTION COsprey::m_SaveData[] = -{ - DEFINE_FIELD( COsprey, m_pGoalEnt, FIELD_CLASSPTR ), - DEFINE_FIELD( COsprey, m_vel1, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_vel2, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_pos1, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( COsprey, m_pos2, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( COsprey, m_ang1, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_ang2, FIELD_VECTOR ), - - DEFINE_FIELD( COsprey, m_startTime, FIELD_TIME ), - DEFINE_FIELD( COsprey, m_dTime, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_velocity, FIELD_VECTOR ), - - DEFINE_FIELD( COsprey, m_flIdealtilt, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_flRotortilt, FIELD_FLOAT ), - - DEFINE_FIELD( COsprey, m_flRightHealth, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_flLeftHealth, FIELD_FLOAT ), - - DEFINE_FIELD( COsprey, m_iUnits, FIELD_INTEGER ), - DEFINE_ARRAY( COsprey, m_hGrunt, FIELD_EHANDLE, MAX_CARRY ), - DEFINE_ARRAY( COsprey, m_vecOrigin, FIELD_POSITION_VECTOR, MAX_CARRY ), - DEFINE_ARRAY( COsprey, m_hRepel, FIELD_EHANDLE, 4 ), - - // DEFINE_FIELD( COsprey, m_iSoundState, FIELD_INTEGER ), - // DEFINE_FIELD( COsprey, m_iSpriteTexture, FIELD_INTEGER ), - // DEFINE_FIELD( COsprey, m_iPitch, FIELD_INTEGER ), - - DEFINE_FIELD( COsprey, m_iDoLeftSmokePuff, FIELD_INTEGER ), - DEFINE_FIELD( COsprey, m_iDoRightSmokePuff, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( COsprey, CBaseMonster ) - -void COsprey::Spawn( void ) -{ - Precache(); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL( ENT( pev ), "models/osprey.mdl" ); - UTIL_SetSize( pev, Vector( -400, -400, -100 ), Vector( 400, 400, 32 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_YES; - m_flRightHealth = 200; - m_flLeftHealth = 200; - pev->health = 400; - - m_flFieldOfView = 0; // 180 degrees - - pev->sequence = 0; - ResetSequenceInfo(); - pev->frame = RANDOM_LONG( 0, 0xFF ); - - InitBoneControllers(); - - SetThink( &COsprey::FindAllThink ); - SetUse( &COsprey::CommandUse ); - - if( !( pev->spawnflags & SF_WAITFORTRIGGER ) ) - { - pev->nextthink = gpGlobals->time + 1.0; - } - - m_pos2 = pev->origin; - m_ang2 = pev->angles; - m_vel2 = pev->velocity; -} - -void COsprey::Precache( void ) -{ - UTIL_PrecacheOther( "monster_human_grunt" ); - - PRECACHE_MODEL( "models/osprey.mdl" ); - PRECACHE_MODEL( "models/HVR.mdl" ); - - PRECACHE_SOUND( "apache/ap_rotor4.wav" ); - PRECACHE_SOUND( "weapons/mortarhit.wav" ); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); - - m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); - m_iTailGibs = PRECACHE_MODEL( "models/osprey_tailgibs.mdl" ); - m_iBodyGibs = PRECACHE_MODEL( "models/osprey_bodygibs.mdl" ); - m_iEngineGibs = PRECACHE_MODEL( "models/osprey_enginegibs.mdl" ); -} - -void COsprey::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->nextthink = gpGlobals->time + 0.1; -} - -void COsprey::FindAllThink( void ) -{ - CBaseEntity *pEntity = NULL; - - m_iUnits = 0; - while( m_iUnits < MAX_CARRY && ( pEntity = UTIL_FindEntityByClassname( pEntity, "monster_human_grunt" ) ) != NULL ) - { - if( pEntity->IsAlive() ) - { - m_hGrunt[m_iUnits] = pEntity; - m_vecOrigin[m_iUnits] = pEntity->pev->origin; - m_iUnits++; - } - } - - if( m_iUnits == 0 ) - { - ALERT( at_console, "osprey error: no grunts to resupply\n" ); - UTIL_Remove( this ); - return; - } - SetThink( &COsprey::FlyThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_startTime = gpGlobals->time; -} - -void COsprey::DeployThink( void ) -{ - UTIL_MakeAimVectors( pev->angles ); - - Vector vecForward = gpGlobals->v_forward; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - - Vector vecSrc; - - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -4096.0 ), ignore_monsters, ENT( pev ), &tr ); - CSoundEnt::InsertSound( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); - - vecSrc = pev->origin + vecForward * 32 + vecRight * 100 + vecUp * -96; - m_hRepel[0] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * -64 + vecRight * 100 + vecUp * -96; - m_hRepel[1] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * 32 + vecRight * -100 + vecUp * -96; - m_hRepel[2] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * -64 + vecRight * -100 + vecUp * -96; - m_hRepel[3] = MakeGrunt( vecSrc ); - - SetThink( &COsprey::HoverThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - -BOOL COsprey::HasDead() -{ - for( int i = 0; i < m_iUnits; i++ ) - { - if( m_hGrunt[i] == 0 || !m_hGrunt[i]->IsAlive() ) - { - return TRUE; - } - else - { - m_vecOrigin[i] = m_hGrunt[i]->pev->origin; // send them to where they died - } - } - return FALSE; -} - -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] == 0 || !m_hGrunt[i]->IsAlive() ) - { - if( m_hGrunt[i] != 0 && m_hGrunt[i]->pev->rendermode == kRenderNormal ) - { - m_hGrunt[i]->SUB_StartFadeOut(); - } - pEntity = Create( "monster_human_grunt", vecSrc, pev->angles ); - pGrunt = pEntity->MyMonsterPointer(); - pGrunt->pev->movetype = MOVETYPE_FLY; - pGrunt->pev->velocity = 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( &CBaseEntity::SUB_Remove ); - pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.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; -} - -void COsprey::HoverThink( void ) -{ - int i; - for( i = 0; i < 4; i++ ) - { - if( m_hRepel[i] != 0 && m_hRepel[i]->pev->health > 0 && !( m_hRepel[i]->pev->flags & FL_ONGROUND ) ) - { - break; - } - } - - if( i == 4 ) - { - m_startTime = gpGlobals->time; - SetThink( &COsprey::FlyThink ); - } - - pev->nextthink = gpGlobals->time + 0.1; - UTIL_MakeAimVectors( pev->angles ); - ShowDamage(); -} - -void COsprey::UpdateGoal() -{ - if( m_pGoalEnt ) - { - m_pos1 = m_pos2; - m_ang1 = m_ang2; - m_vel1 = m_vel2; - m_pos2 = m_pGoalEnt->pev->origin; - m_ang2 = m_pGoalEnt->pev->angles; - UTIL_MakeAimVectors( Vector( 0, m_ang2.y, 0 ) ); - m_vel2 = gpGlobals->v_forward * m_pGoalEnt->pev->speed; - - m_startTime = m_startTime + m_dTime; - m_dTime = 2.0 * ( m_pos1 - m_pos2 ).Length() / ( m_vel1.Length() + m_pGoalEnt->pev->speed ); - - if( m_ang1.y - m_ang2.y < -180 ) - { - m_ang1.y += 360; - } - else if( m_ang1.y - m_ang2.y > 180 ) - { - m_ang1.y -= 360; - } - - if( m_pGoalEnt->pev->speed < 400 ) - m_flIdealtilt = 0; - else - m_flIdealtilt = -90; - } - else - { - ALERT( at_console, "osprey missing target" ); - } -} - -void COsprey::FlyThink( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - if( m_pGoalEnt == NULL && !FStringNull( pev->target) )// this monster has a target - { - m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->target ) ) ); - UpdateGoal(); - } - - if( gpGlobals->time > m_startTime + m_dTime ) - { - if( m_pGoalEnt->pev->speed == 0 ) - { - SetThink( &COsprey::DeployThink ); - } - do{ - m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING( m_pGoalEnt->pev->target ) ) ); - } while( m_pGoalEnt->pev->speed < 400 && !HasDead() ); - UpdateGoal(); - } - - Flight(); - ShowDamage(); -} - -void COsprey::Flight() -{ - float t = ( gpGlobals->time - m_startTime ); - float scale = 1.0 / m_dTime; - - float f = UTIL_SplineFraction( t * scale, 1.0 ); - - Vector pos = ( m_pos1 + m_vel1 * t ) * ( 1.0 - f ) + ( m_pos2 - m_vel2 * ( m_dTime - t ) ) * f; - Vector ang = ( m_ang1 ) * ( 1.0 - f ) + ( m_ang2 ) * f; - m_velocity = m_vel1 * ( 1.0 - f ) + m_vel2 * f; - - UTIL_SetOrigin( pev, pos ); - pev->angles = ang; - UTIL_MakeAimVectors( pev->angles ); - float flSpeed = DotProduct( gpGlobals->v_forward, m_velocity ); - - // float flSpeed = DotProduct( gpGlobals->v_forward, pev->velocity ); - - float m_flIdealtilt = ( 160 - flSpeed ) / 10.0; - - // ALERT( at_console, "%f %f\n", flSpeed, flIdealtilt ); - if( m_flRotortilt < m_flIdealtilt ) - { - m_flRotortilt += 0.5; - if ( m_flRotortilt > 0 ) - m_flRotortilt = 0; - } - if( m_flRotortilt > m_flIdealtilt ) - { - m_flRotortilt -= 0.5; - if( m_flRotortilt < -90 ) - m_flRotortilt = -90; - } - SetBoneController( 0, m_flRotortilt ); - - if( m_iSoundState == 0 ) - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, 0, 110 ); - // EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - } - else - { - CBaseEntity *pPlayer = NULL; - - pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - // UNDONE: this needs to send different sounds to every player for multiplayer. - if( pPlayer ) - { - float pitch = DotProduct( m_velocity - pPlayer->pev->velocity, ( pPlayer->pev->origin - pev->origin ).Normalize() ); - - pitch = (int)( 100 + pitch / 75.0 ); - - if( pitch > 250 ) - pitch = 250; - if( pitch < 50 ) - pitch = 50; - - if( pitch == 100 ) - pitch = 101; - - if( pitch != m_iPitch ) - { - m_iPitch = pitch; - EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch ); - // ALERT( at_console, "%.0f\n", pitch ); - } - } - // EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch ); - } - -} - -void COsprey::HitTouch( CBaseEntity *pOther ) -{ - pev->nextthink = gpGlobals->time + 2.0; -} - -/* -int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if( m_flRotortilt <= -90 ) - { - m_flRotortilt = 0; - } - else - { - m_flRotortilt -= 45; - } - SetBoneController( 0, m_flRotortilt ); - return 0; -} -*/ - -void COsprey::Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->gravity = 0.3; - pev->velocity = m_velocity; - pev->avelocity = Vector( RANDOM_FLOAT( -20, 20 ), 0, RANDOM_FLOAT( -50, 50 ) ); - STOP_SOUND( ENT( pev ), CHAN_STATIC, "apache/ap_rotor4.wav" ); - - UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) ); - SetThink( &COsprey::DyingThink ); - SetTouch( &COsprey::CrashTouch ); - pev->nextthink = gpGlobals->time + 0.1; - pev->health = 0; - pev->takedamage = DAMAGE_NO; - - m_startTime = gpGlobals->time + 4.0; -} - -void COsprey::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if( pOther->pev->solid == SOLID_BSP ) - { - SetTouch( NULL ); - m_startTime = gpGlobals->time; - pev->nextthink = gpGlobals->time; - m_velocity = pev->velocity; - } -} - -void COsprey::DyingThink( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - pev->avelocity = pev->avelocity * 1.02; - - // still falling? - if( m_startTime > gpGlobals->time ) - { - UTIL_MakeAimVectors( pev->angles ); - ShowDamage(); - - Vector vecSpot = pev->origin + pev->velocity * 0.2; - - // random explosions - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_EXPLOSION ); // This just makes a dynamic light now - WRITE_COORD( vecSpot.x + RANDOM_FLOAT( -150, 150 ) ); - WRITE_COORD( vecSpot.y + RANDOM_FLOAT( -150, 150 ) ); - WRITE_COORD( vecSpot.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, vecSpot ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSpot.x + RANDOM_FLOAT( -150, 150 ) ); - WRITE_COORD( vecSpot.y + RANDOM_FLOAT( -150, 150 ) ); - WRITE_COORD( vecSpot.z + RANDOM_FLOAT( -150, -50 ) ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 100 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate - MESSAGE_END(); - - 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( 800 ); - WRITE_COORD( 800 ); - 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_iTailGibs ); //model id# - - // # of shards - WRITE_BYTE( 8 ); // let client decide - - // duration - WRITE_BYTE( 200 );// 10.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 + 512 ); - WRITE_SHORT( m_iExplode ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate - MESSAGE_END(); - */ - - // gibs - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 512 ); - WRITE_SHORT( m_iExplode ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 255 ); // brightness - MESSAGE_END(); - - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 300 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 6 ); // framerate - MESSAGE_END(); - */ - - // blast circle - MESSAGE_BEGIN( MSG_PAS, 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 ); - - // gibs - vecSpot = pev->origin + ( pev->mins + pev->maxs ) * 0.5; - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 64 ); - - // size - WRITE_COORD( 800 ); - WRITE_COORD( 800 ); - WRITE_COORD( 128 ); - - // velocity - WRITE_COORD( m_velocity.x ); - WRITE_COORD( m_velocity.y ); - WRITE_COORD( fabs( m_velocity.z ) * 0.25 ); - - // randomization - WRITE_BYTE( 40 ); - - // Model - WRITE_SHORT( m_iBodyGibs ); //model id# - - // # of shards - WRITE_BYTE( 128 ); - - // duration - WRITE_BYTE( 200 );// 10.0 seconds - - // flags - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - UTIL_Remove( this ); - } -} - -void COsprey::ShowDamage( void ) -{ - if( m_iDoLeftSmokePuff > 0 || RANDOM_LONG( 0, 99 ) > m_flLeftHealth ) - { - Vector vecSrc = pev->origin + gpGlobals->v_right * -340; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG( 0, 9 ) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - if( m_iDoLeftSmokePuff > 0 ) - m_iDoLeftSmokePuff--; - } - if( m_iDoRightSmokePuff > 0 || RANDOM_LONG( 0, 99 ) > m_flRightHealth ) - { - Vector vecSrc = pev->origin + gpGlobals->v_right * 340; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG( 0, 9 ) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - if( m_iDoRightSmokePuff > 0 ) - m_iDoRightSmokePuff--; - } -} - -void COsprey::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); - - // only so much per engine - if( ptr->iHitgroup == 3 ) - { - if( m_flRightHealth < 0 ) - return; - else - m_flRightHealth -= flDamage; - m_iDoLeftSmokePuff = 3 + ( flDamage / 5.0 ); - } - - if( ptr->iHitgroup == 2 ) - { - if( m_flLeftHealth < 0 ) - return; - else - m_flLeftHealth -= flDamage; - m_iDoRightSmokePuff = 3 + ( flDamage / 5.0 ); - } - - // hit hard, hits cockpit, hits engines - if( flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2 || ptr->iHitgroup == 3 ) - { - // ALERT( at_console, "%.0f\n", flDamage ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } - else - { - UTIL_Sparks( ptr->vecEndPos ); - } -} diff --git a/dlls/python.cpp b/dlls/python.cpp deleted file mode 100644 index 90606c50..00000000 --- a/dlls/python.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "monsters.h" -#include "player.h" -#include "gamerules.h" - -enum python_e -{ - PYTHON_IDLE1 = 0, - PYTHON_FIDGET, - PYTHON_FIRE1, - PYTHON_RELOAD, - PYTHON_HOLSTER, - PYTHON_DRAW, - PYTHON_IDLE2, - PYTHON_IDLE3 -}; - -LINK_ENTITY_TO_CLASS( weapon_python, CPython ) -LINK_ENTITY_TO_CLASS( weapon_357, CPython ) - -int CPython::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "357"; - p->iMaxAmmo1 = _357_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = PYTHON_MAX_CLIP; - p->iFlags = 0; - p->iSlot = 1; - p->iPosition = 1; - p->iId = m_iId = WEAPON_PYTHON; - p->iWeight = PYTHON_WEIGHT; - - return 1; -} - -int CPython::AddToPlayer( CBasePlayer *pPlayer ) -{ - if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -void CPython::Spawn() -{ - pev->classname = MAKE_STRING( "weapon_357" ); // hack to allow for old names - Precache(); - m_iId = WEAPON_PYTHON; - SET_MODEL( ENT( pev ), "models/w_357.mdl" ); - - m_iDefaultAmmo = PYTHON_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -void CPython::Precache( void ) -{ - PRECACHE_MODEL( "models/v_357.mdl" ); - PRECACHE_MODEL( "models/w_357.mdl" ); - PRECACHE_MODEL( "models/p_357.mdl" ); - - PRECACHE_MODEL( "models/w_357ammobox.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - - PRECACHE_SOUND( "weapons/357_reload1.wav" ); - PRECACHE_SOUND( "weapons/357_cock1.wav" ); - PRECACHE_SOUND( "weapons/357_shot1.wav" ); - PRECACHE_SOUND( "weapons/357_shot2.wav" ); - - m_usFirePython = PRECACHE_EVENT( 1, "events/python.sc" ); -} - -BOOL CPython::Deploy() -{ -#ifdef CLIENT_DLL - if( bIsMultiplayer() ) -#else - if( g_pGameRules->IsMultiplayer() ) -#endif - { - // enable laser sight geometry. - pev->body = 1; - } - else - { - pev->body = 0; - } - - return DefaultDeploy( "models/v_357.mdl", "models/p_357.mdl", PYTHON_DRAW, "python", UseDecrement(), pev->body ); -} - -void CPython::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - if( m_fInZoom ) - { - SecondaryAttack(); - } - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - SendWeaponAnim( PYTHON_HOLSTER ); -} - -void CPython::SecondaryAttack( void ) -{ -#ifdef CLIENT_DLL - if( !bIsMultiplayer() ) -#else - if( !g_pGameRules->IsMultiplayer() ) -#endif - { - return; - } - - if( m_pPlayer->pev->fov != 0 ) - { - m_fInZoom = FALSE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - } - else if( m_pPlayer->pev->fov != 40 ) - { - m_fInZoom = TRUE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 40; - } - - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; -} - -void CPython::PrimaryAttack() -{ - // don't fire underwater - if( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound(); - m_flNextPrimaryAttack = 0.15; - return; - } - - if( m_iClip <= 0 ) - { - if( !m_fFireOnEmpty ) - Reload(); - else - { - PlayEmptySound(); - m_flNextPrimaryAttack = 0.15; - } - - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - - m_iClip--; - - m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecSrc = m_pPlayer->GetGunPosition(); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - Vector vecDir; - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usFirePython, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if( !m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - - m_flNextPrimaryAttack = 0.75; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - -void CPython::Reload( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == PYTHON_MAX_CLIP ) - return; - - if( m_pPlayer->pev->fov != 0 ) - { - m_fInZoom = FALSE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - } - - int bUseScope = FALSE; -#ifdef CLIENT_DLL - bUseScope = bIsMultiplayer(); -#else - bUseScope = g_pGameRules->IsMultiplayer(); -#endif - if( DefaultReload( PYTHON_MAX_CLIP, PYTHON_RELOAD, 2.0, bUseScope ) ) - { - m_flSoundDelay = 1.5; - } -} - -void CPython::WeaponIdle( void ) -{ - ResetEmptySound(); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); - if( m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) - { - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT( 0.8, 0.9 ), ATTN_NORM ); - m_flSoundDelay = 0; - } - - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0f, 1.0f ); - if( flRand <= 0.5 ) - { - iAnim = PYTHON_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 70.0 / 30.0 ); - } - else if( flRand <= 0.7 ) - { - iAnim = PYTHON_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 60.0 / 30.0 ); - } - else if( flRand <= 0.9 ) - { - iAnim = PYTHON_IDLE3; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 88.0 / 30.0 ); - } - else - { - iAnim = PYTHON_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 170.0 / 30.0 ); - } - - int bUseScope = FALSE; -#ifdef CLIENT_DLL - bUseScope = bIsMultiplayer(); -#else - bUseScope = g_pGameRules->IsMultiplayer(); -#endif - SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0, bUseScope ); -} - -class CPythonAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT(pev), "models/w_357ammobox.mdl" ); - CBasePlayerAmmo::Spawn(); - } - void Precache( void ) - { - PRECACHE_MODEL( "models/w_357ammobox.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if( pOther->GiveAmmo( AMMO_357BOX_GIVE, "357", _357_MAX_CARRY ) != -1 ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo ) -#endif diff --git a/dlls/rat.cpp b/dlls/rat.cpp deleted file mode 100644 index dd9a5905..00000000 --- a/dlls/rat.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// rat - environmental monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CRat : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); -}; - -LINK_ENTITY_TO_CLASS( monster_rat, CRat ) - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CRat::Classify( void ) -{ - return CLASS_INSECT; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CRat::SetYawSpeed( void ) -{ - int ys; - - switch( m_Activity ) - { - case ACT_IDLE: - default: - ys = 45; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// Spawn -//========================================================= -void CRat::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/bigrat.mdl" ); - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = 8; - pev->view_ofs = Vector( 0, 0, 6 );// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CRat::Precache() -{ - PRECACHE_MODEL( "models/bigrat.mdl" ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= diff --git a/dlls/roach.cpp b/dlls/roach.cpp deleted file mode 100644 index 692b4beb..00000000 --- a/dlls/roach.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// cockroach -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "soundent.h" -#include "decals.h" - -#define ROACH_IDLE 0 -#define ROACH_BORED 1 -#define ROACH_SCARED_BY_ENT 2 -#define ROACH_SCARED_BY_LIGHT 3 -#define ROACH_SMELL_FOOD 4 -#define ROACH_EAT 5 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -class CRoach : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - void EXPORT MonsterThink ( void ); - void Move( float flInterval ); - void PickNewDest( int iCondition ); - void EXPORT Touch( CBaseEntity *pOther ); - void Killed( entvars_t *pevAttacker, int iGib ); - - float m_flLastLightLevel; - float m_flNextSmellTime; - int Classify( void ); - void Look( int iDistance ); - int ISoundMask( void ); - - // UNDONE: These don't necessarily need to be save/restored, but if we add more data, it may - BOOL m_fLightHacked; - int m_iMode; - // ----------------------------- -}; - -LINK_ENTITY_TO_CLASS( monster_cockroach, CRoach ) - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CRoach::ISoundMask( void ) -{ - return bits_SOUND_CARCASS | bits_SOUND_MEAT; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CRoach::Classify( void ) -{ - return CLASS_INSECT; -} - -//========================================================= -// Touch -//========================================================= -void CRoach::Touch( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - if( pOther->pev->velocity == g_vecZero || !pOther->IsPlayer() ) - { - return; - } - - vecSpot = pev->origin + Vector( 0, 0, 8 );//move up a bit, and trace down. - UTIL_TraceLine( vecSpot, vecSpot + Vector( 0, 0, -24 ), ignore_monsters, ENT( pev ), &tr ); - - // This isn't really blood. So you don't have to screen it out based on violence levels (UTIL_ShouldShowBlood()) - UTIL_DecalTrace( &tr, DECAL_YBLOOD1 + RANDOM_LONG( 0, 5 ) ); - - TakeDamage( pOther->pev, pOther->pev, pev->health, DMG_CRUSH ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CRoach::SetYawSpeed( void ) -{ - int ys; - - ys = 120; - - pev->yaw_speed = ys; -} - -//========================================================= -// Spawn -//========================================================= -void CRoach::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/roach.mdl" ); - UTIL_SetSize( pev, Vector( -1, -1, 0 ), Vector( 1, 1, 2 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_YELLOW; - pev->effects = 0; - pev->health = 1; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); - SetActivity( ACT_IDLE ); - - pev->view_ofs = Vector( 0, 0, 1 );// position of the eyes relative to monster's origin. - pev->takedamage = DAMAGE_YES; - m_fLightHacked = FALSE; - m_flLastLightLevel = -1; - m_iMode = ROACH_IDLE; - m_flNextSmellTime = gpGlobals->time; -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CRoach::Precache() -{ - PRECACHE_MODEL( "models/roach.mdl" ); - - PRECACHE_SOUND( "roach/rch_die.wav" ); - PRECACHE_SOUND( "roach/rch_walk.wav" ); - PRECACHE_SOUND( "roach/rch_smash.wav" ); -} - -//========================================================= -// Killed. -//========================================================= -void CRoach::Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->solid = SOLID_NOT; - - //random sound - if( RANDOM_LONG( 0, 4 ) == 1 ) - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "roach/rch_die.wav", 0.8, ATTN_NORM, 0, 80 + RANDOM_LONG( 0, 39 ) ); - } - else - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_BODY, "roach/rch_smash.wav", 0.7, ATTN_NORM, 0, 80 + RANDOM_LONG( 0, 39 ) ); - } - - CSoundEnt::InsertSound( bits_SOUND_WORLD, pev->origin, 128, 1 ); - - CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); - if( pOwner ) - { - pOwner->DeathNotice( pev ); - } - UTIL_Remove( this ); -} - -//========================================================= -// MonsterThink, overridden for roaches. -//========================================================= -void CRoach::MonsterThink( void ) -{ - if( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 1, 1.5 ); - else - pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking - - float flInterval = StudioFrameAdvance(); // animate - - if( !m_fLightHacked ) - { - // if light value hasn't been collection for the first time yet, - // suspend the creature for a second so the world finishes spawning, then we'll collect the light level. - pev->nextthink = gpGlobals->time + 1; - m_fLightHacked = TRUE; - return; - } - else if( m_flLastLightLevel < 0 ) - { - // collect light level for the first time, now that all of the lightmaps in the roach's area have been calculated. - m_flLastLightLevel = GETENTITYILLUM( ENT( pev ) ); - } - - switch( m_iMode ) - { - case ROACH_IDLE: - case ROACH_EAT: - { - // if not moving, sample environment to see if anything scary is around. Do a radius search 'look' at random. - if( RANDOM_LONG( 0, 3 ) == 1 ) - { - Look( 150 ); - if( HasConditions( bits_COND_SEE_FEAR ) ) - { - // if see something scary - //ALERT( at_aiconsole, "Scared\n" ); - Eat( 30 + ( RANDOM_LONG( 0, 14 ) ) );// roach will ignore food for 30 to 45 seconds - PickNewDest( ROACH_SCARED_BY_ENT ); - SetActivity( ACT_WALK ); - } - else if( RANDOM_LONG( 0, 149 ) == 1 ) - { - // if roach doesn't see anything, there's still a chance that it will move. (boredom) - //ALERT( at_aiconsole, "Bored\n" ); - PickNewDest( ROACH_BORED ); - SetActivity( ACT_WALK ); - - if( m_iMode == ROACH_EAT ) - { - // roach will ignore food for 30 to 45 seconds if it got bored while eating. - Eat( 30 + ( RANDOM_LONG( 0, 14 ) ) ); - } - } - } - - // don't do this stuff if eating! - if( m_iMode == ROACH_IDLE ) - { - if( FShouldEat() ) - { - Listen(); - } - - if( GETENTITYILLUM( ENT( pev ) ) > m_flLastLightLevel ) - { - // someone turned on lights! - //ALERT( at_console, "Lights!\n" ); - PickNewDest( ROACH_SCARED_BY_LIGHT ); - SetActivity( ACT_WALK ); - } - else if( HasConditions( bits_COND_SMELL_FOOD ) ) - { - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); - - // roach smells food and is just standing around. Go to food unless food isn't on same z-plane. - if( pSound && fabs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3.0 ) - { - PickNewDest( ROACH_SMELL_FOOD ); - SetActivity( ACT_WALK ); - } - } - } - - break; - } - case ROACH_SCARED_BY_LIGHT: - { - // if roach was scared by light, then stop if we're over a spot at least as dark as where we started! - if( GETENTITYILLUM( ENT( pev ) ) <= m_flLastLightLevel ) - { - SetActivity( ACT_IDLE ); - m_flLastLightLevel = GETENTITYILLUM( ENT( pev ) );// make this our new light level. - } - break; - } - } - - if( m_flGroundSpeed != 0 ) - { - Move( flInterval ); - } -} - -//========================================================= -// Picks a new spot for roach to run to.( -//========================================================= -void CRoach::PickNewDest( int iCondition ) -{ - Vector vecNewDir; - Vector vecDest; - float flDist; - - m_iMode = iCondition; - - if( m_iMode == ROACH_SMELL_FOOD ) - { - // find the food and go there. - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); - - if( pSound ) - { - m_Route[0].vecLocation.x = pSound->m_vecOrigin.x + ( 3 - RANDOM_LONG( 0, 5 ) ); - m_Route[0].vecLocation.y = pSound->m_vecOrigin.y + ( 3 - RANDOM_LONG( 0, 5 ) ); - m_Route[0].vecLocation.z = pSound->m_vecOrigin.z; - m_Route[0].iType = bits_MF_TO_LOCATION; - m_movementGoal = RouteClassify( m_Route[0].iType ); - return; - } - } - - do - { - // picks a random spot, requiring that it be at least 128 units away - // else, the roach will pick a spot too close to itself and run in - // circles. this is a hack but buys me time to work on the real monsters. - vecNewDir.x = RANDOM_FLOAT( -1, 1 ); - vecNewDir.y = RANDOM_FLOAT( -1, 1 ); - flDist = 256 + ( RANDOM_LONG( 0, 255 ) ); - vecDest = pev->origin + vecNewDir * flDist; - - } while( ( vecDest - pev->origin ).Length2D() < 128 ); - - m_Route[0].vecLocation.x = vecDest.x; - m_Route[0].vecLocation.y = vecDest.y; - m_Route[0].vecLocation.z = pev->origin.z; - m_Route[0].iType = bits_MF_TO_LOCATION; - m_movementGoal = RouteClassify( m_Route[0].iType ); - - if( RANDOM_LONG( 0, 9 ) == 1 ) - { - // every once in a while, a roach will play a skitter sound when they decide to run - EMIT_SOUND_DYN( ENT( pev ), CHAN_BODY, "roach/rch_walk.wav", 1, ATTN_NORM, 0, 80 + RANDOM_LONG( 0, 39 ) ); - } -} - -//========================================================= -// roach's move function -//========================================================= -void CRoach::Move( float flInterval ) -{ - float flWaypointDist; - Vector vecApex; - - // local move to waypoint. - flWaypointDist = ( m_Route[m_iRouteIndex].vecLocation - pev->origin ).Length2D(); - MakeIdealYaw( m_Route[m_iRouteIndex].vecLocation ); - - ChangeYaw( pev->yaw_speed ); - UTIL_MakeVectors( pev->angles ); - - if( RANDOM_LONG( 0, 7 ) == 1 ) - { - // randomly check for blocked path.(more random load balancing) - if( !WALK_MOVE( ENT( pev ), pev->ideal_yaw, 4, WALKMOVE_NORMAL ) ) - { - // stuck, so just pick a new spot to run off to - PickNewDest( m_iMode ); - } - } - - WALK_MOVE( ENT( pev ), pev->ideal_yaw, m_flGroundSpeed * flInterval, WALKMOVE_NORMAL ); - - // if the waypoint is closer than step size, then stop after next step (ok for roach to overshoot) - if( flWaypointDist <= m_flGroundSpeed * flInterval ) - { - // take truncated step and stop - - SetActivity( ACT_IDLE ); - m_flLastLightLevel = GETENTITYILLUM( ENT( pev ) );// this is roach's new comfortable light level - - if( m_iMode == ROACH_SMELL_FOOD ) - { - m_iMode = ROACH_EAT; - } - else - { - m_iMode = ROACH_IDLE; - } - } - - if( RANDOM_LONG( 0, 149 ) == 1 && m_iMode != ROACH_SCARED_BY_LIGHT && m_iMode != ROACH_SMELL_FOOD ) - { - // random skitter while moving as long as not on a b-line to get out of light or going to food - PickNewDest( FALSE ); - } -} - -//========================================================= -// Look - overriden for the roach, which can virtually see -// 360 degrees. -//========================================================= -void CRoach::Look( int iDistance ) -{ - CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with - CBaseEntity *pPreviousEnt;// the last entity added to the link list - int iSighted = 0; - - // DON'T let visibility information from last frame sit around! - ClearConditions( bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR ); - - // 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! - if( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - return; - } - - m_pLink = NULL; - pPreviousEnt = this; - - // Does sphere also limit itself to PVS? - // Examine all entities within a reasonable radius - // !!!PERFORMANCE - let's trivially reject the ent list before radius searching! - while( ( pSightEnt = UTIL_FindEntityInSphere( pSightEnt, pev->origin, iDistance ) ) != NULL ) - { - // only consider ents that can be damaged. !!!temporarily only considering other monsters and clients - if( pSightEnt->IsPlayer() || FBitSet( pSightEnt->pev->flags, FL_MONSTER ) ) - { - if( /*FVisible( pSightEnt ) &&*/ !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && pSightEnt->pev->health > 0 ) - { - // NULL the Link pointer for each ent added to the link list. If other ents follow, the will overwrite - // this value. If this ent happens to be the last, the list will be properly terminated. - pPreviousEnt->m_pLink = pSightEnt; - pSightEnt->m_pLink = NULL; - pPreviousEnt = pSightEnt; - - // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when - // we see monsters other than the Enemy. - switch( IRelationship( pSightEnt ) ) - { - case R_FR: - iSighted |= bits_COND_SEE_FEAR; - break; - case R_NO: - break; - default: - ALERT( at_console, "%s can't asses %s\n", STRING( pev->classname ), STRING( pSightEnt->pev->classname ) ); - break; - } - } - } - } - SetConditions( iSighted ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp deleted file mode 100644 index dc8724bd..00000000 --- a/dlls/satchel.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - -enum satchel_state -{ - SATCHEL_IDLE = 0, - SATCHEL_READY, - SATCHEL_RELOAD -}; - -enum satchel_e -{ - SATCHEL_IDLE1 = 0, - SATCHEL_FIDGET1, - SATCHEL_DRAW, - SATCHEL_DROP -}; - -enum satchel_radio_e -{ - SATCHEL_RADIO_IDLE1 = 0, - SATCHEL_RADIO_FIDGET1, - SATCHEL_RADIO_DRAW, - SATCHEL_RADIO_FIRE, - SATCHEL_RADIO_HOLSTER -}; - -class CSatchelCharge : public CGrenade -{ - Vector m_lastBounceOrigin; // Used to fix a bug in engine: when object isn't moving, but its speed isn't 0 and on ground isn't set - void Spawn( void ); - void Precache( void ); - void BounceSound( void ); - - void EXPORT SatchelSlide( CBaseEntity *pOther ); - void EXPORT SatchelThink( void ); - -public: - void Deactivate( void ); -}; - -LINK_ENTITY_TO_CLASS( monster_satchel, CSatchelCharge ) - -//========================================================= -// Deactivate - do whatever it is we do to an orphaned -// satchel when we don't want it in the world anymore. -//========================================================= -void CSatchelCharge::Deactivate( void ) -{ - pev->solid = SOLID_NOT; - UTIL_Remove( this ); -} - -void CSatchelCharge::Spawn( void ) -{ - Precache(); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL( ENT( pev ), "models/w_satchel.mdl" ); - //UTIL_SetSize( pev, Vector( -16, -16, -4 ), Vector( 16, 16, 32 ) ); // Old box -- size of headcrab monsters/players get blocked by this - UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) ); // Uses point-sized, and can be stepped over - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( &CSatchelCharge::SatchelSlide ); - SetUse( &CGrenade::DetonateUse ); - SetThink( &CSatchelCharge::SatchelThink ); - pev->nextthink = gpGlobals->time + 0.1; - - pev->gravity = 0.5; - pev->friction = 0.8; - - pev->dmg = gSkillData.plrDmgSatchel; - // ResetSequenceInfo(); - pev->sequence = 1; -} - -void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) -{ - //entvars_t *pevOther = pOther->pev; - - // don't hit the guy that launched this grenade - if( pOther->edict() == pev->owner ) - return; - - // pev->avelocity = Vector( 300, 300, 300 ); - pev->gravity = 1;// normal gravity now - - // HACKHACK - On ground isn't always set, so look for ground underneath - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin - Vector( 0, 0, 10 ), ignore_monsters, edict(), &tr ); - - if( tr.flFraction < 1.0 ) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.95; - pev->avelocity = pev->avelocity * 0.9; - // play sliding sound, volume based on velocity - } - if( !( pev->flags & FL_ONGROUND ) && pev->velocity.Length2D() > 10 ) - { - // Fix for a bug in engine: when object isn't moving, but its speed isn't 0 and on ground isn't set - if( pev->origin != m_lastBounceOrigin ) - BounceSound(); - } - m_lastBounceOrigin = pev->origin; - // There is no model animation so commented this out to prevent net traffic - // StudioFrameAdvance(); -} - -void CSatchelCharge::SatchelThink( void ) -{ - // There is no model animation so commented this out to prevent net traffic - // StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - if( !IsInWorld() ) - { - UTIL_Remove( this ); - return; - } - - if( pev->waterlevel == 3 ) - { - pev->movetype = MOVETYPE_FLY; - pev->velocity = pev->velocity * 0.8; - pev->avelocity = pev->avelocity * 0.9; - pev->velocity.z += 8; - } - else if( pev->waterlevel == 0 ) - { - pev->movetype = MOVETYPE_BOUNCE; - } - else - { - pev->velocity.z -= 8; - } -} - -void CSatchelCharge::Precache( void ) -{ - PRECACHE_MODEL( "models/w_satchel.mdl" ); - PRECACHE_SOUND( "weapons/g_bounce1.wav" ); - PRECACHE_SOUND( "weapons/g_bounce2.wav" ); - PRECACHE_SOUND( "weapons/g_bounce3.wav" ); -} - -void CSatchelCharge::BounceSound( void ) -{ - switch( RANDOM_LONG( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/g_bounce1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/g_bounce2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/g_bounce3.wav", 1, ATTN_NORM ); - break; - } -} - -LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel ) - -//========================================================= -// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal -//========================================================= -int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) -{ - CSatchel *pSatchel; - -#ifdef CLIENT_DLL - if( bIsMultiplayer() ) -#else - if( g_pGameRules->IsMultiplayer() ) -#endif - { - pSatchel = (CSatchel *)pOriginal; - - if( pSatchel->m_chargeReady != SATCHEL_IDLE ) - { - // player has some satchels deployed. Refuse to add more. - return FALSE; - } - } - - return CBasePlayerWeapon::AddDuplicate( pOriginal ); -} - -//========================================================= -//========================================================= -int CSatchel::AddToPlayer( CBasePlayer *pPlayer ) -{ - int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); - - pPlayer->pev->weapons |= ( 1 << m_iId ); - m_chargeReady = SATCHEL_IDLE;// this satchel charge weapon now forgets that any satchels are deployed by it. - - if( bResult ) - { - return AddWeapon(); - } - return FALSE; -} - -void CSatchel::Spawn() -{ - Precache(); - m_iId = WEAPON_SATCHEL; - SET_MODEL( ENT( pev ), "models/w_satchel.mdl" ); - - m_iDefaultAmmo = SATCHEL_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -void CSatchel::Precache( void ) -{ - PRECACHE_MODEL( "models/v_satchel.mdl" ); - PRECACHE_MODEL( "models/v_satchel_radio.mdl" ); - PRECACHE_MODEL( "models/w_satchel.mdl" ); - PRECACHE_MODEL( "models/p_satchel.mdl" ); - PRECACHE_MODEL( "models/p_satchel_radio.mdl" ); - - UTIL_PrecacheOther( "monster_satchel" ); -} - -int CSatchel::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "Satchel Charge"; - p->iMaxAmmo1 = SATCHEL_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 1; - p->iFlags = ITEM_FLAG_SELECTONEMPTY | ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - p->iId = m_iId = WEAPON_SATCHEL; - p->iWeight = SATCHEL_WEIGHT; - - return 1; -} - -//========================================================= -//========================================================= -BOOL CSatchel::IsUseable( void ) -{ - return CanDeploy(); -} - -BOOL CSatchel::CanDeploy( void ) -{ - if( m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] > 0 ) - { - // player is carrying some satchels - return TRUE; - } - - if( m_chargeReady ) - { - // player isn't carrying any satchels, but has some out - return TRUE; - } - - return FALSE; -} - -BOOL CSatchel::Deploy() -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - - if( m_chargeReady ) - return DefaultDeploy( "models/v_satchel_radio.mdl", "models/p_satchel_radio.mdl", SATCHEL_RADIO_DRAW, "hive" ); - else - return DefaultDeploy( "models/v_satchel.mdl", "models/p_satchel.mdl", SATCHEL_DRAW, "trip" ); - - return TRUE; -} - -void CSatchel::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if( m_chargeReady ) - { - SendWeaponAnim( SATCHEL_RADIO_HOLSTER ); - } - else - { - SendWeaponAnim( SATCHEL_DROP ); - } - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM ); - - if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && m_chargeReady != SATCHEL_READY ) - { - m_pPlayer->pev->weapons &= ~( 1 << WEAPON_SATCHEL ); - DestroyItem(); - } -} - -void CSatchel::PrimaryAttack() -{ - switch( m_chargeReady ) - { - case SATCHEL_IDLE: - { - Throw(); - } - break; - case SATCHEL_READY: - { - SendWeaponAnim( SATCHEL_RADIO_FIRE ); - - edict_t *pPlayer = m_pPlayer->edict(); - - CBaseEntity *pSatchel = NULL; - - while( ( pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 ) ) != NULL ) - { - if( FClassnameIs( pSatchel->pev, "monster_satchel" ) ) - { - if( pSatchel->pev->owner == pPlayer ) - { - pSatchel->Use( m_pPlayer, m_pPlayer, USE_ON, 0 ); - } - } - } - - m_chargeReady = SATCHEL_RELOAD; - m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - break; - } - case SATCHEL_RELOAD: - // we're reloading, don't allow fire - break; - } -} - -void CSatchel::SecondaryAttack( void ) -{ - if( m_chargeReady != SATCHEL_RELOAD ) - { - Throw(); - } -} - -void CSatchel::Throw( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { -#ifndef CLIENT_DLL - Vector vecSrc = m_pPlayer->pev->origin; - - Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; - - CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, Vector( 0, 0, 0 ), m_pPlayer->edict() ); - pSatchel->pev->velocity = vecThrow; - pSatchel->pev->avelocity.y = 400; - - m_pPlayer->pev->viewmodel = MAKE_STRING( "models/v_satchel_radio.mdl" ); - m_pPlayer->pev->weaponmodel = MAKE_STRING( "models/p_satchel_radio.mdl" ); -#else - LoadVModel( "models/v_satchel_radio.mdl", m_pPlayer ); -#endif - - SendWeaponAnim( SATCHEL_RADIO_DRAW ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_chargeReady = SATCHEL_READY; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - } -} - -void CSatchel::WeaponIdle( void ) -{ - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - switch( m_chargeReady ) - { - case SATCHEL_IDLE: - SendWeaponAnim( SATCHEL_FIDGET1 ); - // use tripmine animations - strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - break; - case SATCHEL_READY: - SendWeaponAnim( SATCHEL_RADIO_FIDGET1 ); - // use hivehand animations - strcpy( m_pPlayer->m_szAnimExtention, "hive" ); - break; - case SATCHEL_RELOAD: - if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - m_chargeReady = 0; - RetireWeapon(); - return; - } - -#ifndef CLIENT_DLL - m_pPlayer->pev->viewmodel = MAKE_STRING( "models/v_satchel.mdl" ); - m_pPlayer->pev->weaponmodel = MAKE_STRING( "models/p_satchel.mdl" ); -#else - LoadVModel( "models/v_satchel.mdl", m_pPlayer ); -#endif - SendWeaponAnim( SATCHEL_DRAW ); - - // use tripmine animations - strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - - m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_chargeReady = SATCHEL_IDLE; - break; - } - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. -} - -//========================================================= -// DeactivateSatchels - removes all satchels owned by -// the provided player. Should only be used upon death. -// -// Made this global on purpose. -//========================================================= -void DeactivateSatchels( CBasePlayer *pOwner ) -{ - edict_t *pFind; - - pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "monster_satchel" ); - - while( !FNullEnt( pFind ) ) - { - CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); - CSatchelCharge *pSatchel = (CSatchelCharge *)pEnt; - - if( pSatchel ) - { - if( pSatchel->pev->owner == pOwner->edict() ) - { - pSatchel->Deactivate(); - } - } - - pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "monster_satchel" ); - } -} -#endif diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp deleted file mode 100644 index 7e94b286..00000000 --- a/dlls/scientist.cpp +++ /dev/null @@ -1,1431 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// human scientist (passive lab worker) -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "talkmonster.h" -#include "schedule.h" -#include "defaultai.h" -#include "scripted.h" -#include "animation.h" -#include "soundent.h" - -#define NUM_SCIENTIST_HEADS 4 // four heads available for scientist model - -enum -{ - HEAD_GLASSES = 0, - HEAD_EINSTEIN = 1, - HEAD_LUTHER = 2, - HEAD_SLICK = 3 -}; - -enum -{ - SCHED_HIDE = LAST_TALKMONSTER_SCHEDULE + 1, - SCHED_FEAR, - SCHED_PANIC, - SCHED_STARTLE, - SCHED_TARGET_CHASE_SCARED, - SCHED_TARGET_FACE_SCARED -}; - -enum -{ - TASK_SAY_HEAL = LAST_TALKMONSTER_TASK + 1, - TASK_HEAL, - TASK_SAY_FEAR, - TASK_RUN_PATH_SCARED, - TASK_SCREAM, - TASK_RANDOM_SCREAM, - TASK_MOVE_TO_TARGET_RANGE_SCARED -}; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define SCIENTIST_AE_HEAL ( 1 ) -#define SCIENTIST_AE_NEEDLEON ( 2 ) -#define SCIENTIST_AE_NEEDLEOFF ( 3 ) - -//======================================================= -// Scientist -//======================================================= -class CScientist : public CTalkMonster -{ -public: - void Spawn( void ); - void Precache( void ); - - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - int ObjectCaps( void ) { return CTalkMonster::ObjectCaps() | FCAP_IMPULSE_USE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - virtual int FriendNumber( int arrayNumber ); - void SetActivity( Activity newActivity ); - Activity GetStoppedActivity( void ); - int ISoundMask( void ); - void DeclineFollowing( void ); - - float CoverRadius( void ) { return 1200; } // Need more room for cover because scientists want to get far away! - BOOL DisregardEnemy( CBaseEntity *pEnemy ) { return !pEnemy->IsAlive() || ( gpGlobals->time - m_fearTime ) > 15; } - - BOOL CanHeal( void ); - void Heal( void ); - void Scream( void ); - - // Override these to set behavior - Schedule_t *GetScheduleOfType( int Type ); - Schedule_t *GetSchedule( void ); - MONSTERSTATE GetIdealState( void ); - - void DeathSound( void ); - void PainSound( void ); - - void TalkInit( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CUSTOM_SCHEDULES - -private: - float m_painTime; - float m_healTime; - float m_fearTime; -}; - -LINK_ENTITY_TO_CLASS( monster_scientist, CScientist ) - -TYPEDESCRIPTION CScientist::m_SaveData[] = -{ - DEFINE_FIELD( CScientist, m_painTime, FIELD_TIME ), - DEFINE_FIELD( CScientist, m_healTime, FIELD_TIME ), - DEFINE_FIELD( CScientist, m_fearTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CScientist, CTalkMonster ) - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlFollow[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_CANT_FOLLOW }, // If you fail, bail out of follow - { TASK_MOVE_TO_TARGET_RANGE, (float)128 }, // Move within 128 of target ent (client) - //{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slFollow[] = -{ - { - tlFollow, - ARRAYSIZE( tlFollow ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - bits_SOUND_COMBAT | - bits_SOUND_DANGER, - "Follow" - }, -}; - -Task_t tlFollowScared[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_CHASE },// If you fail, follow normally - { TASK_MOVE_TO_TARGET_RANGE_SCARED, (float)128 }, // Move within 128 of target ent (client) - //{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE_SCARED }, -}; - -Schedule_t slFollowScared[] = -{ - { - tlFollowScared, - ARRAYSIZE( tlFollowScared ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - bits_SOUND_DANGER, - "FollowScared" - }, -}; - -Task_t tlFaceTargetScared[] = -{ - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE_SCARED }, -}; - -Schedule_t slFaceTargetScared[] = -{ - { - tlFaceTargetScared, - ARRAYSIZE( tlFaceTargetScared ), - bits_COND_HEAR_SOUND | - bits_COND_NEW_ENEMY, - bits_SOUND_DANGER, - "FaceTargetScared" - }, -}; - -Task_t tlStopFollowing[] = -{ - { TASK_CANT_FOLLOW, (float)0 }, -}; - -Schedule_t slStopFollowing[] = -{ - { - tlStopFollowing, - ARRAYSIZE( tlStopFollowing ), - 0, - 0, - "StopFollowing" - }, -}; - -Task_t tlHeal[] = -{ - { TASK_MOVE_TO_TARGET_RANGE, (float)50 }, // Move within 60 of target ent (client) - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_CHASE }, // If you fail, catch up with that guy! (change this to put syringe away and then chase) - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SAY_HEAL, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_TARGET, (float)ACT_ARM }, // Whip out the needle - { TASK_HEAL, (float)0 }, // Put it in the player - { TASK_PLAY_SEQUENCE_FACE_TARGET, (float)ACT_DISARM }, // Put away the needle -}; - -Schedule_t slHeal[] = -{ - { - tlHeal, - ARRAYSIZE( tlHeal ), - 0, // Don't interrupt or he'll end up running around with a needle all the time - 0, - "Heal" - }, -}; - -Task_t tlFaceTarget[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE }, -}; - -Schedule_t slFaceTarget[] = -{ - { - tlFaceTarget, - ARRAYSIZE( tlFaceTarget ), - bits_COND_CLIENT_PUSH | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - bits_SOUND_COMBAT | - bits_SOUND_DANGER, - "FaceTarget" - }, -}; - -Task_t tlSciPanic[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SCREAM, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_EXCITED }, // This is really fear-stricken excitement - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slSciPanic[] = -{ - { - tlSciPanic, - ARRAYSIZE( tlSciPanic ), - 0, - 0, - "SciPanic" - }, -}; - -Task_t tlIdleSciStand[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds. - { TASK_TLK_HEADRESET, (float)0 }, // reset head position -}; - -Schedule_t slIdleSciStand[] = -{ - { - tlIdleSciStand, - ARRAYSIZE( tlIdleSciStand ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_CLIENT_PUSH | - bits_COND_PROVOKED, - bits_SOUND_COMBAT |// sound flags - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "IdleSciStand" - - }, -}; - -Task_t tlScientistCover[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH_SCARED, (float)0 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_SET_SCHEDULE, (float)SCHED_HIDE }, -}; - -Schedule_t slScientistCover[] = -{ - { - tlScientistCover, - ARRAYSIZE( tlScientistCover ), - bits_COND_NEW_ENEMY, - 0, - "ScientistCover" - }, -}; - -Task_t tlScientistHide[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, // FIXME: This looks lame - { TASK_WAIT_RANDOM, (float)10.0 }, -}; - -Schedule_t slScientistHide[] = -{ - { - tlScientistHide, - ARRAYSIZE( tlScientistHide ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_SEE_ENEMY | - bits_COND_SEE_HATE | - bits_COND_SEE_FEAR | - bits_COND_SEE_DISLIKE, - bits_SOUND_DANGER, - "ScientistHide" - }, -}; - -Task_t tlScientistStartle[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_RANDOM_SCREAM, (float)0.3 }, // Scream 30% of the time - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, - { TASK_RANDOM_SCREAM, (float)0.1 }, // Scream again 10% of the time - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCHIDLE }, - { TASK_WAIT_RANDOM, (float)1.0 }, -}; - -Schedule_t slScientistStartle[] = -{ - { - tlScientistStartle, - ARRAYSIZE( tlScientistStartle ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_ENEMY | - bits_COND_SEE_HATE | - bits_COND_SEE_FEAR | - bits_COND_SEE_DISLIKE, - 0, - "ScientistStartle" - }, -}; - -Task_t tlFear[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SAY_FEAR, (float)0 }, - //{ TASK_PLAY_SEQUENCE, (float)ACT_FEAR_DISPLAY }, -}; - -Schedule_t slFear[] = -{ - { - tlFear, - ARRAYSIZE( tlFear ), - bits_COND_NEW_ENEMY, - 0, - "Fear" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CScientist ) -{ - slFollow, - slFaceTarget, - slIdleSciStand, - slFear, - slScientistCover, - slScientistHide, - slScientistStartle, - slHeal, - slStopFollowing, - slSciPanic, - slFollowScared, - slFaceTargetScared, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CScientist, CTalkMonster ) - -void CScientist::DeclineFollowing( void ) -{ - Talk( 10 ); - m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); -} - -void CScientist::Scream( void ) -{ - if( FOkToSpeak() ) - { - Talk( 10 ); - m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_SCREAM", RANDOM_FLOAT( 3, 6 ), VOL_NORM, ATTN_NORM ); - } -} - -Activity CScientist::GetStoppedActivity( void ) -{ - if( m_hEnemy != 0 ) - return ACT_EXCITED; - return CTalkMonster::GetStoppedActivity(); -} - -void CScientist::StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_SAY_HEAL: - //if( FOkToSpeak() ) - Talk( 2 ); - m_hTalkTarget = m_hTargetEnt; - PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); - TaskComplete(); - break; - case TASK_SCREAM: - Scream(); - TaskComplete(); - break; - case TASK_RANDOM_SCREAM: - if( RANDOM_FLOAT( 0, 1 ) < pTask->flData ) - Scream(); - TaskComplete(); - break; - case TASK_SAY_FEAR: - if( FOkToSpeak() ) - { - Talk( 2 ); - m_hTalkTarget = m_hEnemy; - - //The enemy can be null here. - Solokiller - //Discovered while testing the barnacle grapple on headcrabs with scientists in view. - if( m_hEnemy != 0 && m_hEnemy->IsPlayer() ) - PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); - else - PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); - } - TaskComplete(); - break; - case TASK_HEAL: - m_IdealActivity = ACT_MELEE_ATTACK1; - break; - case TASK_RUN_PATH_SCARED: - m_movementActivity = ACT_RUN_SCARED; - break; - case TASK_MOVE_TO_TARGET_RANGE_SCARED: - { - if( ( m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - if( !MoveToTarget( ACT_WALK_SCARED, 0.5 ) ) - TaskFail(); - } - } - break; - default: - CTalkMonster::StartTask( pTask ); - break; - } -} - -void CScientist::RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_RUN_PATH_SCARED: - if( MovementIsComplete() ) - TaskComplete(); - if( RANDOM_LONG( 0, 31 ) < 8 ) - Scream(); - break; - case TASK_MOVE_TO_TARGET_RANGE_SCARED: - { - if( RANDOM_LONG( 0, 63 ) < 8 ) - Scream(); - - if( m_hEnemy == 0 ) - { - TaskFail(); - } - else - { - float distance; - - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Re-evaluate when you think your finished, or the target has moved too far - if( ( distance < pTask->flData ) || ( m_vecMoveGoal - m_hTargetEnt->pev->origin ).Length() > pTask->flData * 0.5 ) - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - FRefreshRoute(); - } - - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if( distance < pTask->flData ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - else if( distance < 190 && m_movementActivity != ACT_WALK_SCARED ) - m_movementActivity = ACT_WALK_SCARED; - else if( distance >= 270 && m_movementActivity != ACT_RUN_SCARED ) - m_movementActivity = ACT_RUN_SCARED; - } - } - break; - case TASK_HEAL: - if( m_fSequenceFinished ) - { - TaskComplete(); - } - else - { - if( TargetDistance() > 90 ) - TaskComplete(); - pev->ideal_yaw = UTIL_VecToYaw( m_hTargetEnt->pev->origin - pev->origin ); - ChangeYaw( pev->yaw_speed ); - } - break; - default: - CTalkMonster::RunTask( pTask ); - break; - } -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CScientist::Classify( void ) -{ - return CLASS_HUMAN_PASSIVE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CScientist::SetYawSpeed( void ) -{ - int ys; - - ys = 90; - - switch( m_Activity ) - { - case ACT_IDLE: - ys = 120; - break; - case ACT_WALK: - ys = 180; - break; - case ACT_RUN: - ys = 150; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 120; - break; - default: - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CScientist::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case SCIENTIST_AE_HEAL: // Heal my target (if within range) - Heal(); - break; - case SCIENTIST_AE_NEEDLEON: - { - int oldBody = pev->body; - pev->body = ( oldBody % NUM_SCIENTIST_HEADS ) + NUM_SCIENTIST_HEADS * 1; - } - break; - case SCIENTIST_AE_NEEDLEOFF: - { - int oldBody = pev->body; - pev->body = ( oldBody % NUM_SCIENTIST_HEADS ) + NUM_SCIENTIST_HEADS * 0; - } - break; - default: - CTalkMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CScientist::Spawn( void ) -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/scientist.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = gSkillData.scientistHealth; - pev->view_ofs = Vector( 0, 0, 50 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - - //m_flDistTooFar = 256.0; - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - - // White hands - pev->skin = 0; - - if( pev->body == -1 ) - { - // -1 chooses a random head - pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head - } - - // Luther is black, make his hands black - if( pev->body == HEAD_LUTHER ) - pev->skin = 1; - - MonsterInit(); - SetUse( &CTalkMonster::FollowerUse ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CScientist::Precache( void ) -{ - PRECACHE_MODEL( "models/scientist.mdl" ); - PRECACHE_SOUND( "scientist/sci_pain1.wav" ); - PRECACHE_SOUND( "scientist/sci_pain2.wav" ); - PRECACHE_SOUND( "scientist/sci_pain3.wav" ); - PRECACHE_SOUND( "scientist/sci_pain4.wav" ); - PRECACHE_SOUND( "scientist/sci_pain5.wav" ); - - // every new scientist must call this, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - TalkInit(); - - CTalkMonster::Precache(); -} - -// Init talk data -void CScientist::TalkInit() -{ - CTalkMonster::TalkInit(); - - // scientist will try to talk to friends in this order: - - m_szFriends[0] = "monster_scientist"; - m_szFriends[1] = "monster_sitting_scientist"; - m_szFriends[2] = "monster_barney"; - - // scientists speach group names (group names are in sentences.txt) - - m_szGrp[TLK_ANSWER] = "SC_ANSWER"; - m_szGrp[TLK_QUESTION] = "SC_QUESTION"; - m_szGrp[TLK_IDLE] = "SC_IDLE"; - m_szGrp[TLK_STARE] = "SC_STARE"; - m_szGrp[TLK_USE] = "SC_OK"; - m_szGrp[TLK_UNUSE] = "SC_WAIT"; - m_szGrp[TLK_STOP] = "SC_STOP"; - m_szGrp[TLK_NOSHOOT] = "SC_SCARED"; - m_szGrp[TLK_HELLO] = "SC_HELLO"; - - m_szGrp[TLK_PLHURT1] = "!SC_CUREA"; - m_szGrp[TLK_PLHURT2] = "!SC_CUREB"; - m_szGrp[TLK_PLHURT3] = "!SC_CUREC"; - - m_szGrp[TLK_PHELLO] = "SC_PHELLO"; - m_szGrp[TLK_PIDLE] = "SC_PIDLE"; - m_szGrp[TLK_PQUESTION] = "SC_PQUEST"; - m_szGrp[TLK_SMELL] = "SC_SMELL"; - - m_szGrp[TLK_WOUND] = "SC_WOUND"; - m_szGrp[TLK_MORTAL] = "SC_MORTAL"; - - // get voice for head - switch( pev->body % 3 ) - { - default: - case HEAD_GLASSES: - m_voicePitch = 105; - break; //glasses - case HEAD_EINSTEIN: - m_voicePitch = 100; - break; //einstein - case HEAD_LUTHER: - m_voicePitch = 95; - break; //luther - case HEAD_SLICK: - m_voicePitch = 100; - break; //slick - } -} - -int CScientist::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if( pevInflictor && pevInflictor->flags & FL_CLIENT ) - { - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); - } - - // make sure friends talk about it if player hurts scientist... - return CTalkMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CScientist::ISoundMask( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - -//========================================================= -// PainSound -//========================================================= -void CScientist::PainSound( void ) -{ - if( gpGlobals->time < m_painTime ) - return; - - m_painTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 0.75 ); - - switch( RANDOM_LONG( 0, 4 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "scientist/sci_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - case 1: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "scientist/sci_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - case 2: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "scientist/sci_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - case 3: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "scientist/sci_pain4.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - case 4: - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "scientist/sci_pain5.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); - break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CScientist::DeathSound( void ) -{ - PainSound(); -} - -void CScientist::Killed( entvars_t *pevAttacker, int iGib ) -{ - SetUse( NULL ); - CTalkMonster::Killed( pevAttacker, iGib ); -} - -void CScientist::SetActivity( Activity newActivity ) -{ - int iSequence; - - iSequence = LookupActivity( newActivity ); - - // Set to the desired anim, or default anim if the desired is not present - if( iSequence == ACTIVITY_NOT_AVAILABLE ) - newActivity = ACT_IDLE; - CTalkMonster::SetActivity( newActivity ); -} - -Schedule_t *CScientist::GetScheduleOfType( int Type ) -{ - Schedule_t *psched; - - switch( Type ) - { - // Hook these to make a looping schedule - case SCHED_TARGET_FACE: - // call base class default so that scientist will talk - // when 'used' - psched = CTalkMonster::GetScheduleOfType( Type ); - - if( psched == slIdleStand ) - return slFaceTarget; // override this for different target face behavior - else - return psched; - case SCHED_TARGET_CHASE: - return slFollow; - case SCHED_CANT_FOLLOW: - return slStopFollowing; - case SCHED_PANIC: - return slSciPanic; - case SCHED_TARGET_CHASE_SCARED: - return slFollowScared; - case SCHED_TARGET_FACE_SCARED: - return slFaceTargetScared; - case SCHED_IDLE_STAND: - // call base class default so that scientist will talk - // when standing during idle - psched = CTalkMonster::GetScheduleOfType( Type ); - - if( psched == slIdleStand ) - return slIdleSciStand; - else - return psched; - case SCHED_HIDE: - return slScientistHide; - case SCHED_STARTLE: - return slScientistStartle; - case SCHED_FEAR: - return slFear; - } - - return CTalkMonster::GetScheduleOfType( Type ); -} - -Schedule_t *CScientist::GetSchedule( void ) -{ - // so we don't keep calling through the EHANDLE stuff - CBaseEntity *pEnemy = m_hEnemy; - - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if( pSound && ( pSound->m_iType & bits_SOUND_DANGER ) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - - switch( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if( pEnemy ) - { - if( HasConditions( bits_COND_SEE_ENEMY ) ) - m_fearTime = gpGlobals->time; - else if( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert - { - m_hEnemy = 0; - pEnemy = 0; - } - } - - if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - // flinch if hurt - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - // Cower when you hear something scary - if( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if( pSound ) - { - if( pSound->m_iType & ( bits_SOUND_DANGER | bits_SOUND_COMBAT ) ) - { - if( gpGlobals->time - m_fearTime > 3 ) // Only cower every 3 seconds or so - { - m_fearTime = gpGlobals->time; // Update last fear - return GetScheduleOfType( SCHED_STARTLE ); // This will just duck for a second - } - } - } - } - - // Behavior for following the player - if( IsFollowing() ) - { - if( !m_hTargetEnt->IsAlive() ) - { - // UNDONE: Comment about the recently dead player here? - StopFollowing( FALSE ); - break; - } - - int relationship = R_NO; - - // Nothing scary, just me and the player - if( pEnemy != NULL ) - relationship = IRelationship( pEnemy ); - - // UNDONE: Model fear properly, fix R_FR and add multiple levels of fear - if( relationship != R_DL && relationship != R_HT ) - { - // If I'm already close enough to my target - if( TargetDistance() <= 128 ) - { - if( CanHeal() ) // Heal opportunistically - return slHeal; - if( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move - return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); - } - return GetScheduleOfType( SCHED_TARGET_FACE ); // Just face and follow. - } - else // UNDONE: When afraid, scientist won't move out of your way. Keep This? If not, write move away scared - { - if( HasConditions( bits_COND_NEW_ENEMY ) ) // I just saw something new and scary, react - return GetScheduleOfType( SCHED_FEAR ); // React to something scary - return GetScheduleOfType( SCHED_TARGET_FACE_SCARED ); // face and follow, but I'm scared! - } - } - - if( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move - return GetScheduleOfType( SCHED_MOVE_AWAY ); - - // try to say something about smells - TrySmellTalk(); - break; - case MONSTERSTATE_COMBAT: - if( HasConditions( bits_COND_NEW_ENEMY ) ) - return slFear; // Point and scream! - if( HasConditions( bits_COND_SEE_ENEMY ) ) - return slScientistCover; // Take Cover - - if( HasConditions( bits_COND_HEAR_SOUND ) ) - return slTakeCoverFromBestSound; // Cower and panic from the scary sound! - - return slScientistCover; // Run & Cower - break; - default: - break; - } - - return CTalkMonster::GetSchedule(); -} - -MONSTERSTATE CScientist::GetIdealState( void ) -{ - switch( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if( HasConditions( bits_COND_NEW_ENEMY ) ) - { - if( IsFollowing() ) - { - int relationship = IRelationship( m_hEnemy ); - if( relationship != R_FR || ( relationship != R_HT && !HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) ) - { - // Don't go to combat if you're following the player - m_IdealMonsterState = MONSTERSTATE_ALERT; - return m_IdealMonsterState; - } - StopFollowing( TRUE ); - } - } - else if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - // Stop following if you take damage - if( IsFollowing() ) - StopFollowing( TRUE ); - } - break; - case MONSTERSTATE_COMBAT: - { - CBaseEntity *pEnemy = m_hEnemy; - if( pEnemy != NULL ) - { - if( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert - { - // Strip enemy when going to alert - m_IdealMonsterState = MONSTERSTATE_ALERT; - m_hEnemy = 0; - return m_IdealMonsterState; - } - - // Follow if only scared a little - if( m_hTargetEnt != 0 ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - return m_IdealMonsterState; - } - - if( HasConditions( bits_COND_SEE_ENEMY ) ) - { - m_fearTime = gpGlobals->time; - m_IdealMonsterState = MONSTERSTATE_COMBAT; - return m_IdealMonsterState; - } - } - } - break; - default: - break; - } - - return CTalkMonster::GetIdealState(); -} - -BOOL CScientist::CanHeal( void ) -{ - if( ( m_healTime > gpGlobals->time ) || ( m_hTargetEnt == 0 ) || ( m_hTargetEnt->pev->health > ( m_hTargetEnt->pev->max_health * 0.5 ) ) ) - return FALSE; - - return TRUE; -} - -void CScientist::Heal( void ) -{ - if( !CanHeal() ) - return; - - Vector target = m_hTargetEnt->pev->origin - pev->origin; - if( target.Length() > 100 ) - return; - - m_hTargetEnt->TakeHealth( gSkillData.scientistHeal, DMG_GENERIC ); - // Don't heal again for 1 minute - m_healTime = gpGlobals->time + 60; -} - -int CScientist::FriendNumber( int arrayNumber ) -{ - static int array[3] = { 1, 2, 0 }; - if( arrayNumber < 3 ) - return array[arrayNumber]; - return arrayNumber; -} - - -//========================================================= -// Dead Scientist PROP -//========================================================= -class CDeadScientist : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify( void ) - { - return CLASS_HUMAN_PASSIVE; - } - - void KeyValue( KeyValueData *pkvd ); - int m_iPose;// which sequence to display - static const char *m_szPoses[7]; -}; - -const char *CDeadScientist::m_szPoses[] = -{ - "lying_on_back", - "lying_on_stomach", - "dead_sitting", - "dead_hang", - "dead_table1", - "dead_table2", - "dead_table3" -}; - -void CDeadScientist::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "pose" ) ) - { - m_iPose = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} -LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist ) - -// -// ********** DeadScientist SPAWN ********** -// -void CDeadScientist::Spawn() -{ - PRECACHE_MODEL( "models/scientist.mdl" ); - SET_MODEL( ENT( pev ), "models/scientist.mdl" ); - - pev->effects = 0; - pev->sequence = 0; - - // Corpses have less health - pev->health = 8;//gSkillData.scientistHealth; - - m_bloodColor = BLOOD_COLOR_RED; - - if( pev->body == -1 ) - { - // -1 chooses a random head - pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head - } - - // Luther is black, make his hands black - if( pev->body == HEAD_LUTHER ) - pev->skin = 1; - else - pev->skin = 0; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - if( pev->sequence == -1 ) - { - ALERT ( at_console, "Dead scientist with bad pose\n" ); - } - - // pev->skin += 2; // use bloody skin -- UNDONE: Turn this back on when we have a bloody skin again! - MonsterInitDead(); -} - -//========================================================= -// Sitting Scientist PROP -//========================================================= -class CSittingScientist : public CScientist // kdb: changed from public CBaseMonster so he can speak -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT SittingThink( void ); - int Classify( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual void SetAnswerQuestion( CTalkMonster *pSpeaker ); - int FriendNumber( int arrayNumber ); - - int FIdleSpeak( void ); - int m_baseSequence; - int m_headTurn; - float m_flResponseDelay; -}; - -LINK_ENTITY_TO_CLASS( monster_sitting_scientist, CSittingScientist ) - -TYPEDESCRIPTION CSittingScientist::m_SaveData[] = -{ - // Don't need to save/restore m_baseSequence (recalced) - DEFINE_FIELD( CSittingScientist, m_headTurn, FIELD_INTEGER ), - DEFINE_FIELD( CSittingScientist, m_flResponseDelay, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CSittingScientist, CScientist ) - -// animation sequence aliases -typedef enum -{ -SITTING_ANIM_sitlookleft, -SITTING_ANIM_sitlookright, -SITTING_ANIM_sitscared, -SITTING_ANIM_sitting2, -SITTING_ANIM_sitting3 -} SITTING_ANIM; - -// -// ********** Scientist SPAWN ********** -// -void CSittingScientist::Spawn() -{ - PRECACHE_MODEL( "models/scientist.mdl" ); - SET_MODEL( ENT( pev ), "models/scientist.mdl" ); - Precache(); - InitBoneControllers(); - - UTIL_SetSize( pev, Vector( -14, -14, 0 ), Vector( 14, 14, 36 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 50; - - m_bloodColor = BLOOD_COLOR_RED; - m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) - - m_afCapability= bits_CAP_HEAR | bits_CAP_TURN_HEAD; - - SetBits( pev->spawnflags, SF_MONSTER_PREDISASTER ); // predisaster only! - - if( pev->body == -1 ) - { - // -1 chooses a random head - pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head - } - - // Luther is black, make his hands black - if( pev->body == HEAD_LUTHER ) - pev->skin = 1; - - m_baseSequence = LookupSequence( "sitlookleft" ); - pev->sequence = m_baseSequence + RANDOM_LONG( 0, 4 ); - ResetSequenceInfo(); - - SetThink( &CSittingScientist::SittingThink ); - pev->nextthink = gpGlobals->time + 0.1; - - DROP_TO_FLOOR( ENT( pev ) ); -} - -void CSittingScientist::Precache( void ) -{ - m_baseSequence = LookupSequence( "sitlookleft" ); - TalkInit(); -} - -//========================================================= -// ID as a passive human -//========================================================= -int CSittingScientist::Classify( void ) -{ - return CLASS_HUMAN_PASSIVE; -} - -int CSittingScientist::FriendNumber( int arrayNumber ) -{ - static int array[3] = { 2, 1, 0 }; - if( arrayNumber < 3 ) - return array[arrayNumber]; - return arrayNumber; -} - -//========================================================= -// sit, do stuff -//========================================================= -void CSittingScientist::SittingThink( void ) -{ - CBaseEntity *pent; - - StudioFrameAdvance(); - - // try to greet player - if( FIdleHello() ) - { - pent = FindNearestFriend( TRUE ); - if( pent ) - { - float yaw = VecToYaw( pent->pev->origin - pev->origin ) - pev->angles.y; - - if( yaw > 180 ) - yaw -= 360; - if( yaw < -180 ) - yaw += 360; - - if( yaw > 0 ) - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookleft; - else - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookright; - - ResetSequenceInfo(); - pev->frame = 0; - SetBoneController( 0, 0 ); - } - } - else if( m_fSequenceFinished ) - { - int i = RANDOM_LONG( 0, 99 ); - m_headTurn = 0; - - if( m_flResponseDelay && gpGlobals->time > m_flResponseDelay ) - { - // respond to question - IdleRespond(); - pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; - m_flResponseDelay = 0; - } - else if( i < 30 ) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - - // turn towards player or nearest friend and speak - - if( !FBitSet( m_bitsSaid, bit_saidHelloPlayer ) ) - pent = FindNearestFriend( TRUE ); - else - pent = FindNearestFriend( FALSE ); - - if( !FIdleSpeak() || !pent ) - { - m_headTurn = RANDOM_LONG( 0, 8 ) * 10 - 40; - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - } - else - { - // only turn head if we spoke - float yaw = VecToYaw( pent->pev->origin - pev->origin ) - pev->angles.y; - - if( yaw > 180 ) - yaw -= 360; - if( yaw < -180 ) - yaw += 360; - - if( yaw > 0 ) - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookleft; - else - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookright; - - //ALERT( at_console, "sitting speak\n" ); - } - } - else if( i < 60 ) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - m_headTurn = RANDOM_LONG( 0, 8 ) * 10 - 40; - if( RANDOM_LONG( 0, 99 ) < 5 ) - { - //ALERT( at_console, "sitting speak2\n" ); - FIdleSpeak(); - } - } - else if( i < 80 ) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting2; - } - else if( i < 100 ) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; - } - - ResetSequenceInfo( ); - pev->frame = 0; - SetBoneController( 0, m_headTurn ); - } - pev->nextthink = gpGlobals->time + 0.1; -} - -// prepare sitting scientist to answer a question -void CSittingScientist::SetAnswerQuestion( CTalkMonster *pSpeaker ) -{ - m_flResponseDelay = gpGlobals->time + RANDOM_FLOAT( 3, 4 ); - m_hTalkTarget = (CBaseMonster *)pSpeaker; -} - -//========================================================= -// FIdleSpeak -// ask question of nearby friend, or make statement -//========================================================= -int CSittingScientist::FIdleSpeak( void ) -{ - // try to start a conversation, or make statement - int pitch; - - if( !FOkToSpeak() ) - return FALSE; - - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT( 4.8, 5.2 ); - - pitch = GetVoicePitch(); - - // if there is a friend nearby to speak to, play sentence, set friend's response time, return - - // try to talk to any standing or sitting scientists nearby - CBaseEntity *pentFriend = FindNearestFriend( FALSE ); - - if( pentFriend && RANDOM_LONG( 0, 1 ) ) - { - CTalkMonster *pTalkMonster = GetClassPtr( (CTalkMonster *)pentFriend->pev ); - pTalkMonster->SetAnswerQuestion( this ); - - IdleHeadTurn( pentFriend->pev->origin ); - SENTENCEG_PlayRndSz( ENT( pev ), m_szGrp[TLK_PQUESTION], 1.0, ATTN_IDLE, 0, pitch ); - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT( 4.8, 5.2 ); - return TRUE; - } - - // otherwise, play an idle statement - if( RANDOM_LONG( 0, 1 ) ) - { - SENTENCEG_PlayRndSz( ENT( pev ), m_szGrp[TLK_PIDLE], 1.0, ATTN_IDLE, 0, pitch ); - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT( 4.8, 5.2 ); - return TRUE; - } - - // never spoke - CTalkMonster::g_talkWaitTime = 0; - return FALSE; -} diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp deleted file mode 100644 index a08770b3..00000000 --- a/dlls/shotgun.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - -// special deathmatch shotgun spreads -#define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees -#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees - -enum shotgun_e -{ - SHOTGUN_IDLE = 0, - SHOTGUN_FIRE, - SHOTGUN_FIRE2, - SHOTGUN_RELOAD, - SHOTGUN_PUMP, - SHOTGUN_START_RELOAD, - SHOTGUN_DRAW, - SHOTGUN_HOLSTER, - SHOTGUN_IDLE4, - SHOTGUN_IDLE_DEEP -}; - -LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ) - -void CShotgun::Spawn() -{ - Precache(); - m_iId = WEAPON_SHOTGUN; - SET_MODEL( ENT( pev ), "models/w_shotgun.mdl" ); - - m_iDefaultAmmo = SHOTGUN_DEFAULT_GIVE; - - FallInit();// get ready to fall -} - -void CShotgun::Precache( void ) -{ - PRECACHE_MODEL( "models/v_shotgun.mdl" ); - PRECACHE_MODEL( "models/w_shotgun.mdl" ); - PRECACHE_MODEL( "models/p_shotgun.mdl" ); - - m_iShell = PRECACHE_MODEL( "models/shotgunshell.mdl" );// shotgun shell - - PRECACHE_SOUND( "items/9mmclip1.wav" ); - - PRECACHE_SOUND( "weapons/dbarrel1.wav" );//shotgun - PRECACHE_SOUND( "weapons/sbarrel1.wav" );//shotgun - - PRECACHE_SOUND( "weapons/reload1.wav" ); // shotgun reload - PRECACHE_SOUND( "weapons/reload3.wav" ); // shotgun reload - - //PRECACHE_SOUND( "weapons/sshell1.wav" ); // shotgun reload - played on client - //PRECACHE_SOUND( "weapons/sshell3.wav" ); // shotgun reload - played on client - - PRECACHE_SOUND( "weapons/357_cock1.wav" ); // gun empty sound - PRECACHE_SOUND( "weapons/scock1.wav" ); // cock gun - - m_usSingleFire = PRECACHE_EVENT( 1, "events/shotgun1.sc" ); - m_usDoubleFire = PRECACHE_EVENT( 1, "events/shotgun2.sc" ); -} - -int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) -{ - if( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -int CShotgun::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "buckshot"; - p->iMaxAmmo1 = BUCKSHOT_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = SHOTGUN_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 1; - p->iFlags = 0; - p->iId = m_iId = WEAPON_SHOTGUN; - p->iWeight = SHOTGUN_WEIGHT; - - return 1; -} - -BOOL CShotgun::Deploy() -{ - return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" ); -} - -void CShotgun::PrimaryAttack() -{ - // don't fire underwater - if( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound(); - m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); - return; - } - - if( m_iClip <= 0 ) - { - Reload(); - if( m_iClip == 0 ) - PlayEmptySound(); - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip--; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector vecSrc = m_pPlayer->GetGunPosition(); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - Vector vecDir; - -#ifdef CLIENT_DLL - if( bIsMultiplayer() ) -#else - if( g_pGameRules->IsMultiplayer() ) -#endif - { - vecDir = m_pPlayer->FireBulletsPlayer( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // regular old, untouched spread. - vecDir = m_pPlayer->FireBulletsPlayer( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSingleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if( !m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - - //if( m_iClip != 0 ) - m_flPumpTime = gpGlobals->time + 0.5; - - m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - if( m_iClip != 0 ) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; - else - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; - m_fInSpecialReload = 0; -} - -void CShotgun::SecondaryAttack( void ) -{ - // don't fire underwater - if( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound(); - m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); - return; - } - - if( m_iClip <= 1 ) - { - Reload(); - PlayEmptySound(); - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip -= 2; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - m_pPlayer->pev->effects = (int)( m_pPlayer->pev->effects ) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector vecSrc = m_pPlayer->GetGunPosition(); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - Vector vecDir; - -#ifdef CLIENT_DLL - if( bIsMultiplayer() ) -#else - if( g_pGameRules->IsMultiplayer() ) -#endif - { - // tuned for deathmatch - vecDir = m_pPlayer->FireBulletsPlayer( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // untouched default single player - vecDir = m_pPlayer->FireBulletsPlayer( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usDoubleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if( !m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - - //if( m_iClip != 0 ) - m_flPumpTime = gpGlobals->time + 0.95; - - m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; - if( m_iClip != 0 ) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; - else - m_flTimeWeaponIdle = 1.5; - - m_fInSpecialReload = 0; -} - -void CShotgun::Reload( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP ) - return; - - // don't reload until recoil is done - if( m_flNextPrimaryAttack > UTIL_WeaponTimeBase() ) - return; - - // check to see if we're ready to reload - if( m_fInSpecialReload == 0 ) - { - SendWeaponAnim( SHOTGUN_START_RELOAD ); - m_fInSpecialReload = 1; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; - m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; - return; - } - else if( m_fInSpecialReload == 1 ) - { - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - // was waiting for gun to move to side - m_fInSpecialReload = 2; - - if( RANDOM_LONG( 0, 1 ) ) - EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/reload1.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG( 0, 0x1f ) ); - else - EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/reload3.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG( 0, 0x1f ) ); - - SendWeaponAnim( SHOTGUN_RELOAD ); - - m_flNextReload = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - } - else - { - // Add them to the clip - m_iClip += 1; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 1; - m_fInSpecialReload = 1; - } -} - -void CShotgun::WeaponTick() -{ - if( m_flPumpTime && m_flPumpTime < gpGlobals->time ) - { - // play pumping sound - EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG( 0, 0x1f ) ); - m_flPumpTime = 0; - } -} - -void CShotgun::WeaponIdle( void ) -{ - ResetEmptySound(); - - m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) - { - if( m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - Reload(); - } - else if( m_fInSpecialReload != 0 ) - { - if( m_iClip != SHOTGUN_MAX_CLIP && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - Reload(); - } - else - { - // reload debounce has timed out - SendWeaponAnim( SHOTGUN_PUMP ); - - // play cocking sound - EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG( 0, 0x1f ) ); - m_fInSpecialReload = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; - } - } - else - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if( flRand <= 0.8 ) - { - iAnim = SHOTGUN_IDLE_DEEP; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 60.0 / 12.0 );// * RANDOM_LONG( 2, 5 ); - } - else if( flRand <= 0.95 ) - { - iAnim = SHOTGUN_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 20.0 / 9.0 ); - } - else - { - iAnim = SHOTGUN_IDLE4; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + ( 20.0 / 9.0 ); - } - SendWeaponAnim( iAnim ); - } - } -} - -class CShotgunAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache(); - SET_MODEL( ENT( pev ), "models/w_shotbox.mdl" ); - CBasePlayerAmmo::Spawn(); - } - void Precache( void ) - { - PRECACHE_MODEL( "models/w_shotbox.mdl" ); - PRECACHE_SOUND( "items/9mmclip1.wav" ); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if( pOther->GiveAmmo( AMMO_BUCKSHOTBOX_GIVE, "buckshot", BUCKSHOT_MAX_CARRY ) != -1 ) - { - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM ); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmo ) diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp deleted file mode 100644 index 9a46e722..00000000 --- a/dlls/singleplay_gamerules.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "skill.h" -#include "items.h" - -extern DLL_GLOBAL CGameRules *g_pGameRules; -extern DLL_GLOBAL BOOL g_fGameOver; -extern int gmsgDeathMsg; // client dll messages -extern int gmsgScoreInfo; -extern int gmsgMOTD; - -//========================================================= -//========================================================= -CHalfLifeRules::CHalfLifeRules( void ) -{ - RefreshSkillData(); -} - -//========================================================= -//========================================================= -void CHalfLifeRules::Think( void ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsMultiplayer( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsDeathmatch( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsCoOp( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ - if( !pPlayer->m_pActiveItem ) - { - // player doesn't have an active item! - return TRUE; - } - - if( !pPlayer->m_pActiveItem->CanHolster() ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] ) -{ - return TRUE; -} - -void CHalfLifeRules::InitHUD( CBasePlayer *pl ) -{ -} - -//========================================================= -//========================================================= -void CHalfLifeRules::ClientDisconnected( edict_t *pClient ) -{ -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlPlayerFallDamage( CBasePlayer *pPlayer ) -{ - // subtract off the speed at which a player is allowed to fall without being hurt, - // so damage will be based on speed beyond that, not the entire fall - pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; - return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; -} - -//========================================================= -//========================================================= -void CHalfLifeRules::PlayerSpawn( CBasePlayer *pPlayer ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::AllowAutoTargetCrosshair( void ) -{ - return ( g_iSkillLevel == SKILL_EASY ); -} - -//========================================================= -//========================================================= -void CHalfLifeRules::PlayerThink( CBasePlayer *pPlayer ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::FPlayerCanRespawn( CBasePlayer *pPlayer ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlPlayerSpawnTime( CBasePlayer *pPlayer ) -{ - return gpGlobals->time;//now! -} - -//========================================================= -// IPointsForKill - how many points awarded to anyone -// that kills this player? -//========================================================= -int CHalfLifeRules::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - return 1; -} - -//========================================================= -// PlayerKilled - someone/something killed this player -//========================================================= -void CHalfLifeRules::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ -} - -//========================================================= -// Deathnotice -//========================================================= -void CHalfLifeRules::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ -} - -//========================================================= -// PlayerGotWeapon - player has grabbed a weapon that was -// sitting in the world -//========================================================= -void CHalfLifeRules::PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ -} - -//========================================================= -// FlWeaponRespawnTime - what is the time in the future -// at which this weapon may spawn? -//========================================================= -float CHalfLifeRules::FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) -{ - return -1; -} - -//========================================================= -// FlWeaponRespawnTime - Returns 0 if the weapon can respawn -// now, otherwise it returns the time at which it can try -// to spawn again. -//========================================================= -float CHalfLifeRules::FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) -{ - return 0; -} - -//========================================================= -// VecWeaponRespawnSpot - where should this weapon spawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeRules::VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) -{ - return pWeapon->pev->origin; -} - -//========================================================= -// WeaponShouldRespawn - any conditions inhibiting the -// respawning of this weapon? -//========================================================= -int CHalfLifeRules::WeaponShouldRespawn( CBasePlayerItem *pWeapon ) -{ - return GR_WEAPON_RESPAWN_NO; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeRules::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) -{ -} - -//========================================================= -//========================================================= -int CHalfLifeRules::ItemShouldRespawn( CItem *pItem ) -{ - return GR_ITEM_RESPAWN_NO; -} - -//========================================================= -// At what time in the future may this Item respawn? -//========================================================= -float CHalfLifeRules::FlItemRespawnTime( CItem *pItem ) -{ - return -1; -} - -//========================================================= -// Where should this item respawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeRules::VecItemRespawnSpot( CItem *pItem ) -{ - return pItem->pev->origin; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsAllowedToSpawn( CBaseEntity *pEntity ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeRules::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) -{ -} - -//========================================================= -//========================================================= -int CHalfLifeRules::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) -{ - return GR_AMMO_RESPAWN_NO; -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) -{ - return -1; -} - -//========================================================= -//========================================================= -Vector CHalfLifeRules::VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) -{ - return pAmmo->pev->origin; -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlHealthChargerRechargeTime( void ) -{ - return 0;// don't recharge -} - -//========================================================= -//========================================================= -int CHalfLifeRules::DeadPlayerWeapons( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_GUN_NO; -} - -//========================================================= -//========================================================= -int CHalfLifeRules::DeadPlayerAmmo( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_AMMO_NO; -} - -//========================================================= -//========================================================= -int CHalfLifeRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // why would a single player in half life need this? - return GR_NOTTEAMMATE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::FAllowMonsters( void ) -{ - return TRUE; -} diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp deleted file mode 100644 index bfe17ed1..00000000 --- a/dlls/squeakgrenade.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "gamerules.h" - -enum w_squeak_e -{ - WSQUEAK_IDLE1 = 0, - WSQUEAK_FIDGET, - WSQUEAK_JUMP, - WSQUEAK_RUN -}; - -enum squeak_e -{ - SQUEAK_IDLE1 = 0, - SQUEAK_FIDGETFIT, - SQUEAK_FIDGETNIP, - SQUEAK_DOWN, - SQUEAK_UP, - SQUEAK_THROW -}; - -#ifndef CLIENT_DLL -class CSqueakGrenade : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - int Classify( void ); - void EXPORT SuperBounceTouch( CBaseEntity *pOther ); - void EXPORT HuntThink( void ); - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - static float m_flNextBounceSoundTime; - - // CBaseEntity *m_pTarget; - float m_flDie; - Vector m_vecTarget; - float m_flNextHunt; - float m_flNextHit; - Vector m_posPrev; - EHANDLE m_hOwner; - int m_iMyClass; -}; - -float CSqueakGrenade::m_flNextBounceSoundTime = 0; - -LINK_ENTITY_TO_CLASS( monster_snark, CSqueakGrenade ) - -TYPEDESCRIPTION CSqueakGrenade::m_SaveData[] = -{ - DEFINE_FIELD( CSqueakGrenade, m_flDie, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CSqueakGrenade, m_flNextHunt, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_flNextHit, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_posPrev, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CSqueakGrenade, m_hOwner, FIELD_EHANDLE ), -}; - -IMPLEMENT_SAVERESTORE( CSqueakGrenade, CGrenade ) - -#define SQUEEK_DETONATE_DELAY 15.0 - -int CSqueakGrenade::Classify( void ) -{ - if( m_iMyClass != 0 ) - return m_iMyClass; // protect against recursion - - if( m_hEnemy != 0 ) - { - m_iMyClass = CLASS_INSECT; // no one cares about it - switch( m_hEnemy->Classify() ) - { - case CLASS_PLAYER: - case CLASS_HUMAN_PASSIVE: - case CLASS_HUMAN_MILITARY: - m_iMyClass = 0; - return CLASS_ALIEN_MILITARY; // barney's get mad, grunts get mad at it - } - m_iMyClass = 0; - } - - return CLASS_ALIEN_BIOWEAPON; -} - -void CSqueakGrenade::Spawn( void ) -{ - Precache(); - - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL( ENT( pev ), "models/w_squeak.mdl" ); - UTIL_SetSize( pev, Vector( -4, -4, 0 ), Vector( 4, 4, 8 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( &CSqueakGrenade::SuperBounceTouch ); - SetThink( &CSqueakGrenade::HuntThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_flNextHunt = gpGlobals->time + 1E6; - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.snarkHealth; - pev->gravity = 0.5; - pev->friction = 0.5; - - pev->dmg = gSkillData.snarkDmgPop; - - m_flDie = gpGlobals->time + SQUEEK_DETONATE_DELAY; - - m_flFieldOfView = 0; // 180 degrees - - if( pev->owner ) - m_hOwner = Instance( pev->owner ); - - m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned. - - pev->sequence = WSQUEAK_RUN; - ResetSequenceInfo(); -} - -void CSqueakGrenade::Precache( void ) -{ - PRECACHE_MODEL( "models/w_squeak.mdl" ); - PRECACHE_SOUND( "squeek/sqk_blast1.wav" ); - PRECACHE_SOUND( "common/bodysplat.wav" ); - PRECACHE_SOUND( "squeek/sqk_die1.wav" ); - PRECACHE_SOUND( "squeek/sqk_hunt1.wav" ); - PRECACHE_SOUND( "squeek/sqk_hunt2.wav" ); - PRECACHE_SOUND( "squeek/sqk_hunt3.wav" ); - PRECACHE_SOUND( "squeek/sqk_deploy1.wav" ); -} - -void CSqueakGrenade::Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->model = iStringNull;// make invisible - SetThink( &CBaseEntity::SUB_Remove ); - SetTouch( NULL ); - pev->nextthink = gpGlobals->time + 0.1; - - // since squeak grenades never leave a body behind, clear out their takedamage now. - // Squeaks do a bit of radius damage when they pop, and that radius damage will - // continue to call this function unless we acknowledge the Squeak's death now. (sjb) - pev->takedamage = DAMAGE_NO; - - // play squeek blast - EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM ); - - CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 ); - - UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 ); - - if( m_hOwner != 0 ) - RadiusDamage( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST ); - else - RadiusDamage( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST ); - - // reset owner so death message happens - if( m_hOwner != 0 ) - pev->owner = m_hOwner->edict(); - - CBaseMonster::Killed( pevAttacker, GIB_ALWAYS ); -} - -void CSqueakGrenade::GibMonster( void ) -{ - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200 ); -} - -void CSqueakGrenade::HuntThink( void ) -{ - // ALERT( at_console, "think\n" ); - - if( !IsInWorld() ) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - // explode when ready - if( gpGlobals->time >= m_flDie ) - { - g_vecAttackDir = pev->velocity.Normalize(); - pev->health = -1; - Killed( pev, 0 ); - return; - } - - // float - if( pev->waterlevel != 0 ) - { - if( pev->movetype == MOVETYPE_BOUNCE ) - { - pev->movetype = MOVETYPE_FLY; - } - pev->velocity = pev->velocity * 0.9; - pev->velocity.z += 8.0; - } - else if( pev->movetype == MOVETYPE_FLY ) - { - pev->movetype = MOVETYPE_BOUNCE; - } - - // return if not time to hunt - if( m_flNextHunt > gpGlobals->time ) - return; - - m_flNextHunt = gpGlobals->time + 2.0; - - //CBaseEntity *pOther = NULL; - Vector vecDir; - TraceResult tr; - - Vector vecFlat = pev->velocity; - vecFlat.z = 0; - vecFlat = vecFlat.Normalize(); - - UTIL_MakeVectors( pev->angles ); - - if( m_hEnemy == 0 || !m_hEnemy->IsAlive() ) - { - // find target, bounce a bit towards it. - Look( 512 ); - m_hEnemy = BestVisibleEnemy(); - } - - // squeek if it's about time blow up - if( ( m_flDie - gpGlobals->time <= 0.5 ) && ( m_flDie - gpGlobals->time >= 0.3 ) ) - { - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG( 0, 0x3F ) ); - CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); - } - - // higher pitch as squeeker gets closer to detonation time - float flpitch = 155.0 - 60.0 * ( ( m_flDie - gpGlobals->time ) / SQUEEK_DETONATE_DELAY ); - if( flpitch < 80 ) - flpitch = 80; - - if( m_hEnemy != 0 ) - { - if( FVisible( m_hEnemy ) ) - { - vecDir = m_hEnemy->EyePosition() - pev->origin; - m_vecTarget = vecDir.Normalize(); - } - - float flVel = pev->velocity.Length(); - float flAdj = 50.0 / ( flVel + 10.0 ); - - if( flAdj > 1.2 ) - flAdj = 1.2; - - // ALERT( at_console, "think : enemy\n"); - - // ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z ); - - pev->velocity = pev->velocity * flAdj + m_vecTarget * 300; - } - - if( pev->flags & FL_ONGROUND ) - { - pev->avelocity = Vector( 0, 0, 0 ); - } - else - { - if( pev->avelocity == Vector( 0, 0, 0 ) ) - { - pev->avelocity.x = RANDOM_FLOAT( -100, 100 ); - pev->avelocity.z = RANDOM_FLOAT( -100, 100 ); - } - } - - if( ( pev->origin - m_posPrev ).Length() < 1.0 ) - { - pev->velocity.x = RANDOM_FLOAT( -100, 100 ); - pev->velocity.y = RANDOM_FLOAT( -100, 100 ); - } - m_posPrev = pev->origin; - - pev->angles = UTIL_VecToAngles( pev->velocity ); - pev->angles.z = 0; - pev->angles.x = 0; -} - -void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) -{ - float flpitch; - - TraceResult tr = UTIL_GetGlobalTrace(); - - // don't hit the guy that launched this grenade - if( pev->owner && pOther->edict() == pev->owner ) - return; - - // at least until we've bounced once - pev->owner = NULL; - - pev->angles.x = 0; - pev->angles.z = 0; - - // avoid bouncing too much - if( m_flNextHit > gpGlobals->time ) - return; - - // higher pitch as squeeker gets closer to detonation time - flpitch = 155.0 - 60.0 * ( ( m_flDie - gpGlobals->time ) / SQUEEK_DETONATE_DELAY ); - - if( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) - { - // attack! - - // make sure it's me who has touched them - if( tr.pHit == pOther->edict() ) - { - // and it's not another squeakgrenade - if( tr.pHit->v.modelindex != pev->modelindex ) - { - // ALERT( at_console, "hit enemy\n" ); - ClearMultiDamage(); - pOther->TraceAttack( pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH ); - if( m_hOwner != 0 ) - ApplyMultiDamage( pev, m_hOwner->pev ); - else - ApplyMultiDamage( pev, pev ); - - pev->dmg += gSkillData.snarkDmgPop; // add more explosion damage - // m_flDie += 2.0; // add more life - - // make bite sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch ); - m_flNextAttack = gpGlobals->time + 0.5; - } - } - else - { - // ALERT( at_console, "been hit\n" ); - } - } - - m_flNextHit = gpGlobals->time + 0.1; - m_flNextHunt = gpGlobals->time; - - if( g_pGameRules->IsMultiplayer() ) - { - // in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows. - if( gpGlobals->time < m_flNextBounceSoundTime ) - { - // too soon! - return; - } - } - - if( !( pev->flags & FL_ONGROUND ) ) - { - // play bounce sound - float flRndSound = RANDOM_FLOAT( 0, 1 ); - - if( flRndSound <= 0.33 ) - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch ); - else if( flRndSound <= 0.66 ) - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch ); - else - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch ); - CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); - } - else - { - // skittering sound - CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 100, 0.1 ); - } - - m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. -} -#endif - -LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ) - -void CSqueak::Spawn() -{ - Precache(); - m_iId = WEAPON_SNARK; - SET_MODEL( ENT( pev ), "models/w_sqknest.mdl" ); - - FallInit();//get ready to fall down. - - m_iDefaultAmmo = SNARK_DEFAULT_GIVE; - - pev->sequence = 1; - pev->animtime = gpGlobals->time; - pev->framerate = 1.0; -} - -void CSqueak::Precache( void ) -{ - PRECACHE_MODEL( "models/w_sqknest.mdl" ); - PRECACHE_MODEL( "models/v_squeak.mdl" ); - PRECACHE_MODEL( "models/p_squeak.mdl" ); - PRECACHE_SOUND( "squeek/sqk_hunt2.wav" ); - PRECACHE_SOUND( "squeek/sqk_hunt3.wav" ); - UTIL_PrecacheOther( "monster_snark" ); - - m_usSnarkFire = PRECACHE_EVENT( 1, "events/snarkfire.sc" ); -} - -int CSqueak::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "Snarks"; - p->iMaxAmmo1 = SNARK_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 3; - p->iId = m_iId = WEAPON_SNARK; - p->iWeight = SNARK_WEIGHT; - p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - - return 1; -} - -BOOL CSqueak::Deploy() -{ - // play hunt sound - float flRndSound = RANDOM_FLOAT( 0, 1 ); - - if( flRndSound <= 0.5 ) - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 100 ); - else - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 100 ); - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - return DefaultDeploy( "models/v_squeak.mdl", "models/p_squeak.mdl", SQUEAK_UP, "squeak" ); -} - -void CSqueak::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - m_pPlayer->pev->weapons &= ~( 1 << WEAPON_SNARK ); - DestroyItem(); - return; - } - - SendWeaponAnim( SQUEAK_DOWN ); - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM ); -} - -void CSqueak::PrimaryAttack() -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - TraceResult tr; - Vector trace_origin; - - // HACK HACK: Ugly hacks to handle change in origin based on new physics code for players - // Move origin up if crouched and start trace a bit outside of body ( 20 units instead of 16 ) - trace_origin = m_pPlayer->pev->origin; - if( m_pPlayer->pev->flags & FL_DUCKING ) - { - trace_origin = trace_origin - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - } - - // find place to toss monster - UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20, trace_origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr ); - - int flags; -#ifdef CLIENT_WEAPONS - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSnarkFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - - if( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25 ) - { - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); -#ifndef CLIENT_DLL - CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pSqueak->pev->velocity = gpGlobals->v_forward * 200 + m_pPlayer->pev->velocity; -#endif - // play hunt sound - float flRndSound = RANDOM_FLOAT( 0, 1 ); - - if( flRndSound <= 0.5 ) - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 105 ); - else - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 105 ); - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - m_fJustThrown = 1; - - m_flNextPrimaryAttack = GetNextAttackDelay( 0.3 ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - } - } -} - -void CSqueak::SecondaryAttack( void ) -{ - -} - -void CSqueak::WeaponIdle( void ) -{ - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if( m_fJustThrown ) - { - m_fJustThrown = 0; - - if( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) - { - RetireWeapon(); - return; - } - - SendWeaponAnim( SQUEAK_UP ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - return; - } - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if( flRand <= 0.75 ) - { - iAnim = SQUEAK_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); - } - else if( flRand <= 0.875 ) - { - iAnim = SQUEAK_FIDGETFIT; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0; - } - else - { - iAnim = SQUEAK_FIDGETNIP; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 16.0; - } - SendWeaponAnim( iAnim ); -} -#endif diff --git a/dlls/stats.cpp b/dlls/stats.cpp deleted file mode 100644 index e37832c8..00000000 --- a/dlls/stats.cpp +++ /dev/null @@ -1,151 +0,0 @@ -//========= Copyright (c) 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: New version of the slider bar -// -// $NoKeywords: $ -//============================================================================= - -#include "extdll.h" -#include "util.h" - -#include "cbase.h" -#include "player.h" -#include "trains.h" -#include "nodes.h" -#include "weapons.h" -#include "soundent.h" -#include "monsters.h" -#include "../engine/shake.h" -#include "decals.h" -#include "gamerules.h" - -float AmmoDamage( const char *pName ) -{ - if( !pName ) - return 0; - - if( !strcmp( pName, "9mm" ) ) - return gSkillData.plrDmg9MM; - if( !strcmp( pName, "357" ) ) - return gSkillData.plrDmg357; - if( !strcmp( pName, "ARgrenades" ) ) - return gSkillData.plrDmgM203Grenade; - if( !strcmp( pName, "buckshot" ) ) - return gSkillData.plrDmgBuckshot; - if( !strcmp( pName, "bolts") ) - return gSkillData.plrDmgCrossbowMonster; - if( !strcmp( pName, "rockets") ) - return gSkillData.plrDmgRPG; - if( !strcmp( pName, "uranium") ) - return gSkillData.plrDmgGauss; - if( !strcmp( pName, "Hand Grenade") ) - return gSkillData.plrDmgHandGrenade; - if( !strcmp( pName, "Satchel Charge") ) - return gSkillData.plrDmgSatchel; - if( !strcmp( pName, "Trip Mine") ) - return gSkillData.plrDmgTripmine; - - return 0; -} - -void UpdateStatsFile( float dataTime, const char *pMapname, float health, float ammo, int skillLevel ) -{ - FILE *fp; - - fp = fopen( "stats.txt", "a" ); - if( !fp ) - return; - fprintf( fp, "%6.2f, %6.2f, %6.2f, %s, %2d\n", dataTime, health, ammo, pMapname, skillLevel ); - fclose( fp ); -} - -#define AMMO_THRESHOLD 10 // This much ammo goes by before it is "interesting" -#define HEALTH_THRESHOLD 10 // Same for health -#define OUTPUT_LATENCY 3 // This many seconds for ammo/health to settle - -typedef struct -{ - int lastAmmo; - float lastHealth; - float lastOutputTime; // NOTE: These times are in "game" time -- a running total of elapsed time since the game started - float nextOutputTime; - float dataTime; - float gameTime; - float lastGameTime; -} TESTSTATS; - -TESTSTATS gStats = { 0, 0, 0, 0, 0, 0, 0 }; - -void UpdateStats( CBasePlayer *pPlayer ) -{ - int i; - - int ammoCount[MAX_AMMO_SLOTS]; - memcpy( ammoCount, pPlayer->m_rgAmmo, MAX_AMMO_SLOTS * sizeof(int) ); - - // Keep a running time, so the graph doesn't overlap - - if( gpGlobals->time < gStats.lastGameTime ) // Changed level or died, don't b0rk - { - gStats.lastGameTime = gpGlobals->time; - gStats.dataTime = gStats.gameTime; - } - - gStats.gameTime += gpGlobals->time - gStats.lastGameTime; - gStats.lastGameTime = gpGlobals->time; - - for( i = 0; i < MAX_ITEM_TYPES; i++ ) - { - CBasePlayerItem *p = pPlayer->m_rgpPlayerItems[i]; - while( p ) - { - ItemInfo II = {0}; - - p->GetItemInfo( &II ); - - int index = pPlayer->GetAmmoIndex( II.pszAmmo1 ); - if( index >= 0 ) - ammoCount[index] += ( (CBasePlayerWeapon *)p )->m_iClip; - - p = p->m_pNext; - } - } - - float ammo = 0; - for( i = 1; i < MAX_AMMO_SLOTS; i++ ) - { - ammo += ammoCount[i] * AmmoDamage( CBasePlayerItem::AmmoInfoArray[i].pszName ); - } - - float health = pPlayer->pev->health + pPlayer->pev->armorvalue * 2; // Armor is 2X health - float ammoDelta = fabs( ammo - gStats.lastAmmo ); - float healthDelta = fabs( health - gStats.lastHealth ); - int forceWrite = 0; - if( health <= 0 && gStats.lastHealth > 0 ) - forceWrite = 1; - - if( ( ammoDelta > AMMO_THRESHOLD || healthDelta > HEALTH_THRESHOLD ) && !forceWrite ) - { - if( gStats.nextOutputTime == 0 ) - gStats.dataTime = gStats.gameTime; - - gStats.lastAmmo = ammo; - gStats.lastHealth = health; - - gStats.nextOutputTime = gStats.gameTime + OUTPUT_LATENCY; - } - else if( ( gStats.nextOutputTime != 0 && gStats.nextOutputTime < gStats.gameTime ) || forceWrite ) - { - UpdateStatsFile( gStats.dataTime, STRING( gpGlobals->mapname ), health, ammo, (int)CVAR_GET_FLOAT( "skill" ) ); - - gStats.lastAmmo = ammo; - gStats.lastHealth = health; - gStats.lastOutputTime = gStats.gameTime; - gStats.nextOutputTime = 0; - } -} - -void InitStats( CBasePlayer *pPlayer ) -{ - gStats.lastGameTime = gpGlobals->time; // Fixup stats time -} diff --git a/dlls/tentacle.cpp b/dlls/tentacle.cpp deleted file mode 100644 index 44b8b45b..00000000 --- a/dlls/tentacle.cpp +++ /dev/null @@ -1,1023 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -/* - - h_tentacle.cpp - silo of death tentacle monster (half life) - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "soundent.h" - -#define ACT_T_IDLE 1010 -#define ACT_T_TAP 1020 -#define ACT_T_STRIKE 1030 -#define ACT_T_REARIDLE 1040 - -class CTentacle : public CBaseMonster -{ -public: - CTentacle( void ); - - void Spawn(); - void Precache(); - void KeyValue( KeyValueData *pkvd ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - // Don't allow the tentacle to go across transitions!!! - virtual int ObjectCaps( void ) { return CBaseMonster::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -400, -400, 0 ); - pev->absmax = pev->origin + Vector( 400, 400, 850 ); - } - - void EXPORT Cycle( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Start( void ); - void EXPORT DieThink( void ); - - void EXPORT Test( void ); - - void EXPORT HitTouch( CBaseEntity *pOther ); - - float HearingSensitivity( void ) { return 2.0; }; - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void Killed( entvars_t *pevAttacker, int iGib ); - - MONSTERSTATE GetIdealState( void ) { return MONSTERSTATE_IDLE; }; - int CanPlaySequence( BOOL fDisregardState ) { return TRUE; }; - - int Classify( void ); - - int Level( float dz ); - int MyLevel( void ); - float MyHeight( void ); - - float m_flInitialYaw; - int m_iGoalAnim; - int m_iLevel; - int m_iDir; - float m_flFramerateAdj; - float m_flSoundYaw; - int m_iSoundLevel; - float m_flSoundTime; - float m_flSoundRadius; - int m_iHitDmg; - float m_flHitTime; - - float m_flTapRadius; - - float m_flNextSong; - static int g_fFlySound; - static int g_fSquirmSound; - - float m_flMaxYaw; - int m_iTapSound; - - Vector m_vecPrevSound; - float m_flPrevSoundTime; - - static const char *pHitSilo[]; - static const char *pHitDirt[]; - static const char *pHitWater[]; -}; - -int CTentacle::g_fFlySound; -int CTentacle::g_fSquirmSound; - -LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ) - -// stike sounds -#define TE_NONE -1 -#define TE_SILO 0 -#define TE_DIRT 1 -#define TE_WATER 2 - -const char *CTentacle::pHitSilo[] = -{ - "tentacle/te_strike1.wav", - "tentacle/te_strike2.wav", -}; - -const char *CTentacle::pHitDirt[] = -{ - "player/pl_dirt1.wav", - "player/pl_dirt2.wav", - "player/pl_dirt3.wav", - "player/pl_dirt4.wav", -}; - -const char *CTentacle::pHitWater[] = -{ - "player/pl_slosh1.wav", - "player/pl_slosh2.wav", - "player/pl_slosh3.wav", - "player/pl_slosh4.wav", -}; - -TYPEDESCRIPTION CTentacle::m_SaveData[] = -{ - DEFINE_FIELD( CTentacle, m_flInitialYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iGoalAnim, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_iLevel, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_iDir, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flFramerateAdj, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_flSoundYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iSoundLevel, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flSoundTime, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_flSoundRadius, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iHitDmg, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flHitTime, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_flTapRadius, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_flNextSong, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_iTapSound, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flMaxYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_vecPrevSound, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CTentacle, m_flPrevSoundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CTentacle, CBaseMonster ) - -// animation sequence aliases -typedef enum -{ - TENTACLE_ANIM_Pit_Idle, - - TENTACLE_ANIM_rise_to_Temp1, - TENTACLE_ANIM_Temp1_to_Floor, - TENTACLE_ANIM_Floor_Idle, - TENTACLE_ANIM_Floor_Fidget_Pissed, - TENTACLE_ANIM_Floor_Fidget_SmallRise, - TENTACLE_ANIM_Floor_Fidget_Wave, - TENTACLE_ANIM_Floor_Strike, - TENTACLE_ANIM_Floor_Tap, - TENTACLE_ANIM_Floor_Rotate, - TENTACLE_ANIM_Floor_Rear, - TENTACLE_ANIM_Floor_Rear_Idle, - TENTACLE_ANIM_Floor_to_Lev1, - - TENTACLE_ANIM_Lev1_Idle, - TENTACLE_ANIM_Lev1_Fidget_Claw, - TENTACLE_ANIM_Lev1_Fidget_Shake, - TENTACLE_ANIM_Lev1_Fidget_Snap, - TENTACLE_ANIM_Lev1_Strike, - TENTACLE_ANIM_Lev1_Tap, - TENTACLE_ANIM_Lev1_Rotate, - TENTACLE_ANIM_Lev1_Rear, - TENTACLE_ANIM_Lev1_Rear_Idle, - TENTACLE_ANIM_Lev1_to_Lev2, - - TENTACLE_ANIM_Lev2_Idle, - TENTACLE_ANIM_Lev2_Fidget_Shake, - TENTACLE_ANIM_Lev2_Fidget_Swing, - TENTACLE_ANIM_Lev2_Fidget_Tut, - TENTACLE_ANIM_Lev2_Strike, - TENTACLE_ANIM_Lev2_Tap, - TENTACLE_ANIM_Lev2_Rotate, - TENTACLE_ANIM_Lev2_Rear, - TENTACLE_ANIM_Lev2_Rear_Idle, - TENTACLE_ANIM_Lev2_to_Lev3, - - TENTACLE_ANIM_Lev3_Idle, - TENTACLE_ANIM_Lev3_Fidget_Shake, - TENTACLE_ANIM_Lev3_Fidget_Side, - TENTACLE_ANIM_Lev3_Fidget_Swipe, - TENTACLE_ANIM_Lev3_Strike, - TENTACLE_ANIM_Lev3_Tap, - TENTACLE_ANIM_Lev3_Rotate, - TENTACLE_ANIM_Lev3_Rear, - TENTACLE_ANIM_Lev3_Rear_Idle, - - TENTACLE_ANIM_Lev1_Door_reach, - - TENTACLE_ANIM_Lev3_to_Engine, - TENTACLE_ANIM_Engine_Idle, - TENTACLE_ANIM_Engine_Sway, - TENTACLE_ANIM_Engine_Swat, - TENTACLE_ANIM_Engine_Bob, - TENTACLE_ANIM_Engine_Death1, - TENTACLE_ANIM_Engine_Death2, - TENTACLE_ANIM_Engine_Death3, - - TENTACLE_ANIM_none -} TENTACLE_ANIM; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CTentacle::Classify( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -// -// Tentacle Spawn -// -void CTentacle::Spawn() -{ - Precache(); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_FLY; - pev->effects = 0; - pev->health = 75; - pev->sequence = 0; - - SET_MODEL( ENT( pev ), "models/tentacle2.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->takedamage = DAMAGE_AIM; - pev->flags |= FL_MONSTER; - - m_bloodColor = BLOOD_COLOR_GREEN; - - SetThink( &CTentacle::Start ); - SetTouch( &CTentacle::HitTouch ); - SetUse( &CTentacle::CommandUse ); - - pev->nextthink = gpGlobals->time + 0.2; - - ResetSequenceInfo(); - m_iDir = 1; - - pev->yaw_speed = 18; - m_flInitialYaw = pev->angles.y; - pev->ideal_yaw = m_flInitialYaw; - - g_fFlySound = FALSE; - g_fSquirmSound = FALSE; - - m_iHitDmg = 20; - - if( m_flMaxYaw <= 0 ) - m_flMaxYaw = 65; - - m_MonsterState = MONSTERSTATE_IDLE; - - // SetThink( &Test ); - UTIL_SetOrigin( pev, pev->origin ); -} - -void CTentacle::Precache() -{ - PRECACHE_MODEL( "models/tentacle2.mdl" ); - - PRECACHE_SOUND( "ambience/flies.wav" ); - PRECACHE_SOUND( "ambience/squirm2.wav" ); - - PRECACHE_SOUND( "tentacle/te_alert1.wav" ); - PRECACHE_SOUND( "tentacle/te_alert2.wav" ); - PRECACHE_SOUND( "tentacle/te_flies1.wav" ); - PRECACHE_SOUND( "tentacle/te_move1.wav" ); - PRECACHE_SOUND( "tentacle/te_move2.wav" ); - PRECACHE_SOUND( "tentacle/te_roar1.wav" ); - PRECACHE_SOUND( "tentacle/te_roar2.wav" ); - PRECACHE_SOUND( "tentacle/te_search1.wav" ); - PRECACHE_SOUND( "tentacle/te_search2.wav" ); - PRECACHE_SOUND( "tentacle/te_sing1.wav" ); - PRECACHE_SOUND( "tentacle/te_sing2.wav" ); - PRECACHE_SOUND( "tentacle/te_squirm2.wav" ); - PRECACHE_SOUND( "tentacle/te_strike1.wav" ); - PRECACHE_SOUND( "tentacle/te_strike2.wav" ); - PRECACHE_SOUND( "tentacle/te_swing1.wav" ); - PRECACHE_SOUND( "tentacle/te_swing2.wav" ); - - PRECACHE_SOUND_ARRAY( pHitSilo ); - PRECACHE_SOUND_ARRAY( pHitDirt ); - PRECACHE_SOUND_ARRAY( pHitWater ); -} - -CTentacle::CTentacle() -{ - m_flMaxYaw = 65; - m_iTapSound = 0; -} - -void CTentacle::KeyValue( KeyValueData *pkvd ) -{ - if( FStrEq( pkvd->szKeyName, "sweeparc" ) ) - { - m_flMaxYaw = atof( pkvd->szValue ) / 2.0; - pkvd->fHandled = TRUE; - } - else if( FStrEq( pkvd->szKeyName, "sound" ) ) - { - m_iTapSound = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -int CTentacle::Level( float dz ) -{ - if( dz < 216 ) - return 0; - if( dz < 408 ) - return 1; - if( dz < 600 ) - return 2; - return 3; -} - -float CTentacle::MyHeight() -{ - switch( MyLevel() ) - { - case 1: - return 256; - case 2: - return 448; - case 3: - return 640; - } - return 0; -} - -int CTentacle::MyLevel() -{ - switch( pev->sequence ) - { - case TENTACLE_ANIM_Pit_Idle: - return -1; - - case TENTACLE_ANIM_rise_to_Temp1: - case TENTACLE_ANIM_Temp1_to_Floor: - case TENTACLE_ANIM_Floor_to_Lev1: - return 0; - case TENTACLE_ANIM_Floor_Idle: - case TENTACLE_ANIM_Floor_Fidget_Pissed: - case TENTACLE_ANIM_Floor_Fidget_SmallRise: - case TENTACLE_ANIM_Floor_Fidget_Wave: - case TENTACLE_ANIM_Floor_Strike: - case TENTACLE_ANIM_Floor_Tap: - case TENTACLE_ANIM_Floor_Rotate: - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - return 0; - case TENTACLE_ANIM_Lev1_Idle: - case TENTACLE_ANIM_Lev1_Fidget_Claw: - case TENTACLE_ANIM_Lev1_Fidget_Shake: - case TENTACLE_ANIM_Lev1_Fidget_Snap: - case TENTACLE_ANIM_Lev1_Strike: - case TENTACLE_ANIM_Lev1_Tap: - case TENTACLE_ANIM_Lev1_Rotate: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - return 1; - case TENTACLE_ANIM_Lev1_to_Lev2: - return 1; - case TENTACLE_ANIM_Lev2_Idle: - case TENTACLE_ANIM_Lev2_Fidget_Shake: - case TENTACLE_ANIM_Lev2_Fidget_Swing: - case TENTACLE_ANIM_Lev2_Fidget_Tut: - case TENTACLE_ANIM_Lev2_Strike: - case TENTACLE_ANIM_Lev2_Tap: - case TENTACLE_ANIM_Lev2_Rotate: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - return 2; - case TENTACLE_ANIM_Lev2_to_Lev3: - return 2; - case TENTACLE_ANIM_Lev3_Idle: - case TENTACLE_ANIM_Lev3_Fidget_Shake: - case TENTACLE_ANIM_Lev3_Fidget_Side: - case TENTACLE_ANIM_Lev3_Fidget_Swipe: - case TENTACLE_ANIM_Lev3_Strike: - case TENTACLE_ANIM_Lev3_Tap: - case TENTACLE_ANIM_Lev3_Rotate: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - return 3; - case TENTACLE_ANIM_Lev1_Door_reach: - return -1; - } - return -1; -} - -void CTentacle::Test( void ) -{ - pev->sequence = TENTACLE_ANIM_Floor_Strike; - pev->framerate = 0; - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; -} - -// -// TentacleThink -// -void CTentacle::Cycle( void ) -{ - // ALERT( at_console, "%s %.2f %d %d\n", STRING( pev->targetname ), pev->origin.z, m_MonsterState, m_IdealMonsterState ); - pev->nextthink = gpGlobals-> time + 0.1; - - // ALERT( at_console, "%s %d %d %d %f %f\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim, m_iDir, pev->framerate, pev->health ); - - if( m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT ) - { - pev->angles.y = m_flInitialYaw; - pev->ideal_yaw = m_flInitialYaw; - ClearConditions( IgnoreConditions() ); - MonsterThink(); - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - return; - } - - DispatchAnimEvents(); - StudioFrameAdvance(); - - ChangeYaw( pev->yaw_speed ); - - CSound *pSound; - - Listen(); - - // Listen will set this if there's something in my sound list - if( HasConditions( bits_COND_HEAR_SOUND ) ) - pSound = PBestSound(); - else - pSound = NULL; - - if( pSound ) - { - Vector vecDir; - if( gpGlobals->time - m_flPrevSoundTime < 0.5 ) - { - float dt = gpGlobals->time - m_flPrevSoundTime; - vecDir = pSound->m_vecOrigin + ( pSound->m_vecOrigin - m_vecPrevSound ) / dt - pev->origin; - } - else - { - vecDir = pSound->m_vecOrigin - pev->origin; - } - m_flPrevSoundTime = gpGlobals->time; - m_vecPrevSound = pSound->m_vecOrigin; - - m_flSoundYaw = UTIL_VecToYaw( vecDir ) - m_flInitialYaw; - m_iSoundLevel = Level( vecDir.z ); - - if( m_flSoundYaw < -180 ) - m_flSoundYaw += 360; - if( m_flSoundYaw > 180 ) - m_flSoundYaw -= 360; -#if 0 - // ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw ); - if( m_flSoundTime < gpGlobals->time ) - { - // play "I hear new something" sound - const char *sound; - - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - sound = "tentacle/te_alert1.wav"; - break; - case 1: - sound = "tentacle/te_alert2.wav"; - break; - } - - // UTIL_EmitAmbientSound( ENT( pev ), pev->origin + Vector( 0, 0, MyHeight() ), sound, 1.0, ATTN_NORM, 0, 100 ); - } -#endif - m_flSoundTime = gpGlobals->time + RANDOM_FLOAT( 5.0, 10.0 ); - } - - // clip ideal_yaw - float dy = m_flSoundYaw; - switch( pev->sequence ) - { - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - if( dy < 0 && dy > -m_flMaxYaw ) - dy = -m_flMaxYaw; - if( dy > 0 && dy < m_flMaxYaw ) - dy = m_flMaxYaw; - break; - default: - if( dy < -m_flMaxYaw ) - dy = -m_flMaxYaw; - if( dy > m_flMaxYaw ) - dy = m_flMaxYaw; - } - pev->ideal_yaw = m_flInitialYaw + dy; - - if( m_fSequenceFinished ) - { - // ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim ); - if( pev->health <= 1 ) - { - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - if( pev->sequence == TENTACLE_ANIM_Pit_Idle ) - { - pev->health = 75; - } - } - else if( m_flSoundTime > gpGlobals->time ) - { - if( m_flSoundYaw >= -( m_flMaxYaw + 30 ) && m_flSoundYaw <= ( m_flMaxYaw + 30 ) ) - { - // strike - m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); - } - else if( m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2 ) - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); - } - else - { - // go into rear idle - m_iGoalAnim = LookupActivity( ACT_T_REARIDLE + m_iSoundLevel ); - } - } - else if( pev->sequence == TENTACLE_ANIM_Pit_Idle ) - { - // stay in pit until hear noise - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - } - else if( pev->sequence == m_iGoalAnim ) - { - if( MyLevel() >= 0 && gpGlobals->time < m_flSoundTime ) - { - if( RANDOM_LONG( 0, 9 ) < m_flSoundTime - gpGlobals->time ) - { - // continue stike - m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); - } - else - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); - } - } - else if( MyLevel() < 0 ) - { - m_iGoalAnim = LookupActivity( ACT_T_IDLE + 0 ); - } - else - { - if( m_flNextSong < gpGlobals->time ) - { - // play "I hear new something" sound - const char *sound; - - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - sound = "tentacle/te_sing1.wav"; - break; - case 1: - sound = "tentacle/te_sing2.wav"; - break; - } - - EMIT_SOUND( ENT( pev ), CHAN_VOICE, sound, 1.0, ATTN_NORM ); - - m_flNextSong = gpGlobals->time + RANDOM_FLOAT( 10, 20 ); - } - - if( RANDOM_LONG( 0,15 ) == 0 ) - { - // idle on new level - m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG( 0, 3 ) ); - } - else if( RANDOM_LONG( 0, 3 ) == 0 ) - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel() ); - } - else - { - // idle - m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel() ); - } - } - if( m_flSoundYaw < 0 ) - m_flSoundYaw += RANDOM_FLOAT( 2, 8 ); - else - m_flSoundYaw -= RANDOM_FLOAT( 2, 8 ); - } - - pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); - - if( m_iDir > 0 ) - { - pev->frame = 0; - } - else - { - m_iDir = -1; // just to safe - pev->frame = 255; - } - ResetSequenceInfo(); - - m_flFramerateAdj = RANDOM_FLOAT( -0.2, 0.2 ); - pev->framerate = m_iDir * 1.0 + m_flFramerateAdj; - - switch( pev->sequence ) - { - case TENTACLE_ANIM_Floor_Tap: - case TENTACLE_ANIM_Lev1_Tap: - case TENTACLE_ANIM_Lev2_Tap: - case TENTACLE_ANIM_Lev3_Tap: - { - Vector vecSrc; - UTIL_MakeVectors( pev->angles ); - - TraceResult tr1, tr2; - - vecSrc = pev->origin + Vector( 0, 0, MyHeight() - 4 ); - UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr1 ); - - vecSrc = pev->origin + Vector( 0, 0, MyHeight() + 8 ); - UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr2 ); - - // ALERT( at_console, "%f %f\n", tr1.flFraction * 512, tr2.flFraction * 512 ); - - m_flTapRadius = SetBlending( 0, RANDOM_FLOAT( tr1.flFraction * 512, tr2.flFraction * 512 ) ); - } - break; - default: - m_flTapRadius = 336; // 400 - 64 - break; - } - pev->view_ofs.z = MyHeight(); - // ALERT( at_console, "seq %d\n", pev->sequence ); - } - - if( m_flPrevSoundTime + 2.0 > gpGlobals->time ) - { - // 1.5 normal speed if hears sounds - pev->framerate = m_iDir * 1.5 + m_flFramerateAdj; - } - else if( m_flPrevSoundTime + 5.0 > gpGlobals->time ) - { - // slowdown to normal - pev->framerate = m_iDir + m_iDir * ( 5 - ( gpGlobals->time - m_flPrevSoundTime ) ) / 2 + m_flFramerateAdj; - } -} - -void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // ALERT( at_console, "%s triggered %d\n", STRING( pev->targetname ), useType ); - switch( useType ) - { - case USE_OFF: - pev->takedamage = DAMAGE_NO; - SetThink( &CTentacle::DieThink ); - m_iGoalAnim = TENTACLE_ANIM_Engine_Death1; - break; - case USE_ON: - if( pActivator ) - { - // ALERT( at_console, "insert sound\n" ); - CSoundEnt::InsertSound( bits_SOUND_WORLD, pActivator->pev->origin, 1024, 1.0 ); - } - break; - case USE_SET: - break; - case USE_TOGGLE: - pev->takedamage = DAMAGE_NO; - SetThink( &CTentacle::DieThink ); - m_iGoalAnim = TENTACLE_ANIM_Engine_Idle; - break; - } -} - -void CTentacle::DieThink( void ) -{ - pev->nextthink = gpGlobals-> time + 0.1; - - DispatchAnimEvents(); - StudioFrameAdvance(); - - ChangeYaw( 24 ); - - if( m_fSequenceFinished ) - { - if( pev->sequence == m_iGoalAnim ) - { - switch( m_iGoalAnim ) - { - case TENTACLE_ANIM_Engine_Idle: - case TENTACLE_ANIM_Engine_Sway: - case TENTACLE_ANIM_Engine_Swat: - case TENTACLE_ANIM_Engine_Bob: - m_iGoalAnim = TENTACLE_ANIM_Engine_Sway + RANDOM_LONG( 0, 2 ); - break; - case TENTACLE_ANIM_Engine_Death1: - case TENTACLE_ANIM_Engine_Death2: - case TENTACLE_ANIM_Engine_Death3: - UTIL_Remove( this ); - return; - } - } - - // ALERT( at_console, "%d : %d => ", pev->sequence, m_iGoalAnim ); - pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); - // ALERT( at_console, "%d\n", pev->sequence ); - - if( m_iDir > 0 ) - { - pev->frame = 0; - } - else - { - pev->frame = 255; - } - ResetSequenceInfo(); - - float dy; - switch( pev->sequence ) - { - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - case TENTACLE_ANIM_Engine_Idle: - case TENTACLE_ANIM_Engine_Sway: - case TENTACLE_ANIM_Engine_Swat: - case TENTACLE_ANIM_Engine_Bob: - case TENTACLE_ANIM_Engine_Death1: - case TENTACLE_ANIM_Engine_Death2: - case TENTACLE_ANIM_Engine_Death3: - pev->framerate = RANDOM_FLOAT( m_iDir - 0.2, m_iDir + 0.2 ); - dy = 180; - break; - default: - pev->framerate = 1.5; - dy = 0; - break; - } - pev->ideal_yaw = m_flInitialYaw + dy; - } -} - -void CTentacle::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - const char *sound; - - switch( pEvent->event ) - { - case 1: - // bang - { - Vector vecSrc, vecAngles; - GetAttachment( 0, vecSrc, vecAngles ); - - // Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * ( 3.14192653 / 180.0 ) ), sin( pev->angles.y * ( M_PI / 180.0 ) ), 0.0 ); - - // vecSrc.z += MyHeight(); - - switch( m_iTapSound ) - { - case TE_SILO: - UTIL_EmitAmbientSound( ENT( pev ), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), 1.0, ATTN_NORM, 0, 100 ); - break; - case TE_NONE: - break; - case TE_DIRT: - UTIL_EmitAmbientSound( ENT( pev ), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), 1.0, ATTN_NORM, 0, 100 ); - break; - case TE_WATER: - UTIL_EmitAmbientSound( ENT( pev ), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), 1.0, ATTN_NORM, 0, 100 ); - break; - } - gpGlobals->force_retouch++; - } - break; - case 3: - // start killing swing - m_iHitDmg = 200; - // UTIL_EmitAmbientSound( ENT( pev ), pev->origin + Vector( 0, 0, MyHeight() ), "tentacle/te_swing1.wav", 1.0, ATTN_NORM, 0, 100 ); - break; - case 4: - // end killing swing - m_iHitDmg = 25; - break; - case 5: - // just "whoosh" sound - // UTIL_EmitAmbientSound( ENT( pev ), pev->origin + Vector( 0, 0, MyHeight() ), "tentacle/te_swing2.wav", 1.0, ATTN_NORM, 0, 100 ); - break; - case 2: - // tap scrape - case 6: - // light tap - { - Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * ( M_PI / 180.0 ) ), sin( pev->angles.y * ( M_PI / 180.0 ) ), 0.0 ); - - vecSrc.z += MyHeight(); - - float flVol = RANDOM_FLOAT( 0.3, 0.5 ); - - switch( m_iTapSound ) - { - case TE_SILO: - UTIL_EmitAmbientSound( ENT( pev ), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), flVol, ATTN_NORM, 0, 100 ); - break; - case TE_NONE: - break; - case TE_DIRT: - UTIL_EmitAmbientSound( ENT( pev ), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), flVol, ATTN_NORM, 0, 100 ); - break; - case TE_WATER: - UTIL_EmitAmbientSound( ENT( pev ), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), flVol, ATTN_NORM, 0, 100 ); - break; - } - } - break; - case 7: - // roar - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - sound = "tentacle/te_roar1.wav"; - break; - case 1: - sound = "tentacle/te_roar2.wav"; - break; - } - - UTIL_EmitAmbientSound( ENT( pev ), pev->origin + Vector( 0, 0, MyHeight() ), sound, 1.0, ATTN_NORM, 0, 100 ); - break; - case 8: - // search - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - sound = "tentacle/te_search1.wav"; - break; - case 1: - sound = "tentacle/te_search2.wav"; - break; - } - - UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - break; - case 9: - // swing - switch( RANDOM_LONG( 0, 1 ) ) - { - case 0: - sound = "tentacle/te_move1.wav"; - break; - case 1: - sound = "tentacle/te_move2.wav"; - break; - } - UTIL_EmitAmbientSound( ENT( pev ), pev->origin + Vector( 0, 0, MyHeight() ), sound, 1.0, ATTN_NORM, 0, 100 ); - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - } -} - -// -// TentacleStart -// -// void CTentacle::Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -void CTentacle::Start( void ) -{ - SetThink( &CTentacle::Cycle ); - - if( !g_fFlySound ) - { - EMIT_SOUND( ENT( pev ), CHAN_BODY, "ambience/flies.wav", 1, ATTN_NORM ); - g_fFlySound = TRUE; - //pev->nextthink = gpGlobals-> time + 0.1; - } - else if( !g_fSquirmSound ) - { - EMIT_SOUND( ENT( pev ), CHAN_BODY, "ambience/squirm2.wav", 1, ATTN_NORM ); - g_fSquirmSound = TRUE; - } - - pev->nextthink = gpGlobals->time + 0.1; -} - -void CTentacle::HitTouch( CBaseEntity *pOther ) -{ - TraceResult tr = UTIL_GetGlobalTrace(); - - if( pOther->pev->modelindex == pev->modelindex ) - return; - - if( m_flHitTime > gpGlobals->time ) - return; - - // only look at the ones where the player hit me - if( tr.pHit == NULL || tr.pHit->v.modelindex != pev->modelindex ) - return; - - if( tr.iHitgroup >= 3 ) - { - pOther->TakeDamage( pev, pev, m_iHitDmg, DMG_CRUSH ); - // ALERT( at_console, "wack %3d : ", m_iHitDmg ); - } - else if( tr.iHitgroup != 0 ) - { - pOther->TakeDamage( pev, pev, 20, DMG_CRUSH ); - // ALERT( at_console, "tap %3d : ", 20 ); - } - else - { - return; // Huh? - } - - m_flHitTime = gpGlobals->time + 0.5; - - // ALERT( at_console, "%s : ", STRING( tr.pHit->v.classname ) ); - - // ALERT( at_console, "%.0f : %s : %d\n", pev->angles.y, STRING( pOther->pev->classname ), tr.iHitgroup ); -} - -int CTentacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if( flDamage > pev->health ) - { - pev->health = 1; - } - else - { - pev->health -= flDamage; - } - return 1; -} - -void CTentacle::Killed( entvars_t *pevAttacker, int iGib ) -{ - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - return; -} - -class CTentacleMaw : public CBaseMonster -{ -public: - void Spawn(); - void Precache(); -}; - -LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ) - -// -// Tentacle Spawn -// -void CTentacleMaw::Spawn() -{ - Precache(); - SET_MODEL( ENT( pev ), "models/maw.mdl" ); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 75; - pev->yaw_speed = 8; - pev->sequence = 0; - - pev->angles.x = 90; - // ResetSequenceInfo( ); -} - -void CTentacleMaw::Precache() -{ - PRECACHE_MODEL( "models/maw.mdl" ); -} -#endif diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp deleted file mode 100644 index 94907bcd..00000000 --- a/dlls/tripmine.cpp +++ /dev/null @@ -1,518 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "effects.h" -#include "gamerules.h" - -#define TRIPMINE_PRIMARY_VOLUME 450 - -enum tripmine_e -{ - TRIPMINE_IDLE1 = 0, - TRIPMINE_IDLE2, - TRIPMINE_ARM1, - TRIPMINE_ARM2, - TRIPMINE_FIDGET, - TRIPMINE_HOLSTER, - TRIPMINE_DRAW, - TRIPMINE_WORLD, - TRIPMINE_GROUND -}; - -#ifndef CLIENT_DLL -class CTripmineGrenade : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void UpdateOnRemove(); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - void EXPORT WarningThink( void ); - void EXPORT PowerupThink( void ); - void EXPORT BeamBreakThink( void ); - void EXPORT DelayDeathThink( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - - void MakeBeam( void ); - void KillBeam( void ); - - float m_flPowerUp; - Vector m_vecDir; - Vector m_vecEnd; - float m_flBeamLength; - - EHANDLE m_hOwner; - CBeam *m_pBeam; - Vector m_posOwner; - Vector m_angleOwner; - edict_t *m_pRealOwner;// tracelines don't hit PEV->OWNER, which means a player couldn't detonate his own trip mine, so we store the owner here. -}; - -LINK_ENTITY_TO_CLASS( monster_tripmine, CTripmineGrenade ) - -TYPEDESCRIPTION CTripmineGrenade::m_SaveData[] = -{ - DEFINE_FIELD( CTripmineGrenade, m_flPowerUp, FIELD_TIME ), - DEFINE_FIELD( CTripmineGrenade, m_vecDir, FIELD_VECTOR ), - DEFINE_FIELD( CTripmineGrenade, m_vecEnd, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CTripmineGrenade, m_flBeamLength, FIELD_FLOAT ), - DEFINE_FIELD( CTripmineGrenade, m_hOwner, FIELD_EHANDLE ), - DEFINE_FIELD( CTripmineGrenade, m_pBeam, FIELD_CLASSPTR ), - DEFINE_FIELD( CTripmineGrenade, m_posOwner, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CTripmineGrenade, m_angleOwner, FIELD_VECTOR ), - DEFINE_FIELD( CTripmineGrenade, m_pRealOwner, FIELD_EDICT ), -}; - -IMPLEMENT_SAVERESTORE( CTripmineGrenade, CGrenade ) - -void CTripmineGrenade::Spawn( void ) -{ - Precache(); - - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_NOT; - - SET_MODEL( ENT( pev ), "models/v_tripmine.mdl" ); - pev->frame = 0; - pev->body = 3; - pev->sequence = TRIPMINE_WORLD; - ResetSequenceInfo(); - pev->framerate = 0; - - UTIL_SetSize( pev, Vector( -8, -8, -8 ), Vector( 8, 8, 8 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - if( pev->spawnflags & 1 ) - { - // power up quickly - m_flPowerUp = gpGlobals->time + 1.0; - } - else - { - // power up in 2.5 seconds - m_flPowerUp = gpGlobals->time + 2.5; - } - - SetThink( &CTripmineGrenade::PowerupThink ); - pev->nextthink = gpGlobals->time + 0.2; - - pev->takedamage = DAMAGE_YES; - pev->dmg = gSkillData.plrDmgTripmine; - pev->health = 1; // don't let die normally - - if( pev->owner != NULL ) - { - // play deploy sound - EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/mine_deploy.wav", 1.0, ATTN_NORM ); - EMIT_SOUND( ENT( pev ), CHAN_BODY, "weapons/mine_charge.wav", 0.2, ATTN_NORM ); // chargeup - - m_pRealOwner = pev->owner;// see CTripmineGrenade for why. - } - - UTIL_MakeAimVectors( pev->angles ); - - m_vecDir = gpGlobals->v_forward; - m_vecEnd = pev->origin + m_vecDir * 2048; -} - -void CTripmineGrenade::Precache( void ) -{ - PRECACHE_MODEL( "models/v_tripmine.mdl" ); - PRECACHE_SOUND( "weapons/mine_deploy.wav" ); - PRECACHE_SOUND( "weapons/mine_activate.wav" ); - PRECACHE_SOUND( "weapons/mine_charge.wav" ); -} - -void CTripmineGrenade::UpdateOnRemove() -{ - CBaseEntity::UpdateOnRemove(); - - KillBeam(); -} - -void CTripmineGrenade::WarningThink( void ) -{ - // play warning sound - // EMIT_SOUND( ENT( pev ), CHAN_VOICE, "buttons/Blip2.wav", 1.0, ATTN_NORM ); - - // set to power up - SetThink( &CTripmineGrenade::PowerupThink ); - pev->nextthink = gpGlobals->time + 1.0; -} - -void CTripmineGrenade::PowerupThink( void ) -{ - TraceResult tr; - - if( m_hOwner == 0 ) - { - // find an owner - edict_t *oldowner = pev->owner; - pev->owner = NULL; - UTIL_TraceLine( pev->origin + m_vecDir * 8, pev->origin - m_vecDir * 32, dont_ignore_monsters, ENT( pev ), &tr ); - if( tr.fStartSolid || ( oldowner && tr.pHit == oldowner ) ) - { - pev->owner = oldowner; - m_flPowerUp += 0.1; - pev->nextthink = gpGlobals->time + 0.1; - return; - } - if( tr.flFraction < 1.0 ) - { - pev->owner = tr.pHit; - m_hOwner = CBaseEntity::Instance( pev->owner ); - m_posOwner = m_hOwner->pev->origin; - m_angleOwner = m_hOwner->pev->angles; - } - else - { - STOP_SOUND( ENT( pev ), CHAN_VOICE, "weapons/mine_deploy.wav" ); - STOP_SOUND( ENT( pev ), CHAN_BODY, "weapons/mine_charge.wav" ); - SetThink( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - ALERT( at_console, "WARNING:Tripmine at %.0f, %.0f, %.0f removed\n", pev->origin.x, pev->origin.y, pev->origin.z ); - KillBeam(); - return; - } - } - else if( m_posOwner != m_hOwner->pev->origin || m_angleOwner != m_hOwner->pev->angles ) - { - // disable - STOP_SOUND( ENT( pev ), CHAN_VOICE, "weapons/mine_deploy.wav" ); - STOP_SOUND( ENT( pev ), CHAN_BODY, "weapons/mine_charge.wav" ); - CBaseEntity *pMine = Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); - pMine->pev->spawnflags |= SF_NORESPAWN; - - SetThink( &CBaseEntity::SUB_Remove ); - KillBeam(); - pev->nextthink = gpGlobals->time + 0.1; - return; - } - // ALERT( at_console, "%d %.0f %.0f %0.f\n", pev->owner, m_pOwner->pev->origin.x, m_pOwner->pev->origin.y, m_pOwner->pev->origin.z ); - - if( gpGlobals->time > m_flPowerUp ) - { - // make solid - pev->solid = SOLID_BBOX; - UTIL_SetOrigin( pev, pev->origin ); - - MakeBeam(); - - // play enabled sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "weapons/mine_activate.wav", 0.5, ATTN_NORM, 1, 75 ); - } - pev->nextthink = gpGlobals->time + 0.1; -} - -void CTripmineGrenade::KillBeam( void ) -{ - if( m_pBeam ) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } -} - -void CTripmineGrenade::MakeBeam( void ) -{ - TraceResult tr; - - // ALERT( at_console, "serverflags %f\n", gpGlobals->serverflags ); - - UTIL_TraceLine( pev->origin, m_vecEnd, dont_ignore_monsters, ENT( pev ), &tr ); - - m_flBeamLength = tr.flFraction; - - // set to follow laser spot - SetThink( &CTripmineGrenade::BeamBreakThink ); - pev->nextthink = gpGlobals->time + 0.1; - - Vector vecTmpEnd = pev->origin + m_vecDir * 2048 * m_flBeamLength; - - m_pBeam = CBeam::BeamCreate( g_pModelNameLaser, 10 ); - m_pBeam->PointEntInit( vecTmpEnd, entindex() ); - m_pBeam->SetColor( 0, 214, 198 ); - m_pBeam->SetScrollRate( 255 ); - m_pBeam->SetBrightness( 64 ); -} - -void CTripmineGrenade::BeamBreakThink( void ) -{ - BOOL bBlowup = 0; - - TraceResult tr; - - // HACKHACK Set simple box using this really nice global! - gpGlobals->trace_flags = FTRACE_SIMPLEBOX; - UTIL_TraceLine( pev->origin, m_vecEnd, dont_ignore_monsters, ENT( pev ), &tr ); - - // ALERT( at_console, "%f : %f\n", tr.flFraction, m_flBeamLength ); - - // respawn detect. - if( !m_pBeam ) - { - MakeBeam(); - if( tr.pHit ) - m_hOwner = CBaseEntity::Instance( tr.pHit ); // reset owner too - } - - if( fabs( m_flBeamLength - tr.flFraction ) > 0.001 ) - { - bBlowup = 1; - } - else - { - if( m_hOwner == 0 ) - bBlowup = 1; - else if( m_posOwner != m_hOwner->pev->origin ) - bBlowup = 1; - else if( m_angleOwner != m_hOwner->pev->angles ) - bBlowup = 1; - } - - if( bBlowup ) - { - // a bit of a hack, but all CGrenade code passes pev->owner along to make sure the proper player gets credit for the kill - // so we have to restore pev->owner from pRealOwner, because an entity's tracelines don't strike it's pev->owner which meant - // that a player couldn't trigger his own tripmine. Now that the mine is exploding, it's safe the restore the owner so the - // CGrenade code knows who the explosive really belongs to. - pev->owner = m_pRealOwner; - pev->health = 0; - Killed( VARS( pev->owner ), GIB_NORMAL ); - return; - } - - pev->nextthink = gpGlobals->time + 0.1; -} - -int CTripmineGrenade::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if( gpGlobals->time < m_flPowerUp && flDamage < pev->health ) - { - // disable - // Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); - SetThink( &CBaseEntity::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - KillBeam(); - return FALSE; - } - return CGrenade::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CTripmineGrenade::Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->takedamage = DAMAGE_NO; - - if( pevAttacker && ( pevAttacker->flags & FL_CLIENT ) ) - { - // some client has destroyed this mine, he'll get credit for any kills - pev->owner = ENT( pevAttacker ); - } - - SetThink( &CTripmineGrenade::DelayDeathThink ); - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); - - EMIT_SOUND( ENT( pev ), CHAN_BODY, "common/null.wav", 0.5, ATTN_NORM ); // shut off chargeup -} - -void CTripmineGrenade::DelayDeathThink( void ) -{ - KillBeam(); - TraceResult tr; - UTIL_TraceLine( pev->origin + m_vecDir * 8, pev->origin - m_vecDir * 64, dont_ignore_monsters, ENT( pev ), &tr ); - - Explode( &tr, DMG_BLAST ); -} -#endif - -LINK_ENTITY_TO_CLASS( weapon_tripmine, CTripmine ) - -void CTripmine::Spawn() -{ - Precache(); - m_iId = WEAPON_TRIPMINE; - SET_MODEL( ENT( pev ), "models/v_tripmine.mdl" ); - pev->frame = 0; - pev->body = 3; - pev->sequence = TRIPMINE_GROUND; - // ResetSequenceInfo(); - pev->framerate = 0; - - FallInit();// get ready to fall down - - m_iDefaultAmmo = TRIPMINE_DEFAULT_GIVE; - -#ifdef CLIENT_DLL - if( !bIsMultiplayer() ) -#else - if( !g_pGameRules->IsDeathmatch() ) -#endif - { - UTIL_SetSize( pev, Vector( -16, -16, 0 ), Vector( 16, 16, 28 ) ); - } -} - -void CTripmine::Precache( void ) -{ - PRECACHE_MODEL( "models/v_tripmine.mdl" ); - PRECACHE_MODEL( "models/p_tripmine.mdl" ); - UTIL_PrecacheOther( "monster_tripmine" ); - - m_usTripFire = PRECACHE_EVENT( 1, "events/tripfire.sc" ); -} - -int CTripmine::GetItemInfo( ItemInfo *p ) -{ - p->pszName = STRING( pev->classname ); - p->pszAmmo1 = "Trip Mine"; - p->iMaxAmmo1 = TRIPMINE_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 2; - p->iId = m_iId = WEAPON_TRIPMINE; - p->iWeight = TRIPMINE_WEIGHT; - p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - - return 1; -} - -BOOL CTripmine::Deploy() -{ - pev->body = 0; - return DefaultDeploy( "models/v_tripmine.mdl", "models/p_tripmine.mdl", TRIPMINE_DRAW, "trip" ); -} - -void CTripmine::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - // out of mines - m_pPlayer->pev->weapons &= ~( 1 << WEAPON_TRIPMINE ); - DestroyItem(); - } - - SendWeaponAnim( TRIPMINE_HOLSTER ); - EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM ); -} - -void CTripmine::PrimaryAttack( void ) -{ - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - return; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecSrc = m_pPlayer->GetGunPosition(); - Vector vecAiming = gpGlobals->v_forward; - - TraceResult tr; - - UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 128, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); - - int flags; -#ifdef CLIENT_WEAPONS - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usTripFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - - if( tr.flFraction < 1.0 ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if( pEntity && !( pEntity->pev->flags & FL_CONVEYOR ) ) - { - Vector angles = UTIL_VecToAngles( tr.vecPlaneNormal ); - - CBaseEntity::Create( "monster_tripmine", tr.vecEndPos + tr.vecPlaneNormal * 8, angles, m_pPlayer->edict() ); - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - // no more mines! - RetireWeapon(); - return; - } - } - /*else - { - // ALERT( at_console, "no deploy\n" ); - }*/ - } - /*else - { - - }*/ - - m_flNextPrimaryAttack = GetNextAttackDelay( 0.3 ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - -void CTripmine::WeaponIdle( void ) -{ - if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 ) - { - SendWeaponAnim( TRIPMINE_DRAW ); - } - else - { - RetireWeapon(); - return; - } - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if( flRand <= 0.25 ) - { - iAnim = TRIPMINE_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; - } - else if( flRand <= 0.75 ) - { - iAnim = TRIPMINE_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 30.0; - } - else - { - iAnim = TRIPMINE_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 100.0 / 30.0; - } - - SendWeaponAnim( iAnim ); -} diff --git a/dlls/wxdebug.h b/dlls/wxdebug.h deleted file mode 100644 index 026039ae..00000000 --- a/dlls/wxdebug.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef __WXDEBUG__ -#define __WXDEBUG__ - -// This library provides fairly straight forward debugging functionality, this -// is split into two main sections. The first is assertion handling, there are -// three types of assertions provided here. The most commonly used one is the -// ASSERT(condition) macro which will pop up a message box including the file -// and line number if the condition evaluates to FALSE. Then there is the -// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will -// still be executed in NON debug builds. The final type of assertion is the -// KASSERT macro which is more suitable for pure (perhaps kernel) filters as -// the condition is printed onto the debugger rather than in a message box. -// -// The other part of the debug module facilties is general purpose logging. -// This is accessed by calling DbgLog(). The function takes a type and level -// field which define the type of informational string you are presenting and -// it's relative importance. The type field can be a combination (one or more) -// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level -// is a DWORD value where zero defines highest important. Use of zero as the -// debug logging level is to be encouraged ONLY for major errors or events as -// they will ALWAYS be displayed on the debugger. Other debug output has it's -// level matched against the current debug output level stored in the registry -// for this module and if less than the current setting it will be displayed. -// -// Each module or executable has it's own debug output level for each of the -// five types. These are read in when the DbgInitialise function is called -// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL -// is loaded, executables must call it explicitely with the module instance -// handle given to them through the WINMAIN entry point. An executable must -// also call DbgTerminate when they have finished to clean up the resources -// the debug library uses, once again this is done automatically for DLLs - -// These are the five different categories of logging information - -#ifdef _DEBUG - - -enum -{ - LOG_TRACE = 0x00000001, // General tracing - LOG_ENTRY = 0x00000002, // Function entry logging - LOG_EXIT = 0x00000004, // Function exit logging - LOG_MEMORY = 0x00000008, // Memory alloc/free debugging - LOG_ERROR = 0x00000010, // Error notification - LOG_UNUSED0 = 0x00000020, // reserved - LOG_UNUSED1 = 0x00000040, // reserved - LOG_UNUSED2 = 0x00000080, // reserved - LOG_CHUM = 0x00000100, // Chumtoad debugging - LOG_LEECH = 0x00000200, // Leech debugging - LOG_ICHTHYOSAUR = 0x00000400, // Ichthyosaur debugging -}; - - -// These are public but should be called only by the DLLMain function -void WINAPI DbgInitialise(HINSTANCE hInst); -void WINAPI DbgTerminate(); -// These are public but should be called by macro only -void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); -void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); -void WINAPI DbgOutString(LPCTSTR psz); - - -// These are the macros that should be used in code. - -#define DBGASSERT(_x_) \ - if (!(_x_)) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - -#define DBGBREAK(_x_) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - -#define DBGASSERTEXECUTE(_x_) DBGASSERT(_x_) - -#define DBGLOG(_x_) DbgLogInfo _x_ - -#define DBGOUT(_x_) DbgOutString(_x_) - -#define ValidateReadPtr(p,cb) \ - {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ - DBGBREAK("Invalid read pointer");} - -#define ValidateWritePtr(p,cb) \ - {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ - DBGBREAK("Invalid write pointer");} - -#define ValidateReadWritePtr(p,cb) \ - {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} - -#define ValidateStringPtr(p) \ - {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid string pointer");} - -#define ValidateStringPtrA(p) \ - {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid ANSII string pointer");} - -#define ValidateStringPtrW(p) \ - {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid UNICODE string pointer");} - -#else // !_DEBUG - -// Retail builds make public debug functions inert - WARNING the source -// files do not define or build any of the entry points in debug builds -// (public entry points compile to nothing) so if you go trying to call -// any of the private entry points in your source they won't compile - -#define DBGASSERT(_x_) -#define DBGBREAK(_x_) -#define DBGASSERTEXECUTE(_x_) _x_ -#define DBGLOG(_x_) -#define DBGOUT(_x_) -#define ValidateReadPtr(p,cb) -#define ValidateWritePtr(p,cb) -#define ValidateReadWritePtr(p,cb) -#define ValidateStringPtr(p) -#define ValidateStringPtrA(p) -#define ValidateStringPtrW(p) - -#endif // !_DEBUG - - -#ifndef REMIND - // REMIND macro - generates warning as reminder to complete coding - // (eg) usage: - // - // #pragma message (REMIND("Add automation support")) - - - #define REMINDQUOTE(x) #x - #define REMINDQQUOTE(y) REMINDQUOTE(y) - #define REMIND(str) __FILE__ "(" REMINDQQUOTE(__LINE__) ") : " str -#endif - -#endif // __WXDEBUG__ - - diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp deleted file mode 100644 index 96f032e6..00000000 --- a/dlls/zombie.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Zombie -//========================================================= - -// UNDONE: Don't flinch every time you get hit - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ZOMBIE_AE_ATTACK_RIGHT 0x01 -#define ZOMBIE_AE_ATTACK_LEFT 0x02 -#define ZOMBIE_AE_ATTACK_BOTH 0x03 - -#define ZOMBIE_FLINCH_DELAY 2 // at most one flinch every n secs - -class CZombie : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int IgnoreConditions( void ); - - float m_flNextFlinch; - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSound( void ); - - static const char *pAttackSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - - // No range attacks - BOOL CheckRangeAttack1( float flDot, float flDist ) { return FALSE; } - BOOL CheckRangeAttack2( float flDot, float flDist ) { return FALSE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); -}; - -LINK_ENTITY_TO_CLASS( monster_zombie, CZombie ) - -const char *CZombie::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CZombie::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CZombie::pAttackSounds[] = -{ - "zombie/zo_attack1.wav", - "zombie/zo_attack2.wav", -}; - -const char *CZombie::pIdleSounds[] = -{ - "zombie/zo_idle1.wav", - "zombie/zo_idle2.wav", - "zombie/zo_idle3.wav", - "zombie/zo_idle4.wav", -}; - -const char *CZombie::pAlertSounds[] = -{ - "zombie/zo_alert10.wav", - "zombie/zo_alert20.wav", - "zombie/zo_alert30.wav", -}; - -const char *CZombie::pPainSounds[] = -{ - "zombie/zo_pain1.wav", - "zombie/zo_pain2.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CZombie::Classify( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CZombie::SetYawSpeed( void ) -{ - int ys; - - ys = 120; -#if 0 - switch ( m_Activity ) - { - } -#endif - pev->yaw_speed = ys; -} - -int CZombie::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Take 30% damage from bullets - if( bitsDamageType == DMG_BULLET ) - { - Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; - vecDir = vecDir.Normalize(); - float flForce = DamageForce( flDamage ); - pev->velocity = pev->velocity + vecDir * flForce; - flDamage *= 0.3; - } - - // HACK HACK -- until we fix this. - if( IsAlive() ) - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CZombie::PainSound( void ) -{ - int pitch = 95 + RANDOM_LONG( 0, 9 ); - - if( RANDOM_LONG( 0, 5 ) < 2 ) - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pPainSounds[RANDOM_LONG( 0, ARRAYSIZE( pPainSounds ) - 1 )], 1.0, ATTN_NORM, 0, pitch ); -} - -void CZombie::AlertSound( void ) -{ - int pitch = 95 + RANDOM_LONG( 0, 9 ); - - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAlertSounds[ RANDOM_LONG( 0, ARRAYSIZE( pAlertSounds ) - 1 )], 1.0, ATTN_NORM, 0, pitch ); -} - -void CZombie::IdleSound( void ) -{ - int pitch = 95 + RANDOM_LONG( 0, 9 ); - - // Play a random idle sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pIdleSounds[RANDOM_LONG( 0, ARRAYSIZE( pIdleSounds ) -1 )], 1.0, ATTN_NORM, 0, pitch ); -} - -void CZombie::AttackSound( void ) -{ - int pitch = 95 + RANDOM_LONG( 0, 9 ); - - // Play a random attack sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAttackSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackSounds ) - 1 )], 1.0, ATTN_NORM, 0, pitch ); -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CZombie::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case ZOMBIE_AE_ATTACK_RIGHT: - { - // do stuff for this event. - //ALERT( at_console, "Slash right!\n" ); - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); - if( pHurt ) - { - if( pHurt->pev->flags & ( FL_MONSTER | FL_CLIENT ) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; - } - // Play a random attack hit sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5 , 5 ) ); - } - else // Play a random attack miss sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - - if( RANDOM_LONG( 0, 1 ) ) - AttackSound(); - } - break; - case ZOMBIE_AE_ATTACK_LEFT: - { - // do stuff for this event. - //ALERT( at_console, "Slash left!\n" ); - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); - if( pHurt ) - { - if( pHurt->pev->flags & ( FL_MONSTER | FL_CLIENT ) ) - { - pHurt->pev->punchangle.z = 18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100; - } - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - } - else - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - - if( RANDOM_LONG( 0, 1 ) ) - AttackSound(); - } - break; - case ZOMBIE_AE_ATTACK_BOTH: - { - // do stuff for this event. - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgBothSlash, DMG_SLASH ); - if( pHurt ) - { - if( pHurt->pev->flags & ( FL_MONSTER | FL_CLIENT ) ) - { - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -100; - } - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - } - else - EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); - - if( RANDOM_LONG( 0, 1 ) ) - AttackSound(); - } - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CZombie::Spawn() -{ - Precache(); - - SET_MODEL( ENT( pev ), "models/zombie.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.zombieHealth; - pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_DOORS_GROUP; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CZombie::Precache() -{ - size_t i; - - PRECACHE_MODEL( "models/zombie.mdl" ); - - for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND( pAttackHitSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND( pAttackMissSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND( pAttackSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND( pIdleSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND( pAlertSounds[i] ); - - for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND( pPainSounds[i] ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -int CZombie::IgnoreConditions( void ) -{ - int iIgnore = CBaseMonster::IgnoreConditions(); - - if( ( m_Activity == ACT_MELEE_ATTACK1 ) || ( m_Activity == ACT_MELEE_ATTACK1 ) ) - { -#if 0 - if( pev->health < 20 ) - iIgnore |= ( bits_COND_LIGHT_DAMAGE| bits_COND_HEAVY_DAMAGE ); - else -#endif - if( m_flNextFlinch >= gpGlobals->time ) - iIgnore |= ( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ); - } - - if( ( m_Activity == ACT_SMALL_FLINCH ) || ( m_Activity == ACT_BIG_FLINCH ) ) - { - if( m_flNextFlinch < gpGlobals->time ) - m_flNextFlinch = gpGlobals->time + ZOMBIE_FLINCH_DELAY; - } - - return iIgnore; -}