Progress on match logic, respawning, spectating, triggers...

This commit is contained in:
Marco Hladik 2016-12-04 15:04:30 +01:00
parent dac1623b0d
commit 3bd3b7c95f
22 changed files with 629 additions and 135 deletions

View file

@ -18,6 +18,13 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
=================
CSQC_UpdateView
Entry point for drawing on the client
=================
*/
void CSQC_UpdateView( float fWinWidth, float fWinHeight, float fGameFocus ) {
vVideoResolution_x = fWinWidth;
vVideoResolution_y = fWinHeight;
@ -37,6 +44,13 @@ void CSQC_UpdateView( float fWinWidth, float fWinHeight, float fGameFocus ) {
}
}
/*
=================
CSQC_UpdateViewLoading
Doesn't really do anything useful yet
=================
*/
void CSQC_UpdateViewLoading( float fWinWidth, float fWinHeight, float fGameFocus ) {
}

View file

@ -18,10 +18,24 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
void CSQC_Ent_Update( float isnew ) {
/*
=================
CSQC_Ent_Update
Called whenever an entity is sent manually via .SendFlags and so on
=================
*/
void CSQC_Ent_Update( float fIsNew ) {
}
/*
=================
CSQC_Ent_Remove
Self explanatory
=================
*/
void CSQC_Ent_Remove( void ) {
}

View file

@ -18,21 +18,42 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
=================
CSQC_ConsoleCommand_Init
Init all the cmds in one place
=================
*/
void CSQC_ConsoleCommand_Init( void ) {
registercommand( "vgui_buymenu" );
registercommand( "vgui_teammenu" );
registercommand( "use" );
}
/*
=================
CSQC_ConsoleCommand
Can interject cmds and create new ones
=================
*/
float CSQC_ConsoleCommand( string sCMD ) {
tokenize( sCMD );
switch ( argv(0) )
{
case "vgui_buymenu":
if( getstatf( 34 ) == TRUE ) {
if( getstatf( STAT_BUYZONE ) == TRUE ) {
fVGUI_Display = VGUI_BM_MAIN;
}
return TRUE;
break;
case "vgui_teammenu":
if( getstatf( STAT_TEAM ) == 0 ) {
fVGUI_Display = VGUI_TEAMSELECT;
}
return TRUE;
break;
case "use":
sendevent( "PlayerUse", "" );
return TRUE;
@ -42,6 +63,13 @@ float CSQC_ConsoleCommand( string sCMD ) {
return FALSE;
}
/*
=================
CSQC_Parse_Event
Whenever we call a SVC_CGAMEPACKET on the SSQC, this is being run
=================
*/
void CSQC_Parse_Event( void ) {
float fHeader = readbyte();
@ -69,6 +97,13 @@ void CSQC_Parse_Event( void ) {
}
}
/*
=================
CSQC_InputEvent
Updates all our input related globals for use in other functions
=================
*/
float CSQC_InputEvent( float fEventType, float fKey, float fCharacter, float fDeviceID ) {
if ( fEventType == IE_KEYDOWN ) {
if ( fKey == K_MOUSE1 ) {
@ -95,9 +130,16 @@ float CSQC_InputEvent( float fEventType, float fKey, float fCharacter, float fDe
return FALSE;
}
/*
=================
CSQC_Input_Frame
Hijacks and controls what input globals are being sent to the server
=================
*/
void CSQC_Input_Frame( void ) {
// If we are inside a VGUI, don't let the client do stuff outside
if ( fVGUI_Display != VGUI_NONE ) {
if ( ( fVGUI_Display != VGUI_NONE ) ) {
input_angles = '0 0 0';
input_movevalues = '0 0 0';
input_buttons = 0;

View file

@ -21,9 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define HUD_NUMFILE "sprites/640hud7.spr" // We'll precache this
#define HUD_NUMFILE_LAYER "sprites/640hud7.spr_0.tga" // And only use the first frame for drawing (needs precache)
// Sigh
#define NUMSIZE_X 0.09375
#define NUMSIZE_Y 0.09765625
// Instead of calculating them on demand, just read the offsets here
float vHUDNumPos[10] = {
0,
0.09375,
@ -37,6 +39,7 @@ float vHUDNumPos[10] = {
0.84375,
};
// Ditto
vector vHUDCalPos[10] = {
'0 0 0',
'0.09375 0.28125 0', // 50AE
@ -50,17 +53,35 @@ vector vHUDCalPos[10] = {
'0.46875 0.375 0', // 57MM
};
// Wrapper that draws an individual number
/*
=================
HUD_DrawRedNumber
Draws a normal number
=================
*/
void HUD_DrawNumber( int iNumber, vector vPos, float fAlpha ) {
drawsubpic( vPos, '24 25 0', HUD_NUMFILE_LAYER, [ vHUDNumPos[ iNumber ], 0], [ NUMSIZE_X, NUMSIZE_Y ], VGUI_WINDOW_FGCOLOR, fAlpha, DRAWFLAG_ADDITIVE );
}
// Draws a red number
/*
=================
HUD_DrawRedNumber
Draws a red number
=================
*/
void HUD_DrawRedNumber( int iNumber, vector vPos, float fAlpha ) {
drawsubpic( vPos, '24 25 0', HUD_NUMFILE_LAYER, [ vHUDNumPos[ iNumber ], 0], [ NUMSIZE_X, NUMSIZE_Y ], '1 0 0', fAlpha, DRAWFLAG_ADDITIVE );
}
// Draws numerals quickly with a maximum length of 3 - e.g. for health, armor etc.
/*
=================
HUD_DrawNums
Draws numerals quickly for health, armor etc.
=================
*/
void HUD_DrawNums( float fNumber, vector vPos ) {
int iNumber = fNumber;
if ( iNumber > 0 ) {
@ -74,22 +95,43 @@ void HUD_DrawNums( float fNumber, vector vPos ) {
}
}
// Called every frame
void HUD_Draw( void ) {
if( getplayerkeyvalue( player_localnum, "*spectator" ) == "1" ) {
return;
}
/*
=================
HUD_DrawHealth
Draw the current amount of health
=================
*/
void HUD_DrawHealth( void ) {
// Health
vector vHealthPos = [ 16, vVideoResolution_y - 42 ];
drawsubpic( vHealthPos, '24 24 0', HUD_NUMFILE_LAYER, [ NUMSIZE_X * 2, NUMSIZE_Y], [ NUMSIZE_X, NUMSIZE_X ], VGUI_WINDOW_FGCOLOR, 1, DRAWFLAG_ADDITIVE );
HUD_DrawNums( getstatf( STAT_HEALTH ), vHealthPos + '72 0' );
}
/*
=================
HUD_DrawArmor
Draw the current amount of Kevlar
=================
*/
void HUD_DrawArmor( void ) {
// Armor
vector vArmorPos = [ 112, vVideoResolution_y - 42 ];
drawsubpic( vArmorPos, '24 24 0', HUD_NUMFILE_LAYER, [ 0, NUMSIZE_Y], [ NUMSIZE_X, NUMSIZE_X ], VGUI_WINDOW_FGCOLOR, 1, DRAWFLAG_ADDITIVE );
HUD_DrawNums( getstatf( STAT_ARMOR ), vArmorPos + '72 0' );
}
/*
=================
HUD_DrawIcons
Draw icons such as hostage, bomb and buyzones
=================
*/
void HUD_DrawIcons( void ) {
// BuyZone Icon
if( getstatf( STAT_BUYZONE ) == TRUE ) {
vector vBuyIconPos = [ 16, ( vVideoResolution_y / 2 ) - 12 ];
@ -107,8 +149,16 @@ void HUD_Draw( void ) {
vector vBIconPos = [ 16, ( vVideoResolution_y / 2 ) + 48 ];
drawsubpic( vBIconPos, '32 32 0', HUD_NUMFILE_LAYER, [ 0, 0.125 * 5 - 0.046875], [ 0.125, 0.125 ], '0 1 0', 1, DRAWFLAG_ADDITIVE );
}
// The Timer
}
/*
=================
HUD_DrawTimer
Draws the roundtime at the bottom of the screen (always visible)
=================
*/
void HUD_DrawTimer( void ) {
int iMinutes, iSeconds, iTens, iUnits;
vector vTimePos = [ ( vVideoResolution_x / 2 ) - 60, vVideoResolution_y - 42 ];
@ -129,7 +179,7 @@ void HUD_Draw( void ) {
iUnits = iSeconds - 10*iTens;
}
// Timer: Flashing red numbers
// Flashing red numbers
if ( ( iMinutes == 0 ) && ( iTens <= 1 ) ) {
float fAlpha = fabs( sin( time * 20 ) );
HUD_DrawRedNumber( iMinutes, vTimePos + '48 0 0', fAlpha);
@ -147,14 +197,30 @@ void HUD_Draw( void ) {
HUD_DrawNumber( iUnits, vTimePos + '94 0 0', 1);
drawsubpic( vTimePos, '24 25 0', HUD_NUMFILE_LAYER, [ NUMSIZE_X * 6, NUMSIZE_Y * 3], [ NUMSIZE_X, NUMSIZE_Y ], VGUI_WINDOW_FGCOLOR, 1, DRAWFLAG_ADDITIVE );
}
// The money
}
/*
=================
HUD_DrawMoney
Draws the amount of money (0-16000) with an icon to the screen
=================
*/
void HUD_DrawMoney( void ) {
vector vMoneyPos = [ vVideoResolution_x - 160, vVideoResolution_y - 72 ];
drawsubpic( vMoneyPos, '18 25 0', HUD_NUMFILE_LAYER, [ NUMSIZE_X * 8, NUMSIZE_Y * 1], [ NUMSIZE_X * 0.75, NUMSIZE_Y ], VGUI_WINDOW_FGCOLOR, 1, DRAWFLAG_ADDITIVE );
vMoneyPos_x += ( 24 * 5 );
HUD_DrawNums( getstatf( STAT_MONEY ), vMoneyPos );
// Ammo
}
/*
=================
HUD_DrawAmmo
Draws the current clip, the amount of ammo for the caliber and a matching caliber icon
=================
*/
void HUD_DrawAmmo( void ) {
vector vAmmoClipPos = [ vVideoResolution_x - 136, vVideoResolution_y - 42 ];
HUD_DrawNums( getstatf( STAT_CURRENT_CLIP ), vAmmoClipPos );
vector vAmmoCalPos = [ vVideoResolution_x - 64, vVideoResolution_y - 42 ];
@ -163,3 +229,25 @@ void HUD_Draw( void ) {
// Caliber icon
drawsubpic( vVideoResolution - '42 42 0', '24 24 0', HUD_NUMFILE_LAYER, vHUDCalPos[ wptTable[ getstatf( STAT_ACTIVEWEAPON ) ].iCaliber ], [ NUMSIZE_X, NUMSIZE_X ], VGUI_WINDOW_FGCOLOR, 1, DRAWFLAG_ADDITIVE );
}
/*
=================
HUD_Draw
Called every frame in Draw.c
=================
*/
void HUD_Draw( void ) {
HUD_DrawTimer();
if( getplayerkeyvalue( player_localnum, "*spectator" ) == "1" ) {
return;
}
HUD_DrawHealth();
HUD_DrawArmor();
HUD_DrawIcons();
HUD_DrawMoney();
HUD_DrawAmmo();
}

View file

@ -18,6 +18,13 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
=================
CSQC_Init
Comparable to worldspawn in SSQC in that it's mostly used for precaches
=================
*/
void CSQC_Init(float apilevel, string enginename, float engineversion) {
precache_model( HUD_NUMFILE );
@ -29,10 +36,24 @@ void CSQC_Init(float apilevel, string enginename, float engineversion) {
CSQC_VGUI_Init();
}
/*
=================
CSQC_WorldLoaded
Whenever the world is fully initialized...
=================
*/
void CSQC_WorldLoaded( void ) {
}
/*
=================
CSQC_Shutdown
Incase you need to free something
=================
*/
void CSQC_Shutdown( void ) {
}

View file

@ -18,10 +18,17 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
float CSQC_Event_Sound( float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod, float flags ) {
/*float CSQC_Event_Sound( float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod, float flags ) {
}
}*/
/*
=================
Sound_Delayed
Now you can call sounds in advance
=================
*/
void Sound_Delayed( string sSample, float fVol, float fDelay ) {
static void Sound_Delayed_PlayBack( void ) {
print( sprintf( "[SOUND] Playing Event %s\n", self.sSoundSample ) );

View file

@ -35,7 +35,14 @@ vguiwindow_t vguiMenus[11] = {
{ "Equipment", VGUI_BuyMenu_Equipment }
};
// Called every frame
/*
=================
CSQC_VGUI_Draw
This is the entry point for OpenCS own VGUI implementation
Run every frame
=================
*/
void CSQC_VGUI_Draw( void ) {
if ( fVGUI_Display == VGUI_NONE ) {
setcursormode( FALSE );
@ -53,10 +60,14 @@ void CSQC_VGUI_Draw( void ) {
vguiMenus[ fVGUI_Display - 1 ].vDraw( vVGUIWindowPos );
}
// Called by CSQC_Init
/*
=================
CSQC_VGUI_Init
Initialize all there is
=================
*/
void CSQC_VGUI_Init( void ) {
// We start on the MOTD, always
fVGUI_Display = VGUI_MOTD;
}

View file

@ -21,7 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// Stuff that applies to all codebases
enum {
TEAM_T = 1,
TEAM_CT
TEAM_CT,
TEAM_VIP
};
enum {
@ -36,7 +37,9 @@ enum {
STAT_SLOT_GRENADE,
STAT_CURRENT_CLIP,
STAT_CURRENT_CALIBER,
STAT_TEAM
STAT_TEAM,
STAT_WON_T,
STAT_WON_CT
};
enum {

View file

@ -18,12 +18,35 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
void ambient_generic_use( void ) {
sound( self, CHAN_VOICE, self.message, 1, self.style );
}
/*
ambient_generic
The ambient_generic allows you to play a specific sound.
Attributes:
Name (targetname) - Property used to identify entities.
WAV name (message) - This is the path/filename of the .wav file.
Volume (health) - Volume of the sound. Range: 0-10.
Dynamic Presets (preset) - Various effects that can be applied to the sound:
Flags:
Play Everywhere (1) - Sound will be heard in the entire level.
Small Radius (2) - Sound range is about 800 units at max volume.
Medium Radius (4) - Sound range is about 1250 units at max volume.
Large Radius (8) - Sound range is about 2000 units at max volume.
Start Silent (16) - Checking this means the entity must be triggered to work.
Not Toggled (32) - Older FGDs show this as Not Looped.
Makes the entity interpret each call as "turn on" instead of "toggle state".
Must be left unchecked for looping sound files.
Note that actual looping depends purely on cue points defined in the .wav file (see notes).
*/
void ambient_generic( void ) {
static void ambient_generic_use( void ) {
sound( self, CHAN_VOICE, self.message, self.health, self.style );
}
precache_sound( self.message );
self.health = self.health / 10;
if ( self.spawnflags & 1 ) {
self.style = ATTN_NONE;
@ -38,9 +61,9 @@ void ambient_generic( void ) {
}
if ( self.spawnflags & 32 ) {
sound( self, CHAN_VOICE, self.message, 1, self.style );
sound( self, CHAN_VOICE, self.message, self.health, self.style );
} else {
ambientsound( self.origin, self.message, 1, self.style );
ambientsound( self.origin, self.message, self.health, self.style );
}
self.vUse = ambient_generic_use;

View file

@ -25,8 +25,12 @@ void ClientConnect( void ) {}
void ClientDisconnect( void ) {
// We were part of the session
if( self.fInGame == TRUE ) {
fInGamePlayers--;
if( self.iInGame == TRUE ) {
if ( self.team == TEAM_T ) {
iInGamePlayers_T--;
} else if ( self.team == TEAM_CT ) {
iInGamePlayers_CT--;
}
}
}
@ -41,14 +45,7 @@ void PlayerPostThink( void ) {
void PutClientInServer( void ) {
entity eSpawn;
eSpawn = find (world, classname, "trigger_camera");
self.classname = "spectator";
self.health = self.max_health = 999;
self.takedamage = DAMAGE_NO;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_FLY;
self.flags = FL_CLIENT;
self.origin = eSpawn.origin + '0 0 1';
// Rotate camera towards a target
@ -61,13 +58,11 @@ void PutClientInServer( void ) {
}
self.fixangle = TRUE;
self.model = 0;
setsize (self, '-16 -16 -16', '16 16 16');
self.view_ofs = self.velocity = '0 0 0';
self.classname = "spectator";
Spawn_MakeSpectator();
forceinfokey( self, "*spectator", "1" ); // Make sure we are known as a spectator
// Because we don't want to reset these when we die
self.fMoney = cvar( "mp_startmoney" );
}
void SV_RunClientCommand( void ) {
@ -77,7 +72,7 @@ void SV_RunClientCommand( void ) {
self.fInBuyZone = FALSE;
self.fInHostageZone = FALSE;
if( fGameState != GAME_ACTIVE ) {
if( fGameState == GAME_FREEZE && self.team != 0 ) {
input_movevalues = '0 0 0';
input_buttons = 0;
input_impulse = 0;

View file

@ -31,10 +31,16 @@ float EFFECT_BLOOD;
.float fInBombZone;
.float fMoney;
.float fStepTime;
.int iInGame;
// Match specific fields
int iWon_T;
int iWon_CT;
int iInGamePlayers_T;
int iInGamePlayers_CT;
int fOldInGamePlayers;
.float fInGame;
float fInGamePlayers;
float fOldInGamePlayers;
float fGameState;
float fGameTime;
@ -51,6 +57,8 @@ float fGameTime;
int iHostagesMax;
int iHostagesRescued;
int iBombZones;
// Generic entity fields
.int iUsable;
.int iBleeds;
@ -80,6 +88,10 @@ string sCSPlayers[9] = {
"models/player/gign/gign.mdl"
};
void Timer_Begin( float fTime, float fMode);
void Spawn_RespawnClient( int iTeam );
void Spawn_CreateClient( int iTeam );
void Spawn_MakeSpectator( void );
void Client_SendEvent( entity eClient, float fEVType );
void OpenCSGunBase_AccuracyCalc( void );

View file

@ -43,6 +43,8 @@ void Entities_RenderSetup( void ) {
// GoldSrc-Rendermode support
if ( self.rendermode != RENDERMODE_NORMAL ) {
self.alpha = ( self.renderamt / 255 );
self.colormod = self.rendercolor;
if( self.alpha == 0 ) {
self.alpha = 0.0001;
}

View file

@ -18,31 +18,78 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
=================
cycler_sprite
This entity lets you display and cycle through the animation of a sprite (or a model, engine doesn't care).
Attributes:
Name (targetname) - Property used to identify entities.
Pitch Yaw Roll (angles) - Sets the pitch (up / down), yaw (left / right) and roll (bank) respectively. The compass in WorldCraft / Hammer corresponds to Yaw. The settings are not always (or not all) used.
Sprite (model) - A sprite must be specified here (sprites/spritename.spr).
Frames per second (framerate) - Framerate the sprite will run at if animated.
=================
*/
void cycler_sprite( void ) {
static void cycler_sprite_use( void ) {
remove( self );
}
precache_model( self.model );
setmodel( self, self.model );
self.vUse = cycler_sprite_use;
Entities_RenderSetup();
}
/*
=================
env_render
This entity allows you to change the rendering properties
of most of the visible entities in the game (monsters, func_walls etc.), while the map is running.
The four render properties of the env_render will be copied to its target.
Attributes:
Name (targetname) - Property used to identify entities.
Target (target) - When an entity is activated, it triggers the entity with the name specified by Target.
Flags:
No Renderfx (1) - Render FX will not be copied.
No Renderamt (2) - Render Amount will not be copied.
No Rendermode (4) - Render Mode will not be copied.
No Rendercolor (8) - Render Color will not be copied.
Notes:
Use this entity to fake situations that would be impossible for the game engine,
such as apparently binding multiple entities together (e.g. a moving doorhandle on a rotating door).
With a bit of careful setup, it is possible to let the the doorhandle move first,
then become invisible, then let the door move (with a static doorhandle attached).
=================
*/
#define SF_NORENDERFX 1
#define SF_NORENDERAMT 2
#define SF_NORENDERMODE 4
#define SF_NORENDERCOLOR 8
void env_render( void ) {
static void env_render_use( void ) {
entity eFind = findchain( targetname, self.target );
while ( eFind ) {
entity eOldSelf = self;
eFind.rendermode = self.rendermode;
eFind.rendercolor = self.rendercolor;
if ( !( self.spawnflags & SF_NORENDERMODE ) ) {
eFind.rendermode = self.rendermode;
}
if ( !( self.spawnflags & SF_NORENDERCOLOR ) ) {
eFind.colormod = self.colormod;
}
eFind.alpha = self.alpha;
eFind = eFind.chain;
}
}
self.colormod = self.rendercolor;
Entities_RenderSetup();
self.vUse = env_render_use;
}

View file

@ -43,4 +43,6 @@ void func_bomb_target( void ) {
setmodel( self, self.model );
self.model = 0;
self.touch = func_bomb_target_touch;
iBombZones++;
}

View file

@ -22,28 +22,29 @@ void main( void ) {}
void SetNewParms( void ) {}
void SetChangeParms( void ) {}
// Run every frame... by world?
void StartFrame( void ) {
// See if the player count has changed noticeably
if ( fInGamePlayers > fOldInGamePlayers ) {
// bprint( "Starting OpenCS Match...\n" );
// Global amount of players etc.
int iInGamePlayers = ( iInGamePlayers_T + iInGamePlayers_CT );
// See if the player count has changed
if ( iInGamePlayers > fOldInGamePlayers && fGameState == GAME_INACTIVE ) {
bprint( "Starting Match...\n" );
Timer_Begin( cvar( "mp_freezetime" ), GAME_FREEZE );
fOldInGamePlayers = fInGamePlayers;
fOldInGamePlayers = iInGamePlayers;
} else {
// No players? Don't bother updating the Timer
if ( fInGamePlayers == 0 ) {
if ( iInGamePlayers == 0 ) {
fGameState = GAME_INACTIVE;
fGameTime = 0;
} else {
Timer_Update();
}
}
}
// The map... entity.
void worldspawn( void ) {
precache_model (sCSPlayers[1]);
precache_model (sCSPlayers[2]);
@ -62,6 +63,9 @@ void worldspawn( void ) {
precache_sound( "radio/locknload.wav" );
precache_sound( "radio/rescued.wav" );
precache_sound( "radio/hosdown.wav" );
precache_sound( "radio/terwin.wav" );
precache_sound( "radio/ctwin.wav" );
precache_sound( "radio/rounddraw.wav" );
precache_sound( "hostage/hos1.wav" );
precache_sound( "hostage/hos2.wav" );
@ -227,10 +231,11 @@ void worldspawn( void ) {
precache_sound( "weapons/xm1014-1.wav" );
precache_sound( "weapons/zoom.wav" );
// TODO: Merge these into a single field
// TODO: Merge these into a single field?
clientstat( STAT_BUYZONE, EV_FLOAT, fInBuyZone );
clientstat( STAT_HOSTAGEZONE, EV_FLOAT, fInHostageZone );
clientstat( STAT_BOMBZONE, EV_FLOAT, fInBombZone );
clientstat( STAT_MONEY, EV_FLOAT, fMoney );
clientstat( STAT_SLOT_MELEE, EV_INTEGER, iSlotMelee );
clientstat( STAT_SLOT_PRIMARY, EV_INTEGER, iSlotPrimary );
@ -240,5 +245,7 @@ void worldspawn( void ) {
clientstat( STAT_CURRENT_CALIBER, EV_INTEGER, iCurrentCaliber );
clientstat( STAT_TEAM, EV_INTEGER, team );
pointerstat( STAT_GAMETIME, EV_FLOAT, &fGameTime );
pointerstat( STAT_WON_T, EV_INTEGER, &iWon_T );
pointerstat( STAT_WON_CT, EV_INTEGER, &iWon_CT );
}

51
Source/Server/Player.c Normal file
View file

@ -0,0 +1,51 @@
/*
OpenCS Project
Copyright (C) 2015 Marco "eukara" Hladik
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
void Player_Pain( void ) {
}
void Player_Death( void ) {
// Drop a corpse
entity eCorpse = spawn();
setorigin( eCorpse, self.origin );
setmodel( eCorpse, self.model );
eCorpse.angles = self.angles;
eCorpse.frame = 93; // TODO: Pick the right frame
Spawn_MakeSpectator();
if ( self.team == TEAM_T ) {
iInGamePlayers_T--;
if ( iInGamePlayers_T == 0 ) {
Rules_RoundOver( TEAM_CT );
}
} else if ( self.team == TEAM_CT ) {
iInGamePlayers_CT--;
if ( iInGamePlayers_CT == 0 ) {
Rules_RoundOver( TEAM_T );
}
} else if ( self.team == TEAM_VIP ) {
// TODO: Finish me
}
}

68
Source/Server/Rules.c Normal file
View file

@ -0,0 +1,68 @@
/*
OpenCS Project
Copyright (C) 2015 Marco "eukara" Hladik
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Loop through all players and respawn them
void Rules_Restart( void ) {
//localcmd( "restart_ents" );
entity eFind = findchain( classname, "player" );
while ( eFind ) {
entity eOldSelf = self;
self = eFind;
if ( self.health > 0 ) {
Spawn_RespawnClient( self.team );
} else {
Spawn_CreateClient( self.team );
}
self = eOldSelf;
eFind = eFind.chain;
}
Timer_Begin( cvar( "mp_freezetime" ), GAME_FREEZE );
}
// This can happen whenever an objective is complete or time is up
void Rules_RoundOver( int iTeamWon ) {
if ( iTeamWon == TEAM_T ) {
sound( world, CHAN_VOICE, "radio/terwin.wav", 1.0, ATTN_NONE );
iWon_T++;
} else if ( iTeamWon == TEAM_CT ) {
sound( world, CHAN_VOICE, "radio/ctwin.wav", 1.0, ATTN_NONE );
iWon_CT++;
} else {
sound( world, CHAN_VOICE, "radio/rounddraw.wav", 1.0, ATTN_NONE );
}
Timer_Begin( 5, GAME_END); // Round is over, 5 seconds til a new round starts
}
// Whenever mp_roundtime was being counted down to 0
void Rules_TimeOver( void ) {
if ( iBombZones > 0 ) {
Rules_RoundOver( TEAM_CT );
} else if ( iHostagesMax > 0 ) {
Rules_RoundOver( TEAM_T );
} else {
Rules_RoundOver( 0 );
}
}

View file

@ -18,65 +18,127 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
void Spawn_GameClient( float fTeam ) {
entity eSpawn;
if( self.fInGame == FALSE ) {
self.fInGame = TRUE;
fInGamePlayers++;
}
// What team are we on - 0= Spectator, < 5 Terrorists
if( fTeam == 0 ) {
PutClientInServer();
return;
} else if( fTeam < 5 ) {
eSpawn = find ( world, classname, "info_player_deathmatch" );
self.team = TEAM_T;
// TODO: Move this away from here
Weapon_AddItem( WEAPON_GLOCK18 );
Weapon_GiveAmmo( WEAPON_GLOCK18, 40 );
} else {
eSpawn = find ( world, classname, "info_player_start" );
self.team = TEAM_CT;
// TODO: Move this away from here
Weapon_AddItem( WEAPON_USP45 );
Weapon_GiveAmmo( WEAPON_USP45, 24 );
entity eLastTSpawn;
entity eLastCTSpawn;
entity Spawn_FindSpawnPoint( int iTeam ) {
entity eSpot, eLastSpawn;
entity eThing;
int iCount;
string sClassname;
if ( iTeam == TEAM_T ) {
sClassname = "info_player_deathmatch";
eSpot = eLastSpawn = eLastTSpawn;
} else {
sClassname = "info_player_start";
eSpot = eLastSpawn = eLastCTSpawn;
}
while (1) {
eSpot = find(eSpot, classname, sClassname);
if (eSpot != world) {
if (eSpot == eLastSpawn)
return eLastSpawn;
iCount = 0;
eThing = findradius(eSpot.origin, 32);
while(eThing) {
if (eThing.classname == "player")
iCount++;
eThing = eThing.chain;
}
if (iCount == 0) {
eLastSpawn = eSpot;
return eSpot;
}
}
}
return eSpot;
}
void Spawn_RespawnClient( int iTeam ) {
entity eSpawn;
forceinfokey( self, "*spectator", "0" ); // Make sure we are known as a spectator
eSpawn = Spawn_FindSpawnPoint( self.team );
self.classname = "player";
self.health = self.max_health = 100;
self.takedamage = DAMAGE_AIM;
self.takedamage = DAMAGE_YES;
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_WALK;
self.flags = FL_CLIENT;
self.vPain = Player_Pain;
self.vDeath = Player_Death;
self.origin = eSpawn.origin;
self.angles = eSpawn.angles;
self.fixangle = TRUE;
// Get the player-model from Defs.h's list
setmodel( self, sCSPlayers[ fTeam ] );
setmodel( self, sCSPlayers[ iTeam ] );
setsize( self, VEC_HULL_MIN, VEC_HULL_MAX );
self.view_ofs = '0 0 24';
self.velocity = '0 0 0';
self.frame = 1; // Idle frame
}
void Spawn_CreateClient( int iTeam ) {
// What team are we on - 0= Spectator, < 5 Terrorists, CT rest
if( iTeam == 0 ) {
PutClientInServer();
return;
} else if( iTeam < 5 ) {
self.team = TEAM_T;
iInGamePlayers_T++;
Weapon_AddItem( WEAPON_GLOCK18 );
Weapon_GiveAmmo( WEAPON_GLOCK18, 40 );
} else {
self.team = TEAM_CT;
iInGamePlayers_CT++;
Weapon_AddItem( WEAPON_USP45 );
Weapon_GiveAmmo( WEAPON_USP45, 24 );
}
// Set the fields
self.fMoney = cvar( "mp_startmoney" );
if( self.iInGame == FALSE ) {
self.iInGame = TRUE;
}
Spawn_RespawnClient( self.team );
self.fAttackFinished = time + 1;
}
// This is called on connect and whenever a player dies
void Spawn_MakeSpectator( void ) {
self.health = 0;
self.takedamage = DAMAGE_NO;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NOCLIP;
self.flags = FL_CLIENT;
self.weapon = 0;
self.model = 0;
setsize (self, '-16 -16 -16', '16 16 16');
self.view_ofs = self.velocity = '0 0 0';
forceinfokey( self, "*spectator", "1" ); // Make sure we are known as a spectator
// Clear all the ammo stuff
for ( int i = 0; i < CS_WEAPON_COUNT; i++ ) {
self.(wptTable[ i ].iClipfld) = 0;
self.(wptTable[ i ].iCaliberfld) = 0;
}
}
// Event Handling, called by the Client codebase via 'sendevent'
void CSEv_GamePlayerSpawn_f( float fTeam ) {
Spawn_GameClient( fTeam );
Spawn_CreateClient( fTeam );
}
// Counter-Terrorist Spawnpoints

View file

@ -44,6 +44,7 @@ void Timer_Update( void ) {
if ( ( fGameState == GAME_ACTIVE ) || ( fGameState == GAME_FREEZE ) ) {
if ( fGameTime <= 0 ) {
if ( fGameState == GAME_ACTIVE ) {
Rules_TimeOver();
Timer_Begin( 5, GAME_END); // Round is over, 5 seconds til a new round starts
} else {
Timer_Begin( cvar( "mp_roundtime" ) * 60, GAME_ACTIVE ); // Unfreeze
@ -60,7 +61,7 @@ void Timer_Update( void ) {
}
} else if ( fGameState == GAME_END ) {
if ( fGameTime <= 0 ) {
// Restart round
Rules_Restart();
}
}
}

View file

@ -1,44 +1,45 @@
/*
TRIGGER_MULTIPLE
http://twhl.info/wiki.php?id=139
Target (target) - When an entity is activated, it triggers the entity with the name specified by Target.
Name (targetname) - Property used to identify entities.
Master (master) - The name of a multisource (or game_team_master) entity. A master must usually be active in order for the entity to work. Thus they act almost like an on/off switch, in their simplest form, and like an AND gate in the case of the multisource.
Delay before trigger (delay) - Usually the time in seconds before an entity should trigger its target (after being triggered itself). Under other SmartEdit names, delay might also be the time to wait before performing some other action.
Kill target (killtarget) - Remove this entity from the game when triggered
Target Path (netname)
Sound style (sounds)
Message (message)
Delay before reset (wait) - Time in seconds before the entity is ready to be re-triggered.
*/
// This is what they use...
.string killtarget;
.float wait;
.float delay;
void trigger_multiple_trigger( void ) {
Entities_UseTargets();
if ( self.killtarget ) {
entity eFind = findchain( killtarget, self.target );
while ( eFind ) {
entity eRemoveMe = eFind;
remove( eRemoveMe );
eFind = eFind.chain;
}
}
}
/*
=================
SPAWN: trigger_multiple
trigger_multiple
Entry function for this nice trigger object.
This entity triggers a specified target every time its area is entered by players, monsters or pushables.
Attributes:
Target (target) - When an entity is activated, it triggers the entity with the name specified by Target.
Name (targetname) - Property used to identify entities.
Master (master) - The name of a multisource (or game_team_master) entity. A master must usually be active in order for the entity to work. Thus they act almost like an on/off switch, in their simplest form, and like an AND gate in the case of the multisource.
Delay before trigger (delay) - Usually the time in seconds before an entity should trigger its target (after being triggered itself). Under other SmartEdit names, delay might also be the time to wait before performing some other action.
Kill target (killtarget) - Remove this entity from the game when triggered
Target Path (netname)
Sound style (sounds)
Message (message)
Delay before reset (wait) - Time in seconds before the entity is ready to be re-triggered.
Flags:
Monsters (1) - Allow monsters to activate this entity.
No Clients (2) - Players cannot activate this entity.
Pushables (4) - Allow pushable objects to activate this entity.
=================
*/
void trigger_multiple( void ) {
static void trigger_multiple_trigger( void ) {
Entities_UseTargets();
if ( self.killtarget ) {
entity eFind = findchain( killtarget, self.target );
while ( eFind ) {
entity eRemoveMe = eFind;
remove( eRemoveMe );
eFind = eFind.chain;
}
}
}
static void trigger_multiple_use( void ) {
if ( self.delay ) {
self.think = trigger_multiple_trigger;
@ -69,10 +70,31 @@ void trigger_multiple( void ) {
self.touch = trigger_multiple_touch;
}
/*
=================
multi_manager
This entity can activate several different events (including itself) at specific times.
Attributes:
Name (targetname) - Property used to identify entities.
Flags:
Multithreaded (1) - See notes below for an explanation.
Notes:
There were better ways to do this, but someone thought it was viable to use custom, user defined fields
which cannot normally be read by something like QC for targetnames. FTE allows us to read the fields
via the __fullspawndata global at least.
TODO: Try to find out what garbled mess __fullspawndata is trying to give us
=================
*/
void multi_manager( void ) {
static void multi_manager_use( void ) {
eprint( self );
}
self.message = __fullspawndata;
self.think = multi_manager_use;
self.nextthink = self.ltime + 5;

View file

@ -36,6 +36,7 @@ Defs.h
../Shared/Effects.c
Damage.c
TraceAttack.c
Rules.c
Timer.c
Main.c
EntHostage.c
@ -48,6 +49,7 @@ FuncLadder.c
FuncHostageRescue.c
FuncBombTarget.c
FuncBuyZone.c
Player.c
Spawn.c
Footsteps.c
Input.c

View file

@ -51,7 +51,7 @@ void Effect_BreakModel( vector vMins, vector vMaxs, vector vVel, float fStyle )
sModel = "models/metalplategibs.mdl";
break;
case MATERIAL_FLESH:
sModel = "models/fleshgibs.mdl";;
sModel = "models/fleshgibs.mdl";
break;
case MATERIAL_CINDER:
sModel = "models/cindergibs.mdl";