Today our bot is going to get a little bit devious.
He will learn how to throw an exploding backpack. Other deathmatchers will see it, try to pick it up, and boom! it will explode on them. Like my previous tutorials, it's all about giving the bot a personality.
First open TUTOR.QC. Before the routine bot_search_for_items(), paste this new routine:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void() fake_backpack_touch = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { if (other == self.owner || other == world) return; if (other.takedamage == DAMAGE_AIM) { 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 (); T_Damage (other, self, self, 500); } };This will be the exploding pack's touch routine. Child's play: if a player or bot touches the pack, it creates an explosion, hurts them, and removes itself. I just mimicked the explosion code from WEAPONS.QC. After that place this:
// -------------------------------------- void() drop_fake_backpack = // -------------------------------------- { local entity item; item = spawn(); item.origin = self.origin - '0 0 24'; item.velocity_z = 300; item.velocity_x = -100 + (random() * 400); item.velocity_y = -100 + (random() * 400); item.flags = FL_ITEM; item.solid = SOLID_TRIGGER; item.movetype = MOVETYPE_TOSS; setmodel (item, "progs/backpack.mdl"); item.classname = "explopack"; setsize (item, '-16 -16 0', '16 16 56'); item.owner = self; item.touch = fake_backpack_touch; item.nextthink = time + 240; item.think = SUB_Remove; };Just another entity creation routine; you've likely seen a bunch of them. The bot throws an item that looks like a backpack and feels like a rocket. Heehee. Oh, by the way, two things: one, it will not blow up on him and two, since it is flagged as an item, other bots will go for it. Heeheehee.
// checks a radius around him for items item = findradius(self.origin, 1500); while(item) { if ( (item.flags & FL_ITEM) && visible(item) && item.model != string_null && time > item.search_time)We want to add a condition to that last long line. We want to add "&& item.owner != self", so change that line to this:
if ( (item.flags & FL_ITEM) && visible(item) && item.model != string_null && time > item.search_time && item.owner != self)The bots will no longer try to get an item that they own, in this case, the exploding pack. Very good.
if (random() <= 0.02) if (random() < 0.5) drop_fake_backpack();So he will randomly decide when to throw one. This is a pretty good frequency. Maybe you think it's too much or too little. Please feel free to change it, move it, or edit it. It's up to you.
void(entity targ, entity attacker) ClientObituary = { local float rnum; local string deathstring, deathstring2; rnum = random(); if (targ.classname == "player" || targ.classname == "bot") {The "targ" here is a client that just got killed. After the bracket, paste this stuff:
if (attacker.classname == "explopack") { bprint (targ.netname); bprint (" enjoyed "); bprint (attacker.owner.netname); bprint ("'s exploding backpack\n"); attacker.owner.frags = attacker.owner.frags + 1; return; }This code does what it looks like it does: if the client killer was a backpack, it prints a funny little message, gives the owner a point, and exits the subroutine. You can change the message if you like.