diff --git a/Source/Client/Event.c b/Source/Client/Event.c
index 1153a780..286cab39 100755
--- a/Source/Client/Event.c
+++ b/Source/Client/Event.c
@@ -26,7 +26,6 @@ Init all the cmds in one place
=================
*/
void CSQC_ConsoleCommand_Init( void ) {
-
registercommand( "+attack2" );
registercommand( "-attack2" );
registercommand( "+reload" );
@@ -479,6 +478,18 @@ void CSQC_Parse_Event( void ) {
vExploPos_z = readcoord();
Effect_CreateExplosion( vExploPos );
+ } else if ( fHeader == EV_SPARK ) {
+ vector vSparkPos, vSparkAngle;
+
+ vSparkPos_x = readcoord();
+ vSparkPos_y = readcoord();
+ vSparkPos_z = readcoord();
+
+ vSparkAngle_x = readcoord();
+ vSparkAngle_y = readcoord();
+ vSparkAngle_z = readcoord();
+
+ Effect_CreateSpark( vSparkPos, vSparkAngle );
}
}
diff --git a/Source/Client/HUD.c b/Source/Client/HUD.c
index c952bd45..0a5f23a9 100755
--- a/Source/Client/HUD.c
+++ b/Source/Client/HUD.c
@@ -396,6 +396,13 @@ Called every frame in Draw.c
void HUD_Draw( void ) {
vHUDColor = autocvar_con_color * ( 1 / 255 );
+ // I guess viewzoom turns from 0.0-1.0 float into a 0-255 byte
+ if ( getstatf( STAT_VIEWZOOM ) < 255 ) {
+ HUD_DrawScope();
+ } else {
+ HUD_DrawCrosshair();
+ }
+
HUD_DrawTimer();
HUD_DrawRadar();
HUD_DrawHealth();
@@ -406,5 +413,4 @@ void HUD_Draw( void ) {
HUD_DrawOrbituaries();
HUD_DrawProgressBar();
HUD_DrawWeaponSelect();
- HUD_DrawCrosshair();
}
diff --git a/Source/Client/HUDScope.c b/Source/Client/HUDScope.c
new file mode 100755
index 00000000..733d71a7
--- /dev/null
+++ b/Source/Client/HUDScope.c
@@ -0,0 +1,69 @@
+/*
+FreeCS Project
+Copyright (C) 2016, 2017 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.
+*/
+
+float fSBOffset;
+float fSBScale;
+
+/*
+=================
+HUD_DrawScope_Pic
+
+The scope borders are split up into multiple parts.
+We want to fill the screen, so we gotta do some hacking.
+=================
+*/
+void HUD_DrawScope_Pic( vector vPos, vector vSize, string sSprite ) {
+ drawpic( ( vPos * fSBScale ) + [ fSBOffset, 0 ], sSprite, vSize * fSBScale, '1 1 1', 1.0f );
+}
+
+/*
+=================
+HUD_DrawScope
+
+Tries to draw a scope whenever viewzoom < 1.0f
+=================
+*/
+void HUD_DrawScope( void ) {
+ static vector vScopePos;
+
+ // Draw the scope in the middle, seperately from the border
+ vScopePos = ( vVideoResolution / 2 ) + '-128 -128';
+ drawpic( vScopePos, "sprites/sniper_scope.spr_0.tga", '256 256', '1 1 1', 1.0f, DRAWFLAG_NORMAL );
+
+ // Border scale to fit the screen
+ fSBScale = vVideoResolution_y / 480;
+ fSBOffset = ( vVideoResolution_x / 2 ) - ( ( 640 * fSBScale ) / 2 );
+
+ // Type 1 Border... more coming soon?
+ HUD_DrawScope_Pic( '0 0', '192 112', "sprites/top_left.spr_0.tga" );
+ HUD_DrawScope_Pic( '192 0', '256 112', "sprites/top.spr_0.tga" );
+ HUD_DrawScope_Pic( '448 0', '192 112', "sprites/top_right.spr_0.tga" );
+ HUD_DrawScope_Pic( '0 112', '192 256', "sprites/left.spr_0.tga" );
+ HUD_DrawScope_Pic( '448 112', '192 256', "sprites/right.spr_0.tga" );
+ HUD_DrawScope_Pic( '0 368', '192 112', "sprites/bottom_left.spr_0.tga" );
+ HUD_DrawScope_Pic( '192 368', '256 112', "sprites/bottom.spr_0.tga" );
+ HUD_DrawScope_Pic( '448 368', '192 112', "sprites/bottom_right.spr_0.tga" );
+
+ // Rect borders left and right
+ if ( fSBOffset > 0 ) {
+ drawfill( '0 0', [ fSBOffset, vVideoResolution_y ], '0 0 0', 1.0f );
+ drawfill( [ ( 640 * fSBScale ) + fSBOffset, 0 ], [ fSBOffset, vVideoResolution_y ], '0 0 0', 1.0f );
+ }
+}
diff --git a/Source/Client/Init.c b/Source/Client/Init.c
index dda35b67..b82fe06d 100755
--- a/Source/Client/Init.c
+++ b/Source/Client/Init.c
@@ -28,6 +28,16 @@ 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 );
+ precache_model( "sprites/top_left.spr" );
+ precache_model( "sprites/top.spr" );
+ precache_model( "sprites/top_right.spr" );
+ precache_model( "sprites/left.spr" );
+ precache_model( "sprites/right.spr" );
+ precache_model( "sprites/bottom_left.spr" );
+ precache_model( "sprites/bottom.spr" );
+ precache_model( "sprites/bottom_right.spr" );
+
+ precache_model( "sprites/sniper_scope.spr" );
precache_model( "sprites/fexplo.spr" );
precache_model( "sprites/muzzleflash1.spr" );
precache_model( "sprites/radar640.spr" );
diff --git a/Source/Client/VGUI.c b/Source/Client/VGUI.c
index 94882ee3..d872f9fd 100755
--- a/Source/Client/VGUI.c
+++ b/Source/Client/VGUI.c
@@ -39,7 +39,7 @@ vguiwindow_t vguiMenus[11] = {
=================
CSQC_VGUI_Draw
-This is the entry point for OpenCS own VGUI implementation
+This is the entry point for FreeCS own "VGUI" implementation
Run every frame
=================
*/
@@ -79,7 +79,7 @@ void CSQC_VGUI_Init( void ) {
// First load the MESSAGE OF THE DAY
// TODO: Move this to the server and put strings into infokeys
- filestream fmMOTD = fopen( "motd.txt", FILE_READ);
+ filestream fmMOTD = fopen( "motd.txt", FILE_READ );
for ( int i = 0; i < 25; i++ ) {
sTemp = fgets( fmMOTD );
if not ( sTemp ) {
@@ -90,7 +90,7 @@ void CSQC_VGUI_Init( void ) {
fclose( fmMOTD );
// Now load the MAP DESCRIPTION
- fmMOTD = fopen( sprintf( "maps/%s.txt", mapname ), FILE_READ);
+ fmMOTD = fopen( sprintf( "maps/%s.txt", mapname ), FILE_READ );
if ( fmMOTD != -1 ) {
for ( int i = 0; i < 35; i++ ) {
sTemp = fgets( fmMOTD );
diff --git a/Source/Client/View.c b/Source/Client/View.c
index b9bf9654..8da1ff85 100755
--- a/Source/Client/View.c
+++ b/Source/Client/View.c
@@ -170,14 +170,17 @@ void View_DrawViewModel( void ) {
fLastTime = time;
- // Update muzzleflash position and draw it
- if ( eMuzzleflash.alpha > 0.0f ) {
- eMuzzleflash.origin = gettaginfo( eViewModel, eMuzzleflash.skin );
- dynamiclight_add( eMuzzleflash.origin, 400 * eMuzzleflash.alpha, '1 0.45 0');
- addentity( eMuzzleflash );
+ // Only bother when zoomed out
+ if ( getstatf( STAT_VIEWZOOM ) == 255 ) {
+ // Update muzzleflash position and draw it
+ if ( eMuzzleflash.alpha > 0.0f ) {
+ eMuzzleflash.origin = gettaginfo( eViewModel, eMuzzleflash.skin );
+ dynamiclight_add( eMuzzleflash.origin, 400 * eMuzzleflash.alpha, '1 0.45 0');
+ addentity( eMuzzleflash );
+ }
+
+ addentity( eViewModel );
}
-
- addentity( eViewModel );
}
void View_PlayAnimation( int iSequence ) {
diff --git a/Source/Client/progs.src b/Source/Client/progs.src
index a2a74354..7ad7e053 100755
--- a/Source/Client/progs.src
+++ b/Source/Client/progs.src
@@ -56,6 +56,7 @@ VGUIRadio.c
VGUI.c
Nightvision.c
HUDCrosshair.c
+HUDScope.c
HUDWeaponSelect.c
HUDOrbituaries.c
HUD.c
diff --git a/Source/FreeCS-CE.prj b/Source/FreeCS-CE.prj
index 2e0f8ed5..f7d6c372 100755
--- a/Source/FreeCS-CE.prj
+++ b/Source/FreeCS-CE.prj
@@ -7,6 +7,7 @@
+
@@ -59,7 +60,7 @@
-
+
@@ -70,7 +71,7 @@
-
+
@@ -112,12 +113,7 @@
-
-
-
-
-
-
-
+
+
diff --git a/Source/Globals.h b/Source/Globals.h
index d66c2f2e..0e2b41f1 100755
--- a/Source/Globals.h
+++ b/Source/Globals.h
@@ -221,6 +221,7 @@ enum {
EV_WEAPON_RELOAD,
EV_IMPACT,
EV_EXPLOSION,
+ EV_SPARK,
EV_MODELGIB,
EV_CAMERATRIGGER,
EV_RADIOMSG,
diff --git a/Source/Server/Entities.c b/Source/Server/Entities.c
index 50997090..99d8ed93 100755
--- a/Source/Server/Entities.c
+++ b/Source/Server/Entities.c
@@ -61,7 +61,7 @@ void Entities_UseTargets( void ) {
entity eOld = self;
while ( eFind ) {
self = eFind;
- //bprint( sprintf( "Triggering %s %s\n", self.classname, self.targetname ) );
+ dprint( sprintf( "Triggering %s %s\n", self.classname, self.targetname ) );
// Make sure we really do have a target...
if ( self.vUse != __NULL__ ) {
diff --git a/Source/Server/EnvObjects.c b/Source/Server/EnvObjects.c
index 15ddd093..af7d4f0c 100755
--- a/Source/Server/EnvObjects.c
+++ b/Source/Server/EnvObjects.c
@@ -175,7 +175,6 @@ enumflags {
ENVEXPLO_NOSPARKS
};
-// TODO: Finish cosmetic effects
void env_explosion( void ) {
static void env_explosion_use( void ) {
Effect_CreateExplosion( self.origin );
@@ -191,3 +190,67 @@ void env_explosion( void ) {
self.vUse = env_explosion_use;
}
+
+/*
+=================
+env_spark
+
+Produces an electrical spark effect.
+
+Attributes:
+Name (targetname) - Property used to identify entities.
+Pitch Yaw Roll (angles) - Sets the angles respectively.
+Max Delay (MaxDelay) - Maximum delay between sparks.
+
+Flags:
+Toggle (32)
+Start On (64)
+
+
+Notes:
+According to the fieldname MaxDelay, it is probably going to use
+a random number to create a delay between the individual sparks.
+I have no idea why they didn't just reuse the delay field.
+We may never know.
+=================
+*/
+#define SPARK_TOGGLE 32
+#define SPARK_ON 64
+.float MaxDelay;
+void env_spark( void ) {
+ static void env_spark_fire( void ) {
+ Effect_CreateSpark( self.origin, self.angles );
+ }
+ static void env_spark_think( void ) {
+ env_spark_fire();
+ self.nextthink = time + ( random() * self.MaxDelay );
+ }
+ static void env_spark_use( void ) {
+ if ( self.spawnflags & SPARK_TOGGLE ) {
+ if ( self.think != __NULL__ ) {
+ self.think = __NULL__;
+ self.nextthink = 0;
+ } else {
+ self.think = env_spark_think;
+ self.nextthink = time + ( random() * self.MaxDelay );
+ }
+ } else {
+ env_spark_fire();
+ }
+ }
+ static void env_spark_respawn( void ) {
+ if ( self.MaxDelay <= 0 ) {
+ self.MaxDelay = 1.0f;
+ }
+
+ if ( self.spawnflags & SPARK_TOGGLE ) {
+ if ( self.spawnflags & SPARK_ON ) {
+ self.think = env_spark_think;
+ self.nextthink = time + ( random() * self.MaxDelay );
+ }
+ }
+ }
+
+ self.vUse = env_spark_use;
+ Entities_InitRespawnable( env_spark_respawn );
+}
diff --git a/Source/Server/FuncButton.c b/Source/Server/FuncButton.c
index 22a7f5ba..ec33ca90 100755
--- a/Source/Server/FuncButton.c
+++ b/Source/Server/FuncButton.c
@@ -18,20 +18,14 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*
-=================
-func_door Spawnflags
-=================
-*/
+#define SF_BTT_NOMOVE 1
+#define SF_BTT_TOGGLE 32
+#define SF_BTT_TOUCH_ONLY 256
void() FuncButton_MoveAway;
void() FuncButton_MoveBack;
void() FuncButton_Touch;
-#define SF_BTT_NOMOVE 1
-#define SF_BTT_TOGGLE 32
-#define SF_BTT_TOUCH_ONLY 256
-
enum {
STATE_RAISED = 0,
STATE_LOWERED,
@@ -39,6 +33,11 @@ enum {
STATE_DOWN
};
+enum {
+ FRAME_OFF,
+ FRAME_ON
+};
+
.float speed;
.float lip;
.float dmg;
@@ -55,74 +54,73 @@ FuncButton_PrecacheSounds
====================
*/
void FuncButton_PrecacheSounds( void ) {
- string sSample = "buttons/button9.wav"; // Default sample?
-
switch( self.sounds ) {
case 0:
// if you ever wondered why a silent button sounded a bit noisey... it's because this one kinda blows
- sSample = "common/null.wav";
+ self.noise = "common/null.wav";
break;
case 1:
- sSample = "buttons/button1.wav";
+ self.noise = "buttons/button1.wav";
break;
case 2:
- sSample = "buttons/button2.wav";
+ self.noise = "buttons/button2.wav";
break;
case 3:
- sSample = "buttons/button3.wav";
+ self.noise = "buttons/button3.wav";
break;
case 4:
- sSample = "buttons/button4.wav";
+ self.noise = "buttons/button4.wav";
break;
case 5:
- sSample = "buttons/button5.wav";
+ self.noise = "buttons/button5.wav";
break;
case 6:
- sSample = "buttons/button6.wav";
+ self.noise = "buttons/button6.wav";
break;
case 7:
- sSample = "buttons/button7.wav";
+ self.noise = "buttons/button7.wav";
break;
case 8:
- sSample = "buttons/button8.wav";
+ self.noise = "buttons/button8.wav";
break;
case 9:
- sSample = "buttons/button9.wav";
+ self.noise = "buttons/button9.wav";
break;
case 10:
- sSample = "buttons/button10.wav";
+ self.noise = "buttons/button10.wav";
break;
case 11:
- sSample = "buttons/button11.wav";
+ self.noise = "buttons/button11.wav";
break;
case 12:
- sSample = "buttons/latchlocked1.wav";
+ self.noise = "buttons/latchlocked1.wav";
break;
case 13:
- sSample = "buttons/latchunlocked1.wav";
+ self.noise = "buttons/latchunlocked1.wav";
break;
case 14:
- sSample = "buttons/lightswitch2.wav";
+ self.noise = "buttons/lightswitch2.wav";
break;
case 21:
- sSample = "buttons/lever1.wav";
+ self.noise = "buttons/lever1.wav";
break;
case 22:
- sSample = "buttons/lever2.wav";
+ self.noise = "buttons/lever2.wav";
break;
case 23:
- sSample = "buttons/lever3.wav";
+ self.noise = "buttons/lever3.wav";
break;
case 24:
- sSample = "buttons/lever4.wav";
+ self.noise = "buttons/lever4.wav";
break;
case 25:
- sSample = "buttons/lever5.wav";
+ self.noise = "buttons/lever5.wav";
break;
+ default:
+ self.noise = "buttons/button9.wav";
}
- precache_sound( sSample );
- self.noise = sSample;
+ precache_sound( self.noise );
}
/*
@@ -140,8 +138,10 @@ void FuncButton_Arrived( void ) {
return;
}
- self.think = FuncButton_MoveBack;
- self.nextthink = ( self.ltime + self.wait );
+ if ( self.wait != -1 ) {
+ self.think = FuncButton_MoveBack;
+ self.nextthink = ( self.ltime + self.wait );
+ }
}
/*
@@ -155,6 +155,7 @@ void FuncButton_Returned( void ) {
}
self.state = STATE_LOWERED;
+ self.frame = FRAME_OFF;
}
/*
@@ -169,7 +170,12 @@ void FuncButton_MoveBack( void ) {
}
self.state = STATE_DOWN;
- Entities_MoveToDestination ( self.pos1, self.speed, FuncButton_Returned );
+
+ if ( self.pos2 != self.pos1 ) {
+ Entities_MoveToDestination ( self.pos1, self.speed, FuncButton_Returned );
+ } else {
+ FuncButton_Returned();
+ }
}
/*
@@ -188,7 +194,14 @@ void FuncButton_MoveAway( void ) {
}
self.state = STATE_UP;
- Entities_MoveToDestination ( self.pos2, self.speed, FuncButton_Arrived );
+
+ if ( self.pos2 != self.pos1 ) {
+ Entities_MoveToDestination ( self.pos2, self.speed, FuncButton_Arrived );
+ } else {
+ FuncButton_Arrived();
+ }
+
+ self.frame = FRAME_ON;
}
/*
@@ -197,13 +210,15 @@ FuncButton_Trigger
====================
*/
void FuncButton_Trigger( void ) {
- if ( self.fAttackFinished > self.ltime ) {
+ if ( self.fAttackFinished > time ) {
return;
}
- self.fAttackFinished = self.ltime + self.wait;
+ self.fAttackFinished = time + self.wait;
if ( ( self.state == STATE_UP ) || ( self.state == STATE_RAISED ) ){
- FuncButton_MoveBack();
+ if ( self.wait != -1 ) {
+ FuncButton_MoveBack();
+ }
return;
}
@@ -258,7 +273,6 @@ func_button
Spawn function of a moving door entity
====================
*/
-
void func_button( void ) {
FuncButton_PrecacheSounds();
Entities_SetMovementDirection();
diff --git a/Source/Server/FuncDoorRotating.c b/Source/Server/FuncDoorRotating.c
index db8f3558..9ba4d3cc 100755
--- a/Source/Server/FuncDoorRotating.c
+++ b/Source/Server/FuncDoorRotating.c
@@ -234,21 +234,21 @@ void func_door_rotating( void ) {
self.pos1 = self.angles;
- // Only do X
+ // Only do Y
if ( self.spawnflags & SF_ROT_XAXIS ) {
- self.pos2_x = self.pos1_x + self.distance;
+ self.pos2_y = self.pos1_y + self.distance;
}
- // Only do Y
+ // Only do X
if ( self.spawnflags & SF_ROT_YAXIS ) {
- self.pos2_y = self.pos1_y + self.distance;
+ self.pos2_x = self.pos1_x + self.distance;
}
- // ...only do Y by default?
+ // ...only do X by default?
if ( !( self.spawnflags & SF_ROT_YAXIS ) && !( self.spawnflags & SF_ROT_XAXIS ) ) {
- self.pos2_y = self.pos1_y + self.distance;
+ self.pos2_x = self.pos1_x + self.distance;
}
if ( self.spawnflags & SF_ROT_OPEN ) {
diff --git a/Source/Server/Player.c b/Source/Server/Player.c
index 1905e9e2..cee406e5 100755
--- a/Source/Server/Player.c
+++ b/Source/Server/Player.c
@@ -89,7 +89,7 @@ void Player_Death( int iHitBody ) {
Weapon_DropWeapon( SLOT_PRIMARY );
} else {
if ( self.fSlotSecondary ) {
- Weapon_DropWeapon( SLOT_PRIMARY );
+ Weapon_DropWeapon( SLOT_SECONDARY );
}
}
if ( self.fSlotGrenade ) {
@@ -177,16 +177,15 @@ Player_CrouchCheck
=================
*/
float Player_CrouchCheck( entity targ ) {
- float fCheck = FALSE;
vector vTrace = self.origin + '0 0 20';
tracebox( vTrace, VEC_HULL_MIN, VEC_HULL_MAX, vTrace, FALSE, self );
if ( trace_startsolid == FALSE ) {
- fCheck = TRUE;
+ return TRUE;
}
- return fCheck;
+ return FALSE;
}
/*
@@ -195,11 +194,11 @@ Player_CrouchDown
=================
*/
void Player_CrouchDown( void ) {
- if( self.movetype != MOVETYPE_WALK ) {
+ if ( self.movetype != MOVETYPE_WALK ) {
return;
}
- if( !( self.flags & FL_CROUCHING ) ) {
+ if ( !( self.flags & FL_CROUCHING ) ) {
setsize( self, VEC_CHULL_MIN, VEC_CHULL_MAX );
self.flags = self.flags | FL_CROUCHING;
self.view_ofs = VEC_PLAYER_CVIEWPOS;
diff --git a/Source/Server/Spawn.c b/Source/Server/Spawn.c
index 75320d35..7a2d5837 100755
--- a/Source/Server/Spawn.c
+++ b/Source/Server/Spawn.c
@@ -210,6 +210,7 @@ void Spawn_MakeSpectator( void ) {
self.movetype = MOVETYPE_NOCLIP;
self.flags = FL_CLIENT;
self.weapon = 0;
+ self.viewzoom = 1.0f;
self.model = 0;
setsize (self, '-16 -16 -16', '16 16 16');
diff --git a/Source/Server/Triggers.c b/Source/Server/Triggers.c
index 2c50ffb8..6b507448 100755
--- a/Source/Server/Triggers.c
+++ b/Source/Server/Triggers.c
@@ -212,9 +212,17 @@ void multi_manager( void ) {
// Sigh, let's attempt to sanitize this
if ( ( argv( i ) != "classname" ) && ( argv( i ) != "origin" ) && ( argv( i ) != "targetname" ) ) {
entity eTemp = spawn();
- eTemp.target = argv( i );
eTemp.think = multi_manager_enttrigger;
eTemp.nextthink = time + stof( argv( i + 1 ) );
+
+ // sigh, because you obviously don't want to tokenize inside a tokenized loop
+ if ( substring( argv( i ), strlen( argv( i ) ) - 3, 1 ) == "#" ) {
+ eTemp.target = substring( argv( i ), 0, strlen( argv( i ) ) - 3 );
+ } else if ( substring( argv( i ), strlen( argv( i ) ) - 2, 1 ) == "#" ) {
+ eTemp.target = substring( argv( i ), 0, strlen( argv( i ) ) - 2 );
+ } else {
+ eTemp.target = argv( i );
+ }
}
}
}
diff --git a/Source/Shared/Effects.c b/Source/Shared/Effects.c
index da3bbec3..0f4b65ea 100755
--- a/Source/Shared/Effects.c
+++ b/Source/Shared/Effects.c
@@ -54,6 +54,25 @@ void Effect_CreateExplosion( vector vPos ) {
#endif
}
+void Effect_CreateSpark( vector vPos, vector vAngle ) {
+#ifdef SSQC
+ vPos_z += 48;
+ WriteByte( MSG_MULTICAST, SVC_CGAMEPACKET );
+ WriteByte( MSG_MULTICAST, EV_SPARK );
+ WriteCoord( MSG_MULTICAST, vPos_x );
+ WriteCoord( MSG_MULTICAST, vPos_y );
+ WriteCoord( MSG_MULTICAST, vPos_z );
+ WriteCoord( MSG_MULTICAST, vAngle_x );
+ WriteCoord( MSG_MULTICAST, vAngle_y );
+ WriteCoord( MSG_MULTICAST, vAngle_z );
+ msg_entity = self;
+ multicast( vPos, MULTICAST_PVS );
+#else
+ pointparticles( PARTICLE_SPARK, vPos, vAngle, 1 );
+ pointsound( vPos, sprintf( "buttons/spark%d.wav", floor( random() * 6 ) + 1 ), 1, ATTN_STATIC );
+#endif
+}
+
#ifdef CSQC
.float framerate;
void Effect_AnimatedSprite( vector vPos, float fIndex, float fFPS, float fScale, float fAlpha, float fEffects ) {
diff --git a/freecs/csprogs.dat b/freecs/csprogs.dat
index 88124eee..5f2213c9 100644
Binary files a/freecs/csprogs.dat and b/freecs/csprogs.dat differ
diff --git a/freecs/menu.dat b/freecs/menu.dat
index 39e158ea..9712cac2 100755
Binary files a/freecs/menu.dat and b/freecs/menu.dat differ
diff --git a/freecs/progs.dat b/freecs/progs.dat
index 24437875..1a459853 100644
Binary files a/freecs/progs.dat and b/freecs/progs.dat differ