mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-14 16:40:57 +00:00
Added Zaero autocannon to missionpack DLL.
This commit is contained in:
parent
9272d5ea85
commit
02755e0181
17 changed files with 1101 additions and 90 deletions
|
@ -49,7 +49,7 @@ qboolean CanDamage (edict_t *targ, edict_t *inflictor)
|
|||
// from inflictor to targ is blocked by a func_tracktrain, AND the targ is riding/driving
|
||||
// the tracktrain, go ahead and hurt him.
|
||||
|
||||
if(trace.ent && (trace.ent->flags & FL_TRACKTRAIN) && ((trace.ent->owner == targ) || (targ->groundentity == trace.ent)) )
|
||||
if (trace.ent && (trace.ent->flags & FL_TRACKTRAIN) && ((trace.ent->owner == targ) || (targ->groundentity == trace.ent)) )
|
||||
return true;
|
||||
|
||||
VectorCopy (targ->s.origin, dest);
|
||||
|
@ -385,7 +385,7 @@ void CallMyFriends (edict_t *targ, edict_t *attacker)
|
|||
{
|
||||
edict_t *teammate;
|
||||
|
||||
if(!targ || !attacker)
|
||||
if (!targ || !attacker)
|
||||
return;
|
||||
|
||||
// Knightmare- skip this for insanes
|
||||
|
@ -393,28 +393,28 @@ void CallMyFriends (edict_t *targ, edict_t *attacker)
|
|||
return;
|
||||
|
||||
// Lazarus dmgteam stuff
|
||||
if( (attacker->client && !(attacker->flags & FL_NOTARGET)) || (attacker->svflags & SVF_MONSTER))
|
||||
if ( (attacker->client && !(attacker->flags & FL_NOTARGET)) || (attacker->svflags & SVF_MONSTER))
|
||||
{ // the attacker is a player or a monster
|
||||
if( (targ->svflags & SVF_MONSTER) && (targ->dmgteam) && (targ->health > 0) )
|
||||
if ( (targ->svflags & SVF_MONSTER) && (targ->dmgteam) && (targ->health > 0) )
|
||||
{ // the target is a live monster on a dmgteam
|
||||
if( !attacker->dmgteam || strcmp(targ->dmgteam,attacker->dmgteam) )
|
||||
if ( !attacker->dmgteam || strcmp(targ->dmgteam,attacker->dmgteam) )
|
||||
{ // attacker is not on same dmgteam as target
|
||||
if( !Q_stricmp(targ->dmgteam,"player") && attacker->client )
|
||||
if ( !Q_stricmp(targ->dmgteam,"player") && attacker->client )
|
||||
{ // Target is a GOOD_GUY, attacked by the player. Allow self-defense,
|
||||
// but don't get other dmgteam teammates involved.
|
||||
// Special case for misc_actors - if ACTOR_BAD_GUY isn't set,
|
||||
// actor stays on the same team and only taunts player
|
||||
if(!(targ->monsterinfo.aiflags & AI_ACTOR) || (targ->spawnflags & SF_ACTOR_BAD_GUY))
|
||||
if (!(targ->monsterinfo.aiflags & AI_ACTOR) || (targ->spawnflags & SF_ACTOR_BAD_GUY))
|
||||
{
|
||||
targ->enemy = targ->movetarget = targ->goalentity = attacker;
|
||||
targ->monsterinfo.aiflags &= ~AI_FOLLOW_LEADER;
|
||||
if(visible(targ,targ->enemy))
|
||||
if (visible(targ,targ->enemy))
|
||||
FoundTarget(targ);
|
||||
else
|
||||
HuntTarget(targ);
|
||||
}
|
||||
}
|
||||
else if( !(targ->svflags & SVF_MONSTER) || !(attacker->svflags & SVF_MONSTER) ||
|
||||
else if ( !(targ->svflags & SVF_MONSTER) || !(attacker->svflags & SVF_MONSTER) ||
|
||||
(targ->monsterinfo.aiflags2 & AI2_FREEFORALL) ||
|
||||
((targ->monsterinfo.aiflags & AI_GOOD_GUY) != (attacker->monsterinfo.aiflags & AI_GOOD_GUY)) )
|
||||
{
|
||||
|
@ -422,15 +422,15 @@ void CallMyFriends (edict_t *targ, edict_t *attacker)
|
|||
// they're both monsters but one is AI_GOOD_GUY and the other is not,
|
||||
// or we've turned the game into a free-for-all with a target_monsterbattle
|
||||
teammate = G_Find(NULL,FOFS(dmgteam),targ->dmgteam);
|
||||
while(teammate)
|
||||
while (teammate)
|
||||
{
|
||||
if(teammate != targ)
|
||||
if (teammate != targ)
|
||||
{
|
||||
if(teammate->svflags & SVF_MONSTER)
|
||||
if (teammate->svflags & SVF_MONSTER)
|
||||
{
|
||||
if(teammate->health > 0 && (teammate->enemy != attacker) && !(teammate->monsterinfo.aiflags & AI_CHASE_THING))
|
||||
if (teammate->health > 0 && (teammate->enemy != attacker) && !(teammate->monsterinfo.aiflags & AI_CHASE_THING))
|
||||
{
|
||||
if(!teammate->enemy || !teammate->enemy->dmgteam || !attacker->dmgteam )
|
||||
if (!teammate->enemy || !teammate->enemy->dmgteam || !attacker->dmgteam )
|
||||
{
|
||||
// If either 1) this teammate doesn't currently have an enemy,
|
||||
// or 2) the teammate's enemy is not a member of a dmgteam
|
||||
|
@ -438,7 +438,7 @@ void CallMyFriends (edict_t *targ, edict_t *attacker)
|
|||
// then set the attacker as the enemy of this teammate
|
||||
DefendMyFriend(teammate,attacker);
|
||||
}
|
||||
else if(strcmp(teammate->enemy->dmgteam,attacker->dmgteam))
|
||||
else if (strcmp(teammate->enemy->dmgteam,attacker->dmgteam))
|
||||
{
|
||||
// attacker is a member of a team different than the
|
||||
// current enemy
|
||||
|
@ -446,7 +446,7 @@ void CallMyFriends (edict_t *targ, edict_t *attacker)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(!(teammate->svflags & SVF_DEADMONSTER))
|
||||
else if (!(teammate->svflags & SVF_DEADMONSTER))
|
||||
G_UseTargets(teammate,attacker);
|
||||
}
|
||||
teammate = G_Find(teammate,FOFS(dmgteam),targ->dmgteam);
|
||||
|
@ -463,16 +463,16 @@ void CallMyFriends (edict_t *targ, edict_t *attacker)
|
|||
teammate = G_Find(NULL,FOFS(dmgteam),"player");
|
||||
while (teammate)
|
||||
{
|
||||
if((teammate->health > 0) && !(teammate->monsterinfo.aiflags & AI_CHASE_THING) && (teammate != attacker))
|
||||
if ((teammate->health > 0) && !(teammate->monsterinfo.aiflags & AI_CHASE_THING) && (teammate != attacker))
|
||||
{
|
||||
// Can teammate see player?
|
||||
// tr = gi.trace(teammate->s.origin,vec3_origin,vec3_origin,targ->s.origin,teammate,MASK_OPAQUE);
|
||||
// if(tr.fraction == 1.0)
|
||||
if(gi.inPVS(teammate->s.origin,targ->s.origin))
|
||||
// if (tr.fraction == 1.0)
|
||||
if (gi.inPVS(teammate->s.origin,targ->s.origin))
|
||||
{
|
||||
teammate->enemy = attacker;
|
||||
FoundTarget(teammate);
|
||||
if(teammate->monsterinfo.aiflags & AI_ACTOR)
|
||||
if (teammate->monsterinfo.aiflags & AI_ACTOR)
|
||||
{
|
||||
teammate->monsterinfo.aiflags |= AI_FOLLOW_LEADER;
|
||||
teammate->monsterinfo.old_leader = NULL;
|
||||
|
@ -509,8 +509,8 @@ void CallMyFriends (edict_t *targ, edict_t *attacker)
|
|||
}
|
||||
}
|
||||
// 1.6.1.3 change - one chance and one chance only to call friends
|
||||
/* if(targ->dmgteam)
|
||||
if(Q_stricmp(targ->dmgteam,"player"))
|
||||
/* if (targ->dmgteam)
|
||||
if (Q_stricmp(targ->dmgteam,"player"))
|
||||
targ->dmgteam = NULL; */
|
||||
}
|
||||
|
||||
|
@ -525,7 +525,7 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
// if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
|
||||
// return;
|
||||
|
||||
if( targ->health <= 0 )
|
||||
if ( targ->health <= 0 )
|
||||
return;
|
||||
|
||||
// If targ is currently chasing a "thing" or we're running a hint_path test, he
|
||||
|
@ -586,9 +586,9 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
|
||||
VectorCopy(targ->mins,mins);
|
||||
mins[2] += 16; // max step height? not sure about this
|
||||
if(mins[2] > 0) mins[2] = 0;
|
||||
if (mins[2] > 0) mins[2] = 0;
|
||||
VectorCopy(targ->maxs,maxs);
|
||||
if( (attacker==world) ||
|
||||
if ( (attacker==world) ||
|
||||
(!Q_stricmp(attacker->classname,"func_door") ) ||
|
||||
(!Q_stricmp(attacker->classname,"func_water")) ||
|
||||
(!Q_stricmp(attacker->classname,"func_pushable")) )
|
||||
|
@ -611,12 +611,12 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(!Q_stricmp(attacker->classname,"target_laser"))
|
||||
else if (!Q_stricmp(attacker->classname,"target_laser"))
|
||||
{
|
||||
// Send the monster in a direction perpendicular to laser
|
||||
// path, whichever direction is closest to current angles
|
||||
thing = SpawnThing();
|
||||
if(attacker->movedir[2] > 0.7)
|
||||
if (attacker->movedir[2] > 0.7)
|
||||
{
|
||||
// Just move straight ahead and hope for the best
|
||||
AngleVectors(targ->s.angles,best_dir,NULL,NULL);
|
||||
|
@ -629,7 +629,7 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
best_dir[1] = best_dir[2];
|
||||
best_dir[2] = 0;
|
||||
AngleVectors(targ->s.angles,dir,NULL,NULL);
|
||||
if(DotProduct(best_dir,dir) < 0)
|
||||
if (DotProduct(best_dir,dir) < 0)
|
||||
VectorNegate(best_dir,best_dir);
|
||||
}
|
||||
}
|
||||
|
@ -638,7 +638,7 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
// Attacked by a point entity or moving brush model
|
||||
// not covered above. Find a vector that will hide the
|
||||
// monster from the attacker.
|
||||
if(!VectorLength(attacker->size))
|
||||
if (!VectorLength(attacker->size))
|
||||
{
|
||||
// point entity
|
||||
VectorCopy(attacker->s.origin,atk);
|
||||
|
@ -650,9 +650,9 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
}
|
||||
VectorClear(best_dir);
|
||||
AngleVectors(targ->s.angles,forward,NULL,NULL);
|
||||
for(i=0; i<32 && best_dist == 0; i++) {
|
||||
for (i=0; i<32 && best_dist == 0; i++) {
|
||||
// Weight escape route tests in favor of forward-facing direction
|
||||
if(random() > 0.5)
|
||||
if (random() > 0.5)
|
||||
{
|
||||
dir[0] = forward[0] + 0.5*crandom();
|
||||
dir[1] = forward[1] + 0.5*crandom();
|
||||
|
@ -668,20 +668,20 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
VectorMA(targ->s.origin, WORLD_SIZE, dir, end); // was 8192
|
||||
trace1 = gi.trace(targ->s.origin,mins,maxs,end,targ,MASK_MONSTERSOLID);
|
||||
trace2 = gi.trace(trace1.endpos,NULL,NULL,atk,targ,MASK_SOLID);
|
||||
if(trace2.fraction == 1.0) continue;
|
||||
if (trace2.fraction == 1.0) continue;
|
||||
dist = trace1.fraction * WORLD_SIZE; // was 8192
|
||||
if(dist > best_dist)
|
||||
if (dist > best_dist)
|
||||
{
|
||||
best_dist = dist;
|
||||
VectorCopy(dir, best_dir);
|
||||
}
|
||||
}
|
||||
if(best_dist == 0.)
|
||||
if (best_dist == 0.)
|
||||
return;
|
||||
thing = SpawnThing();
|
||||
vectoangles(best_dir,thing->s.angles);
|
||||
}
|
||||
if( (!Q_stricmp(attacker->classname,"func_door")) ||
|
||||
if ( (!Q_stricmp(attacker->classname,"func_door")) ||
|
||||
(!Q_stricmp(attacker->classname,"func_pushable")) )
|
||||
run = 256;
|
||||
else
|
||||
|
@ -691,7 +691,7 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
dist = trace1.fraction * run;
|
||||
VectorMA(targ->s.origin, dist, best_dir, thing->s.origin);
|
||||
// If monster already has an enemy, use a short lifespan for thing
|
||||
if(targ->enemy)
|
||||
if (targ->enemy)
|
||||
thing->touch_debounce_time = level.time + 2.0;
|
||||
else
|
||||
thing->touch_debounce_time = level.time + max(5.0,dist/50.);
|
||||
|
@ -714,13 +714,19 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
{
|
||||
if (attacker->health > targ->health)
|
||||
{
|
||||
if(ai_chicken(targ,attacker))
|
||||
if (ai_chicken(targ,attacker))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Zaero- handle autocanon
|
||||
// if ( !(attacker->client) && !(attacker->svflags & SVF_MONSTER) &&
|
||||
// (strncmp (attacker->classname, "monster_autocannon", 18) != 0) )
|
||||
if ( !strncmp (attacker->classname, "monster_autocannon", 18) )
|
||||
return;
|
||||
|
||||
if (attacker == targ || attacker == targ->enemy)
|
||||
return;
|
||||
|
||||
|
@ -740,10 +746,10 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
float percentHealth;
|
||||
|
||||
// make sure whatever we were pissed at is still around.
|
||||
if(targ->enemy->inuse)
|
||||
if (targ->enemy->inuse)
|
||||
{
|
||||
percentHealth = (float)(targ->health) / (float)(targ->max_health);
|
||||
if( targ->enemy->inuse && percentHealth > 0.33)
|
||||
if ( targ->enemy->inuse && percentHealth > 0.33)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -760,7 +766,7 @@ void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
|
|||
|
||||
percentHealth = (float)(targ->health) / (float)(targ->max_health);
|
||||
// ignore it some of the time
|
||||
if( targ->enemy->inuse && percentHealth > 0.25)
|
||||
if ( targ->enemy->inuse && percentHealth > 0.25)
|
||||
return;
|
||||
|
||||
// remove the medic flag
|
||||
|
@ -895,7 +901,7 @@ void T_Damage (edict_t *in_targ, edict_t *inflictor, edict_t *in_attacker, vec3_
|
|||
// Lazarus: If monster/actor is currently being forced to use
|
||||
// specific animations due to target_animation, release that
|
||||
// control over it.
|
||||
if((targ->think == target_animate) && (targ->svflags & SVF_MONSTER))
|
||||
if ((targ->think == target_animate) && (targ->svflags & SVF_MONSTER))
|
||||
{
|
||||
targ->think = monster_think;
|
||||
targ->nextthink = level.time + FRAMETIME;
|
||||
|
@ -1086,9 +1092,9 @@ void T_Damage (edict_t *in_targ, edict_t *inflictor, edict_t *in_attacker, vec3_
|
|||
{
|
||||
take = 0;
|
||||
save = damage;
|
||||
//Knightmare
|
||||
if (mod != MOD_SHOCK_SPLASH) //no sparks from shockwave detonation effect!!!
|
||||
//end Knightmare
|
||||
// Knightmare
|
||||
if (mod != MOD_SHOCK_SPLASH) // no sparks from shockwave detonation effect!!!
|
||||
// end Knightmare
|
||||
SpawnDamage (TE_SPARKS, point, normal, save);
|
||||
}
|
||||
|
||||
|
@ -1117,7 +1123,7 @@ void T_Damage (edict_t *in_targ, edict_t *inflictor, edict_t *in_attacker, vec3_
|
|||
}
|
||||
// ROGUE
|
||||
|
||||
//Knightmare- falling doesn't damage armor
|
||||
// Knightmare- falling doesn't damage armor
|
||||
if (mod == MOD_FALLING && !falling_armor_damage->value)
|
||||
{
|
||||
psave = 0;
|
||||
|
@ -1131,7 +1137,7 @@ void T_Damage (edict_t *in_targ, edict_t *inflictor, edict_t *in_attacker, vec3_
|
|||
asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
|
||||
take -= asave;
|
||||
|
||||
//treat cheat/powerup savings the same as armor
|
||||
// treat cheat/powerup savings the same as armor
|
||||
asave += save;
|
||||
}
|
||||
|
||||
|
@ -1139,18 +1145,18 @@ void T_Damage (edict_t *in_targ, edict_t *inflictor, edict_t *in_attacker, vec3_
|
|||
if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
|
||||
return;
|
||||
|
||||
// ROGUE - this option will do damage both to the armor and person. originally for DPU rounds
|
||||
// ROGUE - this option will do damage both to the armor and person. originally for DPU rounds
|
||||
if (dflags & DAMAGE_DESTROY_ARMOR)
|
||||
{
|
||||
if(!(targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) &&
|
||||
if (!(targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) &&
|
||||
!(client && client->invincible_framenum > level.framenum))
|
||||
{
|
||||
take = damage;
|
||||
}
|
||||
}
|
||||
// ROGUE
|
||||
// ROGUE
|
||||
|
||||
// do the damage
|
||||
// do the damage
|
||||
if (take)
|
||||
{
|
||||
// Lazarus: dmgteam stuff
|
||||
|
@ -1160,13 +1166,13 @@ void T_Damage (edict_t *in_targ, edict_t *inflictor, edict_t *in_attacker, vec3_
|
|||
if ( (mod != MOD_SHOCK_SPLASH) && ((damage > 0) || ((mod != MOD_TRIGGER_HURT) && (mod != MOD_TARGET_LASER))) )
|
||||
{
|
||||
//PGM- need more blood for chainfist.
|
||||
if(targ->flags & FL_MECHANICAL)
|
||||
if (targ->flags & FL_MECHANICAL)
|
||||
{
|
||||
SpawnDamage (TE_ELECTRIC_SPARKS, point, normal, take);
|
||||
}
|
||||
else if ((targ->svflags & SVF_MONSTER) || (client))
|
||||
{
|
||||
if(targ->blood_type == 1)
|
||||
if (targ->blood_type == 1)
|
||||
SpawnDamage (TE_GREENBLOOD, point, normal, take);
|
||||
else if (targ->blood_type == 2)
|
||||
{
|
||||
|
@ -1266,10 +1272,10 @@ void T_Damage (edict_t *in_targ, edict_t *inflictor, edict_t *in_attacker, vec3_
|
|||
//PGM - spheres need to know who to shoot at
|
||||
if (!sphere_notified)
|
||||
{
|
||||
if(client && client->owned_sphere)
|
||||
if (client && client->owned_sphere)
|
||||
{
|
||||
sphere_notified = true;
|
||||
if(client->owned_sphere->pain)
|
||||
if (client->owned_sphere->pain)
|
||||
client->owned_sphere->pain (client->owned_sphere, attacker, 0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
extern void fire_flare ( edict_t * self , vec3_t start , vec3_t dir , int damage , int speed , float damage_radius , int radius_damage ) ;
|
||||
extern void flare_think ( edict_t * self ) ;
|
||||
extern void flare_flash ( edict_t * ent ) ;
|
||||
extern void angleToward ( edict_t * self , vec3_t point , float speed ) ;
|
||||
extern void SP_trigger_laser ( edict_t * self ) ;
|
||||
extern void trigger_laser_on ( edict_t * self ) ;
|
||||
extern void trigger_laser_think ( edict_t * self ) ;
|
||||
|
@ -160,6 +161,24 @@ extern int zSchoolMonsters ( edict_t * self , float dist , int runStyle , float
|
|||
extern int zFindRoamYaw ( edict_t * self , float distcheck ) ;
|
||||
extern int zSchoolAllVisiable ( edict_t * self ) ;
|
||||
extern void zCreateRaduisList ( edict_t * self ) ;
|
||||
extern void SP_monster_autocannon_floor ( edict_t * self ) ;
|
||||
extern void SP_monster_autocannon ( edict_t * self ) ;
|
||||
extern void monster_autocannon_usestub ( edict_t * self ) ;
|
||||
extern void monster_autocannon_use ( edict_t * self , edict_t * other , edict_t * activator ) ;
|
||||
extern void monster_autocannon_act ( edict_t * self ) ;
|
||||
extern void monster_autocannon_deactivate ( edict_t * self ) ;
|
||||
extern void monster_autocannon_activate ( edict_t * self ) ;
|
||||
extern void monster_autocannon_pain ( edict_t * self , edict_t * other , float kick , int damage ) ;
|
||||
extern void monster_autocannon_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
|
||||
extern void monster_autocannon_explode ( edict_t * ent ) ;
|
||||
extern void monster_autocannon_think ( edict_t * self ) ;
|
||||
extern void monster_autocannon_turn ( edict_t * self ) ;
|
||||
extern void monster_autocannon_findenemy ( edict_t * self ) ;
|
||||
extern qboolean autocannonInfront ( edict_t * self , edict_t * other ) ;
|
||||
extern qboolean canShoot ( edict_t * self , edict_t * e ) ;
|
||||
extern float mod180 ( float val ) ;
|
||||
extern qboolean angleBetween ( float * ang , float * , float * ) ;
|
||||
extern void monster_autocannon_fire ( edict_t * self ) ;
|
||||
extern void Info_SetValueForKey ( char * s , char * key , char * value ) ;
|
||||
extern qboolean Info_Validate ( char * s ) ;
|
||||
extern void Info_RemoveKey ( char * s , char * key ) ;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{"fire_flare", (byte *)fire_flare},
|
||||
{"flare_think", (byte *)flare_think},
|
||||
{"flare_flash", (byte *)flare_flash},
|
||||
{"angleToward", (byte *)angleToward},
|
||||
{"SP_trigger_laser", (byte *)SP_trigger_laser},
|
||||
{"trigger_laser_on", (byte *)trigger_laser_on},
|
||||
{"trigger_laser_think", (byte *)trigger_laser_think},
|
||||
|
@ -160,6 +161,24 @@
|
|||
{"zFindRoamYaw", (byte *)zFindRoamYaw},
|
||||
{"zSchoolAllVisiable", (byte *)zSchoolAllVisiable},
|
||||
{"zCreateRaduisList", (byte *)zCreateRaduisList},
|
||||
{"SP_monster_autocannon_floor", (byte *)SP_monster_autocannon_floor},
|
||||
{"SP_monster_autocannon", (byte *)SP_monster_autocannon},
|
||||
{"monster_autocannon_usestub", (byte *)monster_autocannon_usestub},
|
||||
{"monster_autocannon_use", (byte *)monster_autocannon_use},
|
||||
{"monster_autocannon_act", (byte *)monster_autocannon_act},
|
||||
{"monster_autocannon_deactivate", (byte *)monster_autocannon_deactivate},
|
||||
{"monster_autocannon_activate", (byte *)monster_autocannon_activate},
|
||||
{"monster_autocannon_pain", (byte *)monster_autocannon_pain},
|
||||
{"monster_autocannon_die", (byte *)monster_autocannon_die},
|
||||
{"monster_autocannon_explode", (byte *)monster_autocannon_explode},
|
||||
{"monster_autocannon_think", (byte *)monster_autocannon_think},
|
||||
{"monster_autocannon_turn", (byte *)monster_autocannon_turn},
|
||||
{"monster_autocannon_findenemy", (byte *)monster_autocannon_findenemy},
|
||||
{"autocannonInfront", (byte *)autocannonInfront},
|
||||
{"canShoot", (byte *)canShoot},
|
||||
{"mod180", (byte *)mod180},
|
||||
{"angleBetween", (byte *)angleBetween},
|
||||
{"monster_autocannon_fire", (byte *)monster_autocannon_fire},
|
||||
{"Info_SetValueForKey", (byte *)Info_SetValueForKey},
|
||||
{"Info_Validate", (byte *)Info_Validate},
|
||||
{"Info_RemoveKey", (byte *)Info_RemoveKey},
|
||||
|
|
|
@ -1066,7 +1066,7 @@ qboolean monster_start (edict_t *self)
|
|||
}
|
||||
|
||||
// Lazarus: Good guys
|
||||
//Knightmare- gekks and stalkers use different spawnflag
|
||||
// Knightmare- gekks and stalkers use different spawnflag
|
||||
if ( (UseRegularGoodGuyFlag(self) && (self->spawnflags & SF_MONSTER_GOODGUY))
|
||||
|| (UseSpecialGoodGuyFlag(self) && (self->spawnflags & 16)) )
|
||||
{
|
||||
|
|
|
@ -829,9 +829,11 @@ void target_effect_lightning(edict_t *self, edict_t *activator)
|
|||
{
|
||||
edict_t *target;
|
||||
|
||||
if(!self->target) return;
|
||||
if (!self->target)
|
||||
return;
|
||||
target = G_Find(NULL,FOFS(targetname),self->target);
|
||||
if(!target) return;
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
gi.WriteByte (svc_temp_entity);
|
||||
gi.WriteByte (self->style);
|
||||
|
|
|
@ -175,6 +175,8 @@ void SP_monster_gladb (edict_t *self);
|
|||
void SP_monster_boss5 (edict_t *self);
|
||||
|
||||
// Zaero
|
||||
void SP_monster_autocannon (edict_t *self);
|
||||
void SP_monster_autocannon_floor (edict_t *self);
|
||||
void SP_monster_hound (edict_t *self);
|
||||
void SP_monster_handler (edict_t *self);
|
||||
void SP_monster_sentien(edict_t *self);
|
||||
|
@ -554,6 +556,8 @@ spawn_t spawns[] = {
|
|||
{"monster_widow2", SP_monster_widow2},
|
||||
|
||||
// Zaero
|
||||
{"monster_autocannon", SP_monster_autocannon},
|
||||
{"monster_autocannon_floor", SP_monster_autocannon_floor},
|
||||
{"monster_hound", SP_monster_hound},
|
||||
{"monster_handler", SP_monster_handler},
|
||||
{"monster_sentien", SP_monster_sentien},
|
||||
|
|
|
@ -12,11 +12,12 @@
|
|||
// right now, only the tesla has this
|
||||
#define SVF_DAMAGEABLE 0x00000008
|
||||
//ROGUE end
|
||||
#define SVF_GIB 0x00000010 //Knightmare- gib flag
|
||||
#define SVF_GIB 0x00000010 // Knightmare- gib flag
|
||||
#define SVF_TRIGGER_CAMOWNER 0x00000020
|
||||
#define SVF_MUD 0x00000040 //mud flag
|
||||
#define SVF_CLONED 0x00000080 //How to tell if this entity is a clone
|
||||
#define SVF_OLDPLAYER 0x00000080 //How to tell if this entity is a clone
|
||||
#define SVF_MUD 0x00000040 // mud flag
|
||||
#define SVF_CLONED 0x00000080 // How to tell if this entity is a clone
|
||||
#define SVF_OLDPLAYER 0x00000080 // How to tell if this entity is a clone
|
||||
#define SVF_AUTOMATON 0x00000100 // Not exactly a monster (but causes client obit)...
|
||||
|
||||
// edict->solid values
|
||||
|
||||
|
|
|
@ -206,7 +206,6 @@ cvar_t *sk_max_fuel;
|
|||
/*
|
||||
cvar_t *sk_max_flares;
|
||||
cvar_t *sk_max_tbombs;
|
||||
cvar_t *sk_max_a2k;
|
||||
cvar_t *sk_max_empnuke;
|
||||
cvar_t *sk_max_plasmashield;
|
||||
*/
|
||||
|
@ -242,7 +241,6 @@ cvar_t *sk_pack_fuel;
|
|||
/*
|
||||
cvar_t *sk_pack_flares; // 60
|
||||
cvar_t *sk_pack_tbombs; // 100
|
||||
cvar_t *sk_pack_a2k; // 1
|
||||
cvar_t *sk_pack_empnuke; // 100
|
||||
cvar_t *sk_pack_plasmashield; // 40
|
||||
*/
|
||||
|
@ -295,11 +293,7 @@ cvar_t *sk_ir_time;
|
|||
cvar_t *sk_double_time;
|
||||
cvar_t *sk_quad_fire_time;
|
||||
cvar_t *sk_stasis_time;
|
||||
/*
|
||||
cvar_t *sk_visor_time;
|
||||
cvar_t *sk_sniper_charge_time;
|
||||
cvar_t *sk_a2k_detonate_time;
|
||||
*/
|
||||
//cvar_t *sk_visor_time;
|
||||
|
||||
|
||||
void InitLithiumVars (void)
|
||||
|
@ -505,7 +499,6 @@ void InitLithiumVars (void)
|
|||
/*
|
||||
sk_max_flares = gi.cvar("sk_max_flares", "30", 0);
|
||||
sk_max_tbombs = gi.cvar("sk_max_tbombs", "30", 0);
|
||||
sk_max_a2k = gi.cvar("sk_max_a2k", "1", 0);
|
||||
sk_max_empnuke = gi.cvar("sk_max_empnuke", "50", 0);
|
||||
sk_max_plasmashield = gi.cvar("sk_max_plasmashield", "20", 0);
|
||||
*/
|
||||
|
@ -541,7 +534,6 @@ void InitLithiumVars (void)
|
|||
/*
|
||||
sk_pack_flares = gi.cvar("sk_pack_flares", "100", 0);
|
||||
sk_pack_tbombs = gi.cvar("sk_pack_tbombs", "100", 0);
|
||||
sk_pack_a2k = gi.cvar("sk_pack_a2k", "1", 0);
|
||||
sk_pack_empnuke = gi.cvar("sk_pack_empnuke", "100", 0);
|
||||
sk_pack_plasmashield = gi.cvar("sk_pack_plasmashield", "40", 0);
|
||||
*/
|
||||
|
@ -595,9 +587,5 @@ void InitLithiumVars (void)
|
|||
sk_double_time = gi.cvar("sk_double_time", "30", 0);
|
||||
sk_quad_fire_time = gi.cvar("sk_quad_fire_time", "30", 0);
|
||||
sk_stasis_time = gi.cvar("sk_stasis_time", "30", 0);
|
||||
/*
|
||||
sk_visor_time = gi.cvar("sk_visor_time", "30", 0);
|
||||
sk_sniper_charge_time = gi.cvar("sk_sniper_charge_time", "3", 0);
|
||||
sk_a2k_detonate_time = gi.cvar("sk_a2k_detonate_time", "5", 0);
|
||||
*/
|
||||
// sk_visor_time = gi.cvar("sk_visor_time", "30", 0);
|
||||
}
|
||||
|
|
|
@ -203,7 +203,6 @@ extern cvar_t *sk_max_fuel;
|
|||
/*
|
||||
extern cvar_t *sk_max_flares;
|
||||
extern cvar_t *sk_max_tbombs;
|
||||
extern cvar_t *sk_max_a2k;
|
||||
extern cvar_t *sk_max_empnuke;
|
||||
extern cvar_t *sk_max_plasmashield;
|
||||
*/
|
||||
|
@ -237,7 +236,6 @@ extern cvar_t *sk_pack_fuel;
|
|||
/*
|
||||
extern cvar_t *sk_pack_flares;
|
||||
extern cvar_t *sk_pack_tbombs;
|
||||
extern cvar_t *sk_pack_a2k;
|
||||
extern cvar_t *sk_pack_empnuke;
|
||||
extern cvar_t *sk_pack_plasmashield;
|
||||
*/
|
||||
|
@ -291,8 +289,4 @@ extern cvar_t *sk_double_time;
|
|||
extern cvar_t *sk_quad_fire_time;
|
||||
extern cvar_t *sk_doppleganger_time;
|
||||
extern cvar_t *sk_stasis_time;
|
||||
/*
|
||||
extern cvar_t *sk_visor_time;
|
||||
extern cvar_t *sk_sniper_charge_time;
|
||||
extern cvar_t *sk_a2k_detonate_time;
|
||||
*/
|
||||
//extern cvar_t *sk_visor_time;
|
||||
|
|
|
@ -521,6 +521,10 @@ SOURCE=.\q_shared.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\z_acannon.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\z_ai.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -842,6 +842,10 @@
|
|||
RelativePath="q_shared.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\z_acannon.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\z_ai.c"
|
||||
>
|
||||
|
|
|
@ -587,8 +587,8 @@ void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
|
|||
return;
|
||||
}
|
||||
}
|
||||
//Knightmare- Single-player obits
|
||||
if (attacker->svflags & SVF_MONSTER)
|
||||
// Knightmare- Single-player obits
|
||||
if (attacker->svflags & (SVF_MONSTER|SVF_AUTOMATON))
|
||||
{ // Light Guard
|
||||
if (!strcmp(attacker->classname, "monster_soldier_light"))
|
||||
message = "was blasted by a";
|
||||
|
@ -907,6 +907,24 @@ void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
|
|||
else
|
||||
message = "was slashed to death by a";
|
||||
}
|
||||
// Autocannon
|
||||
else if (!strcmp(attacker->classname, "monster_autocannon") || !strcmp(attacker->classname, "monster_autocannon_floor"))
|
||||
{
|
||||
if (mod == MOD_HYPERBLASTER || mod == MOD_BLASTER) {
|
||||
message = "was melted by an";
|
||||
message2 = "'s blaster";
|
||||
}
|
||||
else if (mod == MOD_ROCKET) {
|
||||
message = "ate an";
|
||||
message2 = "'s rocket";
|
||||
}
|
||||
else if (mod == MOD_R_SPLASH) {
|
||||
message = "almost dodged an";
|
||||
message2 = "'s rocket";
|
||||
}
|
||||
else
|
||||
message = "was pumped full of lead by an";
|
||||
}
|
||||
// Sentien
|
||||
else if (!strcmp(attacker->classname, "monster_sentien"))
|
||||
{
|
||||
|
@ -1003,7 +1021,7 @@ void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
|
|||
}
|
||||
// end Knightmare
|
||||
}
|
||||
//Knightmare- for diagnostics, print name of killing entity
|
||||
// Knightmare- for diagnostics, print name of killing entity
|
||||
/*if (strlen(attacker->classname))
|
||||
gi.bprintf (PRINT_MEDIUM,"%s was killed by %s.\n", self->client->pers.netname, attacker->classname);
|
||||
else*/
|
||||
|
@ -1638,7 +1656,7 @@ void InitClientPersistant (gclient_t *client, int style)
|
|||
// These are currently unused, but init them anyway.
|
||||
client->pers.max_flares = 30; // sk_max_flares->value;
|
||||
client->pers.max_tbombs = 30; // sk_max_tbombs->value;
|
||||
client->pers.max_a2k = 1; // sk_max_a2k->value;
|
||||
client->pers.max_a2k = 1;
|
||||
client->pers.max_empnuke = 50; // sk_max_empnuke->value;
|
||||
client->pers.max_plasmashield = 20; // sk_max_plasmashield->value;
|
||||
// end Zaero
|
||||
|
|
945
missionpack/z_acannon.c
Normal file
945
missionpack/z_acannon.c
Normal file
|
@ -0,0 +1,945 @@
|
|||
#include "g_local.h"
|
||||
|
||||
void angleToward(edict_t *self, vec3_t point, float speed);
|
||||
|
||||
// spawnflags
|
||||
#define AC_SF_START_OFF 1
|
||||
#define AC_SF_BERSERK 2
|
||||
#define AC_SF_BERSERK_TOGGLE 4
|
||||
|
||||
// variables
|
||||
#define AC_RANGE 2048
|
||||
#define AC_TIMEOUT 2.0
|
||||
#define AC_EXPLODE_DMG 150
|
||||
#define AC_EXPLODE_RADIUS 384
|
||||
#define AC_TURN_SPEED 6.0
|
||||
#define AC_TURN_DELAY 1.0
|
||||
// states
|
||||
#define AC_S_IDLE 0
|
||||
#define AC_S_ACTIVATING 1
|
||||
#define AC_S_ACTIVE 2
|
||||
#define AC_S_DEACTIVATING 3
|
||||
// models
|
||||
char* models[] = { NULL,
|
||||
"models/objects/acannon/chain/tris.md2",
|
||||
"models/objects/acannon/rocket/tris.md2",
|
||||
"models/objects/acannon/laser/tris.md2",
|
||||
"models/objects/acannon/laser/tris.md2" };
|
||||
char* floorModels[] = { NULL,
|
||||
"",
|
||||
"models/objects/acannon/rocket2/tris.md2",
|
||||
"models/objects/acannon/laser2/tris.md2",
|
||||
"models/objects/acannon/laser2/tris.md2" };
|
||||
|
||||
// pitch extents
|
||||
const int acPitchExtents[2][2] = { {0,60}, // max, min
|
||||
{-60,0}
|
||||
};
|
||||
|
||||
// frames filler/chain/rocket/laser
|
||||
const int acIdleStart[] = { 0, 0, 0, 0, 0 };
|
||||
const int acIdleEnd[] = { 0, 0, 0, 0, 0 };
|
||||
const int acActStart[] = { 0, 1, 1, 1, 1 };
|
||||
const int acActEnd[] = { 0, 9, 9, 9, 9 };
|
||||
const int acActiveStart[] = { 0, 10, 10, 10, 10 };
|
||||
const int acActiveEnd[] = { 0, 10, 10, 10, 10 };
|
||||
|
||||
typedef struct ac_anim_frame_s
|
||||
{
|
||||
qboolean last;
|
||||
qboolean fire;
|
||||
int frame;
|
||||
} ac_anim_frame_t;
|
||||
|
||||
typedef struct ac_anim_s
|
||||
{
|
||||
int firstNonPause;
|
||||
ac_anim_frame_t frames[32];
|
||||
} ac_anim_t;
|
||||
|
||||
ac_anim_t acFiringFrames[5] =
|
||||
{
|
||||
// dummy
|
||||
{
|
||||
0,
|
||||
{ true, false, -1 }
|
||||
},
|
||||
|
||||
// chaingun
|
||||
{
|
||||
6,
|
||||
{
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
// start of firing sequence
|
||||
{ false, true, 11 },
|
||||
{ false, false, 12 },
|
||||
{ false, true, 13 },
|
||||
{ false, false, 14 },
|
||||
{ false, true, 15 },
|
||||
{ false, false, 16 },
|
||||
{ false, true, 17 },
|
||||
{ false, false, 18 },
|
||||
{ false, true, 19 },
|
||||
{ false, false, 20 },
|
||||
{ false, true, 21 },
|
||||
{ true, false, 2 },
|
||||
}
|
||||
},
|
||||
|
||||
// rockets
|
||||
{
|
||||
6,
|
||||
{
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
// start of firing sequence
|
||||
{ false, true, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 12 },
|
||||
{ false, false, 12 },
|
||||
{ false, false, 13 },
|
||||
{ false, false, 13 },
|
||||
{ false, false, 14 },
|
||||
{ false, false, 14 },
|
||||
{ false, false, 15 },
|
||||
{ false, false, 15 },
|
||||
{ false, false, 16 },
|
||||
{ true, false, 16 },
|
||||
}
|
||||
},
|
||||
|
||||
// laser
|
||||
{
|
||||
6,
|
||||
{
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
// start of firing sequence
|
||||
{ false, true, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ true, false, 11 },
|
||||
}
|
||||
},
|
||||
|
||||
// slow laser
|
||||
{
|
||||
6,
|
||||
{
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
// start of firing sequence
|
||||
{ false, true, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ false, false, 11 },
|
||||
{ true, false, 11 },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
vec3_t fireOffset[5] = { {0,0,0},
|
||||
{24,-4,0},
|
||||
{0,-4,0},
|
||||
{24,-5,0},
|
||||
{24,-5,0} };
|
||||
const int acDeactStart[] = { 0, 23, 23, 23, 23 };
|
||||
const int acDeactEnd[] = { 0, 31, 31, 31, 31 };
|
||||
const qboolean turretIdle[] = { false, false, true, true }; // collapse when idle?
|
||||
|
||||
// turret animations
|
||||
const int turretIdleStart = 0;
|
||||
const int turretIdleEnd = 0;
|
||||
const int turretActStart = 1;
|
||||
const int turretActEnd = 9;
|
||||
const int turretActiveStart = 10;
|
||||
const int turretActiveEnd = 10;
|
||||
const int turretDeactStart = 23;
|
||||
const int turretDeactEnd = 31;
|
||||
|
||||
// bullet params
|
||||
#define AC_BULLET_DMG 4.0
|
||||
#define AC_BULLET_KICK 2.0
|
||||
// rocket params
|
||||
#define AC_ROCKET_DMG 100
|
||||
#define AC_ROCKET_SPEED 650
|
||||
#define AC_ROCKET_RADIUS_DMG 120
|
||||
#define AC_ROCKET_DMG_RADIUS 120
|
||||
// blaster params
|
||||
#define AC_BLASTER_DMG 20
|
||||
#define AC_BLASTER_SPEED 1000
|
||||
|
||||
void monster_autocannon_fire (edict_t *self)
|
||||
{
|
||||
vec3_t forward, right, start;
|
||||
|
||||
// fire straight ahead
|
||||
AngleVectors (self->s.angles, forward, right, NULL);
|
||||
if (self->onFloor)
|
||||
VectorNegate(right, right);
|
||||
VectorMA(self->s.origin, 24, forward, start);
|
||||
G_ProjectSource (self->s.origin, fireOffset[self->style], forward, right, start);
|
||||
|
||||
if (EMPNukeCheck(self, start))
|
||||
{
|
||||
gi.sound (self, CHAN_AUTO, gi.soundindex("items/empnuke/emp_missfire.wav"), 1, ATTN_NORM, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// what to fire?
|
||||
switch (self->style)
|
||||
{
|
||||
case 1:
|
||||
default:
|
||||
fire_bullet (self, start, forward, AC_BULLET_DMG, AC_BULLET_KICK, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_AUTOCANNON);
|
||||
gi.WriteByte (svc_muzzleflash);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (MZ_CHAINGUN2);
|
||||
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||||
break;
|
||||
case 2:
|
||||
fire_rocket (self, start, forward, AC_ROCKET_DMG, AC_ROCKET_SPEED, AC_ROCKET_RADIUS_DMG, AC_ROCKET_DMG_RADIUS, NULL);
|
||||
gi.WriteByte (svc_muzzleflash);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (MZ_ROCKET);
|
||||
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
fire_blaster (self, start, forward, AC_BLASTER_DMG, AC_BLASTER_SPEED, EF_HYPERBLASTER, true, BLASTER_ORANGE);
|
||||
gi.WriteByte (svc_muzzleflash);
|
||||
gi.WriteShort (self - g_edicts);
|
||||
gi.WriteByte (MZ_HYPERBLASTER);
|
||||
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qboolean angleBetween (float *ang, float *min, float *max)
|
||||
{
|
||||
// directly between?
|
||||
if (*ang > *min && *ang < *max)
|
||||
return true;
|
||||
|
||||
// make positive
|
||||
while (*min < 0)
|
||||
*min += 360.0;
|
||||
while (*ang < *min)
|
||||
*ang += 360.0;
|
||||
while (*max < *min)
|
||||
*max += 360.0;
|
||||
|
||||
if (*ang > *min && *ang < *max)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
float mod180 (float val)
|
||||
{
|
||||
while (val > 180)
|
||||
val -= 360.0;
|
||||
while (val < -180)
|
||||
val += 360.0;
|
||||
return val;
|
||||
}
|
||||
|
||||
qboolean canShoot (edict_t *self, edict_t *e)
|
||||
{
|
||||
vec3_t delta;
|
||||
vec3_t dangles;
|
||||
|
||||
VectorSubtract(e->s.origin, self->s.origin, delta);
|
||||
vectoangles(delta, dangles);
|
||||
dangles[PITCH] = mod180(dangles[PITCH]);
|
||||
|
||||
if ((!self->onFloor && dangles[PITCH] < 0) ||
|
||||
(self->onFloor && dangles[PITCH] > 0)) // facing up or down
|
||||
return false;
|
||||
|
||||
|
||||
if (self->monsterinfo.linkcount > 0)
|
||||
{
|
||||
float ideal_yaw = self->monsterinfo.attack_state;
|
||||
float max_yaw = anglemod(ideal_yaw + self->monsterinfo.linkcount);
|
||||
float min_yaw = anglemod(ideal_yaw - self->monsterinfo.linkcount);
|
||||
|
||||
if (!angleBetween(&dangles[YAW], &min_yaw, &max_yaw))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean autocannonInfront (edict_t *self, edict_t *other)
|
||||
{
|
||||
vec3_t vec;
|
||||
vec3_t angle;
|
||||
float dot;
|
||||
float min = -30.0;
|
||||
float max = 30.0;
|
||||
|
||||
// what's the yaw distance between the 2?
|
||||
VectorSubtract (other->s.origin, self->s.origin, vec);
|
||||
vectoangles(vec, angle);
|
||||
dot = angle[YAW] - self->s.angles[YAW];
|
||||
|
||||
if (angleBetween(&dot, &min, &max))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void monster_autocannon_findenemy (edict_t *self)
|
||||
{
|
||||
edict_t *e = NULL;
|
||||
|
||||
// can we still use our enemy?
|
||||
if (self->enemy)
|
||||
{
|
||||
if (!canShoot(self, self->enemy))
|
||||
{
|
||||
self->oldenemy = NULL;
|
||||
self->enemy = NULL;
|
||||
}
|
||||
else if (!visible(self, self->enemy))
|
||||
{
|
||||
self->oldenemy = self->enemy;
|
||||
self->enemy = NULL;
|
||||
}
|
||||
else if (self->enemy->flags & FL_NOTARGET)
|
||||
{
|
||||
self->oldenemy = NULL;
|
||||
self->enemy = NULL;
|
||||
}
|
||||
else if (self->enemy->health <= 0)
|
||||
{
|
||||
self->oldenemy = NULL;
|
||||
self->enemy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
while (self->enemy == NULL)
|
||||
{
|
||||
e = findradius(e, self->s.origin, AC_RANGE);
|
||||
if (e == NULL)
|
||||
{
|
||||
if (self->oldenemy == NULL)
|
||||
return;
|
||||
|
||||
if (level.time > self->timeout)
|
||||
{
|
||||
self->oldenemy = NULL;
|
||||
return;
|
||||
}
|
||||
self->enemy = self->oldenemy;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (self->spawnflags & AC_SF_BERSERK)
|
||||
{
|
||||
// attack clients and monsters
|
||||
if (!e->client && !(e->svflags & SVF_MONSTER))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// only attack clients
|
||||
if (!e->client)
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't target dead stuff
|
||||
if (e->health <= 0)
|
||||
continue;
|
||||
|
||||
// don't target notarget stuff
|
||||
if (e->flags & FL_NOTARGET)
|
||||
continue;
|
||||
|
||||
// don't target other autocannons
|
||||
if (Q_stricmp(e->classname, "monster_autocannon") == 0)
|
||||
continue;
|
||||
|
||||
// don't target self
|
||||
if (e == self)
|
||||
continue;
|
||||
|
||||
// can it be seen?
|
||||
if (!visible(self, e))
|
||||
continue;
|
||||
|
||||
if (!autocannonInfront(self, e))
|
||||
continue;
|
||||
|
||||
if (canShoot(self, e))
|
||||
self->enemy = e;
|
||||
}
|
||||
}
|
||||
|
||||
void monster_autocannon_turn (edict_t *self)
|
||||
{
|
||||
vec3_t old_angles;
|
||||
VectorCopy(self->s.angles, old_angles);
|
||||
if (!self->enemy)
|
||||
{
|
||||
if (self->monsterinfo.linkcount > 0)
|
||||
{
|
||||
int ideal_yaw = self->monsterinfo.attack_state;
|
||||
int max_yaw = anglemod(ideal_yaw + self->monsterinfo.linkcount);
|
||||
int min_yaw = anglemod(ideal_yaw - self->monsterinfo.linkcount);
|
||||
|
||||
while (max_yaw < min_yaw)
|
||||
max_yaw += 360.0;
|
||||
|
||||
self->s.angles[YAW] += (self->monsterinfo.lefty ? -AC_TURN_SPEED : AC_TURN_SPEED);
|
||||
|
||||
// back and forth
|
||||
if (self->s.angles[YAW] > max_yaw)
|
||||
{
|
||||
self->monsterinfo.lefty = 1;
|
||||
self->s.angles[YAW] = max_yaw;
|
||||
}
|
||||
else if (self->s.angles[YAW] < min_yaw)
|
||||
{
|
||||
self->monsterinfo.lefty = 0;
|
||||
self->s.angles[YAW] = min_yaw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->s.angles[YAW] = anglemod(self->s.angles[YAW] + AC_TURN_SPEED);
|
||||
}
|
||||
|
||||
// angle pitch towards 5 to 10...
|
||||
if (!self->onFloor)
|
||||
{
|
||||
if (self->s.angles[PITCH] > 10)
|
||||
self->s.angles[PITCH] -= 4;
|
||||
else if (self->s.angles[PITCH] < 5)
|
||||
self->s.angles[PITCH] += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->s.angles[PITCH] < -10)
|
||||
self->s.angles[PITCH] += 4;
|
||||
else if (self->s.angles[PITCH] > -5)
|
||||
self->s.angles[PITCH] -= 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// look toward enemy mid point
|
||||
if (visible(self, self->enemy))
|
||||
{
|
||||
vec3_t offset, dest;
|
||||
VectorCopy(self->enemy->mins, offset);
|
||||
VectorAdd(offset, self->enemy->maxs, offset);
|
||||
VectorScale(offset, 0.65, offset);
|
||||
VectorAdd(self->enemy->s.origin, offset, dest);
|
||||
angleToward(self, dest, AC_TURN_SPEED);
|
||||
VectorCopy(dest, self->monsterinfo.last_sighting);
|
||||
self->timeout = level.time + AC_TIMEOUT;
|
||||
|
||||
// restrict our range of movement if need be
|
||||
if (self->monsterinfo.linkcount > 0)
|
||||
{
|
||||
float amax = anglemod(self->monsterinfo.attack_state + self->monsterinfo.linkcount);
|
||||
float amin = anglemod(self->monsterinfo.attack_state - self->monsterinfo.linkcount);
|
||||
self->s.angles[YAW] = anglemod(self->s.angles[YAW]);
|
||||
if (!angleBetween(&self->s.angles[YAW], &amin, &amax))
|
||||
{
|
||||
// which is closer?
|
||||
if (self->s.angles[YAW] - amax < amin - self->s.angles[YAW])
|
||||
self->s.angles[YAW] = amin;
|
||||
else
|
||||
self->s.angles[YAW] = amax;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else // not visible now, so head toward last known spot
|
||||
angleToward(self, self->monsterinfo.last_sighting, AC_TURN_SPEED);
|
||||
}
|
||||
|
||||
// get our angles between 180 and -180
|
||||
while (self->s.angles[PITCH] > 180)
|
||||
self->s.angles[PITCH] -= 360.0;
|
||||
while (self->s.angles[PITCH] < -180)
|
||||
self->s.angles[PITCH] += 360;
|
||||
|
||||
// outside of the pitch extents?
|
||||
if (self->s.angles[PITCH] > acPitchExtents[self->onFloor][1])
|
||||
self->s.angles[PITCH] = acPitchExtents[self->onFloor][1];
|
||||
else if (self->s.angles[PITCH] < acPitchExtents[self->onFloor][0])
|
||||
self->s.angles[PITCH] = acPitchExtents[self->onFloor][0];
|
||||
|
||||
// make sure the turret's angles match the gun's
|
||||
self->chain->s.angles[YAW] = self->s.angles[YAW];
|
||||
self->chain->s.angles[PITCH] = 0;
|
||||
|
||||
// setup the sound
|
||||
if (VectorCompare(self->s.angles, old_angles))
|
||||
self->chain->s.sound = 0;
|
||||
else
|
||||
self->chain->s.sound = gi.soundindex("objects/acannon/ac_idle.wav");
|
||||
}
|
||||
|
||||
void monster_autocannon_think (edict_t *self)
|
||||
{
|
||||
ac_anim_frame_t frame;
|
||||
ac_anim_t anim;
|
||||
int lefty = 0;
|
||||
edict_t *old_enemy;
|
||||
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
|
||||
// get an enemy
|
||||
old_enemy = self->enemy;
|
||||
monster_autocannon_findenemy(self);
|
||||
if (self->enemy != NULL && old_enemy != self->enemy)
|
||||
gi.sound(self, CHAN_VOICE, gi.soundindex("objects/acannon/ac_act.wav"), 1, ATTN_NORM, 0);
|
||||
|
||||
// turn whereever
|
||||
lefty = self->monsterinfo.lefty;
|
||||
if (level.time > self->delay)
|
||||
{
|
||||
monster_autocannon_turn(self);
|
||||
if (self->monsterinfo.lefty != lefty)
|
||||
self->delay = level.time + AC_TURN_DELAY;
|
||||
}
|
||||
|
||||
anim = acFiringFrames[self->style];
|
||||
frame = anim.frames[self->seq];
|
||||
|
||||
// ok, we don't have an enemy
|
||||
if (self->enemy == NULL)
|
||||
{
|
||||
if (self->seq == 0)
|
||||
{
|
||||
// get into idle animation
|
||||
self->s.frame++;
|
||||
if (self->s.frame > acActiveEnd[self->style] ||
|
||||
self->s.frame < acActiveStart[self->style])
|
||||
self->s.frame = acActiveStart[self->style];
|
||||
return; // done, we want to wait here
|
||||
}
|
||||
|
||||
// set the frame
|
||||
self->s.frame = frame.frame;
|
||||
|
||||
// fire
|
||||
if (frame.fire)
|
||||
monster_autocannon_fire(self);
|
||||
|
||||
// if we're not done with the firing sequence, we need to finish it off
|
||||
if (frame.last) // end of the loop or firing frame?
|
||||
self->seq = 0;
|
||||
else
|
||||
self->seq++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we have an enemy but he's not infront, go to the beginning of the firing sequence
|
||||
if (!autocannonInfront(self, self->enemy))
|
||||
{
|
||||
self->s.frame = frame.frame;
|
||||
if (self->seq == anim.firstNonPause)
|
||||
return; // done, we want to wait here
|
||||
|
||||
if (frame.last) // end of the loop or firing frame?
|
||||
self->seq = anim.firstNonPause;
|
||||
else
|
||||
self->seq++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// we have an enemy, AND he's visible
|
||||
// let's kick his ass
|
||||
self->s.frame = frame.frame;
|
||||
if (frame.fire)
|
||||
monster_autocannon_fire(self);
|
||||
|
||||
if (frame.last) // end of the loop?
|
||||
self->seq = anim.firstNonPause;
|
||||
else
|
||||
self->seq++;
|
||||
}
|
||||
|
||||
void monster_autocannon_explode (edict_t *ent)
|
||||
{
|
||||
vec3_t origin;
|
||||
|
||||
T_RadiusDamage(ent, ent, AC_EXPLODE_DMG, ent->enemy, AC_EXPLODE_RADIUS, MOD_TRIPBOMB);
|
||||
|
||||
VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
|
||||
gi.WriteByte (svc_temp_entity);
|
||||
if (ent->waterlevel)
|
||||
{
|
||||
if (ent->groundentity)
|
||||
gi.WriteByte (TE_GRENADE_EXPLOSION_WATER);
|
||||
else
|
||||
gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ent->groundentity)
|
||||
gi.WriteByte (TE_GRENADE_EXPLOSION);
|
||||
else
|
||||
gi.WriteByte (TE_ROCKET_EXPLOSION);
|
||||
}
|
||||
gi.WritePosition (origin);
|
||||
gi.multicast (ent->s.origin, MULTICAST_PHS);
|
||||
|
||||
// set the pain skin
|
||||
ent->chain->chain->s.skinnum = 1; // pain
|
||||
ent->chain->chain->rideWith[0] = NULL;
|
||||
ent->chain->chain->rideWith[1] = NULL;
|
||||
G_FreeEdict(ent->chain);
|
||||
G_FreeEdict(ent);
|
||||
}
|
||||
|
||||
|
||||
void monster_autocannon_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
||||
{
|
||||
// explode
|
||||
self->takedamage = DAMAGE_NO;
|
||||
self->think = monster_autocannon_explode;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
}
|
||||
|
||||
void monster_autocannon_pain (edict_t *self, edict_t *other, float kick, int damage)
|
||||
{
|
||||
// keep the enemy
|
||||
if (other->client || other->svflags & SVF_MONSTER)
|
||||
self->enemy = other;
|
||||
}
|
||||
|
||||
void monster_autocannon_activate (edict_t *self)
|
||||
{
|
||||
self->active = AC_S_ACTIVATING;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
|
||||
// go thru the activation frames
|
||||
if (self->s.frame >= acActStart[self->style] &&
|
||||
self->s.frame < acActEnd[self->style])
|
||||
{
|
||||
if (self->s.frame == acActStart[self->style])
|
||||
{
|
||||
// gi.sound(self, CHAN_VOICE, gi.soundindex("objects/acannon/ac_out.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
// continue
|
||||
self->s.frame++;
|
||||
self->chain->s.frame++;
|
||||
}
|
||||
else if (self->s.frame == acActEnd[self->style])
|
||||
{
|
||||
self->s.frame = acActiveStart[self->style];
|
||||
self->chain->s.frame = turretActiveStart;
|
||||
self->think = monster_autocannon_think;
|
||||
self->active = AC_S_ACTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->s.frame = acActStart[self->style];
|
||||
self->chain->s.frame = turretActStart;
|
||||
}
|
||||
}
|
||||
|
||||
void monster_autocannon_deactivate (edict_t *self)
|
||||
{
|
||||
self->active = AC_S_DEACTIVATING;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
|
||||
// go thru the deactivation frames
|
||||
if (self->s.angles[PITCH] != 0)
|
||||
{
|
||||
if (self->s.angles[PITCH] > 0)
|
||||
{
|
||||
self->s.angles[PITCH] -= 5;
|
||||
if (self->s.angles[PITCH] < 0)
|
||||
self->s.angles[PITCH] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->s.angles[PITCH] += 5;
|
||||
if (self->s.angles[PITCH] > 0)
|
||||
self->s.angles[PITCH] = 0;
|
||||
}
|
||||
}
|
||||
else if (self->s.frame >= acDeactStart[self->style] &&
|
||||
self->s.frame < acDeactEnd[self->style])
|
||||
{
|
||||
self->chain->s.sound = 0;
|
||||
if (self->s.frame == acDeactStart[self->style])
|
||||
{
|
||||
//gi.sound(self, CHAN_VOICE, gi.soundindex("objects/acannon/ac_away.wav"), 1, ATTN_NORM, 0);
|
||||
}
|
||||
// continue
|
||||
self->s.frame++;
|
||||
self->chain->s.frame++;
|
||||
}
|
||||
else if (self->s.frame == acDeactEnd[self->style])
|
||||
{
|
||||
self->s.frame = acIdleStart[self->style];
|
||||
self->chain->s.frame = turretIdleStart;
|
||||
self->think = NULL;
|
||||
self->nextthink = 0;
|
||||
self->chain->s.sound = 0;
|
||||
self->active = AC_S_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->s.frame = acDeactStart[self->style];
|
||||
self->chain->s.frame = turretDeactStart;
|
||||
}
|
||||
}
|
||||
|
||||
void monster_autocannon_act (edict_t *self)
|
||||
{
|
||||
if (self->active == AC_S_IDLE)
|
||||
{
|
||||
if (acActStart[self->style] != -1)
|
||||
self->think = monster_autocannon_activate;
|
||||
else
|
||||
{
|
||||
self->s.frame = acActiveStart[self->style];
|
||||
self->chain->s.frame = turretActiveStart;
|
||||
self->think = monster_autocannon_think;
|
||||
self->active = AC_S_ACTIVE;
|
||||
}
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
}
|
||||
else if (self->active == AC_S_ACTIVE)
|
||||
{
|
||||
if (acDeactStart[self->style] != -1)
|
||||
{
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
self->think = monster_autocannon_deactivate;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (turretIdle[self->style])
|
||||
self->chain->s.frame = turretIdleStart;
|
||||
else
|
||||
self->chain->s.frame = turretActiveStart;
|
||||
self->s.frame = acActiveStart[self->style];
|
||||
self->think = NULL;
|
||||
self->active = AC_S_IDLE;
|
||||
self->nextthink = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void monster_autocannon_use (edict_t *self, edict_t *other, edict_t *activator)
|
||||
{
|
||||
// on/off or berserk toggle?
|
||||
if (self->spawnflags & AC_SF_BERSERK_TOGGLE)
|
||||
{
|
||||
if (self->spawnflags & AC_SF_BERSERK)
|
||||
self->spawnflags &= ~AC_SF_BERSERK;
|
||||
else
|
||||
self->spawnflags |= AC_SF_BERSERK;
|
||||
}
|
||||
else
|
||||
monster_autocannon_act(self);
|
||||
}
|
||||
|
||||
void monster_autocannon_usestub (edict_t *self)
|
||||
{
|
||||
// stub
|
||||
monster_autocannon_act(self);
|
||||
}
|
||||
|
||||
|
||||
/*QUAKED monster_autocannon (1 .5 0) (-12 -12 -28) (12 12 16) Ambush Trigger_Spawn Sight GoodGuy
|
||||
Ceiling autoturret.
|
||||
"style"
|
||||
1: chaingun
|
||||
2: rocket
|
||||
3: blaster
|
||||
4: slow blaster
|
||||
model="models/objects/acannon/base/"
|
||||
model2="models/objects/acannon/turret/"
|
||||
*/
|
||||
|
||||
/*QUAKED monster_autocannon_floor (1 .5 0) (-12 -12 -16) (12 12 28) Ambush Trigger_Spawn Sight GoodGuy
|
||||
Floor autoturret.
|
||||
"style"
|
||||
2: rocket
|
||||
3: blaster
|
||||
4: slow blaster
|
||||
model="models/objects/acannon/base2/"
|
||||
model2="models/objects/acannon/turret2/"
|
||||
*/
|
||||
void SP_monster_autocannon (edict_t *self)
|
||||
{
|
||||
edict_t *base, *turret;
|
||||
vec3_t offset;
|
||||
|
||||
if (deathmatch->value)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->style > 4 || self->style < 1)
|
||||
self->style = 1;
|
||||
|
||||
// if we're on hard or nightmare, use fast lasers
|
||||
if (skill->value >= 2 && self->style == 4)
|
||||
self->style = 3;
|
||||
|
||||
// precache some sounds and models
|
||||
gi.soundindex("objects/acannon/ac_idle.wav");
|
||||
gi.soundindex("objects/acannon/ac_act.wav");
|
||||
//gi.soundindex("objects/acannon/ac_out.wav");
|
||||
//gi.soundindex("objects/acannon/ac_away.wav");
|
||||
gi.modelindex("models/objects/rocket/tris.md2");
|
||||
gi.modelindex("models/objects/laser/tris.md2");
|
||||
|
||||
// create the base
|
||||
base = G_Spawn();
|
||||
base->classname = "autocannon base";
|
||||
base->solid = SOLID_BBOX;
|
||||
VectorCopy(self->s.origin, base->s.origin);
|
||||
if (!self->onFloor)
|
||||
base->movetype = MOVETYPE_NONE;
|
||||
else
|
||||
base->movetype = MOVETYPE_RIDE; // make the base MOVETYPE_RIDE so that it can ride on trains
|
||||
|
||||
if (!self->onFloor)
|
||||
base->s.modelindex = gi.modelindex("models/objects/acannon/base/tris.md2");
|
||||
else
|
||||
base->s.modelindex = gi.modelindex("models/objects/acannon/base2/tris.md2");
|
||||
gi.linkentity(base);
|
||||
|
||||
// create the turret
|
||||
turret = G_Spawn();
|
||||
turret->classname = "autocannon turret";
|
||||
turret->solid = SOLID_BBOX;
|
||||
turret->movetype = MOVETYPE_NONE;
|
||||
turret->chain = base;
|
||||
VectorCopy(self->s.origin, turret->s.origin);
|
||||
if (!self->onFloor)
|
||||
turret->s.modelindex = gi.modelindex("models/objects/acannon/turret/tris.md2");
|
||||
else
|
||||
turret->s.modelindex = gi.modelindex("models/objects/acannon/turret2/tris.md2");
|
||||
if (turretIdle[self->style])
|
||||
turret->s.frame = turretIdleStart;
|
||||
else
|
||||
turret->s.frame = turretActiveStart;
|
||||
turret->s.angles[YAW] = self->s.angles[YAW];
|
||||
turret->s.angles[PITCH] = 0;
|
||||
gi.linkentity(turret);
|
||||
|
||||
// fill in the details about ourself
|
||||
self->solid = SOLID_BBOX;
|
||||
self->movetype = MOVETYPE_NONE;
|
||||
if (!self->onFloor)
|
||||
VectorSet(offset, 0, 0, -20); // offset down a bit
|
||||
else
|
||||
VectorSet(offset, 0, 0, 20); // offset up a bit
|
||||
VectorAdd(self->s.origin, offset, self->s.origin);
|
||||
|
||||
// set the bounding box
|
||||
if (!self->onFloor)
|
||||
{
|
||||
VectorSet(self->mins, -12, -12, -28);
|
||||
VectorSet(self->maxs, 12, 12, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet(self->mins, -12, -12, -16);
|
||||
VectorSet(self->maxs, 12, 12, 28);
|
||||
}
|
||||
self->chain = turret;
|
||||
if (!self->onFloor)
|
||||
self->s.modelindex = gi.modelindex(models[self->style]);
|
||||
else
|
||||
self->s.modelindex = gi.modelindex(floorModels[self->style]);
|
||||
self->s.frame = acIdleStart[self->style];
|
||||
self->active = AC_S_IDLE;
|
||||
self->monsterinfo.lefty = 0;
|
||||
self->monsterinfo.attack_state = self->s.angles[YAW]; // used for centre of back-and-forth "search"
|
||||
self->seq = 0;
|
||||
if (st.lip)
|
||||
self->monsterinfo.linkcount = (st.lip > 0 ? st.lip : 0);
|
||||
// self->svflags = SVF_MONSTER;
|
||||
self->svflags |= SVF_AUTOMATON; // Knightmare added
|
||||
|
||||
// default health
|
||||
if (!self->health)
|
||||
self->health = 100;
|
||||
|
||||
// enable/disable? ... berserk/not
|
||||
if (self->targetname)
|
||||
self->use = monster_autocannon_use;
|
||||
|
||||
if (self->spawnflags & AC_SF_BERSERK_TOGGLE || !(self->spawnflags & AC_SF_START_OFF))
|
||||
{
|
||||
self->think = monster_autocannon_usestub;
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
}
|
||||
|
||||
self->takedamage = DAMAGE_AIM;
|
||||
self->die = monster_autocannon_die;
|
||||
self->pain = monster_autocannon_pain;
|
||||
|
||||
// last but not least, setup the "rideWith" information
|
||||
base->rideWith[0] = turret;
|
||||
VectorSubtract(turret->s.origin, base->s.origin, base->rideWithOffset[0]);
|
||||
base->rideWith[1] = self;
|
||||
VectorSubtract(self->s.origin, base->s.origin, base->rideWithOffset[1]);
|
||||
|
||||
// Lazarus
|
||||
self->common_name = "Autocannon";
|
||||
|
||||
gi.linkentity(self);
|
||||
}
|
||||
|
||||
void SP_monster_autocannon_floor (edict_t *self)
|
||||
{
|
||||
if (self->style == 1)
|
||||
{
|
||||
gi.error("monster_autocannon_floor does not permit bullet style");
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->style < 1 || self->style > 4)
|
||||
self->style = 2;
|
||||
self->onFloor = 1; // signify floor mounted
|
||||
|
||||
// call the other one
|
||||
SP_monster_autocannon(self);
|
||||
}
|
|
@ -1732,7 +1732,10 @@ void SP_monster_zboss_precache (void)
|
|||
}
|
||||
|
||||
|
||||
/*QUAKED monster_zboss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
|
||||
/*QUAKED monster_zboss (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight GoodGuy NoGib
|
||||
model="models/monsters/bossz/mech/"
|
||||
model2="models/monsters/bossz/pilot/"
|
||||
model3="models/monsters/bossz/grapple/"
|
||||
*/
|
||||
void SP_monster_zboss (edict_t *self)
|
||||
{
|
||||
|
|
|
@ -422,7 +422,10 @@ void SP_monster_handler_precache(void)
|
|||
}
|
||||
|
||||
|
||||
/*QUAKED monster_handler (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
|
||||
/*QUAKED monster_handler (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight
|
||||
Enforcer with hound. Releases hound on sight.
|
||||
model="models/monsters/guard/handler/"
|
||||
model2="models/monsters/guard/hound/"
|
||||
*/
|
||||
void SP_monster_handler (edict_t *self)
|
||||
{
|
||||
|
|
|
@ -570,7 +570,8 @@ void SP_monster_hound_precache(void)
|
|||
}
|
||||
|
||||
|
||||
/*QUAKED monster_hound (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
|
||||
/*QUAKED monster_hound (1 .5 0) (-16 -16 -24) (16 16 24) Ambush Trigger_Spawn Sight GoodGuy NoGib
|
||||
model="models/monsters/guard/hound/"
|
||||
*/
|
||||
void SP_monster_hound (edict_t *self)
|
||||
{
|
||||
|
|
|
@ -42,6 +42,7 @@ vec_t VectorLengthSquared (vec3_t v)
|
|||
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
void angleToward (edict_t *self, vec3_t point, float speed)
|
||||
{
|
||||
|
@ -65,7 +66,6 @@ void angleToward (edict_t *self, vec3_t point, float speed)
|
|||
vel = VectorLength(self->velocity);
|
||||
VectorScale(forward, vel, self->velocity);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAXROTATION 20
|
||||
|
||||
|
|
Loading…
Reference in a new issue