Disclaimer: this is a one-on-one deathmatch mode, so if you're an ADD kid it may bore you. Also, this lesson may require you to make substantial changes to your bot AI if you are interested in fully implementing the mode. I recommend reading the tutorial before adopting it.)
You know that I've been talking about my unfinished mod called Bot Championship. You know it is a tournament-style botmatch game a bit similar to Quake 3 Arena or Unreal Tournament. Well, I have some bad news and I have some good news.
First, the bad news : it's boring. Not totally boring, just very simple. It just doesn't feel like a complete mod, but rather just a new patch or mode. BC does feature some good AI in it, but most of that is coming out via tutorials on the Cafe. Thus, it does not look as though I will be releasing that particular mod.
The good news is that you benefit from my wasted work, my humiliation, my misfortune. Bot Championship might not have been a deep experience unto itself, but it will serve as an excellent deathmatch mode. The mod was based on a very simplistic concept -- bots that progressed in difficulty -- which was executed with very simplistic code. I will teach you that code now.
For your Tournament Mode to work properly you need a few features in your bot: my variable velocity system, skill-based AI, and multiple skins. As you may remember, the first is implemented through the .speed float. The second may take various forms, including better fighting styles or tighter aiming at high skill levels. The third can be found in skin packs on cdrom.com or the like.
Now let me briefly explain our new mode. Frags are lives. Every contestant starts off with three frags, or lives. If you get killed, you lose a life. Lose all three lives and you lose the tournament. When you kill a bot, he loses a life as well. If he loses all three lives, he is eliminated from the competition. A new more difficult bot takes his place. If you eliminate all the bots, you win the contest.
In a way, it's the opposite of Last Man Standing. Obviously, the last bot should be pretty damn hard to kill. In addition, you have to defeat all these guys with only three lives. Note: for simplicity, this tutorial will focus solely on a one-on-one tournament (in other words, only one bot in the game).
Anyway, enough with the friggin' talk already. Crack open defs.qc and add this line at the bottom:
float current_bot_skill;This variable will hold the value of the number of rockets on each map. Just kidding. I think it's self-explanatory.
if (cvar("deathmatch") == 12) { local entity bot; bot = find(world, classname, "bot"); if (bot != world) { bprint(bot already in game\n"); return; } }This little part checks to see if there is a bot already in the game. If so, we will leave the subroutine, thereby locking any other bots out. (Yes, you could skip this part if you wanted more bots, but you'd be buggin' out your own mod.) Next, add this at the bottom of create_bot():
if (cvar("deathmatch") == 12) { bot.skin = current_bot_skill; current_bot_skill = current_bot_skill + 1; bot.frags = 3; }Here we use the current bot skill as the new bot's skin, we increase it by one, and then we set his frags.
if (cvar("deathmatch") == 12 && self.frags == 0) rise_up_ladder(); if (cvar("deathmatch") == 12 && self.frags > 0) { self.speed = 200 + (current_skill_level * 30); self.health = 100 + (current_skill_level * 5); self.max_health = self.health; }The bot's lives are zero, so we will eliminate him and bring in the next bot, and thus the player rises up our tounament ladder. If he still has lives, we alter his traits according to the current bot skill level. Assuming that ou start your first bot with a speed of 200 and health of 100, we give him more of each of these characteristics depending on the skill level.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void() rise_up_ladder = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { if (current_bot_skill == 15) { local entity plr; plr = find(world, classname, "player"); centerprint(plr, "you won the tournament!\n"); remove(self); return; } bprint("\n"); bprint(self.netname); bprint(" is eliminated\n"); current_bot_skill = current_bot_skill + 1; self.skin = current_bot_skill; self.netname = bot_name(); self.frags = 3; msgUpdateNameToAll(self.fClientNo, self.netname ); msgUpdateColorsToAll(self.fClientNo, self.fShirt, self.fPants ); msgUpdateFragsToAll(self.fClientNo, self.frags ); };Piece of cake. If the player has killed the sixteeth bot, the last bot, then he has won, and we remove the bot. He then must start a new game. If not, we print a little message, increase the current bot level, and apply those changes to the bot. We are literally changing that bot into a new one by altering his skin and his name.
// ------------------------------------------------ string() bot_name = // ------------------------------------------------ { if (current_bot_skill == 0) return "Newbie"; if (current_bot_skill == 1) return "dewD"; if (current_bot_skill == 2) return "Girlie"; if (current_bot_skill == 3) return "�'KANE�'"; if (current_bot_skill == 4) return "Devastator"; if (current_bot_skill == 5) return "Phatboy"; if (current_bot_skill == 6) return "Xeksis"; if (current_bot_skill == 7) return "'Sphinx�"; if (current_bot_skill == 8) return "Velza"; if (current_bot_skill == 9) return "�X�O�X�O�X'"; if (current_bot_skill == 10) return "NeCroSis"; if (current_bot_skill == 11) return "Godlike"; if (current_bot_skill == 12) return "Killer"; if (current_bot_skill == 13) return "Blood-�-guts"; if (current_bot_skill == 14) return "Wrath"; if (current_bot_skill == 15) return "Hades"; };Naturally you can change any of the names. The point here is that the name depends on the current ladder level. Um, what next ... oh, yeah, the file client.qc, open that up. First, scroll down to the sub PutClientInServer(). At the end, add this bit:
if (cvar("deathmatch") == 12 && time < 3) self.frags = 3; if (cvar("deathmatch") == 12 && time > 3 && self.frags == 0) { local entity bot; bot = find(world, classname, "bot"); remove(bot); centerprint(self, "you lost the tournament ...\n"); }If it is the beginning of a tournament game, we start the player with three frags. If it is respawning with no lives left, we remove the bot and tell the player he lost. Yes, it is simple, but you can add frills later.
if (cvar("deathmatch") == 12) { if (targ.classname == "player" || targ.classname == "bot") { bprint (targ.netname); bprint (" loses a life\n"); targ.frags = targ.frags - 1; msgUpdateFragsToAll (targ.fClientNo, targ.frags); return; } }We have basically interrupted the rest of the routine here. Normally it gives frags to the attacker, yet we want it to subtract a frag from the victim. That is what you see above (you may add more death messages to this). Then we merely leave the sub.