as released 1999-04-07
This commit is contained in:
commit
b443b4420e
|
@ -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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
|
@ -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;
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
SCC = This is a Source Code Control file
|
||||
|
||||
[cl_dll.mak]
|
||||
SCC_Project_Name = "$/HLStandardSDK/SourceCode/cl_dll", NUWHAAAA
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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 );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
};
|
|
@ -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 );
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 );
|
||||
};
|
|
@ -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
|
|
@ -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( );
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 ¢er, 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 );
|
||||
}
|
|
@ -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 ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage );
|
||||
|
||||
#endif //EXPLODE_H
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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" );
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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;
|
|
@ -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 );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 );
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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 );
|
||||
}
|
|
@ -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!
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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
|
|
@ -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 );
|
|
@ -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
|
|
@ -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( );
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
LIBRARY mp
|
||||
EXPORTS
|
||||
GiveFnptrsToDll @1
|
||||
SECTIONS
|
||||
.data READ WRITE
|
|
@ -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
|
|
@ -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>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
|
@ -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 );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
Loading…
Reference in New Issue