diff --git a/Source/Builtins.h b/Source/Builtins.h index 9d991abf..993f7960 100644 --- a/Source/Builtins.h +++ b/Source/Builtins.h @@ -617,7 +617,7 @@ void(string dest, string from, string cmd, string info) SV_ParseClusterEvent; /* float(string sender, string body) SV_ParseConnectionlessPacket; /* Provides QC with a way to communicate between servers, or with client server browsers. Sender is the sender's ip. Body is the body of the message. You'll need to add your own password/etc support as required. Self is not valid. */ void(float pauseduration) SV_PausedTic; /* For each frame that the server is paused, this function will be called to give the gamecode a chance to unpause the server again. the pauseduration argument says how long the server has been paused for (the time global is frozen and will not increment while paused). Self is not valid. */ float(float newstatus) SV_ShouldPause; /* Called to give the qc a change to block pause/unpause requests. Return false for the pause request to be ignored. newstatus is 1 if the user is trying to pause the game. For the duration of the call, self will be set to the player who tried to pause, or to world if it was triggered by a server-side event. */ -void() SV_RunClientCommand; /* Called each time a player movement packet was received from a client. Self is set to the player entity which should be updated, while the input_* globals specify the various properties stored within the input packet. The contents of this function should be somewaht identical to the equivelent function in CSQC, or prediction misses will occur. If you're feeling lazy, you can simply call 'runstandardplayerphysics' after modifying the inputs. */ +void() SV_RunClientCommand; /* Called each time a player movement packet was received from a client. Self is set to the player entity which should be updated, while the input_* globals specify the various properties stored within the input packet. The contents of this function should be somewaht identical to the equivelent function in CSQC, or prediction misses will occur. If you're feeling lazy, you can simply call 'runstandardplayerphysicsrunstandardplayerphysics' after modifying the inputs. */ void() SV_AddDebugPolygons; /* Called each video frame. This is the only place where ssqc is allowed to call the R_BeginPolygon/R_PolygonVertex/R_EndPolygon builtins. This is exclusively for debugging, and will break in anything but single player as it will not be called if the engine is not running both a client and a server. */ void() SV_PlayerPhysics; /* Legacy method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful. */ void() EndFrame; /* Called after non-player entities have been run at the end of the physics frame. Player physics is performed out of order and can/will still occur between EndFrame and BeginFrame. */ diff --git a/Source/Client/Event.c b/Source/Client/Event.c index 5aaf8937..db8ae354 100644 --- a/Source/Client/Event.c +++ b/Source/Client/Event.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. void CSQC_ConsoleCommand_Init( void ) { registercommand( "vgui_buymenu" ); + registercommand( "use" ); } float CSQC_ConsoleCommand( string sCMD ) { @@ -31,6 +32,10 @@ float CSQC_ConsoleCommand( string sCMD ) { fVGUI_Display = VGUI_BM_MAIN; } return TRUE; + break; + case "use": + sendevent( "PlayerUse", "" ); + return TRUE; break; } diff --git a/Source/Client/HUD.c b/Source/Client/HUD.c index d4cd3992..ecd470e3 100644 --- a/Source/Client/HUD.c +++ b/Source/Client/HUD.c @@ -111,7 +111,7 @@ void HUD_Draw( void ) { vector vTimePos = [ ( vVideoResolution_x / 2 ) - 60, vVideoResolution_y - 42 ]; if( serverkey( "timelimit" ) ) { - float fTimeLeft = ( stof(serverkey( "timelimit" )) * 60 ) - time; + float fTimeLeft = ( stof(serverkey( "timelimit" )) * 60 ) - getstatf( STAT_GAMETIME ); if( fTimeLeft < 0 ) { iMinutes = iSeconds = iTens = iUnits = 0; } else { @@ -121,8 +121,8 @@ void HUD_Draw( void ) { iUnits = iSeconds - 10*iTens; } } else { - iMinutes = time / 60; - iSeconds = time - 60*iMinutes; + iMinutes = getstatf( STAT_GAMETIME ) / 60; + iSeconds = getstatf( STAT_GAMETIME ) - 60*iMinutes; iTens = iSeconds / 10; iUnits = iSeconds - 10*iTens; } diff --git a/Source/Globals.h b/Source/Globals.h index 356785ca..527d0c42 100644 --- a/Source/Globals.h +++ b/Source/Globals.h @@ -29,7 +29,7 @@ enum { STAT_HOSTAGEZONE, STAT_BOMBZONE, STAT_MONEY, - STAT_SESSIONINFO, + STAT_GAMETIME, STAT_SLOT_MELEE, STAT_SLOT_PRIMARY, STAT_SLOT_SECONDARY, diff --git a/Source/Server/Defs.h b/Source/Server/Defs.h index 42c051ac..50247fe3 100644 --- a/Source/Server/Defs.h +++ b/Source/Server/Defs.h @@ -43,7 +43,14 @@ float fGameTime; // Game specific fields -int iHostages; +int iHostagesMax; +int iHostagesRescued; +.int iUsable; + +// All about +use +entity eActivator; +.void() vUse; +.int iUsable; // GoldSrc-Rendermode Fields .vector rendercolor; diff --git a/Source/Server/EntHostage.c b/Source/Server/EntHostage.c index feabb704..e56e11fc 100644 --- a/Source/Server/EntHostage.c +++ b/Source/Server/EntHostage.c @@ -18,6 +18,57 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +.entity eUser; + +float Client_LerpCamera( float fStart, float fEnd, float fAmount ) { + float shortest_angle = ( ( ( ( fEnd - fStart ) % 360 ) + 540 ) % 360 ) - 180; + return shortest_angle * fAmount; +} + +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; + } else { + self.eUser = world; + } +} + +void hostage_physics( void ) { + input_movevalues = '0 0 0'; + input_impulse = 0; + input_buttons = 0; + input_angles = self.angles; + + if ( self.eUser != world ) { + // This is visible ingame, so this is definitely executed. + vector vEndAngle = vectoangles( self.eUser.origin - self.origin ); + self.angles_y += Client_LerpCamera( self.angles_y, vEndAngle_y, 0.2 ); + + // Just make them move forward right now + // TODO: trace the dist to determine whether or not we should back off + float fDist = vlen( self.eUser.origin - self.origin ); + + if ( fDist < 130 ) { + self.frame = 13; + input_movevalues = '0 0 0'; + } else if ( fDist < 200 ) { + self.frame = 0; + input_movevalues = '110 0 0'; + } else { + self.frame = 2; + input_movevalues = '220 0 0'; + } + } else { + + } + + // Tricking the engine + self.movetype = MOVETYPE_WALK; + runstandardplayerphysics( self ); + self.customphysics = hostage_physics; +} + /* ================= SPAWN: hostage_entity @@ -27,13 +78,19 @@ Entry function for the hostages. */ void hostage_entity( void ) { precache_model( self.model ); - setorigin( self, self.origin + '0 0 -36'); + setorigin( self, self.origin ); self.solid = SOLID_SLIDEBOX; self.movetype = MOVETYPE_WALK; setmodel( self, self.model ); setsize( self, VEC_HULL_MIN + '0 0 36', VEC_HULL_MAX + '0 0 36' ); + self.customphysics = hostage_physics; + + self.eUser = world; + self.iUsable = TRUE; + self.vUse = hostage_use; self.frame = 13; // Idle frame + self.health = 100; - iHostages = iHostages + 1; // Increase the global count of hostages + iHostagesMax = iHostagesMax + 1; // Increase the global count of hostages } diff --git a/Source/Server/FuncHostageRescue.c b/Source/Server/FuncHostageRescue.c index 443e0edf..dee2933f 100644 --- a/Source/Server/FuncHostageRescue.c +++ b/Source/Server/FuncHostageRescue.c @@ -26,6 +26,13 @@ func_hostage_rescue_touch void func_hostage_rescue_touch( void ) { if ( ( other.classname == "player" ) && ( other.team == TEAM_CT ) ) { other.fInHostageZone = TRUE; // Note: this will be cleared every frame inside SV_RunClientCommand + } else if ( other.classname == "hostage_entity" ) { + + sound( world, CHAN_VOICE, "radio/rescued.wav", 1.0, ATTN_NONE ); + iHostagesRescued++; + + other.eUser.fMoney += 1000; + remove( other ); } } diff --git a/Source/Server/Input.c b/Source/Server/Input.c index 7cc2d209..14941861 100644 --- a/Source/Server/Input.c +++ b/Source/Server/Input.c @@ -47,3 +47,25 @@ void Input_Handle( void ) { self.impulse = 0; } + +/* +==================== +CSEv_PlayerUse +==================== +*/ +void CSEv_PlayerUse( void ) { + vector vSource; + entity eOriginalSelf; + + makevectors(self.v_angle); + vSource = self.origin + self.view_ofs; + traceline ( vSource, vSource + ( v_forward * 64 ), FALSE, self); + + if ( trace_ent.iUsable ) { + eActivator = self; + eOriginalSelf = self; + self = trace_ent; + self.vUse(); + self = eOriginalSelf; + } +} diff --git a/Source/Server/Main.c b/Source/Server/Main.c index f769c83d..9e4cde47 100644 --- a/Source/Server/Main.c +++ b/Source/Server/Main.c @@ -57,6 +57,13 @@ void worldspawn( void ) { precache_sound( "radio/moveout.wav" ); precache_sound( "radio/letsgo.wav" ); precache_sound( "radio/locknload.wav" ); + precache_sound( "radio/rescued.wav" ); + + precache_sound( "hostage/hos1.wav" ); + precache_sound( "hostage/hos2.wav" ); + precache_sound( "hostage/hos3.wav" ); + precache_sound( "hostage/hos4.wav" ); + precache_sound( "hostage/hos5.wav" ); precache_sound( "weapons/ak47-1.wav" ); precache_sound( "weapons/ak47-2.wav" ); @@ -227,6 +234,6 @@ void worldspawn( void ) { clientstat( STAT_SLOT_GRENADE, EV_INTEGER, iSlotGrenade ); clientstat( STAT_CURRENT_CLIP, EV_INTEGER, iCurrentClip ); clientstat( STAT_CURRENT_CALIBER, EV_INTEGER, iCurrentCaliber ); - pointerstat( STAT_SESSIONINFO, EV_FLOAT, &fGameState ); + pointerstat( STAT_GAMETIME, EV_FLOAT, &fGameTime ); }