summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--entities.def4
-rw-r--r--src/cgame/cg_animmapobj.c53
-rw-r--r--src/cgame/cg_ents.c30
-rw-r--r--src/cgame/cg_event.c3
-rw-r--r--src/cgame/cg_weapons.c12
-rw-r--r--src/game/bg_misc.c55
-rw-r--r--src/game/bg_public.h31
-rw-r--r--src/game/g_buildable.c83
-rw-r--r--src/game/g_local.h1
-rw-r--r--src/game/g_missile.c225
-rw-r--r--src/game/g_mover.c28
-rw-r--r--src/game/g_weapon.c20
-rw-r--r--src/game/tremulous.h20
13 files changed, 434 insertions, 131 deletions
diff --git a/entities.def b/entities.def
index dbec7e76..03ba5228 100644
--- a/entities.def
+++ b/entities.def
@@ -285,7 +285,7 @@ color: constantLight color of .md3 model included with entity. Has no effect on
model2: path/name of the door model (eg: models/mapobjects/pipe/pipe02.md3).
-origin: alternate method of setting XYZ origin of .md3 model included with entity (See Notes).
+modelOrigin: means of setting the origin of the model.
scale: scale the model in each of the major axes (e.g. 1.0 1.0 2.0 -- twice as high as normal).
@@ -325,7 +325,7 @@ _layers OR layers: Integer value is the number unique root shaders that will be
_shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix.
-------- NOTES --------
-The func_door_model provides two means of positioning and scaling the model representing the door. Firstly if neither the origin nor scale keys are set the client will attempt to scale and position the model so that it fills the associated brush (which incidentally is only used for clipping). This will only work with axially aligned brushes however, so the second method allows the setting of origin and scale manually, providing complete control over the model. In both cases the angle/angles keys are used to affect the orientation of the model.
+Every func_door_model needs its model to be positioned, scaled and orientated using the modelOrigin, scale and angle/angles keys repsectively.
*/
//=============================================================================
diff --git a/src/cgame/cg_animmapobj.c b/src/cgame/cg_animmapobj.c
index 46b64073..2fc98bc6 100644
--- a/src/cgame/cg_animmapobj.c
+++ b/src/cgame/cg_animmapobj.c
@@ -125,11 +125,12 @@ void CG_ModelDoor( centity_t *cent )
{
refEntity_t ent;
entityState_t *es;
- vec3_t mins, maxs, size;
+ vec3_t mins, maxs, size, rotSize;
vec3_t cMins, cMaxs, displacement;
vec3_t bMaxs, scale;
animation_t anim;
lerpFrame_t *lf = &cent->lerpFrame;
+ float temp;
es = &cent->currentState;
@@ -149,51 +150,11 @@ void CG_ModelDoor( centity_t *cent )
ent.skinNum = 0;
ent.hModel = cgs.gameModels[ es->modelindex ];
- if( es->eFlags & EF_NO_AUTO_SCALE )
- {
- //this door is being manually scaled
- VectorScale( ent.axis[ 0 ], es->origin2[ 0 ], ent.axis[ 0 ] );
- VectorScale( ent.axis[ 1 ], es->origin2[ 1 ], ent.axis[ 1 ] );
- VectorScale( ent.axis[ 2 ], es->origin2[ 2 ], ent.axis[ 2 ] );
- ent.nonNormalizedAxes = qtrue;
- }
- else
- {
- //automatically scale and position the model
- trap_R_ModelBounds( ent.hModel, mins, maxs );
-
- //average of mins and maxs
- VectorSubtract( maxs, mins, size );
- VectorScale( size, 0.5f, size );
-
- //set corrected bbox
- VectorCopy( size, cMaxs );
- VectorNegate( size, cMins );
-
- //calculate the displacement needed to align
- //the model with the centre of the brush
- VectorSubtract( cMins, mins, displacement );
-
- VectorCopy( es->angles2, bMaxs );
-
- //scale the axis and displacement by the ratio
- //of the brush to corrected bboxes
- scale[ 0 ] = bMaxs[ 0 ] / cMaxs[ 0 ];
- scale[ 1 ] = bMaxs[ 1 ] / cMaxs[ 1 ];
- scale[ 2 ] = bMaxs[ 2 ] / cMaxs[ 2 ];
-
- VectorScale( ent.axis[ 0 ], scale[ 0 ], ent.axis[ 0 ] );
- VectorScale( ent.axis[ 1 ], scale[ 1 ], ent.axis[ 1 ] );
- VectorScale( ent.axis[ 2 ], scale[ 2 ], ent.axis[ 2 ] );
- ent.nonNormalizedAxes = qtrue;
-
- displacement[ 0 ] = scale[ 0 ] * displacement[ 0 ];
- displacement[ 1 ] = scale[ 1 ] * displacement[ 1 ];
- displacement[ 2 ] = scale[ 2 ] * displacement[ 2 ];
-
- VectorAdd( ent.origin, displacement, ent.origin );
- VectorAdd( ent.oldorigin, displacement, ent.oldorigin );
- }
+ //scale the door
+ VectorScale( ent.axis[ 0 ], es->origin2[ 0 ], ent.axis[ 0 ] );
+ VectorScale( ent.axis[ 1 ], es->origin2[ 1 ], ent.axis[ 1 ] );
+ VectorScale( ent.axis[ 2 ], es->origin2[ 2 ], ent.axis[ 2 ] );
+ ent.nonNormalizedAxes = qtrue;
//setup animation
anim.firstFrame = es->powerups;
diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c
index 6a1fa650..c7590ca0 100644
--- a/src/cgame/cg_ents.c
+++ b/src/cgame/cg_ents.c
@@ -323,6 +323,7 @@ static void CG_Missile( centity_t *cent )
vec3_t up;
float fraction;
int index;
+ qboolean switchBugWorkaround = qfalse;
s1 = &cent->currentState;
if( s1->weapon > WP_NUM_WEAPONS )
@@ -367,7 +368,7 @@ static void CG_Missile( centity_t *cent )
ent.rotation = 0;
ent.customShader = cgs.media.blasterShader;
trap_R_AddRefEntityToScene( &ent );
- return;
+ switchBugWorkaround = qtrue;
break;
case WP_PULSE_RIFLE:
@@ -376,7 +377,7 @@ static void CG_Missile( centity_t *cent )
ent.rotation = 0;
ent.customShader = cgs.media.plasmaBallShader;
trap_R_AddRefEntityToScene( &ent );
- return;
+ switchBugWorkaround = qtrue;
break;
case WP_LUCIFER_CANNON:
@@ -398,9 +399,27 @@ static void CG_Missile( centity_t *cent )
break;
+ case WP_HIVE:
+ //FIXME:
+ ent.reType = RT_SPRITE;
+ ent.radius = 4;
+ ent.rotation = 0;
+ ent.customShader = cgs.media.blasterShader;
+ trap_R_AddRefEntityToScene( &ent );
+ switchBugWorkaround = qtrue;
+ break;
+
+/* case WP_LOCKBLOB_LAUNCHER:
+ //FIXME:
+ break;*/
+
+/* case WP_POUNCE_UPG:
+ //FIXME:
+ break;*/
+
case WP_FLAMER:
//TA: don't actually display the missile (use the particle engine)
- return;
+ switchBugWorkaround = qtrue;
break;
default:
@@ -410,7 +429,7 @@ static void CG_Missile( centity_t *cent )
ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
// convert direction of travel into axis
- if ( VectorNormalize2( s1->pos.trDelta, ent.axis[ 0 ] ) == 0 )
+ if( VectorNormalize2( s1->pos.trDelta, ent.axis[ 0 ] ) == 0 )
ent.axis[ 0 ][ 2 ] = 1;
// spin as it moves
@@ -420,6 +439,9 @@ static void CG_Missile( centity_t *cent )
RotateAroundDirection( ent.axis, s1->time );
}
+ if( switchBugWorkaround )
+ return;
+
// add to refresh list, possibly with quad glow
CG_AddRefEntityWithPowerups( &ent, s1->powerups, TEAM_FREE );
}
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 7d8f38c5..5907228a 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -111,6 +111,9 @@ static void CG_Obituary( entityState_t *ent )
case MOD_SLOWBLOB:
message = "should have visited a medical station";
break;
+ case MOD_SWARM:
+ message = "was hunted down by the swarm";
+ break;
default:
message = NULL;
break;
diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
index 343e359d..7fd3b627 100644
--- a/src/cgame/cg_weapons.c
+++ b/src/cgame/cg_weapons.c
@@ -1559,6 +1559,7 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im
int duration;
vec3_t sprOrg;
vec3_t sprVel;
+ qboolean switchBugWorkaround = qfalse;
mark = 0;
radius = 32;
@@ -1576,7 +1577,6 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im
switch( weapon )
{
- default:
case WP_TESLAGEN:
case WP_AREA_ZAP:
case WP_DIRECT_ZAP:
@@ -1672,8 +1672,18 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im
spark, qfalse, qfalse );
}
break;
+
+ case WP_HIVE:
+ switchBugWorkaround = qtrue;
+ break;
+
+ default:
+ break;
}
+ if( switchBugWorkaround )
+ return;
+
if( sfx )
trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 01033261..eca4e53d 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -153,6 +153,39 @@ buildableAttributes_t bg_buildableList[ ] =
qfalse //qboolean reactorTest;
},
{
+ BA_A_HIVE, //int buildNum;
+ "hive", //char *buildName;
+ "Hive", //char *humanName;
+ "team_alien_hive", //char *entityName;
+ { "models/buildables/acid_tube/acid_tube.md3", 0, 0, 0 },
+ { -35, -35, -11 }, //vec3_t mins;
+ { 35, 35, 40 }, //vec3_t maxs;
+ TR_GRAVITY, //trType_t traj;
+ 0.0, //float bounce;
+ HIVE_BP, //int buildPoints;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ HIVE_HEALTH, //int health;
+ HIVE_REGEN, //int regenRate;
+ HIVE_SPLASHDAMAGE, //int splashDamage;
+ HIVE_SPLASHRADIUS, //int splashRadius;
+ MOD_ASPAWN, //int meansOfDeath;
+ BIT_ALIENS, //int team;
+ ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
+ BANIM_IDLE1, //int idleAnim;
+ 500, //int nextthink;
+ 10000, //int buildTime;
+ qfalse, //qboolean usable;
+ 0, //int turretRange;
+ 0, //int turretFireSpeed;
+ WP_HIVE, //weapon_t turretProjType;
+ 0.707f, //float minNormal;
+ qtrue, //qboolean invertNormal;
+ qtrue, //qboolean creepTest;
+ HIVE_CREEPSIZE, //int creepSize;
+ qfalse, //qboolean dccTest;
+ qfalse //qboolean reactorTest;
+ },
+ {
BA_A_TRAPPER, //int buildNum;
"trapper", //char *buildName;
"Trapper", //char *humanName;
@@ -2622,6 +2655,28 @@ weaponAttributes_t bg_weapons[ ] =
WUT_ALIENS //WUTeam_t team;
},
{
+ WP_HIVE, //int weaponNum;
+ 0, //int price;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ SLOT_WEAPON, //int slots;
+ "hive", //char *weaponName;
+ "Hive", //char *weaponHumanName;
+ 0, //int quan;
+ 0, //int clips;
+ 0, //int maxClips;
+ qtrue, //int infiniteAmmo;
+ qfalse, //int usesEnergy;
+ 500, //int repeatRate1;
+ 500, //int repeatRate2;
+ 500, //int repeatRate3;
+ 0, //int reloadTime;
+ qfalse, //qboolean hasAltMode;
+ qfalse, //qboolean hasThirdMode;
+ qfalse, //qboolean purchasable;
+ 0, //int buildDelay;
+ WUT_ALIENS //WUTeam_t team;
+ },
+ {
WP_MGTURRET, //int weaponNum;
0, //int price;
( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index a519595f..494c3cf7 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -268,20 +268,20 @@ typedef enum
#define EF_PLAYER_EVENT 0x00000004
#define EF_BOUNCE 0x00000008 // for missiles
#define EF_BOUNCE_HALF 0x00000010 // for missiles
-#define EF_WALLCLIMB 0x00000020 // TA: wall walking
-#define EF_WALLCLIMBCEILING 0x00000040 // TA: wall walking ceiling hack
-#define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items)
-#define EF_FIRING 0x00000100 // for lightning gun
-#define EF_FIRING2 0x00000200 // alt fire
-#define EF_FIRING3 0x00000400 // third fire
-#define EF_MOVER_STOP 0x00000800 // will push otherwise
-#define EF_TALK 0x00001000 // draw a talk balloon
-#define EF_CONNECTION 0x00002000 // draw a connection trouble sprite
-#define EF_VOTED 0x00004000 // already cast a vote
-#define EF_TEAMVOTED 0x00008000 // already cast a vote
-#define EF_OVERDRAW_OFF 0x00010000 // TA: disable overdraw protection on sprites
-#define EF_REAL_LIGHT 0x00020000 // TA: light sprites according to ambient light
-#define EF_NO_AUTO_SCALE 0x00040000 // TA: don't auto scale model doors
+#define EF_NO_BOUNCE_SOUND 0x00000020 // for missiles
+#define EF_WALLCLIMB 0x00000040 // TA: wall walking
+#define EF_WALLCLIMBCEILING 0x00000080 // TA: wall walking ceiling hack
+#define EF_NODRAW 0x00000100 // may have an event, but no model (unspawned items)
+#define EF_FIRING 0x00000200 // for lightning gun
+#define EF_FIRING2 0x00000400 // alt fire
+#define EF_FIRING3 0x00000800 // third fire
+#define EF_MOVER_STOP 0x00001000 // will push otherwise
+#define EF_TALK 0x00002000 // draw a talk balloon
+#define EF_CONNECTION 0x00004000 // draw a connection trouble sprite
+#define EF_VOTED 0x00008000 // already cast a vote
+#define EF_TEAMVOTED 0x00010000 // already cast a vote
+#define EF_OVERDRAW_OFF 0x00020000 // TA: disable overdraw protection on sprites
+#define EF_REAL_LIGHT 0x00040000 // TA: light sprites according to ambient light
typedef enum
{
@@ -335,6 +335,7 @@ typedef enum
WP_PAIN_SAW,
WP_LOCKBLOB_LAUNCHER,
+ WP_HIVE,
WP_TESLAGEN,
WP_MGTURRET,
@@ -397,6 +398,7 @@ typedef enum
BA_A_ACIDTUBE,
BA_A_TRAPPER,
BA_A_BOOSTER,
+ BA_A_HIVE,
BA_A_HOVEL,
@@ -825,6 +827,7 @@ typedef enum
MOD_SLOWBLOB,
MOD_POISON,
+ MOD_SWARM,
MOD_HSPAWN,
MOD_TESLAGEN,
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 6ff424f0..50b64f1c 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -663,7 +663,7 @@ void ABarricade_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker,
================
ABarricade_Think
-think function for Alien Barricade
+Think function for Alien Barricade
================
*/
void ABarricade_Think( gentity_t *self )
@@ -694,7 +694,7 @@ void AAcidTube_Think( gentity_t *self );
================
AAcidTube_Damage
-damage function for Alien Acid Tube
+Damage function for Alien Acid Tube
================
*/
void AAcidTube_Damage( gentity_t *self )
@@ -729,7 +729,7 @@ void AAcidTube_Damage( gentity_t *self )
================
AAcidTube_Think
-think function for Alien Acid Tube
+Think function for Alien Acid Tube
================
*/
void AAcidTube_Think( gentity_t *self )
@@ -782,6 +782,77 @@ void AAcidTube_Think( gentity_t *self )
+/*
+================
+AHive_Think
+
+Think function for Alien Hive
+================
+*/
+void AHive_Think( gentity_t *self )
+{
+ int entityList[ MAX_GENTITIES ];
+ vec3_t range = { ACIDTUBE_RANGE, ACIDTUBE_RANGE, ACIDTUBE_RANGE };
+ vec3_t mins, maxs;
+ int i, num;
+ gentity_t *enemy;
+ vec3_t dirToTarget;
+
+ self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+
+ VectorAdd( self->s.origin, range, maxs );
+ VectorSubtract( self->s.origin, range, mins );
+
+ //if there is no creep nearby die
+ if( !findCreep( self ) )
+ {
+ G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+ return;
+ }
+
+ if( self->timestamp < level.time )
+ self->active = qfalse; //nothing has returned in HIVE_REPEAT seconds, forget about it
+
+ if( self->spawned && !self->active )
+ {
+ //do some damage
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
+ {
+ enemy = &g_entities[ entityList[ i ] ];
+
+ if( enemy->health <= 0 )
+ continue;
+
+ if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ {
+ self->active = qtrue;
+ self->target_ent = enemy;
+ self->timestamp = level.time + HIVE_REPEAT;
+
+ VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget );
+ VectorNormalize( dirToTarget );
+ vectoangles( dirToTarget, self->turretAim );
+
+ //fire at target
+ FireWeapon( self );
+ G_setBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ return;
+ }
+ }
+ }
+
+ creepSlow( self->s.modelindex, self->s.origin );
+}
+
+
+
+
+//==================================================================================
+
+
+
+
#define HOVEL_TRACE_DEPTH 16.0f
/*
@@ -2091,6 +2162,12 @@ gentity_t *G_buildItem( gentity_t *builder, buildable_t buildable, vec3_t origin
built->pain = ASpawn_Pain;
break;
+ case BA_A_HIVE:
+ built->die = ABarricade_Die;
+ built->think = AHive_Think;
+ built->pain = ASpawn_Pain;
+ break;
+
case BA_A_TRAPPER:
built->die = ABarricade_Die;
built->think = ATrapper_Think;
diff --git a/src/game/g_local.h b/src/game/g_local.h
index e65d1e69..9d78b932 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -656,6 +656,7 @@ gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir, int da
gentity_t *fire_lockblob( gentity_t *self, vec3_t start, vec3_t dir );
gentity_t *fire_paraLockBlob( gentity_t *self, vec3_t start, vec3_t dir );
gentity_t *fire_slowBlob( gentity_t *self, vec3_t start, vec3_t dir );
+gentity_t *fire_hive( gentity_t *self, vec3_t start, vec3_t dir );
//
diff --git a/src/game/g_missile.c b/src/game/g_missile.c
index 76f3cd10..8eb4169f 100644
--- a/src/game/g_missile.c
+++ b/src/game/g_missile.c
@@ -89,6 +89,7 @@ void G_ExplodeMissile( gentity_t *ent )
trap_LinkEntity( ent );
}
+void AHive_ReturnToHive( gentity_t *self );
/*
================
@@ -98,38 +99,25 @@ G_MissileImpact
*/
void G_MissileImpact( gentity_t *ent, trace_t *trace )
{
- gentity_t *other;
- qboolean hitClient = qfalse;
+ gentity_t *other, *attacker;
+ qboolean returnAfterDamage = qfalse;
other = &g_entities[ trace->entityNum ];
+ attacker = &g_entities[ ent->r.ownerNum ];
// check for bounce
if( !other->takedamage &&
( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) )
{
G_BounceMissile( ent, trace );
- G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
- return;
- }
+
+ //only play a sound if requested
+ if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
+ G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
- // impact damage
- if( other->takedamage )
- {
- // FIXME: wrong damage direction?
- if( ent->damage )
- {
- vec3_t velocity;
-
- BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
- if( VectorLength( velocity ) == 0 )
- velocity[ 2 ] = 1; // stepped on a grenade
-
- G_Damage( other, ent, &g_entities[ ent->r.ownerNum ], velocity,
- ent->s.origin, ent->damage,
- 0, ent->methodOfDeath );
- }
+ return;
}
-
+
if( !strcmp( ent->classname, "lockblob" ) )
{
if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
@@ -148,7 +136,54 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace )
VectorCopy( other->client->ps.viewangles, other->client->ps.grapplePoint );
}
}
+ else if( !strcmp( ent->classname, "hive" ) )
+ {
+ if( other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_HIVE )
+ {
+ if( !ent->parent )
+ G_Printf( S_COLOR_YELLOW "WARNING: hive entity has no parent in G_MissileImpact\n" );
+ else
+ ent->parent->active = qfalse;
+
+ G_FreeEntity( ent );
+ return;
+ }
+ else
+ {
+ //prevent collision with the client when returning
+ ent->r.ownerNum = other->s.number;
+
+ ent->think = AHive_ReturnToHive;
+ ent->nextthink = level.time + FRAMETIME;
+
+ //only damage humans
+ if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ returnAfterDamage = qtrue;
+ else
+ return;
+ }
+ }
+ // impact damage
+ if( other->takedamage )
+ {
+ // FIXME: wrong damage direction?
+ if( ent->damage )
+ {
+ vec3_t velocity;
+
+ BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
+ if( VectorLength( velocity ) == 0 )
+ velocity[ 2 ] = 1; // stepped on a grenade
+
+ G_Damage( other, ent, attacker, velocity, ent->s.origin, ent->damage,
+ 0, ent->methodOfDeath );
+ }
+ }
+
+ if( returnAfterDamage )
+ return;
+
// is it cheaper in bandwidth to just remove this ent and create a new
// one, rather than changing the missile into the explosion?
@@ -195,16 +230,9 @@ void G_RunMissile( gentity_t *ent )
// get current position
BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
- // if this missile bounced off an invulnerability sphere
- if ( ent->target_ent )
- {
- passent = ent->target_ent->s.number;
- }
- else
- {
- // ignore interactions with the missile owner
- passent = ent->r.ownerNum;
- }
+ // ignore interactions with the missile owner
+ passent = ent->r.ownerNum;
+
// trace a line from the previous position to the current position
trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
@@ -233,7 +261,7 @@ void G_RunMissile( gentity_t *ent )
}
G_MissileImpact( ent, &tr );
- if ( ent->s.eType != ET_MISSILE )
+ if( ent->s.eType != ET_MISSILE )
return; // exploded
}
@@ -418,6 +446,136 @@ gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir, int da
//=============================================================================
/*
+================
+AHive_ReturnToHive
+
+Adjust the trajectory to point towards the hive
+================
+*/
+void AHive_ReturnToHive( gentity_t *self )
+{
+ vec3_t dir;
+ trace_t tr;
+
+ if( !self->parent )
+ {
+ G_Printf( S_COLOR_YELLOW "WARNING: AHive_ReturnToHive called with no self->parent\n" );
+ return;
+ }
+
+ trap_UnlinkEntity( self->parent );
+ trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
+ self->parent->r.currentOrigin, self->r.ownerNum, self->clipmask );
+ trap_LinkEntity( self->parent );
+
+ if( tr.fraction < 1.0f )
+ {
+ //if can't see hive then disperse
+ VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
+ self->s.pos.trType = TR_STATIONARY;
+ self->s.pos.trTime = level.time;
+
+ self->think = G_ExplodeMissile;
+ self->nextthink = level.time + 2000;
+ self->parent->active = qfalse; //allow the parent to start again
+ }
+ else
+ {
+ VectorSubtract( self->parent->r.currentOrigin, self->r.currentOrigin, dir );
+ VectorNormalize( dir );
+
+ //change direction towards the hive
+ VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta );
+ SnapVector( self->s.pos.trDelta ); // save net bandwidth
+ VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
+ self->s.pos.trTime = level.time;
+
+ self->think = G_ExplodeMissile;
+ self->nextthink = level.time + 15000;
+ }
+}
+
+/*
+================
+AHive_SearchAndDestroy
+
+Adjust the trajectory to point towards the target
+================
+*/
+void AHive_SearchAndDestroy( gentity_t *self )
+{
+ vec3_t dir;
+ trace_t tr;
+
+ trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
+ self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask );
+
+ //if there is no LOS or the parent hive is too far away or the target is dead, return
+ if( tr.entityNum == ENTITYNUM_WORLD ||
+ Distance( self->r.currentOrigin, self->parent->r.currentOrigin ) > ( HIVE_RANGE * 5 ) ||
+ self->target_ent->health <= 0 )
+ {
+ self->r.ownerNum = ENTITYNUM_WORLD;
+
+ self->think = AHive_ReturnToHive;
+ self->nextthink = level.time + FRAMETIME;
+ }
+ else
+ {
+ VectorSubtract( self->target_ent->r.currentOrigin, self->r.currentOrigin, dir );
+ VectorNormalize( dir );
+
+ //change direction towards the player
+ VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta );
+ SnapVector( self->s.pos.trDelta ); // save net bandwidth
+ VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
+ self->s.pos.trTime = level.time;
+
+ self->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
+ }
+}
+
+/*
+=================
+fire_hive
+=================
+*/
+gentity_t *fire_hive( gentity_t *self, vec3_t start, vec3_t dir )
+{
+ gentity_t *bolt;
+
+ VectorNormalize ( dir );
+
+ bolt = G_Spawn( );
+ bolt->classname = "hive";
+ bolt->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
+ bolt->think = AHive_SearchAndDestroy;
+ bolt->s.eType = ET_MISSILE;
+ bolt->s.eFlags |= EF_BOUNCE|EF_NO_BOUNCE_SOUND;
+ bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ bolt->s.weapon = WP_HIVE;
+ bolt->r.ownerNum = self->s.number;
+ bolt->parent = self;
+ bolt->damage = HIVE_DMG;
+ bolt->splashDamage = 0;
+ bolt->splashRadius = 0;
+ bolt->methodOfDeath = MOD_SWARM;
+ bolt->clipmask = MASK_SHOT;
+ bolt->target_ent = self->target_ent;
+
+ bolt->s.pos.trType = TR_LINEAR;
+ 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, HIVE_SPEED, bolt->s.pos.trDelta );
+ SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
+ VectorCopy( start, bolt->r.currentOrigin );
+
+ return bolt;
+}
+
+//=============================================================================
+
+/*
=================
fire_lockblob
=================
@@ -440,6 +598,7 @@ gentity_t *fire_lockblob( gentity_t *self, vec3_t start, vec3_t dir )
bolt->damage = 0;
bolt->splashDamage = 0;
bolt->splashRadius = 0;
+ bolt->methodOfDeath = MOD_UNKNOWN; //doesn't do damage so will never kill
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
diff --git a/src/game/g_mover.c b/src/game/g_mover.c
index ea7f40be..3d171343 100644
--- a/src/game/g_mover.c
+++ b/src/game/g_mover.c
@@ -1601,8 +1601,6 @@ void SP_func_door_model( gentity_t *ent )
char *sound;
gentity_t *door;
gentity_t *clipBrush;
- vec3_t scale;
- qboolean dontAutoScale = qfalse;
G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s );
ent->sound2to1 = G_SoundIndex( s );
@@ -1638,27 +1636,9 @@ void SP_func_door_model( gentity_t *ent )
VectorCopy( clipBrush->r.mins, ent->r.mins );
VectorCopy( clipBrush->r.maxs, ent->r.maxs );
- if( !VectorLength( ent->s.origin ) )
- {
- //calculate the centre of the brush
- VectorSubtract( ent->r.maxs, ent->r.mins, size );
- VectorScale( size, 0.5f, size );
- VectorAdd( size, ent->r.mins, ent->s.origin );
- }
- else
- dontAutoScale = qtrue;
-
- if( G_SpawnVector( "scale", "1 1 1", scale ) )
- dontAutoScale = qtrue;
-
- //let the client know the scaling of the model
- VectorCopy( scale, ent->s.origin2 );
-
- //let the client know the bounds of the brush
- VectorCopy( size, ent->s.angles2 );
+ G_SpawnVector( "modelOrigin", "0 0 0", ent->s.origin );
- if( dontAutoScale )
- ent->s.eFlags |= EF_NO_AUTO_SCALE;
+ G_SpawnVector( "scale", "1 1 1", ent->s.origin2 );
// if the "model2" key is set, use a seperate model
// for drawing, but clip against the brushes
@@ -1703,10 +1683,12 @@ void SP_func_door_model( gentity_t *ent )
ent->moverState = MODEL_POS1;
ent->s.eType = ET_MODELDOOR;
VectorCopy( ent->s.origin, ent->s.pos.trBase );
+ ent->s.pos.trType = TR_STATIONARY;
ent->s.pos.trTime = 0;
ent->s.pos.trDuration = 0;
VectorClear( ent->s.pos.trDelta );
VectorCopy( ent->s.angles, ent->s.apos.trBase );
+ ent->s.apos.trType = TR_STATIONARY;
ent->s.apos.trTime = 0;
ent->s.apos.trDuration = 0;
VectorClear( ent->s.apos.trDelta );
@@ -1722,8 +1704,6 @@ void SP_func_door_model( gentity_t *ent )
trap_LinkEntity( ent );
- ent->s.pos.trType = TR_STATIONARY;
-
if( !( ent->flags & FL_TEAMSLAVE ) )
{
int health;
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 2590503e..fd44840c 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -212,6 +212,23 @@ void lockBlobLauncherFire( gentity_t *ent )
/*
======================================================================
+HIVE
+
+======================================================================
+*/
+
+void hiveFire( gentity_t *ent )
+{
+ gentity_t *m;
+
+ m = fire_hive( ent, muzzle, forward );
+
+// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+}
+
+/*
+======================================================================
+
BLASTER PISTOL
======================================================================
@@ -1101,6 +1118,9 @@ void FireWeapon( gentity_t *ent )
case WP_LOCKBLOB_LAUNCHER:
lockBlobLauncherFire( ent );
break;
+ case WP_HIVE:
+ hiveFire( ent );
+ break;
case WP_TESLAGEN:
teslaFire( ent );
break;
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index b50be9d9..3ee4bbd7 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -215,6 +215,18 @@
#define ACIDTUBE_RANGE 200.0f
#define ACIDTUBE_REPEAT 10000
+#define HIVE_BP 50
+#define HIVE_HEALTH ABHM(100)
+#define HIVE_REGEN 10
+#define HIVE_SPLASHDAMAGE 30
+#define HIVE_SPLASHRADIUS 200
+#define HIVE_CREEPSIZE 120
+#define HIVE_RANGE 400.0f
+#define HIVE_REPEAT 10000
+#define HIVE_DMG 40
+#define HIVE_SPEED 230.0f
+#define HIVE_DIR_CHANGE_PERIOD 500
+
#define TRAPPER_BP 150
#define TRAPPER_HEALTH ABHM(80)
#define TRAPPER_REGEN 8
@@ -467,10 +479,10 @@
#define HUMAN_BACK_MODIFIER 0.7f
#define HUMAN_SIDE_MODIFIER 0.8f
-#define STAMINA_STOP_RESTORE 10
-#define STAMINA_WALK_RESTORE 5
-#define STAMINA_SPRINT_TAKE 10
-#define STAMINA_LARMOUR_TAKE 5
+#define STAMINA_STOP_RESTORE 20
+#define STAMINA_WALK_RESTORE 10
+#define STAMINA_SPRINT_TAKE 6
+#define STAMINA_LARMOUR_TAKE 3
/*
* Misc