                                  [Image]

                           MULTI-ATTACK MONSTERS:

                                   STEP 1

Well, I'd actually have to say that this tutorial is pretty hard. But, when
 successfully done, just about any monster can launch just about any weapon
 there is. So, to ensure a stable working environment, lock all doors, do a
quick sound proofing on your room, disconnect all non-computer phone lines,
  and kill your family. Well, don't kill your family, maybe someone there
     knows QC :) Anyways, open up your text editor, and geeeet ready..

                                   STEP 2

  Now, open up weapons.qc and scroll down to where you see 'PLAYER WEAPON
        USE'. Now block off a section right above this and put this:



/*
===============================================================================

ENEMY WEAPONS--START CODE

===============================================================================
*/

/*
===============================================================================

ENEMY WEAPONS--END CODE

===============================================================================
*/

   You may be thinking 'well that was useless.' Well, you're pretty much
 correct. But, I find it always helps me keep my bearings to have a 'start'
    and 'end' to work between. So, when you do this tutorial, make sure
 everything goes BETWEEN those two things. Not necessary, but much cleaner.
Anyways, Step 1 will be for making monsters fire a shotgun. You can use the
         same code in army_fire from soldier.qc . So paste this in:

//Enemy Shotgun

void() Enemy_Fire_Shotgun =
{
local vector dir;
local entity en;
ai_face();
sound (self, CHAN_WEAPON, "soldier/sattck1.wav", 1, ATTN_NORM);
en = self.enemy;
dir = en.origin - en.velocity*0.2;
dir = normalize (dir - self.origin);
FireBullets (4, dir, '0.1 0.1 0');
};

And while your there, copy and paste the same thing right below it with the
                  changes in RED to do the super shotgun.

//Enemy Super Shotgun

void() Enemy_Fire_SupShotgun =
{
local vector dir;
local entity en;
ai_face();
sound (self, CHAN_WEAPON, "soldier/sattck1.wav", 1, ATTN_NORM);
en = self.enemy;
dir = en.origin - en.velocity*0.2;
dir = normalize (dir - self.origin);
FireBullets (12, dir, '0.1 0.1 0');
};

          Alright, now all your monsters can shoot either shotgun.

                                   STEP 3

  This next step will allow monsters to fire the nailgun or super nailgun.
         Below the Enemy_Fire_SupShotgun code, add the code below.

//Enemy Nailgun

void() Enemy_Fire_Nailgun =
{

local vector dir;
local entity old;

makevectors (self.v_angle);

sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);

dir = normalize (self.enemy.origin - self.origin);
launch_spike (self.origin + '0 0 16', dir);
};

              Alright, there's the nailgun code, now super...

//Enemy Super Nailgun

void() Enemy_Fire_SNailgun =
{

local vector dir;
local entity old;

sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);

dir = normalize (self.enemy.origin - self.origin);
launch_spike (self.origin + '0 0 16', dir);

newmis.touch = superspike_touch;
setmodel (newmis, "progs/s_spike.mdl");
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
};

                                   STEP 4

  Now I'll show you how to add the code for all monsters to shoot lasers,
 like the enforcer. First though, go up to the void W_Precache, and add the
                           blue lines, like this:

void() W_Precache =
{
precache_sound ("weapons/r_exp3.wav");
precache_sound ("weapons/rocket1i.wav");
precache_sound ("weapons/sgun1.wav");
precache_sound ("weapons/guncock.wav");
precache_sound ("weapons/ric1.wav");
precache_sound ("weapons/ric2.wav");
precache_sound ("weapons/ric3.wav");
precache_sound ("weapons/spike2.wav");
precache_sound ("weapons/tink1.wav");
precache_sound ("weapons/grenade.wav");
precache_sound ("weapons/bounce.wav");
precache_sound ("weapons/shotgn2.wav");
precache_model ("progs/laser.mdl");
precache_sound ("enforcer/enfire.wav");
precache_sound ("enforcer/enfstop.wav");

};

                               Now add this:

