diff --git a/.travis.yml b/.travis.yml index 01d2ba27..fb18612f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,20 @@ compiler: os: - linux - osx -sudo: true +addons: + apt: + packages: + - gcc-multilib + - g++-multilib before_script: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install gcc-multilib g++-multilib; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "gcc" ]]; then sudo apt-get install mingw-w64-i686-dev binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686; fi + - curl http://libsdl.org/release/SDL2-devel-2.0.7-mingw.tar.gz | tar xzf - + - mv SDL2-2.0.7/i686-w64-mingw32/include/SDL2 cl_dll/ script: - mkdir -p build && cd build - - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=0 && make -j3 && rm -rf * - - cmake ../ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VOICEMGR=1 && make -j3 && rm -rf * - - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "gcc" ]]; then cd ..; mkdir build-mingw; cd build-mingw; cmake ../ -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_C_COMPILER=i686-w64-mingw32-gcc -DCMAKE_CXX_COMPILER=i686-w64-mingw32-g++ && make -j3; fi + - cmake ../ -DCMAKE_C_FLAGS="-O2 -pipe -DNDEBUG -fvisibility=hidden -fomit-frame-pointer" -DCMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined -Wl,--strip-all" -DGOLDSOURCE_SUPPORT=1 -DUSE_VOICEMGR=0 && make -j3 + - mkdir -p $TRAVIS_BRANCH-$TRAVIS_OS_NAME-$CC/cl_dlls + - mkdir -p $TRAVIS_BRANCH-$TRAVIS_OS_NAME-$CC/dlls + - cp cl_dll/client.* $TRAVIS_BRANCH-$TRAVIS_OS_NAME-$CC/cl_dlls + - cp dlls/hl.* $TRAVIS_BRANCH-$TRAVIS_OS_NAME-$CC/dlls + - tar -J -cf $TRAVIS_BRANCH-$TRAVIS_OS_NAME-$CC.txz $TRAVIS_BRANCH-$TRAVIS_OS_NAME-$CC + - curl --upload-file $TRAVIS_BRANCH-$TRAVIS_OS_NAME-$CC.txz https://transfer.sh/$TRAVIS_BRANCH-$TRAVIS_OS_NAME-$CC.txz diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index df6130ed..16849791 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -92,7 +92,7 @@ SRCS+=./input_xash3d.cpp SRCS+=./scoreboard.cpp SRCS+=./MOTD.cpp INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls -I../utils/false_vgui/include -DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w -D_snprintf=snprintf +DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -DCROWBAR_IDLE_ANIM -w -D_snprintf=snprintf LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \ $(LOCAL_PATH)/../common \ diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index cde35d14..072511e2 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -31,7 +31,7 @@ if(HAVE_TGMATH_H) add_definitions(-DHAVE_TGMATH_H) endif() -add_definitions(-DCLIENT_WEAPONS -DCLIENT_DLL) +add_definitions(-DCLIENT_WEAPONS -DCLIENT_DLL -DCROWBAR_IDLE_ANIM -DCROWBAR_FIX_RAPID_CROWBAR -DCROWBAR_DELAY_FIX) if(NOT MSVC) add_compile_options(-fno-exceptions) # GCC/Clang flag diff --git a/cl_dll/hud.h b/cl_dll/hud.h index f3e1ed85..129067b1 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -22,8 +22,8 @@ #pragma once #ifndef HUD_H #define HUD_H -#define RGB_YELLOWISH 0x00FFA000 //255,160,0 -#define RGB_REDISH 0x00FF1010 //255,160,0 +#define RGB_YELLOWISH 0x005F5FFF //95,95,255 +#define RGB_REDISH 0x00FF1010 //255,16,16 #define RGB_GREENISH 0x0000A000 //0,160,0 #include "wrect.h" diff --git a/dlls/Android.mk b/dlls/Android.mk index 1dc79616..34505c4b 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -14,7 +14,7 @@ LOCAL_MODULE_FILENAME = libserver_hardfp endif LOCAL_CFLAGS += -D_LINUX -DCLIENT_WEAPONS -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf \ - -fno-exceptions -DNO_VOICEGAMEMGR -w + -fno-exceptions -DNO_VOICEGAMEMGR -DCROWBAR_IDLE_ANIM -w LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index 67a34e11..49ddf44e 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -31,7 +31,7 @@ if(HAVE_TGMATH_H) add_definitions(-DHAVE_TGMATH_H) endif() -add_definitions(-DCLIENT_WEAPONS) +add_definitions(-DCLIENT_WEAPONS -DCROWBAR_IDLE_ANIM -DCROWBAR_FIX_RAPID_CROWBAR -DCROWBAR_DELAY_FIX) if(NOT MSVC) add_compile_options(-fno-exceptions) # GCC/Clang flag diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index ddcb15d8..5d8fd6ed 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -337,7 +337,7 @@ int CCrowbar::Swing( int fFirst ) SetThink( &CCrowbar::Smack ); pev->nextthink = UTIL_WeaponTimeBase() + 0.2f; #endif -#if CROWBAR_DELAY_FIX +#ifdef CROWBAR_DELAY_FIX m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25f; #else m_flNextPrimaryAttack = GetNextAttackDelay( 0.25f ); diff --git a/dlls/effects.cpp b/dlls/effects.cpp index e6ad257f..dceb6140 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -365,7 +365,7 @@ public: void Zap( const Vector &vecSrc, const Vector &vecDest ); void EXPORT StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - + static CLightning *LightningCreate( const char *pSpriteName, int width ); inline BOOL ServerSide( void ) { if( m_life == 0 && !( pev->spawnflags & SF_BEAM_RING ) ) @@ -912,6 +912,19 @@ void CLightning::BeamUpdateVars( void ) SetFlags( BEAM_FSHADEOUT ); } +CLightning *CLightning::LightningCreate( const char *pSpriteName, int width ) +{ + // Create a new entity with CLightning private data + CLightning *pBeam = GetClassPtr( (CLightning *)NULL ); + + pBeam->BeamInit( pSpriteName, width ); + pBeam->pev->classname = MAKE_STRING( "env_beam" ); + pBeam->m_iszSpriteName = MAKE_STRING( pSpriteName ); + pBeam->m_boltWidth = width; + + return pBeam; +} + LINK_ENTITY_TO_CLASS( env_laser, CLaser ) TYPEDESCRIPTION CLaser::m_SaveData[] = @@ -2233,3 +2246,233 @@ void CItemSoda::CanTouch( CBaseEntity *pOther ) SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } + +//========================================================= +// env_warpball +//========================================================= +#define SF_REMOVE_ON_FIRE 0x0001 +#define SF_KILL_CENTER 0x0002 + +class CWarpBall : public CBaseEntity +{ +public: + void Precache(); + void Spawn(); + void EXPORT BallThink(); + void KeyValue( KeyValueData *pkvd ); + void EXPORT WarpBallUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + static CWarpBall *CreateWarpBall( const Vector &p_VecOrigin ); + + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; +// private: + CLightning *m_pBeams; + CSprite *m_pSprite; + // int m_iBeams; + float m_flLastTime; + float m_flMaxFrame; + float m_flBeamRadius; + string_t m_iszWarpTarget; + float m_flWarpStart; + float m_flDamageDelay; + // float m_flTargetDelay; + BOOL m_fPlaying; + BOOL m_fDamageApplied; + // BOOL m_fBeamsCleared; +}; + +LINK_ENTITY_TO_CLASS( env_warpball, CWarpBall ) + +TYPEDESCRIPTION CWarpBall::m_SaveData[] = +{ + // DEFINE_FIELD( CWarpBall, m_iBeams, FIELD_INTEGER ), + DEFINE_FIELD( CWarpBall, m_flLastTime, FIELD_FLOAT ), + DEFINE_FIELD( CWarpBall, m_flMaxFrame, FIELD_FLOAT ), + DEFINE_FIELD( CWarpBall, m_flBeamRadius, FIELD_FLOAT ), + DEFINE_FIELD( CWarpBall, m_iszWarpTarget, FIELD_STRING ), + DEFINE_FIELD( CWarpBall, m_flWarpStart, FIELD_FLOAT ), + DEFINE_FIELD( CWarpBall, m_flDamageDelay, FIELD_FLOAT ), + // DEFINE_FIELD( CWarpBall, m_flTargetDelay, FIELD_FLOAT ), + DEFINE_FIELD( CWarpBall, m_fPlaying, FIELD_BOOLEAN ), + DEFINE_FIELD( CWarpBall, m_fDamageApplied, FIELD_BOOLEAN ), + // DEFINE_FIELD( CWarpBall, m_fBeamsCleared, FIELD_BOOLEAN ), + DEFINE_FIELD( CWarpBall, m_pBeams, FIELD_CLASSPTR ), + DEFINE_FIELD( CWarpBall, m_pSprite, FIELD_CLASSPTR ), +}; + +IMPLEMENT_SAVERESTORE( CWarpBall, CBaseEntity ) + +void CWarpBall::KeyValue( KeyValueData *pkvd ) +{ + if( FStrEq( pkvd->szKeyName, "radius" ) ) + { + m_flBeamRadius = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "warp_target" ) ) + { + m_iszWarpTarget = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "damage_delay" ) ) + { + m_flDamageDelay = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +void CWarpBall::Spawn() +{ + Precache(); + pev->movetype = MOVETYPE_NONE; + pev->solid = SOLID_NOT; + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); + pev->rendermode = kRenderGlow; + pev->renderamt = 255; + pev->renderfx = kRenderFxNoDissipation; + pev->framerate = 10; + m_pSprite = CSprite::SpriteCreate( "sprites/Fexplo1.spr", pev->origin, 1 ); + m_pSprite->TurnOff(); + SetUse( &CWarpBall::WarpBallUse ); +} + +void CWarpBall::Precache() +{ + PRECACHE_MODEL( "sprites/lgtning.spr" ); + PRECACHE_MODEL( "sprites/Fexplo1.spr" ); + PRECACHE_MODEL( "sprites/XFlare1.spr" ); + PRECACHE_SOUND( "debris/alien_teleport.wav" ); +} + +void CWarpBall::WarpBallUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + CBaseEntity *pEntity; + int r = 77, g = 210, b = 130; + + if( m_fPlaying ) + return; + + if( m_iszWarpTarget ) + { + pEntity = UTIL_FindEntityByTargetname( NULL, STRING( m_iszWarpTarget ) ); + if( pEntity ) + UTIL_SetOrigin( pev, pEntity->pev->origin ); + } + + SET_MODEL( ENT( pev ), "sprites/XFlare1.spr" ); + m_flMaxFrame = (float)MODEL_FRAMES( pev->modelindex ) - 1; + + pev->rendercolor = Vector( r, g, b ); + pev->scale = 1.2; + pev->frame = 0; + + if( m_pSprite ) + { + m_pSprite->SetTransparency( kRenderGlow, r, g, b, 255, kRenderFxNoDissipation ); + m_pSprite->pev->scale = 1.0; + m_pSprite->TurnOn(); + } + + if( !m_pBeams ) + { + m_pBeams = CLightning::LightningCreate( "sprites/lgtning.spr", 18 ); + + if( m_pBeams ) + { + UTIL_SetOrigin( m_pBeams->pev, pev->origin ); + m_pBeams->m_restrike = -0.5; + m_pBeams->SetColor( 0, 255, 0 ); + m_pBeams->m_noiseAmplitude = 65; + m_pBeams->m_life = 0.5; + m_pBeams->m_radius = m_flBeamRadius; + m_pBeams->m_iszStartEntity = pev->targetname; + SetBits( m_pBeams->pev->spawnflags, SF_BEAM_TOGGLE | SF_BEAM_SPARKEND ); + m_pBeams->BeamUpdateVars(); + } + } + + if( m_pBeams ) + { + m_pBeams->Spawn(); + m_pBeams->pev->solid = SOLID_NOT; + m_pBeams->SetThink( &CLightning::StrikeThink ); + m_pBeams->pev->nextthink = gpGlobals->time + 0.1; + } + + SetThink( &CWarpBall::BallThink ); + pev->nextthink = gpGlobals->time + 0.1; + + m_flLastTime = gpGlobals->time; + // m_fBeamsCleared = FALSE; + m_fPlaying = TRUE; + + if( !m_flDamageDelay ) + { + RadiusDamage( pev->origin, pev, pev, 300.0, 48.0, CLASS_NONE, DMG_SHOCK ); + m_fDamageApplied = TRUE; + } + else + { + m_fDamageApplied = FALSE; + } + + SUB_UseTargets( this, USE_TOGGLE, 0.0 ); + UTIL_ScreenShake( pev->origin, 4.0, 100.0, 2.0, 1000.0 ); + m_flWarpStart = gpGlobals->time; + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "debris/alien_teleport.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); +} + +void CWarpBall::BallThink( void ) +{ + pev->frame = ( gpGlobals->time - m_flLastTime ) * pev->framerate + pev->frame; + if( pev->frame > m_flMaxFrame ) + { + SET_MODEL( ENT( pev ), "" ); + SetThink( NULL ); + if( pev->spawnflags & SF_REMOVE_ON_FIRE ) + { + UTIL_Remove( m_pSprite ); + UTIL_Remove( m_pBeams ); + UTIL_Remove( this ); + } + + if( m_pSprite ) + m_pSprite->TurnOff(); + m_fPlaying = 0; + } + else + { + if( ( pev->spawnflags & SF_KILL_CENTER ) && !m_fDamageApplied + && gpGlobals->time - m_flWarpStart >= m_flDamageDelay ) + { + RadiusDamage( pev->origin, pev, pev, 300.0, 48.0, CLASS_NONE, DMG_SHOCK ); + m_fDamageApplied = TRUE; + } + + if( m_pBeams ) + { + if( pev->frame >= m_flMaxFrame - 4.0 ) + { + m_pBeams->SetThink( NULL ); + m_pBeams->pev->nextthink = gpGlobals->time; + } + } + + pev->nextthink = gpGlobals->time + 0.1; + m_flLastTime = gpGlobals->time; + } +} + +CWarpBall *CWarpBall::CreateWarpBall( const Vector &p_VecOrigin ) +{ + // Create a new entity with CWarpball private data + CWarpBall *pWarpBall = GetClassPtr( (CWarpBall *)NULL ); + pWarpBall->pev->classname = MAKE_STRING( "env_warpball" ); + + UTIL_SetOrigin( pWarpBall->pev, p_VecOrigin ); + return pWarpBall; +} diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp index 3cc0acc6..2df9ddc4 100644 --- a/dlls/genericmonster.cpp +++ b/dlls/genericmonster.cpp @@ -23,11 +23,11 @@ // For holograms, make them not solid so the player can walk through them #define SF_GENERICMONSTER_NOTSOLID 4 +#define SF_HEAD_CONTROLLER 8 //========================================================= // Monster's Anim Events Go Here //========================================================= - class CGenericMonster : public CBaseMonster { public: @@ -37,10 +37,33 @@ public: int Classify( void ); void HandleAnimEvent( MonsterEvent_t *pEvent ); int ISoundMask( void ); + void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); + void IdleHeadTurn( Vector &vecFriend ); + void EXPORT MonsterThink(); + + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + +private: + float m_talkTime; + EHANDLE m_hTalkTarget; + float m_flIdealYaw; + float m_flCurrentYaw; }; LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ) +TYPEDESCRIPTION CGenericMonster::m_SaveData[] = +{ + DEFINE_FIELD( CGenericMonster, m_talkTime, FIELD_FLOAT ), + DEFINE_FIELD( CGenericMonster, m_hTalkTarget, FIELD_EHANDLE ), + DEFINE_FIELD( CGenericMonster, m_flIdealYaw, FIELD_FLOAT ), + DEFINE_FIELD( CGenericMonster, m_flCurrentYaw, FIELD_FLOAT ), +}; + +IMPLEMENT_SAVERESTORE( CGenericMonster, CBaseMonster ) + //========================================================= // Classify - indicates this monster's place in the // relationship table. @@ -119,6 +142,13 @@ void CGenericMonster::Spawn() MonsterInit(); + if( pev->spawnflags & SF_HEAD_CONTROLLER ) + { + m_afCapability = bits_CAP_TURN_HEAD; + } + + m_flIdealYaw = m_flCurrentYaw = 0; + if( pev->spawnflags & SF_GENERICMONSTER_NOTSOLID ) { pev->solid = SOLID_NOT; @@ -134,6 +164,64 @@ void CGenericMonster::Precache() PRECACHE_MODEL( STRING( pev->model ) ); } +void CGenericMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) +{ + m_talkTime = gpGlobals->time + duration; + PlaySentence( pszSentence, duration, volume, attenuation ); + + m_hTalkTarget = pListener; +} + +void CGenericMonster::IdleHeadTurn( Vector &vecFriend ) +{ + // turn head in desired direction only if ent has a turnable head + if( m_afCapability & bits_CAP_TURN_HEAD ) + { + float yaw = VecToYaw( vecFriend - pev->origin ) - pev->angles.y; + + if( yaw > 180 ) + yaw -= 360; + if( yaw < -180 ) + yaw += 360; + + m_flIdealYaw = yaw; + } +} + +void CGenericMonster::MonsterThink() +{ + if( m_afCapability & bits_CAP_TURN_HEAD ) + { + if( m_hTalkTarget != 0 ) + { + if( gpGlobals->time > m_talkTime ) + { + m_flIdealYaw = 0; + m_hTalkTarget = 0; + } + else + { + IdleHeadTurn( m_hTalkTarget->pev->origin ); + } + } + + if( m_flCurrentYaw != m_flIdealYaw ) + { + if( m_flCurrentYaw <= m_flIdealYaw ) + { + m_flCurrentYaw += Q_min( m_flIdealYaw - m_flCurrentYaw, 20.0f ); + } + else + { + m_flCurrentYaw -= Q_min( m_flCurrentYaw - m_flIdealYaw, 20.0f ); + } + SetBoneController( 0, m_flCurrentYaw ); + } + } + + CBaseMonster::MonsterThink(); +} + //========================================================= // AI Schedules Specific to this monster //========================================================= diff --git a/dlls/items.cpp b/dlls/items.cpp index 08a13711..20279011 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -200,6 +200,74 @@ class CItemSuit : public CItem LINK_ENTITY_TO_CLASS( item_suit, CItemSuit ) +class CItemArmorVest : public CItem +{ + void Spawn( void ) + { + Precache(); + SET_MODEL( ENT( pev ), "models/barney_vest.mdl" ); + CItem::Spawn(); + } + void Precache( void ) + { + PRECACHE_MODEL( "models/barney_vest.mdl" ); + PRECACHE_SOUND( "items/gunpickup2.wav" ); + } + BOOL MyTouch( CBasePlayer *pPlayer ) + { + if( ( pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY ) && + ( pPlayer->pev->weapons & ( 1 << WEAPON_SUIT ) ) ) + { + pPlayer->pev->armorvalue += 60; + pPlayer->pev->armorvalue = Q_min( pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY ); + + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + + MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); + WRITE_STRING( STRING( pev->classname ) ); + MESSAGE_END(); + return TRUE; + } + return FALSE; + } +}; + +LINK_ENTITY_TO_CLASS( item_armorvest, CItemArmorVest ) + +class CItemHelmet : public CItem +{ + void Spawn( void ) + { + Precache(); + SET_MODEL( ENT( pev ), "models/barney_helmet.mdl" ); + CItem::Spawn(); + } + void Precache( void ) + { + PRECACHE_MODEL( "models/barney_helmet.mdl" ); + PRECACHE_SOUND( "items/gunpickup2.wav" ); + } + BOOL MyTouch( CBasePlayer *pPlayer ) + { + if( ( pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY ) && + ( pPlayer->pev->weapons & ( 1 << WEAPON_SUIT ) ) ) + { + pPlayer->pev->armorvalue += 40; + pPlayer->pev->armorvalue = Q_min( pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY ); + + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + + MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); + WRITE_STRING( STRING( pev->classname ) ); + MESSAGE_END(); + return TRUE; + } + return FALSE; + } +}; + +LINK_ENTITY_TO_CLASS( item_helmet, CItemHelmet ) + class CItemBattery : public CItem { void Spawn( void ) diff --git a/dlls/player.cpp b/dlls/player.cpp index 6b741778..f93cde01 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -3458,7 +3458,9 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) case 101: gEvilImpulse101 = TRUE; GiveNamedItem( "item_suit" ); - GiveNamedItem( "item_battery" ); + GiveNamedItem( "item_armorvest" ); + GiveNamedItem( "item_helmet" ); + // GiveNamedItem( "item_battery" ); GiveNamedItem( "weapon_crowbar" ); GiveNamedItem( "weapon_9mmhandgun" ); GiveNamedItem( "ammo_9mmclip" ); diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index e679770a..e38f2abf 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -119,6 +119,7 @@ private: }; LINK_ENTITY_TO_CLASS( monster_scientist, CScientist ) +LINK_ENTITY_TO_CLASS( monster_rosenberg, CScientist ) TYPEDESCRIPTION CScientist::m_SaveData[] = { @@ -419,7 +420,10 @@ void CScientist::DeclineFollowing( void ) { Talk( 10 ); m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); + if( FClassnameIs( pev, "monster_rosenberg" ) ) + PlaySentence( "RO_POK", 2, VOL_NORM, ATTN_NORM ); + else + PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); } void CScientist::Scream( void ) @@ -428,7 +432,10 @@ void CScientist::Scream( void ) { Talk( 10 ); m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_SCREAM", RANDOM_FLOAT( 3.0f, 6.0f ), VOL_NORM, ATTN_NORM ); + if( FClassnameIs( pev, "monster_rosenberg" ) ) + PlaySentence( "RO_SCREAM", RANDOM_FLOAT( 3.0f, 6.0f ), VOL_NORM, ATTN_NORM ); + else + PlaySentence( "SC_SCREAM", RANDOM_FLOAT( 3.0f, 6.0f ), VOL_NORM, ATTN_NORM ); } } @@ -447,7 +454,10 @@ void CScientist::StartTask( Task_t *pTask ) //if( FOkToSpeak() ) Talk( 2 ); m_hTalkTarget = m_hTargetEnt; - PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); + if( FClassnameIs( pev, "monster_rosenberg" ) ) + PlaySentence( "RO_HEAL", 2, VOL_NORM, ATTN_IDLE ); + else + PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); TaskComplete(); break; case TASK_SCREAM: @@ -465,12 +475,19 @@ void CScientist::StartTask( Task_t *pTask ) 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 ); + if( FClassnameIs( pev, "monster_rosenberg" ) ) + { + PlaySentence( "RO_FEAR", 5, VOL_NORM, ATTN_NORM ); + } else - PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); + { + //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; @@ -647,7 +664,10 @@ void CScientist::Spawn( void ) pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; m_bloodColor = BLOOD_COLOR_RED; - pev->health = gSkillData.scientistHealth; + if( FClassnameIs( pev, "monster_rosenberg" ) ) + pev->health = gSkillData.scientistHealth * 2; + else + 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; @@ -679,11 +699,26 @@ void CScientist::Spawn( void ) 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" ); + if( !FClassnameIs( pev, "monster_rosenberg" ) ) + { + 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" ); + } + else + { + PRECACHE_SOUND( "rosenberg/ro_pain0.wav" ); + PRECACHE_SOUND( "rosenberg/ro_pain1.wav" ); + PRECACHE_SOUND( "rosenberg/ro_pain2.wav" ); + PRECACHE_SOUND( "rosenberg/ro_pain3.wav" ); + PRECACHE_SOUND( "rosenberg/ro_pain4.wav" ); + PRECACHE_SOUND( "rosenberg/ro_pain5.wav" ); + PRECACHE_SOUND( "rosenberg/ro_pain6.wav" ); + PRECACHE_SOUND( "rosenberg/ro_pain7.wav" ); + PRECACHE_SOUND( "rosenberg/ro_pain8.wav" ); + } // every new scientist must call this, otherwise // when a level is loaded, nobody will talk (time is reset to 0) @@ -698,28 +733,54 @@ void CScientist::TalkInit() CTalkMonster::TalkInit(); // 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"; + if( FClassnameIs( pev, "monster_rosenberg" ) ) + { + m_szGrp[TLK_ANSWER] = "RO_ANSWER"; + m_szGrp[TLK_QUESTION] = "RO_QUESTION"; + m_szGrp[TLK_IDLE] = "RO_IDLE"; + m_szGrp[TLK_STARE] = "RO_STARE"; + m_szGrp[TLK_USE] = "RO_OK"; + m_szGrp[TLK_UNUSE] = "RO_WAIT"; + m_szGrp[TLK_STOP] = "RO_STOP"; + m_szGrp[TLK_NOSHOOT] = "RO_SCARED"; + m_szGrp[TLK_HELLO] = "RO_HELLO"; + + m_szGrp[TLK_PLHURT1] = "!RO_CUREA"; + m_szGrp[TLK_PLHURT2] = "!RO_CUREB"; + m_szGrp[TLK_PLHURT3] = "!RO_CUREC"; + + m_szGrp[TLK_PHELLO] = "RO_PHELLO"; + m_szGrp[TLK_PIDLE] = "RO_PIDLE"; + m_szGrp[TLK_PQUESTION] = "RO_PQUEST"; + m_szGrp[TLK_SMELL] = "RO_SMELL"; + + m_szGrp[TLK_WOUND] = "RO_WOUND"; + m_szGrp[TLK_MORTAL] = "RO_MORTAL"; + } + else + { + 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 ) @@ -744,8 +805,11 @@ int CScientist::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, flo { if( pevInflictor && pevInflictor->flags & FL_CLIENT ) { - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); + if( !FClassnameIs( pev, "monster_rosenberg" ) ) + { + Remember( bits_MEMORY_PROVOKED ); + StopFollowing( TRUE ); + } } // make sure friends talk about it if player hurts scientist... @@ -770,29 +834,64 @@ int CScientist::ISoundMask( void ) //========================================================= void CScientist::PainSound( void ) { + const char *pszSound; if( gpGlobals->time < m_painTime ) return; m_painTime = gpGlobals->time + RANDOM_FLOAT( 0.5f, 0.75f ); - 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; - } + if( FClassnameIs( pev, "monster_rosenberg" ) ) + switch( RANDOM_LONG( 0, 8 ) ) + { + case 0: + pszSound = "rosenberg/ro_pain0.wav"; + break; + case 1: + pszSound = "rosenberg/ro_pain1.wav"; + break; + case 2: + pszSound = "rosenberg/ro_pain2.wav"; + break; + case 3: + pszSound = "rosenberg/ro_pain3.wav"; + break; + case 4: + pszSound = "rosenberg/ro_pain4.wav"; + break; + case 5: + pszSound = "rosenberg/ro_pain5.wav"; + break; + case 6: + pszSound = "rosenberg/ro_pain6.wav"; + break; + case 7: + pszSound = "rosenberg/ro_pain7.wav"; + break; + case 8: + pszSound = "rosenberg/ro_pain8.wav"; + break; + } + else + switch( RANDOM_LONG( 0, 4 ) ) + { + case 0: + pszSound = "scientist/sci_pain1.wav"; + break; + case 1: + pszSound = "scientist/sci_pain2.wav"; + break; + case 2: + pszSound = "scientist/sci_pain3.wav"; + break; + case 3: + pszSound = "scientist/sci_pain4.wav"; + break; + case 4: + pszSound = "scientist/sci_pain5.wav"; + break; + } + + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pszSound, 1, ATTN_NORM, 0, GetVoicePitch() ); } //========================================================= @@ -952,7 +1051,7 @@ Schedule_t *CScientist::GetSchedule( void ) } 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 + else if( !FClassnameIs( pev, "monster_rosenberg" ) ) // 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 diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index 581d87a9..79aab120 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -882,6 +882,7 @@ int CTalkMonster::FOkToSpeak( void ) if( gpGlobals->time <= CTalkMonster::g_talkWaitTime ) return FALSE; + // monster generic can speak always if( pev->spawnflags & SF_MONSTER_GAG ) return FALSE; diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 2c0888c9..01dddb85 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -2039,6 +2039,26 @@ void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) pOther->pev->gravity = pev->gravity; } +class CTriggerPlayerFreeze : public CBaseDelay +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } +}; + +LINK_ENTITY_TO_CLASS( trigger_playerfreeze, CTriggerPlayerFreeze ) + +void CTriggerPlayerFreeze::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if( !pActivator || !pActivator->IsPlayer() ) + pActivator = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); + + if( pActivator->pev->flags & FL_FROZEN ) + ( (CBasePlayer*)( pActivator ) )->EnableControl( TRUE ); + else + ( (CBasePlayer*)( pActivator ) )->EnableControl( FALSE ); +}; + // this is a really bad idea. class CTriggerChangeTarget : public CBaseDelay { diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index ec98e0ca..9f3f411a 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -296,6 +296,8 @@ void W_Precache( void ) // common world objects UTIL_PrecacheOther( "item_suit" ); UTIL_PrecacheOther( "item_healthkit" ); + UTIL_PrecacheOther( "item_armorvest" ); + UTIL_PrecacheOther( "item_helmet" ); UTIL_PrecacheOther( "item_battery" ); UTIL_PrecacheOther( "item_antidote" ); UTIL_PrecacheOther( "item_security" );