The definition of fuzzy logic is eh, somewhat fuzzy.
I have spotted that fancy AI term in the readme.txt files of certain deathmatch bots. Oh, it looked very classy, very sophisticated. But I knew it probably didn't apply, because fuzzy logic is more than a couple nested if-then statements.
True, the term is easy to invoke. Fuzzy logic can mean that your bot makes slightly different decisions in certain situations. In a way, we have seen fuzzy logic tutorials here at the Cafe: when the bot doesn't always choose the rocket launcher as his preferred weapon, that's kinda fuzzy, right? For instance, if we peer into bot_bestweapon(), we see some straight-up black-and-white decision-making:
if (self.ammo_rockets > 0 && (self.items & IT_ROCKET_LAUNCHER)) return IT_ROCKET_LAUNCHER;But, we can screw with that a bit and come up with a butt-simple form of fuzzy logic:
if (self.ammo_rockets > 0 && (self.items & IT_ROCKET_LAUNCHER) && self.health < 50) return IT_ROCKET_LAUNCHER;In this example, the bot says "If my health is pretty good, then I don't really need to carry the rocket launcher." Thus, he will not always act perfectly, think perfectly. He won't always make the same decision.
if (self.ammo_rockets > 0 && (self.items & IT_ROCKET_LAUNCHER)) { local float chance; if (self.health > 50) chance = chance + 1; if (self.frags > 10) chance = chance + 1; if (cvar("skill") < 2) chance = chance + 1; if (floor(random() * chance) == 0) return IT_ROCKET_LAUNCHER; }Whoa, that's pretty fuzzy. What we have done here is literally to build a small decision-making machine. We look at three criteria to formulate the likelihood of the bot choosing the rocket launcher. As the float chance gets higher, the bot is less likely to select this gun.
We now possess a good grasp of what fuzzy logic means, and we now know of a neat way to implement it. We now must find a cool situation in which to utilize it.
What is the most critical point in deathmatch? Yep, combat.
That is the time when the bot's intelligence will be most noticeable, so it's a splendid place to insert some fuzzy logic. Here I will assume that you have a list of bot fighting styles availible, ranging from lame to lethal. I will also assume that you have implemented my variable bot speed system. If you haven't, I have a tall hat and a corner for you to sit in.
Okay. Our bot will use his fuzzy logic immediately after he spots an enemy. We want him to "size up" this opponent and adjust his combat tactics accordingly. In both bot_look_for_players() and bot_look_for_bots() you will see a line reading FoundTarget(). After these lines, add this (if you want):
size_up_enemy();Here he calls his new logic routine. Now we must write it. Before the previous two routines, add this one:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void() size_up_enemy = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { local float danger; if (self.enemy.frags > self.frags) danger = danger + 1; if (self.enemy.frags > self.frags + 5) danger = danger + 2; if (self.frags < 10) danger = danger + 1; if (self.enemy.health > self.health) danger = danger + 1; if (self.health < 25) danger = danger + 1; if (self.enemy.weapon == IT_LIGHTNING) danger = danger + 2; if (self.enemy.weapon == IT_LIGHTNING && self.enemy.ammo_cells > 50) danger = danger + 1; if (self.enemy.weapon == IT_ROCKET_LAUNCHER) danger = danger + 3; if (self.enemy.weapon == IT_ROCKET_LAUNCHER && self.enemy.ammo_rockets > 10) danger = danger + 1; if (self.weapon != IT_ROCKET_LAUNCHER) danger = danger + 1; if (cvar("skill") > 2) danger = danger + 1; if ((self.enemy.items & IT_INVINCIBLE)) danger = danger + 2; if ((self.enemy.items & IT_QUAD)) danger = danger + 1; // 18 possible danger points if (danger < 4) { self.speed = 100; self.attack_state = STANDING_STILL; return; } if (danger < 8) { self.speed = 200; self.attack_state = RUNNING_FOR_COVER return; } if (danger < 12) { self.speed = 300; self.attack_state = STRAFING; return; } if (danger < 14) { self.speed = 400; self.attack_state = CIRCLING; return; } self.speed = 500; self.attack_state = CHASING; };Isn't that special, a fuzzy logic routine. What's happening here is rather simple: the more dangerous the situation is, the tougher the bot chooses to be.
"If a threatening condition is true, then my danger goes up. If my danger ends up low, I'll take it easy and run slowly. If my danger is high, I'll choose a deadly tactic and run quickly."
Another cool thing is that he adjusts his running speed. You may not like this; you may think it's cheating. But you have to agree that it will make a huge difference during battle (bots should have some advantages). Moreover, he won't really run fast unless the player is very good anyway.
You may not agree with my ranking of the attack patterns, either. In other words, you may think strafing is deadlier than chasing. That's fine, just change it. The fact is that it's hard to decide which is more lethal.
Anyway, you get the picture. You may not use any of this, but you can still see how to implement fuzzy logic in a useful way. You may even have other, deadlier fighting styles. Or you may want to add in new danger criteria. Please do so if you wish.
One last note about this routine: you will notice that it sets your bot's .attack_state variable. Because of this, your bot_strafe() subroutine would have to look something like this:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void() bot_strafe = // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { if (self.attack_state == STANDING_STILL) return; if (self.attack_state == RUNNING_FOR_COVER) run_for_cover(); if (self.attack_state == STRAFING) bot_run_slide(); if (self.attack_state == CIRCLING) circle_enemy(); if (self.attack_state == CHASING) chase_enemy(); };Mmmmm yep. Obviously, fuzzy logic can be applied to many different decisions that the bot makes. Also, the criteria you examine in your logic can get very long and complicated; make sure your bot doesn't analyze trivial data that the player would never ever consider. Your AI should be as visible -- yet tough -- as possible. Don't make your bot so fuzzy that he's easy to defeat.