void() Enemy_Laser_Touch =
{
local vector org;
if (other == self.owner)
return; // don't explode on owner
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC);
org = self.origin - 8*normalize(self.velocity);

if (other.health)
{
SpawnBlood (org, self.velocity*0.2, 15);
T_Damage (other, self, self.owner, 15);
}
else
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
}
remove(self);
};

void(vector org, vector vec) Enemy_LaunchLaser =
{
local vector vec;
if (self.classname == "monster_enforcer")
sound (self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM);

vec = normalize(vec);
newmis = spawn();
newmis.owner = self;
newmis.movetype = MOVETYPE_FLY;
newmis.solid = SOLID_BBOX;
newmis.effects = EF_DIMLIGHT;

setmodel (newmis, "progs/laser.mdl");
setsize (newmis, '0 0 0', '0 0 0');
setorigin (newmis, org);

newmis.velocity = vec * 600;
newmis.angles = vectoangles(newmis.velocity);
newmis.nextthink = time + 5;
newmis.think = SUB_Remove;
newmis.touch = Enemy_Laser_Touch;
};

void() Enemy_Fire_Laser =
{
local vector org;

self.effects = self.effects | EF_MUZZLEFLASH;
makevectors (self.angles);
org = self.origin + v_forward * 30 + v_right * 8.5 + '0 0 16';

Enemy_LaunchLaser(org, self.enemy.origin - self.origin);
};

                                   STEP 5

        Ok, now we'll insert the code for the grenade launcher now.



//Enemy Grenade

void() EnemyGrenadeExplode =
{
T_RadiusDamage (self, self.owner, 40, world);
sound (self, CHAN_VOICE, "weapons/r_exp3.wav", 1, ATTN_NORM);

WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);

self.velocity = '0 0 0';
self.touch = SUB_Null;
setmodel (self, "progs/s_explod.spr");
self.solid = SOLID_NOT;
s_explode1 ();
};

void() EnemyGrenadeTouch =
{
if (other == self.owner)
return; // don't explode on owner
if (other.takedamage == DAMAGE_AIM)
{
EnemyGrenadeExplode();
return;
}
sound (self, CHAN_VOICE, "weapons/bounce.wav", 1, ATTN_NORM); // bounce
sound
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};

void() Enemy_Fire_Grenade =
{
local entity missile, mpuff;
self.effects = self.effects | EF_MUZZLEFLASH;

sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);

missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_BOUNCE;
missile.solid = SOLID_BBOX;
// set missile speed

makevectors (self.angles);

missile.velocity = normalize(self.enemy.origin - self.origin);
missile.velocity = missile.velocity * 600;
missile.velocity_z = 200;
missile.avelocity = '300 300 300';

missile.angles = vectoangles(missile.velocity);
missile.touch = EnemyGrenadeTouch;
// set missile duration
missile.nextthink = time + 2.5;
missile.think = EnemyGrenadeExplode;

setmodel (missile, "progs/grenade.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.origin);
};

                                   STEP 6

  Well, we're almost done. Now we just have to add the code for the rocket
                        launcher. So, here we go....

//Enemy Rocket

void() T_EnemyMisTouch =
{
local float damg;

if (other == self.owner)
return; // don't explode on owner

if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}

damg = 10 + random()*2;

if (other.health)
{
if (other.classname == "monster_shambler")
damg = damg * 0.5; // mostly immune
T_Damage (other, self, self.owner, damg );
}

T_RadiusDamage (self, self.owner, 10, other); //Changed from 120 to 10

self.origin = self.origin - 8*normalize(self.velocity);

WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);

BecomeExplosion ();

};

void() W_EnemyRocket =
{
local entity missile, mpuff;

sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);

missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_FLYMISSILE;
missile.solid = SOLID_BBOX;
missile.classname = "missile";
missile.velocity = normalize(self.enemy.origin - self.origin);
missile.velocity = missile.velocity * 600;
missile.angles = vectoangles(missile.velocity);
missile.touch = T_EnemyMisTouch;
missile.nextthink = time + 5;
missile.think = SUB_Remove;

setmodel (missile, "progs/missile.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.origin + v_forward*8 + '0 0 16');
};

void() Enemy_Fire_Rocket =
{
local vector dir;
local entity en;

ai_face();

sound (self, CHAN_WEAPON, "soldier/sattck1.wav", 1, ATTN_NORM);

en = self.enemy;
dir = en.origin - en.velocity*0.2;
dir = normalize (dir - self.origin);

W_EnemyRocket();

};

  Wow....that was loooong...anyways, we're almost done. In fact, you could
    skip this next step if you want, but I think it's more fun this way.

                                   STEP 7

  Alrighty, in this step, we're going to create a void that will randomize
   the enemies choice of attack, choosing either shotgun, super shotgun,
    nailgun, super nailgun, grenade launcher, laser, or rocket launcher.

//Enemy Randomizer

void() Enemy_Weapons_Random =
{
local float ewrandom;
ewrandom = random();
if (ewrandom < 0.16 )
Enemy_Fire_Shotgun();
else if ((ewrandom > 0.15) && (ewrandom < 0.32)
Enemy_Fire_SupShotgun();
else if ((ewrandom > 0.31) && (ewrandom < 0.48)
Enemy_Fire_Nailgun();
else if ((ewrandom > 0.47) && (ewrandom < 0.64)
Enemy_Fire_SNailgun();
else if ((ewrandom > 0.63) && (ewrandom < 0.8)
Enemy_Fire_Grenade();
else if ((ewrandom > 0.79) && (ewrandom < 0.96)
Enemy_Fire_Rocket();
else
Enemy_Fire_Shotgun();
};

                                   STEP 8

 Yes, here we are at Step #7, and STILL working. Now, I'll give you a short
little part on how to add this for every weapon firing monster. You can add
 this to non-shooting monsters, but it'd look really bizzare if a dog or a
fiend started shooting rockets out of its mouth :) (Remember, if you have a
        specific weapon you want the monster to shoot, just replace
      Enemy_Weapons_Random(); with Enemy_FireShotgun(); or whatever.)

                                 ENFORCER:

 Lines 163 & 167 (of a clean version, if you dont have it clean, just find
                             these lines) read:

void() enf_atk6 =[ $attack6, enf_atk7 ] {enforcer_fire();};
void() enf_atk10 =[ $attack6, enf_atk11 ] {enforcer_fire();};

                              Change them to:

void() enf_atk6 =[ $attack6, enf_atk7 ] {Enemy_Weapons_Random();};
void() enf_atk10 =[ $attack6, enf_atk11 ] {Enemy_Weapons_Random();};

                                   OGRE:

                                 Line 256:

void() ogre_nail4 =[ $shoot3, ogre_nail5 ] {ai_face();OgreFireGrenade();};

                                 Change to:

void() ogre_nail4 =[ $shoot3, ogre_nail5 ]
{ai_face();Enemy_Weapons_Random();};

                                  SOLDIER:

                                 Line 101:

void() army_atk5 =[ $shoot5, army_atk6 ] {ai_face();army_fire();

                                 Change to:

void() army_atk5 =[ $shoot5, army_atk6 ] {ai_face();Enemy_Weapons_Random();



  Of course, you can apply this to more monsters, but these three are the
                                best for it.

                                   STEP 9

Well, I know you must be glad to be finished. I sure as hell am, this thing
 took me 6 hours. But, it has been checked for any and every flaw, and none
 are there. So, load it up and have fun. ((I may write an extension to this
tutorial later that will tell the monsters which weapons to use close range
                             and long range))

          This tutorial copyright (C) 1997 James "Drywall" Layman
