diff options
author | Tim Angus <tim@ngus.net> | 2005-08-31 03:15:00 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2005-08-31 03:15:00 +0000 |
commit | f40ad7c74f940dd0274cd0a82248a5a4e8846eac (patch) | |
tree | 1e045cd77b9fba27a2f967544df24bbd2f475885 | |
parent | 426a6d2269d5087ed6a83fe271f23e2e3b12d6f6 (diff) |
* Reimplemented how buildables play damage sounds to not use the event system
* Reworked the ammo/clips packing system to remove the confusion of concepts
* Marauder lightning now requires aim, does damage over time and chains to other entities
* Implemented the Medkit -- a means for a human to restore health and cure poison in the field
* "Disable Build Warnings" replaced with "Disable Warning Dialogs" and improved
* Disabled client side ET_MISSILE collision
* Sped spectator move speed up
* Implemented "step down" physics for all characters; no more jumping down stairs
* Re-adjusted step time values
* Increased frequency with which the Acid Tube deals damage
* G_RadiusSelectiveDamage no longer applies locational damage
* Moved some speed adjustment code into prediction; should prevent some prediction misses
* Tyrant can no longer charge up forever and must pass a specific minimum charge level
* Wrapped all calls to trap_SendServerCommand in order to circumvent the q3amsgboom.cfg exploit
* Implemented command queueing for commands sent to clients in order to prevent overflows even sv_floodProtect is off, but not by dropping commands
* Added LOS check to creep slowing
* Overmind now only complains if there are 0 spawns
* Spawns can no longer be built when there is no Overmind/Reactor
* The spawn closest to the point of death is chosen preferably if available
* Evolving no longer restores all health
* "give weapons" and "give ammo" cheats removed
* Fixed restoration of energy weapons bug
* When selling the battery pack, max ammo is given
* Fixed a bug where locational damage could sometimes scale damage to 0
* Added stage information to the end of game stats
* Hacked around trap_LinkEntity to allow missiles to have a bounding box displayed
* Added G_ClosestEnt
* Reduced Dragoon spitball damage from 120 to 110
* Reduced Tyrant claw damage from 120 to 100
* Reduced Tyrant charge damage from 160 to 110
* Increased Barricade regeneration rate from 12 to 14
* Increased Overmind health from 500 to 750
* Decreased Overmind regeneration rate from 10 to 6
* Doubled Blaster speed from 700 to 1400
* Reduced Painsaw damage from 18 to 15
* Reduced Painsaw range from 48.0 to 40.0
* Reduced Grenade price from 300 to 200
* Reduced Shotgun repeat rate from 1200 to 1000
* Increased Shotgun damage from 6 to 7
* Increased Mass driver damage from 35 to 38
* Increased Chaingun damage from 5 to 6
* Reduced Flamer repeat rate from 300 to 200
* Extended Flamer range
* Increased ammo on all human weapons
* Reduced splashdamage on MG Turrets
* Moved build directory from tremulous to tremulous-dev
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/cgame/cg_buildable.c | 28 | ||||
-rw-r--r-- | src/cgame/cg_draw.c | 16 | ||||
-rw-r--r-- | src/cgame/cg_ents.c | 64 | ||||
-rw-r--r-- | src/cgame/cg_event.c | 23 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 11 | ||||
-rw-r--r-- | src/cgame/cg_main.c | 8 | ||||
-rw-r--r-- | src/cgame/cg_predict.c | 2 | ||||
-rw-r--r-- | src/cgame/cg_servercmds.c | 217 | ||||
-rw-r--r-- | src/cgame/cg_weapons.c | 42 | ||||
-rw-r--r-- | src/game/bg_misc.c | 190 | ||||
-rw-r--r-- | src/game/bg_pmove.c | 110 | ||||
-rw-r--r-- | src/game/bg_public.h | 24 | ||||
-rw-r--r-- | src/game/bg_slidemove.c | 25 | ||||
-rw-r--r-- | src/game/g_active.c | 129 | ||||
-rw-r--r-- | src/game/g_buildable.c | 80 | ||||
-rw-r--r-- | src/game/g_client.c | 42 | ||||
-rw-r--r-- | src/game/g_cmds.c | 253 | ||||
-rw-r--r-- | src/game/g_combat.c | 41 | ||||
-rw-r--r-- | src/game/g_local.h | 68 | ||||
-rw-r--r-- | src/game/g_main.c | 77 | ||||
-rw-r--r-- | src/game/g_missile.c | 4 | ||||
-rw-r--r-- | src/game/g_svcmds.c | 4 | ||||
-rw-r--r-- | src/game/g_target.c | 4 | ||||
-rw-r--r-- | src/game/g_team.c | 4 | ||||
-rw-r--r-- | src/game/g_trigger.c | 6 | ||||
-rw-r--r-- | src/game/g_utils.c | 230 | ||||
-rw-r--r-- | src/game/g_weapon.c | 248 | ||||
-rw-r--r-- | src/game/tremulous.h | 70 | ||||
-rw-r--r-- | src/ui/ui_main.c | 1 | ||||
-rw-r--r-- | src/ui/ui_shared.c | 1 |
31 files changed, 1385 insertions, 639 deletions
@@ -8,7 +8,7 @@ # --Makefile variables-- MOUNT_DIR=./src Q3A_DIR=/home/tma/.q3a -MOD_DIR=tremulous +MOD_DIR=tremulous-dev # --object list-- GOBJ = \ diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c index 3b462dec..0c334e7b 100644 --- a/src/cgame/cg_buildable.c +++ b/src/cgame/cg_buildable.c @@ -925,6 +925,8 @@ static void CG_BuildableHealthBar( centity_t *cent ) } } +#define BUILDABLE_SOUND_PERIOD 500 + /* ================== CG_Buildable @@ -940,6 +942,8 @@ void CG_Buildable( centity_t *cent ) float rotAngle; buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex ); float scale; + int health; + float healthScale; //must be before EF_NODRAW check if( team == BIT_ALIENS ) @@ -1132,12 +1136,34 @@ void CG_Buildable( centity_t *cent ) if( weapon->wim[ WPM_PRIMARY ].firingSound ) { - trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->wim[ WPM_PRIMARY ].firingSound ); + trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, + weapon->wim[ WPM_PRIMARY ].firingSound ); } else if( weapon->readySound ) trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound ); } + health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT ); + healthScale = (float)health / B_HEALTH_SCALE; + + if( healthScale < cent->lastBuildableHealthScale && ( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) + { + if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time ) + { + if( team == BIT_HUMANS ) + { + int i = rand( ) % 4; + trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] ); + } + else if( team == BIT_ALIENS ) + trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage ); + + cent->lastBuildableDamageSoundTime = cg.time; + } + } + + cent->lastBuildableHealthScale = healthScale; + //smoke etc for damaged buildables CG_BuildableParticleEffects( cent ); } diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index f5fb5487..9cb1740c 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -896,7 +896,7 @@ static void CG_DrawPlayerPoisonBarbs( rectDef_t *rect, vec4_t color, qhandle_t s qboolean vertical; int iconsize, numBarbs, i; - BG_UnpackAmmoArray( ps->weapon, ps->ammo, ps->powerups, &numBarbs, NULL, NULL ); + BG_UnpackAmmoArray( ps->weapon, ps->ammo, ps->powerups, &numBarbs, NULL ); if( height > width ) { @@ -981,7 +981,7 @@ static void CG_DrawPlayerAmmoValue( rectDef_t *rect, vec4_t color ) break; default: - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &value, NULL, NULL ); + BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &value, NULL ); break; } @@ -1140,7 +1140,7 @@ static void CG_DrawPlayerClipsValue( rectDef_t *rect, vec4_t color ) break; default: - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, NULL, &value, NULL ); + BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, NULL, &value ); if( value > -1 ) { @@ -1433,7 +1433,7 @@ float CG_GetValue( int ownerDraw ) int value; BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, - &value, NULL, NULL ); + &value, NULL ); return value; } @@ -1444,7 +1444,7 @@ float CG_GetValue( int ownerDraw ) int value; BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, - NULL, &value, NULL ); + NULL, &value ); return value; } @@ -2309,15 +2309,15 @@ CG_DrawWeaponIcon */ void CG_DrawWeaponIcon( rectDef_t *rect, vec4_t color ) { - int ammo, clips, maxAmmo, maxClips; + int ammo, clips, maxAmmo; centity_t *cent; playerState_t *ps; cent = &cg_entities[ cg.snap->ps.clientNum ]; ps = &cg.snap->ps; - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &ammo, &clips, NULL ); - BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, &maxClips, NULL ); + BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &ammo, &clips ); + BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, NULL ); // don't display if dead if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c index 1ed6cb2e..df269155 100644 --- a/src/cgame/cg_ents.c +++ b/src/cgame/cg_ents.c @@ -758,6 +758,64 @@ static void CG_LightFlare( centity_t *cent ) /* ========================= +CG_Lev2ZapChain +========================= +*/ +static void CG_Lev2ZapChain( centity_t *cent ) +{ + int i = 0; + entityState_t *es; + vec3_t start, end; + centity_t *source, *target; + + es = ¢->currentState; + + if( es->time > 0 ) + { + source = &cg_entities[ es->powerups ]; + target = &cg_entities[ es->time ]; + + if( es->powerups == cg.predictedPlayerState.clientNum ) + VectorCopy( cg.predictedPlayerState.origin, start ); + else + VectorCopy( source->currentState.pos.trBase, start ); + + VectorCopy( target->currentState.pos.trBase, end ); + + CG_DynamicLightningBolt( cgs.media.lightningShader, start, end, + 1+((cg.time%((i+2)*(i+3)))+i)%2, 7 + (float)(i%3)*5 + 6.0*random(), + qtrue, 1.0, 0, i*i*3 ); + } + + if( es->time2 > 0 ) + { + source = &cg_entities[ es->time ]; + target = &cg_entities[ es->time2 ]; + + VectorCopy( source->currentState.pos.trBase, start ); + VectorCopy( target->currentState.pos.trBase, end ); + + CG_DynamicLightningBolt( cgs.media.lightningShader, start, end, + 1+((cg.time%((i+2)*(i+3)))+i)%2, 7 + (float)(i%3)*5 + 6.0*random(), + qtrue, 1.0, 0, i*i*3 ); + } + + if( es->constantLight > 0 ) + { + source = &cg_entities[ es->time2 ]; + target = &cg_entities[ es->constantLight ]; + + VectorCopy( source->currentState.pos.trBase, start ); + VectorCopy( target->currentState.pos.trBase, end ); + + CG_DynamicLightningBolt( cgs.media.lightningShader, start, end, + 1+((cg.time%((i+2)*(i+3)))+i)%2, 7 + (float)(i%3)*5 + 6.0*random(), + qtrue, 1.0, 0, i*i*3 ); + } +} + +/* +========================= CG_AdjustPositionForMover Also called by client movement prediction code @@ -1010,6 +1068,10 @@ static void CG_AddCEntity( centity_t *cent ) case ET_LIGHTFLARE: CG_LightFlare( cent ); break; + + case ET_LEV2_ZAP_CHAIN: + CG_Lev2ZapChain( cent ); + break; } } @@ -1122,7 +1184,7 @@ void CG_AddPacketEntities( void ) mins[ 2 ] = -zd; maxs[ 2 ] = zu; - CG_DrawBoundingBox( es->origin, mins, maxs ); + CG_DrawBoundingBox( cent->lerpOrigin, mins, maxs ); break; default: diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index 049cea33..4ac8f984 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -376,7 +376,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) const char *s; int clientNum; clientInfo_t *ci; - int steptime, i; + int steptime; if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) steptime = 200; @@ -767,28 +767,12 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) CG_AlienBuildableExplosion( position, dir ); break; - case EV_HUMAN_BUILDABLE_DAMAGE: - DEBUGNAME( "EV_HUMAN_BUILDABLE_DAMAGE" ); - i = rand( ) % 4; - trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] ); - break; - - case EV_ALIEN_BUILDABLE_DAMAGE: - DEBUGNAME( "EV_ALIEN_BUILDABLE_DAMAGE" ); - trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage ); - break; - case EV_TESLATRAIL: DEBUGNAME( "EV_TESLATRAIL" ); cent->currentState.weapon = WP_TESLAGEN; CG_TeslaTrail( es->origin2, es->pos.trBase, es->generic1, es->clientNum ); break; - case EV_ALIENZAP: - DEBUGNAME( "EV_ALIENZAP" ); - CG_AlienZap( es->origin2, es->pos.trBase, es->generic1, es->clientNum ); - break; - case EV_BULLET_HIT_WALL: DEBUGNAME( "EV_BULLET_HIT_WALL" ); ByteToDir( es->eventParm, dir ); @@ -955,6 +939,11 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) } break; + case EV_MEDKIT_USED: + DEBUGNAME( "EV_MEDKIT_USED" ); + trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound ); + break; + case EV_PLAYER_RESPAWN: DEBUGNAME( "EV_PLAYER_RESPAWN" ); if( es->number == cg.clientNum ) diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index 821972d9..d12e8001 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -479,6 +479,8 @@ typedef struct centity_s buildableAnimNumber_t buildableAnim; //persistant anim number buildableAnimNumber_t oldBuildableAnim; //to detect when new anims are set particleSystem_t *buildablePS; + float lastBuildableHealthScale; + int lastBuildableDamageSoundTime; lightFlareStatus_t lfs; @@ -1194,7 +1196,8 @@ typedef struct qhandle_t jetPackHoverPS; qhandle_t jetPackAscendPS; - //TA: + sfxHandle_t medkitUseSound; + sfxHandle_t alienStageTransition; sfxHandle_t humanStageTransition; @@ -1220,8 +1223,6 @@ typedef struct //TA: for wolf trail effects qhandle_t sparkFlareShader; - //TA: media used for armour switching stuff - //light armour qhandle_t larmourHeadSkin; qhandle_t larmourLegsSkin; @@ -1393,7 +1394,6 @@ extern vmCvar_t cg_debugAnim; extern vmCvar_t cg_debugPosition; extern vmCvar_t cg_debugEvents; extern vmCvar_t cg_teslaTrailTime; -extern vmCvar_t cg_alienZapTime; extern vmCvar_t cg_railTrailTime; extern vmCvar_t cg_errorDecay; extern vmCvar_t cg_nopredict; @@ -1467,7 +1467,7 @@ extern vmCvar_t cg_consoleLatency; extern vmCvar_t cg_lightFlare; extern vmCvar_t cg_debugParticles; extern vmCvar_t cg_debugPVS; -extern vmCvar_t cg_disableBuildWarnings; +extern vmCvar_t cg_disableWarningDialogs; extern vmCvar_t cg_disableScannerPlane; //TA: hack to get class an carriage through to UI module @@ -1663,7 +1663,6 @@ void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboole void CG_ShotgunFire( entityState_t *es ); void CG_TeslaTrail( vec3_t start, vec3_t end, int srcENum, int destENum ); -void CG_AlienZap( vec3_t start, vec3_t end, int srcENum, int destENum ); void CG_AddViewWeapon (playerState_t *ps); void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ); void CG_DrawItemSelect( rectDef_t *rect, vec4_t color ); diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index 056fd76f..8a657ab7 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -96,7 +96,6 @@ upgradeInfo_t cg_upgrades[ 32 ]; buildableInfo_t cg_buildables[ BA_NUM_BUILDABLES ]; vmCvar_t cg_teslaTrailTime; -vmCvar_t cg_alienZapTime; vmCvar_t cg_railTrailTime; vmCvar_t cg_centertime; vmCvar_t cg_runpitch; @@ -200,7 +199,7 @@ vmCvar_t cg_consoleLatency; vmCvar_t cg_lightFlare; vmCvar_t cg_debugParticles; vmCvar_t cg_debugPVS; -vmCvar_t cg_disableBuildWarnings; +vmCvar_t cg_disableWarningDialogs; vmCvar_t cg_disableScannerPlane; //TA: hack to get class and carriage through to UI module @@ -254,7 +253,6 @@ static cvarTable_t cvarTable[ ] = { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE }, { &cg_lagometer, "cg_lagometer", "0", CVAR_ARCHIVE }, { &cg_teslaTrailTime, "cg_teslaTrailTime", "600", CVAR_ARCHIVE }, - { &cg_alienZapTime, "cg_alienZapTime", "500", CVAR_ARCHIVE }, { &cg_railTrailTime, "cg_railTrailTime", "400", CVAR_ARCHIVE }, { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT }, { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT }, @@ -305,7 +303,7 @@ static cvarTable_t cvarTable[ ] = { &cg_lightFlare, "cg_lightFlare", "3", CVAR_ARCHIVE }, { &cg_debugParticles, "cg_debugParticles", "0", CVAR_CHEAT }, { &cg_debugPVS, "cg_debugPVS", "0", CVAR_CHEAT }, - { &cg_disableBuildWarnings, "cg_disableBuildWarnings", "0", CVAR_ARCHIVE }, + { &cg_disableWarningDialogs, "cg_disableWarningDialogs", "0", CVAR_ARCHIVE }, { &cg_disableScannerPlane, "cg_disableScannerPlane", "0", CVAR_ARCHIVE }, { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE}, @@ -680,6 +678,8 @@ static void CG_RegisterSounds( void ) cgs.media.jetpackDescendSound = trap_S_RegisterSound( "sound/upgrades/jetpack/low.wav", qfalse ); cgs.media.jetpackIdleSound = trap_S_RegisterSound( "sound/upgrades/jetpack/idle.wav", qfalse ); cgs.media.jetpackAscendSound = trap_S_RegisterSound( "sound/upgrades/jetpack/hi.wav", qfalse ); + + cgs.media.medkitUseSound = trap_S_RegisterSound( "sound/upgrades/medkit/medkit.wav", qfalse ); cgs.media.alienEvolveSound = trap_S_RegisterSound( "sound/player/alienevolve.wav", qfalse ); diff --git a/src/cgame/cg_predict.c b/src/cgame/cg_predict.c index 548efb86..d66fd653 100644 --- a/src/cgame/cg_predict.c +++ b/src/cgame/cg_predict.c @@ -63,7 +63,7 @@ void CG_BuildSolidList( void ) continue; } - if( cent->nextState.solid ) + if( cent->nextState.solid && ent->eType != ET_MISSILE ) { cg_solidEntities[ cg_numSolidEntities ] = cent; cg_numSolidEntities++; diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c index e529d1ab..90b74f8c 100644 --- a/src/cgame/cg_servercmds.c +++ b/src/cgame/cg_servercmds.c @@ -556,7 +556,8 @@ static void CG_SetUIVars( void ) } for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) { - if( BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) ) + if( BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) && + BG_FindPurchasableForUpgrade( i ) ) strcat( carriageCvar, va( "U%d ", i ) ); } strcat( carriageCvar, "$" ); @@ -598,107 +599,158 @@ void CG_Menu( int menu ) break; case MN_H_NOROOM: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "There is no room to build here. Move until the buildable turns " "translucent green indicating a valid build location." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "There is no room to build here\n" ); + break; case MN_H_NOPOWER: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "There is no power remaining. Free up power by destroying existing " "buildable objects." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "There is no power remaining\n" ); + break; case MN_H_NOTPOWERED: - trap_Cvar_Set( "ui_dialog", "This buildable is not powered. Build a reactor and/or repeater in " - "order to power it." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "This buildable is not powered. Build a Reactor and/or Repeater in " + "order to power it." ); + trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); + } + else + CG_Printf( "This buildable is not powered\n" ); + break; case MN_H_NORMAL: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "Cannot build on this surface. The surface is too steep or unsuitable " "to build on. Please choose another site for this structure." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "Cannot build on this surface\n" ); + break; case MN_H_REACTOR: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { - trap_Cvar_Set( "ui_dialog", "There can only be one reactor. Destroy the existing one if you " + trap_Cvar_Set( "ui_dialog", "There can only be one Reactor. Destroy the existing one if you " "wish to move it." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "There can only be one Reactor\n" ); + break; case MN_H_REPEATER: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "There is no power here. If available, a Repeater may be used to " "transmit power to this location." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "There is no power here\n" ); + break; case MN_H_NODCC: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "There is no Defense Computer. A Defense Computer is needed to build " "this." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "There is no Defense Computer\n" ); + break; case MN_H_TNODEWARN: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { - trap_Cvar_Set( "ui_dialog", "WARNING: This telenode will not be powered. Build near a power " + trap_Cvar_Set( "ui_dialog", "WARNING: This Telenode will not be powered. Build near a power " "structure to prevent seeing this message again." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "This Telenode will not be powered\n" ); + break; case MN_H_RPTWARN: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { - trap_Cvar_Set( "ui_dialog", "WARNING: This repeater will not be powered as there is no parent " - "reactor providing power. Build a reactor." ); + trap_Cvar_Set( "ui_dialog", "WARNING: This Repeater will not be powered as there is no parent " + "Reactor providing power. Build a Reactor." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "This Repeater will not be powered\n" ); + break; case MN_H_RPTWARN2: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { - trap_Cvar_Set( "ui_dialog", "This area already has power. A repeater is not required here." ); + trap_Cvar_Set( "ui_dialog", "This area already has power. A Repeater is not required here." ); trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); } + else + CG_Printf( "This area already has power\n" ); + break; case MN_H_NOSLOTS: - trap_Cvar_Set( "ui_dialog", "You have no room to carry this. Please sell any conflicting " - "upgrades before purchasing this item." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "You have no room to carry this. Please sell any conflicting " + "upgrades before purchasing this item." ); + trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); + } + else + CG_Printf( "You have no room to carry this\n" ); + break; case MN_H_NOFUNDS: - trap_Cvar_Set( "ui_dialog", "Insufficient funds. You do not have enough credits to perform this " - "action." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "Insufficient funds. You do not have enough credits to perform this " + "action." ); + trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); + } + else + CG_Printf( "Insufficient funds\n" ); + break; case MN_H_ITEMHELD: - trap_Cvar_Set( "ui_dialog", "You already hold this item. It is not possible to carry multiple items " - "of the same type." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "You already hold this item. It is not possible to carry multiple items " + "of the same type." ); + trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); + } + else + CG_Printf( "You already hold this item\n" ); + break; @@ -706,103 +758,160 @@ void CG_Menu( int menu ) case MN_A_NOROOM: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "There is no room to build here. Move until the structure turns " "translucent green indicating a valid build location." ); trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); } + else + CG_Printf( "There is no room to build here\n" ); + break; case MN_A_NOCREEP: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "There is no creep here. You must build near existing Eggs or " "the Overmind. Alien structures will not support themselves." ); trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); } + else + CG_Printf( "There is no creep here\n" ); + break; case MN_A_NOOVMND: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "There is no Overmind. An Overmind must be built to control " "the structure you tried to place" ); trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); } + else + CG_Printf( "There is no Overmind\n" ); + break; case MN_A_OVERMIND: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "There can only be one Overmind. Destroy the existing one if you " "wish to move it." ); trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); } + else + CG_Printf( "There can only be one Overmind\n" ); + break; case MN_A_NOASSERT: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { - trap_Cvar_Set( "ui_dialog", "The Overmind cannot control anymore structures. Destroy existing " + trap_Cvar_Set( "ui_dialog", "The Overmind cannot control any more structures. Destroy existing " "structures to build more." ); trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); } + else + CG_Printf( "The Overmind cannot control any more structures\n" ); + break; case MN_A_SPWNWARN: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "WARNING: This spawn will not be controlled by an Overmind. " "Build an Overmind to prevent seeing this message again." ); trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); } + else + CG_Printf( "This spawn will not be controlled by an Overmind\n" ); + break; case MN_A_NORMAL: - if( !cg_disableBuildWarnings.integer ) + if( !cg_disableWarningDialogs.integer ) { trap_Cvar_Set( "ui_dialog", "Cannot build on this surface. This surface is too steep or unsuitable " "to build on. Please choose another site for this structure." ); trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); } + else + CG_Printf( "Cannot build on this surface\n" ); + break; case MN_A_NOEROOM: - trap_Cvar_Set( "ui_dialog", "There is no room to evolve here. Move away from walls or other " - "nearby objects and try again." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "There is no room to evolve here. Move away from walls or other " + "nearby objects and try again." ); + trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + } + else + CG_Printf( "There is no room to evolve here\n" ); + break; case MN_A_TOOCLOSE: - trap_Cvar_Set( "ui_dialog", "This location is too close to the enemy to evolve. " - "Move away until you are no longer aware of the enemy's " - "presence and try again." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "This location is too close to the enemy to evolve. " + "Move away until you are no longer aware of the enemy's " + "presence and try again." ); + trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + } + else + CG_Printf( "This location is too close to the enemy to evolve\n" ); + break; case MN_A_NOOVMND_EVOLVE: - trap_Cvar_Set( "ui_dialog", "There is no Overmind. An Overmind must be built to allow " - "you to upgrade." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "There is no Overmind. An Overmind must be built to allow " + "you to upgrade." ); + trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + } + else + CG_Printf( "There is no Overmind\n" ); + break; case MN_A_HOVEL_OCCUPIED: - trap_Cvar_Set( "ui_dialog", "This Hovel is occupied by another builder. Please find or build " - "another." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "This Hovel is occupied by another builder. Please find or build " + "another." ); + trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + } + else + CG_Printf( "This Hovel is occupied by another builder\n" ); + break; case MN_A_HOVEL_BLOCKED: - trap_Cvar_Set( "ui_dialog", "The exit to this Hovel is currently blocked. Please wait until it " - "becomes clear then try again." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "The exit to this Hovel is currently blocked. Please wait until it " + "becomes clear then try again." ); + trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + } + else + CG_Printf( "The exit to this Hovel is currently blocked\n" ); + break; case MN_A_HOVEL_EXIT: - trap_Cvar_Set( "ui_dialog", "The exit to this Hovel will always be blocked. Please choose " - "a more suitable location." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + if( !cg_disableWarningDialogs.integer ) + { + trap_Cvar_Set( "ui_dialog", "The exit to this Hovel would always be blocked. Please choose " + "a more suitable location." ); + trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); + } + else + CG_Printf( "The exit to this Hovel would always be blocked\n" ); + break; case MN_A_INFEST: diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c index afd9bb45..c67eaa04 100644 --- a/src/cgame/cg_weapons.c +++ b/src/cgame/cg_weapons.c @@ -186,36 +186,6 @@ void CG_TeslaTrail( vec3_t start, vec3_t end, int srcENum, int destENum ) VectorCopy( end, re->oldorigin ); } -/* -========================== -CG_AlienZap -========================== -*/ -void CG_AlienZap( vec3_t start, vec3_t end, int srcENum, int destENum ) -{ - localEntity_t *le; - refEntity_t *re; - - //add a bunch of bolt segments - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - le->leType = LE_LIGHTNING_BOLT; - le->startTime = cg.time; - le->endTime = cg.time + cg_alienZapTime.value; - le->lifeRate = 1.0 / ( le->endTime - le->startTime ); - re->customShader = cgs.media.lightningShader; - - le->srcENum = srcENum; - le->destENum = destENum; - le->vOffset = 6.0f; - - le->maxRange = LEVEL2_AREAZAP_RANGE * M_ROOT3; - - VectorCopy( start, re->origin ); - VectorCopy( end, re->oldorigin ); -} - /* ================= @@ -1362,16 +1332,12 @@ void CG_DrawItemSelect( rectDef_t *rect, vec4_t color ) int length; int selectWindow; qboolean vertical; - int ammo, clips, maxAmmo, maxClips; centity_t *cent; playerState_t *ps; cent = &cg_entities[ cg.snap->ps.clientNum ]; ps = &cg.snap->ps; - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &ammo, &clips, NULL ); - BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, &maxClips, NULL ); - // don't display if dead if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) return; @@ -1504,13 +1470,13 @@ CG_WeaponSelectable */ static qboolean CG_WeaponSelectable( int i ) { - int ammo, clips, maxclips; + int ammo, clips; - BG_UnpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips, &maxclips ); + BG_UnpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips ); //TA: this is a pain in the ass -/* if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) ) - return qfalse;*/ + //if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) ) + // return qfalse; if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) ) return qfalse; diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c index 9922bf13..3c4134fd 100644 --- a/src/game/bg_misc.c +++ b/src/game/bg_misc.c @@ -153,7 +153,7 @@ buildableAttributes_t bg_buildableList[ ] = BIT_ALIENS, //int team; ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; BANIM_IDLE1, //int idleAnim; - 500, //int nextthink; + 200, //int nextthink; ACIDTUBE_BT, //int buildTime; qfalse, //qboolean usable; 0, //int turretRange; @@ -1475,7 +1475,7 @@ classAttributes_t bg_classList[ ] = 0.000f, //float bob; 1.0f, //float bobCycle; 350, //int steptime; - 100, //float speed; + 600, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; 6.0f, //float friction; @@ -1512,7 +1512,7 @@ classAttributes_t bg_classList[ ] = 80, //int fov; 0.001f, //float bob; 2.0f, //float bobCycle; - 200, //int steptime; + 150, //int steptime; ABUILDER_SPEED, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; @@ -1550,7 +1550,7 @@ classAttributes_t bg_classList[ ] = 110, //int fov; 0.001f, //float bob; 2.0f, //float bobCycle; - 200, //int steptime; + 100, //int steptime; ABUILDER_UPG_SPEED, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; @@ -1628,7 +1628,7 @@ classAttributes_t bg_classList[ ] = 120, //int fov; 0.001f, //float bob; 1.8f, //float bobCycle; - 25, //int steptime; + 60, //int steptime; LEVEL1_SPEED, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; @@ -1667,7 +1667,7 @@ classAttributes_t bg_classList[ ] = 120, //int fov; 0.001f, //float bob; 1.8f, //float bobCycle; - 25, //int steptime; + 60, //int steptime; LEVEL1_UPG_SPEED, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; @@ -1706,7 +1706,7 @@ classAttributes_t bg_classList[ ] = 90, //int fov; 0.001f, //float bob; 1.5f, //float bobCycle; - 60, //int steptime; + 80, //int steptime; LEVEL2_SPEED, //float speed; 10.0f, //float acceleration; 2.0f, //float airAcceleration; @@ -1745,7 +1745,7 @@ classAttributes_t bg_classList[ ] = 90, //int fov; 0.001f, //float bob; 1.5f, //float bobCycle; - 60, //int steptime; + 80, //int steptime; LEVEL2_UPG_SPEED, //float speed; 10.0f, //float acceleration; 2.0f, //float airAcceleration; @@ -1784,7 +1784,7 @@ classAttributes_t bg_classList[ ] = 110, //int fov; 0.0005f, //float bob; 1.3f, //float bobCycle; - 25, //int steptime; + 90, //int steptime; LEVEL3_SPEED, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; @@ -1823,7 +1823,7 @@ classAttributes_t bg_classList[ ] = 110, //int fov; 0.0005f, //float bob; 1.3f, //float bobCycle; - 25, //int steptime; + 90, //int steptime; LEVEL3_UPG_SPEED, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; @@ -1862,7 +1862,7 @@ classAttributes_t bg_classList[ ] = 90, //int fov; 0.001f, //float bob; 1.1f, //float bobCycle; - 60, //int steptime; + 100, //int steptime; LEVEL4_SPEED, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; @@ -1901,7 +1901,7 @@ classAttributes_t bg_classList[ ] = 90, //int fov; 0.002f, //float bob; 1.0f, //float bobCycle; - 200, //int steptime; + 100, //int steptime; 1.0f, //float speed; 10.0f, //float acceleration; 1.0f, //float airAcceleration; @@ -2952,8 +2952,7 @@ weaponAttributes_t bg_weapons[ ] = 0, //int slots; "blaster", //char *weaponName; "Blaster", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -2976,8 +2975,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "rifle", //char *weaponName; "Rifle", //char *weaponHumanName; - RIFLE_CLIPSIZE, //int quan; - RIFLE_SPAWNCLIPS, //int clips; + RIFLE_CLIPSIZE, //int maxAmmo; RIFLE_MAXCLIPS, //int maxClips; qfalse, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3000,8 +2998,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "shotgun", //char *weaponName; "Shotgun", //char *weaponHumanName; - SHOTGUN_SHELLS, //int quan; - SHOTGUN_SPAWNCLIPS, //int clips; + SHOTGUN_SHELLS, //int maxAmmo; SHOTGUN_MAXCLIPS, //int maxClips; qfalse, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3024,8 +3021,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "flamer", //char *weaponName; "Flame Thrower", //char *weaponHumanName; - FLAMER_GAS, //int quan; - 0, //int clips; + FLAMER_GAS, //int maxAmmo; 0, //int maxClips; qfalse, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3048,8 +3044,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "chaingun", //char *weaponName; "Chaingun", //char *weaponHumanName; - CHAINGUN_BULLETS, //int quan; - 0, //int clips; + CHAINGUN_BULLETS, //int maxAmmo; 0, //int maxClips; qfalse, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3072,8 +3067,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "mdriver", //char *weaponName; "Mass Driver", //char *weaponHumanName; - MDRIVER_CLIPSIZE, //int quan; - MDRIVER_SPAWNCLIPS, //int clips; + MDRIVER_CLIPSIZE, //int maxAmmo; MDRIVER_MAXCLIPS, //int maxClips; qfalse, //int infiniteAmmo; qtrue, //int usesEnergy; @@ -3096,8 +3090,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "prifle", //char *weaponName; "Pulse Rifle", //char *weaponHumanName; - PRIFLE_CLIPS, //int quan; - PRIFLE_SPAWNCLIPS, //int clips; + PRIFLE_CLIPS, //int maxAmmo; PRIFLE_MAXCLIPS, //int maxClips; qfalse, //int infiniteAmmo; qtrue, //int usesEnergy; @@ -3120,8 +3113,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "lcannon", //char *weaponName; "Lucifer Cannon", //char *weaponHumanName; - LCANNON_AMMO, //int quan; - 0, //int clips; + LCANNON_AMMO, //int maxAmmo; 0, //int maxClips; qfalse, //int infiniteAmmo; qtrue, //int usesEnergy; @@ -3144,8 +3136,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "lgun", //char *weaponName; "Las Gun", //char *weaponHumanName; - LASGUN_AMMO, //int quan; - 0, //int clips; + LASGUN_AMMO, //int maxAmmo; 0, //int maxClips; qfalse, //int infiniteAmmo; qtrue, //int usesEnergy; @@ -3168,8 +3159,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "psaw", //char *weaponName; "Pain Saw", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3192,8 +3182,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_NONE, //int slots; "grenade", //char *weaponName; "Grenade", //char *weaponHumanName; - 1, //int quan; - 0, //int clips; + 1, //int maxAmmo; 0, //int maxClips; qfalse, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3216,8 +3205,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "ckit", //char *weaponName; "Construction Kit", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3240,8 +3228,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "ackit", //char *weaponName; "Adv Construction Kit",//char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3264,8 +3251,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "abuild", //char *weaponName; "Alien build weapon", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3288,8 +3274,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "abuild2", //char *weaponName; "Alien build weapon2",//char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3312,8 +3297,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "bite", //char *weaponName; "Bite", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3336,8 +3320,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "pounce", //char *weaponName; "Claw and pounce", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3360,8 +3343,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "pounce_upgrade", //char *weaponName; "Claw and pounce (upgrade)", //char *weaponHumanName; - 3, //int quan; - 0, //int clips; + 3, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3384,8 +3366,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "grabandclaw", //char *weaponName; "Claws", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3408,8 +3389,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "grabandclaw_upgrade",//char *weaponName; "Claws Upgrade", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3432,8 +3412,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "areazap", //char *weaponName; "Area Zap", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3456,8 +3435,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "directzap", //char *weaponName; "Directed Zap", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3480,8 +3458,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "charge", //char *weaponName; "Charge", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3504,8 +3481,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "lockblob", //char *weaponName; "Lock Blob", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3528,8 +3504,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "hive", //char *weaponName; "Hive", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3552,8 +3527,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "mgturret", //char *weaponName; "Machinegun Turret", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; @@ -3576,8 +3550,7 @@ weaponAttributes_t bg_weapons[ ] = SLOT_WEAPON, //int slots; "teslagen", //char *weaponName; "Tesla Generator", //char *weaponHumanName; - 0, //int quan; - 0, //int clips; + 0, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qtrue, //int usesEnergy; @@ -3722,7 +3695,7 @@ char *BG_FindHumanNameForWeapon( int weapon ) BG_FindAmmoForWeapon ============== */ -void BG_FindAmmoForWeapon( int weapon, int *quan, int *clips, int *maxClips ) +void BG_FindAmmoForWeapon( int weapon, int *maxAmmo, int *maxClips ) { int i; @@ -3730,10 +3703,8 @@ void BG_FindAmmoForWeapon( int weapon, int *quan, int *clips, int *maxClips ) { if( bg_weapons[ i ].weaponNum == weapon ) { - if( quan != NULL ) - *quan = bg_weapons[ i ].quan; - if( clips != NULL ) - *clips = bg_weapons[ i ].clips; + if( maxAmmo != NULL ) + *maxAmmo = bg_weapons[ i ].maxAmmo; if( maxClips != NULL ) *maxClips = bg_weapons[ i ].maxClips; @@ -4009,6 +3980,7 @@ upgradeAttributes_t bg_upgrades[ ] = "larmour", //char *upgradeName; "Light Armour", //char *upgradeHumanName; "icons/iconu_larmour", + qtrue, //qboolean purchasable WUT_HUMANS //WUTeam_t team; }, { @@ -4019,16 +3991,18 @@ upgradeAttributes_t bg_upgrades[ ] = "helmet", //char *upgradeName; "Helmet", //char *upgradeHumanName; "icons/iconu_helmet", + qtrue, //qboolean purchasable WUT_HUMANS //WUTeam_t team; }, { - UP_ANTITOXIN, //int upgradeNum; - ANTITOXIN_PRICE, //int price; + UP_MEDKIT, //int upgradeNum; + MEDKIT_PRICE, //int price; ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages SLOT_NONE, //int slots; - "atoxin", //char *upgradeName; - "Anti-toxin", //char *upgradeHumanName; + "medkit", //char *upgradeName; + "Medkit", //char *upgradeHumanName; "icons/iconu_atoxin", + qfalse, //qboolean purchasable WUT_HUMANS //WUTeam_t team; }, { @@ -4039,6 +4013,7 @@ upgradeAttributes_t bg_upgrades[ ] = "battpack", //char *upgradeName; "Battery Pack", //char *upgradeHumanName; "icons/iconu_battpack", + qtrue, //qboolean purchasable WUT_HUMANS //WUTeam_t team; }, { @@ -4049,6 +4024,7 @@ upgradeAttributes_t bg_upgrades[ ] = "jetpack", //char *upgradeName; "Jet Pack", //char *upgradeHumanName; "icons/iconu_jetpack", + qtrue, //qboolean purchasable WUT_HUMANS //WUTeam_t team; }, { @@ -4059,6 +4035,7 @@ upgradeAttributes_t bg_upgrades[ ] = "bsuit", //char *upgradeName; "Battlesuit", //char *upgradeHumanName; "icons/iconu_bsuit", + qtrue, //qboolean purchasable WUT_HUMANS //WUTeam_t team; }, { @@ -4069,6 +4046,7 @@ upgradeAttributes_t bg_upgrades[ ] = "gren", //char *upgradeName; "Grenade", //char *upgradeHumanName; 0, + qtrue, //qboolean purchasable WUT_HUMANS //WUTeam_t team; }, { @@ -4079,6 +4057,7 @@ upgradeAttributes_t bg_upgrades[ ] = "ammo", //char *upgradeName; "Ammunition", //char *upgradeHumanName; 0, + qtrue, //qboolean purchasable WUT_HUMANS //WUTeam_t team; } }; @@ -4226,6 +4205,24 @@ char *BG_FindIconForUpgrade( int upgrade ) /* ============== +BG_FindPurchasableForUpgrade +============== +*/ +qboolean BG_FindPurchasableForUpgrade( int upgrade ) +{ + int i; + + for( i = 0; i < bg_numUpgrades; i++ ) + { + if( bg_upgrades[ i ].upgradeNum == upgrade ) + return bg_upgrades[ i ].purchasable; + } + + return qfalse; +} + +/* +============== BG_FindTeamForUpgrade ============== */ @@ -4420,7 +4417,6 @@ char *eventnames[ ] = "EV_MISSILE_MISS", "EV_MISSILE_MISS_METAL", "EV_TESLATRAIL", - "EV_ALIENZAP", "EV_BULLET", // otherEntity is the shooter "EV_LEV1_GRAB", @@ -4443,9 +4439,9 @@ char *eventnames[ ] = "EV_HUMAN_BUILDABLE_EXPLOSION", "EV_ALIEN_BUILDABLE_EXPLOSION", "EV_ALIEN_ACIDTUBE", - "EV_HUMAN_BUILDABLE_DAMAGE", - "EV_ALIEN_BUILDABLE_DAMAGE", + "EV_MEDKIT_USED", + "EV_ALIEN_EVOLVE", "EV_ALIEN_EVOLVE_FAILED", @@ -4751,25 +4747,22 @@ BG_UnpackAmmoArray Extract the ammo quantity from the array ======================== */ -void BG_UnpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips ) +void BG_UnpackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int *ammo, int *clips ) { - int ammoarray[32]; + int ammoarray[ 32 ]; int i; for( i = 0; i <= 15; i++ ) - ammoarray[ i ] = ammo[ i ]; + ammoarray[ i ] = psAmmo[ i ]; for( i = 16; i <= 31; i++ ) - ammoarray[ i ] = ammo2[ i - 16 ]; + ammoarray[ i ] = psAmmo2[ i - 16 ]; - if( quan != NULL ) - *quan = ammoarray[ weapon ] & 0x03FF; + if( ammo != NULL ) + *ammo = ammoarray[ weapon ] & 0x0FFF; if( clips != NULL ) - *clips = ( ammoarray[ weapon ] >> 10 ) & 0x07; - - if( maxclips != NULL ) - *maxclips = ( ammoarray[ weapon ] >> 13 ) & 0x07; + *clips = ( ammoarray[ weapon ] >> 12 ) & 0x0F; } /* @@ -4779,16 +4772,16 @@ BG_PackAmmoArray Pack the ammo quantity into the array ======================== */ -void BG_PackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips ) +void BG_PackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int ammo, int clips ) { int weaponvalue; - weaponvalue = quan | ( clips << 10 ) | ( maxclips << 13 ); + weaponvalue = ammo | ( clips << 12 ); if( weapon <= 15 ) - ammo[ weapon ] = weaponvalue; + psAmmo[ weapon ] = weaponvalue; else if( weapon >= 16 ) - ammo2[ weapon - 16 ] = weaponvalue; + psAmmo2[ weapon - 16 ] = weaponvalue; } /* @@ -4798,15 +4791,18 @@ BG_WeaponIsFull Check if a weapon has full ammo ======================== */ -qboolean BG_WeaponIsFull( weapon_t weapon, int ammo[ ], int ammo2[ ] ) +qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int psAmmo[ ], int psAmmo2[ ] ) { int maxAmmo, maxClips; - int quan, clips; + int ammo, clips; - BG_FindAmmoForWeapon( weapon, &maxAmmo, NULL, &maxClips ); - BG_UnpackAmmoArray( weapon, ammo, ammo2, &quan, &clips, NULL ); + BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); + BG_UnpackAmmoArray( weapon, psAmmo, psAmmo2, &ammo, &clips ); - return ( maxAmmo == quan ) && ( maxClips == clips ); + if( BG_InventoryContainsUpgrade( UP_BATTPACK, stats ) ) + maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); + + return ( maxAmmo == ammo ) && ( maxClips == clips ); } /* diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c index b28366be..e349958d 100644 --- a/src/game/bg_pmove.c +++ b/src/game/bg_pmove.c @@ -385,6 +385,15 @@ static float PM_CmdScale( usercmd_t *cmd ) modifier *= ( 1.0f + ( pm->ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME ) * ( LEVEL4_CHARGE_SPEED - 1.0f ) ); + //slow player if charging up for a pounce + if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) && + cmd->buttons & BUTTON_ATTACK2 ) + modifier *= LEVEL3_POUNCE_SPEED_MOD; + + //slow the player if slow locked + if( pm->ps->stats[ STAT_STATE ] & SS_SLOWLOCKED ) + modifier *= ABUILDER_BLOB_SPEED_MOD; + if( pm->ps->pm_type == PM_GRABBED ) modifier = 0.0f; @@ -469,7 +478,8 @@ static void PM_CheckCharge( void ) if( pm->ps->weapon != WP_ALEVEL4 ) return; - if( pm->cmd.buttons & BUTTON_ATTACK2 ) + if( pm->cmd.buttons & BUTTON_ATTACK2 && + !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) ) { pm->ps->pm_flags &= ~PMF_CHARGE; return; @@ -2046,43 +2056,66 @@ static void PM_GroundTrace( void ) // if the trace didn't hit anything, we are in free fall if( trace.fraction == 1.0f ) { - PM_GroundTraceMissed( ); - pml.groundPlane = qfalse; - pml.walking = qfalse; - - if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) + qboolean steppedDown = qfalse; + + // try to step down + if( pml.groundPlane != qfalse && PM_PredictStepMove( ) ) { - ProjectPointOnPlane( movedir, pml.forward, refNormal ); - VectorNormalize( movedir ); - - if( pm->cmd.forwardmove < 0 ) - VectorNegate( movedir, movedir ); + //step down + point[ 0 ] = pm->ps->origin[ 0 ]; + point[ 1 ] = pm->ps->origin[ 1 ]; + point[ 2 ] = pm->ps->origin[ 2 ] - STEPSIZE; + pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - //allow strafe transitions - if( pm->cmd.rightmove ) + //if we hit something + if( trace.fraction < 1.0f ) { - VectorCopy( pml.right, movedir ); - - if( pm->cmd.rightmove < 0 ) - VectorNegate( movedir, movedir ); + PM_StepEvent( pm->ps->origin, trace.endpos, refNormal ); + VectorCopy( trace.endpos, pm->ps->origin ); + steppedDown = qtrue; } - - //trace into direction we are moving - VectorMA( pm->ps->origin, 0.25f, movedir, point ); - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - - if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) && - ( trace.entityNum == ENTITYNUM_WORLD ) ) + } + + if( !steppedDown ) + { + PM_GroundTraceMissed( ); + pml.groundPlane = qfalse; + pml.walking = qfalse; + + if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) { - if( !VectorCompare( trace.plane.normal, pm->ps->grapplePoint ) ) + ProjectPointOnPlane( movedir, pml.forward, refNormal ); + VectorNormalize( movedir ); + + if( pm->cmd.forwardmove < 0 ) + VectorNegate( movedir, movedir ); + + //allow strafe transitions + if( pm->cmd.rightmove ) + { + VectorCopy( pml.right, movedir ); + + if( pm->cmd.rightmove < 0 ) + VectorNegate( movedir, movedir ); + } + + //trace into direction we are moving + VectorMA( pm->ps->origin, 0.25f, movedir, point ); + pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); + + if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) && + ( trace.entityNum == ENTITYNUM_WORLD ) ) { - VectorCopy( trace.plane.normal, pm->ps->grapplePoint ); - PM_CheckWallJump( ); + if( !VectorCompare( trace.plane.normal, pm->ps->grapplePoint ) ) + { + VectorCopy( trace.plane.normal, pm->ps->grapplePoint ); + PM_CheckWallJump( ); + } } } + + return; } - - return; } // check if getting thrown off the ground @@ -2619,7 +2652,7 @@ Generates weapon events and modifes the weapon counter static void PM_Weapon( void ) { int addTime = 200; //default addTime - should never be used - int ammo, clips, maxclips; + int ammo, clips, maxClips; qboolean attack1 = qfalse; qboolean attack2 = qfalse; qboolean attack3 = qfalse; @@ -2717,7 +2750,8 @@ static void PM_Weapon( void ) // start the animation even if out of ammo - BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips, &maxclips ); + BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips ); + BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips ); // check for out of ammo if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) @@ -2730,17 +2764,17 @@ static void PM_Weapon( void ) //done reloading so give em some ammo if( pm->ps->weaponstate == WEAPON_RELOADING ) { - if( maxclips > 0 ) + if( maxClips > 0 ) { clips--; - BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL, NULL ); + BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL ); } if( BG_FindUsesEnergyForWeapon( pm->ps->weapon ) && BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) ) ammo = (int)( (float)ammo * BATTPACK_MODIFIER ); - BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips ); + BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); //allow some time for the weapon to be raised pm->ps->weaponstate = WEAPON_RAISING; @@ -2967,13 +3001,13 @@ static void PM_Weapon( void ) else ammo--; - BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips ); + BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); } else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 ) { //special case for slowblob ammo--; - BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips ); + BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); } //FIXME: predicted angles miss a problem?? @@ -3175,11 +3209,11 @@ void trap_SnapVector( float *v ); void PmoveSingle( pmove_t *pmove ) { - int ammo, clips, maxclips; + int ammo, clips; pm = pmove; - BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips, &maxclips ); + BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips ); // this counter lets us debug movement problems with a journal // by setting a conditional breakpoint fot the previous frame diff --git a/src/game/bg_public.h b/src/game/bg_public.h index c2b3805f..1104dccb 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -233,6 +233,8 @@ typedef enum #define SS_BOOSTED 0x00000200 #define SS_SLOWLOCKED 0x00000400 #define SS_POISONCLOUDED 0x00000800 +#define SS_MEDKIT_ACTIVE 0x00001000 +#define SS_CHARGING 0x00002000 #define SB_VALID_TOGGLEBIT 0x00004000 @@ -369,7 +371,7 @@ typedef enum UP_LIGHTARMOUR, UP_HELMET, - UP_ANTITOXIN, + UP_MEDKIT, UP_BATTPACK, UP_JETPACK, UP_BATTLESUIT, @@ -527,7 +529,6 @@ typedef enum EV_MISSILE_MISS, EV_MISSILE_MISS_METAL, EV_TESLATRAIL, - EV_ALIENZAP, EV_BULLET, // otherEntity is the shooter EV_LEV1_GRAB, @@ -550,8 +551,8 @@ typedef enum EV_HUMAN_BUILDABLE_EXPLOSION, EV_ALIEN_BUILDABLE_EXPLOSION, EV_ALIEN_ACIDTUBE, - EV_HUMAN_BUILDABLE_DAMAGE, - EV_ALIEN_BUILDABLE_DAMAGE, + + EV_MEDKIT_USED, EV_ALIEN_EVOLVE, EV_ALIEN_EVOLVE_FAILED, @@ -1031,8 +1032,7 @@ typedef struct char *weaponName; char *weaponHumanName; - int quan; - int clips; + int maxAmmo; int maxClips; qboolean infiniteAmmo; qboolean usesEnergy; @@ -1070,14 +1070,16 @@ typedef struct char *icon; + qboolean purchasable; + WUTeam_t team; } upgradeAttributes_t; //TA: -void BG_UnpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips ); -void BG_PackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips ); -qboolean BG_WeaponIsFull( weapon_t weapon, int ammo[ ], int ammo2[ ] ); +void BG_UnpackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int *ammo, int *clips ); +void BG_PackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int ammo, int clips ); +qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int psAmmo[ ], int psAmmo2[ ] ); void BG_AddWeaponToInventory( int weapon, int stats[ ] ); void BG_RemoveWeaponFromInventory( int weapon, int stats[ ] ); qboolean BG_InventoryContainsWeapon( int weapon, int stats[ ] ); @@ -1175,7 +1177,7 @@ char *BG_FindModelsForWeapon( int weapon, int modelNum ); char *BG_FindIconForWeapon( int weapon ); char *BG_FindCrosshairForWeapon( int weapon ); int BG_FindCrosshairSizeForWeapon( int weapon ); -void BG_FindAmmoForWeapon( int weapon, int *quan, int *clips, int *maxClips ); +void BG_FindAmmoForWeapon( int weapon, int *maxAmmo, int *maxClips ); qboolean BG_FindInfinteAmmoForWeapon( int weapon ); qboolean BG_FindUsesEnergyForWeapon( int weapon ); int BG_FindRepeatRate1ForWeapon( int weapon ); @@ -1197,6 +1199,7 @@ char *BG_FindNameForUpgrade( int upgrade ); int BG_FindUpgradeNumForName( char *name ); char *BG_FindHumanNameForUpgrade( int upgrade ); char *BG_FindIconForUpgrade( int upgrade ); +qboolean BG_FindPurchasableForUpgrade( int upgrade ); WUTeam_t BG_FindTeamForUpgrade( int upgrade ); // content masks @@ -1235,6 +1238,7 @@ typedef enum ET_ANIMMAPOBJ, ET_MODELDOOR, ET_LIGHTFLARE, + ET_LEV2_ZAP_CHAIN, ET_EVENTS // any of the EV_* events can be added freestanding // by setting eType to ET_EVENTS + eventNum diff --git a/src/game/bg_slidemove.c b/src/game/bg_slidemove.c index e4f7f6c5..2ddd952b 100644 --- a/src/game/bg_slidemove.c +++ b/src/game/bg_slidemove.c @@ -305,21 +305,18 @@ qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive ) if( PM_SlideMove( gravity ) == 0 ) { - if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - VectorCopy( start_o, down ); - VectorMA( down, -STEPSIZE, normal, down ); - pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask ); + VectorCopy( start_o, down ); + VectorMA( down, -STEPSIZE, normal, down ); + pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask ); - //we can step down - if( trace.fraction > 0.01f && trace.fraction < 1.0f && - !trace.allsolid && pml.groundPlane != qfalse ) - { - if( pm->debugLevel ) - Com_Printf( "%d: step down\n", c_pmove ); - - stepped = qtrue; - } + //we can step down + if( trace.fraction > 0.01f && trace.fraction < 1.0f && + !trace.allsolid && pml.groundPlane != qfalse ) + { + if( pm->debugLevel ) + Com_Printf( "%d: step down\n", c_pmove ); + + stepped = qtrue; } } else diff --git a/src/game/g_active.c b/src/game/g_active.c index e3f09d69..581069cc 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -334,7 +334,7 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) else client->ps.pm_type = PM_SPECTATOR; - client->ps.speed = 400; // faster than normal + client->ps.speed = BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] ); client->ps.stats[ STAT_STAMINA ] = 0; client->ps.stats[ STAT_MISC ] = 0; @@ -440,7 +440,7 @@ qboolean ClientInactivityTimer( gclient_t *client ) if( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) { client->inactivityWarning = qtrue; - trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" ); + G_SendCommandFromServer( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" ); } } @@ -542,23 +542,30 @@ void ClientTimerActions( gentity_t *ent, int msec ) if( client->ps.weapon == WP_ALEVEL4 ) { if( client->ps.stats[ STAT_MISC ] < LEVEL4_CHARGE_TIME && ucmd->buttons & BUTTON_ATTACK2 && - ( ucmd->forwardmove > 0 ) && !client->charging ) + !client->charging ) { client->charging = qfalse; //should already be off, just making sure + client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING; - //trigger charge sound - if( client->ps.stats[ STAT_MISC ] <= 0 ) - G_AddEvent( ent, EV_LEV4_CHARGE_PREPARE, 0 ); - - client->ps.stats[ STAT_MISC ] += (int)( 100 * (float)LEVEL4_CHARGE_CHARGE_RATIO ); - - if( client->ps.stats[ STAT_MISC ] > LEVEL4_CHARGE_TIME ) - client->ps.stats[ STAT_MISC ] = LEVEL4_CHARGE_TIME; + if( ucmd->forwardmove > 0 ) + { + //trigger charge sound...is quite annoying + //if( client->ps.stats[ STAT_MISC ] <= 0 ) + // G_AddEvent( ent, EV_LEV4_CHARGE_PREPARE, 0 ); + + client->ps.stats[ STAT_MISC ] += (int)( 100 * (float)LEVEL4_CHARGE_CHARGE_RATIO ); + + if( client->ps.stats[ STAT_MISC ] > LEVEL4_CHARGE_TIME ) + client->ps.stats[ STAT_MISC ] = LEVEL4_CHARGE_TIME; + } + else + client->ps.stats[ STAT_MISC ] = 0; } - if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging ) + if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging || + client->ps.stats[ STAT_MISC ] == LEVEL4_CHARGE_TIME ) { - if( client->ps.stats[ STAT_MISC ] > 0 ) + if( client->ps.stats[ STAT_MISC ] > LEVEL4_MIN_CHARGE_TIME ) { client->ps.stats[ STAT_MISC ] -= 100; @@ -566,20 +573,25 @@ void ClientTimerActions( gentity_t *ent, int msec ) G_AddEvent( ent, EV_LEV4_CHARGE_START, 0 ); client->charging = qtrue; + client->ps.stats[ STAT_STATE ] |= SS_CHARGING; //if the charger has stopped moving take a chunk of charge away if( VectorLength( client->ps.velocity ) < 64.0f || aRight ) - client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] >> 1; + client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] / 2; //can't charge backwards if( ucmd->forwardmove < 0 ) client->ps.stats[ STAT_MISC ] = 0; } + else + client->ps.stats[ STAT_MISC ] = 0; + if( client->ps.stats[ STAT_MISC ] <= 0 ) { client->ps.stats[ STAT_MISC ] = 0; client->charging = qfalse; + client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING; } } } @@ -589,7 +601,7 @@ void ClientTimerActions( gentity_t *ent, int msec ) { int ammo; - BG_UnpackAmmoArray( WP_LUCIFER_CANNON, client->ps.ammo, client->ps.powerups, &ammo, NULL, NULL ); + BG_UnpackAmmoArray( WP_LUCIFER_CANNON, client->ps.ammo, client->ps.powerups, &ammo, NULL ); if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE && ucmd->buttons & BUTTON_ATTACK ) client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE; @@ -631,6 +643,43 @@ void ClientTimerActions( gentity_t *ent, int msec ) default: break; } + + if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE ) + { + int remainingStartupTime = MEDKIT_STARTUP_TIME - ( level.time - client->lastMedKitTime ); + + if( remainingStartupTime < 0 ) + { + if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] && + ent->client->medKitHealthToRestore && + ent->client->ps.pm_type != PM_DEAD ) + { + ent->client->medKitHealthToRestore--; + ent->health++; + } + else + ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE; + } + else + { + if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] && + ent->client->medKitHealthToRestore && + ent->client->ps.pm_type != PM_DEAD ) + { + //partial increase + if( level.time > client->medKitIncrementTime ) + { + ent->client->medKitHealthToRestore--; + ent->health++; + + client->medKitIncrementTime = level.time + + ( remainingStartupTime / MEDKIT_STARTUP_SPEED ); + } + } + else + ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE; + } + } } while( client->time1000 >= 1000 ) @@ -697,7 +746,7 @@ void ClientTimerActions( gentity_t *ent, int msec ) } if( ent->health < client->ps.stats[ STAT_MAX_HEALTH ] && - ( client->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) + ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) ent->health += BG_FindRegenRateForClass( client->ps.stats[ STAT_PCLASS ] ) * modifier; if( ent->health > client->ps.stats[ STAT_MAX_HEALTH ] ) @@ -713,13 +762,13 @@ void ClientTimerActions( gentity_t *ent, int msec ) { int ammo, maxAmmo; - BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL, NULL ); - BG_UnpackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, &ammo, NULL, NULL ); + BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL ); + BG_UnpackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, &ammo, NULL ); if( ammo < maxAmmo ) { ammo++; - BG_PackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, ammo, 0, 0 ); + BG_PackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, ammo, 0 ); } } } @@ -833,14 +882,14 @@ void ClientEvents( gentity_t *ent, int oldEventSequence ) if( BG_InventoryContainsWeapon( j, ent->client->ps.stats ) ) { - trap_SendServerCommand( ent - g_entities, va( "weaponswitch %d", j ) ); + G_SendCommandFromServer( ent - g_entities, va( "weaponswitch %d", j ) ); break; } } //only got the blaster to switch to if( j == WP_NUM_WEAPONS ) - trap_SendServerCommand( ent - g_entities, va( "weaponswitch %d", WP_BLASTER ) ); + G_SendCommandFromServer( ent - g_entities, va( "weaponswitch %d", WP_BLASTER ) ); //update ClientInfo ClientUserinfoChanged( ent->client->ps.clientNum ); @@ -1022,16 +1071,33 @@ void ClientThink_real( gentity_t *ent ) client->ps.gravity = g_gravity.value; - if( BG_InventoryContainsUpgrade( UP_ANTITOXIN, client->ps.stats ) && - BG_UpgradeIsActive( UP_ANTITOXIN, client->ps.stats ) ) + if( BG_InventoryContainsUpgrade( UP_MEDKIT, client->ps.stats ) && + BG_UpgradeIsActive( UP_MEDKIT, client->ps.stats ) ) { - if( client->ps.stats[ STAT_STATE ] & SS_POISONED ) + //if currently using a medkit or have no need for a medkit now + if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE || + ( client->ps.stats[ STAT_HEALTH ] == client->ps.stats[ STAT_MAX_HEALTH ] && + !( client->ps.stats[ STAT_STATE ] & SS_POISONED ) ) ) + { + BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats ); + } + else { //remove anti toxin - BG_DeactivateUpgrade( UP_ANTITOXIN, client->ps.stats ); - BG_RemoveUpgradeFromInventory( UP_ANTITOXIN, client->ps.stats ); + BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats ); + BG_RemoveUpgradeFromInventory( UP_MEDKIT, client->ps.stats ); client->ps.stats[ STAT_STATE ] &= ~SS_POISONED; + client->poisonImmunityTime = level.time + MEDKIT_POISON_IMMUNITY_TIME; + + client->ps.stats[ STAT_STATE ] |= SS_MEDKIT_ACTIVE; + client->lastMedKitTime = level.time; + client->medKitHealthToRestore = + client->ps.stats[ STAT_MAX_HEALTH ] - client->ps.stats[ STAT_HEALTH ]; + client->medKitIncrementTime = level.time + + ( MEDKIT_STARTUP_TIME / MEDKIT_STARTUP_SPEED ); + + G_AddEvent( ent, EV_MEDKIT_USED, 0 ); } } @@ -1053,15 +1119,6 @@ void ClientThink_real( gentity_t *ent ) // set speed client->ps.speed = g_speed.value * BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] ); - //TA: slow player if charging up for a pounce - if( ( client->ps.weapon == WP_ALEVEL3 || client->ps.weapon == WP_ALEVEL3_UPG ) && - ucmd->buttons & BUTTON_ATTACK2 ) - client->ps.speed *= LEVEL3_POUNCE_SPEED_MOD; - - //TA: slow the player if slow locked - if( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED ) - client->ps.speed *= ABUILDER_BLOB_SPEED_MOD; - if( client->lastCreepSlowTime + CREEP_TIMEOUT < level.time ) client->ps.stats[ STAT_STATE ] &= ~SS_CREEPSLOWED; @@ -1069,7 +1126,7 @@ void ClientThink_real( gentity_t *ent ) if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) { - if( client->lastDamageTime + JETPACK_DISABLE_TIME > level.time ) + if( ent->lastDamageTime + JETPACK_DISABLE_TIME > level.time ) { if( random( ) > JETPACK_DISABLE_CHANCE ) client->ps.pm_type = PM_NORMAL; diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index 47815cb5..21a3d059 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -319,7 +319,7 @@ static qboolean findOvermind( gentity_t *self ) continue; //if entity is an overmind calculate the distance to it - if( ent->s.modelindex == BA_A_OVERMIND && ent->spawned ) + if( ent->s.modelindex == BA_A_OVERMIND && ent->spawned && ent->health > 0 ) { self->overmindNode = ent; return qtrue; @@ -424,19 +424,20 @@ creepSlow Set any nearby humans' SS_CREEPSLOWED flag ================ */ -static void creepSlow( buildable_t buildable, vec3_t origin ) +static void creepSlow( gentity_t *self ) { - int entityList[ MAX_GENTITIES ]; - vec3_t range; - vec3_t mins, maxs; - int i, num; - gentity_t *enemy; - float creepSize = (float)BG_FindCreepSizeForBuildable( buildable ); + int entityList[ MAX_GENTITIES ]; + vec3_t range; + vec3_t mins, maxs; + int i, num; + gentity_t *enemy; + buildable_t buildable = self->s.modelindex; + float creepSize = (float)BG_FindCreepSizeForBuildable( buildable ); VectorSet( range, creepSize, creepSize, creepSize ); - VectorAdd( origin, range, maxs ); - VectorSubtract( origin, range, mins ); + VectorAdd( self->s.origin, range, maxs ); + VectorSubtract( self->s.origin, range, mins ); //find humans num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); @@ -445,7 +446,8 @@ static void creepSlow( buildable_t buildable, vec3_t origin ) enemy = &g_entities[ entityList[ i ] ]; if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS && - enemy->client->ps.groundEntityNum != ENTITYNUM_NONE ) + enemy->client->ps.groundEntityNum != ENTITYNUM_NONE && + G_Visible( self, enemy ) ) { enemy->client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED; enemy->client->lastCreepSlowTime = level.time; @@ -642,7 +644,7 @@ void ASpawn_Think( gentity_t *self ) } } - creepSlow( self->s.modelindex, self->s.origin ); + creepSlow( self ); self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); } @@ -709,7 +711,7 @@ void AOvermind_Think( gentity_t *self ) } //low on spawns - if( level.numAlienSpawns <= 1 && level.time > self->overmindSpawnsTimer ) + if( level.numAlienSpawns <= 0 && level.time > self->overmindSpawnsTimer ) { self->overmindSpawnsTimer = level.time + OVERMIND_SPAWNS_PERIOD; G_BroadcastEvent( EV_OVERMIND_SPAWNS, 0 ); @@ -731,8 +733,10 @@ void AOvermind_Think( gentity_t *self ) self->lastHealth = self->health; } + else + self->overmindSpawnsTimer = level.time + OVERMIND_SPAWNS_PERIOD; - creepSlow( self->s.modelindex, self->s.origin ); + creepSlow( self ); self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); } @@ -829,7 +833,7 @@ void ABarricade_Think( gentity_t *self ) return; } - creepSlow( self->s.modelindex, self->s.origin ); + creepSlow( self ); self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); } @@ -874,7 +878,7 @@ void AAcidTube_Damage( gentity_t *self ) self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS ); } - creepSlow( self->s.modelindex, self->s.origin ); + creepSlow( self ); self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); } @@ -926,7 +930,7 @@ void AAcidTube_Think( gentity_t *self ) } } - creepSlow( self->s.modelindex, self->s.origin ); + creepSlow( self ); self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); } @@ -1002,7 +1006,7 @@ void AHive_Think( gentity_t *self ) } } - creepSlow( self->s.modelindex, self->s.origin ); + creepSlow( self ); } @@ -1166,7 +1170,7 @@ void AHovel_Think( gentity_t *self ) G_setIdleBuildableAnim( self, BANIM_IDLE1 ); } - creepSlow( self->s.modelindex, self->s.origin ); + creepSlow( self ); self->nextthink = level.time + 200; } @@ -1242,7 +1246,7 @@ Called when an alien touches a booster */ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace ) { - int ammo, clips, maxClips; + int maxAmmo, maxClips; gclient_t *client = other->client; if( !self->spawned ) @@ -1262,8 +1266,8 @@ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace ) return; //restore ammo, if any - BG_FindAmmoForWeapon( client->ps.weapon, &ammo, &clips, &maxClips ); - BG_PackAmmoArray( client->ps.weapon, client->ps.ammo, client->ps.powerups, ammo, clips, maxClips ); + BG_FindAmmoForWeapon( client->ps.weapon, &maxAmmo, &maxClips ); + BG_PackAmmoArray( client->ps.weapon, client->ps.ammo, client->ps.powerups, maxAmmo, maxClips ); if( !( client->ps.stats[ STAT_STATE ] & SS_BOOSTED ) ) { @@ -1418,7 +1422,7 @@ void ATrapper_Think( gentity_t *self ) int range = BG_FindRangeForBuildable( self->s.modelindex ); int firespeed = BG_FindFireSpeedForBuildable( self->s.modelindex ); - creepSlow( self->s.modelindex, self->s.origin ); + creepSlow( self ); self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); @@ -1520,14 +1524,14 @@ void HRpt_Use( gentity_t *self, gentity_t *other, gentity_t *activator ) if( !BG_FindUsesEnergyForWeapon( weapon ) ) return; - if( !BG_WeaponIsFull( weapon, ps->ammo, ps->powerups ) ) + if( !BG_WeaponIsFull( weapon, ps->stats, ps->ammo, ps->powerups ) ) { - BG_FindAmmoForWeapon( weapon, &maxAmmo, NULL, &maxClips ); + BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); if( BG_InventoryContainsUpgrade( UP_BATTPACK, ps->stats ) ) maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); - BG_PackAmmoArray( weapon, ps->ammo, ps->powerups, maxAmmo, maxClips, maxClips ); + BG_PackAmmoArray( weapon, ps->ammo, ps->powerups, maxAmmo, maxClips ); G_AddEvent( activator, EV_RPTUSE_SOUND, 0 ); activator->client->lastRefilTime = level.time; @@ -1737,6 +1741,8 @@ void HMedistat_Think( gentity_t *self ) self->active = qtrue; } } + else if( !BG_InventoryContainsUpgrade( UP_MEDKIT, player->client->ps.stats ) ) + BG_AddUpgradeToInventory( UP_MEDKIT, player->client->ps.stats ); } } } @@ -1754,7 +1760,15 @@ void HMedistat_Think( gentity_t *self ) if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_POISONED ) self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED; + if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE ) + self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE; + self->enemy->health++; + + //if they're completely healed, give them a medkit + if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] && + !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) ) + BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats ); } } } @@ -2347,7 +2361,8 @@ void G_BuildableThink( gentity_t *ent, int msec ) if( !ent->spawned ) ent->health += (int)( ceil( (float)bHealth / (float)( bTime * 0.001 ) ) ); - else if( ent->health > 0 && ent->health < bHealth && bRegen ) + else if( ent->biteam == BIT_ALIENS && ent->health > 0 && ent->health < bHealth && + bRegen && ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) ent->health += bRegen; if( ent->health > bHealth ) @@ -2498,12 +2513,7 @@ itemBuildError_t G_itemFits( gentity_t *ent, buildable_t buildable, int distance //if none found... if( i >= level.num_entities && buildable != BA_A_OVERMIND ) - { - if( buildable == BA_A_SPAWN ) - reason = IBE_SPWNWARN; - else - reason = IBE_NOOVERMIND; - } + reason = IBE_NOOVERMIND; //can we only have one of these? if( BG_FindUniqueTestForBuildable( buildable ) ) @@ -2532,10 +2542,6 @@ itemBuildError_t G_itemFits( gentity_t *ent, buildable_t buildable, int distance //tell player to build a repeater to provide power if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER ) reason = IBE_REPEATER; - - //warn that the current spawn will not be externally powered - if( buildable == BA_H_SPAWN ) - reason = IBE_TNODEWARN; } //this buildable requires a DCC diff --git a/src/game/g_client.c b/src/game/g_client.c index 23fca525..7c564be9 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -316,11 +316,10 @@ SelectAlienSpawnPoint go to a random point that doesn't telefrag ================ */ -gentity_t *SelectAlienSpawnPoint( void ) +gentity_t *SelectAlienSpawnPoint( vec3_t preference ) { gentity_t *spot; int count; - int selection; gentity_t *spots[ MAX_SPAWN_POINTS ]; if( level.numAlienSpawns <= 0 ) @@ -354,8 +353,7 @@ gentity_t *SelectAlienSpawnPoint( void ) if( !count ) return NULL; - selection = rand() % count; - return spots[ selection ]; + return G_ClosestEnt( preference, spots, count ); } @@ -366,11 +364,10 @@ SelectHumanSpawnPoint go to a random point that doesn't telefrag ================ */ -gentity_t *SelectHumanSpawnPoint( void ) +gentity_t *SelectHumanSpawnPoint( vec3_t preference ) { gentity_t *spot; int count; - int selection; gentity_t *spots[ MAX_SPAWN_POINTS ]; if( level.numHumanSpawns <= 0 ) @@ -404,8 +401,7 @@ gentity_t *SelectHumanSpawnPoint( void ) if( !count ) return NULL; - selection = rand() % count; - return spots[ selection ]; + return G_ClosestEnt( preference, spots, count ); } @@ -429,14 +425,14 @@ SelectTremulousSpawnPoint Chooses a player start, deathmatch start, etc ============ */ -gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t origin, vec3_t angles ) +gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t preference, vec3_t origin, vec3_t angles ) { gentity_t *spot = NULL; if( team == PTE_ALIENS ) - spot = SelectAlienSpawnPoint( ); + spot = SelectAlienSpawnPoint( preference ); else if( team == PTE_HUMANS ) - spot = SelectHumanSpawnPoint( ); + spot = SelectHumanSpawnPoint( preference ); //no available spots if( !spot ) @@ -997,7 +993,7 @@ void ClientUserinfoChanged( int clientNum ) { if( strcmp( oldname, client->pers.netname ) ) { - trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, + G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, client->pers.netname ) ); } } @@ -1158,7 +1154,7 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) // don't do the "xxx connected" messages if they were caried over from previous level if( firstTime ) - trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) ); + G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) ); // count current clients and rank for scoreboard CalculateRanks( ); @@ -1218,10 +1214,12 @@ void ClientBegin( int clientNum ) tent->s.clientNum = ent->s.clientNum; } - trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) ); + G_InitCommandQueue( clientNum ); + + G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) ); // request the clients PTR code - trap_SendServerCommand( ent - g_entities, "ptrcrequest" ); + G_SendCommandFromServer( ent - g_entities, "ptrcrequest" ); G_LogPrintf( "ClientBegin: %i\n", clientNum ); @@ -1254,7 +1252,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles int eventSequence; char userinfo[ MAX_INFO_STRING ]; vec3_t up = { 0.0f, 0.0f, 1.0f }; - int ammo, clips, maxClips; + int maxAmmo, maxClips; weapon_t weapon; @@ -1387,6 +1385,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles if( ent->client->pers.classSelection == PCL_HUMAN ) { BG_AddWeaponToInventory( WP_BLASTER, client->ps.stats ); + BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); weapon = client->pers.humanItemSelection; } else if( client->sess.sessionTeam != TEAM_SPECTATOR ) @@ -1394,9 +1393,9 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles else weapon = WP_NONE; - BG_FindAmmoForWeapon( weapon, &ammo, &clips, &maxClips ); + BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); BG_AddWeaponToInventory( weapon, client->ps.stats ); - BG_PackAmmoArray( weapon, client->ps.ammo, client->ps.powerups, ammo, clips, maxClips ); + BG_PackAmmoArray( weapon, client->ps.ammo, client->ps.powerups, maxAmmo, maxClips ); ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.classSelection; ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection; @@ -1407,6 +1406,13 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles // health will count down towards max_health ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25; + + //if evolving scale health + if( ent == spawn ) + { + ent->health *= ent->client->pers.evolveHealthFraction; + client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction; + } //clear the credits array for( i = 0; i < MAX_CLIENTS; i++ ) diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index cc5b49c2..a5e9cc3a 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -67,7 +67,7 @@ int G_ClientNumberFromString( gentity_t *to, char *s ) if( idnum < 0 || idnum >= level.maxclients ) { - trap_SendServerCommand( to - g_entities, va( "print \"Bad client slot: %i\n\"", idnum ) ); + G_SendCommandFromServer( to - g_entities, va( "print \"Bad client slot: %i\n\"", idnum ) ); return -1; } @@ -75,7 +75,7 @@ int G_ClientNumberFromString( gentity_t *to, char *s ) if( cl->pers.connected != CON_CONNECTED ) { - trap_SendServerCommand( to - g_entities, va( "print \"Client %i is not active\n\"", idnum ) ); + G_SendCommandFromServer( to - g_entities, va( "print \"Client %i is not active\n\"", idnum ) ); return -1; } @@ -96,7 +96,7 @@ int G_ClientNumberFromString( gentity_t *to, char *s ) return idnum; } - trap_SendServerCommand( to - g_entities, va( "print \"User %s is not on the server\n\"", s ) ); + G_SendCommandFromServer( to - g_entities, va( "print \"User %s is not on the server\n\"", s ) ); return -1; } @@ -170,7 +170,7 @@ void ScoreboardMessage( gentity_t *ent ) stringlength += j; } - trap_SendServerCommand( ent-g_entities, va( "scores %i %i %i%s", i, + G_SendCommandFromServer( ent-g_entities, va( "scores %i %i %i%s", i, level.alienKills, level.humanKills, string ) ); } @@ -198,13 +198,13 @@ qboolean CheatsOk( gentity_t *ent ) { if( !g_cheats.integer ) { - trap_SendServerCommand( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) ); return qfalse; } if( ent->health <= 0 ) { - trap_SendServerCommand( ent-g_entities, va( "print \"You must be alive to use this command\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You must be alive to use this command\n\"" ) ); return qfalse; } @@ -261,7 +261,6 @@ Give items to a client void Cmd_Give_f( gentity_t *ent ) { char *name; - int i; qboolean give_all; if( !CheatsOk( ent ) ) @@ -281,23 +280,6 @@ void Cmd_Give_f( gentity_t *ent ) return; } - if( give_all || Q_stricmp( name, "weapons" ) == 0 ) - { - BG_AddWeaponToInventory( ( 1 << WP_NUM_WEAPONS ) - 1 - ( 1 << WP_NONE ), ent->client->ps.stats ); - - if( !give_all ) - return; - } - - if( give_all || Q_stricmp( name, "ammo" ) == 0 ) - { - for( i = 0; i < MAX_WEAPONS; i++ ) - BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, 999, 0, 0 ); - - if( !give_all ) - return; - } - if( give_all || Q_stricmpn( name, "funds", 5 ) == 0 ) { int credits = atoi( name + 6 ); @@ -336,7 +318,7 @@ void Cmd_God_f( gentity_t *ent ) else msg = "godmode ON\n"; - trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) ); + G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) ); } @@ -363,7 +345,7 @@ void Cmd_Notarget_f( gentity_t *ent ) else msg = "notarget ON\n"; - trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) ); + G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) ); } @@ -388,7 +370,7 @@ void Cmd_Noclip_f( gentity_t *ent ) ent->client->noclip = !ent->client->noclip; - trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) ); + G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) ); } @@ -408,7 +390,7 @@ void Cmd_LevelShot_f( gentity_t *ent ) return; BeginIntermission( ); - trap_SendServerCommand( ent - g_entities, "clientLevelShot" ); + G_SendCommandFromServer( ent - g_entities, "clientLevelShot" ); } /* @@ -429,7 +411,7 @@ void Cmd_Kill_f( gentity_t *ent ) if( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) { - trap_SendServerCommand( ent-g_entities, "print \"Leave the hovel first (use your destroy key)\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Leave the hovel first (use your destroy key)\n\"" ); return; } @@ -446,12 +428,12 @@ void Cmd_Kill_f( gentity_t *ent ) { if( ent->suicideTime == 0 ) { - trap_SendServerCommand( ent-g_entities, "print \"You will suicide in 20 seconds\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"You will suicide in 20 seconds\n\"" ); ent->suicideTime = level.time + 20000; } else if( ent->suicideTime > level.time ) { - trap_SendServerCommand( ent-g_entities, "print \"Suicide cancelled\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Suicide cancelled\n\"" ); ent->suicideTime = 0; } } @@ -502,7 +484,7 @@ void Cmd_Team_f( gentity_t *ent ) if( !strlen( s ) ) { - trap_SendServerCommand( ent-g_entities, va("print \"team: %i\n\"", ent->client->pers.teamSelection ) ); + G_SendCommandFromServer( ent-g_entities, va("print \"team: %i\n\"", ent->client->pers.teamSelection ) ); return; } @@ -539,16 +521,16 @@ void Cmd_Team_f( gentity_t *ent ) } else { - trap_SendServerCommand( ent-g_entities, va( "print \"Unknown team: %s\n\"", s ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown team: %s\n\"", s ) ); return; } G_ChangeTeam( ent, team ); if( team == PTE_ALIENS ) - trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " joined the aliens\n\"", ent->client->pers.netname ) ); + G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " joined the aliens\n\"", ent->client->pers.netname ) ); else if( team == PTE_HUMANS ) - trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " joined the humans\n\"", ent->client->pers.netname ) ); + G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " joined the humans\n\"", ent->client->pers.netname ) ); } @@ -574,7 +556,7 @@ static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, cons if( mode == SAY_TEAM && !OnSameTeam( ent, other ) ) return; - trap_SendServerCommand( other-g_entities, va( "%s \"%s%c%c%s\"", + G_SendCommandFromServer( other-g_entities, va( "%s \"%s%c%c%s\"", mode == SAY_TEAM ? "tchat" : "chat", name, Q_COLOR_ESCAPE, color, message ) ); } @@ -708,7 +690,7 @@ Cmd_Where_f */ void Cmd_Where_f( gentity_t *ent ) { - trap_SendServerCommand( ent-g_entities, va( "print \"%s\n\"", vtos( ent->s.origin ) ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"%s\n\"", vtos( ent->s.origin ) ) ); } /* @@ -724,25 +706,25 @@ void Cmd_CallVote_f( gentity_t *ent ) if( !g_allowVote.integer ) { - trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Voting not allowed here\n\"" ); return; } if( level.voteTime ) { - trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"A vote is already in progress\n\"" ); return; } if( ent->client->pers.voteCount >= MAX_VOTE_COUNT ) { - trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of votes\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"You have called the maximum number of votes\n\"" ); return; } if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE ) { - trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" ); return; } @@ -752,7 +734,7 @@ void Cmd_CallVote_f( gentity_t *ent ) if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Invalid vote string\n\"" ); return; } @@ -764,8 +746,8 @@ void Cmd_CallVote_f( gentity_t *ent ) else if( !Q_stricmp( arg1, "timelimit" ) ) { } else { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" ); - trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map <mapname>, " + G_SendCommandFromServer( ent-g_entities, "print \"Invalid vote string\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map <mapname>, " "kick <player>, clientkick <clientnum>, " "timelimit <time>\n\"" ); return; @@ -801,7 +783,7 @@ void Cmd_CallVote_f( gentity_t *ent ) if( !*s ) { - trap_SendServerCommand( ent-g_entities, "print \"nextmap not set\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"nextmap not set\n\"" ); return; } @@ -814,7 +796,7 @@ void Cmd_CallVote_f( gentity_t *ent ) Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString ); } - trap_SendServerCommand( -1, va( "print \"%s called a vote\n\"", ent->client->pers.netname ) ); + G_SendCommandFromServer( -1, va( "print \"%s called a vote\n\"", ent->client->pers.netname ) ); // start the voting, the caller autoamtically votes yes level.voteTime = level.time; @@ -843,23 +825,23 @@ void Cmd_Vote_f( gentity_t *ent ) if( !level.voteTime ) { - trap_SendServerCommand( ent-g_entities, "print \"No vote in progress\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"No vote in progress\n\"" ); return; } if( ent->client->ps.eFlags & EF_VOTED ) { - trap_SendServerCommand( ent-g_entities, "print \"Vote already cast\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Vote already cast\n\"" ); return; } if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE ) { - trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to vote as spectator\n\"" ); return; } - trap_SendServerCommand( ent-g_entities, "print \"Vote cast\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Vote cast\n\"" ); ent->client->ps.eFlags |= EF_VOTED; @@ -902,25 +884,25 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) if( !g_allowVote.integer ) { - trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Voting not allowed here\n\"" ); return; } if( level.teamVoteTime[ cs_offset ] ) { - trap_SendServerCommand( ent-g_entities, "print \"A team vote is already in progress\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"A team vote is already in progress\n\"" ); return; } if( ent->client->pers.teamVoteCount >= MAX_VOTE_COUNT ) { - trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of team votes\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"You have called the maximum number of team votes\n\"" ); return; } if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE ) { - trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" ); return; } @@ -930,7 +912,7 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) { - trap_SendServerCommand( ent-g_entities, "print \"Invalid team vote string\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Invalid team vote string\n\"" ); return; } @@ -958,14 +940,14 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) if( i >= level.maxclients ) { - trap_SendServerCommand( ent-g_entities, va( "print \"%s is not a valid player on your team\n\"", arg2 ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"%s is not a valid player on your team\n\"", arg2 ) ); return; } } else { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" ); - trap_SendServerCommand( ent-g_entities, "print \"Team vote commands are: teamkick <player>\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Invalid vote string\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Team vote commands are: teamkick <player>\n\"" ); return; } @@ -978,7 +960,7 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) continue; if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == team ) - trap_SendServerCommand( i, va("print \"%s called a team vote\n\"", ent->client->pers.netname ) ); + G_SendCommandFromServer( i, va("print \"%s called a team vote\n\"", ent->client->pers.netname ) ); } // start the voting, the caller autoamtically votes yes @@ -1021,23 +1003,23 @@ void Cmd_TeamVote_f( gentity_t *ent ) if( !level.teamVoteTime[ cs_offset ] ) { - trap_SendServerCommand( ent-g_entities, "print \"No team vote in progress\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"No team vote in progress\n\"" ); return; } if( ent->client->ps.eFlags & EF_TEAMVOTED ) { - trap_SendServerCommand( ent-g_entities, "print \"Team vote already cast\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Team vote already cast\n\"" ); return; } if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE ) { - trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to vote as spectator\n\"" ); return; } - trap_SendServerCommand( ent-g_entities, "print \"Team vote cast\n\"" ); + G_SendCommandFromServer( ent-g_entities, "print \"Team vote cast\n\"" ); ent->client->ps.eFlags |= EF_TEAMVOTED; @@ -1072,13 +1054,13 @@ void Cmd_SetViewpos_f( gentity_t *ent ) if( !g_cheats.integer ) { - trap_SendServerCommand( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) ); return; } if( trap_Argc( ) != 5 ) { - trap_SendServerCommand( ent-g_entities, va( "print \"usage: setviewpos x y z yaw\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"usage: setviewpos x y z yaw\n\"" ) ); return; } @@ -1184,7 +1166,7 @@ void Cmd_Class_f( gentity_t *ent ) currentClass == PCL_ALIEN_BUILDER0_UPG ) && ent->client->ps.stats[ STAT_MISC ] > 0 ) { - trap_SendServerCommand( ent-g_entities, va( "print \"Cannot evolve until build timer expires\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Cannot evolve until build timer expires\n\"" ) ); return; } @@ -1193,7 +1175,7 @@ void Cmd_Class_f( gentity_t *ent ) if( ent->client->pers.classSelection == PCL_NONE ) { - trap_SendServerCommand( ent-g_entities, va( "print \"Unknown class\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown class\n\"" ) ); return; } @@ -1230,6 +1212,14 @@ void Cmd_Class_f( gentity_t *ent ) //...check we can evolve to that class if( numLevels >= 0 && BG_FindStagesForClass( ent->client->pers.classSelection, g_alienStage.integer ) ) { + ent->client->pers.evolveHealthFraction = (float)ent->client->ps.stats[ STAT_HEALTH ] / + (float)BG_FindHealthForClass( currentClass ); + + if( ent->client->pers.evolveHealthFraction < 0.0f ) + ent->client->pers.evolveHealthFraction = 0.0f; + else if( ent->client->pers.evolveHealthFraction > 1.0f ) + ent->client->pers.evolveHealthFraction = 1.0f; + //remove credit G_AddCreditToClient( ent->client, -(short)numLevels, qtrue ); @@ -1241,7 +1231,7 @@ void Cmd_Class_f( gentity_t *ent ) else { ent->client->pers.classSelection = PCL_NONE; - trap_SendServerCommand( ent-g_entities, + G_SendCommandFromServer( ent-g_entities, va( "print \"You cannot evolve from your current class\n\"" ) ); return; } @@ -1272,11 +1262,11 @@ void Cmd_Class_f( gentity_t *ent ) } ent->client->pers.classSelection = PCL_NONE; - trap_SendServerCommand( ent-g_entities, va( "print \"You cannot spawn as this class\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You cannot spawn as this class\n\"" ) ); } else { - trap_SendServerCommand( ent-g_entities, va( "print \"Unknown class\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown class\n\"" ) ); return; } } @@ -1286,7 +1276,7 @@ void Cmd_Class_f( gentity_t *ent ) //humans cannot use this command whilst alive if( ent->client->pers.classSelection != PCL_NONE ) { - trap_SendServerCommand( ent-g_entities, va( "print \"You must be dead to use the class command\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You must be dead to use the class command\n\"" ) ); return; } @@ -1304,7 +1294,7 @@ void Cmd_Class_f( gentity_t *ent ) else { ent->client->pers.classSelection = PCL_NONE; - trap_SendServerCommand( ent-g_entities, va( "print \"Unknown starting item\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown starting item\n\"" ) ); return; } @@ -1316,7 +1306,7 @@ void Cmd_Class_f( gentity_t *ent ) ent->client->pers.classSelection = PCL_NONE; ent->client->sess.sessionTeam = TEAM_FREE; ClientSpawn( ent, NULL, NULL, NULL ); - trap_SendServerCommand( ent-g_entities, va( "print \"Join a team first\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Join a team first\n\"" ) ); } } @@ -1392,10 +1382,10 @@ void Cmd_ActivateItem_f( gentity_t *ent ) { //force a weapon change ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH; - trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", weapon ) ); + G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", weapon ) ); } else - trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) ); } @@ -1420,7 +1410,7 @@ void Cmd_DeActivateItem_f( gentity_t *ent ) if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) ) BG_DeactivateUpgrade( upgrade, ent->client->ps.stats ); else - trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) ); } @@ -1469,7 +1459,7 @@ void Cmd_ToggleItem_f( gentity_t *ent ) //force a weapon change ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH; - trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", weapon ) ); + G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", weapon ) ); } else if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) ) { @@ -1479,7 +1469,7 @@ void Cmd_ToggleItem_f( gentity_t *ent ) BG_ActivateUpgrade( upgrade, ent->client->ps.stats ); } else - trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) ); } /* @@ -1490,10 +1480,10 @@ G_GiveClientMaxAmmo static void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo ) { int i; - int quan, clips, maxClips; + int maxAmmo, maxClips; qboolean weaponType; - for( i = WP_NONE; i < WP_NUM_WEAPONS; i++ ) + for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) { if( buyingEnergyAmmo ) weaponType = BG_FindUsesEnergyForWeapon( i ); @@ -1502,9 +1492,10 @@ static void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo ) if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) && weaponType && !BG_FindInfinteAmmoForWeapon( i ) && - !BG_WeaponIsFull( i, ent->client->ps.ammo, ent->client->ps.powerups ) ) + !BG_WeaponIsFull( i, ent->client->ps.stats, + ent->client->ps.ammo, ent->client->ps.powerups ) ) { - BG_FindAmmoForWeapon( i, &quan, &clips, &maxClips ); + BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips ); if( buyingEnergyAmmo ) { @@ -1512,18 +1503,18 @@ static void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo ) ent->client->lastRefilTime = level.time; if( BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) ) - quan = (int)( (float)quan * BATTPACK_MODIFIER ); + maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); } else G_AddEvent( ent, EV_CHANGE_WEAPON, 0 ); BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, - quan, clips, maxClips ); + maxAmmo, maxClips ); //force a weapon change //FIXME: needs to work even if weapon is the same //ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH; - //trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", ent->client->ps.weapon ) ); + //G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", ent->client->ps.weapon ) ); } } } @@ -1538,7 +1529,7 @@ void Cmd_Buy_f( gentity_t *ent ) char s[ MAX_TOKEN_CHARS ]; int i; int weapon, upgrade, numItems = 0; - int quan, clips, maxClips; + int maxAmmo, maxClips; qboolean buyingEnergyAmmo = qfalse; for( i = UP_NONE; i < UP_NUM_UPGRADES; i++ ) @@ -1576,7 +1567,7 @@ void Cmd_Buy_f( gentity_t *ent ) //no armoury nearby if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) && !buyingEnergyAmmo ) { - trap_SendServerCommand( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) ); return; } @@ -1612,38 +1603,38 @@ void Cmd_Buy_f( gentity_t *ent ) if( BG_FindTeamForWeapon( weapon ) != WUT_HUMANS ) { //shouldn't need a fancy dialog - trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) ); return; } //are we /allowed/ to buy this? if( !BG_FindPurchasableForWeapon( weapon ) ) { - trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) ); return; } //are we /allowed/ to buy this? if( !BG_FindStagesForWeapon( weapon, g_humanStage.integer ) ) { - trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) ); return; } //add to inventory BG_AddWeaponToInventory( weapon, ent->client->ps.stats ); - BG_FindAmmoForWeapon( weapon, &quan, &clips, &maxClips ); + BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); if( BG_FindUsesEnergyForWeapon( weapon ) && BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) ) - quan = (int)( (float)quan * BATTPACK_MODIFIER ); + maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); BG_PackAmmoArray( weapon, ent->client->ps.ammo, ent->client->ps.powerups, - quan, clips, maxClips ); + maxAmmo, maxClips ); //force a weapon change ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH; - trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", weapon ) ); + G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", weapon ) ); //set build delay/pounce etc to 0 ent->client->ps.stats[ STAT_MISC ] = 0; @@ -1683,14 +1674,21 @@ void Cmd_Buy_f( gentity_t *ent ) if( BG_FindTeamForUpgrade( upgrade ) != WUT_HUMANS ) { //shouldn't need a fancy dialog - trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) ); + return; + } + + //are we /allowed/ to buy this? + if( !BG_FindPurchasableForUpgrade( upgrade ) ) + { + G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) ); return; } //are we /allowed/ to buy this? if( !BG_FindStagesForUpgrade( upgrade, g_humanStage.integer ) ) { - trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) ); return; } @@ -1710,7 +1708,7 @@ void Cmd_Buy_f( gentity_t *ent ) } else { - trap_SendServerCommand( ent-g_entities, va( "print \"Unknown item\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown item\n\"" ) ); } //if the buyer previously had no items at all, force a new selection @@ -1751,7 +1749,7 @@ void Cmd_Sell_f( gentity_t *ent ) //no armoury nearby if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) ) { - trap_SendServerCommand( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) ); return; } @@ -1763,7 +1761,7 @@ void Cmd_Sell_f( gentity_t *ent ) //are we /allowed/ to sell this? if( !BG_FindPurchasableForWeapon( weapon ) ) { - trap_SendServerCommand( ent-g_entities, va( "print \"You can't sell this weapon\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"You can't sell this weapon\n\"" ) ); return; } @@ -1774,7 +1772,7 @@ void Cmd_Sell_f( gentity_t *ent ) if( ( weapon == WP_HBUILD || weapon == WP_HBUILD2 ) && ent->client->ps.stats[ STAT_MISC ] > 0 ) { - trap_SendServerCommand( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) ); return; } @@ -1789,31 +1787,24 @@ void Cmd_Sell_f( gentity_t *ent ) { //force a weapon change ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH; - trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", WP_BLASTER ) ); + G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", WP_BLASTER ) ); } } else if( upgrade != UP_NONE ) { + //are we /allowed/ to sell this? + if( !BG_FindPurchasableForUpgrade( upgrade ) ) + { + G_SendCommandFromServer( ent-g_entities, va( "print \"You can't sell this item\n\"" ) ); + return; + } //remove upgrade if carried if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) ) { BG_RemoveUpgradeFromInventory( upgrade, ent->client->ps.stats ); if( upgrade == UP_BATTPACK ) - { - int j; - - //remove energy - for( j = WP_NONE; j < WP_NUM_WEAPONS; j++ ) - { - if( BG_InventoryContainsWeapon( j, ent->client->ps.stats ) && - BG_FindUsesEnergyForWeapon( j ) && - !BG_FindInfinteAmmoForWeapon( j ) ) - { - BG_PackAmmoArray( j, ent->client->ps.ammo, ent->client->ps.powerups, 0, 0, 0 ); - } - } - } + G_GiveClientMaxAmmo( ent, qtrue ); //add to funds G_AddCreditToClient( ent->client, (short)BG_FindPriceForUpgrade( upgrade ), qfalse ); @@ -1831,7 +1822,7 @@ void Cmd_Sell_f( gentity_t *ent ) if( ( i == WP_HBUILD || i == WP_HBUILD2 ) && ent->client->ps.stats[ STAT_MISC ] > 0 ) { - trap_SendServerCommand( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) ); continue; } @@ -1848,7 +1839,7 @@ void Cmd_Sell_f( gentity_t *ent ) { //force a weapon change ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH; - trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", WP_BLASTER ) ); + G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", WP_BLASTER ) ); } } } @@ -1872,7 +1863,7 @@ void Cmd_Sell_f( gentity_t *ent ) BG_FindUsesEnergyForWeapon( j ) && !BG_FindInfinteAmmoForWeapon( j ) ) { - BG_PackAmmoArray( j, ent->client->ps.ammo, ent->client->ps.powerups, 0, 0, 0 ); + BG_PackAmmoArray( j, ent->client->ps.ammo, ent->client->ps.powerups, 0, 0 ); } } } @@ -1887,7 +1878,7 @@ void Cmd_Sell_f( gentity_t *ent ) } } else - trap_SendServerCommand( ent-g_entities, va( "print \"Unknown item\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown item\n\"" ) ); if( trap_Argc( ) >= 2 ) { @@ -1982,7 +1973,7 @@ void Cmd_Build_f( gentity_t *ent ) } else { - trap_SendServerCommand( ent-g_entities, va( "print \"Cannot build this item\n\"" ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"Cannot build this item\n\"" ) ); G_LogPrintf( "Client %d tried to build %d using weapon %d\n", ent->client->ps.clientNum, @@ -2004,7 +1995,7 @@ void Cmd_Echo_f( gentity_t *ent ) trap_Argv( 1, s, sizeof( s ) ); - trap_SendServerCommand( ent-g_entities, va( "print \"%s\n\"", s ) ); + G_SendCommandFromServer( ent-g_entities, va( "print \"%s\n\"", s ) ); } @@ -2216,7 +2207,7 @@ void Cmd_PTRCVerify_f( gentity_t *ent ) // valid code if( connection->clientTeam != PTE_NONE ) - trap_SendServerCommand( ent->client->ps.clientNum, "ptrcconfirm" ); + G_SendCommandFromServer( ent->client->ps.clientNum, "ptrcconfirm" ); // restore mapping ent->client->pers.connection = connection; @@ -2228,7 +2219,7 @@ void Cmd_PTRCVerify_f( gentity_t *ent ) if( connection ) { - trap_SendServerCommand( ent->client->ps.clientNum, + G_SendCommandFromServer( ent->client->ps.clientNum, va( "ptrcissue %d", connection->ptrCode ) ); } } @@ -2258,7 +2249,7 @@ void Cmd_PTRCRestore_f( gentity_t *ent ) { if( ent->client->pers.joinedATeam ) { - trap_SendServerCommand( ent - g_entities, + G_SendCommandFromServer( ent - g_entities, "print \"You cannot use a PTR code after joining a team\n\"" ); } else @@ -2279,7 +2270,7 @@ void Cmd_PTRCRestore_f( gentity_t *ent ) } else { - trap_SendServerCommand( ent - g_entities, + G_SendCommandFromServer( ent - g_entities, va( "print \"\"%d\" is not a valid PTR code\n\"", code ) ); } } @@ -2297,11 +2288,11 @@ void Cmd_Test_f( gentity_t *ent ) /* ent->client->ps.stats[ STAT_STATE ] |= SS_POISONCLOUDED; ent->client->lastPoisonCloudedTime = level.time; ent->client->lastPoisonCloudedClient = ent; - trap_SendServerCommand( ent->client->ps.clientNum, "poisoncloud" );*/ + G_SendCommandFromServer( ent->client->ps.clientNum, "poisoncloud" );*/ - ent->client->ps.stats[ STAT_STATE ] |= SS_POISONED; +/* ent->client->ps.stats[ STAT_STATE ] |= SS_POISONED; ent->client->lastPoisonTime = level.time; - ent->client->lastPoisonClient = ent; + ent->client->lastPoisonClient = ent;*/ } @@ -2347,11 +2338,7 @@ void ClientCommand( int clientNum ) // ignore all other commands when at intermission if( level.intermissiontime ) - { - //TA: prevent menu babble at the end of games - /*Cmd_Say_f( ent, qfalse, qtrue );*/ return; - } if( Q_stricmp( cmd, "give" ) == 0 ) Cmd_Give_f( ent ); @@ -2416,5 +2403,5 @@ void ClientCommand( int clientNum ) else if( Q_stricmp( cmd, "test" ) == 0 ) Cmd_Test_f( ent ); else - trap_SendServerCommand( clientNum, va( "print \"unknown cmd %s\n\"", cmd ) ); + G_SendCommandFromServer( clientNum, va( "print \"unknown cmd %s\n\"", cmd ) ); } diff --git a/src/game/g_combat.c b/src/game/g_combat.c index 7b84ccc2..3df21614 100644 --- a/src/game/g_combat.c +++ b/src/game/g_combat.c @@ -368,6 +368,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int } self->client->pers.classSelection = PCL_NONE; //TA: reset the classtype + VectorCopy( self->s.origin, self->client->pers.lastDeathLocation ); self->takedamage = qfalse; // can still be gibbed @@ -1003,18 +1004,9 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, attacker->client->ps.persistant[ PERS_HITS ]++; } - if( damage < 1 ) - damage = 1; - take = damage; save = 0; - if( g_debugDamage.integer ) - { - G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number, - targ->health, take, asave ); - } - // add to the damage inflicted on a player this frame // the total will be turned into screen blends and view angle kicks // at the end of the frame @@ -1051,7 +1043,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, { if( !( targ->client->ps.stats[ STAT_STATE ] & SS_POISONED ) && !BG_InventoryContainsUpgrade( UP_BATTLESUIT, targ->client->ps.stats ) && - mod != MOD_LEVEL2_ZAP ) + mod != MOD_LEVEL2_ZAP && + targ->client->poisonImmunityTime < level.time ) { targ->client->ps.stats[ STAT_STATE ] |= SS_POISONED; targ->client->lastPoisonTime = level.time; @@ -1060,24 +1053,24 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } } + if( take < 1 ) + take = 1; + + if( g_debugDamage.integer ) + { + G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number, + targ->health, take, asave ); + } + // do the damage if( take ) { targ->health = targ->health - take; - if( targ->s.eType == ET_BUILDABLE ) - { - if( targ->biteam == BIT_ALIENS ) - G_AddEvent( targ, EV_ALIEN_BUILDABLE_DAMAGE, 0 ); - else if( targ->biteam == BIT_HUMANS ) - G_AddEvent( targ, EV_HUMAN_BUILDABLE_DAMAGE, 0 ); - } - if( targ->client ) - { targ->client->ps.stats[ STAT_HEALTH ] = targ->health; - targ->client->lastDamageTime = level.time; - } + + targ->lastDamageTime = level.time; //TA: add to the attackers "account" on the target if( targ->client && attacker->client ) @@ -1225,7 +1218,8 @@ qboolean G_SelectiveRadiusDamage( vec3_t origin, gentity_t *attacker, float dama // push the center of mass higher than the origin so players // get knocked into the air more dir[ 2 ] += 24; - G_SelectiveDamage( ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod, team ); + G_SelectiveDamage( ent, NULL, attacker, dir, origin, + (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod, team ); } } @@ -1295,7 +1289,8 @@ qboolean G_RadiusDamage( vec3_t origin, gentity_t *attacker, float damage, // push the center of mass higher than the origin so players // get knocked into the air more dir[ 2 ] += 24; - G_Damage( ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod ); + G_Damage( ent, NULL, attacker, dir, origin, + (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod ); } } diff --git a/src/game/g_local.h b/src/game/g_local.h index 4b18234f..63a4970e 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -228,6 +228,8 @@ struct gentity_s int triggerGravity; //TA: gravity for this trigger int suicideTime; //TA: when the client will suicide + + int lastDamageTime; }; typedef enum @@ -322,11 +324,14 @@ typedef struct qboolean teamInfo; // send team overlay updates? pClass_t classSelection; //TA: player class (copied to ent->client->ps.stats[ STAT_PCLASS ] once spawned) + float evolveHealthFraction; weapon_t humanItemSelection; //TA: humans have a starting item pTeam_t teamSelection; //TA: player team (copied to ps.stats[ STAT_PTEAM ]) qboolean joinedATeam; //TA: used to tell when a PTR code is valid connectionRecord_t *connection; + + vec3_t lastDeathLocation; } clientPersistant_t; // this structure is cleared on each ClientSpawn(), @@ -394,6 +399,7 @@ struct gclient_s gentity_t *hovel; //TA: body that is being infested. must be persistant int lastPoisonTime; + int poisonImmunityTime; gentity_t *lastPoisonClient; int lastPoisonCloudedTime; gentity_t *lastPoisonCloudedClient; @@ -401,8 +407,10 @@ struct gclient_s int lastLockTime; int lastSlowTime; int lastBoostedTime; + int lastMedKitTime; + int medKitHealthToRestore; + int medKitIncrementTime; int lastCreepSlowTime; //TA: time until creep can be removed - int lastDamageTime; int pouncePayload; //TA: amount of damage pounce attack will do qboolean allowedToPounce; @@ -433,6 +441,7 @@ typedef struct spawnQueue_s void G_InitSpawnQueue( spawnQueue_t *sq ); int G_GetSpawnQueueLength( spawnQueue_t *sq ); int G_PopSpawnQueue( spawnQueue_t *sq ); +int G_PeekSpawnQueue( spawnQueue_t *sq ); void G_PushSpawnQueue( spawnQueue_t *sq, int clientNum ); qboolean G_RemoveFromSpawnQueue( spawnQueue_t *sq, int clientNum ); int G_GetPosInSpawnQueue( spawnQueue_t *sq, int clientNum ); @@ -694,10 +703,32 @@ void G_SetOrigin( gentity_t *ent, vec3_t origin ); void AddRemap(const char *oldShader, const char *newShader, float timeOffset); const char *BuildShaderStateConfig(); +#define MAX_QUEUE_COMMANDS 10 + +typedef struct commandQueueElement_s +{ + qboolean used; + struct commandQueueElement_s *next; + char command[ MAX_TOKEN_CHARS ]; +} commandQueueElement_t; + +typedef struct commandQueue_s +{ + int nextCommandTime; //next time that the queue can be popped + + commandQueueElement_t *front; + commandQueueElement_t *back; +} commandQueue_t; + +void G_ProcessCommandQueues( void ); +void G_SendCommandFromServer( int clientNum, const char *cmd ); +void G_InitCommandQueue( int clientNum ); + void G_TriggerMenu( int clientNum, dynMenu_t menu ); void G_CloseMenus( int clientNum ); qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 ); +gentity_t *G_ClosestEnt( vec3_t origin, gentity_t **entities, int numEntities ); // // g_combat.c @@ -764,12 +795,44 @@ void ShineTorch( gentity_t *self ); // // g_weapon.c // + +/*typedef struct zap_s +{ + qboolean used; + + gentity_t *creator; + gentity_t *source; + gentity_t *target; + + int timeToLive; + + int depth; + + gentity_t *effectTempEnt; +} zap_t;*/ + +#define MAX_ZAP_TARGETS LEVEL2_AREAZAP_MAX_TARGETS + +typedef struct zap_s +{ + qboolean used; + + gentity_t *creator; + gentity_t *targets[ MAX_ZAP_TARGETS ]; + int numTargets; + + int timeToLive; + + gentity_t *effectChannel; +} zap_t; + void CalcMuzzlePoint( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ); void SnapVectorTowards( vec3_t v, vec3_t to ); qboolean CheckVenomAttack( gentity_t *ent ); void CheckGrabAttack( gentity_t *ent ); qboolean CheckPounceAttack( gentity_t *ent ); void ChargeAttack( gentity_t *ent, gentity_t *victim ); +void G_UpdateZaps( int msec ); // @@ -778,7 +841,7 @@ void ChargeAttack( gentity_t *ent, gentity_t *victim ); void G_AddCreditToClient( gclient_t *client, short credit, qboolean cap ); team_t TeamCount( int ignoreClientNum, int team ); void SetClientViewAngle( gentity_t *ent, vec3_t angle ); -gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t origin, vec3_t angles ); +gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t preference, vec3_t origin, vec3_t angles ); gentity_t *SelectSpawnPoint( vec3_t avoidPoint, vec3_t origin, vec3_t angles ); void SpawnCorpse( gentity_t *ent ); void respawn( gentity_t *ent ); @@ -961,6 +1024,7 @@ extern vmCvar_t g_cheats; extern vmCvar_t g_maxclients; // allow this many total, including spectators extern vmCvar_t g_maxGameClients; // allow this many active extern vmCvar_t g_restarted; +extern vmCvar_t g_minCommandPeriod; extern vmCvar_t g_timelimit; extern vmCvar_t g_suddenDeathTime; diff --git a/src/game/g_main.c b/src/game/g_main.c index 98566cb4..ecb56723 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -74,6 +74,7 @@ vmCvar_t pmove_fixed; vmCvar_t pmove_msec; vmCvar_t g_rankings; vmCvar_t g_listEntity; +vmCvar_t g_minCommandPeriod; //TA vmCvar_t g_humanBuildPoints; @@ -154,6 +155,7 @@ static cvarTable_t gameCvarTable[ ] = { &g_allowVote, "g_allowVote", "1", CVAR_ARCHIVE, 0, qfalse }, { &g_listEntity, "g_listEntity", "0", 0, 0, qfalse }, + { &g_minCommandPeriod, "g_minCommandPeriod", "500", 0, 0, qfalse}, { &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse}, { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse}, @@ -261,7 +263,7 @@ void QDECL G_Printf( const char *fmt, ... ) if( !g_dedicated.integer ) { Com_sprintf( clientText, 1048, "gprintf \"%s\"", text ); - trap_SendServerCommand( -1, clientText ); + G_SendCommandFromServer( -1, clientText ); } trap_Printf( text ); @@ -403,7 +405,7 @@ void G_UpdateCvars( void ) cv->modificationCount = cv->vmCvar->modificationCount; if( cv->trackChange ) - trap_SendServerCommand( -1, va( "print \"Server: %s changed to %s\n\"", + G_SendCommandFromServer( -1, va( "print \"Server: %s changed to %s\n\"", cv->cvarName, cv->vmCvar->string ) ); if( cv->teamShader ) @@ -703,6 +705,18 @@ int G_PopSpawnQueue( spawnQueue_t *sq ) /* ============ +G_PeekSpawnQueue + +Look at front element from a spawn queue +============ +*/ +int G_PeekSpawnQueue( spawnQueue_t *sq ) +{ + return sq->clients[ sq->front ]; +} + +/* +============ G_PushSpawnQueue Add an element to the back of the spawn queue @@ -844,7 +858,12 @@ void G_SpawnClients( pTeam_t team ) if( G_GetSpawnQueueLength( sq ) > 0 && numSpawns > 0 ) { - if( ( spawn = SelectTremulousSpawnPoint( team, spawn_origin, spawn_angles ) ) ) + clientNum = G_PeekSpawnQueue( sq ); + ent = &g_entities[ clientNum ]; + + if( ( spawn = SelectTremulousSpawnPoint( team, + ent->client->pers.lastDeathLocation, + spawn_origin, spawn_angles ) ) ) { clientNum = G_PopSpawnQueue( sq ); @@ -1545,6 +1564,9 @@ void CheckIntermissionExit( void ) if( cl->pers.connected != CON_CONNECTED ) continue; + if( cl->sess.sessionTeam == TEAM_SPECTATOR ) + continue; + if( g_entities[ cl->ps.clientNum ].r.svFlags & SVF_BOT ) continue; @@ -1649,10 +1671,13 @@ void CheckExitRules( void ) { if( level.time - level.startTime >= g_timelimit.integer * 60000 ) { - trap_SendServerCommand( -1, "print \"Timelimit hit\n\"" ); - G_LogPrintf( "STATS T:L A:%f H:%f M:%s D:%d\n", level.averageNumAlienClients, - level.averageNumHumanClients, - s, level.time - level.startTime ); + G_SendCommandFromServer( -1, "print \"Timelimit hit\n\"" ); + + G_LogPrintf( "STATS T:L A:%f H:%f M:%s D:%d AS:%d HS:%d\n", + level.averageNumAlienClients, level.averageNumHumanClients, + s, level.time - level.startTime, + g_alienStage.integer, g_humanStage.integer ); + level.lastWin = PTE_NONE; LogExit( "Timelimit hit." ); return; @@ -1666,11 +1691,13 @@ void CheckExitRules( void ) { //humans win level.lastWin = PTE_HUMANS; - trap_SendServerCommand( -1, "print \"Humans win\n\""); - G_LogPrintf( "STATS T:H A:%f H:%f M:%s D:%d\n", level.averageNumAlienClients, - level.averageNumHumanClients, - s, level.time - level.startTime ); + G_SendCommandFromServer( -1, "print \"Humans win\n\""); + G_LogPrintf( "STATS T:H A:%f H:%f M:%s D:%d AS:%d HS:%d\n", + level.averageNumAlienClients, level.averageNumHumanClients, + s, level.time - level.startTime, + g_alienStage.integer, g_humanStage.integer ); + LogExit( "Humans win." ); return; } @@ -1680,11 +1707,13 @@ void CheckExitRules( void ) { //aliens win level.lastWin = PTE_ALIENS; - trap_SendServerCommand( -1, "print \"Aliens win\n\""); - G_LogPrintf( "STATS T:A A:%f H:%f M:%s D:%d\n", level.averageNumAlienClients, - level.averageNumHumanClients, - s, level.time - level.startTime ); + G_SendCommandFromServer( -1, "print \"Aliens win\n\""); + G_LogPrintf( "STATS T:A A:%f H:%f M:%s D:%d AS:%d HS:%d\n", + level.averageNumAlienClients, level.averageNumHumanClients, + s, level.time - level.startTime, + g_alienStage.integer, g_humanStage.integer ); + LogExit( "Aliens win." ); return; } @@ -1733,13 +1762,13 @@ void CheckVote( void ) if( level.voteYes > level.voteNo ) { // execute the command, then remove the vote - trap_SendServerCommand( -1, "print \"Vote passed\n\"" ); + G_SendCommandFromServer( -1, "print \"Vote passed\n\"" ); level.voteExecuteTime = level.time + 3000; } else { // same behavior as a timeout - trap_SendServerCommand( -1, "print \"Vote failed\n\"" ); + G_SendCommandFromServer( -1, "print \"Vote failed\n\"" ); } } else @@ -1747,13 +1776,13 @@ void CheckVote( void ) if( level.voteYes > level.numConnectedClients / 2 ) { // execute the command, then remove the vote - trap_SendServerCommand( -1, "print \"Vote passed\n\"" ); + G_SendCommandFromServer( -1, "print \"Vote passed\n\"" ); level.voteExecuteTime = level.time + 3000; } else if( level.voteNo >= level.numConnectedClients / 2 ) { // same behavior as a timeout - trap_SendServerCommand( -1, "print \"Vote failed\n\"" ); + G_SendCommandFromServer( -1, "print \"Vote failed\n\"" ); } else { @@ -1788,21 +1817,21 @@ void CheckTeamVote( int team ) if( level.time - level.teamVoteTime[ cs_offset ] >= VOTE_TIME ) { - trap_SendServerCommand( -1, "print \"Team vote failed\n\"" ); + G_SendCommandFromServer( -1, "print \"Team vote failed\n\"" ); } else { if( level.teamVoteYes[ cs_offset ] > level.numteamVotingClients[ cs_offset ] / 2 ) { // execute the command, then remove the vote - trap_SendServerCommand( -1, "print \"Team vote passed\n\"" ); + G_SendCommandFromServer( -1, "print \"Team vote passed\n\"" ); // trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.teamVoteString[ cs_offset ] ) ); } else if( level.teamVoteNo[ cs_offset ] >= level.numteamVotingClients[ cs_offset ] / 2 ) { // same behavior as a timeout - trap_SendServerCommand( -1, "print \"Team vote failed\n\"" ); + G_SendCommandFromServer( -1, "print \"Team vote failed\n\"" ); } else { @@ -2016,7 +2045,11 @@ void G_RunFrame( int levelTime ) G_SpawnClients( PTE_ALIENS ); G_SpawnClients( PTE_HUMANS ); G_CalculateAvgPlayers( ); + G_UpdateZaps( msec ); + //send any pending commands + G_ProcessCommandQueues( ); + // see if it is time to end the level CheckExitRules( ); diff --git a/src/game/g_missile.c b/src/game/g_missile.c index b1a71ac3..1d30974d 100644 --- a/src/game/g_missile.c +++ b/src/game/g_missile.c @@ -260,7 +260,9 @@ void G_RunMissile( gentity_t *ent ) else VectorCopy( tr.endpos, ent->r.currentOrigin ); + ent->r.contents = CONTENTS_SOLID; //trick trap_LinkEntity into... trap_LinkEntity( ent ); + ent->r.contents = 0; //...encoding bbox information if( tr.fraction != 1 ) { @@ -317,6 +319,8 @@ gentity_t *fire_flamer( gentity_t *self, vec3_t start, vec3_t dir ) bolt->splashMethodOfDeath = MOD_FLAMER_SPLASH; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; + bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -15.0f; + bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 15.0f; bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index c86ac2b6..0c5c3b27 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -567,12 +567,12 @@ qboolean ConsoleCommand( void ) { if( Q_stricmp( cmd, "say" ) == 0 ) { - trap_SendServerCommand( -1, va( "print \"server: %s\n\"", ConcatArgs( 1 ) ) ); + G_SendCommandFromServer( -1, va( "print \"server: %s\n\"", ConcatArgs( 1 ) ) ); return qtrue; } // everything else will also be printed as a say command - trap_SendServerCommand( -1, va( "print \"server: %s\n\"", ConcatArgs( 0 ) ) ); + G_SendCommandFromServer( -1, va( "print \"server: %s\n\"", ConcatArgs( 0 ) ) ); return qtrue; } diff --git a/src/game/g_target.c b/src/game/g_target.c index 64a3f33e..f57f173e 100644 --- a/src/game/g_target.c +++ b/src/game/g_target.c @@ -78,7 +78,7 @@ void Use_Target_Print( gentity_t *ent, gentity_t *other, gentity_t *activator ) { if( activator->client && ( ent->spawnflags & 4 ) ) { - trap_SendServerCommand( activator-g_entities, va( "cp \"%s\"", ent->message ) ); + G_SendCommandFromServer( activator-g_entities, va( "cp \"%s\"", ent->message ) ); return; } @@ -92,7 +92,7 @@ void Use_Target_Print( gentity_t *ent, gentity_t *other, gentity_t *activator ) return; } - trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ) ); + G_SendCommandFromServer( -1, va("cp \"%s\"", ent->message ) ); } void SP_target_print( gentity_t *ent ) diff --git a/src/game/g_team.c b/src/game/g_team.c index 9e0eb078..f4e035b9 100644 --- a/src/game/g_team.c +++ b/src/game/g_team.c @@ -34,7 +34,7 @@ void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... ) while( ( p = strchr( msg, '"' ) ) != NULL ) *p = '\''; - trap_SendServerCommand( ( ( ent == NULL ) ? -1 : ent-g_entities ), va( "print \"%s\"", msg ) ); + G_SendCommandFromServer( ( ( ent == NULL ) ? -1 : ent-g_entities ), va( "print \"%s\"", msg ) ); } @@ -204,7 +204,7 @@ void TeamplayInfoMessage( gentity_t *ent ) } } - trap_SendServerCommand( ent - g_entities, va( "tinfo %i %s", cnt, string ) ); + G_SendCommandFromServer( ent - g_entities, va( "tinfo %i %s", cnt, string ) ); } void CheckTeamStatus( void ) diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c index fbcf4c4f..aff816dc 100644 --- a/src/game/g_trigger.c +++ b/src/game/g_trigger.c @@ -1111,9 +1111,9 @@ void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace ) else self->timestamp = level.time + FRAMETIME; - BG_FindAmmoForWeapon( other->client->ps.weapon, &maxAmmo, NULL, NULL ); + BG_FindAmmoForWeapon( other->client->ps.weapon, &maxAmmo, &maxClips ); BG_UnpackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.powerups, - &ammo, &clips, &maxClips ); + &ammo, &clips ); if( ( ammo + self->damage ) > maxAmmo ) { @@ -1129,7 +1129,7 @@ void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace ) ammo += self->damage; BG_PackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.powerups, - ammo, clips, maxClips ); + ammo, clips ); } /* diff --git a/src/game/g_utils.c b/src/game/g_utils.c index 95e117d2..b09ec8cb 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -155,7 +155,7 @@ void G_TeamCommand( pTeam_t team, char *cmd ) if( level.clients[ i ].pers.connected == CON_CONNECTED ) { if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == team ) - trap_SendServerCommand( i, va( "%s", cmd ) ); + G_SendCommandFromServer( i, va( "%s", cmd ) ); } } } @@ -683,6 +683,195 @@ void G_Sound( gentity_t *ent, int channel, int soundIndex ) } +#define MAX_QUEUE_ELEMENTS MAX_CLIENTS * MAX_QUEUE_COMMANDS + +static commandQueueElement_t queuedCommandElements[ MAX_QUEUE_ELEMENTS ]; +static commandQueue_t queuedCommands[ MAX_CLIENTS ]; + +/* +=============== +G_PopCommandQueue + +Return the front of a command queue +Must use immediately or copy to a buffer +=============== +*/ +static const char *G_PopCommandQueue( commandQueue_t *cq ) +{ + if( cq->front ) + { + commandQueueElement_t *cqe = cq->front; + + cq->front = cqe->next; + + // last element in the queue + if( cq->front == NULL ) + cq->back = NULL; + + cq->nextCommandTime = level.time + g_minCommandPeriod.integer; + cqe->used = qfalse; + + return cqe->command; + } + else + return NULL; +} + +/* +=============== +G_PushCommandQueue + +Put a command on a command queue +=============== +*/ +static void G_PushCommandQueue( commandQueue_t *cq, const char *cmd ) +{ + int i; + + for( i = 0; i < MAX_QUEUE_ELEMENTS; i++ ) + { + commandQueueElement_t *cqe = &queuedCommandElements[ i ]; + + if( !cqe->used ) + { + cqe->used = qtrue; + cqe->next = NULL; + Q_strncpyz( cqe->command, cmd, MAX_TOKEN_CHARS ); + + if( cq->back ) + { + cq->back->next = cqe; + cq->back = cqe; + } + else + { + cq->front = cqe; + cq->back = cqe; + } + + return; + } + } + + //drop the command +} + +/* +=============== +G_PrintCommandQueue +=============== +*/ +#if 0 //quiet compiler +static void G_PrintCommandQueue( commandQueue_t *cq ) +{ + commandQueueElement_t *cqe; + + if( cq->front ) + { + cqe = cq->front; + + do + { + G_Printf( "->\"%s\"", cqe->command ); + } while( ( cqe = cqe->next ) ); + + G_Printf( "\n" ); + } +} +#endif + +/* +=============== +G_ReadyToDequeue +=============== +*/ +static qboolean G_ReadyToDequeue( commandQueue_t *cq ) +{ + if( !cq ) + return qfalse; + + return cq->front && cq->nextCommandTime <= level.time; +} + +/* +=============== +G_ProcessCommandQueues + +Check for any outstanding commands to be sent +=============== +*/ +void G_ProcessCommandQueues( void ) +{ + int i; + + for( i = 0; i < MAX_CLIENTS; i++ ) + { + commandQueue_t *cq = &queuedCommands[ i ]; + + if( G_ReadyToDequeue( cq ) ) + { + const char *command = G_PopCommandQueue( cq ); + + if( command ) + trap_SendServerCommand( i, command ); + } + } +} + +/* +=============== +G_InitCommandQueue +=============== +*/ +void G_InitCommandQueue( int clientNum ) +{ + commandQueue_t *cq = &queuedCommands[ clientNum ]; + + if( clientNum >= 0 && clientNum < MAX_CLIENTS ) + { + cq->front = cq->back = NULL; + cq->nextCommandTime = 0; + } +} + +/* +=============== +G_SendCommandFromServer + +Sends a command to a client +=============== +*/ +void G_SendCommandFromServer( int clientNum, const char *cmd ) +{ + commandQueue_t *cq = &queuedCommands[ clientNum ]; + + if( clientNum < 0 ) + cq = NULL; + + if( strlen( cmd ) > 1022 ) + { + G_LogPrintf( "G_SendCommandFromServer( %d, ... ) length exceeds 1022.\n", clientNum ); + G_LogPrintf( "cmd [%s]\n", cmd ); + return; + } + + if( cq ) + { + if( cq->nextCommandTime > level.time ) + { + //can't send yet, so queue the command up + G_PushCommandQueue( cq, cmd ); + } + else + { + cq->nextCommandTime = level.time + g_minCommandPeriod.integer; + trap_SendServerCommand( clientNum, cmd ); + } + } + else + trap_SendServerCommand( clientNum, cmd ); +} + //============================================================================== @@ -735,8 +924,13 @@ gentity_t *G_FindRadius( gentity_t *from, vec3_t org, float rad ) return NULL; } -// (NOBODY): Code helper function -// +/* +=============== +G_Visible + +Test for a LOS between two entities +=============== +*/ qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 ) { trace_t trace; @@ -749,6 +943,32 @@ qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 ) return qtrue; } +/* +=============== +G_ClosestEnt + +Test a list of entities for the closest to a particular point +=============== +*/ +gentity_t *G_ClosestEnt( vec3_t origin, gentity_t **entities, int numEntities ) +{ + int i; + float nd, d = 1000000.0f; + gentity_t *closestEnt = NULL; + + for( i = 0; i < numEntities; i++ ) + { + gentity_t *ent = entities[ i ]; + + if( ( nd = VectorDistance( origin, ent->s.origin ) ) < d ) + { + d = nd; + closestEnt = ent; + } + } + + return closestEnt; +} /* =============== @@ -762,7 +982,7 @@ void G_TriggerMenu( int clientNum, dynMenu_t menu ) char buffer[ 32 ]; Com_sprintf( buffer, 32, "servermenu %d", menu ); - trap_SendServerCommand( clientNum, buffer ); + G_SendCommandFromServer( clientNum, buffer ); } @@ -778,7 +998,7 @@ void G_CloseMenus( int clientNum ) char buffer[ 32 ]; Com_sprintf( buffer, 32, "serverclosemenus" ); - trap_SendServerCommand( clientNum, buffer ); + G_SendCommandFromServer( clientNum, buffer ); } diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 7094bcdb..1dbd5c15 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -871,7 +871,7 @@ void poisonCloud( gentity_t *ent ) humanPlayer->client->ps.stats[ STAT_STATE ] |= SS_POISONCLOUDED; humanPlayer->client->lastPoisonCloudedTime = level.time; humanPlayer->client->lastPoisonCloudedClient = ent; - trap_SendServerCommand( humanPlayer->client->ps.clientNum, "poisoncloud" ); + G_SendCommandFromServer( humanPlayer->client->ps.clientNum, "poisoncloud" ); } } } @@ -886,25 +886,27 @@ LEVEL2 ====================================================================== */ +#define MAX_ZAPS 64 + +static zap_t zaps[ MAX_CLIENTS ]; + /* =============== -areaZapFire +G_FindNewZapTarget =============== */ -void areaZapFire( gentity_t *ent ) +static gentity_t *G_FindNewZapTarget( gentity_t *ent ) { int entityList[ MAX_GENTITIES ]; - int targetList[ MAX_GENTITIES ]; vec3_t range = { LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE }; - vec3_t mins, maxs, dir; - int i, num, numTargets = 0; + vec3_t mins, maxs; + int i, j, k, num; gentity_t *enemy; - gentity_t *tent; trace_t tr; - int damage; - VectorAdd( ent->client->ps.origin, range, maxs ); - VectorSubtract( ent->client->ps.origin, range, mins ); + VectorScale( range, 1.0f / M_ROOT3, range ); + VectorAdd( ent->s.origin, range, maxs ); + VectorSubtract( ent->s.origin, range, mins ); num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); @@ -912,41 +914,227 @@ void areaZapFire( gentity_t *ent ) { enemy = &g_entities[ entityList[ i ] ]; - if( ( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || - ( enemy->s.eType == ET_BUILDABLE && BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) ) + if( ( ( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || + ( enemy->s.eType == ET_BUILDABLE && + BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) ) && enemy->health > 0 ) { + qboolean foundOldTarget = qfalse; + trap_Trace( &tr, muzzle, NULL, NULL, enemy->s.origin, ent->s.number, MASK_SHOT ); //can't see target from here if( tr.entityNum == ENTITYNUM_WORLD ) continue; - targetList[ numTargets++ ] = entityList[ i ]; + for( j = 0; j < MAX_ZAPS; j++ ) + { + zap_t *zap = &zaps[ j ]; + + for( k = 0; k < zap->numTargets; k++ ) + { + if( zap->targets[ k ] == enemy ) + { + foundOldTarget = qtrue; + break; + } + } + + if( foundOldTarget ) + break; + } + + // enemy is already targetted + if( foundOldTarget ) + continue; + + return enemy; } } - damage = (int)( (float)LEVEL2_AREAZAP_DMG / (float)numTargets ); - for( i = 0; i < numTargets; i++ ) - { - enemy = &g_entities[ targetList[ i ] ]; + return NULL; +} - VectorSubtract( enemy->s.origin, muzzle, dir ); - VectorNormalize( dir ); - - //do some damage - G_Damage( enemy, ent, ent, dir, tr.endpos, - damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP ); +/* +=============== +G_UpdateZapEffect +=============== +*/ +static void G_UpdateZapEffect( zap_t *zap ) +{ + int j; + gentity_t *effect = zap->effectChannel; + + effect->s.eType = ET_LEV2_ZAP_CHAIN; + effect->classname = "lev2zapchain"; + G_SetOrigin( effect, zap->creator->s.origin ); + effect->s.powerups = zap->creator->s.number; + + effect->s.time = effect->s.time2 = effect->s.constantLight = -1; + + for( j = 0; j < zap->numTargets; j++ ) + { + int number = zap->targets[ j ]->s.number; - // snap the endpos to integers to save net bandwidth, but nudged towards the line - SnapVectorTowards( tr.endpos, muzzle ); + switch( j ) + { + case 0: effect->s.time = number; break; + case 1: effect->s.time2 = number; break; + case 2: effect->s.constantLight = number; break; + default: break; + } + } + + trap_LinkEntity( effect ); +} + +/* +=============== +G_CreateNewZap +=============== +*/ +static void G_CreateNewZap( gentity_t *creator, gentity_t *target ) +{ + int i, j; + zap_t *zap; + + for( i = 0; i < MAX_ZAPS; i++ ) + { + zap = &zaps[ i ]; + + if( !zap->used ) + { + zap->used = qtrue; + + zap->timeToLive = LEVEL2_AREAZAP_TIME; + + zap->creator = creator; + + zap->targets[ 0 ] = target; + zap->numTargets = 1; + + for( j = 1; j < MAX_ZAP_TARGETS && zap->targets[ j - 1 ]; j++ ) + { + zap->targets[ j ] = G_FindNewZapTarget( zap->targets[ j - 1 ] ); + + if( zap->targets[ j ] ) + zap->numTargets++; + } + + zap->effectChannel = G_Spawn( ); + G_UpdateZapEffect( zap ); + + return; + } + } +} + + +/* +=============== +G_UpdateZaps +=============== +*/ +void G_UpdateZaps( int msec ) +{ + int i, j; + zap_t *zap; + int damage; + + for( i = 0; i < MAX_ZAPS; i++ ) + { + zap = &zaps[ i ]; + + if( zap->used ) + { + //check each target is valid + for( j = 0; j < zap->numTargets; j++ ) + { + gentity_t *source; + gentity_t *target = zap->targets[ j ]; + + if( j == 0 ) + source = zap->creator; + else + source = zap->targets[ j - 1 ]; + + if( target->health <= 0 || !target->inuse || //early out + VectorDistance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE ) + { + target = zap->targets[ j ] = G_FindNewZapTarget( source ); + + //couldn't find a target, so forget about the rest of the chain + if( !target ) + zap->numTargets = j; + } + + } + + if( zap->numTargets ) + { + for( j = 0; j < zap->numTargets; j++ ) + { + gentity_t *source; + gentity_t *target = zap->targets[ j ]; + float r = 1.0f / zap->numTargets; + float damageFraction = 2 * r - 2 * j * r * r - r * r; + + if( j == 0 ) + source = zap->creator; + else + source = zap->targets[ j - 1 ]; + + damage = ceil( ( (float)msec / LEVEL2_AREAZAP_TIME ) * + LEVEL2_AREAZAP_DMG * damageFraction ); + + //do the damage + if( damage ) + G_Damage( target, source, zap->creator, NULL, NULL, + damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP ); + } + } + + G_UpdateZapEffect( zap ); + + zap->timeToLive -= msec; + + if( zap->timeToLive <= 0 || zap->numTargets == 0 || zap->creator->health <= 0 ) + { + zap->used = qfalse; + G_FreeEntity( zap->effectChannel ); + } + } + } +} - // send arc effect - tent = G_TempEntity( enemy->s.pos.trBase, EV_ALIENZAP ); +/* +=============== +areaZapFire +=============== +*/ +void areaZapFire( gentity_t *ent ) +{ + trace_t tr; + vec3_t end; + gentity_t *traceEnt; - VectorCopy( ent->client->ps.origin, tent->s.origin2 ); + // set aiming directions + AngleVectors( ent->client->ps.viewangles, forward, right, up ); + + CalcMuzzlePoint( ent, forward, right, up, muzzle ); + + VectorMA( muzzle, LEVEL2_AREAZAP_RANGE, forward, end ); + + trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); + if( tr.surfaceFlags & SURF_NOIMPACT ) + return; - tent->s.generic1 = ent->s.number; //src - tent->s.clientNum = enemy->s.number; //dest + traceEnt = &g_entities[ tr.entityNum ]; + + if( ( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || + ( traceEnt->s.eType == ET_BUILDABLE && + BG_FindTeamForBuildable( traceEnt->s.modelindex ) == BIT_HUMANS ) ) && traceEnt->health > 0 ) + { + G_CreateNewZap( ent, traceEnt ); } } diff --git a/src/game/tremulous.h b/src/game/tremulous.h index ce0fbff4..98fb60de 100644 --- a/src/game/tremulous.h +++ b/src/game/tremulous.h @@ -64,6 +64,8 @@ #define LEVEL2_AREAZAP_DMG ADM(80) #define LEVEL2_AREAZAP_RANGE 200.0f #define LEVEL2_AREAZAP_REPEAT 3000 +#define LEVEL2_AREAZAP_TIME 1000 +#define LEVEL2_AREAZAP_MAX_TARGETS 3 #define LEVEL2_WALLJUMP_MAXSPEED 1000.0f #define LEVEL3_CLAW_DMG ADM(80) @@ -78,11 +80,11 @@ #define LEVEL3_POUNCE_UPG_SPEED 800 #define LEVEL3_POUNCE_SPEED_MOD 0.75f #define LEVEL3_POUNCE_TIME 700 -#define LEVEL3_BOUNCEBALL_DMG ADM(120) +#define LEVEL3_BOUNCEBALL_DMG ADM(110) #define LEVEL3_BOUNCEBALL_REPEAT 1000 #define LEVEL3_BOUNCEBALL_SPEED 1000.0f -#define LEVEL4_CLAW_DMG ADM(120) +#define LEVEL4_CLAW_DMG ADM(100) #define LEVEL4_CLAW_RANGE 128.0f #define LEVEL4_CLAW_WIDTH 20.0f #define LEVEL4_CLAW_REPEAT 750 @@ -90,10 +92,11 @@ #define LEVEL4_REGEN_MOD 2.0f #define LEVEL4_CHARGE_SPEED 2.0f #define LEVEL4_CHARGE_TIME 3000 -#define LEVEL4_CHARGE_CHARGE_TIME 1000 +#define LEVEL4_CHARGE_CHARGE_TIME 1500 +#define LEVEL4_MIN_CHARGE_TIME 750 #define LEVEL4_CHARGE_CHARGE_RATIO (LEVEL4_CHARGE_TIME/LEVEL4_CHARGE_CHARGE_TIME) -#define LEVEL4_CHARGE_REPEAT 500 -#define LEVEL4_CHARGE_DMG ADM(160) +#define LEVEL4_CHARGE_REPEAT 1000 +#define LEVEL4_CHARGE_DMG ADM(110) @@ -210,7 +213,7 @@ #define BARRICADE_BP 10 #define BARRICADE_BT 20000 #define BARRICADE_HEALTH ABHM(200) -#define BARRICADE_REGEN 12 +#define BARRICADE_REGEN 14 #define BARRICADE_SPLASHDAMAGE 50 #define BARRICADE_SPLASHRADIUS 50 #define BARRICADE_CREEPSIZE 120 @@ -229,7 +232,7 @@ #define ACIDTUBE_BT 15000 #define ACIDTUBE_HEALTH ABHM(125) #define ACIDTUBE_REGEN 10 -#define ACIDTUBE_SPLASHDAMAGE 30 +#define ACIDTUBE_SPLASHDAMAGE 6 #define ACIDTUBE_SPLASHRADIUS 300 #define ACIDTUBE_CREEPSIZE 120 #define ACIDTUBE_RANGE 300.0f @@ -262,8 +265,8 @@ #define OVERMIND_BP 0 #define OVERMIND_BT 30000 -#define OVERMIND_HEALTH ABHM(500) -#define OVERMIND_REGEN 10 +#define OVERMIND_HEALTH ABHM(750) +#define OVERMIND_REGEN 6 #define OVERMIND_SPLASHDAMAGE 15 #define OVERMIND_SPLASHRADIUS 300 #define OVERMIND_CREEPSIZE 120 @@ -314,12 +317,11 @@ #define BLASTER_REPEAT 600 #define BLASTER_SPREAD 200 -#define BLASTER_SPEED 700 +#define BLASTER_SPEED 1400 #define BLASTER_DMG HDM(9) #define RIFLE_CLIPSIZE 30 -#define RIFLE_SPAWNCLIPS 4 -#define RIFLE_MAXCLIPS 4 +#define RIFLE_MAXCLIPS 6 #define RIFLE_REPEAT 90 #define RIFLE_RELOAD 2000 #define RIFLE_PRICE 0 @@ -328,10 +330,10 @@ #define PAINSAW_PRICE 100 #define PAINSAW_REPEAT 75 -#define PAINSAW_DAMAGE HDM(18) -#define PAINSAW_RANGE 48.0f +#define PAINSAW_DAMAGE HDM(15) +#define PAINSAW_RANGE 40.0f -#define GRENADE_PRICE 300 +#define GRENADE_PRICE 200 #define GRENADE_REPEAT 0 #define GRENADE_DAMAGE HDM(310) #define GRENADE_RANGE 192.0f @@ -340,53 +342,50 @@ #define SHOTGUN_PRICE 150 #define SHOTGUN_SHELLS 8 #define SHOTGUN_PELLETS 8 //used to sync server and client side -#define SHOTGUN_SPAWNCLIPS 2 -#define SHOTGUN_MAXCLIPS 2 -#define SHOTGUN_REPEAT 1200 +#define SHOTGUN_MAXCLIPS 3 +#define SHOTGUN_REPEAT 1000 #define SHOTGUN_RELOAD 2000 #define SHOTGUN_SPREAD 900 -#define SHOTGUN_DMG HDM(6) +#define SHOTGUN_DMG HDM(7) #define LASGUN_PRICE 250 -#define LASGUN_AMMO 150 +#define LASGUN_AMMO 200 #define LASGUN_REPEAT 200 #define LASGUN_RELOAD 2000 #define LASGUN_DAMAGE HDM(9) #define MDRIVER_PRICE 350 #define MDRIVER_CLIPSIZE 5 -#define MDRIVER_SPAWNCLIPS 3 -#define MDRIVER_MAXCLIPS 3 -#define MDRIVER_DMG HDM(35) +#define MDRIVER_MAXCLIPS 4 +#define MDRIVER_DMG HDM(38) #define MDRIVER_REPEAT 1000 #define MDRIVER_RELOAD 2000 #define CHAINGUN_PRICE 400 -#define CHAINGUN_BULLETS 200 +#define CHAINGUN_BULLETS 300 #define CHAINGUN_REPEAT 80 #define CHAINGUN_SPREAD 1000 -#define CHAINGUN_DMG HDM(5) +#define CHAINGUN_DMG HDM(6) #define PRIFLE_PRICE 400 #define PRIFLE_CLIPS 50 -#define PRIFLE_SPAWNCLIPS 2 -#define PRIFLE_MAXCLIPS 2 +#define PRIFLE_MAXCLIPS 4 #define PRIFLE_REPEAT 100 #define PRIFLE_RELOAD 2000 #define PRIFLE_DMG HDM(9) #define PRIFLE_SPEED 1000 #define FLAMER_PRICE 450 -#define FLAMER_GAS 80 -#define FLAMER_REPEAT 300 +#define FLAMER_GAS 150 +#define FLAMER_REPEAT 200 #define FLAMER_DMG HDM(31) #define FLAMER_RADIUS 50 -#define FLAMER_LIFETIME 500.0f +#define FLAMER_LIFETIME 800.0f #define FLAMER_SPEED 200.0f #define FLAMER_LAG 0.65f //the amount of player velocity that is added to the fireball #define LCANNON_PRICE 600 -#define LCANNON_AMMO 60 +#define LCANNON_AMMO 90 #define LCANNON_REPEAT 500 #define LCANNON_CHARGEREPEAT 1000 #define LCANNON_RELOAD 2000 @@ -418,7 +417,7 @@ #define HELMET_PRICE 90 #define HELMET_RANGE 1000.0f -#define ANTITOXIN_PRICE 20 +#define MEDKIT_PRICE 0 #define BATTPACK_PRICE 100 #define BATTPACK_MODIFIER 1.5f //modifier for extra energy storage available @@ -437,6 +436,9 @@ #define GAS_PRICE 0 +#define MEDKIT_POISON_IMMUNITY_TIME 30000 +#define MEDKIT_STARTUP_TIME 4000 +#define MEDKIT_STARTUP_SPEED 5 /* @@ -476,8 +478,8 @@ #define MGTURRET_BP 8 #define MGTURRET_BT 10000 #define MGTURRET_HEALTH HBHM(190) -#define MGTURRET_SPLASHDAMAGE 200 -#define MGTURRET_SPLASHRADIUS 150 +#define MGTURRET_SPLASHDAMAGE 100 +#define MGTURRET_SPLASHRADIUS 100 #define MGTURRET_ANGULARSPEED 8 //degrees/think ~= 200deg/sec #define MGTURRET_ACCURACYTOLERANCE MGTURRET_ANGULARSPEED / 1.5f //angular difference for turret to fire #define MGTURRET_VERTICALCAP 30 // +/- maximum pitch diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c index 200b8b8a..34f77c91 100644 --- a/src/ui/ui_main.c +++ b/src/ui/ui_main.c @@ -3445,6 +3445,7 @@ static void UI_LoadTremHumanArmouryBuys( ) for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) { if( BG_FindTeamForUpgrade( i ) == WUT_HUMANS && + BG_FindPurchasableForUpgrade( i ) && BG_FindStagesForUpgrade( i, stage ) && !( BG_FindSlotsForUpgrade( i ) & slots ) && !( upgrades & ( 1 << i ) ) ) diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 06ba8cde..8d019150 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -3410,6 +3410,7 @@ static bind_t g_bindings[] = { "+button5", K_MOUSE2, -1, -1, -1 }, //TA: secondary attack { "reload", 'r', -1, -1, -1 }, //TA: reload { "buy ammo", 'b', -1, -1, -1 }, //TA: buy ammo + { "itemact medkit", 'm', -1, -1, -1 }, //TA: use medkit { "+button7", 'q', -1, -1, -1 }, //TA: buildable use { "deconstruct", 'e', -1, -1, -1 }, //TA: buildable destroy { "weapprev", '[', -1, -1, -1 }, |