By the end of this tutorial, your bot will know how to rocket-jump. Woo ha.
What, I don't sound enthusiastic? No, I am. Bot rocket-jumping is one of those sexy topics, a feature that looks great in your readme.txt file. There just isn't a frequent need for it in a game.
You may not like my approach to rocket-jumping. It doesn't utilize all kinds of realistic physic. It's one of those Coffee Quick Jobbies, but hey, it works.
Step one. We will first look at when the bot should execute this sexy maneuver. Before the AI sub bot_walk(), add this routine:
void() rock_jump1; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ float() should_rocket_jump = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { if (self.goalentity == world) return FALSE; if (!visible(self.goalentity)) return FALSE; if (!(self.flags & FL_ONGROUND)) return FALSE; if (self.goalentity.origin_z < self.origin_z) return FALSE; if (self.health < 25) return FALSE; if (vlen(self.origin - self.goalentity.origin) > 250) return FALSE; self.angles_y = vectoyaw(self.goalentity.origin - self.origin); self.angles_x = -25; rock_jump1(); return TRUE; };Whoa, check that shit out. We want to make the bot decide when to rocket jump. Here, if any of these conditions are false -- for instance, if he has no goal entity to jump to -- he will leave the subroutine. If he's higher than his goal, if he's too far away, et cetera, he'll do the same.
void() rock_jump1 =[ $rockatt1, rock_jump2 ] {}; void() rock_jump2 =[ $rockatt2, rock_jump3 ] {do_rocket_jump();}; void() rock_jump3 =[ $rockatt2, rock_jump4 ] {}; void() rock_jump4 =[ $rockatt2, rock_jump5 ] {}; void() rock_jump5 =[ $rockatt2, rock_jump6 ] {self.angles_x = 0;}; void() rock_jump6 =[ $rockatt2, bot_walk1 ] {};This is pretty simple. I chose the first two frames of the rocket attack, so it looks as though he is firing (have you caught on yet that he won't?). In the second frame, he performs the actual rocket jump. In the fifth frame, he straightens himself out. When done, he returns to walking.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void() do_rocket_jump = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { local entity exp; local float dam; exp = spawn(); exp.movetype = MOVETYPE_NONE; exp.velocity = '0 0 0'; setmodel(exp, "progs/s_explod.spr"); setorigin(exp, self.origin); exp.solid = SOLID_NOT; exp.think = s_explode1; exp.nextthink = time + 0.1; 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); dam = floor(random() * 20) + 10; T_Damage (self, self, self, dam); self.flags = self.flags - (self.flags & FL_ONGROUND); makevectors(self.angles); self.velocity = self.velocity + (v_forward * 400); self.velocity_z = self.velocity_z + 500; };Oh, the trickery. In this code, we create an entity. This entity becomes a fake explosion underneath the bot. We then damage the bot a little (for, eh, realism) and propel him into the air. Hence, a bot rocket jump. See, no messy physics.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void() bot_walk = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { // this is his main AI routine, where he will look for items and enemies if (!(self.flags & FL_ONGROUND)) return;After that, add this:
if (should_rocket_jump()) return;Here he wonders if he should do the nasty. If so, he leaves the routine, since he will be executing an animation sequence.