One of the biggest differences between monsters and players is strafing; players do, monsters don't. Strafing during combat is probably the most effective way to kick ass.
Today we'll teach our enforcer to strafe and shoot. It's quite simple, in fact. First, open the file ENFORCER.QC and scroll down to his attack sequence, which begins like this:
void() enf_atk1 =[ $attack1, enf_atk2 ] {ai_face();};Now we want to paste the following code before that attack sequence:
void() ai_strafe = { self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); ChangeYaw (); ai_run_slide(); };Good. That is the subroutine which will make him move from side to side. There is no magic or mystery here. It's actually id's code. His ideal yaw is the direction he should face, and ChangeYaw() turns him to it. Then ai_run_slide() makes him strafe.
void() enf_strafe1 =[ $attack1, enf_strafe2 ] {ai_strafe();}; void() enf_strafe2 =[ $attack6, enf_strafe3 ] {ai_strafe(); enforcer_fire();}; void() enf_strafe3 =[ $attack1, enf_strafe4 ] {ai_strafe();}; void() enf_strafe4 =[ $attack6, enf_strafe5 ] {ai_strafe(); enforcer_fire();}; void() enf_strafe5 =[ $attack1, enf_strafe6 ] {ai_strafe();}; void() enf_strafe6 =[ $attack6, enf_strafe7 ] {ai_strafe(); enforcer_fire();}; void() enf_strafe7 =[ $attack1, enf_strafe7 ] {ai_strafe(); if (visible(self.enemy)) enf_strafe1(); else enf_run1(); };Great. As you can see, this animation scene is made of only two frames, $attack1 and $attack6. I merely copied these out of his attack routine. You really don't need a lot of animation when you're strafing.
"If I can see my enemy, I will repeat my strafing. If I can't, I'll think my normal running thoughts."
You can compile now. The enforcer will strafe back and forth, firing his laser until you're toast. If you want him to be even more like a player, however, replace the whole routine called enforcer_fire() with the following code:
void() enforcer_fire = { local vector org; sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM); self.effects = self.effects | EF_MUZZLEFLASH; makevectors (self.angles); org = self.origin + v_forward * 30 + v_right * 8.5 + '0 0 16'; launch_spike (org, self.enemy.origin - self.origin); newmis.touch = superspike_touch; setmodel (newmis, "progs/s_spike.mdl"); setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); };Yeah baby, yeah. What I did here was change the sound and model from a laser to a nailgun. Basically I looked at the player's nailgun routine and the enforcer's firing routine and combined them.