diff --git a/README.md b/README.md index 6148da5a..dd1b18df 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,32 @@ Open-Source implementation of CS running on FTE QuakeWorld # Goals The goal of this project is to provide an open-source implementation of Counter-Strike 1.5. Counter-Strike, being one of the most popular multiplayer games to exist, surprisingly hasn't had -a free-software implementation done until now. Meaning you could only run it on the platforms -Valve chose to support ( Microsoft Windows, MacOS X and GNU/Linux at the time of this writing ) +a free-software implementation done until now. -Together we can create a foundation for people to enhance the Counter-Strike experience -by allowing them to add new weapons, gamemodes and more! +Some of the cool things you can do with this: +* Play/Host CS and CS Servers on virtually every platform. ( Main selling point ) +* Customize the game to whatever extent you like. +* Create entirely new weapons! +* Create completely new and refreshing gamemodes! +* Have a guarantee to be able to play it 20 years into the future! +* Use it as a base for your own games/mods! (As long as you own the rights to the assets) -# Compiling +# Status +All the weapons are implemented, but only hostage rescue maps are supported at the moment. +No equipment is implemented, no map radar/overview and no player animations. +Basically, hostage rescue is playable as long as you don't care about grenades/kevlar. + +# Compiling/Installing 1. Download the latest version of FTE QuakeWorld. 2. Download csv15full.exe and to get the cstrike folder. 3. Move both the cstrike folder and FTE QuakeWorld into a folder -4. Compile the Client and Server modules using fteqcc and put them into the cstrike folder +4. Compile the Client and Server modules using FTEQCC and put them into the cstrike folder 5. Run FTE QuakeWorld + +# Special Thanks +Spike - Creator of FTE QuakeWorld and FTEQCC ( http://fte.triptohell.info/ ) +TWHL - Mapping Community with CS/HL entity information ( http://twhl.info ) + +This repository uses no content from Half-Life nor the original CS, for credits +as to who created the ORIGINAL Counter-Strike, please visit +http://web.archive.org/web/20021016230745/http://counter-strike.net/csteam.html diff --git a/Source/Client/Draw.c b/Source/Client/Draw.c index b9745ef5..341ef204 100644 --- a/Source/Client/Draw.c +++ b/Source/Client/Draw.c @@ -40,7 +40,6 @@ void CSQC_UpdateView( float fWinWidth, float fWinHeight, float fGameFocus ) { if( fGameFocus == TRUE ) { HUD_Draw(); CSQC_VGUI_Draw(); - drawstring( '320 240 0 ', sprintf( "FRAMETIME: %f", eViewModel.frame1time ) , '8 8 0', '1 1 1', 1, 0 ); } } diff --git a/Source/Client/Sound.c b/Source/Client/Sound.c index 76883050..c6c113af 100644 --- a/Source/Client/Sound.c +++ b/Source/Client/Sound.c @@ -31,7 +31,7 @@ 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 ) ); + //print( sprintf( "[SOUND] Playing Event %s\n", self.sSoundSample ) ); localsound( self.sSoundSample, CHAN_AUTO, self.fVolume ); remove( self ); } diff --git a/Source/Client/VGUI.c b/Source/Client/VGUI.c index e50f6dee..cc605b72 100644 --- a/Source/Client/VGUI.c +++ b/Source/Client/VGUI.c @@ -68,6 +68,30 @@ Initialize all there is ================= */ void CSQC_VGUI_Init( void ) { + string sTemp; + + // First load the MESSAGE OF THE DAY + filestream fmMOTD = fopen( "motd.txt", FILE_READ); + for ( int i = 0; i < 25; i++ ) { + sTemp = fgets( fmMOTD ); + if not ( sTemp ) { + break; + } + sMOTDString[ i ] = sTemp; + } + fclose( fmMOTD ); + + // Now load the MAP DESCRIPTION + fmMOTD = fopen( sprintf( "maps/%s.txt", mapname ), FILE_READ); + for ( int i = 0; i < 35; i++ ) { + sTemp = fgets( fmMOTD ); + if not ( sTemp ) { + break; + } + sMapString[ i ] = sTemp; + } + fclose( fmMOTD ); + // We start on the MOTD, always fVGUI_Display = VGUI_MOTD; } diff --git a/Source/Client/VGUI.h b/Source/Client/VGUI.h index 750bcb47..5a054086 100644 --- a/Source/Client/VGUI.h +++ b/Source/Client/VGUI.h @@ -41,6 +41,9 @@ enum { vector vVGUIWindowPos; vector vVGUIButtonPos; +string sMOTDString[25]; +string sMapString[35]; + typedef struct { string sTitle; void( vector vPos ) vDraw; diff --git a/Source/Client/VGUI_BuyMenu.c b/Source/Client/VGUI_BuyMenu.c index 3aa0fac9..f85b42ea 100644 --- a/Source/Client/VGUI_BuyMenu.c +++ b/Source/Client/VGUI_BuyMenu.c @@ -65,9 +65,11 @@ void VGUI_BuyMenu_Main( vector vPos ) { fVGUI_Display = VGUI_BM_MGS; } static void BuyMenu_Main_6( void ) { + sendevent( "GamePlayerBuyAmmo", "f", 0 ); fVGUI_Display = VGUI_NONE; } static void BuyMenu_Main_7( void ) { + sendevent( "GamePlayerBuyAmmo", "f", 1 ); fVGUI_Display = VGUI_NONE; } static void BuyMenu_Main_8( void ) { diff --git a/Source/Client/VGUI_MOTD.c b/Source/Client/VGUI_MOTD.c index f24d0542..c6155c74 100644 --- a/Source/Client/VGUI_MOTD.c +++ b/Source/Client/VGUI_MOTD.c @@ -28,8 +28,11 @@ void VGUI_MessageOfTheDay( vector vPos ) { VGUI_Text( serverkey( "hostname" ), vPos + '16 64 0', '16 16 0'); - VGUI_Text( "You are playing an early preview of this game.", vPos + '16 116 0', '8 8 0' ); - VGUI_Text( "Just press OK to proceed, or whatever.", vPos + '16 132 0', '8 8 0' ); + vector vTextPos = vPos + '16 116 0'; + for ( int i = 0; i < 25; i++ ) { + VGUI_Text( sMOTDString[ i ], vTextPos, '8 8 0' ); + vTextPos_y += 10; + } VGUI_Button( "OK", MessageOfTheDay_ButtonOK, vPos + '16 440 0', '80 24 0' ); } diff --git a/Source/Client/VGUI_TeamSelect.c b/Source/Client/VGUI_TeamSelect.c index c33dda9c..ce627b19 100644 --- a/Source/Client/VGUI_TeamSelect.c +++ b/Source/Client/VGUI_TeamSelect.c @@ -35,13 +35,16 @@ void VGUI_TeamSelect_Main( vector vPos ) { fVGUI_Display = VGUI_NONE; } - VGUI_Text( "Gamemode Title", vPos + '16 64 0', '16 16 0'); + VGUI_Text( sMapString[ 0 ], vPos + '16 64 0', '16 16 0'); - VGUI_Text( "This is a description of the gamemode that you are playing.", vPos + '16 116 0', '8 8 0' ); - VGUI_Text( "As you can see, that stuff is not implemented yet.", vPos + '16 132 0', '8 8 0' ); - - VGUI_Button( "Terrorists", TeamSelect_Main_ButtonT, vPos + '16 240 0', '180 24 0' ); - VGUI_Button( "Counter-Terrorists", TeamSelect_Main_ButtonCT, vPos + '16 272 0', '180 24 0' ); + vector vTextPos = vPos + '224 116 0'; + for ( int i = 1; i < 35; i++ ) { + VGUI_Text( sMapString[ i ], vTextPos, '8 8 0' ); + vTextPos_y += 10; + } + + VGUI_Button( "Terrorists", TeamSelect_Main_ButtonT, vPos + '16 116 0', '180 24 0' ); + VGUI_Button( "Counter-Terrorists", TeamSelect_Main_ButtonCT, vPos + '16 148 0', '180 24 0' ); VGUI_Button( "Auto-Assign", TeamSelect_Main_ButtonAuto, vPos + '16 336 0', '180 24 0' ); VGUI_Button( "Spectate", TeamSelect_Main_ButtonSpectate, vPos + '16 368 0', '180 24 0' ); diff --git a/Source/Globals.h b/Source/Globals.h index c38ae992..d2bc41ad 100644 --- a/Source/Globals.h +++ b/Source/Globals.h @@ -81,6 +81,7 @@ enum { CALIBER_50AE = 1, CALIBER_762MM, CALIBER_556MM, + CALIBER_556MMBOX, CALIBER_338MAG, CALIBER_9MM, CALIBER_BUCKSHOT, @@ -92,6 +93,7 @@ enum { .int iAmmo_50AE; .int iAmmo_762MM; .int iAmmo_556MM; +.int iAmmo_556MMBOX; .int iAmmo_338MAG; .int iAmmo_9MM; .int iAmmo_BUCKSHOT; @@ -142,6 +144,12 @@ typedef struct { float fMaxInaccuracy; } weaponinfo_t; +typedef struct { + int iSize; + int iMaxAmount; + int iPrice; +} ammoinfo_t; + typedef struct { void() vDraw; void() vPrimary; diff --git a/Source/Server/Ammo.c b/Source/Server/Ammo.c new file mode 100644 index 00000000..f79426b2 --- /dev/null +++ b/Source/Server/Ammo.c @@ -0,0 +1,85 @@ +/* +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. +*/ + +ammoinfo_t ammoTable[11] = { + { 0, 0, 0 }, + { 7, 35, 40 }, //CALIBER_50AE + { 30, 90, 80 }, //CALIBER_762MM + { 30, 90, 60 }, //CALIBER_556MM + { 30, 200, 60 }, //CALIBER_556MMBOX + { 10, 30, 125 }, //CALIBER_338MAG + { 30, 150, 20 }, //CALIBER_9MM + { 8, 32, 65 }, //CALIBER_BUCKSHOT + { 12, 100, 25 }, //CALIBER_45ACP + { 13, 52, 50 }, //CALIBER_357SIG + { 50, 100, 50 } //CALIBER_57MM +}; + +void Ammo_BuyPrimary( void ) { + if ( !self.iSlotPrimary ) { + return; + } + + int iRequiredAmmo = ( ammoTable[ wptTable[ self.iSlotPrimary ].iCaliber ].iMaxAmount - self.(wptTable[ self.iSlotPrimary ].iCaliberfld)); + float fNew = ceil( ( (float)iRequiredAmmo / (float)ammoTable[ wptTable[ self.iSlotPrimary ].iCaliber ].iSize ) ); + + for ( int i = 0; i < fNew; i++ ) { + self.(wptTable[ self.iSlotPrimary ].iCaliberfld) += ammoTable[ wptTable[ self.iSlotPrimary ].iCaliber ].iSize; + self.fMoney -= ammoTable[ wptTable[ self.iSlotPrimary ].iCaliber ].iPrice; + + if ( self.(wptTable[ self.iSlotPrimary ].iCaliberfld) > ammoTable[ wptTable[ self.iSlotPrimary ].iCaliber ].iMaxAmount ) { + self.(wptTable[ self.iSlotPrimary ].iCaliberfld) = ammoTable[ wptTable[ self.iSlotPrimary ].iCaliber ].iMaxAmount; + } + } +} + +void Ammo_BuySecondary( void ) { + if ( !self.iSlotSecondary ) { + return; + } + + int iRequiredAmmo = ( ammoTable[ wptTable[ self.iSlotSecondary ].iCaliber ].iMaxAmount - self.(wptTable[ self.iSlotSecondary ].iCaliberfld)); + float fNew = ceil( ( (float)iRequiredAmmo / (float)ammoTable[ wptTable[ self.iSlotSecondary ].iCaliber ].iSize ) ); + + for ( int i = 0; i < fNew; i++ ) { + self.(wptTable[ self.iSlotSecondary ].iCaliberfld) += ammoTable[ wptTable[ self.iSlotSecondary ].iCaliber ].iSize; + self.fMoney -= ammoTable[ wptTable[ self.iSlotSecondary ].iCaliber ].iPrice; + + if ( self.(wptTable[ self.iSlotSecondary ].iCaliberfld) > ammoTable[ wptTable[ self.iSlotSecondary ].iCaliber ].iMaxAmount ) { + self.(wptTable[ self.iSlotSecondary ].iCaliberfld) = ammoTable[ wptTable[ self.iSlotSecondary ].iCaliber ].iMaxAmount; + } + } +} + +void CSEv_GamePlayerBuyAmmo_f( float fType ) { + if ( Rules_BuyingPossible() == FALSE ) { + return; + } + + if ( fType == 0 ) { + Ammo_BuyPrimary(); + } else { + Ammo_BuySecondary(); + } + + Weapon_UpdateCurrents(); + self.fAttackFinished = time + 1.0; +} + diff --git a/Source/Server/Defs.h b/Source/Server/Defs.h index d8ca3e81..6bc53c3b 100644 --- a/Source/Server/Defs.h +++ b/Source/Server/Defs.h @@ -20,6 +20,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define VEC_HULL_MIN '-16 -16 -36' #define VEC_HULL_MAX '16 16 36' +#define VEC_PLAYER_VIEWPOS '0 0 24' + +#define VEC_CHULL_MIN '-16 -16 -18' +#define VEC_CHULL_MAX '16 16 18' +#define VEC_PLAYER_CVIEWPOS '0 0 12' + // Particle Fields float EFFECT_GUNSHOT; @@ -32,6 +38,9 @@ float EFFECT_BLOOD; .float fMoney; .float fStepTime; .int iInGame; +.float fCharModel; +.int iCrouching; +.int iCrouchAttempt; // Match specific fields int iWon_T; @@ -40,7 +49,6 @@ int iInGamePlayers_T; int iInGamePlayers_CT; int fOldInGamePlayers; - float fGameState; float fGameTime; @@ -89,9 +97,10 @@ string sCSPlayers[9] = { "models/player/gign/gign.mdl" }; +float Rules_BuyingPossible( void ); void Timer_Begin( float fTime, float fMode); -void Spawn_RespawnClient( int iTeam ); -void Spawn_CreateClient( int iTeam ); +void Spawn_RespawnClient( float fTeam ); +void Spawn_CreateClient( float fTeam ); void Spawn_MakeSpectator( void ); void Client_SendEvent( entity eClient, float fEVType ); diff --git a/Source/Server/EntHostage.c b/Source/Server/EntHostage.c index 2482789b..78b9c547 100644 --- a/Source/Server/EntHostage.c +++ b/Source/Server/EntHostage.c @@ -54,12 +54,14 @@ void hostage_die( void ) { // Happens upon calling 'use' void hostage_use( void ) { - if ( self.eUser == world ) { - sound( self, CHAN_VOICE, sprintf( "hostage/hos%d.wav", ceil( random() * 5 ) ), 1.0, ATTN_IDLE ); - self.eUser = eActivator; - self.eTargetPoint = self.eUser; - } else { - self.eUser = world; + if ( eActivator.team == TEAM_CT ) { + if ( ( self.eUser == world ) ) { + sound( self, CHAN_VOICE, sprintf( "hostage/hos%d.wav", ceil( random() * 5 ) ), 1.0, ATTN_IDLE ); + self.eUser = eActivator; + self.eTargetPoint = self.eUser; + } else { + self.eUser = world; + } } } diff --git a/Source/Server/FuncEscapeZone.c b/Source/Server/FuncEscapeZone.c new file mode 100644 index 00000000..185c0ad6 --- /dev/null +++ b/Source/Server/FuncEscapeZone.c @@ -0,0 +1,54 @@ +/* +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. +*/ + +/* +================= +func_escapezone_touch +================= +*/ +void func_escapezone_touch( void ) { + if ( ( other.classname == "player" ) && ( other.team == TEAM_T ) ) { + + } +} + +/* +================= +SPAWN: func_escapezone + +Entry function for the terrorist escape zone +================= +*/ +void func_escapezone( void ) { + self.angles = '0 0 0'; + self.movetype = MOVETYPE_NONE; + self.solid = SOLID_TRIGGER; + + if ( self.model ) { + setmodel( self, self.model ); + } else { + setsize( self, self.mins, self.maxs ); + } + + self.model = 0; + self.touch = func_escapezone_touch; + + iRescueZones++; +} diff --git a/Source/Server/Input.c b/Source/Server/Input.c index 14941861..c3cc5431 100644 --- a/Source/Server/Input.c +++ b/Source/Server/Input.c @@ -19,6 +19,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ void Input_Handle( void ) { + // TODO: Make this fast switch only + if ( self.impulse == 1 ) { + Weapon_Switch( SLOT_MELEE ); + } else if ( self.impulse == 2 ) { + Weapon_Switch( SLOT_SECONDARY ); + } else if ( self.impulse == 3 ) { + Weapon_Switch( SLOT_PRIMARY ); + } else if ( self.impulse == 4 ) { + Weapon_Switch( SLOT_GRENADE ); + } + + if ( self.button3 ) { + Player_CrouchDown(); + } else if ( self.iCrouching == TRUE ) { + Player_CrouchUp(); + } if ( self.button0 ) { Weapon_PrimaryAttack( self.weapon ); @@ -28,23 +44,6 @@ void Input_Handle( void ) { Weapon_SecondaryAttack( self.weapon ); } - if ( cvar( "developer" ) == 1 ) { - if( self.impulse == 10 ) { - if ( self.weapon < ( CS_WEAPON_COUNT - 1 ) ) { - dprint( "Weapon Cheat +\n" ); - self.weapon++; - CSEv_GamePlayerBuy_f( self.weapon ); - } - } - if( self.impulse == 11 ) { - if ( self.weapon > 1 ) { - dprint( "Weapon Cheat -\n" ); - self.weapon--; - CSEv_GamePlayerBuy_f( self.weapon ); - } - } - } - self.impulse = 0; } diff --git a/Source/Server/Player.c b/Source/Server/Player.c index 66a6ee23..34e00ef4 100644 --- a/Source/Server/Player.c +++ b/Source/Server/Player.c @@ -49,3 +49,88 @@ void Player_Death( void ) { // TODO: Finish me } } + +/* +================= +Player_CrouchCheck + +TODO: Tracebox implementation sucks, BUT SHOULD BE USED HERE. +This is just a hack because for some reason traceboxes hate HLBSP +================= +*/ +float Player_CrouchCheck( entity targ ) { + float fCheck = TRUE; + vector vTrace = self.origin + '0 0 20'; + + traceline( vTrace + '0 0 -36', vTrace + '0 0 36', FALSE, self ); + if ( trace_fraction != 1 ) { + fCheck = FALSE; + } + + // Now the 4 edges + traceline( vTrace + '-16 0 -36', vTrace + '-16 0 36', FALSE, self ); + if ( trace_fraction != 1 ) { + fCheck = FALSE; + } + traceline( vTrace + '0 -16 -36', vTrace + '0 -16 36', FALSE, self ); + if ( trace_fraction != 1 ) { + fCheck = FALSE; + } + traceline( vTrace + '16 0 -36', vTrace + '16 0 36', FALSE, self ); + if ( trace_fraction != 1 ) { + fCheck = FALSE; + } + traceline( vTrace + '0 16 -36', vTrace + '0 16 36', FALSE, self ); + if ( trace_fraction != 1 ) { + fCheck = FALSE; + } + + return fCheck; +} + +/* +================= +Player_CrouchDown +================= +*/ +void Player_CrouchDown( void ) { + if( self.movetype != MOVETYPE_WALK ) { + return; + } + + if( !self.iCrouching ) { + setsize( self, VEC_CHULL_MIN, VEC_CHULL_MAX ); + self.iCrouching = TRUE; + self.view_ofs = VEC_PLAYER_CVIEWPOS; + self.velocity_z = self.velocity_z + 50; + self.iCrouchAttempt = 1; + return; + } + + self.iCrouchAttempt = FALSE; +} + +/* +================= +Player_CrouchUp +================= +*/ +void Player_CrouchUp( void ) { + if ( self.movetype != MOVETYPE_WALK ) { + return; + } + + if ( self.iCrouching && ( !self.velocity_z ) && (Player_CrouchCheck( self ) ) ) { + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + + setorigin( self, self.origin + '0 0 18'); + self.velocity_z = self.velocity_z + 16; + self.view_ofs = VEC_PLAYER_VIEWPOS; + self.iCrouching = FALSE; + self.iCrouchAttempt = FALSE; + + return; + } + + self.iCrouchAttempt = TRUE; +} diff --git a/Source/Server/Rules.c b/Source/Server/Rules.c index 5bdbf7c3..be74d47a 100644 --- a/Source/Server/Rules.c +++ b/Source/Server/Rules.c @@ -18,9 +18,22 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +// Checks if it is possible for players to buy anything +float Rules_BuyingPossible( void ) { + if ( fGameState == GAME_ACTIVE ) { + if ( ( ( cvar( "mp_roundtime" ) * 60 ) - fGameTime ) > cvar( "mp_buytime" ) ) { + centerprint( self, sprintf( "%d seconds have passed...\nYou can't buy anything now!", cvar( "mp_buytime" ) ) ); + self.fAttackFinished = time + 1.0; + return FALSE; + } + } + + return TRUE; +} + // Loop through all players and respawn them void Rules_Restart( void ) { - localcmd( "restart_ents" ); + //localcmd( "restart_ents" ); entity eFind = findchain( classname, "player" ); @@ -31,7 +44,7 @@ void Rules_Restart( void ) { if ( self.health > 0 ) { Spawn_RespawnClient( self.team ); } else { - Spawn_CreateClient( self.team ); + Spawn_CreateClient( self.fCharModel ); } self = eOldSelf; diff --git a/Source/Server/Spawn.c b/Source/Server/Spawn.c index 64be50f7..6795f3fb 100644 --- a/Source/Server/Spawn.c +++ b/Source/Server/Spawn.c @@ -20,13 +20,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. entity eLastTSpawn; entity eLastCTSpawn; -entity Spawn_FindSpawnPoint( int iTeam ) { +entity Spawn_FindSpawnPoint( float fTeam ) { entity eSpot, eLastSpawn; entity eThing; int iCount; string sClassname; - if ( iTeam == TEAM_T ) { + if ( fTeam == TEAM_T ) { sClassname = "info_player_deathmatch"; eSpot = eLastSpawn = eLastTSpawn; } else { @@ -57,7 +57,7 @@ entity Spawn_FindSpawnPoint( int iTeam ) { return eSpot; } -void Spawn_RespawnClient( int iTeam ) { +void Spawn_RespawnClient( float fTeam ) { entity eSpawn; forceinfokey( self, "*spectator", "0" ); // Make sure we are known as a spectator eSpawn = Spawn_FindSpawnPoint( self.team ); @@ -76,21 +76,21 @@ void Spawn_RespawnClient( int iTeam ) { self.fixangle = TRUE; // Get the player-model from Defs.h's list - setmodel( self, sCSPlayers[ iTeam ] ); + setmodel( self, sCSPlayers[ self.fCharModel ] ); setsize( self, VEC_HULL_MIN, VEC_HULL_MAX ); - self.view_ofs = '0 0 24'; + self.view_ofs = VEC_PLAYER_VIEWPOS; self.velocity = '0 0 0'; self.frame = 1; // Idle frame } -void Spawn_CreateClient( int iTeam ) { +void Spawn_CreateClient( float fCharModel ) { // What team are we on - 0= Spectator, < 5 Terrorists, CT rest - if( iTeam == 0 ) { + if( fCharModel == 0 ) { PutClientInServer(); return; - } else if( iTeam < 5 ) { + } else if( fCharModel < 5 ) { self.team = TEAM_T; iInGamePlayers_T++; @@ -102,7 +102,6 @@ void Spawn_CreateClient( int iTeam ) { Weapon_AddItem( WEAPON_USP45 ); Weapon_GiveAmmo( WEAPON_USP45, 24 ); - } if( self.iInGame == FALSE ) { @@ -134,11 +133,34 @@ void Spawn_MakeSpectator( void ) { self.(wptTable[ i ].iClipfld) = 0; self.(wptTable[ i ].iCaliberfld) = 0; } + + // Clear the inventory + self.iSlotMelee = self.iSlotPrimary = self.iSlotSecondary = self.iSlotGrenade = 0; } // Event Handling, called by the Client codebase via 'sendevent' -void CSEv_GamePlayerSpawn_f( float fTeam ) { - Spawn_CreateClient( fTeam ); +void CSEv_GamePlayerSpawn_f( float fChar ) { + // Only allow to spawn directly into the game if we are still freezed/inactive + if ( fGameState == GAME_ACTIVE || fGameState == GAME_END ) { + // Yeah, set the future player model and stuff but let's act dead + if( fChar == 0 ) { + PutClientInServer(); + return; + } else if( fChar < 5 ) { + self.team = TEAM_T; + } else { + self.team = TEAM_CT; + } + + self.classname = "player"; + self.fCharModel = fChar; + self.health = 0; + Spawn_MakeSpectator(); + } else { + self.fCharModel = fChar; + Spawn_CreateClient( fChar ); + } + } // Counter-Terrorist Spawnpoints diff --git a/Source/Server/Triggers.c b/Source/Server/Triggers.c index 1e5b82a8..f0f2fb36 100644 --- a/Source/Server/Triggers.c +++ b/Source/Server/Triggers.c @@ -96,6 +96,5 @@ void multi_manager( void ) { } self.message = __fullspawndata; - self.think = multi_manager_use; - self.nextthink = self.ltime + 5; + self.vUse = multi_manager_use; } diff --git a/Source/Server/progs.src b/Source/Server/progs.src index 0906d0fe..7e0d1782 100644 --- a/Source/Server/progs.src +++ b/Source/Server/progs.src @@ -32,8 +32,9 @@ Defs.h ../Shared/WeaponXM1014.c ../Shared/WeaponBase.c ../Shared/Weapons.c - ../Shared/Effects.c + +Ammo.c Damage.c TraceAttack.c Rules.c diff --git a/Source/Shared/WeaponBase.c b/Source/Shared/WeaponBase.c index 1bcfa2a0..1b85b8d9 100644 --- a/Source/Shared/WeaponBase.c +++ b/Source/Shared/WeaponBase.c @@ -87,12 +87,13 @@ float OpenCSGunBase_Reload( void ) { return FALSE; } + // What if we've got less in our caliberfield than we need if ( self.(wptTable[ self.weapon ].iCaliberfld) < wptTable[ self.weapon ].iClipSize ) { self.(wptTable[ self.weapon ].iClipfld) = self.(wptTable[ self.weapon ].iCaliberfld); self.(wptTable[ self.weapon ].iCaliberfld) = 0; } else { + self.(wptTable[ self.weapon ].iCaliberfld) -= ( wptTable[ self.weapon ].iClipSize - self.(wptTable[ self.weapon ].iClipfld) ); self.(wptTable[ self.weapon ].iClipfld) = wptTable[ self.weapon ].iClipSize; - self.(wptTable[ self.weapon ].iCaliberfld) -= wptTable[ self.weapon ].iClipSize; } self.fAttackFinished = time + wptTable[ self.weapon ].fReloadFinished; diff --git a/Source/Shared/WeaponPara.c b/Source/Shared/WeaponPara.c index 9fc0ddb0..3491b5ff 100644 --- a/Source/Shared/WeaponPara.c +++ b/Source/Shared/WeaponPara.c @@ -25,7 +25,7 @@ weaponinfo_t wptPARA = { WEAPON_PARA, // Identifier SLOT_PRIMARY, 5750, // Price - CALIBER_556MM, // Caliber ID + CALIBER_556MMBOX, // Caliber ID 220, // Max Player Speed 1, // Bullets Per Shot 100, // Clip/MagSize @@ -36,7 +36,7 @@ weaponinfo_t wptPARA = { TYPE_AUTO, 0.08, // Attack-Delay 3.0, // Reload-Delay - iAmmo_556MM, // Caliber Pointer + iAmmo_556MMBOX, // Caliber Pointer iClip_PARA, // Clip Pointer 175, // Accuracy Divisor 0.4, // Accuracy Offset diff --git a/Source/Shared/Weapons.c b/Source/Shared/Weapons.c index a969af89..ed66ecbb 100644 --- a/Source/Shared/Weapons.c +++ b/Source/Shared/Weapons.c @@ -53,10 +53,15 @@ weaponfunc_t wpnFuncTable[ CS_WEAPON_COUNT ] = { }; void Weapon_Draw( float fWeapon ) { + if ( !fWeapon ) { + return; + } + wpnFuncTable[ fWeapon ].vDraw(); #ifdef SSQC self.maxspeed = (float)wptTable[ fWeapon ].iPlayerSpeed; + self.fAttackFinished = time + 1.0; #endif } @@ -91,6 +96,32 @@ void Weapon_Reload( float fWeapon ) { } #ifdef SSQC + +void Weapon_Switch( int iSlot ) { + if ( self.fAttackFinished > time ) { + return; + } + + float fWeapon; + + if ( iSlot == SLOT_MELEE ) { + fWeapon = self.iSlotMelee; + } else if ( iSlot == SLOT_PRIMARY ) { + fWeapon = self.iSlotPrimary; + } else if ( iSlot == SLOT_SECONDARY ) { + fWeapon = self.iSlotSecondary; + } else if ( iSlot == SLOT_GRENADE ) { + fWeapon = self.iSlotGrenade; + } + + if ( !fWeapon || self.weapon == fWeapon ) { + return; + } + + self.weapon = fWeapon; + Weapon_Draw( fWeapon ); +} + void Weapon_UpdateCurrents( void ) { self.iCurrentClip = self.(wptTable[ self.weapon ].iClipfld); self.iCurrentCaliber = self.(wptTable[ self.weapon ].iCaliberfld); @@ -127,8 +158,12 @@ void Weapon_GiveAmmo( float fWeapon, float fAmount ) { } void CSEv_GamePlayerBuy_f( float fWeapon ) { + if ( Rules_BuyingPossible() == FALSE ) { + return; + } + Weapon_AddItem( fWeapon ); - Weapon_GiveAmmo( fWeapon, 99 ); + self.fMoney -= wptTable[ fWeapon ].iPrice; self.fAttackFinished = time + 1.0; }