summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cgame/cg_event.c18
-rw-r--r--src/cgame/cg_local.h12
-rw-r--r--src/cgame/cg_main.c16
-rw-r--r--src/cgame/cg_view.c37
-rw-r--r--src/cgame/cg_weapons.c176
-rw-r--r--src/game/bg_misc.c50
-rw-r--r--src/game/bg_mod.h2
-rw-r--r--src/game/bg_public.h2
-rw-r--r--src/game/g_active.c15
-rw-r--r--src/game/g_missile.c38
-rw-r--r--src/game/g_weapon.c64
-rw-r--r--src/game/tremulous.h8
12 files changed, 326 insertions, 112 deletions
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 794b8a4..e5002cd 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -244,10 +244,7 @@ static void CG_Obituary( entityState_t *ent )
else
message = "^5was terminated by own flames";
break;
-
- case MOD_SMOKE:
- message = "^5smoked himself up";
- break;
+
case MOD_ABOMB:
message = "^5bombed himself up";
break;
@@ -338,6 +335,9 @@ static void CG_Obituary( entityState_t *ent )
message = "^5almost dodged^7";
message2 = "^5's ^5rocket";
break;
+ case MOD_LIGHTNING:
+ message = "^5was electrocuted by^7";
+ break;
case MOD_GRENADE:
message = "^5couldn't escape^7";
message2 = "^5's ^5grenade";
@@ -357,11 +357,6 @@ static void CG_Obituary( entityState_t *ent )
message2 = "^5's ^5flames";
break;
- case MOD_SMOKE:
- message = "^5tasted^7";
- message2 = "^5's ^5smoke";
- break;
-
case MOD_ABUILDER_CLAW:
message = "^5should leave^7";
message2 = "^5's ^5buildings alone";
@@ -1014,9 +1009,12 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_METAL, es->torsoAnim );
break;
+#define BUILDABLE_EXPLOSION_QUAKE 50
+
case EV_HUMAN_BUILDABLE_EXPLOSION:
ByteToDir( es->eventParm, dir );
CG_HumanBuildableExplosion( position, dir, es->modelindex );
+ CG_InduceViewQuake( position, BUILDABLE_EXPLOSION_QUAKE );
break;
case EV_ALIEN_BUILDABLE_EXPLOSION:
@@ -1025,6 +1023,8 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
if ( es->modelindex == BA_A_SPITEFUL_ABCESS )
CG_AlienSPITEFUL_ABCESSExplosion( position, dir );
+
+ CG_InduceViewQuake( position, BUILDABLE_EXPLOSION_QUAKE );
break;
//Scleim greifer schwanz f\FCr slime
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index 10e89fd..ab3e9e6 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -787,6 +787,7 @@ typedef struct weaponInfoMode_s
vec3_t flashDlightColor;
sfxHandle_t flashSound[ 4 ]; // fast firing weapons randomly choose
qboolean continuousFlash;
+ float flashQuake;
qhandle_t missileModel;
sfxHandle_t missileSound;
@@ -816,6 +817,7 @@ typedef struct weaponInfoMode_s
qhandle_t impactMarkSize;
sfxHandle_t impactSound[ 4 ]; //random impact sound
sfxHandle_t impactFleshSound[ 4 ]; //random impact sound
+ float impactQuake;
} weaponInfoMode_t;
// each WP_* weapon enum has an associated weaponInfo_t
@@ -1159,6 +1161,8 @@ typedef struct
int nearUsableBuildable;
int nextWeaponClickTime;
+
+ float viewQuake;
} cg_t;
@@ -1341,6 +1345,9 @@ typedef struct
qhandle_t humanBuildPoolBar;
qhandle_t alienNoBPFlash;
qhandle_t humanNoBPFlash;
+
+ qhandle_t lightningBeam;
+ qhandle_t lightningImpactPS;
} cgMedia_t;
typedef struct
@@ -1595,6 +1602,10 @@ extern vmCvar_t cg_chatTeamPrefix;
extern vmCvar_t cg_drawBubble;
extern vmCvar_t cg_BubbleZoom;
+extern vmCvar_t cg_viewQuake;
+extern vmCvar_t cg_viewQuakeLambda;
+extern vmCvar_t cg_viewQuakeLimit;
+
//
// cg_main.c
//
@@ -1636,6 +1647,7 @@ void CG_TestModelNextSkin_f( void );
void CG_TestModelPrevSkin_f( void );
void CG_AddBufferedSound( sfxHandle_t sfx );
void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
+void CG_InduceViewQuake( vec3_t src, float mag );
void CG_OffsetFirstPersonView( void );
void CG_OffsetThirdPersonView( void );
void CG_OffsetShoulderView( void );
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index 3985834..7ed3bfc 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -226,7 +226,11 @@ vmCvar_t cg_chatTeamPrefix;
vmCvar_t cg_drawBubble;
vmCvar_t cg_BubbleZoom;
-vmCvar_t cg_EDGEFPSFIX;
+vmCvar_t cg_EDGEFPSFIX;
+
+vmCvar_t cg_viewQuake;
+vmCvar_t cg_viewQuakeLambda;
+vmCvar_t cg_viewQuakeLimit;
typedef struct
{
@@ -371,7 +375,11 @@ static cvarTable_t cvarTable[ ] =
// { &cg_chatTeamPrefix, "cg_chatTeamPrefix", "1", CVAR_ARCHIVE}
{ &cg_chatTeamPrefix, "cg_chatTeamPrefix", "1", CVAR_ARCHIVE},
- { &cg_EDGEFPSFIX, "cg_EDGEFPSFIX", "0", CVAR_ARCHIVE|CVAR_USERINFO }
+ { &cg_EDGEFPSFIX, "cg_EDGEFPSFIX", "0", CVAR_ARCHIVE|CVAR_USERINFO },
+
+ { &cg_viewQuake, "cg_viewQuake", "1", CVAR_ARCHIVE },
+ { &cg_viewQuakeLambda, "cg_viewQuakeLambda", "-10", CVAR_ARCHIVE },
+ { &cg_viewQuakeLimit, "cg_viewQuakeLimit", "5", CVAR_ARCHIVE }
};
static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
@@ -827,6 +835,8 @@ static void CG_RegisterGraphics( void )
cgs.media.alienNoBPFlash = trap_R_RegisterShader( "ui/assets/alien/nobp_flash.tga" );
cgs.media.humanNoBPFlash = trap_R_RegisterShader( "ui/assets/human/nobp_flash.tga" );
+ cgs.media.lightningBeam = trap_R_RegisterShader( "gfx/lightning/beam" );
+
cgs.media.disconnectPS = CG_RegisterParticleSystem( "disconnectPS" );
CG_UpdateMediaFraction( 0.7f );
@@ -870,6 +880,8 @@ static void CG_RegisterGraphics( void )
cgs.media.humanWoundsBleedPS = CG_RegisterParticleSystem( "humanWoundBleedPS" );
cgs.media.headShotPS = CG_RegisterParticleSystem( "headShotPS" );
+ cgs.media.lightningImpactPS = CG_RegisterParticleSystem( "models/weapons/lightning/impactPS" );
+
CG_BuildableStatusParse( "ui/assets/human/buildstat.cfg", &cgs.humanBuildStat );
CG_BuildableStatusParse( "ui/assets/alien/buildstat.cfg", &cgs.alienBuildStat );
diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c
index a0142d0..eb6e88d 100644
--- a/src/cgame/cg_view.c
+++ b/src/cgame/cg_view.c
@@ -537,6 +537,29 @@ static void CG_StepOffset( void )
#define PCLOUD_ZOOM_FREQUENCY 0.625f // 2.5s / 4
#define PCLOUD_DISORIENT_DURATION 2500
+/*
+===============
+CG_InduceViewQuake
+===============
+*/
+
+void CG_InduceViewQuake( vec3_t src, float mag )
+{
+ if( !src )
+ {
+ cg.viewQuake += mag;
+ }
+ else
+ {
+ float dist;
+
+ dist = Distance( src, cg.refdef.vieworg );
+ cg.viewQuake += mag / dist / dist * 1000.0f;
+ }
+
+ if( cg.viewQuake > cg_viewQuakeLimit.value )
+ cg.viewQuake = cg_viewQuakeLimit.value;
+}
/*
===============
@@ -838,6 +861,20 @@ void CG_OffsetFirstPersonView( void )
// add step offset
CG_StepOffset( );
+
+
+ // view quake
+ if( cg.thisFrameTeleport )
+ {
+ cg.viewQuake = 0;
+ }
+ else
+ {
+ angles[ PITCH ] += crandom( ) * cg.viewQuake * cg_viewQuake.value;
+ angles[ YAW ] += crandom( ) * cg.viewQuake * cg_viewQuake.value;
+
+ cg.viewQuake *= pow( 2, (float)cg.frametime * 1.0e-3 * cg_viewQuakeLambda.value );
+ }
}
//======================================================================
diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
index 2b41d13..8e3b438 100644
--- a/src/cgame/cg_weapons.c
+++ b/src/cgame/cg_weapons.c
@@ -65,8 +65,6 @@ void CG_RegisterUpgrade( int upgradeNum )
upgradeInfo->upgradeIcon = cg_weapons[ WP_GRENADE ].weaponIcon;
else if( upgradeNum == UP_MINE )
upgradeInfo->upgradeIcon = cg_weapons[ WP_MINE ].weaponIcon;
- else if( upgradeNum == UP_SMOKE )
- upgradeInfo->upgradeIcon = cg_weapons[ WP_SMOKE ].weaponIcon;
else if( ( icon = BG_Upgrade( upgradeNum )->icon ) )
upgradeInfo->upgradeIcon = trap_R_RegisterShader( icon );
}
@@ -418,6 +416,26 @@ static qboolean CG_ParseWeaponModeSection( weaponInfoMode_t *wim, char **text_p
continue;
}
+ else if( !Q_stricmp( token, "impactQuake" ) )
+ {
+ token = COM_Parse( text_p );
+ if( !token )
+ break;
+
+ wim->impactQuake = atof( token );
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "flashQuake" ) )
+ {
+ token = COM_Parse( text_p );
+ if( !token )
+ break;
+
+ wim->flashQuake = atof( token );
+
+ continue;
+ }
else if( !Q_stricmp( token, "}" ) )
return qtrue; //reached the end of this weapon section
else
@@ -868,6 +886,60 @@ static float CG_MachinegunSpinAngle( centity_t *cent, qboolean firing )
return angle;
}
+/*
+=============
+CG_RenderGenericBeam
+=============
+*/
+
+void CG_RenderGenericBeam( const vec3_t start, const vec3_t end, qhandle_t shader, float radius )
+{
+ vec3_t delta, viewdelta, side;
+ float length;
+ polyVert_t quad[ 4 ];
+
+ VectorSubtract( end, start, delta );
+ length = VectorLength( delta );
+ VectorSubtract( start, cg.refdef.vieworg, viewdelta );
+ CrossProduct( delta, viewdelta, side );
+ VectorNormalize( side );
+
+ VectorMA( start, radius, side, quad[ 3 ].xyz );
+ VectorMA( start, -radius, side, quad[ 2 ].xyz );
+ VectorMA( end, -radius, side, quad[ 1 ].xyz );
+ VectorMA( end, radius, side, quad[ 0 ].xyz );
+
+ quad[ 0 ].st[ 0 ] = length / radius * 0.1;
+ quad[ 0 ].st[ 1 ] = 0;
+ quad[ 0 ].modulate[ 0 ] = 255;
+ quad[ 0 ].modulate[ 1 ] = 255;
+ quad[ 0 ].modulate[ 2 ] = 255;
+ quad[ 0 ].modulate[ 3 ] = 255;
+
+ quad[ 1 ].st[ 0 ] = length / radius * 0.1;
+ quad[ 1 ].st[ 1 ] = 1;
+ quad[ 1 ].modulate[ 0 ] = 255;
+ quad[ 1 ].modulate[ 1 ] = 255;
+ quad[ 1 ].modulate[ 2 ] = 255;
+ quad[ 1 ].modulate[ 3 ] = 255;
+
+ quad[ 2 ].st[ 0 ] = 0;
+ quad[ 2 ].st[ 1 ] = 1;
+ quad[ 2 ].modulate[ 0 ] = 255;
+ quad[ 2 ].modulate[ 1 ] = 255;
+ quad[ 2 ].modulate[ 2 ] = 255;
+ quad[ 2 ].modulate[ 3 ] = 255;
+
+ quad[ 3 ].st[ 0 ] = 0;
+ quad[ 3 ].st[ 1 ] = 0;
+ quad[ 3 ].modulate[ 0 ] = 255;
+ quad[ 3 ].modulate[ 1 ] = 255;
+ quad[ 3 ].modulate[ 2 ] = 255;
+ quad[ 3 ].modulate[ 3 ] = 255;
+
+ trap_R_AddPolyToScene( shader, 4, quad );
+}
+
/*
=============
@@ -878,6 +950,7 @@ The main player will have this called for BOTH cases, so effects like light and
sound should only be done on the world model case.
=============
*/
+
void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent )
{
refEntity_t gun;
@@ -1116,6 +1189,66 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
cent->muzzlePsTrigger = qfalse;
}
+ // Lightning Gun's beam
+ if( weaponNum == WP_LIGHTNING_GUN )
+ {
+ attachment_t attachment;
+ vec3_t muzzle, forward, end, beam_start;
+ trace_t tr;
+
+ if( ps )
+ {
+ BG_GetClientViewOrigin( ps, muzzle );
+ AngleVectors( ps->viewangles, forward, NULL, NULL );
+ }
+ else
+ {
+ // NOTE: this code assumes that the player's normal is (0,0,1)
+ // it will break when humans start walking on walls
+ class_t class = ( cent->currentState.misc >> 8 ) & 0xFF;
+
+ VectorCopy( cent->lerpOrigin, muzzle );
+
+ // the only way to tell if a human is crouching is to check its bbox
+ // which is transmitted in a weird, encoded form (hence the magic number)
+ if( class == PCL_HUMAN && cent->currentState.solid == 3151887 )
+ muzzle[ 2 ] += BG_ClassConfig( class )->crouchViewheight;
+ else
+ muzzle[ 2 ] += BG_ClassConfig( class )->viewheight;
+
+ AngleVectors( cent->lerpAngles, forward, NULL, NULL );
+ }
+
+ VectorMA( muzzle, LIGHTNING_RANGE, forward, end );
+
+ CG_Trace( &tr, muzzle, NULL, NULL, end, cg.predictedPlayerState.clientNum, MASK_SHOT );
+
+ memset( &attachment, 0, sizeof( attachment ) );
+
+ if( noGunModel )
+ CG_SetAttachmentTag( &attachment, *parent, parent->hModel, "tag_weapon" );
+ else
+ CG_SetAttachmentTag( &attachment, gun, gun.hModel, "tag_flash" );
+
+ CG_AttachToTag( &attachment );
+
+ if( CG_AttachmentPoint( &attachment, beam_start ) )
+ CG_RenderGenericBeam( beam_start, tr.endpos, cgs.media.lightningBeam, 3 );
+
+ if( tr.entityNum != ENTITYNUM_NONE &&
+ !( tr.surfaceFlags & SURF_NOIMPACT ) )
+ {
+ particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.lightningImpactPS );
+
+ if( CG_IsParticleSystemValid( &ps ) )
+ {
+ CG_SetAttachmentPoint( &ps->attachment, tr.endpos );
+ CG_SetParticleSystemNormal( ps, tr.plane.normal );
+ CG_AttachToPoint( &ps->attachment );
+ }
+ }
+ }
+
// make a dlight for the flash
if( weapon->wim[ weaponMode ].flashDlightColor[ 0 ] ||
weapon->wim[ weaponMode ].flashDlightColor[ 1 ] ||
@@ -1254,6 +1387,15 @@ void CG_AddViewWeapon( playerState_t *ps )
}
+ // Lightning Gun vibration effect
+ if( ( weapon == WP_LIGHTNING_GUN ) && ps->eFlags & EF_FIRING )
+ {
+ VectorMA( hand.origin, random( ) * 0.1, cg.refdef.viewaxis[ 0 ],
+ hand.origin );
+ VectorMA( hand.origin, random( ) * 0.1, cg.refdef.viewaxis[ 1 ],
+ hand.origin );
+ }
+
AnglesToAxis( angles, hand.axis );
// map torso animations to weapon animations
@@ -1654,6 +1796,7 @@ void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode )
int c;
weaponInfo_t *wi;
weapon_t weaponNum;
+ qboolean skipSound = qfalse;
es = &cent->currentState;
@@ -1673,6 +1816,10 @@ void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode )
wi = &cg_weapons[ weaponNum ];
+ if( wi->wim[ weaponMode ].continuousFlash &&
+ cent->muzzleFlashTime >= cg.time - 100 )
+ skipSound = qtrue;
+
// mark the entity as muzzle flashing, so when it is added it will
// append the flash to the weapon model
cent->muzzleFlashTime = cg.time;
@@ -1684,6 +1831,9 @@ void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode )
cent->muzzlePsTrigger = qtrue;
}
+ if( skipSound )
+ return;
+
// play a sound
for( c = 0; c < 4; c++ )
{
@@ -1697,6 +1847,14 @@ void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode )
if( wi->wim[ weaponMode ].flashSound[ c ] )
trap_S_StartSound( NULL, es->number, CHAN_WEAPON, wi->wim[ weaponMode ].flashSound[ c ] );
}
+
+ if( cent == &cg.predictedPlayerEntity )
+ {
+ float quake;
+
+ quake = wi->wim[ weaponMode ].flashQuake;
+ CG_InduceViewQuake( NULL, quake );
+ }
}
@@ -1713,7 +1871,7 @@ void CG_MissileHitWall( weapon_t weaponNum, weaponMode_t weaponMode, int clientN
qhandle_t mark = 0;
qhandle_t ps = 0;
int c;
- float radius = 1.0f;
+ float radius = 1.0f, quake;
weaponInfo_t *weapon = &cg_weapons[ weaponNum ];
if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES )
@@ -1722,6 +1880,7 @@ void CG_MissileHitWall( weapon_t weaponNum, weaponMode_t weaponMode, int clientN
mark = weapon->wim[ weaponMode ].impactMark;
radius = weapon->wim[ weaponMode ].impactMarkSize;
ps = weapon->wim[ weaponMode ].impactParticleSystem;
+ quake = weapon->wim[ weaponMode ].impactQuake;
if( soundType == IMPACTSOUND_FLESH )
{
@@ -1775,6 +1934,11 @@ void CG_MissileHitWall( weapon_t weaponNum, weaponMode_t weaponMode, int clientN
//
if( radius > 0.0f )
CG_ImpactMark( mark, origin, dir, random( ) * 360, 1, 1, 1, 1, qfalse, radius, qfalse );
+
+ if( weaponNum == WP_LUCIFER_CANNON )
+ quake *= charge;
+
+ CG_InduceViewQuake( origin, quake );
}
@@ -1788,6 +1952,7 @@ void CG_MissileHitEntity( weapon_t weaponNum, weaponMode_t weaponMode,
{
vec3_t normal;
weaponInfo_t *weapon = &cg_weapons[ weaponNum ];
+ float quake = weapon->wim[ weaponMode ].impactQuake;
VectorCopy( dir, normal );
VectorInverse( normal );
@@ -1817,6 +1982,11 @@ void CG_MissileHitEntity( weapon_t weaponNum, weaponMode_t weaponMode,
CG_MissileHitWall( weaponNum, weaponMode, 0, origin, dir, sound, charge );
}
+
+ if( weaponNum == WP_LUCIFER_CANNON )
+ quake *= charge;
+
+ CG_InduceViewQuake( origin, quake );
}
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 92f3826..efdc300 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -3575,6 +3575,31 @@ static const weaponAttributes_t bg_weapons[ ] =
TEAM_HUMANS //team_t team;
},
{
+ WP_LIGHTNING_GUN, //int weaponNum;
+ LIGHTNING_PRICE, //int price;
+ STAGE_GE_5, //int stages
+ SLOT_WEAPON, //int slots;
+ "lightning", //char *weaponName;
+ "[yefarms]Lightning Gun", //char *humanName;
+ "This is a lightning gun. It guns lightning.",
+ LIGHTNING_AMMO, //int maxAmmo;
+ 0, //int maxClips;
+ qfalse, //int infiniteAmmo;
+ qtrue, //int usesEnergy;
+ LIGHTNING_REPEAT, //int repeatRate1;
+ 0, //int repeatRate2;
+ 0, //int repeatRate3;
+ 0, //int reloadTime;
+ LIGHTNING_K_SCALE, //float knockbackScale;
+ qfalse, //qboolean hasAltMode;
+ qfalse, //qboolean hasThirdMode;
+ qfalse, //qboolean canZoom;
+ 90.0f, //float zoomFov;
+ qtrue, //qboolean purchasable;
+ qtrue, //qboolean longRanged;
+ TEAM_HUMANS //team_t team;
+ },
+ {
WP_LUCIFER_CANNON, //int weaponNum;
LCANNON_PRICE, //int price;
STAGE_GE_5, //int stages
@@ -3652,31 +3677,6 @@ static const weaponAttributes_t bg_weapons[ ] =
TEAM_HUMANS //team_t team;
},
{
- WP_SMOKE, //int weaponNum;
- SMOKE_PRICE, //int price;
- STAGE_GE_5, //int stages
- SLOT_NONE, //int slots;
- "smoke", //char *weaponName;
- "Smoke", //char *weaponHumanName;
- "",
- 1, //int maxAmmo;
- 0, //int maxClips;
- qfalse, //int infiniteAmmo;
- qfalse, //int usesEnergy;
- SMOKE_REPEAT, //int repeatRate1;
- 0, //int repeatRate2;
- 0, //int repeatRate3;
- 0, //int reloadTime;
- SMOKE_K_SCALE, //float knockbackScale;
- qfalse, //qboolean hasAltMode;
- qfalse, //qboolean hasThirdMode;
- qfalse, //qboolean canZoom;
- 90.0f, //float zoomFov;
- qfalse, //qboolean purchasable;
- qfalse, //qboolean longRanged;
- TEAM_HUMANS //WUTeam_t team;
- },
- {
WP_MINE, //int weaponNum;
MINE_PRICE, //int price;
STAGE_GE_5, //int stages
diff --git a/src/game/bg_mod.h b/src/game/bg_mod.h
index 5e4245b..6f09037 100644
--- a/src/game/bg_mod.h
+++ b/src/game/bg_mod.h
@@ -8,6 +8,7 @@ MOD( MOD_CHAINGUN ),
MOD( MOD_PRIFLE ),
MOD( MOD_MDRIVER ),
MOD( MOD_LASGUN ),
+MOD( MOD_LIGHTNING ),
MOD( MOD_LCANNON ),
MOD( MOD_LCANNON_SPLASH ),
MOD( MOD_FLAMER ),
@@ -18,7 +19,6 @@ MOD( MOD_GRENADE ),
MOD( MOD_PSAWBLADE ),
MOD( MOD_MINE ),
MOD( MOD_FLAMES ),
-MOD( MOD_SMOKE ),
MOD( MOD_SPITEFUL_ABCESS ),
MOD( MOD_WATER ),
MOD( MOD_SLIME ),
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 9edd57b..bbf064e 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -357,10 +357,10 @@ typedef enum
WP_CHAINGUN,
WP_FLAMER,
WP_PULSE_RIFLE,
+ WP_LIGHTNING_GUN,
WP_LUCIFER_CANNON,
WP_ROCKET_LAUNCHER,
WP_GRENADE,
- WP_SMOKE,
WP_MINE,
WP_LOCKBLOB_LAUNCHER,
WP_HIVE,
diff --git a/src/game/g_active.c b/src/game/g_active.c
index c7a8977..951a3a9 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -1941,21 +1941,6 @@ void ClientThink_real( gentity_t *ent )
ent->s.weapon = lastWeapon;
}
- if( BG_InventoryContainsUpgrade( UP_SMOKE, client->ps.stats ) &&
- BG_UpgradeIsActive( UP_SMOKE, client->ps.stats ) )
- {
- int lastWeapon = ent->s.weapon;
-
- //remove SMOKE
- BG_DeactivateUpgrade( UP_SMOKE, client->ps.stats );
- BG_RemoveUpgradeFromInventory( UP_SMOKE, client->ps.stats );
-
- //M-M-M-M-MONSTER HACK
- ent->s.weapon = WP_SMOKE;
- FireWeapon( ent );
- ent->s.weapon = lastWeapon;
- }
-
// set speed
if( client->ps.pm_type == PM_NOCLIP )
client->ps.speed = client->pers.flySpeed;
diff --git a/src/game/g_missile.c b/src/game/g_missile.c
index fddfe3b..ab0156b 100644
--- a/src/game/g_missile.c
+++ b/src/game/g_missile.c
@@ -1242,44 +1242,6 @@ gentity_t *launch_saw( gentity_t *self, vec3_t start, vec3_t dir )
return bolt;
}
-
-gentity_t *launch_smoke( gentity_t *self, vec3_t start, vec3_t dir )
-{
- gentity_t *bolt;
-
- VectorNormalize( dir );
- bolt = G_Spawn( );
- bolt->classname = "smoke";
- bolt->nextthink = level.time + 200;
- bolt->think = G_ProcessSmoke;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_SMOKE;
- bolt->s.eFlags = EF_BOUNCE_HALF;
- bolt->s.generic1 = WPM_PRIMARY; //weaponMode
- bolt->r.ownerNum = self->s.number;
- bolt->parent = self;
- bolt->damage = SMOKE_DAMAGE;
- bolt->splashDamage = 0;
- bolt->splashRadius = 0;
- bolt->methodOfDeath = MOD_SMOKE;
- bolt->splashMethodOfDeath = MOD_SMOKE;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
- bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -3.0f;
- bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 3.0f;
- bolt->s.time = level.time;
- bolt->s.pos.trType = TR_GRAVITY;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, SMOKE_SPEED, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
-
- VectorCopy( start, bolt->r.currentOrigin );
-
- return bolt;
-}
-
/*
================
AHive_SearchAndDestroy
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 5453913..1c333ab 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -698,18 +698,6 @@ void acidBombFire2x( gentity_t *ent, int wp )
/*
======================================================================
-SMOKE
-======================================================================
-*/
-
-void throwSmoke( gentity_t *ent )
-{
- gentity_t *m;
- m = launch_smoke( ent, muzzle, forward );
-}
-
-/*
-======================================================================
LAS GUN
======================================================================
*/
@@ -831,9 +819,7 @@ void LCChargeFire( gentity_t *ent, qboolean secondary )
/*
======================================================================
-
-PULSE RIFLE
-
+ROCKET LAUNCHER
======================================================================
*/
@@ -842,6 +828,48 @@ void rocketLauncherFire( gentity_t *ent )
fire_rocket( ent, muzzle, forward );
}
+
+/*
+======================================================================
+LIGHTNING GUN
+======================================================================
+*/
+
+void lightningGunFire( gentity_t *ent )
+{
+ vec3_t start, end;
+ trace_t tr;
+ gentity_t *target;
+
+ VectorMA( muzzle, LIGHTNING_RANGE, forward, end );
+
+ G_UnlaggedOn( ent, muzzle, LIGHTNING_RANGE );
+ trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+ G_UnlaggedOff( );
+
+ if( tr.fraction == 1.0f ||
+ tr.entityNum == ENTITYNUM_NONE ||
+ ( tr.surfaceFlags & SURF_NOIMPACT ) )
+ return;
+
+ target = g_entities + tr.entityNum;
+
+ if( target->s.eType == ET_PLAYER || target->s.eType == ET_BUILDABLE )
+ BloodSpurt( ent, target, &tr );
+ else
+ {
+ gentity_t *tent;
+
+ tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
+ tent->s.eventParm = DirToByte( tr.plane.normal );
+ tent->s.weapon = ent->s.weapon;
+ tent->s.generic1 = ent->s.generic1;
+ }
+
+ G_Damage( target, ent, ent, forward, tr.endpos, LIGHTNING_DAMAGE, 0, MOD_LIGHTNING );
+}
+
+
/*
======================================================================
TESLA GENERATOR
@@ -1988,15 +2016,15 @@ void FireWeapon( gentity_t *ent )
case WP_ROCKET_LAUNCHER:
rocketLauncherFire( ent );
break;
+ case WP_LIGHTNING_GUN:
+ lightningGunFire( ent );
+ break;
case WP_GRENADE:
throwGrenade( ent );
break;
case WP_MINE:
throwMine( ent );
break;
- case WP_SMOKE:
- throwSmoke( ent );
- break;
case WP_LOCKBLOB_LAUNCHER:
lockBlobLauncherFire( ent );
break;
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index d05ebe4..3b9c8bc 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -514,6 +514,14 @@ TREMULOUS EDGE MOD SRC FILE
#define PRIFLE_SECONDARY_SPEED 900
#define PRIFLE_SECONDARY_REPEAT 400
+#define LIGHTNING_PRICE 500
+#define LIGHTNING_AMMO 300
+#define LIGHTNING_K_SCALE 1
+#define LIGHTNING_DPS 60 // damage per second
+#define LIGHTNING_REPEAT 50 // keep it as low as possible
+#define LIGHTNING_DAMAGE ( LIGHTNING_DPS * LIGHTNING_REPEAT / 1000 )
+#define LIGHTNING_RANGE 450
+
#define LCANNON_PRICE 600
#define LCANNON_AMMO 80
#define LCANNON_K_SCALE 1.0f