From 6d814ef919836eb62c025eecbe175d9464789afc Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sun, 30 Jul 2017 10:24:07 +0500 Subject: [PATCH] Merge @malortie's patches for "Swiss Cheese Halloween". --- dlls/agrunt.cpp | 46 +- dlls/basemonster.h | 2 +- dlls/bigmomma.cpp | 17 +- dlls/combat.cpp | 26 +- dlls/controller.cpp | 8 +- dlls/gargantua.cpp | 60 ++- dlls/halloween/shall_map_fixes.cpp | 795 +++++++++++++++++++++++++++++ dlls/halloween/shall_map_fixes.h | 21 + dlls/handgrenade.cpp | 52 +- dlls/headcrab.cpp | 9 +- dlls/hgrunt.cpp | 323 +++--------- dlls/houndeye.cpp | 6 +- dlls/islave.cpp | 3 +- dlls/monsters.cpp | 10 +- dlls/player.cpp | 17 + dlls/player.h | 2 + dlls/squeakgrenade.cpp | 3 +- dlls/triggers.cpp | 8 + dlls/util.cpp | 48 ++ dlls/util.h | 4 + dlls/weapons.h | 3 + dlls/world.cpp | 7 +- dlls/zombie.cpp | 13 +- 23 files changed, 1128 insertions(+), 355 deletions(-) create mode 100644 dlls/halloween/shall_map_fixes.cpp create mode 100644 dlls/halloween/shall_map_fixes.h diff --git a/dlls/agrunt.cpp b/dlls/agrunt.cpp index cb47ac65..3ac3849e 100644 --- a/dlls/agrunt.cpp +++ b/dlls/agrunt.cpp @@ -214,46 +214,9 @@ int CAGrunt::ISoundMask( void ) //========================================================= 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 ); - } + // Pumpkin beasts do not wear armors. + SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage );// a little surface blood. + TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); } @@ -588,7 +551,8 @@ void CAGrunt::Spawn() pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; + // Pumpkin beasts (jack o lantern) use red blood. + m_bloodColor = BLOOD_COLOR_RED; 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 ) diff --git a/dlls/basemonster.h b/dlls/basemonster.h index 0d22104f..d62b1f5c 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -290,7 +290,7 @@ public: Activity GetSmallFlinchActivity( void ); virtual void Killed( entvars_t *pevAttacker, int iGib ); virtual void GibMonster( void ); - BOOL ShouldGibMonster( int iGib ); + virtual BOOL ShouldGibMonster( int iGib ); void CallGibMonster( void ); virtual BOOL HasHumanGibs( void ); virtual BOOL HasAlienGibs( void ); diff --git a/dlls/bigmomma.cpp b/dlls/bigmomma.cpp index 6b594983..2cbd9212 100644 --- a/dlls/bigmomma.cpp +++ b/dlls/bigmomma.cpp @@ -536,18 +536,8 @@ void CBigMomma::HandleAnimEvent( MonsterEvent_t *pEvent ) 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 ) + // Bigmomma does not wear armor. + if( gpGlobals->time > m_painSoundTime ) { m_painSoundTime = gpGlobals->time + RANDOM_LONG( 1, 3 ); EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); @@ -637,7 +627,8 @@ void CBigMomma::Spawn() pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; + // Bigmomma's blood color should be red. + m_bloodColor = BLOOD_COLOR_RED; 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 ) diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 35e4ffcf..7ccd9f74 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -254,9 +254,20 @@ BOOL CBaseMonster::HasHumanGibs( void ) { int myClass = Classify(); + // Only reapers. + if( myClass == CLASS_ALIEN_MONSTER && !FClassnameIs( pev, "monster_bigmomma" ) && !FClassnameIs( pev, "monster_houndeye" ) ) + return TRUE; + + // Witches are humans and should use human gibs. + if( myClass == CLASS_ALIEN_MILITARY && FClassnameIs( pev, "monster_alien_slave" ) ) + return TRUE; + if( myClass == CLASS_HUMAN_MILITARY || myClass == CLASS_PLAYER_ALLY || myClass == CLASS_HUMAN_PASSIVE || + + // Vampire should have human gibs. + myClass == CLASS_ALIEN_PREY || myClass == CLASS_PLAYER ) return TRUE; @@ -268,12 +279,17 @@ BOOL CBaseMonster::HasAlienGibs( void ) { int myClass = Classify(); - if( myClass == CLASS_ALIEN_MILITARY || - myClass == CLASS_ALIEN_MONSTER || - myClass == CLASS_ALIEN_PASSIVE || + // Big momma pumpkin and martians should use alien gibs. + if( myClass == CLASS_ALIEN_MONSTER && ( FClassnameIs( pev, "monster_bigmomma" ) || FClassnameIs( pev, "monster_houndeye" ) ) ) + return TRUE; + + // Witches are humans and should not use alien gibs. + if( myClass == CLASS_ALIEN_MILITARY && !FClassnameIs( pev, "monster_alien_slave" ) ) + return TRUE; + + if( myClass == CLASS_ALIEN_PASSIVE || myClass == CLASS_INSECT || - myClass == CLASS_ALIEN_PREDATOR || - myClass == CLASS_ALIEN_PREY ) + myClass == CLASS_ALIEN_PREDATOR ) return TRUE; diff --git a/dlls/controller.cpp b/dlls/controller.cpp index e1d57517..f1df0e10 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -90,6 +90,7 @@ public: int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); void Killed( entvars_t *pevAttacker, int iGib ); void GibMonster( void ); + BOOL ShouldGibMonster( int iGib ) { return FALSE; } // Ghosts should not gib. CSprite *m_pBall[2]; // hand balls int m_iBall[2]; // how bright it should be @@ -223,7 +224,9 @@ void CController::GibMonster( void ) UTIL_Remove( m_pBall[1] ); m_pBall[1] = NULL; } - CSquadMonster::GibMonster(); + + // Ghosts do not gib. + FadeMonster(); } void CController::PainSound( void ) @@ -357,7 +360,8 @@ void CController::Spawn() pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_FLY; pev->flags |= FL_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; + // Ghost use red blood. + m_bloodColor = BLOOD_COLOR_RED; 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 ) diff --git a/dlls/gargantua.cpp b/dlls/gargantua.cpp index f3155d7f..e7762a13 100644 --- a/dlls/gargantua.cpp +++ b/dlls/gargantua.cpp @@ -229,15 +229,16 @@ public: void EyeOn( int level ); void EyeUpdate( void ); void Leap( void ); - void StompAttack( 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[]; @@ -458,7 +459,7 @@ void CGargantua::EyeUpdate( void ) UTIL_SetOrigin( m_pEyeGlow->pev, pev->origin ); } } - +/* void CGargantua::StompAttack( void ) { TraceResult trace; @@ -674,9 +675,10 @@ void CGargantua::FlameDestroy( void ) } } } - +*/ void CGargantua::PrescheduleThink( void ) { +/* if( !HasConditions( bits_COND_SEE_ENEMY ) ) { m_seeTime = gpGlobals->time + 5; @@ -686,6 +688,7 @@ void CGargantua::PrescheduleThink( void ) EyeOn( 200 ); EyeUpdate(); +*/ } //========================================================= @@ -746,9 +749,9 @@ void CGargantua::Spawn() MonsterInit(); - m_pEyeGlow = CSprite::SpriteCreate( GARG_EYE_SPRITE_NAME, pev->origin, FALSE ); +/* 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 ); + m_pEyeGlow->SetAttachment( edict(), 1 );*/ EyeOff(); m_seeTime = gpGlobals->time + 5; m_flameTime = gpGlobals->time + 2; @@ -807,13 +810,13 @@ void CGargantua::UpdateOnRemove() { CBaseEntity::UpdateOnRemove(); - if( m_pEyeGlow ) + /*if( m_pEyeGlow ) { UTIL_Remove( m_pEyeGlow ); m_pEyeGlow = 0; } - FlameDestroy(); + FlameDestroy();*/ } void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) @@ -840,13 +843,15 @@ void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec if( bitsDamageType == 0 ) { - if( pev->dmgtime != gpGlobals->time || (RANDOM_LONG( 0, 100 ) < 20 ) ) + // Final boss (Reaper) does not wear armor. + // Also, leave it immune to any damage. +/* 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; } @@ -895,8 +900,8 @@ void CGargantua::DeathEffect( void ) void CGargantua::Killed( entvars_t *pevAttacker, int iGib ) { EyeOff(); - UTIL_Remove( m_pEyeGlow ); - m_pEyeGlow = NULL; +/* UTIL_Remove( m_pEyeGlow ); + m_pEyeGlow = NULL;*/ CBaseMonster::Killed( pevAttacker, GIB_NEVER ); } @@ -921,15 +926,15 @@ BOOL CGargantua::CheckMeleeAttack1( float flDot, float flDist ) BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) { //ALERT( at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist ); - - if( gpGlobals->time > m_flameTime ) +/* if( gpGlobals->time > m_flameTime ) { if( flDot >= 0.8 && flDist > GARG_ATTACKDIST ) { if ( flDist <= GARG_FLAME_LENGTH ) return TRUE; } - } + }*/ + // Final boss (Reaper) should not use melee attack 2. return FALSE; } @@ -944,13 +949,14 @@ BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) //========================================================= BOOL CGargantua::CheckRangeAttack1( float flDot, float flDist ) { - if( gpGlobals->time > m_seeTime ) +/* if( gpGlobals->time > m_seeTime ) { if( flDot >= 0.7 && flDist > GARG_ATTACKDIST ) { return TRUE; } - } + }*/ + // Final boss (Reaper) should not use range attack 1. return FALSE; } @@ -991,8 +997,8 @@ void CGargantua::HandleAnimEvent( MonsterEvent_t *pEvent ) 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; + /*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 ) ); @@ -1043,13 +1049,13 @@ CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage Schedule_t *CGargantua::GetScheduleOfType( int Type ) { // HACKHACK - turn off the flames if they are on and garg goes scripted / dead - if( FlameIsOn() ) - FlameDestroy(); + /*if( FlameIsOn() ) + FlameDestroy();*/ switch( Type ) { - case SCHED_MELEE_ATTACK2: - return slGargFlame; + /*case SCHED_MELEE_ATTACK2: + return slGargFlame;*/ case SCHED_MELEE_ATTACK1: return slGargSwipe; break; @@ -1062,13 +1068,13 @@ void CGargantua::StartTask( Task_t *pTask ) { switch( pTask->iTask ) { - case TASK_FLAME_SWEEP: + /*case TASK_FLAME_SWEEP: FlameCreate(); m_flWaitFinished = gpGlobals->time + pTask->flData; m_flameTime = gpGlobals->time + 6; m_flameX = 0; m_flameY = 0; - break; + 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 ); @@ -1161,7 +1167,7 @@ void CGargantua::RunTask( Task_t *pTask ) else CBaseMonster::RunTask( pTask ); break; - case TASK_FLAME_SWEEP: +/* case TASK_FLAME_SWEEP: if( gpGlobals->time > m_flWaitFinished ) { FlameDestroy(); @@ -1200,7 +1206,7 @@ void CGargantua::RunTask( Task_t *pTask ) // FlameControls( angles.x + 2 * sin( gpGlobals->time * 8 ), angles.y + 28 * sin( gpGlobals->time * 8.5 ) ); FlameControls( angles.x, angles.y ); } - break; + break;*/ default: CBaseMonster::RunTask( pTask ); break; diff --git a/dlls/halloween/shall_map_fixes.cpp b/dlls/halloween/shall_map_fixes.cpp new file mode 100644 index 00000000..2c9b68f0 --- /dev/null +++ b/dlls/halloween/shall_map_fixes.cpp @@ -0,0 +1,795 @@ +/*** +* +* Copyright (c) 1996-2001, 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 "nodes.h" +#include "soundent.h" +#include "decals.h" +#include "effects.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "shall_map_fixes.h" + +#if defined ( SHALL_MAPFIXES ) + +#define RANDOM_ANGLE() Vector( 0, RANDOM_LONG(1, 6) * RANDOM_LONG(1, 6) * RANDOM_LONG(1, 10), 0 ) + +static CBaseEntity* CreateItemAtPosition(char* classname, const Vector& position, const Vector& angles) +{ + CBaseEntity* item = CBaseEntity::Create(classname, position, angles, NULL); + if (item != NULL) + { + item->Precache(); + item->Spawn(); + } + + return item; +} + +static CBaseEntity* CreateHealthKitAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("item_healthkit", position, angles); +} + +static CBaseEntity* CreateBatteryAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("item_battery", position, angles); +} + +static CBaseEntity* CreateWeaponCrowbarAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("weapon_crowbar", position, angles); +} + +static CBaseEntity* CreateWeaponMP5AtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("weapon_9mmAR", position, angles); +} + +static CBaseEntity* CreateWeaponShotgunAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("weapon_shotgun", position, angles); +} + +static CBaseEntity* CreateWeapon357AtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("weapon_357", position, angles); +} + +static CBaseEntity* CreateWeaponSatchelAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("weapon_satchel", position, angles); +} + +static CBaseEntity* CreateWeaponTripmineAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("weapon_tripmine", position, angles); +} + +static CBaseEntity* CreateMP5AmmoAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("ammo_9mmAR", position, angles); +} + +static CBaseEntity* CreateMP5GrenadeAmmoAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("ammo_ARGrenades", position, angles); +} + +static CBaseEntity* CreateShotgunAmmoAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("ammo_buckshot", position, angles); +} + +static CBaseEntity* Create357AmmoAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("ammo_357", position, angles); +} + +static CBaseEntity* Create9mmAmmoBoxAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("ammo_9mmbox", position, angles); +} + +enum CrossbowPlacement +{ + Normal = 0, + Realistic = 1, +}; + +static CBaseEntity* CreateWeaponCrossbowAtPosition(const Vector& position, const Vector& angles, CrossbowPlacement placement = CrossbowPlacement::Normal) +{ + CBaseEntity* crossbow = CreateItemAtPosition("weapon_crossbow", position, angles); + + if(crossbow != NULL) + crossbow->pev->sequence = (int)placement; + + return crossbow; +} + +static CBaseEntity* CreateCrossbowAmmoAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("ammo_crossbow", position, angles); +} + +static CBaseEntity* Create9mmBoxAmmoAtPosition(const Vector& position, const Vector& angles) +{ + return CreateItemAtPosition("ammo_9mmbox", position, angles); +} + +class MapFixPatchSpawnPosition +{ +public: + void ApplyFixToPlayer(CBasePlayer* player); +}; + +class MapFixPatchAddWeaponsAndAmmo +{ +public: + void ApplyFix(); + +protected: + void SpawnWeaponsAndAmmoAtSpawn(float floorZ); + void SpawnWeaponsAndAmmoAtBeginningOfSecondSection(float floorZ); + void SpawnWeaponsAndAmmoAtBeginningOfThirdSection(float floorZ); + void SpawnWeaponsAndAmmoAtBeginningOfFourthSection(float floorZ); + void SpawnWeaponsAndAmmoAtBeginningOfFifthSection(float floorZ); +}; + +class MapFixCornAddWeaponsAndAmmo +{ +public: + void ApplyFix(); + void SpawnCrowbarAtSpawn(float floorZ); + void SpawnHealthAndBattery(float floorZ); +}; + +class MapFixShipAddWeaponsAndAmmo +{ +public: + void ApplyFix(); + void SpawnHealthAndBatteryAtLevel1(float floorZ); + void SpawnHealthNearExit(float floorZ); +}; + +class MapFixWoodsAddWeaponsAndAmmo +{ +public: + void ApplyFix(); + void SpawnHealth(float floorZ); +}; + +class CChangeLevelToGrave : public CBaseEntity +{ +public: + virtual int Save(CSave &save); + virtual int Restore(CRestore &restore); + static TYPEDESCRIPTION m_SaveData[]; + + void Spawn(void); + int ObjectCaps(void) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + void EXPORT WaitAndAppendToMultiManager(void); + void EXPORT TeleportPlayerToChangeLevel(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value); + void EXPORT TeleportThink(void); + +protected: + CBaseEntity* FindTriggerByTarget(const char* triggerTarget); + CBaseEntity* FindMultiManagerByName(const char* nextmap); + void AddThisEntityToMultiManagerOutputList(); + +private: + CBaseEntity* m_multimanager; +}; + +LINK_ENTITY_TO_CLASS(shall_teleporttochangelevel, CChangeLevelToGrave); + +TYPEDESCRIPTION CChangeLevelToGrave::m_SaveData[] = +{ + DEFINE_FIELD(CChangeLevelToGrave, m_multimanager, FIELD_CLASSPTR), +}; +IMPLEMENT_SAVERESTORE(CChangeLevelToGrave, CBaseEntity); + +class MapFixWitch +{ +public: + void ApplyFix(); + void SpawnHealthAndBatteryNearHouseEntry(float floorZ); + void AppendMultiManagerEntryToTeleportPlayerToChangeLevelAfterLevelIsDone(); +}; + +class MapFixGraveAddWeaponsAndAmmo +{ +public: + void ApplyFix(); + void SpawnHealthAndBatteryNextToCoffin(float floorZ); +}; + +class MapFixVamp +{ +public: + void ApplyFix(); + void CreateAndSetupTriggerToCallLift1(); + void CreateAndSetupTriggerToCallLift2(); + void CreateAndSetupTriggerToCallLift3(); + void SpawnHealthAtHighestTowerBeforeLongJump(float floorZ); +protected: + CBaseEntity* CreateLiftTrigger(const Vector& origin, const Vector& angles, float liftHeight); +}; + +class MapFixHellAddWeaponsAndAmmo +{ +public: + void ApplyFix(); + void SpawnHealthAmmoWeaponsAtLightNearSpawn(float floorZ); + void SpawnHealthAmmoWeaponsAtPositionBeforeFinalBattle(float floorZ); +}; + +class MapFixes +{ +public: + + void ApplyMapFixPatch(); + void ApplyMapFixCorn(); + void ApplyMapFixShip(); + void ApplyMapFixWoods(); + void ApplyMapFixWitch(); + void ApplyMapFixGrave(); + void ApplyMapFixVamp(); + void ApplyMapFixHell(); + void FixupMapPatchPlayerSpawnPosition(CBasePlayer* player); + + MapFixPatchSpawnPosition* GetPatchSpawnPositionSingleton(); + MapFixPatchAddWeaponsAndAmmo* GetPatchAddWeaponsAndAmmoSingleton(); + MapFixCornAddWeaponsAndAmmo* GetCornAddWeaponsAndAmmoSingleton(); + MapFixShipAddWeaponsAndAmmo* GetShipAddWeaponsAndAmmoSingleton(); + MapFixWoodsAddWeaponsAndAmmo* GetWoodsAddWeaponsAndAmmoSingleton(); + MapFixWitch* GetWitchSingleton(); + MapFixGraveAddWeaponsAndAmmo* GetGraveAddWeaponsAndAmmoSingleton(); + MapFixVamp* GetVampSingleton(); + MapFixHellAddWeaponsAndAmmo* GetHellAddWeaponsAndAmmoSingleton(); +}; + +void MapFixPatchSpawnPosition::ApplyFixToPlayer( CBasePlayer* player ) +{ + player->pev->velocity = player->pev->avelocity = g_vecZero; + player->pev->angles = player->pev->v_angle = Vector(0, 90, 0); + + UTIL_SetOrigin(player->pev, Vector(2910, -2332, -410)); +} + +void MapFixPatchAddWeaponsAndAmmo::ApplyFix() +{ + // spawn + SpawnWeaponsAndAmmoAtSpawn(-444); + + // beginning of second section (pumpkin field #1). + SpawnWeaponsAndAmmoAtBeginningOfSecondSection(-446); + + // beginning of third section (square bales with cabin and vampire). + SpawnWeaponsAndAmmoAtBeginningOfThirdSection(2); + + // beginning of fourth section (pumpkin field #2). + SpawnWeaponsAndAmmoAtBeginningOfFourthSection(514); + + // beginning of fifth section (big mommas). + SpawnWeaponsAndAmmoAtBeginningOfFifthSection(1024); +} + +void MapFixPatchAddWeaponsAndAmmo::SpawnWeaponsAndAmmoAtSpawn(float floorZ) +{ + CreateWeaponMP5AtPosition(Vector(2966, -1718, floorZ), RANDOM_ANGLE()); + CreateWeaponShotgunAtPosition(Vector(2903, -1738, floorZ), RANDOM_ANGLE()); + CreateMP5AmmoAtPosition(Vector(2936, -1705, floorZ), RANDOM_ANGLE()); + CreateShotgunAmmoAtPosition(Vector(3011, -1707, floorZ), RANDOM_ANGLE()); + CreateShotgunAmmoAtPosition(Vector(2977, -1744, floorZ), RANDOM_ANGLE()); + CreateMP5AmmoAtPosition(Vector(2944, -1760, floorZ), RANDOM_ANGLE()); +} + +void MapFixPatchAddWeaponsAndAmmo::SpawnWeaponsAndAmmoAtBeginningOfSecondSection(float floorZ) +{ + CreateHealthKitAtPosition(Vector(-2972, -2694, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(-3012, -2722, floorZ), RANDOM_ANGLE()); + CreateMP5AmmoAtPosition(Vector(-2967, -2726, floorZ), RANDOM_ANGLE()); + CreateShotgunAmmoAtPosition(Vector(-2995, -2754, floorZ), RANDOM_ANGLE()); +} + +void MapFixPatchAddWeaponsAndAmmo::SpawnWeaponsAndAmmoAtBeginningOfThirdSection(float floorZ) +{ + CreateWeaponCrossbowAtPosition(Vector(917, -719, floorZ), RANDOM_ANGLE(), CrossbowPlacement::Realistic); + Create9mmBoxAmmoAtPosition(Vector(946, -786, floorZ), RANDOM_ANGLE()); + CreateCrossbowAmmoAtPosition(Vector(888, -762, floorZ), RANDOM_ANGLE()); + CreateCrossbowAmmoAtPosition(Vector(915, -766, floorZ), RANDOM_ANGLE()); + CreateCrossbowAmmoAtPosition(Vector(903, -785, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(876, -794, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(854, -806, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(855, -840, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(899, -821, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(913, -844, floorZ), RANDOM_ANGLE()); +} + +void MapFixPatchAddWeaponsAndAmmo::SpawnWeaponsAndAmmoAtBeginningOfFourthSection(float floorZ) +{ + CreateWeapon357AtPosition(Vector(689, 2776, floorZ), RANDOM_ANGLE()); + CreateWeaponShotgunAtPosition(Vector(649, 2752, floorZ), RANDOM_ANGLE()); + Create357AmmoAtPosition(Vector(688, 2750, floorZ), RANDOM_ANGLE()); + CreateShotgunAmmoAtPosition(Vector(705, 2734, floorZ), RANDOM_ANGLE()); + CreateShotgunAmmoAtPosition(Vector(663, 2706, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(681, 2729, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(718, 2710, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(690, 2707, floorZ), RANDOM_ANGLE()); +} + +void MapFixPatchAddWeaponsAndAmmo::SpawnWeaponsAndAmmoAtBeginningOfFifthSection(float floorZ) +{ + CreateWeaponSatchelAtPosition(Vector(-2884, 551, floorZ), RANDOM_ANGLE()); + CreateWeaponSatchelAtPosition(Vector(-2846, 568, floorZ), RANDOM_ANGLE()); + CreateWeaponTripmineAtPosition(Vector(-2852, 536, floorZ), RANDOM_ANGLE()); + CreateWeaponTripmineAtPosition(Vector(-2830, 549, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-2893, 528, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-2838, 513, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-2859, 495, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(-2867, 514, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(-2881, 495, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(-2902, 502, floorZ), RANDOM_ANGLE()); +} + +void MapFixCornAddWeaponsAndAmmo::ApplyFix() +{ + SpawnCrowbarAtSpawn(-430); + SpawnHealthAndBattery(-430); +} + +void MapFixCornAddWeaponsAndAmmo::SpawnCrowbarAtSpawn(float floorZ) +{ + CreateWeaponCrowbarAtPosition(Vector(3168, -2341, floorZ), RANDOM_ANGLE()); +} + +void MapFixCornAddWeaponsAndAmmo::SpawnHealthAndBattery(float floorZ) +{ + CreateBatteryAtPosition(Vector(2332, 2099, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(2307, 2126, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(2225, 2105, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(2332, 2134, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(2282, 2105, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(2262, 2134, floorZ), RANDOM_ANGLE()); + + CreateBatteryAtPosition(Vector(-205, 2359, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(-204, 2331, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-172, 2358, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-173, 2334, floorZ), RANDOM_ANGLE()); + + CreateBatteryAtPosition(Vector(-210, 1428, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(-186, 1430, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-158, 1430, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-124, 1430, floorZ), RANDOM_ANGLE()); +} + +void MapFixShipAddWeaponsAndAmmo::ApplyFix() +{ + SpawnHealthAndBatteryAtLevel1(2080); + SpawnHealthNearExit(2080); +} + +void MapFixShipAddWeaponsAndAmmo::SpawnHealthAndBatteryAtLevel1(float floorZ) +{ + CreateBatteryAtPosition(Vector(-672, -159, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(-672, -135, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-674, -208, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-672, -186, floorZ), RANDOM_ANGLE()); + + CreateBatteryAtPosition(Vector(-205, 673, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(-179, 670, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-134, 672, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-106, 672, floorZ), RANDOM_ANGLE()); + + CreateBatteryAtPosition(Vector(666, 109, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(669, 85, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(658, 188, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(653, 166, floorZ), RANDOM_ANGLE()); +} + +void MapFixShipAddWeaponsAndAmmo::SpawnHealthNearExit(float floorZ) +{ + CreateHealthKitAtPosition(Vector(140, 48, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(169, 53, floorZ), RANDOM_ANGLE()); +} + +void MapFixWoodsAddWeaponsAndAmmo::ApplyFix() +{ + SpawnHealth(-433); +} + +void CChangeLevelToGrave::Spawn(void) +{ + m_multimanager = NULL; + + SetThink(&CChangeLevelToGrave::WaitAndAppendToMultiManager); + pev->nextthink = gpGlobals->time + 0.1; +} + +void CChangeLevelToGrave::WaitAndAppendToMultiManager(void) +{ + if (m_multimanager == NULL) + m_multimanager = FindMultiManagerByName("explm"); + + if (m_multimanager == NULL) + pev->nextthink = gpGlobals->time + 1.0; + else + { + AddThisEntityToMultiManagerOutputList(); + SetUse(&CChangeLevelToGrave::TeleportPlayerToChangeLevel); + SetThink(&CBaseEntity::SUB_DoNothing); + pev->nextthink = gpGlobals->time + 0.2f; + } +} + +void CChangeLevelToGrave::TeleportPlayerToChangeLevel(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value) +{ + SetThink(&CChangeLevelToGrave::TeleportThink); + pev->nextthink = gpGlobals->time; +} + +void CChangeLevelToGrave::TeleportThink(void) +{ + CBasePlayer* player = dynamic_cast(UTIL_FindEntityByClassname(NULL, "player")); + if (player != NULL) + { + CBaseEntity* teleportDestination = UTIL_FindEntityByTargetname(NULL, "mx2"); + if (teleportDestination != NULL) + { + // Constantly teleport the player to the changelevel + // volume in case the event was missed. + player->pev->velocity = player->pev->avelocity = g_vecZero; + UTIL_SetOrigin(player->pev, teleportDestination->pev->origin); + } + } + + pev->nextthink = gpGlobals->time + 2.0f; +} + +CBaseEntity* CChangeLevelToGrave::FindTriggerByTarget(const char* triggerTarget) +{ + return UTIL_FindEntityByString(NULL, "target", triggerTarget); +} + +CBaseEntity* CChangeLevelToGrave::FindMultiManagerByName(const char* targetname) +{ + return UTIL_FindEntityByTargetname(NULL, targetname); +} + +void CChangeLevelToGrave::AddThisEntityToMultiManagerOutputList() +{ + // Setup targetname to allow this entity's use method to be called. + pev->targetname = ALLOC_STRING("witchtograve_teleport"); + + KeyValueData kvd; + + // Tell the multimanager to call this entity in 10 seconds. + kvd.szKeyName = (char*)STRING(pev->targetname); + kvd.szValue = "10"; + + // Append new entry to multimanager. + m_multimanager->KeyValue(&kvd); +} + +void MapFixWitch::ApplyFix() +{ + AppendMultiManagerEntryToTeleportPlayerToChangeLevelAfterLevelIsDone(); + SpawnHealthAndBatteryNearHouseEntry(-446); +} + +void MapFixWitch::SpawnHealthAndBatteryNearHouseEntry(float floorZ) +{ + CreateBatteryAtPosition(Vector(1440, -240, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(1465, -239, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(1493, -238, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(1521, -237, floorZ), RANDOM_ANGLE()); +} + +void MapFixWitch::AppendMultiManagerEntryToTeleportPlayerToChangeLevelAfterLevelIsDone() +{ + CBaseEntity* changeLevelTeleporter = CBaseEntity::Create("shall_teleporttochangelevel", g_vecZero, g_vecZero, NULL); + if (changeLevelTeleporter != NULL) + { + changeLevelTeleporter->Spawn(); + } +} + +void MapFixGraveAddWeaponsAndAmmo::ApplyFix() +{ + SpawnHealthAndBatteryNextToCoffin(-446); +} + +void MapFixGraveAddWeaponsAndAmmo::SpawnHealthAndBatteryNextToCoffin(float floorZ) +{ + CreateBatteryAtPosition(Vector(2080, -1602, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(2085, -1561, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(2079, -1679, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(2082, -1639, floorZ), RANDOM_ANGLE()); +} + +void MapFixVamp::ApplyFix() +{ + SpawnHealthAtHighestTowerBeforeLongJump(2062); + CreateAndSetupTriggerToCallLift1(); + CreateAndSetupTriggerToCallLift2(); + CreateAndSetupTriggerToCallLift3(); +} + +#define LIFT_HEIGHT 562 + +void MapFixVamp::CreateAndSetupTriggerToCallLift1() +{ + CBaseToggle* trigger = dynamic_cast(CreateLiftTrigger(Vector(-384, 0, -312), g_vecZero, LIFT_HEIGHT)); + + if (trigger) + { + trigger->m_flWait = 1.0f; + trigger->pev->target = ALLOC_STRING("lift1"); + } +} + +void MapFixVamp::CreateAndSetupTriggerToCallLift2() +{ + CBaseToggle* trigger = dynamic_cast(CreateLiftTrigger(Vector(1408, 1024, 255), g_vecZero, LIFT_HEIGHT)); + + if (trigger) + { + trigger->m_flWait = 1.0f; + trigger->pev->target = ALLOC_STRING("lift2"); + } +} + +void MapFixVamp::CreateAndSetupTriggerToCallLift3() +{ + CBaseToggle* trigger = dynamic_cast(CreateLiftTrigger(Vector(-1408, 1792, 200), g_vecZero, LIFT_HEIGHT)); + + if (trigger) + { + trigger->m_flWait = 1.0f; + trigger->pev->target = ALLOC_STRING("lift3"); + } +} + +void MapFixVamp::SpawnHealthAtHighestTowerBeforeLongJump(float floorZ) +{ + CreateHealthKitAtPosition(Vector(-116, 2448, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-148, 2440, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-116, 2420, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-148, 2420, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-119, 2391, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-149, 2392, floorZ), RANDOM_ANGLE()); +} + +CBaseEntity* MapFixVamp::CreateLiftTrigger(const Vector& origin, const Vector& angles, float liftHeight) +{ + edict_t* pevCreate = CREATE_NAMED_ENTITY(MAKE_STRING("trigger_multiple")); + if (pevCreate == NULL) + { + ALERT(at_console, "** Could not create trigger_multiple for lift!**\n"); + return NULL; + } + + CBaseToggle* trigger = dynamic_cast(CBaseEntity::Instance(pevCreate)); + + if (trigger == NULL) + { + ALERT(at_console, "** Could not retrieve trigger_multiple instance!**\n"); + return NULL; + } + + trigger->pev->angles = angles; + DispatchSpawn(trigger->edict()); + + UTIL_SetOrigin(trigger->pev, origin); + UTIL_SetSize(trigger->pev, Vector(-64, -64, 0), Vector( 64, 64, liftHeight ) ); + + return trigger; +} + +void MapFixWoodsAddWeaponsAndAmmo::SpawnHealth(float floorZ) +{ + CreateWeaponCrowbarAtPosition(Vector(-2515, -1190, floorZ), RANDOM_ANGLE()); + + CreateHealthKitAtPosition(Vector(-2809, 2575, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(-2845, 2578, floorZ), RANDOM_ANGLE()); + + CreateHealthKitAtPosition(Vector(1469, 2862, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(1452, 2885, floorZ), RANDOM_ANGLE()); + + CreateHealthKitAtPosition(Vector(-2829, -4, floorZ), RANDOM_ANGLE()); + + CreateHealthKitAtPosition(Vector(1971, -2564, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(1966, -2539, floorZ), RANDOM_ANGLE()); +} + +void MapFixHellAddWeaponsAndAmmo::ApplyFix() +{ + SpawnHealthAmmoWeaponsAtLightNearSpawn(-2558); + SpawnHealthAmmoWeaponsAtPositionBeforeFinalBattle(-2524); +} + +void MapFixHellAddWeaponsAndAmmo::SpawnHealthAmmoWeaponsAtLightNearSpawn(float floorZ) +{ + CreateWeaponMP5AtPosition(Vector(1397, 1263, floorZ), RANDOM_ANGLE()); + CreateWeaponShotgunAtPosition(Vector(1405, 1209, floorZ), RANDOM_ANGLE()); + CreateWeaponCrossbowAtPosition(Vector(1323, 1271, floorZ), RANDOM_ANGLE(), CrossbowPlacement::Realistic); + CreateWeaponCrowbarAtPosition(Vector(1345, 1237, floorZ), RANDOM_ANGLE()); + CreateMP5AmmoAtPosition(Vector(1418, 1260, floorZ), RANDOM_ANGLE()); + CreateShotgunAmmoAtPosition(Vector(1412, 1301, floorZ), RANDOM_ANGLE()); + CreateCrossbowAmmoAtPosition(Vector(1337, 1298, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(1345, 1205, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(1343, 1184, floorZ), RANDOM_ANGLE()); +} + +void MapFixHellAddWeaponsAndAmmo::SpawnHealthAmmoWeaponsAtPositionBeforeFinalBattle(float floorZ) +{ + CreateWeapon357AtPosition(Vector(2469, -1492, floorZ), RANDOM_ANGLE()); + Create357AmmoAtPosition(Vector(2494, -1495, floorZ), RANDOM_ANGLE()); + CreateMP5GrenadeAmmoAtPosition(Vector(2436, -1470, floorZ), RANDOM_ANGLE()); + CreateMP5GrenadeAmmoAtPosition(Vector(2457, -1473, floorZ), RANDOM_ANGLE()); + Create9mmAmmoBoxAtPosition(Vector(2495, -1445, floorZ), RANDOM_ANGLE()); + + CreateHealthKitAtPosition(Vector(2398, -1451, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(2447, -1440, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(2405, -1399, floorZ), RANDOM_ANGLE()); + CreateHealthKitAtPosition(Vector(2443, -1388, floorZ), RANDOM_ANGLE()); + + CreateBatteryAtPosition(Vector(2420, -1434, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(2470, -1411, floorZ), RANDOM_ANGLE()); + CreateBatteryAtPosition(Vector(2479, -1470, floorZ), RANDOM_ANGLE()); +} + +MapFixPatchSpawnPosition* MapFixes::GetPatchSpawnPositionSingleton() +{ + static MapFixPatchSpawnPosition singleton; + return &singleton; +} + +MapFixPatchAddWeaponsAndAmmo* MapFixes::GetPatchAddWeaponsAndAmmoSingleton() +{ + static MapFixPatchAddWeaponsAndAmmo singleton; + return &singleton; +} + +MapFixCornAddWeaponsAndAmmo* MapFixes::GetCornAddWeaponsAndAmmoSingleton() +{ + static MapFixCornAddWeaponsAndAmmo singleton; + return &singleton; +} + +MapFixShipAddWeaponsAndAmmo* MapFixes::GetShipAddWeaponsAndAmmoSingleton() +{ + static MapFixShipAddWeaponsAndAmmo singleton; + return &singleton; +} + +MapFixWoodsAddWeaponsAndAmmo* MapFixes::GetWoodsAddWeaponsAndAmmoSingleton() +{ + static MapFixWoodsAddWeaponsAndAmmo singleton; + return &singleton; +} + +MapFixWitch* MapFixes::GetWitchSingleton() +{ + static MapFixWitch singleton; + return &singleton; +} + +MapFixGraveAddWeaponsAndAmmo* MapFixes::GetGraveAddWeaponsAndAmmoSingleton() +{ + static MapFixGraveAddWeaponsAndAmmo singleton; + return &singleton; +} + +MapFixVamp* MapFixes::GetVampSingleton() +{ + static MapFixVamp singleton; + return &singleton; +} + +MapFixHellAddWeaponsAndAmmo* MapFixes::GetHellAddWeaponsAndAmmoSingleton() +{ + static MapFixHellAddWeaponsAndAmmo singleton; + return &singleton; +} + +void MapFixes::ApplyMapFixPatch() +{ + GetPatchAddWeaponsAndAmmoSingleton()->ApplyFix(); +} + +void MapFixes::ApplyMapFixCorn() +{ + GetCornAddWeaponsAndAmmoSingleton()->ApplyFix(); +} + +void MapFixes::ApplyMapFixShip() +{ + GetShipAddWeaponsAndAmmoSingleton()->ApplyFix(); +} + +void MapFixes::ApplyMapFixWoods() +{ + GetWoodsAddWeaponsAndAmmoSingleton()->ApplyFix(); +} + +void MapFixes::ApplyMapFixWitch() +{ + GetWitchSingleton()->ApplyFix(); +} + +void MapFixes::ApplyMapFixGrave() +{ + GetGraveAddWeaponsAndAmmoSingleton()->ApplyFix(); +} + +void MapFixes::ApplyMapFixVamp() +{ + GetVampSingleton()->ApplyFix(); +} + +void MapFixes::ApplyMapFixHell() +{ + GetHellAddWeaponsAndAmmoSingleton()->ApplyFix(); +} + +static MapFixes* GetMapFixesSingleton() +{ + static MapFixes singleton; + return &singleton; +} + +void MapFixes_ApplyAllPossibleFixes() +{ + if (IsCurrentMap("corn")) + { + GetMapFixesSingleton()->ApplyMapFixCorn(); + } + else if (IsCurrentMap("grave")) + { + GetMapFixesSingleton()->ApplyMapFixGrave(); + } + else if (IsCurrentMap("hell")) + { + GetMapFixesSingleton()->ApplyMapFixHell(); + } + else if (IsCurrentMap("patch")) + { + GetMapFixesSingleton()->ApplyMapFixPatch(); + } + else if (IsCurrentMap("ship")) + { + GetMapFixesSingleton()->ApplyMapFixShip(); + } + else if (IsCurrentMap("vamp")) + { + GetMapFixesSingleton()->ApplyMapFixVamp(); + } + else if (IsCurrentMap("witch")) + { + GetMapFixesSingleton()->ApplyMapFixWitch(); + } + else if (IsCurrentMap("woods")) + { + GetMapFixesSingleton()->ApplyMapFixWoods(); + } +} + +#endif // defined ( SHALL_MAPFIXES ) \ No newline at end of file diff --git a/dlls/halloween/shall_map_fixes.h b/dlls/halloween/shall_map_fixes.h new file mode 100644 index 00000000..bb2c7f72 --- /dev/null +++ b/dlls/halloween/shall_map_fixes.h @@ -0,0 +1,21 @@ +/*** +* +* Copyright (c) 1996-2001, 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 SHALL_MAPFIXES_H__ +#define SHALL_MAPFIXES_H__ + +void MapFixes_ApplyAllPossibleFixes(); + +#endif // SHALL_MAPFIXES_H__ \ No newline at end of file diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index c2bbd7f9..0e4c95ae 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -61,8 +61,21 @@ void CHandGrenade::Precache( void ) int CHandGrenade::GetItemInfo( ItemInfo *p ) { p->pszName = STRING( pev->classname ); +#if defined( CLIENT_DLL ) p->pszAmmo1 = "Hand Grenade"; p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY; +#else + if( HasInfiniteAmmo() ) + { + p->pszAmmo1 = NULL; + p->iMaxAmmo1 = -1; + } + else + { + p->pszAmmo1 = "Hand Grenade"; + p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY; + } +#endif// defined(CLIENT_DLL) p->pszAmmo2 = NULL; p->iMaxAmmo2 = -1; p->iMaxClip = WEAPON_NOCLIP; @@ -71,7 +84,10 @@ int CHandGrenade::GetItemInfo( ItemInfo *p ) p->iId = m_iId = WEAPON_HANDGRENADE; p->iWeight = HANDGRENADE_WEIGHT; p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - +#if !defined(CLIENT_DLL) + if( HasInfiniteAmmo() ) + p->iFlags |= ITEM_FLAG_NOAUTORELOAD; +#endif return 1; } @@ -91,7 +107,11 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; +#if defined(CLIENT_DLL) if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) +#else + if( IsUseable() ) +#endif // defined( CLIENT_DLL ) { SendWeaponAnim( HANDGRENADE_HOLSTER ); } @@ -113,7 +133,11 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ ) void CHandGrenade::PrimaryAttack() { +#if defined(CLIENT_DLL) if( !m_flStartThrow && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 ) +#else + if( !m_flStartThrow && IsUseable() ) +#endif // defined(CLIENT_DLL) { m_flStartThrow = gpGlobals->time; m_flReleaseThrow = 0; @@ -177,10 +201,16 @@ void CHandGrenade::WeaponIdle( void ) m_flStartThrow = 0; m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - +#if defined(CLIENT_DLL) m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) +#else + if( !HasInfiniteAmmo() ) + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; + + if( !IsUseable() ) +#endif // defined(CLIENT_DLL) { // just threw last grenade // set attack times in the future, and weapon idle in the future so we can see the whole throw @@ -194,7 +224,11 @@ void CHandGrenade::WeaponIdle( void ) // we've finished the throw, restart. m_flStartThrow = 0; +#if defined(CLIENT_DLL) if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) +#else + if( IsUseable() ) +#endif // defined(CLIENT_DLL) { SendWeaponAnim( HANDGRENADE_DRAW ); } @@ -209,7 +243,11 @@ void CHandGrenade::WeaponIdle( void ) return; } +#if defined(CLIENT_DLL) if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) +#else + if( IsUseable() ) +#endif // defined(CLIENT_DLL) { int iAnim; float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); @@ -227,3 +265,13 @@ void CHandGrenade::WeaponIdle( void ) SendWeaponAnim( iAnim ); } } + +BOOL CHandGrenade::HasInfiniteAmmo() +{ + return IsCurrentMap( "witch" ); +} + +BOOL CHandGrenade::IsUseable() +{ + return HasInfiniteAmmo() || m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0; +} diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp index 60e03c10..3f6c5d8d 100644 --- a/dlls/headcrab.cpp +++ b/dlls/headcrab.cpp @@ -282,16 +282,19 @@ void CHeadCrab::Spawn() Precache(); SET_MODEL( ENT( pev ), "models/headcrab.mdl" ); - UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) ); + // Vampire monsters use human hull size. + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; + // Vampires use red blood. + m_bloodColor = BLOOD_COLOR_RED; 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 ) + // Allow vampires to see 360 degrees (+180/-180) + m_flFieldOfView = -1.0f;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_MonsterState = MONSTERSTATE_NONE; MonsterInit(); diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index 4cb85c2c..34b66a27 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -144,6 +144,7 @@ public: void Shotgun( void ); void PrescheduleThink( void ); void GibMonster( void ); + BOOL ShouldGibMonster( int iGib ); void SpeakSentence( void ); int Save( CSave &save ); @@ -159,6 +160,7 @@ public: BOOL FOkToSpeak( void ); void JustSpoke( void ); + BOOL IsWhiteLadySpirit(); CUSTOM_SCHEDULES static TYPEDESCRIPTION m_SaveData[]; @@ -311,6 +313,12 @@ void CHGrunt::GibMonster( void ) } } + if( IsWhiteLadySpirit() ) + { + // White lady spirits should not be gibbed. + FadeMonster(); + return; + } CBaseMonster::GibMonster(); } @@ -332,6 +340,10 @@ int CHGrunt::ISoundMask( void ) //========================================================= BOOL CHGrunt::FOkToSpeak( void ) { + // Scarecrows; werewolves; white Ladies; hell minions; + // should not use team radio. + return FALSE; + // if someone else is talking, don't speak if( gpGlobals->time <= CTalkMonster::g_talkWaitTime ) return FALSE; @@ -444,6 +456,9 @@ BOOL CHGrunt::CheckMeleeAttack1( float flDot, float flDist ) //========================================================= BOOL CHGrunt::CheckRangeAttack1( float flDot, float flDist ) { + // Scarecrows; werewolves; white Ladies; hell minions; + // cannot use range attacks. + return FALSE; if( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) { TraceResult tr; @@ -474,6 +489,9 @@ BOOL CHGrunt::CheckRangeAttack1( float flDot, float flDist ) //========================================================= BOOL CHGrunt::CheckRangeAttack2( float flDot, float flDist ) { + // Scarecrows; werewolves; white Ladies; hell minions; + // cannot use range attacks. + return FALSE; if( !FBitSet( pev->weapons, ( HGRUNT_HANDGRENADE | HGRUNT_GRENADELAUNCHER ) ) ) { return FALSE; @@ -600,23 +618,8 @@ BOOL CHGrunt::CheckRangeAttack2( float flDot, float flDist ) //========================================================= 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; - } + // Scarecrows; werewolves; white Ladies; hell minions; + // do not wear armors or helmets. CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); } @@ -980,7 +983,9 @@ void CHGrunt::Spawn() 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 ) + // Allow Scarecrows; werewolves; white Ladies; hell minions; + // are allowed to see 360 degrees (+180/-180). + m_flFieldOfView = -1.0f;// 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; @@ -1881,7 +1886,7 @@ void CHGrunt::SetActivity( Activity NewActivity ) iSequence = LookupSequence( "launchgrenade" ); } break; - case ACT_RUN: +/* case ACT_RUN: if( pev->health <= HGRUNT_LIMP_HEALTH ) { // limp! @@ -1909,7 +1914,7 @@ void CHGrunt::SetActivity( Activity NewActivity ) NewActivity = ACT_IDLE_ANGRY; } iSequence = LookupActivity( NewActivity ); - break; + break;*/ default: iSequence = LookupActivity( NewActivity ); break; @@ -1942,244 +1947,41 @@ void CHGrunt::SetActivity( Activity NewActivity ) //========================================================= 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( 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 ); - } + return CSquadMonster::GetSchedule(); } - // 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: + case MONSTERSTATE_IDLE: { - // 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 ); - } + return GetScheduleOfType( SCHED_IDLE_STAND ); } break; - default: + case MONSTERSTATE_ALERT: + { + return GetScheduleOfType( SCHED_ALERT_STAND ); + } break; + case MONSTERSTATE_COMBAT: + { + if( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions( bits_COND_ENEMY_OCCLUDED ) ) + { + 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 ); + } + default: + return CSquadMonster::GetSchedule(); } // no special cases here, call the base class @@ -2332,6 +2134,14 @@ Schedule_t *CHGrunt::GetScheduleOfType( int Type ) { return &slGruntRepelLand[0]; } + // Scarecrows; werewolves; white Ladies; hell minions; + // should not use flinch schedule. + case SCHED_ALERT_SMALL_FLINCH: + case SCHED_ALERT_BIG_FLINCH: + case SCHED_SMALL_FLINCH: + { + return GetScheduleOfType( SCHED_COMBAT_STAND ); + } default: { return CSquadMonster::GetScheduleOfType( Type ); @@ -2339,6 +2149,21 @@ Schedule_t *CHGrunt::GetScheduleOfType( int Type ) } } +BOOL CHGrunt::ShouldGibMonster( int iGib ) +{ + // Gibbing is allowed if the current model + // is not a white lady (spirit). + if( IsWhiteLadySpirit() ) + return FALSE; + + return CSquadMonster::ShouldGibMonster( iGib ); +} + +BOOL CHGrunt::IsWhiteLadySpirit() +{ + return GetBodygroup( HEAD_GROUP ) == HEAD_GRUNT; +} + //========================================================= // CHGruntRepel - when triggered, spawns a monster_human_grunt // repelling down a line. diff --git a/dlls/houndeye.cpp b/dlls/houndeye.cpp index cedee258..76495ade 100644 --- a/dlls/houndeye.cpp +++ b/dlls/houndeye.cpp @@ -319,7 +319,8 @@ void CHoundeye::Spawn() Precache(); SET_MODEL( ENT( pev ), "models/houndeye.mdl" ); - UTIL_SetSize( pev, Vector( -16, -16, 0 ), Vector( 16, 16, 36 ) ); + // Aliens should use human hull. + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; @@ -327,7 +328,8 @@ void CHoundeye::Spawn() 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 ) + // Allow martians to see 360 degrees (+180/-180) + m_flFieldOfView = -1.0f;// 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; diff --git a/dlls/islave.cpp b/dlls/islave.cpp index b516c09b..d84a5c89 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -513,7 +513,8 @@ void CISlave::Spawn() pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; + // Witches should use red blood color. + m_bloodColor = BLOOD_COLOR_RED; pev->effects = 0; pev->health = gSkillData.slaveHealth; pev->view_ofs = Vector( 0, 0, 64 );// position of the eyes relative to monster's origin. diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index a9796a80..d7525d06 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -2168,12 +2168,12 @@ int CBaseMonster::IRelationship( CBaseEntity *pTarget ) /*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL }, /*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL }, /*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO }, - /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO }, - /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, + /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_NO ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_HT, R_NO, R_NO }, + /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, /*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, + /*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, /*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO }, /*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO }, /*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL }, diff --git a/dlls/player.cpp b/dlls/player.cpp index 38038b36..3c44d873 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -36,6 +36,7 @@ #include "game.h" #include "pm_shared.h" #include "hltv.h" +#include "shall_map_fixes.h" // #define DUCKFIX @@ -119,6 +120,8 @@ TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ), DEFINE_FIELD( CBasePlayer, m_iFOV, FIELD_INTEGER ), + DEFINE_FIELD( CBasePlayer, m_bWasTouchingTriggerPushBeforeFinalBattle, FIELD_BOOLEAN ), + //DEFINE_FIELD( CBasePlayer, m_fDeadTime, FIELD_FLOAT ), // only used in multiplayer games //DEFINE_FIELD( CBasePlayer, m_fGameHUDInitialized, FIELD_INTEGER ), // only used in multiplayer games //DEFINE_FIELD( CBasePlayer, m_flStopExtraSoundTime, FIELD_TIME ), @@ -429,6 +432,14 @@ void CBasePlayer::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { + // If players are descending to the final battle, + // prevent them from taking damage. + if( m_bWasTouchingTriggerPushBeforeFinalBattle ) + { + m_bWasTouchingTriggerPushBeforeFinalBattle = FALSE; + return 0; + } + // have suit diagnose the problem - ie: report damage type int bitsDamage = bitsDamageType; int ffound = TRUE; @@ -2865,6 +2876,12 @@ void CBasePlayer::Spawn( void ) m_flNextChatTime = gpGlobals->time; + // On 2001 version level, give the the suit to player. + if( IsCurrentMap( "trick" ) ) + pev->weapons |= ( 1 << WEAPON_SUIT ); + + m_bWasTouchingTriggerPushBeforeFinalBattle = FALSE; + g_pGameRules->PlayerSpawn( this ); } diff --git a/dlls/player.h b/dlls/player.h index 54e7fa85..fc1f9228 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -196,6 +196,8 @@ public: char m_szTeamName[TEAM_NAME_LENGTH]; + BOOL m_bWasTouchingTriggerPushBeforeFinalBattle; + virtual void Spawn( void ); void Pain( void ); diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index bfe17ed1..1bba0162 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -50,7 +50,8 @@ class CSqueakGrenade : public CGrenade int Classify( void ); void EXPORT SuperBounceTouch( CBaseEntity *pOther ); void EXPORT HuntThink( void ); - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } + // Bats should use red blood color. + int BloodColor( void ) { return BLOOD_COLOR_RED; } void Killed( entvars_t *pevAttacker, int iGib ); void GibMonster( void ); diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 8171a195..20eea6f7 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -1824,6 +1824,14 @@ void CTriggerPush::Touch( CBaseEntity *pOther ) pevToucher->flags |= FL_BASEVELOCITY; //ALERT( at_console, "Vel %f, base %f\n", pevToucher->velocity.z, pevToucher->basevelocity.z ); + + // Use this variable to prevent players from + // taking damage once they hit the floor on + // final battle. + if( FStrEq( STRING( gpGlobals->mapname ), "hell" ) && pOther->IsPlayer() ) + { + ( (CBasePlayer*)pOther )->m_bWasTouchingTriggerPushBeforeFinalBattle = TRUE; + } } } } diff --git a/dlls/util.cpp b/dlls/util.cpp index 68ba30cd..7108839c 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -31,6 +31,54 @@ #include "weapons.h" #include "gamerules.h" +BOOL IsCurrentMap( const char* mapname ) +{ + return FStrEq( STRING( gpGlobals->mapname ), mapname ); +} + +BOOL IsCurrentMapPartOfCampaignOrTraining() +{ + static const char* shallModMaps[] = + { + "beach", + "corn", + "grave", + "hall_trick02", + "hall_vamp", + "hell", + "grave", + "htest", + "patch", + "ship", + "sorry", + "styx", + "trick", + "trick02", + "vamp", + "witch", + "woods", + }; + + BOOL foundMap = FALSE; + for( int i = 0; !foundMap && i < ARRAYSIZE( shallModMaps ); i++ ) + { + if( IsCurrentMap( shallModMaps[i] ) ) + foundMap = TRUE; + } + + return foundMap; +} + +#define IDEAL_RENDER_DISTANCE_FOR_SHALL_MOD 16384 + +float GetIdealRenderDistance( float defaultDistance ) +{ + if( IsCurrentMapPartOfCampaignOrTraining() ) + return IDEAL_RENDER_DISTANCE_FOR_SHALL_MOD; + + return defaultDistance; +} + float UTIL_WeaponTimeBase( void ) { #if defined( CLIENT_WEAPONS ) diff --git a/dlls/util.h b/dlls/util.h index 2ffe536e..02abd3aa 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -575,3 +575,7 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); float UTIL_WeaponTimeBase( void ); + +BOOL IsCurrentMap( const char* mapname ); +BOOL IsCurrentMapPartOfCampaignOrTraining(); +float GetIdealRenderDistance( float defaultDistance ); diff --git a/dlls/weapons.h b/dlls/weapons.h index f48767c8..e1c71562 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -904,6 +904,9 @@ public: return FALSE; #endif } + + BOOL HasInfiniteAmmo(); + BOOL IsUseable(); }; class CSatchel : public CBasePlayerWeapon diff --git a/dlls/world.cpp b/dlls/world.cpp index 3b9a1f1e..6089ea36 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -33,6 +33,7 @@ #include "weapons.h" #include "gamerules.h" #include "teamplay_gamerules.h" +#include "shall_map_fixes.h" #include "physcallback.h" extern CGraph WorldGraph; @@ -456,6 +457,7 @@ void CWorld::Spawn( void ) { g_fGameOver = FALSE; Precache(); + MapFixes_ApplyAllPossibleFixes(); } void CWorld::Precache( void ) @@ -685,7 +687,10 @@ void CWorld::KeyValue( KeyValueData *pkvd ) } else if( FStrEq( pkvd->szKeyName, "MaxRange" ) ) { - pev->speed = atof( pkvd->szValue ); + // Since this mod features large levels, + // therefore adjust the view distance to + // render a farer distance. + pev->speed = GetIdealRenderDistance( atof( pkvd->szValue ) ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "chaptertitle" ) ) diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp index 96f032e6..d8db93aa 100644 --- a/dlls/zombie.cpp +++ b/dlls/zombie.cpp @@ -61,6 +61,8 @@ public: 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 ); + BOOL ShouldGibMonster(int iGib) { return FALSE; } // Reapers should not gib. + void GibMonster( void ); }; LINK_ENTITY_TO_CLASS( monster_zombie, CZombie ) @@ -267,11 +269,13 @@ void CZombie::Spawn() Precache(); SET_MODEL( ENT( pev ), "models/zombie.mdl" ); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); + // Reapers have a taller model. + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN + Vector( -8, -8, 0 ), VEC_HUMAN_HULL_MAX + Vector( 8, 8, 48 ) ); pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; + // Reapers should use red blood color. + m_bloodColor = BLOOD_COLOR_RED; 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 ) @@ -336,3 +340,8 @@ int CZombie::IgnoreConditions( void ) return iIgnore; } + +void CZombie::GibMonster( void ) +{ + FadeMonster(); +}