diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cgame/cg_draw.c | 9 | ||||
-rw-r--r-- | src/cgame/cg_event.c | 23 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 2 | ||||
-rw-r--r-- | src/cgame/cg_predict.c | 2 | ||||
-rw-r--r-- | src/cgame/cg_view.c | 14 | ||||
-rw-r--r-- | src/cgame/cg_weapons.c | 5 | ||||
-rw-r--r-- | src/game/bg_misc.c | 150 | ||||
-rw-r--r-- | src/game/bg_pmove.c | 3 | ||||
-rw-r--r-- | src/game/bg_public.h | 21 | ||||
-rw-r--r-- | src/game/g_active.c | 42 | ||||
-rw-r--r-- | src/game/g_buildable.c | 2 | ||||
-rw-r--r-- | src/game/g_client.c | 61 | ||||
-rw-r--r-- | src/game/g_cmds.c | 129 | ||||
-rw-r--r-- | src/game/g_local.h | 48 | ||||
-rw-r--r-- | src/game/g_team.c | 4 | ||||
-rw-r--r-- | src/game/g_utils.c | 7 |
16 files changed, 371 insertions, 151 deletions
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index cc087856..ff9d2525 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -1094,7 +1094,8 @@ static float CG_DrawScores( float y ) { x = 640; score = cg.snap->ps.persistant[PERS_SCORE]; - spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ); + spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) || + ( cg.snap->ps.stats[ STAT_STATE ] & SS_INFESTING ); // always show your score in the second box if not in first place if ( s1 != score ) { @@ -1805,7 +1806,8 @@ static void CG_DrawCrosshair(void) { return; } - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) { + if( ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) || + ( cg.snap->ps.stats[ STAT_STATE ] & SS_INFESTING ) ) { return; } @@ -2224,7 +2226,8 @@ static void CG_Draw2D( void ) { return; } - if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) { + if( ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) || + ( cg.snap->ps.stats[ STAT_STATE ] & SS_INFESTING ) ) { CG_DrawSpectator(); CG_DrawCrosshair(); CG_DrawCrosshairNames(); diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index c8a3fab2..a2be137c 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -421,6 +421,9 @@ CG_Menu */ void CG_Menu( int eventParm ) { + char menuDef[ MAX_STRING_CHARS ]; + int i; + switch( eventParm ) { case MN_TEAM: @@ -447,6 +450,20 @@ void CG_Menu( int eventParm ) trap_SendConsoleCommand( "menu hmcumenu\n" ); break; + case MN_INFEST: + strcpy( menuDef, "5,5|Infest|0.8,0,0.8,1|0.6,0,0.6,0.8|1,0,1,1|1|16|" ); + for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) + { + if( BG_ClassCanEvolveFromTo( cg.snap->ps.stats[ STAT_PCLASS ], i ) ) + strcat( menuDef, va( "%s, class %s|", BG_FindNameForClassNum( i ), BG_FindNameForClassNum( i ) ) ); + } + strcat( menuDef, "|Choose a class|to evolve to" ); + + trap_SendConsoleCommand( va( "defmenu infest \"%s\"\n", menuDef ) ); + trap_SendConsoleCommand( "menu infest\n" ); + trap_SendConsoleCommand( "undefmenu infest\n" ); + break; + default: Com_Printf( "cgame: debug: no such menu %d\n", eventParm ); @@ -985,6 +1002,12 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { CG_Menu( es->eventParm ); break; + case EV_PLAYER_RESPAWN: + DEBUGNAME("EV_PLAYER_RESPAWN"); + if( es->number == cg.clientNum ) + cg.spawnTime = cg.time; + break; + default: DEBUGNAME("UNKNOWN"); CG_Error( "Unknown event: %i", event ); diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index d1703528..886fb16a 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -632,6 +632,8 @@ typedef struct { char testModelName[MAX_QPATH]; qboolean testGun; + int spawnTime; //TA: fovwarp + } cg_t; diff --git a/src/cgame/cg_predict.c b/src/cgame/cg_predict.c index dfcaf752..6ded046c 100644 --- a/src/cgame/cg_predict.c +++ b/src/cgame/cg_predict.c @@ -432,6 +432,8 @@ void CG_PredictPlayerState( void ) { cg_pmove.ps = &cg.predictedPlayerState; cg_pmove.trace = CG_Trace; cg_pmove.pointcontents = CG_PointContents; + + //TA: FIXME BIG NEON SIGN..... COULD MAYBE BE A FIX FOR THAT HACK IN bg_pmove.c.. MAYBE \/ if ( cg_pmove.ps->pm_type == PM_DEAD ) { cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; } diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c index d8401334..393ac480 100644 --- a/src/cgame/cg_view.c +++ b/src/cgame/cg_view.c @@ -516,6 +516,7 @@ Fixed fov at intermissions, otherwise account for fov variable and zooms. */ #define WAVE_AMPLITUDE 1 #define WAVE_FREQUENCY 0.4 +#define FOVWARPTIME 400.0 static int CG_CalcFov( void ) { float x; @@ -545,6 +546,19 @@ static int CG_CalcFov( void ) { fov_x = 1; else if ( fov_x > 160 ) fov_x = 160; + + if( cg.spawnTime > ( cg.time - FOVWARPTIME ) && + BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_FOVWARPS ) ) + { + float temp, temp2; + + temp = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME; + temp2 = ( 180 - fov_x ) * temp; + + //Com_Printf( "%f %f\n", temp*100, temp2*100 ); + + fov_x = 180 - temp2; + } } // account for zooms diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c index 15992501..318e227a 100644 --- a/src/cgame/cg_weapons.c +++ b/src/cgame/cg_weapons.c @@ -1070,7 +1070,8 @@ void CG_AddViewWeapon( playerState_t *ps ) { vec3_t angles; weaponInfo_t *weapon; - if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { + if( ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) || + ( ps->stats[ STAT_STATE ] & SS_INFESTING ) ) { return; } @@ -1105,7 +1106,7 @@ void CG_AddViewWeapon( playerState_t *ps ) { //if ( cg_fov.integer > 90 ) { //TA: the client side variable isn't used ( shouldn't iD have done this anyway? ) if( cg.refdef.fov_y > 90 ) - fovOffset = -0.2 * ( cg.refdef.fov_y - 90 ); + fovOffset = -0.4 * ( cg.refdef.fov_y - 90 ); else fovOffset = 0; diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c index 63eed9c8..f1ede9bb 100644 --- a/src/game/bg_misc.c +++ b/src/game/bg_misc.c @@ -891,8 +891,31 @@ int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1; classAttributes_t bg_classList[ ] = { + { + PCL_D_B_BASE, + "Builder", + "lucy", + "default", + { -15, -15, -20 }, + { 15, 15, 20 }, + { 15, 15, 20 }, + { -15, -15, -4 }, + { 15, 15, 4 }, + 12, 12, + 50, + 50, + SCA_TAKESFALLDAMAGE|SCA_FOVWARPS, + 80, + 0.015f, + 350, + 0.5f, + 1.0f, + { PCL_D_D_BASE, PCL_D_O_BASE, PCL_NONE }, + 2000 + }, { PCL_D_O_BASE, + "Offensive", "klesk", "default", { -15, -15, -15 }, @@ -903,15 +926,18 @@ classAttributes_t bg_classList[ ] = 4, 4, 25, 0, - SCA_WALLCLIMBER|SCA_CANJUMP|SCA_NOWEAPONDRIFT, + SCA_WALLCLIMBER|SCA_CANJUMP|SCA_NOWEAPONDRIFT|SCA_FOVWARPS, 140, 0.0f, 25, 2.0f, - 5.0f + 5.0f, + { PCL_D_D_BASE, PCL_D_B_BASE, PCL_NONE }, + 3000 }, { PCL_D_D_BASE, + "Defensive", "orbb", "default", { -15, -15, -15 }, @@ -922,34 +948,18 @@ classAttributes_t bg_classList[ ] = 4, 4, 50, 0, - SCA_WALLCLIMBER|SCA_CANJUMP|SCA_NOWEAPONDRIFT, - 160, + SCA_WALLCLIMBER|SCA_CANJUMP|SCA_NOWEAPONDRIFT|SCA_FOVWARPS, + 90, 0.0f, 25, 1.5f, - 3.0f - }, - { - PCL_D_B_BASE, - "lucy", - "default", - { -15, -15, -20 }, - { 15, 15, 20 }, - { 15, 15, 20 }, - { -15, -15, -4 }, - { 15, 15, 4 }, - 12, 12, - 50, - 50, - SCA_TAKESFALLDAMAGE, - 80, - 0.015f, - 350, - 0.5f, - 1.0f + 3.0f, + { PCL_D_O_BASE, PCL_D_B_BASE, PCL_NONE }, + 1000 }, { PCL_H_BASE, + "Human", "sarge", "default", { -15, -15, -24 }, @@ -965,7 +975,9 @@ classAttributes_t bg_classList[ ] = 0.002f, 200, 1.0f, - 1.0f + 1.0f, + { PCL_NONE, PCL_NONE, PCL_NONE }, + 0 } }; @@ -973,6 +985,44 @@ int bg_numPclasses = sizeof( bg_classList ) / sizeof( bg_classList[ 0 ] ); /* ============== +BG_FindClassNumForName +============== +*/ +int BG_FindClassNumForName( char *name ) +{ + int i; + + for( i = 0; i < bg_numPclasses; i++ ) + { + if( !Q_stricmp( bg_classList[ i ].className, name ) ) + return bg_classList[ i ].classNum; + } + + //wimp out + return PCL_NONE; +} + +/* +============== +BG_FindNameForClassNum +============== +*/ +char *BG_FindNameForClassNum( int pclass ) +{ + int i; + + for( i = 0; i < bg_numPclasses; i++ ) + { + if( bg_classList[ i ].classNum == pclass ) + return bg_classList[ i ].className; + } + + //wimp out + return ""; +} + +/* +============== BG_FindModelNameForClass ============== */ @@ -986,7 +1036,7 @@ char *BG_FindModelNameForClass( int pclass ) return bg_classList[ i ].modelName; } - //wimp out + //note: must return a valid modelName! return bg_classList[ 0 ].modelName; } @@ -1208,7 +1258,6 @@ int BG_FindSteptimeForClass( int pclass ) return 200; } - /* ============== BG_ClassHasAbility @@ -1233,6 +1282,52 @@ qboolean BG_ClassHasAbility( int pclass, int ability ) return qfalse; } +/* +============== +BG_ClassCanEvolveFromTo +============== +*/ +qboolean BG_ClassCanEvolveFromTo( int fclass, int tclass ) +{ + int i, j; + + if( tclass == PCL_NONE ) + return qfalse; + + for( i = 0; i < bg_numPclasses; i++ ) + { + if( bg_classList[ i ].classNum == fclass ) + { + for( j = 0; j <= 3; j++ ) + if( bg_classList[ i ].children[ j ] == tclass ) return qtrue; + + return qfalse; //may as well return by this point + } + } + + return qfalse; +} + +/* +============== +BG_FindEvolveTimeForClass +============== +*/ +int BG_FindEvolveTimeForClass( int pclass ) +{ + int i; + + for( i = 0; i < bg_numPclasses; i++ ) + { + if( bg_classList[ i ].classNum == pclass ) + { + return bg_classList[ i ].timeToEvolve; + } + } + + return 5000; +} + /* ============== @@ -1605,6 +1700,7 @@ char *eventnames[] = { "EV_USE_ITEM15", "EV_ITEM_RESPAWN", + "EV_PLAYER_RESPAWN", "EV_ITEM_POP", "EV_PLAYER_TELEPORT_IN", "EV_PLAYER_TELEPORT_OUT", diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c index 40915b22..0b50f4a2 100644 --- a/src/game/bg_pmove.c +++ b/src/game/bg_pmove.c @@ -2144,6 +2144,9 @@ static void PM_Weapon( void ) { if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { return; } + if( pm->ps->stats[ STAT_STATE ] & SS_INFESTING ) { + return; + } // check for dead player if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { diff --git a/src/game/bg_public.h b/src/game/bg_public.h index ab40ae77..49e71c38 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -249,12 +249,14 @@ typedef enum { #define SCA_CANZOOM 4 #define SCA_CANJUMP 8 #define SCA_NOWEAPONDRIFT 16 +#define SCA_FOVWARPS 32 #define SS_WALLCLIMBING 1 #define SS_GPISROTVEC 2 #define SS_CREEPSLOWED 4 #define SS_WALLTRANSIDING 8 #define SS_SPEEDBOOST 16 +#define SS_INFESTING 32 // player_state->persistant[] indexes @@ -450,6 +452,7 @@ typedef enum { EV_USE_ITEM15, EV_ITEM_RESPAWN, + EV_PLAYER_RESPAWN, //TA: for fovwarp effects EV_ITEM_GROW, //droid items that grow EV_ITEM_POP, EV_PLAYER_TELEPORT_IN, @@ -506,7 +509,8 @@ typedef enum MN_HUMAN, MN_ABUILD, MN_HBUILD, - MN_MCU + MN_MCU, + MN_INFEST } dynMenu_t; // animations @@ -696,23 +700,34 @@ typedef struct gitem_s { typedef struct { int classNum; + + char *className; + char *modelName; char *skinName; + vec3_t mins; vec3_t maxs; vec3_t crouchMaxs; vec3_t deadMins; vec3_t deadMaxs; + int viewheight; int crouchViewheight; + int health; int armor; + int abilities; + int fov; float bob; int steptime; float speed; float sticky; + + int children[ 3 ]; + int timeToEvolve; } classAttributes_t; @@ -728,6 +743,8 @@ gitem_t *BG_FindItemForPowerup( powerup_t pw ); gitem_t *BG_FindItemForHoldable( holdable_t pw ); //TA: +int BG_FindClassNumForName( char *name ); +char *BG_FindNameForClassNum( int pclass ); char *BG_FindModelNameForClass( int pclass ); void BG_FindBBoxForClass( int pclass, vec3_t mins, vec3_t maxs, vec3_t cmaxs, vec3_t dmins, vec3_t dmaxs ); void BG_FindViewheightForClass( int pclass, int *viewheight, int *cViewheight ); @@ -739,6 +756,8 @@ float BG_FindSpeedForClass( int pclass ); float BG_FindStickyForClass( int pclass ); int BG_FindSteptimeForClass( int pclass ); qboolean BG_ClassHasAbility( int pclass, int ability ); +qboolean BG_ClassCanEvolveFromTo( int fclass, int tclass ); +int BG_FindEvolveTimeForClass( int pclass ); #define ITEM_INDEX(x) ((x)-bg_itemlist) qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ); diff --git a/src/game/g_active.c b/src/game/g_active.c index 0cf4f644..514224c9 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -276,7 +276,8 @@ void G_TouchTriggers( gentity_t *ent ) { } // ignore most entities if a spectator - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { + if( ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) || + ( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) ) { if ( hit->s.eType != ET_TELEPORT_TRIGGER && // this is ugly but adding a new ET_? type will // most likely cause network incompatibilities @@ -652,6 +653,13 @@ void ClientThink_real( gentity_t *ent ) { int i; qboolean cSlowed = qfalse; + //TA: time + static int lastTime; + int dTime; + + dTime = level.time - lastTime; + lastTime = level.time; + //Com_Printf( "%d\n", G_LuminanceAtPoint( ent->s.origin ) ); client = ent->client; @@ -724,11 +732,20 @@ void ClientThink_real( gentity_t *ent ) { client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET ); } - if ( client->noclip ) { + if( client->noclip ) + { client->ps.pm_type = PM_NOCLIP; - } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) { + } + else if( client->ps.stats[STAT_HEALTH] <= 0 ) + { client->ps.pm_type = PM_DEAD; - } else { + } + else if( client->ps.stats[ STAT_STATE ] & SS_INFESTING ) + { + client->ps.pm_type = PM_FREEZE; + } + else + { client->ps.pm_type = PM_NORMAL; } @@ -810,18 +827,18 @@ void ClientThink_real( gentity_t *ent ) { if( ( client->ps.stats[ STAT_STATE ] & SS_SPEEDBOOST ) && ucmd->upmove >= 0 ) { //subtract stamina - client->ps.stats[ STAT_STAMINA ] -= 2; + client->ps.stats[ STAT_STAMINA ] -= dTime/6.0f; } if( ( aForward <= 64 && aForward > 5 ) || ( aRight <= 64 && aRight > 5 ) ) { //restore stamina - client->ps.stats[ STAT_STAMINA ] += 3; + client->ps.stats[ STAT_STAMINA ] += dTime/4.0f; } else if( aForward <= 5 && aRight <= 5 ) { //restore stamina faster - client->ps.stats[ STAT_STAMINA ] += 2; + client->ps.stats[ STAT_STAMINA ] += dTime/6.0f; } // set up for pmove @@ -848,6 +865,9 @@ void ClientThink_real( gentity_t *ent ) { if ( pm.ps->pm_type == PM_DEAD ) { pm.tracemask = MASK_PLAYERSOLID; // & ~CONTENTS_BODY; } + if ( pm.ps->stats[ STAT_STATE ] & SS_INFESTING ) { + pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; + } else if ( ent->r.svFlags & SVF_BOT ) { pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP; } @@ -954,6 +974,14 @@ void ClientThink_real( gentity_t *ent ) { return; } + if( ( ( client->lastInfestTime + + BG_FindEvolveTimeForClass( client->ps.stats[ STAT_PCLASS ] ) ) < level.time ) && + ( client->ps.stats[ STAT_STATE ] & SS_INFESTING ) ) + { + client->ps.stats[ STAT_STATE ] &= ~SS_INFESTING; + ClientSpawn( ent, client->infestBody ); + } + // perform once-a-second actions ClientTimerActions( ent, msec ); } diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index cb35b4c6..01fdcdb8 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -330,6 +330,8 @@ qboolean hdef1_checktarget(gentity_t *self, gentity_t *target) return qfalse; if( target->client->sess.sessionTeam == TEAM_SPECTATOR ) // is the target alive? return qfalse; + if( target->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) // is the target alive? + return qfalse; if( target->health <= 0 ) // is the target still alive? return qfalse; diff --git a/src/game/g_client.c b/src/game/g_client.c index 89dd7ded..cb41b37a 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -542,7 +542,7 @@ void InfestBody( gentity_t *self, gentity_t *other, gentity_t *activator ) { if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_DROIDS ) return; - G_AddPredictableEvent( activator, EV_MENU, MN_DROID ); + G_AddPredictableEvent( activator, EV_MENU, MN_INFEST ); } /* @@ -935,7 +935,10 @@ void ClientUserinfoChanged( int clientNum ) { if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) { client->pers.maxHealth = 100; } - //client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; + + //hack to force a client update if the config string does not change between spawning + if( client->pers.pclass == PCL_NONE ) + client->pers.maxHealth = 0; // set model s = BG_FindModelNameForClass( client->pers.pclass ); @@ -1156,22 +1159,24 @@ Initializes all non-persistant parts of playerState ============ */ void ClientSpawn( gentity_t *ent, gentity_t *spawn ) { - int index; - vec3_t spawn_origin, spawn_angles; - gclient_t *client; - int i; + int index; + vec3_t spawn_origin, spawn_angles; + gclient_t *client; + int i; clientPersistant_t saved; - clientSession_t savedSess; - int persistant[MAX_PERSISTANT]; - gentity_t *spawnPoint; - int flags; - int savedPing; - int ammoIndex, ammoSubIndex; - int teamLocal; - int accuracy_hits, accuracy_shots; - int savedEvents[MAX_PS_EVENTS]; - int eventSequence; - char userinfo[MAX_INFO_STRING]; + clientSession_t savedSess; + int persistant[MAX_PERSISTANT]; + gentity_t *spawnPoint; + int flags; + int savedPing; + int ammoIndex, ammoSubIndex; + int teamLocal; + int accuracy_hits, accuracy_shots; + int savedEvents[MAX_PS_EVENTS]; + int eventSequence; + char userinfo[MAX_INFO_STRING]; + vec3_t bodyMaxs, classMins, up = { 0, 0, 1 }; + index = ent - g_entities; client = ent->client; @@ -1204,19 +1209,17 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn ) { } else { + //this is an infest spawn if( spawn != NULL ) { - vec3_t bodyMaxs; - vec3_t classMins; - vec3_t up = { 0, 0, 1 }; - - VectorCopy ( spawn->s.pos.trBase, spawn_origin ); - VectorCopy ( spawn->s.angles, spawn_angles ); + //spawn as new droid + VectorCopy( spawn->s.pos.trBase, spawn_origin ); + VectorCopy( spawn->s.angles, spawn_angles ); BG_FindBBoxForClass( spawn->s.clientNum, NULL, NULL, NULL, NULL, bodyMaxs ); BG_FindBBoxForClass( ent->client->pers.pclass, classMins, NULL, NULL, NULL, NULL ); - spawn_origin[ 2 ] += 64; + spawn_origin[ 2 ] += bodyMaxs[ 2 ] + abs( classMins[ 2 ] ) + 1; G_AddEvent( spawn, EV_GIB_DROID, DirToByte( up ) ); spawn->freeAfterEvent = qtrue; } @@ -1272,9 +1275,9 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn ) { if( client->sess.sessionTeam == TEAM_SPECTATOR ) { if( teamLocal == PTE_DROIDS ) - G_AddEvent( ent, EV_MENU, MN_DROID ); + G_AddPredictableEvent( ent, EV_MENU, MN_DROID ); else if( teamLocal == PTE_HUMANS ) - G_AddEvent( ent, EV_MENU, MN_HUMAN ); + G_AddPredictableEvent( ent, EV_MENU, MN_HUMAN ); } // increment the spawncount so the client will detect the respawn @@ -1306,8 +1309,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn ) { client->ps.eFlags = flags; client->ps.clientNum = index; - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); + BG_FindBBoxForClass( ent->client->pers.pclass, ent->r.mins, ent->r.maxs, NULL, NULL, NULL ); client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = BG_FindHealthForClass( ent->client->pers.pclass ); client->ps.stats[ STAT_ARMOR ] = BG_FindArmorForClass( ent->client->pers.pclass ); @@ -1386,7 +1388,10 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn ) { client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; + //TA: STAT_SPAWNTIME for droid fov effects client->respawnTime = level.time; + G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); + client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 1b2c2be0..d6eb998b 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -419,12 +419,15 @@ Cmd_Kill_f ================= */ void Cmd_Kill_f( gentity_t *ent ) { - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { + if( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) return; - } - if (ent->health <= 0) { + + if( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) return; - } + + if (ent->health <= 0) + return; + ent->flags &= ~FL_GODMODE; ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; player_die (ent, ent, ent, 100000, MOD_SUICIDE); @@ -1541,26 +1544,23 @@ Cmd_Class_f */ void Cmd_Class_f( gentity_t *ent ) { - char s[ MAX_TOKEN_CHARS ]; - qboolean dontSpawn = qfalse; - int clientNum; + char s[ MAX_TOKEN_CHARS ]; + qboolean dontSpawn = qfalse; + int clientNum; gentity_t *body, *victim; vec3_t distance; int length = 4096; int i; + trace_t tr; + vec3_t infestOrigin, infestAngles; clientNum = ent->client - level.clients; trap_Argv( 1, s, sizeof( s ) ); - if( !strlen( s ) && ( ent->client->pers.pteam != PTE_HUMANS ) ) - { - trap_SendServerCommand( ent-g_entities, va("print \"class number: %i\n\"", ent->client->pers.pclass ) ); - return; - } - if( ent->client->pers.pteam == PTE_DROIDS ) { - if( ent->client->pers.pclass ) + //if we are not currently spectating, we are attempting evolution + if( ent->client->pers.pclass != PCL_NONE ) { for ( i = 1, body = g_entities + i; i < level.num_entities; i++, body++ ) { @@ -1575,58 +1575,72 @@ void Cmd_Class_f( gentity_t *ent ) } } + //if a human corpse is nearby... if( length <= 200 ) { - if( !Q_stricmp(s, "0") ) - ent->client->pers.pclass = PCL_D_B_BASE; - else if( !Q_stricmp(s, "1") ) - ent->client->pers.pclass = PCL_D_O_BASE; - else if( !Q_stricmp(s, "2") ) - ent->client->pers.pclass = PCL_D_D_BASE; - else + ent->client->pers.pclass = BG_FindClassNumForName( s ); + + //...check we can evolve to that class + if( !BG_ClassCanEvolveFromTo( ent->client->ps.stats[ STAT_PCLASS ], + ent->client->pers.pclass ) ) { - trap_SendServerCommand( ent-g_entities, va("print \"Unknown class\n\"" ) ); - dontSpawn = qtrue; + trap_SendServerCommand( ent-g_entities, va("print \"You cannot evolve from your current class\n\"" ) ); + return; } - if( !dontSpawn ) + if( ent->client->pers.pclass != PCL_NONE ) { + //evolve + ent->client->ps.stats[ STAT_PCLASS ] = PCL_NONE; ent->client->sess.sessionTeam = TEAM_FREE; ClientUserinfoChanged( clientNum ); - ClientSpawn( ent, victim ); + ent->client->ps.stats[ STAT_STATE ] |= SS_INFESTING; + ent->client->lastInfestTime = level.time; + ent->client->infestBody = victim; + + VectorCopy( victim->s.pos.trBase, infestOrigin ); + infestOrigin[ 2 ] += 128; + + /*trap_Trace( &tr, victim->s.pos.trBase, NULL, NULL, infestOrigin, victim->s.number, MASK_PLAYERSOLID ); + VectorCopy( tr.endpos, infestOrigin );*/ + VectorCopy( victim->s.angles, infestAngles ); + + infestAngles[ PITCH ] = 90; + + G_SetOrigin( ent, infestOrigin ); + VectorCopy( infestOrigin, ent->client->ps.origin ); + + SetClientViewAngle( ent, infestAngles ); + } + else + { + trap_SendServerCommand( ent-g_entities, va("print \"Unknown class\n\"" ) ); + return; } } - - return; - } - else if( ent->client->pers.pclass != 0 ) - { - trap_SendServerCommand( ent-g_entities, va("print \"You must be dead to spawn from a bioegg\n\"" ) ); - return; } - - if( !Q_stricmp(s, "0") ) - ent->client->pers.pclass = PCL_D_B_BASE; - else if( !Q_stricmp(s, "1") ) - ent->client->pers.pclass = PCL_D_O_BASE; - else if( !Q_stricmp(s, "2") ) - ent->client->pers.pclass = PCL_D_D_BASE; else { - trap_SendServerCommand( ent-g_entities, va("print \"Unknown class\n\"" ) ); - dontSpawn = qtrue; - } + //spawing from a bioegg + ent->client->pers.pclass = BG_FindClassNumForName( s ); - if( !dontSpawn ) - { - ent->client->sess.sessionTeam = TEAM_FREE; - ClientUserinfoChanged( clientNum ); - ClientSpawn( ent, NULL ); + if( ent->client->pers.pclass != PCL_NONE ) + { + ent->client->sess.sessionTeam = TEAM_FREE; + ClientUserinfoChanged( clientNum ); + ClientSpawn( ent, NULL ); + } + else + { + trap_SendServerCommand( ent-g_entities, va("print \"Unknown class\n\"" ) ); + return; + } } } else if( ent->client->pers.pteam == PTE_HUMANS ) { - if( ent->client->pers.pclass != 0 ) + //humans cannot use this command whilst alive + if( ent->client->pers.pclass != PCL_NONE ) { trap_SendServerCommand( ent-g_entities, va("print \"You must be dead to use the class command\n\"" ) ); return; @@ -1634,26 +1648,29 @@ void Cmd_Class_f( gentity_t *ent ) ent->client->pers.pclass = PCL_H_BASE; - if( !Q_stricmp( s, "0" ) ) + //set the item to spawn with + if( !Q_stricmp( s, "rifle" ) ) ent->client->pers.pitem = WP_MACHINEGUN; - else if( !Q_stricmp( s, "1" ) ) + else if( !Q_stricmp( s, "ckit" ) ) ent->client->pers.pitem = WP_HBUILD; - + else + { + trap_SendServerCommand( ent-g_entities, va("print \"Unknown starting item\n\"" ) ); + return; + } + ent->client->sess.sessionTeam = TEAM_FREE; ClientUserinfoChanged( clientNum ); ClientSpawn( ent, NULL ); } else if( ent->client->pers.pteam == PTE_NONE ) { - ent->client->pers.pclass = 0; + //can't use this command unless on a team + ent->client->pers.pclass = PCL_NONE; ent->client->sess.sessionTeam = TEAM_FREE; ClientSpawn( ent, NULL ); trap_SendServerCommand( ent-g_entities, va("print \"Join a team first\n\"" ) ); } - else - { - trap_SendServerCommand( ent-g_entities, va("print \"?\n\"" ) ); - } } diff --git a/src/game/g_local.h b/src/game/g_local.h index 1ddc628e..b32f07ff 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -274,55 +274,57 @@ struct gclient_s { qboolean noclip; - int lastCmdTime; // level.time of last usercmd_t, for EF_CONNECTION - // we can't just use pers.lastCommand.time, because - // of the g_sycronousclients case - int buttons; - int oldbuttons; - int latched_buttons; + int lastCmdTime; // level.time of last usercmd_t, for EF_CONNECTION + // we can't just use pers.lastCommand.time, because + // of the g_sycronousclients case + int buttons; + int oldbuttons; + int latched_buttons; vec3_t oldOrigin; // sum up damage over an entire frame, so // shotgun blasts give a single big kick - int damage_armor; // damage absorbed by armor - int damage_blood; // damage taken out of health - int damage_knockback; // impact damage + int damage_armor; // damage absorbed by armor + int damage_blood; // damage taken out of health + int damage_knockback; // impact damage vec3_t damage_from; // origin for vector calculation qboolean damage_fromWorld; // if true, don't use the damage_from vector - int accurateCount; // for "impressive" reward sound - int accuracy_shots; // total number of shots - int accuracy_hits; // total number of hits + int accurateCount; // for "impressive" reward sound + int accuracy_shots; // total number of shots + int accuracy_hits; // total number of hits // - int lastkilled_client; // last client that this client killed - int lasthurt_client; // last client that damaged this client - int lasthurt_mod; // type of damage the client did + int lastkilled_client; // last client that this client killed + int lasthurt_client; // last client that damaged this client + int lasthurt_mod; // type of damage the client did // timers - int respawnTime; // can respawn when time > this, force after g_forcerespwan - int inactivityTime; // kick players when time > this + int respawnTime; // can respawn when time > this, force after g_forcerespwan + int inactivityTime; // kick players when time > this qboolean inactivityWarning; // qtrue if the five seoond warning has been given - int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this + int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this - int airOutTime; + int airOutTime; - int lastKillTime; // for multiple kill rewards + int lastKillTime; // for multiple kill rewards qboolean fireHeld; // used for hook gentity_t *hook; // grapple hook if out - int switchTeamTime; // time the player switched teams + int switchTeamTime; // time the player switched teams gentity_t *torch; //TA: torch entity ( NULL if switched off ) // timeResidual is used to handle events that happen every second // like health / armor countdowns and regeneration - int timeResidual; + int timeResidual; - char *areabits; + char *areabits; float classSpeed; //TA: here to save STAT_ space + int lastInfestTime; //TA: to keep track of how long infests take + gentity_t *infestBody; //TA: body that is being infested. must be persistant }; // diff --git a/src/game/g_team.c b/src/game/g_team.c index b6e2c8a7..ce9263d1 100644 --- a/src/game/g_team.c +++ b/src/game/g_team.c @@ -472,7 +472,7 @@ void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker) /*if (targ->client->sess.sessionTeam == TEAM_HUMANS) flag_pw = PW_BLUEFLAG; else - flag_pw = PW_REDFLAG;*/ + flag_pw = PW_REDFLAG; if (targ->client->ps.powerups[flag_pw] && targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam) @@ -481,7 +481,7 @@ void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker) // skulls if (targ->client->ps.generic1 && targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam) - attacker->client->pers.teamState.lasthurtcarrier = level.time; + attacker->client->pers.teamState.lasthurtcarrier = level.time;*/ } diff --git a/src/game/g_utils.c b/src/game/g_utils.c index dc960ab0..a72f57ad 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -540,10 +540,13 @@ void G_KillBox (gentity_t *ent) { for (i=0 ; i<num ; i++) { hit = &g_entities[touch[i]]; - if ( !hit->client ) { + if ( !hit->client ) continue; - } + //TA: impossible to telefrag self + if( ent == hit ) + continue; + // nail it G_Damage ( hit, ent, ent, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG); |