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