From 7235d2435fbe3acf3eedea656cbceceb8feb60ce Mon Sep 17 00:00:00 2001 From: Night Owl Date: Mon, 9 Jan 2017 03:11:40 +0500 Subject: [PATCH] Upload missing files. --- dlls/bubblemod/BMOD_CameraPoint.cpp | 82 +++ dlls/bubblemod/BMOD_CameraPoint.h | 40 ++ dlls/bubblemod/BMOD_boxmarker.cpp | 123 ++++ dlls/bubblemod/BMOD_boxmarker.h | 47 ++ dlls/bubblemod/BMOD_constants.h | 61 ++ dlls/bubblemod/BMOD_egon.cpp | 939 ++++++++++++++++++++++++++ dlls/bubblemod/BMOD_flyingcrowbar.cpp | 187 +++++ dlls/bubblemod/BMOD_flyingcrowbar.h | 57 ++ dlls/bubblemod/BMOD_gamerules.cpp | 669 ++++++++++++++++++ dlls/bubblemod/BMOD_hornetgun.cpp | 163 +++++ dlls/bubblemod/BMOD_hornetgun.h | 72 ++ dlls/bubblemod/BMOD_messaging.cpp | 121 ++++ dlls/bubblemod/BMOD_messaging.h | 44 ++ dlls/bubblemod/BMOD_player.cpp | 704 +++++++++++++++++++ dlls/bubblemod/BMOD_player.h | 53 ++ dlls/bubblemod/BMOD_rune.cpp | 444 ++++++++++++ dlls/bubblemod/BMOD_rune.h | 49 ++ dlls/bubblemod/BMOD_snarkmine.cpp | 524 ++++++++++++++ dlls/bubblemod/BMOD_snarkmine.h | 84 +++ dlls/bubblemod/BMOD_squeakgrenade.cpp | 153 +++++ dlls/bubblemod/BMOD_tripmines.cpp | 155 +++++ dlls/bubblemod/BMOD_util.cpp | 533 +++++++++++++++ dlls/bubblemod/BMOD_zapgunrift.cpp | 369 ++++++++++ dlls/bubblemod/BMOD_zapgunrift.h | 62 ++ dlls/bubblemod/egon.h | 91 +++ dlls/bubblemod/squeakgrenade.h | 68 ++ dlls/bubblemod/tripmine.h | 48 ++ 27 files changed, 5942 insertions(+) create mode 100644 dlls/bubblemod/BMOD_CameraPoint.cpp create mode 100644 dlls/bubblemod/BMOD_CameraPoint.h create mode 100644 dlls/bubblemod/BMOD_boxmarker.cpp create mode 100644 dlls/bubblemod/BMOD_boxmarker.h create mode 100644 dlls/bubblemod/BMOD_constants.h create mode 100644 dlls/bubblemod/BMOD_egon.cpp create mode 100644 dlls/bubblemod/BMOD_flyingcrowbar.cpp create mode 100644 dlls/bubblemod/BMOD_flyingcrowbar.h create mode 100644 dlls/bubblemod/BMOD_gamerules.cpp create mode 100644 dlls/bubblemod/BMOD_hornetgun.cpp create mode 100644 dlls/bubblemod/BMOD_hornetgun.h create mode 100644 dlls/bubblemod/BMOD_messaging.cpp create mode 100644 dlls/bubblemod/BMOD_messaging.h create mode 100644 dlls/bubblemod/BMOD_player.cpp create mode 100644 dlls/bubblemod/BMOD_player.h create mode 100644 dlls/bubblemod/BMOD_rune.cpp create mode 100644 dlls/bubblemod/BMOD_rune.h create mode 100644 dlls/bubblemod/BMOD_snarkmine.cpp create mode 100644 dlls/bubblemod/BMOD_snarkmine.h create mode 100644 dlls/bubblemod/BMOD_squeakgrenade.cpp create mode 100644 dlls/bubblemod/BMOD_tripmines.cpp create mode 100644 dlls/bubblemod/BMOD_util.cpp create mode 100644 dlls/bubblemod/BMOD_zapgunrift.cpp create mode 100644 dlls/bubblemod/BMOD_zapgunrift.h create mode 100644 dlls/bubblemod/egon.h create mode 100644 dlls/bubblemod/squeakgrenade.h create mode 100644 dlls/bubblemod/tripmine.h diff --git a/dlls/bubblemod/BMOD_CameraPoint.cpp b/dlls/bubblemod/BMOD_CameraPoint.cpp new file mode 100644 index 00000000..82f940da --- /dev/null +++ b/dlls/bubblemod/BMOD_CameraPoint.cpp @@ -0,0 +1,82 @@ +// --------------------------------------------------------------- +// Camera Point Entity +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" +#include "effects.h" +#include "BMOD_CameraPoint.h" +#include "shake.h" + +LINK_ENTITY_TO_CLASS( campoint, CCamPoint ); + +void CCamPoint::Precache( void ) +{ +} + +void CCamPoint::Spawn( void ) +{ + pev->movetype = MOVETYPE_NOCLIP; + pev->solid = SOLID_NOT; // Remove model & collisions + pev->renderamt = 0; // The engine won't draw this model if this + // is set to 0 and blending is on + pev->rendermode = kRenderTransTexture; + + SetThink ( Think ); + pev->nextthink = gpGlobals->time + 0.1; +} + +void CCamPoint::Think( void ) +{ + + // If we have no owner, our owner is not in type mode, + // our owner is not connected, our owner is invisible, + // or our owner is a defuct player, remove ourselves. + if (!m_pOwner + || !m_pOwner->m_bIsConnected + || !m_pOwner->m_bTypeMode + || m_pOwner->pev->effects & EF_NODRAW + || (STRING(m_pOwner->pev->netname)[0] == 0) + ) { + // UTIL_ClientPrintAll( HUD_PRINTTALK, " Camera point destroyed.\n"); + UTIL_Remove( this ); + pev->nextthink = gpGlobals->time + .1; + return; + } + + pev->origin = m_pOwner->pev->origin + Vector(0,0,40), + pev->angles = Vector(m_pOwner->pev->angles.x + 22, + m_pOwner->pev->angles.y + 180, + 0), + + // Wait until it's time to think again. + pev->nextthink = gpGlobals->time + 0.01; +} \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_CameraPoint.h b/dlls/bubblemod/BMOD_CameraPoint.h new file mode 100644 index 00000000..f49d8d3e --- /dev/null +++ b/dlls/bubblemod/BMOD_CameraPoint.h @@ -0,0 +1,40 @@ +// --------------------------------------------------------------- +// Zap Rift Entity +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#ifndef C_CAM_POINT +#define C_CAM_POINT + +class CCamPoint : public CPointEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT Think( void ); + + CBasePlayer *m_pOwner; +}; + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_boxmarker.cpp b/dlls/bubblemod/BMOD_boxmarker.cpp new file mode 100644 index 00000000..4069098c --- /dev/null +++ b/dlls/bubblemod/BMOD_boxmarker.cpp @@ -0,0 +1,123 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "effects.h" +#include "gamerules.h" +#include "BMOD_boxmarker.h" + +LINK_ENTITY_TO_CLASS( boxmarker, CBoxMarker ); + +void CBoxMarker :: Spawn( void ) +{ + + pev->classname = MAKE_STRING("boxmarker"); + + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_NOT; + + SetThink( PowerupThink ); + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(.1, 1); + + m_vecExtents = Vector (16, 16, 16); + m_beamsFired = 0; +} + +void CBoxMarker :: PowerupThink( void ) +{ + Vector vecStart, vecEnd; + + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(.1, .5); + + switch (m_beamsFired) + { + case 0: + vecStart = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * 1, m_vecExtents.z * 1); + vecEnd = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * 1, m_vecExtents.z * 1); + break; + case 1: + vecStart = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * 1, m_vecExtents.z * 1); + vecEnd = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * -1, m_vecExtents.z * 1); + break; + case 2: + vecStart = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * -1, m_vecExtents.z * 1); + vecEnd = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * -1, m_vecExtents.z * 1); + break; + case 3: + vecStart = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * -1, m_vecExtents.z * 1); + vecEnd = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * 1, m_vecExtents.z * 1); + break; + case 4: + vecStart = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * 1, m_vecExtents.z * 1); + vecEnd = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * 1, m_vecExtents.z * -1); + break; + case 5: + vecStart = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * 1, m_vecExtents.z * 1); + vecEnd = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * 1, m_vecExtents.z * -1); + break; + case 6: + vecStart = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * -1, m_vecExtents.z * 1); + vecEnd = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * -1, m_vecExtents.z * -1); + break; + case 7: + vecStart = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * -1, m_vecExtents.z * 1); + vecEnd = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * -1, m_vecExtents.z * -1); + break; + case 8: + vecStart = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * 1, m_vecExtents.z * -1); + vecEnd = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * 1, m_vecExtents.z * -1); + break; + case 9: + vecStart = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * 1, m_vecExtents.z * -1); + vecEnd = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * -1, m_vecExtents.z * -1); + break; + case 10: + vecStart = pev->origin + Vector(m_vecExtents.x * -1 , m_vecExtents.y * -1, m_vecExtents.z * -1); + vecEnd = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * -1, m_vecExtents.z * -1); + break; + case 11: + vecStart = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * -1, m_vecExtents.z * -1); + vecEnd = pev->origin + Vector(m_vecExtents.x * 1 , m_vecExtents.y * 1, m_vecExtents.z * -1); + SetThink(NULL); + break; + } + + m_pBeam[m_beamsFired] = CBeam::BeamCreate( g_pModelNameLaser, 10 ); + m_pBeam[m_beamsFired]->PointsInit( vecStart, vecEnd ); + m_pBeam[m_beamsFired]->SetColor( 0, 255, 0 ); + m_pBeam[m_beamsFired]->SetScrollRate( 255 ); + m_pBeam[m_beamsFired]->SetBrightness( 64 ); + + m_beamsFired++; + +} + diff --git a/dlls/bubblemod/BMOD_boxmarker.h b/dlls/bubblemod/BMOD_boxmarker.h new file mode 100644 index 00000000..9dc6b57f --- /dev/null +++ b/dlls/bubblemod/BMOD_boxmarker.h @@ -0,0 +1,47 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#ifndef MY_BOX_MARKER +#define MY_BOX_MARKER + +#include "effects.h" + +class CBoxMarker : public CPointEntity +{ +public: + void Spawn( void ); + + void EXPORT PowerupThink( void ); + void Killed( void ); + + Vector m_vecExtents; + +private: + int m_beamsFired; + CBeam *m_pBeam[12]; +}; + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_constants.h b/dlls/bubblemod/BMOD_constants.h new file mode 100644 index 00000000..349fe968 --- /dev/null +++ b/dlls/bubblemod/BMOD_constants.h @@ -0,0 +1,61 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- +// Global BubbleMod Constants + +#ifndef BMOD_CONSTANTS_H +#define BMOD_CONSTANTS_H + +// --------------------------------------------------------------- +// Branch customizations +// Information in the next three constants will be used for servers +// running your mod on the BubbleWatch pages on bubblemod.org. Fill +// these in with the information you would like to appear on that page. +// +// If you do NOT want servers running your branch to appear on the +// BubbleWatch page, simply set BMOD_VERSION below to "", or run your +// server with no master server reporting. + +// Fill this in with the title of your bubblemod branch +#define BMOD_BRANCH_NAME "Custom Bubblemod" + +// The version of your branch +#define BMOD_BRANCH_VERSION "1.0.0" + +// The URL of the website describing your branch +#define BMOD_BRANCH_URL "http://www.bubblemod.org" + +// End branch customizations +// --------------------------------------------------------------- + +#define BMOD_VERSION "2.2.3a" + +#ifdef _WIN32 +#define BMOD_PLATFORM "WIN32" +#else +#define BMOD_PLATFORM "Linux" +#endif + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_egon.cpp b/dlls/bubblemod/BMOD_egon.cpp new file mode 100644 index 00000000..cffb2866 --- /dev/null +++ b/dlls/bubblemod/BMOD_egon.cpp @@ -0,0 +1,939 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "effects.h" +#include "customentity.h" +#include "gamerules.h" +#include "shake.h" +#include "BMOD_messaging.h" + +#define EGON_PRIMARY_VOLUME 450 +#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" +#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" +#define EGON_SOUND_OFF "weapons/egon_off1.wav" +#define EGON_SOUND_RUN "weapons/egon_run3.wav" +#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" +#define BUBB_SOUND_OFF "debris/flesh5.wav" +#define BUBB_SOUND_RUN "debris/flesh5.wav" +#define BUBB_SOUND_STARTUP "debris/flesh6.wav" +#define HEAL_SOUND_OFF "debris/beamstart7.wav" + +#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes +#define EGON_SWITCH_WIDE_TIME 1.5 + +#define BUBBLE_HEAL_RADIUS 64 +#define BUBBLE_HEAL_AMT 70 + +extern cvar_t bm_gluon_mod; +extern cvar_t bm_thrust; + +enum egon_e { + EGON_IDLE1 = 0, + EGON_FIDGET1, + EGON_ALTFIREON, + EGON_ALTFIRECYCLE, + EGON_ALTFIREOFF, + EGON_FIRE1, + EGON_FIRE2, + EGON_FIRE3, + EGON_FIRE4, + EGON_DRAW, + EGON_HOLSTER +}; + + +class CEgon : public CBasePlayerWeapon +{ +public: + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 4; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + + void CreateEffect( void ); + void UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ); + void DestroyEffect( void ); + + void EndBubbleAttack( void ); + void EndAttack( void ); + void BubbleAttack( void ); + void Attack( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + static int g_fireAnims1[]; + static int g_fireAnims2[]; + + float m_flAmmoUseTime;// since we use < 1 point of ammo per update, we subtract ammo on a timer. + + float GetPulseInterval( void ); + float GetDischargeInterval( void ); + + void Fire( const Vector &vecOrigSrc, const Vector &vecDir ); + void BubbleFire( const Vector &vecOrigSrc, const Vector &vecDir ); + void FireHeal( void ); + + BOOL HasAmmo( void ) + { + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + return FALSE; + return TRUE; + } + + void UseAmmo( int count ) + { + if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count ) + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count; + else + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0; + } + + enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; + enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; + +private: + float m_shootTime; + CBeam *m_pBeam; + CBeam *m_pNoise; + CSprite *m_pSprite; + EGON_FIRESTATE m_fireState; + EGON_FIREMODE m_fireMode; + float m_shakeTime; + BOOL m_deployed; + float m_bubbletime; + + float m_healAmmoUsed; + float m_healAmmoUseTime; + + unsigned short m_usEgonFire; + unsigned short m_usEgonStop; + +}; + +LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ); + +int CEgon::g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; +int CEgon::g_fireAnims2[] = { EGON_ALTFIRECYCLE }; + + +TYPEDESCRIPTION CEgon::m_SaveData[] = +{ + DEFINE_FIELD( CEgon, m_pBeam, FIELD_CLASSPTR ), + DEFINE_FIELD( CEgon, m_pNoise, FIELD_CLASSPTR ), + DEFINE_FIELD( CEgon, m_pSprite, FIELD_CLASSPTR ), + DEFINE_FIELD( CEgon, m_shootTime, FIELD_TIME ), + DEFINE_FIELD( CEgon, m_fireState, FIELD_INTEGER ), + DEFINE_FIELD( CEgon, m_fireMode, FIELD_INTEGER ), + DEFINE_FIELD( CEgon, m_shakeTime, FIELD_TIME ), + DEFINE_FIELD( CEgon, m_flAmmoUseTime, FIELD_TIME ), +}; +IMPLEMENT_SAVERESTORE( CEgon, CBasePlayerWeapon ); + + +void CEgon::Spawn( ) +{ + pev->classname = MAKE_STRING("weapon_egon"); + Precache( ); + m_iId = WEAPON_EGON; + SET_MODEL(ENT(pev), "models/w_egon.mdl"); + + m_iDefaultAmmo = EGON_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CEgon::Precache( void ) +{ + PRECACHE_MODEL("models/w_egon.mdl"); + PRECACHE_MODEL("models/v_egon.mdl"); + PRECACHE_MODEL("models/p_egon.mdl"); + + PRECACHE_MODEL("models/w_9mmclip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + + PRECACHE_SOUND( EGON_SOUND_OFF ); + PRECACHE_SOUND( EGON_SOUND_RUN ); + PRECACHE_SOUND( EGON_SOUND_STARTUP ); + + PRECACHE_SOUND( BUBB_SOUND_OFF ); + PRECACHE_SOUND( BUBB_SOUND_RUN ); + PRECACHE_SOUND( BUBB_SOUND_STARTUP ); + PRECACHE_SOUND( HEAL_SOUND_OFF ); + + PRECACHE_MODEL( EGON_BEAM_SPRITE ); + PRECACHE_MODEL( EGON_FLARE_SPRITE ); + + PRECACHE_SOUND ("weapons/357_cock1.wav"); + + m_usEgonFire = PRECACHE_EVENT ( 1, "events/egon_fire.sc" ); + m_usEgonStop = PRECACHE_EVENT ( 1, "events/egon_stop.sc" ); + +} + + +BOOL CEgon::Deploy( void ) +{ + if (bm_gluon_mod.value) { + PrintMessage( m_pPlayer, BMOD_CHAN_WEAPON, Vector (20,250,20), Vector (1, 4, 2), "BUBBLE GUN\nPRIMARY FIRE: Breathe bubbles underwater.\nSECONDARY FIRE: Hold down 5 seconds for area effect healing."); + } + + m_deployed = FALSE; + return DefaultDeploy( "models/v_egon.mdl", "models/p_egon.mdl", EGON_DRAW, "egon" ); +} + +int CEgon::AddToPlayer( CBasePlayer *pPlayer ) +{ + if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); + WRITE_BYTE( m_iId ); + MESSAGE_END(); + return TRUE; + } + return FALSE; +} + + + +void CEgon::Holster( int skiplocal /* = 0 */ ) +{ + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + // m_flTimeWeaponIdle = gpGlobals->time + UTIL_RandomFloat ( 10, 15 ); + SendWeaponAnim( EGON_HOLSTER ); + + if ( m_fireState != FIRE_OFF ) { + if (bm_gluon_mod.value) + EndBubbleAttack(); + else + EndAttack(); + } +} + +int CEgon::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "uranium"; + p->iMaxAmmo1 = URANIUM_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = WEAPON_NOCLIP; + p->iSlot = 3; + p->iPosition = 2; + p->iId = m_iId = WEAPON_EGON; + p->iFlags = 0; + p->iWeight = EGON_WEIGHT; + + return 1; +} + + +//#define EGON_PULSE_INTERVAL 0.25 +//#define EGON_DISCHARGE_INTERVAL 0.5 + +#define EGON_PULSE_INTERVAL 0.1 +#define EGON_DISCHARGE_INTERVAL 0.1 + +float CEgon::GetPulseInterval( void ) +{ + if ( g_pGameRules->IsMultiplayer() ) + { + return 0.1; + } + + return EGON_PULSE_INTERVAL; +} + +float CEgon::GetDischargeInterval( void ) +{ + if ( g_pGameRules->IsMultiplayer() ) + { + return 0.1; + } + + return EGON_DISCHARGE_INTERVAL; +} + +void CEgon::BubbleAttack( void ) +{ + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + Vector vecAiming = gpGlobals->v_forward; + Vector vecSrc = m_pPlayer->GetGunPosition( ); + + switch( m_fireState ) + { + case FIRE_OFF: + { + if ( !HasAmmo() ) + { + m_flNextPrimaryAttack = gpGlobals->time + 0.25; + if (m_flNextSecondaryAttack <= gpGlobals->time) + m_flNextSecondaryAttack = gpGlobals->time + 0.25; + PlayEmptySound( ); + return; + } + + m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP. + + SendWeaponAnim( g_fireAnims1[ RANDOM_LONG(0,ARRAYSIZE(g_fireAnims1)-1) ] ); + m_shakeTime = 0; + + m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; + m_flTimeWeaponIdle = gpGlobals->time + 0.1; + // m_shootTime = gpGlobals->time + 2; + m_shootTime = gpGlobals->time + .2; + + if ( m_fireMode == FIRE_WIDE ) + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, BUBB_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); + } + else + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, BUBB_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 80 ); + m_healAmmoUsed = 0; + m_healAmmoUseTime = -1; + } + + pev->dmgtime = gpGlobals->time + GetPulseInterval(); + m_fireState = FIRE_CHARGE; + } + break; + + case FIRE_CHARGE: + { + if ( m_fireMode == FIRE_WIDE ) + BubbleFire( vecSrc, vecAiming ); + else + FireHeal(); + + m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; + + if ( m_shootTime != 0 && gpGlobals->time > m_shootTime ) + { + if ( m_fireMode == FIRE_WIDE ) + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_STATIC, BUBB_SOUND_RUN, 0.98, ATTN_NORM, 0, 100 + RANDOM_LONG(0, 100) ); + } + else + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_STATIC, BUBB_SOUND_RUN, 0.9, ATTN_NORM, 0, 50 + (m_healAmmoUsed * 2) ); + } + + m_shootTime += (.1 + RANDOM_FLOAT(0,.1)); + } + if ( !HasAmmo() ) + { + EndBubbleAttack(); + m_fireState = FIRE_OFF; + m_flNextPrimaryAttack = gpGlobals->time + 1.0; + if (m_flNextSecondaryAttack <= gpGlobals->time) + m_flNextSecondaryAttack = gpGlobals->time + 1.0; + } + + } + break; + } +} + +void CEgon::PrimaryAttack( void ) +{ + if (bm_gluon_mod.value) { + m_fireMode = FIRE_WIDE; + BubbleAttack(); + } + else { + m_fireMode = FIRE_WIDE; + Attack(); + } +} + +void CEgon::SecondaryAttack( void ) +{ + if (bm_gluon_mod.value) { + m_fireMode = FIRE_NARROW; + BubbleAttack(); + } + else { + } +} + +// *********************************** +// Eggplant's Bubble Gun +// *********************************** +void CEgon::BubbleFire( const Vector &vecOrigSrc, const Vector &vecDir ) +{ + + if (!(m_bubbletime <= gpGlobals->time)) + return; + m_bubbletime = gpGlobals->time + .05; + + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * bm_thrust.value; + + TraceResult tr; + + // Give player air! + m_pPlayer->pev->air_finished = gpGlobals->time + 12; + + // First determine where the bubble will appear. It will appear in a random location + // from the barrel of the gun to +128 units from the barrel. + Vector tmpSrcMin = vecOrigSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3; + Vector tmpSrcMax = tmpSrcMin + gpGlobals->v_forward * RANDOM_LONG(32, 128); + + // We dont want to be able to shoot through walls or people, so trace the line from the barrel to the + // bubble point and make sure nothing is in the way. + UTIL_TraceLine(tmpSrcMin, tmpSrcMax, dont_ignore_monsters, ENT(pev), &tr); + if (tr.fStartSolid) + return; + Vector tmpSrc1 = tmpSrcMin + gpGlobals->v_forward * 32; + Vector tmpSrc2 = tr.vecEndPos; + + // Now trace from the bubble point up 256 units to see where the bubble should pop. + Vector vecDest = tmpSrc2 + Vector ( 0, 0, 1 ) * 256; + UTIL_TraceLine(tmpSrc2, vecDest, ignore_monsters, ENT(pev), &tr); + float flHeight = tr.vecEndPos.z - tmpSrc2.z; + + // Tell the client about the new bubble. + // MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tmpSrc ); + // WRITE_BYTE( TE_BUBBLES ); + // WRITE_COORD( vecMin.x ); // mins + // WRITE_COORD( vecMin.y ); + // WRITE_COORD( vecMin.z ); + // WRITE_COORD( vecMax.x ); // maxz + // WRITE_COORD( vecMax.y ); + // WRITE_COORD( vecMax.z ); + // WRITE_COORD( flHeight ); // height + // WRITE_SHORT( g_sModelIndexBubbles ); + // WRITE_BYTE( 3 ); // count + // WRITE_COORD( 8 ); // speed + // MESSAGE_END(); + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BUBBLETRAIL ); + WRITE_COORD( tmpSrc1.x ); // mins + WRITE_COORD( tmpSrc1.y ); + WRITE_COORD( tmpSrc1.z ); + WRITE_COORD( tmpSrc2.x ); // maxz + WRITE_COORD( tmpSrc2.y ); + WRITE_COORD( tmpSrc2.z ); + WRITE_COORD( flHeight ); // height + WRITE_SHORT( g_sModelIndexBubbles ); + WRITE_BYTE( 5 ); // count + WRITE_COORD( 8 ); // speed + MESSAGE_END(); +} + +void CEgon::FireHeal( void ) { + + // Only do this every once in a while to save bandwidth. + if (!(m_bubbletime <= gpGlobals->time)) + return; + m_bubbletime = gpGlobals->time + .1; + + Vector vecOrigSrc = m_pPlayer->GetGunPosition( ); + int bubbleRadius = 1; + int numBubbles = 1; + int bubbleSpeed = 8; + + if (m_healAmmoUseTime <= gpGlobals->time) { + m_healAmmoUseTime = gpGlobals->time +.5; + UseAmmo(5); + m_healAmmoUsed += 5; + + // Runes halve the ammo needed. + int healTime = 50; + if (m_pPlayer->m_RuneFlags == RUNE_BATTERY || + m_pPlayer->m_RuneFlags == RUNE_HEALTH) { + healTime /= 2; + } + + if (m_healAmmoUsed >= healTime) { + // Heal all players within a radius. + CBaseEntity *pEntity = NULL; + + // Find all the players inside the radius. Heal them, and make the screen flash. + while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecOrigSrc, BUBBLE_HEAL_RADIUS )) != NULL) + { + if (pEntity->IsPlayer()) + if (m_pPlayer->m_RuneFlags == RUNE_BATTERY) { + pEntity->pev->armorvalue += BUBBLE_HEAL_AMT; + if (pEntity->pev->armorvalue > 100) + pEntity->pev->armorvalue = 100; + } + else { + pEntity->TakeHealth(BUBBLE_HEAL_AMT, DMG_GENERIC); + } + UTIL_ScreenFade( pEntity, Vector(0,128,255), 2, 0.5, 200, FFADE_IN ); + } + + // Make a big bubble cloud. + bubbleRadius = BUBBLE_HEAL_RADIUS; + numBubbles = 1000; + bubbleSpeed = -8; + + // Turn off the bubble gun. + EndBubbleAttack(); + + // Make sure they can't do this again for a while. + m_flNextSecondaryAttack = gpGlobals->time + 30; + + // Make a sound effect. + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_STATIC, HEAL_SOUND_OFF, 0.98, ATTN_NORM, 0, 100); + } + } + + // Make bubble(s) + TraceResult tr; + Vector vecDest = vecOrigSrc + Vector ( 0, 0, 1 ) * 256; + UTIL_TraceLine(vecOrigSrc, vecDest, ignore_monsters, ENT(pev), &tr); + float flHeight = tr.vecEndPos.z - vecOrigSrc.z; + + // Tell the client about the new bubble. + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecOrigSrc ); + WRITE_BYTE( TE_BUBBLES ); + WRITE_COORD( vecOrigSrc.x - bubbleRadius ); // mins + WRITE_COORD( vecOrigSrc.y - bubbleRadius ); + WRITE_COORD( vecOrigSrc.z - bubbleRadius ); + WRITE_COORD( vecOrigSrc.x + bubbleRadius ); // maxz + WRITE_COORD( vecOrigSrc.y + bubbleRadius ); + WRITE_COORD( vecOrigSrc.z + bubbleRadius ); + WRITE_COORD( flHeight ); // height + WRITE_SHORT( g_sModelIndexBubbles ); + WRITE_BYTE( numBubbles ); // count + WRITE_COORD( bubbleSpeed ); // speed + MESSAGE_END(); +} + + +void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ) +{ + if ( !m_pBeam ) + { + CreateEffect(); + } + + m_pBeam->SetStartPos( endPoint ); + m_pBeam->SetBrightness( 255 - (timeBlend*180) ); + m_pBeam->SetWidth( 40 - (timeBlend*20) ); + + if ( m_fireMode == FIRE_WIDE ) + m_pBeam->SetColor( 30 + (25*timeBlend), 30 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); + else + m_pBeam->SetColor( 60 + (25*timeBlend), 120 + (30*timeBlend), 64 + 80*fabs(sin(gpGlobals->time*10)) ); + + + UTIL_SetOrigin( m_pSprite->pev, endPoint ); + m_pSprite->pev->frame += 8 * gpGlobals->frametime; + if ( m_pSprite->pev->frame > m_pSprite->Frames() ) + m_pSprite->pev->frame = 0; + + m_pNoise->SetStartPos( endPoint ); +} + + +void CEgon::CreateEffect( void ) +{ + DestroyEffect(); + + m_pBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 40 ); + m_pBeam->PointEntInit( pev->origin, m_pPlayer->entindex() ); + m_pBeam->SetFlags( BEAM_FSINE ); + m_pBeam->SetEndAttachment( 1 ); + m_pBeam->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition + + m_pNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 55 ); + m_pNoise->PointEntInit( pev->origin, m_pPlayer->entindex() ); + m_pNoise->SetScrollRate( 25 ); + m_pNoise->SetBrightness( 100 ); + m_pNoise->SetEndAttachment( 1 ); + m_pNoise->pev->spawnflags |= SF_BEAM_TEMPORARY; + + m_pSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, pev->origin, FALSE ); + m_pSprite->pev->scale = 1.0; + m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); + m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY; + + if ( m_fireMode == FIRE_WIDE ) + { + m_pBeam->SetScrollRate( 50 ); + m_pBeam->SetNoise( 20 ); + m_pNoise->SetColor( 50, 50, 255 ); + m_pNoise->SetNoise( 8 ); + } + else + { + m_pBeam->SetScrollRate( 110 ); + m_pBeam->SetNoise( 5 ); + m_pNoise->SetColor( 80, 120, 255 ); + m_pNoise->SetNoise( 2 ); + } +} + + +void CEgon::DestroyEffect( void ) +{ + if ( m_pBeam ) + { + UTIL_Remove( m_pBeam ); + m_pBeam = NULL; + } + if ( m_pNoise ) + { + UTIL_Remove( m_pNoise ); + m_pNoise = NULL; + } + if ( m_pSprite ) + { + if ( m_fireMode == FIRE_WIDE ) + m_pSprite->Expand( 10, 500 ); + else + UTIL_Remove( m_pSprite ); + m_pSprite = NULL; + } +} + + +void CEgon::WeaponIdle( void ) +{ + ResetEmptySound( ); + + if ( m_flTimeWeaponIdle > gpGlobals->time ) + return; + + if ( m_fireState != FIRE_OFF ) { + if (bm_gluon_mod.value) + EndBubbleAttack(); + else + EndAttack(); + } + + int iAnim; + + float flRand = RANDOM_FLOAT(0,1); + + if ( flRand <= 0.5 ) + { + iAnim = EGON_IDLE1; + m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT(10,15); + } + else + { + iAnim = EGON_FIDGET1; + m_flTimeWeaponIdle = gpGlobals->time + 3; + } + + SendWeaponAnim( iAnim ); + m_deployed = TRUE; +} + +void CEgon::EndBubbleAttack( void ) +{ + STOP_SOUND( ENT(m_pPlayer->pev), CHAN_STATIC, BUBB_SOUND_RUN ); + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, BUBB_SOUND_OFF, 0.98, ATTN_NORM, 0, 100); + m_fireState = FIRE_OFF; + m_flTimeWeaponIdle = gpGlobals->time + 2.0; + m_flNextPrimaryAttack = gpGlobals->time + 0.5; + // m_flNextSecondaryAttack = gpGlobals->time + 30; + DestroyEffect(); +} + +void CEgon::EndAttack( void ) +{ + STOP_SOUND( ENT(m_pPlayer->pev), CHAN_STATIC, EGON_SOUND_RUN ); + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100); + m_fireState = FIRE_OFF; + m_flTimeWeaponIdle = gpGlobals->time + 2.0; + m_flNextPrimaryAttack = gpGlobals->time + 0.5; + // m_flNextSecondaryAttack = gpGlobals->time + 30; + DestroyEffect(); +} + +void CEgon::Attack( void ) +{ + // don't fire underwater + if ( m_pPlayer->pev->waterlevel == 3 ) + { + + if ( m_fireState != FIRE_OFF || m_pBeam ) + { + EndAttack(); + } + else + { + PlayEmptySound( ); + } + return; + } + + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + Vector vecAiming = gpGlobals->v_forward; + Vector vecSrc = m_pPlayer->GetGunPosition( ); + + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + switch( m_fireState ) + { + case FIRE_OFF: + { + if ( !HasAmmo() ) + { + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; + PlayEmptySound( ); + return; + } + + m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP. + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 1, 0 ); + + m_shakeTime = 0; + + m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; + pev->fuser1 = UTIL_WeaponTimeBase() + 2; + m_shootTime = gpGlobals->time +2; + + if ( m_fireMode == FIRE_WIDE ) + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); + } + else + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 80 ); + } + + pev->dmgtime = gpGlobals->time + GetPulseInterval(); + m_fireState = FIRE_CHARGE; + } + break; + + case FIRE_CHARGE: + { + Fire( vecSrc, vecAiming ); + + m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; + + if ( m_shootTime != 0 && gpGlobals->time > m_shootTime ) + { + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); + m_shootTime = 0; + } + + //if ( pev->fuser1 <= UTIL_WeaponTimeBase() ) + //{ + // PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 0, 0 ); + // pev->fuser1 = 1000; + // } + + if ( !HasAmmo() ) + { + EndAttack(); + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; + } + + } + break; + } +} + +void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) +{ + Vector vecDest = vecOrigSrc + vecDir * 2048; + edict_t *pentIgnore; + TraceResult tr; + + pentIgnore = m_pPlayer->edict(); + Vector tmpSrc = vecOrigSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3; + + // ALERT( at_console, "." ); + + UTIL_TraceLine( vecOrigSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); + + if (tr.fAllSolid) + return; + +#ifndef CLIENT_DLL + CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); + + if (pEntity == NULL) + return; + + if ( g_pGameRules->IsMultiplayer() ) + { + if ( m_pSprite && pEntity->pev->takedamage ) + { + m_pSprite->pev->effects &= ~EF_NODRAW; + } + else if ( m_pSprite ) + { + m_pSprite->pev->effects |= EF_NODRAW; + } + } + + +#endif + + float timedist; + + switch ( m_fireMode ) + { + case FIRE_NARROW: +#ifndef CLIENT_DLL + if ( pev->dmgtime < gpGlobals->time ) + { + // Narrow mode only does damage to the entity it hits + ClearMultiDamage(); + if (pEntity->pev->takedamage) + { + pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonNarrow, vecDir, &tr, DMG_ENERGYBEAM ); + } + ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); + + if ( g_pGameRules->IsMultiplayer() ) + { + // multiplayer uses 1 ammo every 1/10th second + if ( gpGlobals->time >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->time + 0.1; + } + } + else + { + // single player, use 3 ammo/second + if ( gpGlobals->time >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->time + 0.166; + } + } + + pev->dmgtime = gpGlobals->time + GetPulseInterval(); + } +#endif + timedist = ( pev->dmgtime - gpGlobals->time ) / GetPulseInterval(); + break; + + case FIRE_WIDE: +#ifndef CLIENT_DLL + if ( pev->dmgtime < gpGlobals->time ) + { + // wide mode does damage to the ent, and radius damage + ClearMultiDamage(); + if (pEntity->pev->takedamage) + { + pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonWide, vecDir, &tr, DMG_ENERGYBEAM | DMG_ALWAYSGIB); + } + ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); + + if ( g_pGameRules->IsMultiplayer() ) + { + // radius damage a little more potent in multiplayer. + ::RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, gSkillData.plrDmgEgonWide/4, 128, CLASS_NONE, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ); + } + + if ( !m_pPlayer->IsAlive() ) + return; + + if ( g_pGameRules->IsMultiplayer() ) + { + //multiplayer uses 5 ammo/second + if ( gpGlobals->time >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->time + 0.2; + } + } + else + { + // Wide mode uses 10 charges per second in single player + if ( gpGlobals->time >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->time + 0.1; + } + } + + pev->dmgtime = gpGlobals->time + GetDischargeInterval(); + if ( m_shakeTime < gpGlobals->time ) + { + UTIL_ScreenShake( tr.vecEndPos, 5.0, 150.0, 0.75, 250.0 ); + m_shakeTime = gpGlobals->time + 1.5; + } + } +#endif + timedist = ( pev->dmgtime - gpGlobals->time ) / GetDischargeInterval(); + break; + } + + if ( timedist < 0 ) + timedist = 0; + else if ( timedist > 1 ) + timedist = 1; + timedist = 1-timedist; + + UpdateEffect( tmpSrc, tr.vecEndPos, timedist ); +} + + +class CEgonAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + pev->classname = MAKE_STRING("ammo_egonclip"); + Precache( ); + SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_chainammo.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ); + + + +#endif diff --git a/dlls/bubblemod/BMOD_flyingcrowbar.cpp b/dlls/bubblemod/BMOD_flyingcrowbar.cpp new file mode 100644 index 00000000..9e0e0525 --- /dev/null +++ b/dlls/bubblemod/BMOD_flyingcrowbar.cpp @@ -0,0 +1,187 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" +#include "BMOD_flyingcrowbar.h" + +LINK_ENTITY_TO_CLASS( flying_crowbar, CFlyingCrowbar ); + +void CFlyingCrowbar::Spawn( ) +{ + Precache( ); + + // The flying crowbar is MOVETYPE_TOSS, and SOLID_BBOX. + // We want it to be affected by gravity, and hit objects + // within the game. + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_BBOX; + + // Use the world crowbar model. + SET_MODEL(ENT(pev), "models/w_crowbar.mdl"); + + // Set the origin and size for the HL engine collision + // tables. + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize(pev, Vector(-4, -4, -4), Vector(4, 4, 4)); + + // Store the owner for later use. We want the owner to be able + // to hit themselves with the crowbar. The pev->owner gets cleared + // later to avoid hitting the player as they throw the crowbar. + if ( pev->owner ) + m_hOwner = Instance( pev->owner ); + + // Set the think funtion. + SetThink( BubbleThink ); + pev->nextthink = gpGlobals->time + 0.25; + + // Set the touch function. + SetTouch( SpinTouch ); +} + + +void CFlyingCrowbar::Precache( ) +{ + PRECACHE_MODEL ("models/w_crowbar.mdl"); + PRECACHE_SOUND ("weapons/cbar_hitbod1.wav"); + PRECACHE_SOUND ("weapons/cbar_hit1.wav"); + PRECACHE_SOUND ("weapons/cbar_miss1.wav"); +} + + +void CFlyingCrowbar::SpinTouch( CBaseEntity *pOther ) +{ + // We touched something in the game. Look to see if the object + // is allowed to take damage. + if (pOther->pev->takedamage) + { + // Get the traceline info to the target. + TraceResult tr = UTIL_GetGlobalTrace( ); + + // Apply damage to the target. If we have an owner stored, use that one, + // otherwise count it as self-inflicted. + ClearMultiDamage( ); + pOther->TraceAttack(pev, 90, pev->velocity.Normalize(), &tr, + DMG_NEVERGIB ); + if (m_hOwner != NULL) + ApplyMultiDamage( pev, m_hOwner->pev ); + else + ApplyMultiDamage( pev, pev ); + } + + // If we hit a player, make a nice squishy thunk sound. Otherwise + // make a clang noise and throw a bunch of sparks. + if (pOther->IsPlayer()) + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/cbar_hitbod1.wav", + 1.0, ATTN_NORM, 0, 100); + else + { + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/cbar_hit1.wav", + 1.0, ATTN_NORM, 0, 100); + if (UTIL_PointContents(pev->origin) != CONTENTS_WATER) + { + UTIL_Sparks( pev->origin ); + UTIL_Sparks( pev->origin ); + UTIL_Sparks( pev->origin ); + } + } + + // Don't draw the flying crowbar anymore. + pev->effects |= EF_NODRAW; + pev->solid = SOLID_NOT; + + // Spawn a crowbar weapon + CBasePlayerWeapon *pItem = (CBasePlayerWeapon *)Create( "weapon_crowbar", + pev->origin , pev->angles, edict() ); + + // Spawn a weapon box + CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( + "weaponbox", pev->origin, pev->angles, edict() ); + + // don't let weapon box tilt. + pWeaponBox->pev->angles.x = 0; + pWeaponBox->pev->angles.z = 0; + + // remove the weapon box after 4 mins. + pWeaponBox->pev->nextthink = gpGlobals->time + 240; + pWeaponBox->SetThink( CWeaponBox::Kill ); + + // Pack the crowbar in the weapon box + pWeaponBox->PackWeapon( pItem ); + + // *** Start BubbleMod Rune code *** + // Check to see if the crowbar rune is active on the owner, + // if it is, then remove this crowbar after 3 seconds + // instead if 2 mins. This prevents too many crowbars from + // piling up on the server. + // + // REMOVE THIS IF YOU ARE NOT USING THE RUNE CODE + if (m_pPlayer->m_RuneFlags == RUNE_CROWBAR) + pWeaponBox->pev->nextthink = gpGlobals->time + 3; + // *** End BubbleMod Rune Code *** + + // Get the unit vector in the direction of motion. + Vector vecDir = pev->velocity.Normalize( ); + + // Trace a line along the velocity vector to get the normal at impact. + TraceResult tr; + UTIL_TraceLine(pev->origin, pev->origin + vecDir * 100, + dont_ignore_monsters, ENT(pev), &tr); + + // Throw the weapon box along the normal so it looks kinda + // like a ricochet. This would be better if I actually + // calcualted the reflection angle, but I'm lazy. :) + pWeaponBox->pev->velocity = tr.vecPlaneNormal * 300; + + // Remove this flying_crowbar from the world. + SetThink ( SUB_Remove ); + pev->nextthink = gpGlobals->time + .1; +} + +void CFlyingCrowbar::BubbleThink( void ) +{ + // We have no owner. We do this .25 seconds AFTER the crowbar + // is thrown so that we don't hit the owner immediately when throwing + // it. If is comes back later, we want to be able to hit the owner. + pev->owner = NULL; + + // Only think every .25 seconds. + pev->nextthink = gpGlobals->time + 0.25; + + // Make a whooshy sound. + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/cbar_miss1.wav", + 1, ATTN_NORM, 0, 120); + + // If the crowbar enters water, make some bubbles. + if (pev->waterlevel) + UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 1 ); +} diff --git a/dlls/bubblemod/BMOD_flyingcrowbar.h b/dlls/bubblemod/BMOD_flyingcrowbar.h new file mode 100644 index 00000000..36a6ac46 --- /dev/null +++ b/dlls/bubblemod/BMOD_flyingcrowbar.h @@ -0,0 +1,57 @@ +// --------------------------------------------------------------- +// Flying Crowbar Entity. Ver 1.0 as seen in Lambda BubbleMod +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- +// Flying Crowbar Entity + +#ifndef C_FLYING_CROWBAR +#define C_FLYING_CROWBAR + +class CFlyingCrowbar : public CBaseEntity +{ +public: + + void Spawn( void ); + void Precache( void ); + void EXPORT BubbleThink( void ); + void EXPORT SpinTouch( CBaseEntity *pOther ); + CBasePlayer *m_pPlayer; + +private: + + EHANDLE m_hOwner; // Original owner is stored here so we can + // allow the crowbar to hit the user. +}; + +#endif + + + + + + + + diff --git a/dlls/bubblemod/BMOD_gamerules.cpp b/dlls/bubblemod/BMOD_gamerules.cpp new file mode 100644 index 00000000..fba7f931 --- /dev/null +++ b/dlls/bubblemod/BMOD_gamerules.cpp @@ -0,0 +1,669 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "game.h" +#include "BMOD_constants.h" + +#define MAX_RULE_BUFFER 1024 + +extern DLL_GLOBAL int g_VoteStatus; +extern DLL_GLOBAL float g_VoteTimer; + +typedef struct mapcycle_item_s +{ + struct mapcycle_item_s *next; + + char mapname[ 32 ]; + int minplayers, maxplayers; + char rulebuffer[ MAX_RULE_BUFFER ]; +} mapcycle_item_t; + +typedef struct mapcycle_s +{ + struct mapcycle_item_s *items; + struct mapcycle_item_s *next_item; +} mapcycle_t; + +extern DLL_GLOBAL BOOL g_fGameOver; + +extern int gmsgSpectator; +extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); +extern int CountPlayers( void ); +extern void DestroyMapCycle( mapcycle_t *cycle ); +extern int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ); +extern void ExtractCommandString( char *s, char *szCommand ); + +extern cvar_t bm_guns; +extern cvar_t bm_ammo; +extern cvar_t bm_g; +extern cvar_t bm_cbar_mod; +extern cvar_t bm_mp5_mod; +extern cvar_t bm_shotty_mod; +extern cvar_t bm_xbow_mod; +extern cvar_t bm_rpg_mod; +extern cvar_t bm_tau_mod; +extern cvar_t bm_gluon_mod; +extern cvar_t bm_hornet_mod; +extern cvar_t bm_trip_mod; +extern cvar_t bm_snarks_mod; +extern cvar_t bm_spawneffects; +/* +extern cvar_t bm_score_crowbar; +extern cvar_t bm_score_throwncbar; +extern cvar_t bm_score_9mm; +extern cvar_t bm_score_357; +extern cvar_t bm_score_mp5; +extern cvar_t bm_score_shotgun; +extern cvar_t bm_score_squidspit; +extern cvar_t bm_score_zapgun; +extern cvar_t bm_score_mp5grenade; +extern cvar_t bm_score_gluon; +extern cvar_t bm_score_tau; +extern cvar_t bm_score_bolt; +extern cvar_t bm_score_crossbow; +extern cvar_t bm_score_satchel; +extern cvar_t bm_score_handgrenade; +extern cvar_t bm_score_rpg; +extern cvar_t bm_score_snarks; +extern cvar_t bm_score_tripmine; + +int CGameRules :: BMOD_IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled, entvars_t *pInflictor) +{ + if (g_pGameRules->IsTeamplay()) + { + if ( !pKilled ) + return 0; + + if ( !pAttacker ) + return 1; + + if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) + return -1; + } + + if (!strcmp(STRING(pInflictor->classname), "weapon_crowbar")) + return bm_score_crowbar.value; + else if (!strcmp(STRING(pInflictor->classname), "flying_crowbar")) + return bm_score_throwncbar.value; + else if (!strcmp(STRING(pInflictor->classname), "weapon_9mmhandgun")) + return bm_score_9mm.value; + else if (!strcmp(STRING(pInflictor->classname), "weapon_357")) + return bm_score_357.value; + else if (!strcmp(STRING(pInflictor->classname), "weapon_9mmAR")) + return bm_score_mp5.value; + else if (!strcmp(STRING(pInflictor->classname), "weapon_shotgun")) + return bm_score_shotgun.value; + else if (!strcmp(STRING(pInflictor->classname), "squidspit")) + return bm_score_squidspit.value; + else if (!strcmp(STRING(pInflictor->classname), "weapon_hornetgun")) + return bm_score_zapgun.value; + else if (!strcmp(STRING(pInflictor->classname), "weapon_egon")) + return bm_score_gluon.value; + else if (!strcmp(STRING(pInflictor->classname), "weapon_gauss")) + return bm_score_tau.value; + else if (!strcmp(STRING(pInflictor->classname), "bolt")) + return bm_score_bolt.value; + else if (!strcmp(STRING(pInflictor->classname), "weapon_crossbow")) + return bm_score_crossbow.value; + else if (!strcmp(STRING(pInflictor->classname), "monster_satchel")) + return bm_score_satchel.value; + else if (!strcmp(STRING(pInflictor->classname), "hand_grenade")) + return bm_score_handgrenade.value; + else if (!strcmp(STRING(pInflictor->classname), "rpg_rocket")) + return bm_score_rpg.value; + else if (!strcmp(STRING(pInflictor->classname), "monster_snark")) + return bm_score_snarks.value; + else + return 1; +} +*/ +void CHalfLifeMultiplay :: BMOD_ClientDisconnected(edict_t *pClient, CBasePlayer *pPlayer) +{ + // Disconnecting observers + //MESSAGE_BEGIN( MSG_ALL, gmsgSpectator ); + // WRITE_BYTE( ENTINDEX(pClient) ); + // WRITE_BYTE( 0 ); + //MESSAGE_END(); + + CBasePlayer *client = NULL; + while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) + { + if ( !client->pev ) + continue; + if ( client == pPlayer ) + continue; + + // If a spectator was chasing this player, move him/her onto the next player + if ( client->m_hObserverTarget == pPlayer ) + { + int iMode = client->pev->iuser1; + client->pev->iuser1 = 0; + client->m_hObserverTarget = NULL; + client->Observer_SetMode( iMode ); + } + } + + // Destroy all satchels, trips, and snark mines owned by this player. + DeactivateSatchels( pPlayer ); + DeactivateTrips( pPlayer ); + DeactivateSnarkTrips( pPlayer ); + + pPlayer->m_bIsConnected = FALSE; + UTIL_SaveRestorePlayer(pPlayer, 1, 0); +} + +void CHalfLifeMultiplay :: BMOD_PlayerSpawn( CBasePlayer *pPlayer ) +{ + // Send new players into observer mode. + if (!pPlayer->m_iFirstSpawn) + { + pPlayer->m_iFirstSpawn = TRUE; + edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer ); + pPlayer->StartObserver( VARS(pentSpawnSpot)->origin, VARS(pentSpawnSpot)->angles); + pPlayer->m_iSpawnKills = 0; + pPlayer->m_iTypeKills = 0; + pPlayer->m_bBanMe = FALSE; + UTIL_SaveRestorePlayer(pPlayer, 0, 0); + } + + // Else stuff for a new player. + else if (bm_spawneffects.value) { + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_TELEPORT ); //This denotes which temporary intity we want to use + WRITE_COORD(pPlayer->pev->origin.x);// Location-X + WRITE_COORD(pPlayer->pev->origin.y);// Location-Y + WRITE_COORD(pPlayer->pev->origin.z);// Location-Z + MESSAGE_END(); + + EMIT_SOUND(ENT(pPlayer->pev), CHAN_BODY, "debris/beamstart8.wav", 1.0, ATTN_NORM); + + } +} + +void CHalfLifeMultiplay :: BMOD_InitHUD( CBasePlayer *pl ) +{ + pl->m_bIsConnected = TRUE; + pl->m_iKillsThisFrame = 0; + pl->m_iSpamSay = 0; + pl->m_LocateMode = FALSE; + pl->m_LeetSpeak = FALSE; + // pl->m_iHLHack = 0; +} + +void CGameRules :: BMOD_PreChangeLevel( void ) +{ + return; +} + +void CHalfLifeMultiplay :: BMOD_PreChangeLevel( void ) +{ + static char szPreviousMapCycleFile[ 256 ]; + static mapcycle_t mapcycle; + + char szNextMap[32]; + char szFirstMapInList[32]; + char szCommands[ 1500 ]; + char szRules[ 1500 ]; + int minplayers = 0, maxplayers = 0; + strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 + + int curplayers; + BOOL do_cycle = TRUE; + + // find the map to change to + char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); + ASSERT( mapcfile != NULL ); + + szCommands[ 0 ] = '\0'; + szRules[ 0 ] = '\0'; + + curplayers = CountPlayers(); + + // Has the map cycle filename changed? + if ( stricmp( mapcfile, szPreviousMapCycleFile ) ) + { + strcpy( szPreviousMapCycleFile, mapcfile ); + + DestroyMapCycle( &mapcycle ); + + if ( !ReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) ) + { + ALERT( at_console, "Unable to load map cycle file %s\n", mapcfile ); + do_cycle = FALSE; + } + } + + if ( do_cycle && mapcycle.items ) + { + BOOL keeplooking = FALSE; + BOOL found = FALSE; + mapcycle_item_s *item; + + // Assume current map + strcpy( szNextMap, STRING(gpGlobals->mapname) ); + strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); + + // Traverse list + for ( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next ) + { + keeplooking = FALSE; + + ASSERT( item != NULL ); + + if ( item->minplayers != 0 ) + { + if ( curplayers >= item->minplayers ) + { + found = TRUE; + minplayers = item->minplayers; + } + else + { + keeplooking = TRUE; + } + } + + if ( item->maxplayers != 0 ) + { + if ( curplayers <= item->maxplayers ) + { + found = TRUE; + maxplayers = item->maxplayers; + } + else + { + keeplooking = TRUE; + } + } + + if ( keeplooking ) + continue; + + found = TRUE; + break; + } + + if ( !found ) + { + item = mapcycle.next_item; + } + + // Increment next item pointer + mapcycle.next_item = item->next; + + // Perform logic on current item + strcpy( szNextMap, item->mapname ); + + ExtractCommandString( item->rulebuffer, szCommands ); + strcpy( szRules, item->rulebuffer ); + } + + if ( !IS_MAP_VALID(szNextMap) ) + { + strcpy( szNextMap, szFirstMapInList ); + } + + CVAR_SET_STRING("bm_map", STRING(gpGlobals->mapname) ); + CVAR_SET_STRING("bm_nextmap", szNextMap ); +} + +// Bmod version of Changelevel +void CHalfLifeMultiplay :: ChangeLevel( void ) +{ + char szNextMap[32]; + + // Confirm what map we need. + // BMOD_PreChangeLevel(); + + strcpy( szNextMap, (char*)CVAR_GET_STRING( "bm_nextmap" ) ); + + g_fGameOver = TRUE; + + ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); + + CHANGE_LEVEL( szNextMap, NULL ); +} + +void CHalfLifeMultiplay :: BMOD_Think ( void ) +{ + static float setVarsTime = 0; + + if (setVarsTime < gpGlobals->time ) + { + g_engfuncs.pfnCvar_DirectSet( &bm_ver, UTIL_VarArgs( "%s", BMOD_VERSION ) ); + g_engfuncs.pfnCvar_DirectSet( &bm_bname, UTIL_VarArgs( "%s", BMOD_BRANCH_NAME ) ); + g_engfuncs.pfnCvar_DirectSet( &bm_bver, UTIL_VarArgs( "%s", BMOD_BRANCH_VERSION ) ); + g_engfuncs.pfnCvar_DirectSet( &bm_burl, UTIL_VarArgs( "%s", BMOD_BRANCH_URL ) ); + + BMOD_UpdateGuns(); + BMOD_UpdateMods(); + //UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( " updated at %f", gpGlobals->time)); + + setVarsTime = gpGlobals->time + 1; + } + + // BMod voting + if ((g_VoteStatus == 1) && (g_VoteTimer < gpGlobals->time)) + { + int players = CountPlayers(); + int votesNeeded = (players * 3 / 4) + ((players < 3) ? 1 : 0); + + char winner[81]; + strcpy(winner, UTIL_CountVotes()); + int winvotes = winner[0]; + char map[81]; + strcpy(map, &winner[1]); + + UTIL_SpeakAll("dadeda"); + if (winvotes >= votesNeeded) { + UTIL_ClientPrintAll( HUD_PRINTTALK, " *** We have a winner! ***\n"); + } + else { + UTIL_ClientPrintAll( HUD_PRINTTALK, " *** Voting is closed! ***\n"); + } + + /*if (winvotes) + UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( " \"%s\" got %i vote(s). (needed %i to win with %i players)\n", + &(winner[1]), + winvotes, + votesNeeded, + players ) );*/ + + if (winvotes == 0) + UTIL_ClientPrintAll( HUD_PRINTTALK, " No votes were cast!\n"); + + if (winvotes >= votesNeeded) + { + if (!strcmp(map, "extend")) { + UTIL_ClientPrintAll( HUD_PRINTTALK, " Extend won the vote! This map will be extended 30 mins & 25 kills.\n"); + int newTime = CVAR_GET_FLOAT("mp_timelimit") + 30; + int newFrags = CVAR_GET_FLOAT("mp_fraglimit") + 25; + CVAR_SET_FLOAT( "mp_timelimit", (newTime > bm_maxtime.value) ? bm_maxtime.value : newTime); + CVAR_SET_FLOAT( "mp_fraglimit", (newFrags > bm_maxfrags.value) ? bm_maxfrags.value : newFrags); + g_VoteStatus = 0; + } + else { + UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( " \"%s\" Won the vote! Changing map... please wait.\n", + &(winner[1]) + )); + CVAR_SET_STRING("bm_nextmap", &(winner[1])); + g_VoteStatus = 2; + g_VoteTimer = gpGlobals->time + 10; + } + UTIL_LogPrintf( "// Map \"%s\" won the map vote.\n", map); + } + else + { + if (winvotes) + UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( " \"%s\" got %i vote(s). (needed %i to win with %i players)\n", + &(winner[1]), + winvotes, + votesNeeded, + players ) ); + UTIL_LogPrintf( "// Map vote ended.\n", map); + g_VoteStatus = 0; + } + } + if ((g_VoteStatus == 2) && (g_VoteTimer < gpGlobals->time)) + { + g_VoteStatus = 0; + CVAR_SET_FLOAT( "mp_timelimit", 1); + } + // BMod +} + +void CHalfLifeMultiplay :: BMOD_GiveGunsAndAmmo ( CBasePlayer *pPlayer ) +{ + char *pName; + char itemlist[1025]; + char szTemp[80]; + int iszItem; + + // Give ammo + // make a copy because strtok is destructive + strncpy( itemlist, bm_ammo.string, 1024 ); + pName = itemlist; + pName = strtok( pName, ";" ); + while ( pName != NULL && *pName ) + { + strcpy( szTemp, "ammo_" ); + strcat( szTemp, pName ); + iszItem = ALLOC_STRING( szTemp ); + pPlayer->GiveNamedItem( STRING(iszItem) ); + pName = strtok( NULL, ";" ); + } + + // Give guns + // make a copy because strtok is destructive + strncpy( itemlist, bm_guns.string, 1024 ); + pName = itemlist; + pName = strtok( pName, ";" ); + int guns = 0; + while ( pName != NULL && *pName ) + { + strcpy( szTemp, "weapon_" ); + strcat( szTemp, pName ); + + if (!strcmp(szTemp, "weapon_glock")) + { + strcpy( szTemp, "weapon_9mmhandgun" ); + } + else if (!strcmp(szTemp, "weapon_mp5")) + { + strcpy( szTemp, "weapon_9mmAR" ); + } + else if (!strcmp(szTemp, "weapon_python")) + { + strcpy( szTemp, "weapon_357" ); + } + + iszItem = ALLOC_STRING( szTemp ); + pPlayer->GiveNamedItem( STRING(iszItem) ); + pPlayer->SelectItem( STRING(iszItem) ); + pName = strtok( NULL, ";" ); + } +} + +void CHalfLifeMultiplay :: BMOD_UpdateGuns ( void ) +{ + char *pName; + char itemlist[1024]; + + int guns = 0; + + // guns + // make a copy because strtok is destructive + strncpy( itemlist, bm_guns.string, 1024 ); + pName = itemlist; + pName = strtok( pName, ";" ); + while ( pName != NULL && *pName ) + { + if (!strcmp(pName, "crowbar")) + { + guns = guns | (1 << 0); + } + else if (!strcmp(pName, "9mmhandgun") || !strcmp(pName, "glock")) + { + guns = guns | (1 << 1); + } + else if (!strcmp(pName, "357") || !strcmp(pName, "python")) + { + guns = guns | (1 << 2); + } + else if (!strcmp(pName, "9mmAR") || !strcmp(pName, "mp5")) + { + guns = guns | (1 << 3); + } + else if (!strcmp(pName, "shotgun")) + { + guns = guns | (1 << 4); + } + else if (!strcmp(pName, "egon")) + { + guns = guns | (1 << 5); + } + else if (!strcmp(pName, "gauss")) + { + guns = guns | (1 << 6); + } + else if (!strcmp(pName, "rpg")) + { + guns = guns | (1 << 7); + } + else if (!strcmp(pName, "hornetgun")) + { + guns = guns | (1 << 8); + } + else if (!strcmp(pName, "tripmine")) + { + guns = guns | (1 << 9); + } + else if (!strcmp(pName, "satchel")) + { + guns = guns | (1 << 10); + } + else if (!strcmp(pName, "handgrenade")) + { + guns = guns | (1 << 11); + } + else if (!strcmp(pName, "snark")) + { + guns = guns | (1 << 12); + } + else if (!strcmp(pName, "crossbow")) + { + guns = guns | (1 << 13); + } + + pName = strtok( NULL, ";" ); + } + g_engfuncs.pfnCvar_DirectSet( &bm_g, UTIL_VarArgs( "%d", guns ) ); +} + +void CHalfLifeMultiplay :: BMOD_UpdateMods ( void ) +{ + + int mods = 0; + + // mods + // bm_cbar_mod + // bm_mp5_mod + // bm_shotty_mod + // bm_xbow_mod + // bm_rpg_mod + // bm_tau_mod + // bm_gluon_mod + // bm_hornet_mod + // bm_trip_mod + // bm_snarks_mod + + if (bm_cbar_mod.value) + { + mods = mods | (1 << 0); + } + + /* + if (!strcmp(pName, "9mmhandgun") || !strcmp(pName, "glock")) + { + mods = mods | (1 << 1); + } + */ + + /* + if (!strcmp(pName, "357") || !strcmp(pName, "python")) + { + mods = mods | (1 << 2); + } + */ + + if (bm_mp5_mod.value) + { + mods = mods | (1 << 3); + } + + if (bm_shotty_mod.value) + { + mods = mods | (1 << 4); + } + + if (bm_gluon_mod.value) + { + mods = mods | (1 << 5); + } + + if (bm_tau_mod.value) + { + mods = mods | (1 << 6); + } + + if (bm_rpg_mod.value) + { + mods = mods | (1 << 7); + } + + if (bm_hornet_mod.value) + { + mods = mods | (1 << 8); + } + + if (bm_trip_mod.value) + { + mods = mods | (1 << 9); + } + + /* + if (!strcmp(pName, "satchel")) + { + mods = mods | (1 << 10); + } + */ + + /* + if (!strcmp(pName, "handgrenade")) + { + mods = mods | (1 << 11); + } + */ + + if (bm_snarks_mod.value) + { + mods = mods | (1 << 12); + } + + if (bm_xbow_mod.value) + { + mods = mods | (1 << 13); + } + + + g_engfuncs.pfnCvar_DirectSet( &bm_mods, UTIL_VarArgs( "%d", mods ) ); +} \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_hornetgun.cpp b/dlls/bubblemod/BMOD_hornetgun.cpp new file mode 100644 index 00000000..b8935e5f --- /dev/null +++ b/dlls/bubblemod/BMOD_hornetgun.cpp @@ -0,0 +1,163 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "BMOD_hornetgun.h" + +//========================================================= +// Bullsquid's spit projectile +//========================================================= +class BMODSquidSpit : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + + static void Shoot( entvars_t *Owner, Vector vecStart, Vector vecVelocity ); + void Touch( CBaseEntity *pOther ); + void EXPORT Animate( void ); + + static TYPEDESCRIPTION m_SaveData[]; + + int m_maxFrame; + entvars_t *pevOwner; + +}; +LINK_ENTITY_TO_CLASS( bmod_squidspit, BMODSquidSpit ); + + +void BMODSquidSpit::Precache( void ) +{ + +} + +void BMODSquidSpit::Spawn( void ) +{ + pev->movetype = MOVETYPE_FLY; + pev->classname = MAKE_STRING( "bmod_squidspit" ); + + pev->solid = SOLID_BBOX; + pev->rendermode = kRenderTransAlpha; + pev->renderamt = 255; + + SET_MODEL(ENT(pev), "sprites/bigspit.spr"); + pev->frame = 0; + pev->scale = 0.5; + + UTIL_SetSize( pev, Vector( -4, -4, -4), Vector(4, 4, 4) ); + + m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMFOLLOW ); + WRITE_SHORT(entindex()); // entity + WRITE_SHORT(g_sModelIndexSmokeTrail ); // model + WRITE_BYTE( 2 ); // life + WRITE_BYTE( 4 ); // width + WRITE_BYTE( 128 ); // r, g, b + WRITE_BYTE( 200 ); // r, g, b + WRITE_BYTE( 0 ); // r, g, b + WRITE_BYTE( 255 ); // brightness + MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) + +} + +void BMODSquidSpit::Animate( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + if ( pev->frame++ ) + { + if ( pev->frame > m_maxFrame ) + { + pev->frame = 0; + } + } +} + +void BMODSquidSpit::Shoot( entvars_t *Owner, Vector vecStart, Vector vecVelocity ) +{ + BMODSquidSpit *pSpit = GetClassPtr( (BMODSquidSpit *)NULL ); + pSpit->Spawn(); + + UTIL_SetOrigin( pSpit->pev, vecStart ); + pSpit->pev->velocity = vecVelocity; + pSpit->pev->owner = ENT(Owner); + pSpit->pevOwner = Owner; + + pSpit->SetThink ( Animate ); + pSpit->pev->nextthink = gpGlobals->time + 0.1; +} + +void BMODSquidSpit::Touch ( CBaseEntity *pOther ) +{ + TraceResult tr; + int iPitch; + + // splat sound + iPitch = RANDOM_FLOAT( 90, 110 ); + + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); + + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); + break; + case 1: + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); + break; + } + + // make a splat on the wall + UTIL_TraceLine( pev->origin, pev->origin + pev->velocity, dont_ignore_monsters, ENT( pev ), &tr ); + UTIL_DecalTrace(&tr, DECAL_SPIT1 + RANDOM_LONG(0,1)); + + // make some flecks + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos ); + WRITE_BYTE( TE_SPRITE_SPRAY ); + WRITE_COORD( tr.vecEndPos.x); // pos + WRITE_COORD( tr.vecEndPos.y); + WRITE_COORD( tr.vecEndPos.z); + WRITE_COORD( tr.vecPlaneNormal.x); // dir + WRITE_COORD( tr.vecPlaneNormal.y); + WRITE_COORD( tr.vecPlaneNormal.z); + WRITE_SHORT( g_sModelIndexSpit ); // model + WRITE_BYTE ( 5 ); // count + WRITE_BYTE ( 30 ); // speed + WRITE_BYTE ( 80 ); // noise ( client will divide by 100 ) + MESSAGE_END(); + + if ( pOther->IsPlayer() ) + { + ClearMultiDamage( ); + pOther->TraceAttack( pevOwner, 30, pev->origin + pev->velocity, &tr, DMG_GENERIC ); + ApplyMultiDamage( pev, pevOwner ); + } + + SetThink ( SUB_Remove ); + pev->nextthink = gpGlobals->time; +} + diff --git a/dlls/bubblemod/BMOD_hornetgun.h b/dlls/bubblemod/BMOD_hornetgun.h new file mode 100644 index 00000000..2e80feca --- /dev/null +++ b/dlls/bubblemod/BMOD_hornetgun.h @@ -0,0 +1,72 @@ +#ifndef HORNETGUN_H +#define HORNETGUN_H + + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "hornet.h" +#include "gamerules.h" +#include "decals.h" +#include "BMOD_messaging.h" + +extern cvar_t bm_hornet_mod; + +#define HGUN_MAX_BEAMS 6 +#define HGUN_CHARGE_TIME .8 / HGUN_MAX_BEAMS +#define HGUN_ZAP_TIME 1 + +class CHgun : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 4; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + BOOL Deploy( void ); + BOOL IsUseable( void ); + void Holster( int skiplocal = 0 ); + void Reload( void ); + void Recharge( void ); + void WeaponIdle( void ); + float m_flNextAnimTime; + + float m_flRechargeTime; + + int m_iFirePhase;// don't save me. + float m_fNextPhaseTime; + CBeam *m_pBeam[HGUN_MAX_BEAMS]; + void ClearBeams( ); + void ArmBeam( Vector color ); + void ZapBeam( void ); + void BeamGlow( void ); + void FreezeRay( void ); + void ZapGun (void ); + void MultiZapGun (void ); + void SquidSpit ( void ); + void LaunchSnark ( void ); + void OldPrimaryAttack( void ); + void OldSecondaryAttack( void ); + + int m_iFireMode; + float m_fModeSwitchDelay; + int m_iBeams; + short m_sGlowSpr; + + int m_iMaxammo; + short iZapBeamSpr; +private: + unsigned short m_usHornetFire; + +}; + + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_messaging.cpp b/dlls/bubblemod/BMOD_messaging.cpp new file mode 100644 index 00000000..c424388a --- /dev/null +++ b/dlls/bubblemod/BMOD_messaging.cpp @@ -0,0 +1,121 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "BMOD_messaging.h" +#include "game.h" +#include "BMOD_constants.h" + +extern cvar_t timeleft; +extern cvar_t fragsleft; +// extern cvar_t timelimit; +extern cvar_t fraglimit; + +// pEnt is the player the message needs to go to +// iChannel is the message channel defind in BMOD_messaging.h +// vecColor is r, g, b color values for the message +// vecTime is fadein, hold, and fadeout times in seconds. +// msg is the message to display. +// +// Special msg values: +// "SPEC" - spectator message. +// +void PrintMessage( CBaseEntity *pEnt, int iChannel, Vector vecColor, Vector vecTime, char *msg) +{ + char szText[256]; + hudtextparms_t hText; + + if (!strcmp("SPEC", msg)) + { + char szTime[51] = "No Limit"; + + if (timeleft.value) + { + float time = timeleft.value; + sprintf(szTime, "%im, %is", (int)time/60, (int)time%60 ); + } + + // BMOD_PreChangeLevel(); + + sprintf(szText, "BUBBLE MOD - http://www.bubblemod.org\n%s Version %s - %s\n\nCurrent Map: %s\nNext Map: %s\nTime Left: %s\nFrags Left: %i/%i", + BMOD_BRANCH_NAME, + BMOD_BRANCH_VERSION, + BMOD_PLATFORM, + CVAR_GET_STRING("bm_map"), + CVAR_GET_STRING("bm_nextmap"), + szTime, + (int)fragsleft.value, + (int)fraglimit.value + ); + } + else { + sprintf(szText, msg); + } + + memset(&hText, 0, sizeof(hText)); + + switch (iChannel) + { + case BMOD_CHAN_INFO: + hText.x = 0.01; + hText.y = 0.1; + break; + + case BMOD_CHAN_RUNE: + hText.x = -1; + hText.y = 1; + break; + + case BMOD_CHAN_COUNTDOWN: + hText.x = -1; + hText.y = -1; + break; + + case BMOD_CHAN_WEAPON: + hText.x = -1; + hText.y = 0.875; + break; + } + + hText.a1 = 240; // Brightness + hText.a2 = 240; + + hText.r1 = vecColor.x; // Color + hText.r2 = vecColor.x; + hText.g1 = vecColor.y; + hText.g2 = vecColor.y; + hText.b1 = vecColor.z; + hText.b2 = vecColor.z; + + hText.channel = iChannel; // Channel + + hText.effect = 0; //Just fade in fade out + hText.fadeinTime = vecTime.x; + hText.fadeoutTime = vecTime.z; + hText.holdTime = vecTime.y; + hText.fxTime = 0.5; //Does nothing in this case + + UTIL_HudMessage(pEnt, hText, szText); +} diff --git a/dlls/bubblemod/BMOD_messaging.h b/dlls/bubblemod/BMOD_messaging.h new file mode 100644 index 00000000..e1d3a799 --- /dev/null +++ b/dlls/bubblemod/BMOD_messaging.h @@ -0,0 +1,44 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +// This contains the messaging functions for the spectator messages +// rune, and weapon info messages. + +#ifndef BMOD_MESSAGING +#define BMOD_MESSAGING + +#include "extdll.h" +#include "util.h" +#include "cbase.h" + +#define BMOD_CHAN_INFO 1 +#define BMOD_CHAN_RUNE 2 +#define BMOD_CHAN_COUNTDOWN 3 +#define BMOD_CHAN_WEAPON 4 + +void PrintMessage( CBaseEntity *pEnt, int iChannel, Vector vecColor, Vector vecTime, char *msg); + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_player.cpp b/dlls/bubblemod/BMOD_player.cpp new file mode 100644 index 00000000..4b3c3752 --- /dev/null +++ b/dlls/bubblemod/BMOD_player.cpp @@ -0,0 +1,704 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" + +#include "BMOD_messaging.h" +#include "BMOD_CameraPoint.h" +#include "BMOD_player.h" + +extern int gmsgCurWeapon; +extern int gmsgSetFOV; +extern int gmsgTeamInfo; +extern int gmsgSpectator; + +extern void respawn(entvars_t *pev, BOOL fCopyCorpse); + +extern cvar_t bm_spawnkilltime; +extern cvar_t bm_typekills; +extern cvar_t bm_bantime; +extern cvar_t bm_antispam; +extern cvar_t bm_spamlimit; +extern cvar_t bm_typecam; + +// Player has become a spectator. Set it up. +// This was moved from player.cpp. +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) +{ + // ?? + // clear any clientside entities attached to this player + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_KILLPLAYERATTACHMENTS ); + WRITE_BYTE( (BYTE)entindex() ); + MESSAGE_END(); + + // Holster weapon immediately, to allow it to cleanup + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + // ?? Let go of tanks? + if ( m_pTank != NULL ) + { + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + } + + // clear out the suit message cache so we don't keep chattering + SetSuitUpdate(NULL, FALSE, 0); + + // Tell Ammo Hud that the player is dead + MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); + WRITE_BYTE(0); + WRITE_BYTE(0XFF); + WRITE_BYTE(0xFF); + MESSAGE_END(); + + // reset FOV + m_iFOV = 0; + m_iClientFOV = -1; + pev->fov = m_iFOV; + SET_VIEW(edict(), edict()); + + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE(0); + MESSAGE_END(); + + // Setup flags + m_iHideHUD = (HIDEHUD_FLASHLIGHT | HIDEHUD_WEAPONS | HIDEHUD_HEALTH); + m_afPhysicsFlags |= PFLAG_OBSERVER; + pev->effects |= EF_NODRAW; + pev->view_ofs = g_vecZero; + pev->angles = pev->v_angle = vecViewAngle; + pev->fixangle = TRUE; + pev->solid = SOLID_NOT; + pev->takedamage = DAMAGE_NO; + pev->movetype = MOVETYPE_NOCLIP; + ClearBits( m_afPhysicsFlags, PFLAG_DUCKING ); + ClearBits( pev->flags, FL_DUCKING ); + pev->deadflag = DEAD_RESPAWNABLE; + pev->health = 1; + + // Clear out the status bar + m_fInitHUD = TRUE; + + // Update Team Status + // pev->team = 0; + + // Remove all the player's stuff + // RemoveAllItems( FALSE ); + + // Move them to the new position + UTIL_SetOrigin( pev, vecPosition ); + + // Find a player to watch + Observer_SetMode(OBS_ROAMING); + + // Tell all clients this player is now a spectator + //MESSAGE_BEGIN( MSG_ALL, gmsgSpectator ); + // WRITE_BYTE( ENTINDEX( edict() ) ); + // WRITE_BYTE( 1 ); + //MESSAGE_END(); + + //MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + // WRITE_BYTE( ENTINDEX(edict()) ); + // WRITE_STRING( "" ); + //MESSAGE_END(); + + m_fMsgTimer = gpGlobals->time + .5; + m_bSentMsg = FALSE; +} + +// Leave observer mode +void CBasePlayer::StopObserver( void ) +{ + // Turn off spectator + if ( pev->iuser1 || pev->iuser2 ) + { + // Tell all clients this player is not a spectator anymore + //MESSAGE_BEGIN( MSG_ALL, gmsgSpectator ); + // WRITE_BYTE( ENTINDEX( edict() ) ); + // WRITE_BYTE( 0 ); + //MESSAGE_END(); + + pev->iuser1 = pev->iuser2 = 0; + m_hObserverTarget = NULL; + m_iHideHUD = 0; + + //MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + // WRITE_BYTE( ENTINDEX(edict()) ); + // WRITE_STRING( m_szTeamName ); + //MESSAGE_END(); + } +} + +// Find the next client in the game for this player to spectate +void CBasePlayer::Observer_FindNextPlayer( bool bReverse ) +{ + + int iStart; + if ( m_hObserverTarget ) + iStart = ENTINDEX( m_hObserverTarget->edict() ); + else + iStart = ENTINDEX( edict() ); + int iCurrent = iStart; + m_hObserverTarget = NULL; + int iDir = 1; + + do + { + iCurrent += iDir; + + // Loop through the clients + if (iCurrent > gpGlobals->maxClients) + iCurrent = 1; + if (iCurrent < 1) + iCurrent = gpGlobals->maxClients; + + CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent ); + if ( !pEnt ) + continue; + if ( pEnt == this ) + continue; + // Don't spec observers or invisible players or defunct players + if ( ((CBasePlayer*)pEnt)->IsObserver() + || (pEnt->pev->effects & EF_NODRAW) + || (STRING(pEnt->pev->netname)[0] == 0) + || (!((CBasePlayer*)pEnt)->m_bIsConnected) + ) + continue; + + // MOD AUTHORS: Add checks on target here. + + m_hObserverTarget = pEnt; + break; + + } while ( iCurrent != iStart ); + + // Did we find a target? + if ( m_hObserverTarget ) + { + // Store the target in pev so the physics DLL can get to it + pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); + // Move to the target + UTIL_SetOrigin( pev, m_hObserverTarget->pev->origin ); + + // ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("Chase Camera: %s\n", STRING( m_hObserverTarget->pev->netname ) ) ); + ALERT( at_console, "Now Tracking %s\n", STRING( m_hObserverTarget->pev->netname ) ); + } + else + { + ALERT( at_console, "No observer targets.\n" ); + } +} + +// Handle buttons in observer mode +void CBasePlayer::Observer_HandleButtons() +{ + // Slow down mouse clicks + if ( m_fMsgTimer <= gpGlobals->time ) + { + // Show the observer mode instructions + if (!m_bSentMsg) + { + m_bSentMsg = TRUE; + PrintMessage( this, BMOD_CHAN_INFO, Vector (20,250,20), Vector (.5, 15, 2), "SPEC"); + PrintMessage( this, BMOD_CHAN_RUNE, Vector (20,250,20), Vector (.5, 86400, 2), + "-Spectator Mode-\n FIRE=Spawn JUMP=Switch Modes ALT FIRE=Switch Targets"); + } + + // Check to see if the observer wants to spray their logo + if (pev->impulse == 201) { + ImpulseCommands(); + } + + // Jump changes modes: Chase to Roaming + if ( pev->button & IN_JUMP ) + { + if ( pev->iuser1 == OBS_ROAMING ) + Observer_SetMode( OBS_CHASE_FREE ); + else + Observer_SetMode( OBS_ROAMING ); + m_fMsgTimer = gpGlobals->time + 0.2; + } + + // Attack2 cycles player targets + if ( pev->button & IN_ATTACK2 && pev->iuser1 != OBS_ROAMING ) + { + Observer_FindNextPlayer( false ); + m_fMsgTimer = gpGlobals->time + 0.2; + } + + // Attack Spawns + // if ( m_afButtonPressed & IN_ATTACK && pev->iuser1 != OBS_ROAMING ) + if ( pev->button & IN_ATTACK ) + { +// g_engfuncs.pfnServerPrint( "Player spawned from Obs!\n" ); + StopObserver(); + m_fMsgTimer = gpGlobals->time + 0.2; + } + } + + // clear attack/use commands from player + m_afButtonPressed = 0; + pev->button = 0; + m_afButtonReleased = 0; + + pev->impulse = 0; + if ((m_hObserverTarget != NULL) && (m_hObserverTarget->IsPlayer()) && (pev->iuser1 == OBS_CHASE_FREE)) + { + pev->origin = m_hObserverTarget->pev->origin; + pev->velocity = m_hObserverTarget->pev->velocity; + } +} + +// Attempt to change the observer mode +void CBasePlayer::Observer_SetMode( int iMode ) +{ + // Just abort if we're changing to the mode we're already in + if ( iMode == pev->iuser1 ) + return; + + // Changing to Roaming? + if ( iMode == OBS_ROAMING ) + { + // MOD AUTHORS: If you don't want to allow roaming observers at all in your mod, just abort here. + pev->iuser1 = OBS_ROAMING; + pev->iuser2 = 0; + m_hObserverTarget = NULL; + + ClientPrint( pev, HUD_PRINTCENTER, "#Spec_Mode3" ); + // pev->maxspeed = 320; + pev->maxspeed = 1000; + return; + } + + // Changing to Chase Lock? + if ( iMode == OBS_CHASE_LOCKED ) + { + // If changing from Roaming, or starting observing, make sure there is a target + if ( m_hObserverTarget == NULL ) + Observer_FindNextPlayer( false ); + + if (m_hObserverTarget) + { + pev->iuser1 = OBS_CHASE_LOCKED; + pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); + ClientPrint( pev, HUD_PRINTCENTER, "#Spec_Mode1" ); + pev->maxspeed = 0; + } + else + { + ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" ); + Observer_SetMode(OBS_ROAMING); + } + + return; + } + + // Changing to Chase Freelook? + if ( iMode == OBS_CHASE_FREE ) + { + // If changing from Roaming, or starting observing, make sure there is a target + // if ( m_hObserverTarget == NULL ) + if ( pev->iuser1 == OBS_ROAMING ) + Observer_FindNextPlayer( false ); + + if (m_hObserverTarget) + { + pev->iuser1 = OBS_CHASE_FREE; + pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); + // ClientPrint( pev, HUD_PRINTCENTER, "Chase-Camera Mode" ); + pev->maxspeed = 0; + } + else + { + ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" ); + Observer_SetMode(OBS_ROAMING); + } + + return; + } +} + +void CBasePlayer::BMOD_PreThink(void) +{ + // Bubblemod freeze ray + if (m_flFreezeTime > 0) + { + if (m_flFreezeTime <= gpGlobals->time) + { + EnableControl(TRUE); + // pev->movetype = MOVETYPE_WALK; + pev->rendermode = kRenderNormal; + pev->renderfx = kRenderFxNone; + pev->renderamt = 0; + + m_flFreezeTime = 0; + } + else + { + pev->v_angle = m_vFreezeAngle; + pev->fixangle = TRUE; + } + } + + // Bubblemod spawn + if ( + m_fSpawnTimeStamp && + m_fSpawnTimeStamp + bm_spawnkilltime.value >= gpGlobals->time && + m_iMessageFire + ) + { + PrintMessage( this, BMOD_CHAN_INFO, Vector (255,0,0), Vector (.1, bm_spawnkilltime.value, .1), + UTIL_VarArgs("Spawn Protection: %d seconds", (int)(m_fSpawnTimeStamp + bm_spawnkilltime.value - gpGlobals->time)) + ); + } + + if (m_fSpawnTimeStamp > 0 && + ((m_fSpawnTimeStamp + bm_spawnkilltime.value) <= gpGlobals->time) ) { + + if (m_RuneFlags == RUNE_NONE && + m_flFreezeTime == 0) { + pev->rendermode = kRenderNormal; + pev->renderfx = kRenderFxNone; + pev->renderamt = 0; + } + BMOD_ResetSpawnKill(); + } + + // Bubblemod runes + if (m_RuneFlags && (m_RuneTime < gpGlobals->time) ) + { + m_RuneFlags = RUNE_NONE; + pev->rendermode = kRenderNormal; + pev->renderfx = kRenderFxNone; + pev->renderamt = 0; + } + + // BubbleMod Type detection + if (pev->button & ~IN_SCORE ) { + BMOD_ResetTypeKill(); + } + + // Color the typer + if (BMOD_IsTyping() && + m_iMessageFire ) { + if (!(m_iMessageCounter % 2)) { + //MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + // WRITE_BYTE( TE_SMOKE ); + // WRITE_COORD( pev->origin.x ); + // WRITE_COORD( pev->origin.y ); + // WRITE_COORD( pev->origin.z - 36 ); + // WRITE_SHORT( g_sModelIndexSmoke ); + // WRITE_BYTE( 10 ); // scale * 10 + // WRITE_BYTE( 10 ); // framerate + //MESSAGE_END(); + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_SPRITE ); + WRITE_COORD( pev->origin.x + RANDOM_LONG( -10, 10) ); + WRITE_COORD( pev->origin.y + RANDOM_LONG( -10, 10) ); + WRITE_COORD( pev->origin.z + RANDOM_LONG( -30, 30) ); + WRITE_SHORT( g_sModelIndexFlare ); + WRITE_BYTE( 3 ); // scale * 10 + WRITE_BYTE( 255 ); // alpha + MESSAGE_END(); + } + float fCos = cos( gpGlobals->time * 4.00) * 8; + float fSin = sin( gpGlobals->time * 4.00) * 8; + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_BUBBLES ); + WRITE_COORD( pev->origin.x + fCos); + WRITE_COORD( pev->origin.y + fSin); + WRITE_COORD( pev->origin.z - 36 ); + WRITE_COORD( pev->origin.x + fCos); // mins + WRITE_COORD( pev->origin.y + fSin); + WRITE_COORD( pev->origin.z - 36 ); + WRITE_COORD( 75 ); // height + WRITE_SHORT( g_sModelIndexBubbles ); + WRITE_BYTE( 3 ); // count + WRITE_COORD( -1 ); // speed + MESSAGE_END(); + + // Away put your weapons! + //if (m_pActiveItem) { + // ResetAutoaim( ); + // m_pActiveItem->Holster( ); + // m_pActiveItem = NULL; + //} + m_pLastItem = m_pActiveItem; + + if (!m_bTypeMode) { + m_bTypeMode = TRUE; + // EnableControl(FALSE); + if (bm_typecam.value) { + // spawn a camera above us and use that for our view. + CCamPoint *pCam = (CCamPoint*)CBaseEntity::Create( "campoint", + pev->origin + Vector(0,0,40), + Vector(pev->angles.x + 22, pev->angles.y + 180, 0), + edict() ); + if (pCam) { + pCam->m_pOwner = this; + pCam->Think(); + // UTIL_ClientPrintAll( HUD_PRINTTALK, " Camera point created.\n"); + SET_VIEW(edict(), pCam->edict()); + SET_MODEL(ENT(pCam->pev), STRING(pev->model) ); + pev->fov = m_iFOV = 140; + } + } + } + } +} + +void CBasePlayer::BMOD_Think( void ) +{ + // BMOD End - Message delayer. + // Message delayer. USE THIS for general messages to players. + // counts tenths of seconds. + if (m_fMessageTimer < gpGlobals->time) + { + m_fMessageTimer = gpGlobals->time + .1; + m_iMessageCounter++; + m_iMessageFire = TRUE; + } + + // Locator + if (m_LocateMode && m_iMessageFire) { + int yang = (int)pev->angles.y; + if (yang < 0) + yang += 360; + + ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("Location: %dx %dy %dz, facing %d", + (int)pev->origin.x, + (int)pev->origin.y, + (int)pev->origin.z, + yang + ) ); + } + + // Llamas! + if (m_IsLlama && m_iMessageFire && !(m_iMessageCounter%5)) { + CLIENT_COMMAND(edict(), "drop\n"); + } + + // Autoban + if (m_bBanMe && m_iMessageFire) + { + char cmd[81] = ""; + sprintf( cmd, "banid %d %s kick\n", (int)bm_bantime.value, GETPLAYERAUTHID( edict() )); + SERVER_COMMAND(cmd); + } + + // BMOD Begin - Spam Kick + if (m_iMessageFire && !(m_iMessageCounter%10) && m_iSpamSay) + { + m_iSpamSay--; + } + + if (bm_antispam.value && m_iSpamSay > bm_spamlimit.value) + { + char cmd[81] = ""; + sprintf( cmd, "kick # %u\n", GETPLAYERUSERID( edict() )); + SERVER_COMMAND(cmd); + UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( " %s was kicked for spamming.\n", + STRING( pev->netname ))); + UTIL_LogPrintf( "\"SERVER<-1><-1><>\" say \"%s was was kicked for spamming.\"\n", + STRING( pev->netname )); + UTIL_LogPrintf( "// \"%s<%i><%s><%s>\" was kicked for spamming.\n", + STRING( pev->netname ), + GETPLAYERUSERID( edict() ), + GETPLAYERAUTHID( edict() ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( edict() ), "model" ) + ); + m_iSpamSay = 0; + } + // BMOD End - Spam Kick + + +} + +void CBasePlayer::BMOD_PostThink( void ) +{ + +} + +void CBasePlayer::BMOD_Identify( void ) +{ + static float timer = gpGlobals->time; + static CBasePlayer *LastIdentPlayer = NULL; + + TraceResult tr; + + CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pev); + + Vector anglesAim = pPlayer->pev->v_angle; + UTIL_MakeVectors( anglesAim ); + anglesAim.x = -anglesAim.x; + Vector vecSrc = pPlayer->GetGunPosition( ) - gpGlobals->v_up * 1; + Vector vecDir = gpGlobals->v_forward; + + gpGlobals->trace_flags = FTRACE_SIMPLEBOX; + UTIL_TraceLine(vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, ENT(pPlayer->pev), &tr); + + CBaseEntity *pOther = CBaseEntity::Instance( tr.pHit ); + + // Do we have our nose in a wall? + if (((tr.vecEndPos - vecSrc).Length() > 40) || pOther->IsPlayer()) { + BMOD_ResetTypeKill(); + } + + if ( pOther->IsPlayer() && + ( + (CBasePlayer *)pOther != LastIdentPlayer || + timer <= gpGlobals->time + ) + ) + { + char szExtra[81] = "\n"; + if (((CBasePlayer *)pOther)->BMOD_IsASpawn()) { + strcat(szExtra, "\nFresh Spawn! DO NOT SHOOT!"); + } + if (((CBasePlayer *)pOther)->BMOD_IsTyping()) { + strcat(szExtra, "\nTyping! DO NOT SHOOT!"); + } + + CBasePlayer *pPlayer = (CBasePlayer *)pOther; + if (IsObserver()) + ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("-%s-\n(%s) %i / %i%s", + STRING( pPlayer->pev->netname ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ), + (int)pPlayer->pev->health, + (int)pPlayer->pev->armorvalue, + szExtra + ) ); + else if ( g_pGameRules->PlayerRelationship( pOther, this ) == GR_TEAMMATE ) + ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("-%s-\n%i / %i", + STRING( pPlayer->pev->netname ), + (int)pPlayer->pev->health, + (int)pPlayer->pev->armorvalue) + ); + else + ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("-%s-\n(%s)%s", + STRING( pPlayer->pev->netname ), + g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ), + szExtra + ) ); + + timer = gpGlobals->time + .5; + LastIdentPlayer = (CBasePlayer *)pOther; + } + else if (!pOther->IsPlayer()) { + LastIdentPlayer = NULL; + } +} + +int CBasePlayer::BMOD_WasSpawnKilled( void ) +{ + if ( !IsAlive() && + m_fSpawnTimeStamp && + ((m_fSpawnTimeStamp + bm_spawnkilltime.value) > gpGlobals->time) && + bm_spawnkilltime.value) + return TRUE; + return FALSE; +} + +int CBasePlayer::BMOD_IsASpawn( void ) +{ + if ( IsAlive() && + m_fSpawnTimeStamp && + ((m_fSpawnTimeStamp + bm_spawnkilltime.value) > gpGlobals->time) && + bm_spawnkilltime.value) + return TRUE; + return FALSE; +} + +void CBasePlayer::BMOD_ResetSpawnKill( void ) +{ + + + if (m_RuneFlags == RUNE_NONE && + m_flFreezeTime == 0) { + pev->rendermode = kRenderNormal; + pev->renderfx = kRenderFxNone; + pev->renderamt = 0; + } + m_fSpawnTimeStamp = 0; + PrintMessage( this, BMOD_CHAN_INFO, Vector (20,250,20), Vector (.1, 1, .1), ""); +} + + +int CBasePlayer::BMOD_WasTypeKilled( void ) +{ + if ( !IsAlive() && + m_flTypeKillStamp > 0 && + m_flTypeKillStamp < gpGlobals->time && + !bm_typekills.value ) + return TRUE; + return FALSE; +} + +int CBasePlayer::BMOD_IsTyping( void ) +{ + if ( IsAlive() && + m_flTypeKillStamp && + m_flTypeKillStamp < gpGlobals->time && + !bm_typekills.value ) { + + // Do we have a crowbar? + if (m_pActiveItem != NULL && + strcmp("weapon_crowbar", STRING(m_pActiveItem->pev->classname)) + ) + { + BMOD_ResetTypeKill(); + return FALSE; + } + + return TRUE; + } + return FALSE; +} + +void CBasePlayer::BMOD_ResetTypeKill( void ) +{ + if ( IsAlive() ) { + // make a sound if we are coming out of type mode. + if (m_bTypeMode) + { + EMIT_SOUND(ENT(pev), CHAN_VOICE, "fvox/alert.wav", 1.0, ATTN_NORM); + SET_VIEW(edict(), edict()); + pev->fov = m_iFOV = 0; + } + m_bTypeMode = FALSE; + // EnableControl(TRUE); + m_flTypeKillStamp = gpGlobals->time + 4; + } + return; +} + diff --git a/dlls/bubblemod/BMOD_player.h b/dlls/bubblemod/BMOD_player.h new file mode 100644 index 00000000..efa41db6 --- /dev/null +++ b/dlls/bubblemod/BMOD_player.h @@ -0,0 +1,53 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#ifndef BMOD_PLAYER_H +#define BMOD_PLAYER_H + +#define OBS_CHASE_LOCKED 1 +#define OBS_CHASE_FREE 2 +#define OBS_ROAMING 3 +/* +typedef enum +{ + RUNE_NONE, + RUNE_CROWBAR, + RUNE_GRENADE, + RUNE_357, + RUNE_HEALTH, + RUNE_BATTERY, + RUNE_SHOTGUN, +} RUNE_FLAGS; +*/ +#define RUNE_NONE 0 +#define RUNE_CROWBAR (1<<0) +#define RUNE_GRENADE (1<<1) +#define RUNE_357 (1<<2) +#define RUNE_HEALTH (1<<3) +#define RUNE_BATTERY (1<<4) +#define RUNE_SHOTGUN (1<<5) + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_rune.cpp b/dlls/bubblemod/BMOD_rune.cpp new file mode 100644 index 00000000..9c5f3bdb --- /dev/null +++ b/dlls/bubblemod/BMOD_rune.cpp @@ -0,0 +1,444 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "weapons.h" +#include "player.h" +#include "skill.h" +#include "items.h" +#include "gamerules.h" +#include "BMOD_rune.h" +#include "BMOD_messaging.h" +#include "BMOD_player.h" + +#define RUNE_MODEL "models/w_oxygen.mdl" + +extern DLL_GLOBAL BOOL g_runes_learn; +extern cvar_t bm_runemask; + +void CRune::Spawn( void ) +{ + Precache(); + // SET_MODEL(ENT(pev), RUNE_MODEL); + pev->movetype = MOVETYPE_BOUNCE; + pev->solid = SOLID_TRIGGER; + pev->classname = MAKE_STRING("rune"); + + pev->renderfx |= kRenderFxGlowShell; + pev->rendercolor = m_vRuneColor; + pev->renderamt = 50; + + m_randomize = FALSE; + + UTIL_SetOrigin( pev, pev->origin ); + UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); + SetTouch(RuneTouch); + + pev->effects |= EF_NODRAW; + SetThink ( Materialize ); + pev->nextthink = gpGlobals->time + RANDOM_FLOAT(.5, 2); + + if (DROP_TO_FLOOR(ENT(pev)) == 0) + { + ALERT(at_error, "Item %s fell out of level at %f,%f,%f", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z); + UTIL_Remove( this ); + return; + } +} + +void CRune::RuneTouch( CBaseEntity *pOther ) +{ + + // if it's not a player, just bounce + if ( !pOther->IsPlayer() ) + { + + if (!pev->velocity) + return; + + TraceResult tr; + UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,10), ignore_monsters, edict(), &tr ); + + if ( tr.flFraction < 1.0 ) + { + // add a bit of static friction + pev->velocity = pev->velocity * 0.5; + } + return; + } + + + CBasePlayer *pPlayer = (CBasePlayer *)pOther; + + if (!pPlayer->BMOD_IsASpawn() && MyTouch( pPlayer )) + { + pPlayer->pev->rendermode = kRenderNormal; + pPlayer->pev->renderfx = kRenderFxGlowShell; + pPlayer->pev->rendercolor = m_vRuneColor; + pPlayer->pev->renderamt = 10; // glow shell distance from entity + + SetTouch( NULL ); + Respawn(); + } +} + +CBaseEntity* CRune::Respawn( void ) +{ + pev->effects |= EF_NODRAW; + + if (m_randomize) + SetThink ( MaterializeRandom ); + else + SetThink ( Materialize ); + + return this; +} + +void CRune::MaterializeRandom ( void ) +{ + // Make sure at least one rune type is allowed + if (!((int)bm_runemask.value & 63)) + { + UTIL_Remove( this ); + return; + } + + CBaseEntity *NewRune = NULL; + int rand = 1; + + for (int i = 0; i < RANDOM_LONG(3,10); i++) + { + do { + rand *= 2; + if (rand > 63) + rand = 1; + } while (!(rand & (int)bm_runemask.value)); + } + + if (rand == RUNE_CROWBAR) + NewRune = CBaseEntity::Create("item_CrowbarRune", pev->origin, Vector (0,0,0), NULL ); + else if (rand == RUNE_GRENADE) + NewRune = CBaseEntity::Create("item_GrenadeRune", pev->origin, Vector (0,0,0), NULL ); + else if (rand == RUNE_357) + NewRune = CBaseEntity::Create("item_357Rune", pev->origin, Vector (0,0,0), NULL ); + else if (rand == RUNE_HEALTH) + NewRune = CBaseEntity::Create("item_HealthRune", pev->origin, Vector (0,0,0), NULL ); + else if (rand == RUNE_BATTERY) + NewRune = CBaseEntity::Create("item_BatteryRune", pev->origin, Vector (0,0,0), NULL ); + else if (rand == RUNE_SHOTGUN) + NewRune = CBaseEntity::Create("item_ShotgunRune", pev->origin, Vector (0,0,0), NULL ); + + ((CRune *)NewRune)->m_randomize = TRUE; + UTIL_Remove( this ); +} + +void CRune::Materialize( void ) +{ + // Pool of random spawn points. + static Vector spawnPoints[200]; + + // Populate the random spawn point pool. + if (!g_runes_learn) { + g_runes_learn = TRUE; + CBaseEntity *pSpot = NULL; + for ( int i = 0; i < 200; i++ ) { + do + pSpot = UTIL_FindEntityInSphere( pSpot, Vector(0,0,0), 4096 ); + while (pSpot==NULL || + !( + !strcmp(STRING(pSpot->pev->classname), "info_player_deathmatch") | + !strncmp(STRING(pSpot->pev->classname), "weapon_", 7) | + !strncmp(STRING(pSpot->pev->classname), "ammo_", 5) + )); + spawnPoints[i] = pSpot->pev->origin; + } + + } + + if ( pev->effects & EF_NODRAW ) + { + pev->angles.x = 0; + pev->angles.z = 0; + pev->origin = spawnPoints[RANDOM_LONG(0, 199)]; + + pev->velocity.x = RANDOM_FLOAT( .5, 2 ); + if (RANDOM_LONG(0,1)) + pev->velocity.x = pev->velocity.x * -1; + + pev->velocity.y = RANDOM_FLOAT( .5, 2 ); + if (RANDOM_LONG(0,1)) + pev->velocity.y = pev->velocity.y * -1; + + pev->velocity.z = RANDOM_FLOAT( .5, 2 ); + pev->avelocity.y = RANDOM_FLOAT( 0, 100 ); + pev->velocity = pev->velocity.Normalize() * 300; + + // changing from invisible state to visible. + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); + pev->effects &= ~EF_NODRAW; + pev->effects |= EF_MUZZLEFLASH; + + SetTouch( RuneTouch ); + } + // EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "buttons/blip2.wav", 1, ATTN_NORM, 0, 150 ); + pev->nextthink = gpGlobals->time + 2; +} + +void CRune::Precache( void ) +{ + PRECACHE_MODEL (RUNE_MODEL); + PRECACHE_SOUND ("buttons/blip2.wav"); +} + +LINK_ENTITY_TO_CLASS( item_rune, CRune ); + +//////////////////////////////////////////////// +// Crowbar rune +//////////////////////////////////////////////// +#define CROWBARRUNE_MODEL "models/w_crowbar.mdl" +class CCrowbarRune : public CRune +{ + void Spawn ( void ) + { + m_vRuneColor = Vector(255,20,20); + SET_MODEL(ENT(pev), CROWBARRUNE_MODEL); + CRune::Spawn(); + + } + void Precache( void ) + { + PRECACHE_MODEL (CROWBARRUNE_MODEL); + } + BOOL MyTouch (CBasePlayer *pPlayer ) + { + // One rune at a time folks. + if (!pPlayer->m_RuneFlags) + { + float time = max(1, CVAR_GET_FLOAT("bm_rune_cbar_t")); + float respawn = max(1, CVAR_GET_FLOAT("bm_rune_cbar_r")); + + //RuneMsg( pPlayer, MSG_RUNE_CROWBAR, m_vRuneColor, time - .5); + PrintMessage( pPlayer, BMOD_CHAN_RUNE, m_vRuneColor, Vector (.1, time - .5, .1), "SUPER CROWBAR\nIncreased crowbar damage / infinite throws."); + + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + pPlayer->m_RuneFlags = RUNE_CROWBAR; + pPlayer->m_RuneTime = gpGlobals->time + time; + pev->nextthink = gpGlobals->time + respawn; + return TRUE; + } + else + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( item_CrowbarRune, CCrowbarRune ); + +//////////////////////////////////////////////// +// Grenade rune +//////////////////////////////////////////////// +#define GRENADERUNE_MODEL "models/w_grenade.mdl" +class CGrenadeRune : public CRune +{ + void Spawn ( void ) + { + m_vRuneColor = Vector(255,128,0); + SET_MODEL(ENT(pev), GRENADERUNE_MODEL); + CRune::Spawn(); + } + void Precache( void ) + { + PRECACHE_MODEL (GRENADERUNE_MODEL); + } + BOOL MyTouch (CBasePlayer *pPlayer ) + { + // One rune at a time folks. + if (!pPlayer->m_RuneFlags) + { + float time = max(1, CVAR_GET_FLOAT("bm_rune_gren_t")); + float respawn = max(1, CVAR_GET_FLOAT("bm_rune_gren_r")); + + PrintMessage( pPlayer, BMOD_CHAN_RUNE, m_vRuneColor, Vector (.1, time - .5, .1), "MEGA GRENADE\nIncreased hand grenade damage."); + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + pPlayer->m_RuneFlags = RUNE_GRENADE; + pPlayer->m_RuneTime = gpGlobals->time + time; + pev->nextthink = gpGlobals->time + respawn; + return TRUE; + } + else + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( item_GrenadeRune, CGrenadeRune ); + + +//////////////////////////////////////////////// +// Health rune +//////////////////////////////////////////////// +#define HEALTHRUNE_MODEL "models/w_medkit.mdl" +class CHealthRune : public CRune +{ + void Spawn ( void ) + { + m_vRuneColor = Vector(20,255,20); + SET_MODEL(ENT(pev), HEALTHRUNE_MODEL); + CRune::Spawn(); + } + void Precache( void ) + { + PRECACHE_MODEL (HEALTHRUNE_MODEL); + } + BOOL MyTouch (CBasePlayer *pPlayer ) + { + // One rune at a time folks. + if (!pPlayer->m_RuneFlags) + { + float time = max(1, CVAR_GET_FLOAT("bm_rune_health_t")); + float respawn = max(1, CVAR_GET_FLOAT("bm_rune_health_r")); + PrintMessage( pPlayer, BMOD_CHAN_RUNE, m_vRuneColor, Vector (.1, time - .5, .1), "DOUBLE HEALTH PICKUPS\nMed packs / machines give 2X health. Fast Heal on Bubble Gun."); + + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + pPlayer->m_RuneFlags = RUNE_HEALTH; + pPlayer->m_RuneTime = gpGlobals->time + time; + pev->nextthink = gpGlobals->time + respawn; + return TRUE; + } + else + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( item_HealthRune, CHealthRune ); + +//////////////////////////////////////////////// +// Battery rune +//////////////////////////////////////////////// +#define BATTERYRUNE_MODEL "models/w_battery.mdl" +class CBatteryRune : public CRune +{ + void Spawn ( void ) + { + m_vRuneColor = Vector(0,255,255); + SET_MODEL(ENT(pev), BATTERYRUNE_MODEL); + CRune::Spawn(); + } + void Precache( void ) + { + PRECACHE_MODEL (BATTERYRUNE_MODEL); + } + BOOL MyTouch (CBasePlayer *pPlayer ) + { + // One rune at a time folks. + if (!pPlayer->m_RuneFlags) + { + float time = max(1, CVAR_GET_FLOAT("bm_rune_armor_t")); + float respawn = max(1, CVAR_GET_FLOAT("bm_rune_armor_r")); + + PrintMessage( pPlayer, BMOD_CHAN_RUNE, m_vRuneColor, Vector (.1, time - .5, .1), "DOUBLE ARMOR PICKUPS\nArmor batteries / machines give 2X armor. Bubble Gun gives armor."); + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + pPlayer->m_RuneFlags = RUNE_BATTERY; + pPlayer->m_RuneTime = gpGlobals->time + time; + pev->nextthink = gpGlobals->time + respawn; + return TRUE; + } + else + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( item_BatteryRune, CBatteryRune ); + +//////////////////////////////////////////////// +// 357 rune +//////////////////////////////////////////////// +#define _357RUNE_MODEL "models/w_357.mdl" +class C357Rune : public CRune +{ + void Spawn ( void ) + { + m_vRuneColor = Vector(250,20,250); + SET_MODEL(ENT(pev), _357RUNE_MODEL); + CRune::Spawn(); + } + void Precache( void ) + { + PRECACHE_MODEL (_357RUNE_MODEL); + } + BOOL MyTouch (CBasePlayer *pPlayer ) + { + // One rune at a time folks. + if (!pPlayer->m_RuneFlags) + { + float time = max(1, CVAR_GET_FLOAT("bm_rune_357_t")); + float respawn = max(1, CVAR_GET_FLOAT("bm_rune_357_r")); + + PrintMessage( pPlayer, BMOD_CHAN_RUNE, m_vRuneColor, Vector (.1, time - .5, .1), "SUPER MAGNUM\nIncreased magnum damage."); + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + pPlayer->m_RuneFlags = RUNE_357; + pPlayer->m_RuneTime = gpGlobals->time + time; + pev->nextthink = gpGlobals->time + respawn; + return TRUE; + } + else + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( item_357Rune, C357Rune ); + +//////////////////////////////////////////////// +// Shotgun rune +//////////////////////////////////////////////// +#define SHOTGUNRUNE_MODEL "models/w_shotgun.mdl" +class CShotgunRune : public CRune +{ + void Spawn ( void ) + { + m_vRuneColor = Vector(20,20,255); + SET_MODEL(ENT(pev), SHOTGUNRUNE_MODEL); + CRune::Spawn(); + } + void Precache( void ) + { + PRECACHE_MODEL (SHOTGUNRUNE_MODEL); + } + BOOL MyTouch (CBasePlayer *pPlayer ) + { + // One rune at a time folks. + if (!pPlayer->m_RuneFlags) + { + float time = max(1, CVAR_GET_FLOAT("bm_rune_shotty_t")); + float respawn = max(1, CVAR_GET_FLOAT("bm_rune_shotty_r")); + + PrintMessage( pPlayer, BMOD_CHAN_RUNE, m_vRuneColor, Vector (.1, time - .5, .1), "SUPER SHOTGUN\nIncreased shotgun speed / fast reload."); + EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); + pPlayer->m_RuneFlags = RUNE_SHOTGUN; + pPlayer->m_RuneTime = gpGlobals->time + time; + pev->nextthink = gpGlobals->time + respawn; + return TRUE; + } + else + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( item_ShotgunRune, CShotgunRune ); diff --git a/dlls/bubblemod/BMOD_rune.h b/dlls/bubblemod/BMOD_rune.h new file mode 100644 index 00000000..4c750221 --- /dev/null +++ b/dlls/bubblemod/BMOD_rune.h @@ -0,0 +1,49 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- +// Runes + + +#ifndef RUNE_H +#define RUNE_H + +class CRune : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache(void); + CBaseEntity* Respawn( void ); + void EXPORT RuneTouch( CBaseEntity *pOther ); + void EXPORT Materialize( void ); + void EXPORT MaterializeRandom( void ); + virtual BOOL MyTouch( CBasePlayer *pPlayer ) { EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); return TRUE; }; + BOOL IsRune( void ) { return TRUE; } + virtual char* RuneName ( void ) { return "Generic Rune"; } + + BOOL m_randomize; + Vector m_vRuneColor; +}; + +#endif // RUNE_H diff --git a/dlls/bubblemod/BMOD_snarkmine.cpp b/dlls/bubblemod/BMOD_snarkmine.cpp new file mode 100644 index 00000000..79428fc0 --- /dev/null +++ b/dlls/bubblemod/BMOD_snarkmine.cpp @@ -0,0 +1,524 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- +// Snark Mines + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "effects.h" +#include "gamerules.h" +#include "BMOD_snarkmine.h" + +#define TRIPMINE_PRIMARY_VOLUME 450 +#define TRIPSNARK_FLARE "sprites/xspark3.spr" + +extern cvar_t bm_spawnmines; + +enum tripmine_e { + TRIPMINE_IDLE1 = 0, + TRIPMINE_IDLE2, + TRIPMINE_ARM1, + TRIPMINE_ARM2, + TRIPMINE_FIDGET, + TRIPMINE_HOLSTER, + TRIPMINE_DRAW, + TRIPMINE_WORLD, + TRIPMINE_GROUND, +}; + +LINK_ENTITY_TO_CLASS( monster_tripsnark, CTripSnarkGrenade ); + +TYPEDESCRIPTION CTripSnarkGrenade::m_SaveData[] = +{ + DEFINE_FIELD( CTripSnarkGrenade, m_flPowerUp, FIELD_TIME ), + DEFINE_FIELD( CTripSnarkGrenade, m_vecDir, FIELD_VECTOR ), + DEFINE_FIELD( CTripSnarkGrenade, m_vecEnd, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CTripSnarkGrenade, m_flBeamLength, FIELD_FLOAT ), + DEFINE_FIELD( CTripSnarkGrenade, m_hOwner, FIELD_EHANDLE ), + DEFINE_FIELD( CTripSnarkGrenade, m_pBeam, FIELD_CLASSPTR ), + DEFINE_FIELD( CTripSnarkGrenade, m_posOwner, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( CTripSnarkGrenade, m_angleOwner, FIELD_VECTOR ), + DEFINE_FIELD( CTripSnarkGrenade, m_pRealOwner, FIELD_EDICT ), +}; + +IMPLEMENT_SAVERESTORE(CTripSnarkGrenade,CGrenade); + + +void CTripSnarkGrenade :: Spawn( void ) +{ + Precache( ); + // motor + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_NOT; + + SET_MODEL(ENT(pev), "models/v_tripmine.mdl"); + pev->frame = 0; + pev->body = 3; + pev->sequence = TRIPMINE_WORLD; + ResetSequenceInfo( ); + pev->framerate = 0; + + UTIL_SetSize(pev, Vector( -8, -8, -8), Vector(8, 8, 8)); + UTIL_SetOrigin( pev, pev->origin ); + + if (pev->spawnflags & 1) + { + // power up quickly + m_flPowerUp = gpGlobals->time + 1.0; + } + else + { + // power up in 2.5 seconds + m_flPowerUp = gpGlobals->time + 2.5; + } + + SetThink( PowerupThink ); + pev->nextthink = gpGlobals->time + 0.2; + + pev->takedamage = DAMAGE_YES; + // pev->dmg = gSkillData.plrDmgTripmine; + pev->health = 1; // don't let die normally + + if (pev->owner != NULL) + { + // play deploy sound + EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav", 1.0, ATTN_NORM ); + EMIT_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav", 0.2, ATTN_NORM ); // chargeup + + m_pRealOwner = pev->owner;// see CTripSnarkGrenade for why. + } + + UTIL_MakeAimVectors( pev->angles ); + + m_vecDir = gpGlobals->v_forward; + m_vecEnd = pev->origin + m_vecDir * 2048; +} + + +void CTripSnarkGrenade :: Precache( void ) +{ + PRECACHE_MODEL("models/v_tripmine.mdl"); + PRECACHE_SOUND("weapons/mine_deploy.wav"); + PRECACHE_SOUND("squeek/sqk_deploy1.wav"); + PRECACHE_SOUND("weapons/mine_charge.wav"); + PRECACHE_SOUND("debris/beamstart2.wav"); + PRECACHE_MODEL( TRIPSNARK_FLARE ); + m_LaserSprite = PRECACHE_MODEL( "sprites/laserbeam.spr" ); +} + + +void CTripSnarkGrenade :: WarningThink( void ) +{ + // play warning sound + // EMIT_SOUND( ENT(pev), CHAN_VOICE, "buttons/Blip2.wav", 1.0, ATTN_NORM ); + + // set to power up + SetThink( PowerupThink ); + pev->nextthink = gpGlobals->time + 1.0; +} + + +void CTripSnarkGrenade :: PowerupThink( void ) +{ + TraceResult tr; + + if (m_hOwner == NULL) + { + // find an owner + edict_t *oldowner = pev->owner; + pev->owner = NULL; + UTIL_TraceLine( pev->origin + m_vecDir * 8, pev->origin - m_vecDir * 32, dont_ignore_monsters, ENT( pev ), &tr ); + if (tr.fStartSolid || (oldowner && tr.pHit == oldowner)) + { + pev->owner = oldowner; + m_flPowerUp += 0.1; + pev->nextthink = gpGlobals->time + 0.1; + return; + } + if (tr.flFraction < 1.0) + { + pev->owner = tr.pHit; + m_hOwner = CBaseEntity::Instance( pev->owner ); + m_posOwner = m_hOwner->pev->origin; + m_angleOwner = m_hOwner->pev->angles; + } + else + { + STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav" ); + STOP_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav" ); + SetThink( SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; + ALERT( at_console, "WARNING:Tripmine at %.0f, %.0f, %.0f removed\n", pev->origin.x, pev->origin.y, pev->origin.z ); + KillBeam(); + return; + } + } + else if (m_posOwner != m_hOwner->pev->origin || m_angleOwner != m_hOwner->pev->angles) + { + // disable + STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav" ); + STOP_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav" ); + CBaseEntity *pMine = Create( "weapon_snark", pev->origin + m_vecDir * 24, pev->angles ); + pMine->pev->spawnflags |= SF_NORESPAWN; + SetThink( SUB_Remove ); + KillBeam(); + pev->nextthink = gpGlobals->time + 0.1; + return; + + /* + // Just detonate + pev->owner = m_pRealOwner; + pev->health = 0; + Killed( VARS( pev->owner ), GIB_NORMAL ); + return; + */ + } + // ALERT( at_console, "%d %.0f %.0f %0.f\n", pev->owner, m_pOwner->pev->origin.x, m_pOwner->pev->origin.y, m_pOwner->pev->origin.z ); + + if (gpGlobals->time > m_flPowerUp) + { + // make solid + pev->solid = SOLID_BBOX; + UTIL_SetOrigin( pev, pev->origin ); + + MakeBeam( ); + + // play enabled sound + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "squeek/sqk_deploy1.wav", 0.5, ATTN_NORM, 1.0, 75 ); + } + pev->nextthink = gpGlobals->time + 0.1; +} + + +void CTripSnarkGrenade :: KillBeam( void ) +{ + if ( m_pBeam ) + { + UTIL_Remove( m_pBeam ); + m_pBeam = NULL; + } +} + + +void CTripSnarkGrenade :: MakeBeam( void ) +{ + TraceResult tr; + + // ALERT( at_console, "serverflags %f\n", gpGlobals->serverflags ); + + UTIL_TraceLine( pev->origin, m_vecEnd, dont_ignore_monsters, ENT( pev ), &tr ); + + m_flBeamLength = tr.flFraction; + + // set to follow laser spot + SetThink( BeamBreakThink ); + pev->nextthink = gpGlobals->time + 0.1; + + Vector vecTmpEnd = pev->origin + m_vecDir * 2048 * m_flBeamLength; + + m_pBeam = CBeam::BeamCreate( g_pModelNameLaser, 10 ); + m_pBeam->PointEntInit( vecTmpEnd, entindex() ); + m_pBeam->SetColor( 255, 20, 20 ); + m_pBeam->SetScrollRate( 255 ); + m_pBeam->SetBrightness( 40 ); + + if (IsSpawnMine()) + { + pev->owner = m_pRealOwner; + pev->health = 0; + Killed( VARS( pev->owner ), GIB_NORMAL ); + + UTIL_SpeakBadWeapon(); + + UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "%s tried to place a spawn snark mine!\n", + STRING( VARS( pev->owner )->netname ) ) ); + } +} + + +void CTripSnarkGrenade :: BeamBreakThink( void ) +{ + BOOL bBlowup = 0; + + TraceResult tr; + + // HACKHACK Set simple box using this really nice global! + gpGlobals->trace_flags = FTRACE_SIMPLEBOX; + UTIL_TraceLine( pev->origin, m_vecEnd, dont_ignore_monsters, ENT( pev ), &tr ); + + // ALERT( at_console, "%f : %f\n", tr.flFraction, m_flBeamLength ); + + // respawn detect. + if ( !m_pBeam ) + { + MakeBeam( ); + if ( tr.pHit ) + m_hOwner = CBaseEntity::Instance( tr.pHit ); // reset owner too + } + + if (fabs( m_flBeamLength - tr.flFraction ) > 0.001) + { + bBlowup = 1; + } + else + { + if (m_hOwner == NULL) + bBlowup = 1; + else if (m_posOwner != m_hOwner->pev->origin) + bBlowup = 1; + else if (m_angleOwner != m_hOwner->pev->angles) + bBlowup = 1; + } + + if (bBlowup) + { + // a bit of a hack, but all CGrenade code passes pev->owner along to make sure the proper player gets credit for the kill + // so we have to restore pev->owner from pRealOwner, because an entity's tracelines don't strike it's pev->owner which meant + // that a player couldn't trigger his own tripmine. Now that the mine is exploding, it's safe the restore the owner so the + // CGrenade code knows who the explosive really belongs to. + pev->owner = m_pRealOwner; + pev->health = 0; + Killed( VARS( pev->owner ), GIB_NORMAL ); + return; + } + + pev->nextthink = gpGlobals->time + 0.1; +} + +int CTripSnarkGrenade :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) +{ + if (gpGlobals->time < m_flPowerUp && flDamage < pev->health) + { + // disable + // Create( "weapon_tripsnark", pev->origin + m_vecDir * 24, pev->angles ); + SetThink( SUB_Remove ); + pev->nextthink = gpGlobals->time + 0.1; + KillBeam(); + return FALSE; + } + return CGrenade::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +void CTripSnarkGrenade::Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->takedamage = DAMAGE_NO; + + if ( pevAttacker && ( pevAttacker->flags & FL_CLIENT ) ) + { + // some client has destroyed this mine, he'll get credit for any kills + pev->owner = ENT( pevAttacker ); + } + + SetThink( DelayDeathThink ); + pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); + + EMIT_SOUND( ENT(pev), CHAN_BODY, "common/null.wav", 0.5, ATTN_NORM ); // shut off chargeup +} + + +void CTripSnarkGrenade::Explode( TraceResult *pTrace ) +{ + // Make mine invisible + pev->model = iStringNull;//invisible + pev->solid = SOLID_NOT;// intangible + pev->effects |= EF_NODRAW; + pev->takedamage = DAMAGE_NO; + + // Pull out of the wall a bit + if ( pTrace->flFraction != 1.0 ) + { + pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * 20); + } + + // Make teleport sound effect + EMIT_SOUND( ENT(pev), CHAN_BODY, "debris/beamstart2.wav", 0.5, ATTN_NORM ); + + // Create Animated Sprite + m_pSprite = CSprite::SpriteCreate( TRIPSNARK_FLARE, pev->origin, TRUE ); + m_pSprite->Animate( 1 ); + m_pSprite->pev->scale = 1.4; + m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); + m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY; + + // Spawn snarks + CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", pev->origin, m_vecDir , pev->owner ); + pSqueak->pev->velocity = m_vecDir * 200; + pSqueak = CBaseEntity::Create( "monster_snark", pev->origin + Vector(8, 8, 0), m_vecDir , pev->owner ); + pSqueak->pev->velocity = m_vecDir * 200; + pSqueak = CBaseEntity::Create( "monster_snark", pev->origin + Vector(-8, 8, 0), m_vecDir , pev->owner ); + pSqueak->pev->velocity = m_vecDir * 200; + pSqueak = CBaseEntity::Create( "monster_snark", pev->origin + Vector(8, -8, 0), m_vecDir , pev->owner ); + pSqueak->pev->velocity = m_vecDir * 200; + pSqueak = CBaseEntity::Create( "monster_snark", pev->origin + Vector(-8, -8, 0), m_vecDir , pev->owner ); + pSqueak->pev->velocity = m_vecDir * 200; + + // Tell the mine what do do for the next little while. + SetThink( RiftThink ); + pev->nextthink = gpGlobals->time + 0.1; + m_RiftTime = gpGlobals->time + 3; +} + +void CTripSnarkGrenade::RiftThink( void ) +{ + // Setup next think time + pev->nextthink = gpGlobals->time + 0.1; + + // Make a lightning strike + Vector vecEnd; + TraceResult tr; + vecEnd.x = RANDOM_FLOAT(-1.0,1.0); // Pick a random direction + vecEnd.y = RANDOM_FLOAT(-1.0,1.0); + vecEnd.z = RANDOM_FLOAT(-1.0,1.0); + // vecEnd = vecEnd.Normalize(); + vecEnd = pev->origin + vecEnd.Normalize() * 128; + + UTIL_TraceLine( pev->origin, vecEnd, ignore_monsters, ENT(pev), &tr); + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD(pev->origin.x); + WRITE_COORD(pev->origin.y); + WRITE_COORD(pev->origin.z); + WRITE_COORD( tr.vecEndPos.x ); + WRITE_COORD( tr.vecEndPos.y ); + WRITE_COORD( tr.vecEndPos.z ); + WRITE_SHORT( m_LaserSprite ); + WRITE_BYTE( 0 ); // Starting frame + WRITE_BYTE( 0 ); // framerate * 0.1 + WRITE_BYTE( 5 ); // life * 0.1 + WRITE_BYTE( 3 ); // width + WRITE_BYTE( 64 ); // noise + WRITE_BYTE( 10 ); // color r,g,b + WRITE_BYTE( 200 ); // color r,g,b + WRITE_BYTE( 255 ); // color r,g,b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 0 ); // scroll speed + MESSAGE_END(); + + // Animate Sprite + m_pSprite->Animate(1); + + // Check to see if the rift should fade away + if (m_RiftTime <= gpGlobals->time) { + m_pSprite->Expand( 10, 500 ); + m_pSprite = NULL; + UTIL_Remove( this ); + } +} + +void CTripSnarkGrenade::DelayDeathThink( void ) +{ + KillBeam(); + TraceResult tr; + UTIL_TraceLine ( pev->origin + m_vecDir * 8, pev->origin - m_vecDir * 64, dont_ignore_monsters, ENT(pev), & tr); + + Explode( &tr ); +} + +BOOL CTripSnarkGrenade::IsSpawnMine() +{ + if (bm_spawnmines.value) + return FALSE; + + BOOL result = FALSE; + + CBaseEntity *pEntity = NULL; + TraceResult tr; + Vector vecSpot, vecTop; + Vector vecSrc = pev->origin; + float flRadius = 375; + + int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); + + vecSrc.z += 1;// in case grenade is lying on the ground + + // iterate on all entities in the vicinity. + while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) + { + // Only look for deathmatch spawn points + if ( FClassnameIs( pEntity->pev, "info_player_deathmatch" ) ) + { + // blast's don't tavel into or out of water, + // so ignore spawn points that lie on the other side. + if (bInWater && pEntity->pev->waterlevel == 0) + continue; + if (!bInWater && pEntity->pev->waterlevel == 3) + continue; + + // Trace a small line from the trip out to the potential damage radius. + UTIL_TraceLine ( vecSrc, vecSrc + m_vecDir * flRadius, ignore_monsters, ENT(pev), &tr ); + vecSpot = tr.vecEndPos; + + UTIL_TraceLine( pEntity->pev->origin, pEntity->pev->origin - Vector(0,0,1024), ignore_monsters, ENT(pev), &tr); + Vector vecTop = pEntity->pev->origin + Vector(0,0,36); + float height = fabs(vecTop.z - tr.vecEndPos.z) / 2; + + if (UTIL_OBB_LineTest(vecSrc, vecSpot, Vector(vecTop.x, vecTop.y, (vecTop.z + tr.vecEndPos.z) / 2), Vector(16,16,height) )) + result = TRUE; + } + } + return result; +} + +void CTripSnarkGrenade::Deactivate( void ) +{ + pev->solid = SOLID_NOT; + KillBeam(); + UTIL_Remove( this ); +} + +//========================================================= +// DeactivateSnarkTrips - removes all snark trips owned by +// the provided player. +// +// Made this global on purpose. +//========================================================= +void DeactivateSnarkTrips( CBasePlayer *pOwner ) +{ + edict_t *pFind; + + pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "monster_tripsnark" ); + + while ( !FNullEnt( pFind ) ) + { + CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); + CTripSnarkGrenade *pTrip = (CTripSnarkGrenade *)pEnt; + + if ( pTrip ) + { + if ( pTrip->Owner() == pOwner->edict() ) + { + pTrip->Deactivate(); + } + } + + pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "monster_tripsnark" ); + } +} \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_snarkmine.h b/dlls/bubblemod/BMOD_snarkmine.h new file mode 100644 index 00000000..8d5520d4 --- /dev/null +++ b/dlls/bubblemod/BMOD_snarkmine.h @@ -0,0 +1,84 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- +// Snark Mines + +#ifndef SNARKMINE_H +#define SNARKMINE_H + +#include "extdll.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "effects.h" + +class CTripSnarkGrenade : public CGrenade +{ + void Spawn( void ); + void Precache( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + + void EXPORT WarningThink( void ); + void EXPORT PowerupThink( void ); + void EXPORT BeamBreakThink( void ); + void EXPORT DelayDeathThink( void ); + void EXPORT RiftThink( void ); + void Killed( entvars_t *pevAttacker, int iGib ); + void Explode( TraceResult *pTrace ); + + void MakeBeam( void ); + void KillBeam( void ); + BOOL IsSpawnMine( void ); + + float m_flPowerUp; + Vector m_vecDir; + Vector m_vecEnd; + float m_flBeamLength; + + EHANDLE m_hOwner; + CBeam *m_pBeam; + Vector m_posOwner; + Vector m_angleOwner; + edict_t *m_pRealOwner;// tracelines don't hit PEV->OWNER, which means a player couldn't detonate his own trip mine, so we store the owner here. + +private: + + int m_RiftTime; + CSprite *m_pSprite; + short m_LaserSprite; + +public: + void Deactivate( void ); + edict_t *Owner( void ) { return m_pRealOwner; }; +}; + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_squeakgrenade.cpp b/dlls/bubblemod/BMOD_squeakgrenade.cpp new file mode 100644 index 00000000..5de37fdd --- /dev/null +++ b/dlls/bubblemod/BMOD_squeakgrenade.cpp @@ -0,0 +1,153 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- +// Extra Snark Functions + +#include "squeakgrenade.h" +#include "BMOD_snarkmine.h" +extern cvar_t bm_snarks_mod; + +void CSqueak::SecondaryAttack( void ) +{ + +if (!bm_snarks_mod.value || m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 5) + return; + + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming = gpGlobals->v_forward; + + TraceResult tr; + + UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 128, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); + + if (tr.flFraction < 1.0) + { + // ALERT( at_console, "hit %f\n", tr.flFraction ); + + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + if (pEntity && !(pEntity->pev->flags & FL_CONVEYOR)) + { + Vector angles = UTIL_VecToAngles( tr.vecPlaneNormal ); + + CBaseEntity *pEnt = CBaseEntity::Create( "monster_tripsnark", tr.vecEndPos + tr.vecPlaneNormal * 8, angles, m_pPlayer->edict() ); + + CTripSnarkGrenade *pMine = (CTripSnarkGrenade *)pEnt; + + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 5; + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0) + { + SendWeaponAnim( SQUEAK_UP ); + } + else + { + // no more mines! + RetireWeapon(); + return; + } + } + else + { + // ALERT( at_console, "no deploy\n" ); + } + } + else + { + + } + + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 ); +} + +//========================================================= +// BestVisibleEnemy - this functions searches the link +// list whose head is the caller's m_pLink field, and returns +// a pointer to the enemy entity in that list that is nearest the +// caller. +// +// !!!UNDONE - currently, this only returns the closest enemy. +// we'll want to consider distance, relationship, attack types, back turned, etc. +//========================================================= +CBaseEntity *CSqueakGrenade :: BMOD_BestVisibleEnemy ( void ) +{ + CBaseEntity *pReturn; + CBaseEntity *pNextEnt; + BOOL typer; + int iNearest; + int iDist; + int iBestRelationship; + + iNearest = 8192;// so first visible entity will become the closest. + pNextEnt = m_pLink; + pReturn = NULL; + typer = 0; + iBestRelationship = R_NO; + + while ( pNextEnt != NULL ) + { + if (pNextEnt->IsPlayer()) { + typer = ((CBasePlayer*)pNextEnt)->BMOD_IsTyping(); + } + else { + typer = 0; + } + + if ( pNextEnt->IsAlive() && !typer) + { + if ( IRelationship( pNextEnt) > iBestRelationship ) + { + // this entity is disliked MORE than the entity that we + // currently think is the best visible enemy. No need to do + // a distance check, just get mad at this one for now. + iBestRelationship = IRelationship ( pNextEnt ); + iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); + pReturn = pNextEnt; + } + else if ( IRelationship( pNextEnt) == iBestRelationship ) + { + // this entity is disliked just as much as the entity that + // we currently think is the best visible enemy, so we only + // get mad at it if it is closer. + iDist = ( pNextEnt->pev->origin - pev->origin ).Length(); + + if ( iDist <= iNearest ) + { + iNearest = iDist; + iBestRelationship = IRelationship ( pNextEnt ); + pReturn = pNextEnt; + } + } + } + + pNextEnt = pNextEnt->m_pLink; + } + + return pReturn; +} \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_tripmines.cpp b/dlls/bubblemod/BMOD_tripmines.cpp new file mode 100644 index 00000000..9859da95 --- /dev/null +++ b/dlls/bubblemod/BMOD_tripmines.cpp @@ -0,0 +1,155 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "game.h" +#include "tripmine.h" +#include "shake.h" + +BOOL CTripmineGrenade::BMOD_IsSpawnMine() +{ + if (bm_spawnmines.value) + return FALSE; + + BOOL result = FALSE; + CBaseEntity *pEntity = NULL; + TraceResult tr; + Vector vecSpot, vecTop; + Vector vecSrc = pev->origin; + float flRadius = pev->dmg * 2.5; + + int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); + + vecSrc.z += 1;// in case grenade is lying on the ground + + // iterate on all entities in the vicinity. + while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) + { + // Only look for deathmatch spawn points + if ( FClassnameIs( pEntity->pev, "info_player_deathmatch" ) ) + { + // blast's don't tavel into or out of water, + // so ignore spawn points that lie on the other side. + if (bInWater && pEntity->pev->waterlevel == 0) + continue; + if (!bInWater && pEntity->pev->waterlevel == 3) + continue; + + // Trace a small line from the trip out to the potential damage radius. + UTIL_TraceLine ( vecSrc, vecSrc + m_vecDir * flRadius, ignore_monsters, ENT(pev), &tr ); + vecSpot = tr.vecEndPos; + + UTIL_TraceLine( pEntity->pev->origin, pEntity->pev->origin - Vector(0,0,1024), ignore_monsters, ENT(pev), &tr); + Vector vecTop = pEntity->pev->origin + Vector(0,0,36); + float height = fabs(vecTop.z - tr.vecEndPos.z) / 2; + + if (UTIL_OBB_LineTest(vecSrc, vecSpot, Vector(vecTop.x, vecTop.y, (vecTop.z + tr.vecEndPos.z) / 2), Vector(16,16,height) )) + result = TRUE; + } + } + return result; +} + +void CTripmineGrenade::FlashBang( void ) +{ +#define FLASH_RANGE 600 + pev->nextthink = gpGlobals->time + 0.3; + SetThink( Smoke ); + + // Find all players in range + CBaseEntity *pEntity = NULL; + TraceResult tr; + Vector vecSpot; + float amount, range; + + EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/pl_gun2.wav", 1, ATTN_NORM); + + while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, FLASH_RANGE )) != NULL) + { + // Only look for players + if ( FClassnameIs( pEntity->pev, "player" ) ) + { + vecSpot = pEntity->BodyTarget( pev->origin ); + + // Trace a small line from the trip out to the player. + UTIL_TraceLine ( pev->origin, vecSpot, dont_ignore_monsters, ENT(pev), &tr ); + if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict()) + { + range = (vecSpot - pev->origin).Length(); + amount = range + * range + * -1 + / FLASH_RANGE + + 255; + UTIL_ScreenFade( pEntity, Vector(255,255,255), 5.0, 1.0, amount, FFADE_IN); + + } + + } + } + +} + +void CTripmineGrenade::Deactivate( void ) +{ + pev->solid = SOLID_NOT; + KillBeam(); + UTIL_Remove( this ); +} + +//========================================================= +// DeactivateTrips - removes all trips owned by +// the provided player. +// +// Made this global on purpose. +//========================================================= +void DeactivateTrips( CBasePlayer *pOwner ) +{ + edict_t *pFind; + + pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "monster_tripmine" ); + + while ( !FNullEnt( pFind ) ) + { + CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); + CTripmineGrenade *pTrip = (CTripmineGrenade *)pEnt; + + if ( pTrip ) + { + if ( pTrip->Owner() == pOwner->edict() ) + { + pTrip->Deactivate(); + } + } + + pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "monster_tripmine" ); + } +} \ No newline at end of file diff --git a/dlls/bubblemod/BMOD_util.cpp b/dlls/bubblemod/BMOD_util.cpp new file mode 100644 index 00000000..d782a26b --- /dev/null +++ b/dlls/bubblemod/BMOD_util.cpp @@ -0,0 +1,533 @@ +// --------------------------------------------------------------- +// BubbleMod +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "saverestore.h" +#include +#include "shake.h" +#include "decals.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include +#include + +// bigguy's CastPlayer functions + +CBasePlayer* UTIL_CastPlayer ( CBaseEntity *pEnt ) +{ + if (pEnt) // check validity + { + if (pEnt->IsPlayer()) // is it even a player? + { + CBasePlayer *plr = GetClassPtr((CBasePlayer *)pEnt); // cast player + if (plr) // check validity + return plr; // return pointer + } + } + + return NULL; // otherwise, its not a player +} + +CBasePlayer* UTIL_CastPlayer ( entvars_t *pev ) +{ + if (pev) // check validity + { + if (FClassnameIs(pev, "player")) // is it even a player? + { + CBasePlayer *plr = GetClassPtr((CBasePlayer *)pev); // cast player + if (plr) // check validity + return plr; // return pointer + } + } + return NULL; // otherwise, its not a player +} +CBasePlayer* UTIL_CastPlayer ( edict_t *pEdict ) +{ + if (pEdict) // check validity + { +// if (FClassnameIs(pEdict, "player")) // is it even a player? +// { + entvars_t *pev = &pEdict->v; + // CBasePlayer *plr = GetClassPtr((CBasePlayer *)pev); // cast player + CBasePlayer *plr = (CBasePlayer*) CBasePlayer::Instance( pev ); // cast player + if (plr) // check validity + return plr; // return pointer +// } + } + return NULL; // otherwise, its not a player +} +CBasePlayer* UTIL_CastPlayer ( int index ) +{ + if (index > 0 && index <= gpGlobals->maxClients) // check validity + { + edict_t *pEdict = INDEXENT(index); // cast pEdict + CBasePlayer *plr = UTIL_CastPlayer(pEdict); // cast player + if (plr) // check validity + return plr; // return pointer + } + return NULL; // otherwise, its not a player +} + +// Oriented Bounding Box to line segment intersection test +// Adapted from Miguel Gomez article on Gamasutra Oct. '99 +// +// Arguments are line start point, line end point, BBox center, and BBox extents +// +// Returns TRUE if the line and BBox intersect, FALSE if they do not. +BOOL UTIL_OBB_LineTest(Vector vecSrc, Vector vecDst, Vector boxP, Vector boxE) +{ + // Unit vector in direction of line. + Vector l = vecDst - vecSrc; + + // Half of line segment length + float hl = fabs(l.Length() / 2); + + l = l.Normalize(); + + // midpoint of line segemnt. + Vector mid = (vecDst + vecSrc) / 2; + + // The separating axis. + Vector T = boxP - mid; +/* + char sPlayers[256] = ""; + sprintf(sPlayers, "Start: %f, %f, %f\nEnd: %f, %f, %f\nhl: %f\nunit: %f, %f, %f\n\n", vecSrc.x, vecSrc.y, vecSrc.z, + vecDst.x, vecDst.y, vecDst.z, hl, l.x, l.y, l.z); + g_engfuncs.pfnServerPrint( sPlayers ); + + + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD(mid.x); + WRITE_COORD(mid.y); + WRITE_COORD(mid.z); + WRITE_COORD(mid.x + (hl * l.x)); + WRITE_COORD(mid.y + (hl * l.y)); + WRITE_COORD(mid.z + (hl * l.z)); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // Starting frame + WRITE_BYTE( 0 ); // framerate * 0.1 + WRITE_BYTE( 255 ); // life * 0.1 + WRITE_BYTE( 10 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 0 ); // color r,g,b + WRITE_BYTE( 0 ); // color r,g,b + WRITE_BYTE( 255 ); // color r,g,b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 0 ); // scroll speed + MESSAGE_END(); + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD(mid.x); + WRITE_COORD(mid.y); + WRITE_COORD(mid.z); + WRITE_COORD(mid.x - (hl * l.x)); + WRITE_COORD(mid.y - (hl * l.y)); + WRITE_COORD(mid.z - (hl * l.z)); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // Starting frame + WRITE_BYTE( 0 ); // framerate * 0.1 + WRITE_BYTE( 255 ); // life * 0.1 + WRITE_BYTE( 10 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 255 ); // color r,g,b + WRITE_BYTE( 0 ); // color r,g,b + WRITE_BYTE( 0 ); // color r,g,b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 0 ); // scroll speed + MESSAGE_END(); + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD(mid.x); + WRITE_COORD(mid.y); + WRITE_COORD(mid.z); + WRITE_COORD(boxP.x); + WRITE_COORD(boxP.y); + WRITE_COORD(boxP.z); + WRITE_SHORT( g_sModelIndexLaser ); + WRITE_BYTE( 0 ); // Starting frame + WRITE_BYTE( 0 ); // framerate * 0.1 + WRITE_BYTE( 255 ); // life * 0.1 + WRITE_BYTE( 10 ); // width + WRITE_BYTE( 0 ); // noise + WRITE_BYTE( 255 ); // color r,g,b + WRITE_BYTE( 255 ); // color r,g,b + WRITE_BYTE( 255 ); // color r,g,b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 0 ); // scroll speed + MESSAGE_END(); +*/ + // The box is assumed to be axis aligned to the world, so we start + // with those trivial cases. + if( ( fabs(T.x) > boxE.x + hl * fabs(l.x) ) || + ( fabs(T.y) > boxE.y + hl * fabs(l.y) ) || + ( fabs(T.z) > boxE.z + hl * fabs(l.z) ) ) + return FALSE; + + // Now we check the box transformed into the line space. + if ( ( fabs(T.y*l.z - T.z*l.y) > boxE.y*fabs(l.z) + boxE.z*fabs(l.y) ) || + ( fabs(T.z*l.x - T.x*l.z) > boxE.z*fabs(l.x) + boxE.x*fabs(l.z) ) || + ( fabs(T.x*l.y - T.y*l.x) > boxE.x*fabs(l.y) + boxE.y*fabs(l.x) ) ) + return FALSE; + + return TRUE; +} + +// Oriented Bounding Box to point intersection test +// +// Arguments are line point, BBox center, and BBox extents +// +// Returns TRUE if the point and BBox intersect, FALSE if they do not. +BOOL UTIL_OBB_PointTest(Vector vecSrc, Vector boxP, Vector boxE) +{ + if ((vecSrc.x < (boxP.x - boxE.x) )|| + (vecSrc.x > (boxP.x + boxE.x) )|| + (vecSrc.y < (boxP.y - boxE.y) )|| + (vecSrc.y > (boxP.y + boxE.y) )|| + (vecSrc.z < (boxP.z - boxE.z) )|| + (vecSrc.z > (boxP.z + boxE.z) )) + return FALSE; + + return TRUE; +} + +void UTIL_SpeakAll( char *message ) +{ + char text[256]; + strcpy(text, "speak \""); + strcat(text, message); + strcat(text, "\"\n"); + + CBasePlayer *client = NULL; + + while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) + { + CLIENT_COMMAND(client->edict(), text); + } +} + +void UTIL_SpeakBadWeapon( void ) +{ + switch (RANDOM_LONG(0, 3)) + { + case 0: + UTIL_SpeakAll("deeoo, warning, unauthorized weapon use detected"); + break; + case 1: + UTIL_SpeakAll("deeoo, warning, weapon violation detected"); + break; + case 2: + UTIL_SpeakAll("deeoo, warning, forbidden use of detonation device"); + break; + case 3: + UTIL_SpeakAll("deeoo, warning, illegal explosion in sector fourty two"); + break; + } +} + +char* UTIL_CountVotes() +{ + static char string[128]; + char maps[32][81]; + int votes[32]; + int p = 0; + int q = 0; + + for (int i = 0; i < 32; i++) + { + strcpy(maps[i], ""); + votes[i] = 0; + } + + CBasePlayer *client = NULL; + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + client = (CBasePlayer*)UTIL_PlayerByIndex( i ); + + if ( client && (client->m_bIsConnected) && (IS_MAP_VALID(client->m_sMapVote) || !strcmp(client->m_sMapVote, "extend"))) + { + p = 0; + while(strcmp(client->m_sMapVote, maps[p]) && (p < 32)) + { + p++; + } + + if (p < 32) + { + votes[p]++; + } + else + { + strcpy(maps[q], client->m_sMapVote); + votes[q]++; + q++; + } + } + } + + q = 0; + for (i = 0; i < 32; i++) + { + if (votes[i] > votes[q]) + q = i; + } + + string[0] = (char)votes[q]; + string[1] = 0; + + strcat(&(string[1]), maps[q]); + + return string; +} + +typedef struct +{ + char WONid[81]; +// unsigned int WONid; + int frags; + int deaths; + int SpawnKills; + int TypeKills; + BOOL IsLlama; +} SavedPlayer; + +void UTIL_SaveRestorePlayer( CBasePlayer *pPlayer, BOOL save, BOOL resetall ) +{ + // return; + + static SavedPlayer Player[32]; + static BOOL init = FALSE; + + // Initialize the array + if (!init || resetall) + { + for (int i = 0; i < 32; i++) + { + Player[i].WONid[0] = 0; +// Player[i].WONid = 0; + Player[i].frags = 0; + Player[i].deaths = 0; + Player[i].SpawnKills = 0; + Player[i].TypeKills = 0; + Player[i].IsLlama = 0; + } + init = TRUE; + } + + if (resetall) + return; + + // Save a player's data + if (save) + { + for (int i = 0; i < 32; i++) + { + if (Player[i].WONid[0] == 0) +// if (Player[i].WONid == 0) + { + strcpy(Player[i].WONid, GETPLAYERAUTHID(pPlayer->edict())); +// Player[i].WONid = GETPLAYERAUTHID(pPlayer->edict()); + //Player[i].frags = pPlayer->pev->frags; + //Player[i].deaths = pPlayer->m_iDeaths; + Player[i].SpawnKills = pPlayer->m_iSpawnKills; + Player[i].TypeKills = pPlayer->m_iTypeKills; + Player[i].IsLlama = pPlayer->m_IsLlama; + break; + } + } + } + + // Otherwise load a player's data + else + { + for (int i = 0; i < 32; i++) + { + if (!strcmp(Player[i].WONid, GETPLAYERAUTHID(pPlayer->edict()))) +// if (Player[i].WONid == GETPLAYERAUTHID(pPlayer->edict())) + { + //pPlayer->pev->frags = Player[i].frags; + //pPlayer->m_iDeaths = Player[i].deaths; + pPlayer->m_IsLlama = Player[i].IsLlama; + pPlayer->m_iSpawnKills = Player[i].SpawnKills; + pPlayer->m_iTypeKills = Player[i].TypeKills; + Player[i].WONid[0] = 0; +// Player[i].WONid = 0; + Player[i].frags = 0; + Player[i].deaths = 0; + Player[i].SpawnKills = 0; + Player[i].TypeKills = 0; + break; + } + } + } +} + +const int NUMSTRINGS = 43; +const char *XLate [NUMSTRINGS*5] ={ "YOU", "J00", "JO0", "j00", "Jo0", + "?", "?!", "!?", "?!?", "!?!", + "!", "!!", "!", "!!", "!", + "IES", "YS", "yZ", "Y$", "y5", + "HACKER", "H4X0r" ,"H4><0r", "h4X0r", "h4XoR", + "SUCK", "SuX0rZ" ,"Su><0rZ", "sUX0rz", "suXoRZ", + "DUDE", "D00D" ,"d00d", "dUUD", "|)0o|)", + "QU", "|", "o", "0", "()", + "P", "P", "p", "P", "p", + "Q", "Q", "q", "Q", "q", + "R", "R", "r", "|2", "|2", + "S", "z", "$", "5", "Z", + "T", "T", "t", "7", "+", + "U", "U", "u", "U", "u", + "V", "V", "v", "\\/", "V", + "W", "W", "w", "vv", "W", + "X", "X", "x", "><", "%", + "Y", "Y", "y", "Y", "y", + "Z", "Z", "z", "Z", "z" + }; + +void UTIL_Speak_2_l33t( char *szTarget, char *szOString ) +{ + const int MAX_L33T = 512; + + int i = 0; + char szNewString[MAX_L33T] = ""; + char szString[MAX_L33T] = ""; + strcpy(szString, szOString); + int j; + BOOL match; + + for (i=0; i<(int)strlen(szString); i++) + { + szString[i] = toupper(szString[i]); + }; + + i = 0; + for (i=0; i<(int)strlen(szString); i++) + { + match = false; + for(j=0; jtm_hour; + hour = hour > 12 ? hour - 12 : hour; + hour = hour == 0 ? 12 : hour; + int min = adjustedTime->tm_min; + char *ampm = "AM"; + if (adjustedTime->tm_hour > 11) + ampm = "PM"; + + sprintf(szTime, " Local server time is: %d:%02d %s\n", hour, min, ampm); + UTIL_ClientPrintAll( HUD_PRINTTALK, szTime); +} + +// Convert a four digit hex string to an int. +int UTIL_axtoi(char *hexStg) { + int n = 0; // position in string + int m = 0; // position in digit[] to shift + int count; // loop index + int intValue = 0; // integer value of hex string + int digit[5]; // hold values to convert + while (n < 4) { + if (hexStg[n]=='\0') + break; + if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9 + digit[n] = hexStg[n] & 0x0f; //convert to int + else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f + digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int + else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F + digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int + else break; + n++; + } + count = n; + m = n - 1; + n = 0; + while(n < count) { + // digit[n] is value of hex digit at position n + // (m << 2) is the number of positions to shift + // OR the bits into return value + intValue = intValue | (digit[n] << (m << 2)); + m--; // adjust the position to set + n++; // next digit to process + } + return (intValue); +} diff --git a/dlls/bubblemod/BMOD_zapgunrift.cpp b/dlls/bubblemod/BMOD_zapgunrift.cpp new file mode 100644 index 00000000..286980ed --- /dev/null +++ b/dlls/bubblemod/BMOD_zapgunrift.cpp @@ -0,0 +1,369 @@ +// --------------------------------------------------------------- +// Zap Rift Entity +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "gamerules.h" +#include "effects.h" +#include "BMOD_zapgunrift.h" +#include "shake.h" + +#define RIFTSPR "sprites/cnt1.spr" +#define RIFTSPR2 "sprites/cnt1.spr" + +LINK_ENTITY_TO_CLASS( zaprift, CZapRift ); + +void CZapRift::Precache( void ) +{ + PRECACHE_SOUND("debris/zap4.wav"); + PRECACHE_SOUND("weapons/electro4.wav"); + PRECACHE_SOUND("hassault/hw_shoot1.wav"); + PRECACHE_MODEL( RIFTSPR ); + PRECACHE_MODEL( RIFTSPR2 ); +} + +void CZapRift::Spawn( void ) +{ + pev->classname = MAKE_STRING( "zapgun" ); + + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_NOT; + + pev->rendermode = kRenderGlow; + pev->renderamt = 240; + pev->renderfx = kRenderFxNoDissipation; + + UTIL_MakeAimVectors( pev->angles ); + //pev->origin = pev->origin + gpGlobals->v_forward * 8; + + SET_MODEL(ENT(pev), RIFTSPR); + pev->frame = 0; + pev->scale = 2; + m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; + + // Create Inner Animated Sprite + m_pSprite = CSprite::SpriteCreate( RIFTSPR2, pev->origin, TRUE ); + m_pSprite->Animate( 1 ); + m_pSprite->pev->scale = 1; + m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 180, kRenderFxNoDissipation ); + m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY; + + SetThink ( Animate ); + pev->nextthink = gpGlobals->time + 0.1; + m_fLifeSpan = gpGlobals->time + 3; + m_fNextElectrify = gpGlobals->time + 0.1; + + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0,100 ); +} + +void CZapRift::Animate( void ) +{ + pev->nextthink = gpGlobals->time + 0.1; + + + + if ( pev->frame++ ) + { + if ( pev->frame > m_maxFrame ) + { + pev->frame = 0; + } + } + + m_pSprite->pev->scale = RANDOM_FLOAT(.5, 3); + + if ( m_fLifeSpan < gpGlobals->time) + { + pev->effects |= EF_NODRAW; + m_pSprite->Expand( 10, 100 ); + SetThink(SUB_Remove); + pev->nextthink = gpGlobals->time + 5; + } + + if ( m_fNextElectrify < gpGlobals->time ) + { + // Send out electric streamers and do area effect damage + + for (int i = 0; i < 3; i++) + { + Vector vecTemp; + Vector vecEnd = Vector (0,0,0); + + // Hopefully find a long beam + for (int j = 0; j < 5; j++) + { + vecTemp = FindBeam(); + if ( vecTemp.Length() > vecEnd.Length() ) + vecEnd = vecTemp; + } + + // Draw the streamer + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD(pev->origin.x); + WRITE_COORD(pev->origin.y); + WRITE_COORD(pev->origin.z); + WRITE_COORD( vecEnd.x ); + WRITE_COORD( vecEnd.y ); + WRITE_COORD( vecEnd.z ); + WRITE_SHORT( g_sModelIndexLightning ); + WRITE_BYTE( 0 ); // Starting frame + WRITE_BYTE( 0 ); // framerate * 0.1 + WRITE_BYTE( 20 ); // life * 0.1 + WRITE_BYTE( 80 ); // width + WRITE_BYTE( 50 ); // noise + WRITE_BYTE( 180 ); // color r,g,b + WRITE_BYTE( 255 ); // color r,g,b + WRITE_BYTE( 96 ); // color r,g,b + WRITE_BYTE( 255 ); // brightness + WRITE_BYTE( 0 ); // scroll speed + MESSAGE_END(); + + } + + // Deal damage. + CBaseEntity *pEntity= NULL; + TraceResult tr; + while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, 512 )) != NULL) + { + // Only look for players + if ( pEntity->pev->takedamage != DAMAGE_NO ) + { + // blast's don't tavel out of water, + // so ignore players that lie on the other side. + if (pEntity->pev->waterlevel == 0) + continue; + + // Trace to the target + UTIL_TraceLine( pev->origin, pEntity->BodyTarget( pev->origin ) , dont_ignore_monsters, ENT(pev), &tr); + if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict()) + { + ClearMultiDamage( ); + pEntity->TraceAttack( VARS( pev->owner ), 30, Vector(0,0,1), &tr, DMG_SHOCK | DMG_ALWAYSGIB ); + ApplyMultiDamage( pev, VARS( pev->owner ) ); + UTIL_ScreenFade( pEntity, Vector(180,255,96), 2, 0.5, 128, FFADE_IN ); + } + } + } + m_fNextElectrify = gpGlobals->time + 1; + } + +} + +Vector CZapRift::FindBeam( void ) +{ + TraceResult tr; + + // Direction is within the forward hemisphere. + UTIL_MakeAimVectors( pev->angles ); + Vector vecDir = gpGlobals->v_right * RANDOM_FLOAT( -1, 1) + + gpGlobals->v_up * RANDOM_FLOAT( -1, 1) + + gpGlobals->v_forward * RANDOM_FLOAT( 0, 1); + vecDir = vecDir.Normalize(); + + // Maximum distance + float fDist = 1024; + + // End point of the streamer + Vector vecEnd = pev->origin + vecDir * fDist; + + // Trace to the end of the streamer to see if + // there is architecture in the way. + UTIL_TraceLine(pev->origin, vecEnd, ignore_monsters, ENT(pev), &tr); + fDist = (tr.vecEndPos - pev->origin).Length(); + + // Now we need to find the distance to the water transition. + // (if there is one) + if (UTIL_PointContents(tr.vecEndPos) != CONTENTS_WATER) + { + Vector vecMin = pev->origin; + Vector vecMax = pev->origin + vecDir * fDist; + Vector vecMid; + float diff = fDist; + + while (diff > 1.0) + { + vecMid = vecMin + (vecMax - vecMin).Normalize() * diff / 2; + if (UTIL_PointContents(vecMid) == CONTENTS_WATER) + { + vecMin = vecMid; + } + else + { + vecMax = vecMid; + } + diff = (vecMax - vecMin).Length(); + } + + fDist = (vecMid - pev->origin).Length(); + } + + // Return new endpoint. + return pev->origin + vecDir * fDist; +} + +LINK_ENTITY_TO_CLASS( zapbounce, CZapBounce ); + +void CZapBounce::Precache( void ) +{ + PRECACHE_SOUND("debris/zap4.wav"); + PRECACHE_SOUND("weapons/electro4.wav"); + PRECACHE_SOUND("hassault/hw_shoot1.wav"); + PRECACHE_MODEL( RIFTSPR ); + PRECACHE_MODEL( RIFTSPR2 ); +} + +void CZapBounce::Spawn( void ) +{ + pev->classname = MAKE_STRING( "multizapper" ); + + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_NOT; + + //UTIL_MakeAimVectors( pev->angles ); + m_vecStart = pev->origin; + m_vecDir = pev->angles; + m_fDamage = 90; + m_iBounce = 5; + m_bFirstZap = TRUE; + + SetThink ( BounceThink ); + pev->nextthink = gpGlobals->time + 0.2; + + EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0,100 ); +} + +void CZapBounce::BounceThink( void ) +{ + TraceResult tr; + CBaseEntity *pEntity; + + pev->nextthink = gpGlobals->time + 0.05; + + // Zap Forward with some randomness. + if (!m_bFirstZap) + { + m_vecDir = m_vecDir * 5 + Vector(RANDOM_FLOAT( -1, 1), + RANDOM_FLOAT( -1, 1), + RANDOM_FLOAT( -1, 1) + ); + } + m_vecDir = m_vecDir.Normalize(); + + // Maximum distance for this segment. + float fDist = 128; + + // End point of the streamer + Vector vecEnd = m_vecStart + m_vecDir * fDist; + + // Trace to the end of the streamer + UTIL_TraceLine(m_vecStart, vecEnd, dont_ignore_monsters, pentIgnore, &tr); + fDist = (tr.vecEndPos - m_vecStart).Length(); + + // draw lightning + for (int i = 0; i < 2; i++) + { + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMPOINTS ); + WRITE_COORD(m_vecStart.x); + WRITE_COORD(m_vecStart.y); + WRITE_COORD(m_vecStart.z); + WRITE_COORD( tr.vecEndPos.x ); + WRITE_COORD( tr.vecEndPos.y ); + WRITE_COORD( tr.vecEndPos.z ); + WRITE_SHORT( g_sModelIndexLightning ); + WRITE_BYTE( 0 ); // Starting frame + WRITE_BYTE( 0 ); // framerate * 0.1 + WRITE_BYTE( 10 ); // life * 0.1 + WRITE_BYTE( m_iBounce * 10 ); // width + WRITE_BYTE( 10 * (6 - m_iBounce )); // noise + WRITE_BYTE( 96 ); // color r,g,b + WRITE_BYTE( 180 ); // color r,g,b + WRITE_BYTE( 255 ); // color r,g,b + WRITE_BYTE( m_iBounce * 50); // brightness + WRITE_BYTE( 0 ); // scroll speed + MESSAGE_END(); + } + + m_vecStart = tr.vecEndPos; + + // Did we hit an entity? Then do damage. + pEntity = CBaseEntity::Instance(tr.pHit); + if (pEntity) { + if (pEntity->pev->takedamage) + { + ClearMultiDamage( ); + pEntity->TraceAttack( VARS(pev->owner), m_fDamage, m_vecDir, &tr, DMG_SHOCK | DMG_ALWAYSGIB ); + ApplyMultiDamage( VARS(pev->owner), VARS(pev->owner) ); + UTIL_ScreenFade( pEntity, Vector(96,180,255), 2, 0.5, 128, FFADE_IN ); + } + // Did we hit a wall? Then reflect. + else + { + float n; + n = -DotProduct(tr.vecPlaneNormal, m_vecDir); + + Vector r; + r = 2.0 * tr.vecPlaneNormal * n + m_vecDir; + m_vecDir = r; + } + pentIgnore = ENT(pEntity->pev); + } + + // We can hurt ourselves after the first beam. + m_bFirstZap = FALSE; + + // bounce once + m_iBounce--; + if (m_iBounce < 1) + { + // UTIL_ClientPrintAll( HUD_PRINTTALK, " Zap bounce point destroyed.\n"); + SetThink(SUB_Remove); + pev->nextthink = gpGlobals->time + .1; + return; + } + + // split beam? + if (RANDOM_LONG(0,100) < 80) + { + m_fDamage *= .75; + + CZapBounce* pRift = (CZapBounce*)CBaseEntity::Create( "zapbounce", + m_vecStart, + m_vecDir, + ENT(pev->owner) ); + pRift->m_fDamage = m_fDamage; + pRift->m_iBounce = m_iBounce; + pRift->m_bFirstZap = FALSE; + pRift->pev->nextthink = gpGlobals->time + RANDOM_LONG(.2,.3); + } +} + diff --git a/dlls/bubblemod/BMOD_zapgunrift.h b/dlls/bubblemod/BMOD_zapgunrift.h new file mode 100644 index 00000000..e0810ab6 --- /dev/null +++ b/dlls/bubblemod/BMOD_zapgunrift.h @@ -0,0 +1,62 @@ +// --------------------------------------------------------------- +// Zap Rift Entity +// +// AUTHOR +// Tyler Lund +// +// LICENSE +// +// Permission is granted to anyone to use this software for +// any purpose on any computer system, and to redistribute it +// in any way, subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of +// use of this software, no matter how awful, even if they +// arise from defects in it. +// 2. The origin of this software must not be misrepresented, +// either by explicit claim or by omission. +// 3. Altered versions must be plainly marked as such, and +// must not be misrepresented (by explicit claim or +// omission) as being the original software. +// 3a. It would be nice if I got a copy of your improved +// version sent to halflife@bubblemod.org. +// 4. This notice must not be removed or altered. +// +// --------------------------------------------------------------- + +#ifndef C_ZAP_RIFT +#define C_ZAP_RIFT + +class CZapRift : public CPointEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT Animate( void ); + Vector FindBeam( void ); + + int m_maxFrame; + CSprite *m_pSprite; + float m_fLifeSpan; + float m_fNextElectrify; + + Vector m_vecZapDir; + +}; + +class CZapBounce : public CPointEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT BounceThink( void ); + + Vector m_vecStart; + Vector m_vecDir; + edict_t *pentIgnore; + BOOL m_bFirstZap; + float m_fDamage; + int m_iBounce; +}; + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/egon.h b/dlls/bubblemod/egon.h new file mode 100644 index 00000000..3c61ea4d --- /dev/null +++ b/dlls/bubblemod/egon.h @@ -0,0 +1,91 @@ + + +#ifndef EGON_H +#define EGON_H + +#include "weapons.h" + +#define BUBBLE_SOUND_OFF "debris/flesh5.wav" +#define BUBBLE_SOUND_RUN "debris/flesh5.wav" +#define BUBBLE_SOUND_STARTUP "debris/flesh6.wav" +#define EGON_PRIMARY_VOLUME 450 + +extern cvar_t bm_gluon_mod; + +class CEgon : public CBasePlayerWeapon +{ +public: +#ifndef CLIENT_DLL + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; +#endif + + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 4; } + int GetItemInfo(ItemInfo *p); + int AddToPlayer( CBasePlayer *pPlayer ); + + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + + void UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ); + + void CreateEffect ( void ); + void DestroyEffect ( void ); + + void EndAttack( void ); + void Attack( void ); + void PrimaryAttack( void ); + void WeaponIdle( void ); + + float m_flAmmoUseTime;// since we use < 1 point of ammo per update, we subtract ammo on a timer. + + float GetPulseInterval( void ); + float GetDischargeInterval( void ); + + void Fire( const Vector &vecOrigSrc, const Vector &vecDir ); + + BOOL HasAmmo( void ); + + void UseAmmo( int count ); + + enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; + + CBeam *m_pBeam; + CBeam *m_pNoise; + CSprite *m_pSprite; + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + + unsigned short m_usEgonStop; + + // BMOD Begin - bubblegun + void BubbleAttack( void ); + void FireBubbles( void ); + float m_bubbletime; + void FireHeal( void ); + static int g_fireAnims1[]; + static int g_fireAnims2[]; + float m_healAmmoUsed; + float m_healAmmoUseTime; + // BMOD End - bubblegun + +private: + float m_shootTime; + EGON_FIREMODE m_fireMode; + float m_shakeTime; + BOOL m_deployed; + + unsigned short m_usEgonFire; +}; + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/squeakgrenade.h b/dlls/bubblemod/squeakgrenade.h new file mode 100644 index 00000000..f0816206 --- /dev/null +++ b/dlls/bubblemod/squeakgrenade.h @@ -0,0 +1,68 @@ + +#ifndef SQUEAKGRENADE_H +#define SQUEAKGRENADE_H + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" +#include "soundent.h" +#include "gamerules.h" +#include "BMOD_messaging.h" + +enum w_squeak_e { + WSQUEAK_IDLE1 = 0, + WSQUEAK_FIDGET, + WSQUEAK_JUMP, + WSQUEAK_RUN, +}; + +enum squeak_e { + SQUEAK_IDLE1 = 0, + SQUEAK_FIDGETFIT, + SQUEAK_FIDGETNIP, + SQUEAK_DOWN, + SQUEAK_UP, + SQUEAK_THROW +}; + +extern cvar_t bm_snarks_mod; +extern cvar_t bm_snarktrails; + +class CSqueakGrenade : public CGrenade +{ + void Spawn( void ); + void Precache( void ); + int Classify( void ); + void EXPORT SuperBounceTouch( CBaseEntity *pOther ); + void EXPORT HuntThink( void ); + int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } + void Killed( entvars_t *pevAttacker, int iGib ); + void GibMonster( void ); + + CBaseEntity *CSqueakGrenade :: BMOD_BestVisibleEnemy ( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + static float m_flNextBounceSoundTime; + + // CBaseEntity *m_pTarget; + float m_flDie; + Vector m_vecTarget; + float m_flNextHunt; + float m_flNextHit; + Vector m_posPrev; + EHANDLE m_hOwner; + int m_iMyClass; + +public: + BOOL m_bWasLaunched; +}; + +#endif \ No newline at end of file diff --git a/dlls/bubblemod/tripmine.h b/dlls/bubblemod/tripmine.h new file mode 100644 index 00000000..140d678e --- /dev/null +++ b/dlls/bubblemod/tripmine.h @@ -0,0 +1,48 @@ + +#ifndef TRIPMINE_H +#define TRIPMINE_H + +class CTripmineGrenade : public CGrenade +{ + void Spawn( void ); + void Precache( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + + void EXPORT WarningThink( void ); + void EXPORT PowerupThink( void ); + void EXPORT BeamBreakThink( void ); + void EXPORT DelayDeathThink( void ); + void Killed( entvars_t *pevAttacker, int iGib ); + + void MakeBeam( void ); + void KillBeam( void ); + + float m_flPowerUp; + Vector m_vecDir; + Vector m_vecEnd; + float m_flBeamLength; + + EHANDLE m_hOwner; + CBeam *m_pBeam; + Vector m_posOwner; + Vector m_angleOwner; + edict_t *m_pRealOwner;// tracelines don't hit PEV->OWNER, which means a player couldn't detonate his own trip mine, so we store the owner here. + + // BMOD Begin - New tripmine functions + BOOL BMOD_IsSpawnMine( void ); + void FlashBang( void ); +public: + void Deactivate( void ); + edict_t *Owner( void ) { return m_pRealOwner; }; + BOOL m_bIsFlashbang; + // BMOD End - New tripmine functions + +}; + +#endif \ No newline at end of file