Artificial intelligence for games is never about creating a realistic replica of what a user would do. It's about creating the illusion of a realistic replica of what a user would do. As simply as possible. In this case, the computer needs to be smart enough to occasionally spit the correct comeback at the user. But it also needs to be dumb enough to mess up. Otherwise the user would never be able to win, which doesn't sound like a very fun game to me.
For insults, this is easy enough—pick a random insult, remember its index (just like _lastUserChoiceSelected) and display the text on the screen. For comebacks it's only slightly trickier:
var shouldOpponentBeCorrect:Boolean = _(_random(0,2) == 0);
if(shouldOpponentBeCorrect)
{
_lastOpponentChoiceSelected = _lastUserChoiceSelected;
_mc.opponentTxt_mc.glow_mc.txt.text = Constants.COMEBACKS[_lastOpponentChoiceSelected];
}
else
{
_lastOpponentChoiceSelected = -1;
_mc.opponentTxt_mc.glow_mc.txt.text = Constants.GENERIC_WRONG_COMEBACKS[_random(0,
Constants.GENERIC_WRONG_COMEBACKS.length-1)];
}
var t:Timer = new Timer(_mc.opponentTxt_mc.glow_mc.txt.text.length * Constants.READ_SPEED);
t.addEventListener(TimerEvent.TIMER,_onOpponentTimer,false,0,true);
t.start();
_random() is a utility function I created to pick a random number between a minimum and maximum range. In this case, the minimum is 0, the maximum is 2. shouldOpponentBeCorrect is a Boolean set to true only if that random number is 0. In other words, roughly 33% of the time the computer will answer with the correct insult. Then I display the text on the screen for the opponent the exact same way I did for the user. That's all. Artificial Intelligence indeed.
Suppose the gamer has chosen "You fight like a dairy farmer." I know that translates to Insult #7 in my array, counting from 0. I have this saved as _lastUserChoiceSelected. I know the computer has just selected a comeback, the index of which I have stored as _lastOpponentChoiceSelected.
Scoring is as simple as this:
// award 1 point to whoever won the round
if(_lastOpponentChoiceSelected == _lastUserChoiceSelected)
{
if(!_knownComebacksObject["key_" + _lastOpponentChoiceSelected.toString()] && !Constants.CHARACTER_DATA[_opponentKey].BOSS)
{
_knownComebacks.push(_lastOpponentChoiceSelected); // now I can use this comeback!
_knownComebacksObject["key_" + _lastOpponentChoiceSelected.toString()] = true;
dispatchEvent(new DatabaseSaveEvent(DatabaseSaveEvent.SAVE,_lastOpponentChoiceSelected,
Constants.TABLE_COMEBACKS)); // that's it. Main will ask the Database to save the comeback.
}
_score--;
}
else _score++;
_userMC.gotoAndPlay("PARRY");
_opponentMC.gotoAndPlay("PARRY");
Add to _score if the user won the round, subtract if the opponent did. In addition, if the user lost the round but didn't know the comeback (which I can check from _knownComebackObjects), add that comeback to the _knownComebacks array. Now the user can use that comeback.
The next round is the same flow reversed:
_lastOpponentChoiceSelected is saved.LibraryItem_GameOptions, this time with the text of all known comebacks. Detecting Adobe AIR is essential for several reasons. First, a Flash app assumes it's been built for the browser. If you try to use an Adobe AIR method when not in Adobe AIR, your application will break. At Big Spaceship I built a simple utility class which I distribute called Environment. In it, I have a static function that returns a Boolean: true if this is in Adobe AIR, false if not:
public static function get IS_IN_AIR():Boolean {
return Capabilities.playerType == "Desktop";
};
IS_IN_AIR enables you to detect this pitfall at runtime, so your Adobe AIR methods only happen when needed.
In addition sometimes the flow of testing in the IDE is different than in final deployment. For example, in the IDE you can't create an XML file if it doesn't already exist. If you can detect that you're not in AIR, then you can program a way to bypass loading an XML file you know won't be there.