as released 1999-04-07

This commit is contained in:
archive 1999-04-07 00:00:00 +00:00
commit b443b4420e
261 changed files with 97134 additions and 0 deletions

141
cl_dll/MOTD.cpp Normal file
View File

@ -0,0 +1,141 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// MOTD.cpp
//
// for displaying a server-sent message of the day
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
DECLARE_MESSAGE( m_MOTD, MOTD );
int CHudMOTD::MOTD_DISPLAY_TIME;
int CHudMOTD :: Init( void )
{
gHUD.AddHudElem( this );
HOOK_MESSAGE( MOTD );
CVAR_CREATE( "motd_display_time", "6", 0 );
m_iFlags &= ~HUD_ACTIVE; // start out inactive
m_szMOTD[0] = 0;
return 1;
}
int CHudMOTD :: VidInit( void )
{
// Load sprites here
return 1;
}
void CHudMOTD :: Reset( void )
{
m_iFlags &= ~HUD_ACTIVE; // start out inactive
m_szMOTD[0] = 0;
m_iLines = 0;
m_flActiveTill = 0;
}
#define LINE_HEIGHT 13
int CHudMOTD :: Draw( float fTime )
{
// Draw MOTD line-by-line
if ( m_flActiveTill < gHUD.m_flTime )
{ // finished with MOTD, disable it
m_szMOTD[0] = 0;
m_iLines = 0;
m_iFlags &= ~HUD_ACTIVE;
return 1;
}
// cap activetill time to the display time
m_flActiveTill = min( gHUD.m_flTime + MOTD_DISPLAY_TIME, m_flActiveTill );
// find the top of where the MOTD should be drawn, so the whole thing is centered in the screen
int ypos = max(((ScreenHeight - (m_iLines * LINE_HEIGHT)) / 2) - 40, 30 ); // shift it up slightly
char *ch = m_szMOTD;
while ( *ch )
{
int line_length = 0; // count the length of the current line
for ( char *next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ )
line_length += gHUD.m_scrinfo.charWidths[ *next_line ];
char *top = next_line;
if ( *top == '\n' )
*top = 0;
else
top = NULL;
// find where to start drawing the line
int xpos = (ScreenWidth - line_length) / 2;
gHUD.DrawHudString( xpos, ypos, ScreenWidth, ch, 255, 180, 0 );
ypos += LINE_HEIGHT;
if ( top ) // restore
*top = '\n';
ch = next_line;
if ( *ch == '\n' )
ch++;
if ( ypos > (ScreenHeight - 20) )
break; // don't let it draw too low
}
return 1;
}
int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf )
{
if ( m_iFlags & HUD_ACTIVE )
{
Reset(); // clear the current MOTD in prep for this one
}
BEGIN_READ( pbuf, iSize );
int is_finished = READ_BYTE();
strcat( m_szMOTD, READ_STRING() );
if ( is_finished )
{
m_iFlags |= HUD_ACTIVE;
MOTD_DISPLAY_TIME = CVAR_GET_FLOAT( "motd_display_time" );
m_flActiveTill = gHUD.m_flTime + MOTD_DISPLAY_TIME;
for ( char *sz = m_szMOTD; *sz != 0; sz++ ) // count the number of lines in the MOTD
{
if ( *sz == '\n' )
m_iLines++;
}
}
return 1;
}

1177
cl_dll/ammo.cpp Normal file

File diff suppressed because it is too large Load Diff

62
cl_dll/ammo.h Normal file
View File

@ -0,0 +1,62 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef __AMMO_H__
#define __AMMO_H__
#define MAX_WEAPON_NAME 128
#define WEAPON_FLAGS_SELECTONEMPTY 1
#define WEAPON_IS_ONTARGET 0x40
struct WEAPON
{
char szName[MAX_WEAPON_NAME];
int iAmmoType;
int iAmmo2Type;
int iMax1;
int iMax2;
int iSlot;
int iSlotPos;
int iFlags;
int iId;
int iClip;
int iCount; // # of itesm in plist
HSPRITE hActive;
wrect_t rcActive;
HSPRITE hInactive;
wrect_t rcInactive;
HSPRITE hAmmo;
wrect_t rcAmmo;
HSPRITE hAmmo2;
wrect_t rcAmmo2;
HSPRITE hCrosshair;
wrect_t rcCrosshair;
HSPRITE hAutoaim;
wrect_t rcAutoaim;
HSPRITE hZoomedCrosshair;
wrect_t rcZoomedCrosshair;
HSPRITE hZoomedAutoaim;
wrect_t rcZoomedAutoaim;
};
typedef int AMMO;
#endif

159
cl_dll/ammo_secondary.cpp Normal file
View File

@ -0,0 +1,159 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// ammo_secondary.cpp
//
// implementation of CHudAmmoSecondary class
//
#include "hud.h"
#include "util.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal );
DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon );
int CHudAmmoSecondary :: Init( void )
{
HOOK_MESSAGE( SecAmmoVal );
HOOK_MESSAGE( SecAmmoIcon );
gHUD.AddHudElem(this);
m_HUD_ammoicon = 0;
for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ )
m_iAmmoAmounts[i] = -1; // -1 means don't draw this value
Reset();
return 1;
}
void CHudAmmoSecondary :: Reset( void )
{
m_fFade = 0;
}
int CHudAmmoSecondary :: VidInit( void )
{
return 1;
}
int CHudAmmoSecondary :: Draw(float flTime)
{
if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) )
return 1;
// draw secondary ammo icons above normal ammo readout
int a, x, y, r, g, b, AmmoWidth;
UnpackRGB( r, g, b, RGB_YELLOWISH );
a = (int) max( MIN_ALPHA, m_fFade );
if (m_fFade > 0)
m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons
ScaleColors( r, g, b, a );
AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left;
y = ScreenHeight - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values
x = ScreenWidth - AmmoWidth;
if ( m_HUD_ammoicon )
{
// Draw the ammo icon
x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left);
y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom);
SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b );
SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) );
}
else
{ // move the cursor by the '0' char instead, since we don't have an icon to work with
x -= AmmoWidth;
y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom);
}
// draw the ammo counts, in reverse order, from right to left
for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- )
{
if ( m_iAmmoAmounts[i] < 0 )
continue; // negative ammo amounts imply that they shouldn't be drawn
// half a char gap between the ammo number and the previous pic
x -= (AmmoWidth / 2);
// draw the number, right-aligned
x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth);
gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b );
if ( i != 0 )
{
// draw the divider bar
x -= (AmmoWidth / 2);
FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a);
}
}
return 1;
}
// Message handler for Secondary Ammo Value
// accepts one value:
// string: sprite name
int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_HUD_ammoicon = gHUD.GetSpriteIndex( READ_STRING() );
return 1;
}
// Message handler for Secondary Ammo Icon
// Sets an ammo value
// takes two values:
// byte: ammo index
// byte: ammo value
int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int index = READ_BYTE();
if ( index < 0 || index >= MAX_SEC_AMMO_VALUES )
return 1;
m_iAmmoAmounts[index] = READ_BYTE();
m_iFlags |= HUD_ACTIVE;
// check to see if there is anything left to draw
int count = 0;
for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ )
{
count += max( 0, m_iAmmoAmounts[i] );
}
if ( count == 0 )
{ // the ammo fields are all empty, so turn off this hud area
m_iFlags &= ~HUD_ACTIVE;
return 1;
}
// make the icons light up
m_fFade = 200.0f;
return 1;
}

190
cl_dll/ammohistory.cpp Normal file
View File

@ -0,0 +1,190 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// ammohistory.cpp
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
#include "ammohistory.h"
HistoryResource gHR;
#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5)
#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2))
#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight - 100)
#define MAX_ITEM_NAME 32
int HISTORY_DRAW_TIME = 5;
// keep a list of items
struct ITEM_INFO
{
char szName[MAX_ITEM_NAME];
HSPRITE spr;
wrect_t rect;
};
void HistoryResource :: AddToHistory( int iType, int iId, int iCount )
{
if ( iType == HISTSLOT_AMMO && !iCount )
return; // no amount, so don't add
if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) )
{ // the pic would have to be drawn too high
// so start from the bottom
iCurrentHistorySlot = 0;
}
HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot
HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" );
freeslot->type = iType;
freeslot->iId = iId;
freeslot->iCount = iCount;
freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME;
}
void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount )
{
if ( iType != HISTSLOT_ITEM )
return;
if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) )
{ // the pic would have to be drawn too high
// so start from the bottom
iCurrentHistorySlot = 0;
}
HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot
// I am really unhappy with all the code in this file
int i = gHUD.GetSpriteIndex( szName );
if ( i == -1 )
return; // unknown sprite name, don't add it to history
freeslot->iId = i;
freeslot->type = iType;
freeslot->iCount = iCount;
HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" );
freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME;
}
void HistoryResource :: CheckClearHistory( void )
{
for ( int i = 0; i < MAX_HISTORY; i++ )
{
if ( rgAmmoHistory[i].type )
return;
}
iCurrentHistorySlot = 0;
}
//
// Draw Ammo pickup history
//
int HistoryResource :: DrawAmmoHistory( float flTime )
{
for ( int i = 0; i < MAX_HISTORY; i++ )
{
if ( rgAmmoHistory[i].type )
{
rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME );
if ( rgAmmoHistory[i].DisplayTime <= flTime )
{ // pic drawing time has expired
memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) );
CheckClearHistory();
}
else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO )
{
wrect_t rcPic;
HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic );
int r, g, b;
UnpackRGB(r,g,b, RGB_YELLOWISH);
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
ScaleColors(r, g, b, min(scale, 255) );
// Draw the pic
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - 24;
if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic
{ // the dll has to make sure it has sent info the weapons you need
SPR_Set( *spr, r, g, b );
SPR_DrawAdditive( 0, xpos, ypos, &rcPic );
}
// Draw the number
gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b );
}
else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP )
{
WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId );
if ( !weap )
return 1; // we don't know about the weapon yet, so don't draw anything
int r, g, b;
UnpackRGB(r,g,b, RGB_YELLOWISH);
if ( !gWR.HasAmmo( weap ) )
UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
ScaleColors(r, g, b, min(scale, 255) );
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - (weap->rcInactive.right - weap->rcInactive.left);
SPR_Set( weap->hInactive, r, g, b );
SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive );
}
else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM )
{
int r, g, b;
if ( !rgAmmoHistory[i].iId )
continue; // sprite not loaded
wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId );
UnpackRGB(r,g,b, RGB_YELLOWISH);
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
ScaleColors(r, g, b, min(scale, 255) );
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - (rect.right - rect.left) - 10;
SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b );
SPR_DrawAdditive( 0, xpos, ypos, &rect );
}
}
}
return 1;
}

144
cl_dll/ammohistory.h Normal file
View File

@ -0,0 +1,144 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// ammohistory.h
//
// this is the max number of items in each bucket
#define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS
class WeaponsResource
{
private:
// Information about weapons & ammo
WEAPON rgWeapons[MAX_WEAPONS]; // Weapons Array
// counts of weapons * ammo
WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1]; // The slots currently in use by weapons. The value is a pointer to the weapon; if it's NULL, no weapon is there
int riAmmo[MAX_AMMO_TYPES]; // count of each ammo type
public:
void Init( void )
{
memset( rgWeapons, 0, sizeof rgWeapons );
Reset();
}
void Reset( void )
{
iOldWeaponBits = 0;
memset( rgSlots, 0, sizeof rgSlots );
memset( riAmmo, 0, sizeof riAmmo );
}
///// WEAPON /////
int iOldWeaponBits;
WEAPON *GetWeapon( int iId ) { return &rgWeapons[iId]; }
void AddWeapon( WEAPON *wp )
{
rgWeapons[ wp->iId ] = *wp;
LoadWeaponSprites( &rgWeapons[ wp->iId ] );
}
void PickupWeapon( WEAPON *wp )
{
rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp;
}
void DropWeapon( WEAPON *wp )
{
rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL;
}
void DropAllWeapons( void )
{
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
if ( rgWeapons[i].iId )
DropWeapon( &rgWeapons[i] );
}
}
WEAPON* GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; }
void LoadWeaponSprites( WEAPON* wp );
void LoadAllWeaponSprites( void );
WEAPON* GetFirstPos( int iSlot );
void SelectSlot( int iSlot, int fAdvance, int iDirection );
WEAPON* GetNextActivePos( int iSlot, int iSlotPos );
int HasAmmo( WEAPON *p );
///// AMMO /////
AMMO GetAmmo( int iId ) { return iId; }
void SetAmmo( int iId, int iCount ) { riAmmo[ iId ] = iCount; }
int CountAmmo( int iId );
HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect );
};
extern WeaponsResource gWR;
#define MAX_HISTORY 12
enum {
HISTSLOT_EMPTY,
HISTSLOT_AMMO,
HISTSLOT_WEAP,
HISTSLOT_ITEM,
};
class HistoryResource
{
private:
struct HIST_ITEM {
int type;
float DisplayTime; // the time at which this item should be removed from the history
int iCount;
int iId;
};
HIST_ITEM rgAmmoHistory[MAX_HISTORY];
public:
void Init( void )
{
Reset();
}
void Reset( void )
{
memset( rgAmmoHistory, 0, sizeof rgAmmoHistory );
}
int iHistoryGap;
int iCurrentHistorySlot;
void AddToHistory( int iType, int iId, int iCount = 0 );
void AddToHistory( int iType, const char *szName, int iCount = 0 );
void CheckClearHistory( void );
int DrawAmmoHistory( float flTime );
};
extern HistoryResource gHR;

138
cl_dll/battery.cpp Normal file
View File

@ -0,0 +1,138 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// battery.cpp
//
// implementation of CHudBattery class
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
DECLARE_MESSAGE(m_Battery, Battery)
int CHudBattery::Init(void)
{
m_iBat = 0;
m_fFade = 0;
m_iFlags = 0;
HOOK_MESSAGE(Battery);
gHUD.AddHudElem(this);
return 1;
};
int CHudBattery::VidInit(void)
{
int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" );
int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" );
m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded
m_prc1 = &gHUD.GetSpriteRect( HUD_suit_empty );
m_prc2 = &gHUD.GetSpriteRect( HUD_suit_full );
m_iHeight = m_prc2->bottom - m_prc1->top;
m_fFade = 0;
return 1;
};
int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf )
{
m_iFlags |= HUD_ACTIVE;
BEGIN_READ( pbuf, iSize );
int x = READ_SHORT();
if (x != m_iBat)
{
m_fFade = FADE_TIME;
m_iBat = x;
}
return 1;
}
int CHudBattery::Draw(float flTime)
{
if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH )
return 1;
int r, g, b, x, y, a;
wrect_t rc;
rc = *m_prc2;
rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1
UnpackRGB(r,g,b, RGB_YELLOWISH);
if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) ))
return 1;
// Has health changed? Flash the health #
if (m_fFade)
{
if (m_fFade > FADE_TIME)
m_fFade = FADE_TIME;
m_fFade -= (gHUD.m_flTimeDelta * 20);
if (m_fFade <= 0)
{
a = 128;
m_fFade = 0;
}
// Fade the health number back to dim
a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128;
}
else
a = MIN_ALPHA;
ScaleColors(r, g, b, a );
int iOffset = (m_prc1->bottom - m_prc1->top)/6;
y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2;
x = ScreenWidth/5;
// make sure we have the right sprite handles
if ( !m_hSprite1 )
m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) );
if ( !m_hSprite2 )
m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) );
SPR_Set(m_hSprite1, r, g, b );
SPR_DrawAdditive( 0, x, y - iOffset, m_prc1);
if (rc.bottom > rc.top)
{
SPR_Set(m_hSprite2, r, g, b );
SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc);
}
x += (m_prc1->right - m_prc1->left);
x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b);
return 1;
}

147
cl_dll/cdll_int.cpp Normal file
View File

@ -0,0 +1,147 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// cdll_int.c
//
// this implementation handles the linking of the engine to the DLL
//
#include "hud.h"
#include "util.h"
#include <string.h>
#define DLLEXPORT __declspec( dllexport )
cl_enginefunc_t gEngfuncs;
CHud gHUD;
/*
==========================
Initialize
Called when the DLL is first loaded.
==========================
*/
extern "C"
{
int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion );
int DLLEXPORT HUD_VidInit( void );
int DLLEXPORT HUD_Init( void );
int DLLEXPORT HUD_Redraw( float flTime, int intermission );
int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime );
int DLLEXPORT HUD_Reset ( void );
}
int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion )
{
gEngfuncs = *pEnginefuncs;
//!!! mwh UNDONE We need to think about our versioning strategy. Do we want to try to be compatible
// with previous versions, especially when we're only 'bonus' functionality? Should it be the engine
// that decides if the DLL is compliant?
if (iVersion != CLDLL_INTERFACE_VERSION)
return 0;
memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t));
return 1;
}
/*
==========================
HUD_VidInit
Called when the game initializes
and whenever the vid_mode is changed
so the HUD can reinitialize itself.
==========================
*/
int DLLEXPORT HUD_VidInit( void )
{
gHUD.VidInit();
return 1;
}
/*
==========================
HUD_Init
Called whenever the client connects
to a server. Reinitializes all
the hud variables.
==========================
*/
int DLLEXPORT HUD_Init( void )
{
gHUD.Init();
return 1;
}
/*
==========================
HUD_Redraw
called every screen frame to
redraw the HUD.
===========================
*/
int DLLEXPORT HUD_Redraw( float time, int intermission )
{
gHUD.Redraw( time, intermission );
return 1;
}
/*
==========================
HUD_UpdateClientData
called every time shared client
dll/engine data gets changed,
and gives the cdll a chance
to modify the data.
returns 1 if anything has been changed, 0 otherwise.
==========================
*/
int DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime )
{
return gHUD.UpdateClientData(pcldata, flTime );
}
/*
==========================
HUD_Reset
Called at start and end of demos to restore to "non"HUD state.
==========================
*/
int DLLEXPORT HUD_Reset( void )
{
gHUD.VidInit();
return 1;
}

247
cl_dll/cl_dll.dsp Normal file
View File

@ -0,0 +1,247 @@
# Microsoft Developer Studio Project File - Name="cl_dll" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=cl_dll - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "cl_dll.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "cl_dll.mak" CFG="cl_dll - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "cl_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "cl_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/GoldSrc/cl_dll", HGEBAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "cl_dll - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir ".\Release"
# PROP BASE Intermediate_Dir ".\Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ".\Release"
# PROP Intermediate_Dir ".\Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:".\Release\client.dll"
# Begin Custom Build - Copying to \half-life\mp\cl_dlls
TargetDir=.\Release
InputPath=.\Release\client.dll
SOURCE="$(InputPath)"
"\half-life\mp\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
copy $(TargetDir)\client.dll \half-life\mp\cl_dlls
# End Custom Build
!ELSEIF "$(CFG)" == "cl_dll - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir ".\Debug"
# PROP BASE Intermediate_Dir ".\Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ".\Debug"
# PROP Intermediate_Dir ".\Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\client.dll"
# Begin Custom Build - Copying to \half-life\mp\cl_dlls
TargetDir=.\Debug
InputPath=.\Debug\client.dll
SOURCE="$(InputPath)"
"\half-life\mp\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
copy $(TargetDir)\client.dll \half-life\mp\cl_dlls
# End Custom Build
!ENDIF
# Begin Target
# Name "cl_dll - Win32 Release"
# Name "cl_dll - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
# Begin Source File
SOURCE=.\ammo.cpp
# End Source File
# Begin Source File
SOURCE=.\ammo_secondary.cpp
# End Source File
# Begin Source File
SOURCE=.\ammohistory.cpp
# End Source File
# Begin Source File
SOURCE=.\battery.cpp
# End Source File
# Begin Source File
SOURCE=.\cdll_int.cpp
# End Source File
# Begin Source File
SOURCE=.\death.cpp
# End Source File
# Begin Source File
SOURCE=.\flashlight.cpp
# End Source File
# Begin Source File
SOURCE=.\geiger.cpp
# End Source File
# Begin Source File
SOURCE=.\health.cpp
# End Source File
# Begin Source File
SOURCE=.\hud.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_msg.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_redraw.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_update.cpp
# End Source File
# Begin Source File
SOURCE=.\menu.cpp
# End Source File
# Begin Source File
SOURCE=.\message.cpp
# End Source File
# Begin Source File
SOURCE=.\MOTD.cpp
# End Source File
# Begin Source File
SOURCE=.\parsemsg.cpp
# End Source File
# Begin Source File
SOURCE=.\parsemsg.h
# End Source File
# Begin Source File
SOURCE=.\saytext.cpp
# End Source File
# Begin Source File
SOURCE=.\scoreboard.cpp
# End Source File
# Begin Source File
SOURCE=.\status_icons.cpp
# End Source File
# Begin Source File
SOURCE=.\statusbar.cpp
# End Source File
# Begin Source File
SOURCE=.\text_message.cpp
# End Source File
# Begin Source File
SOURCE=.\train.cpp
# End Source File
# Begin Source File
SOURCE=.\util.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\ammo.h
# End Source File
# Begin Source File
SOURCE=.\ammohistory.h
# End Source File
# Begin Source File
SOURCE=.\cl_dll.h
# End Source File
# Begin Source File
SOURCE=.\health.h
# End Source File
# Begin Source File
SOURCE=.\hud.h
# End Source File
# Begin Source File
SOURCE=.\util.h
# End Source File
# Begin Source File
SOURCE=.\util_vector.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

37
cl_dll/cl_dll.dsw Normal file
View File

@ -0,0 +1,37 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "cl_dll"=.\cl_dll.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/GoldSrc/cl_dll", HGEBAAAA
.
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
begin source code control
"$/GoldSrc/cl_dll", HGEBAAAA
.
end source code control
}}}
Package=<3>
{{{
}}}
###############################################################################

39
cl_dll/cl_dll.h Normal file
View File

@ -0,0 +1,39 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// cl_dll.h
//
// 4-23-98 JOHN
//
// This DLL is linked by the client when they first initialize.
// This DLL is responsible for the following tasks:
// - Loading the HUD graphics upon initialization
// - Drawing the HUD graphics every frame
// - Handling the custum HUD-update packets
//
typedef unsigned char byte;
typedef unsigned short word;
typedef float vec_t;
typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf);
#include "util_vector.h"
#define EXPORT _declspec( dllexport )
#include "../engine/cdll_int.h"
#include "../dlls/cdll_dll.h"
extern cl_enginefunc_t gEngfuncs;

1245
cl_dll/cl_dll.mak Normal file

File diff suppressed because it is too large Load Diff

223
cl_dll/death.cpp Normal file
View File

@ -0,0 +1,223 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// death notice
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
DECLARE_MESSAGE( m_DeathNotice, DeathMsg );
struct DeathNoticeItem {
char szKiller[MAX_PLAYER_NAME_LENGTH];
char szVictim[MAX_PLAYER_NAME_LENGTH];
int iId; // the index number of the associated sprite
int iSuicide;
int iTeamKill;
float flDisplayTime;
};
#define MAX_DEATHNOTICES 4
static int DEATHNOTICE_DISPLAY_TIME = 6;
#define DEATHNOTICE_TOP 20
DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ];
int CHudDeathNotice :: Init( void )
{
gHUD.AddHudElem( this );
HOOK_MESSAGE( DeathMsg );
CVAR_CREATE( "hud_deathnotice_time", "6", 0 );
return 1;
}
void CHudDeathNotice :: InitHUDData( void )
{
memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) );
}
int CHudDeathNotice :: VidInit( void )
{
m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" );
return 1;
}
int CHudDeathNotice :: Draw( float flTime )
{
int x, y, r, g, b;
for ( int i = 0; i < MAX_DEATHNOTICES; i++ )
{
if ( rgDeathNoticeList[i].iId == 0 )
break; // we've gone through them all
if ( rgDeathNoticeList[i].flDisplayTime < flTime )
{ // display time has expired
// remove the current item from the list
memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) );
i--; // continue on the next item; stop the counter getting incremented
continue;
}
rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME );
// Draw the death notice
y = DEATHNOTICE_TOP + (20 * i); //!!!
int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId;
x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left);
if ( !rgDeathNoticeList[i].iSuicide )
{
x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) );
// Draw killers name
x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller );
}
r = 255; g = 80; b = 0;
if ( rgDeathNoticeList[i].iTeamKill )
{
r = 10; g = 240; b = 10; // display it in sickly green
}
// Draw death weapon
SPR_Set( gHUD.GetSprite(id), r, g, b );
SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) );
x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left);
// Draw victims name
x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim );
}
return 1;
}
// This message handler may be better off elsewhere
int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf )
{
m_iFlags |= HUD_ACTIVE;
BEGIN_READ( pbuf, iSize );
int killer = READ_BYTE();
int victim = READ_BYTE();
char killedwith[32];
strcpy( killedwith, "d_" );
strncat( killedwith, READ_STRING(), 32 );
gHUD.m_Scoreboard.DeathMsg( killer, victim );
for ( int i = 0; i < MAX_DEATHNOTICES; i++ )
{
if ( rgDeathNoticeList[i].iId == 0 )
break;
}
if ( i == MAX_DEATHNOTICES )
{ // move the rest of the list forward to make room for this item
memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES );
i = MAX_DEATHNOTICES - 1;
}
gHUD.m_Scoreboard.GetAllPlayersInfo();
char *killer_name = gHUD.m_Scoreboard.m_PlayerInfoList[ killer ].name;
char *victim_name = gHUD.m_Scoreboard.m_PlayerInfoList[ victim ].name;
if ( !killer_name )
killer_name = "";
if ( !victim_name )
victim_name = "";
strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH );
strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH );
if ( killer == victim || killer == 0 )
rgDeathNoticeList[i].iSuicide = TRUE;
if ( !strcmp( killedwith, "d_teammate" ) )
rgDeathNoticeList[i].iTeamKill = TRUE;
// Find the sprite in the list
int spr = gHUD.GetSpriteIndex( killedwith );
rgDeathNoticeList[i].iId = spr;
DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" );
rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME;
// record the death notice in the console
if ( rgDeathNoticeList[i].iSuicide )
{
ConsolePrint( rgDeathNoticeList[i].szVictim );
if ( !strcmp( killedwith, "d_world" ) )
{
ConsolePrint( " died" );
}
else
{
ConsolePrint( " killed self" );
}
}
else if ( rgDeathNoticeList[i].iTeamKill )
{
ConsolePrint( rgDeathNoticeList[i].szKiller );
ConsolePrint( " killed his teammate " );
ConsolePrint( rgDeathNoticeList[i].szVictim );
}
else
{
ConsolePrint( rgDeathNoticeList[i].szKiller );
ConsolePrint( " killed " );
ConsolePrint( rgDeathNoticeList[i].szVictim );
}
if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill )
{
ConsolePrint( " with " );
// replace the code names with the 'real' names
if ( !strcmp( killedwith+2, "egon" ) )
strcpy( killedwith, "d_gluon gun" );
if ( !strcmp( killedwith+2, "gauss" ) )
strcpy( killedwith, "d_tau cannon" );
ConsolePrint( killedwith+2 ); // skip over the "d_" part
}
ConsolePrint( "\n" );
return 1;
}

149
cl_dll/flashlight.cpp Normal file
View File

@ -0,0 +1,149 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// flashlight.cpp
//
// implementation of CHudFlashlight class
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
DECLARE_MESSAGE(m_Flash, FlashBat)
DECLARE_MESSAGE(m_Flash, Flashlight)
#define BAT_NAME "sprites/%d_Flashlight.spr"
int CHudFlashlight::Init(void)
{
m_fFade = 0;
m_fOn = 0;
HOOK_MESSAGE(Flashlight);
HOOK_MESSAGE(FlashBat);
m_iFlags |= HUD_ACTIVE;
gHUD.AddHudElem(this);
return 1;
};
void CHudFlashlight::Reset(void)
{
m_fFade = 0;
m_fOn = 0;
}
int CHudFlashlight::VidInit(void)
{
int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" );
int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" );
int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" );
m_hSprite1 = gHUD.GetSprite(HUD_flash_empty);
m_hSprite2 = gHUD.GetSprite(HUD_flash_full);
m_hBeam = gHUD.GetSprite(HUD_flash_beam);
m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty);
m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full);
m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam);
m_iWidth = m_prc2->right - m_prc2->left;
return 1;
};
int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int x = READ_BYTE();
m_iBat = x;
m_flBat = ((float)x)/100.0;
return 1;
}
int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_fOn = READ_BYTE();
int x = READ_BYTE();
m_iBat = x;
m_flBat = ((float)x)/100.0;
return 1;
}
int CHudFlashlight::Draw(float flTime)
{
if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) )
return 1;
int r, g, b, x, y, a;
wrect_t rc;
if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) ))
return 1;
if (m_fOn)
a = 225;
else
a = MIN_ALPHA;
if (m_flBat < 0.20)
UnpackRGB(r,g,b, RGB_REDISH);
else
UnpackRGB(r,g,b, RGB_YELLOWISH);
ScaleColors(r, g, b, a);
y = (m_prc1->bottom - m_prc2->top)/2;
x = ScreenWidth - m_iWidth - m_iWidth/2 ;
// Draw the flashlight casing
SPR_Set(m_hSprite1, r, g, b );
SPR_DrawAdditive( 0, x, y, m_prc1);
if ( m_fOn )
{ // draw the flashlight beam
x = ScreenWidth - m_iWidth/2;
SPR_Set( m_hBeam, r, g, b );
SPR_DrawAdditive( 0, x, y, m_prcBeam );
}
// draw the flashlight energy level
x = ScreenWidth - m_iWidth - m_iWidth/2 ;
int iOffset = m_iWidth * (1.0 - m_flBat);
if (iOffset < m_iWidth)
{
rc = *m_prc2;
rc.left += iOffset;
SPR_Set(m_hSprite2, r, g, b );
SPR_DrawAdditive( 0, x + iOffset, y, &rc);
}
return 1;
}

184
cl_dll/geiger.cpp Normal file
View File

@ -0,0 +1,184 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// Geiger.cpp
//
// implementation of CHudAmmo class
//
#include "hud.h"
#include "util.h"
#include <string.h>
#include <time.h>
#include <stdio.h>
#include "parsemsg.h"
DECLARE_MESSAGE(m_Geiger, Geiger )
int CHudGeiger::Init(void)
{
HOOK_MESSAGE( Geiger );
m_iGeigerRange = 0;
m_iFlags = 0;
gHUD.AddHudElem(this);
srand( (unsigned)time( NULL ) );
return 1;
};
int CHudGeiger::VidInit(void)
{
return 1;
};
int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
// update geiger data
m_iGeigerRange = READ_BYTE();
m_iGeigerRange = m_iGeigerRange << 2;
m_iFlags |= HUD_ACTIVE;
return 1;
}
int CHudGeiger::Draw (float flTime)
{
int pct;
float flvol;
int rg[3];
int i;
if (m_iGeigerRange < 1000 && m_iGeigerRange > 0)
{
// peicewise linear is better than continuous formula for this
if (m_iGeigerRange > 800)
{
pct = 0; //Con_Printf ( "range > 800\n");
}
else if (m_iGeigerRange > 600)
{
pct = 2;
flvol = 0.4; //Con_Printf ( "range > 600\n");
rg[0] = 1;
rg[1] = 1;
i = 2;
}
else if (m_iGeigerRange > 500)
{
pct = 4;
flvol = 0.5; //Con_Printf ( "range > 500\n");
rg[0] = 1;
rg[1] = 2;
i = 2;
}
else if (m_iGeigerRange > 400)
{
pct = 8;
flvol = 0.6; //Con_Printf ( "range > 400\n");
rg[0] = 1;
rg[1] = 2;
rg[2] = 3;
i = 3;
}
else if (m_iGeigerRange > 300)
{
pct = 8;
flvol = 0.7; //Con_Printf ( "range > 300\n");
rg[0] = 2;
rg[1] = 3;
rg[2] = 4;
i = 3;
}
else if (m_iGeigerRange > 200)
{
pct = 28;
flvol = 0.78; //Con_Printf ( "range > 200\n");
rg[0] = 2;
rg[1] = 3;
rg[2] = 4;
i = 3;
}
else if (m_iGeigerRange > 150)
{
pct = 40;
flvol = 0.80; //Con_Printf ( "range > 150\n");
rg[0] = 3;
rg[1] = 4;
rg[2] = 5;
i = 3;
}
else if (m_iGeigerRange > 100)
{
pct = 60;
flvol = 0.85; //Con_Printf ( "range > 100\n");
rg[0] = 3;
rg[1] = 4;
rg[2] = 5;
i = 3;
}
else if (m_iGeigerRange > 75)
{
pct = 80;
flvol = 0.9; //Con_Printf ( "range > 75\n");
//gflGeigerDelay = cl.time + GEIGERDELAY * 0.75;
rg[0] = 4;
rg[1] = 5;
rg[2] = 6;
i = 3;
}
else if (m_iGeigerRange > 50)
{
pct = 90;
flvol = 0.95; //Con_Printf ( "range > 50\n");
rg[0] = 5;
rg[1] = 6;
i = 2;
}
else
{
pct = 95;
flvol = 1.0; //Con_Printf ( "range < 50\n");
rg[0] = 5;
rg[1] = 6;
i = 2;
}
flvol = (flvol * ((rand() & 127)) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5);
if ((rand() & 127) < pct || (rand() & 127) < pct)
{
//S_StartDynamicSound (-1, 0, rgsfx[rand() % i], r_origin, flvol, 1.0, 0, 100);
char sz[256];
int j = rand() & 1;
if (i > 2)
j += rand() & 1;
sprintf(sz, "player/geiger%d.wav", j + 1);
PlaySound(sz, flvol);
}
}
return 1;
}

475
cl_dll/health.cpp Normal file
View File

@ -0,0 +1,475 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// Health.cpp
//
// implementation of CHudHealth class
//
#include "STDIO.H"
#include "STDLIB.H"
#include "MATH.H"
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
DECLARE_MESSAGE(m_Health, Health )
DECLARE_MESSAGE(m_Health, Damage )
#define PAIN_NAME "sprites/%d_pain.spr"
#define DAMAGE_NAME "sprites/%d_dmg.spr"
int giDmgHeight, giDmgWidth;
int giDmgFlags[NUM_DMG_TYPES] =
{
DMG_POISON,
DMG_ACID,
DMG_FREEZE|DMG_SLOWFREEZE,
DMG_DROWN,
DMG_BURN|DMG_SLOWBURN,
DMG_NERVEGAS,
DMG_RADIATION,
DMG_SHOCK,
DMG_CALTROP,
DMG_TRANQ,
DMG_CONCUSS,
DMG_HALLUC
};
int CHudHealth::Init(void)
{
HOOK_MESSAGE(Health);
HOOK_MESSAGE(Damage);
m_iHealth = 100;
m_fFade = 0;
m_iFlags = 0;
m_bitsDamage = 0;
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
giDmgHeight = 0;
giDmgWidth = 0;
memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES);
gHUD.AddHudElem(this);
return 1;
}
void CHudHealth::Reset( void )
{
// make sure the pain compass is cleared when the player respawns
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
// force all the flashing damage icons to expire
m_bitsDamage = 0;
for ( int i = 0; i < NUM_DMG_TYPES; i++ )
{
m_dmg[i].fExpire = 0;
}
}
int CHudHealth::VidInit(void)
{
m_hSprite = 0;
m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1;
m_HUD_cross = gHUD.GetSpriteIndex( "cross" );
giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left;
giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top;
return 1;
}
int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf )
{
// TODO: update local health data
BEGIN_READ( pbuf, iSize );
int x = READ_BYTE();
m_iFlags |= HUD_ACTIVE;
// Only update the fade if we've changed health
if (x != m_iHealth)
{
m_fFade = FADE_TIME;
m_iHealth = x;
}
return 1;
}
int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int armor = READ_BYTE(); // armor
int damageTaken = READ_BYTE(); // health
long bitsDamage = READ_LONG(); // damage bits
vec3_t vecFrom;
for ( int i = 0 ; i < 3 ; i++)
vecFrom[i] = READ_COORD();
UpdateTiles(gHUD.m_flTime, bitsDamage);
// Actually took damage?
if ( damageTaken > 0 || armor > 0 )
CalcDamageDirection(vecFrom);
return 1;
}
// Returns back a color from the
// Green <-> Yellow <-> Red ramp
void CHudHealth::GetPainColor( int &r, int &g, int &b )
{
int iHealth = m_iHealth;
if (iHealth > 25)
iHealth -= 25;
else if ( iHealth < 0 )
iHealth = 0;
#if 0
g = iHealth * 255 / 100;
r = 255 - g;
b = 0;
#else
if (m_iHealth > 25)
{
UnpackRGB(r,g,b, RGB_YELLOWISH);
}
else
{
r = 250;
g = 0;
b = 0;
}
#endif
}
int CHudHealth::Draw(float flTime)
{
int r, g, b;
int a = 0, x, y;
int HealthWidth;
// if (m_iHealth <= 0)
// return 1;
if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH )
return 1;
if ( !m_hSprite )
m_hSprite = LoadSprite(PAIN_NAME);
// Has health changed? Flash the health #
if (m_fFade)
{
m_fFade -= (gHUD.m_flTimeDelta * 20);
if (m_fFade <= 0)
{
a = MIN_ALPHA;
m_fFade = 0;
}
// Fade the health number back to dim
a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128;
}
else
a = MIN_ALPHA;
// If health is getting low, make it bright red
if (m_iHealth <= 15)
a = 255;
GetPainColor( r, g, b );
ScaleColors(r, g, b, a );
// Only draw health if we have the suit.
if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)))
{
HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left;
int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left;
y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2;
x = CrossWidth /2;
SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b);
SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross));
x = CrossWidth + HealthWidth / 2;
x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b);
x += HealthWidth/2;
int iHeight = gHUD.m_iFontHeight;
int iWidth = HealthWidth/10;
FillRGBA(x, y, iWidth, iHeight, 255, 160, 0, a);
}
DrawDamage(flTime);
return DrawPain(flTime);
}
void CHudHealth::CalcDamageDirection(vec3_t vecFrom)
{
vec3_t forward, right, up;
float side, front;
vec3_t vecOrigin, vecAngles;
if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2])
{
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
return;
}
memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t));
memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t));
VectorSubtract (vecFrom, vecOrigin, vecFrom);
float flDistToTarget = vecFrom.Length();
vecFrom = vecFrom.Normalize();
AngleVectors (vecAngles, forward, right, up);
front = DotProduct (vecFrom, right);
side = DotProduct (vecFrom, forward);
if (flDistToTarget <= 50)
{
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1;
}
else
{
if (side > 0)
{
if (side > 0.3)
m_fAttackFront = max(m_fAttackFront, side);
}
else
{
float f = fabs(side);
if (f > 0.3)
m_fAttackRear = max(m_fAttackRear, f);
}
if (front > 0)
{
if (front > 0.3)
m_fAttackRight = max(m_fAttackRight, front);
}
else
{
float f = fabs(front);
if (f > 0.3)
m_fAttackLeft = max(m_fAttackLeft, f);
}
}
}
int CHudHealth::DrawPain(float flTime)
{
if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight))
return 1;
int r, g, b;
int x, y, a, shade;
// TODO: get the shift value of the health
a = 255; // max brightness until then
float fFade = gHUD.m_flTimeDelta * 2;
// SPR_Draw top
if (m_fAttackFront > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackFront, 0.5 );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2;
y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3;
SPR_DrawAdditive(0, x, y, NULL);
m_fAttackFront = max( 0, m_fAttackFront - fFade );
} else
m_fAttackFront = 0;
if (m_fAttackRight > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackRight, 0.5 );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2;
y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2;
SPR_DrawAdditive(1, x, y, NULL);
m_fAttackRight = max( 0, m_fAttackRight - fFade );
} else
m_fAttackRight = 0;
if (m_fAttackRear > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackRear, 0.5 );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2;
y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2;
SPR_DrawAdditive(2, x, y, NULL);
m_fAttackRear = max( 0, m_fAttackRear - fFade );
} else
m_fAttackRear = 0;
if (m_fAttackLeft > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackLeft, 0.5 );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 - SPR_Width(m_hSprite, 3) * 3;
y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2;
SPR_DrawAdditive(3, x, y, NULL);
m_fAttackLeft = max( 0, m_fAttackLeft - fFade );
} else
m_fAttackLeft = 0;
return 1;
}
int CHudHealth::DrawDamage(float flTime)
{
int r, g, b, a;
DAMAGE_IMAGE *pdmg;
if (!m_bitsDamage)
return 1;
UnpackRGB(r,g,b, RGB_YELLOWISH);
a = (int)( fabs(sin(flTime*2)) * 256.0);
ScaleColors(r, g, b, a);
// Draw all the items
for (int i = 0; i < NUM_DMG_TYPES; i++)
{
if (m_bitsDamage & giDmgFlags[i])
{
pdmg = &m_dmg[i];
SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b );
SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i));
}
}
// check for bits that should be expired
for ( i = 0; i < NUM_DMG_TYPES; i++ )
{
DAMAGE_IMAGE *pdmg = &m_dmg[i];
if ( m_bitsDamage & giDmgFlags[i] )
{
pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire );
if ( pdmg->fExpire <= flTime // when the time has expired
&& a < 40 ) // and the flash is at the low point of the cycle
{
pdmg->fExpire = 0;
int y = pdmg->y;
pdmg->x = pdmg->y = 0;
// move everyone above down
for (int j = 0; j < NUM_DMG_TYPES; j++)
{
pdmg = &m_dmg[j];
if ((pdmg->y) && (pdmg->y < y))
pdmg->y += giDmgHeight;
}
m_bitsDamage &= ~giDmgFlags[i]; // clear the bits
}
}
}
return 1;
}
void CHudHealth::UpdateTiles(float flTime, long bitsDamage)
{
DAMAGE_IMAGE *pdmg;
// Which types are new?
long bitsOn = ~m_bitsDamage & bitsDamage;
for (int i = 0; i < NUM_DMG_TYPES; i++)
{
pdmg = &m_dmg[i];
// Is this one already on?
if (m_bitsDamage & giDmgFlags[i])
{
pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration
if (!pdmg->fBaseline)
pdmg->fBaseline = flTime;
}
// Are we just turning it on?
if (bitsOn & giDmgFlags[i])
{
// put this one at the bottom
pdmg->x = giDmgWidth/8;
pdmg->y = ScreenHeight - giDmgHeight * 2;
pdmg->fExpire=flTime + DMG_IMAGE_LIFE;
// move everyone else up
for (int j = 0; j < NUM_DMG_TYPES; j++)
{
if (j == i)
continue;
pdmg = &m_dmg[j];
if (pdmg->y)
pdmg->y -= giDmgHeight;
}
pdmg = &m_dmg[i];
}
}
// damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage())
m_bitsDamage |= bitsDamage;
}

127
cl_dll/health.h Normal file
View File

@ -0,0 +1,127 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
#define DMG_IMAGE_LIFE 2 // seconds that image is up
#define DMG_IMAGE_POISON 0
#define DMG_IMAGE_ACID 1
#define DMG_IMAGE_COLD 2
#define DMG_IMAGE_DROWN 3
#define DMG_IMAGE_BURN 4
#define DMG_IMAGE_NERVE 5
#define DMG_IMAGE_RAD 6
#define DMG_IMAGE_SHOCK 7
//tf defines
#define DMG_IMAGE_CALTROP 8
#define DMG_IMAGE_TRANQ 9
#define DMG_IMAGE_CONCUSS 10
#define DMG_IMAGE_HALLUC 11
#define NUM_DMG_TYPES 12
// instant damage
#define DMG_GENERIC 0 // generic damage was done
#define DMG_CRUSH (1 << 0) // crushed by falling or moving object
#define DMG_BULLET (1 << 1) // shot
#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
#define DMG_BURN (1 << 3) // heat burned
#define DMG_FREEZE (1 << 4) // frozen
#define DMG_FALL (1 << 5) // fell too far
#define DMG_BLAST (1 << 6) // explosive blast damage
#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
#define DMG_SHOCK (1 << 8) // electric shock
#define DMG_SONIC (1 << 9) // sound pulse shockwave
#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam
#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death
#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death.
// time-based damage
//mask off TF-specific stuff too
#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage
#define DMG_DROWN (1 << 14) // Drowning
#define DMG_FIRSTTIMEBASED DMG_DROWN
#define DMG_PARALYZE (1 << 15) // slows affected creature down
#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad
#define DMG_POISON (1 << 17) // blood poisioning
#define DMG_RADIATION (1 << 18) // radiation exposure
#define DMG_DROWNRECOVER (1 << 19) // drowning recovery
#define DMG_ACID (1 << 20) // toxic chemicals or acid burns
#define DMG_SLOWBURN (1 << 21) // in an oven
#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer
#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar)
//TF ADDITIONS
#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn
#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance
#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius.
#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor
#define DMG_AIMED (1 << 28) // Does Hit location damage
#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls
#define DMG_CALTROP (1<<30)
#define DMG_HALLUC (1<<31)
// TF Healing Additions for TakeHealth
#define DMG_IGNORE_MAXHEALTH DMG_IGNITE
// TF Redefines since we never use the originals
#define DMG_NAIL DMG_SLASH
#define DMG_NOT_SELF DMG_FREEZE
#define DMG_TRANQ DMG_MORTAR
#define DMG_CONCUSS DMG_SONIC
typedef struct
{
float fExpire;
float fBaseline;
int x, y;
} DAMAGE_IMAGE;
//
//-----------------------------------------------------
//
class CHudHealth: public CHudBase
{
public:
virtual int Init( void );
virtual int VidInit( void );
virtual int Draw(float fTime);
virtual void Reset( void );
int MsgFunc_Health(const char *pszName, int iSize, void *pbuf);
int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf);
int m_iHealth;
int m_HUD_dmg_bio;
int m_HUD_cross;
private:
HSPRITE m_hSprite;
HSPRITE m_hDamage;
DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES];
int m_bitsDamage;
float m_fFade;
void GetPainColor( int &r, int &g, int &b );
int DrawPain(float fTime);
int DrawDamage(float fTime);
float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight;
void CalcDamageDirection(vec3_t vecFrom);
void UpdateTiles(float fTime, long bits);
};

319
cl_dll/hud.cpp Normal file
View File

@ -0,0 +1,319 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// hud.cpp
//
// implementation of CHud class
//
#include "hud.h"
#include "util.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount);
//DECLARE_MESSAGE(m_Logo, Logo)
int __MsgFunc_Logo(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_Logo(pszName, iSize, pbuf );
}
//DECLARE_MESSAGE(m_Logo, Logo)
int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf );
}
int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf)
{
gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf );
return 1;
}
int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf );
}
int __MsgFunc_Concuss(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf );
}
int __MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf )
{
return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf );
}
// This is called every time the DLL is loaded
void CHud :: Init( void )
{
HOOK_MESSAGE( Logo );
HOOK_MESSAGE( ResetHUD );
HOOK_MESSAGE( GameMode );
HOOK_MESSAGE( InitHUD );
HOOK_MESSAGE( SetFOV );
HOOK_MESSAGE( Concuss );
m_iLogo = 0;
m_iFOV = 0;
CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 );
CVAR_CREATE( "default_fov", "90", 0 );
m_pSpriteList = NULL;
// Clear any old HUD list
if ( m_pHudList )
{
HUDLIST *pList;
while ( m_pHudList )
{
pList = m_pHudList;
m_pHudList = m_pHudList->pNext;
free( pList );
}
m_pHudList = NULL;
}
// In case we get messages before the first update -- time will be valid
m_flTime = 1.0;
m_Ammo.Init();
m_Health.Init();
m_Geiger.Init();
m_Train.Init();
m_Battery.Init();
m_Flash.Init();
m_Message.Init();
m_Scoreboard.Init();
m_MOTD.Init();
m_StatusBar.Init();
m_DeathNotice.Init();
m_AmmoSecondary.Init();
m_TextMessage.Init();
m_StatusIcons.Init();
m_SayText.Init();
m_Menu.Init();
MsgFunc_ResetHUD(0, 0, NULL );
}
// CHud destructor
// cleans up memory allocated for m_rg* arrays
CHud :: ~CHud()
{
delete [] m_rghSprites;
delete [] m_rgrcRects;
delete [] m_rgszSpriteNames;
}
// GetSpriteIndex()
// searches through the sprite list loaded from hud.txt for a name matching SpriteName
// returns an index into the gHUD.m_rghSprites[] array
// returns 0 if sprite not found
int CHud :: GetSpriteIndex( const char *SpriteName )
{
// look through the loaded sprite name list for SpriteName
for ( int i = 0; i < m_iSpriteCount; i++ )
{
if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 )
return i;
}
return -1; // invalid sprite
}
void CHud :: VidInit( void )
{
m_scrinfo.iSize = sizeof(m_scrinfo);
GetScreenInfo(&m_scrinfo);
// ----------
// Load Sprites
// ---------
// m_hsprFont = LoadSprite("sprites/%d_font.spr");
m_hsprLogo = 0;
if (ScreenWidth < 640)
m_iRes = 320;
else
m_iRes = 640;
// Only load this once
if ( !m_pSpriteList )
{
// we need to load the hud.txt, and all sprites within
m_pSpriteList = SPR_GetList("sprites/hud.txt", &m_iSpriteCountAllRes);
if (m_pSpriteList)
{
// count the number of sprites of the appropriate res
m_iSpriteCount = 0;
client_sprite_t *p = m_pSpriteList;
for ( int j = 0; j < m_iSpriteCountAllRes; j++ )
{
if ( p->iRes == m_iRes )
m_iSpriteCount++;
p++;
}
// allocated memory for sprite handle arrays
m_rghSprites = new HSPRITE[m_iSpriteCount];
m_rgrcRects = new wrect_t[m_iSpriteCount];
m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH];
p = m_pSpriteList;
int index = 0;
for ( j = 0; j < m_iSpriteCountAllRes; j++ )
{
if ( p->iRes == m_iRes )
{
char sz[256];
sprintf(sz, "sprites/%s.spr", p->szSprite);
m_rghSprites[index] = SPR_Load(sz);
m_rgrcRects[index] = p->rc;
strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH );
index++;
}
p++;
}
}
}
else
{
// we have already have loaded the sprite reference from hud.txt, but
// we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game)
client_sprite_t *p = m_pSpriteList;
int index = 0;
for ( int j = 0; j < m_iSpriteCountAllRes; j++ )
{
if ( p->iRes == m_iRes )
{
char sz[256];
sprintf( sz, "sprites/%s.spr", p->szSprite );
m_rghSprites[index] = SPR_Load(sz);
index++;
}
p++;
}
}
// assumption: number_1, number_2, etc, are all listed and loaded sequentially
m_HUD_number_0 = GetSpriteIndex( "number_0" );
m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top;
m_Ammo.VidInit();
m_Health.VidInit();
m_Geiger.VidInit();
m_Train.VidInit();
m_Battery.VidInit();
m_Flash.VidInit();
m_Message.VidInit();
m_Scoreboard.VidInit();
m_MOTD.VidInit();
m_StatusBar.VidInit();
m_DeathNotice.VidInit();
m_SayText.VidInit();
m_Menu.VidInit();
m_AmmoSecondary.VidInit();
m_TextMessage.VidInit();
m_StatusIcons.VidInit();
}
int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
// update Train data
m_iLogo = READ_BYTE();
return 1;
}
int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
int newfov = READ_BYTE();
int def_fov = CVAR_GET_FLOAT( "default_fov" );
if ( newfov == 0 )
{
m_iFOV = def_fov;
}
else
{
m_iFOV = newfov;
}
// the clients fov is actually set in the client data update section of the hud
// Set a new sensitivity
if ( m_iFOV == def_fov )
{
// reset to saved sensitivity
m_flMouseSensitivity = 0;
}
else
{
// set a new sensitivity that is proportional to the change from the FOV default
m_flMouseSensitivity = CVAR_GET_FLOAT("sensitivity") * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio");
}
return 1;
}
void CHud::AddHudElem(CHudBase *phudelem)
{
HUDLIST *pdl, *ptemp;
//phudelem->Think();
if (!phudelem)
return;
pdl = (HUDLIST *)malloc(sizeof(HUDLIST));
if (!pdl)
return;
memset(pdl, 0, sizeof(HUDLIST));
pdl->p = phudelem;
if (!m_pHudList)
{
m_pHudList = pdl;
return;
}
ptemp = m_pHudList;
while (ptemp->pNext)
ptemp = ptemp->pNext;
ptemp->pNext = pdl;
}

611
cl_dll/hud.h Normal file
View File

@ -0,0 +1,611 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// hud.h
//
// class CHud declaration
//
// CHud handles the message, calculation, and drawing the HUD
//
#define RGB_YELLOWISH 0x00FFA000 //255,160,0
#define RGB_REDISH 0x00FF1010 //255,160,0
#define RGB_GREENISH 0x0000A000 //0,160,0
typedef struct rect_s
{
int left, right, top, bottom;
} wrect_t;
#include "cl_dll.h"
#include "ammo.h"
#define DHN_DRAWZERO 1
#define DHN_2DIGITS 2
#define DHN_3DIGITS 4
#define MIN_ALPHA 100
#define HUDELEM_ACTIVE 1
typedef struct {
int x, y;
} POSITION;
typedef struct {
unsigned char r,g,b,a;
} RGBA;
#define HUD_ACTIVE 1
#define HUD_INTERMISSION 2
#define MAX_PLAYER_NAME_LENGTH 32
//
//-----------------------------------------------------
//
class CHudBase
{
public:
POSITION m_pos;
int m_type;
int m_iFlags; // active, moving,
virtual int Init( void ) {return 0;}
virtual int VidInit( void ) {return 0;}
virtual int Draw(float flTime) {return 0;}
virtual void Think(void) {return;}
virtual void Reset(void) {return;}
virtual void InitHUDData( void ) {} // called every time a server is connected to
};
struct HUDLIST {
CHudBase *p;
HUDLIST *pNext;
};
//
//-----------------------------------------------------
//
class CHudAmmo: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
void Think(void);
void Reset(void);
int DrawWList(float flTime);
int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf);
int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf);
int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf);
int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf );
int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf );
int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf );
int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf );
void _cdecl UserCmd_Slot1( void );
void _cdecl UserCmd_Slot2( void );
void _cdecl UserCmd_Slot3( void );
void _cdecl UserCmd_Slot4( void );
void _cdecl UserCmd_Slot5( void );
void _cdecl UserCmd_Slot6( void );
void _cdecl UserCmd_Slot7( void );
void _cdecl UserCmd_Slot8( void );
void _cdecl UserCmd_Slot9( void );
void _cdecl UserCmd_Slot10( void );
void _cdecl UserCmd_Close( void );
void _cdecl UserCmd_NextWeapon( void );
void _cdecl UserCmd_PrevWeapon( void );
private:
float m_fFade;
RGBA m_rgba;
WEAPON *m_pWeapon;
int m_HUD_bucket0;
int m_HUD_selection;
};
//
//-----------------------------------------------------
//
class CHudAmmoSecondary: public CHudBase
{
public:
int Init( void );
int VidInit( void );
void Reset( void );
int Draw(float flTime);
int MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf );
int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf );
private:
enum {
MAX_SEC_AMMO_VALUES = 4
};
int m_HUD_ammoicon; // sprite indices
int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES];
float m_fFade;
};
#include "health.h"
#define FADE_TIME 100
//
//-----------------------------------------------------
//
class CHudGeiger: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf);
private:
int m_iGeigerRange;
};
//
//-----------------------------------------------------
//
class CHudTrain: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_Train(const char *pszName, int iSize, void *pbuf);
private:
HSPRITE m_hSprite;
int m_iPos;
};
//
//-----------------------------------------------------
//
class CHudMOTD : public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw( float flTime );
void Reset( void );
int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf );
protected:
enum { MAX_MOTD_LENGTH = 241, };
static int MOTD_DISPLAY_TIME;
char m_szMOTD[ MAX_MOTD_LENGTH ];
float m_flActiveTill;
int m_iLines;
};
//
//-----------------------------------------------------
//
class CHudStatusBar : public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw( float flTime );
void Reset( void );
void ParseStatusString( int line_num );
int MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf );
int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf );
protected:
enum {
MAX_STATUSTEXT_LENGTH = 128,
MAX_STATUSBAR_VALUES = 8,
MAX_STATUSBAR_LINES = 2,
};
char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn
char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn
int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar
int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated
};
//
//-----------------------------------------------------
//
class CHudScoreboard: public CHudBase
{
public:
int Init( void );
void InitHUDData( void );
int VidInit( void );
int Draw( float flTime );
int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing
void UserCmd_ShowScores( void );
void UserCmd_HideScores( void );
int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf );
int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf );
int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf );
void DeathMsg( int killer, int victim );
enum {
MAX_PLAYERS = 64,
MAX_TEAMS = 64,
MAX_TEAM_NAME = 16,
};
struct extra_player_info_t {
short frags;
short deaths;
char teamname[MAX_TEAM_NAME];
};
struct team_info_t {
char name[MAX_TEAM_NAME];
short frags;
short deaths;
short ping;
short packetloss;
short ownteam;
short players;
int already_drawn;
int scores_overriden;
};
hud_player_info_t m_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine
extra_player_info_t m_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll
team_info_t m_TeamInfo[MAX_TEAMS+1];
int m_iNumTeams;
int m_iLastKilledBy;
int m_fLastKillTime;
int m_iPlayerNum;
int m_iShowscoresHeld;
void GetAllPlayersInfo( void );
};
//
//-----------------------------------------------------
//
class CHudDeathNotice : public CHudBase
{
public:
int Init( void );
void InitHUDData( void );
int VidInit( void );
int Draw( float flTime );
int MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf );
private:
int m_HUD_d_skull; // sprite index of skull icon
};
//
//-----------------------------------------------------
//
class CHudMenu : public CHudBase
{
public:
int Init( void );
void InitHUDData( void );
int VidInit( void );
void Reset( void );
int Draw( float flTime );
int MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf );
void SelectMenuItem( int menu_item );
int m_fMenuDisplayed;
int m_bitsValidSlots;
float m_flShutoffTime;
int m_fWaitingForMore;
};
//
//-----------------------------------------------------
//
class CHudSayText : public CHudBase
{
public:
int Init( void );
void InitHUDData( void );
int VidInit( void );
int Draw( float flTime );
int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf );
void SayTextPrint( const char *pszBuf, int iBufSize );
void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line );
};
//
//-----------------------------------------------------
//
class CHudBattery: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf );
private:
HSPRITE m_hSprite1;
HSPRITE m_hSprite2;
wrect_t *m_prc1;
wrect_t *m_prc2;
int m_iBat;
float m_fFade;
int m_iHeight; // width of the battery innards
};
//
//-----------------------------------------------------
//
class CHudFlashlight: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
void Reset( void );
int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf );
int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf );
private:
HSPRITE m_hSprite1;
HSPRITE m_hSprite2;
HSPRITE m_hBeam;
wrect_t *m_prc1;
wrect_t *m_prc2;
wrect_t *m_prcBeam;
float m_flBat;
int m_iBat;
int m_fOn;
float m_fFade;
int m_iWidth; // width of the battery innards
};
//
//-----------------------------------------------------
//
const int maxHUDMessages = 16;
struct message_parms_t
{
client_textmessage_t *pMessage;
float time;
int x, y;
int totalWidth, totalHeight;
int width;
int lines;
int lineLength;
int length;
int r, g, b;
int text;
int fadeBlend;
float charTime;
float fadeTime;
};
//
//-----------------------------------------------------
//
class CHudTextMessage: public CHudBase
{
public:
int Init( void );
char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size );
char *BufferedLocaliseTextString( const char *msg );
char *LookupString( const char *msg_name, int *msg_dest = NULL );
int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf);
};
//
//-----------------------------------------------------
//
class CHudMessage: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf);
int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf);
float FadeBlend( float fadein, float fadeout, float hold, float localTime );
int XPosition( float x, int width, int lineWidth );
int YPosition( float y, int height );
void MessageAdd( const char *pName, float time );
void MessageDrawScan( client_textmessage_t *pMessage, float time );
void MessageScanStart( void );
void MessageScanNextChar( void );
void Reset( void );
private:
client_textmessage_t *m_pMessages[maxHUDMessages];
float m_startTime[maxHUDMessages];
message_parms_t m_parms;
float m_gameTitleTime;
client_textmessage_t *m_pGameTitle;
int m_HUD_title_life;
int m_HUD_title_half;
};
//
//-----------------------------------------------------
//
#define MAX_SPRITE_NAME_LENGTH 24
class CHudStatusIcons: public CHudBase
{
public:
int Init( void );
int VidInit( void );
void Reset( void );
int Draw(float flTime);
int MsgFunc_StatusIcon(const char *pszName, int iSize, void *pbuf);
enum {
MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH,
MAX_ICONSPRITES = 4,
};
//had to make these public so CHud could access them (to enable concussion icon)
//could use a friend declaration instead...
void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue );
void DisableIcon( char *pszIconName );
private:
typedef struct
{
char szSpriteName[MAX_ICONSPRITENAME_LENGTH];
HSPRITE spr;
wrect_t rc;
unsigned char r, g, b;
} icon_sprite_t;
icon_sprite_t m_IconList[MAX_ICONSPRITES];
};
//
//-----------------------------------------------------
//
class CHud
{
private:
HUDLIST *m_pHudList;
HSPRITE m_hsprLogo;
int m_iLogo;
client_sprite_t *m_pSpriteList;
int m_iSpriteCount;
int m_iSpriteCountAllRes;
float m_flMouseSensitivity;
int m_iConcussionEffect;
public:
float m_flTime; // the current client time
float m_fOldTime; // the time at which the HUD was last redrawn
double m_flTimeDelta; // the difference between flTime and fOldTime
Vector m_vecOrigin;
Vector m_vecAngles;
int m_iKeyBits;
int m_iHideHUDDisplay;
int m_iFOV;
int m_Teamplay;
int m_iRes;
int m_iFontHeight;
int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b );
int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b );
int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b );
int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b );
int GetNumWidth(int iNumber, int iFlags);
private:
// the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded.
// freed in ~CHud()
HSPRITE *m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt
wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/
char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/
public:
HSPRITE GetSprite( int index )
{
return (index < 0) ? 0 : m_rghSprites[index];
}
wrect_t& GetSpriteRect( int index )
{
return m_rgrcRects[index];
}
int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array
CHudAmmo m_Ammo;
CHudHealth m_Health;
CHudGeiger m_Geiger;
CHudBattery m_Battery;
CHudTrain m_Train;
CHudFlashlight m_Flash;
CHudMessage m_Message;
CHudScoreboard m_Scoreboard;
CHudMOTD m_MOTD;
CHudStatusBar m_StatusBar;
CHudDeathNotice m_DeathNotice;
CHudSayText m_SayText;
CHudMenu m_Menu;
CHudAmmoSecondary m_AmmoSecondary;
CHudTextMessage m_TextMessage;
CHudStatusIcons m_StatusIcons;
void Init( void );
void VidInit( void );
void Think(void);
int Redraw( float flTime, int intermission );
int UpdateClientData( client_data_t *cdata, float time );
CHud() : m_iSpriteCount(0), m_pHudList(NULL) {}
~CHud(); // destructor, frees allocated memory
// user messages
int _cdecl MsgFunc_Damage(const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_Logo(const char *pszName, int iSize, void *pbuf);
int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf);
void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf);
int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf );
// Screen information
SCREENINFO m_scrinfo;
int m_iWeaponBits;
int m_fPlayerDead;
int m_iIntermission;
// sprite indexes
int m_HUD_number_0;
void AddHudElem(CHudBase *p);
};
extern CHud gHUD;

105
cl_dll/hud_msg.cpp Normal file
View File

@ -0,0 +1,105 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// hud_msg.cpp
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
/// USER-DEFINED SERVER MESSAGE HANDLERS
int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf )
{
ASSERT( iSize == 0 );
// clear all hud data
HUDLIST *pList = m_pHudList;
while ( pList )
{
if ( pList->p )
pList->p->Reset();
pList = pList->pNext;
}
// reset sensitivity
m_flMouseSensitivity = 0;
// reset concussion effect
m_iConcussionEffect = 0;
return 1;
}
void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf )
{
// prepare all hud data
HUDLIST *pList = m_pHudList;
while (pList)
{
if ( pList->p )
pList->p->InitHUDData();
pList = pList->pNext;
}
}
int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_Teamplay = READ_BYTE();
return 1;
}
int CHud :: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf )
{
int armor, blood;
Vector from;
int i;
float count;
BEGIN_READ( pbuf, iSize );
armor = READ_BYTE();
blood = READ_BYTE();
for (i=0 ; i<3 ; i++)
from[i] = READ_COORD();
count = (blood * 0.5) + (armor * 0.5);
if (count < 10)
count = 10;
// TODO: kick viewangles, show damage visually
return 1;
}
int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_iConcussionEffect = READ_BYTE();
if (m_iConcussionEffect)
this->m_StatusIcons.EnableIcon("dmg_concuss",255,160,0);
else
this->m_StatusIcons.DisableIcon("dmg_concuss");
return 1;
}

259
cl_dll/hud_redraw.cpp Normal file
View File

@ -0,0 +1,259 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// hud_redraw.cpp
//
#include <math.h>
#include "hud.h"
#include "util.h"
#define MAX_LOGO_FRAMES 56
int grgLogoFrame[MAX_LOGO_FRAMES] =
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15,
16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31
};
// Think
void CHud::Think(void)
{
HUDLIST *pList = m_pHudList;
while (pList)
{
if (pList->p->m_iFlags & HUD_ACTIVE)
pList->p->Think();
pList = pList->pNext;
}
// think about default fov
if ( m_iFOV == 0 )
{ // only let players adjust up in fov, and only if they are not overriden by something else
m_iFOV = max( CVAR_GET_FLOAT( "default_fov" ), 90 );
}
}
// Redraw
// step through the local data, placing the appropriate graphics & text as appropriate
// returns 1 if they've changed, 0 otherwise
int CHud :: Redraw( float flTime, int intermission )
{
m_fOldTime = m_flTime; // save time of previous redraw
m_flTime = flTime;
m_flTimeDelta = (double)m_flTime - m_fOldTime;
// Clock was reset, reset delta
if ( m_flTimeDelta < 0 )
m_flTimeDelta = 0;
m_iIntermission = intermission;
// if no redrawing is necessary
// return 0;
HUDLIST *pList = m_pHudList;
while (pList)
{
if ( !intermission )
{
if ((pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL))
pList->p->Draw(flTime);
}
else
{ // it's an intermission, so only draw hud elements that are set to draw during intermissions
if ( pList->p->m_iFlags & HUD_INTERMISSION )
pList->p->Draw( flTime );
}
pList = pList->pNext;
}
// are we in demo mode? do we need to draw the logo in the top corner?
if (m_iLogo)
{
int x, y, i;
if (m_hsprLogo == 0)
m_hsprLogo = LoadSprite("sprites/%d_logo.spr");
SPR_Set(m_hsprLogo, 250, 250, 250 );
x = SPR_Width(m_hsprLogo, 0);
x = ScreenWidth - x;
y = SPR_Height(m_hsprLogo, 0)/2;
// Draw the logo at 20 fps
int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES;
i = grgLogoFrame[iFrame] - 1;
SPR_DrawAdditive(i, x, y, NULL);
}
return 1;
}
void ScaleColors( int &r, int &g, int &b, int a )
{
float x = (float)a / 255;
r = (int)(r * x);
g = (int)(g * x);
b = (int)(b * x);
}
int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b )
{
// draw the string until we hit the null character or a newline character
for ( ; *szIt != 0 && *szIt != '\n'; szIt++ )
{
int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool
if ( next > iMaxX )
return xpos;
TextMessageDrawChar( xpos, ypos, *szIt, r, g, b );
xpos = next;
}
return xpos;
}
int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b )
{
char szString[32];
sprintf( szString, "%d", iNumber );
return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b );
}
// draws a string from right to left (right-aligned)
int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b )
{
// find the end of the string
for ( char *szIt = szString; *szIt != 0; szIt++ )
{ // we should count the length?
}
// iterate throug the string in reverse
for ( szIt--; szIt != (szString-1); szIt-- )
{
int next = xpos - gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool
if ( next < iMinX )
return xpos;
xpos = next;
TextMessageDrawChar( xpos, ypos, *szIt, r, g, b );
}
return xpos;
}
int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b)
{
int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left;
int k;
if (iNumber > 0)
{
// SPR_Draw 100's
if (iNumber >= 100)
{
k = iNumber/100;
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
x += iWidth;
}
else if (iFlags & (DHN_3DIGITS))
{
//SPR_DrawAdditive( 0, x, y, &rc );
x += iWidth;
}
// SPR_Draw 10's
if (iNumber >= 10)
{
k = (iNumber % 100)/10;
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
x += iWidth;
}
else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS))
{
//SPR_DrawAdditive( 0, x, y, &rc );
x += iWidth;
}
// SPR_Draw ones
k = iNumber % 10;
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
x += iWidth;
}
else if (iFlags & DHN_DRAWZERO)
{
SPR_Set(GetSprite(m_HUD_number_0), r, g, b );
// SPR_Draw 100's
if (iFlags & (DHN_3DIGITS))
{
//SPR_DrawAdditive( 0, x, y, &rc );
x += iWidth;
}
if (iFlags & (DHN_3DIGITS | DHN_2DIGITS))
{
//SPR_DrawAdditive( 0, x, y, &rc );
x += iWidth;
}
// SPR_Draw ones
SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0));
x += iWidth;
}
return x;
}
int CHud::GetNumWidth( int iNumber, int iFlags )
{
if (iFlags & (DHN_3DIGITS))
return 3;
if (iFlags & (DHN_2DIGITS))
return 2;
if (iNumber <= 0)
{
if (iFlags & (DHN_DRAWZERO))
return 1;
else
return 0;
}
if (iNumber < 10)
return 1;
if (iNumber < 100)
return 2;
return 3;
}

45
cl_dll/hud_update.cpp Normal file
View File

@ -0,0 +1,45 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// hud_update.cpp
//
#include <math.h>
#include "hud.h"
#include "util.h"
#include <stdlib.h>
int CHud::UpdateClientData(client_data_t *cdata, float time)
{
memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t));
memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t));
m_iKeyBits = cdata->iKeyBits;
m_iWeaponBits = cdata->iWeaponBits;
gHUD.Think();
cdata->iKeyBits = m_iKeyBits;
cdata->fov = m_iFOV;
cdata->view_idlescale = m_iConcussionEffect;
if ( m_flMouseSensitivity )
cdata->mouse_sensitivity = m_flMouseSensitivity;
// return 1 if in anything in the client_data struct has been changed, 0 otherwise
return 1;
}

174
cl_dll/menu.cpp Normal file
View File

@ -0,0 +1,174 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// menu.cpp
//
// generic menu handler
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
#define MAX_MENU_STRING 512
char g_szMenuString[MAX_MENU_STRING];
char g_szPrelocalisedMenuString[MAX_MENU_STRING];
DECLARE_MESSAGE( m_Menu, ShowMenu );
int CHudMenu :: Init( void )
{
gHUD.AddHudElem( this );
HOOK_MESSAGE( ShowMenu );
InitHUDData();
return 1;
}
void CHudMenu :: InitHUDData( void )
{
m_fMenuDisplayed = 0;
m_bitsValidSlots = 0;
Reset();
}
void CHudMenu :: Reset( void )
{
g_szPrelocalisedMenuString[0] = 0;
m_fWaitingForMore = FALSE;
}
int CHudMenu :: VidInit( void )
{
return 1;
}
int CHudMenu :: Draw( float flTime )
{
// check for if menu is set to disappear
if ( m_flShutoffTime > 0 )
{
if ( m_flShutoffTime <= gHUD.m_flTime )
{ // times up, shutoff
m_fMenuDisplayed = 0;
m_iFlags &= ~HUD_ACTIVE;
return 1;
}
}
// don't draw the menu if the scoreboard is being shown
if ( gHUD.m_Scoreboard.m_iShowscoresHeld )
return 1;
// draw the menu, along the left-hand side of the screen
// count the number of newlines
int nlc = 0;
for ( int i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ )
{
if ( g_szMenuString[i] == '\n' )
nlc++;
}
// center it
int y = (ScreenHeight/2) - ((nlc/2)*12) - 40; // make sure it is above the say text
int x = 20;
i = 0;
while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' )
{
gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 );
y += 12;
while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' )
i++;
if ( g_szMenuString[i] == '\n' )
i++;
}
return 1;
}
// selects an item from the menu
void CHudMenu :: SelectMenuItem( int menu_item )
{
// if menu_item is in a valid slot, send a menuselect command to the server
if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) )
{
char szbuf[32];
sprintf( szbuf, "menuselect %d\n", menu_item );
ClientCmd( szbuf );
// remove the menu
m_fMenuDisplayed = 0;
m_iFlags &= ~HUD_ACTIVE;
}
}
// Message handler for ShowMenu message
// takes four values:
// short: a bitfield of keys that are valid input
// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen.
// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string
// string: menu string to display
// if this message is never received, then scores will simply be the combined totals of the players.
int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_bitsValidSlots = READ_SHORT();
int DisplayTime = READ_CHAR();
int NeedMore = READ_BYTE();
if ( DisplayTime > 0 )
m_flShutoffTime = DisplayTime + gHUD.m_flTime;
else
m_flShutoffTime = -1;
if ( m_bitsValidSlots )
{
if ( !m_fWaitingForMore ) // this is the start of a new menu
{
strncpy( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING );
}
else
{ // append to the current menu string
strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) );
}
g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not)
if ( !NeedMore )
{ // we have the whole string, so we can localise it now
strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) );
}
m_fMenuDisplayed = 1;
m_iFlags |= HUD_ACTIVE;
}
else
{
m_fMenuDisplayed = 0; // no valid slots means that the menu should be turned off
m_iFlags &= ~HUD_ACTIVE;
}
m_fWaitingForMore = NeedMore;
return 1;
}

463
cl_dll/message.cpp Normal file
View File

@ -0,0 +1,463 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// Message.cpp
//
// implementation of CHudMessage class
//
#include "hud.h"
#include "util.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
DECLARE_MESSAGE( m_Message, HudText )
DECLARE_MESSAGE( m_Message, GameTitle )
int CHudMessage::Init(void)
{
HOOK_MESSAGE( HudText );
HOOK_MESSAGE( GameTitle );
gHUD.AddHudElem(this);
Reset();
return 1;
};
int CHudMessage::VidInit( void )
{
m_HUD_title_half = gHUD.GetSpriteIndex( "title_half" );
m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" );
return 1;
};
void CHudMessage::Reset( void )
{
memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages );
memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages );
m_gameTitleTime = 0;
m_pGameTitle = NULL;
}
float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime )
{
float fadeTime = fadein + hold;
float fadeBlend;
if ( localTime < 0 )
return 0;
if ( localTime < fadein )
{
fadeBlend = 1 - ((fadein - localTime) / fadein);
}
else if ( localTime > fadeTime )
{
if ( fadeout > 0 )
fadeBlend = 1 - ((localTime - fadeTime) / fadeout);
else
fadeBlend = 0;
}
else
fadeBlend = 1;
return fadeBlend;
}
int CHudMessage::XPosition( float x, int width, int totalWidth )
{
int xPos;
if ( x == -1 )
{
xPos = (ScreenWidth - width) / 2;
}
else
{
if ( x < 0 )
xPos = (1.0 + x) * ScreenWidth - totalWidth; // Alight right
else
xPos = x * ScreenWidth;
}
if ( xPos + width > ScreenWidth )
xPos = ScreenWidth - width;
else if ( xPos < 0 )
xPos = 0;
return xPos;
}
int CHudMessage::YPosition( float y, int height )
{
int yPos;
if ( y == -1 ) // Centered?
yPos = (ScreenHeight - height) * 0.5;
else
{
// Alight bottom?
if ( y < 0 )
yPos = (1.0 + y) * ScreenHeight - height; // Alight bottom
else // align top
yPos = y * ScreenHeight;
}
if ( yPos + height > ScreenHeight )
yPos = ScreenHeight - height;
else if ( yPos < 0 )
yPos = 0;
return yPos;
}
void CHudMessage::MessageScanNextChar( void )
{
int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue;
int blend;
srcRed = m_parms.pMessage->r1;
srcGreen = m_parms.pMessage->g1;
srcBlue = m_parms.pMessage->b1;
blend = 0; // Pure source
switch( m_parms.pMessage->effect )
{
// Fade-in / Fade-out
case 0:
case 1:
destRed = destGreen = destBlue = 0;
blend = m_parms.fadeBlend;
break;
case 2:
m_parms.charTime += m_parms.pMessage->fadein;
if ( m_parms.charTime > m_parms.time )
{
srcRed = srcGreen = srcBlue = 0;
blend = 0; // pure source
}
else
{
float deltaTime = m_parms.time - m_parms.charTime;
destRed = destGreen = destBlue = 0;
if ( m_parms.time > m_parms.fadeTime )
{
blend = m_parms.fadeBlend;
}
else if ( deltaTime > m_parms.pMessage->fxtime )
blend = 0; // pure dest
else
{
destRed = m_parms.pMessage->r2;
destGreen = m_parms.pMessage->g2;
destBlue = m_parms.pMessage->b2;
blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5);
}
}
break;
}
if ( blend > 255 )
blend = 255;
else if ( blend < 0 )
blend = 0;
m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8;
m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8;
m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8;
if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 )
{
if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth )
TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 );
}
}
void CHudMessage::MessageScanStart( void )
{
switch( m_parms.pMessage->effect )
{
// Fade-in / out with flicker
case 1:
case 0:
m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime;
if ( m_parms.time < m_parms.pMessage->fadein )
{
m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255);
}
else if ( m_parms.time > m_parms.fadeTime )
{
if ( m_parms.pMessage->fadeout > 0 )
m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255);
else
m_parms.fadeBlend = 255; // Pure dest (off)
}
else
m_parms.fadeBlend = 0; // Pure source (on)
m_parms.charTime = 0;
if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 )
m_parms.charTime = 1;
break;
case 2:
m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime;
if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 )
m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255);
else
m_parms.fadeBlend = 0;
break;
}
}
void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time )
{
int i, j, length, width;
const char *pText;
unsigned char line[80];
pText = pMessage->pMessage;
// Count lines
m_parms.lines = 1;
m_parms.time = time;
m_parms.pMessage = pMessage;
length = 0;
width = 0;
m_parms.totalWidth = 0;
while ( *pText )
{
if ( *pText == '\n' )
{
m_parms.lines++;
if ( width > m_parms.totalWidth )
m_parms.totalWidth = width;
width = 0;
}
else
width += gHUD.m_scrinfo.charWidths[*pText];
pText++;
length++;
}
m_parms.length = length;
m_parms.totalHeight = (m_parms.lines * gHUD.m_scrinfo.iCharHeight);
m_parms.y = YPosition( pMessage->y, m_parms.totalHeight );
pText = pMessage->pMessage;
m_parms.charTime = 0;
MessageScanStart();
for ( i = 0; i < m_parms.lines; i++ )
{
m_parms.lineLength = 0;
m_parms.width = 0;
while ( *pText && *pText != '\n' )
{
unsigned char c = *pText;
line[m_parms.lineLength] = c;
m_parms.width += gHUD.m_scrinfo.charWidths[c];
m_parms.lineLength++;
pText++;
}
pText++; // Skip LF
line[m_parms.lineLength] = 0;
m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth );
for ( j = 0; j < m_parms.lineLength; j++ )
{
m_parms.text = line[j];
int next = m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ];
MessageScanNextChar();
if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth )
TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b );
m_parms.x = next;
}
m_parms.y += gHUD.m_scrinfo.iCharHeight;
}
}
int CHudMessage::Draw( float fTime )
{
int i, drawn;
client_textmessage_t *pMessage;
float endTime;
drawn = 0;
if ( m_gameTitleTime > 0 )
{
float localTime = gHUD.m_flTime - m_gameTitleTime;
float brightness;
// Maybe timer isn't set yet
if ( m_gameTitleTime > gHUD.m_flTime )
m_gameTitleTime = gHUD.m_flTime;
if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) )
m_gameTitleTime = 0;
else
{
brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime );
int halfWidth = gHUD.GetSpriteRect(m_HUD_title_half).right - gHUD.GetSpriteRect(m_HUD_title_half).left;
int fullWidth = halfWidth + gHUD.GetSpriteRect(m_HUD_title_life).right - gHUD.GetSpriteRect(m_HUD_title_life).left;
int fullHeight = gHUD.GetSpriteRect(m_HUD_title_half).bottom - gHUD.GetSpriteRect(m_HUD_title_half).top;
int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth );
int y = YPosition( m_pGameTitle->y, fullHeight );
SPR_Set( gHUD.GetSprite(m_HUD_title_half), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 );
SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_title_half) );
SPR_Set( gHUD.GetSprite(m_HUD_title_life), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 );
SPR_DrawAdditive( 0, x + halfWidth, y, &gHUD.GetSpriteRect(m_HUD_title_life) );
drawn = 1;
}
}
// Fixup level transitions
for ( i = 0; i < maxHUDMessages; i++ )
{
// Assume m_parms.time contains last time
if ( m_pMessages[i] )
{
pMessage = m_pMessages[i];
if ( m_startTime[i] > gHUD.m_flTime )
m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this
}
}
for ( i = 0; i < maxHUDMessages; i++ )
{
if ( m_pMessages[i] )
{
pMessage = m_pMessages[i];
// This is when the message is over
switch( pMessage->effect )
{
case 0:
case 1:
endTime = m_startTime[i] + pMessage->fadein + pMessage->fadeout + pMessage->holdtime;
break;
// Fade in is per character in scanning messages
case 2:
endTime = m_startTime[i] + (pMessage->fadein * strlen( pMessage->pMessage )) + pMessage->fadeout + pMessage->holdtime;
break;
}
if ( fTime <= endTime )
{
float messageTime = fTime - m_startTime[i];
// Draw the message
// effect 0 is fade in/fade out
// effect 1 is flickery credits
// effect 2 is write out (training room)
MessageDrawScan( pMessage, messageTime );
drawn++;
}
else
{
// The message is over
m_pMessages[i] = NULL;
}
}
}
// Remember the time -- to fix up level transitions
m_parms.time = gHUD.m_flTime;
// Don't call until we get another message
if ( !drawn )
m_iFlags &= ~HUD_ACTIVE;
return 1;
}
void CHudMessage::MessageAdd( const char *pName, float time )
{
int i;
for ( i = 0; i < maxHUDMessages; i++ )
{
if ( !m_pMessages[i] )
{
m_pMessages[i] = TextMessageGet( pName );
m_startTime[i] = time;
return;
}
}
}
int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
char *pString = READ_STRING();
MessageAdd( pString, gHUD.m_flTime );
// Remember the time -- to fix up level transitions
m_parms.time = gHUD.m_flTime;
// Turn on drawing
if ( !(m_iFlags & HUD_ACTIVE) )
m_iFlags |= HUD_ACTIVE;
return 1;
}
int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf )
{
m_pGameTitle = TextMessageGet( "GAMETITLE" );
if ( m_pGameTitle != NULL )
{
m_gameTitleTime = gHUD.m_flTime;
// Turn on drawing
if ( !(m_iFlags & HUD_ACTIVE) )
m_iFlags |= HUD_ACTIVE;
}
return 1;
}

4
cl_dll/mssccprj.scc Normal file
View File

@ -0,0 +1,4 @@
SCC = This is a Source Code Control file
[cl_dll.mak]
SCC_Project_Name = "$/HLStandardSDK/SourceCode/cl_dll", NUWHAAAA

166
cl_dll/parsemsg.cpp Normal file
View File

@ -0,0 +1,166 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// parsemsg.cpp
//
typedef unsigned char byte;
#define true 1
static byte *gpBuf;
static int giSize;
static int giRead;
static int giBadRead;
void BEGIN_READ( void *buf, int size )
{
giRead = 0;
giBadRead = 0;
giSize = size;
gpBuf = (byte*)buf;
}
int READ_CHAR( void )
{
int c;
if (giRead + 1 > giSize)
{
giBadRead = true;
return -1;
}
c = (signed char)gpBuf[giRead];
giRead++;
return c;
}
int READ_BYTE( void )
{
int c;
if (giRead+1 > giSize)
{
giBadRead = true;
return -1;
}
c = (unsigned char)gpBuf[giRead];
giRead++;
return c;
}
int READ_SHORT( void )
{
int c;
if (giRead+2 > giSize)
{
giBadRead = true;
return -1;
}
c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) );
giRead += 2;
return c;
}
int READ_WORD( void )
{
return READ_SHORT();
}
int READ_LONG( void )
{
int c;
if (giRead+4 > giSize)
{
giBadRead = true;
return -1;
}
c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24);
giRead += 4;
return c;
}
float READ_FLOAT( void )
{
union
{
byte b[4];
float f;
int l;
} dat;
dat.b[0] = gpBuf[giRead];
dat.b[1] = gpBuf[giRead+1];
dat.b[2] = gpBuf[giRead+2];
dat.b[3] = gpBuf[giRead+3];
giRead += 4;
// dat.l = LittleLong (dat.l);
return dat.f;
}
char* READ_STRING( void )
{
static char string[2048];
int l,c;
string[0] = 0;
l = 0;
do
{
if ( giRead+1 > giSize )
break; // no more characters
c = READ_CHAR();
if (c == -1 || c == 0)
break;
string[l] = c;
l++;
} while (l < sizeof(string)-1);
string[l] = 0;
return string;
}
float READ_COORD( void )
{
return (float)(READ_SHORT() * (1.0/8));
}
float READ_ANGLE( void )
{
return (float)(READ_CHAR() * (360.0/256));
}
float READ_HIRESANGLE( void )
{
return (float)(READ_SHORT() * (360.0/65536));
}

40
cl_dll/parsemsg.h Normal file
View File

@ -0,0 +1,40 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// parsemsg.h
//
#define ASSERT( x )
void BEGIN_READ( void *buf, int size );
int READ_CHAR( void );
int READ_BYTE( void );
int READ_SHORT( void );
int READ_WORD( void );
int READ_LONG( void );
float READ_FLOAT( void );
char* READ_STRING( void );
float READ_COORD( void );
float READ_ANGLE( void );
float READ_HIRESANGLE( void );

107
cl_dll/readme.txt Normal file
View File

@ -0,0 +1,107 @@
client dll readme.txt
-------------------------
This file details the structure of the half-life client dll, and
how it communicates with the half-life game engine.
Engine callback functions:
Drawing functions:
HSPRITE SPR_Load( char *picname );
Loads a sprite into memory, and returns a handle to it.
int SPR_Frames( HSPRITE sprite );
Returns the number of frames stored in the specified sprite.
int SPR_Height( HSPRITE x, int frame )
Returns the height, in pixels, of a sprite at the specified frame.
Returns 0 is the frame number or the sprite handle is invalid.
int SPR_Width( HSPRITE x, int f )
Returns the width, in pixels, of a sprite at the specified frame.
Returns 0 is the frame number or the sprite handle is invalid.
int SPR_Set( HSPRITE sprite, int r, int g, int b );
Prepares a sprite about to be drawn. RBG color values are applied to the sprite at this time.
void SPR_Draw( int frame, int x, int y );
Precondition: SPR_Set has already been called for a sprite.
Draws the currently active sprite to the screen, at position (x,y), where (0,0) is
the top left-hand corner of the screen.
void SPR_DrawHoles( int frame, int x, int y );
Precondition: SPR_Set has already been called for a sprite.
Draws the currently active sprite to the screen. Color index #255 is treated as transparent.
void SPR_DrawAdditive( int frame, int x, int y );
Precondition: SPR_Set has already been called for a sprite.
Draws the currently active sprite to the screen, adding it's color values to the background.
void SPR_EnableScissor( int x, int y, int width, int height );
Creates a clipping rectangle. No pixels will be drawn outside the specified area. Will
stay in effect until either the next frame, or SPR_DisableScissor is called.
void SPR_DisableScissor( void );
Disables the effect of an SPR_EnableScissor call.
int IsHighRes( void );
returns 1 if the res mode is 640x480 or higher; 0 otherwise.
int ScreenWidth( void );
returns the screen width, in pixels.
int ScreenHeight( void );
returns the screen height, in pixels.
// Sound functions
void PlaySound( char *szSound, int volume )
plays the sound 'szSound' at the specified volume. Loads the sound if it hasn't been cached.
If it can't find the sound, it displays an error message and plays no sound.
void PlaySound( int iSound, int volume )
Precondition: iSound has been precached.
Plays the sound, from the precache list.
// Communication functions
void SendClientCmd( char *szCmdString );
sends a command to the server, just as if the client had typed the szCmdString at the console.
char *GetPlayerName( int entity_number );
returns a pointer to a string, that contains the name of the specified client.
Returns NULL if the entity_number is not a client.
DECLARE_MESSAGE(), HOOK_MESSAGE()
These two macros bind the message sending between the entity DLL and the client DLL to
the CHud object.
HOOK_MESSAGE( message_name )
This is used inside CHud::Init(). It calls into the engine to hook that message
from the incoming message stream.
Precondition: There must be a function of name UserMsg_message_name declared
for CHud. Eg, CHud::UserMsg_Health() must be declared if you want to
use HOOK_MESSAGE( Health );
DECLARE_MESSAGE( message_name )
For each HOOK_MESSAGE you must have an equivalent DECLARE_MESSAGE. This creates
a function which passes the hooked messages into the CHud object.
HOOK_COMMAND(), DECLARE_COMMAND()
These two functions declare and hook console commands into the client dll.
HOOK_COMMAND( char *command, command_name )
Whenever the user types the 'command' at the console, the function 'command_name'
will be called.
Precondition: There must be a function of the name UserCmd_command_name declared
for CHud. Eg, CHud::UserMsg_ShowScores() must be declared if you want to
use HOOK_COMMAND( "+showscores", ShowScores );
DECLARE_COMMAND( command_name )
For each HOOK_COMMAND you must have an equivelant DECLARE_COMMAND. This creates
a function which passes the hooked commands into the CHud object.

231
cl_dll/saytext.cpp Normal file
View File

@ -0,0 +1,231 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// saytext.cpp
//
// implementation of CHudSayText class
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
#define MAX_LINES 5
#define MAX_CHARS_PER_LINE 128 /* it can be less than this, depending on char size */
// allow 20 pixels on either side of the text
#define MAX_LINE_WIDTH ( ScreenWidth - 40 )
#define LINE_START 10
static float SCROLL_SPEED = 5;
static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ];
static float flScrollTime = 0; // the time at which the lines next scroll up
static int Y_START = 0;
static int line_height = 0;
DECLARE_MESSAGE( m_SayText, SayText );
int CHudSayText :: Init( void )
{
gHUD.AddHudElem( this );
HOOK_MESSAGE( SayText );
InitHUDData();
CVAR_CREATE( "hud_saytext_time", "5", 0 );
return 1;
}
void CHudSayText :: InitHUDData( void )
{
memset( g_szLineBuffer, 0, sizeof g_szLineBuffer );
}
int CHudSayText :: VidInit( void )
{
return 1;
}
void ScrollTextUp( void )
{
ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer
memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line
if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines
{
g_szLineBuffer[0][0] = 2;
ScrollTextUp();
}
}
int CHudSayText :: Draw( float flTime )
{
int y = Y_START;
// make sure the scrolltime is within reasonable bounds, to guard against the clock being reset
flScrollTime = min( flScrollTime, flTime + SCROLL_SPEED );
// make sure the scrolltime is within reasonable bounds, to guard against the clock being reset
flScrollTime = min( flScrollTime, flTime + SCROLL_SPEED );
if ( flScrollTime <= flTime )
{
if ( *g_szLineBuffer[0] )
{
flScrollTime = flTime + SCROLL_SPEED;
// push the console up
ScrollTextUp();
}
else
{ // buffer is empty, just disable drawing of this section
m_iFlags &= ~HUD_ACTIVE;
}
}
for ( int i = 0; i < MAX_LINES; i++ )
{
if ( *g_szLineBuffer[i] )
DrawConsoleString( LINE_START, y, g_szLineBuffer[i] );
y += line_height;
}
return 1;
}
int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int client_index = READ_BYTE(); // the client who spoke the message
SayTextPrint( READ_STRING(), iSize - 1 );
return 1;
}
void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize )
{
// find an empty string slot
for ( int i = 0; i < MAX_LINES; i++ )
{
if ( ! *g_szLineBuffer[i] )
break;
}
if ( i == MAX_LINES )
{
// force scroll buffer up
ScrollTextUp();
i = MAX_LINES - 1;
}
strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) );
// make sure the text fits in one line
EnsureTextFitsInOneLineAndWrapIfHaveTo( i );
// Set scroll time
if ( i == 0 )
{
SCROLL_SPEED = CVAR_GET_FLOAT( "hud_saytext_time" );
flScrollTime = gHUD.m_flTime + SCROLL_SPEED;
}
m_iFlags |= HUD_ACTIVE;
PlaySound( "misc/talk.wav", 1 );
if ( ScreenHeight >= 480 )
Y_START = ScreenHeight - 45;
else
Y_START = ScreenHeight - 35;
Y_START -= (line_height * (MAX_LINES+1));
}
void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line )
{
int line_width = 0;
GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height );
if ( (line_width + LINE_START) > MAX_LINE_WIDTH )
{ // string is too long to fit on line
// scan the string until we find what word is too long, and wrap the end of the sentence after the word
int length = LINE_START;
int tmp_len = 0;
char *last_break = NULL;
for ( char *x = g_szLineBuffer[line]; *x != 0; x++ )
{
char buf[2];
buf[1] = 0;
if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character
last_break = x;
buf[0] = *x; // get the length of the current character
GetConsoleStringSize( buf, &tmp_len, &line_height );
length += tmp_len;
if ( length > MAX_LINE_WIDTH )
{ // needs to be broken up
if ( !last_break )
last_break = x-1;
x = last_break;
// find an empty string slot
for ( int j = 0; j < MAX_LINES; j++ )
{
if ( ! *g_szLineBuffer[j] )
break;
}
if ( j == MAX_LINES )
{
j = MAX_LINES - 1;
}
// copy remaining string into next buffer, making sure it starts with a space character
if ( (char)*last_break == (char)' ' )
{
int linelen = strlen(g_szLineBuffer[j]);
int remaininglen = strlen(last_break);
if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE )
strcat( g_szLineBuffer[j], last_break );
}
else
{
if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE )
{
strcat( g_szLineBuffer[j], " " );
strcat( g_szLineBuffer[j], last_break );
}
}
*last_break = 0; // cut off the last string
EnsureTextFitsInOneLineAndWrapIfHaveTo( j );
break;
}
}
}
}

528
cl_dll/scoreboard.cpp Normal file
View File

@ -0,0 +1,528 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// Scoreboard.cpp
//
// implementation of CHudScoreboard class
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
DECLARE_COMMAND( m_Scoreboard, ShowScores );
DECLARE_COMMAND( m_Scoreboard, HideScores );
DECLARE_MESSAGE( m_Scoreboard, ScoreInfo );
DECLARE_MESSAGE( m_Scoreboard, TeamInfo );
DECLARE_MESSAGE( m_Scoreboard, TeamScore );
int CHudScoreboard :: Init( void )
{
gHUD.AddHudElem( this );
// Hook messages & commands here
HOOK_COMMAND( "+showscores", ShowScores );
HOOK_COMMAND( "-showscores", HideScores );
HOOK_MESSAGE( ScoreInfo );
HOOK_MESSAGE( TeamScore );
HOOK_MESSAGE( TeamInfo );
InitHUDData();
return 1;
}
int CHudScoreboard :: VidInit( void )
{
// Load sprites here
return 1;
}
void CHudScoreboard :: InitHUDData( void )
{
memset( m_PlayerExtraInfo, 0, sizeof m_PlayerExtraInfo );
m_iLastKilledBy = 0;
m_fLastKillTime = 0;
m_iPlayerNum = 0;
m_iNumTeams = 0;
memset( m_TeamInfo, 0, sizeof m_TeamInfo );
m_iFlags &= ~HUD_ACTIVE; // starts out inactive
m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission
}
/* The scoreboard
We have a minimum width of 1-320 - we could have the field widths scale with it?
*/
// X positions
// relative to the side of the scoreboard
#define NAME_RANGE_MIN 20
#define NAME_RANGE_MAX 145
#define KILLS_RANGE_MIN 130
#define KILLS_RANGE_MAX 170
#define DIVIDER_POS 180
#define DEATHS_RANGE_MIN 185
#define DEATHS_RANGE_MAX 210
#define PING_RANGE_MIN 245
#define PING_RANGE_MAX 295
#define SCOREBOARD_WIDTH 320
// Y positions
#define ROW_GAP 13
#define ROW_RANGE_MIN 15
#define ROW_RANGE_MAX ( ScreenHeight - 50 )
int CHudScoreboard :: Draw( float fTime )
{
if ( !m_iShowscoresHeld && gHUD.m_Health.m_iHealth > 0 && !gHUD.m_iIntermission )
return 1;
GetAllPlayersInfo();
// just sort the list on the fly
// list is sorted first by frags, then by deaths
float list_slot = 0;
int xpos_rel = (ScreenWidth - SCOREBOARD_WIDTH) / 2;
// print the heading line
int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP);
int xpos = NAME_RANGE_MIN + xpos_rel;
if ( !gHUD.m_Teamplay )
gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 );
else
gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 );
gHUD.DrawHudStringReverse( KILLS_RANGE_MAX + xpos_rel, ypos, 0, "kills", 255, 140, 0 );
gHUD.DrawHudString( DIVIDER_POS + xpos_rel, ypos, ScreenWidth, "/", 255, 140, 0 );
gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, "deaths", 255, 140, 0 );
gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "latency", 255, 140, 0 );
list_slot += 1.2;
ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP);
xpos = NAME_RANGE_MIN + xpos_rel;
FillRGBA( xpos - 5, ypos, PING_RANGE_MAX - 5, 1, 255, 140, 0, 255); // draw the seperator line
list_slot += 0.8;
if ( !gHUD.m_Teamplay )
{
// it's not teamplay, so just draw a simple player list
DrawPlayers( xpos_rel, list_slot );
return 1;
}
// clear out team scores
for ( int i = 1; i <= m_iNumTeams; i++ )
{
if ( !m_TeamInfo[i].scores_overriden )
m_TeamInfo[i].frags = m_TeamInfo[i].deaths = 0;
m_TeamInfo[i].ping = m_TeamInfo[i].packetloss = 0;
}
// recalc the team scores, then draw them
for ( i = 1; i < MAX_PLAYERS; i++ )
{
if ( m_PlayerInfoList[i].name == NULL )
continue; // empty player slot, skip
if ( m_PlayerExtraInfo[i].teamname[0] == 0 )
continue; // skip over players who are not in a team
// find what team this player is in
for ( int j = 1; j <= m_iNumTeams; j++ )
{
if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) )
break;
}
if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy
continue;
if ( !m_TeamInfo[j].scores_overriden )
{
m_TeamInfo[j].frags += m_PlayerExtraInfo[i].frags;
m_TeamInfo[j].deaths += m_PlayerExtraInfo[i].deaths;
}
m_TeamInfo[j].ping += m_PlayerInfoList[i].ping;
m_TeamInfo[j].packetloss += m_PlayerInfoList[i].packetloss;
if ( m_PlayerInfoList[i].thisplayer )
m_TeamInfo[j].ownteam = TRUE;
else
m_TeamInfo[j].ownteam = FALSE;
}
// find team ping/packetloss averages
for ( i = 1; i <= m_iNumTeams; i++ )
{
m_TeamInfo[i].already_drawn = FALSE;
if ( m_TeamInfo[i].players > 0 )
{
m_TeamInfo[i].ping /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping
m_TeamInfo[i].packetloss /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping
}
}
// Draw the teams
while ( 1 )
{
int highest_frags = -99999; int lowest_deaths = 99999;
int best_team = 0;
for ( i = 1; i <= m_iNumTeams; i++ )
{
if ( m_TeamInfo[i].players < 0 )
continue;
if ( !m_TeamInfo[i].already_drawn && m_TeamInfo[i].frags >= highest_frags )
{
if ( m_TeamInfo[i].frags > highest_frags || m_TeamInfo[i].deaths < lowest_deaths )
{
best_team = i;
lowest_deaths = m_TeamInfo[i].deaths;
highest_frags = m_TeamInfo[i].frags;
}
}
}
// draw the best team on the scoreboard
if ( !best_team )
break;
// draw out the best team
team_info_t *team_info = &m_TeamInfo[best_team];
ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP);
// check we haven't drawn too far down
if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border
break;
xpos = NAME_RANGE_MIN + xpos_rel;
int r = 255, g = 225, b = 55; // draw the stuff kinda yellowish
if ( team_info->ownteam ) // if it is their team, draw the background different color
{
// overlay the background in blue, then draw the score text over it
FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 );
}
// draw their name (left to right)
gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b );
// draw kills (right to left)
xpos = KILLS_RANGE_MAX + xpos_rel;
gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, team_info->frags, r, g, b );
// draw divider
xpos = DIVIDER_POS + xpos_rel;
gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b );
// draw deaths
xpos = DEATHS_RANGE_MAX + xpos_rel;
gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, team_info->deaths, r, g, b );
// draw ping
// draw ping & packetloss
static char buf[64];
sprintf( buf, "%d", team_info->ping );
xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25;
UnpackRGB( r, g, b, RGB_YELLOWISH );
gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b );
/* Packetloss removed on Kelly 'shipping nazi' Bailey's orders
sprintf( buf, " %d", team_info->packetloss );
gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b );
*/
team_info->already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get drawn again
list_slot++;
// draw all the players that belong to this team, indented slightly
list_slot = DrawPlayers( xpos_rel, list_slot, 10, team_info->name );
}
// draw all the players who are not in a team
list_slot += 0.5;
DrawPlayers( xpos_rel, list_slot, 0, "" );
return 1;
}
// returns the ypos where it finishes drawing
int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset, char *team )
{
// draw the players, in order, and restricted to team if set
while ( 1 )
{
// Find the top ranking player
int highest_frags = -99999; int lowest_deaths = 99999;
int best_player = 0;
for ( int i = 1; i < MAX_PLAYERS; i++ )
{
if ( m_PlayerInfoList[i].name && m_PlayerExtraInfo[i].frags >= highest_frags )
{
if ( !(team && stricmp(m_PlayerExtraInfo[i].teamname, team)) ) // make sure it is the specified team
{
extra_player_info_t *pl_info = &m_PlayerExtraInfo[i];
if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths )
{
best_player = i;
lowest_deaths = pl_info->deaths;
highest_frags = pl_info->frags;
}
}
}
}
if ( !best_player )
break;
// draw out the best player
hud_player_info_t *pl_info = &m_PlayerInfoList[best_player];
int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP);
// check we haven't drawn too far down
if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border
break;
int xpos = NAME_RANGE_MIN + xpos_rel;
int r = 255, g = 255, b = 255;
if ( best_player == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime )
{
if ( pl_info->thisplayer )
{ // green is the suicide color? i wish this could do grey...
FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 80, 155, 0, 70 );
}
else
{ // Highlight the killers name - overlay the background in red, then draw the score text over it
FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 255, 0, 0, ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) );
}
}
else if ( pl_info->thisplayer ) // if it is their name, draw it a different color
{
// overlay the background in blue, then draw the score text over it
FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 );
}
// draw their name (left to right)
gHUD.DrawHudString( xpos + nameoffset, ypos, NAME_RANGE_MAX + xpos_rel, pl_info->name, r, g, b );
// draw kills (right to left)
xpos = KILLS_RANGE_MAX + xpos_rel;
gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, m_PlayerExtraInfo[best_player].frags, r, g, b );
// draw divider
xpos = DIVIDER_POS + xpos_rel;
gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b );
// draw deaths
xpos = DEATHS_RANGE_MAX + xpos_rel;
gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, m_PlayerExtraInfo[best_player].deaths, r, g, b );
// draw ping & packetloss
static char buf[64];
sprintf( buf, "%d", m_PlayerInfoList[best_player].ping );
xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25;
gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b );
/* Packetloss removed on Kelly 'shipping nazi' Bailey's orders
if ( m_PlayerInfoList[best_player].packetloss >= 63 )
{
UnpackRGB( r, g, b, RGB_REDISH );
sprintf( buf, " !!!!" );
}
else
{
sprintf( buf, " %d", m_PlayerInfoList[best_player].packetloss );
}
gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b );
*/
pl_info->name = NULL; // set the name to be NULL, so this client won't get drawn again
list_slot++;
}
return list_slot;
}
void CHudScoreboard :: GetAllPlayersInfo( void )
{
for ( int i = 1; i < MAX_PLAYERS; i++ )
{
GetPlayerInfo( i, &m_PlayerInfoList[i] );
if ( m_PlayerInfoList[i].thisplayer )
m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine
}
}
int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf )
{
m_iFlags |= HUD_ACTIVE;
BEGIN_READ( pbuf, iSize );
short cl = READ_BYTE();
short frags = READ_SHORT();
short deaths = READ_SHORT();
if ( cl > 0 && cl <= MAX_PLAYERS )
{
m_PlayerExtraInfo[cl].frags = frags;
m_PlayerExtraInfo[cl].deaths = deaths;
}
return 1;
}
// Message handler for TeamInfo message
// accepts two values:
// byte: client number
// string: client team name
int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
short cl = READ_BYTE();
if ( cl > 0 && cl <= MAX_PLAYERS )
{ // set the players team
strncpy( m_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME );
}
// rebuild the list of teams
// clear out player counts from teams
for ( int i = 1; i <= m_iNumTeams; i++ )
{
m_TeamInfo[i].players = 0;
}
// rebuild the team list
GetAllPlayersInfo();
m_iNumTeams = 0;
for ( i = 1; i < MAX_PLAYERS; i++ )
{
if ( m_PlayerInfoList[i].name == NULL )
continue;
if ( m_PlayerExtraInfo[i].teamname[0] == 0 )
continue; // skip over players who are not in a team
// is this player in an existing team?
for ( int j = 1; j <= m_iNumTeams; j++ )
{
if ( m_TeamInfo[j].name[0] == '\0' )
break;
if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) )
break;
}
if ( j > m_iNumTeams )
{ // they aren't in a listed team, so make a new one
// search through for an empty team slot
for ( int j = 1; j <= m_iNumTeams; j++ )
{
if ( m_TeamInfo[j].name[0] == '\0' )
break;
}
m_iNumTeams = max( j, m_iNumTeams );
strncpy( m_TeamInfo[j].name, m_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME );
m_TeamInfo[j].players = 0;
}
m_TeamInfo[j].players++;
}
// clear out any empty teams
for ( i = 1; i <= m_iNumTeams; i++ )
{
if ( m_TeamInfo[i].players < 1 )
memset( &m_TeamInfo[i], 0, sizeof(team_info_t) );
}
return 1;
}
// Message handler for TeamScore message
// accepts three values:
// string: team name
// short: teams kills
// short: teams deaths
// if this message is never received, then scores will simply be the combined totals of the players.
int CHudScoreboard :: MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
char *TeamName = READ_STRING();
// find the team matching the name
for ( int i = 1; i <= m_iNumTeams; i++ )
{
if ( !stricmp( TeamName, m_TeamInfo[i].name ) )
break;
}
if ( i > m_iNumTeams )
return 1;
// use this new score data instead of combined player scores
m_TeamInfo[i].scores_overriden = TRUE;
m_TeamInfo[i].frags = READ_SHORT();
m_TeamInfo[i].deaths = READ_SHORT();
return 1;
}
void CHudScoreboard :: DeathMsg( int killer, int victim )
{
// if we were the one killed, or the world killed us, set the scoreboard to indicate suicide
if ( victim == m_iPlayerNum || killer == 0 )
{
m_iLastKilledBy = killer ? killer : m_iPlayerNum;
m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds
if ( killer == m_iPlayerNum )
m_iLastKilledBy = m_iPlayerNum;
}
}
void CHudScoreboard :: UserCmd_ShowScores( void )
{
m_iShowscoresHeld = TRUE;
}
void CHudScoreboard :: UserCmd_HideScores( void )
{
m_iShowscoresHeld = FALSE;
}

149
cl_dll/status_icons.cpp Normal file
View File

@ -0,0 +1,149 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// status_icons.cpp
//
#include "hud.h"
#include "util.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
DECLARE_MESSAGE( m_StatusIcons, StatusIcon );
int CHudStatusIcons::Init( void )
{
HOOK_MESSAGE( StatusIcon );
gHUD.AddHudElem( this );
Reset();
return 1;
}
int CHudStatusIcons::VidInit( void )
{
return 1;
}
void CHudStatusIcons::Reset( void )
{
memset( m_IconList, 0, sizeof m_IconList );
m_iFlags &= ~HUD_ACTIVE;
}
// Draw status icons along the left-hand side of the screen
int CHudStatusIcons::Draw( float flTime )
{
// find starting position to draw from, along right-hand side of screen
int x = 5;
int y = ScreenHeight / 2;
// loop through icon list, and draw any valid icons drawing up from the middle of screen
for ( int i = 0; i < MAX_ICONSPRITES; i++ )
{
if ( m_IconList[i].spr )
{
y -= ( m_IconList[i].rc.bottom - m_IconList[i].rc.top ) + 5;
SPR_Set( m_IconList[i].spr, m_IconList[i].r, m_IconList[i].g, m_IconList[i].b );
SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc );
}
}
return 1;
}
// Message handler for StatusIcon message
// accepts five values:
// byte : TRUE = ENABLE icon, FALSE = DISABLE icon
// string : the sprite name to display
// byte : red
// byte : green
// byte : blue
int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int ShouldEnable = READ_BYTE();
char *pszIconName = READ_STRING();
if ( ShouldEnable )
{
int r = READ_BYTE();
int g = READ_BYTE();
int b = READ_BYTE();
EnableIcon( pszIconName, r, g, b );
m_iFlags |= HUD_ACTIVE;
}
else
{
DisableIcon( pszIconName );
}
return 1;
}
// add the icon to the icon list, and set it's drawing color
void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue )
{
// check to see if the sprite is in the current list
for ( int i = 0; i < MAX_ICONSPRITES; i++ )
{
if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) )
break;
}
if ( i == MAX_ICONSPRITES )
{
// icon not in list, so find an empty slot to add to
for ( i = 0; i < MAX_ICONSPRITES; i++ )
{
if ( !m_IconList[i].spr )
break;
}
}
// if we've run out of space in the list, overwrite the first icon
if ( i == MAX_ICONSPRITES )
{
i = 0;
}
// Load the sprite and add it to the list
// the sprite must be listed in hud.txt
int spr_index = gHUD.GetSpriteIndex( pszIconName );
m_IconList[i].spr = gHUD.GetSprite( spr_index );
m_IconList[i].rc = gHUD.GetSpriteRect( spr_index );
m_IconList[i].r = red;
m_IconList[i].g = green;
m_IconList[i].b = blue;
strcpy( m_IconList[i].szSpriteName, pszIconName );
}
void CHudStatusIcons::DisableIcon( char *pszIconName )
{
// find the sprite is in the current list
for ( int i = 0; i < MAX_ICONSPRITES; i++ )
{
if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) )
{
// clear the item from the list
memset( &m_IconList[i], 0, sizeof icon_sprite_t );
return;
}
}
}

252
cl_dll/statusbar.cpp Normal file
View File

@ -0,0 +1,252 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// statusbar.cpp
//
// generic text status bar, set by game dll
// runs across bottom of screen
//
#include "hud.h"
#include "util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
DECLARE_MESSAGE( m_StatusBar, StatusText );
DECLARE_MESSAGE( m_StatusBar, StatusValue );
#define STATUSBAR_ID_LINE 1
int CHudStatusBar :: Init( void )
{
gHUD.AddHudElem( this );
HOOK_MESSAGE( StatusText );
HOOK_MESSAGE( StatusValue );
Reset();
CVAR_CREATE( "hud_centerid", "0", FCVAR_ARCHIVE );
return 1;
}
int CHudStatusBar :: VidInit( void )
{
// Load sprites here
return 1;
}
void CHudStatusBar :: Reset( void )
{
m_iFlags &= ~HUD_ACTIVE; // start out inactive
for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ )
m_szStatusText[i][0] = 0;
memset( m_iStatusValues, 0, sizeof m_iStatusValues );
m_iStatusValues[0] = 1; // 0 is the special index, which always returns true
}
void CHudStatusBar :: ParseStatusString( int line_num )
{
// localise string first
char szBuffer[MAX_STATUSTEXT_LENGTH];
memset( szBuffer, 0, sizeof szBuffer );
gHUD.m_TextMessage.LocaliseTextString( m_szStatusText[line_num], szBuffer, MAX_STATUSTEXT_LENGTH );
// parse m_szStatusText & m_iStatusValues into m_szStatusBar
memset( m_szStatusBar[line_num], 0, MAX_STATUSTEXT_LENGTH );
char *src = szBuffer;
char *dst = m_szStatusBar[line_num];
char *src_start = src, *dst_start = dst;
while ( *src != 0 )
{
while ( *src == '\n' )
src++; // skip over any newlines
if ( ((src - src_start) >= MAX_STATUSTEXT_LENGTH) || ((dst - dst_start) >= MAX_STATUSTEXT_LENGTH) )
break;
int index = atoi( src );
// should we draw this line?
if ( (index >= 0 && index < MAX_STATUSBAR_VALUES) && (m_iStatusValues[index] != 0) )
{ // parse this line and append result to the status bar
while ( *src >= '0' && *src <= '9' )
src++;
if ( *src == '\n' || *src == 0 )
continue; // no more left in this text line
// copy the text, char by char, until we hit a % or a \n
while ( *src != '\n' && *src != 0 )
{
if ( *src != '%' )
{ // just copy the character
*dst = *src;
dst++, src++;
}
else
{
// get the descriptor
char valtype = *(++src); // move over %
// if it's a %, draw a % sign
if ( valtype == '%' )
{
*dst = valtype;
dst++, src++;
continue;
}
// move over descriptor, then get and move over the index
index = atoi( ++src );
while ( *src >= '0' && *src <= '9' )
src++;
if ( index >= 0 && index < MAX_STATUSBAR_VALUES )
{
int indexval = m_iStatusValues[index];
// get the string to substitute in place of the %XX
char szRepString[MAX_PLAYER_NAME_LENGTH];
switch ( valtype )
{
case 'p': // player name
GetPlayerInfo( indexval, &gHUD.m_Scoreboard.m_PlayerInfoList[indexval] );
if ( gHUD.m_Scoreboard.m_PlayerInfoList[indexval].name != NULL )
{
strncpy( szRepString, gHUD.m_Scoreboard.m_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH );
}
else
{
strcpy( szRepString, "******" );
}
break;
case 'i': // number
sprintf( szRepString, "%d", indexval );
break;
default:
szRepString[0] = 0;
}
for ( char *cp = szRepString; *cp != 0 && ((dst - dst_start) < MAX_STATUSTEXT_LENGTH); cp++, dst++ )
*dst = *cp;
}
}
}
}
else
{
// skip to next line of text
while ( *src != 0 && *src != '\n' )
src++;
}
}
}
int CHudStatusBar :: Draw( float fTime )
{
if ( m_bReparseString )
{
for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ )
ParseStatusString( i );
m_bReparseString = FALSE;
}
// Draw the status bar lines
for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ )
{
int TextHeight, TextWidth;
GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight );
int Y_START;
if ( ScreenHeight >= 480 )
Y_START = ScreenHeight - 45;
else
Y_START = ScreenHeight - 35;
int x = 5;
int y = Y_START - ( TextHeight * i ); // draw along bottom of screen
// let user set status ID bar centering
if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT("hud_centerid") )
{
x = max( 0, max(2, (ScreenWidth - TextWidth)) / 2 );
y = (ScreenHeight / 2) + (TextHeight*CVAR_GET_FLOAT("hud_centerid"));
}
DrawConsoleString( x, y, m_szStatusBar[i] );
}
return 1;
}
// Message handler for StatusText message
// accepts two values:
// byte: line number of status bar text
// string: status bar text
// this string describes how the status bar should be drawn
// a semi-regular expression:
// ( slotnum ([a..z] [%pX] [%iX])*)*
// where slotnum is an index into the Value table (see below)
// if slotnum is 0, the string is always drawn
// if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline
// %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X]
// %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X]
int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int line = READ_BYTE();
if ( line < 0 || line >= MAX_STATUSBAR_LINES )
return 1;
strncpy( m_szStatusText[line], READ_STRING(), MAX_STATUSTEXT_LENGTH );
m_szStatusText[line][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long)
if ( m_szStatusText[0] == 0 )
m_iFlags &= ~HUD_ACTIVE;
else
m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar
m_bReparseString = TRUE;
return 1;
}
// Message handler for StatusText message
// accepts two values:
// byte: index into the status value array
// short: value to store
int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int index = READ_BYTE();
if ( index < 1 || index >= MAX_STATUSBAR_VALUES )
return 1; // index out of range
m_iStatusValues[index] = READ_SHORT();
m_bReparseString = TRUE;
return 1;
}

207
cl_dll/text_message.cpp Normal file
View File

@ -0,0 +1,207 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// text_message.cpp
//
// implementation of CHudTextMessage class
//
// this class routes messages through titles.txt for localisation
//
#include "hud.h"
#include "util.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
DECLARE_MESSAGE( m_TextMessage, TextMsg );
int CHudTextMessage::Init(void)
{
HOOK_MESSAGE( TextMsg );
gHUD.AddHudElem( this );
Reset();
return 1;
};
// Searches through the string for any msg names (indicated by a '#')
// any found are looked up in titles.txt and the new message substituted
// the new value is pushed into dst_buffer
char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size )
{
char *dst = dst_buffer;
for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- )
{
if ( *src == '#' )
{
// cut msg name out of string
static char word_buf[255];
char *wdst = word_buf, *word_start = src;
for ( ++src ; *src >= 'A' && *src <= 'z'; wdst++, src++ )
{
*wdst = *src;
}
*wdst = 0;
// lookup msg name in titles.txt
client_textmessage_t *clmsg = TextMessageGet( word_buf );
if ( !clmsg || !(clmsg->pMessage) )
{
src = word_start;
*dst = *src;
dst++, src++;
continue;
}
// copy string into message over the msg name
for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ )
{
*dst = *wsrc;
}
*dst = 0;
}
else
{
*dst = *src;
dst++, src++;
*dst = 0;
}
}
dst_buffer[buffer_size-1] = 0; // ensure null termination
return dst_buffer;
}
// As above, but with a local static buffer
char *CHudTextMessage::BufferedLocaliseTextString( const char *msg )
{
char dst_buffer[1024];
return LocaliseTextString( msg, dst_buffer, 1024 );
}
// Simplified version of LocaliseTextString; assumes string is only one word
char *CHudTextMessage::LookupString( const char *msg, int *msg_dest )
{
if ( !msg )
return "";
// '#' character indicates this is a reference to a string in titles.txt, and not the string itself
if ( msg[0] == '#' )
{
// this is a message name, so look up the real message
client_textmessage_t *clmsg = TextMessageGet( msg+1 );
if ( !clmsg || !(clmsg->pMessage) )
return (char*)msg; // lookup failed, so return the original string
if ( msg_dest )
{
// check to see if titles.txt info overrides msg destination
// if clmsg->effect is less than 0, then clmsg->effect holds -1 * message_destination
if ( clmsg->effect < 0 ) //
*msg_dest = -clmsg->effect;
}
return (char*)clmsg->pMessage;
}
else
{ // nothing special about this message, so just return the same string
return (char*)msg;
}
}
void StripEndNewlineFromString( char *str )
{
int s = strlen( str ) - 1;
if ( str[s] == '\n' || str[s] == '\r' )
str[s] = 0;
}
// converts all '\r' characters to '\n', so that the engine can deal with the properly
// returns a pointer to str
char* ConvertCRtoNL( char *str )
{
for ( char *ch = str; *ch != 0; ch++ )
if ( *ch == '\r' )
*ch = '\n';
return str;
}
// Message handler for text messages
// displays a string, looking them up from the titles.txt file, which can be localised
// parameters:
// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK )
// string: message
// optional parameters:
// string: message parameter 1
// string: message parameter 2
// string: message parameter 3
// string: message parameter 4
// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt
// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#')
int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int msg_dest = READ_BYTE();
static char szBuf[6][128];
char *msg_text = LookupString( READ_STRING(), &msg_dest );
msg_text = strcpy( szBuf[0], msg_text );
// keep reading strings and using C format strings for subsituting the strings into the localised text string
char *sstr1 = LookupString( READ_STRING() );
sstr1 = strcpy( szBuf[1], sstr1 );
StripEndNewlineFromString( sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines
char *sstr2 = LookupString( READ_STRING() );
sstr2 = strcpy( szBuf[2], sstr2 );
StripEndNewlineFromString( sstr2 );
char *sstr3 = LookupString( READ_STRING() );
sstr3 = strcpy( szBuf[3], sstr3 );
StripEndNewlineFromString( sstr3 );
char *sstr4 = LookupString( READ_STRING() );
sstr4 = strcpy( szBuf[4], sstr4 );
StripEndNewlineFromString( sstr4 );
char *psz = szBuf[5];
switch ( msg_dest )
{
case HUD_PRINTCENTER:
sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 );
CenterPrint( ConvertCRtoNL( psz ) );
break;
case HUD_PRINTNOTIFY:
psz[0] = 1; // mark this message to go into the notify buffer
sprintf( psz+1, msg_text, sstr1, sstr2, sstr3, sstr4 );
ConsolePrint( ConvertCRtoNL( psz ) );
break;
case HUD_PRINTTALK:
sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 );
gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), 128 );
break;
case HUD_PRINTCONSOLE:
sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 );
ConsolePrint( ConvertCRtoNL( psz ) );
break;
}
return 1;
}

85
cl_dll/train.cpp Normal file
View File

@ -0,0 +1,85 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// Train.cpp
//
// implementation of CHudAmmo class
//
#include "hud.h"
#include "util.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
DECLARE_MESSAGE(m_Train, Train )
int CHudTrain::Init(void)
{
HOOK_MESSAGE( Train );
m_iPos = 0;
m_iFlags = 0;
gHUD.AddHudElem(this);
return 1;
};
int CHudTrain::VidInit(void)
{
m_hSprite = 0;
return 1;
};
int CHudTrain::Draw(float fTime)
{
if ( !m_hSprite )
m_hSprite = LoadSprite("sprites/%d_train.spr");
if (m_iPos)
{
int r, g, b, x, y;
UnpackRGB(r,g,b, RGB_YELLOWISH);
SPR_Set(m_hSprite, r, g, b );
// This should show up to the right and part way up the armor number
y = ScreenHeight - SPR_Height(m_hSprite,0) - gHUD.m_iFontHeight;
x = ScreenWidth/3 + SPR_Width(m_hSprite,0)/4;
SPR_DrawAdditive( m_iPos - 1, x, y, NULL);
}
return 1;
}
int CHudTrain::MsgFunc_Train(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
// update Train data
m_iPos = READ_BYTE();
if (m_iPos)
m_iFlags |= HUD_ACTIVE;
else
m_iFlags &= ~HUD_ACTIVE;
return 1;
}

45
cl_dll/util.cpp Normal file
View File

@ -0,0 +1,45 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// util.cpp
//
// implementation of class-less helper functions
//
#include "STDIO.H"
#include "STDLIB.H"
#include "MATH.H"
#include "hud.h"
#include "util.h"
#include <string.h>
HSPRITE LoadSprite(const char *pszName)
{
int i;
char sz[256];
if (ScreenWidth < 640)
i = 320;
else
i = 640;
sprintf(sz, pszName, i);
return SPR_Load(sz);
}

141
cl_dll/util.h Normal file
View File

@ -0,0 +1,141 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// util.h
//
#include <windows.h>
#include "../engine/cvardef.h"
// Macros to hook function calls into the HUD object
#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x );
#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \
{ \
return gHUD.##y.MsgFunc_##x(pszName, iSize, pbuf ); \
}
#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y );
#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \
{ \
gHUD.##y.UserCmd_##x( ); \
}
inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); }
inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); }
inline void CVAR_CREATE( const char *cv, const char *val, const int flags ) { gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); }
#define SPR_Load (*gEngfuncs.pfnSPR_Load)
#define SPR_Set (*gEngfuncs.pfnSPR_Set)
#define SPR_Frames (*gEngfuncs.pfnSPR_Frames)
#define SPR_GetList (*gEngfuncs.pfnSPR_GetList)
// SPR_Draw draws a the current sprite as solid
#define SPR_Draw (*gEngfuncs.pfnSPR_Draw)
// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent)
#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles)
// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency)
#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive)
// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen.
#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor)
// SPR_DisableScissor disables the clipping rect
#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor)
//
#define FillRGBA (*gEngfuncs.pfnFillRGBA)
// ScreenHeight returns the height of the screen, in pixels
#define ScreenHeight (gHUD.m_scrinfo.iHeight)
// ScreenWidth returns the width of the screen, in pixels
#define ScreenWidth (gHUD.m_scrinfo.iWidth)
#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo)
#define ServerCmd (*gEngfuncs.pfnServerCmd)
#define ClientCmd (*gEngfuncs.pfnClientCmd)
#define SetCrosshair (*gEngfuncs.pfnSetCrosshair)
#define AngleVectors (*gEngfuncs.pfnAngleVectors)
// Gets the height & width of a sprite, at the specified frame
inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); }
inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); }
inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); }
inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b )
{
return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b );
}
inline int DrawConsoleString( int x, int y, const char *string )
{
return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string );
}
inline void GetConsoleStringSize( const char *string, int *width, int *height )
{
gEngfuncs.pfnDrawConsoleStringLen( string, width, height );
}
inline int ConsoleStringLen( const char *string )
{
int _width, _height;
GetConsoleStringSize( string, &_width, &_height );
return _width;
}
inline void ConsolePrint( const char *string )
{
gEngfuncs.pfnConsolePrint( string );
}
inline void CenterPrint( const char *string )
{
gEngfuncs.pfnCenterPrint( string );
}
// returns the players name of entity no.
#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo)
// sound functions
inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); }
inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); }
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define fabs(x) ((x) > 0 ? (x) : 0 - (x))
void ScaleColors( int &r, int &g, int &b, int a );
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];}
#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];}
#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];}
// disable 'possible loss of data converting float to int' warning message
#pragma warning( disable: 4244 )
// disable 'truncation from 'const double' to 'float' warning message
#pragma warning( disable: 4305 )
inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\
{\
r = (ulRGB & 0xFF0000) >>16;\
g = (ulRGB & 0xFF00) >> 8;\
b = ulRGB & 0xFF;\
}
HSPRITE LoadSprite(const char *pszName);

121
cl_dll/util_vector.h Normal file
View File

@ -0,0 +1,121 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
// Vector.h
// A subset of the extdll.h in the project HL Entity DLL
//
// Misc C-runtime library headers
#include "STDIO.H"
#include "STDLIB.H"
#include "MATH.H"
// Header file containing definition of globalvars_t and entvars_t
typedef int func_t; //
typedef int string_t; // from engine's pr_comp.h;
typedef float vec_t; // needed before including progdefs.h
//=========================================================
// 2DVector - used for many pathfinding and many other
// operations that are treated as planar rather than 3d.
//=========================================================
class Vector2D
{
public:
inline Vector2D(void) { }
inline Vector2D(float X, float Y) { x = X; y = Y; }
inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); }
inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); }
inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); }
inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); }
inline float Length(void) const { return (float)sqrt(x*x + y*y ); }
inline Vector2D Normalize ( void ) const
{
Vector2D vec2;
float flLen = Length();
if ( flLen == 0 )
{
return Vector2D( (float)0, (float)0 );
}
else
{
flLen = 1 / flLen;
return Vector2D( x * flLen, y * flLen );
}
}
vec_t x, y;
};
inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); }
inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; }
//=========================================================
// 3D Vector
//=========================================================
class Vector // same data-layout as engine's vec3_t,
{ // which is a vec_t[3]
public:
// Construction/destruction
inline Vector(void) { }
inline Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; }
inline Vector(double X, double Y, double Z) { x = (float)X; y = (float)Y; z = (float)Z; }
inline Vector(int X, int Y, int Z) { x = (float)X; y = (float)Y; z = (float)Z; }
inline Vector(const Vector& v) { x = v.x; y = v.y; z = v.z; }
inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; }
// Operators
inline Vector operator-(void) const { return Vector(-x,-y,-z); }
inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; }
inline int operator!=(const Vector& v) const { return !(*this==v); }
inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); }
inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); }
inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); }
inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); }
// Methods
inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; }
inline float Length(void) const { return (float)sqrt(x*x + y*y + z*z); }
operator float *() { return &x; } // Vectors will now automatically convert to float * when needed
operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed
inline Vector Normalize(void) const
{
float flLen = Length();
if (flLen == 0) return Vector(0,0,1); // ????
flLen = 1 / flLen;
return Vector(x * flLen, y * flLen, z * flLen);
}
inline Vector2D Make2D ( void ) const
{
Vector2D Vec2;
Vec2.x = x;
Vec2.y = y;
return Vec2;
}
inline float Length2D(void) const { return (float)sqrt(x*x + y*y); }
// Members
vec_t x, y, z;
};
inline Vector operator*(float fl, const Vector& v) { return v * fl; }
inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); }
inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); }
#define vec3_t Vector

109
dlls/activity.h Normal file
View File

@ -0,0 +1,109 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef ACTIVITY_H
#define ACTIVITY_H
typedef enum {
ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity
ACT_IDLE = 1,
ACT_GUARD,
ACT_WALK,
ACT_RUN,
ACT_FLY, // Fly (and flap if appropriate)
ACT_SWIM,
ACT_HOP, // vertical jump
ACT_LEAP, // long forward jump
ACT_FALL,
ACT_LAND,
ACT_STRAFE_LEFT,
ACT_STRAFE_RIGHT,
ACT_ROLL_LEFT, // tuck and roll, left
ACT_ROLL_RIGHT, // tuck and roll, right
ACT_TURN_LEFT, // turn quickly left (stationary)
ACT_TURN_RIGHT, // turn quickly right (stationary)
ACT_CROUCH, // the act of crouching down from a standing position
ACT_CROUCHIDLE, // holding body in crouched position (loops)
ACT_STAND, // the act of standing from a crouched position
ACT_USE,
ACT_SIGNAL1,
ACT_SIGNAL2,
ACT_SIGNAL3,
ACT_TWITCH,
ACT_COWER,
ACT_SMALL_FLINCH,
ACT_BIG_FLINCH,
ACT_RANGE_ATTACK1,
ACT_RANGE_ATTACK2,
ACT_MELEE_ATTACK1,
ACT_MELEE_ATTACK2,
ACT_RELOAD,
ACT_ARM, // pull out gun, for instance
ACT_DISARM, // reholster gun
ACT_EAT, // monster chowing on a large food item (loop)
ACT_DIESIMPLE,
ACT_DIEBACKWARD,
ACT_DIEFORWARD,
ACT_DIEVIOLENT,
ACT_BARNACLE_HIT, // barnacle tongue hits a monster
ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop )
ACT_BARNACLE_CHOMP, // barnacle latches on to the monster
ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop )
ACT_SLEEP,
ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor
ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you ( doesn't HAVE to be a wall or on a wall )
ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop)
ACT_WALK_HURT, // limp (loop)
ACT_RUN_HURT, // limp (loop)
ACT_HOVER, // Idle while in flight
ACT_GLIDE, // Fly (don't flap)
ACT_FLY_LEFT, // Turn left in flight
ACT_FLY_RIGHT, // Turn right in flight
ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air
ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster
ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops.
ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc )
ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of
ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever.
ACT_SPECIAL_ATTACK1, // very monster specific special attacks.
ACT_SPECIAL_ATTACK2,
ACT_COMBAT_IDLE, // agitated idle.
ACT_WALK_SCARED,
ACT_RUN_SCARED,
ACT_VICTORY_DANCE, // killed a player, do a victory dance.
ACT_DIE_HEADSHOT, // die, hit in head.
ACT_DIE_CHESTSHOT, // die, hit in chest
ACT_DIE_GUTSHOT, // die, hit in gut
ACT_DIE_BACKSHOT, // die, hit in back
ACT_FLINCH_HEAD,
ACT_FLINCH_CHEST,
ACT_FLINCH_STOMACH,
ACT_FLINCH_LEFTARM,
ACT_FLINCH_RIGHTARM,
ACT_FLINCH_LEFTLEG,
ACT_FLINCH_RIGHTLEG,
} Activity;
typedef struct {
int type;
char *name;
} activity_map_t;
extern activity_map_t activity_map[];
#endif //ACTIVITY_H

97
dlls/activitymap.h Normal file
View File

@ -0,0 +1,97 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
#define _A( a ) { a, #a }
activity_map_t activity_map[] =
{
_A( ACT_IDLE ),
_A( ACT_GUARD ),
_A( ACT_WALK ),
_A( ACT_RUN ),
_A( ACT_FLY ),
_A( ACT_SWIM ),
_A( ACT_HOP ),
_A( ACT_LEAP ),
_A( ACT_FALL ),
_A( ACT_LAND ),
_A( ACT_STRAFE_LEFT ),
_A( ACT_STRAFE_RIGHT ),
_A( ACT_ROLL_LEFT ),
_A( ACT_ROLL_RIGHT ),
_A( ACT_TURN_LEFT ),
_A( ACT_TURN_RIGHT ),
_A( ACT_CROUCH ),
_A( ACT_CROUCHIDLE ),
_A( ACT_STAND ),
_A( ACT_USE ),
_A( ACT_SIGNAL1 ),
_A( ACT_SIGNAL2 ),
_A( ACT_SIGNAL3 ),
_A( ACT_TWITCH ),
_A( ACT_COWER ),
_A( ACT_SMALL_FLINCH ),
_A( ACT_BIG_FLINCH ),
_A( ACT_RANGE_ATTACK1 ),
_A( ACT_RANGE_ATTACK2 ),
_A( ACT_MELEE_ATTACK1 ),
_A( ACT_MELEE_ATTACK2 ),
_A( ACT_RELOAD ),
_A( ACT_ARM ),
_A( ACT_DISARM ),
_A( ACT_EAT ),
_A( ACT_DIESIMPLE ),
_A( ACT_DIEBACKWARD ),
_A( ACT_DIEFORWARD ),
_A( ACT_DIEVIOLENT ),
_A( ACT_BARNACLE_HIT ),
_A( ACT_BARNACLE_PULL ),
_A( ACT_BARNACLE_CHOMP ),
_A( ACT_BARNACLE_CHEW ),
_A( ACT_SLEEP ),
_A( ACT_INSPECT_FLOOR ),
_A( ACT_INSPECT_WALL ),
_A( ACT_IDLE_ANGRY ),
_A( ACT_WALK_HURT ),
_A( ACT_RUN_HURT ),
_A( ACT_HOVER ),
_A( ACT_GLIDE ),
_A( ACT_FLY_LEFT ),
_A( ACT_FLY_RIGHT ),
_A( ACT_DETECT_SCENT ),
_A( ACT_SNIFF ),
_A( ACT_BITE ),
_A( ACT_THREAT_DISPLAY ),
_A( ACT_FEAR_DISPLAY ),
_A( ACT_EXCITED ),
_A( ACT_SPECIAL_ATTACK1 ),
_A( ACT_SPECIAL_ATTACK2 ),
_A( ACT_COMBAT_IDLE ),
_A( ACT_WALK_SCARED ),
_A( ACT_RUN_SCARED ),
_A( ACT_VICTORY_DANCE ),
_A( ACT_DIE_HEADSHOT ),
_A( ACT_DIE_CHESTSHOT ),
_A( ACT_DIE_GUTSHOT ),
_A( ACT_DIE_BACKSHOT ),
_A( ACT_FLINCH_HEAD ),
_A( ACT_FLINCH_CHEST ),
_A( ACT_FLINCH_STOMACH ),
_A( ACT_FLINCH_LEFTARM ),
_A( ACT_FLINCH_RIGHTARM ),
_A( ACT_FLINCH_LEFTLEG ),
_A( ACT_FLINCH_RIGHTLEG ),
0, NULL
};

118
dlls/airtank.cpp Normal file
View File

@ -0,0 +1,118 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
class CAirtank : public CGrenade
{
void Spawn( void );
void Precache( void );
void EXPORT TankThink( void );
void EXPORT TankTouch( CBaseEntity *pOther );
int BloodColor( void ) { return DONT_BLEED; };
void Killed( entvars_t *pevAttacker, int iGib );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
int m_state;
};
LINK_ENTITY_TO_CLASS( item_airtank, CAirtank );
TYPEDESCRIPTION CAirtank::m_SaveData[] =
{
DEFINE_FIELD( CAirtank, m_state, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CAirtank, CGrenade );
void CAirtank :: Spawn( void )
{
Precache( );
// motor
pev->movetype = MOVETYPE_FLY;
pev->solid = SOLID_BBOX;
SET_MODEL(ENT(pev), "models/w_oxygen.mdl");
UTIL_SetSize(pev, Vector( -16, -16, 0), Vector(16, 16, 36));
UTIL_SetOrigin( pev, pev->origin );
SetTouch( TankTouch );
SetThink( TankThink );
pev->flags |= FL_MONSTER;
pev->takedamage = DAMAGE_YES;
pev->health = 20;
pev->dmg = 50;
m_state = 1;
}
void CAirtank::Precache( void )
{
PRECACHE_MODEL("models/w_oxygen.mdl");
PRECACHE_SOUND("doors/aliendoor3.wav");
}
void CAirtank :: Killed( entvars_t *pevAttacker, int iGib )
{
pev->owner = ENT( pevAttacker );
// UNDONE: this should make a big bubble cloud, not an explosion
Explode( pev->origin, Vector( 0, 0, -1 ) );
}
void CAirtank::TankThink( void )
{
// Fire trigger
m_state = 1;
SUB_UseTargets( this, USE_TOGGLE, 0 );
}
void CAirtank::TankTouch( CBaseEntity *pOther )
{
if ( !pOther->IsPlayer() )
return;
if (!m_state)
{
// "no oxygen" sound
EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 1.0, ATTN_NORM );
return;
}
// give player 12 more seconds of air
pOther->pev->air_finished = gpGlobals->time + 12;
// suit recharge sound
EMIT_SOUND( ENT(pev), CHAN_VOICE, "doors/aliendoor3.wav", 1.0, ATTN_NORM );
// recharge airtank in 30 seconds
pev->nextthink = gpGlobals->time + 30;
m_state = 0;
SUB_UseTargets( this, USE_TOGGLE, 1 );
}

313
dlls/animating.cpp Normal file
View File

@ -0,0 +1,313 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== monsters.cpp ========================================================
Monster-related utility code
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "animation.h"
#include "saverestore.h"
TYPEDESCRIPTION CBaseAnimating::m_SaveData[] =
{
DEFINE_FIELD( CBaseMonster, m_flFrameRate, FIELD_FLOAT ),
DEFINE_FIELD( CBaseMonster, m_flGroundSpeed, FIELD_FLOAT ),
DEFINE_FIELD( CBaseMonster, m_flLastEventCheck, FIELD_TIME ),
DEFINE_FIELD( CBaseMonster, m_fSequenceFinished, FIELD_BOOLEAN ),
DEFINE_FIELD( CBaseMonster, m_fSequenceLoops, FIELD_BOOLEAN ),
};
IMPLEMENT_SAVERESTORE( CBaseAnimating, CBaseDelay );
//=========================================================
// StudioFrameAdvance - advance the animation frame up to the current time
// if an flInterval is passed in, only advance animation that number of seconds
//=========================================================
float CBaseAnimating :: StudioFrameAdvance ( float flInterval )
{
if (flInterval == 0.0)
{
flInterval = (gpGlobals->time - pev->animtime);
if (flInterval <= 0.001)
{
pev->animtime = gpGlobals->time;
return 0.0;
}
}
if (! pev->animtime)
flInterval = 0.0;
pev->frame += flInterval * m_flFrameRate * pev->framerate;
pev->animtime = gpGlobals->time;
if (pev->frame < 0.0 || pev->frame >= 256.0)
{
if (m_fSequenceLoops)
pev->frame -= (int)(pev->frame / 256.0) * 256.0;
else
pev->frame = (pev->frame < 0.0) ? 0 : 255;
m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents
}
return flInterval;
}
//=========================================================
// LookupActivity
//=========================================================
int CBaseAnimating :: LookupActivity ( int activity )
{
ASSERT( activity != 0 );
void *pmodel = GET_MODEL_PTR( ENT(pev) );
return ::LookupActivity( pmodel, pev, activity );
}
//=========================================================
// LookupActivityHeaviest
//
// Get activity with highest 'weight'
//
//=========================================================
int CBaseAnimating :: LookupActivityHeaviest ( int activity )
{
void *pmodel = GET_MODEL_PTR( ENT(pev) );
return ::LookupActivityHeaviest( pmodel, pev, activity );
}
//=========================================================
//=========================================================
int CBaseAnimating :: LookupSequence ( const char *label )
{
void *pmodel = GET_MODEL_PTR( ENT(pev) );
return ::LookupSequence( pmodel, label );
}
//=========================================================
//=========================================================
void CBaseAnimating :: ResetSequenceInfo ( )
{
void *pmodel = GET_MODEL_PTR( ENT(pev) );
GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed );
m_fSequenceLoops = ((GetSequenceFlags() & STUDIO_LOOPING) != 0);
pev->animtime = gpGlobals->time;
pev->framerate = 1.0;
m_fSequenceFinished = FALSE;
m_flLastEventCheck = gpGlobals->time;
}
//=========================================================
//=========================================================
BOOL CBaseAnimating :: GetSequenceFlags( )
{
void *pmodel = GET_MODEL_PTR( ENT(pev) );
return ::GetSequenceFlags( pmodel, pev );
}
//=========================================================
// DispatchAnimEvents
//=========================================================
void CBaseAnimating :: DispatchAnimEvents ( float flInterval )
{
MonsterEvent_t event;
void *pmodel = GET_MODEL_PTR( ENT(pev) );
if ( !pmodel )
{
ALERT( at_aiconsole, "Gibbed monster is thinking!\n" );
return;
}
// FIXME: I have to do this or some events get missed, and this is probably causing the problem below
flInterval = 0.1;
// FIX: this still sometimes hits events twice
float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate;
float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate;
m_flLastEventCheck = pev->animtime + flInterval;
m_fSequenceFinished = FALSE;
if (flEnd >= 256 || flEnd <= 0.0)
m_fSequenceFinished = TRUE;
int index = 0;
while ( (index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 )
{
HandleAnimEvent( &event );
}
}
//=========================================================
//=========================================================
float CBaseAnimating :: SetBoneController ( int iController, float flValue )
{
void *pmodel = GET_MODEL_PTR( ENT(pev) );
return SetController( pmodel, pev, iController, flValue );
}
//=========================================================
//=========================================================
void CBaseAnimating :: InitBoneControllers ( void )
{
void *pmodel = GET_MODEL_PTR( ENT(pev) );
SetController( pmodel, pev, 0, 0.0 );
SetController( pmodel, pev, 1, 0.0 );
SetController( pmodel, pev, 2, 0.0 );
SetController( pmodel, pev, 3, 0.0 );
}
//=========================================================
//=========================================================
float CBaseAnimating :: SetBlending ( int iBlender, float flValue )
{
void *pmodel = GET_MODEL_PTR( ENT(pev) );
return ::SetBlending( pmodel, pev, iBlender, flValue );
}
//=========================================================
//=========================================================
void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles )
{
GET_BONE_POSITION( ENT(pev), iBone, origin, angles );
}
//=========================================================
//=========================================================
void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles )
{
GET_ATTACHMENT( ENT(pev), iAttachment, origin, angles );
}
//=========================================================
//=========================================================
int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir )
{
void *pmodel = GET_MODEL_PTR( ENT(pev) );
if (piDir == NULL)
{
int iDir;
int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir );
if (iDir != 1)
return -1;
else
return sequence;
}
return ::FindTransition( pmodel, iEndingSequence, iGoalSequence, piDir );
}
//=========================================================
//=========================================================
void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval )
{
}
void CBaseAnimating :: SetBodygroup( int iGroup, int iValue )
{
::SetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup, iValue );
}
int CBaseAnimating :: GetBodygroup( int iGroup )
{
return ::GetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup );
}
int CBaseAnimating :: ExtractBbox( int sequence, float *mins, float *maxs )
{
return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs );
}
//=========================================================
//=========================================================
void CBaseAnimating :: SetSequenceBox( void )
{
Vector mins, maxs;
// Get sequence bbox
if ( ExtractBbox( pev->sequence, mins, maxs ) )
{
// expand box for rotation
// find min / max for rotations
float yaw = pev->angles.y * (M_PI / 180.0);
Vector xvector, yvector;
xvector.x = cos(yaw);
xvector.y = sin(yaw);
yvector.x = -sin(yaw);
yvector.y = cos(yaw);
Vector bounds[2];
bounds[0] = mins;
bounds[1] = maxs;
Vector rmin( 9999, 9999, 9999 );
Vector rmax( -9999, -9999, -9999 );
Vector base, transformed;
for (int i = 0; i <= 1; i++ )
{
base.x = bounds[i].x;
for ( int j = 0; j <= 1; j++ )
{
base.y = bounds[j].y;
for ( int k = 0; k <= 1; k++ )
{
base.z = bounds[k].z;
// transform the point
transformed.x = xvector.x*base.x + yvector.x*base.y;
transformed.y = xvector.y*base.x + yvector.y*base.y;
transformed.z = base.z;
for ( int l = 0; l < 3; l++ )
{
if (transformed[l] < rmin[l])
rmin[l] = transformed[l];
if (transformed[l] > rmax[l])
rmax[l] = transformed[l];
}
}
}
}
rmin.z = 0;
rmax.z = rmin.z + 1;
UTIL_SetSize( pev, rmin, rmax );
}
}

521
dlls/animation.cpp Normal file
View File

@ -0,0 +1,521 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// hack into header files that we can ship
typedef int qboolean;
typedef unsigned char byte;
#include "../utils/common/mathlib.h"
#include "const.h"
#include "progs.h"
#include "progdefs.h"
#include "eiface.h"
#include "../engine/studio.h"
#ifndef ACTIVITY_H
#include "activity.h"
#endif
#include "activitymap.h"
#ifndef ANIMATION_H
#include "animation.h"
#endif
#ifndef SCRIPTEVENT_H
#include "scriptevent.h"
#endif
#ifndef ENGINECALLBACK_H
#include "enginecallback.h"
#endif
extern globalvars_t *gpGlobals;
#pragma warning( disable : 4244 )
int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return 0;
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
mins[0] = pseqdesc[ sequence ].bbmin[0];
mins[1] = pseqdesc[ sequence ].bbmin[1];
mins[2] = pseqdesc[ sequence ].bbmin[2];
maxs[0] = pseqdesc[ sequence ].bbmax[0];
maxs[1] = pseqdesc[ sequence ].bbmax[1];
maxs[2] = pseqdesc[ sequence ].bbmax[2];
return 1;
}
int LookupActivity( void *pmodel, entvars_t *pev, int activity )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return 0;
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
int weighttotal = 0;
int seq = ACTIVITY_NOT_AVAILABLE;
for (int i = 0; i < pstudiohdr->numseq; i++)
{
if (pseqdesc[i].activity == activity)
{
weighttotal += pseqdesc[i].actweight;
if (!weighttotal || RANDOM_LONG(0,weighttotal-1) < pseqdesc[i].actweight)
seq = i;
}
}
return seq;
}
int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if ( !pstudiohdr )
return 0;
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
int weight = 0;
int seq = ACTIVITY_NOT_AVAILABLE;
for (int i = 0; i < pstudiohdr->numseq; i++)
{
if (pseqdesc[i].activity == activity)
{
if ( pseqdesc[i].actweight > weight )
{
weight = pseqdesc[i].actweight;
seq = i;
}
}
}
return seq;
}
void GetEyePosition ( void *pmodel, float *vecEyePosition )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if ( !pstudiohdr )
{
ALERT ( at_console, "GetEyePosition() Can't get pstudiohdr ptr!\n" );
return;
}
VectorCopy ( pstudiohdr->eyeposition, vecEyePosition );
}
int LookupSequence( void *pmodel, const char *label )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return 0;
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
for (int i = 0; i < pstudiohdr->numseq; i++)
{
if (stricmp( pseqdesc[i].label, label ) == 0)
return i;
}
return -1;
}
int IsSoundEvent( int eventNumber )
{
if ( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE )
return 1;
return 0;
}
void SequencePrecache( void *pmodel, const char *pSequenceName )
{
int index = LookupSequence( pmodel, pSequenceName );
if ( index >= 0 )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if ( !pstudiohdr || index >= pstudiohdr->numseq )
return;
mstudioseqdesc_t *pseqdesc;
mstudioevent_t *pevent;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index;
pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex);
for (int i = 0; i < pseqdesc->numevents; i++)
{
// Don't send client-side events to the server AI
if ( pevent[i].event >= EVENT_CLIENT )
continue;
// UNDONE: Add a callback to check to see if a sound is precached yet and don't allocate a copy
// of it's name if it is.
if ( IsSoundEvent( pevent[i].event ) )
{
if ( !strlen(pevent[i].options) )
{
ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options );
}
PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) );
}
}
}
}
void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return;
mstudioseqdesc_t *pseqdesc;
if (pev->sequence >= pstudiohdr->numseq)
{
*pflFrameRate = 0.0;
*pflGroundSpeed = 0.0;
return;
}
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence;
if (pseqdesc->numframes > 1)
{
*pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1);
*pflGroundSpeed = sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] );
*pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1);
}
else
{
*pflFrameRate = 256.0;
*pflGroundSpeed = 0.0;
}
}
int GetSequenceFlags( void *pmodel, entvars_t *pev )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq )
return 0;
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence;
return pseqdesc->flags;
}
int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent )
return 0;
int events = 0;
mstudioseqdesc_t *pseqdesc;
mstudioevent_t *pevent;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence;
pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex);
if (pseqdesc->numevents == 0 || index > pseqdesc->numevents )
return 0;
if (pseqdesc->numframes > 1)
{
flStart *= (pseqdesc->numframes - 1) / 256.0;
flEnd *= (pseqdesc->numframes - 1) / 256.0;
}
else
{
flStart = 0;
flEnd = 1.0;
}
for (; index < pseqdesc->numevents; index++)
{
// Don't send client-side events to the server AI
if ( pevent[index].event >= EVENT_CLIENT )
continue;
if ( (pevent[index].frame >= flStart && pevent[index].frame < flEnd) ||
((pseqdesc->flags & STUDIO_LOOPING) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1) )
{
pMonsterEvent->event = pevent[index].event;
pMonsterEvent->options = pevent[index].options;
return index + 1;
}
}
return 0;
}
float SetController( void *pmodel, entvars_t *pev, int iController, float flValue )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return flValue;
mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex);
// find first controller that matches the index
for (int i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++)
{
if (pbonecontroller->index == iController)
break;
}
if (i >= pstudiohdr->numbonecontrollers)
return flValue;
// wrap 0..360 if it's a rotational controller
if (pbonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR))
{
// ugly hack, invert value if end < start
if (pbonecontroller->end < pbonecontroller->start)
flValue = -flValue;
// does the controller not wrap?
if (pbonecontroller->start + 359.0 >= pbonecontroller->end)
{
if (flValue > ((pbonecontroller->start + pbonecontroller->end) / 2.0) + 180)
flValue = flValue - 360;
if (flValue < ((pbonecontroller->start + pbonecontroller->end) / 2.0) - 180)
flValue = flValue + 360;
}
else
{
if (flValue > 360)
flValue = flValue - (int)(flValue / 360.0) * 360.0;
else if (flValue < 0)
flValue = flValue + (int)((flValue / -360.0) + 1) * 360.0;
}
}
int setting = 255 * (flValue - pbonecontroller->start) / (pbonecontroller->end - pbonecontroller->start);
if (setting < 0) setting = 0;
if (setting > 255) setting = 255;
pev->controller[iController] = setting;
return setting * (1.0 / 255.0) * (pbonecontroller->end - pbonecontroller->start) + pbonecontroller->start;
}
float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return flValue;
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence;
if (pseqdesc->blendtype[iBlender] == 0)
return flValue;
if (pseqdesc->blendtype[iBlender] & (STUDIO_XR | STUDIO_YR | STUDIO_ZR))
{
// ugly hack, invert value if end < start
if (pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender])
flValue = -flValue;
// does the controller not wrap?
if (pseqdesc->blendstart[iBlender] + 359.0 >= pseqdesc->blendend[iBlender])
{
if (flValue > ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) + 180)
flValue = flValue - 360;
if (flValue < ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) - 180)
flValue = flValue + 360;
}
}
int setting = 255 * (flValue - pseqdesc->blendstart[iBlender]) / (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]);
if (setting < 0) setting = 0;
if (setting > 255) setting = 255;
pev->blending[iBlender] = setting;
return setting * (1.0 / 255.0) * (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]) + pseqdesc->blendstart[iBlender];
}
int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return iGoalAnim;
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
// bail if we're going to or from a node 0
if (pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0)
{
return iGoalAnim;
}
int iEndNode;
// ALERT( at_console, "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode );
if (*piDir > 0)
{
iEndNode = pseqdesc[iEndingAnim].exitnode;
}
else
{
iEndNode = pseqdesc[iEndingAnim].entrynode;
}
if (iEndNode == pseqdesc[iGoalAnim].entrynode)
{
*piDir = 1;
return iGoalAnim;
}
byte *pTransition = ((byte *)pstudiohdr + pstudiohdr->transitionindex);
int iInternNode = pTransition[(iEndNode-1)*pstudiohdr->numtransitions + (pseqdesc[iGoalAnim].entrynode-1)];
if (iInternNode == 0)
return iGoalAnim;
int i;
// look for someone going
for (i = 0; i < pstudiohdr->numseq; i++)
{
if (pseqdesc[i].entrynode == iEndNode && pseqdesc[i].exitnode == iInternNode)
{
*piDir = 1;
return i;
}
if (pseqdesc[i].nodeflags)
{
if (pseqdesc[i].exitnode == iEndNode && pseqdesc[i].entrynode == iInternNode)
{
*piDir = -1;
return i;
}
}
}
ALERT( at_console, "error in transition graph" );
return iGoalAnim;
}
void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return;
if (iGroup > pstudiohdr->numbodyparts)
return;
mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup;
if (iValue >= pbodypart->nummodels)
return;
int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels;
pev->body = (pev->body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base));
}
int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup )
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (! pstudiohdr)
return 0;
if (iGroup > pstudiohdr->numbodyparts)
return 0;
mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup;
if (pbodypart->nummodels <= 1)
return 0;
int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels;
return iCurrent;
}

47
dlls/animation.h Normal file
View File

@ -0,0 +1,47 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef ANIMATION_H
#define ANIMATION_H
#define ACTIVITY_NOT_AVAILABLE -1
#ifndef MONSTEREVENT_H
#include "monsterevent.h"
#endif
extern int IsSoundEvent( int eventNumber );
int LookupActivity( void *pmodel, entvars_t *pev, int activity );
int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity );
int LookupSequence( void *pmodel, const char *label );
void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed );
int GetSequenceFlags( void *pmodel, entvars_t *pev );
int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd );
float SetController( void *pmodel, entvars_t *pev, int iController, float flValue );
float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue );
void GetEyePosition( void *pmodel, float *vecEyePosition );
void SequencePrecache( void *pmodel, const char *pSequenceName );
int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir );
void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue );
int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup );
int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index );
int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs );
// From /engine/studio.h
#define STUDIO_LOOPING 0x0001
#endif //ANIMATION_H

94
dlls/basemonster.h Normal file
View File

@ -0,0 +1,94 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef BASEMONSTER_H
#define BASEMONSTER_H
class CBaseMonster : public CBaseToggle
{
public:
Activity m_Activity;// what the monster is doing (animation)
Activity m_IdealActivity;// monster should switch to this activity
int m_LastHitGroup; // the last body region that took damage
int m_bitsDamageType; // what types of damage has monster (player) taken
BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED];
MONSTERSTATE m_MonsterState;// monster's current state
MONSTERSTATE m_IdealMonsterState;// monster should change to this state
int m_afConditions;
int m_afMemory;
float m_flNextAttack; // cannot attack again until this time
EHANDLE m_hEnemy; // the entity that the monster is fighting.
EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach
float m_flFieldOfView;// width of monster's field of view ( dot product )
int m_bloodColor; // color of blood particless
Vector m_HackedGunPos; // HACK until we can query end of gun
Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin)
void KeyValue( KeyValueData *pkvd );
void MakeIdealYaw( Vector vecTarget );
virtual float ChangeYaw ( int speed );
virtual BOOL HasHumanGibs( void );
virtual BOOL HasAlienGibs( void );
virtual void FadeMonster( void ); // Called instead of GibMonster() when gibs are disabled
virtual void GibMonster( void );
virtual Activity GetDeathActivity ( void );
Activity GetSmallFlinchActivity( void );
virtual void BecomeDead( void );
BOOL ShouldGibMonster( int iGib );
void CallGibMonster( void );
virtual BOOL ShouldFadeOnDeath( void );
BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target.
virtual int IRelationship ( CBaseEntity *pTarget );
virtual int TakeHealth( float flHealth, int bitsDamageType );
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
int DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
float DamageForce( float damage );
virtual void Killed( entvars_t *pevAttacker, int iGib );
virtual void PainSound ( void ) { return; };
void RadiusDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType );
void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType );
inline void SetConditions( int iConditions ) { m_afConditions |= iConditions; }
inline void ClearConditions( int iConditions ) { m_afConditions &= ~iConditions; }
inline BOOL HasConditions( int iConditions ) { if ( m_afConditions & iConditions ) return TRUE; return FALSE; }
inline BOOL HasAllConditions( int iConditions ) { if ( (m_afConditions & iConditions) == iConditions ) return TRUE; return FALSE; }
inline void Remember( int iMemory ) { m_afMemory |= iMemory; }
inline void Forget( int iMemory ) { m_afMemory &= ~iMemory; }
inline BOOL HasMemory( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE; return FALSE; }
inline BOOL HasAllMemories( int iMemory ) { if ( (m_afMemory & iMemory) == iMemory ) return TRUE; return FALSE; }
// This will stop animation until you call ResetSequenceInfo() at some point in the future
inline void StopAnimation( void ) { pev->framerate = 0; }
virtual void ReportAIState( void );
virtual void MonsterInitDead( void ); // Call after animation/pose is set up
void EXPORT CorpseFallThink( void );
virtual void Look ( int iDistance );// basic sight function for monsters
virtual CBaseEntity* BestVisibleEnemy ( void );// finds best visible enemy for attack
CBaseEntity *CheckTraceHullAttack( float flDist, int iDamage, int iDmgType );
virtual BOOL FInViewCone ( CBaseEntity *pEntity );// see if pEntity is in monster's view cone
virtual BOOL FInViewCone ( Vector *pOrigin );// see if given location is in monster's view cone
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
void MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir );
virtual BOOL IsAlive( void ) { return (pev->deadflag != DEAD_DEAD); }
};
#endif

958
dlls/bmodels.cpp Normal file
View File

@ -0,0 +1,958 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== bmodels.cpp ========================================================
spawn, think, and use functions for entities that use brush models
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "doors.h"
extern DLL_GLOBAL Vector g_vecAttackDir;
#define SF_BRUSH_ACCDCC 16// brush should accelerate and decelerate when toggled
#define SF_BRUSH_HURT 32// rotating brush that inflicts pain based on rotation speed
#define SF_ROTATING_NOT_SOLID 64 // some special rotating objects are not solid.
// covering cheesy noise1, noise2, & noise3 fields so they make more sense (for rotating fans)
#define noiseStart noise1
#define noiseStop noise2
#define noiseRunning noise3
#define SF_PENDULUM_SWING 2 // spawnflag that makes a pendulum a rope swing.
//
// BModelOrigin - calculates origin of a bmodel from absmin/size because all bmodel origins are 0 0 0
//
Vector VecBModelOrigin( entvars_t* pevBModel )
{
return pevBModel->absmin + ( pevBModel->size * 0.5 );
}
// =================== FUNC_WALL ==============================================
/*QUAKED func_wall (0 .5 .8) ?
This is just a solid wall if not inhibited
*/
class CFuncWall : public CBaseEntity
{
public:
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
// Bmodels don't go across transitions
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
};
LINK_ENTITY_TO_CLASS( func_wall, CFuncWall );
void CFuncWall :: Spawn( void )
{
pev->angles = g_vecZero;
pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything
pev->solid = SOLID_BSP;
SET_MODEL( ENT(pev), STRING(pev->model) );
// If it can't move/go away, it's really part of the world
pev->flags |= FL_WORLDBRUSH;
}
void CFuncWall :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( ShouldToggle( useType, (int)(pev->frame)) )
pev->frame = 1 - pev->frame;
}
#define SF_WALL_START_OFF 0x0001
class CFuncWallToggle : public CFuncWall
{
public:
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void TurnOff( void );
void TurnOn( void );
BOOL IsOn( void );
};
LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle );
void CFuncWallToggle :: Spawn( void )
{
CFuncWall::Spawn();
if ( pev->spawnflags & SF_WALL_START_OFF )
TurnOff();
}
void CFuncWallToggle :: TurnOff( void )
{
pev->solid = SOLID_NOT;
pev->effects |= EF_NODRAW;
UTIL_SetOrigin( pev, pev->origin );
}
void CFuncWallToggle :: TurnOn( void )
{
pev->solid = SOLID_BSP;
pev->effects &= ~EF_NODRAW;
UTIL_SetOrigin( pev, pev->origin );
}
BOOL CFuncWallToggle :: IsOn( void )
{
if ( pev->solid == SOLID_NOT )
return FALSE;
return TRUE;
}
void CFuncWallToggle :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
int status = IsOn();
if ( ShouldToggle( useType, status ) )
{
if ( status )
TurnOff();
else
TurnOn();
}
}
#define SF_CONVEYOR_VISUAL 0x0001
#define SF_CONVEYOR_NOTSOLID 0x0002
class CFuncConveyor : public CFuncWall
{
public:
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void UpdateSpeed( float speed );
};
LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor );
void CFuncConveyor :: Spawn( void )
{
SetMovedir( pev );
CFuncWall::Spawn();
if ( !(pev->spawnflags & SF_CONVEYOR_VISUAL) )
SetBits( pev->flags, FL_CONVEYOR );
// HACKHACK - This is to allow for some special effects
if ( pev->spawnflags & SF_CONVEYOR_NOTSOLID )
{
pev->solid = SOLID_NOT;
pev->skin = 0; // Don't want the engine thinking we've got special contents on this brush
}
if ( pev->speed == 0 )
pev->speed = 100;
UpdateSpeed( pev->speed );
}
// HACKHACK -- This is ugly, but encode the speed in the rendercolor to avoid adding more data to the network stream
void CFuncConveyor :: UpdateSpeed( float speed )
{
// Encode it as an integer with 4 fractional bits
int speedCode = (int)(fabs(speed) * 16.0);
if ( speed < 0 )
pev->rendercolor.x = 1;
else
pev->rendercolor.x = 0;
pev->rendercolor.y = (speedCode >> 8);
pev->rendercolor.z = (speedCode & 0xFF);
}
void CFuncConveyor :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
pev->speed = -pev->speed;
UpdateSpeed( pev->speed );
}
// =================== FUNC_ILLUSIONARY ==============================================
/*QUAKED func_illusionary (0 .5 .8) ?
A simple entity that looks solid but lets you walk through it.
*/
class CFuncIllusionary : public CBaseToggle
{
public:
void Spawn( void );
void EXPORT SloshTouch( CBaseEntity *pOther );
void KeyValue( KeyValueData *pkvd );
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
};
LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary );
void CFuncIllusionary :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type
{
pev->skin = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue( pkvd );
}
void CFuncIllusionary :: Spawn( void )
{
pev->angles = g_vecZero;
pev->movetype = MOVETYPE_NONE;
pev->solid = SOLID_NOT;// always solid_not
SET_MODEL( ENT(pev), STRING(pev->model) );
// I'd rather eat the network bandwidth of this than figure out how to save/restore
// these entities after they have been moved to the client, or respawn them ala Quake
// Perhaps we can do this in deathmatch only.
// MAKE_STATIC(ENT(pev));
}
// -------------------------------------------------------------------------------
//
// Monster only clip brush
//
// This brush will be solid for any entity who has the FL_MONSTERCLIP flag set
// in pev->flags
//
// otherwise it will be invisible and not solid. This can be used to keep
// specific monsters out of certain areas
//
// -------------------------------------------------------------------------------
class CFuncMonsterClip : public CFuncWall
{
public:
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) {} // Clear out func_wall's use function
};
LINK_ENTITY_TO_CLASS( func_monsterclip, CFuncMonsterClip );
void CFuncMonsterClip::Spawn( void )
{
CFuncWall::Spawn();
if ( CVAR_GET_FLOAT("showtriggers") == 0 )
pev->effects = EF_NODRAW;
pev->flags |= FL_MONSTERCLIP;
}
// =================== FUNC_ROTATING ==============================================
class CFuncRotating : public CBaseEntity
{
public:
// basic functions
void Spawn( void );
void Precache( void );
void EXPORT SpinUp ( void );
void EXPORT SpinDown ( void );
void KeyValue( KeyValueData* pkvd);
void EXPORT HurtTouch ( CBaseEntity *pOther );
void EXPORT RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT Rotate( void );
void RampPitchVol (int fUp );
void Blocked( CBaseEntity *pOther );
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
float m_flFanFriction;
float m_flAttenuation;
float m_flVolume;
float m_pitch;
int m_sounds;
};
TYPEDESCRIPTION CFuncRotating::m_SaveData[] =
{
DEFINE_FIELD( CFuncRotating, m_flFanFriction, FIELD_FLOAT ),
DEFINE_FIELD( CFuncRotating, m_flAttenuation, FIELD_FLOAT ),
DEFINE_FIELD( CFuncRotating, m_flVolume, FIELD_FLOAT ),
DEFINE_FIELD( CFuncRotating, m_pitch, FIELD_FLOAT ),
DEFINE_FIELD( CFuncRotating, m_sounds, FIELD_INTEGER )
};
IMPLEMENT_SAVERESTORE( CFuncRotating, CBaseEntity );
LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating );
void CFuncRotating :: KeyValue( KeyValueData* pkvd)
{
if (FStrEq(pkvd->szKeyName, "fanfriction"))
{
m_flFanFriction = atof(pkvd->szValue)/100;
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "Volume"))
{
m_flVolume = atof(pkvd->szValue)/10.0;
if (m_flVolume > 1.0)
m_flVolume = 1.0;
if (m_flVolume < 0.0)
m_flVolume = 0.0;
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "spawnorigin"))
{
Vector tmp;
UTIL_StringToVector( (float *)tmp, pkvd->szValue );
if ( tmp != g_vecZero )
pev->origin = tmp;
}
else if (FStrEq(pkvd->szKeyName, "sounds"))
{
m_sounds = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue( pkvd );
}
/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS
You need to have an origin brush as part of this entity. The
center of that brush will be
the point around which it is rotated. It will rotate around the Z
axis by default. You can
check either the X_AXIS or Y_AXIS box to change that.
"speed" determines how fast it moves; default value is 100.
"dmg" damage to inflict when blocked (2 default)
REVERSE will cause the it to rotate in the opposite direction.
*/
void CFuncRotating :: Spawn( )
{
// set final pitch. Must not be PITCH_NORM, since we
// plan on pitch shifting later.
m_pitch = PITCH_NORM - 1;
// maintain compatibility with previous maps
if (m_flVolume == 0.0)
m_flVolume = 1.0;
// if the designer didn't set a sound attenuation, default to one.
m_flAttenuation = ATTN_NORM;
if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_SMALLRADIUS) )
{
m_flAttenuation = ATTN_IDLE;
}
else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_MEDIUMRADIUS) )
{
m_flAttenuation = ATTN_STATIC;
}
else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_LARGERADIUS) )
{
m_flAttenuation = ATTN_NORM;
}
// prevent divide by zero if level designer forgets friction!
if ( m_flFanFriction == 0 )
{
m_flFanFriction = 1;
}
if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_Z_AXIS) )
pev->movedir = Vector(0,0,1);
else if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_X_AXIS) )
pev->movedir = Vector(1,0,0);
else
pev->movedir = Vector(0,1,0); // y-axis
// check for reverse rotation
if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_BACKWARDS) )
pev->movedir = pev->movedir * -1;
// some rotating objects like fake volumetric lights will not be solid.
if ( FBitSet(pev->spawnflags, SF_ROTATING_NOT_SOLID) )
{
pev->solid = SOLID_NOT;
pev->skin = CONTENTS_EMPTY;
pev->movetype = MOVETYPE_PUSH;
}
else
{
pev->solid = SOLID_BSP;
pev->movetype = MOVETYPE_PUSH;
}
UTIL_SetOrigin(pev, pev->origin);
SET_MODEL( ENT(pev), STRING(pev->model) );
SetUse( RotatingUse );
// did level designer forget to assign speed?
if (pev->speed <= 0)
pev->speed = 0;
// Removed this per level designers request. -- JAY
// if (pev->dmg == 0)
// pev->dmg = 2;
// instant-use brush?
if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) )
{
SetThink( SUB_CallUseToggle );
pev->nextthink = pev->ltime + 1.5; // leave a magic delay for client to start up
}
// can this brush inflict pain?
if ( FBitSet (pev->spawnflags, SF_BRUSH_HURT) )
{
SetTouch( HurtTouch );
}
Precache( );
}
void CFuncRotating :: Precache( void )
{
char* szSoundFile = (char*) STRING(pev->message);
// set up fan sounds
if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0)
{
// if a path is set for a wave, use it
PRECACHE_SOUND(szSoundFile);
pev->noiseRunning = ALLOC_STRING(szSoundFile);
} else
{
// otherwise use preset sound
switch (m_sounds)
{
case 1:
PRECACHE_SOUND ("fans/fan1.wav");
pev->noiseRunning = ALLOC_STRING("fans/fan1.wav");
break;
case 2:
PRECACHE_SOUND ("fans/fan2.wav");
pev->noiseRunning = ALLOC_STRING("fans/fan2.wav");
break;
case 3:
PRECACHE_SOUND ("fans/fan3.wav");
pev->noiseRunning = ALLOC_STRING("fans/fan3.wav");
break;
case 4:
PRECACHE_SOUND ("fans/fan4.wav");
pev->noiseRunning = ALLOC_STRING("fans/fan4.wav");
break;
case 5:
PRECACHE_SOUND ("fans/fan5.wav");
pev->noiseRunning = ALLOC_STRING("fans/fan5.wav");
break;
case 0:
default:
if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0)
{
PRECACHE_SOUND(szSoundFile);
pev->noiseRunning = ALLOC_STRING(szSoundFile);
break;
} else
{
pev->noiseRunning = ALLOC_STRING("common/null.wav");
break;
}
}
}
if (pev->avelocity != g_vecZero )
{
// if fan was spinning, and we went through transition or save/restore,
// make sure we restart the sound. 1.5 sec delay is magic number. KDB
SetThink ( SpinUp );
pev->nextthink = pev->ltime + 1.5;
}
}
//
// Touch - will hurt others based on how fast the brush is spinning
//
void CFuncRotating :: HurtTouch ( CBaseEntity *pOther )
{
entvars_t *pevOther = pOther->pev;
// we can't hurt this thing, so we're not concerned with it
if ( !pevOther->takedamage )
return;
// calculate damage based on rotation speed
pev->dmg = pev->avelocity.Length() / 10;
pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH);
pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * pev->dmg;
}
//
// RampPitchVol - ramp pitch and volume up to final values, based on difference
// between how fast we're going vs how fast we plan to go
//
#define FANPITCHMIN 30
#define FANPITCHMAX 100
void CFuncRotating :: RampPitchVol (int fUp)
{
Vector vecAVel = pev->avelocity;
vec_t vecCur;
vec_t vecFinal;
float fpct;
float fvol;
float fpitch;
int pitch;
// get current angular velocity
vecCur = abs(vecAVel.x != 0 ? vecAVel.x : (vecAVel.y != 0 ? vecAVel.y : vecAVel.z));
// get target angular velocity
vecFinal = (pev->movedir.x != 0 ? pev->movedir.x : (pev->movedir.y != 0 ? pev->movedir.y : pev->movedir.z));
vecFinal *= pev->speed;
vecFinal = abs(vecFinal);
// calc volume and pitch as % of final vol and pitch
fpct = vecCur / vecFinal;
// if (fUp)
// fvol = m_flVolume * (0.5 + fpct/2.0); // spinup volume ramps up from 50% max vol
// else
fvol = m_flVolume * fpct; // slowdown volume ramps down to 0
fpitch = FANPITCHMIN + (FANPITCHMAX - FANPITCHMIN) * fpct;
pitch = (int) fpitch;
if (pitch == PITCH_NORM)
pitch = PITCH_NORM-1;
// change the fan's vol and pitch
EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning),
fvol, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch);
}
//
// SpinUp - accelerates a non-moving func_rotating up to it's speed
//
void CFuncRotating :: SpinUp( void )
{
Vector vecAVel;//rotational velocity
pev->nextthink = pev->ltime + 0.1;
pev->avelocity = pev->avelocity + ( pev->movedir * ( pev->speed * m_flFanFriction ) );
vecAVel = pev->avelocity;// cache entity's rotational velocity
// if we've met or exceeded target speed, set target speed and stop thinking
if ( abs(vecAVel.x) >= abs(pev->movedir.x * pev->speed) &&
abs(vecAVel.y) >= abs(pev->movedir.y * pev->speed) &&
abs(vecAVel.z) >= abs(pev->movedir.z * pev->speed) )
{
pev->avelocity = pev->movedir * pev->speed;// set speed in case we overshot
EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning),
m_flVolume, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, FANPITCHMAX);
SetThink( Rotate );
Rotate();
}
else
{
RampPitchVol(TRUE);
}
}
//
// SpinDown - decelerates a moving func_rotating to a standstill.
//
void CFuncRotating :: SpinDown( void )
{
Vector vecAVel;//rotational velocity
vec_t vecdir;
pev->nextthink = pev->ltime + 0.1;
pev->avelocity = pev->avelocity - ( pev->movedir * ( pev->speed * m_flFanFriction ) );//spin down slower than spinup
vecAVel = pev->avelocity;// cache entity's rotational velocity
if (pev->movedir.x != 0)
vecdir = pev->movedir.x;
else if (pev->movedir.y != 0)
vecdir = pev->movedir.y;
else
vecdir = pev->movedir.z;
// if we've met or exceeded target speed, set target speed and stop thinking
// (note: must check for movedir > 0 or < 0)
if (((vecdir > 0) && (vecAVel.x <= 0 && vecAVel.y <= 0 && vecAVel.z <= 0)) ||
((vecdir < 0) && (vecAVel.x >= 0 && vecAVel.y >= 0 && vecAVel.z >= 0)))
{
pev->avelocity = g_vecZero;// set speed in case we overshot
// stop sound, we're done
EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning /* Stop */),
0, 0, SND_STOP, m_pitch);
SetThink( Rotate );
Rotate();
}
else
{
RampPitchVol(FALSE);
}
}
void CFuncRotating :: Rotate( void )
{
pev->nextthink = pev->ltime + 10;
}
//=========================================================
// Rotating Use - when a rotating brush is triggered
//=========================================================
void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// is this a brush that should accelerate and decelerate when turned on/off (fan)?
if ( FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) )
{
// fan is spinning, so stop it.
if ( pev->avelocity != g_vecZero )
{
SetThink ( SpinDown );
//EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop),
// m_flVolume, m_flAttenuation, 0, m_pitch);
pev->nextthink = pev->ltime + 0.1;
}
else// fan is not moving, so start it
{
SetThink ( SpinUp );
EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning),
0.01, m_flAttenuation, 0, FANPITCHMIN);
pev->nextthink = pev->ltime + 0.1;
}
}
else if ( !FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) )//this is a normal start/stop brush.
{
if ( pev->avelocity != g_vecZero )
{
// play stopping sound here
SetThink ( SpinDown );
// EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop),
// m_flVolume, m_flAttenuation, 0, m_pitch);
pev->nextthink = pev->ltime + 0.1;
// pev->avelocity = g_vecZero;
}
else
{
EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning),
m_flVolume, m_flAttenuation, 0, FANPITCHMAX);
pev->avelocity = pev->movedir * pev->speed;
SetThink( Rotate );
Rotate();
}
}
}
//
// RotatingBlocked - An entity has blocked the brush
//
void CFuncRotating :: Blocked( CBaseEntity *pOther )
{
pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH);
}
//#endif
class CPendulum : public CBaseEntity
{
public:
void Spawn ( void );
void KeyValue( KeyValueData *pkvd );
void EXPORT Swing( void );
void EXPORT PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT Stop( void );
void Touch( CBaseEntity *pOther );
void EXPORT RopeTouch ( CBaseEntity *pOther );// this touch func makes the pendulum a rope
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
void Blocked( CBaseEntity *pOther );
static TYPEDESCRIPTION m_SaveData[];
float m_accel; // Acceleration
float m_distance; //
float m_time;
float m_damp;
float m_maxSpeed;
float m_dampSpeed;
vec3_t m_center;
vec3_t m_start;
};
LINK_ENTITY_TO_CLASS( func_pendulum, CPendulum );
TYPEDESCRIPTION CPendulum::m_SaveData[] =
{
DEFINE_FIELD( CPendulum, m_accel, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_distance, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_time, FIELD_TIME ),
DEFINE_FIELD( CPendulum, m_damp, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_maxSpeed, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_dampSpeed, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_center, FIELD_VECTOR ),
DEFINE_FIELD( CPendulum, m_start, FIELD_VECTOR ),
};
IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity );
void CPendulum :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "distance"))
{
m_distance = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "damp"))
{
m_damp = atof(pkvd->szValue) * 0.001;
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue( pkvd );
}
void CPendulum :: Spawn( void )
{
// set the axis of rotation
CBaseToggle :: AxisDir( pev );
if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) )
pev->solid = SOLID_NOT;
else
pev->solid = SOLID_BSP;
pev->movetype = MOVETYPE_PUSH;
UTIL_SetOrigin(pev, pev->origin);
SET_MODEL(ENT(pev), STRING(pev->model) );
if ( m_distance == 0 )
return;
if (pev->speed == 0)
pev->speed = 100;
m_accel = (pev->speed * pev->speed) / (2 * fabs(m_distance)); // Calculate constant acceleration from speed and distance
m_maxSpeed = pev->speed;
m_start = pev->angles;
m_center = pev->angles + (m_distance * 0.5) * pev->movedir;
if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) )
{
SetThink( SUB_CallUseToggle );
pev->nextthink = gpGlobals->time + 0.1;
}
pev->speed = 0;
SetUse( PendulumUse );
if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) )
{
SetTouch ( RopeTouch );
}
}
void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( pev->speed ) // Pendulum is moving, stop it and auto-return if necessary
{
if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) )
{
float delta;
delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_start );
pev->avelocity = m_maxSpeed * pev->movedir;
pev->nextthink = pev->ltime + (delta / m_maxSpeed);
SetThink( Stop );
}
else
{
pev->speed = 0; // Dead stop
SetThink( NULL );
pev->avelocity = g_vecZero;
}
}
else
{
pev->nextthink = pev->ltime + 0.1; // Start the pendulum moving
m_time = gpGlobals->time; // Save time to calculate dt
SetThink( Swing );
m_dampSpeed = m_maxSpeed;
}
}
void CPendulum :: Stop( void )
{
pev->angles = m_start;
pev->speed = 0;
SetThink( NULL );
pev->avelocity = g_vecZero;
}
void CPendulum::Blocked( CBaseEntity *pOther )
{
m_time = gpGlobals->time;
}
void CPendulum :: Swing( void )
{
float delta, dt;
delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_center );
dt = gpGlobals->time - m_time; // How much time has passed?
m_time = gpGlobals->time; // Remember the last time called
if ( delta > 0 && m_accel > 0 )
pev->speed -= m_accel * dt; // Integrate velocity
else
pev->speed += m_accel * dt;
if ( pev->speed > m_maxSpeed )
pev->speed = m_maxSpeed;
else if ( pev->speed < -m_maxSpeed )
pev->speed = -m_maxSpeed;
// scale the destdelta vector by the time spent traveling to get velocity
pev->avelocity = pev->speed * pev->movedir;
// Call this again
pev->nextthink = pev->ltime + 0.1;
if ( m_damp )
{
m_dampSpeed -= m_damp * m_dampSpeed * dt;
if ( m_dampSpeed < 30.0 )
{
pev->angles = m_center;
pev->speed = 0;
SetThink( NULL );
pev->avelocity = g_vecZero;
}
else if ( pev->speed > m_dampSpeed )
pev->speed = m_dampSpeed;
else if ( pev->speed < -m_dampSpeed )
pev->speed = -m_dampSpeed;
}
}
void CPendulum :: Touch ( CBaseEntity *pOther )
{
entvars_t *pevOther = pOther->pev;
if ( pev->dmg <= 0 )
return;
// we can't hurt this thing, so we're not concerned with it
if ( !pevOther->takedamage )
return;
// calculate damage based on rotation speed
float damage = pev->dmg * pev->speed * 0.01;
if ( damage < 0 )
damage = -damage;
pOther->TakeDamage( pev, pev, damage, DMG_CRUSH );
pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * damage;
}
void CPendulum :: RopeTouch ( CBaseEntity *pOther )
{
entvars_t *pevOther = pOther->pev;
if ( !pOther->IsPlayer() )
{// not a player!
ALERT ( at_console, "Not a client\n" );
return;
}
if ( ENT(pevOther) == pev->enemy )
{// this player already on the rope.
return;
}
pev->enemy = pOther->edict();
pevOther->velocity = g_vecZero;
pevOther->movetype = MOVETYPE_NONE;
}

1276
dlls/buttons.cpp Normal file

File diff suppressed because it is too large Load Diff

727
dlls/cbase.cpp Normal file
View File

@ -0,0 +1,727 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "saverestore.h"
#include "client.h"
#include "decals.h"
#include "gamerules.h"
#include "game.h"
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd );
extern Vector VecBModelOrigin( entvars_t* pevBModel );
extern DLL_GLOBAL Vector g_vecAttackDir;
extern DLL_GLOBAL int g_iSkillLevel;
static DLL_FUNCTIONS gFunctionTable =
{
GameDLLInit, //pfnGameInit
DispatchSpawn, //pfnSpawn
DispatchThink, //pfnThink
DispatchUse, //pfnUse
DispatchTouch, //pfnTouch
DispatchBlocked, //pfnBlocked
DispatchKeyValue, //pfnKeyValue
DispatchSave, //pfnSave
DispatchRestore, //pfnRestore
DispatchObjectCollsionBox, //pfnAbsBox
SaveWriteFields, //pfnSaveWriteFields
SaveReadFields, //pfnSaveReadFields
SaveGlobalState, //pfnSaveGlobalState
RestoreGlobalState, //pfnRestoreGlobalState
ResetGlobalState, //pfnResetGlobalState
ClientConnect, //pfnClientConnect
ClientDisconnect, //pfnClientDisconnect
ClientKill, //pfnClientKill
ClientPutInServer, //pfnClientPutInServer
ClientCommand, //pfnClientCommand
ClientUserInfoChanged, //pfnClientUserInfoChanged
ServerActivate, //pfnServerActivate
PlayerPreThink, //pfnPlayerPreThink
PlayerPostThink, //pfnPlayerPostThink
StartFrame, //pfnStartFrame
ParmsNewLevel, //pfnParmsNewLevel
ParmsChangeLevel, //pfnParmsChangeLevel
GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game.
PlayerCustomization, //pfnPlayerCustomization Notifies .dll of new customization for player.
SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server
SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server
SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t)
};
static void SetObjectCollisionBox( entvars_t *pev );
int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion )
{
if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION )
return FALSE;
memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) );
return TRUE;
}
int DispatchSpawn( edict_t *pent )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if (pEntity)
{
// Initialize these or entities who don't link to the world won't have anything in here
pEntity->pev->absmin = pEntity->pev->origin - Vector(1,1,1);
pEntity->pev->absmax = pEntity->pev->origin + Vector(1,1,1);
pEntity->Spawn();
// Try to get the pointer again, in case the spawn function deleted the entity.
// UNDONE: Spawn() should really return a code to ask that the entity be deleted, but
// that would touch too much code for me to do that right now.
pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if ( pEntity )
{
if ( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) )
return -1; // return that this entity should be deleted
if ( pEntity->pev->flags & FL_KILLME )
return -1;
}
// Handle global stuff here
if ( pEntity && pEntity->pev->globalname )
{
const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname );
if ( pGlobal )
{
// Already dead? delete
if ( pGlobal->state == GLOBAL_DEAD )
return -1;
else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) )
pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive
// In this level & not dead, continue on as normal
}
else
{
// Spawned entities default to 'On'
gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON );
// ALERT( at_console, "Added global entity %s (%s)\n", STRING(pEntity->pev->classname), STRING(pEntity->pev->globalname) );
}
}
}
return 0;
}
void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd )
{
if ( !pkvd || !pentKeyvalue )
return;
EntvarsKeyvalue( VARS(pentKeyvalue), pkvd );
// If the key was an entity variable, or there's no class set yet, don't look for the object, it may
// not exist yet.
if ( pkvd->fHandled || pkvd->szClassName == NULL )
return;
// Get the actualy entity object
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentKeyvalue);
if ( !pEntity )
return;
pEntity->KeyValue( pkvd );
}
// HACKHACK -- this is a hack to keep the node graph entity from "touching" things (like triggers)
// while it builds the graph
BOOL gTouchDisabled = FALSE;
void DispatchTouch( edict_t *pentTouched, edict_t *pentOther )
{
if ( gTouchDisabled )
return;
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentTouched);
CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther );
if ( pEntity && pOther && ! ((pEntity->pev->flags | pOther->pev->flags) & FL_KILLME) )
pEntity->Touch( pOther );
}
void DispatchUse( edict_t *pentUsed, edict_t *pentOther )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentUsed);
CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE(pentOther);
if (pEntity && !(pEntity->pev->flags & FL_KILLME) )
pEntity->Use( pOther, pOther, USE_TOGGLE, 0 );
}
void DispatchThink( edict_t *pent )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if (pEntity)
{
if ( FBitSet( pEntity->pev->flags, FL_DORMANT ) )
ALERT( at_error, "Dormant entity %s is thinking!!\n", STRING(pEntity->pev->classname) );
pEntity->Think();
}
}
void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentBlocked );
CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther );
if (pEntity)
pEntity->Blocked( pOther );
}
void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if ( pEntity && pSaveData )
{
ENTITYTABLE *pTable = &pSaveData->pTable[ pSaveData->currentIndex ];
if ( pTable->pent != pent )
ALERT( at_error, "ENTITY TABLE OR INDEX IS WRONG!!!!\n" );
if ( pEntity->ObjectCaps() & FCAP_DONT_SAVE )
return;
// These don't use ltime & nextthink as times really, but we'll fudge around it.
if ( pEntity->pev->movetype == MOVETYPE_PUSH )
{
float delta = pEntity->pev->nextthink - pEntity->pev->ltime;
pEntity->pev->ltime = gpGlobals->time;
pEntity->pev->nextthink = pEntity->pev->ltime + delta;
}
pTable->location = pSaveData->size; // Remember entity position for file I/O
pTable->classname = pEntity->pev->classname; // Remember entity class for respawn
CSave saveHelper( pSaveData );
pEntity->Save( saveHelper );
pTable->size = pSaveData->size - pTable->location; // Size of entity block is data size written to block
}
}
// Find the matching global entity. Spit out an error if the designer made entities of
// different classes with the same global name
CBaseEntity *FindGlobalEntity( string_t classname, string_t globalname )
{
edict_t *pent = FIND_ENTITY_BY_STRING( NULL, "globalname", STRING(globalname) );
CBaseEntity *pReturn = CBaseEntity::Instance( pent );
if ( pReturn )
{
if ( !FClassnameIs( pReturn->pev, STRING(classname) ) )
{
ALERT( at_console, "Global entity found %s, wrong class %s\n", STRING(globalname), STRING(pReturn->pev->classname) );
pReturn = NULL;
}
}
return pReturn;
}
int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if ( pEntity && pSaveData )
{
entvars_t tmpVars;
Vector oldOffset;
CRestore restoreHelper( pSaveData );
if ( globalEntity )
{
CRestore tmpRestore( pSaveData );
tmpRestore.PrecacheMode( 0 );
tmpRestore.ReadEntVars( "ENTVARS", &tmpVars );
// HACKHACK - reset the save pointers, we're going to restore for real this time
pSaveData->size = pSaveData->pTable[pSaveData->currentIndex].location;
pSaveData->pCurrentData = pSaveData->pBaseData + pSaveData->size;
// -------------------
const globalentity_t *pGlobal = gGlobalState.EntityFromTable( tmpVars.globalname );
// Don't overlay any instance of the global that isn't the latest
// pSaveData->szCurrentMapName is the level this entity is coming from
// pGlobla->levelName is the last level the global entity was active in.
// If they aren't the same, then this global update is out of date.
if ( !FStrEq( pSaveData->szCurrentMapName, pGlobal->levelName ) )
return 0;
// Compute the new global offset
oldOffset = pSaveData->vecLandmarkOffset;
CBaseEntity *pNewEntity = FindGlobalEntity( tmpVars.classname, tmpVars.globalname );
if ( pNewEntity )
{
// ALERT( at_console, "Overlay %s with %s\n", STRING(pNewEntity->pev->classname), STRING(tmpVars.classname) );
// Tell the restore code we're overlaying a global entity from another level
restoreHelper.SetGlobalMode( 1 ); // Don't overwrite global fields
pSaveData->vecLandmarkOffset = (pSaveData->vecLandmarkOffset - pNewEntity->pev->mins) + tmpVars.mins;
pEntity = pNewEntity;// we're going to restore this data OVER the old entity
pent = ENT( pEntity->pev );
// Update the global table to say that the global definition of this entity should come from this level
gGlobalState.EntityUpdate( pEntity->pev->globalname, gpGlobals->mapname );
}
else
{
// This entity will be freed automatically by the engine. If we don't do a restore on a matching entity (below)
// or call EntityUpdate() to move it to this level, we haven't changed global state at all.
return 0;
}
}
if ( pEntity->ObjectCaps() & FCAP_MUST_SPAWN )
{
pEntity->Restore( restoreHelper );
pEntity->Spawn();
}
else
{
pEntity->Restore( restoreHelper );
pEntity->Precache( );
}
// Again, could be deleted, get the pointer again.
pEntity = (CBaseEntity *)GET_PRIVATE(pent);
#if 0
if ( pEntity && pEntity->pev->globalname && globalEntity )
{
ALERT( at_console, "Global %s is %s\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->model) );
}
#endif
// Is this an overriding global entity (coming over the transition), or one restoring in a level
if ( globalEntity )
{
// ALERT( at_console, "After: %f %f %f %s\n", pEntity->pev->origin.x, pEntity->pev->origin.y, pEntity->pev->origin.z, STRING(pEntity->pev->model) );
pSaveData->vecLandmarkOffset = oldOffset;
if ( pEntity )
{
UTIL_SetOrigin( pEntity->pev, pEntity->pev->origin );
pEntity->OverrideReset();
}
}
else if ( pEntity && pEntity->pev->globalname )
{
const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname );
if ( pGlobal )
{
// Already dead? delete
if ( pGlobal->state == GLOBAL_DEAD )
return -1;
else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) )
{
pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive
}
// In this level & not dead, continue on as normal
}
else
{
ALERT( at_error, "Global Entity %s (%s) not in table!!!\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->classname) );
// Spawned entities default to 'On'
gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON );
}
}
}
return 0;
}
void DispatchObjectCollsionBox( edict_t *pent )
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
if (pEntity)
{
pEntity->SetObjectCollisionBox();
}
else
SetObjectCollisionBox( &pent->v );
}
void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount )
{
CSave saveHelper( pSaveData );
saveHelper.WriteFields( pname, pBaseData, pFields, fieldCount );
}
void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount )
{
CRestore restoreHelper( pSaveData );
restoreHelper.ReadFields( pname, pBaseData, pFields, fieldCount );
}
edict_t * EHANDLE::Get( void )
{
if (m_pent)
{
if (m_pent->serialnumber == m_serialnumber)
return m_pent;
else
return NULL;
}
return NULL;
};
edict_t * EHANDLE::Set( edict_t *pent )
{
m_pent = pent;
if (pent)
m_serialnumber = m_pent->serialnumber;
return pent;
};
EHANDLE :: operator CBaseEntity *()
{
return (CBaseEntity *)GET_PRIVATE( Get( ) );
};
CBaseEntity * EHANDLE :: operator = (CBaseEntity *pEntity)
{
if (pEntity)
{
m_pent = ENT( pEntity->pev );
if (m_pent)
m_serialnumber = m_pent->serialnumber;
}
else
{
m_pent = NULL;
m_serialnumber = 0;
}
return pEntity;
}
EHANDLE :: operator int ()
{
return Get() != NULL;
}
CBaseEntity * EHANDLE :: operator -> ()
{
return (CBaseEntity *)GET_PRIVATE( Get( ) );
}
// give health
int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType )
{
if (!pev->takedamage)
return 0;
// heal
if ( pev->health >= pev->max_health )
return 0;
pev->health += flHealth;
if (pev->health > pev->max_health)
pev->health = pev->max_health;
return 1;
}
// inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH
int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
{
Vector vecTemp;
if (!pev->takedamage)
return 0;
// UNDONE: some entity types may be immune or resistant to some bitsDamageType
// if Attacker == Inflictor, the attack was a melee or other instant-hit attack.
// (that is, no actual entity projectile was involved in the attack so use the shooter's origin).
if ( pevAttacker == pevInflictor )
{
vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) );
}
else
// an actual missile was involved.
{
vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) );
}
// this global is still used for glass and other non-monster killables, along with decals.
g_vecAttackDir = vecTemp.Normalize();
// save damage based on the target's armor level
// figure momentum add (don't let hurt brushes or other triggers move player)
if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER) )
{
Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
vecDir = vecDir.Normalize();
float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5;
if (flForce > 1000.0)
flForce = 1000.0;
pev->velocity = pev->velocity + vecDir * flForce;
}
// do the damage
pev->health -= flDamage;
if (pev->health <= 0)
{
Killed( pevAttacker, GIB_NORMAL );
return 0;
}
return 1;
}
void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib )
{
pev->takedamage = DAMAGE_NO;
pev->deadflag = DEAD_DEAD;
UTIL_Remove( this );
}
CBaseEntity *CBaseEntity::GetNextTarget( void )
{
if ( FStringNull( pev->target ) )
return NULL;
edict_t *pTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) );
if ( FNullEnt(pTarget) )
return NULL;
return Instance( pTarget );
}
// Global Savedata for Delay
TYPEDESCRIPTION CBaseEntity::m_SaveData[] =
{
DEFINE_FIELD( CBaseEntity, m_pGoalEnt, FIELD_CLASSPTR ),
DEFINE_FIELD( CBaseEntity, m_pfnThink, FIELD_FUNCTION ), // UNDONE: Build table of these!!!
DEFINE_FIELD( CBaseEntity, m_pfnTouch, FIELD_FUNCTION ),
DEFINE_FIELD( CBaseEntity, m_pfnUse, FIELD_FUNCTION ),
DEFINE_FIELD( CBaseEntity, m_pfnBlocked, FIELD_FUNCTION ),
};
int CBaseEntity::Save( CSave &save )
{
if ( save.WriteEntVars( "ENTVARS", pev ) )
return save.WriteFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) );
return 0;
}
int CBaseEntity::Restore( CRestore &restore )
{
int status;
status = restore.ReadEntVars( "ENTVARS", pev );
if ( status )
status = restore.ReadFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) );
if ( pev->modelindex != 0 && !FStringNull(pev->model) )
{
Vector mins, maxs;
mins = pev->mins; // Set model is about to destroy these
maxs = pev->maxs;
PRECACHE_MODEL( (char *)STRING(pev->model) );
SET_MODEL(ENT(pev), STRING(pev->model));
UTIL_SetSize(pev, mins, maxs); // Reset them
}
return status;
}
// Initialize absmin & absmax to the appropriate box
void SetObjectCollisionBox( entvars_t *pev )
{
if ( (pev->solid == SOLID_BSP) &&
(pev->angles.x || pev->angles.y|| pev->angles.z) )
{ // expand for rotation
float max, v;
int i;
max = 0;
for (i=0 ; i<3 ; i++)
{
v = fabs( pev->mins[i]);
if (v > max)
max = v;
v = fabs( pev->maxs[i]);
if (v > max)
max = v;
}
for (i=0 ; i<3 ; i++)
{
pev->absmin[i] = pev->origin[i] - max;
pev->absmax[i] = pev->origin[i] + max;
}
}
else
{
pev->absmin = pev->origin + pev->mins;
pev->absmax = pev->origin + pev->maxs;
}
pev->absmin.x -= 1;
pev->absmin.y -= 1;
pev->absmin.z -= 1;
pev->absmax.x += 1;
pev->absmax.y += 1;
pev->absmax.z += 1;
}
void CBaseEntity::SetObjectCollisionBox( void )
{
::SetObjectCollisionBox( pev );
}
int CBaseEntity :: Intersects( CBaseEntity *pOther )
{
if ( pOther->pev->absmin.x > pev->absmax.x ||
pOther->pev->absmin.y > pev->absmax.y ||
pOther->pev->absmin.z > pev->absmax.z ||
pOther->pev->absmax.x < pev->absmin.x ||
pOther->pev->absmax.y < pev->absmin.y ||
pOther->pev->absmax.z < pev->absmin.z )
return 0;
return 1;
}
void CBaseEntity :: MakeDormant( void )
{
SetBits( pev->flags, FL_DORMANT );
// Don't touch
pev->solid = SOLID_NOT;
// Don't move
pev->movetype = MOVETYPE_NONE;
// Don't draw
SetBits( pev->effects, EF_NODRAW );
// Don't think
pev->nextthink = 0;
// Relink
UTIL_SetOrigin( pev, pev->origin );
}
int CBaseEntity :: IsDormant( void )
{
return FBitSet( pev->flags, FL_DORMANT );
}
BOOL CBaseEntity :: IsInWorld( void )
{
// position
if (pev->origin.x >= 4096) return FALSE;
if (pev->origin.y >= 4096) return FALSE;
if (pev->origin.z >= 4096) return FALSE;
if (pev->origin.x <= -4096) return FALSE;
if (pev->origin.y <= -4096) return FALSE;
if (pev->origin.z <= -4096) return FALSE;
// speed
if (pev->velocity.x >= 2000) return FALSE;
if (pev->velocity.y >= 2000) return FALSE;
if (pev->velocity.z >= 2000) return FALSE;
if (pev->velocity.x <= -2000) return FALSE;
if (pev->velocity.y <= -2000) return FALSE;
if (pev->velocity.z <= -2000) return FALSE;
return TRUE;
}
int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState )
{
if ( useType != USE_TOGGLE && useType != USE_SET )
{
if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) )
return 0;
}
return 1;
}
int CBaseEntity :: DamageDecal( int bitsDamageType )
{
if ( pev->rendermode == kRenderTransAlpha )
return -1;
if ( pev->rendermode != kRenderNormal )
return DECAL_BPROOF1;
return DECAL_GUNSHOT1 + RANDOM_LONG(0,4);
}
// NOTE: szName must be a pointer to constant memory, e.g. "monster_class" because the entity
// will keep a pointer to it after this call.
CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner )
{
edict_t *pent;
CBaseEntity *pEntity;
pent = CREATE_NAMED_ENTITY( MAKE_STRING( szName ));
if ( FNullEnt( pent ) )
{
ALERT ( at_console, "NULL Ent in Create!\n" );
return NULL;
}
pEntity = Instance( pent );
pEntity->pev->owner = pentOwner;
pEntity->pev->origin = vecOrigin;
pEntity->pev->angles = vecAngles;
DispatchSpawn( pEntity->edict() );
return pEntity;
}

784
dlls/cbase.h Normal file
View File

@ -0,0 +1,784 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
Class Hierachy
CBaseEntity
CBaseDelay
CBaseToggle
CBaseItem
CBaseMonster
CBaseCycler
CBasePlayer
CBaseGroup
*/
#define MAX_PATH_SIZE 10 // max number of nodes available for a path.
// These are caps bits to indicate what an object's capabilities (currently used for save/restore and level transitions)
#define FCAP_CUSTOMSAVE 0x00000001
#define FCAP_ACROSS_TRANSITION 0x00000002 // should transfer between transitions
#define FCAP_MUST_SPAWN 0x00000004 // Spawn after restore
#define FCAP_DONT_SAVE 0x80000000 // Don't save this
#define FCAP_IMPULSE_USE 0x00000008 // can be used by the player
#define FCAP_CONTINUOUS_USE 0x00000010 // can be used by the player
#define FCAP_ONOFF_USE 0x00000020 // can be used by the player
#define FCAP_DIRECTIONAL_USE 0x00000040 // Player sends +/- 1 when using (currently only tracktrains)
#define FCAP_MASTER 0x00000080 // Can be used to "master" other entities (like multisource)
// UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!!
#define FCAP_FORCE_TRANSITION 0x00000080 // ALWAYS goes across transitions
#include "saverestore.h"
#include "schedule.h"
#ifndef MONSTEREVENT_H
#include "monsterevent.h"
#endif
// C functions for external declarations that call the appropriate C++ methods
#define EXPORT _declspec( dllexport )
extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion );
extern int DispatchSpawn( edict_t *pent );
extern void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd );
extern void DispatchTouch( edict_t *pentTouched, edict_t *pentOther );
extern void DispatchUse( edict_t *pentUsed, edict_t *pentOther );
extern void DispatchThink( edict_t *pent );
extern void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther );
extern void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData );
extern int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity );
extern void DispatchObjectCollsionBox( edict_t *pent );
extern void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount );
extern void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount );
extern void SaveGlobalState( SAVERESTOREDATA *pSaveData );
extern void RestoreGlobalState( SAVERESTOREDATA *pSaveData );
extern void ResetGlobalState( void );
typedef enum { USE_OFF = 0, USE_ON = 1, USE_SET = 2, USE_TOGGLE = 3 } USE_TYPE;
extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
typedef void (CBaseEntity::*BASEPTR)(void);
typedef void (CBaseEntity::*ENTITYFUNCPTR)(CBaseEntity *pOther );
typedef void (CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
// For CLASSIFY
#define CLASS_NONE 0
#define CLASS_MACHINE 1
#define CLASS_PLAYER 2
#define CLASS_HUMAN_PASSIVE 3
#define CLASS_HUMAN_MILITARY 4
#define CLASS_ALIEN_MILITARY 5
#define CLASS_ALIEN_PASSIVE 6
#define CLASS_ALIEN_MONSTER 7
#define CLASS_ALIEN_PREY 8
#define CLASS_ALIEN_PREDATOR 9
#define CLASS_INSECT 10
#define CLASS_PLAYER_ALLY 11
#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players
#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace
#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures.
class CBaseEntity;
class CBaseMonster;
class CBasePlayerItem;
class CSquadMonster;
#define SF_NORESPAWN ( 1 << 30 )// !!!set this bit on guns and stuff that should never respawn.
//
// EHANDLE. Safe way to point to CBaseEntities who may die between frames
//
class EHANDLE
{
private:
edict_t *m_pent;
int m_serialnumber;
public:
edict_t *Get( void );
edict_t *Set( edict_t *pent );
operator int ();
operator CBaseEntity *();
CBaseEntity * operator = (CBaseEntity *pEntity);
CBaseEntity * operator ->();
};
//
// Base Entity. All entity types derive from this
//
class CBaseEntity
{
public:
// Constructor. Set engine to use C/C++ callback functions
// pointers to engine data
entvars_t *pev; // Don't need to save/restore this pointer, the engine resets it
// path corners
CBaseEntity *m_pGoalEnt;// path corner we are heading towards
CBaseEntity *m_pLink;// used for temporary link-list operations.
// initialization functions
virtual void Spawn( void ) { return; }
virtual void Precache( void ) { return; }
virtual void KeyValue( KeyValueData* pkvd) { pkvd->fHandled = FALSE; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; }
virtual void Activate( void ) {}
// Setup the object->object collision box (pev->mins / pev->maxs is the object->world collision box)
virtual void SetObjectCollisionBox( void );
// Classify - returns the type of group (i.e, "houndeye", or "human military" so that monsters with different classnames
// still realize that they are teammates. (overridden for monsters that form groups)
virtual int Classify ( void ) { return CLASS_NONE; };
virtual void DeathNotice ( entvars_t *pevChild ) {}// monster maker children use this to tell the monster maker that they have died.
static TYPEDESCRIPTION m_SaveData[];
virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
virtual int TakeHealth( float flHealth, int bitsDamageType );
virtual void Killed( entvars_t *pevAttacker, int iGib );
virtual int BloodColor( void ) { return DONT_BLEED; }
virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
virtual BOOL IsTriggered( CBaseEntity *pActivator ) {return TRUE;}
virtual CBaseMonster *MyMonsterPointer( void ) { return NULL;}
virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL;}
virtual int GetToggleState( void ) { return TS_AT_TOP; }
virtual void AddPoints( int score, BOOL bAllowNegativeScore ) {}
virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ) {}
virtual BOOL AddPlayerItem( CBasePlayerItem *pItem ) { return 0; }
virtual BOOL RemovePlayerItem( CBasePlayerItem *pItem ) { return 0; }
virtual int GiveAmmo( int iAmount, char *szName, int iMax ) { return -1; };
virtual float GetDelay( void ) { return 0; }
virtual int IsMoving( void ) { return pev->velocity != g_vecZero; }
virtual void OverrideReset( void ) {}
virtual int DamageDecal( int bitsDamageType );
// This is ONLY used by the node graph to test movement through a door
virtual void SetToggleState( int state ) {}
virtual void StartSneaking( void ) {}
virtual void StopSneaking( void ) {}
virtual BOOL OnControls( entvars_t *pev ) { return FALSE; }
virtual BOOL IsSneaking( void ) { return FALSE; }
virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; }
virtual BOOL IsBSPModel( void ) { return pev->solid == SOLID_BSP || pev->movetype == MOVETYPE_PUSHSTEP; }
virtual BOOL ReflectGauss( void ) { return ( IsBSPModel() && !pev->takedamage ); }
virtual BOOL HasTarget( string_t targetname ) { return FStrEq(STRING(targetname), STRING(pev->targetname) ); }
virtual BOOL IsInWorld( void );
virtual BOOL IsPlayer( void ) { return FALSE; }
virtual BOOL IsNetClient( void ) { return FALSE; }
virtual const char *TeamID( void ) { return ""; }
// virtual void SetActivator( CBaseEntity *pActivator ) {}
virtual CBaseEntity *GetNextTarget( void );
// fundamental callbacks
void (CBaseEntity ::*m_pfnThink)(void);
void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther );
void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther );
virtual void Think( void ) { if (m_pfnThink) (this->*m_pfnThink)(); };
virtual void Touch( CBaseEntity *pOther ) { if (m_pfnTouch) (this->*m_pfnTouch)( pOther ); };
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (m_pfnUse)
(this->*m_pfnUse)( pActivator, pCaller, useType, value );
}
virtual void Blocked( CBaseEntity *pOther ) { if (m_pfnBlocked) (this->*m_pfnBlocked)( pOther ); };
// allow engine to allocate instance data
void *operator new( size_t stAllocateBlock, entvars_t *pev )
{
return (void *)ALLOC_PRIVATE(ENT(pev), stAllocateBlock);
};
// don't use this.
#if _MSC_VER >= 1200 // only build this code if MSVC++ 6.0 or higher
void operator delete(void *pMem, entvars_t *pev)
{
pev->flags |= FL_KILLME;
};
#endif
void UpdateOnRemove( void );
// common member functions
void EXPORT SUB_Remove( void );
void EXPORT SUB_DoNothing( void );
void EXPORT SUB_StartFadeOut ( void );
void EXPORT SUB_FadeOut ( void );
void EXPORT SUB_CallUseToggle( void ) { this->Use( this, this, USE_TOGGLE, 0 ); }
int ShouldToggle( USE_TYPE useType, BOOL currentState );
void FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL );
virtual CBaseEntity *Respawn( void ) { return NULL; }
void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value );
// Do the bounding boxes of these two intersect?
int Intersects( CBaseEntity *pOther );
void MakeDormant( void );
int IsDormant( void );
BOOL IsLockedByMaster( void ) { return FALSE; }
#ifdef _DEBUG
static CBaseEntity *Instance( edict_t *pent )
{
if ( !pent )
pent = ENT(0);
CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent);
ASSERT(pEnt!=NULL);
return pEnt;
}
#else
static CBaseEntity *Instance( edict_t *pent )
{
if ( !pent )
pent = ENT(0);
CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent);
return pEnt;
}
#endif
static CBaseEntity *Instance( entvars_t *pev ) { return Instance( ENT( pev ) ); }
static CBaseEntity *Instance( int eoffset) { return Instance( ENT( eoffset) ); }
CBaseMonster *GetMonsterPointer( entvars_t *pevMonster )
{
CBaseEntity *pEntity = Instance( pevMonster );
if ( pEntity )
return pEntity->MyMonsterPointer();
return NULL;
}
CBaseMonster *GetMonsterPointer( edict_t *pentMonster )
{
CBaseEntity *pEntity = Instance( pentMonster );
if ( pEntity )
return pEntity->MyMonsterPointer();
return NULL;
}
// Ugly code to lookup all functions to make sure they are exported when set.
#ifdef _DEBUG
void FunctionCheck( void *pFunction, char *name )
{
if (pFunction && !NAME_FOR_FUNCTION((unsigned long)(pFunction)) )
ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction );
}
BASEPTR ThinkSet( BASEPTR func, char *name )
{
m_pfnThink = func;
FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnThink)))), name );
return func;
}
ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name )
{
m_pfnTouch = func;
FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnTouch)))), name );
return func;
}
USEPTR UseSet( USEPTR func, char *name )
{
m_pfnUse = func;
FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnUse)))), name );
return func;
}
ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name )
{
m_pfnBlocked = func;
FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnBlocked)))), name );
return func;
}
#endif
// virtual functions used by a few classes
// used by monsters that are created by the MonsterMaker
virtual void UpdateOwner( void ) { return; };
//
static CBaseEntity *Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner = NULL );
virtual BOOL FBecomeProne( void ) {return FALSE;};
edict_t *edict() { return ENT( pev ); };
EOFFSET eoffset( ) { return OFFSET( pev ); };
int entindex( ) { return ENTINDEX( edict() ); };
virtual Vector Center( ) { return (pev->absmax + pev->absmin) * 0.5; }; // center point of entity
virtual Vector EyePosition( ) { return pev->origin + pev->view_ofs; }; // position of eyes
virtual Vector EarPosition( ) { return pev->origin + pev->view_ofs; }; // position of ears
virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ); }; // position to shoot at
virtual int Illumination( ) { return GETENTITYILLUM( ENT( pev ) ); };
virtual BOOL FVisible ( CBaseEntity *pEntity );
virtual BOOL FVisible ( const Vector &vecOrigin );
};
// Ugly technique to override base member functions
// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a
// member function of a base class. static_cast is a sleezy way around that problem.
#ifdef _DEBUG
#define SetThink( a ) ThinkSet( static_cast <void (CBaseEntity::*)(void)> (a), #a )
#define SetTouch( a ) TouchSet( static_cast <void (CBaseEntity::*)(CBaseEntity *)> (a), #a )
#define SetUse( a ) UseSet( static_cast <void (CBaseEntity::*)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )> (a), #a )
#define SetBlocked( a ) BlockedSet( static_cast <void (CBaseEntity::*)(CBaseEntity *)> (a), #a )
#else
#define SetThink( a ) m_pfnThink = static_cast <void (CBaseEntity::*)(void)> (a)
#define SetTouch( a ) m_pfnTouch = static_cast <void (CBaseEntity::*)(CBaseEntity *)> (a)
#define SetUse( a ) m_pfnUse = static_cast <void (CBaseEntity::*)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )> (a)
#define SetBlocked( a ) m_pfnBlocked = static_cast <void (CBaseEntity::*)(CBaseEntity *)> (a)
#endif
class CPointEntity : public CBaseEntity
{
public:
void Spawn( void );
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
private:
};
typedef struct locksounds // sounds that doors and buttons make when locked/unlocked
{
string_t sLockedSound; // sound a door makes when it's locked
string_t sLockedSentence; // sentence group played when door is locked
string_t sUnlockedSound; // sound a door makes when it's unlocked
string_t sUnlockedSentence; // sentence group played when door is unlocked
int iLockedSentence; // which sentence in sentence group to play next
int iUnlockedSentence; // which sentence in sentence group to play next
float flwaitSound; // time delay between playing consecutive 'locked/unlocked' sounds
float flwaitSentence; // time delay between playing consecutive sentences
BYTE bEOFLocked; // true if hit end of list of locked sentences
BYTE bEOFUnlocked; // true if hit end of list of unlocked sentences
} locksound_t;
void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton);
//
// MultiSouce
//
#define MAX_MULTI_TARGETS 16 // maximum number of targets a single multi_manager entity may be assigned.
#define MS_MAX_TARGETS 32
class CMultiSource : public CPointEntity
{
public:
void Spawn( );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int ObjectCaps( void ) { return (CPointEntity::ObjectCaps() | FCAP_MASTER); }
BOOL IsTriggered( CBaseEntity *pActivator );
void EXPORT Register( void );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
EHANDLE m_rgEntities[MS_MAX_TARGETS];
int m_rgTriggered[MS_MAX_TARGETS];
int m_iTotal;
string_t m_globalstate;
};
//
// generic Delay entity.
//
class CBaseDelay : public CBaseEntity
{
public:
float m_flDelay;
int m_iszKillTarget;
virtual void KeyValue( KeyValueData* pkvd);
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
// common member functions
void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value );
void EXPORT DelayThink( void );
};
class CBaseAnimating : public CBaseDelay
{
public:
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
// Basic Monster Animation functions
float StudioFrameAdvance( float flInterval = 0.0 ); // accumulate animation frame time from last time called until now
int GetSequenceFlags( void );
int LookupActivity ( int activity );
int LookupActivityHeaviest ( int activity );
int LookupSequence ( const char *label );
void ResetSequenceInfo ( );
void DispatchAnimEvents ( float flFutureInterval = 0.1 ); // Handle events that have happend since last time called up until X seconds into the future
virtual void HandleAnimEvent( MonsterEvent_t *pEvent ) { return; };
float SetBoneController ( int iController, float flValue );
void InitBoneControllers ( void );
float SetBlending ( int iBlender, float flValue );
void GetBonePosition ( int iBone, Vector &origin, Vector &angles );
void GetAutomovement( Vector &origin, Vector &angles, float flInterval = 0.1 );
int FindTransition( int iEndingSequence, int iGoalSequence, int *piDir );
void GetAttachment ( int iAttachment, Vector &origin, Vector &angles );
void SetBodygroup( int iGroup, int iValue );
int GetBodygroup( int iGroup );
int ExtractBbox( int sequence, float *mins, float *maxs );
void SetSequenceBox( void );
// animation needs
float m_flFrameRate; // computed FPS for current sequence
float m_flGroundSpeed; // computed linear movement rate for current sequence
float m_flLastEventCheck; // last time the event list was checked
BOOL m_fSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry
BOOL m_fSequenceLoops; // true if the sequence loops
};
//
// generic Toggle entity.
//
#define SF_ITEM_USE_ONLY 256 // ITEM_USE_ONLY = BUTTON_USE_ONLY = DOOR_USE_ONLY!!!
class CBaseToggle : public CBaseAnimating
{
public:
void KeyValue( KeyValueData *pkvd );
TOGGLE_STATE m_toggle_state;
float m_flActivateFinished;//like attack_finished, but for doors
float m_flMoveDistance;// how far a door should slide or rotate
float m_flWait;
float m_flLip;
float m_flTWidth;// for plats
float m_flTLength;// for plats
Vector m_vecPosition1;
Vector m_vecPosition2;
Vector m_vecAngle1;
Vector m_vecAngle2;
int m_cTriggersLeft; // trigger_counter only, # of activations remaining
float m_flHeight;
EHANDLE m_hActivator;
void (CBaseToggle::*m_pfnCallWhenMoveDone)(void);
Vector m_vecFinalDest;
Vector m_vecFinalAngle;
int m_bitsDamageInflict; // DMG_ damage type that the door or tigger does
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
virtual int GetToggleState( void ) { return m_toggle_state; }
virtual float GetDelay( void ) { return m_flWait; }
// common member functions
void LinearMove( Vector vecDest, float flSpeed );
void EXPORT LinearMoveDone( void );
void AngularMove( Vector vecDestAngle, float flSpeed );
void EXPORT AngularMoveDone( void );
BOOL IsLockedByMaster( void );
static float AxisValue( int flags, const Vector &angles );
static void AxisDir( entvars_t *pev );
static float AxisDelta( int flags, const Vector &angle1, const Vector &angle2 );
string_t m_sMaster; // If this button has a master switch, this is the targetname.
// A master switch must be of the multisource type. If all
// of the switches in the multisource have been triggered, then
// the button will be allowed to operate. Otherwise, it will be
// deactivated.
};
#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast <void (CBaseToggle::*)(void)> (a)
// people gib if their health is <= this at the time of death
#define GIB_HEALTH_VALUE -30
#define ROUTE_SIZE 8 // how many waypoints a monster can store at one time
#define MAX_OLD_ENEMIES 4 // how many old enemies to remember
#define bits_CAP_DUCK ( 1 << 0 )// crouch
#define bits_CAP_JUMP ( 1 << 1 )// jump/leap
#define bits_CAP_STRAFE ( 1 << 2 )// strafe ( walk/run sideways)
#define bits_CAP_SQUAD ( 1 << 3 )// can form squads
#define bits_CAP_SWIM ( 1 << 4 )// proficiently navigate in water
#define bits_CAP_CLIMB ( 1 << 5 )// climb ladders/ropes
#define bits_CAP_USE ( 1 << 6 )// open doors/push buttons/pull levers
#define bits_CAP_HEAR ( 1 << 7 )// can hear forced sounds
#define bits_CAP_AUTO_DOORS ( 1 << 8 )// can trigger auto doors
#define bits_CAP_OPEN_DOORS ( 1 << 9 )// can open manual doors
#define bits_CAP_TURN_HEAD ( 1 << 10)// can turn head, always bone controller 0
#define bits_CAP_RANGE_ATTACK1 ( 1 << 11)// can do a range attack 1
#define bits_CAP_RANGE_ATTACK2 ( 1 << 12)// can do a range attack 2
#define bits_CAP_MELEE_ATTACK1 ( 1 << 13)// can do a melee attack 1
#define bits_CAP_MELEE_ATTACK2 ( 1 << 14)// can do a melee attack 2
#define bits_CAP_FLY ( 1 << 15)// can fly, move all around
#define bits_CAP_DOORS_GROUP (bits_CAP_USE | bits_CAP_AUTO_DOORS | bits_CAP_OPEN_DOORS)
// used by suit voice to indicate damage sustained and repaired type to player
// instant damage
#define DMG_GENERIC 0 // generic damage was done
#define DMG_CRUSH (1 << 0) // crushed by falling or moving object
#define DMG_BULLET (1 << 1) // shot
#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
#define DMG_BURN (1 << 3) // heat burned
#define DMG_FREEZE (1 << 4) // frozen
#define DMG_FALL (1 << 5) // fell too far
#define DMG_BLAST (1 << 6) // explosive blast damage
#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
#define DMG_SHOCK (1 << 8) // electric shock
#define DMG_SONIC (1 << 9) // sound pulse shockwave
#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam
#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death
#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death.
#define DMG_DROWN (1 << 14) // Drowning
// time-based damage
#define DMG_TIMEBASED (~(0x3fff)) // mask for time-based damage
#define DMG_PARALYZE (1 << 15) // slows affected creature down
#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad
#define DMG_POISON (1 << 17) // blood poisioning
#define DMG_RADIATION (1 << 18) // radiation exposure
#define DMG_DROWNRECOVER (1 << 19) // drowning recovery
#define DMG_ACID (1 << 20) // toxic chemicals or acid burns
#define DMG_SLOWBURN (1 << 21) // in an oven
#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer
#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar)
// these are the damage types that are allowed to gib corpses
#define DMG_GIB_CORPSE ( DMG_CRUSH | DMG_FALL | DMG_BLAST | DMG_SONIC | DMG_CLUB )
// these are the damage types that have client hud art
#define DMG_SHOWNHUD (DMG_POISON | DMG_ACID | DMG_FREEZE | DMG_SLOWFREEZE | DMG_DROWN | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION | DMG_SHOCK)
// NOTE: tweak these values based on gameplay feedback:
#define PARALYZE_DURATION 2 // number of 2 second intervals to take damage
#define PARALYZE_DAMAGE 1.0 // damage to take each 2 second interval
#define NERVEGAS_DURATION 2
#define NERVEGAS_DAMAGE 5.0
#define POISON_DURATION 5
#define POISON_DAMAGE 2.0
#define RADIATION_DURATION 2
#define RADIATION_DAMAGE 1.0
#define ACID_DURATION 2
#define ACID_DAMAGE 5.0
#define SLOWBURN_DURATION 2
#define SLOWBURN_DAMAGE 1.0
#define SLOWFREEZE_DURATION 2
#define SLOWFREEZE_DAMAGE 1.0
#define itbd_Paralyze 0
#define itbd_NerveGas 1
#define itbd_Poison 2
#define itbd_Radiation 3
#define itbd_DrownRecover 4
#define itbd_Acid 5
#define itbd_SlowBurn 6
#define itbd_SlowFreeze 7
#define CDMG_TIMEBASED 8
// when calling KILLED(), a value that governs gib behavior is expected to be
// one of these three values
#define GIB_NORMAL 0// gib if entity was overkilled
#define GIB_NEVER 1// never gib, no matter how much death damage is done ( freezing, etc )
#define GIB_ALWAYS 2// always gib ( Houndeye Shock, Barnacle Bite )
class CBaseMonster;
class CCineMonster;
class CSound;
#include "basemonster.h"
char *ButtonSound( int sound ); // get string of button sound number
//
// Generic Button
//
class CBaseButton : public CBaseToggle
{
public:
void Spawn( void );
virtual void Precache( void );
void RotSpawn( void );
virtual void KeyValue( KeyValueData* pkvd);
void ButtonActivate( );
void SparkSoundCache( void );
void EXPORT ButtonShot( void );
void EXPORT ButtonTouch( CBaseEntity *pOther );
void EXPORT ButtonSpark ( void );
void EXPORT TriggerAndWait( void );
void EXPORT ButtonReturn( void );
void EXPORT ButtonBackHome( void );
void EXPORT ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
enum BUTTON_CODE { BUTTON_NOTHING, BUTTON_ACTIVATE, BUTTON_RETURN };
BUTTON_CODE ButtonResponseToTouch( void );
static TYPEDESCRIPTION m_SaveData[];
// Buttons that don't take damage can be IMPULSE used
virtual int ObjectCaps( void ) { return (CBaseToggle:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | (pev->takedamage?0:FCAP_IMPULSE_USE); }
BOOL m_fStayPushed; // button stays pushed in until touched again?
BOOL m_fRotating; // a rotating button? default is a sliding button.
string_t m_strChangeTarget; // if this field is not null, this is an index into the engine string array.
// when this button is touched, it's target entity's TARGET field will be set
// to the button's ChangeTarget. This allows you to make a func_train switch paths, etc.
locksound_t m_ls; // door lock sounds
BYTE m_bLockedSound; // ordinals from entity selection
BYTE m_bLockedSentence;
BYTE m_bUnlockedSound;
BYTE m_bUnlockedSentence;
int m_sounds;
};
//
// Weapons
//
#define BAD_WEAPON 0x00007FFF
//
// Converts a entvars_t * to a class pointer
// It will allocate the class and entity if necessary
//
template <class T> T * GetClassPtr( T *a )
{
entvars_t *pev = (entvars_t *)a;
// allocate entity if necessary
if (pev == NULL)
pev = VARS(CREATE_ENTITY());
// get the private data
a = (T *)GET_PRIVATE(ENT(pev));
if (a == NULL)
{
// allocate private data
a = new(pev) T;
a->pev = pev;
}
return a;
}
/*
bit_PUSHBRUSH_DATA | bit_TOGGLE_DATA
bit_MONSTER_DATA
bit_DELAY_DATA
bit_TOGGLE_DATA | bit_DELAY_DATA | bit_MONSTER_DATA
bit_PLAYER_DATA | bit_MONSTER_DATA
bit_MONSTER_DATA | CYCLER_DATA
bit_LIGHT_DATA
path_corner_data
bit_MONSTER_DATA | wildcard_data
bit_MONSTER_DATA | bit_GROUP_DATA
boid_flock_data
boid_data
CYCLER_DATA
bit_ITEM_DATA
bit_ITEM_DATA | func_hud_data
bit_TOGGLE_DATA | bit_ITEM_DATA
EOFFSET
env_sound_data
env_sound_data
push_trigger_data
*/
#define TRACER_FREQ 4 // Tracers fire every 4 bullets
typedef struct _SelAmmo
{
BYTE Ammo1Type;
BYTE Ammo1;
BYTE Ammo2Type;
BYTE Ammo2;
} SelAmmo;
// this moved here from world.cpp, to allow classes to be derived from it
//=======================
// CWorld
//
// This spawns first when each level begins.
//=======================
class CWorld : public CBaseEntity
{
public:
void Spawn( void );
void Precache( void );
void KeyValue( KeyValueData *pkvd );
};

46
dlls/cdll_dll.h Normal file
View File

@ -0,0 +1,46 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// cdll_dll.h
// this file is included by both the game-dll and the client-dll,
#ifndef CDLL_DLL_H
#define CDLL_DLL_H
#define MAX_WEAPONS 32 // ???
#define MAX_WEAPON_SLOTS 5 // hud item selection slots
#define MAX_ITEM_TYPES 6 // hud item selection slots
#define MAX_ITEMS 5 // hard coded item types
#define HIDEHUD_WEAPONS ( 1<<0 )
#define HIDEHUD_FLASHLIGHT ( 1<<1 )
#define HIDEHUD_ALL ( 1<<2 )
#define HIDEHUD_HEALTH ( 1<<3 )
#define MAX_AMMO_TYPES 32 // ???
#define MAX_AMMO_SLOTS 32 // not really slots
#define HUD_PRINTNOTIFY 1
#define HUD_PRINTCONSOLE 2
#define HUD_PRINTTALK 3
#define HUD_PRINTCENTER 4
#define WEAPON_SUIT 31
#endif

729
dlls/client.cpp Normal file
View File

@ -0,0 +1,729 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
// Robin, 4-22-98: Moved set_suicide_frame() here from player.cpp to allow us to
// have one without a hardcoded player.mdl in tf_client.cpp
/*
===== client.cpp ========================================================
client/server game specific stuff
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "saverestore.h"
#include "player.h"
#include "spectator.h"
#include "client.h"
#include "soundent.h"
#include "gamerules.h"
extern DLL_GLOBAL ULONG g_ulModelIndexPlayer;
extern DLL_GLOBAL BOOL g_fGameOver;
extern DLL_GLOBAL int g_iSkillLevel;
extern DLL_GLOBAL ULONG g_ulFrameCount;
extern void CopyToBodyQue(entvars_t* pev);
extern int giPrecacheGrunt;
extern int gmsgSayText;
/*
* used by kill command and disconnect command
* ROBIN: Moved here from player.cpp, to allow multiple player models
*/
void set_suicide_frame(entvars_t* pev)
{
if (!FStrEq(STRING(pev->model), "models/player.mdl"))
return; // allready gibbed
// pev->frame = $deatha11;
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_TOSS;
pev->deadflag = DEAD_DEAD;
pev->nextthink = -1;
}
/*
===========
ClientConnect
called when a player connects to a server
============
*/
BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] )
{
return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason );
// a client connecting during an intermission can cause problems
// if (intermission_running)
// ExitIntermission ();
}
/*
===========
ClientDisconnect
called when a player disconnects from a server
GLOBALS ASSUMED SET: g_fGameOver
============
*/
void ClientDisconnect( edict_t *pEntity )
{
if (g_fGameOver)
return;
char text[256];
sprintf( text, "- %s has left the game\n", STRING(pEntity->v.netname) );
MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL );
WRITE_BYTE( ENTINDEX(pEntity) );
WRITE_STRING( text );
MESSAGE_END();
CSound *pSound;
pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) );
{
// since this client isn't around to think anymore, reset their sound.
if ( pSound )
{
pSound->Reset();
}
}
// since the edict doesn't get deleted, fix it so it doesn't interfere.
pEntity->v.takedamage = DAMAGE_NO;// don't attract autoaim
pEntity->v.solid = SOLID_NOT;// nonsolid
UTIL_SetOrigin ( &pEntity->v, pEntity->v.origin );
g_pGameRules->ClientDisconnected( pEntity );
}
// called by ClientKill and DeadThink
void respawn(entvars_t* pev, BOOL fCopyCorpse)
{
if (gpGlobals->coop || gpGlobals->deathmatch)
{
if ( fCopyCorpse )
{
// make a copy of the dead body for appearances sake
CopyToBodyQue(pev);
}
// respawn player
GetClassPtr( (CBasePlayer *)pev)->Spawn( );
}
else
{ // restart the entire server
SERVER_COMMAND("reload\n");
}
}
/*
============
ClientKill
Player entered the suicide command
GLOBALS ASSUMED SET: g_ulModelIndexPlayer
============
*/
void ClientKill( edict_t *pEntity )
{
entvars_t *pev = &pEntity->v;
CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev );
if ( pl->m_fNextSuicideTime > gpGlobals->time )
return; // prevent suiciding too ofter
pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding
// have the player kill themself
pev->health = 0;
pl->Killed( pev, GIB_NEVER );
// pev->modelindex = g_ulModelIndexPlayer;
// pev->frags -= 2; // extra penalty
// respawn( pev );
}
/*
===========
ClientPutInServer
called each time a player is spawned
============
*/
void ClientPutInServer( edict_t *pEntity )
{
CBasePlayer *pPlayer;
entvars_t *pev = &pEntity->v;
pPlayer = GetClassPtr((CBasePlayer *)pev);
pPlayer->SetCustomDecalFrames(-1); // Assume none;
// Allocate a CBasePlayer for pev, and call spawn
pPlayer->Spawn() ;
}
//// HOST_SAY
// String comes in as
// say blah blah blah
// or as
// blah blah blah
//
void Host_Say( edict_t *pEntity, int teamonly )
{
CBasePlayer *client;
int j;
char *p;
char text[128];
char szTemp[256];
const char *cpSay = "say";
const char *cpSayTeam = "say_team";
const char *pcmd = CMD_ARGV(0);
// We can get a raw string now, without the "say " prepended
if ( CMD_ARGC() == 0 )
return;
if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) )
{
if ( CMD_ARGC() >= 2 )
{
p = (char *)CMD_ARGS();
}
else
{
// say with a blank message, nothing to do
return;
}
}
else // Raw text, need to prepend argv[0]
{
if ( CMD_ARGC() >= 2 )
{
sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() );
}
else
{
// Just a one word command, use the first word...sigh
sprintf( szTemp, "%s", ( char * )pcmd );
}
p = szTemp;
}
// remove quotes if present
if (*p == '"')
{
p++;
p[strlen(p)-1] = 0;
}
// make sure the text has content
for ( char *pc = p; pc != NULL && *pc != 0; pc++ )
{
if ( isprint( *pc ) && !isspace( *pc ) )
{
pc = NULL; // we've found an alphanumeric character, so text is valid
break;
}
}
if ( pc != NULL )
return; // no character found, so say nothing
// turn on color set 2 (color on, no sound)
if ( teamonly )
sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) );
else
sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) );
j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator
if ( (int)strlen(p) > j )
p[j] = 0;
strcat( text, p );
strcat( text, "\n" );
// loop through all players
// Start with the first player.
// This may return the world in single player if the client types something between levels or during spawn
// so check it, or it will infinite loop
client = NULL;
while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) )
{
if ( !client->pev )
continue;
if ( client->edict() == pEntity )
continue;
if ( !(client->IsNetClient()) ) // Not a client ? (should never be true)
continue;
if ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE )
continue;
MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev );
WRITE_BYTE( ENTINDEX(client->edict()) );
WRITE_STRING( text );
MESSAGE_END();
}
// print to the sending client
MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, &pEntity->v );
WRITE_BYTE( ENTINDEX(pEntity) );
WRITE_STRING( text );
MESSAGE_END();
// echo to server console
g_engfuncs.pfnServerPrint( text );
}
/*
===========
ClientCommand
called each time a player uses a "cmd" command
============
*/
extern float g_flWeaponCheat;
// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command.
void ClientCommand( edict_t *pEntity )
{
const char *pcmd = CMD_ARGV(0);
const char *pstr;
// Is the client spawned yet?
if ( !pEntity->pvPrivateData )
return;
entvars_t *pev = &pEntity->v;
if ( FStrEq(pcmd, "say" ) )
{
Host_Say( pEntity, 0 );
}
else if ( FStrEq(pcmd, "say_team" ) )
{
Host_Say( pEntity, 1 );
}
else if ( FStrEq(pcmd, "give" ) )
{
if ( g_flWeaponCheat != 0.0)
{
int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname
GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) );
}
}
else if ( FStrEq(pcmd, "drop" ) )
{
// player is dropping an item.
GetClassPtr((CBasePlayer *)pev)->DropPlayerItem((char *)CMD_ARGV(1));
}
else if ( FStrEq(pcmd, "fov" ) )
{
if ( g_flWeaponCheat && CMD_ARGC() > 1)
{
GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) );
}
else
{
CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr((CBasePlayer *)pev)->m_iFOV ) );
}
}
else if ( FStrEq(pcmd, "use" ) )
{
GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV(1));
}
else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd))
{
GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd);
}
else if (FStrEq(pcmd, "lastinv" ))
{
GetClassPtr((CBasePlayer *)pev)->SelectLastItem();
}
else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd ) )
{
// MenuSelect returns true only if the command is properly handled, so don't print a warning
}
else
{
// tell the user they entered an unknown command
ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", pcmd ) );
}
}
/*
========================
ClientUserInfoChanged
called after the player changes
userinfo - gives dll a chance to modify it before
it gets sent into the rest of the engine.
========================
*/
void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer )
{
// Is the client spawned yet?
if ( !pEntity->pvPrivateData )
return;
// msg everyone if someone changes their name, and it isn't the first time (changing no name to current name)
if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq( STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" )) )
{
char text[256];
sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) );
MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL );
WRITE_BYTE( ENTINDEX(pEntity) );
WRITE_STRING( text );
MESSAGE_END();
UTIL_LogPrintf( "\"%s<%i>\" changed name to \"%s<%i>\"\n", STRING( pEntity->v.netname ), GETPLAYERUSERID( pEntity ), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ), GETPLAYERUSERID( pEntity ) );
}
g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer );
}
void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
{
int i;
CBaseEntity *pClass;
// Clients have not been initialized yet
for ( i = 0; i < edictCount; i++ )
{
if ( pEdictList[i].free )
continue;
// Clients aren't necessarily initialized until ClientPutInServer()
if ( i < clientMax || !pEdictList[i].pvPrivateData )
continue;
pClass = CBaseEntity::Instance( &pEdictList[i] );
// Activate this entity if it's got a class & isn't dormant
if ( pClass && !(pClass->pev->flags & FL_DORMANT) )
{
pClass->Activate();
}
else
{
ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) );
}
}
}
/*
================
PlayerPreThink
Called every frame before physics are run
================
*/
void PlayerPreThink( edict_t *pEntity )
{
entvars_t *pev = &pEntity->v;
CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity);
if (pPlayer)
pPlayer->PreThink( );
}
/*
================
PlayerPostThink
Called every frame after physics are run
================
*/
void PlayerPostThink( edict_t *pEntity )
{
entvars_t *pev = &pEntity->v;
CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity);
if (pPlayer)
pPlayer->PostThink( );
}
void ParmsNewLevel( void )
{
}
void ParmsChangeLevel( void )
{
// retrieve the pointer to the save data
SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData;
if ( pSaveData )
pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS );
}
//
// GLOBALS ASSUMED SET: g_ulFrameCount
//
void StartFrame( void )
{
if ( g_pGameRules )
g_pGameRules->Think();
if ( g_fGameOver )
return;
gpGlobals->teamplay = CVAR_GET_FLOAT("teamplay");
g_iSkillLevel = CVAR_GET_FLOAT("skill");
g_ulFrameCount++;
}
void ClientPrecache( void )
{
// setup precaches always needed
PRECACHE_SOUND("player/sprayer.wav"); // spray paint sound for PreAlpha
// PRECACHE_SOUND("player/pl_jumpland2.wav"); // UNDONE: play 2x step sound
PRECACHE_SOUND("player/pl_fallpain2.wav");
PRECACHE_SOUND("player/pl_fallpain3.wav");
PRECACHE_SOUND("player/pl_step1.wav"); // walk on concrete
PRECACHE_SOUND("player/pl_step2.wav");
PRECACHE_SOUND("player/pl_step3.wav");
PRECACHE_SOUND("player/pl_step4.wav");
PRECACHE_SOUND("common/npc_step1.wav"); // NPC walk on concrete
PRECACHE_SOUND("common/npc_step2.wav");
PRECACHE_SOUND("common/npc_step3.wav");
PRECACHE_SOUND("common/npc_step4.wav");
PRECACHE_SOUND("player/pl_metal1.wav"); // walk on metal
PRECACHE_SOUND("player/pl_metal2.wav");
PRECACHE_SOUND("player/pl_metal3.wav");
PRECACHE_SOUND("player/pl_metal4.wav");
PRECACHE_SOUND("player/pl_dirt1.wav"); // walk on dirt
PRECACHE_SOUND("player/pl_dirt2.wav");
PRECACHE_SOUND("player/pl_dirt3.wav");
PRECACHE_SOUND("player/pl_dirt4.wav");
PRECACHE_SOUND("player/pl_duct1.wav"); // walk in duct
PRECACHE_SOUND("player/pl_duct2.wav");
PRECACHE_SOUND("player/pl_duct3.wav");
PRECACHE_SOUND("player/pl_duct4.wav");
PRECACHE_SOUND("player/pl_grate1.wav"); // walk on grate
PRECACHE_SOUND("player/pl_grate2.wav");
PRECACHE_SOUND("player/pl_grate3.wav");
PRECACHE_SOUND("player/pl_grate4.wav");
PRECACHE_SOUND("player/pl_slosh1.wav"); // walk in shallow water
PRECACHE_SOUND("player/pl_slosh2.wav");
PRECACHE_SOUND("player/pl_slosh3.wav");
PRECACHE_SOUND("player/pl_slosh4.wav");
PRECACHE_SOUND("player/pl_tile1.wav"); // walk on tile
PRECACHE_SOUND("player/pl_tile2.wav");
PRECACHE_SOUND("player/pl_tile3.wav");
PRECACHE_SOUND("player/pl_tile4.wav");
PRECACHE_SOUND("player/pl_tile5.wav");
PRECACHE_SOUND("player/pl_swim1.wav"); // breathe bubbles
PRECACHE_SOUND("player/pl_swim2.wav");
PRECACHE_SOUND("player/pl_swim3.wav");
PRECACHE_SOUND("player/pl_swim4.wav");
PRECACHE_SOUND("player/pl_ladder1.wav"); // climb ladder rung
PRECACHE_SOUND("player/pl_ladder2.wav");
PRECACHE_SOUND("player/pl_ladder3.wav");
PRECACHE_SOUND("player/pl_ladder4.wav");
PRECACHE_SOUND("player/pl_wade1.wav"); // wade in water
PRECACHE_SOUND("player/pl_wade2.wav");
PRECACHE_SOUND("player/pl_wade3.wav");
PRECACHE_SOUND("player/pl_wade4.wav");
PRECACHE_SOUND("debris/wood1.wav"); // hit wood texture
PRECACHE_SOUND("debris/wood2.wav");
PRECACHE_SOUND("debris/wood3.wav");
PRECACHE_SOUND("plats/train_use1.wav"); // use a train
PRECACHE_SOUND("buttons/spark5.wav"); // hit computer texture
PRECACHE_SOUND("buttons/spark6.wav");
PRECACHE_SOUND("debris/glass1.wav");
PRECACHE_SOUND("debris/glass2.wav");
PRECACHE_SOUND("debris/glass3.wav");
PRECACHE_SOUND( SOUND_FLASHLIGHT_ON );
PRECACHE_SOUND( SOUND_FLASHLIGHT_OFF );
// player gib sounds
PRECACHE_SOUND("common/bodysplat.wav");
// player pain sounds
PRECACHE_SOUND("player/pl_pain2.wav");
PRECACHE_SOUND("player/pl_pain4.wav");
PRECACHE_SOUND("player/pl_pain5.wav");
PRECACHE_SOUND("player/pl_pain6.wav");
PRECACHE_SOUND("player/pl_pain7.wav");
PRECACHE_MODEL("models/player.mdl");
// hud sounds
PRECACHE_SOUND("common/wpn_hudoff.wav");
PRECACHE_SOUND("common/wpn_hudon.wav");
PRECACHE_SOUND("common/wpn_moveselect.wav");
PRECACHE_SOUND("common/wpn_select.wav");
PRECACHE_SOUND("common/wpn_denyselect.wav");
// geiger sounds
PRECACHE_SOUND("player/geiger6.wav");
PRECACHE_SOUND("player/geiger5.wav");
PRECACHE_SOUND("player/geiger4.wav");
PRECACHE_SOUND("player/geiger3.wav");
PRECACHE_SOUND("player/geiger2.wav");
PRECACHE_SOUND("player/geiger1.wav");
if (giPrecacheGrunt)
UTIL_PrecacheOther("monster_human_grunt");
}
/*
===============
const char *GetGameDescription()
Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2
===============
*/
const char *GetGameDescription()
{
if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized
return g_pGameRules->GetGameDescription();
else
return "Half-Life";
}
/*
================
PlayerCustomization
A new player customization has been registered on the server
UNDONE: This only sets the # of frames of the spray can logo
animation right now.
================
*/
void PlayerCustomization( edict_t *pEntity, customization_t *pCust )
{
entvars_t *pev = &pEntity->v;
CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity);
if (!pPlayer)
{
ALERT(at_console, "PlayerCustomization: Couldn't get player!\n");
return;
}
if (!pCust)
{
ALERT(at_console, "PlayerCustomization: NULL customization!\n");
return;
}
switch (pCust->resource.type)
{
case t_decal:
pPlayer->SetCustomDecalFrames(pCust->nUserData2); // Second int is max # of frames.
break;
case t_sound:
case t_skin:
case t_model:
// Ignore for now.
break;
default:
ALERT(at_console, "PlayerCustomization: Unknown customization type!\n");
break;
}
}
/*
================
SpectatorConnect
A spectator has joined the game
================
*/
void SpectatorConnect( edict_t *pEntity )
{
entvars_t *pev = &pEntity->v;
CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity);
if (pPlayer)
pPlayer->SpectatorConnect( );
}
/*
================
SpectatorConnect
A spectator has left the game
================
*/
void SpectatorDisconnect( edict_t *pEntity )
{
entvars_t *pev = &pEntity->v;
CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity);
if (pPlayer)
pPlayer->SpectatorDisconnect( );
}
/*
================
SpectatorConnect
A spectator has sent a usercmd
================
*/
void SpectatorThink( edict_t *pEntity )
{
entvars_t *pev = &pEntity->v;
CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity);
if (pPlayer)
pPlayer->SpectatorThink( );
}

41
dlls/client.h Normal file
View File

@ -0,0 +1,41 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef CLIENT_H
#define CLIENT_H
extern void respawn( entvars_t* pev, BOOL fCopyCorpse );
extern BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] );
extern void ClientDisconnect( edict_t *pEntity );
extern void ClientKill( edict_t *pEntity );
extern void ClientPutInServer( edict_t *pEntity );
extern void ClientCommand( edict_t *pEntity );
extern void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer );
extern void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax );
extern void StartFrame( void );
extern void PlayerPostThink( edict_t *pEntity );
extern void PlayerPreThink( edict_t *pEntity );
extern void ParmsNewLevel( void );
extern void ParmsChangeLevel( void );
extern void ClientPrecache( void );
extern const char *GetGameDescription( void );
extern void PlayerCustomization( edict_t *pEntity, customization_t *pCust );
extern void SpectatorConnect ( edict_t *pEntity );
extern void SpectatorDisconnect ( edict_t *pEntity );
extern void SpectatorThink ( edict_t *pEntity );
#endif // CLIENT_H

1666
dlls/combat.cpp Normal file

File diff suppressed because it is too large Load Diff

600
dlls/crossbow.cpp Normal file
View File

@ -0,0 +1,600 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "gamerules.h"
#define BOLT_AIR_VELOCITY 2000
#define BOLT_WATER_VELOCITY 1000
// UNDONE: Save/restore this? Don't forget to set classname and LINK_ENTITY_TO_CLASS()
//
// OVERLOADS SOME ENTVARS:
//
// speed - the ideal magnitude of my velocity
class CCrossbowBolt : public CBaseEntity
{
void Spawn( void );
void Precache( void );
int Classify ( void );
void EXPORT BubbleThink( void );
void EXPORT BoltTouch( CBaseEntity *pOther );
void EXPORT ExplodeThink( void );
int m_iTrail;
public:
static CCrossbowBolt *BoltCreate( void );
};
LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt );
CCrossbowBolt *CCrossbowBolt::BoltCreate( void )
{
// Create a new entity with CCrossbowBolt private data
CCrossbowBolt *pBolt = GetClassPtr( (CCrossbowBolt *)NULL );
pBolt->pev->classname = MAKE_STRING("bolt");
pBolt->Spawn();
return pBolt;
}
void CCrossbowBolt::Spawn( )
{
Precache( );
pev->movetype = MOVETYPE_FLY;
pev->solid = SOLID_BBOX;
pev->gravity = 0.5;
SET_MODEL(ENT(pev), "models/crossbow_bolt.mdl");
UTIL_SetOrigin( pev, pev->origin );
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));
SetTouch( BoltTouch );
SetThink( BubbleThink );
pev->nextthink = gpGlobals->time + 0.2;
}
void CCrossbowBolt::Precache( )
{
PRECACHE_MODEL ("models/crossbow_bolt.mdl");
PRECACHE_SOUND("weapons/xbow_hitbod1.wav");
PRECACHE_SOUND("weapons/xbow_hitbod2.wav");
PRECACHE_SOUND("weapons/xbow_fly1.wav");
PRECACHE_SOUND("weapons/xbow_hit1.wav");
PRECACHE_SOUND("fvox/beep.wav");
m_iTrail = PRECACHE_MODEL("sprites/streak.spr");
}
int CCrossbowBolt :: Classify ( void )
{
return CLASS_NONE;
}
void CCrossbowBolt::BoltTouch( CBaseEntity *pOther )
{
SetTouch( NULL );
SetThink( NULL );
if (pOther->pev->takedamage)
{
TraceResult tr = UTIL_GetGlobalTrace( );
entvars_t *pevOwner;
pevOwner = VARS( pev->owner );
// UNDONE: this needs to call TraceAttack instead
ClearMultiDamage( );
if ( pOther->IsPlayer() )
{
pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowClient, pev->velocity.Normalize(), &tr, DMG_NEVERGIB );
}
else
{
pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowMonster, pev->velocity.Normalize(), &tr, DMG_BULLET | DMG_NEVERGIB );
}
ApplyMultiDamage( pev, pevOwner );
pev->velocity = Vector( 0, 0, 0 );
// play body "thwack" sound
switch( RANDOM_LONG(0,1) )
{
case 0:
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break;
case 1:
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break;
}
if ( !g_pGameRules->IsMultiplayer() )
{
Killed( pev, GIB_NEVER );
}
}
else
{
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7));
SetThink( SUB_Remove );
pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit.
if ( FClassnameIs( pOther->pev, "worldspawn" ) )
{
// if what we hit is static architecture, can stay around for a while.
Vector vecDir = pev->velocity.Normalize( );
UTIL_SetOrigin( pev, pev->origin - vecDir * 12 );
pev->angles = UTIL_VecToAngles( vecDir );
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_FLY;
pev->velocity = Vector( 0, 0, 0 );
pev->avelocity.z = 0;
pev->angles.z = RANDOM_LONG(0,360);
pev->nextthink = gpGlobals->time + 10.0;
}
if (UTIL_PointContents(pev->origin) != CONTENTS_WATER)
{
UTIL_Sparks( pev->origin );
}
}
if ( g_pGameRules->IsMultiplayer() )
{
SetThink( ExplodeThink );
pev->nextthink = gpGlobals->time + 0.1;
}
}
void CCrossbowBolt::BubbleThink( void )
{
pev->nextthink = gpGlobals->time + 0.1;
if (pev->waterlevel == 0)
return;
UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 1 );
}
void CCrossbowBolt::ExplodeThink( void )
{
int iContents = UTIL_PointContents ( pev->origin );
int iScale;
pev->dmg = 40;
iScale = 10;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_EXPLOSION);
WRITE_COORD( pev->origin.x );
WRITE_COORD( pev->origin.y );
WRITE_COORD( pev->origin.z );
if (iContents != CONTENTS_WATER)
{
WRITE_SHORT( g_sModelIndexFireball );
}
else
{
WRITE_SHORT( g_sModelIndexWExplosion );
}
WRITE_BYTE( iScale ); // scale * 10
WRITE_BYTE( 15 ); // framerate
WRITE_BYTE( TE_EXPLFLAG_NONE );
MESSAGE_END();
entvars_t *pevOwner;
if ( pev->owner )
pevOwner = VARS( pev->owner );
else
pevOwner = NULL;
pev->owner = NULL; // can't traceline attack owner if this is set
::RadiusDamage( pev->origin, pev, pevOwner, pev->dmg, 128, CLASS_NONE, DMG_BLAST | DMG_ALWAYSGIB );
UTIL_Remove(this);
}
enum crossbow_e {
CROSSBOW_IDLE1 = 0, // full
CROSSBOW_IDLE2, // empty
CROSSBOW_FIDGET1, // full
CROSSBOW_FIDGET2, // empty
CROSSBOW_FIRE1, // full
CROSSBOW_FIRE2, // reload
CROSSBOW_FIRE3, // empty
CROSSBOW_RELOAD, // from empty
CROSSBOW_DRAW1, // full
CROSSBOW_DRAW2, // empty
CROSSBOW_HOLSTER1, // full
CROSSBOW_HOLSTER2, // empty
};
class CCrossbow : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( ) { return 3; }
int GetItemInfo(ItemInfo *p);
void FireBolt( void );
void FireSniperBolt( void );
void PrimaryAttack( void );
void SecondaryAttack( void );
int AddToPlayer( CBasePlayer *pPlayer );
BOOL Deploy( );
void Holster( );
void Reload( void );
void WeaponIdle( void );
int m_fInZoom; // don't save this
};
LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow );
void CCrossbow::Spawn( )
{
Precache( );
m_iId = WEAPON_CROSSBOW;
SET_MODEL(ENT(pev), "models/w_crossbow.mdl");
m_iDefaultAmmo = CROSSBOW_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
int CCrossbow::AddToPlayer( CBasePlayer *pPlayer )
{
if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
WRITE_BYTE( m_iId );
MESSAGE_END();
return TRUE;
}
return FALSE;
}
void CCrossbow::Precache( void )
{
PRECACHE_MODEL("models/w_crossbow.mdl");
PRECACHE_MODEL("models/v_crossbow.mdl");
PRECACHE_MODEL("models/p_crossbow.mdl");
PRECACHE_SOUND("weapons/xbow_fire1.wav");
PRECACHE_SOUND("weapons/xbow_reload1.wav");
UTIL_PrecacheOther( "crossbow_bolt" );
}
int CCrossbow::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "bolts";
p->iMaxAmmo1 = BOLT_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = CROSSBOW_MAX_CLIP;
p->iSlot = 2;
p->iPosition = 2;
p->iId = WEAPON_CROSSBOW;
p->iFlags = 0;
p->iWeight = CROSSBOW_WEIGHT;
return 1;
}
BOOL CCrossbow::Deploy( )
{
if (m_iClip)
return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW1, "bow" );
return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW2, "bow" );
}
void CCrossbow::Holster( )
{
m_fInReload = FALSE;// cancel any reload in progress.
if ( m_fInZoom )
{
SecondaryAttack( );
}
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
if (m_iClip)
SendWeaponAnim( CROSSBOW_HOLSTER1 );
else
SendWeaponAnim( CROSSBOW_HOLSTER2 );
}
void CCrossbow::PrimaryAttack( void )
{
if ( m_fInZoom && g_pGameRules->IsMultiplayer() )
{
FireSniperBolt();
return;
}
FireBolt();
}
// this function only gets called in multiplayer
void CCrossbow::FireSniperBolt()
{
m_flNextPrimaryAttack = gpGlobals->time + 0.75;
if (m_iClip == 0)
{
PlayEmptySound( );
return;
}
TraceResult tr;
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_iClip--;
// make twang sound
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/xbow_fire1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));
if (m_iClip)
{
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));
SendWeaponAnim( CROSSBOW_FIRE1 );
}
else if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0)
{
SendWeaponAnim( CROSSBOW_FIRE3 );
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle;
UTIL_MakeVectors( anglesAim );
Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2;
Vector vecDir = gpGlobals->v_forward;
UTIL_TraceLine(vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, m_pPlayer->edict(), &tr);
if ( tr.pHit->v.takedamage )
{
switch( RANDOM_LONG(0,1) )
{
case 0:
EMIT_SOUND( tr.pHit, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break;
case 1:
EMIT_SOUND( tr.pHit, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break;
}
ClearMultiDamage( );
CBaseEntity::Instance(tr.pHit)->TraceAttack(m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB );
ApplyMultiDamage( pev, m_pPlayer->pev );
}
else
{
// create a bolt
CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate();
pBolt->pev->origin = tr.vecEndPos - vecDir * 10;
pBolt->pev->angles = UTIL_VecToAngles( vecDir );
pBolt->pev->solid = SOLID_NOT;
pBolt->SetTouch( NULL );
pBolt->SetThink( SUB_Remove );
EMIT_SOUND( pBolt->edict(), CHAN_WEAPON, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM );
if (UTIL_PointContents(tr.vecEndPos) != CONTENTS_WATER)
{
UTIL_Sparks( tr.vecEndPos );
}
if ( FClassnameIs( tr.pHit, "worldspawn" ) )
{
// let the bolt sit around for a while if it hit static architecture
pBolt->pev->nextthink = gpGlobals->time + 5.0;
}
else
{
pBolt->pev->nextthink = gpGlobals->time;
}
}
}
void CCrossbow::FireBolt()
{
TraceResult tr;
if (m_iClip == 0)
{
PlayEmptySound( );
return;
}
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_iClip--;
// make twang sound
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/xbow_fire1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));
if (m_iClip)
{
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));
SendWeaponAnim( CROSSBOW_FIRE1 );
}
else if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0)
{
SendWeaponAnim( CROSSBOW_FIRE3 );
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle;
UTIL_MakeVectors( anglesAim );
// Vector vecSrc = pev->origin + gpGlobals->v_up * 16 + gpGlobals->v_forward * 20 + gpGlobals->v_right * 4;
anglesAim.x = -anglesAim.x;
Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2;
Vector vecDir = gpGlobals->v_forward;
//CBaseEntity *pBolt = CBaseEntity::Create( "crossbow_bolt", vecSrc, anglesAim, m_pPlayer->edict() );
CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate();
pBolt->pev->origin = vecSrc;
pBolt->pev->angles = anglesAim;
pBolt->pev->owner = m_pPlayer->edict();
if (m_pPlayer->pev->waterlevel == 3)
{
pBolt->pev->velocity = vecDir * BOLT_WATER_VELOCITY;
pBolt->pev->speed = BOLT_WATER_VELOCITY;
}
else
{
pBolt->pev->velocity = vecDir * BOLT_AIR_VELOCITY;
pBolt->pev->speed = BOLT_AIR_VELOCITY;
}
pBolt->pev->avelocity.z = 10;
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_flNextPrimaryAttack = gpGlobals->time + 0.75;
m_flNextSecondaryAttack = gpGlobals->time + 0.75;
if (m_iClip != 0)
m_flTimeWeaponIdle = gpGlobals->time + 5.0;
else
m_flTimeWeaponIdle = 0.75;
m_pPlayer->pev->punchangle.x -= 2;
}
void CCrossbow::SecondaryAttack()
{
if (m_fInZoom)
{
m_pPlayer->m_iFOV = 0; // 0 means reset to default fov
m_fInZoom = 0;
}
else
{
m_pPlayer->m_iFOV = 20;
m_fInZoom = 1;
}
pev->nextthink = gpGlobals->time + 0.1;
m_flNextSecondaryAttack = gpGlobals->time + 1.0;
}
void CCrossbow::Reload( void )
{
if ( m_fInZoom )
{
SecondaryAttack();
}
if (DefaultReload( 5, CROSSBOW_RELOAD, 4.5 ))
{
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));
}
}
void CCrossbow::WeaponIdle( void )
{
m_pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES ); // get the autoaim vector but ignore it; used for autoaim crosshair in DM
ResetEmptySound( );
if (m_flTimeWeaponIdle < gpGlobals->time)
{
float flRand = RANDOM_FLOAT(0, 1);
if (flRand <= 0.75)
{
if (m_iClip)
{
SendWeaponAnim( CROSSBOW_IDLE1 );
}
else
{
SendWeaponAnim( CROSSBOW_IDLE2 );
}
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
}
else
{
if (m_iClip)
{
SendWeaponAnim( CROSSBOW_FIDGET1 );
m_flTimeWeaponIdle = gpGlobals->time + 90.0 / 30.0;
}
else
{
SendWeaponAnim( CROSSBOW_FIDGET2 );
m_flTimeWeaponIdle = gpGlobals->time + 80.0 / 30.0;
}
}
}
}
class CCrossbowAmmo : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_crossbow_clip.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_crossbow_clip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
if (pOther->GiveAmmo( AMMO_CROSSBOWCLIP_GIVE, "bolts", BOLT_MAX_CARRY ) != -1)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
return TRUE;
}
return FALSE;
}
};
LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo );
#endif

334
dlls/crowbar.cpp Normal file
View File

@ -0,0 +1,334 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "gamerules.h"
#define CROWBAR_BODYHIT_VOLUME 128
#define CROWBAR_WALLHIT_VOLUME 512
class CCrowbar : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 1; }
void EXPORT SwingAgain( void );
void EXPORT Smack( void );
int GetItemInfo(ItemInfo *p);
void PrimaryAttack( void );
int Swing( int fFirst );
BOOL Deploy( void );
void Holster( void );
int m_iSwing;
TraceResult m_trHit;
};
LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar );
enum gauss_e {
CROWBAR_IDLE = 0,
CROWBAR_DRAW,
CROWBAR_HOLSTER,
CROWBAR_ATTACK1HIT,
CROWBAR_ATTACK1MISS,
CROWBAR_ATTACK2MISS,
CROWBAR_ATTACK2HIT,
CROWBAR_ATTACK3MISS,
CROWBAR_ATTACK3HIT
};
void CCrowbar::Spawn( )
{
Precache( );
m_iId = WEAPON_CROWBAR;
SET_MODEL(ENT(pev), "models/w_crowbar.mdl");
m_iClip = -1;
FallInit();// get ready to fall down.
}
void CCrowbar::Precache( void )
{
PRECACHE_MODEL("models/v_crowbar.mdl");
PRECACHE_MODEL("models/w_crowbar.mdl");
PRECACHE_MODEL("models/p_crowbar.mdl");
PRECACHE_SOUND("weapons/cbar_hit1.wav");
PRECACHE_SOUND("weapons/cbar_hit2.wav");
PRECACHE_SOUND("weapons/cbar_hitbod1.wav");
PRECACHE_SOUND("weapons/cbar_hitbod2.wav");
PRECACHE_SOUND("weapons/cbar_hitbod3.wav");
PRECACHE_SOUND("weapons/cbar_miss1.wav");
}
int CCrowbar::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = NULL;
p->iMaxAmmo1 = -1;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 0;
p->iPosition = 0;
p->iId = WEAPON_CROWBAR;
p->iWeight = CROWBAR_WEIGHT;
return 1;
}
BOOL CCrowbar::Deploy( )
{
return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" );
}
void CCrowbar::Holster( )
{
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
SendWeaponAnim( CROWBAR_HOLSTER );
}
void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity )
{
int i, j, k;
float distance;
float *minmaxs[2] = {mins, maxs};
TraceResult tmpTrace;
Vector vecHullEnd = tr.vecEndPos;
Vector vecEnd;
distance = 1e6f;
vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace );
if ( tmpTrace.flFraction < 1.0 )
{
tr = tmpTrace;
return;
}
for ( i = 0; i < 2; i++ )
{
for ( j = 0; j < 2; j++ )
{
for ( k = 0; k < 2; k++ )
{
vecEnd.x = vecHullEnd.x + minmaxs[i][0];
vecEnd.y = vecHullEnd.y + minmaxs[j][1];
vecEnd.z = vecHullEnd.z + minmaxs[k][2];
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace );
if ( tmpTrace.flFraction < 1.0 )
{
float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length();
if ( thisDistance < distance )
{
tr = tmpTrace;
distance = thisDistance;
}
}
}
}
}
}
void CCrowbar::PrimaryAttack()
{
if (! Swing( 1 ))
{
SetThink( SwingAgain );
pev->nextthink = gpGlobals->time + 0.1;
}
}
void CCrowbar::Smack( )
{
DecalGunshot( &m_trHit, BULLET_PLAYER_CROWBAR );
}
void CCrowbar::SwingAgain( void )
{
Swing( 0 );
}
int CCrowbar::Swing( int fFirst )
{
int fDidHit = FALSE;
TraceResult tr;
UTIL_MakeVectors (m_pPlayer->pev->v_angle);
Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecEnd = vecSrc + gpGlobals->v_forward * 32;
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );
if ( tr.flFraction >= 1.0 )
{
UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr );
if ( tr.flFraction < 1.0 )
{
// Calculate the point of intersection of the line (or hull) and the object we hit
// This is and approximation of the "best" intersection
CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit );
if ( !pHit || pHit->IsBSPModel() )
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() );
vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space)
}
}
if ( tr.flFraction >= 1.0 )
{
if (fFirst)
{
// miss
switch( (m_iSwing++) % 3 )
{
case 0:
SendWeaponAnim( CROWBAR_ATTACK1MISS ); break;
case 1:
SendWeaponAnim( CROWBAR_ATTACK2MISS ); break;
case 2:
SendWeaponAnim( CROWBAR_ATTACK3MISS ); break;
}
m_flNextPrimaryAttack = gpGlobals->time + 0.5;
// play wiff or swish sound
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xF));
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
}
}
else
{
// hit
fDidHit = TRUE;
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
switch( ((m_iSwing++) % 2) + 1 )
{
case 0:
SendWeaponAnim( CROWBAR_ATTACK1HIT ); break;
case 1:
SendWeaponAnim( CROWBAR_ATTACK2HIT ); break;
case 2:
SendWeaponAnim( CROWBAR_ATTACK3HIT ); break;
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
ClearMultiDamage( );
if ( (m_flNextPrimaryAttack + 1 < gpGlobals->time) || g_pGameRules->IsMultiplayer() )
{
// first swing does full damage
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB );
}
else
{
// subsequent swings do half
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar / 2, gpGlobals->v_forward, &tr, DMG_CLUB );
}
ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev );
m_flNextPrimaryAttack = gpGlobals->time + 0.25;
// play thwack, smack, or dong sound
float flVol = 1.0;
int fHitWorld = TRUE;
if (pEntity)
{
if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE)
{
// play thwack or smack sound
switch( RANDOM_LONG(0,2) )
{
case 0:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break;
case 1:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break;
case 2:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break;
}
m_pPlayer->m_iWeaponVolume = CROWBAR_BODYHIT_VOLUME;
if (!pEntity->IsAlive() )
return TRUE;
else
flVol = 0.1;
fHitWorld = FALSE;
}
}
// play texture hit sound
// UNDONE: Calculate the correct point of intersection when we hit with the hull instead of the line
if (fHitWorld)
{
float fvolbar = TEXTURETYPE_PlaySound(&tr, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_PLAYER_CROWBAR);
if ( g_pGameRules->IsMultiplayer() )
{
// override the volume here, cause we don't play texture sounds in multiplayer,
// and fvolbar is going to be 0 from the above call.
fvolbar = 1;
}
// also play crowbar strike
switch( RANDOM_LONG(0,1) )
{
case 0:
//UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
break;
case 1:
//UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
break;
}
}
// delay the decal a bit
m_trHit = tr;
SetThink( Smack );
pev->nextthink = gpGlobals->time + 0.2;
m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME;
}
return fDidHit;
}

75
dlls/decals.h Normal file
View File

@ -0,0 +1,75 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef DECALS_H
#define DECALS_H
//
// Dynamic Decals
//
enum decal_e
{
DECAL_GUNSHOT1 = 0,
DECAL_GUNSHOT2,
DECAL_GUNSHOT3,
DECAL_GUNSHOT4,
DECAL_GUNSHOT5,
DECAL_LAMBDA1,
DECAL_LAMBDA2,
DECAL_LAMBDA3,
DECAL_LAMBDA4,
DECAL_LAMBDA5,
DECAL_LAMBDA6,
DECAL_SCORCH1,
DECAL_SCORCH2,
DECAL_BLOOD1,
DECAL_BLOOD2,
DECAL_BLOOD3,
DECAL_BLOOD4,
DECAL_BLOOD5,
DECAL_BLOOD6,
DECAL_YBLOOD1,
DECAL_YBLOOD2,
DECAL_YBLOOD3,
DECAL_YBLOOD4,
DECAL_YBLOOD5,
DECAL_YBLOOD6,
DECAL_GLASSBREAK1,
DECAL_GLASSBREAK2,
DECAL_GLASSBREAK3,
DECAL_BIGSHOT1,
DECAL_BIGSHOT2,
DECAL_BIGSHOT3,
DECAL_BIGSHOT4,
DECAL_BIGSHOT5,
DECAL_SPIT1,
DECAL_SPIT2,
DECAL_BPROOF1, // Bulletproof glass decal
DECAL_GARGSTOMP1, // Gargantua stomp crack
DECAL_SMALLSCORCH1, // Small scorch mark
DECAL_SMALLSCORCH2, // Small scorch mark
DECAL_SMALLSCORCH3, // Small scorch mark
DECAL_MOMMABIRTH, // Big momma birth splatter
DECAL_MOMMASPLAT,
};
typedef struct
{
char *name;
int index;
} DLL_DECALLIST;
extern DLL_DECALLIST gDecals[];
#endif // DECALS_H

1026
dlls/doors.cpp Normal file

File diff suppressed because it is too large Load Diff

33
dlls/doors.h Normal file
View File

@ -0,0 +1,33 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef DOORS_H
#define DOORS_H
// doors
#define SF_DOOR_ROTATE_Y 0
#define SF_DOOR_START_OPEN 1
#define SF_DOOR_ROTATE_BACKWARDS 2
#define SF_DOOR_PASSABLE 8
#define SF_DOOR_ONEWAY 16
#define SF_DOOR_NO_AUTO_RETURN 32
#define SF_DOOR_ROTATE_Z 64
#define SF_DOOR_ROTATE_X 128
#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button.
#define SF_DOOR_NOMONSTERS 512 // Monster can't open
#define SF_DOOR_SILENT 0x80000000
#endif //DOORS_H

2264
dlls/effects.cpp Normal file

File diff suppressed because it is too large Load Diff

209
dlls/effects.h Normal file
View File

@ -0,0 +1,209 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef EFFECTS_H
#define EFFECTS_H
#define SF_BEAM_STARTON 0x0001
#define SF_BEAM_TOGGLE 0x0002
#define SF_BEAM_RANDOM 0x0004
#define SF_BEAM_RING 0x0008
#define SF_BEAM_SPARKSTART 0x0010
#define SF_BEAM_SPARKEND 0x0020
#define SF_BEAM_DECALS 0x0040
#define SF_BEAM_SHADEIN 0x0080
#define SF_BEAM_SHADEOUT 0x0100
#define SF_BEAM_TEMPORARY 0x8000
#define SF_SPRITE_STARTON 0x0001
#define SF_SPRITE_ONCE 0x0002
#define SF_SPRITE_TEMPORARY 0x8000
class CSprite : public CPointEntity
{
public:
void Spawn( void );
void Precache( void );
int ObjectCaps( void )
{
int flags = 0;
if ( pev->spawnflags & SF_SPRITE_TEMPORARY )
flags = FCAP_DONT_SAVE;
return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags;
}
void EXPORT AnimateThink( void );
void EXPORT ExpandThink( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void Animate( float frames );
void Expand( float scaleSpeed, float fadeSpeed );
void SpriteInit( const char *pSpriteName, const Vector &origin );
inline void SetAttachment( edict_t *pEntity, int attachment )
{
if ( pEntity )
{
pev->skin = ENTINDEX(pEntity);
pev->body = attachment;
pev->aiment = pEntity;
pev->movetype = MOVETYPE_FOLLOW;
}
}
void TurnOff( void );
void TurnOn( void );
inline float Frames( void ) { return m_maxFrame; }
inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx )
{
pev->rendermode = rendermode;
pev->rendercolor.x = r;
pev->rendercolor.y = g;
pev->rendercolor.z = b;
pev->renderamt = a;
pev->renderfx = fx;
}
inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; }
inline void SetScale( float scale ) { pev->scale = scale; }
inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
inline void SetBrightness( int brightness ) { pev->renderamt = brightness; }
inline void AnimateAndDie( float framerate )
{
SetThink(AnimateUntilDead);
pev->framerate = framerate;
pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate);
pev->nextthink = gpGlobals->time;
}
void EXPORT AnimateUntilDead( void );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
static CSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate );
private:
float m_lastTime;
float m_maxFrame;
};
class CBeam : public CBaseEntity
{
public:
void Spawn( void );
void Precache( void );
int ObjectCaps( void )
{
int flags = 0;
if ( pev->spawnflags & SF_BEAM_TEMPORARY )
flags = FCAP_DONT_SAVE;
return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags;
}
void EXPORT TriggerTouch( CBaseEntity *pOther );
// These functions are here to show the way beams are encoded as entities.
// Encoding beams as entities simplifies their management in the client/server architecture
inline void SetType( int type ) { pev->rendermode = (pev->rendermode & 0xF0) | (type&0x0F); }
inline void SetFlags( int flags ) { pev->rendermode = (pev->rendermode & 0x0F) | (flags&0xF0); }
inline void SetStartPos( const Vector& pos ) { pev->origin = pos; }
inline void SetEndPos( const Vector& pos ) { pev->angles = pos; }
void SetStartEntity( int entityIndex );
void SetEndEntity( int entityIndex );
inline void SetStartAttachment( int attachment ) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment&0xF)<<12); }
inline void SetEndAttachment( int attachment ) { pev->skin = (pev->skin & 0x0FFF) | ((attachment&0xF)<<12); }
inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; }
inline void SetWidth( int width ) { pev->scale = width; }
inline void SetNoise( int amplitude ) { pev->body = amplitude; }
inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
inline void SetBrightness( int brightness ) { pev->renderamt = brightness; }
inline void SetFrame( float frame ) { pev->frame = frame; }
inline void SetScrollRate( int speed ) { pev->animtime = speed; }
inline int GetType( void ) { return pev->rendermode & 0x0F; }
inline int GetFlags( void ) { return pev->rendermode & 0xF0; }
inline int GetStartEntity( void ) { return pev->sequence & 0xFFF; }
inline int GetEndEntity( void ) { return pev->skin & 0xFFF; }
const Vector &GetStartPos( void );
const Vector &GetEndPos( void );
Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam
inline int GetTexture( void ) { return pev->modelindex; }
inline int GetWidth( void ) { return pev->scale; }
inline int GetNoise( void ) { return pev->body; }
// inline void GetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
inline int GetBrightness( void ) { return pev->renderamt; }
inline int GetFrame( void ) { return pev->frame; }
inline int GetScrollRate( void ) { return pev->animtime; }
// Call after you change start/end positions
void RelinkBeam( void );
// void SetObjectCollisionBox( void );
void DoSparks( const Vector &start, const Vector &end );
CBaseEntity *RandomTargetname( const char *szName );
void BeamDamage( TraceResult *ptr );
// Init after BeamCreate()
void BeamInit( const char *pSpriteName, int width );
void PointsInit( const Vector &start, const Vector &end );
void PointEntInit( const Vector &start, int endIndex );
void EntsInit( int startIndex, int endIndex );
void HoseInit( const Vector &start, const Vector &direction );
static CBeam *BeamCreate( const char *pSpriteName, int width );
inline void LiveForTime( float time ) { SetThink(SUB_Remove); pev->nextthink = gpGlobals->time + time; }
inline void BeamDamageInstant( TraceResult *ptr, float damage )
{
pev->dmg = damage;
pev->dmgtime = gpGlobals->time - 1;
BeamDamage(ptr);
}
};
#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out
#define SF_MESSAGE_ALL 0x0002 // Send to all clients
class CLaser : public CBeam
{
public:
void Spawn( void );
void Precache( void );
void KeyValue( KeyValueData *pkvd );
void TurnOn( void );
void TurnOff( void );
int IsOn( void );
void FireAtPoint( TraceResult &point );
void EXPORT StrikeThink( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
CSprite *m_pSprite;
int m_iszSpriteName;
Vector m_firePosition;
};
#endif //EFFECTS_H

623
dlls/egon.cpp Normal file
View File

@ -0,0 +1,623 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "effects.h"
#include "customentity.h"
#include "gamerules.h"
#define EGON_PRIMARY_VOLUME 450
#define EGON_BEAM_SPRITE "sprites/xbeam1.spr"
#define EGON_FLARE_SPRITE "sprites/XSpark1.spr"
#define EGON_SOUND_OFF "weapons/egon_off1.wav"
#define EGON_SOUND_RUN "weapons/egon_run3.wav"
#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav"
#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes
#define EGON_SWITCH_WIDE_TIME 1.5
enum egon_e {
EGON_IDLE1 = 0,
EGON_FIDGET1,
EGON_ALTFIREON,
EGON_ALTFIRECYCLE,
EGON_ALTFIREOFF,
EGON_FIRE1,
EGON_FIRE2,
EGON_FIRE3,
EGON_FIRE4,
EGON_DRAW,
EGON_HOLSTER
};
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( void );
void CreateEffect( void );
void UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend );
void DestroyEffect( void );
void EndAttack( void );
void Attack( void );
void PrimaryAttack( 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 );
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;
};
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( )
{
Precache( );
m_iId = WEAPON_EGON;
SET_MODEL(ENT(pev), "models/w_egon.mdl");
m_iDefaultAmmo = EGON_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CEgon::Precache( void )
{
PRECACHE_MODEL("models/w_egon.mdl");
PRECACHE_MODEL("models/v_egon.mdl");
PRECACHE_MODEL("models/p_egon.mdl");
PRECACHE_MODEL("models/w_9mmclip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
PRECACHE_SOUND( EGON_SOUND_OFF );
PRECACHE_SOUND( EGON_SOUND_RUN );
PRECACHE_SOUND( EGON_SOUND_STARTUP );
PRECACHE_MODEL( EGON_BEAM_SPRITE );
PRECACHE_MODEL( EGON_FLARE_SPRITE );
PRECACHE_SOUND ("weapons/357_cock1.wav");
}
BOOL CEgon::Deploy( void )
{
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( void )
{
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
// m_flTimeWeaponIdle = gpGlobals->time + UTIL_RandomFloat ( 10, 15 );
SendWeaponAnim( EGON_HOLSTER );
if ( m_fireState != FIRE_OFF )
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::Attack( void )
{
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
if ( 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( );
switch( m_fireState )
{
case FIRE_OFF:
{
if ( !HasAmmo() )
{
m_flNextPrimaryAttack = 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;
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, 100 );
}
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 )
{
if ( m_fireMode == FIRE_WIDE )
{
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 );
}
else
{
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 );
}
m_shootTime = 0;
}
if ( !HasAmmo() )
{
EndAttack();
m_fireState = FIRE_OFF;
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + 1.0;
}
}
break;
}
}
void CEgon::PrimaryAttack( void )
{
m_fireMode = FIRE_WIDE;
Attack();
}
void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir )
{
Vector vecDest = vecOrigSrc + vecDir * 2048;
edict_t *pentIgnore;
TraceResult tr;
pentIgnore = m_pPlayer->edict();
Vector tmpSrc = vecOrigSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3;
// ALERT( at_console, "." );
UTIL_TraceLine( vecOrigSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr );
if (tr.fAllSolid)
return;
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;
}
}
float timedist;
switch ( m_fireMode )
{
case FIRE_NARROW:
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();
}
timedist = ( pev->dmgtime - gpGlobals->time ) / GetPulseInterval();
break;
case FIRE_WIDE:
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;
}
}
timedist = ( pev->dmgtime - gpGlobals->time ) / GetDischargeInterval();
break;
}
if ( timedist < 0 )
timedist = 0;
else if ( timedist > 1 )
timedist = 1;
timedist = 1-timedist;
UpdateEffect( tmpSrc, tr.vecEndPos, timedist );
}
void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend )
{
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 )
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::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 = m_flNextSecondaryAttack = gpGlobals->time + 0.5;
DestroyEffect();
}
class CEgonAmmo : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_chainammo.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_chainammo.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
return TRUE;
}
return FALSE;
}
};
LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo );
#endif

123
dlls/enginecallback.h Normal file
View File

@ -0,0 +1,123 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef ENGINECALLBACK_H
#define ENGINECALLBACK_H
// Must be provided by user of this code
extern enginefuncs_t g_engfuncs;
// The actual engine callbacks
#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId)
#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel)
#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound)
#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric)
#define SET_MODEL (*g_engfuncs.pfnSetModel)
#define MODEL_INDEX (*g_engfuncs.pfnModelIndex)
#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames)
#define SET_SIZE (*g_engfuncs.pfnSetSize)
#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel)
#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms)
#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms)
#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw)
#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles)
#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin)
#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw)
#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch)
#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors)
#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity)
#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity)
#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity)
#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic)
#define ENT_IS_ON_FLOOR (*g_engfuncs.pfnEntIsOnFloor)
#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor)
#define WALK_MOVE (*g_engfuncs.pfnWalkMove)
#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin)
#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound)
#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg)
#define TRACE_LINE (*g_engfuncs.pfnTraceLine)
#define TRACE_TOSS (*g_engfuncs.pfnTraceToss)
#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull)
#define TRACE_HULL (*g_engfuncs.pfnTraceHull)
#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector)
#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand)
#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute)
#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand)
#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect)
#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle)
#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex)
#define POINT_CONTENTS (*g_engfuncs.pfnPointContents)
#define CRC32_INIT (*g_engfuncs.pfnCRC32_Init)
#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC32_ProcessBuffer)
#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC32_ProcessByte)
#define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final)
#define RANDOM_LONG (*g_engfuncs.pfnRandomLong)
#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat)
inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL ) {
(*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed);
}
#define MESSAGE_END (*g_engfuncs.pfnMessageEnd)
#define WRITE_BYTE (*g_engfuncs.pfnWriteByte)
#define WRITE_CHAR (*g_engfuncs.pfnWriteChar)
#define WRITE_SHORT (*g_engfuncs.pfnWriteShort)
#define WRITE_LONG (*g_engfuncs.pfnWriteLong)
#define WRITE_ANGLE (*g_engfuncs.pfnWriteAngle)
#define WRITE_COORD (*g_engfuncs.pfnWriteCoord)
#define WRITE_STRING (*g_engfuncs.pfnWriteString)
#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity)
#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister)
#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat)
#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString)
#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat)
#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString)
#define ALERT (*g_engfuncs.pfnAlertMessage)
#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf)
#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData)
inline void *GET_PRIVATE( edict_t *pent )
{
if ( pent )
return pent->pvPrivateData;
return NULL;
}
#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData)
//#define STRING (*g_engfuncs.pfnSzFromIndex)
#define ALLOC_STRING (*g_engfuncs.pfnAllocString)
#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString)
#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum)
#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere)
#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS)
#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound)
#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr)
#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg)
#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition)
#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName)
#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction)
#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture)
#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf)
#define CMD_ARGS (*g_engfuncs.pfnCmd_Args)
#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc)
#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv)
#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment)
#define SET_VIEW (*g_engfuncs.pfnSetView)
#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle)
#define LOAD_FILE_FOR_ME (*g_engfuncs.pfnLoadFileForMe)
#define FREE_FILE (*g_engfuncs.pfnFreeFile)
#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime)
#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir)
#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid)
#define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities)
#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer)
#endif //ENGINECALLBACK_H

273
dlls/explode.cpp Normal file
View File

@ -0,0 +1,273 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== explode.cpp ========================================================
Explosion-related code
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "decals.h"
#include "explode.h"
// Spark Shower
class CShower : public CBaseEntity
{
void Spawn( void );
void Think( void );
void Touch( CBaseEntity *pOther );
int ObjectCaps( void ) { return FCAP_DONT_SAVE; }
};
LINK_ENTITY_TO_CLASS( spark_shower, CShower );
void CShower::Spawn( void )
{
pev->velocity = RANDOM_FLOAT( 200, 300 ) * pev->angles;
pev->velocity.x += RANDOM_FLOAT(-100.f,100.f);
pev->velocity.y += RANDOM_FLOAT(-100.f,100.f);
if ( pev->velocity.z >= 0 )
pev->velocity.z += 200;
else
pev->velocity.z -= 200;
pev->movetype = MOVETYPE_BOUNCE;
pev->gravity = 0.5;
pev->nextthink = gpGlobals->time + 0.1;
pev->solid = SOLID_NOT;
SET_MODEL( edict(), "models/grenade.mdl"); // Need a model, just use the grenade, we don't draw it anyway
UTIL_SetSize(pev, g_vecZero, g_vecZero );
pev->effects |= EF_NODRAW;
pev->speed = RANDOM_FLOAT( 0.5, 1.5 );
pev->angles = g_vecZero;
}
void CShower::Think( void )
{
UTIL_Sparks( pev->origin );
pev->speed -= 0.1;
if ( pev->speed > 0 )
pev->nextthink = gpGlobals->time + 0.1;
else
UTIL_Remove( this );
pev->flags &= ~FL_ONGROUND;
}
void CShower::Touch( CBaseEntity *pOther )
{
if ( pev->flags & FL_ONGROUND )
pev->velocity = pev->velocity * 0.1;
else
pev->velocity = pev->velocity * 0.6;
if ( (pev->velocity.x*pev->velocity.x+pev->velocity.y*pev->velocity.y) < 10.0 )
pev->speed = 0;
}
class CEnvExplosion : public CBaseMonster
{
public:
void Spawn( );
void EXPORT Smoke ( void );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
int m_iMagnitude;// how large is the fireball? how much damage?
int m_spriteScale; // what's the exact fireball sprite scale?
};
TYPEDESCRIPTION CEnvExplosion::m_SaveData[] =
{
DEFINE_FIELD( CEnvExplosion, m_iMagnitude, FIELD_INTEGER ),
DEFINE_FIELD( CEnvExplosion, m_spriteScale, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CEnvExplosion, CBaseMonster );
LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion );
void CEnvExplosion::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "iMagnitude"))
{
m_iMagnitude = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue( pkvd );
}
void CEnvExplosion::Spawn( void )
{
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
pev->movetype = MOVETYPE_NONE;
/*
if ( m_iMagnitude > 250 )
{
m_iMagnitude = 250;
}
*/
float flSpriteScale;
flSpriteScale = ( m_iMagnitude - 50) * 0.6;
/*
if ( flSpriteScale > 50 )
{
flSpriteScale = 50;
}
*/
if ( flSpriteScale < 10 )
{
flSpriteScale = 10;
}
m_spriteScale = (int)flSpriteScale;
}
void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
TraceResult tr;
pev->model = iStringNull;//invisible
pev->solid = SOLID_NOT;// intangible
Vector vecSpot;// trace starts here!
vecSpot = pev->origin + Vector ( 0 , 0 , 8 );
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr);
// Pull out of the wall a bit
if ( tr.flFraction != 1.0 )
{
pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (m_iMagnitude - 24) * 0.6);
}
else
{
pev->origin = pev->origin;
}
// draw decal
if (! ( pev->spawnflags & SF_ENVEXPLOSION_NODECAL))
{
if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 )
{
UTIL_DecalTrace( &tr, DECAL_SCORCH1 );
}
else
{
UTIL_DecalTrace( &tr, DECAL_SCORCH2 );
}
}
// draw fireball
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOFIREBALL ) )
{
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_EXPLOSION);
WRITE_COORD( pev->origin.x );
WRITE_COORD( pev->origin.y );
WRITE_COORD( pev->origin.z );
WRITE_SHORT( g_sModelIndexFireball );
WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10
WRITE_BYTE( 15 ); // framerate
WRITE_BYTE( TE_EXPLFLAG_NONE );
MESSAGE_END();
}
else
{
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_EXPLOSION);
WRITE_COORD( pev->origin.x );
WRITE_COORD( pev->origin.y );
WRITE_COORD( pev->origin.z );
WRITE_SHORT( g_sModelIndexFireball );
WRITE_BYTE( 0 ); // no sprite
WRITE_BYTE( 15 ); // framerate
WRITE_BYTE( TE_EXPLFLAG_NONE );
MESSAGE_END();
}
// do damage
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) )
{
RadiusDamage ( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST );
}
SetThink( Smoke );
pev->nextthink = gpGlobals->time + 0.3;
// draw sparks
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSPARKS ) )
{
int sparkCount = RANDOM_LONG(0,3);
for ( int i = 0; i < sparkCount; i++ )
{
Create( "spark_shower", pev->origin, tr.vecPlaneNormal, NULL );
}
}
}
void CEnvExplosion::Smoke( void )
{
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSMOKE ) )
{
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_SMOKE );
WRITE_COORD( pev->origin.x );
WRITE_COORD( pev->origin.y );
WRITE_COORD( pev->origin.z );
WRITE_SHORT( g_sModelIndexSmoke );
WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10
WRITE_BYTE( 12 ); // framerate
MESSAGE_END();
}
if ( !(pev->spawnflags & SF_ENVEXPLOSION_REPEATABLE) )
{
UTIL_Remove( this );
}
}
// HACKHACK -- create one of these and fake a keyvalue to get the right explosion setup
void ExplosionCreate( const Vector &center, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage )
{
KeyValueData kvd;
char buf[128];
CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, angles, pOwner );
sprintf( buf, "%3d", magnitude );
kvd.szKeyName = "iMagnitude";
kvd.szValue = buf;
pExplosion->KeyValue( &kvd );
if ( !doDamage )
pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE;
pExplosion->Spawn();
pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 );
}

32
dlls/explode.h Normal file
View File

@ -0,0 +1,32 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef EXPLODE_H
#define EXPLODE_H
#define SF_ENVEXPLOSION_NODAMAGE ( 1 << 0 ) // when set, ENV_EXPLOSION will not actually inflict damage
#define SF_ENVEXPLOSION_REPEATABLE ( 1 << 1 ) // can this entity be refired?
#define SF_ENVEXPLOSION_NOFIREBALL ( 1 << 2 ) // don't draw the fireball
#define SF_ENVEXPLOSION_NOSMOKE ( 1 << 3 ) // don't draw the smoke
#define SF_ENVEXPLOSION_NODECAL ( 1 << 4 ) // don't make a scorch mark
#define SF_ENVEXPLOSION_NOSPARKS ( 1 << 5 ) // don't make a scorch mark
extern DLL_GLOBAL short g_sModelIndexFireball;
extern DLL_GLOBAL short g_sModelIndexSmoke;
extern void ExplosionCreate( const Vector &center, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage );
#endif //EXPLODE_H

69
dlls/extdll.h Normal file
View File

@ -0,0 +1,69 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef EXTDLL_H
#define EXTDLL_H
//
// Global header file for extension DLLs
//
// Allow "DEBUG" in addition to default "_DEBUG"
#ifdef _DEBUG
#define DEBUG 1
#endif
// Silence certain warnings
#pragma warning(disable : 4244) // int or float down-conversion
#pragma warning(disable : 4305) // int or float data truncation
#pragma warning(disable : 4201) // nameless struct/union
#pragma warning(disable : 4514) // unreferenced inline function removed
#pragma warning(disable : 4100) // unreferenced formal parameter
// Prevent tons of unused windows definitions
#define WIN32_LEAN_AND_MEAN
#define NOWINRES
#define NOSERVICE
#define NOMCX
#define NOIME
#include "WINDOWS.H"
// Misc C-runtime library headers
#include "STDIO.H"
#include "STDLIB.H"
#include "MATH.H"
// Header file containing definition of globalvars_t and entvars_t
typedef int func_t; //
typedef int string_t; // from engine's pr_comp.h;
typedef float vec_t; // needed before including progdefs.h
// Vector class
#include "vector.h"
// Defining it as a (bogus) struct helps enforce type-checking
#define vec3_t Vector
// Shared engine/DLL constants
#include "const.h"
#include "progs.h"
// Shared header describing protocol between engine and DLLs
#include "eiface.h"
// Shared header between the client DLL and the game DLLs
#include "cdll_dll.h"
#endif //EXTDLL_H

998
dlls/func_break.cpp Normal file
View File

@ -0,0 +1,998 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== bmodels.cpp ========================================================
spawn, think, and use functions for entities that use brush models
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "saverestore.h"
#include "func_break.h"
#include "decals.h"
#include "explode.h"
extern DLL_GLOBAL Vector g_vecAttackDir;
// =================== FUNC_Breakable ==============================================
// Just add more items to the bottom of this array and they will automagically be supported
// This is done instead of just a classname in the FGD so we can control which entities can
// be spawned, and still remain fairly flexible
const char *CBreakable::pSpawnObjects[] =
{
NULL, // 0
"item_battery", // 1
"item_healthkit", // 2
"weapon_9mmhandgun",// 3
"ammo_9mmclip", // 4
"weapon_9mmAR", // 5
"ammo_9mmAR", // 6
"ammo_ARgrenades", // 7
"weapon_shotgun", // 8
"ammo_buckshot", // 9
"weapon_crossbow", // 10
"ammo_crossbow", // 11
"weapon_357", // 12
"ammo_357", // 13
"weapon_rpg", // 14
"ammo_rpgclip", // 15
"ammo_gaussclip", // 16
"weapon_handgrenade",// 17
"weapon_tripmine", // 18
"weapon_satchel", // 19
"weapon_snark", // 20
"weapon_hornetgun", // 21
};
void CBreakable::KeyValue( KeyValueData* pkvd )
{
// UNDONE_WC: explicitly ignoring these fields, but they shouldn't be in the map file!
if (FStrEq(pkvd->szKeyName, "explosion"))
{
if (!stricmp(pkvd->szValue, "directed"))
m_Explosion = expDirected;
else if (!stricmp(pkvd->szValue, "random"))
m_Explosion = expRandom;
else
m_Explosion = expRandom;
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "material"))
{
int i = atoi( pkvd->szValue);
// 0:glass, 1:metal, 2:flesh, 3:wood
if ((i < 0) || (i >= matLastMaterial))
m_Material = matWood;
else
m_Material = (Materials)i;
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "deadmodel"))
{
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "shards"))
{
// m_iShards = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "gibmodel") )
{
m_iszGibModel = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "spawnobject") )
{
int object = atoi( pkvd->szValue );
if ( object > 0 && object < ARRAYSIZE(pSpawnObjects) )
m_iszSpawnObject = MAKE_STRING( pSpawnObjects[object] );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "explodemagnitude") )
{
ExplosionSetMagnitude( atoi( pkvd->szValue ) );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "lip") )
pkvd->fHandled = TRUE;
else
CBaseDelay::KeyValue( pkvd );
}
//
// func_breakable - bmodel that breaks into pieces after taking damage
//
LINK_ENTITY_TO_CLASS( func_breakable, CBreakable );
TYPEDESCRIPTION CBreakable::m_SaveData[] =
{
DEFINE_FIELD( CBreakable, m_Material, FIELD_INTEGER ),
DEFINE_FIELD( CBreakable, m_Explosion, FIELD_INTEGER ),
// Don't need to save/restore these because we precache after restore
// DEFINE_FIELD( CBreakable, m_idShard, FIELD_INTEGER ),
DEFINE_FIELD( CBreakable, m_angle, FIELD_FLOAT ),
DEFINE_FIELD( CBreakable, m_iszGibModel, FIELD_STRING ),
DEFINE_FIELD( CBreakable, m_iszSpawnObject, FIELD_STRING ),
// Explosion magnitude is stored in pev->impulse
};
IMPLEMENT_SAVERESTORE( CBreakable, CBaseEntity );
void CBreakable::Spawn( void )
{
Precache( );
if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) )
pev->takedamage = DAMAGE_NO;
else
pev->takedamage = DAMAGE_YES;
pev->solid = SOLID_BSP;
pev->movetype = MOVETYPE_PUSH;
m_angle = pev->angles.y;
pev->angles.y = 0;
SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world.
SetTouch( BreakTouch );
if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) // Only break on trigger
SetTouch( NULL );
// Flag unbreakable glass as "worldbrush" so it will block ALL tracelines
if ( !IsBreakable() && pev->rendermode != kRenderNormal )
pev->flags |= FL_WORLDBRUSH;
}
const char *CBreakable::pSoundsWood[] =
{
"debris/wood1.wav",
"debris/wood2.wav",
"debris/wood3.wav",
};
const char *CBreakable::pSoundsFlesh[] =
{
"debris/flesh1.wav",
"debris/flesh2.wav",
"debris/flesh3.wav",
"debris/flesh5.wav",
"debris/flesh6.wav",
"debris/flesh7.wav",
};
const char *CBreakable::pSoundsMetal[] =
{
"debris/metal1.wav",
"debris/metal2.wav",
"debris/metal3.wav",
};
const char *CBreakable::pSoundsConcrete[] =
{
"debris/concrete1.wav",
"debris/concrete2.wav",
"debris/concrete3.wav",
};
const char *CBreakable::pSoundsGlass[] =
{
"debris/glass1.wav",
"debris/glass2.wav",
"debris/glass3.wav",
};
const char **CBreakable::MaterialSoundList( Materials precacheMaterial, int &soundCount )
{
const char **pSoundList = NULL;
switch ( precacheMaterial )
{
case matWood:
pSoundList = pSoundsWood;
soundCount = ARRAYSIZE(pSoundsWood);
break;
case matFlesh:
pSoundList = pSoundsFlesh;
soundCount = ARRAYSIZE(pSoundsFlesh);
break;
case matComputer:
case matUnbreakableGlass:
case matGlass:
pSoundList = pSoundsGlass;
soundCount = ARRAYSIZE(pSoundsGlass);
break;
case matMetal:
pSoundList = pSoundsMetal;
soundCount = ARRAYSIZE(pSoundsMetal);
break;
case matCinderBlock:
case matRocks:
pSoundList = pSoundsConcrete;
soundCount = ARRAYSIZE(pSoundsConcrete);
break;
case matCeilingTile:
case matNone:
default:
soundCount = 0;
break;
}
return pSoundList;
}
void CBreakable::MaterialSoundPrecache( Materials precacheMaterial )
{
const char **pSoundList;
int i, soundCount = 0;
pSoundList = MaterialSoundList( precacheMaterial, soundCount );
for ( i = 0; i < soundCount; i++ )
{
PRECACHE_SOUND( (char *)pSoundList[i] );
}
}
void CBreakable::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume )
{
const char **pSoundList;
int soundCount = 0;
pSoundList = MaterialSoundList( soundMaterial, soundCount );
if ( soundCount )
EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0,soundCount-1) ], volume, 1.0 );
}
void CBreakable::Precache( void )
{
const char *pGibName;
switch (m_Material)
{
case matWood:
pGibName = "models/woodgibs.mdl";
PRECACHE_SOUND("debris/bustcrate1.wav");
PRECACHE_SOUND("debris/bustcrate2.wav");
break;
case matFlesh:
pGibName = "models/fleshgibs.mdl";
PRECACHE_SOUND("debris/bustflesh1.wav");
PRECACHE_SOUND("debris/bustflesh2.wav");
break;
case matComputer:
PRECACHE_SOUND("buttons/spark5.wav");
PRECACHE_SOUND("buttons/spark6.wav");
pGibName = "models/computergibs.mdl";
PRECACHE_SOUND("debris/bustmetal1.wav");
PRECACHE_SOUND("debris/bustmetal2.wav");
break;
case matUnbreakableGlass:
case matGlass:
pGibName = "models/glassgibs.mdl";
PRECACHE_SOUND("debris/bustglass1.wav");
PRECACHE_SOUND("debris/bustglass2.wav");
break;
case matMetal:
pGibName = "models/metalplategibs.mdl";
PRECACHE_SOUND("debris/bustmetal1.wav");
PRECACHE_SOUND("debris/bustmetal2.wav");
break;
case matCinderBlock:
pGibName = "models/cindergibs.mdl";
PRECACHE_SOUND("debris/bustconcrete1.wav");
PRECACHE_SOUND("debris/bustconcrete2.wav");
break;
case matRocks:
pGibName = "models/rockgibs.mdl";
PRECACHE_SOUND("debris/bustconcrete1.wav");
PRECACHE_SOUND("debris/bustconcrete2.wav");
break;
case matCeilingTile:
pGibName = "models/ceilinggibs.mdl";
PRECACHE_SOUND ("debris/bustceiling.wav");
break;
}
MaterialSoundPrecache( m_Material );
if ( m_iszGibModel )
pGibName = STRING(m_iszGibModel);
m_idShard = PRECACHE_MODEL( (char *)pGibName );
// Precache the spawn item's data
if ( m_iszSpawnObject )
UTIL_PrecacheOther( (char *)STRING( m_iszSpawnObject ) );
}
// play shard sound when func_breakable takes damage.
// the more damage, the louder the shard sound.
void CBreakable::DamageSound( void )
{
int pitch;
float fvol;
char *rgpsz[6];
int i;
int material = m_Material;
// if (RANDOM_LONG(0,1))
// return;
if (RANDOM_LONG(0,2))
pitch = PITCH_NORM;
else
pitch = 95 + RANDOM_LONG(0,34);
fvol = RANDOM_FLOAT(0.75, 1.0);
if (material == matComputer && RANDOM_LONG(0,1))
material = matMetal;
switch (material)
{
case matComputer:
case matGlass:
case matUnbreakableGlass:
rgpsz[0] = "debris/glass1.wav";
rgpsz[1] = "debris/glass2.wav";
rgpsz[2] = "debris/glass3.wav";
i = 3;
break;
case matWood:
rgpsz[0] = "debris/wood1.wav";
rgpsz[1] = "debris/wood2.wav";
rgpsz[2] = "debris/wood3.wav";
i = 3;
break;
case matMetal:
rgpsz[0] = "debris/metal1.wav";
rgpsz[1] = "debris/metal3.wav";
rgpsz[2] = "debris/metal2.wav";
i = 2;
break;
case matFlesh:
rgpsz[0] = "debris/flesh1.wav";
rgpsz[1] = "debris/flesh2.wav";
rgpsz[2] = "debris/flesh3.wav";
rgpsz[3] = "debris/flesh5.wav";
rgpsz[4] = "debris/flesh6.wav";
rgpsz[5] = "debris/flesh7.wav";
i = 6;
break;
case matRocks:
case matCinderBlock:
rgpsz[0] = "debris/concrete1.wav";
rgpsz[1] = "debris/concrete2.wav";
rgpsz[2] = "debris/concrete3.wav";
i = 3;
break;
case matCeilingTile:
// UNDONE: no ceiling tile shard sound yet
i = 0;
break;
}
if (i)
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, rgpsz[RANDOM_LONG(0,i-1)], fvol, ATTN_NORM, 0, pitch);
}
void CBreakable::BreakTouch( CBaseEntity *pOther )
{
float flDamage;
entvars_t* pevToucher = pOther->pev;
// only players can break these right now
if ( !pOther->IsPlayer() || !IsBreakable() )
{
return;
}
if ( FBitSet ( pev->spawnflags, SF_BREAK_TOUCH ) )
{// can be broken when run into
flDamage = pevToucher->velocity.Length() * 0.01;
if (flDamage >= pev->health)
{
SetTouch( NULL );
TakeDamage(pevToucher, pevToucher, flDamage, DMG_CRUSH);
// do a little damage to player if we broke glass or computer
pOther->TakeDamage( pev, pev, flDamage/4, DMG_SLASH );
}
}
if ( FBitSet ( pev->spawnflags, SF_BREAK_PRESSURE ) && pevToucher->absmin.z >= pev->maxs.z - 2 )
{// can be broken when stood upon
// play creaking sound here.
DamageSound();
SetThink ( Die );
SetTouch( NULL );
if ( m_flDelay == 0 )
{// !!!BUGBUG - why doesn't zero delay work?
m_flDelay = 0.1;
}
pev->nextthink = pev->ltime + m_flDelay;
}
}
//
// Smash the our breakable object
//
// Break when triggered
void CBreakable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( IsBreakable() )
{
pev->angles.y = m_angle;
UTIL_MakeVectors(pev->angles);
g_vecAttackDir = gpGlobals->v_forward;
Die();
}
}
void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
{
// random spark if this is a 'computer' object
if (RANDOM_LONG(0,1) )
{
switch( m_Material )
{
case matComputer:
{
UTIL_Sparks( ptr->vecEndPos );
float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range
switch ( RANDOM_LONG(0,1) )
{
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break;
}
}
break;
case matUnbreakableGlass:
UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) );
break;
}
}
CBaseDelay::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}
//=========================================================
// Special takedamage for func_breakable. Allows us to make
// exceptions that are breakable-specific
// bitsDamageType indicates the type of damage sustained ie: DMG_CRUSH
//=========================================================
int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
{
Vector vecTemp;
// if Attacker == Inflictor, the attack was a melee or other instant-hit attack.
// (that is, no actual entity projectile was involved in the attack so use the shooter's origin).
if ( pevAttacker == pevInflictor )
{
vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) );
// if a client hit the breakable with a crowbar, and breakable is crowbar-sensitive, break it now.
if ( FBitSet ( pevAttacker->flags, FL_CLIENT ) &&
FBitSet ( pev->spawnflags, SF_BREAK_CROWBAR ) && (bitsDamageType & DMG_CLUB))
flDamage = pev->health;
}
else
// an actual missile was involved.
{
vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) );
}
if (!IsBreakable())
return 0;
// Breakables take double damage from the crowbar
if ( bitsDamageType & DMG_CLUB )
flDamage *= 2;
// Boxes / glass / etc. don't take much poison damage, just the impact of the dart - consider that 10%
if ( bitsDamageType & DMG_POISON )
flDamage *= 0.1;
// this global is still used for glass and other non-monster killables, along with decals.
g_vecAttackDir = vecTemp.Normalize();
// do the damage
pev->health -= flDamage;
if (pev->health <= 0)
{
Killed( pevAttacker, GIB_NORMAL );
Die();
return 0;
}
// Make a shard noise each time func breakable is hit.
// Don't play shard noise if cbreakable actually died.
DamageSound();
return 1;
}
void CBreakable::Die( void )
{
Vector vecSpot;// shard origin
Vector vecVelocity;// shard velocity
CBaseEntity *pEntity = NULL;
char cFlag = 0;
int pitch;
float fvol;
pitch = 95 + RANDOM_LONG(0,29);
if (pitch > 97 && pitch < 103)
pitch = 100;
// The more negative pev->health, the louder
// the sound should be.
fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(pev->health) / 100.0);
if (fvol > 1.0)
fvol = 1.0;
switch (m_Material)
{
case matGlass:
switch ( RANDOM_LONG(0,1) )
{
case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch);
break;
case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch);
break;
}
cFlag = BREAK_GLASS;
break;
case matWood:
switch ( RANDOM_LONG(0,1) )
{
case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch);
break;
case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch);
break;
}
cFlag = BREAK_WOOD;
break;
case matComputer:
case matMetal:
switch ( RANDOM_LONG(0,1) )
{
case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch);
break;
case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch);
break;
}
cFlag = BREAK_METAL;
break;
case matFlesh:
switch ( RANDOM_LONG(0,1) )
{
case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch);
break;
case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch);
break;
}
cFlag = BREAK_FLESH;
break;
case matRocks:
case matCinderBlock:
switch ( RANDOM_LONG(0,1) )
{
case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch);
break;
case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch);
break;
}
cFlag = BREAK_CONCRETE;
break;
case matCeilingTile:
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch);
break;
}
if (m_Explosion == expDirected)
vecVelocity = g_vecAttackDir * 200;
else
{
vecVelocity.x = 0;
vecVelocity.y = 0;
vecVelocity.z = 0;
}
vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot );
WRITE_BYTE( TE_BREAKMODEL);
// position
WRITE_COORD( vecSpot.x );
WRITE_COORD( vecSpot.y );
WRITE_COORD( vecSpot.z );
// size
WRITE_COORD( pev->size.x);
WRITE_COORD( pev->size.y);
WRITE_COORD( pev->size.z);
// velocity
WRITE_COORD( vecVelocity.x );
WRITE_COORD( vecVelocity.y );
WRITE_COORD( vecVelocity.z );
// randomization
WRITE_BYTE( 10 );
// Model
WRITE_SHORT( m_idShard ); //model id#
// # of shards
WRITE_BYTE( 0 ); // let client decide
// duration
WRITE_BYTE( 25 );// 2.5 seconds
// flags
WRITE_BYTE( cFlag );
MESSAGE_END();
float size = pev->size.x;
if ( size < pev->size.y )
size = pev->size.y;
if ( size < pev->size.z )
size = pev->size.z;
// !!! HACK This should work!
// Build a box above the entity that looks like an 8 pixel high sheet
Vector mins = pev->absmin;
Vector maxs = pev->absmax;
mins.z = pev->absmax.z;
maxs.z += 8;
// BUGBUG -- can only find 256 entities on a breakable -- should be enough
CBaseEntity *pList[256];
int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND );
if ( count )
{
for ( int i = 0; i < count; i++ )
{
ClearBits( pList[i]->pev->flags, FL_ONGROUND );
pList[i]->pev->groundentity = NULL;
}
}
// Don't fire something that could fire myself
pev->targetname = 0;
pev->solid = SOLID_NOT;
// Fire targets on break
SUB_UseTargets( NULL, USE_TOGGLE, 0 );
SetThink( SUB_Remove );
pev->nextthink = pev->ltime + 0.1;
if ( m_iszSpawnObject )
CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() );
if ( Explodable() )
{
ExplosionCreate( Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE );
}
}
BOOL CBreakable :: IsBreakable( void )
{
return m_Material != matUnbreakableGlass;
}
int CBreakable :: DamageDecal( int bitsDamageType )
{
if ( m_Material == matGlass )
return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2);
if ( m_Material == matUnbreakableGlass )
return DECAL_BPROOF1;
return CBaseEntity::DamageDecal( bitsDamageType );
}
class CPushable : public CBreakable
{
public:
void Spawn ( void );
void Precache( void );
void Touch ( CBaseEntity *pOther );
void Move( CBaseEntity *pMover, int push );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT StopSound( void );
// virtual void SetActivator( CBaseEntity *pActivator ) { m_pPusher = pActivator; }
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_CONTINUOUS_USE; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
inline float MaxSpeed( void ) { return m_maxSpeed; }
// breakables use an overridden takedamage
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
static TYPEDESCRIPTION m_SaveData[];
static char *m_soundNames[3];
int m_lastSound; // no need to save/restore, just keeps the same sound from playing twice in a row
float m_maxSpeed;
float m_soundTime;
};
TYPEDESCRIPTION CPushable::m_SaveData[] =
{
DEFINE_FIELD( CPushable, m_maxSpeed, FIELD_FLOAT ),
DEFINE_FIELD( CPushable, m_soundTime, FIELD_TIME ),
};
IMPLEMENT_SAVERESTORE( CPushable, CBreakable );
LINK_ENTITY_TO_CLASS( func_pushable, CPushable );
char *CPushable :: m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", "debris/pushbox3.wav" };
void CPushable :: Spawn( void )
{
if ( pev->spawnflags & SF_PUSH_BREAKABLE )
CBreakable::Spawn();
else
Precache( );
pev->movetype = MOVETYPE_PUSHSTEP;
pev->solid = SOLID_BBOX;
SET_MODEL( ENT(pev), STRING(pev->model) );
if ( pev->friction > 399 )
pev->friction = 399;
m_maxSpeed = 400 - pev->friction;
SetBits( pev->flags, FL_FLOAT );
pev->friction = 0;
pev->origin.z += 1; // Pick up off of the floor
UTIL_SetOrigin( pev, pev->origin );
// Multiply by area of the box's cross-section (assume 1000 units^3 standard volume)
pev->skin = ( pev->skin * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005;
m_soundTime = 0;
}
void CPushable :: Precache( void )
{
for ( int i = 0; i < 3; i++ )
PRECACHE_SOUND( m_soundNames[i] );
if ( pev->spawnflags & SF_PUSH_BREAKABLE )
CBreakable::Precache( );
}
void CPushable :: KeyValue( KeyValueData *pkvd )
{
if ( FStrEq(pkvd->szKeyName, "size") )
{
int bbox = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
switch( bbox )
{
case 0: // Point
UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8));
break;
case 2: // Big Hull!?!? !!!BUGBUG Figure out what this hull really is
UTIL_SetSize(pev, VEC_DUCK_HULL_MIN*2, VEC_DUCK_HULL_MAX*2);
break;
case 3: // Player duck
UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX);
break;
default:
case 1: // Player
UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX);
break;
}
}
else if ( FStrEq(pkvd->szKeyName, "buoyancy") )
{
pev->skin = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBreakable::KeyValue( pkvd );
}
// Pull the func_pushable
void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !pActivator || !pActivator->IsPlayer() )
{
if ( pev->spawnflags & SF_PUSH_BREAKABLE )
this->CBreakable::Use( pActivator, pCaller, useType, value );
return;
}
if ( pActivator->pev->velocity != g_vecZero )
Move( pActivator, 0 );
}
void CPushable :: Touch( CBaseEntity *pOther )
{
if ( FClassnameIs( pOther->pev, "worldspawn" ) )
return;
Move( pOther, 1 );
}
void CPushable :: Move( CBaseEntity *pOther, int push )
{
entvars_t* pevToucher = pOther->pev;
int playerTouch = 0;
// Is entity standing on this pushable ?
if ( FBitSet(pevToucher->flags,FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev )
{
// Only push if floating
if ( pev->waterlevel > 0 )
pev->velocity.z += pevToucher->velocity.z * 0.1;
return;
}
if ( pOther->IsPlayer() )
{
if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) // Don't push unless the player is pushing forward and NOT use (pull)
return;
playerTouch = 1;
}
float factor;
if ( playerTouch )
{
if ( !(pevToucher->flags & FL_ONGROUND) ) // Don't push away from jumping/falling players unless in water
{
if ( pev->waterlevel < 1 )
return;
else
factor = 0.1;
}
else
factor = 1;
}
else
factor = 0.25;
pev->velocity.x += pevToucher->velocity.x * factor;
pev->velocity.y += pevToucher->velocity.y * factor;
float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y );
if ( push && (length > MaxSpeed()) )
{
pev->velocity.x = (pev->velocity.x * MaxSpeed() / length );
pev->velocity.y = (pev->velocity.y * MaxSpeed() / length );
}
if ( playerTouch )
{
pevToucher->velocity.x = pev->velocity.x;
pevToucher->velocity.y = pev->velocity.y;
if ( (gpGlobals->time - m_soundTime) > 0.7 )
{
m_soundTime = gpGlobals->time;
if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) )
{
m_lastSound = RANDOM_LONG(0,2);
EMIT_SOUND(ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5, ATTN_NORM);
// SetThink( StopSound );
// pev->nextthink = pev->ltime + 0.1;
}
else
STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] );
}
}
}
#if 0
void CPushable::StopSound( void )
{
Vector dist = pev->oldorigin - pev->origin;
if ( dist.Length() <= 0 )
STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] );
}
#endif
int CPushable::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
{
if ( pev->spawnflags & SF_PUSH_BREAKABLE )
return CBreakable::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
return 1;
}

74
dlls/func_break.h Normal file
View File

@ -0,0 +1,74 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef FUNC_BREAK_H
#define FUNC_BREAK_H
typedef enum { expRandom, expDirected} Explosions;
typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials;
#define NUM_SHARDS 6 // this many shards spawned when breakable objects break;
class CBreakable : public CBaseDelay
{
public:
// basic functions
void Spawn( void );
void Precache( void );
void KeyValue( KeyValueData* pkvd);
void EXPORT BreakTouch( CBaseEntity *pOther );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void DamageSound( void );
// breakables use an overridden takedamage
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
// To spark when hit
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
BOOL IsBreakable( void );
BOOL SparkWhenHit( void );
int DamageDecal( int bitsDamageType );
void EXPORT Die( void );
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; }
inline int ExplosionMagnitude( void ) { return pev->impulse; }
inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; }
static void MaterialSoundPrecache( Materials precacheMaterial );
static void MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume );
static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount );
static const char *pSoundsWood[];
static const char *pSoundsFlesh[];
static const char *pSoundsGlass[];
static const char *pSoundsMetal[];
static const char *pSoundsConcrete[];
static const char *pSpawnObjects[];
static TYPEDESCRIPTION m_SaveData[];
Materials m_Material;
Explosions m_Explosion;
int m_idShard;
float m_angle;
int m_iszGibModel;
int m_iszSpawnObject;
};
#endif // FUNC_BREAK_H

1035
dlls/func_tank.cpp Normal file

File diff suppressed because it is too large Load Diff

876
dlls/game.cpp Normal file
View File

@ -0,0 +1,876 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "eiface.h"
#include "util.h"
#include "game.h"
cvar_t displaysoundlist = {"displaysoundlist","0"};
cvar_t mapcyclefile = {"mapcyclefile","mapcycle.txt"};
cvar_t servercfgfile = {"servercfgfile","server.cfg"};
cvar_t lservercfgfile = {"lservercfgfile","listenserver.cfg"};
// multiplayer server rules
cvar_t teamplay = {"mp_teamplay","0", FCVAR_SERVER };
cvar_t fraglimit = {"mp_fraglimit","0", FCVAR_SERVER };
cvar_t timelimit = {"mp_timelimit","0", FCVAR_SERVER };
cvar_t friendlyfire= {"mp_friendlyfire","0", FCVAR_SERVER };
cvar_t falldamage = {"mp_falldamage","0", FCVAR_SERVER };
cvar_t weaponstay = {"mp_weaponstay","0", FCVAR_SERVER };
cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER };
cvar_t footsteps = {"mp_footsteps","1", FCVAR_SERVER };
cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER };
cvar_t aimcrosshair= {"mp_autocrosshair","1", FCVAR_SERVER };
cvar_t decalfrequency = {"decalfrequency","30", FCVAR_SERVER };
cvar_t teamlist = {"mp_teamlist","hgrunt;scientist", FCVAR_SERVER };
cvar_t teamoverride = {"mp_teamoverride","1" };
cvar_t defaultteam = {"mp_defaultteam","0" };
cvar_t allowmonsters={"mp_allowmonsters","0", FCVAR_SERVER };
//CVARS FOR SKILL LEVEL SETTINGS
// Agrunt
cvar_t sk_agrunt_health1 = {"sk_agrunt_health1","0"};
cvar_t sk_agrunt_health2 = {"sk_agrunt_health2","0"};
cvar_t sk_agrunt_health3 = {"sk_agrunt_health3","0"};
cvar_t sk_agrunt_dmg_punch1 = {"sk_agrunt_dmg_punch1","0"};
cvar_t sk_agrunt_dmg_punch2 = {"sk_agrunt_dmg_punch2","0"};
cvar_t sk_agrunt_dmg_punch3 = {"sk_agrunt_dmg_punch3","0"};
// Apache
cvar_t sk_apache_health1 = {"sk_apache_health1","0"};
cvar_t sk_apache_health2 = {"sk_apache_health2","0"};
cvar_t sk_apache_health3 = {"sk_apache_health3","0"};
// Barney
cvar_t sk_barney_health1 = {"sk_barney_health1","0"};
cvar_t sk_barney_health2 = {"sk_barney_health2","0"};
cvar_t sk_barney_health3 = {"sk_barney_health3","0"};
// Bullsquid
cvar_t sk_bullsquid_health1 = {"sk_bullsquid_health1","0"};
cvar_t sk_bullsquid_health2 = {"sk_bullsquid_health2","0"};
cvar_t sk_bullsquid_health3 = {"sk_bullsquid_health3","0"};
cvar_t sk_bullsquid_dmg_bite1 = {"sk_bullsquid_dmg_bite1","0"};
cvar_t sk_bullsquid_dmg_bite2 = {"sk_bullsquid_dmg_bite2","0"};
cvar_t sk_bullsquid_dmg_bite3 = {"sk_bullsquid_dmg_bite3","0"};
cvar_t sk_bullsquid_dmg_whip1 = {"sk_bullsquid_dmg_whip1","0"};
cvar_t sk_bullsquid_dmg_whip2 = {"sk_bullsquid_dmg_whip2","0"};
cvar_t sk_bullsquid_dmg_whip3 = {"sk_bullsquid_dmg_whip3","0"};
cvar_t sk_bullsquid_dmg_spit1 = {"sk_bullsquid_dmg_spit1","0"};
cvar_t sk_bullsquid_dmg_spit2 = {"sk_bullsquid_dmg_spit2","0"};
cvar_t sk_bullsquid_dmg_spit3 = {"sk_bullsquid_dmg_spit3","0"};
// Big Momma
cvar_t sk_bigmomma_health_factor1 = {"sk_bigmomma_health_factor1","1.0"};
cvar_t sk_bigmomma_health_factor2 = {"sk_bigmomma_health_factor2","1.0"};
cvar_t sk_bigmomma_health_factor3 = {"sk_bigmomma_health_factor3","1.0"};
cvar_t sk_bigmomma_dmg_slash1 = {"sk_bigmomma_dmg_slash1","50"};
cvar_t sk_bigmomma_dmg_slash2 = {"sk_bigmomma_dmg_slash2","50"};
cvar_t sk_bigmomma_dmg_slash3 = {"sk_bigmomma_dmg_slash3","50"};
cvar_t sk_bigmomma_dmg_blast1 = {"sk_bigmomma_dmg_blast1","100"};
cvar_t sk_bigmomma_dmg_blast2 = {"sk_bigmomma_dmg_blast2","100"};
cvar_t sk_bigmomma_dmg_blast3 = {"sk_bigmomma_dmg_blast3","100"};
cvar_t sk_bigmomma_radius_blast1 = {"sk_bigmomma_radius_blast1","250"};
cvar_t sk_bigmomma_radius_blast2 = {"sk_bigmomma_radius_blast2","250"};
cvar_t sk_bigmomma_radius_blast3 = {"sk_bigmomma_radius_blast3","250"};
// Gargantua
cvar_t sk_gargantua_health1 = {"sk_gargantua_health1","0"};
cvar_t sk_gargantua_health2 = {"sk_gargantua_health2","0"};
cvar_t sk_gargantua_health3 = {"sk_gargantua_health3","0"};
cvar_t sk_gargantua_dmg_slash1 = {"sk_gargantua_dmg_slash1","0"};
cvar_t sk_gargantua_dmg_slash2 = {"sk_gargantua_dmg_slash2","0"};
cvar_t sk_gargantua_dmg_slash3 = {"sk_gargantua_dmg_slash3","0"};
cvar_t sk_gargantua_dmg_fire1 = {"sk_gargantua_dmg_fire1","0"};
cvar_t sk_gargantua_dmg_fire2 = {"sk_gargantua_dmg_fire2","0"};
cvar_t sk_gargantua_dmg_fire3 = {"sk_gargantua_dmg_fire3","0"};
cvar_t sk_gargantua_dmg_stomp1 = {"sk_gargantua_dmg_stomp1","0"};
cvar_t sk_gargantua_dmg_stomp2 = {"sk_gargantua_dmg_stomp2","0"};
cvar_t sk_gargantua_dmg_stomp3 = {"sk_gargantua_dmg_stomp3","0"};
// Hassassin
cvar_t sk_hassassin_health1 = {"sk_hassassin_health1","0"};
cvar_t sk_hassassin_health2 = {"sk_hassassin_health2","0"};
cvar_t sk_hassassin_health3 = {"sk_hassassin_health3","0"};
// Headcrab
cvar_t sk_headcrab_health1 = {"sk_headcrab_health1","0"};
cvar_t sk_headcrab_health2 = {"sk_headcrab_health2","0"};
cvar_t sk_headcrab_health3 = {"sk_headcrab_health3","0"};
cvar_t sk_headcrab_dmg_bite1 = {"sk_headcrab_dmg_bite1","0"};
cvar_t sk_headcrab_dmg_bite2 = {"sk_headcrab_dmg_bite2","0"};
cvar_t sk_headcrab_dmg_bite3 = {"sk_headcrab_dmg_bite3","0"};
// Hgrunt
cvar_t sk_hgrunt_health1 = {"sk_hgrunt_health1","0"};
cvar_t sk_hgrunt_health2 = {"sk_hgrunt_health2","0"};
cvar_t sk_hgrunt_health3 = {"sk_hgrunt_health3","0"};
cvar_t sk_hgrunt_kick1 = {"sk_hgrunt_kick1","0"};
cvar_t sk_hgrunt_kick2 = {"sk_hgrunt_kick2","0"};
cvar_t sk_hgrunt_kick3 = {"sk_hgrunt_kick3","0"};
cvar_t sk_hgrunt_pellets1 = {"sk_hgrunt_pellets1","0"};
cvar_t sk_hgrunt_pellets2 = {"sk_hgrunt_pellets2","0"};
cvar_t sk_hgrunt_pellets3 = {"sk_hgrunt_pellets3","0"};
cvar_t sk_hgrunt_gspeed1 = {"sk_hgrunt_gspeed1","0"};
cvar_t sk_hgrunt_gspeed2 = {"sk_hgrunt_gspeed2","0"};
cvar_t sk_hgrunt_gspeed3 = {"sk_hgrunt_gspeed3","0"};
// Houndeye
cvar_t sk_houndeye_health1 = {"sk_houndeye_health1","0"};
cvar_t sk_houndeye_health2 = {"sk_houndeye_health2","0"};
cvar_t sk_houndeye_health3 = {"sk_houndeye_health3","0"};
cvar_t sk_houndeye_dmg_blast1 = {"sk_houndeye_dmg_blast1","0"};
cvar_t sk_houndeye_dmg_blast2 = {"sk_houndeye_dmg_blast2","0"};
cvar_t sk_houndeye_dmg_blast3 = {"sk_houndeye_dmg_blast3","0"};
// ISlave
cvar_t sk_islave_health1 = {"sk_islave_health1","0"};
cvar_t sk_islave_health2 = {"sk_islave_health2","0"};
cvar_t sk_islave_health3 = {"sk_islave_health3","0"};
cvar_t sk_islave_dmg_claw1 = {"sk_islave_dmg_claw1","0"};
cvar_t sk_islave_dmg_claw2 = {"sk_islave_dmg_claw2","0"};
cvar_t sk_islave_dmg_claw3 = {"sk_islave_dmg_claw3","0"};
cvar_t sk_islave_dmg_clawrake1 = {"sk_islave_dmg_clawrake1","0"};
cvar_t sk_islave_dmg_clawrake2 = {"sk_islave_dmg_clawrake2","0"};
cvar_t sk_islave_dmg_clawrake3 = {"sk_islave_dmg_clawrake3","0"};
cvar_t sk_islave_dmg_zap1 = {"sk_islave_dmg_zap1","0"};
cvar_t sk_islave_dmg_zap2 = {"sk_islave_dmg_zap2","0"};
cvar_t sk_islave_dmg_zap3 = {"sk_islave_dmg_zap3","0"};
// Icthyosaur
cvar_t sk_ichthyosaur_health1 = {"sk_ichthyosaur_health1","0"};
cvar_t sk_ichthyosaur_health2 = {"sk_ichthyosaur_health2","0"};
cvar_t sk_ichthyosaur_health3 = {"sk_ichthyosaur_health3","0"};
cvar_t sk_ichthyosaur_shake1 = {"sk_ichthyosaur_shake1","0"};
cvar_t sk_ichthyosaur_shake2 = {"sk_ichthyosaur_shake2","0"};
cvar_t sk_ichthyosaur_shake3 = {"sk_ichthyosaur_shake3","0"};
// Leech
cvar_t sk_leech_health1 = {"sk_leech_health1","0"};
cvar_t sk_leech_health2 = {"sk_leech_health2","0"};
cvar_t sk_leech_health3 = {"sk_leech_health3","0"};
cvar_t sk_leech_dmg_bite1 = {"sk_leech_dmg_bite1","0"};
cvar_t sk_leech_dmg_bite2 = {"sk_leech_dmg_bite2","0"};
cvar_t sk_leech_dmg_bite3 = {"sk_leech_dmg_bite3","0"};
// Controller
cvar_t sk_controller_health1 = {"sk_controller_health1","0"};
cvar_t sk_controller_health2 = {"sk_controller_health2","0"};
cvar_t sk_controller_health3 = {"sk_controller_health3","0"};
cvar_t sk_controller_dmgzap1 = {"sk_controller_dmgzap1","0"};
cvar_t sk_controller_dmgzap2 = {"sk_controller_dmgzap2","0"};
cvar_t sk_controller_dmgzap3 = {"sk_controller_dmgzap3","0"};
cvar_t sk_controller_speedball1 = {"sk_controller_speedball1","0"};
cvar_t sk_controller_speedball2 = {"sk_controller_speedball2","0"};
cvar_t sk_controller_speedball3 = {"sk_controller_speedball3","0"};
cvar_t sk_controller_dmgball1 = {"sk_controller_dmgball1","0"};
cvar_t sk_controller_dmgball2 = {"sk_controller_dmgball2","0"};
cvar_t sk_controller_dmgball3 = {"sk_controller_dmgball3","0"};
// Nihilanth
cvar_t sk_nihilanth_health1 = {"sk_nihilanth_health1","0"};
cvar_t sk_nihilanth_health2 = {"sk_nihilanth_health2","0"};
cvar_t sk_nihilanth_health3 = {"sk_nihilanth_health3","0"};
cvar_t sk_nihilanth_zap1 = {"sk_nihilanth_zap1","0"};
cvar_t sk_nihilanth_zap2 = {"sk_nihilanth_zap2","0"};
cvar_t sk_nihilanth_zap3 = {"sk_nihilanth_zap3","0"};
// Scientist
cvar_t sk_scientist_health1 = {"sk_scientist_health1","0"};
cvar_t sk_scientist_health2 = {"sk_scientist_health2","0"};
cvar_t sk_scientist_health3 = {"sk_scientist_health3","0"};
// Snark
cvar_t sk_snark_health1 = {"sk_snark_health1","0"};
cvar_t sk_snark_health2 = {"sk_snark_health2","0"};
cvar_t sk_snark_health3 = {"sk_snark_health3","0"};
cvar_t sk_snark_dmg_bite1 = {"sk_snark_dmg_bite1","0"};
cvar_t sk_snark_dmg_bite2 = {"sk_snark_dmg_bite2","0"};
cvar_t sk_snark_dmg_bite3 = {"sk_snark_dmg_bite3","0"};
cvar_t sk_snark_dmg_pop1 = {"sk_snark_dmg_pop1","0"};
cvar_t sk_snark_dmg_pop2 = {"sk_snark_dmg_pop2","0"};
cvar_t sk_snark_dmg_pop3 = {"sk_snark_dmg_pop3","0"};
// Zombie
cvar_t sk_zombie_health1 = {"sk_zombie_health1","0"};
cvar_t sk_zombie_health2 = {"sk_zombie_health2","0"};
cvar_t sk_zombie_health3 = {"sk_zombie_health3","0"};
cvar_t sk_zombie_dmg_one_slash1 = {"sk_zombie_dmg_one_slash1","0"};
cvar_t sk_zombie_dmg_one_slash2 = {"sk_zombie_dmg_one_slash2","0"};
cvar_t sk_zombie_dmg_one_slash3 = {"sk_zombie_dmg_one_slash3","0"};
cvar_t sk_zombie_dmg_both_slash1 = {"sk_zombie_dmg_both_slash1","0"};
cvar_t sk_zombie_dmg_both_slash2 = {"sk_zombie_dmg_both_slash2","0"};
cvar_t sk_zombie_dmg_both_slash3 = {"sk_zombie_dmg_both_slash3","0"};
//Turret
cvar_t sk_turret_health1 = {"sk_turret_health1","0"};
cvar_t sk_turret_health2 = {"sk_turret_health2","0"};
cvar_t sk_turret_health3 = {"sk_turret_health3","0"};
// MiniTurret
cvar_t sk_miniturret_health1 = {"sk_miniturret_health1","0"};
cvar_t sk_miniturret_health2 = {"sk_miniturret_health2","0"};
cvar_t sk_miniturret_health3 = {"sk_miniturret_health3","0"};
// Sentry Turret
cvar_t sk_sentry_health1 = {"sk_sentry_health1","0"};
cvar_t sk_sentry_health2 = {"sk_sentry_health2","0"};
cvar_t sk_sentry_health3 = {"sk_sentry_health3","0"};
// PLAYER WEAPONS
// Crowbar whack
cvar_t sk_plr_crowbar1 = {"sk_plr_crowbar1","0"};
cvar_t sk_plr_crowbar2 = {"sk_plr_crowbar2","0"};
cvar_t sk_plr_crowbar3 = {"sk_plr_crowbar3","0"};
// Glock Round
cvar_t sk_plr_9mm_bullet1 = {"sk_plr_9mm_bullet1","0"};
cvar_t sk_plr_9mm_bullet2 = {"sk_plr_9mm_bullet2","0"};
cvar_t sk_plr_9mm_bullet3 = {"sk_plr_9mm_bullet3","0"};
// 357 Round
cvar_t sk_plr_357_bullet1 = {"sk_plr_357_bullet1","0"};
cvar_t sk_plr_357_bullet2 = {"sk_plr_357_bullet2","0"};
cvar_t sk_plr_357_bullet3 = {"sk_plr_357_bullet3","0"};
// MP5 Round
cvar_t sk_plr_9mmAR_bullet1 = {"sk_plr_9mmAR_bullet1","0"};
cvar_t sk_plr_9mmAR_bullet2 = {"sk_plr_9mmAR_bullet2","0"};
cvar_t sk_plr_9mmAR_bullet3 = {"sk_plr_9mmAR_bullet3","0"};
// M203 grenade
cvar_t sk_plr_9mmAR_grenade1 = {"sk_plr_9mmAR_grenade1","0"};
cvar_t sk_plr_9mmAR_grenade2 = {"sk_plr_9mmAR_grenade2","0"};
cvar_t sk_plr_9mmAR_grenade3 = {"sk_plr_9mmAR_grenade3","0"};
// Shotgun buckshot
cvar_t sk_plr_buckshot1 = {"sk_plr_buckshot1","0"};
cvar_t sk_plr_buckshot2 = {"sk_plr_buckshot2","0"};
cvar_t sk_plr_buckshot3 = {"sk_plr_buckshot3","0"};
// Crossbow
cvar_t sk_plr_xbow_bolt_client1 = {"sk_plr_xbow_bolt_client1","0"};
cvar_t sk_plr_xbow_bolt_client2 = {"sk_plr_xbow_bolt_client2","0"};
cvar_t sk_plr_xbow_bolt_client3 = {"sk_plr_xbow_bolt_client3","0"};
cvar_t sk_plr_xbow_bolt_monster1 = {"sk_plr_xbow_bolt_monster1","0"};
cvar_t sk_plr_xbow_bolt_monster2 = {"sk_plr_xbow_bolt_monster2","0"};
cvar_t sk_plr_xbow_bolt_monster3 = {"sk_plr_xbow_bolt_monster3","0"};
// RPG
cvar_t sk_plr_rpg1 = {"sk_plr_rpg1","0"};
cvar_t sk_plr_rpg2 = {"sk_plr_rpg2","0"};
cvar_t sk_plr_rpg3 = {"sk_plr_rpg3","0"};
// Zero Point Generator
cvar_t sk_plr_gauss1 = {"sk_plr_gauss1","0"};
cvar_t sk_plr_gauss2 = {"sk_plr_gauss2","0"};
cvar_t sk_plr_gauss3 = {"sk_plr_gauss3","0"};
// Tau Cannon
cvar_t sk_plr_egon_narrow1 = {"sk_plr_egon_narrow1","0"};
cvar_t sk_plr_egon_narrow2 = {"sk_plr_egon_narrow2","0"};
cvar_t sk_plr_egon_narrow3 = {"sk_plr_egon_narrow3","0"};
cvar_t sk_plr_egon_wide1 = {"sk_plr_egon_wide1","0"};
cvar_t sk_plr_egon_wide2 = {"sk_plr_egon_wide2","0"};
cvar_t sk_plr_egon_wide3 = {"sk_plr_egon_wide3","0"};
// Hand Grendade
cvar_t sk_plr_hand_grenade1 = {"sk_plr_hand_grenade1","0"};
cvar_t sk_plr_hand_grenade2 = {"sk_plr_hand_grenade2","0"};
cvar_t sk_plr_hand_grenade3 = {"sk_plr_hand_grenade3","0"};
// Satchel Charge
cvar_t sk_plr_satchel1 = {"sk_plr_satchel1","0"};
cvar_t sk_plr_satchel2 = {"sk_plr_satchel2","0"};
cvar_t sk_plr_satchel3 = {"sk_plr_satchel3","0"};
// Tripmine
cvar_t sk_plr_tripmine1 = {"sk_plr_tripmine1","0"};
cvar_t sk_plr_tripmine2 = {"sk_plr_tripmine2","0"};
cvar_t sk_plr_tripmine3 = {"sk_plr_tripmine3","0"};
// WORLD WEAPONS
cvar_t sk_12mm_bullet1 = {"sk_12mm_bullet1","0"};
cvar_t sk_12mm_bullet2 = {"sk_12mm_bullet2","0"};
cvar_t sk_12mm_bullet3 = {"sk_12mm_bullet3","0"};
cvar_t sk_9mmAR_bullet1 = {"sk_9mmAR_bullet1","0"};
cvar_t sk_9mmAR_bullet2 = {"sk_9mmAR_bullet2","0"};
cvar_t sk_9mmAR_bullet3 = {"sk_9mmAR_bullet3","0"};
cvar_t sk_9mm_bullet1 = {"sk_9mm_bullet1","0"};
cvar_t sk_9mm_bullet2 = {"sk_9mm_bullet2","0"};
cvar_t sk_9mm_bullet3 = {"sk_9mm_bullet3","0"};
// HORNET
cvar_t sk_hornet_dmg1 = {"sk_hornet_dmg1","0"};
cvar_t sk_hornet_dmg2 = {"sk_hornet_dmg2","0"};
cvar_t sk_hornet_dmg3 = {"sk_hornet_dmg3","0"};
// HEALTH/CHARGE
cvar_t sk_suitcharger1 = { "sk_suitcharger1","0" };
cvar_t sk_suitcharger2 = { "sk_suitcharger2","0" };
cvar_t sk_suitcharger3 = { "sk_suitcharger3","0" };
cvar_t sk_battery1 = { "sk_battery1","0" };
cvar_t sk_battery2 = { "sk_battery2","0" };
cvar_t sk_battery3 = { "sk_battery3","0" };
cvar_t sk_healthcharger1 = { "sk_healthcharger1","0" };
cvar_t sk_healthcharger2 = { "sk_healthcharger2","0" };
cvar_t sk_healthcharger3 = { "sk_healthcharger3","0" };
cvar_t sk_healthkit1 = { "sk_healthkit1","0" };
cvar_t sk_healthkit2 = { "sk_healthkit2","0" };
cvar_t sk_healthkit3 = { "sk_healthkit3","0" };
cvar_t sk_scientist_heal1 = { "sk_scientist_heal1","0" };
cvar_t sk_scientist_heal2 = { "sk_scientist_heal2","0" };
cvar_t sk_scientist_heal3 = { "sk_scientist_heal3","0" };
// monster damage adjusters
cvar_t sk_monster_head1 = { "sk_monster_head1","2" };
cvar_t sk_monster_head2 = { "sk_monster_head2","2" };
cvar_t sk_monster_head3 = { "sk_monster_head3","2" };
cvar_t sk_monster_chest1 = { "sk_monster_chest1","1" };
cvar_t sk_monster_chest2 = { "sk_monster_chest2","1" };
cvar_t sk_monster_chest3 = { "sk_monster_chest3","1" };
cvar_t sk_monster_stomach1 = { "sk_monster_stomach1","1" };
cvar_t sk_monster_stomach2 = { "sk_monster_stomach2","1" };
cvar_t sk_monster_stomach3 = { "sk_monster_stomach3","1" };
cvar_t sk_monster_arm1 = { "sk_monster_arm1","1" };
cvar_t sk_monster_arm2 = { "sk_monster_arm2","1" };
cvar_t sk_monster_arm3 = { "sk_monster_arm3","1" };
cvar_t sk_monster_leg1 = { "sk_monster_leg1","1" };
cvar_t sk_monster_leg2 = { "sk_monster_leg2","1" };
cvar_t sk_monster_leg3 = { "sk_monster_leg3","1" };
// player damage adjusters
cvar_t sk_player_head1 = { "sk_player_head1","2" };
cvar_t sk_player_head2 = { "sk_player_head2","2" };
cvar_t sk_player_head3 = { "sk_player_head3","2" };
cvar_t sk_player_chest1 = { "sk_player_chest1","1" };
cvar_t sk_player_chest2 = { "sk_player_chest2","1" };
cvar_t sk_player_chest3 = { "sk_player_chest3","1" };
cvar_t sk_player_stomach1 = { "sk_player_stomach1","1" };
cvar_t sk_player_stomach2 = { "sk_player_stomach2","1" };
cvar_t sk_player_stomach3 = { "sk_player_stomach3","1" };
cvar_t sk_player_arm1 = { "sk_player_arm1","1" };
cvar_t sk_player_arm2 = { "sk_player_arm2","1" };
cvar_t sk_player_arm3 = { "sk_player_arm3","1" };
cvar_t sk_player_leg1 = { "sk_player_leg1","1" };
cvar_t sk_player_leg2 = { "sk_player_leg2","1" };
cvar_t sk_player_leg3 = { "sk_player_leg3","1" };
// END Cvars for Skill Level settings
// Register your console variables here
// This gets called one time when the game is initialied
void GameDLLInit( void )
{
// Register cvars here:
CVAR_REGISTER (&displaysoundlist);
CVAR_REGISTER (&mapcyclefile);
CVAR_REGISTER (&servercfgfile);
CVAR_REGISTER (&lservercfgfile);
CVAR_REGISTER (&teamplay);
CVAR_REGISTER (&fraglimit);
CVAR_REGISTER (&timelimit);
CVAR_REGISTER (&friendlyfire);
CVAR_REGISTER (&falldamage);
CVAR_REGISTER (&weaponstay);
CVAR_REGISTER (&forcerespawn);
CVAR_REGISTER (&footsteps);
CVAR_REGISTER (&flashlight);
CVAR_REGISTER (&aimcrosshair);
CVAR_REGISTER (&decalfrequency);
CVAR_REGISTER (&teamlist);
CVAR_REGISTER (&teamoverride);
CVAR_REGISTER (&defaultteam);
CVAR_REGISTER (&allowmonsters);
// REGISTER CVARS FOR SKILL LEVEL STUFF
// Agrunt
CVAR_REGISTER ( &sk_agrunt_health1 );// {"sk_agrunt_health1","0"};
CVAR_REGISTER ( &sk_agrunt_health2 );// {"sk_agrunt_health2","0"};
CVAR_REGISTER ( &sk_agrunt_health3 );// {"sk_agrunt_health3","0"};
CVAR_REGISTER ( &sk_agrunt_dmg_punch1 );// {"sk_agrunt_dmg_punch1","0"};
CVAR_REGISTER ( &sk_agrunt_dmg_punch2 );// {"sk_agrunt_dmg_punch2","0"};
CVAR_REGISTER ( &sk_agrunt_dmg_punch3 );// {"sk_agrunt_dmg_punch3","0"};
// Apache
CVAR_REGISTER ( &sk_apache_health1 );// {"sk_apache_health1","0"};
CVAR_REGISTER ( &sk_apache_health2 );// {"sk_apache_health2","0"};
CVAR_REGISTER ( &sk_apache_health3 );// {"sk_apache_health3","0"};
// Barney
CVAR_REGISTER ( &sk_barney_health1 );// {"sk_barney_health1","0"};
CVAR_REGISTER ( &sk_barney_health2 );// {"sk_barney_health2","0"};
CVAR_REGISTER ( &sk_barney_health3 );// {"sk_barney_health3","0"};
// Bullsquid
CVAR_REGISTER ( &sk_bullsquid_health1 );// {"sk_bullsquid_health1","0"};
CVAR_REGISTER ( &sk_bullsquid_health2 );// {"sk_bullsquid_health2","0"};
CVAR_REGISTER ( &sk_bullsquid_health3 );// {"sk_bullsquid_health3","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_bite1 );// {"sk_bullsquid_dmg_bite1","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_bite2 );// {"sk_bullsquid_dmg_bite2","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_bite3 );// {"sk_bullsquid_dmg_bite3","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_whip1 );// {"sk_bullsquid_dmg_whip1","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_whip2 );// {"sk_bullsquid_dmg_whip2","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_whip3 );// {"sk_bullsquid_dmg_whip3","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_spit1 );// {"sk_bullsquid_dmg_spit1","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_spit2 );// {"sk_bullsquid_dmg_spit2","0"};
CVAR_REGISTER ( &sk_bullsquid_dmg_spit3 );// {"sk_bullsquid_dmg_spit3","0"};
CVAR_REGISTER ( &sk_bigmomma_health_factor1 );// {"sk_bigmomma_health_factor1","1.0"};
CVAR_REGISTER ( &sk_bigmomma_health_factor2 );// {"sk_bigmomma_health_factor2","1.0"};
CVAR_REGISTER ( &sk_bigmomma_health_factor3 );// {"sk_bigmomma_health_factor3","1.0"};
CVAR_REGISTER ( &sk_bigmomma_dmg_slash1 );// {"sk_bigmomma_dmg_slash1","50"};
CVAR_REGISTER ( &sk_bigmomma_dmg_slash2 );// {"sk_bigmomma_dmg_slash2","50"};
CVAR_REGISTER ( &sk_bigmomma_dmg_slash3 );// {"sk_bigmomma_dmg_slash3","50"};
CVAR_REGISTER ( &sk_bigmomma_dmg_blast1 );// {"sk_bigmomma_dmg_blast1","100"};
CVAR_REGISTER ( &sk_bigmomma_dmg_blast2 );// {"sk_bigmomma_dmg_blast2","100"};
CVAR_REGISTER ( &sk_bigmomma_dmg_blast3 );// {"sk_bigmomma_dmg_blast3","100"};
CVAR_REGISTER ( &sk_bigmomma_radius_blast1 );// {"sk_bigmomma_radius_blast1","250"};
CVAR_REGISTER ( &sk_bigmomma_radius_blast2 );// {"sk_bigmomma_radius_blast2","250"};
CVAR_REGISTER ( &sk_bigmomma_radius_blast3 );// {"sk_bigmomma_radius_blast3","250"};
// Gargantua
CVAR_REGISTER ( &sk_gargantua_health1 );// {"sk_gargantua_health1","0"};
CVAR_REGISTER ( &sk_gargantua_health2 );// {"sk_gargantua_health2","0"};
CVAR_REGISTER ( &sk_gargantua_health3 );// {"sk_gargantua_health3","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_slash1 );// {"sk_gargantua_dmg_slash1","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_slash2 );// {"sk_gargantua_dmg_slash2","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_slash3 );// {"sk_gargantua_dmg_slash3","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_fire1 );// {"sk_gargantua_dmg_fire1","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_fire2 );// {"sk_gargantua_dmg_fire2","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_fire3 );// {"sk_gargantua_dmg_fire3","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_stomp1 );// {"sk_gargantua_dmg_stomp1","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_stomp2 );// {"sk_gargantua_dmg_stomp2","0"};
CVAR_REGISTER ( &sk_gargantua_dmg_stomp3 );// {"sk_gargantua_dmg_stomp3","0"};
// Hassassin
CVAR_REGISTER ( &sk_hassassin_health1 );// {"sk_hassassin_health1","0"};
CVAR_REGISTER ( &sk_hassassin_health2 );// {"sk_hassassin_health2","0"};
CVAR_REGISTER ( &sk_hassassin_health3 );// {"sk_hassassin_health3","0"};
// Headcrab
CVAR_REGISTER ( &sk_headcrab_health1 );// {"sk_headcrab_health1","0"};
CVAR_REGISTER ( &sk_headcrab_health2 );// {"sk_headcrab_health2","0"};
CVAR_REGISTER ( &sk_headcrab_health3 );// {"sk_headcrab_health3","0"};
CVAR_REGISTER ( &sk_headcrab_dmg_bite1 );// {"sk_headcrab_dmg_bite1","0"};
CVAR_REGISTER ( &sk_headcrab_dmg_bite2 );// {"sk_headcrab_dmg_bite2","0"};
CVAR_REGISTER ( &sk_headcrab_dmg_bite3 );// {"sk_headcrab_dmg_bite3","0"};
// Hgrunt
CVAR_REGISTER ( &sk_hgrunt_health1 );// {"sk_hgrunt_health1","0"};
CVAR_REGISTER ( &sk_hgrunt_health2 );// {"sk_hgrunt_health2","0"};
CVAR_REGISTER ( &sk_hgrunt_health3 );// {"sk_hgrunt_health3","0"};
CVAR_REGISTER ( &sk_hgrunt_kick1 );// {"sk_hgrunt_kick1","0"};
CVAR_REGISTER ( &sk_hgrunt_kick2 );// {"sk_hgrunt_kick2","0"};
CVAR_REGISTER ( &sk_hgrunt_kick3 );// {"sk_hgrunt_kick3","0"};
CVAR_REGISTER ( &sk_hgrunt_pellets1 );
CVAR_REGISTER ( &sk_hgrunt_pellets2 );
CVAR_REGISTER ( &sk_hgrunt_pellets3 );
CVAR_REGISTER ( &sk_hgrunt_gspeed1 );
CVAR_REGISTER ( &sk_hgrunt_gspeed2 );
CVAR_REGISTER ( &sk_hgrunt_gspeed3 );
// Houndeye
CVAR_REGISTER ( &sk_houndeye_health1 );// {"sk_houndeye_health1","0"};
CVAR_REGISTER ( &sk_houndeye_health2 );// {"sk_houndeye_health2","0"};
CVAR_REGISTER ( &sk_houndeye_health3 );// {"sk_houndeye_health3","0"};
CVAR_REGISTER ( &sk_houndeye_dmg_blast1 );// {"sk_houndeye_dmg_blast1","0"};
CVAR_REGISTER ( &sk_houndeye_dmg_blast2 );// {"sk_houndeye_dmg_blast2","0"};
CVAR_REGISTER ( &sk_houndeye_dmg_blast3 );// {"sk_houndeye_dmg_blast3","0"};
// ISlave
CVAR_REGISTER ( &sk_islave_health1 );// {"sk_islave_health1","0"};
CVAR_REGISTER ( &sk_islave_health2 );// {"sk_islave_health2","0"};
CVAR_REGISTER ( &sk_islave_health3 );// {"sk_islave_health3","0"};
CVAR_REGISTER ( &sk_islave_dmg_claw1 );// {"sk_islave_dmg_claw1","0"};
CVAR_REGISTER ( &sk_islave_dmg_claw2 );// {"sk_islave_dmg_claw2","0"};
CVAR_REGISTER ( &sk_islave_dmg_claw3 );// {"sk_islave_dmg_claw3","0"};
CVAR_REGISTER ( &sk_islave_dmg_clawrake1 );// {"sk_islave_dmg_clawrake1","0"};
CVAR_REGISTER ( &sk_islave_dmg_clawrake2 );// {"sk_islave_dmg_clawrake2","0"};
CVAR_REGISTER ( &sk_islave_dmg_clawrake3 );// {"sk_islave_dmg_clawrake3","0"};
CVAR_REGISTER ( &sk_islave_dmg_zap1 );// {"sk_islave_dmg_zap1","0"};
CVAR_REGISTER ( &sk_islave_dmg_zap2 );// {"sk_islave_dmg_zap2","0"};
CVAR_REGISTER ( &sk_islave_dmg_zap3 );// {"sk_islave_dmg_zap3","0"};
// Icthyosaur
CVAR_REGISTER ( &sk_ichthyosaur_health1 );// {"sk_ichthyosaur_health1","0"};
CVAR_REGISTER ( &sk_ichthyosaur_health2 );// {"sk_ichthyosaur_health2","0"};
CVAR_REGISTER ( &sk_ichthyosaur_health3 );// {"sk_ichthyosaur_health3","0"};
CVAR_REGISTER ( &sk_ichthyosaur_shake1 );// {"sk_ichthyosaur_health3","0"};
CVAR_REGISTER ( &sk_ichthyosaur_shake2 );// {"sk_ichthyosaur_health3","0"};
CVAR_REGISTER ( &sk_ichthyosaur_shake3 );// {"sk_ichthyosaur_health3","0"};
// Leech
CVAR_REGISTER ( &sk_leech_health1 );// {"sk_leech_health1","0"};
CVAR_REGISTER ( &sk_leech_health2 );// {"sk_leech_health2","0"};
CVAR_REGISTER ( &sk_leech_health3 );// {"sk_leech_health3","0"};
CVAR_REGISTER ( &sk_leech_dmg_bite1 );// {"sk_leech_dmg_bite1","0"};
CVAR_REGISTER ( &sk_leech_dmg_bite2 );// {"sk_leech_dmg_bite2","0"};
CVAR_REGISTER ( &sk_leech_dmg_bite3 );// {"sk_leech_dmg_bite3","0"};
// Controller
CVAR_REGISTER ( &sk_controller_health1 );
CVAR_REGISTER ( &sk_controller_health2 );
CVAR_REGISTER ( &sk_controller_health3 );
CVAR_REGISTER ( &sk_controller_dmgzap1 );
CVAR_REGISTER ( &sk_controller_dmgzap2 );
CVAR_REGISTER ( &sk_controller_dmgzap3 );
CVAR_REGISTER ( &sk_controller_speedball1 );
CVAR_REGISTER ( &sk_controller_speedball2 );
CVAR_REGISTER ( &sk_controller_speedball3 );
CVAR_REGISTER ( &sk_controller_dmgball1 );
CVAR_REGISTER ( &sk_controller_dmgball2 );
CVAR_REGISTER ( &sk_controller_dmgball3 );
// Nihilanth
CVAR_REGISTER ( &sk_nihilanth_health1 );// {"sk_nihilanth_health1","0"};
CVAR_REGISTER ( &sk_nihilanth_health2 );// {"sk_nihilanth_health2","0"};
CVAR_REGISTER ( &sk_nihilanth_health3 );// {"sk_nihilanth_health3","0"};
CVAR_REGISTER ( &sk_nihilanth_zap1 );
CVAR_REGISTER ( &sk_nihilanth_zap2 );
CVAR_REGISTER ( &sk_nihilanth_zap3 );
// Scientist
CVAR_REGISTER ( &sk_scientist_health1 );// {"sk_scientist_health1","0"};
CVAR_REGISTER ( &sk_scientist_health2 );// {"sk_scientist_health2","0"};
CVAR_REGISTER ( &sk_scientist_health3 );// {"sk_scientist_health3","0"};
// Snark
CVAR_REGISTER ( &sk_snark_health1 );// {"sk_snark_health1","0"};
CVAR_REGISTER ( &sk_snark_health2 );// {"sk_snark_health2","0"};
CVAR_REGISTER ( &sk_snark_health3 );// {"sk_snark_health3","0"};
CVAR_REGISTER ( &sk_snark_dmg_bite1 );// {"sk_snark_dmg_bite1","0"};
CVAR_REGISTER ( &sk_snark_dmg_bite2 );// {"sk_snark_dmg_bite2","0"};
CVAR_REGISTER ( &sk_snark_dmg_bite3 );// {"sk_snark_dmg_bite3","0"};
CVAR_REGISTER ( &sk_snark_dmg_pop1 );// {"sk_snark_dmg_pop1","0"};
CVAR_REGISTER ( &sk_snark_dmg_pop2 );// {"sk_snark_dmg_pop2","0"};
CVAR_REGISTER ( &sk_snark_dmg_pop3 );// {"sk_snark_dmg_pop3","0"};
// Zombie
CVAR_REGISTER ( &sk_zombie_health1 );// {"sk_zombie_health1","0"};
CVAR_REGISTER ( &sk_zombie_health2 );// {"sk_zombie_health3","0"};
CVAR_REGISTER ( &sk_zombie_health3 );// {"sk_zombie_health3","0"};
CVAR_REGISTER ( &sk_zombie_dmg_one_slash1 );// {"sk_zombie_dmg_one_slash1","0"};
CVAR_REGISTER ( &sk_zombie_dmg_one_slash2 );// {"sk_zombie_dmg_one_slash2","0"};
CVAR_REGISTER ( &sk_zombie_dmg_one_slash3 );// {"sk_zombie_dmg_one_slash3","0"};
CVAR_REGISTER ( &sk_zombie_dmg_both_slash1 );// {"sk_zombie_dmg_both_slash1","0"};
CVAR_REGISTER ( &sk_zombie_dmg_both_slash2 );// {"sk_zombie_dmg_both_slash2","0"};
CVAR_REGISTER ( &sk_zombie_dmg_both_slash3 );// {"sk_zombie_dmg_both_slash3","0"};
//Turret
CVAR_REGISTER ( &sk_turret_health1 );// {"sk_turret_health1","0"};
CVAR_REGISTER ( &sk_turret_health2 );// {"sk_turret_health2","0"};
CVAR_REGISTER ( &sk_turret_health3 );// {"sk_turret_health3","0"};
// MiniTurret
CVAR_REGISTER ( &sk_miniturret_health1 );// {"sk_miniturret_health1","0"};
CVAR_REGISTER ( &sk_miniturret_health2 );// {"sk_miniturret_health2","0"};
CVAR_REGISTER ( &sk_miniturret_health3 );// {"sk_miniturret_health3","0"};
// Sentry Turret
CVAR_REGISTER ( &sk_sentry_health1 );// {"sk_sentry_health1","0"};
CVAR_REGISTER ( &sk_sentry_health2 );// {"sk_sentry_health2","0"};
CVAR_REGISTER ( &sk_sentry_health3 );// {"sk_sentry_health3","0"};
// PLAYER WEAPONS
// Crowbar whack
CVAR_REGISTER ( &sk_plr_crowbar1 );// {"sk_plr_crowbar1","0"};
CVAR_REGISTER ( &sk_plr_crowbar2 );// {"sk_plr_crowbar2","0"};
CVAR_REGISTER ( &sk_plr_crowbar3 );// {"sk_plr_crowbar3","0"};
// Glock Round
CVAR_REGISTER ( &sk_plr_9mm_bullet1 );// {"sk_plr_9mm_bullet1","0"};
CVAR_REGISTER ( &sk_plr_9mm_bullet2 );// {"sk_plr_9mm_bullet2","0"};
CVAR_REGISTER ( &sk_plr_9mm_bullet3 );// {"sk_plr_9mm_bullet3","0"};
// 357 Round
CVAR_REGISTER ( &sk_plr_357_bullet1 );// {"sk_plr_357_bullet1","0"};
CVAR_REGISTER ( &sk_plr_357_bullet2 );// {"sk_plr_357_bullet2","0"};
CVAR_REGISTER ( &sk_plr_357_bullet3 );// {"sk_plr_357_bullet3","0"};
// MP5 Round
CVAR_REGISTER ( &sk_plr_9mmAR_bullet1 );// {"sk_plr_9mmAR_bullet1","0"};
CVAR_REGISTER ( &sk_plr_9mmAR_bullet2 );// {"sk_plr_9mmAR_bullet2","0"};
CVAR_REGISTER ( &sk_plr_9mmAR_bullet3 );// {"sk_plr_9mmAR_bullet3","0"};
// M203 grenade
CVAR_REGISTER ( &sk_plr_9mmAR_grenade1 );// {"sk_plr_9mmAR_grenade1","0"};
CVAR_REGISTER ( &sk_plr_9mmAR_grenade2 );// {"sk_plr_9mmAR_grenade2","0"};
CVAR_REGISTER ( &sk_plr_9mmAR_grenade3 );// {"sk_plr_9mmAR_grenade3","0"};
// Shotgun buckshot
CVAR_REGISTER ( &sk_plr_buckshot1 );// {"sk_plr_buckshot1","0"};
CVAR_REGISTER ( &sk_plr_buckshot2 );// {"sk_plr_buckshot2","0"};
CVAR_REGISTER ( &sk_plr_buckshot3 );// {"sk_plr_buckshot3","0"};
// Crossbow
CVAR_REGISTER ( &sk_plr_xbow_bolt_monster1 );// {"sk_plr_xbow_bolt1","0"};
CVAR_REGISTER ( &sk_plr_xbow_bolt_monster2 );// {"sk_plr_xbow_bolt2","0"};
CVAR_REGISTER ( &sk_plr_xbow_bolt_monster3 );// {"sk_plr_xbow_bolt3","0"};
CVAR_REGISTER ( &sk_plr_xbow_bolt_client1 );// {"sk_plr_xbow_bolt1","0"};
CVAR_REGISTER ( &sk_plr_xbow_bolt_client2 );// {"sk_plr_xbow_bolt2","0"};
CVAR_REGISTER ( &sk_plr_xbow_bolt_client3 );// {"sk_plr_xbow_bolt3","0"};
// RPG
CVAR_REGISTER ( &sk_plr_rpg1 );// {"sk_plr_rpg1","0"};
CVAR_REGISTER ( &sk_plr_rpg2 );// {"sk_plr_rpg2","0"};
CVAR_REGISTER ( &sk_plr_rpg3 );// {"sk_plr_rpg3","0"};
// Gauss Gun
CVAR_REGISTER ( &sk_plr_gauss1 );// {"sk_plr_gauss1","0"};
CVAR_REGISTER ( &sk_plr_gauss2 );// {"sk_plr_gauss2","0"};
CVAR_REGISTER ( &sk_plr_gauss3 );// {"sk_plr_gauss3","0"};
// Egon Gun
CVAR_REGISTER ( &sk_plr_egon_narrow1 );// {"sk_plr_egon_narrow1","0"};
CVAR_REGISTER ( &sk_plr_egon_narrow2 );// {"sk_plr_egon_narrow2","0"};
CVAR_REGISTER ( &sk_plr_egon_narrow3 );// {"sk_plr_egon_narrow3","0"};
CVAR_REGISTER ( &sk_plr_egon_wide1 );// {"sk_plr_egon_wide1","0"};
CVAR_REGISTER ( &sk_plr_egon_wide2 );// {"sk_plr_egon_wide2","0"};
CVAR_REGISTER ( &sk_plr_egon_wide3 );// {"sk_plr_egon_wide3","0"};
// Hand Grendade
CVAR_REGISTER ( &sk_plr_hand_grenade1 );// {"sk_plr_hand_grenade1","0"};
CVAR_REGISTER ( &sk_plr_hand_grenade2 );// {"sk_plr_hand_grenade2","0"};
CVAR_REGISTER ( &sk_plr_hand_grenade3 );// {"sk_plr_hand_grenade3","0"};
// Satchel Charge
CVAR_REGISTER ( &sk_plr_satchel1 );// {"sk_plr_satchel1","0"};
CVAR_REGISTER ( &sk_plr_satchel2 );// {"sk_plr_satchel2","0"};
CVAR_REGISTER ( &sk_plr_satchel3 );// {"sk_plr_satchel3","0"};
// Tripmine
CVAR_REGISTER ( &sk_plr_tripmine1 );// {"sk_plr_tripmine1","0"};
CVAR_REGISTER ( &sk_plr_tripmine2 );// {"sk_plr_tripmine2","0"};
CVAR_REGISTER ( &sk_plr_tripmine3 );// {"sk_plr_tripmine3","0"};
// WORLD WEAPONS
CVAR_REGISTER ( &sk_12mm_bullet1 );// {"sk_12mm_bullet1","0"};
CVAR_REGISTER ( &sk_12mm_bullet2 );// {"sk_12mm_bullet2","0"};
CVAR_REGISTER ( &sk_12mm_bullet3 );// {"sk_12mm_bullet3","0"};
CVAR_REGISTER ( &sk_9mmAR_bullet1 );// {"sk_9mm_bullet1","0"};
CVAR_REGISTER ( &sk_9mmAR_bullet2 );// {"sk_9mm_bullet1","0"};
CVAR_REGISTER ( &sk_9mmAR_bullet3 );// {"sk_9mm_bullet1","0"};
CVAR_REGISTER ( &sk_9mm_bullet1 );// {"sk_9mm_bullet1","0"};
CVAR_REGISTER ( &sk_9mm_bullet2 );// {"sk_9mm_bullet2","0"};
CVAR_REGISTER ( &sk_9mm_bullet3 );// {"sk_9mm_bullet3","0"};
// HORNET
CVAR_REGISTER ( &sk_hornet_dmg1 );// {"sk_hornet_dmg1","0"};
CVAR_REGISTER ( &sk_hornet_dmg2 );// {"sk_hornet_dmg2","0"};
CVAR_REGISTER ( &sk_hornet_dmg3 );// {"sk_hornet_dmg3","0"};
// HEALTH/SUIT CHARGE DISTRIBUTION
CVAR_REGISTER ( &sk_suitcharger1 );
CVAR_REGISTER ( &sk_suitcharger2 );
CVAR_REGISTER ( &sk_suitcharger3 );
CVAR_REGISTER ( &sk_battery1 );
CVAR_REGISTER ( &sk_battery2 );
CVAR_REGISTER ( &sk_battery3 );
CVAR_REGISTER ( &sk_healthcharger1 );
CVAR_REGISTER ( &sk_healthcharger2 );
CVAR_REGISTER ( &sk_healthcharger3 );
CVAR_REGISTER ( &sk_healthkit1 );
CVAR_REGISTER ( &sk_healthkit2 );
CVAR_REGISTER ( &sk_healthkit3 );
CVAR_REGISTER ( &sk_scientist_heal1 );
CVAR_REGISTER ( &sk_scientist_heal2 );
CVAR_REGISTER ( &sk_scientist_heal3 );
// monster damage adjusters
CVAR_REGISTER ( &sk_monster_head1 );
CVAR_REGISTER ( &sk_monster_head2 );
CVAR_REGISTER ( &sk_monster_head3 );
CVAR_REGISTER ( &sk_monster_chest1 );
CVAR_REGISTER ( &sk_monster_chest2 );
CVAR_REGISTER ( &sk_monster_chest3 );
CVAR_REGISTER ( &sk_monster_stomach1 );
CVAR_REGISTER ( &sk_monster_stomach2 );
CVAR_REGISTER ( &sk_monster_stomach3 );
CVAR_REGISTER ( &sk_monster_arm1 );
CVAR_REGISTER ( &sk_monster_arm2 );
CVAR_REGISTER ( &sk_monster_arm3 );
CVAR_REGISTER ( &sk_monster_leg1 );
CVAR_REGISTER ( &sk_monster_leg2 );
CVAR_REGISTER ( &sk_monster_leg3 );
// player damage adjusters
CVAR_REGISTER ( &sk_player_head1 );
CVAR_REGISTER ( &sk_player_head2 );
CVAR_REGISTER ( &sk_player_head3 );
CVAR_REGISTER ( &sk_player_chest1 );
CVAR_REGISTER ( &sk_player_chest2 );
CVAR_REGISTER ( &sk_player_chest3 );
CVAR_REGISTER ( &sk_player_stomach1 );
CVAR_REGISTER ( &sk_player_stomach2 );
CVAR_REGISTER ( &sk_player_stomach3 );
CVAR_REGISTER ( &sk_player_arm1 );
CVAR_REGISTER ( &sk_player_arm2 );
CVAR_REGISTER ( &sk_player_arm3 );
CVAR_REGISTER ( &sk_player_leg1 );
CVAR_REGISTER ( &sk_player_leg2 );
CVAR_REGISTER ( &sk_player_leg3 );
// END REGISTER CVARS FOR SKILL LEVEL STUFF
SERVER_COMMAND( "exec skill.cfg\n" );
}

42
dlls/game.h Normal file
View File

@ -0,0 +1,42 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef GAME_H
#define GAME_H
extern void GameDLLInit( void );
extern cvar_t displaysoundlist;
extern cvar_t mapcyclefile;
extern cvar_t servercfgfile;
extern cvar_t lservercfgfile;
// multiplayer server rules
extern cvar_t fraglimit;
extern cvar_t timelimit;
extern cvar_t friendlyfir;
extern cvar_t falldamage;
extern cvar_t weaponstay;
extern cvar_t forcerespaw;
extern cvar_t footsteps;
extern cvar_t flashlight;
extern cvar_t aimcrosshair;
extern cvar_t decalfrequency;
extern cvar_t teamlist;
extern cvar_t teamoverride;
extern cvar_t defaultteam;
#endif // GAME_H

335
dlls/gamerules.cpp Normal file
View File

@ -0,0 +1,335 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//=========================================================
// GameRules.cpp
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
#include "weapons.h"
#include "gamerules.h"
#include "teamplay_gamerules.h"
#include "skill.h"
extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer );
DLL_GLOBAL CGameRules* g_pGameRules = NULL;
extern DLL_GLOBAL BOOL g_fGameOver;
extern int gmsgDeathMsg; // client dll messages
extern int gmsgScoreInfo;
extern int gmsgMOTD;
//=========================================================
//=========================================================
BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry )
{
int iAmmoIndex;
if ( pszAmmoName )
{
iAmmoIndex = pPlayer->GetAmmoIndex( pszAmmoName );
if ( iAmmoIndex > -1 )
{
if ( pPlayer->AmmoInventory( iAmmoIndex ) < iMaxCarry )
{
// player has room for more of this type of ammo
return TRUE;
}
}
}
return FALSE;
}
//=========================================================
//=========================================================
edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer )
{
edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer );
pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1);
pPlayer->pev->v_angle = g_vecZero;
pPlayer->pev->velocity = g_vecZero;
pPlayer->pev->angles = VARS(pentSpawnSpot)->angles;
pPlayer->pev->punchangle = g_vecZero;
pPlayer->pev->fixangle = TRUE;
return pentSpawnSpot;
}
//=========================================================
//=========================================================
BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon )
{
if ( pWeapon->pszAmmo1() )
{
if ( !CanHaveAmmo( pPlayer, pWeapon->pszAmmo1(), pWeapon->iMaxAmmo1() ) )
{
// we can't carry anymore ammo for this gun. We can only
// have the gun if we aren't already carrying one of this type
if ( pPlayer->HasPlayerItem( pWeapon ) )
{
return FALSE;
}
}
}
else
{
// weapon doesn't use ammo, don't take another if you already have it.
if ( pPlayer->HasPlayerItem( pWeapon ) )
{
return FALSE;
}
}
// note: will fall through to here if GetItemInfo doesn't fill the struct!
return TRUE;
}
//=========================================================
// load the SkillData struct with the proper values based on the skill level.
//=========================================================
void CGameRules::RefreshSkillData ( void )
{
int iSkill;
iSkill = (int)CVAR_GET_FLOAT("skill");
if ( iSkill < 1 )
{
iSkill = 1;
}
else if ( iSkill > 3 )
{
iSkill = 3;
}
gSkillData.iSkillLevel = iSkill;
ALERT ( at_console, "\nGAME SKILL LEVEL:%d\n",iSkill );
//Agrunt
gSkillData.agruntHealth = GetSkillCvar( "sk_agrunt_health" );
gSkillData.agruntDmgPunch = GetSkillCvar( "sk_agrunt_dmg_punch");
// Apache
gSkillData.apacheHealth = GetSkillCvar( "sk_apache_health");
// Barney
gSkillData.barneyHealth = GetSkillCvar( "sk_barney_health");
// Big Momma
gSkillData.bigmommaHealthFactor = GetSkillCvar( "sk_bigmomma_health_factor" );
gSkillData.bigmommaDmgSlash = GetSkillCvar( "sk_bigmomma_dmg_slash" );
gSkillData.bigmommaDmgBlast = GetSkillCvar( "sk_bigmomma_dmg_blast" );
gSkillData.bigmommaRadiusBlast = GetSkillCvar( "sk_bigmomma_radius_blast" );
// Bullsquid
gSkillData.bullsquidHealth = GetSkillCvar( "sk_bullsquid_health");
gSkillData.bullsquidDmgBite = GetSkillCvar( "sk_bullsquid_dmg_bite");
gSkillData.bullsquidDmgWhip = GetSkillCvar( "sk_bullsquid_dmg_whip");
gSkillData.bullsquidDmgSpit = GetSkillCvar( "sk_bullsquid_dmg_spit");
// Gargantua
gSkillData.gargantuaHealth = GetSkillCvar( "sk_gargantua_health");
gSkillData.gargantuaDmgSlash = GetSkillCvar( "sk_gargantua_dmg_slash");
gSkillData.gargantuaDmgFire = GetSkillCvar( "sk_gargantua_dmg_fire");
gSkillData.gargantuaDmgStomp = GetSkillCvar( "sk_gargantua_dmg_stomp");
// Hassassin
gSkillData.hassassinHealth = GetSkillCvar( "sk_hassassin_health");
// Headcrab
gSkillData.headcrabHealth = GetSkillCvar( "sk_headcrab_health");
gSkillData.headcrabDmgBite = GetSkillCvar( "sk_headcrab_dmg_bite");
// Hgrunt
gSkillData.hgruntHealth = GetSkillCvar( "sk_hgrunt_health");
gSkillData.hgruntDmgKick = GetSkillCvar( "sk_hgrunt_kick");
gSkillData.hgruntShotgunPellets = GetSkillCvar( "sk_hgrunt_pellets");
gSkillData.hgruntGrenadeSpeed = GetSkillCvar( "sk_hgrunt_gspeed");
// Houndeye
gSkillData.houndeyeHealth = GetSkillCvar( "sk_houndeye_health");
gSkillData.houndeyeDmgBlast = GetSkillCvar( "sk_houndeye_dmg_blast");
// ISlave
gSkillData.slaveHealth = GetSkillCvar( "sk_islave_health");
gSkillData.slaveDmgClaw = GetSkillCvar( "sk_islave_dmg_claw");
gSkillData.slaveDmgClawrake = GetSkillCvar( "sk_islave_dmg_clawrake");
gSkillData.slaveDmgZap = GetSkillCvar( "sk_islave_dmg_zap");
// Icthyosaur
gSkillData.ichthyosaurHealth = GetSkillCvar( "sk_ichthyosaur_health");
gSkillData.ichthyosaurDmgShake = GetSkillCvar( "sk_ichthyosaur_shake");
// Leech
gSkillData.leechHealth = GetSkillCvar( "sk_leech_health");
gSkillData.leechDmgBite = GetSkillCvar( "sk_leech_dmg_bite");
// Controller
gSkillData.controllerHealth = GetSkillCvar( "sk_controller_health");
gSkillData.controllerDmgZap = GetSkillCvar( "sk_controller_dmgzap");
gSkillData.controllerSpeedBall = GetSkillCvar( "sk_controller_speedball");
gSkillData.controllerDmgBall = GetSkillCvar( "sk_controller_dmgball");
// Nihilanth
gSkillData.nihilanthHealth = GetSkillCvar( "sk_nihilanth_health");
gSkillData.nihilanthZap = GetSkillCvar( "sk_nihilanth_zap");
// Scientist
gSkillData.scientistHealth = GetSkillCvar( "sk_scientist_health");
// Snark
gSkillData.snarkHealth = GetSkillCvar( "sk_snark_health");
gSkillData.snarkDmgBite = GetSkillCvar( "sk_snark_dmg_bite");
gSkillData.snarkDmgPop = GetSkillCvar( "sk_snark_dmg_pop");
// Zombie
gSkillData.zombieHealth = GetSkillCvar( "sk_zombie_health");
gSkillData.zombieDmgOneSlash = GetSkillCvar( "sk_zombie_dmg_one_slash");
gSkillData.zombieDmgBothSlash = GetSkillCvar( "sk_zombie_dmg_both_slash");
//Turret
gSkillData.turretHealth = GetSkillCvar( "sk_turret_health");
// MiniTurret
gSkillData.miniturretHealth = GetSkillCvar( "sk_miniturret_health");
// Sentry Turret
gSkillData.sentryHealth = GetSkillCvar( "sk_sentry_health");
// PLAYER WEAPONS
// Crowbar whack
gSkillData.plrDmgCrowbar = GetSkillCvar( "sk_plr_crowbar");
// Glock Round
gSkillData.plrDmg9MM = GetSkillCvar( "sk_plr_9mm_bullet");
// 357 Round
gSkillData.plrDmg357 = GetSkillCvar( "sk_plr_357_bullet");
// MP5 Round
gSkillData.plrDmgMP5 = GetSkillCvar( "sk_plr_9mmAR_bullet");
// M203 grenade
gSkillData.plrDmgM203Grenade = GetSkillCvar( "sk_plr_9mmAR_grenade");
// Shotgun buckshot
gSkillData.plrDmgBuckshot = GetSkillCvar( "sk_plr_buckshot");
// Crossbow
gSkillData.plrDmgCrossbowClient = GetSkillCvar( "sk_plr_xbow_bolt_client");
gSkillData.plrDmgCrossbowMonster = GetSkillCvar( "sk_plr_xbow_bolt_monster");
// RPG
gSkillData.plrDmgRPG = GetSkillCvar( "sk_plr_rpg");
// Gauss gun
gSkillData.plrDmgGauss = GetSkillCvar( "sk_plr_gauss");
// Egon Gun
gSkillData.plrDmgEgonNarrow = GetSkillCvar( "sk_plr_egon_narrow");
gSkillData.plrDmgEgonWide = GetSkillCvar( "sk_plr_egon_wide");
// Hand Grendade
gSkillData.plrDmgHandGrenade = GetSkillCvar( "sk_plr_hand_grenade");
// Satchel Charge
gSkillData.plrDmgSatchel = GetSkillCvar( "sk_plr_satchel");
// Tripmine
gSkillData.plrDmgTripmine = GetSkillCvar( "sk_plr_tripmine");
// MONSTER WEAPONS
gSkillData.monDmg12MM = GetSkillCvar( "sk_12mm_bullet");
gSkillData.monDmgMP5 = GetSkillCvar ("sk_9mmAR_bullet" );
gSkillData.monDmg9MM = GetSkillCvar( "sk_9mm_bullet");
// MONSTER HORNET
gSkillData.monDmgHornet = GetSkillCvar( "sk_hornet_dmg");
// PLAYER HORNET
// Up to this point, player hornet damage and monster hornet damage were both using
// monDmgHornet to determine how much damage to do. In tuning the hivehand, we now need
// to separate player damage and monster hivehand damage. Since it's so late in the project, we've
// added plrDmgHornet to the SKILLDATA struct, but not to the engine CVar list, so it's inaccesible
// via SKILLS.CFG. Any player hivehand tuning must take place in the code. (sjb)
gSkillData.plrDmgHornet = 7;
// HEALTH/CHARGE
gSkillData.suitchargerCapacity = GetSkillCvar( "sk_suitcharger" );
gSkillData.batteryCapacity = GetSkillCvar( "sk_battery" );
gSkillData.healthchargerCapacity = GetSkillCvar ( "sk_healthcharger" );
gSkillData.healthkitCapacity = GetSkillCvar ( "sk_healthkit" );
gSkillData.scientistHeal = GetSkillCvar ( "sk_scientist_heal" );
// monster damage adj
gSkillData.monHead = GetSkillCvar( "sk_monster_head" );
gSkillData.monChest = GetSkillCvar( "sk_monster_chest" );
gSkillData.monStomach = GetSkillCvar( "sk_monster_stomach" );
gSkillData.monLeg = GetSkillCvar( "sk_monster_leg" );
gSkillData.monArm = GetSkillCvar( "sk_monster_arm" );
// player damage adj
gSkillData.plrHead = GetSkillCvar( "sk_player_head" );
gSkillData.plrChest = GetSkillCvar( "sk_player_chest" );
gSkillData.plrStomach = GetSkillCvar( "sk_player_stomach" );
gSkillData.plrLeg = GetSkillCvar( "sk_player_leg" );
gSkillData.plrArm = GetSkillCvar( "sk_player_arm" );
}
//=========================================================
// instantiate the proper game rules object
//=========================================================
CGameRules *InstallGameRules( void )
{
SERVER_COMMAND( "exec game.cfg\n" );
SERVER_EXECUTE( );
if ( !gpGlobals->deathmatch )
{
// generic half-life
return new CHalfLifeRules;
}
else
{
if ( CVAR_GET_FLOAT( "mp_teamplay" ) > 0 )
{
// teamplay
return new CHalfLifeTeamplay;
}
if ((int)gpGlobals->deathmatch == 1)
{
// vanilla deathmatch
return new CHalfLifeMultiplay;
}
else
{
// vanilla deathmatch??
return new CHalfLifeMultiplay;
}
}
}

359
dlls/gamerules.h Normal file
View File

@ -0,0 +1,359 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//=========================================================
// GameRules
//=========================================================
//#include "weapons.h"
//#include "items.h"
class CBasePlayerItem;
class CBasePlayer;
class CItem;
class CBasePlayerAmmo;
// weapon respawning return codes
enum
{
GR_NONE = 0,
GR_WEAPON_RESPAWN_YES,
GR_WEAPON_RESPAWN_NO,
GR_AMMO_RESPAWN_YES,
GR_AMMO_RESPAWN_NO,
GR_ITEM_RESPAWN_YES,
GR_ITEM_RESPAWN_NO,
GR_PLR_DROP_GUN_ALL,
GR_PLR_DROP_GUN_ACTIVE,
GR_PLR_DROP_GUN_NO,
GR_PLR_DROP_AMMO_ALL,
GR_PLR_DROP_AMMO_ACTIVE,
GR_PLR_DROP_AMMO_NO,
};
// Player relationship return codes
enum
{
GR_NOTTEAMMATE = 0,
GR_TEAMMATE,
GR_ENEMY,
GR_ALLY,
GR_NEUTRAL,
};
class CGameRules
{
public:
virtual void RefreshSkillData( void );// fill skill data struct with proper values
virtual void Think( void ) = 0;// GR_Think - runs every server frame, should handle any timer tasks, periodic events, etc.
virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ) = 0; // Can this item spawn (eg monsters don't spawn in deathmatch).
virtual BOOL FAllowFlashlight( void ) = 0;// Are players allowed to switch on their flashlight?
virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// should the player switch to this weapon?
virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) = 0;// I can't use this weapon anymore, get me the next best one.
// Functions to verify the single/multiplayer status of a game
virtual BOOL IsMultiplayer( void ) = 0;// is this a multiplayer game? (either coop or deathmatch)
virtual BOOL IsDeathmatch( void ) = 0;//is this a deathmatch game?
virtual BOOL IsTeamplay( void ) { return FALSE; };// is this deathmatch game being played with team rules?
virtual BOOL IsCoOp( void ) = 0;// is this a coop game?
virtual const char *GetGameDescription( void ) { return "Half-Life"; } // this is the game name that gets seen in the server browser
// Client connection/disconnection
virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) = 0;// a client just connected to the server (player hasn't spawned yet)
virtual void InitHUD( CBasePlayer *pl ) = 0; // the client dll is ready for updating
virtual void ClientDisconnected( edict_t *pClient ) = 0;// a client just disconnected from the server
virtual void UpdateGameMode( CBasePlayer *pPlayer ) {} // the client needs to be informed of the current game mode
// Client damage rules
virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ) = 0;// this client just hit the ground after a fall. How much damage?
virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) {return TRUE;};// can this player take damage from this attacker?
virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) { return TRUE; }
// Client spawn/respawn control
virtual void PlayerSpawn( CBasePlayer *pPlayer ) = 0;// called by CBasePlayer::Spawn just before releasing player into the game
virtual void PlayerThink( CBasePlayer *pPlayer ) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted
virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ) = 0;// is this player allowed to respawn now?
virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ) = 0;// When in the future will this player be able to spawn?
virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer );// Place this player on their spawnspot and face them the proper direction.
virtual BOOL AllowAutoTargetCrosshair( void ) { return TRUE; };
virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { return FALSE; }; // handles the user commands; returns TRUE if command handled properly
virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) {} // the player has changed userinfo; can change it now
// Client kills/scoring
virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) = 0;// how many points do I award whoever kills this player?
virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) = 0;// Called each time a player dies
virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )= 0;// Call this from within a GameRules class to report an obituary.
// Weapon retrieval
virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him?
virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// Called each time a player picks up a weapon from the ground
// Weapon spawn/respawn control
virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ) = 0;// should this weapon respawn?
virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) = 0;// when may this weapon respawn?
virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) = 0; // can i respawn now, and if not, when should i try again?
virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) = 0;// where in the world should this weapon respawn?
// Item retrieval
virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// is this player allowed to take this item?
virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// call each time a player picks up an item (battery, healthkit, longjump)
// Item spawn/respawn control
virtual int ItemShouldRespawn( CItem *pItem ) = 0;// Should this item respawn?
virtual float FlItemRespawnTime( CItem *pItem ) = 0;// when may this item respawn?
virtual Vector VecItemRespawnSpot( CItem *pItem ) = 0;// where in the world should this item respawn?
// Ammo retrieval
virtual BOOL CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry );// can this player take more of this ammo?
virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) = 0;// called each time a player picks up some ammo in the world
// Ammo spawn/respawn control
virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) = 0;// should this ammo item respawn?
virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) = 0;// when should this ammo item respawn?
virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) = 0;// where in the world should this ammo item respawn?
// by default, everything spawns
// Healthcharger respawn control
virtual float FlHealthChargerRechargeTime( void ) = 0;// how long until a depleted HealthCharger recharges itself?
virtual float FlHEVChargerRechargeTime( void ) { return 0; }// how long until a depleted HealthCharger recharges itself?
// What happens to a dead player's weapons
virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ) = 0;// what do I do with a player's weapons when he's killed?
// What happens to a dead player's ammo
virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ) = 0;// Do I drop ammo when the player dies? How much?
// Teamplay stuff
virtual const char *GetTeamID( CBaseEntity *pEntity ) = 0;// what team is this entity on?
virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) = 0;// What is the player's relationship with this entity?
virtual int GetTeamIndex( const char *pTeamName ) { return -1; }
virtual const char *GetIndexedTeamName( int teamIndex ) { return ""; }
virtual BOOL IsValidTeam( const char *pTeamName ) { return TRUE; }
virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) {}
virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; }
// Sounds
virtual BOOL PlayTextureSounds( void ) { return TRUE; }
virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ) { return TRUE; }
// Monsters
virtual BOOL FAllowMonsters( void ) = 0;//are monsters allowed
// Immediately end a multiplayer game
virtual void EndMultiplayerGame( void ) {}
};
extern CGameRules *InstallGameRules( void );
//=========================================================
// CHalfLifeRules - rules for the single player Half-Life
// game.
//=========================================================
class CHalfLifeRules : public CGameRules
{
public:
CHalfLifeRules ( void );
// GR_Think
virtual void Think( void );
virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity );
virtual BOOL FAllowFlashlight( void ) { return TRUE; };
virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );
virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon );
// Functions to verify the single/multiplayer status of a game
virtual BOOL IsMultiplayer( void );
virtual BOOL IsDeathmatch( void );
virtual BOOL IsCoOp( void );
// Client connection/disconnection
virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] );
virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating
virtual void ClientDisconnected( edict_t *pClient );
// Client damage rules
virtual float FlPlayerFallDamage( CBasePlayer *pPlayer );
// Client spawn/respawn control
virtual void PlayerSpawn( CBasePlayer *pPlayer );
virtual void PlayerThink( CBasePlayer *pPlayer );
virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer );
virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer );
virtual BOOL AllowAutoTargetCrosshair( void );
// Client kills/scoring
virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled );
virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor );
virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor );
// Weapon retrieval
virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );
// Weapon spawn/respawn control
virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon );
virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon );
virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon );
virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon );
// Item retrieval
virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem );
virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem );
// Item spawn/respawn control
virtual int ItemShouldRespawn( CItem *pItem );
virtual float FlItemRespawnTime( CItem *pItem );
virtual Vector VecItemRespawnSpot( CItem *pItem );
// Ammo retrieval
virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount );
// Ammo spawn/respawn control
virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo );
virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo );
virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo );
// Healthcharger respawn control
virtual float FlHealthChargerRechargeTime( void );
// What happens to a dead player's weapons
virtual int DeadPlayerWeapons( CBasePlayer *pPlayer );
// What happens to a dead player's ammo
virtual int DeadPlayerAmmo( CBasePlayer *pPlayer );
// Monsters
virtual BOOL FAllowMonsters( void );
// Teamplay stuff
virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";};
virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget );
};
//=========================================================
// CHalfLifeMultiplay - rules for the basic half life multiplayer
// competition
//=========================================================
class CHalfLifeMultiplay : public CGameRules
{
public:
CHalfLifeMultiplay();
// GR_Think
virtual void Think( void );
virtual void RefreshSkillData( void );
virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity );
virtual BOOL FAllowFlashlight( void );
virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );
virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon );
// Functions to verify the single/multiplayer status of a game
virtual BOOL IsMultiplayer( void );
virtual BOOL IsDeathmatch( void );
virtual BOOL IsCoOp( void );
// Client connection/disconnection
// If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in
// svRejectReason
// Only the client's name and remote address are provided to the dll for verification.
virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] );
virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating
virtual void ClientDisconnected( edict_t *pClient );
virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode
// Client damage rules
virtual float FlPlayerFallDamage( CBasePlayer *pPlayer );
virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker );
// Client spawn/respawn control
virtual void PlayerSpawn( CBasePlayer *pPlayer );
virtual void PlayerThink( CBasePlayer *pPlayer );
virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer );
virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer );
virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer );
virtual BOOL AllowAutoTargetCrosshair( void );
// Client kills/scoring
virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled );
virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor );
virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor );
// Weapon retrieval
virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );
virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him?
// Weapon spawn/respawn control
virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon );
virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon );
virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon );
virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon );
// Item retrieval
virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem );
virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem );
// Item spawn/respawn control
virtual int ItemShouldRespawn( CItem *pItem );
virtual float FlItemRespawnTime( CItem *pItem );
virtual Vector VecItemRespawnSpot( CItem *pItem );
// Ammo retrieval
virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount );
// Ammo spawn/respawn control
virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo );
virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo );
virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo );
// Healthcharger respawn control
virtual float FlHealthChargerRechargeTime( void );
virtual float FlHEVChargerRechargeTime( void );
// What happens to a dead player's weapons
virtual int DeadPlayerWeapons( CBasePlayer *pPlayer );
// What happens to a dead player's ammo
virtual int DeadPlayerAmmo( CBasePlayer *pPlayer );
// Teamplay stuff
virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}
virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget );
virtual BOOL PlayTextureSounds( void ) { return FALSE; }
virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol );
// Monsters
virtual BOOL FAllowMonsters( void );
// Immediately end a multiplayer game
virtual void EndMultiplayerGame( void ) { GoToIntermission(); }
protected:
virtual void ChangeLevel( void );
virtual void GoToIntermission( void );
float m_flIntermissionEndTime;
BOOL m_iEndIntermissionButtonHit;
void SendMOTDToClient( edict_t *client );
};
extern DLL_GLOBAL CGameRules* g_pGameRules;

857
dlls/gauss.cpp Normal file
View File

@ -0,0 +1,857 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "soundent.h"
#include "shake.h"
#include "gamerules.h"
#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging
#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged
enum gauss_e {
GAUSS_IDLE = 0,
GAUSS_IDLE2,
GAUSS_FIDGET,
GAUSS_SPINUP,
GAUSS_SPIN,
GAUSS_FIRE,
GAUSS_FIRE2,
GAUSS_HOLSTER,
GAUSS_DRAW
};
class CGauss : 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( void );
void PrimaryAttack( void );
void SecondaryAttack( void );
void WeaponIdle( void );
int m_fInAttack;
float m_flStartCharge;
float m_flPlayAftershock;
void StartFire( void );
void Fire( Vector vecOrigSrc, Vector vecDirShooting, float flDamage );
float GetFullChargeTime( void );
int m_iBalls;
int m_iGlow;
int m_iBeam;
int m_iSoundState; // don't save this
float m_flNextAmmoBurn;// while charging, when to absorb another unit of player's ammo?
// was this weapon just fired primary or secondary?
// we need to know so we can pick the right set of effects.
BOOL m_fPrimaryFire;
};
LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss );
TYPEDESCRIPTION CGauss::m_SaveData[] =
{
DEFINE_FIELD( CGauss, m_fInAttack, FIELD_INTEGER ),
DEFINE_FIELD( CGauss, m_flStartCharge, FIELD_TIME ),
DEFINE_FIELD( CGauss, m_flPlayAftershock, FIELD_TIME ),
DEFINE_FIELD( CGauss, m_flNextAmmoBurn, FIELD_TIME ),
DEFINE_FIELD( CGauss, m_fPrimaryFire, FIELD_BOOLEAN ),
};
IMPLEMENT_SAVERESTORE( CGauss, CBasePlayerWeapon );
float CGauss::GetFullChargeTime( void )
{
if ( g_pGameRules->IsMultiplayer() )
{
return 1.5;
}
return 4;
}
void CGauss::Spawn( )
{
Precache( );
m_iId = WEAPON_GAUSS;
SET_MODEL(ENT(pev), "models/w_gauss.mdl");
m_iDefaultAmmo = GAUSS_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CGauss::Precache( void )
{
PRECACHE_MODEL("models/w_gauss.mdl");
PRECACHE_MODEL("models/v_gauss.mdl");
PRECACHE_MODEL("models/p_gauss.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
PRECACHE_SOUND("weapons/gauss2.wav");
PRECACHE_SOUND("weapons/electro4.wav");
PRECACHE_SOUND("weapons/electro5.wav");
PRECACHE_SOUND("weapons/electro6.wav");
PRECACHE_SOUND("ambience/pulsemachine.wav");
m_iGlow = PRECACHE_MODEL( "sprites/hotglow.spr" );
m_iBalls = PRECACHE_MODEL( "sprites/hotglow.spr" );
m_iBeam = PRECACHE_MODEL( "sprites/smoke.spr" );
}
int CGauss::AddToPlayer( CBasePlayer *pPlayer )
{
if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
WRITE_BYTE( m_iId );
MESSAGE_END();
return TRUE;
}
return FALSE;
}
int CGauss::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "uranium";
p->iMaxAmmo1 = URANIUM_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 3;
p->iPosition = 1;
p->iId = m_iId = WEAPON_GAUSS;
p->iFlags = 0;
p->iWeight = GAUSS_WEIGHT;
return 1;
}
BOOL CGauss::Deploy( )
{
return DefaultDeploy( "models/v_gauss.mdl", "models/p_gauss.mdl", GAUSS_DRAW, "gauss" );
}
void CGauss::Holster( )
{
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
// m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
SendWeaponAnim( GAUSS_HOLSTER );
m_fInAttack = 0;
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM);
}
void CGauss::PrimaryAttack()
{
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
PlayEmptySound( );
m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->time + 0.15;
return;
}
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 2)
{
PlayEmptySound( );
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
return;
}
m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME;
m_fPrimaryFire = TRUE;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 2;
StartFire();
m_fInAttack = 0;
m_flTimeWeaponIdle = gpGlobals->time + 1.0;
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.2;
}
void CGauss::SecondaryAttack()
{
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
if ( m_fInAttack != 0 )
{
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f));
SendWeaponAnim( GAUSS_IDLE );
m_fInAttack = 0;
}
else
{
PlayEmptySound( );
}
m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->time + 0.5;
return;
}
if (m_fInAttack == 0)
{
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
{
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM);
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
return;
}
m_fPrimaryFire = FALSE;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;// take one ammo just to start the spin
m_flNextAmmoBurn = gpGlobals->time;
// spin up
m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME;
SendWeaponAnim( GAUSS_SPINUP );
m_fInAttack = 1;
m_flTimeWeaponIdle = gpGlobals->time + 0.5;
m_flStartCharge = gpGlobals->time;
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "ambience/pulsemachine.wav",1.0 , ATTN_NORM, 0, 110 );
m_iSoundState = SND_CHANGE_PITCH;
}
else if (m_fInAttack == 1)
{
if (m_flTimeWeaponIdle < gpGlobals->time)
{
SendWeaponAnim( GAUSS_SPIN );
m_fInAttack = 2;
}
}
else
{
if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0 )
{
// out of ammo! force the gun to fire
StartFire();
m_fInAttack = 0;
m_flTimeWeaponIdle = gpGlobals->time + 1.0;
m_pPlayer->m_flNextAttack = gpGlobals->time + 1;
return;
}
// during the charging process, eat one bit of ammo every once in a while
if ( gpGlobals->time > m_flNextAmmoBurn && m_flNextAmmoBurn != -1 )
{
if ( g_pGameRules->IsMultiplayer() )
{
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
m_flNextAmmoBurn = gpGlobals->time + 0.1;
}
else
{
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
m_flNextAmmoBurn = gpGlobals->time + 0.3;
}
}
if ( gpGlobals->time - m_flStartCharge >= GetFullChargeTime() )
{
// don't eat any more ammo after gun is fully charged.
m_flNextAmmoBurn = -1;
}
int pitch = (gpGlobals->time - m_flStartCharge) * (150/GetFullChargeTime()) + 100;
if (pitch > 250)
pitch = 250;
// ALERT( at_console, "%d %d %d\n", m_fInAttack, m_iSoundState, pitch );
if (m_iSoundState == 0)
ALERT( at_console, "sound state %d\n", m_iSoundState );
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, m_iSoundState, pitch);
m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions
m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME;
// m_flTimeWeaponIdle = gpGlobals->time + 0.1;
if (m_flStartCharge < gpGlobals->time - 10)
{
// Player charged up too long. Zap him.
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f));
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/electro6.wav", 1.0, ATTN_NORM, 0, 75 + RANDOM_LONG(0,0x3f));
m_fInAttack = 0;
m_flTimeWeaponIdle = gpGlobals->time + 1.0;
m_pPlayer->m_flNextAttack = gpGlobals->time + 1.0;
m_pPlayer->TakeDamage( VARS(eoNullEntity), VARS(eoNullEntity), 50, DMG_SHOCK );
UTIL_ScreenFade( m_pPlayer, Vector(255,128,0), 2, 0.5, 128, FFADE_IN );
SendWeaponAnim( GAUSS_IDLE );
// Player may have been killed and this weapon dropped, don't execute any more code after this!
return;
}
}
}
//=========================================================
// StartFire- since all of this code has to run and then
// call Fire(), it was easier at this point to rip it out
// of weaponidle() and make its own function then to try to
// merge this into Fire(), which has some identical variable names
//=========================================================
void CGauss::StartFire( void )
{
float flDamage;
UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );
Vector vecAiming = gpGlobals->v_forward;
Vector vecSrc = m_pPlayer->GetGunPosition( ); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8;
if (gpGlobals->time - m_flStartCharge > GetFullChargeTime())
{
flDamage = 200;
}
else
{
flDamage = 200 * ((gpGlobals->time - m_flStartCharge) / GetFullChargeTime() );
}
if ( m_fPrimaryFire )
{
// fixed damage on primary attack
flDamage = gSkillData.plrDmgGauss;
m_pPlayer->pev->punchangle.x = -2;// punch now, after building aim vector
}
if (m_fInAttack != 3)
{
//ALERT ( at_console, "Time:%f Damage:%f\n", gpGlobals->time - m_flStartCharge, flDamage );
float flZVel = m_pPlayer->pev->velocity.z;
if ( !m_fPrimaryFire )
{
m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * flDamage * 5;
}
if ( !g_pGameRules->IsDeathmatch() )
{
// in deathmatch, gauss can pop you up into the air. Not in single play.
m_pPlayer->pev->velocity.z = flZVel;
}
SendWeaponAnim( GAUSS_FIRE2 );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
}
STOP_SOUND( ENT(m_pPlayer->pev), CHAN_WEAPON, "ambience/pulsemachine.wav" );
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f));
// time until aftershock 'static discharge' sound
m_flPlayAftershock = gpGlobals->time + RANDOM_FLOAT(0.3, 0.8);
Fire( vecSrc, vecAiming, flDamage );
}
void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage )
{
m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME;
Vector vecSrc = vecOrigSrc;
Vector vecDest = vecSrc + vecDir * 8192;
edict_t *pentIgnore;
TraceResult tr, beam_tr;
float flMaxFrac = 1.0;
int nTotal = 0;
int fHasPunched = 0;
int fFirstBeam = 1;
int nMaxHits = 10;
pentIgnore = ENT( m_pPlayer->pev );
/*
ALERT( at_console, "%f %f %f\n%f %f %f\n",
vecSrc.x, vecSrc.y, vecSrc.z,
vecDest.x, vecDest.y, vecDest.z );
*/
// ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac );
while (flDamage > 10 && nMaxHits > 0)
{
nMaxHits--;
// ALERT( at_console, "." );
UTIL_TraceLine(vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr);
if (tr.fAllSolid)
break;
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
if (pEntity == NULL)
break;
if (fFirstBeam)
{
m_pPlayer->pev->effects |= EF_MUZZLEFLASH;
fFirstBeam = 0;
Vector tmpSrc = vecSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3;
// don't draw beam until the damn thing looks like it's coming out of the barrel
// draw beam
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos );
WRITE_BYTE( TE_BEAMENTPOINT );
WRITE_SHORT( m_pPlayer->entindex() + 0x1000 );
WRITE_COORD( tr.vecEndPos.x);
WRITE_COORD( tr.vecEndPos.y);
WRITE_COORD( tr.vecEndPos.z);
WRITE_SHORT( m_iBeam );
WRITE_BYTE( 0 ); // startframe
WRITE_BYTE( 0 ); // framerate
WRITE_BYTE( 1 ); // life
if ( m_fPrimaryFire )
{
WRITE_BYTE( 10 ); // width
}
else
{
WRITE_BYTE( 25 ); // width
}
WRITE_BYTE( 0 ); // noise
if ( m_fPrimaryFire )
{
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 128 ); // r, g, b
WRITE_BYTE( 0 ); // r, g, b
WRITE_BYTE( 128 ); // brightness
}
else
{
// secondary shot is always white, and intensity based on charge
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( flDamage ); // brightness
}
WRITE_BYTE( 0 ); // speed
MESSAGE_END();
nTotal += 26;
}
else
{
// draw beam
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecSrc );
WRITE_BYTE( TE_BEAMPOINTS);
WRITE_COORD( vecSrc.x);
WRITE_COORD( vecSrc.y);
WRITE_COORD( vecSrc.z);
WRITE_COORD( tr.vecEndPos.x);
WRITE_COORD( tr.vecEndPos.y);
WRITE_COORD( tr.vecEndPos.z);
WRITE_SHORT( m_iBeam );
WRITE_BYTE( 0 ); // startframe
WRITE_BYTE( 0 ); // framerate
WRITE_BYTE( 1 ); // life
if ( m_fPrimaryFire )
{
WRITE_BYTE( 10 ); // width
}
else
{
WRITE_BYTE( 25 ); // width
}
WRITE_BYTE( 0 ); // noise
if ( m_fPrimaryFire )
{
// primary shot always looks full intensity
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 128 ); // r, g, b
WRITE_BYTE( 0 ); // r, g, b
WRITE_BYTE( 128 ); // brightness
}
else
{
// secondary shot is always white, and intensity based on charge
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( flDamage ); // brightness
}
WRITE_BYTE( 0 ); // speed
MESSAGE_END();
nTotal += 26;
}
if (pEntity->pev->takedamage)
{
ClearMultiDamage();
pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET );
ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev);
}
// ALERT( at_console, "%s\n", STRING( pEntity->pev->classname ));
if ( pEntity->ReflectGauss() )
{
float n;
pentIgnore = NULL;
n = -DotProduct(tr.vecPlaneNormal, vecDir);
if (n < 0.5) // 60 degrees
{
// ALERT( at_console, "reflect %f\n", n );
// reflect
Vector r;
r = 2.0 * tr.vecPlaneNormal * n + vecDir;
flMaxFrac = flMaxFrac - tr.flFraction;
vecDir = r;
vecSrc = tr.vecEndPos + vecDir * 8;
vecDest = vecSrc + vecDir * 8192;
// explode a bit
m_pPlayer->RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, flDamage * n, CLASS_NONE, DMG_BLAST );
// bounce wall glow
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos );
WRITE_BYTE( TE_GLOWSPRITE );
WRITE_COORD( tr.vecEndPos.x); // pos
WRITE_COORD( tr.vecEndPos.y);
WRITE_COORD( tr.vecEndPos.z);
WRITE_SHORT( m_iGlow ); // model
WRITE_BYTE( flDamage * n * 0.5 ); // life * 10
WRITE_BYTE( 2 ); // size * 10
WRITE_BYTE( flDamage * n ); // brightness
MESSAGE_END();
nTotal += 13;
// balls
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos );
WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL);
WRITE_COORD( tr.vecEndPos.x );
WRITE_COORD( tr.vecEndPos.y );
WRITE_COORD( tr.vecEndPos.z );
WRITE_COORD( tr.vecEndPos.x + tr.vecPlaneNormal.x );
WRITE_COORD( tr.vecEndPos.y + tr.vecPlaneNormal.y );
WRITE_COORD( tr.vecEndPos.z + tr.vecPlaneNormal.z );
WRITE_SHORT( m_iBalls ); // model
WRITE_BYTE( n * flDamage * 0.3 ); // count
WRITE_BYTE( 10 ); // life * 10
WRITE_BYTE( RANDOM_LONG( 1, 2 ) ); // size * 10
WRITE_BYTE( 10 ); // amplitude * 0.1
WRITE_BYTE( 20 ); // speed * 100
MESSAGE_END();
nTotal += 21;
// lose energy
if (n == 0) n = 0.1;
flDamage = flDamage * (1 - n);
}
else
{
// tunnel
DecalGunshot( &tr, BULLET_MONSTER_12MM );
// entry wall glow
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos );
WRITE_BYTE( TE_GLOWSPRITE );
WRITE_COORD( tr.vecEndPos.x); // pos
WRITE_COORD( tr.vecEndPos.y);
WRITE_COORD( tr.vecEndPos.z);
WRITE_SHORT( m_iGlow ); // model
WRITE_BYTE( 60 ); // life * 10
WRITE_BYTE( 10 ); // size * 10
WRITE_BYTE( flDamage ); // brightness
MESSAGE_END();
nTotal += 13;
// limit it to one hole punch
if (fHasPunched)
break;
fHasPunched = 1;
// try punching through wall if secondary attack (primary is incapable of breaking through)
if ( !m_fPrimaryFire )
{
UTIL_TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, &beam_tr);
if (!beam_tr.fAllSolid)
{
// trace backwards to find exit point
UTIL_TraceLine( beam_tr.vecEndPos, tr.vecEndPos, dont_ignore_monsters, pentIgnore, &beam_tr);
float n = (beam_tr.vecEndPos - tr.vecEndPos).Length( );
if (n < flDamage)
{
if (n == 0) n = 1;
flDamage -= n;
// ALERT( at_console, "punch %f\n", n );
// absorption balls
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos );
WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL);
WRITE_COORD( tr.vecEndPos.x );
WRITE_COORD( tr.vecEndPos.y );
WRITE_COORD( tr.vecEndPos.z );
WRITE_COORD( tr.vecEndPos.x - vecDir.x );
WRITE_COORD( tr.vecEndPos.y - vecDir.y );
WRITE_COORD( tr.vecEndPos.z - vecDir.z );
WRITE_SHORT( m_iBalls ); // model
WRITE_BYTE( 3 ); // count
WRITE_BYTE( 10 ); // life * 10
WRITE_BYTE( RANDOM_LONG( 1, 2 ) ); // size * 10
WRITE_BYTE( 10 ); // amplitude * 0.1
WRITE_BYTE( 1 ); // speed * 100
MESSAGE_END();
nTotal += 21;
// exit blast damage
m_pPlayer->RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, CLASS_NONE, DMG_BLAST );
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 );
DecalGunshot( &beam_tr, BULLET_MONSTER_12MM );
nTotal += 19;
// exit wall glow
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, beam_tr.vecEndPos );
WRITE_BYTE( TE_GLOWSPRITE );
WRITE_COORD( beam_tr.vecEndPos.x); // pos
WRITE_COORD( beam_tr.vecEndPos.y);
WRITE_COORD( beam_tr.vecEndPos.z);
WRITE_SHORT( m_iGlow ); // model
WRITE_BYTE( 60 ); // life * 10
WRITE_BYTE( 10 ); // size * 10
WRITE_BYTE( flDamage ); // brightness
MESSAGE_END();
nTotal += 13;
// balls
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, beam_tr.vecEndPos );
WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL);
WRITE_COORD( beam_tr.vecEndPos.x );
WRITE_COORD( beam_tr.vecEndPos.y );
WRITE_COORD( beam_tr.vecEndPos.z );
WRITE_COORD( beam_tr.vecEndPos.x + vecDir.x );
WRITE_COORD( beam_tr.vecEndPos.y + vecDir.y );
WRITE_COORD( beam_tr.vecEndPos.z + vecDir.z );
WRITE_SHORT( m_iBalls ); // model
WRITE_BYTE( flDamage * 0.3 ); // count
WRITE_BYTE( 10 ); // life * 10
WRITE_BYTE( RANDOM_LONG( 1, 2 ) ); // size * 10
WRITE_BYTE( 20 ); // amplitude * 0.1
WRITE_BYTE( 40 ); // speed * 100
MESSAGE_END();
nTotal += 21;
vecSrc = beam_tr.vecEndPos + vecDir;
}
}
else
{
//ALERT( at_console, "blocked %f\n", n );
flDamage = 0;
}
}
else
{
//ALERT( at_console, "blocked solid\n" );
if ( m_fPrimaryFire )
{
// slug doesn't punch through ever with primary
// fire, so leave a little glowy bit and make some balls
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos );
WRITE_BYTE( TE_GLOWSPRITE );
WRITE_COORD( tr.vecEndPos.x); // pos
WRITE_COORD( tr.vecEndPos.y);
WRITE_COORD( tr.vecEndPos.z);
WRITE_SHORT( m_iGlow ); // model
WRITE_BYTE( 20 ); // life * 10
WRITE_BYTE( 3 ); // size * 10
WRITE_BYTE( 200 ); // brightness
MESSAGE_END();
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos );
WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL);
WRITE_COORD( tr.vecEndPos.x );
WRITE_COORD( tr.vecEndPos.y );
WRITE_COORD( tr.vecEndPos.z );
WRITE_COORD( tr.vecEndPos.x + tr.vecPlaneNormal.x );
WRITE_COORD( tr.vecEndPos.y + tr.vecPlaneNormal.y );
WRITE_COORD( tr.vecEndPos.z + tr.vecPlaneNormal.z );
WRITE_SHORT( m_iBalls ); // model
WRITE_BYTE( 8 ); // count
WRITE_BYTE( 6 ); // life * 10
WRITE_BYTE( RANDOM_LONG( 1, 2 ) ); // size * 10
WRITE_BYTE( 10 ); // amplitude * 0.1
WRITE_BYTE( 20 ); // speed * 100
MESSAGE_END();
}
flDamage = 0;
}
}
}
else
{
vecSrc = tr.vecEndPos + vecDir;
pentIgnore = ENT( pEntity->pev );
}
}
// ALERT( at_console, "%d bytes\n", nTotal );
}
void CGauss::WeaponIdle( void )
{
ResetEmptySound( );
// play aftershock static discharge
if (m_flPlayAftershock && m_flPlayAftershock < gpGlobals->time)
{
switch (RANDOM_LONG(0,3))
{
case 0: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro5.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break;
case 2: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro6.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break;
case 3: break; // no sound
}
m_flPlayAftershock = 0.0;
}
if (m_flTimeWeaponIdle > gpGlobals->time)
return;
if (m_fInAttack != 0)
{
StartFire();
m_fInAttack = 0;
m_flTimeWeaponIdle = gpGlobals->time + 2.0;
}
else
{
int iAnim;
float flRand = RANDOM_FLOAT(0, 1);
if (flRand <= 0.5)
{
iAnim = GAUSS_IDLE;
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
}
else if (flRand <= 0.75)
{
iAnim = GAUSS_IDLE2;
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
}
else
{
iAnim = GAUSS_FIDGET;
m_flTimeWeaponIdle = gpGlobals->time + 3;
}
return;
SendWeaponAnim( iAnim );
}
}
class CGaussAmmo : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_gaussammo.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_gaussammo.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
return TRUE;
}
return FALSE;
}
};
LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo );
#endif

488
dlls/ggrenade.cpp Normal file
View File

@ -0,0 +1,488 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== generic grenade.cpp ========================================================
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "soundent.h"
#include "decals.h"
//===================grenade
LINK_ENTITY_TO_CLASS( grenade, CGrenade );
// Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges
#define SF_DETONATE 0x0001
//
// Grenade Explode
//
void CGrenade::Explode( Vector vecSrc, Vector vecAim )
{
TraceResult tr;
UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), & tr);
Explode( &tr, DMG_BLAST );
}
// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution.
void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType )
{
float flRndSound;// sound randomizer
pev->model = iStringNull;//invisible
pev->solid = SOLID_NOT;// intangible
pev->takedamage = DAMAGE_NO;
// Pull out of the wall a bit
if ( pTrace->flFraction != 1.0 )
{
pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * (pev->dmg - 24) * 0.6);
}
int iContents = UTIL_PointContents ( pev->origin );
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound
WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound
WRITE_COORD( pev->origin.y );
WRITE_COORD( pev->origin.z );
if (iContents != CONTENTS_WATER)
{
WRITE_SHORT( g_sModelIndexFireball );
}
else
{
WRITE_SHORT( g_sModelIndexWExplosion );
}
WRITE_BYTE( (pev->dmg - 50) * .60 ); // scale * 10
WRITE_BYTE( 15 ); // framerate
WRITE_BYTE( TE_EXPLFLAG_NONE );
MESSAGE_END();
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 );
entvars_t *pevOwner;
if ( pev->owner )
pevOwner = VARS( pev->owner );
else
pevOwner = NULL;
pev->owner = NULL; // can't traceline attack owner if this is set
RadiusDamage ( pev, pevOwner, pev->dmg, CLASS_NONE, bitsDamageType );
if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 )
{
UTIL_DecalTrace( pTrace, DECAL_SCORCH1 );
}
else
{
UTIL_DecalTrace( pTrace, DECAL_SCORCH2 );
}
flRndSound = RANDOM_FLOAT( 0 , 1 );
switch ( RANDOM_LONG( 0, 2 ) )
{
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM); break;
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM); break;
}
pev->effects |= EF_NODRAW;
SetThink( Smoke );
pev->velocity = g_vecZero;
pev->nextthink = gpGlobals->time + 0.3;
if (iContents != CONTENTS_WATER)
{
int sparkCount = RANDOM_LONG(0,3);
for ( int i = 0; i < sparkCount; i++ )
Create( "spark_shower", pev->origin, pTrace->vecPlaneNormal, NULL );
}
}
void CGrenade::Smoke( void )
{
if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER)
{
UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
}
else
{
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 );
WRITE_SHORT( g_sModelIndexSmoke );
WRITE_BYTE( (pev->dmg - 50) * 0.80 ); // scale * 10
WRITE_BYTE( 12 ); // framerate
MESSAGE_END();
}
UTIL_Remove( this );
}
void CGrenade::Killed( entvars_t *pevAttacker, int iGib )
{
Detonate( );
}
// Timed grenade, this think is called when time runs out.
void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
SetThink( Detonate );
pev->nextthink = gpGlobals->time;
}
void CGrenade::PreDetonate( void )
{
CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 );
SetThink( Detonate );
pev->nextthink = gpGlobals->time + 1;
}
void CGrenade::Detonate( void )
{
TraceResult tr;
Vector vecSpot;// trace starts here!
vecSpot = pev->origin + Vector ( 0 , 0 , 8 );
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr);
Explode( &tr, DMG_BLAST );
}
//
// Contact grenade, explode when it touches something
//
void CGrenade::ExplodeTouch( CBaseEntity *pOther )
{
TraceResult tr;
Vector vecSpot;// trace starts here!
pev->enemy = pOther->edict();
vecSpot = pev->origin - pev->velocity.Normalize() * 32;
UTIL_TraceLine( vecSpot, vecSpot + pev->velocity.Normalize() * 64, ignore_monsters, ENT(pev), &tr );
Explode( &tr, DMG_BLAST );
}
void CGrenade::DangerSoundThink( void )
{
if (!IsInWorld())
{
UTIL_Remove( this );
return;
}
CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, pev->velocity.Length( ), 0.2 );
pev->nextthink = gpGlobals->time + 0.2;
if (pev->waterlevel != 0)
{
pev->velocity = pev->velocity * 0.5;
}
}
void CGrenade::BounceTouch( CBaseEntity *pOther )
{
// don't hit the guy that launched this grenade
if ( pOther->edict() == pev->owner )
return;
// only do damage if we're moving fairly fast
if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100)
{
entvars_t *pevOwner = VARS( pev->owner );
if (pevOwner)
{
TraceResult tr = UTIL_GetGlobalTrace( );
ClearMultiDamage( );
pOther->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
ApplyMultiDamage( pev, pevOwner);
}
m_flNextAttack = gpGlobals->time + 1.0; // debounce
}
Vector vecTestVelocity;
// pev->avelocity = Vector (300, 300, 300);
// this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical
// or thrown very far tend to slow down too quickly for me to always catch just by testing velocity.
// trimming the Z velocity a bit seems to help quite a bit.
vecTestVelocity = pev->velocity;
vecTestVelocity.z *= 0.45;
if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 )
{
//ALERT( at_console, "Grenade Registered!: %f\n", vecTestVelocity.Length() );
// grenade is moving really slow. It's probably very close to where it will ultimately stop moving.
// go ahead and emit the danger sound.
// register a radius louder than the explosion, so we make sure everyone gets out of the way
CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, pev->dmg / 0.4, 0.3 );
m_fRegisteredSound = TRUE;
}
if (pev->flags & FL_ONGROUND)
{
// add a bit of static friction
pev->velocity = pev->velocity * 0.8;
pev->sequence = RANDOM_LONG( 1, 1 );
}
else
{
// play bounce sound
BounceSound();
}
pev->framerate = pev->velocity.Length() / 200.0;
if (pev->framerate > 1.0)
pev->framerate = 1;
else if (pev->framerate < 0.5)
pev->framerate = 0;
}
void CGrenade::SlideTouch( CBaseEntity *pOther )
{
// don't hit the guy that launched this grenade
if ( pOther->edict() == pev->owner )
return;
// pev->avelocity = Vector (300, 300, 300);
if (pev->flags & FL_ONGROUND)
{
// add a bit of static friction
pev->velocity = pev->velocity * 0.95;
if (pev->velocity.x != 0 || pev->velocity.y != 0)
{
// maintain sliding sound
}
}
else
{
BounceSound();
}
}
void CGrenade :: BounceSound( void )
{
switch ( RANDOM_LONG( 0, 2 ) )
{
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit1.wav", 0.25, ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit2.wav", 0.25, ATTN_NORM); break;
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit3.wav", 0.25, ATTN_NORM); break;
}
}
void CGrenade :: TumbleThink( void )
{
if (!IsInWorld())
{
UTIL_Remove( this );
return;
}
StudioFrameAdvance( );
pev->nextthink = gpGlobals->time + 0.1;
if (pev->dmgtime - 1 < gpGlobals->time)
{
CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * (pev->dmgtime - gpGlobals->time), 400, 0.1 );
}
if (pev->dmgtime <= gpGlobals->time)
{
SetThink( Detonate );
}
if (pev->waterlevel != 0)
{
pev->velocity = pev->velocity * 0.5;
pev->framerate = 0.2;
}
}
void CGrenade:: Spawn( void )
{
pev->movetype = MOVETYPE_BOUNCE;
pev->classname = MAKE_STRING( "grenade" );
pev->solid = SOLID_BBOX;
SET_MODEL(ENT(pev), "models/grenade.mdl");
UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0));
pev->dmg = 100;
m_fRegisteredSound = FALSE;
}
CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity )
{
CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL );
pGrenade->Spawn();
// contact grenades arc lower
pGrenade->pev->gravity = 0.5;// lower gravity since grenade is aerodynamic and engine doesn't know it.
UTIL_SetOrigin( pGrenade->pev, vecStart );
pGrenade->pev->velocity = vecVelocity;
pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity);
pGrenade->pev->owner = ENT(pevOwner);
// make monsters afaid of it while in the air
pGrenade->SetThink( DangerSoundThink );
pGrenade->pev->nextthink = gpGlobals->time;
// Tumble in air
pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 );
// Explode on contact
pGrenade->SetTouch( ExplodeTouch );
pGrenade->pev->dmg = gSkillData.plrDmgM203Grenade;
return pGrenade;
}
CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time )
{
CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL );
pGrenade->Spawn();
UTIL_SetOrigin( pGrenade->pev, vecStart );
pGrenade->pev->velocity = vecVelocity;
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
pGrenade->pev->owner = ENT(pevOwner);
pGrenade->SetTouch( BounceTouch ); // Bounce if touched
// Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate
// will insert a DANGER sound into the world sound list and delay detonation for one second so that
// the grenade explodes after the exact amount of time specified in the call to ShootTimed().
pGrenade->pev->dmgtime = gpGlobals->time + time;
pGrenade->SetThink( TumbleThink );
pGrenade->pev->nextthink = gpGlobals->time + 0.1;
if (time < 0.1)
{
pGrenade->pev->nextthink = gpGlobals->time;
pGrenade->pev->velocity = Vector( 0, 0, 0 );
}
pGrenade->pev->sequence = RANDOM_LONG( 3, 6 );
pGrenade->pev->framerate = 1.0;
// Tumble through the air
// pGrenade->pev->avelocity.x = -400;
pGrenade->pev->gravity = 0.5;
pGrenade->pev->friction = 0.8;
SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl");
pGrenade->pev->dmg = 100;
return pGrenade;
}
CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity )
{
CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL );
pGrenade->pev->movetype = MOVETYPE_BOUNCE;
pGrenade->pev->classname = MAKE_STRING( "grenade" );
pGrenade->pev->solid = SOLID_BBOX;
SET_MODEL(ENT(pGrenade->pev), "models/grenade.mdl"); // Change this to satchel charge model
UTIL_SetSize(pGrenade->pev, Vector( 0, 0, 0), Vector(0, 0, 0));
pGrenade->pev->dmg = 200;
UTIL_SetOrigin( pGrenade->pev, vecStart );
pGrenade->pev->velocity = vecVelocity;
pGrenade->pev->angles = g_vecZero;
pGrenade->pev->owner = ENT(pevOwner);
// Detonate in "time" seconds
pGrenade->SetThink( SUB_DoNothing );
pGrenade->SetUse( DetonateUse );
pGrenade->SetTouch( SlideTouch );
pGrenade->pev->spawnflags = SF_DETONATE;
pGrenade->pev->friction = 0.9;
return pGrenade;
}
void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code )
{
edict_t *pentFind;
edict_t *pentOwner;
if ( !pevOwner )
return;
CBaseEntity *pOwner = CBaseEntity::Instance( pevOwner );
pentOwner = pOwner->edict();
pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "grenade" );
while ( !FNullEnt( pentFind ) )
{
CBaseEntity *pEnt = Instance( pentFind );
if ( pEnt )
{
if ( FBitSet( pEnt->pev->spawnflags, SF_DETONATE ) && pEnt->pev->owner == pentOwner )
{
if ( code == SATCHEL_DETONATE )
pEnt->Use( pOwner, pOwner, USE_ON, 0 );
else // SATCHEL_RELEASE
pEnt->pev->owner = NULL;
}
}
pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "grenade" );
}
}
//======================end grenade

39
dlls/globals.cpp Normal file
View File

@ -0,0 +1,39 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== globals.cpp ========================================================
DLL-wide global variable definitions.
They're all defined here, for convenient centralization.
Source files that need them should "extern ..." declare each
variable, to better document what globals they care about.
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "soundent.h"
DLL_GLOBAL ULONG g_ulFrameCount;
DLL_GLOBAL ULONG g_ulModelIndexEyes;
DLL_GLOBAL ULONG g_ulModelIndexPlayer;
DLL_GLOBAL Vector g_vecAttackDir;
DLL_GLOBAL int g_iSkillLevel;
DLL_GLOBAL int gDisplayTitle;
DLL_GLOBAL BOOL g_fGameOver;
DLL_GLOBAL const Vector g_vecZero = Vector(0,0,0);
DLL_GLOBAL int g_Language;

297
dlls/glock.cpp Normal file
View File

@ -0,0 +1,297 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
enum glock_e {
GLOCK_IDLE1 = 0,
GLOCK_IDLE2,
GLOCK_IDLE3,
GLOCK_SHOOT,
GLOCK_SHOOT_EMPTY,
GLOCK_RELOAD,
GLOCK_RELOAD_NOT_EMPTY,
GLOCK_DRAW,
GLOCK_HOLSTER,
GLOCK_ADD_SILENCER
};
class CGlock : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 2; }
int GetItemInfo(ItemInfo *p);
void PrimaryAttack( void );
void SecondaryAttack( void );
void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim );
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );
int m_iShell;
};
LINK_ENTITY_TO_CLASS( weapon_glock, CGlock );
LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock );
void CGlock::Spawn( )
{
pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names
Precache( );
m_iId = WEAPON_GLOCK;
SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl");
m_iDefaultAmmo = GLOCK_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CGlock::Precache( void )
{
PRECACHE_MODEL("models/v_9mmhandgun.mdl");
PRECACHE_MODEL("models/w_9mmhandgun.mdl");
PRECACHE_MODEL("models/p_9mmhandgun.mdl");
m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
PRECACHE_SOUND("items/9mmclip1.wav");
PRECACHE_SOUND("items/9mmclip2.wav");
PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun
PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun
PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun
}
int CGlock::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "9mm";
p->iMaxAmmo1 = _9MM_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = GLOCK_MAX_CLIP;
p->iSlot = 1;
p->iPosition = 0;
p->iFlags = 0;
p->iId = m_iId = WEAPON_GLOCK;
p->iWeight = GLOCK_WEIGHT;
return 1;
}
BOOL CGlock::Deploy( )
{
// pev->body = 1;
return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded" );
}
void CGlock::SecondaryAttack( void )
{
GlockFire( 0.1, 0.2, FALSE );
}
void CGlock::PrimaryAttack( void )
{
GlockFire( 0.01, 0.3, TRUE );
}
void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim )
{
if (m_iClip <= 0)
{
if (m_fFireOnEmpty)
{
PlayEmptySound();
m_flNextPrimaryAttack = gpGlobals->time + 0.2;
}
return;
}
m_iClip--;
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
if (m_iClip != 0)
SendWeaponAnim( GLOCK_SHOOT );
else
SendWeaponAnim( GLOCK_SHOOT_EMPTY );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );
Vector vecShellVelocity = m_pPlayer->pev->velocity
+ gpGlobals->v_right * RANDOM_FLOAT(50,70)
+ gpGlobals->v_up * RANDOM_FLOAT(100,150)
+ gpGlobals->v_forward * 25;
EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 32 + gpGlobals->v_right * 6 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL );
// silenced
if (pev->body == 1)
{
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;
switch(RANDOM_LONG(0,1))
{
case 0:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM);
break;
case 1:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM);
break;
}
}
else
{
// non-silenced
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun3.wav", RANDOM_FLOAT(0.92, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
}
Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecAiming;
if ( fUseAutoAim )
{
vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
}
else
{
vecAiming = gpGlobals->v_forward;
}
m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + flCycleTime;
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
m_pPlayer->pev->punchangle.x -= 2;
}
void CGlock::Reload( void )
{
int iResult;
if (m_iClip == 0)
iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 );
else
iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 );
if (iResult)
{
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
}
}
void CGlock::WeaponIdle( void )
{
ResetEmptySound( );
m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
if (m_flTimeWeaponIdle > gpGlobals->time)
return;
// only idle if the slid isn't back
if (m_iClip != 0)
{
int iAnim;
float flRand = RANDOM_FLOAT(0, 1);
if (flRand <= 0.3 + 0 * 0.75)
{
iAnim = GLOCK_IDLE3;
m_flTimeWeaponIdle = gpGlobals->time + 49.0 / 16;
}
else if (flRand <= 0.6 + 0 * 0.875)
{
iAnim = GLOCK_IDLE1;
m_flTimeWeaponIdle = gpGlobals->time + 60.0 / 16.0;
}
else
{
iAnim = GLOCK_IDLE2;
m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0;
}
SendWeaponAnim( iAnim );
}
}
class CGlockAmmo : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_9mmclip.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_9mmclip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
return TRUE;
}
return FALSE;
}
};
LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo );
LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo );

198
dlls/h_ai.cpp Normal file
View File

@ -0,0 +1,198 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
h_ai.cpp - halflife specific ai code
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#define NUM_LATERAL_CHECKS 13 // how many checks are made on each side of a monster looking for lateral cover
#define NUM_LATERAL_LOS_CHECKS 6 // how many checks are made on each side of a monster looking for lateral cover
//float flRandom = RANDOM_FLOAT(0,1);
DLL_GLOBAL BOOL g_fDrawLines = FALSE;
//=========================================================
//
// AI UTILITY FUNCTIONS
//
// !!!UNDONE - move CBaseMonster functions to monsters.cpp
//=========================================================
//=========================================================
// FBoxVisible - a more accurate ( and slower ) version
// of FVisible.
//
// !!!UNDONE - make this CBaseMonster?
//=========================================================
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize )
{
// don't look through water
if ((pevLooker->waterlevel != 3 && pevTarget->waterlevel == 3)
|| (pevLooker->waterlevel == 3 && pevTarget->waterlevel == 0))
return FALSE;
TraceResult tr;
Vector vecLookerOrigin = pevLooker->origin + pevLooker->view_ofs;//look through the monster's 'eyes'
for (int i = 0; i < 5; i++)
{
Vector vecTarget = pevTarget->origin;
vecTarget.x += RANDOM_FLOAT( pevTarget->mins.x + flSize, pevTarget->maxs.x - flSize);
vecTarget.y += RANDOM_FLOAT( pevTarget->mins.y + flSize, pevTarget->maxs.y - flSize);
vecTarget.z += RANDOM_FLOAT( pevTarget->mins.z + flSize, pevTarget->maxs.z - flSize);
UTIL_TraceLine(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, ENT(pevLooker)/*pentIgnore*/, &tr);
if (tr.flFraction == 1.0)
{
vecTargetOrigin = vecTarget;
return TRUE;// line of sight is valid.
}
}
return FALSE;// Line of sight is not established
}
//
// VecCheckToss - returns the velocity at which an object should be lobbed from vecspot1 to land near vecspot2.
// returns g_vecZero if toss is not feasible.
//
Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj )
{
TraceResult tr;
Vector vecMidPoint;// halfway point between Spot1 and Spot2
Vector vecApex;// highest point
Vector vecScale;
Vector vecGrenadeVel;
Vector vecTemp;
float flGravity = CVAR_GET_FLOAT( "sv_gravity" ) * flGravityAdj;
if (vecSpot2.z - vecSpot1.z > 500)
{
// to high, fail
return g_vecZero;
}
UTIL_MakeVectors (pev->angles);
// toss a little bit to the left or right, not right down on the enemy's bean (head).
vecSpot2 = vecSpot2 + gpGlobals->v_right * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) );
vecSpot2 = vecSpot2 + gpGlobals->v_forward * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) );
// calculate the midpoint and apex of the 'triangle'
// UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT
// How much time does it take to get there?
// get a rough idea of how high it can be thrown
vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,500), ignore_monsters, ENT(pev), &tr);
vecMidPoint = tr.vecEndPos;
// (subtract 15 so the grenade doesn't hit the ceiling)
vecMidPoint.z -= 15;
if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z)
{
// to not enough space, fail
return g_vecZero;
}
// How high should the grenade travel to reach the apex
float distance1 = (vecMidPoint.z - vecSpot1.z);
float distance2 = (vecMidPoint.z - vecSpot2.z);
// How long will it take for the grenade to travel this distance
float time1 = sqrt( distance1 / (0.5 * flGravity) );
float time2 = sqrt( distance2 / (0.5 * flGravity) );
if (time1 < 0.1)
{
// too close
return g_vecZero;
}
// how hard to throw sideways to get there in time.
vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2);
// how hard upwards to reach the apex at the right time.
vecGrenadeVel.z = flGravity * time1;
// find the apex
vecApex = vecSpot1 + vecGrenadeVel * time1;
vecApex.z = vecMidPoint.z;
UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr);
if (tr.flFraction != 1.0)
{
// fail!
return g_vecZero;
}
// UNDONE: either ignore monsters or change it to not care if we hit our enemy
UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr);
if (tr.flFraction != 1.0)
{
// fail!
return g_vecZero;
}
return vecGrenadeVel;
}
//
// VecCheckThrow - returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2.
// returns g_vecZero if throw is not feasible.
//
Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj )
{
float flGravity = CVAR_GET_FLOAT( "sv_gravity" ) * flGravityAdj;
Vector vecGrenadeVel = (vecSpot2 - vecSpot1);
// throw at a constant time
float time = vecGrenadeVel.Length( ) / flSpeed;
vecGrenadeVel = vecGrenadeVel * (1.0 / time);
// adjust upward toss to compensate for gravity loss
vecGrenadeVel.z += flGravity * time * 0.5;
Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5);
TraceResult tr;
UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr);
if (tr.flFraction != 1.0)
{
// fail!
return g_vecZero;
}
UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr);
if (tr.flFraction != 1.0)
{
// fail!
return g_vecZero;
}
return vecGrenadeVel;
}

200
dlls/h_battery.cpp Normal file
View File

@ -0,0 +1,200 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== h_battery.cpp ========================================================
battery-related code
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "saverestore.h"
#include "skill.h"
#include "gamerules.h"
class CRecharge : public CBaseToggle
{
public:
void Spawn( );
void Precache( void );
void EXPORT Off(void);
void EXPORT Recharge(void);
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
float m_flNextCharge;
int m_iReactivate ; // DeathMatch Delay until reactvated
int m_iJuice;
int m_iOn; // 0 = off, 1 = startup, 2 = going
float m_flSoundTime;
};
TYPEDESCRIPTION CRecharge::m_SaveData[] =
{
DEFINE_FIELD( CRecharge, m_flNextCharge, FIELD_TIME ),
DEFINE_FIELD( CRecharge, m_iReactivate, FIELD_INTEGER),
DEFINE_FIELD( CRecharge, m_iJuice, FIELD_INTEGER),
DEFINE_FIELD( CRecharge, m_iOn, FIELD_INTEGER),
DEFINE_FIELD( CRecharge, m_flSoundTime, FIELD_TIME ),
};
IMPLEMENT_SAVERESTORE( CRecharge, CBaseEntity );
LINK_ENTITY_TO_CLASS(func_recharge, CRecharge);
void CRecharge::KeyValue( KeyValueData *pkvd )
{
if ( FStrEq(pkvd->szKeyName, "style") ||
FStrEq(pkvd->szKeyName, "height") ||
FStrEq(pkvd->szKeyName, "value1") ||
FStrEq(pkvd->szKeyName, "value2") ||
FStrEq(pkvd->szKeyName, "value3"))
{
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "dmdelay"))
{
m_iReactivate = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue( pkvd );
}
void CRecharge::Spawn()
{
Precache( );
pev->solid = SOLID_BSP;
pev->movetype = MOVETYPE_PUSH;
UTIL_SetOrigin(pev, pev->origin); // set size and link into world
UTIL_SetSize(pev, pev->mins, pev->maxs);
SET_MODEL(ENT(pev), STRING(pev->model) );
m_iJuice = gSkillData.suitchargerCapacity;
pev->frame = 0;
}
void CRecharge::Precache()
{
PRECACHE_SOUND("items/suitcharge1.wav");
PRECACHE_SOUND("items/suitchargeno1.wav");
PRECACHE_SOUND("items/suitchargeok1.wav");
}
void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// if it's not a player, ignore
if (!FClassnameIs(pActivator->pev, "player"))
return;
// if there is no juice left, turn it off
if (m_iJuice <= 0)
{
pev->frame = 1;
Off();
}
// if the player doesn't have the suit, or there is no juice left, make the deny noise
if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<<WEAPON_SUIT))))
{
if (m_flSoundTime <= gpGlobals->time)
{
m_flSoundTime = gpGlobals->time + 0.62;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM );
}
return;
}
pev->nextthink = pev->ltime + 0.25;
SetThink(Off);
// Time to recharge yet?
if (m_flNextCharge >= gpGlobals->time)
return;
// Make sure that we have a caller
if (!pActivator)
return;
m_hActivator = pActivator;
//only recharge the player
if (!m_hActivator->IsPlayer() )
return;
// Play the on sound or the looping charging sound
if (!m_iOn)
{
m_iOn++;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeok1.wav", 0.85, ATTN_NORM );
m_flSoundTime = 0.56 + gpGlobals->time;
}
if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time))
{
m_iOn++;
EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM );
}
// charge the player
if (m_hActivator->pev->armorvalue < 100)
{
m_iJuice--;
m_hActivator->pev->armorvalue += 1;
if (m_hActivator->pev->armorvalue > 100)
m_hActivator->pev->armorvalue = 100;
}
// govern the rate of charge
m_flNextCharge = gpGlobals->time + 0.1;
}
void CRecharge::Recharge(void)
{
m_iJuice = gSkillData.suitchargerCapacity;
pev->frame = 0;
SetThink( SUB_DoNothing );
}
void CRecharge::Off(void)
{
// Stop looping sound.
if (m_iOn > 1)
STOP_SOUND( ENT(pev), CHAN_STATIC, "items/suitcharge1.wav" );
m_iOn = 0;
if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) )
{
pev->nextthink = pev->ltime + m_iReactivate;
SetThink(Recharge);
}
else
SetThink( SUB_DoNothing );
}

471
dlls/h_cycler.cpp Normal file
View File

@ -0,0 +1,471 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== h_cycler.cpp ========================================================
The Halflife Cycler Monsters
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "animation.h"
#include "weapons.h"
#include "player.h"
#define TEMP_FOR_SCREEN_SHOTS
#ifdef TEMP_FOR_SCREEN_SHOTS //===================================================
class CCycler : public CBaseMonster
{
public:
void GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax);
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_IMPULSE_USE); }
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
void Spawn( void );
void Think( void );
//void Pain( float flDamage );
void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
// Don't treat as a live target
virtual BOOL IsAlive( void ) { return FALSE; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
int m_animate;
};
TYPEDESCRIPTION CCycler::m_SaveData[] =
{
DEFINE_FIELD( CCycler, m_animate, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CCycler, CBaseMonster );
//
// we should get rid of all the other cyclers and replace them with this.
//
class CGenericCycler : public CCycler
{
public:
void Spawn( void ) { GenericCyclerSpawn( (char *)STRING(pev->model), Vector(-16, -16, 0), Vector(16, 16, 72) ); }
};
LINK_ENTITY_TO_CLASS( cycler, CGenericCycler );
// Probe droid imported for tech demo compatibility
//
// PROBE DROID
//
class CCyclerProbe : public CCycler
{
public:
void Spawn( void );
};
LINK_ENTITY_TO_CLASS( cycler_prdroid, CCyclerProbe );
void CCyclerProbe :: Spawn( void )
{
pev->origin = pev->origin + Vector ( 0, 0, 16 );
GenericCyclerSpawn( "models/prdroid.mdl", Vector(-16,-16,-16), Vector(16,16,16));
}
// Cycler member functions
void CCycler :: GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax)
{
if (!szModel || !*szModel)
{
ALERT(at_error, "cycler at %.0f %.0f %0.f missing modelname", pev->origin.x, pev->origin.y, pev->origin.z );
REMOVE_ENTITY(ENT(pev));
return;
}
pev->classname = MAKE_STRING("cycler");
PRECACHE_MODEL( szModel );
SET_MODEL(ENT(pev), szModel);
CCycler::Spawn( );
UTIL_SetSize(pev, vecMin, vecMax);
}
void CCycler :: Spawn( )
{
InitBoneControllers();
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_NONE;
pev->takedamage = DAMAGE_YES;
pev->effects = 0;
pev->health = 80000;// no cycler should die
pev->yaw_speed = 5;
pev->ideal_yaw = pev->angles.y;
ChangeYaw( 360 );
m_flFrameRate = 75;
m_flGroundSpeed = 0;
pev->nextthink += 1.0;
ResetSequenceInfo( );
if (pev->sequence != 0 || pev->frame != 0)
{
m_animate = 0;
pev->framerate = 0;
}
else
{
m_animate = 1;
}
}
//
// cycler think
//
void CCycler :: Think( void )
{
pev->nextthink = gpGlobals->time + 0.1;
if (m_animate)
{
StudioFrameAdvance ( );
}
if (m_fSequenceFinished && !m_fSequenceLoops)
{
// ResetSequenceInfo();
// hack to avoid reloading model every frame
pev->animtime = gpGlobals->time;
pev->framerate = 1.0;
m_fSequenceFinished = FALSE;
m_flLastEventCheck = gpGlobals->time;
pev->frame = 0;
if (!m_animate)
pev->framerate = 0.0; // FIX: don't reset framerate
}
}
//
// CyclerUse - starts a rotation trend
//
void CCycler :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
m_animate = !m_animate;
if (m_animate)
pev->framerate = 1.0;
else
pev->framerate = 0.0;
}
//
// CyclerPain , changes sequences when shot
//
//void CCycler :: Pain( float flDamage )
int CCycler :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
{
if (m_animate)
{
pev->sequence++;
ResetSequenceInfo( );
if (m_flFrameRate == 0.0)
{
pev->sequence = 0;
ResetSequenceInfo( );
}
pev->frame = 0;
}
else
{
pev->framerate = 1.0;
StudioFrameAdvance ( 0.1 );
pev->framerate = 0;
ALERT( at_console, "sequence: %d, frame %.0f\n", pev->sequence, pev->frame );
}
return 0;
}
#endif
class CCyclerSprite : public CBaseEntity
{
public:
void Spawn( void );
void Think( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_DONT_SAVE | FCAP_IMPULSE_USE); }
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
void Animate( float frames );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
inline int ShouldAnimate( void ) { return m_animate && m_maxFrame > 1.0; }
int m_animate;
float m_lastTime;
float m_maxFrame;
};
LINK_ENTITY_TO_CLASS( cycler_sprite, CCyclerSprite );
TYPEDESCRIPTION CCyclerSprite::m_SaveData[] =
{
DEFINE_FIELD( CCyclerSprite, m_animate, FIELD_INTEGER ),
DEFINE_FIELD( CCyclerSprite, m_lastTime, FIELD_TIME ),
DEFINE_FIELD( CCyclerSprite, m_maxFrame, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CCyclerSprite, CBaseEntity );
void CCyclerSprite::Spawn( void )
{
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_NONE;
pev->takedamage = DAMAGE_YES;
pev->effects = 0;
pev->frame = 0;
pev->nextthink = gpGlobals->time + 0.1;
m_animate = 1;
m_lastTime = gpGlobals->time;
PRECACHE_MODEL( (char *)STRING(pev->model) );
SET_MODEL( ENT(pev), STRING(pev->model) );
m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1;
}
void CCyclerSprite::Think( void )
{
if ( ShouldAnimate() )
Animate( pev->framerate * (gpGlobals->time - m_lastTime) );
pev->nextthink = gpGlobals->time + 0.1;
m_lastTime = gpGlobals->time;
}
void CCyclerSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
m_animate = !m_animate;
ALERT( at_console, "Sprite: %s\n", STRING(pev->model) );
}
int CCyclerSprite::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
{
if ( m_maxFrame > 1.0 )
{
Animate( 1.0 );
}
return 1;
}
void CCyclerSprite::Animate( float frames )
{
pev->frame += frames;
if ( m_maxFrame > 0 )
pev->frame = fmod( pev->frame, m_maxFrame );
}
class CWeaponCycler : public CBasePlayerWeapon
{
public:
void Spawn( void );
int iItemSlot( void ) { return 1; }
int GetItemInfo(ItemInfo *p) {return 0; }
void PrimaryAttack( void );
void SecondaryAttack( void );
BOOL Deploy( void );
void Holster( void );
int m_iszModel;
int m_iModel;
};
LINK_ENTITY_TO_CLASS( cycler_weapon, CWeaponCycler );
void CWeaponCycler::Spawn( )
{
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_NONE;
PRECACHE_MODEL( (char *)STRING(pev->model) );
SET_MODEL( ENT(pev), STRING(pev->model) );
m_iszModel = pev->model;
m_iModel = pev->modelindex;
UTIL_SetOrigin( pev, pev->origin );
UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16));
SetTouch( DefaultTouch );
}
BOOL CWeaponCycler::Deploy( )
{
m_pPlayer->pev->viewmodel = m_iszModel;
m_pPlayer->m_flNextAttack = gpGlobals->time + 1.0;
SendWeaponAnim( 0 );
m_iClip = 0;
return TRUE;
}
void CWeaponCycler::Holster( )
{
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
}
void CWeaponCycler::PrimaryAttack()
{
SendWeaponAnim( pev->sequence );
m_flNextPrimaryAttack = gpGlobals->time + 0.3;
}
void CWeaponCycler::SecondaryAttack( void )
{
float flFrameRate, flGroundSpeed;
pev->sequence = (pev->sequence + 1) % 8;
pev->modelindex = m_iModel;
void *pmodel = GET_MODEL_PTR( ENT(pev) );
GetSequenceInfo( pmodel, pev, &flFrameRate, &flGroundSpeed );
pev->modelindex = 0;
if (flFrameRate == 0.0)
{
pev->sequence = 0;
}
SendWeaponAnim( pev->sequence );
m_flNextSecondaryAttack = gpGlobals->time + 0.3;
}
// Flaming Wreakage
class CWreckage : public CBaseMonster
{
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
void Spawn( void );
void Precache( void );
void Think( void );
int m_flStartTime;
};
TYPEDESCRIPTION CWreckage::m_SaveData[] =
{
DEFINE_FIELD( CWreckage, m_flStartTime, FIELD_TIME ),
};
IMPLEMENT_SAVERESTORE( CWreckage, CBaseMonster );
LINK_ENTITY_TO_CLASS( cycler_wreckage, CWreckage );
void CWreckage::Spawn( void )
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->takedamage = 0;
pev->effects = 0;
pev->frame = 0;
pev->nextthink = gpGlobals->time + 0.1;
if (pev->model)
{
PRECACHE_MODEL( (char *)STRING(pev->model) );
SET_MODEL( ENT(pev), STRING(pev->model) );
}
// pev->scale = 5.0;
m_flStartTime = gpGlobals->time;
}
void CWreckage::Precache( )
{
if ( pev->model )
PRECACHE_MODEL( (char *)STRING(pev->model) );
}
void CWreckage::Think( void )
{
StudioFrameAdvance( );
pev->nextthink = gpGlobals->time + 0.2;
if (pev->dmgtime)
{
if (pev->dmgtime < gpGlobals->time)
{
UTIL_Remove( this );
return;
}
else if (RANDOM_FLOAT( 0, pev->dmgtime - m_flStartTime ) > pev->dmgtime - gpGlobals->time)
{
return;
}
}
Vector VecSrc;
VecSrc.x = RANDOM_FLOAT( pev->absmin.x, pev->absmax.x );
VecSrc.y = RANDOM_FLOAT( pev->absmin.y, pev->absmax.y );
VecSrc.z = RANDOM_FLOAT( pev->absmin.z, pev->absmax.z );
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, VecSrc );
WRITE_BYTE( TE_SMOKE );
WRITE_COORD( VecSrc.x );
WRITE_COORD( VecSrc.y );
WRITE_COORD( VecSrc.z );
WRITE_SHORT( g_sModelIndexSmoke );
WRITE_BYTE( RANDOM_LONG(0,49) + 50 ); // scale * 10
WRITE_BYTE( RANDOM_LONG(0, 3) + 8 ); // framerate
MESSAGE_END();
}

55
dlls/h_export.cpp Normal file
View File

@ -0,0 +1,55 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== h_export.cpp ========================================================
Entity classes exported by Halflife.
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
// Required DLL entry point
BOOL WINAPI DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
// Holds engine functionality callbacks
enginefuncs_t g_engfuncs;
globalvars_t *gpGlobals;
void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals )
{
memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t));
gpGlobals = pGlobals;
}

245
dlls/handgrenade.cpp Normal file
View File

@ -0,0 +1,245 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#define HANDGRENADE_PRIMARY_VOLUME 450
enum handgrenade_e {
HANDGRENADE_IDLE = 0,
HANDGRENADE_FIDGET,
HANDGRENADE_PINPULL,
HANDGRENADE_THROW1, // toss
HANDGRENADE_THROW2, // medium
HANDGRENADE_THROW3, // hard
HANDGRENADE_HOLSTER,
HANDGRENADE_DRAW
};
class CHandGrenade : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 5; }
int GetItemInfo(ItemInfo *p);
void PrimaryAttack( void );
BOOL Deploy( void );
BOOL CanHolster( void );
void Holster( void );
void WeaponIdle( void );
float m_flStartThrow;
float m_flReleaseThrow;
};
LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade );
void CHandGrenade::Spawn( )
{
Precache( );
m_iId = WEAPON_HANDGRENADE;
SET_MODEL(ENT(pev), "models/w_grenade.mdl");
pev->dmg = gSkillData.plrDmgHandGrenade;
m_iDefaultAmmo = HANDGRENADE_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CHandGrenade::Precache( void )
{
PRECACHE_MODEL("models/w_grenade.mdl");
PRECACHE_MODEL("models/v_grenade.mdl");
PRECACHE_MODEL("models/p_grenade.mdl");
}
int CHandGrenade::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "Hand Grenade";
p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 4;
p->iPosition = 0;
p->iId = m_iId = WEAPON_HANDGRENADE;
p->iWeight = HANDGRENADE_WEIGHT;
p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
return 1;
}
BOOL CHandGrenade::Deploy( )
{
m_flReleaseThrow = -1;
return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" );
}
BOOL CHandGrenade::CanHolster( void )
{
// can only holster hand grenades when not primed!
return ( m_flStartThrow == 0 );
}
void CHandGrenade::Holster( )
{
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType])
{
SendWeaponAnim( HANDGRENADE_HOLSTER );
}
else
{
// no more grenades!
m_pPlayer->pev->weapons &= ~(1<<WEAPON_HANDGRENADE);
SetThink( DestroyItem );
pev->nextthink = gpGlobals->time + 0.1;
}
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM);
}
void CHandGrenade::PrimaryAttack()
{
if (!m_flStartThrow && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0)
{
m_flStartThrow = gpGlobals->time;
m_flReleaseThrow = 0;
SendWeaponAnim( HANDGRENADE_PINPULL );
m_flTimeWeaponIdle = gpGlobals->time + 0.5;
}
}
void CHandGrenade::WeaponIdle( void )
{
if (m_flReleaseThrow == 0)
m_flReleaseThrow = gpGlobals->time;
if (m_flTimeWeaponIdle > gpGlobals->time)
return;
if (m_flStartThrow)
{
Vector angThrow = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle;
if (angThrow.x < 0)
angThrow.x = -10 + angThrow.x * ((90 - 10) / 90.0);
else
angThrow.x = -10 + angThrow.x * ((90 + 10) / 90.0);
float flVel = (90 - angThrow.x) * 4;
if (flVel > 500)
flVel = 500;
UTIL_MakeVectors( angThrow );
Vector vecSrc = m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16;
Vector vecThrow = gpGlobals->v_forward * flVel + m_pPlayer->pev->velocity;
// alway explode 3 seconds after the pin was pulled
float time = m_flStartThrow - gpGlobals->time + 3.0;
if (time < 0)
time = 0;
CGrenade::ShootTimed( m_pPlayer->pev, vecSrc, vecThrow, time );
if (flVel < 500)
{
SendWeaponAnim( HANDGRENADE_THROW1 );
}
else if (flVel < 1000)
{
SendWeaponAnim( HANDGRENADE_THROW2 );
}
else
{
SendWeaponAnim( HANDGRENADE_THROW3 );
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
m_flStartThrow = 0;
m_flNextPrimaryAttack = gpGlobals->time + 0.5;
m_flTimeWeaponIdle = gpGlobals->time + 0.5;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] )
{
// just threw last grenade
// set attack times in the future, and weapon idle in the future so we can see the whole throw
// animation, weapon idle will automatically retire the weapon for us.
m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->time + 0.5;// ensure that the animation can finish playing
}
return;
}
else if (m_flReleaseThrow > 0)
{
// we've finished the throw, restart.
m_flStartThrow = 0;
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType])
{
SendWeaponAnim( HANDGRENADE_DRAW );
}
else
{
RetireWeapon();
return;
}
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
m_flReleaseThrow = -1;
return;
}
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType])
{
int iAnim;
float flRand = RANDOM_FLOAT(0, 1);
if (flRand <= 0.75)
{
iAnim = HANDGRENADE_IDLE;
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );// how long till we do this again.
}
else
{
iAnim = HANDGRENADE_FIDGET;
m_flTimeWeaponIdle = gpGlobals->time + 75.0 / 30.0;
}
SendWeaponAnim( iAnim );
}
}

259
dlls/healthkit.cpp Normal file
View File

@ -0,0 +1,259 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "items.h"
#include "gamerules.h"
extern int gmsgItemPickup;
class CHealthKit : public CItem
{
void Spawn( void );
void Precache( void );
BOOL MyTouch( CBasePlayer *pPlayer );
/*
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
*/
};
LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit );
/*
TYPEDESCRIPTION CHealthKit::m_SaveData[] =
{
};
IMPLEMENT_SAVERESTORE( CHealthKit, CItem);
*/
void CHealthKit :: Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_medkit.mdl");
CItem::Spawn();
}
void CHealthKit::Precache( void )
{
PRECACHE_MODEL("models/w_medkit.mdl");
PRECACHE_SOUND("items/smallmedkit1.wav");
}
BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer->TakeHealth( gSkillData.healthkitCapacity, DMG_GENERIC ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev );
WRITE_STRING( STRING(pev->classname) );
MESSAGE_END();
EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM);
if ( g_pGameRules->ItemShouldRespawn( this ) )
{
Respawn();
}
else
{
UTIL_Remove(this);
}
return TRUE;
}
return FALSE;
}
//-------------------------------------------------------------
// Wall mounted health kit
//-------------------------------------------------------------
class CWallHealth : public CBaseToggle
{
public:
void Spawn( );
void Precache( void );
void EXPORT Off(void);
void EXPORT Recharge(void);
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
float m_flNextCharge;
int m_iReactivate ; // DeathMatch Delay until reactvated
int m_iJuice;
int m_iOn; // 0 = off, 1 = startup, 2 = going
float m_flSoundTime;
};
TYPEDESCRIPTION CWallHealth::m_SaveData[] =
{
DEFINE_FIELD( CWallHealth, m_flNextCharge, FIELD_TIME),
DEFINE_FIELD( CWallHealth, m_iReactivate, FIELD_INTEGER),
DEFINE_FIELD( CWallHealth, m_iJuice, FIELD_INTEGER),
DEFINE_FIELD( CWallHealth, m_iOn, FIELD_INTEGER),
DEFINE_FIELD( CWallHealth, m_flSoundTime, FIELD_TIME),
};
IMPLEMENT_SAVERESTORE( CWallHealth, CBaseEntity );
LINK_ENTITY_TO_CLASS(func_healthcharger, CWallHealth);
void CWallHealth::KeyValue( KeyValueData *pkvd )
{
if ( FStrEq(pkvd->szKeyName, "style") ||
FStrEq(pkvd->szKeyName, "height") ||
FStrEq(pkvd->szKeyName, "value1") ||
FStrEq(pkvd->szKeyName, "value2") ||
FStrEq(pkvd->szKeyName, "value3"))
{
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "dmdelay"))
{
m_iReactivate = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue( pkvd );
}
void CWallHealth::Spawn()
{
Precache( );
pev->solid = SOLID_BSP;
pev->movetype = MOVETYPE_PUSH;
UTIL_SetOrigin(pev, pev->origin); // set size and link into world
UTIL_SetSize(pev, pev->mins, pev->maxs);
SET_MODEL(ENT(pev), STRING(pev->model) );
m_iJuice = gSkillData.healthchargerCapacity;
pev->frame = 0;
}
void CWallHealth::Precache()
{
PRECACHE_SOUND("items/medshot4.wav");
PRECACHE_SOUND("items/medshotno1.wav");
PRECACHE_SOUND("items/medcharge4.wav");
}
void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Make sure that we have a caller
if (!pActivator)
return;
// if it's not a player, ignore
if ( !pActivator->IsPlayer() )
return;
// if there is no juice left, turn it off
if (m_iJuice <= 0)
{
pev->frame = 1;
Off();
}
// if the player doesn't have the suit, or there is no juice left, make the deny noise
if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<<WEAPON_SUIT))))
{
if (m_flSoundTime <= gpGlobals->time)
{
m_flSoundTime = gpGlobals->time + 0.62;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshotno1.wav", 1.0, ATTN_NORM );
}
return;
}
pev->nextthink = pev->ltime + 0.25;
SetThink(Off);
// Time to recharge yet?
if (m_flNextCharge >= gpGlobals->time)
return;
// Play the on sound or the looping charging sound
if (!m_iOn)
{
m_iOn++;
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM );
m_flSoundTime = 0.56 + gpGlobals->time;
}
if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time))
{
m_iOn++;
EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM );
}
// charge the player
if ( pActivator->TakeHealth( 1, DMG_GENERIC ) )
{
m_iJuice--;
}
// govern the rate of charge
m_flNextCharge = gpGlobals->time + 0.1;
}
void CWallHealth::Recharge(void)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM );
m_iJuice = gSkillData.healthchargerCapacity;
pev->frame = 0;
SetThink( SUB_DoNothing );
}
void CWallHealth::Off(void)
{
// Stop looping sound.
if (m_iOn > 1)
STOP_SOUND( ENT(pev), CHAN_STATIC, "items/medcharge4.wav" );
m_iOn = 0;
if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) )
{
pev->nextthink = pev->ltime + m_iReactivate;
SetThink(Recharge);
}
else
SetThink( SUB_DoNothing );
}

426
dlls/hornet.cpp Normal file
View File

@ -0,0 +1,426 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//=========================================================
// Hornets
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "soundent.h"
#include "hornet.h"
#include "gamerules.h"
int iHornetTrail;
int iHornetPuff;
LINK_ENTITY_TO_CLASS( hornet, CHornet );
//=========================================================
// Save/Restore
//=========================================================
TYPEDESCRIPTION CHornet::m_SaveData[] =
{
DEFINE_FIELD( CHornet, m_flStopAttack, FIELD_TIME ),
DEFINE_FIELD( CHornet, m_iHornetType, FIELD_INTEGER ),
DEFINE_FIELD( CHornet, m_flFlySpeed, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CHornet, CBaseMonster );
//=========================================================
// don't let hornets gib, ever.
//=========================================================
int CHornet :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
// filter these bits a little.
bitsDamageType &= ~ ( DMG_ALWAYSGIB );
bitsDamageType |= DMG_NEVERGIB;
return CBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType );
}
//=========================================================
//=========================================================
void CHornet :: Spawn( void )
{
Precache();
pev->movetype = MOVETYPE_FLY;
pev->solid = SOLID_BBOX;
pev->takedamage = DAMAGE_YES;
pev->flags |= FL_MONSTER;
pev->health = 1;// weak!
if ( g_pGameRules->IsMultiplayer() )
{
// hornets don't live as long in multiplayer
m_flStopAttack = gpGlobals->time + 3.5;
}
else
{
m_flStopAttack = gpGlobals->time + 5.0;
}
m_flFieldOfView = 0.9; // +- 25 degrees
if ( RANDOM_LONG ( 1, 5 ) <= 2 )
{
m_iHornetType = HORNET_TYPE_RED;
m_flFlySpeed = HORNET_RED_SPEED;
}
else
{
m_iHornetType = HORNET_TYPE_ORANGE;
m_flFlySpeed = HORNET_ORANGE_SPEED;
}
SET_MODEL(ENT( pev ), "models/hornet.mdl");
UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) );
SetTouch( DieTouch );
SetThink( StartTrack );
edict_t *pSoundEnt = pev->owner;
if ( !pSoundEnt )
pSoundEnt = edict();
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM); break;
case 1: EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM); break;
case 2: EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM); break;
}
if ( !FNullEnt(pev->owner) && (pev->owner->v.flags & FL_CLIENT) )
{
pev->dmg = gSkillData.plrDmgHornet;
}
else
{
// no real owner, or owner isn't a client.
pev->dmg = gSkillData.monDmgHornet;
}
pev->nextthink = gpGlobals->time + 0.1;
ResetSequenceInfo( );
}
void CHornet :: Precache()
{
PRECACHE_MODEL("models/hornet.mdl");
PRECACHE_SOUND( "agrunt/ag_fire1.wav" );
PRECACHE_SOUND( "agrunt/ag_fire2.wav" );
PRECACHE_SOUND( "agrunt/ag_fire3.wav" );
PRECACHE_SOUND( "hornet/ag_buzz1.wav" );
PRECACHE_SOUND( "hornet/ag_buzz2.wav" );
PRECACHE_SOUND( "hornet/ag_buzz3.wav" );
PRECACHE_SOUND( "hornet/ag_hornethit1.wav" );
PRECACHE_SOUND( "hornet/ag_hornethit2.wav" );
PRECACHE_SOUND( "hornet/ag_hornethit3.wav" );
iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" );
iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr");
}
//=========================================================
// hornets will never get mad at each other, no matter who the owner is.
//=========================================================
int CHornet::IRelationship ( CBaseEntity *pTarget )
{
if ( pTarget->pev->modelindex == pev->modelindex )
{
return R_NO;
}
return CBaseMonster :: IRelationship( pTarget );
}
//=========================================================
// ID's Hornet as their owner
//=========================================================
int CHornet::Classify ( void )
{
if ( pev->owner && pev->owner->v.flags & FL_CLIENT)
{
return CLASS_PLAYER_BIOWEAPON;
}
return CLASS_ALIEN_BIOWEAPON;
}
//=========================================================
// StartTrack - starts a hornet out tracking its target
//=========================================================
void CHornet :: StartTrack ( void )
{
IgniteTrail();
SetTouch( TrackTouch );
SetThink( TrackTarget );
pev->nextthink = gpGlobals->time + 0.1;
}
//=========================================================
// StartDart - starts a hornet out just flying straight.
//=========================================================
void CHornet :: StartDart ( void )
{
IgniteTrail();
SetTouch( DartTouch );
SetThink( SUB_Remove );
pev->nextthink = gpGlobals->time + 4;
}
void CHornet::IgniteTrail( void )
{
/*
ted's suggested trail colors:
r161
g25
b97
r173
g39
b14
old colors
case HORNET_TYPE_RED:
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 128 ); // r, g, b
WRITE_BYTE( 0 ); // r, g, b
break;
case HORNET_TYPE_ORANGE:
WRITE_BYTE( 0 ); // r, g, b
WRITE_BYTE( 100 ); // r, g, b
WRITE_BYTE( 255 ); // r, g, b
break;
*/
// trail
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_BEAMFOLLOW );
WRITE_SHORT( entindex() ); // entity
WRITE_SHORT( iHornetTrail ); // model
WRITE_BYTE( 10 ); // life
WRITE_BYTE( 2 ); // width
switch ( m_iHornetType )
{
case HORNET_TYPE_RED:
WRITE_BYTE( 179 ); // r, g, b
WRITE_BYTE( 39 ); // r, g, b
WRITE_BYTE( 14 ); // r, g, b
break;
case HORNET_TYPE_ORANGE:
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 128 ); // r, g, b
WRITE_BYTE( 0 ); // r, g, b
break;
}
WRITE_BYTE( 128 ); // brightness
MESSAGE_END();
}
//=========================================================
// Hornet is flying, gently tracking target
//=========================================================
void CHornet :: TrackTarget ( void )
{
Vector vecFlightDir;
Vector vecDirToEnemy;
float flDelta;
StudioFrameAdvance( );
if (gpGlobals->time > m_flStopAttack)
{
SetTouch( NULL );
SetThink( SUB_Remove );
pev->nextthink = gpGlobals->time + 0.1;
return;
}
// UNDONE: The player pointer should come back after returning from another level
if ( m_hEnemy == NULL )
{// enemy is dead.
Look( 512 );
m_hEnemy = BestVisibleEnemy( );
}
if ( m_hEnemy != NULL && FVisible( m_hEnemy ))
{
m_vecEnemyLKP = m_hEnemy->BodyTarget( pev->origin );
}
else
{
m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1;
}
vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize();
if (pev->velocity.Length() < 0.1)
vecFlightDir = vecDirToEnemy;
else
vecFlightDir = pev->velocity.Normalize();
// measure how far the turn is, the wider the turn, the slow we'll go this time.
flDelta = DotProduct ( vecFlightDir, vecDirToEnemy );
if ( flDelta < 0.5 )
{// hafta turn wide again. play sound
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
}
}
if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED )
{// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far.
flDelta = 0.25;
}
pev->velocity = ( vecFlightDir + vecDirToEnemy).Normalize();
if ( pev->owner && (pev->owner->v.flags & FL_MONSTER) )
{
// random pattern only applies to hornets fired by monsters, not players.
pev->velocity.x += RANDOM_FLOAT ( -0.10, 0.10 );// scramble the flight dir a bit.
pev->velocity.y += RANDOM_FLOAT ( -0.10, 0.10 );
pev->velocity.z += RANDOM_FLOAT ( -0.10, 0.10 );
}
switch ( m_iHornetType )
{
case HORNET_TYPE_RED:
pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn )
pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 );
break;
case HORNET_TYPE_ORANGE:
pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn.
pev->nextthink = gpGlobals->time + 0.1;// fixed think time
break;
}
pev->angles = UTIL_VecToAngles (pev->velocity);
pev->solid = SOLID_BBOX;
// if hornet is close to the enemy, jet in a straight line for a half second.
// (only in the single player game)
if ( m_hEnemy != NULL && !g_pGameRules->IsMultiplayer() )
{
if ( flDelta >= 0.4 && ( pev->origin - m_vecEnemyLKP ).Length() <= 300 )
{
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_SPRITE );
WRITE_COORD( pev->origin.x); // pos
WRITE_COORD( pev->origin.y);
WRITE_COORD( pev->origin.z);
WRITE_SHORT( iHornetPuff ); // model
// WRITE_BYTE( 0 ); // life * 10
WRITE_BYTE( 2 ); // size * 10
WRITE_BYTE( 128 ); // brightness
MESSAGE_END();
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
}
pev->velocity = pev->velocity * 2;
pev->nextthink = gpGlobals->time + 1.0;
// don't attack again
m_flStopAttack = gpGlobals->time;
}
}
}
//=========================================================
// Tracking Hornet hit something
//=========================================================
void CHornet :: TrackTouch ( CBaseEntity *pOther )
{
if ( pOther->edict() == pev->owner || pOther->pev->modelindex == pev->modelindex )
{// bumped into the guy that shot it.
pev->solid = SOLID_NOT;
return;
}
if ( IRelationship( pOther ) <= R_NO )
{
// hit something we don't want to hurt, so turn around.
pev->velocity = pev->velocity.Normalize();
pev->velocity.x *= -1;
pev->velocity.y *= -1;
pev->origin = pev->origin + pev->velocity * 4; // bounce the hornet off a bit.
pev->velocity = pev->velocity * m_flFlySpeed;
return;
}
DieTouch( pOther );
}
void CHornet::DartTouch( CBaseEntity *pOther )
{
DieTouch( pOther );
}
void CHornet::DieTouch ( CBaseEntity *pOther )
{
if ( pOther && pOther->pev->takedamage )
{// do the damage
switch (RANDOM_LONG(0,2))
{// buzz when you plug someone
case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit1.wav", 1, ATTN_NORM); break;
case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit2.wav", 1, ATTN_NORM); break;
case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit3.wav", 1, ATTN_NORM); break;
}
pOther->TakeDamage( pev, VARS( pev->owner ), pev->dmg, DMG_BULLET );
}
pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid
pev->solid = SOLID_NOT;
SetThink ( SUB_Remove );
pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish!
}

58
dlls/hornet.h Normal file
View File

@ -0,0 +1,58 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//=========================================================
// Hornets
//=========================================================
//=========================================================
// Hornet Defines
//=========================================================
#define HORNET_TYPE_RED 0
#define HORNET_TYPE_ORANGE 1
#define HORNET_RED_SPEED (float)600
#define HORNET_ORANGE_SPEED (float)800
#define HORNET_BUZZ_VOLUME (float)0.8
extern int iHornetPuff;
//=========================================================
// Hornet - this is the projectile that the Alien Grunt fires.
//=========================================================
class CHornet : public CBaseMonster
{
public:
void Spawn( void );
void Precache( void );
int Classify ( void );
int IRelationship ( CBaseEntity *pTarget );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
void IgniteTrail( void );
void EXPORT StartTrack ( void );
void EXPORT StartDart ( void );
void EXPORT TrackTarget ( void );
void EXPORT TrackTouch ( CBaseEntity *pOther );
void EXPORT DartTouch( CBaseEntity *pOther );
void EXPORT DieTouch ( CBaseEntity *pOther );
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
float m_flStopAttack;
int m_iHornetType;
float m_flFlySpeed;
};

293
dlls/hornetgun.cpp Normal file
View File

@ -0,0 +1,293 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "hornet.h"
#include "gamerules.h"
enum hgun_e {
HGUN_IDLE1 = 0,
HGUN_FIDGETSWAY,
HGUN_FIDGETSHAKE,
HGUN_DOWN,
HGUN_UP,
HGUN_SHOOT
};
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( void );
void Reload( void );
void WeaponIdle( void );
float m_flNextAnimTime;
float m_flRechargeTime;
int m_iFirePhase;// don't save me.
};
LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun );
BOOL CHgun::IsUseable( void )
{
return TRUE;
}
void CHgun::Spawn( )
{
Precache( );
m_iId = WEAPON_HORNETGUN;
SET_MODEL(ENT(pev), "models/w_hgun.mdl");
m_iDefaultAmmo = HIVEHAND_DEFAULT_GIVE;
m_iFirePhase = 0;
FallInit();// get ready to fall down.
}
void CHgun::Precache( void )
{
PRECACHE_MODEL("models/v_hgun.mdl");
PRECACHE_MODEL("models/w_hgun.mdl");
PRECACHE_MODEL("models/p_hgun.mdl");
UTIL_PrecacheOther("hornet");
}
int CHgun::AddToPlayer( CBasePlayer *pPlayer )
{
if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
{
if ( g_pGameRules->IsMultiplayer() )
{
// in multiplayer, all hivehands come full.
pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = HORNET_MAX_CARRY;
}
MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
WRITE_BYTE( m_iId );
MESSAGE_END();
return TRUE;
}
return FALSE;
}
int CHgun::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "Hornets";
p->iMaxAmmo1 = HORNET_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 3;
p->iPosition = 3;
p->iId = m_iId = WEAPON_HORNETGUN;
p->iFlags = ITEM_FLAG_NOAUTOSWITCHEMPTY | ITEM_FLAG_NOAUTORELOAD;
p->iWeight = HORNETGUN_WEIGHT;
return 1;
}
BOOL CHgun::Deploy( )
{
return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" );
}
void CHgun::Holster( )
{
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
// m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
SendWeaponAnim( HGUN_DOWN );
//!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either.
if ( !m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] )
{
m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = 1;
}
}
void CHgun::PrimaryAttack()
{
Reload( );
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
{
return;
}
UTIL_MakeVectors( m_pPlayer->pev->v_angle );
CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, m_pPlayer->edict() );
pHornet->pev->velocity = gpGlobals->v_forward * 300;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
m_flRechargeTime = gpGlobals->time + 0.5;
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;
SendWeaponAnim( HGUN_SHOOT );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.25;
if (m_flNextPrimaryAttack < gpGlobals->time)
{
m_flNextPrimaryAttack = gpGlobals->time + 0.25;
}
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
}
void CHgun::SecondaryAttack( void )
{
Reload();
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
{
return;
}
CBaseEntity *pHornet;
Vector vecSrc;
UTIL_MakeVectors( m_pPlayer->pev->v_angle );
vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12;
m_iFirePhase++;
switch ( m_iFirePhase )
{
case 1:
vecSrc = vecSrc + gpGlobals->v_up * 8;
break;
case 2:
vecSrc = vecSrc + gpGlobals->v_up * 8;
vecSrc = vecSrc + gpGlobals->v_right * 8;
break;
case 3:
vecSrc = vecSrc + gpGlobals->v_right * 8;
break;
case 4:
vecSrc = vecSrc + gpGlobals->v_up * -8;
vecSrc = vecSrc + gpGlobals->v_right * 8;
break;
case 5:
vecSrc = vecSrc + gpGlobals->v_up * -8;
break;
case 6:
vecSrc = vecSrc + gpGlobals->v_up * -8;
vecSrc = vecSrc + gpGlobals->v_right * -8;
break;
case 7:
vecSrc = vecSrc + gpGlobals->v_right * -8;
break;
case 8:
vecSrc = vecSrc + gpGlobals->v_up * 8;
vecSrc = vecSrc + gpGlobals->v_right * -8;
m_iFirePhase = 0;
break;
}
pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict() );
pHornet->pev->velocity = gpGlobals->v_forward * 1200;
pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity );
pHornet->SetThink( CHornet::StartDart );
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;
m_flRechargeTime = gpGlobals->time + 0.5;
SendWeaponAnim( HGUN_SHOOT );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + 0.1;
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( 0, 2 );
}
void CHgun::Reload( void )
{
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= HORNET_MAX_CARRY)
return;
while (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < HORNET_MAX_CARRY && m_flRechargeTime < gpGlobals->time)
{
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]++;
m_flRechargeTime += 0.5;
}
}
void CHgun::WeaponIdle( void )
{
Reload( );
if (m_flTimeWeaponIdle > gpGlobals->time)
return;
int iAnim;
float flRand = RANDOM_FLOAT(0, 1);
if (flRand <= 0.75)
{
iAnim = HGUN_IDLE1;
m_flTimeWeaponIdle = gpGlobals->time + 30.0 / 16 * (2);
}
else if (flRand <= 0.875)
{
iAnim = HGUN_FIDGETSWAY;
m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0;
}
else
{
iAnim = HGUN_FIDGETSHAKE;
m_flTimeWeaponIdle = gpGlobals->time + 35.0 / 16.0;
}
SendWeaponAnim( iAnim );
}
#endif

335
dlls/items.cpp Normal file
View File

@ -0,0 +1,335 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== items.cpp ========================================================
functions governing the selection/use of weapons for players
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "weapons.h"
#include "player.h"
#include "skill.h"
#include "items.h"
#include "gamerules.h"
extern int gmsgItemPickup;
class CWorldItem : public CBaseEntity
{
public:
void KeyValue(KeyValueData *pkvd );
void Spawn( void );
int m_iType;
};
LINK_ENTITY_TO_CLASS(world_items, CWorldItem);
void CWorldItem::KeyValue(KeyValueData *pkvd)
{
if (FStrEq(pkvd->szKeyName, "type"))
{
m_iType = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue( pkvd );
}
void CWorldItem::Spawn( void )
{
CBaseEntity *pEntity = NULL;
switch (m_iType)
{
case 44: // ITEM_BATTERY:
pEntity = CBaseEntity::Create( "item_battery", pev->origin, pev->angles );
break;
case 42: // ITEM_ANTIDOTE:
pEntity = CBaseEntity::Create( "item_antidote", pev->origin, pev->angles );
break;
case 43: // ITEM_SECURITY:
pEntity = CBaseEntity::Create( "item_security", pev->origin, pev->angles );
break;
case 45: // ITEM_SUIT:
pEntity = CBaseEntity::Create( "item_suit", pev->origin, pev->angles );
break;
}
if (!pEntity)
{
ALERT( at_console, "unable to create world_item %d\n", m_iType );
}
else
{
pEntity->pev->target = pev->target;
pEntity->pev->targetname = pev->targetname;
pEntity->pev->spawnflags = pev->spawnflags;
}
REMOVE_ENTITY(edict());
}
void CItem::Spawn( void )
{
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;
UTIL_SetOrigin( pev, pev->origin );
UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16));
SetTouch(ItemTouch);
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;
}
}
extern int gEvilImpulse101;
void CItem::ItemTouch( CBaseEntity *pOther )
{
// if it's not a player, ignore
if ( !pOther->IsPlayer() )
{
return;
}
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
// ok, a player is touching this item, but can he have it?
if ( !g_pGameRules->CanHaveItem( pPlayer, this ) )
{
// no? Ignore the touch.
return;
}
if (MyTouch( pPlayer ))
{
SUB_UseTargets( pOther, USE_TOGGLE, 0 );
SetTouch( NULL );
// player grabbed the item.
g_pGameRules->PlayerGotItem( pPlayer, this );
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES )
{
Respawn();
}
else
{
UTIL_Remove( this );
}
}
else if (gEvilImpulse101)
{
UTIL_Remove( this );
}
}
CBaseEntity* CItem::Respawn( void )
{
SetTouch( NULL );
pev->effects |= EF_NODRAW;
UTIL_SetOrigin( pev, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn.
SetThink ( Materialize );
pev->nextthink = g_pGameRules->FlItemRespawnTime( this );
return this;
}
void CItem::Materialize( void )
{
if ( pev->effects & EF_NODRAW )
{
// 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( ItemTouch );
}
#define SF_SUIT_SHORTLOGON 0x0001
class CItemSuit : public CItem
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_suit.mdl");
CItem::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_suit.mdl");
}
BOOL MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer->pev->weapons & (1<<WEAPON_SUIT) )
return FALSE;
if ( pev->spawnflags & SF_SUIT_SHORTLOGON )
EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_A0"); // short version of suit logon,
else
EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_AAx"); // long version of suit logon
pPlayer->pev->weapons |= (1<<WEAPON_SUIT);
return TRUE;
}
};
LINK_ENTITY_TO_CLASS(item_suit, CItemSuit);
class CItemBattery : public CItem
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_battery.mdl");
CItem::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_battery.mdl");
PRECACHE_SOUND( "items/gunpickup2.wav" );
}
BOOL MyTouch( CBasePlayer *pPlayer )
{
if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) &&
(pPlayer->pev->weapons & (1<<WEAPON_SUIT)))
{
int pct;
char szcharge[64];
pPlayer->pev->armorvalue += gSkillData.batteryCapacity;
pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY);
EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM );
MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev );
WRITE_STRING( STRING(pev->classname) );
MESSAGE_END();
// Suit reports new power level
// For some reason this wasn't working in release build -- round it.
pct = (int)( (float)(pPlayer->pev->armorvalue * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5);
pct = (pct / 5);
if (pct > 0)
pct--;
sprintf( szcharge,"!HEV_%1dP", pct );
//EMIT_SOUND_SUIT(ENT(pev), szcharge);
pPlayer->SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC);
return TRUE;
}
return FALSE;
}
};
LINK_ENTITY_TO_CLASS(item_battery, CItemBattery);
class CItemAntidote : public CItem
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_antidote.mdl");
CItem::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_antidote.mdl");
}
BOOL MyTouch( CBasePlayer *pPlayer )
{
pPlayer->SetSuitUpdate("!HEV_DET4", FALSE, SUIT_NEXT_IN_1MIN);
pPlayer->m_rgItems[ITEM_ANTIDOTE] += 1;
return TRUE;
}
};
LINK_ENTITY_TO_CLASS(item_antidote, CItemAntidote);
class CItemSecurity : public CItem
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_security.mdl");
CItem::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_security.mdl");
}
BOOL MyTouch( CBasePlayer *pPlayer )
{
pPlayer->m_rgItems[ITEM_SECURITY] += 1;
return TRUE;
}
};
LINK_ENTITY_TO_CLASS(item_security, CItemSecurity);
class CItemLongJump : public CItem
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_longjump.mdl");
CItem::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_longjump.mdl");
}
BOOL MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer->m_fLongJump )
{
return FALSE;
}
if ( ( pPlayer->pev->weapons & (1<<WEAPON_SUIT) ) )
{
pPlayer->m_fLongJump = TRUE;// player now has longjump module
MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev );
WRITE_STRING( STRING(pev->classname) );
MESSAGE_END();
EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" ); // Play the longjump sound UNDONE: Kelly? correct sound?
return TRUE;
}
return FALSE;
}
};
LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump );

29
dlls/items.h Normal file
View File

@ -0,0 +1,29 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef ITEMS_H
#define ITEMS_H
class CItem : public CBaseEntity
{
public:
void Spawn( void );
CBaseEntity* Respawn( void );
void EXPORT ItemTouch( CBaseEntity *pOther );
void EXPORT Materialize( void );
virtual BOOL MyTouch( CBasePlayer *pPlayer ) { return FALSE; };
};
#endif // ITEMS_H

199
dlls/lights.cpp Normal file
View File

@ -0,0 +1,199 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== lights.cpp ========================================================
spawn and think functions for editor-placed lights
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
class CLight : public CPointEntity
{
public:
virtual void KeyValue( KeyValueData* pkvd );
virtual void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
private:
int m_iStyle;
int m_iszPattern;
};
LINK_ENTITY_TO_CLASS( light, CLight );
TYPEDESCRIPTION CLight::m_SaveData[] =
{
DEFINE_FIELD( CLight, m_iStyle, FIELD_INTEGER ),
DEFINE_FIELD( CLight, m_iszPattern, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CLight, CPointEntity );
//
// Cache user-entity-field values until spawn is called.
//
void CLight :: KeyValue( KeyValueData* pkvd)
{
if (FStrEq(pkvd->szKeyName, "style"))
{
m_iStyle = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "pitch"))
{
pev->angles.x = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "pattern"))
{
m_iszPattern = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
{
CPointEntity::KeyValue( pkvd );
}
}
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) LIGHT_START_OFF
Non-displayed light.
Default light value is 300
Default style is 0
If targeted, it will toggle between on or off.
*/
void CLight :: Spawn( void )
{
if (FStringNull(pev->targetname))
{ // inert light
REMOVE_ENTITY(ENT(pev));
return;
}
if (m_iStyle >= 32)
{
// CHANGE_METHOD(ENT(pev), em_use, light_use);
if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF))
LIGHT_STYLE(m_iStyle, "a");
else if (m_iszPattern)
LIGHT_STYLE(m_iStyle, (char *)STRING( m_iszPattern ));
else
LIGHT_STYLE(m_iStyle, "m");
}
}
void CLight :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (m_iStyle >= 32)
{
if ( !ShouldToggle( useType, !FBitSet(pev->spawnflags, SF_LIGHT_START_OFF) ) )
return;
if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF))
{
if (m_iszPattern)
LIGHT_STYLE(m_iStyle, (char *)STRING( m_iszPattern ));
else
LIGHT_STYLE(m_iStyle, "m");
ClearBits(pev->spawnflags, SF_LIGHT_START_OFF);
}
else
{
LIGHT_STYLE(m_iStyle, "a");
SetBits(pev->spawnflags, SF_LIGHT_START_OFF);
}
}
}
//
// shut up spawn functions for new spotlights
//
LINK_ENTITY_TO_CLASS( light_spot, CLight );
class CEnvLight : public CLight
{
public:
void KeyValue( KeyValueData* pkvd );
void Spawn( void );
};
LINK_ENTITY_TO_CLASS( light_environment, CEnvLight );
void CEnvLight::KeyValue( KeyValueData* pkvd )
{
if (FStrEq(pkvd->szKeyName, "_light"))
{
int r, g, b, v, j;
char szColor[64];
j = sscanf( pkvd->szValue, "%d %d %d %d\n", &r, &g, &b, &v );
if (j == 1)
{
g = b = r;
}
else if (j == 4)
{
r = r * (v / 255.0);
g = g * (v / 255.0);
b = b * (v / 255.0);
}
// simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling
r = pow( r / 114.0, 0.6 ) * 264;
g = pow( g / 114.0, 0.6 ) * 264;
b = pow( b / 114.0, 0.6 ) * 264;
pkvd->fHandled = TRUE;
sprintf( szColor, "%d", r );
CVAR_SET_STRING( "cl_skycolor_r", szColor );
sprintf( szColor, "%d", g );
CVAR_SET_STRING( "cl_skycolor_g", szColor );
sprintf( szColor, "%d", b );
CVAR_SET_STRING( "cl_skycolor_b", szColor );
}
else
{
CLight::KeyValue( pkvd );
}
}
void CEnvLight :: Spawn( void )
{
char szVector[64];
UTIL_MakeAimVectors( pev->angles );
sprintf( szVector, "%f", gpGlobals->v_forward.x );
CVAR_SET_STRING( "cl_skyvec_x", szVector );
sprintf( szVector, "%f", gpGlobals->v_forward.y );
CVAR_SET_STRING( "cl_skyvec_y", szVector );
sprintf( szVector, "%f", gpGlobals->v_forward.z );
CVAR_SET_STRING( "cl_skyvec_z", szVector );
CLight::Spawn( );
}

918
dlls/maprules.cpp Normal file
View File

@ -0,0 +1,918 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
// -------------------------------------------
//
// maprules.cpp
//
// This module contains entities for implementing/changing game
// rules dynamically within each map (.BSP)
//
// -------------------------------------------
#include "extdll.h"
#include "eiface.h"
#include "util.h"
#include "gamerules.h"
#include "maprules.h"
#include "cbase.h"
#include "player.h"
class CRuleEntity : public CBaseEntity
{
public:
void Spawn( void );
void KeyValue( KeyValueData *pkvd );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
void SetMaster( int iszMaster ) { m_iszMaster = iszMaster; }
protected:
BOOL CanFireForActivator( CBaseEntity *pActivator );
private:
string_t m_iszMaster;
};
TYPEDESCRIPTION CRuleEntity::m_SaveData[] =
{
DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING),
};
IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity );
void CRuleEntity::Spawn( void )
{
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
pev->effects = EF_NODRAW;
}
void CRuleEntity::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "master"))
{
SetMaster( ALLOC_STRING(pkvd->szValue) );
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue( pkvd );
}
BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator )
{
if ( m_iszMaster )
{
if ( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) )
return TRUE;
else
return FALSE;
}
return TRUE;
}
//
// CRulePointEntity -- base class for all rule "point" entities (not brushes)
//
class CRulePointEntity : public CRuleEntity
{
public:
void Spawn( void );
};
void CRulePointEntity::Spawn( void )
{
CRuleEntity::Spawn();
pev->frame = 0;
pev->model = 0;
}
//
// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes)
// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing
//
class CRuleBrushEntity : public CRuleEntity
{
public:
void Spawn( void );
private:
};
void CRuleBrushEntity::Spawn( void )
{
SET_MODEL( edict(), STRING(pev->model) );
CRuleEntity::Spawn();
}
// CGameScore / game_score -- award points to player / team
// Points +/- total
// Flag: Allow negative scores SF_SCORE_NEGATIVE
// Flag: Award points to team in teamplay SF_SCORE_TEAM
#define SF_SCORE_NEGATIVE 0x0001
#define SF_SCORE_TEAM 0x0002
class CGameScore : public CRulePointEntity
{
public:
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void KeyValue( KeyValueData *pkvd );
inline int Points( void ) { return pev->frags; }
inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; }
inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; }
inline void SetPoints( int points ) { pev->frags = points; }
private:
};
LINK_ENTITY_TO_CLASS( game_score, CGameScore );
void CGameScore::Spawn( void )
{
CRulePointEntity::Spawn();
}
void CGameScore::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "points"))
{
SetPoints( atoi(pkvd->szValue) );
pkvd->fHandled = TRUE;
}
else
CRulePointEntity::KeyValue( pkvd );
}
void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
// Only players can use this
if ( pActivator->IsPlayer() )
{
if ( AwardToTeam() )
{
pActivator->AddPointsToTeam( Points(), AllowNegativeScore() );
}
else
{
pActivator->AddPoints( Points(), AllowNegativeScore() );
}
}
}
// CGameEnd / game_end -- Ends the game in MP
class CGameEnd : public CRulePointEntity
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
private:
};
LINK_ENTITY_TO_CLASS( game_end, CGameEnd );
void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
g_pGameRules->EndMultiplayerGame();
}
//
// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message)
// Flag: All players SF_ENVTEXT_ALLPLAYERS
//
#define SF_ENVTEXT_ALLPLAYERS 0x0001
class CGameText : public CRulePointEntity
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void KeyValue( KeyValueData *pkvd );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
inline BOOL MessageToAll( void ) { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS); }
inline void MessageSet( const char *pMessage ) { pev->message = ALLOC_STRING(pMessage); }
inline const char *MessageGet( void ) { return STRING(pev->message); }
private:
hudtextparms_t m_textParms;
};
LINK_ENTITY_TO_CLASS( game_text, CGameText );
// Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so
// it can't impact saved Half-Life games.
TYPEDESCRIPTION CGameText::m_SaveData[] =
{
DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ),
};
IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity );
void CGameText::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "channel"))
{
m_textParms.channel = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "x"))
{
m_textParms.x = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "y"))
{
m_textParms.y = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "effect"))
{
m_textParms.effect = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "color"))
{
int color[4];
UTIL_StringToIntArray( color, 4, pkvd->szValue );
m_textParms.r1 = color[0];
m_textParms.g1 = color[1];
m_textParms.b1 = color[2];
m_textParms.a1 = color[3];
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "color2"))
{
int color[4];
UTIL_StringToIntArray( color, 4, pkvd->szValue );
m_textParms.r2 = color[0];
m_textParms.g2 = color[1];
m_textParms.b2 = color[2];
m_textParms.a2 = color[3];
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "fadein"))
{
m_textParms.fadeinTime = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "fadeout"))
{
m_textParms.fadeoutTime = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "holdtime"))
{
m_textParms.holdTime = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "fxtime"))
{
m_textParms.fxTime = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CRulePointEntity::KeyValue( pkvd );
}
void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
if ( MessageToAll() )
{
UTIL_HudMessageAll( m_textParms, MessageGet() );
}
else
{
if ( pActivator->IsNetClient() )
{
UTIL_HudMessage( pActivator, m_textParms, MessageGet() );
}
}
}
//
// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator
// Only allows mastered entity to fire if the team matches my team
//
// team index (pulled from server team list "mp_teamlist"
// Flag: Remove on Fire
// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it)
//
#define SF_TEAMMASTER_FIREONCE 0x0001
#define SF_TEAMMASTER_ANYTEAM 0x0002
class CGameTeamMaster : public CRulePointEntity
{
public:
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int ObjectCaps( void ) { return CRulePointEntity:: ObjectCaps() | FCAP_MASTER; }
BOOL IsTriggered( CBaseEntity *pActivator );
const char *TeamID( void );
inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) ? TRUE : FALSE; }
inline BOOL AnyTeam( void ) { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) ? TRUE : FALSE; }
private:
BOOL TeamMatch( CBaseEntity *pActivator );
int m_teamIndex;
USE_TYPE triggerType;
};
LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster );
void CGameTeamMaster::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "teamindex"))
{
m_teamIndex = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "triggerstate"))
{
int type = atoi( pkvd->szValue );
switch( type )
{
case 0:
triggerType = USE_OFF;
break;
case 2:
triggerType = USE_TOGGLE;
break;
default:
triggerType = USE_ON;
break;
}
pkvd->fHandled = TRUE;
}
else
CRulePointEntity::KeyValue( pkvd );
}
void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
if ( useType == USE_SET )
{
if ( value < 0 )
{
m_teamIndex = -1;
}
else
{
m_teamIndex = g_pGameRules->GetTeamIndex( pActivator->TeamID() );
}
return;
}
if ( TeamMatch( pActivator ) )
{
SUB_UseTargets( pActivator, triggerType, value );
if ( RemoveOnFire() )
UTIL_Remove( this );
}
}
BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator )
{
return TeamMatch( pActivator );
}
const char *CGameTeamMaster::TeamID( void )
{
if ( m_teamIndex < 0 ) // Currently set to "no team"
return "";
return g_pGameRules->GetIndexedTeamName( m_teamIndex ); // UNDONE: Fill this in with the team from the "teamlist"
}
BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator )
{
if ( m_teamIndex < 0 && AnyTeam() )
return TRUE;
if ( !pActivator )
return FALSE;
return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() );
}
//
// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team
// Flag: Fire once
// Flag: Clear team -- Sets the team to "NONE" instead of activator
#define SF_TEAMSET_FIREONCE 0x0001
#define SF_TEAMSET_CLEARTEAM 0x0002
class CGameTeamSet : public CRulePointEntity
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMSET_FIREONCE) ? TRUE : FALSE; }
inline BOOL ShouldClearTeam( void ) { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) ? TRUE : FALSE; }
private:
};
LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet );
void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
if ( ShouldClearTeam() )
{
SUB_UseTargets( pActivator, USE_SET, -1 );
}
else
{
SUB_UseTargets( pActivator, USE_SET, 0 );
}
if ( RemoveOnFire() )
{
UTIL_Remove( this );
}
}
//
// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired
//
// Needs master?
class CGamePlayerZone : public CRuleBrushEntity
{
public:
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
private:
string_t m_iszInTarget;
string_t m_iszOutTarget;
string_t m_iszInCount;
string_t m_iszOutCount;
};
LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone );
TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] =
{
DEFINE_FIELD( CGamePlayerZone, m_iszInTarget, FIELD_STRING ),
DEFINE_FIELD( CGamePlayerZone, m_iszOutTarget, FIELD_STRING ),
DEFINE_FIELD( CGamePlayerZone, m_iszInCount, FIELD_STRING ),
DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity );
void CGamePlayerZone::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "intarget"))
{
m_iszInTarget = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "outtarget"))
{
m_iszOutTarget = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "incount"))
{
m_iszInCount = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "outcount"))
{
m_iszOutCount = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CRuleBrushEntity::KeyValue( pkvd );
}
void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
int playersInCount = 0;
int playersOutCount = 0;
if ( !CanFireForActivator( pActivator ) )
return;
CBaseEntity *pPlayer = NULL;
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
pPlayer = UTIL_PlayerByIndex( i );
if ( pPlayer )
{
TraceResult trace;
int hullNumber;
hullNumber = human_hull;
if ( pPlayer->pev->flags & FL_DUCKING )
{
hullNumber = head_hull;
}
UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace );
if ( trace.fStartSolid )
{
playersInCount++;
if ( m_iszInTarget )
{
FireTargets( STRING(m_iszInTarget), pPlayer, pActivator, useType, value );
}
}
else
{
playersOutCount++;
if ( m_iszOutTarget )
{
FireTargets( STRING(m_iszOutTarget), pPlayer, pActivator, useType, value );
}
}
}
}
if ( m_iszInCount )
{
FireTargets( STRING(m_iszInCount), pActivator, this, USE_SET, playersInCount );
}
if ( m_iszOutCount )
{
FireTargets( STRING(m_iszOutCount), pActivator, this, USE_SET, playersOutCount );
}
}
//
// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it
// Flag: Fire once
#define SF_PKILL_FIREONCE 0x0001
class CGamePlayerHurt : public CRulePointEntity
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PKILL_FIREONCE) ? TRUE : FALSE; }
private:
};
LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt );
void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
if ( pActivator->IsPlayer() )
{
if ( pev->dmg < 0 )
pActivator->TakeHealth( -pev->dmg, DMG_GENERIC );
else
pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC );
}
SUB_UseTargets( pActivator, useType, value );
if ( RemoveOnFire() )
{
UTIL_Remove( this );
}
}
//
// CGameCounter / game_counter -- Counts events and fires target
// Flag: Fire once
// Flag: Reset on Fire
#define SF_GAMECOUNT_FIREONCE 0x0001
#define SF_GAMECOUNT_RESET 0x0002
class CGameCounter : public CRulePointEntity
{
public:
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) ? TRUE : FALSE; }
inline BOOL ResetOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_RESET) ? TRUE : FALSE; }
inline void CountUp( void ) { pev->frags++; }
inline void CountDown( void ) { pev->frags--; }
inline void ResetCount( void ) { pev->frags = pev->dmg; }
inline int CountValue( void ) { return pev->frags; }
inline int LimitValue( void ) { return pev->health; }
inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); }
private:
inline void SetCountValue( int value ) { pev->frags = value; }
inline void SetInitialValue( int value ) { pev->dmg = value; }
};
LINK_ENTITY_TO_CLASS( game_counter, CGameCounter );
void CGameCounter::Spawn( void )
{
// Save off the initial count
SetInitialValue( CountValue() );
CRulePointEntity::Spawn();
}
void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
switch( useType )
{
case USE_ON:
case USE_TOGGLE:
CountUp();
break;
case USE_OFF:
CountDown();
break;
case USE_SET:
SetCountValue( (int)value );
break;
}
if ( HitLimit() )
{
SUB_UseTargets( pActivator, USE_TOGGLE, 0 );
if ( RemoveOnFire() )
{
UTIL_Remove( this );
}
if ( ResetOnFire() )
{
ResetCount();
}
}
}
//
// CGameCounterSet / game_counter_set -- Sets the counter's value
// Flag: Fire once
#define SF_GAMECOUNTSET_FIREONCE 0x0001
class CGameCounterSet : public CRulePointEntity
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) ? TRUE : FALSE; }
private:
};
LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet );
void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
SUB_UseTargets( pActivator, USE_SET, pev->frags );
if ( RemoveOnFire() )
{
UTIL_Remove( this );
}
}
//
// CGamePlayerEquip / game_playerequip -- Sets the default player equipment
// Flag: USE Only
#define SF_PLAYEREQUIP_USEONLY 0x0001
#define MAX_EQUIP 32
class CGamePlayerEquip : public CRulePointEntity
{
public:
void KeyValue( KeyValueData *pkvd );
void Touch( CBaseEntity *pOther );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
inline BOOL UseOnly( void ) { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) ? TRUE : FALSE; }
private:
void EquipPlayer( CBaseEntity *pPlayer );
string_t m_weaponNames[MAX_EQUIP];
int m_weaponCount[MAX_EQUIP];
};
LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip );
void CGamePlayerEquip::KeyValue( KeyValueData *pkvd )
{
CRulePointEntity::KeyValue( pkvd );
if ( !pkvd->fHandled )
{
for ( int i = 0; i < MAX_EQUIP; i++ )
{
if ( !m_weaponNames[i] )
{
char tmp[128];
UTIL_StripToken( pkvd->szKeyName, tmp );
m_weaponNames[i] = ALLOC_STRING(tmp);
m_weaponCount[i] = atoi(pkvd->szValue);
m_weaponCount[i] = max(1,m_weaponCount[i]);
pkvd->fHandled = TRUE;
break;
}
}
}
}
void CGamePlayerEquip::Touch( CBaseEntity *pOther )
{
if ( !CanFireForActivator( pOther ) )
return;
if ( UseOnly() )
return;
EquipPlayer( pOther );
}
void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity )
{
CBasePlayer *pPlayer = NULL;
if ( pEntity->IsPlayer() )
{
pPlayer = (CBasePlayer *)pEntity;
}
if ( !pPlayer )
return;
for ( int i = 0; i < MAX_EQUIP; i++ )
{
if ( !m_weaponNames[i] )
break;
for ( int j = 0; j < m_weaponCount[i]; j++ )
{
pPlayer->GiveNamedItem( STRING(m_weaponNames[i]) );
}
}
}
void CGamePlayerEquip::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
EquipPlayer( pActivator );
}
//
// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it
// Flag: Fire once
// Flag: Kill Player
// Flag: Gib Player
#define SF_PTEAM_FIREONCE 0x0001
#define SF_PTEAM_KILL 0x0002
#define SF_PTEAM_GIB 0x0004
class CGamePlayerTeam : public CRulePointEntity
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
private:
inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PTEAM_FIREONCE) ? TRUE : FALSE; }
inline BOOL ShouldKillPlayer( void ) { return (pev->spawnflags & SF_PTEAM_KILL) ? TRUE : FALSE; }
inline BOOL ShouldGibPlayer( void ) { return (pev->spawnflags & SF_PTEAM_GIB) ? TRUE : FALSE; }
const char *TargetTeamName( const char *pszTargetName );
};
LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam );
const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName )
{
CBaseEntity *pTeamEntity = NULL;
while ((pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName )) != NULL)
{
if ( FClassnameIs( pTeamEntity->pev, "game_team_master" ) )
return pTeamEntity->TeamID();
}
return NULL;
}
void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanFireForActivator( pActivator ) )
return;
if ( pActivator->IsPlayer() )
{
const char *pszTargetTeam = TargetTeamName( STRING(pev->target) );
if ( pszTargetTeam )
{
CBasePlayer *pPlayer = (CBasePlayer *)pActivator;
g_pGameRules->ChangePlayerTeam( pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer() );
}
}
if ( RemoveOnFire() )
{
UTIL_Remove( this );
}
}

22
dlls/maprules.h Normal file
View File

@ -0,0 +1,22 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef MAPRULES_H
#define MAPRULES_H
#endif // MAPRULES_H

34
dlls/monsterevent.h Normal file
View File

@ -0,0 +1,34 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef MONSTEREVENT_H
#define MONSTEREVENT_H
typedef struct
{
int event;
char *options;
} MonsterEvent_t;
#define EVENT_SPECIFIC 0
#define EVENT_SCRIPTED 1000
#define EVENT_SHARED 2000
#define EVENT_CLIENT 5000
#define MONSTER_EVENT_BODYDROP_LIGHT 2001
#define MONSTER_EVENT_BODYDROP_HEAVY 2002
#define MONSTER_EVENT_SWISHSOUND 2010
#endif // MONSTEREVENT_H

88
dlls/monsters.h Normal file
View File

@ -0,0 +1,88 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef MONSTERS_H
#include "skill.h"
#define MONSTERS_H
/*
===== monsters.h ========================================================
Header file for monster-related utility code
*/
// Hit Group standards
#define HITGROUP_GENERIC 0
#define HITGROUP_HEAD 1
#define HITGROUP_CHEST 2
#define HITGROUP_STOMACH 3
#define HITGROUP_LEFTARM 4
#define HITGROUP_RIGHTARM 5
#define HITGROUP_LEFTLEG 6
#define HITGROUP_RIGHTLEG 7
// spawn flags 256 and above are already taken by the engine
extern void UTIL_MoveToOrigin( edict_t* pent, const Vector &vecGoal, float flDist, int iMoveType );
Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj = 1.0 );
Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0 );
extern DLL_GLOBAL Vector g_vecAttackDir;
extern DLL_GLOBAL CONSTANT float g_flMeleeRange;
extern DLL_GLOBAL CONSTANT float g_flMediumRange;
extern DLL_GLOBAL CONSTANT float g_flLongRange;
extern void EjectBrass (const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype );
extern void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count );
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget );
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize = 0.0 );
// monster to monster relationship types
#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable.
#define R_FR -1// (FEAR)will run
#define R_NO 0// (NO RELATIONSHIP) disregard
#define R_DL 1// (DISLIKE) will attack
#define R_HT 2// (HATE)will attack this character instead of any visible DISLIKEd characters
#define R_NM 3// (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what
#define bits_MEMORY_KILLED ( 1 << 7 )// HACKHACK -- remember that I've already called my Killed()
//
// A gib is a chunk of a body, or a piece of wood/metal/rocks/etc.
//
class CGib : public CBaseEntity
{
public:
void Spawn( const char *szGibModel );
void EXPORT BounceGibTouch ( CBaseEntity *pOther );
void EXPORT StickyGibTouch ( CBaseEntity *pOther );
void EXPORT WaitTillLand( void );
void LimitVelocity( void );
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; }
static void SpawnHeadGib( entvars_t *pevVictim );
static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human );
static void SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs );
int m_bloodColor;
int m_cBloodDecals;
int m_material;
float m_lifeTime;
};
#endif //MONSTERS_H

323
dlls/mortar.cpp Normal file
View File

@ -0,0 +1,323 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
/*
===== mortar.cpp ========================================================
the "LaBuznik" mortar device
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "saverestore.h"
#include "weapons.h"
#include "decals.h"
#include "soundent.h"
class CFuncMortarField : public CBaseToggle
{
public:
void Spawn( void );
void Precache( void );
void KeyValue( KeyValueData *pkvd );
// Bmodels don't go across transitions
virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
void EXPORT FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int m_iszXController;
int m_iszYController;
float m_flSpread;
float m_flDelay;
int m_iCount;
int m_fControl;
};
LINK_ENTITY_TO_CLASS( func_mortar_field, CFuncMortarField );
TYPEDESCRIPTION CFuncMortarField::m_SaveData[] =
{
DEFINE_FIELD( CFuncMortarField, m_iszXController, FIELD_STRING ),
DEFINE_FIELD( CFuncMortarField, m_iszYController, FIELD_STRING ),
DEFINE_FIELD( CFuncMortarField, m_flSpread, FIELD_FLOAT ),
DEFINE_FIELD( CFuncMortarField, m_flDelay, FIELD_FLOAT ),
DEFINE_FIELD( CFuncMortarField, m_iCount, FIELD_INTEGER ),
DEFINE_FIELD( CFuncMortarField, m_fControl, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CFuncMortarField, CBaseToggle );
void CFuncMortarField :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "m_iszXController"))
{
m_iszXController = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_iszYController"))
{
m_iszYController = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_flSpread"))
{
m_flSpread = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_fControl"))
{
m_fControl = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "m_iCount"))
{
m_iCount = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
}
// Drop bombs from above
void CFuncMortarField :: Spawn( void )
{
pev->solid = SOLID_NOT;
SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world
pev->movetype = MOVETYPE_NONE;
SetBits( pev->effects, EF_NODRAW );
SetUse( FieldUse );
Precache();
}
void CFuncMortarField :: Precache( void )
{
PRECACHE_SOUND ("weapons/mortar.wav");
PRECACHE_SOUND ("weapons/mortarhit.wav");
PRECACHE_MODEL( "sprites/lgtning.spr" );
}
// If connected to a table, then use the table controllers, else hit where the trigger is.
void CFuncMortarField :: FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
Vector vecStart;
vecStart.x = RANDOM_FLOAT( pev->mins.x, pev->maxs.x );
vecStart.y = RANDOM_FLOAT( pev->mins.y, pev->maxs.y );
vecStart.z = pev->maxs.z;
switch( m_fControl )
{
case 0: // random
break;
case 1: // Trigger Activator
if (pActivator != NULL)
{
vecStart.x = pActivator->pev->origin.x;
vecStart.y = pActivator->pev->origin.y;
}
break;
case 2: // table
{
CBaseEntity *pController;
if (!FStringNull(m_iszXController))
{
pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszXController));
if (pController != NULL)
{
vecStart.x = pev->mins.x + pController->pev->ideal_yaw * (pev->size.x);
}
}
if (!FStringNull(m_iszYController))
{
pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszYController));
if (pController != NULL)
{
vecStart.y = pev->mins.y + pController->pev->ideal_yaw * (pev->size.y);
}
}
}
break;
}
int pitch = RANDOM_LONG(95,124);
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortar.wav", 1.0, ATTN_NONE, 0, pitch);
float t = 2.5;
for (int i = 0; i < m_iCount; i++)
{
Vector vecSpot = vecStart;
vecSpot.x += RANDOM_FLOAT( -m_flSpread, m_flSpread );
vecSpot.y += RANDOM_FLOAT( -m_flSpread, m_flSpread );
TraceResult tr;
UTIL_TraceLine( vecSpot, vecSpot + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pev), &tr );
edict_t *pentOwner = NULL;
if (pActivator) pentOwner = pActivator->edict();
CBaseEntity *pMortar = Create("monster_mortar", tr.vecEndPos, Vector( 0, 0, 0 ), pentOwner );
pMortar->pev->nextthink = gpGlobals->time + t;
t += RANDOM_FLOAT( 0.2, 0.5 );
if (i == 0)
CSoundEnt::InsertSound ( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 );
}
}
class CMortar : public CGrenade
{
public:
void Spawn( void );
void Precache( void );
void EXPORT MortarExplode( void );
int m_spriteTexture;
};
LINK_ENTITY_TO_CLASS( monster_mortar, CMortar );
void CMortar::Spawn( )
{
pev->movetype = MOVETYPE_NONE;
pev->solid = SOLID_NOT;
pev->dmg = 200;
SetThink( MortarExplode );
pev->nextthink = 0;
Precache( );
}
void CMortar::Precache( )
{
m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr" );
}
void CMortar::MortarExplode( void )
{
#if 1
// mortar beam
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(pev->origin.x);
WRITE_COORD(pev->origin.y);
WRITE_COORD(pev->origin.z + 1024);
WRITE_SHORT(m_spriteTexture );
WRITE_BYTE( 0 ); // framerate
WRITE_BYTE( 0 ); // framerate
WRITE_BYTE( 1 ); // life
WRITE_BYTE( 40 ); // width
WRITE_BYTE( 0 ); // noise
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 160 ); // r, g, b
WRITE_BYTE( 100 ); // r, g, b
WRITE_BYTE( 128 ); // brightness
WRITE_BYTE( 0 ); // speed
MESSAGE_END();
#endif
#if 0
// blast circle
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_BEAMTORUS);
WRITE_COORD(pev->origin.x);
WRITE_COORD(pev->origin.y);
WRITE_COORD(pev->origin.z + 32);
WRITE_COORD(pev->origin.x);
WRITE_COORD(pev->origin.y);
WRITE_COORD(pev->origin.z + 32 + pev->dmg * 2 / .2); // reach damage radius over .3 seconds
WRITE_SHORT(m_spriteTexture );
WRITE_BYTE( 0 ); // startframe
WRITE_BYTE( 0 ); // framerate
WRITE_BYTE( 2 ); // life
WRITE_BYTE( 12 ); // width
WRITE_BYTE( 0 ); // noise
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 160 ); // r, g, b
WRITE_BYTE( 100 ); // r, g, b
WRITE_BYTE( 255 ); // brightness
WRITE_BYTE( 0 ); // speed
MESSAGE_END();
#endif
TraceResult tr;
UTIL_TraceLine( pev->origin + Vector( 0, 0, 1024 ), pev->origin - Vector( 0, 0, 1024 ), dont_ignore_monsters, ENT(pev), &tr );
Explode( &tr, DMG_BLAST | DMG_MORTAR );
UTIL_ScreenShake( tr.vecEndPos, 25.0, 150.0, 1.0, 750 );
#if 0
int pitch = RANDOM_LONG(95,124);
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortarhit.wav", 1.0, 0.55, 0, pitch);
// ForceSound( SNDRADIUS_MP5, bits_SOUND_COMBAT );
// ExplodeModel( pev->origin, 400, g_sModelIndexShrapnel, 30 );
RadiusDamage ( pev, VARS(pev->owner), pev->dmg, CLASS_NONE, DMG_BLAST );
/*
if ( RANDOM_FLOAT ( 0 , 1 ) < 0.5 )
{
UTIL_DecalTrace( pTrace, DECAL_SCORCH1 );
}
else
{
UTIL_DecalTrace( pTrace, DECAL_SCORCH2 );
}
*/
SetThink( SUB_Remove );
pev->nextthink = gpGlobals->time + 0.1;
#endif
}
#if 0
void CMortar::ShootTimed( EVARS *pevOwner, Vector vecStart, float time )
{
CMortar *pMortar = GetClassPtr( (CMortar *)NULL );
pMortar->Spawn();
TraceResult tr;
UTIL_TraceLine( vecStart, vecStart + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pMortar->pev), &tr );
pMortar->pev->nextthink = gpGlobals->time + time;
UTIL_SetOrigin( pMortar->pev, tr.vecEndPos );
}
#endif

5
dlls/mp.def Normal file
View File

@ -0,0 +1,5 @@
LIBRARY mp
EXPORTS
GiveFnptrsToDll @1
SECTIONS
.data READ WRITE

550
dlls/mp.dsp Normal file
View File

@ -0,0 +1,550 @@
# Microsoft Developer Studio Project File - Name="mp" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=mp - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "mp.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "mp.mak" CFG="mp - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "mp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "mp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "mp - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/SDKSrc/Public/dlls", NVGBAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "mp - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir ".\Release"
# PROP BASE Intermediate_Dir ".\Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ".\Releasemp"
# PROP Intermediate_Dir ".\Releasemp"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /YX /FD /c
# SUBTRACT CPP /Fr
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\mp.def"
# SUBTRACT LINK32 /profile
# Begin Custom Build - Copying to \half-life\mp\dlls
TargetPath=.\Releasemp\mp.dll
TargetName=mp
InputPath=.\Releasemp\mp.dll
SOURCE="$(InputPath)"
"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
copy $(TargetPath) \half-life\mp\dlls
# End Custom Build
!ELSEIF "$(CFG)" == "mp - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir ".\mp___Win"
# PROP BASE Intermediate_Dir ".\mp___Win"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ".\debugmp"
# PROP Intermediate_Dir ".\debugmp"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /I "..\engine" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /i "..\engine" /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
# ADD LINK32 user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\mp.def" /implib:".\Debug\mp.lib"
# SUBTRACT LINK32 /profile
# Begin Custom Build - Copying to \half-life\mp\dlls
TargetPath=.\debugmp\mp.dll
TargetName=mp
InputPath=.\debugmp\mp.dll
SOURCE="$(InputPath)"
"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
copy $(TargetPath) \half-life\mp\dlls
# End Custom Build
!ELSEIF "$(CFG)" == "mp - Win32 Profile"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir ".\mp___Win"
# PROP BASE Intermediate_Dir ".\mp___Win"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ".\Profilemp"
# PROP Intermediate_Dir ".\Profilemp"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /YX /c
# SUBTRACT BASE CPP /Fr
# ADD CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /YX /FD /c
# SUBTRACT CPP /Fr
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\mp.def"
# SUBTRACT BASE LINK32 /profile
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /profile /debug /machine:I386 /def:".\mp.def"
# Begin Custom Build - Copying to \half-life\mp\dlls
TargetDir=.\Profilemp
InputPath=.\Profilemp\mp.dll
SOURCE="$(InputPath)"
BuildCmds= \
copy $(TargetDir)\mp.dll \half-life\mp\dlls \
copy $(TargetDir)\mp.map \half-life\mp\dlls \
"\half-life\mp\dlls\mp.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
"\half-life\mp\dlls\mp.map" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
# End Custom Build
!ENDIF
# Begin Target
# Name "mp - Win32 Release"
# Name "mp - Win32 Debug"
# Name "mp - Win32 Profile"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
# Begin Source File
SOURCE=.\airtank.cpp
# End Source File
# Begin Source File
SOURCE=.\animating.cpp
# End Source File
# Begin Source File
SOURCE=.\animation.cpp
# End Source File
# Begin Source File
SOURCE=.\bmodels.cpp
# End Source File
# Begin Source File
SOURCE=.\buttons.cpp
# End Source File
# Begin Source File
SOURCE=.\cbase.cpp
# End Source File
# Begin Source File
SOURCE=.\client.cpp
# End Source File
# Begin Source File
SOURCE=.\combat.cpp
# End Source File
# Begin Source File
SOURCE=.\crossbow.cpp
# End Source File
# Begin Source File
SOURCE=.\crowbar.cpp
# End Source File
# Begin Source File
SOURCE=.\doors.cpp
# End Source File
# Begin Source File
SOURCE=.\effects.cpp
# End Source File
# Begin Source File
SOURCE=.\egon.cpp
# End Source File
# Begin Source File
SOURCE=.\explode.cpp
# End Source File
# Begin Source File
SOURCE=.\func_break.cpp
# End Source File
# Begin Source File
SOURCE=.\func_tank.cpp
# End Source File
# Begin Source File
SOURCE=.\game.cpp
# End Source File
# Begin Source File
SOURCE=.\gamerules.cpp
# End Source File
# Begin Source File
SOURCE=.\gauss.cpp
# End Source File
# Begin Source File
SOURCE=.\ggrenade.cpp
# End Source File
# Begin Source File
SOURCE=.\globals.cpp
# End Source File
# Begin Source File
SOURCE=.\glock.cpp
# End Source File
# Begin Source File
SOURCE=.\h_ai.cpp
# End Source File
# Begin Source File
SOURCE=.\h_battery.cpp
# End Source File
# Begin Source File
SOURCE=.\h_cycler.cpp
# End Source File
# Begin Source File
SOURCE=.\h_export.cpp
# End Source File
# Begin Source File
SOURCE=.\handgrenade.cpp
# End Source File
# Begin Source File
SOURCE=.\healthkit.cpp
# End Source File
# Begin Source File
SOURCE=.\hornet.cpp
# End Source File
# Begin Source File
SOURCE=.\hornetgun.cpp
# End Source File
# Begin Source File
SOURCE=.\items.cpp
# End Source File
# Begin Source File
SOURCE=.\lights.cpp
# End Source File
# Begin Source File
SOURCE=.\maprules.cpp
# End Source File
# Begin Source File
SOURCE=.\mortar.cpp
# End Source File
# Begin Source File
SOURCE=.\mp5.cpp
# End Source File
# Begin Source File
SOURCE=.\mpstubb.cpp
# End Source File
# Begin Source File
SOURCE=.\multiplay_gamerules.cpp
# End Source File
# Begin Source File
SOURCE=.\pathcorner.cpp
# End Source File
# Begin Source File
SOURCE=.\plane.cpp
# End Source File
# Begin Source File
SOURCE=.\plats.cpp
# End Source File
# Begin Source File
SOURCE=.\player.cpp
# End Source File
# Begin Source File
SOURCE=.\python.cpp
# End Source File
# Begin Source File
SOURCE=.\rpg.cpp
# End Source File
# Begin Source File
SOURCE=.\satchel.cpp
# End Source File
# Begin Source File
SOURCE=.\shotgun.cpp
# End Source File
# Begin Source File
SOURCE=.\singleplay_gamerules.cpp
# End Source File
# Begin Source File
SOURCE=.\skill.cpp
# End Source File
# Begin Source File
SOURCE=.\sound.cpp
# End Source File
# Begin Source File
SOURCE=.\soundent.cpp
# End Source File
# Begin Source File
SOURCE=.\spectator.cpp
# End Source File
# Begin Source File
SOURCE=.\squeakgrenade.cpp
# End Source File
# Begin Source File
SOURCE=.\subs.cpp
# End Source File
# Begin Source File
SOURCE=.\teamplay_gamerules.cpp
# End Source File
# Begin Source File
SOURCE=.\triggers.cpp
# End Source File
# Begin Source File
SOURCE=.\tripmine.cpp
# End Source File
# Begin Source File
SOURCE=.\util.cpp
# End Source File
# Begin Source File
SOURCE=.\weapons.cpp
# End Source File
# Begin Source File
SOURCE=.\world.cpp
# End Source File
# Begin Source File
SOURCE=.\xen.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\activity.h
# End Source File
# Begin Source File
SOURCE=.\activitymap.h
# End Source File
# Begin Source File
SOURCE=.\animation.h
# End Source File
# Begin Source File
SOURCE=.\basemonster.h
# End Source File
# Begin Source File
SOURCE=.\cbase.h
# End Source File
# Begin Source File
SOURCE=.\cdll_dll.h
# End Source File
# Begin Source File
SOURCE=.\client.h
# End Source File
# Begin Source File
SOURCE=.\decals.h
# End Source File
# Begin Source File
SOURCE=.\doors.h
# End Source File
# Begin Source File
SOURCE=.\effects.h
# End Source File
# Begin Source File
SOURCE=.\enginecallback.h
# End Source File
# Begin Source File
SOURCE=.\explode.h
# End Source File
# Begin Source File
SOURCE=.\extdll.h
# End Source File
# Begin Source File
SOURCE=.\func_break.h
# End Source File
# Begin Source File
SOURCE=.\game.h
# End Source File
# Begin Source File
SOURCE=.\gamerules.h
# End Source File
# Begin Source File
SOURCE=.\hornet.h
# End Source File
# Begin Source File
SOURCE=.\items.h
# End Source File
# Begin Source File
SOURCE=.\maprules.h
# End Source File
# Begin Source File
SOURCE=.\monsterevent.h
# End Source File
# Begin Source File
SOURCE=.\monsters.h
# End Source File
# Begin Source File
SOURCE=.\nodes.h
# End Source File
# Begin Source File
SOURCE=.\plane.h
# End Source File
# Begin Source File
SOURCE=.\player.h
# End Source File
# Begin Source File
SOURCE=.\saverestore.h
# End Source File
# Begin Source File
SOURCE=.\schedule.h
# End Source File
# Begin Source File
SOURCE=.\scriptevent.h
# End Source File
# Begin Source File
SOURCE=.\skill.h
# End Source File
# Begin Source File
SOURCE=.\soundent.h
# End Source File
# Begin Source File
SOURCE=.\spectator.h
# End Source File
# Begin Source File
SOURCE=.\talkmonster.h
# End Source File
# Begin Source File
SOURCE=.\teamplay_gamerules.h
# End Source File
# Begin Source File
SOURCE=.\trains.h
# End Source File
# Begin Source File
SOURCE=.\util.h
# End Source File
# Begin Source File
SOURCE=.\vector.h
# End Source File
# Begin Source File
SOURCE=.\weapons.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

37
dlls/mp.dsw Normal file
View File

@ -0,0 +1,37 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "mp"=.\mp.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/SDKSrc/Public/dlls", NVGBAAAA
.
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
begin source code control
"$/SDKSrc/Public/dlls", NVGBAAAA
.
end source code control
}}}
Package=<3>
{{{
}}}
###############################################################################

415
dlls/mp5.cpp Normal file
View File

@ -0,0 +1,415 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "soundent.h"
#include "gamerules.h"
enum mp5_e
{
MP5_LONGIDLE = 0,
MP5_IDLE1,
MP5_LAUNCH,
MP5_RELOAD,
MP5_DEPLOY,
MP5_FIRE1,
MP5_FIRE2,
MP5_FIRE3,
};
class CMP5 : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 3; }
int GetItemInfo(ItemInfo *p);
int AddToPlayer( CBasePlayer *pPlayer );
void PrimaryAttack( void );
void SecondaryAttack( void );
int SecondaryAmmoIndex( void );
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );
float m_flNextAnimTime;
int m_iShell;
};
LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 );
LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 );
//=========================================================
//=========================================================
int CMP5::SecondaryAmmoIndex( void )
{
return m_iSecondaryAmmoType;
}
void CMP5::Spawn( )
{
pev->classname = MAKE_STRING("weapon_9mmAR"); // hack to allow for old names
Precache( );
SET_MODEL(ENT(pev), "models/w_9mmAR.mdl");
m_iId = WEAPON_MP5;
m_iDefaultAmmo = MP5_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CMP5::Precache( void )
{
PRECACHE_MODEL("models/v_9mmAR.mdl");
PRECACHE_MODEL("models/w_9mmAR.mdl");
PRECACHE_MODEL("models/p_9mmAR.mdl");
m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shellTE_MODEL
PRECACHE_MODEL("models/grenade.mdl"); // grenade
PRECACHE_MODEL("models/w_9mmARclip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
PRECACHE_SOUND("items/clipinsert1.wav");
PRECACHE_SOUND("items/cliprelease1.wav");
// PRECACHE_SOUND("items/guncock1.wav");
PRECACHE_SOUND ("weapons/hks1.wav");// H to the K
PRECACHE_SOUND ("weapons/hks2.wav");// H to the K
PRECACHE_SOUND ("weapons/hks3.wav");// H to the K
PRECACHE_SOUND( "weapons/glauncher.wav" );
PRECACHE_SOUND( "weapons/glauncher2.wav" );
PRECACHE_SOUND ("weapons/357_cock1.wav");
}
int CMP5::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "9mm";
p->iMaxAmmo1 = _9MM_MAX_CARRY;
p->pszAmmo2 = "ARgrenades";
p->iMaxAmmo2 = M203_GRENADE_MAX_CARRY;
p->iMaxClip = MP5_MAX_CLIP;
p->iSlot = 2;
p->iPosition = 0;
p->iFlags = 0;
p->iId = m_iId = WEAPON_MP5;
p->iWeight = MP5_WEIGHT;
return 1;
}
int CMP5::AddToPlayer( CBasePlayer *pPlayer )
{
if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
WRITE_BYTE( m_iId );
MESSAGE_END();
return TRUE;
}
return FALSE;
}
BOOL CMP5::Deploy( )
{
return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" );
}
void CMP5::PrimaryAttack()
{
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
PlayEmptySound( );
m_flNextPrimaryAttack = gpGlobals->time + 0.15;
return;
}
if (m_iClip <= 0)
{
PlayEmptySound();
m_flNextPrimaryAttack = gpGlobals->time + 0.15;
return;
}
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
m_iClip--;
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
if (1 || m_flNextAnimTime < gpGlobals->time)
{
SendWeaponAnim( MP5_FIRE1 + RANDOM_LONG(0,2));
m_flNextAnimTime = gpGlobals->time + 0.2;
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
switch( RANDOM_LONG(0,1) )
{
case 0: EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xf)); break;
case 1: EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xf)); break;
// case 2: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break;
}
UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );
Vector vecShellVelocity = m_pPlayer->pev->velocity
+ gpGlobals->v_right * RANDOM_FLOAT(50,70)
+ gpGlobals->v_up * RANDOM_FLOAT(100,150)
+ gpGlobals->v_forward * 25;
EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs
+ gpGlobals->v_up * -12
+ gpGlobals->v_forward * 20
+ gpGlobals->v_right * 4, vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL);
Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
if ( g_pGameRules->IsDeathmatch() )
{
// optimized multiplayer. Widened to make it easier to hit a moving player
m_pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2 );
}
else
{
// single player spread
m_pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2 );
}
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.1;
if (m_flNextPrimaryAttack < gpGlobals->time)
m_flNextPrimaryAttack = gpGlobals->time + 0.1;
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( -2, 2 );
}
void CMP5::SecondaryAttack( void )
{
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
PlayEmptySound( );
m_flNextPrimaryAttack = gpGlobals->time + 0.15;
return;
}
if (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] == 0)
{
PlayEmptySound( );
return;
}
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER;
m_pPlayer->m_flStopExtraSoundTime = gpGlobals->time + 0.2;
m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--;
SendWeaponAnim( MP5_LAUNCH );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
if ( RANDOM_LONG(0,1) )
{
// play this sound through BODY channel so we can hear it if player didn't stop firing MP3
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/glauncher.wav", 0.8, ATTN_NORM);
}
else
{
// play this sound through BODY channel so we can hear it if player didn't stop firing MP3
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/glauncher2.wav", 0.8, ATTN_NORM);
}
UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );
// we don't add in player velocity anymore.
CGrenade::ShootContact( m_pPlayer->pev,
m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16,
gpGlobals->v_forward * 800 );
m_flNextPrimaryAttack = gpGlobals->time + 1;
m_flNextSecondaryAttack = gpGlobals->time + 1;
m_flTimeWeaponIdle = gpGlobals->time + 5;// idle pretty soon after shooting.
if (!m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType])
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_pPlayer->pev->punchangle.x -= 10;
}
void CMP5::Reload( void )
{
DefaultReload( MP5_MAX_CLIP, MP5_RELOAD, 1.5 );
}
void CMP5::WeaponIdle( void )
{
ResetEmptySound( );
m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
if (m_flTimeWeaponIdle > gpGlobals->time)
return;
int iAnim;
switch ( RANDOM_LONG( 0, 1 ) )
{
case 0:
iAnim = MP5_LONGIDLE;
break;
default:
case 1:
iAnim = MP5_IDLE1;
break;
}
SendWeaponAnim( iAnim );
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );// how long till we do this again.
}
class CMP5AmmoClip : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_9mmARclip.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_9mmARclip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
int bResult = (pOther->GiveAmmo( AMMO_MP5CLIP_GIVE, "9mm", _9MM_MAX_CARRY) != -1);
if (bResult)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
}
return bResult;
}
};
LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip );
LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip );
class CMP5Chainammo : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_chainammo.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_chainammo.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
int bResult = (pOther->GiveAmmo( AMMO_CHAINBOX_GIVE, "9mm", _9MM_MAX_CARRY) != -1);
if (bResult)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
}
return bResult;
}
};
LINK_ENTITY_TO_CLASS( ammo_9mmbox, CMP5Chainammo );
class CMP5AmmoGrenade : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_ARgrenade.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_ARgrenade.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
int bResult = (pOther->GiveAmmo( AMMO_M203BOX_GIVE, "ARgrenades", M203_GRENADE_MAX_CARRY ) != -1);
if (bResult)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
}
return bResult;
}
};
LINK_ENTITY_TO_CLASS( ammo_mp5grenades, CMP5AmmoGrenade );
LINK_ENTITY_TO_CLASS( ammo_ARgrenades, CMP5AmmoGrenade );

264
dlls/mpstubb.cpp Normal file
View File

@ -0,0 +1,264 @@
/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "soundent.h"
#include "nodes.h"
#include "talkmonster.h"
float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: used so that two NPCs don't talk at once
/*********************************************************/
CGraph WorldGraph;
void CGraph :: InitGraph( void ) { }
int CGraph :: FLoadGraph ( char *szMapName ) { return FALSE; }
int CGraph :: AllocNodes ( void ) { return FALSE; }
int CGraph :: CheckNODFile ( char *szMapName ) { return FALSE; }
int CGraph :: FSetGraphPointers ( void ) { return 0; }
void CGraph :: ShowNodeConnections ( int iNode ) { }
int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) { return 0; }
/*********************************************************/
void CBaseMonster :: ReportAIState( void ) { }
float CBaseMonster :: ChangeYaw ( int speed ) { return 0; }
void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { }
void CBaseMonster::CorpseFallThink( void )
{
if ( pev->flags & FL_ONGROUND )
{
SetThink ( NULL );
SetSequenceBox( );
UTIL_SetOrigin( pev, pev->origin );// link into world.
}
else
pev->nextthink = gpGlobals->time + 0.1;
}
// Call after animation/pose is set up
void CBaseMonster :: MonsterInitDead( void )
{
InitBoneControllers();
pev->solid = SOLID_BBOX;
pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground
pev->frame = 0;
ResetSequenceInfo( );
pev->framerate = 0;
// Copy health
pev->max_health = pev->health;
pev->deadflag = DEAD_DEAD;
UTIL_SetSize(pev, g_vecZero, g_vecZero );
UTIL_SetOrigin( pev, pev->origin );
// Setup health counters, etc.
BecomeDead();
SetThink( CorpseFallThink );
pev->nextthink = gpGlobals->time + 0.5;
}
BOOL CBaseMonster :: ShouldFadeOnDeath( void )
{
return FALSE;
}
BOOL CBaseMonster :: FCheckAITrigger ( void )
{
return FALSE;
}
void CBaseMonster :: KeyValue( KeyValueData *pkvd )
{
CBaseToggle::KeyValue( pkvd );
}
int CBaseMonster::IRelationship ( CBaseEntity *pTarget )
{
static int iEnemy[14][14] =
{ // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN
/*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO },
/*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL },
/*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL },
/*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO },
/*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO },
/*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO },
/*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO },
/*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO },
/*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO },
/*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO },
/*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO },
/*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO },
/*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL },
/*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO }
};
return iEnemy[ Classify() ][ pTarget->Classify() ];
}
//=========================================================
// Look - Base class monster function to find enemies or
// food by sight. iDistance is distance ( in units ) that the
// monster can see.
//
// Sets the sight bits of the m_afConditions mask to indicate
// which types of entities were sighted.
// Function also sets the Looker's m_pLink
// to the head of a link list that contains all visible ents.
// (linked via each ent's m_pLink field)
//
//=========================================================
void CBaseMonster :: Look ( int iDistance )
{
int iSighted = 0;
// DON'T let visibility information from last frame sit around!
ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT);
m_pLink = NULL;
CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with
CBaseEntity *pList[100];
Vector delta = Vector( iDistance, iDistance, iDistance );
// Find only monsters/clients in box, NOT limited to PVS
int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER );
for ( int i = 0; i < count; i++ )
{
pSightEnt = pList[i];
if ( pSightEnt != this && pSightEnt->pev->health > 0 )
{
// the looker will want to consider this entity
// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) )
{
if ( pSightEnt->IsPlayer() )
{
// if we see a client, remember that (mostly for scripted AI)
iSighted |= bits_COND_SEE_CLIENT;
}
pSightEnt->m_pLink = m_pLink;
m_pLink = pSightEnt;
if ( pSightEnt == m_hEnemy )
{
// we know this ent is visible, so if it also happens to be our enemy, store that now.
iSighted |= bits_COND_SEE_ENEMY;
}
// don't add the Enemy's relationship to the conditions. We only want to worry about conditions when
// we see monsters other than the Enemy.
switch ( IRelationship ( pSightEnt ) )
{
case R_NM:
iSighted |= bits_COND_SEE_NEMESIS;
break;
case R_HT:
iSighted |= bits_COND_SEE_HATE;
break;
case R_DL:
iSighted |= bits_COND_SEE_DISLIKE;
break;
case R_FR:
iSighted |= bits_COND_SEE_FEAR;
break;
case R_AL:
break;
default:
ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) );
break;
}
}
}
}
SetConditions( iSighted );
}
//=========================================================
// 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 *CBaseMonster :: BestVisibleEnemy ( void )
{
CBaseEntity *pReturn;
CBaseEntity *pNextEnt;
int iNearest;
int iDist;
int iBestRelationship;
iNearest = 8192;// so first visible entity will become the closest.
pNextEnt = m_pLink;
pReturn = NULL;
iBestRelationship = R_NO;
while ( pNextEnt != NULL )
{
if ( pNextEnt->IsAlive() )
{
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;
}

1056
dlls/multiplay_gamerules.cpp Normal file

File diff suppressed because it is too large Load Diff

54
dlls/nodes.h Normal file
View File

@ -0,0 +1,54 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//=========================================================
// nodes.h
//=========================================================
#ifndef NODES_H
#define NODES_H
#define bits_NODE_GROUP_REALM 1
class CLink
{
public:
entvars_t *m_pLinkEnt;// the entity that blocks this connection (doors, etc)
};
class CGraph
{
public:
BOOL m_fGraphPresent;// is the graph in memory?
BOOL m_fGraphPointersSet;// are the entity pointers for the graph all set?
int m_cLinks;// total number of links
CLink *m_pLinkPool;// big list of all node connections
void InitGraph( void );
int AllocNodes ( void );
int CheckNODFile(char *szMapName);
int FLoadGraph(char *szMapName);
int FSetGraphPointers(void);
void ShowNodeConnections ( int iNode );
int FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity );
int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes );
};
extern CGraph WorldGraph;
#endif // NODES_H

428
dlls/pathcorner.cpp Normal file
View File

@ -0,0 +1,428 @@
/***
*
* Copyright (c) 1999, 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.
*
****/
//
// ========================== PATH_CORNER ===========================
//
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "trains.h"
#include "saverestore.h"
class CPathCorner : public CPointEntity
{
public:
void Spawn( );
void KeyValue( KeyValueData* pkvd );
float GetDelay( void ) { return m_flWait; }
// void Touch( CBaseEntity *pOther );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
private:
float m_flWait;
};
LINK_ENTITY_TO_CLASS( path_corner, CPathCorner );
// Global Savedata for Delay
TYPEDESCRIPTION CPathCorner::m_SaveData[] =
{
DEFINE_FIELD( CPathCorner, m_flWait, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CPathCorner, CPointEntity );
//
// Cache user-entity-field values until spawn is called.
//
void CPathCorner :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "wait"))
{
m_flWait = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CPointEntity::KeyValue( pkvd );
}
void CPathCorner :: Spawn( )
{
ASSERTSZ(!FStringNull(pev->targetname), "path_corner without a targetname");
}
#if 0
void CPathCorner :: Touch( CBaseEntity *pOther )
{
entvars_t* pevToucher = pOther->pev;
if ( FBitSet ( pevToucher->flags, FL_MONSTER ) )
{// monsters don't navigate path corners based on touch anymore
return;
}
// If OTHER isn't explicitly looking for this path_corner, bail out
if ( pOther->m_pGoalEnt != this )
{
return;
}
// If OTHER has an enemy, this touch is incidental, ignore
if ( !FNullEnt(pevToucher->enemy) )
{
return; // fighting, not following a path
}
// UNDONE: support non-zero flWait
/*
if (m_flWait != 0)
ALERT(at_warning, "Non-zero path-cornder waits NYI");
*/
// Find the next "stop" on the path, make it the goal of the "toucher".
if (FStringNull(pev->target))
{
ALERT(at_warning, "PathCornerTouch: no next stop specified");
}
pOther->m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ) );
// If "next spot" was not found (does not exist - level design error)
if ( !pOther->m_pGoalEnt )
{
ALERT(at_console, "PathCornerTouch--%s couldn't find next stop in path: %s", STRING(pev->classname), STRING(pev->target));
return;
}
// Turn towards the next stop in the path.
pevToucher->ideal_yaw = UTIL_VecToYaw ( pOther->m_pGoalEnt->pev->origin - pevToucher->origin );
}
#endif
TYPEDESCRIPTION CPathTrack::m_SaveData[] =
{
DEFINE_FIELD( CPathTrack, m_length, FIELD_FLOAT ),
DEFINE_FIELD( CPathTrack, m_pnext, FIELD_CLASSPTR ),
DEFINE_FIELD( CPathTrack, m_paltpath, FIELD_CLASSPTR ),
DEFINE_FIELD( CPathTrack, m_pprevious, FIELD_CLASSPTR ),
DEFINE_FIELD( CPathTrack, m_altName, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CPathTrack, CBaseEntity );
LINK_ENTITY_TO_CLASS( path_track, CPathTrack );
//
// Cache user-entity-field values until spawn is called.
//
void CPathTrack :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "altpath"))
{
m_altName = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CPointEntity::KeyValue( pkvd );
}
void CPathTrack :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
int on;
// Use toggles between two paths
if ( m_paltpath )
{
on = !FBitSet( pev->spawnflags, SF_PATH_ALTERNATE );
if ( ShouldToggle( useType, on ) )
{
if ( on )
SetBits( pev->spawnflags, SF_PATH_ALTERNATE );
else
ClearBits( pev->spawnflags, SF_PATH_ALTERNATE );
}
}
else // Use toggles between enabled/disabled
{
on = !FBitSet( pev->spawnflags, SF_PATH_DISABLED );
if ( ShouldToggle( useType, on ) )
{
if ( on )
SetBits( pev->spawnflags, SF_PATH_DISABLED );
else
ClearBits( pev->spawnflags, SF_PATH_DISABLED );
}
}
}
void CPathTrack :: Link( void )
{
edict_t *pentTarget;
if ( !FStringNull(pev->target) )
{
pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) );
if ( !FNullEnt(pentTarget) )
{
m_pnext = CPathTrack::Instance( pentTarget );
if ( m_pnext ) // If no next pointer, this is the end of a path
{
m_pnext->SetPrevious( this );
}
}
else
ALERT( at_console, "Dead end link %s\n", STRING(pev->target) );
}
// Find "alternate" path
if ( m_altName )
{
pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_altName) );
if ( !FNullEnt(pentTarget) )
{
m_paltpath = CPathTrack::Instance( pentTarget );
if ( m_paltpath ) // If no next pointer, this is the end of a path
{
m_paltpath->SetPrevious( this );
}
}
}
}
void CPathTrack :: Spawn( void )
{
pev->solid = SOLID_TRIGGER;
UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8));
m_pnext = NULL;
m_pprevious = NULL;
// DEBUGGING CODE
#if PATH_SPARKLE_DEBUG
SetThink( Sparkle );
pev->nextthink = gpGlobals->time + 0.5;
#endif
}
void CPathTrack::Activate( void )
{
if ( !FStringNull( pev->targetname ) ) // Link to next, and back-link
Link();
}
CPathTrack *CPathTrack :: ValidPath( CPathTrack *ppath, int testFlag )
{
if ( !ppath )
return NULL;
if ( testFlag && FBitSet( ppath->pev->spawnflags, SF_PATH_DISABLED ) )
return NULL;
return ppath;
}
void CPathTrack :: Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist )
{
if ( pstart && pend )
{
Vector dir = (pend->pev->origin - pstart->pev->origin);
dir = dir.Normalize();
*origin = pend->pev->origin + dir * dist;
}
}
CPathTrack *CPathTrack::GetNext( void )
{
if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && !FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) )
return m_paltpath;
return m_pnext;
}
CPathTrack *CPathTrack::GetPrevious( void )
{
if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) )
return m_paltpath;
return m_pprevious;
}
void CPathTrack::SetPrevious( CPathTrack *pprev )
{
// Only set previous if this isn't my alternate path
if ( pprev && !FStrEq( STRING(pprev->pev->targetname), STRING(m_altName) ) )
m_pprevious = pprev;
}
// Assumes this is ALWAYS enabled
CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move )
{
CPathTrack *pcurrent;
float originalDist = dist;
pcurrent = this;
Vector currentPos = *origin;
if ( dist < 0 ) // Travelling backwards through path
{
dist = -dist;
while ( dist > 0 )
{
Vector dir = pcurrent->pev->origin - currentPos;
float length = dir.Length();
if ( !length )
{
if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now.
{
if ( !move )
Project( pcurrent->GetNext(), pcurrent, origin, dist );
return NULL;
}
pcurrent = pcurrent->GetPrevious();
}
else if ( length > dist ) // enough left in this path to move
{
*origin = currentPos + (dir * (dist / length));
return pcurrent;
}
else
{
dist -= length;
currentPos = pcurrent->pev->origin;
*origin = currentPos;
if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now.
return NULL;
pcurrent = pcurrent->GetPrevious();
}
}
*origin = currentPos;
return pcurrent;
}
else
{
while ( dist > 0 )
{
if ( !ValidPath(pcurrent->GetNext(), move) ) // If there is no next node, or it's disabled, return now.
{
if ( !move )
Project( pcurrent->GetPrevious(), pcurrent, origin, dist );
return NULL;
}
Vector dir = pcurrent->GetNext()->pev->origin - currentPos;
float length = dir.Length();
if ( !length && !ValidPath( pcurrent->GetNext()->GetNext(), move ) )
{
if ( dist == originalDist ) // HACK -- up against a dead end
return NULL;
return pcurrent;
}
if ( length > dist ) // enough left in this path to move
{
*origin = currentPos + (dir * (dist / length));
return pcurrent;
}
else
{
dist -= length;
currentPos = pcurrent->GetNext()->pev->origin;
pcurrent = pcurrent->GetNext();
*origin = currentPos;
}
}
*origin = currentPos;
}
return pcurrent;
}
// Assumes this is ALWAYS enabled
CPathTrack *CPathTrack :: Nearest( Vector origin )
{
int deadCount;
float minDist, dist;
Vector delta;
CPathTrack *ppath, *pnearest;
delta = origin - pev->origin;
delta.z = 0;
minDist = delta.Length();
pnearest = this;
ppath = GetNext();
// Hey, I could use the old 2 racing pointers solution to this, but I'm lazy :)
deadCount = 0;
while ( ppath && ppath != this )
{
deadCount++;
if ( deadCount > 9999 )
{
ALERT( at_error, "Bad sequence of path_tracks from %s", STRING(pev->targetname) );
return NULL;
}
delta = origin - ppath->pev->origin;
delta.z = 0;
dist = delta.Length();
if ( dist < minDist )
{
minDist = dist;
pnearest = ppath;
}
ppath = ppath->GetNext();
}
return pnearest;
}
CPathTrack *CPathTrack::Instance( edict_t *pent )
{
if ( FClassnameIs( pent, "path_track" ) )
return (CPathTrack *)GET_PRIVATE(pent);
return NULL;
}
// DEBUGGING CODE
#if PATH_SPARKLE_DEBUG
void CPathTrack :: Sparkle( void )
{
pev->nextthink = gpGlobals->time + 0.2;
if ( FBitSet( pev->spawnflags, SF_PATH_DISABLED ) )
UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 210, 10);
else
UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 84, 10);
}
#endif

Some files were not shown because too many files have changed in this diff Show More